Updated google-breakpad.
This commit is contained in:
		
							parent
							
								
									f602743c5a
								
							
						
					
					
						commit
						f652f53a22
					
				
							
								
								
									
										45
									
								
								google-breakpad/.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										45
									
								
								google-breakpad/.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,45 @@ | |||||||
|  | # Copyright 2014 Google Inc. All rights reserved. | ||||||
|  | # | ||||||
|  | # Redistribution and use in source and binary forms, with or without | ||||||
|  | # modification, are permitted provided that the following conditions are | ||||||
|  | # met: | ||||||
|  | # | ||||||
|  | #     * Redistributions of source code must retain the above copyright | ||||||
|  | # notice, this list of conditions and the following disclaimer. | ||||||
|  | #     * Redistributions in binary form must reproduce the above | ||||||
|  | # copyright notice, this list of conditions and the following disclaimer | ||||||
|  | # in the documentation and/or other materials provided with the | ||||||
|  | # distribution. | ||||||
|  | #     * Neither the name of Google Inc. nor the names of its | ||||||
|  | # contributors may be used to endorse or promote products derived from | ||||||
|  | # this software without specific prior written permission. | ||||||
|  | # | ||||||
|  | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||||||
|  | # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||||||
|  | # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | ||||||
|  | # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | ||||||
|  | # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | ||||||
|  | # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | ||||||
|  | # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | ||||||
|  | # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | ||||||
|  | # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||||||
|  | # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | ||||||
|  | # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||||||
|  | 
 | ||||||
|  | # Ignore GYP generated Visual Studio artifacts. | ||||||
|  | *.filters | ||||||
|  | *.sdf | ||||||
|  | *.sln | ||||||
|  | *.suo | ||||||
|  | *.vcproj | ||||||
|  | *.vcxproj | ||||||
|  | 
 | ||||||
|  | # Ignore compiled Python files. | ||||||
|  | *.pyc | ||||||
|  | 
 | ||||||
|  | # Ignore directories gclient syncs. | ||||||
|  | src/testing | ||||||
|  | src/third_party/glog | ||||||
|  | src/third_party/lss | ||||||
|  | src/third_party/protobuf | ||||||
|  | src/tools/gyp | ||||||
| @ -1,5 +1,4 @@ | |||||||
| # Copyright (c) 2010, Google Inc. | # Copyright 2010 Google Inc. All rights reserved. | ||||||
| # All rights reserved. |  | ||||||
| # | # | ||||||
| # Redistribution and use in source and binary forms, with or without | # Redistribution and use in source and binary forms, with or without | ||||||
| # modification, are permitted provided that the following conditions are | # modification, are permitted provided that the following conditions are | ||||||
| @ -27,18 +26,41 @@ | |||||||
| # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | ||||||
| # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||||||
| 
 | 
 | ||||||
| # We only use this file to ease the steps of generating projects after | # This is used to mimic the svn:externals mechanism for gclient (both Git and | ||||||
| # syncing, if we use gclient. All dependencies are svn:externals instead. | # SVN) based checkouts of Breakpad. As such, its use is entirely optional. If | ||||||
| # If you're not using gclient, you need to run the gyp python script to | # using a manually managed SVN checkout as opposed to a gclient managed checkout | ||||||
| # generate the projects. | # you can still use the hooks mechanism for generating project files by calling | ||||||
| # This can be done by the following command (assuming current directory): | # 'gclient runhooks' rather than 'gclient sync'. | ||||||
| #   src\tools\gyp\gyp.bat src\client\windows\breakpad_client.gyp | 
 | ||||||
|  | deps = { | ||||||
|  |   # Logging code. | ||||||
|  |   "src/src/third_party/glog": | ||||||
|  |     "http://google-glog.googlecode.com/svn/trunk@97", | ||||||
|  | 
 | ||||||
|  |   # Testing libraries and utilities. | ||||||
|  |   "src/src/testing": "http://googlemock.googlecode.com/svn/trunk@408", | ||||||
|  |   "src/src/testing/gtest": "http://googletest.googlecode.com/svn/trunk@615", | ||||||
|  | 
 | ||||||
|  |   # Protobuf. | ||||||
|  |   "src/src/third_party/protobuf/protobuf": | ||||||
|  |     "http://protobuf.googlecode.com/svn/trunk@407", | ||||||
|  | 
 | ||||||
|  |   # GYP project generator. | ||||||
|  |   "src/src/tools/gyp": "http://gyp.googlecode.com/svn/trunk@1886", | ||||||
|  | 
 | ||||||
|  |   # Linux syscall support. | ||||||
|  |   "src/src/third_party/lss": | ||||||
|  |     "http://linux-syscall-support.googlecode.com/svn/trunk/lss@24", | ||||||
|  | } | ||||||
|  | 
 | ||||||
| hooks = [ | hooks = [ | ||||||
|   { |   { | ||||||
|     # A change to a .gyp, .gypi, or to GYP itself should run the generator. |     # TODO(chrisha): Fix the GYP files so that they work without | ||||||
|  |     # --no-circular-check. | ||||||
|     "pattern": ".", |     "pattern": ".", | ||||||
|     "action": ["python", |     "action": ["python", | ||||||
|                "src/src/tools/gyp/gyp", |                "src/src/tools/gyp/gyp_main.py", | ||||||
|  |                "--no-circular-check", | ||||||
|                "src/src/client/windows/breakpad_client.gyp"], |                "src/src/client/windows/breakpad_client.gyp"], | ||||||
|   }, |   }, | ||||||
| ] | ] | ||||||
|  | |||||||
| @ -1,11 +1,13 @@ | |||||||
| Installation Instructions | Installation Instructions | ||||||
| ************************* | ************************* | ||||||
| 
 | 
 | ||||||
| Copyright (C) 1994, 1995, 1996, 1999, 2000, 2001, 2002, 2004, 2005, | Copyright (C) 1994-1996, 1999-2002, 2004-2013 Free Software Foundation, | ||||||
| 2006 Free Software Foundation, Inc. | Inc. | ||||||
| 
 | 
 | ||||||
| This file is free documentation; the Free Software Foundation gives |    Copying and distribution of this file, with or without modification, | ||||||
| unlimited permission to copy, distribute and modify it. | are permitted in any medium without royalty provided the copyright | ||||||
|  | notice and this notice are preserved.  This file is offered as-is, | ||||||
|  | without warranty of any kind. | ||||||
| 
 | 
 | ||||||
| Basic Installation | Basic Installation | ||||||
| ================== | ================== | ||||||
| @ -13,7 +15,11 @@ Basic Installation | |||||||
|    Briefly, the shell commands `./configure; make; make install' should |    Briefly, the shell commands `./configure; make; make install' should | ||||||
| configure, build, and install this package.  The following | configure, build, and install this package.  The following | ||||||
| more-detailed instructions are generic; see the `README' file for | more-detailed instructions are generic; see the `README' file for | ||||||
| instructions specific to this package. | instructions specific to this package.  Some packages provide this | ||||||
|  | `INSTALL' file but do not implement all of the features documented | ||||||
|  | below.  The lack of an optional feature in a given package is not | ||||||
|  | necessarily a bug.  More recommendations for GNU packages can be found | ||||||
|  | in *note Makefile Conventions: (standards)Makefile Conventions. | ||||||
| 
 | 
 | ||||||
|    The `configure' shell script attempts to guess correct values for |    The `configure' shell script attempts to guess correct values for | ||||||
| various system-dependent variables used during compilation.  It uses | various system-dependent variables used during compilation.  It uses | ||||||
| @ -53,12 +59,22 @@ The simplest way to compile this package is: | |||||||
|   2. Type `make' to compile the package. |   2. Type `make' to compile the package. | ||||||
| 
 | 
 | ||||||
|   3. Optionally, type `make check' to run any self-tests that come with |   3. Optionally, type `make check' to run any self-tests that come with | ||||||
|      the package. |      the package, generally using the just-built uninstalled binaries. | ||||||
| 
 | 
 | ||||||
|   4. Type `make install' to install the programs and any data files and |   4. Type `make install' to install the programs and any data files and | ||||||
|      documentation. |      documentation.  When installing into a prefix owned by root, it is | ||||||
|  |      recommended that the package be configured and built as a regular | ||||||
|  |      user, and only the `make install' phase executed with root | ||||||
|  |      privileges. | ||||||
| 
 | 
 | ||||||
|   5. You can remove the program binaries and object files from the |   5. Optionally, type `make installcheck' to repeat any self-tests, but | ||||||
|  |      this time using the binaries in their final installed location. | ||||||
|  |      This target does not install anything.  Running this target as a | ||||||
|  |      regular user, particularly if the prior `make install' required | ||||||
|  |      root privileges, verifies that the installation completed | ||||||
|  |      correctly. | ||||||
|  | 
 | ||||||
|  |   6. You can remove the program binaries and object files from the | ||||||
|      source code directory by typing `make clean'.  To also remove the |      source code directory by typing `make clean'.  To also remove the | ||||||
|      files that `configure' created (so you can compile the package for |      files that `configure' created (so you can compile the package for | ||||||
|      a different kind of computer), type `make distclean'.  There is |      a different kind of computer), type `make distclean'.  There is | ||||||
| @ -67,12 +83,22 @@ The simplest way to compile this package is: | |||||||
|      all sorts of other programs in order to regenerate files that came |      all sorts of other programs in order to regenerate files that came | ||||||
|      with the distribution. |      with the distribution. | ||||||
| 
 | 
 | ||||||
|  |   7. Often, you can also type `make uninstall' to remove the installed | ||||||
|  |      files again.  In practice, not all packages have tested that | ||||||
|  |      uninstallation works correctly, even though it is required by the | ||||||
|  |      GNU Coding Standards. | ||||||
|  | 
 | ||||||
|  |   8. Some packages, particularly those that use Automake, provide `make | ||||||
|  |      distcheck', which can by used by developers to test that all other | ||||||
|  |      targets like `make install' and `make uninstall' work correctly. | ||||||
|  |      This target is generally not run by end users. | ||||||
|  | 
 | ||||||
| Compilers and Options | Compilers and Options | ||||||
| ===================== | ===================== | ||||||
| 
 | 
 | ||||||
| Some systems require unusual options for compilation or linking that the |    Some systems require unusual options for compilation or linking that | ||||||
| `configure' script does not know about.  Run `./configure --help' for | the `configure' script does not know about.  Run `./configure --help' | ||||||
| details on some of the pertinent environment variables. | for details on some of the pertinent environment variables. | ||||||
| 
 | 
 | ||||||
|    You can give `configure' initial values for configuration parameters |    You can give `configure' initial values for configuration parameters | ||||||
| by setting variables in the command line or in the environment.  Here | by setting variables in the command line or in the environment.  Here | ||||||
| @ -90,20 +116,36 @@ same time, by placing the object files for each architecture in their | |||||||
| own directory.  To do this, you can use GNU `make'.  `cd' to the | own directory.  To do this, you can use GNU `make'.  `cd' to the | ||||||
| directory where you want the object files and executables to go and run | directory where you want the object files and executables to go and run | ||||||
| the `configure' script.  `configure' automatically checks for the | the `configure' script.  `configure' automatically checks for the | ||||||
| source code in the directory that `configure' is in and in `..'. | source code in the directory that `configure' is in and in `..'.  This | ||||||
|  | is known as a "VPATH" build. | ||||||
| 
 | 
 | ||||||
|    With a non-GNU `make', it is safer to compile the package for one |    With a non-GNU `make', it is safer to compile the package for one | ||||||
| architecture at a time in the source code directory.  After you have | architecture at a time in the source code directory.  After you have | ||||||
| installed the package for one architecture, use `make distclean' before | installed the package for one architecture, use `make distclean' before | ||||||
| reconfiguring for another architecture. | reconfiguring for another architecture. | ||||||
| 
 | 
 | ||||||
|  |    On MacOS X 10.5 and later systems, you can create libraries and | ||||||
|  | executables that work on multiple system types--known as "fat" or | ||||||
|  | "universal" binaries--by specifying multiple `-arch' options to the | ||||||
|  | compiler but only a single `-arch' option to the preprocessor.  Like | ||||||
|  | this: | ||||||
|  | 
 | ||||||
|  |      ./configure CC="gcc -arch i386 -arch x86_64 -arch ppc -arch ppc64" \ | ||||||
|  |                  CXX="g++ -arch i386 -arch x86_64 -arch ppc -arch ppc64" \ | ||||||
|  |                  CPP="gcc -E" CXXCPP="g++ -E" | ||||||
|  | 
 | ||||||
|  |    This is not guaranteed to produce working output in all cases, you | ||||||
|  | may have to build one architecture at a time and combine the results | ||||||
|  | using the `lipo' tool if you have problems. | ||||||
|  | 
 | ||||||
| Installation Names | Installation Names | ||||||
| ================== | ================== | ||||||
| 
 | 
 | ||||||
|    By default, `make install' installs the package's commands under |    By default, `make install' installs the package's commands under | ||||||
| `/usr/local/bin', include files under `/usr/local/include', etc.  You | `/usr/local/bin', include files under `/usr/local/include', etc.  You | ||||||
| can specify an installation prefix other than `/usr/local' by giving | can specify an installation prefix other than `/usr/local' by giving | ||||||
| `configure' the option `--prefix=PREFIX'. | `configure' the option `--prefix=PREFIX', where PREFIX must be an | ||||||
|  | absolute file name. | ||||||
| 
 | 
 | ||||||
|    You can specify separate installation prefixes for |    You can specify separate installation prefixes for | ||||||
| architecture-specific files and architecture-independent files.  If you | architecture-specific files and architecture-independent files.  If you | ||||||
| @ -114,15 +156,46 @@ Documentation and other data files still use the regular prefix. | |||||||
|    In addition, if you use an unusual directory layout you can give |    In addition, if you use an unusual directory layout you can give | ||||||
| options like `--bindir=DIR' to specify different values for particular | options like `--bindir=DIR' to specify different values for particular | ||||||
| kinds of files.  Run `configure --help' for a list of the directories | kinds of files.  Run `configure --help' for a list of the directories | ||||||
| you can set and what kinds of files go in them. | you can set and what kinds of files go in them.  In general, the | ||||||
|  | default for these options is expressed in terms of `${prefix}', so that | ||||||
|  | specifying just `--prefix' will affect all of the other directory | ||||||
|  | specifications that were not explicitly provided. | ||||||
|  | 
 | ||||||
|  |    The most portable way to affect installation locations is to pass the | ||||||
|  | correct locations to `configure'; however, many packages provide one or | ||||||
|  | both of the following shortcuts of passing variable assignments to the | ||||||
|  | `make install' command line to change installation locations without | ||||||
|  | having to reconfigure or recompile. | ||||||
|  | 
 | ||||||
|  |    The first method involves providing an override variable for each | ||||||
|  | affected directory.  For example, `make install | ||||||
|  | prefix=/alternate/directory' will choose an alternate location for all | ||||||
|  | directory configuration variables that were expressed in terms of | ||||||
|  | `${prefix}'.  Any directories that were specified during `configure', | ||||||
|  | but not in terms of `${prefix}', must each be overridden at install | ||||||
|  | time for the entire installation to be relocated.  The approach of | ||||||
|  | makefile variable overrides for each directory variable is required by | ||||||
|  | the GNU Coding Standards, and ideally causes no recompilation. | ||||||
|  | However, some platforms have known limitations with the semantics of | ||||||
|  | shared libraries that end up requiring recompilation when using this | ||||||
|  | method, particularly noticeable in packages that use GNU Libtool. | ||||||
|  | 
 | ||||||
|  |    The second method involves providing the `DESTDIR' variable.  For | ||||||
|  | example, `make install DESTDIR=/alternate/directory' will prepend | ||||||
|  | `/alternate/directory' before all installation names.  The approach of | ||||||
|  | `DESTDIR' overrides is not required by the GNU Coding Standards, and | ||||||
|  | does not work on platforms that have drive letters.  On the other hand, | ||||||
|  | it does better at avoiding recompilation issues, and works well even | ||||||
|  | when some directory options were not specified in terms of `${prefix}' | ||||||
|  | at `configure' time. | ||||||
|  | 
 | ||||||
|  | Optional Features | ||||||
|  | ================= | ||||||
| 
 | 
 | ||||||
|    If the package supports it, you can cause programs to be installed |    If the package supports it, you can cause programs to be installed | ||||||
| with an extra prefix or suffix on their names by giving `configure' the | with an extra prefix or suffix on their names by giving `configure' the | ||||||
| option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'. | option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'. | ||||||
| 
 | 
 | ||||||
| Optional Features |  | ||||||
| ================= |  | ||||||
| 
 |  | ||||||
|    Some packages pay attention to `--enable-FEATURE' options to |    Some packages pay attention to `--enable-FEATURE' options to | ||||||
| `configure', where FEATURE indicates an optional part of the package. | `configure', where FEATURE indicates an optional part of the package. | ||||||
| They may also pay attention to `--with-PACKAGE' options, where PACKAGE | They may also pay attention to `--with-PACKAGE' options, where PACKAGE | ||||||
| @ -135,14 +208,58 @@ find the X include and library files automatically, but if it doesn't, | |||||||
| you can use the `configure' options `--x-includes=DIR' and | you can use the `configure' options `--x-includes=DIR' and | ||||||
| `--x-libraries=DIR' to specify their locations. | `--x-libraries=DIR' to specify their locations. | ||||||
| 
 | 
 | ||||||
|  |    Some packages offer the ability to configure how verbose the | ||||||
|  | execution of `make' will be.  For these packages, running `./configure | ||||||
|  | --enable-silent-rules' sets the default to minimal output, which can be | ||||||
|  | overridden with `make V=1'; while running `./configure | ||||||
|  | --disable-silent-rules' sets the default to verbose, which can be | ||||||
|  | overridden with `make V=0'. | ||||||
|  | 
 | ||||||
|  | Particular systems | ||||||
|  | ================== | ||||||
|  | 
 | ||||||
|  |    On HP-UX, the default C compiler is not ANSI C compatible.  If GNU | ||||||
|  | CC is not installed, it is recommended to use the following options in | ||||||
|  | order to use an ANSI C compiler: | ||||||
|  | 
 | ||||||
|  |      ./configure CC="cc -Ae -D_XOPEN_SOURCE=500" | ||||||
|  | 
 | ||||||
|  | and if that doesn't work, install pre-built binaries of GCC for HP-UX. | ||||||
|  | 
 | ||||||
|  |    HP-UX `make' updates targets which have the same time stamps as | ||||||
|  | their prerequisites, which makes it generally unusable when shipped | ||||||
|  | generated files such as `configure' are involved.  Use GNU `make' | ||||||
|  | instead. | ||||||
|  | 
 | ||||||
|  |    On OSF/1 a.k.a. Tru64, some versions of the default C compiler cannot | ||||||
|  | parse its `<wchar.h>' header file.  The option `-nodtk' can be used as | ||||||
|  | a workaround.  If GNU CC is not installed, it is therefore recommended | ||||||
|  | to try | ||||||
|  | 
 | ||||||
|  |      ./configure CC="cc" | ||||||
|  | 
 | ||||||
|  | and if that doesn't work, try | ||||||
|  | 
 | ||||||
|  |      ./configure CC="cc -nodtk" | ||||||
|  | 
 | ||||||
|  |    On Solaris, don't put `/usr/ucb' early in your `PATH'.  This | ||||||
|  | directory contains several dysfunctional programs; working variants of | ||||||
|  | these programs are available in `/usr/bin'.  So, if you need `/usr/ucb' | ||||||
|  | in your `PATH', put it _after_ `/usr/bin'. | ||||||
|  | 
 | ||||||
|  |    On Haiku, software installed for all users goes in `/boot/common', | ||||||
|  | not `/usr/local'.  It is recommended to use the following options: | ||||||
|  | 
 | ||||||
|  |      ./configure --prefix=/boot/common | ||||||
|  | 
 | ||||||
| Specifying the System Type | Specifying the System Type | ||||||
| ========================== | ========================== | ||||||
| 
 | 
 | ||||||
| There may be some features `configure' cannot figure out automatically, |    There may be some features `configure' cannot figure out | ||||||
| but needs to determine by the type of machine the package will run on. | automatically, but needs to determine by the type of machine the package | ||||||
| Usually, assuming the package is built to be run on the _same_ | will run on.  Usually, assuming the package is built to be run on the | ||||||
| architectures, `configure' can figure that out, but if it prints a | _same_ architectures, `configure' can figure that out, but if it prints | ||||||
| message saying it cannot guess the machine type, give it the | a message saying it cannot guess the machine type, give it the | ||||||
| `--build=TYPE' option.  TYPE can either be a short name for the system | `--build=TYPE' option.  TYPE can either be a short name for the system | ||||||
| type, such as `sun4', or a canonical name which has the form: | type, such as `sun4', or a canonical name which has the form: | ||||||
| 
 | 
 | ||||||
| @ -150,7 +267,8 @@ type, such as `sun4', or a canonical name which has the form: | |||||||
| 
 | 
 | ||||||
| where SYSTEM can have one of these forms: | where SYSTEM can have one of these forms: | ||||||
| 
 | 
 | ||||||
|      OS KERNEL-OS |      OS | ||||||
|  |      KERNEL-OS | ||||||
| 
 | 
 | ||||||
|    See the file `config.sub' for the possible values of each field.  If |    See the file `config.sub' for the possible values of each field.  If | ||||||
| `config.sub' isn't included in this package, then this package doesn't | `config.sub' isn't included in this package, then this package doesn't | ||||||
| @ -168,9 +286,9 @@ eventually be run) with `--host=TYPE'. | |||||||
| Sharing Defaults | Sharing Defaults | ||||||
| ================ | ================ | ||||||
| 
 | 
 | ||||||
| If you want to set default values for `configure' scripts to share, you |    If you want to set default values for `configure' scripts to share, | ||||||
| can create a site shell script called `config.site' that gives default | you can create a site shell script called `config.site' that gives | ||||||
| values for variables like `CC', `cache_file', and `prefix'. | default values for variables like `CC', `cache_file', and `prefix'. | ||||||
| `configure' looks for `PREFIX/share/config.site' if it exists, then | `configure' looks for `PREFIX/share/config.site' if it exists, then | ||||||
| `PREFIX/etc/config.site' if it exists.  Or, you can set the | `PREFIX/etc/config.site' if it exists.  Or, you can set the | ||||||
| `CONFIG_SITE' environment variable to the location of the site script. | `CONFIG_SITE' environment variable to the location of the site script. | ||||||
| @ -191,18 +309,27 @@ causes the specified `gcc' to be used as the C compiler (unless it is | |||||||
| overridden in the site shell script). | overridden in the site shell script). | ||||||
| 
 | 
 | ||||||
| Unfortunately, this technique does not work for `CONFIG_SHELL' due to | Unfortunately, this technique does not work for `CONFIG_SHELL' due to | ||||||
| an Autoconf bug.  Until the bug is fixed you can use this workaround: | an Autoconf limitation.  Until the limitation is lifted, you can use | ||||||
|  | this workaround: | ||||||
| 
 | 
 | ||||||
|      CONFIG_SHELL=/bin/bash /bin/bash ./configure CONFIG_SHELL=/bin/bash |      CONFIG_SHELL=/bin/bash ./configure CONFIG_SHELL=/bin/bash | ||||||
| 
 | 
 | ||||||
| `configure' Invocation | `configure' Invocation | ||||||
| ====================== | ====================== | ||||||
| 
 | 
 | ||||||
| `configure' recognizes the following options to control how it operates. |    `configure' recognizes the following options to control how it | ||||||
|  | operates. | ||||||
| 
 | 
 | ||||||
| `--help' | `--help' | ||||||
| `-h' | `-h' | ||||||
|      Print a summary of the options to `configure', and exit. |      Print a summary of all of the options to `configure', and exit. | ||||||
|  | 
 | ||||||
|  | `--help=short' | ||||||
|  | `--help=recursive' | ||||||
|  |      Print a summary of the options unique to this package's | ||||||
|  |      `configure', and exit.  The `short' variant lists options used | ||||||
|  |      only in the top level, while the `recursive' variant lists options | ||||||
|  |      also present in any nested packages. | ||||||
| 
 | 
 | ||||||
| `--version' | `--version' | ||||||
| `-V' | `-V' | ||||||
| @ -229,6 +356,15 @@ an Autoconf bug.  Until the bug is fixed you can use this workaround: | |||||||
|      Look for the package's source code in directory DIR.  Usually |      Look for the package's source code in directory DIR.  Usually | ||||||
|      `configure' can determine that directory automatically. |      `configure' can determine that directory automatically. | ||||||
| 
 | 
 | ||||||
|  | `--prefix=DIR' | ||||||
|  |      Use DIR as the installation prefix.  *note Installation Names:: | ||||||
|  |      for more details, including other options available for fine-tuning | ||||||
|  |      the installation locations. | ||||||
|  | 
 | ||||||
|  | `--no-create' | ||||||
|  | `-n' | ||||||
|  |      Run the configure checks, but stop before creating any output | ||||||
|  |      files. | ||||||
|  | 
 | ||||||
| `configure' also accepts some other, not widely useful, options.  Run | `configure' also accepts some other, not widely useful, options.  Run | ||||||
| `configure --help' for more details. | `configure --help' for more details. | ||||||
| 
 |  | ||||||
|  | |||||||
| @ -26,3 +26,25 @@ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | |||||||
| THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||||||
| (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | ||||||
| OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||||||
|  | 
 | ||||||
|  | -------------------------------------------------------------------- | ||||||
|  | 
 | ||||||
|  | Copyright 2001-2004 Unicode, Inc. | ||||||
|  | 
 | ||||||
|  | Disclaimer | ||||||
|  | 
 | ||||||
|  | This source code is provided as is by Unicode, Inc. No claims are | ||||||
|  | made as to fitness for any particular purpose. No warranties of any | ||||||
|  | kind are expressed or implied. The recipient agrees to determine | ||||||
|  | applicability of information provided. If this file has been | ||||||
|  | purchased on magnetic or optical media from Unicode, Inc., the | ||||||
|  | sole remedy for any claim will be exchange of defective media | ||||||
|  | within 90 days of receipt. | ||||||
|  | 
 | ||||||
|  | Limitations on Rights to Redistribute This Code | ||||||
|  | 
 | ||||||
|  | Unicode, Inc. hereby grants the right to freely use the information | ||||||
|  | supplied in this file in the creation of products supporting the | ||||||
|  | Unicode Standard, and to make copies of this file in any form | ||||||
|  | for internal or external distribution as long as this notice | ||||||
|  | remains attached. | ||||||
| @ -64,17 +64,50 @@ endif | |||||||
| # Specify include paths for ac macros
 | # Specify include paths for ac macros
 | ||||||
| ACLOCAL_AMFLAGS = -I m4 | ACLOCAL_AMFLAGS = -I m4 | ||||||
| 
 | 
 | ||||||
|  | # License file is called LICENSE not COPYING
 | ||||||
|  | AUTOMAKE_OPTIONS = foreign | ||||||
|  | 
 | ||||||
| ## Documentation
 | ## Documentation
 | ||||||
| docdir = $(prefix)/share/doc/$(PACKAGE)-$(VERSION) | docdir = $(prefix)/share/doc/$(PACKAGE)-$(VERSION) | ||||||
| 
 | 
 | ||||||
| dist_doc_DATA = \
 | dist_doc_DATA = \
 | ||||||
| 	AUTHORS \
 | 	AUTHORS \
 | ||||||
| 	COPYING \
 |  | ||||||
| 	ChangeLog \
 | 	ChangeLog \
 | ||||||
| 	INSTALL \
 | 	INSTALL \
 | ||||||
|  | 	LICENSE \
 | ||||||
| 	NEWS \
 | 	NEWS \
 | ||||||
| 	README | 	README | ||||||
| 
 | 
 | ||||||
|  | ## Headers
 | ||||||
|  | if LINUX_HOST | ||||||
|  | includeclhdir = $(includedir)/$(PACKAGE)/client/linux/handler | ||||||
|  | includeclh_HEADERS = $(top_srcdir)/src/client/linux/handler/*.h | ||||||
|  | 
 | ||||||
|  | includeclmdir = $(includedir)/$(PACKAGE)/client/linux/minidump_writer | ||||||
|  | includeclm_HEADERS = $(top_srcdir)/src/client/linux/minidump_writer/*.h | ||||||
|  | 
 | ||||||
|  | includeclcdir = $(includedir)/$(PACKAGE)/client/linux/crash_generation | ||||||
|  | includeclc_HEADERS = $(top_srcdir)/src/client/linux/crash_generation/*.h | ||||||
|  | 
 | ||||||
|  | includelssdir = $(includedir)/$(PACKAGE)/third_party/lss | ||||||
|  | includelss_HEADERS = $(top_srcdir)/src/third_party/lss/*.h | ||||||
|  | 
 | ||||||
|  | includecldir = $(includedir)/$(PACKAGE)/common/linux | ||||||
|  | includecl_HEADERS = $(top_srcdir)/src/common/linux/*.h | ||||||
|  | endif | ||||||
|  | 
 | ||||||
|  | includegbcdir = $(includedir)/$(PACKAGE)/google_breakpad/common | ||||||
|  | includegbc_HEADERS = $(top_srcdir)/src/google_breakpad/common/*.h | ||||||
|  | 
 | ||||||
|  | includecdir = $(includedir)/$(PACKAGE)/common | ||||||
|  | includec_HEADERS = $(top_srcdir)/src/common/*.h | ||||||
|  | 
 | ||||||
|  | includepdir = $(includedir)/$(PACKAGE)/processor | ||||||
|  | includep_HEADERS = $(top_srcdir)/src/processor/*.h | ||||||
|  | 
 | ||||||
|  | ## pkgconfig files
 | ||||||
|  | pkgconfigdir = $(libdir)/pkgconfig | ||||||
|  | pkgconfig_DATA = | ||||||
| 
 | 
 | ||||||
| ## Libraries
 | ## Libraries
 | ||||||
| noinst_LIBRARIES = | noinst_LIBRARIES = | ||||||
| @ -84,18 +117,24 @@ check_PROGRAMS = | |||||||
| 
 | 
 | ||||||
| if !DISABLE_PROCESSOR | if !DISABLE_PROCESSOR | ||||||
| lib_LIBRARIES += src/libbreakpad.a | lib_LIBRARIES += src/libbreakpad.a | ||||||
|  | pkgconfig_DATA += breakpad.pc | ||||||
| noinst_LIBRARIES += src/third_party/libdisasm/libdisasm.a | noinst_LIBRARIES += src/third_party/libdisasm/libdisasm.a | ||||||
| endif | endif | ||||||
| 
 | 
 | ||||||
| if LINUX_HOST | if LINUX_HOST | ||||||
| lib_LIBRARIES += src/client/linux/libbreakpad_client.a | lib_LIBRARIES += src/client/linux/libbreakpad_client.a | ||||||
|  | pkgconfig_DATA += breakpad-client.pc | ||||||
| 
 | 
 | ||||||
| src_client_linux_libbreakpad_client_a_SOURCES = \
 | src_client_linux_libbreakpad_client_a_SOURCES = \
 | ||||||
| 	src/client/linux/crash_generation/crash_generation_client.cc \
 | 	src/client/linux/crash_generation/crash_generation_client.cc \
 | ||||||
| 	src/client/linux/crash_generation/crash_generation_server.cc \
 | 	src/client/linux/crash_generation/crash_generation_server.cc \
 | ||||||
|  | 	src/client/linux/dump_writer_common/seccomp_unwinder.cc \
 | ||||||
|  | 	src/client/linux/dump_writer_common/thread_info.cc \
 | ||||||
|  | 	src/client/linux/dump_writer_common/ucontext_reader.cc \
 | ||||||
| 	src/client/linux/handler/exception_handler.cc \
 | 	src/client/linux/handler/exception_handler.cc \
 | ||||||
| 	src/client/linux/handler/minidump_descriptor.cc \
 | 	src/client/linux/handler/minidump_descriptor.cc \
 | ||||||
| 	src/client/linux/log/log.cc \
 | 	src/client/linux/log/log.cc \
 | ||||||
|  | 	src/client/linux/microdump_writer/microdump_writer.cc \
 | ||||||
| 	src/client/linux/minidump_writer/linux_dumper.cc \
 | 	src/client/linux/minidump_writer/linux_dumper.cc \
 | ||||||
| 	src/client/linux/minidump_writer/linux_ptrace_dumper.cc \
 | 	src/client/linux/minidump_writer/linux_ptrace_dumper.cc \
 | ||||||
| 	src/client/linux/minidump_writer/minidump_writer.cc \
 | 	src/client/linux/minidump_writer/minidump_writer.cc \
 | ||||||
| @ -124,11 +163,15 @@ src_libbreakpad_a_SOURCES = \ | |||||||
| 	src/google_breakpad/processor/call_stack.h \
 | 	src/google_breakpad/processor/call_stack.h \
 | ||||||
| 	src/google_breakpad/processor/code_module.h \
 | 	src/google_breakpad/processor/code_module.h \
 | ||||||
| 	src/google_breakpad/processor/code_modules.h \
 | 	src/google_breakpad/processor/code_modules.h \
 | ||||||
|  | 	src/google_breakpad/processor/dump_context.h \
 | ||||||
|  | 	src/google_breakpad/processor/dump_object.h \
 | ||||||
| 	src/google_breakpad/processor/exploitability.h \
 | 	src/google_breakpad/processor/exploitability.h \
 | ||||||
| 	src/google_breakpad/processor/fast_source_line_resolver.h \
 | 	src/google_breakpad/processor/fast_source_line_resolver.h \
 | ||||||
| 	src/google_breakpad/processor/memory_region.h \
 | 	src/google_breakpad/processor/memory_region.h \
 | ||||||
|  |         src/google_breakpad/processor/microdump_processor.h \
 | ||||||
| 	src/google_breakpad/processor/minidump.h \
 | 	src/google_breakpad/processor/minidump.h \
 | ||||||
| 	src/google_breakpad/processor/minidump_processor.h \
 | 	src/google_breakpad/processor/minidump_processor.h \
 | ||||||
|  | 	src/google_breakpad/processor/process_result.h \
 | ||||||
| 	src/google_breakpad/processor/process_state.h \
 | 	src/google_breakpad/processor/process_state.h \
 | ||||||
| 	src/google_breakpad/processor/source_line_resolver_base.h \
 | 	src/google_breakpad/processor/source_line_resolver_base.h \
 | ||||||
| 	src/google_breakpad/processor/source_line_resolver_interface.h \
 | 	src/google_breakpad/processor/source_line_resolver_interface.h \
 | ||||||
| @ -154,7 +197,11 @@ src_libbreakpad_a_SOURCES = \ | |||||||
| 	src/processor/contained_range_map.h \
 | 	src/processor/contained_range_map.h \
 | ||||||
| 	src/processor/disassembler_x86.h \
 | 	src/processor/disassembler_x86.h \
 | ||||||
| 	src/processor/disassembler_x86.cc \
 | 	src/processor/disassembler_x86.cc \
 | ||||||
|  | 	src/processor/dump_context.cc \
 | ||||||
|  | 	src/processor/dump_object.cc \
 | ||||||
| 	src/processor/exploitability.cc \
 | 	src/processor/exploitability.cc \
 | ||||||
|  | 	src/processor/exploitability_linux.h \
 | ||||||
|  | 	src/processor/exploitability_linux.cc \
 | ||||||
| 	src/processor/exploitability_win.h \
 | 	src/processor/exploitability_win.h \
 | ||||||
| 	src/processor/exploitability_win.cc \
 | 	src/processor/exploitability_win.cc \
 | ||||||
| 	src/processor/fast_source_line_resolver_types.h \
 | 	src/processor/fast_source_line_resolver_types.h \
 | ||||||
| @ -164,6 +211,7 @@ src_libbreakpad_a_SOURCES = \ | |||||||
| 	src/processor/logging.cc \
 | 	src/processor/logging.cc \
 | ||||||
| 	src/processor/map_serializers-inl.h \
 | 	src/processor/map_serializers-inl.h \
 | ||||||
| 	src/processor/map_serializers.h \
 | 	src/processor/map_serializers.h \
 | ||||||
|  |         src/processor/microdump_processor.cc \
 | ||||||
| 	src/processor/minidump.cc \
 | 	src/processor/minidump.cc \
 | ||||||
| 	src/processor/minidump_processor.cc \
 | 	src/processor/minidump_processor.cc \
 | ||||||
| 	src/processor/module_comparer.cc \
 | 	src/processor/module_comparer.cc \
 | ||||||
| @ -185,12 +233,19 @@ src_libbreakpad_a_SOURCES = \ | |||||||
| 	src/processor/windows_frame_info.h \
 | 	src/processor/windows_frame_info.h \
 | ||||||
| 	src/processor/source_line_resolver_base_types.h \
 | 	src/processor/source_line_resolver_base_types.h \
 | ||||||
| 	src/processor/source_line_resolver_base.cc \
 | 	src/processor/source_line_resolver_base.cc \
 | ||||||
|  | 	src/processor/stack_frame_cpu.cc \
 | ||||||
| 	src/processor/stack_frame_symbolizer.cc \
 | 	src/processor/stack_frame_symbolizer.cc \
 | ||||||
| 	src/processor/stackwalker.cc \
 | 	src/processor/stackwalker.cc \
 | ||||||
| 	src/processor/stackwalker_amd64.cc \
 | 	src/processor/stackwalker_amd64.cc \
 | ||||||
| 	src/processor/stackwalker_amd64.h \
 | 	src/processor/stackwalker_amd64.h \
 | ||||||
| 	src/processor/stackwalker_arm.cc \
 | 	src/processor/stackwalker_arm.cc \
 | ||||||
| 	src/processor/stackwalker_arm.h \
 | 	src/processor/stackwalker_arm.h \
 | ||||||
|  | 	src/processor/stackwalker_arm64.cc \
 | ||||||
|  | 	src/processor/stackwalker_arm64.h \
 | ||||||
|  | 	src/processor/stackwalker_address_list.cc \
 | ||||||
|  | 	src/processor/stackwalker_address_list.h \
 | ||||||
|  | 	src/processor/stackwalker_mips.cc \
 | ||||||
|  | 	src/processor/stackwalker_mips.h \
 | ||||||
| 	src/processor/stackwalker_ppc.cc \
 | 	src/processor/stackwalker_ppc.cc \
 | ||||||
| 	src/processor/stackwalker_ppc.h \
 | 	src/processor/stackwalker_ppc.h \
 | ||||||
| 	src/processor/stackwalker_ppc64.cc \
 | 	src/processor/stackwalker_ppc64.cc \
 | ||||||
| @ -276,6 +331,7 @@ check_PROGRAMS += \ | |||||||
| 	src/processor/exploitability_unittest \
 | 	src/processor/exploitability_unittest \
 | ||||||
| 	src/processor/fast_source_line_resolver_unittest \
 | 	src/processor/fast_source_line_resolver_unittest \
 | ||||||
| 	src/processor/map_serializers_unittest \
 | 	src/processor/map_serializers_unittest \
 | ||||||
|  |         src/processor/microdump_processor_unittest \
 | ||||||
| 	src/processor/minidump_processor_unittest \
 | 	src/processor/minidump_processor_unittest \
 | ||||||
| 	src/processor/minidump_unittest \
 | 	src/processor/minidump_unittest \
 | ||||||
| 	src/processor/static_address_map_unittest \
 | 	src/processor/static_address_map_unittest \
 | ||||||
| @ -287,6 +343,9 @@ check_PROGRAMS += \ | |||||||
| 	src/processor/range_map_unittest \
 | 	src/processor/range_map_unittest \
 | ||||||
| 	src/processor/stackwalker_amd64_unittest \
 | 	src/processor/stackwalker_amd64_unittest \
 | ||||||
| 	src/processor/stackwalker_arm_unittest \
 | 	src/processor/stackwalker_arm_unittest \
 | ||||||
|  | 	src/processor/stackwalker_arm64_unittest \
 | ||||||
|  | 	src/processor/stackwalker_address_list_unittest \
 | ||||||
|  | 	src/processor/stackwalker_mips_unittest \
 | ||||||
| 	src/processor/stackwalker_x86_unittest \
 | 	src/processor/stackwalker_x86_unittest \
 | ||||||
| 	src/processor/synth_minidump_unittest | 	src/processor/synth_minidump_unittest | ||||||
| endif | endif | ||||||
| @ -322,18 +381,28 @@ endif | |||||||
| TESTS = $(check_PROGRAMS) $(check_SCRIPTS) | TESTS = $(check_PROGRAMS) $(check_SCRIPTS) | ||||||
| 
 | 
 | ||||||
| if ANDROID_HOST | if ANDROID_HOST | ||||||
| # Wrapper script to run unit test programs on a connected Android device.
 | # Since Autotools 1.2, tests are run through a special "test driver" script.
 | ||||||
| TESTS_ENVIRONMENT = $(top_srcdir)/android/test-shell.sh | # Unfortunately, it's not possible anymore to specify an alternative shell to
 | ||||||
|  | # run them on connected devices, so use a slightly modified version of the
 | ||||||
|  | # driver for Android.
 | ||||||
|  | LOG_DRIVER = $(top_srcdir)/android/test-driver | ||||||
| else | else | ||||||
| TESTS_ENVIRONMENT = | # The default Autotools test driver script.
 | ||||||
|  | LOG_DRIVER = $(top_srcdir)/autotools/test-driver | ||||||
| endif | endif | ||||||
| 
 | 
 | ||||||
| if LINUX_HOST | if LINUX_HOST | ||||||
| src_client_linux_linux_dumper_unittest_helper_SOURCES = \
 | src_client_linux_linux_dumper_unittest_helper_SOURCES = \
 | ||||||
| 	src/client/linux/minidump_writer/linux_dumper_unittest_helper.cc | 	src/client/linux/minidump_writer/linux_dumper_unittest_helper.cc | ||||||
| src_client_linux_linux_dumper_unittest_helper_CXXFLAGS=$(PTHREAD_CFLAGS) |  | ||||||
| src_client_linux_linux_dumper_unittest_helper_LDFLAGS=$(PTHREAD_CFLAGS) | src_client_linux_linux_dumper_unittest_helper_LDFLAGS=$(PTHREAD_CFLAGS) | ||||||
| src_client_linux_linux_dumper_unittest_helper_CC=$(PTHREAD_CC) | src_client_linux_linux_dumper_unittest_helper_CC=$(PTHREAD_CC) | ||||||
|  | if ANDROID_HOST | ||||||
|  | # On Android PTHREAD_CFLAGS is empty, and adding src/common/android/include
 | ||||||
|  | # to the include path is necessary to build this program.
 | ||||||
|  | src_client_linux_linux_dumper_unittest_helper_CXXFLAGS=$(AM_CXXFLAGS) | ||||||
|  | else | ||||||
|  | src_client_linux_linux_dumper_unittest_helper_CXXFLAGS=$(PTHREAD_CFLAGS) | ||||||
|  | endif | ||||||
| 
 | 
 | ||||||
| src_client_linux_linux_client_unittest_shlib_SOURCES = \
 | src_client_linux_linux_client_unittest_shlib_SOURCES = \
 | ||||||
| 	src/client/linux/handler/exception_handler_unittest.cc \
 | 	src/client/linux/handler/exception_handler_unittest.cc \
 | ||||||
| @ -355,6 +424,8 @@ src_client_linux_linux_client_unittest_shlib_SOURCES = \ | |||||||
| 	src/testing/gtest/src/gtest_main.cc \
 | 	src/testing/gtest/src/gtest_main.cc \
 | ||||||
| 	src/testing/src/gmock-all.cc \
 | 	src/testing/src/gmock-all.cc \
 | ||||||
| 	src/processor/basic_code_modules.cc \
 | 	src/processor/basic_code_modules.cc \
 | ||||||
|  | 	src/processor/dump_context.cc \
 | ||||||
|  | 	src/processor/dump_object.cc \
 | ||||||
| 	src/processor/logging.cc \
 | 	src/processor/logging.cc \
 | ||||||
| 	src/processor/minidump.cc \
 | 	src/processor/minidump.cc \
 | ||||||
| 	src/processor/pathname_stripper.cc | 	src/processor/pathname_stripper.cc | ||||||
| @ -373,10 +444,14 @@ src_client_linux_linux_client_unittest_shlib_LDFLAGS = \ | |||||||
| 	-shared \
 | 	-shared \
 | ||||||
| 	-Wl,-h,linux_client_unittest_shlib | 	-Wl,-h,linux_client_unittest_shlib | ||||||
| src_client_linux_linux_client_unittest_shlib_LDADD = \
 | src_client_linux_linux_client_unittest_shlib_LDADD = \
 | ||||||
|  | 	src/client/linux/crash_generation/crash_generation_client.o \
 | ||||||
|  | 	src/client/linux/dump_writer_common/seccomp_unwinder.o \
 | ||||||
|  | 	src/client/linux/dump_writer_common/thread_info.o \
 | ||||||
|  | 	src/client/linux/dump_writer_common/ucontext_reader.o \
 | ||||||
| 	src/client/linux/handler/exception_handler.o \
 | 	src/client/linux/handler/exception_handler.o \
 | ||||||
| 	src/client/linux/handler/minidump_descriptor.o \
 | 	src/client/linux/handler/minidump_descriptor.o \
 | ||||||
| 	src/client/linux/log/log.o \
 | 	src/client/linux/log/log.o \
 | ||||||
| 	src/client/linux/crash_generation/crash_generation_client.o \
 | 	src/client/linux/microdump_writer/microdump_writer.o \
 | ||||||
| 	src/client/linux/minidump_writer/linux_dumper.o \
 | 	src/client/linux/minidump_writer/linux_dumper.o \
 | ||||||
| 	src/client/linux/minidump_writer/linux_ptrace_dumper.o \
 | 	src/client/linux/minidump_writer/linux_ptrace_dumper.o \
 | ||||||
| 	src/client/linux/minidump_writer/minidump_writer.o \
 | 	src/client/linux/minidump_writer/minidump_writer.o \
 | ||||||
| @ -437,6 +512,7 @@ src_tools_linux_dump_syms_dump_syms_SOURCES = \ | |||||||
| 	src/common/dwarf/bytereader.cc \
 | 	src/common/dwarf/bytereader.cc \
 | ||||||
| 	src/common/dwarf/dwarf2diehandler.cc \
 | 	src/common/dwarf/dwarf2diehandler.cc \
 | ||||||
| 	src/common/dwarf/dwarf2reader.cc \
 | 	src/common/dwarf/dwarf2reader.cc \
 | ||||||
|  | 	src/common/linux/crc32.cc \
 | ||||||
| 	src/common/linux/dump_symbols.cc \
 | 	src/common/linux/dump_symbols.cc \
 | ||||||
| 	src/common/linux/elf_symbols_to_module.cc \
 | 	src/common/linux/elf_symbols_to_module.cc \
 | ||||||
| 	src/common/linux/elfutils.cc \
 | 	src/common/linux/elfutils.cc \
 | ||||||
| @ -485,6 +561,7 @@ src_common_dumper_unittest_SOURCES = \ | |||||||
| 	src/common/dwarf/dwarf2reader.cc \
 | 	src/common/dwarf/dwarf2reader.cc \
 | ||||||
| 	src/common/dwarf/dwarf2reader_cfi_unittest.cc \
 | 	src/common/dwarf/dwarf2reader_cfi_unittest.cc \
 | ||||||
| 	src/common/dwarf/dwarf2reader_die_unittest.cc \
 | 	src/common/dwarf/dwarf2reader_die_unittest.cc \
 | ||||||
|  | 	src/common/linux/crc32.cc \
 | ||||||
| 	src/common/linux/dump_symbols.cc \
 | 	src/common/linux/dump_symbols.cc \
 | ||||||
| 	src/common/linux/dump_symbols_unittest.cc \
 | 	src/common/linux/dump_symbols_unittest.cc \
 | ||||||
| 	src/common/linux/elf_core_dump.cc \
 | 	src/common/linux/elf_core_dump.cc \
 | ||||||
| @ -611,19 +688,27 @@ src_processor_exploitability_unittest_LDADD = \ | |||||||
| 	src/processor/process_state.o \
 | 	src/processor/process_state.o \
 | ||||||
| 	src/processor/disassembler_x86.o \
 | 	src/processor/disassembler_x86.o \
 | ||||||
| 	src/processor/exploitability.o \
 | 	src/processor/exploitability.o \
 | ||||||
|  | 	src/processor/exploitability_linux.o \
 | ||||||
| 	src/processor/exploitability_win.o \
 | 	src/processor/exploitability_win.o \
 | ||||||
| 	src/processor/basic_code_modules.o \
 | 	src/processor/basic_code_modules.o \
 | ||||||
| 	src/processor/basic_source_line_resolver.o \
 | 	src/processor/basic_source_line_resolver.o \
 | ||||||
| 	src/processor/call_stack.o \
 | 	src/processor/call_stack.o \
 | ||||||
| 	src/processor/cfi_frame_info.o \
 | 	src/processor/cfi_frame_info.o \
 | ||||||
|  | 	src/processor/dump_context.o \
 | ||||||
|  | 	src/processor/dump_object.o \
 | ||||||
| 	src/processor/logging.o \
 | 	src/processor/logging.o \
 | ||||||
| 	src/processor/minidump.o \
 | 	src/processor/minidump.o \
 | ||||||
| 	src/processor/pathname_stripper.o \
 | 	src/processor/pathname_stripper.o \
 | ||||||
|  | 	src/processor/simple_symbol_supplier.o \
 | ||||||
| 	src/processor/source_line_resolver_base.o \
 | 	src/processor/source_line_resolver_base.o \
 | ||||||
|  | 	src/processor/stack_frame_cpu.o \
 | ||||||
| 	src/processor/stack_frame_symbolizer.o \
 | 	src/processor/stack_frame_symbolizer.o \
 | ||||||
| 	src/processor/stackwalker.o \
 | 	src/processor/stackwalker.o \
 | ||||||
| 	src/processor/stackwalker_amd64.o \
 | 	src/processor/stackwalker_amd64.o \
 | ||||||
| 	src/processor/stackwalker_arm.o \
 | 	src/processor/stackwalker_arm.o \
 | ||||||
|  | 	src/processor/stackwalker_arm64.o \
 | ||||||
|  | 	src/processor/stackwalker_address_list.o \
 | ||||||
|  | 	src/processor/stackwalker_mips.o \
 | ||||||
| 	src/processor/stackwalker_ppc.o \
 | 	src/processor/stackwalker_ppc.o \
 | ||||||
| 	src/processor/stackwalker_ppc64.o \
 | 	src/processor/stackwalker_ppc64.o \
 | ||||||
| 	src/processor/stackwalker_sparc.o \
 | 	src/processor/stackwalker_sparc.o \
 | ||||||
| @ -685,6 +770,19 @@ src_processor_map_serializers_unittest_LDADD = \ | |||||||
| 	src/processor/pathname_stripper.o \
 | 	src/processor/pathname_stripper.o \
 | ||||||
| 	$(PTHREAD_CFLAGS) $(PTHREAD_LIBS) | 	$(PTHREAD_CFLAGS) $(PTHREAD_LIBS) | ||||||
| 
 | 
 | ||||||
|  | src_processor_microdump_processor_unittest_SOURCES = \
 | ||||||
|  |   src/processor/microdump_processor_unittest.cc \
 | ||||||
|  |   src/testing/gtest/src/gtest-all.cc \
 | ||||||
|  |   src/testing/src/gmock-all.cc | ||||||
|  | src_processor_microdump_processor_unittest_CPPFLAGS = \
 | ||||||
|  |   -I$(top_srcdir)/src \
 | ||||||
|  |   -I$(top_srcdir)/src/testing/include \
 | ||||||
|  |   -I$(top_srcdir)/src/testing/gtest/include \
 | ||||||
|  |   -I$(top_srcdir)/src/testing/gtest \
 | ||||||
|  |   -I$(top_srcdir)/src/testing | ||||||
|  | src_processor_microdump_processor_unittest_LDADD = \
 | ||||||
|  |   $(PTHREAD_CFLAGS) $(PTHREAD_LIBS) | ||||||
|  | 
 | ||||||
| src_processor_minidump_processor_unittest_SOURCES = \
 | src_processor_minidump_processor_unittest_SOURCES = \
 | ||||||
| 	src/processor/minidump_processor_unittest.cc \
 | 	src/processor/minidump_processor_unittest.cc \
 | ||||||
| 	src/testing/gtest/src/gtest-all.cc \
 | 	src/testing/gtest/src/gtest-all.cc \
 | ||||||
| @ -701,7 +799,10 @@ src_processor_minidump_processor_unittest_LDADD = \ | |||||||
| 	src/processor/call_stack.o \
 | 	src/processor/call_stack.o \
 | ||||||
| 	src/processor/cfi_frame_info.o \
 | 	src/processor/cfi_frame_info.o \
 | ||||||
| 	src/processor/disassembler_x86.o \
 | 	src/processor/disassembler_x86.o \
 | ||||||
|  | 	src/processor/dump_context.o \
 | ||||||
|  | 	src/processor/dump_object.o \
 | ||||||
| 	src/processor/exploitability.o \
 | 	src/processor/exploitability.o \
 | ||||||
|  | 	src/processor/exploitability_linux.o \
 | ||||||
| 	src/processor/exploitability_win.o \
 | 	src/processor/exploitability_win.o \
 | ||||||
| 	src/processor/logging.o \
 | 	src/processor/logging.o \
 | ||||||
| 	src/processor/minidump_processor.o \
 | 	src/processor/minidump_processor.o \
 | ||||||
| @ -709,10 +810,14 @@ src_processor_minidump_processor_unittest_LDADD = \ | |||||||
| 	src/processor/pathname_stripper.o \
 | 	src/processor/pathname_stripper.o \
 | ||||||
| 	src/processor/process_state.o \
 | 	src/processor/process_state.o \
 | ||||||
| 	src/processor/source_line_resolver_base.o \
 | 	src/processor/source_line_resolver_base.o \
 | ||||||
|  | 	src/processor/stack_frame_cpu.o \
 | ||||||
| 	src/processor/stack_frame_symbolizer.o \
 | 	src/processor/stack_frame_symbolizer.o \
 | ||||||
| 	src/processor/stackwalker.o \
 | 	src/processor/stackwalker.o \
 | ||||||
| 	src/processor/stackwalker_amd64.o \
 | 	src/processor/stackwalker_amd64.o \
 | ||||||
| 	src/processor/stackwalker_arm.o \
 | 	src/processor/stackwalker_arm.o \
 | ||||||
|  | 	src/processor/stackwalker_arm64.o \
 | ||||||
|  | 	src/processor/stackwalker_address_list.o \
 | ||||||
|  | 	src/processor/stackwalker_mips.o \
 | ||||||
| 	src/processor/stackwalker_ppc.o \
 | 	src/processor/stackwalker_ppc.o \
 | ||||||
| 	src/processor/stackwalker_ppc64.o \
 | 	src/processor/stackwalker_ppc64.o \
 | ||||||
| 	src/processor/stackwalker_sparc.o \
 | 	src/processor/stackwalker_sparc.o \
 | ||||||
| @ -736,6 +841,8 @@ src_processor_minidump_unittest_CPPFLAGS = \ | |||||||
| 	-I$(top_srcdir)/src/testing | 	-I$(top_srcdir)/src/testing | ||||||
| src_processor_minidump_unittest_LDADD = \
 | src_processor_minidump_unittest_LDADD = \
 | ||||||
| 	src/processor/basic_code_modules.o \
 | 	src/processor/basic_code_modules.o \
 | ||||||
|  | 	src/processor/dump_context.o \
 | ||||||
|  | 	src/processor/dump_object.o \
 | ||||||
| 	src/processor/logging.o \
 | 	src/processor/logging.o \
 | ||||||
| 	src/processor/minidump.o \
 | 	src/processor/minidump.o \
 | ||||||
| 	src/processor/pathname_stripper.o \
 | 	src/processor/pathname_stripper.o \
 | ||||||
| @ -829,15 +936,20 @@ src_processor_stackwalker_selftest_LDADD = \ | |||||||
| 	src/processor/call_stack.o \
 | 	src/processor/call_stack.o \
 | ||||||
| 	src/processor/disassembler_x86.o \
 | 	src/processor/disassembler_x86.o \
 | ||||||
| 	src/processor/exploitability.o \
 | 	src/processor/exploitability.o \
 | ||||||
|  | 	src/processor/exploitability_linux.o \
 | ||||||
| 	src/processor/exploitability_win.o \
 | 	src/processor/exploitability_win.o \
 | ||||||
| 	src/processor/logging.o \
 | 	src/processor/logging.o \
 | ||||||
| 	src/processor/minidump.o \
 | 	src/processor/minidump.o \
 | ||||||
| 	src/processor/pathname_stripper.o \
 | 	src/processor/pathname_stripper.o \
 | ||||||
| 	src/processor/source_line_resolver_base.o \
 | 	src/processor/source_line_resolver_base.o \
 | ||||||
|  | 	src/processor/stack_frame_cpu.o \
 | ||||||
| 	src/processor/stack_frame_symbolizer.o \
 | 	src/processor/stack_frame_symbolizer.o \
 | ||||||
| 	src/processor/stackwalker.o \
 | 	src/processor/stackwalker.o \
 | ||||||
| 	src/processor/stackwalker_amd64.o \
 | 	src/processor/stackwalker_amd64.o \
 | ||||||
| 	src/processor/stackwalker_arm.o \
 | 	src/processor/stackwalker_arm.o \
 | ||||||
|  | 	src/processor/stackwalker_arm64.o \
 | ||||||
|  | 	src/processor/stackwalker_address_list.o \
 | ||||||
|  | 	src/processor/stackwalker_mips.o \
 | ||||||
| 	src/processor/stackwalker_ppc.o \
 | 	src/processor/stackwalker_ppc.o \
 | ||||||
| 	src/processor/stackwalker_ppc64.o \
 | 	src/processor/stackwalker_ppc64.o \
 | ||||||
| 	src/processor/stackwalker_sparc.o \
 | 	src/processor/stackwalker_sparc.o \
 | ||||||
| @ -877,6 +989,54 @@ src_processor_stackwalker_arm_unittest_CPPFLAGS = \ | |||||||
| 	-I$(top_srcdir)/src/testing/gtest \
 | 	-I$(top_srcdir)/src/testing/gtest \
 | ||||||
| 	-I$(top_srcdir)/src/testing | 	-I$(top_srcdir)/src/testing | ||||||
| 
 | 
 | ||||||
|  | src_processor_stackwalker_arm64_unittest_SOURCES = \
 | ||||||
|  | 	src/common/test_assembler.cc \
 | ||||||
|  | 	src/processor/stackwalker_arm64_unittest.cc \
 | ||||||
|  | 	src/testing/gtest/src/gtest-all.cc \
 | ||||||
|  | 	src/testing/gtest/src/gtest_main.cc \
 | ||||||
|  | 	src/testing/src/gmock-all.cc | ||||||
|  | src_processor_stackwalker_arm64_unittest_LDADD = \
 | ||||||
|  | 	src/libbreakpad.a \
 | ||||||
|  | 	$(PTHREAD_CFLAGS) $(PTHREAD_LIBS) | ||||||
|  | src_processor_stackwalker_arm64_unittest_CPPFLAGS = \
 | ||||||
|  | 	-I$(top_srcdir)/src \
 | ||||||
|  | 	-I$(top_srcdir)/src/testing/include \
 | ||||||
|  | 	-I$(top_srcdir)/src/testing/gtest/include \
 | ||||||
|  | 	-I$(top_srcdir)/src/testing/gtest \
 | ||||||
|  | 	-I$(top_srcdir)/src/testing | ||||||
|  | 
 | ||||||
|  | src_processor_stackwalker_address_list_unittest_SOURCES = \
 | ||||||
|  | 	src/common/test_assembler.cc \
 | ||||||
|  | 	src/processor/stackwalker_address_list_unittest.cc \
 | ||||||
|  | 	src/testing/gtest/src/gtest-all.cc \
 | ||||||
|  | 	src/testing/gtest/src/gtest_main.cc \
 | ||||||
|  | 	src/testing/src/gmock-all.cc | ||||||
|  | src_processor_stackwalker_address_list_unittest_LDADD = \
 | ||||||
|  | 	src/libbreakpad.a \
 | ||||||
|  | 	$(PTHREAD_CFLAGS) $(PTHREAD_LIBS) | ||||||
|  | src_processor_stackwalker_address_list_unittest_CPPFLAGS = \
 | ||||||
|  | 	-I$(top_srcdir)/src \
 | ||||||
|  | 	-I$(top_srcdir)/src/testing/include \
 | ||||||
|  | 	-I$(top_srcdir)/src/testing/gtest/include \
 | ||||||
|  | 	-I$(top_srcdir)/src/testing/gtest \
 | ||||||
|  | 	-I$(top_srcdir)/src/testing | ||||||
|  | 
 | ||||||
|  | src_processor_stackwalker_mips_unittest_SOURCES = \
 | ||||||
|  | 	src/common/test_assembler.cc \
 | ||||||
|  | 	src/processor/stackwalker_mips_unittest.cc \
 | ||||||
|  | 	src/testing/gtest/src/gtest-all.cc \
 | ||||||
|  | 	src/testing/gtest/src/gtest_main.cc \
 | ||||||
|  | 	src/testing/src/gmock-all.cc | ||||||
|  | src_processor_stackwalker_mips_unittest_LDADD = \
 | ||||||
|  | 	src/libbreakpad.a \
 | ||||||
|  | 	$(PTHREAD_CFLAGS) $(PTHREAD_LIBS) | ||||||
|  | src_processor_stackwalker_mips_unittest_CPPFLAGS = \
 | ||||||
|  | 	-I$(top_srcdir)/src \
 | ||||||
|  | 	-I$(top_srcdir)/src/testing/include \
 | ||||||
|  | 	-I$(top_srcdir)/src/testing/gtest/include \
 | ||||||
|  | 	-I$(top_srcdir)/src/testing/gtest \
 | ||||||
|  | 	-I$(top_srcdir)/src/testing | ||||||
|  | 
 | ||||||
| src_processor_stackwalker_x86_unittest_SOURCES = \
 | src_processor_stackwalker_x86_unittest_SOURCES = \
 | ||||||
| 	src/common/test_assembler.cc \
 | 	src/common/test_assembler.cc \
 | ||||||
| 	src/processor/stackwalker_x86_unittest.cc \
 | 	src/processor/stackwalker_x86_unittest.cc \
 | ||||||
| @ -933,6 +1093,8 @@ src_processor_minidump_dump_SOURCES = \ | |||||||
| 	src/processor/minidump_dump.cc | 	src/processor/minidump_dump.cc | ||||||
| src_processor_minidump_dump_LDADD = \
 | src_processor_minidump_dump_LDADD = \
 | ||||||
| 	src/processor/basic_code_modules.o \
 | 	src/processor/basic_code_modules.o \
 | ||||||
|  | 	src/processor/dump_context.o \
 | ||||||
|  | 	src/processor/dump_object.o \
 | ||||||
| 	src/processor/logging.o \
 | 	src/processor/logging.o \
 | ||||||
| 	src/processor/minidump.o \
 | 	src/processor/minidump.o \
 | ||||||
| 	src/processor/pathname_stripper.o | 	src/processor/pathname_stripper.o | ||||||
| @ -946,7 +1108,10 @@ src_processor_minidump_stackwalk_LDADD = \ | |||||||
| 	src/processor/call_stack.o \
 | 	src/processor/call_stack.o \
 | ||||||
| 	src/processor/cfi_frame_info.o \
 | 	src/processor/cfi_frame_info.o \
 | ||||||
| 	src/processor/disassembler_x86.o \
 | 	src/processor/disassembler_x86.o \
 | ||||||
|  | 	src/processor/dump_context.o \
 | ||||||
|  | 	src/processor/dump_object.o \
 | ||||||
| 	src/processor/exploitability.o \
 | 	src/processor/exploitability.o \
 | ||||||
|  | 	src/processor/exploitability_linux.o \
 | ||||||
| 	src/processor/exploitability_win.o \
 | 	src/processor/exploitability_win.o \
 | ||||||
| 	src/processor/logging.o \
 | 	src/processor/logging.o \
 | ||||||
| 	src/processor/minidump.o \
 | 	src/processor/minidump.o \
 | ||||||
| @ -955,10 +1120,14 @@ src_processor_minidump_stackwalk_LDADD = \ | |||||||
| 	src/processor/process_state.o \
 | 	src/processor/process_state.o \
 | ||||||
| 	src/processor/simple_symbol_supplier.o \
 | 	src/processor/simple_symbol_supplier.o \
 | ||||||
| 	src/processor/source_line_resolver_base.o \
 | 	src/processor/source_line_resolver_base.o \
 | ||||||
|  | 	src/processor/stack_frame_cpu.o \
 | ||||||
| 	src/processor/stack_frame_symbolizer.o \
 | 	src/processor/stack_frame_symbolizer.o \
 | ||||||
| 	src/processor/stackwalker.o \
 | 	src/processor/stackwalker.o \
 | ||||||
| 	src/processor/stackwalker_amd64.o \
 | 	src/processor/stackwalker_amd64.o \
 | ||||||
| 	src/processor/stackwalker_arm.o \
 | 	src/processor/stackwalker_arm.o \
 | ||||||
|  | 	src/processor/stackwalker_arm64.o \
 | ||||||
|  | 	src/processor/stackwalker_address_list.o \
 | ||||||
|  | 	src/processor/stackwalker_mips.o \
 | ||||||
| 	src/processor/stackwalker_ppc.o \
 | 	src/processor/stackwalker_ppc.o \
 | ||||||
| 	src/processor/stackwalker_ppc64.o \
 | 	src/processor/stackwalker_ppc64.o \
 | ||||||
| 	src/processor/stackwalker_sparc.o \
 | 	src/processor/stackwalker_sparc.o \
 | ||||||
| @ -1021,6 +1190,7 @@ EXTRA_DIST = \ | |||||||
| 	src/client/windows/sender/crash_report_sender.vcproj \
 | 	src/client/windows/sender/crash_report_sender.vcproj \
 | ||||||
| 	src/common/convert_UTF.c \
 | 	src/common/convert_UTF.c \
 | ||||||
| 	src/common/convert_UTF.h \
 | 	src/common/convert_UTF.h \
 | ||||||
|  | 	src/common/linux/crc32.cc \
 | ||||||
| 	src/common/linux/dump_symbols.cc \
 | 	src/common/linux/dump_symbols.cc \
 | ||||||
| 	src/common/linux/dump_symbols.h \
 | 	src/common/linux/dump_symbols.h \
 | ||||||
| 	src/common/linux/elf_symbols_to_module.cc \
 | 	src/common/linux/elf_symbols_to_module.cc \
 | ||||||
|  | |||||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										649
									
								
								google-breakpad/aclocal.m4
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										649
									
								
								google-breakpad/aclocal.m4
									
									
									
									
										vendored
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @ -1 +0,0 @@ | |||||||
| /usr/share/automake-1.11/compile |  | ||||||
							
								
								
									
										347
									
								
								google-breakpad/autotools/compile
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										347
									
								
								google-breakpad/autotools/compile
									
									
									
									
									
										Executable file
									
								
							| @ -0,0 +1,347 @@ | |||||||
|  | #! /bin/sh | ||||||
|  | # Wrapper for compilers which do not understand '-c -o'. | ||||||
|  | 
 | ||||||
|  | scriptversion=2012-10-14.11; # UTC | ||||||
|  | 
 | ||||||
|  | # Copyright (C) 1999-2013 Free Software Foundation, Inc. | ||||||
|  | # Written by Tom Tromey <tromey@cygnus.com>. | ||||||
|  | # | ||||||
|  | # This program is free software; you can redistribute it and/or modify | ||||||
|  | # it under the terms of the GNU General Public License as published by | ||||||
|  | # the Free Software Foundation; either version 2, or (at your option) | ||||||
|  | # any later version. | ||||||
|  | # | ||||||
|  | # This program is distributed in the hope that it will be useful, | ||||||
|  | # but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||||
|  | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||||
|  | # GNU General Public License for more details. | ||||||
|  | # | ||||||
|  | # You should have received a copy of the GNU General Public License | ||||||
|  | # along with this program.  If not, see <http://www.gnu.org/licenses/>. | ||||||
|  | 
 | ||||||
|  | # As a special exception to the GNU General Public License, if you | ||||||
|  | # distribute this file as part of a program that contains a | ||||||
|  | # configuration script generated by Autoconf, you may include it under | ||||||
|  | # the same distribution terms that you use for the rest of that program. | ||||||
|  | 
 | ||||||
|  | # This file is maintained in Automake, please report | ||||||
|  | # bugs to <bug-automake@gnu.org> or send patches to | ||||||
|  | # <automake-patches@gnu.org>. | ||||||
|  | 
 | ||||||
|  | nl=' | ||||||
|  | ' | ||||||
|  | 
 | ||||||
|  | # We need space, tab and new line, in precisely that order.  Quoting is | ||||||
|  | # there to prevent tools from complaining about whitespace usage. | ||||||
|  | IFS=" ""	$nl" | ||||||
|  | 
 | ||||||
|  | file_conv= | ||||||
|  | 
 | ||||||
|  | # func_file_conv build_file lazy | ||||||
|  | # Convert a $build file to $host form and store it in $file | ||||||
|  | # Currently only supports Windows hosts. If the determined conversion | ||||||
|  | # type is listed in (the comma separated) LAZY, no conversion will | ||||||
|  | # take place. | ||||||
|  | func_file_conv () | ||||||
|  | { | ||||||
|  |   file=$1 | ||||||
|  |   case $file in | ||||||
|  |     / | /[!/]*) # absolute file, and not a UNC file | ||||||
|  |       if test -z "$file_conv"; then | ||||||
|  | 	# lazily determine how to convert abs files | ||||||
|  | 	case `uname -s` in | ||||||
|  | 	  MINGW*) | ||||||
|  | 	    file_conv=mingw | ||||||
|  | 	    ;; | ||||||
|  | 	  CYGWIN*) | ||||||
|  | 	    file_conv=cygwin | ||||||
|  | 	    ;; | ||||||
|  | 	  *) | ||||||
|  | 	    file_conv=wine | ||||||
|  | 	    ;; | ||||||
|  | 	esac | ||||||
|  |       fi | ||||||
|  |       case $file_conv/,$2, in | ||||||
|  | 	*,$file_conv,*) | ||||||
|  | 	  ;; | ||||||
|  | 	mingw/*) | ||||||
|  | 	  file=`cmd //C echo "$file " | sed -e 's/"\(.*\) " *$/\1/'` | ||||||
|  | 	  ;; | ||||||
|  | 	cygwin/*) | ||||||
|  | 	  file=`cygpath -m "$file" || echo "$file"` | ||||||
|  | 	  ;; | ||||||
|  | 	wine/*) | ||||||
|  | 	  file=`winepath -w "$file" || echo "$file"` | ||||||
|  | 	  ;; | ||||||
|  |       esac | ||||||
|  |       ;; | ||||||
|  |   esac | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | # func_cl_dashL linkdir | ||||||
|  | # Make cl look for libraries in LINKDIR | ||||||
|  | func_cl_dashL () | ||||||
|  | { | ||||||
|  |   func_file_conv "$1" | ||||||
|  |   if test -z "$lib_path"; then | ||||||
|  |     lib_path=$file | ||||||
|  |   else | ||||||
|  |     lib_path="$lib_path;$file" | ||||||
|  |   fi | ||||||
|  |   linker_opts="$linker_opts -LIBPATH:$file" | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | # func_cl_dashl library | ||||||
|  | # Do a library search-path lookup for cl | ||||||
|  | func_cl_dashl () | ||||||
|  | { | ||||||
|  |   lib=$1 | ||||||
|  |   found=no | ||||||
|  |   save_IFS=$IFS | ||||||
|  |   IFS=';' | ||||||
|  |   for dir in $lib_path $LIB | ||||||
|  |   do | ||||||
|  |     IFS=$save_IFS | ||||||
|  |     if $shared && test -f "$dir/$lib.dll.lib"; then | ||||||
|  |       found=yes | ||||||
|  |       lib=$dir/$lib.dll.lib | ||||||
|  |       break | ||||||
|  |     fi | ||||||
|  |     if test -f "$dir/$lib.lib"; then | ||||||
|  |       found=yes | ||||||
|  |       lib=$dir/$lib.lib | ||||||
|  |       break | ||||||
|  |     fi | ||||||
|  |     if test -f "$dir/lib$lib.a"; then | ||||||
|  |       found=yes | ||||||
|  |       lib=$dir/lib$lib.a | ||||||
|  |       break | ||||||
|  |     fi | ||||||
|  |   done | ||||||
|  |   IFS=$save_IFS | ||||||
|  | 
 | ||||||
|  |   if test "$found" != yes; then | ||||||
|  |     lib=$lib.lib | ||||||
|  |   fi | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | # func_cl_wrapper cl arg... | ||||||
|  | # Adjust compile command to suit cl | ||||||
|  | func_cl_wrapper () | ||||||
|  | { | ||||||
|  |   # Assume a capable shell | ||||||
|  |   lib_path= | ||||||
|  |   shared=: | ||||||
|  |   linker_opts= | ||||||
|  |   for arg | ||||||
|  |   do | ||||||
|  |     if test -n "$eat"; then | ||||||
|  |       eat= | ||||||
|  |     else | ||||||
|  |       case $1 in | ||||||
|  | 	-o) | ||||||
|  | 	  # configure might choose to run compile as 'compile cc -o foo foo.c'. | ||||||
|  | 	  eat=1 | ||||||
|  | 	  case $2 in | ||||||
|  | 	    *.o | *.[oO][bB][jJ]) | ||||||
|  | 	      func_file_conv "$2" | ||||||
|  | 	      set x "$@" -Fo"$file" | ||||||
|  | 	      shift | ||||||
|  | 	      ;; | ||||||
|  | 	    *) | ||||||
|  | 	      func_file_conv "$2" | ||||||
|  | 	      set x "$@" -Fe"$file" | ||||||
|  | 	      shift | ||||||
|  | 	      ;; | ||||||
|  | 	  esac | ||||||
|  | 	  ;; | ||||||
|  | 	-I) | ||||||
|  | 	  eat=1 | ||||||
|  | 	  func_file_conv "$2" mingw | ||||||
|  | 	  set x "$@" -I"$file" | ||||||
|  | 	  shift | ||||||
|  | 	  ;; | ||||||
|  | 	-I*) | ||||||
|  | 	  func_file_conv "${1#-I}" mingw | ||||||
|  | 	  set x "$@" -I"$file" | ||||||
|  | 	  shift | ||||||
|  | 	  ;; | ||||||
|  | 	-l) | ||||||
|  | 	  eat=1 | ||||||
|  | 	  func_cl_dashl "$2" | ||||||
|  | 	  set x "$@" "$lib" | ||||||
|  | 	  shift | ||||||
|  | 	  ;; | ||||||
|  | 	-l*) | ||||||
|  | 	  func_cl_dashl "${1#-l}" | ||||||
|  | 	  set x "$@" "$lib" | ||||||
|  | 	  shift | ||||||
|  | 	  ;; | ||||||
|  | 	-L) | ||||||
|  | 	  eat=1 | ||||||
|  | 	  func_cl_dashL "$2" | ||||||
|  | 	  ;; | ||||||
|  | 	-L*) | ||||||
|  | 	  func_cl_dashL "${1#-L}" | ||||||
|  | 	  ;; | ||||||
|  | 	-static) | ||||||
|  | 	  shared=false | ||||||
|  | 	  ;; | ||||||
|  | 	-Wl,*) | ||||||
|  | 	  arg=${1#-Wl,} | ||||||
|  | 	  save_ifs="$IFS"; IFS=',' | ||||||
|  | 	  for flag in $arg; do | ||||||
|  | 	    IFS="$save_ifs" | ||||||
|  | 	    linker_opts="$linker_opts $flag" | ||||||
|  | 	  done | ||||||
|  | 	  IFS="$save_ifs" | ||||||
|  | 	  ;; | ||||||
|  | 	-Xlinker) | ||||||
|  | 	  eat=1 | ||||||
|  | 	  linker_opts="$linker_opts $2" | ||||||
|  | 	  ;; | ||||||
|  | 	-*) | ||||||
|  | 	  set x "$@" "$1" | ||||||
|  | 	  shift | ||||||
|  | 	  ;; | ||||||
|  | 	*.cc | *.CC | *.cxx | *.CXX | *.[cC]++) | ||||||
|  | 	  func_file_conv "$1" | ||||||
|  | 	  set x "$@" -Tp"$file" | ||||||
|  | 	  shift | ||||||
|  | 	  ;; | ||||||
|  | 	*.c | *.cpp | *.CPP | *.lib | *.LIB | *.Lib | *.OBJ | *.obj | *.[oO]) | ||||||
|  | 	  func_file_conv "$1" mingw | ||||||
|  | 	  set x "$@" "$file" | ||||||
|  | 	  shift | ||||||
|  | 	  ;; | ||||||
|  | 	*) | ||||||
|  | 	  set x "$@" "$1" | ||||||
|  | 	  shift | ||||||
|  | 	  ;; | ||||||
|  |       esac | ||||||
|  |     fi | ||||||
|  |     shift | ||||||
|  |   done | ||||||
|  |   if test -n "$linker_opts"; then | ||||||
|  |     linker_opts="-link$linker_opts" | ||||||
|  |   fi | ||||||
|  |   exec "$@" $linker_opts | ||||||
|  |   exit 1 | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | eat= | ||||||
|  | 
 | ||||||
|  | case $1 in | ||||||
|  |   '') | ||||||
|  |      echo "$0: No command.  Try '$0 --help' for more information." 1>&2 | ||||||
|  |      exit 1; | ||||||
|  |      ;; | ||||||
|  |   -h | --h*) | ||||||
|  |     cat <<\EOF | ||||||
|  | Usage: compile [--help] [--version] PROGRAM [ARGS] | ||||||
|  | 
 | ||||||
|  | Wrapper for compilers which do not understand '-c -o'. | ||||||
|  | Remove '-o dest.o' from ARGS, run PROGRAM with the remaining | ||||||
|  | arguments, and rename the output as expected. | ||||||
|  | 
 | ||||||
|  | If you are trying to build a whole package this is not the | ||||||
|  | right script to run: please start by reading the file 'INSTALL'. | ||||||
|  | 
 | ||||||
|  | Report bugs to <bug-automake@gnu.org>. | ||||||
|  | EOF | ||||||
|  |     exit $? | ||||||
|  |     ;; | ||||||
|  |   -v | --v*) | ||||||
|  |     echo "compile $scriptversion" | ||||||
|  |     exit $? | ||||||
|  |     ;; | ||||||
|  |   cl | *[/\\]cl | cl.exe | *[/\\]cl.exe ) | ||||||
|  |     func_cl_wrapper "$@"      # Doesn't return... | ||||||
|  |     ;; | ||||||
|  | esac | ||||||
|  | 
 | ||||||
|  | ofile= | ||||||
|  | cfile= | ||||||
|  | 
 | ||||||
|  | for arg | ||||||
|  | do | ||||||
|  |   if test -n "$eat"; then | ||||||
|  |     eat= | ||||||
|  |   else | ||||||
|  |     case $1 in | ||||||
|  |       -o) | ||||||
|  | 	# configure might choose to run compile as 'compile cc -o foo foo.c'. | ||||||
|  | 	# So we strip '-o arg' only if arg is an object. | ||||||
|  | 	eat=1 | ||||||
|  | 	case $2 in | ||||||
|  | 	  *.o | *.obj) | ||||||
|  | 	    ofile=$2 | ||||||
|  | 	    ;; | ||||||
|  | 	  *) | ||||||
|  | 	    set x "$@" -o "$2" | ||||||
|  | 	    shift | ||||||
|  | 	    ;; | ||||||
|  | 	esac | ||||||
|  | 	;; | ||||||
|  |       *.c) | ||||||
|  | 	cfile=$1 | ||||||
|  | 	set x "$@" "$1" | ||||||
|  | 	shift | ||||||
|  | 	;; | ||||||
|  |       *) | ||||||
|  | 	set x "$@" "$1" | ||||||
|  | 	shift | ||||||
|  | 	;; | ||||||
|  |     esac | ||||||
|  |   fi | ||||||
|  |   shift | ||||||
|  | done | ||||||
|  | 
 | ||||||
|  | if test -z "$ofile" || test -z "$cfile"; then | ||||||
|  |   # If no '-o' option was seen then we might have been invoked from a | ||||||
|  |   # pattern rule where we don't need one.  That is ok -- this is a | ||||||
|  |   # normal compilation that the losing compiler can handle.  If no | ||||||
|  |   # '.c' file was seen then we are probably linking.  That is also | ||||||
|  |   # ok. | ||||||
|  |   exec "$@" | ||||||
|  | fi | ||||||
|  | 
 | ||||||
|  | # Name of file we expect compiler to create. | ||||||
|  | cofile=`echo "$cfile" | sed 's|^.*[\\/]||; s|^[a-zA-Z]:||; s/\.c$/.o/'` | ||||||
|  | 
 | ||||||
|  | # Create the lock directory. | ||||||
|  | # Note: use '[/\\:.-]' here to ensure that we don't use the same name | ||||||
|  | # that we are using for the .o file.  Also, base the name on the expected | ||||||
|  | # object file name, since that is what matters with a parallel build. | ||||||
|  | lockdir=`echo "$cofile" | sed -e 's|[/\\:.-]|_|g'`.d | ||||||
|  | while true; do | ||||||
|  |   if mkdir "$lockdir" >/dev/null 2>&1; then | ||||||
|  |     break | ||||||
|  |   fi | ||||||
|  |   sleep 1 | ||||||
|  | done | ||||||
|  | # FIXME: race condition here if user kills between mkdir and trap. | ||||||
|  | trap "rmdir '$lockdir'; exit 1" 1 2 15 | ||||||
|  | 
 | ||||||
|  | # Run the compile. | ||||||
|  | "$@" | ||||||
|  | ret=$? | ||||||
|  | 
 | ||||||
|  | if test -f "$cofile"; then | ||||||
|  |   test "$cofile" = "$ofile" || mv "$cofile" "$ofile" | ||||||
|  | elif test -f "${cofile}bj"; then | ||||||
|  |   test "${cofile}bj" = "$ofile" || mv "${cofile}bj" "$ofile" | ||||||
|  | fi | ||||||
|  | 
 | ||||||
|  | rmdir "$lockdir" | ||||||
|  | exit $ret | ||||||
|  | 
 | ||||||
|  | # Local Variables: | ||||||
|  | # mode: shell-script | ||||||
|  | # sh-indentation: 2 | ||||||
|  | # eval: (add-hook 'write-file-hooks 'time-stamp) | ||||||
|  | # time-stamp-start: "scriptversion=" | ||||||
|  | # time-stamp-format: "%:y-%02m-%02d.%02H" | ||||||
|  | # time-stamp-time-zone: "UTC" | ||||||
|  | # time-stamp-end: "; # UTC" | ||||||
|  | # End: | ||||||
							
								
								
									
										337
									
								
								google-breakpad/autotools/config.guess
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										337
									
								
								google-breakpad/autotools/config.guess
									
									
									
									
										vendored
									
									
								
							| @ -1,14 +1,12 @@ | |||||||
| #! /bin/sh | #! /bin/sh | ||||||
| # Attempt to guess a canonical system name. | # Attempt to guess a canonical system name. | ||||||
| #   Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, | #   Copyright 1992-2014 Free Software Foundation, Inc. | ||||||
| #   2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, |  | ||||||
| #   2011, 2012 Free Software Foundation, Inc. |  | ||||||
| 
 | 
 | ||||||
| timestamp='2012-06-17' | timestamp='2014-03-23' | ||||||
| 
 | 
 | ||||||
| # This file is free software; you can redistribute it and/or modify it | # This file is free software; you can redistribute it and/or modify it | ||||||
| # under the terms of the GNU General Public License as published by | # under the terms of the GNU General Public License as published by | ||||||
| # the Free Software Foundation; either version 2 of the License, or | # the Free Software Foundation; either version 3 of the License, or | ||||||
| # (at your option) any later version. | # (at your option) any later version. | ||||||
| # | # | ||||||
| # This program is distributed in the hope that it will be useful, but | # This program is distributed in the hope that it will be useful, but | ||||||
| @ -22,19 +20,17 @@ timestamp='2012-06-17' | |||||||
| # As a special exception to the GNU General Public License, if you | # As a special exception to the GNU General Public License, if you | ||||||
| # distribute this file as part of a program that contains a | # distribute this file as part of a program that contains a | ||||||
| # configuration script generated by Autoconf, you may include it under | # configuration script generated by Autoconf, you may include it under | ||||||
| # the same distribution terms that you use for the rest of that program. | # the same distribution terms that you use for the rest of that | ||||||
| 
 | # program.  This Exception is an additional permission under section 7 | ||||||
| 
 | # of the GNU General Public License, version 3 ("GPLv3"). | ||||||
| # Originally written by Per Bothner.  Please send patches (context |  | ||||||
| # diff format) to <config-patches@gnu.org> and include a ChangeLog |  | ||||||
| # entry. |  | ||||||
| # | # | ||||||
| # This script attempts to guess a canonical system name similar to | # Originally written by Per Bothner. | ||||||
| # config.sub.  If it succeeds, it prints the system name on stdout, and |  | ||||||
| # exits with 0.  Otherwise, it exits with 1. |  | ||||||
| # | # | ||||||
| # You can get the latest version of this script from: | # You can get the latest version of this script from: | ||||||
| # http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess;hb=HEAD | # http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess;hb=HEAD | ||||||
|  | # | ||||||
|  | # Please send patches with a ChangeLog entry to config-patches@gnu.org. | ||||||
|  | 
 | ||||||
| 
 | 
 | ||||||
| me=`echo "$0" | sed -e 's,.*/,,'` | me=`echo "$0" | sed -e 's,.*/,,'` | ||||||
| 
 | 
 | ||||||
| @ -54,9 +50,7 @@ version="\ | |||||||
| GNU config.guess ($timestamp) | GNU config.guess ($timestamp) | ||||||
| 
 | 
 | ||||||
| Originally written by Per Bothner. | Originally written by Per Bothner. | ||||||
| Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, | Copyright 1992-2014 Free Software Foundation, Inc. | ||||||
| 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012 |  | ||||||
| Free Software Foundation, Inc. |  | ||||||
| 
 | 
 | ||||||
| This is free software; see the source for copying conditions.  There is NO | This is free software; see the source for copying conditions.  There is NO | ||||||
| warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." | warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." | ||||||
| @ -138,6 +132,27 @@ UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown | |||||||
| UNAME_SYSTEM=`(uname -s) 2>/dev/null`  || UNAME_SYSTEM=unknown | UNAME_SYSTEM=`(uname -s) 2>/dev/null`  || UNAME_SYSTEM=unknown | ||||||
| UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown | UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown | ||||||
| 
 | 
 | ||||||
|  | case "${UNAME_SYSTEM}" in | ||||||
|  | Linux|GNU|GNU/*) | ||||||
|  | 	# If the system lacks a compiler, then just pick glibc. | ||||||
|  | 	# We could probably try harder. | ||||||
|  | 	LIBC=gnu | ||||||
|  | 
 | ||||||
|  | 	eval $set_cc_for_build | ||||||
|  | 	cat <<-EOF > $dummy.c | ||||||
|  | 	#include <features.h> | ||||||
|  | 	#if defined(__UCLIBC__) | ||||||
|  | 	LIBC=uclibc | ||||||
|  | 	#elif defined(__dietlibc__) | ||||||
|  | 	LIBC=dietlibc | ||||||
|  | 	#else | ||||||
|  | 	LIBC=gnu | ||||||
|  | 	#endif | ||||||
|  | 	EOF | ||||||
|  | 	eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^LIBC' | sed 's, ,,g'` | ||||||
|  | 	;; | ||||||
|  | esac | ||||||
|  | 
 | ||||||
| # Note: order is significant - the case branches are not exclusive. | # Note: order is significant - the case branches are not exclusive. | ||||||
| 
 | 
 | ||||||
| case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in | case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in | ||||||
| @ -306,7 +321,7 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in | |||||||
|     arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*) |     arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*) | ||||||
| 	echo arm-acorn-riscix${UNAME_RELEASE} | 	echo arm-acorn-riscix${UNAME_RELEASE} | ||||||
| 	exit ;; | 	exit ;; | ||||||
|     arm:riscos:*:*|arm:RISCOS:*:*) |     arm*:riscos:*:*|arm*:RISCOS:*:*) | ||||||
| 	echo arm-unknown-riscos | 	echo arm-unknown-riscos | ||||||
| 	exit ;; | 	exit ;; | ||||||
|     SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*) |     SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*) | ||||||
| @ -805,10 +820,13 @@ EOF | |||||||
|     i*:CYGWIN*:*) |     i*:CYGWIN*:*) | ||||||
| 	echo ${UNAME_MACHINE}-pc-cygwin | 	echo ${UNAME_MACHINE}-pc-cygwin | ||||||
| 	exit ;; | 	exit ;; | ||||||
|  |     *:MINGW64*:*) | ||||||
|  | 	echo ${UNAME_MACHINE}-pc-mingw64 | ||||||
|  | 	exit ;; | ||||||
|     *:MINGW*:*) |     *:MINGW*:*) | ||||||
| 	echo ${UNAME_MACHINE}-pc-mingw32 | 	echo ${UNAME_MACHINE}-pc-mingw32 | ||||||
| 	exit ;; | 	exit ;; | ||||||
|     i*:MSYS*:*) |     *:MSYS*:*) | ||||||
| 	echo ${UNAME_MACHINE}-pc-msys | 	echo ${UNAME_MACHINE}-pc-msys | ||||||
| 	exit ;; | 	exit ;; | ||||||
|     i*:windows32*:*) |     i*:windows32*:*) | ||||||
| @ -856,21 +874,21 @@ EOF | |||||||
| 	exit ;; | 	exit ;; | ||||||
|     *:GNU:*:*) |     *:GNU:*:*) | ||||||
| 	# the GNU system | 	# the GNU system | ||||||
| 	echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-gnu`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'` | 	echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-${LIBC}`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'` | ||||||
| 	exit ;; | 	exit ;; | ||||||
|     *:GNU/*:*:*) |     *:GNU/*:*:*) | ||||||
| 	# other systems with GNU libc and userland | 	# other systems with GNU libc and userland | ||||||
| 	echo ${UNAME_MACHINE}-unknown-`echo ${UNAME_SYSTEM} | sed 's,^[^/]*/,,' | tr '[A-Z]' '[a-z]'``echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`-gnu | 	echo ${UNAME_MACHINE}-unknown-`echo ${UNAME_SYSTEM} | sed 's,^[^/]*/,,' | tr '[A-Z]' '[a-z]'``echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`-${LIBC} | ||||||
| 	exit ;; | 	exit ;; | ||||||
|     i*86:Minix:*:*) |     i*86:Minix:*:*) | ||||||
| 	echo ${UNAME_MACHINE}-pc-minix | 	echo ${UNAME_MACHINE}-pc-minix | ||||||
| 	exit ;; | 	exit ;; | ||||||
|     aarch64:Linux:*:*) |     aarch64:Linux:*:*) | ||||||
| 	echo ${UNAME_MACHINE}-unknown-linux-gnu | 	echo ${UNAME_MACHINE}-unknown-linux-${LIBC} | ||||||
| 	exit ;; | 	exit ;; | ||||||
|     aarch64_be:Linux:*:*) |     aarch64_be:Linux:*:*) | ||||||
| 	UNAME_MACHINE=aarch64_be | 	UNAME_MACHINE=aarch64_be | ||||||
| 	echo ${UNAME_MACHINE}-unknown-linux-gnu | 	echo ${UNAME_MACHINE}-unknown-linux-${LIBC} | ||||||
| 	exit ;; | 	exit ;; | ||||||
|     alpha:Linux:*:*) |     alpha:Linux:*:*) | ||||||
| 	case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in | 	case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in | ||||||
| @ -883,59 +901,54 @@ EOF | |||||||
| 	  EV68*) UNAME_MACHINE=alphaev68 ;; | 	  EV68*) UNAME_MACHINE=alphaev68 ;; | ||||||
| 	esac | 	esac | ||||||
| 	objdump --private-headers /bin/sh | grep -q ld.so.1 | 	objdump --private-headers /bin/sh | grep -q ld.so.1 | ||||||
| 	if test "$?" = 0 ; then LIBC="libc1" ; else LIBC="" ; fi | 	if test "$?" = 0 ; then LIBC="gnulibc1" ; fi | ||||||
| 	echo ${UNAME_MACHINE}-unknown-linux-gnu${LIBC} | 	echo ${UNAME_MACHINE}-unknown-linux-${LIBC} | ||||||
|  | 	exit ;; | ||||||
|  |     arc:Linux:*:* | arceb:Linux:*:*) | ||||||
|  | 	echo ${UNAME_MACHINE}-unknown-linux-${LIBC} | ||||||
| 	exit ;; | 	exit ;; | ||||||
|     arm*:Linux:*:*) |     arm*:Linux:*:*) | ||||||
| 	eval $set_cc_for_build | 	eval $set_cc_for_build | ||||||
| 	if echo __ARM_EABI__ | $CC_FOR_BUILD -E - 2>/dev/null \ | 	if echo __ARM_EABI__ | $CC_FOR_BUILD -E - 2>/dev/null \ | ||||||
| 	    | grep -q __ARM_EABI__ | 	    | grep -q __ARM_EABI__ | ||||||
| 	then | 	then | ||||||
| 	    echo ${UNAME_MACHINE}-unknown-linux-gnu | 	    echo ${UNAME_MACHINE}-unknown-linux-${LIBC} | ||||||
| 	else | 	else | ||||||
| 	    if echo __ARM_PCS_VFP | $CC_FOR_BUILD -E - 2>/dev/null \ | 	    if echo __ARM_PCS_VFP | $CC_FOR_BUILD -E - 2>/dev/null \ | ||||||
| 		| grep -q __ARM_PCS_VFP | 		| grep -q __ARM_PCS_VFP | ||||||
| 	    then | 	    then | ||||||
| 		echo ${UNAME_MACHINE}-unknown-linux-gnueabi | 		echo ${UNAME_MACHINE}-unknown-linux-${LIBC}eabi | ||||||
| 	    else | 	    else | ||||||
| 		echo ${UNAME_MACHINE}-unknown-linux-gnueabihf | 		echo ${UNAME_MACHINE}-unknown-linux-${LIBC}eabihf | ||||||
| 	    fi | 	    fi | ||||||
| 	fi | 	fi | ||||||
| 	exit ;; | 	exit ;; | ||||||
|     avr32*:Linux:*:*) |     avr32*:Linux:*:*) | ||||||
| 	echo ${UNAME_MACHINE}-unknown-linux-gnu | 	echo ${UNAME_MACHINE}-unknown-linux-${LIBC} | ||||||
| 	exit ;; | 	exit ;; | ||||||
|     cris:Linux:*:*) |     cris:Linux:*:*) | ||||||
| 	echo ${UNAME_MACHINE}-axis-linux-gnu | 	echo ${UNAME_MACHINE}-axis-linux-${LIBC} | ||||||
| 	exit ;; | 	exit ;; | ||||||
|     crisv32:Linux:*:*) |     crisv32:Linux:*:*) | ||||||
| 	echo ${UNAME_MACHINE}-axis-linux-gnu | 	echo ${UNAME_MACHINE}-axis-linux-${LIBC} | ||||||
| 	exit ;; | 	exit ;; | ||||||
|     frv:Linux:*:*) |     frv:Linux:*:*) | ||||||
| 	echo ${UNAME_MACHINE}-unknown-linux-gnu | 	echo ${UNAME_MACHINE}-unknown-linux-${LIBC} | ||||||
| 	exit ;; | 	exit ;; | ||||||
|     hexagon:Linux:*:*) |     hexagon:Linux:*:*) | ||||||
| 	echo ${UNAME_MACHINE}-unknown-linux-gnu | 	echo ${UNAME_MACHINE}-unknown-linux-${LIBC} | ||||||
| 	exit ;; | 	exit ;; | ||||||
|     i*86:Linux:*:*) |     i*86:Linux:*:*) | ||||||
| 	LIBC=gnu | 	echo ${UNAME_MACHINE}-pc-linux-${LIBC} | ||||||
| 	eval $set_cc_for_build |  | ||||||
| 	sed 's/^	//' << EOF >$dummy.c |  | ||||||
| 	#ifdef __dietlibc__ |  | ||||||
| 	LIBC=dietlibc |  | ||||||
| 	#endif |  | ||||||
| EOF |  | ||||||
| 	eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^LIBC'` |  | ||||||
| 	echo "${UNAME_MACHINE}-pc-linux-${LIBC}" |  | ||||||
| 	exit ;; | 	exit ;; | ||||||
|     ia64:Linux:*:*) |     ia64:Linux:*:*) | ||||||
| 	echo ${UNAME_MACHINE}-unknown-linux-gnu | 	echo ${UNAME_MACHINE}-unknown-linux-${LIBC} | ||||||
| 	exit ;; | 	exit ;; | ||||||
|     m32r*:Linux:*:*) |     m32r*:Linux:*:*) | ||||||
| 	echo ${UNAME_MACHINE}-unknown-linux-gnu | 	echo ${UNAME_MACHINE}-unknown-linux-${LIBC} | ||||||
| 	exit ;; | 	exit ;; | ||||||
|     m68*:Linux:*:*) |     m68*:Linux:*:*) | ||||||
| 	echo ${UNAME_MACHINE}-unknown-linux-gnu | 	echo ${UNAME_MACHINE}-unknown-linux-${LIBC} | ||||||
| 	exit ;; | 	exit ;; | ||||||
|     mips:Linux:*:* | mips64:Linux:*:*) |     mips:Linux:*:* | mips64:Linux:*:*) | ||||||
| 	eval $set_cc_for_build | 	eval $set_cc_for_build | ||||||
| @ -954,54 +967,74 @@ EOF | |||||||
| 	#endif | 	#endif | ||||||
| EOF | EOF | ||||||
| 	eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^CPU'` | 	eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^CPU'` | ||||||
| 	test x"${CPU}" != x && { echo "${CPU}-unknown-linux-gnu"; exit; } | 	test x"${CPU}" != x && { echo "${CPU}-unknown-linux-${LIBC}"; exit; } | ||||||
| 	;; | 	;; | ||||||
|     or32:Linux:*:*) |     openrisc*:Linux:*:*) | ||||||
| 	echo ${UNAME_MACHINE}-unknown-linux-gnu | 	echo or1k-unknown-linux-${LIBC} | ||||||
|  | 	exit ;; | ||||||
|  |     or32:Linux:*:* | or1k*:Linux:*:*) | ||||||
|  | 	echo ${UNAME_MACHINE}-unknown-linux-${LIBC} | ||||||
| 	exit ;; | 	exit ;; | ||||||
|     padre:Linux:*:*) |     padre:Linux:*:*) | ||||||
| 	echo sparc-unknown-linux-gnu | 	echo sparc-unknown-linux-${LIBC} | ||||||
| 	exit ;; | 	exit ;; | ||||||
|     parisc64:Linux:*:* | hppa64:Linux:*:*) |     parisc64:Linux:*:* | hppa64:Linux:*:*) | ||||||
| 	echo hppa64-unknown-linux-gnu | 	echo hppa64-unknown-linux-${LIBC} | ||||||
| 	exit ;; | 	exit ;; | ||||||
|     parisc:Linux:*:* | hppa:Linux:*:*) |     parisc:Linux:*:* | hppa:Linux:*:*) | ||||||
| 	# Look for CPU level | 	# Look for CPU level | ||||||
| 	case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in | 	case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in | ||||||
| 	  PA7*) echo hppa1.1-unknown-linux-gnu ;; | 	  PA7*) echo hppa1.1-unknown-linux-${LIBC} ;; | ||||||
| 	  PA8*) echo hppa2.0-unknown-linux-gnu ;; | 	  PA8*) echo hppa2.0-unknown-linux-${LIBC} ;; | ||||||
| 	  *)    echo hppa-unknown-linux-gnu ;; | 	  *)    echo hppa-unknown-linux-${LIBC} ;; | ||||||
| 	esac | 	esac | ||||||
| 	exit ;; | 	exit ;; | ||||||
|     ppc64:Linux:*:*) |     ppc64:Linux:*:*) | ||||||
| 	echo powerpc64-unknown-linux-gnu | 	echo powerpc64-unknown-linux-${LIBC} | ||||||
| 	exit ;; | 	exit ;; | ||||||
|     ppc:Linux:*:*) |     ppc:Linux:*:*) | ||||||
| 	echo powerpc-unknown-linux-gnu | 	echo powerpc-unknown-linux-${LIBC} | ||||||
|  | 	exit ;; | ||||||
|  |     ppc64le:Linux:*:*) | ||||||
|  | 	echo powerpc64le-unknown-linux-${LIBC} | ||||||
|  | 	exit ;; | ||||||
|  |     ppcle:Linux:*:*) | ||||||
|  | 	echo powerpcle-unknown-linux-${LIBC} | ||||||
| 	exit ;; | 	exit ;; | ||||||
|     s390:Linux:*:* | s390x:Linux:*:*) |     s390:Linux:*:* | s390x:Linux:*:*) | ||||||
| 	echo ${UNAME_MACHINE}-ibm-linux | 	echo ${UNAME_MACHINE}-ibm-linux-${LIBC} | ||||||
| 	exit ;; | 	exit ;; | ||||||
|     sh64*:Linux:*:*) |     sh64*:Linux:*:*) | ||||||
| 	echo ${UNAME_MACHINE}-unknown-linux-gnu | 	echo ${UNAME_MACHINE}-unknown-linux-${LIBC} | ||||||
| 	exit ;; | 	exit ;; | ||||||
|     sh*:Linux:*:*) |     sh*:Linux:*:*) | ||||||
| 	echo ${UNAME_MACHINE}-unknown-linux-gnu | 	echo ${UNAME_MACHINE}-unknown-linux-${LIBC} | ||||||
| 	exit ;; | 	exit ;; | ||||||
|     sparc:Linux:*:* | sparc64:Linux:*:*) |     sparc:Linux:*:* | sparc64:Linux:*:*) | ||||||
| 	echo ${UNAME_MACHINE}-unknown-linux-gnu | 	echo ${UNAME_MACHINE}-unknown-linux-${LIBC} | ||||||
| 	exit ;; | 	exit ;; | ||||||
|     tile*:Linux:*:*) |     tile*:Linux:*:*) | ||||||
| 	echo ${UNAME_MACHINE}-unknown-linux-gnu | 	echo ${UNAME_MACHINE}-unknown-linux-${LIBC} | ||||||
| 	exit ;; | 	exit ;; | ||||||
|     vax:Linux:*:*) |     vax:Linux:*:*) | ||||||
| 	echo ${UNAME_MACHINE}-dec-linux-gnu | 	echo ${UNAME_MACHINE}-dec-linux-${LIBC} | ||||||
| 	exit ;; | 	exit ;; | ||||||
|     x86_64:Linux:*:*) |     x86_64:Linux:*:*) | ||||||
| 	echo ${UNAME_MACHINE}-unknown-linux-gnu | 	eval $set_cc_for_build | ||||||
|  | 	X86_64_ABI= | ||||||
|  | 	# If there is a compiler, see if it is configured for 32-bit objects. | ||||||
|  | 	if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then | ||||||
|  | 	    if (echo '#ifdef __ILP32__'; echo IS_X32; echo '#endif') | \ | ||||||
|  | 		(CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \ | ||||||
|  | 		grep IS_X32 >/dev/null | ||||||
|  | 	    then | ||||||
|  | 		X86_64_ABI=x32 | ||||||
|  | 	    fi | ||||||
|  | 	fi | ||||||
|  | 	echo x86_64-unknown-linux-gnu${X86_64_ABI} | ||||||
| 	exit ;; | 	exit ;; | ||||||
|     xtensa*:Linux:*:*) |     xtensa*:Linux:*:*) | ||||||
| 	echo ${UNAME_MACHINE}-unknown-linux-gnu | 	echo ${UNAME_MACHINE}-unknown-linux-${LIBC} | ||||||
| 	exit ;; | 	exit ;; | ||||||
|     i*86:DYNIX/ptx:4*:*) |     i*86:DYNIX/ptx:4*:*) | ||||||
| 	# ptx 4.0 does uname -s correctly, with DYNIX/ptx in there. | 	# ptx 4.0 does uname -s correctly, with DYNIX/ptx in there. | ||||||
| @ -1205,6 +1238,9 @@ EOF | |||||||
|     BePC:Haiku:*:*)	# Haiku running on Intel PC compatible. |     BePC:Haiku:*:*)	# Haiku running on Intel PC compatible. | ||||||
| 	echo i586-pc-haiku | 	echo i586-pc-haiku | ||||||
| 	exit ;; | 	exit ;; | ||||||
|  |     x86_64:Haiku:*:*) | ||||||
|  | 	echo x86_64-unknown-haiku | ||||||
|  | 	exit ;; | ||||||
|     SX-4:SUPER-UX:*:*) |     SX-4:SUPER-UX:*:*) | ||||||
| 	echo sx4-nec-superux${UNAME_RELEASE} | 	echo sx4-nec-superux${UNAME_RELEASE} | ||||||
| 	exit ;; | 	exit ;; | ||||||
| @ -1231,19 +1267,31 @@ EOF | |||||||
| 	exit ;; | 	exit ;; | ||||||
|     *:Darwin:*:*) |     *:Darwin:*:*) | ||||||
| 	UNAME_PROCESSOR=`uname -p` || UNAME_PROCESSOR=unknown | 	UNAME_PROCESSOR=`uname -p` || UNAME_PROCESSOR=unknown | ||||||
| 	case $UNAME_PROCESSOR in |  | ||||||
| 	    i386) |  | ||||||
| 	eval $set_cc_for_build | 	eval $set_cc_for_build | ||||||
|  | 	if test "$UNAME_PROCESSOR" = unknown ; then | ||||||
|  | 	    UNAME_PROCESSOR=powerpc | ||||||
|  | 	fi | ||||||
|  | 	if test `echo "$UNAME_RELEASE" | sed -e 's/\..*//'` -le 10 ; then | ||||||
| 	    if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then | 	    if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then | ||||||
| 		if (echo '#ifdef __LP64__'; echo IS_64BIT_ARCH; echo '#endif') | \ | 		if (echo '#ifdef __LP64__'; echo IS_64BIT_ARCH; echo '#endif') | \ | ||||||
| 		    (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \ | 		    (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \ | ||||||
| 		    grep IS_64BIT_ARCH >/dev/null | 		    grep IS_64BIT_ARCH >/dev/null | ||||||
| 		then | 		then | ||||||
| 		      UNAME_PROCESSOR="x86_64" | 		    case $UNAME_PROCESSOR in | ||||||
| 		  fi | 			i386) UNAME_PROCESSOR=x86_64 ;; | ||||||
| 		fi ;; | 			powerpc) UNAME_PROCESSOR=powerpc64 ;; | ||||||
| 	    unknown) UNAME_PROCESSOR=powerpc ;; |  | ||||||
| 		    esac | 		    esac | ||||||
|  | 		fi | ||||||
|  | 	    fi | ||||||
|  | 	elif test "$UNAME_PROCESSOR" = i386 ; then | ||||||
|  | 	    # Avoid executing cc on OS X 10.9, as it ships with a stub | ||||||
|  | 	    # that puts up a graphical alert prompting to install | ||||||
|  | 	    # developer tools.  Any system running Mac OS X 10.7 or | ||||||
|  | 	    # later (Darwin 11 and later) is required to have a 64-bit | ||||||
|  | 	    # processor. This is not true of the ARM version of Darwin | ||||||
|  | 	    # that Apple uses in portable devices. | ||||||
|  | 	    UNAME_PROCESSOR=x86_64 | ||||||
|  | 	fi | ||||||
| 	echo ${UNAME_PROCESSOR}-apple-darwin${UNAME_RELEASE} | 	echo ${UNAME_PROCESSOR}-apple-darwin${UNAME_RELEASE} | ||||||
| 	exit ;; | 	exit ;; | ||||||
|     *:procnto*:*:* | *:QNX:[0123456789]*:*) |     *:procnto*:*:* | *:QNX:[0123456789]*:*) | ||||||
| @ -1334,157 +1382,6 @@ EOF | |||||||
| 	exit ;; | 	exit ;; | ||||||
| esac | esac | ||||||
| 
 | 
 | ||||||
| #echo '(No uname command or uname output not recognized.)' 1>&2 |  | ||||||
| #echo "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" 1>&2 |  | ||||||
| 
 |  | ||||||
| eval $set_cc_for_build |  | ||||||
| cat >$dummy.c <<EOF |  | ||||||
| #ifdef _SEQUENT_ |  | ||||||
| # include <sys/types.h> |  | ||||||
| # include <sys/utsname.h> |  | ||||||
| #endif |  | ||||||
| main () |  | ||||||
| { |  | ||||||
| #if defined (sony) |  | ||||||
| #if defined (MIPSEB) |  | ||||||
|   /* BFD wants "bsd" instead of "newsos".  Perhaps BFD should be changed, |  | ||||||
|      I don't know....  */ |  | ||||||
|   printf ("mips-sony-bsd\n"); exit (0); |  | ||||||
| #else |  | ||||||
| #include <sys/param.h> |  | ||||||
|   printf ("m68k-sony-newsos%s\n", |  | ||||||
| #ifdef NEWSOS4 |  | ||||||
| 	"4" |  | ||||||
| #else |  | ||||||
| 	"" |  | ||||||
| #endif |  | ||||||
| 	); exit (0); |  | ||||||
| #endif |  | ||||||
| #endif |  | ||||||
| 
 |  | ||||||
| #if defined (__arm) && defined (__acorn) && defined (__unix) |  | ||||||
|   printf ("arm-acorn-riscix\n"); exit (0); |  | ||||||
| #endif |  | ||||||
| 
 |  | ||||||
| #if defined (hp300) && !defined (hpux) |  | ||||||
|   printf ("m68k-hp-bsd\n"); exit (0); |  | ||||||
| #endif |  | ||||||
| 
 |  | ||||||
| #if defined (NeXT) |  | ||||||
| #if !defined (__ARCHITECTURE__) |  | ||||||
| #define __ARCHITECTURE__ "m68k" |  | ||||||
| #endif |  | ||||||
|   int version; |  | ||||||
|   version=`(hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null`; |  | ||||||
|   if (version < 4) |  | ||||||
|     printf ("%s-next-nextstep%d\n", __ARCHITECTURE__, version); |  | ||||||
|   else |  | ||||||
|     printf ("%s-next-openstep%d\n", __ARCHITECTURE__, version); |  | ||||||
|   exit (0); |  | ||||||
| #endif |  | ||||||
| 
 |  | ||||||
| #if defined (MULTIMAX) || defined (n16) |  | ||||||
| #if defined (UMAXV) |  | ||||||
|   printf ("ns32k-encore-sysv\n"); exit (0); |  | ||||||
| #else |  | ||||||
| #if defined (CMU) |  | ||||||
|   printf ("ns32k-encore-mach\n"); exit (0); |  | ||||||
| #else |  | ||||||
|   printf ("ns32k-encore-bsd\n"); exit (0); |  | ||||||
| #endif |  | ||||||
| #endif |  | ||||||
| #endif |  | ||||||
| 
 |  | ||||||
| #if defined (__386BSD__) |  | ||||||
|   printf ("i386-pc-bsd\n"); exit (0); |  | ||||||
| #endif |  | ||||||
| 
 |  | ||||||
| #if defined (sequent) |  | ||||||
| #if defined (i386) |  | ||||||
|   printf ("i386-sequent-dynix\n"); exit (0); |  | ||||||
| #endif |  | ||||||
| #if defined (ns32000) |  | ||||||
|   printf ("ns32k-sequent-dynix\n"); exit (0); |  | ||||||
| #endif |  | ||||||
| #endif |  | ||||||
| 
 |  | ||||||
| #if defined (_SEQUENT_) |  | ||||||
|     struct utsname un; |  | ||||||
| 
 |  | ||||||
|     uname(&un); |  | ||||||
| 
 |  | ||||||
|     if (strncmp(un.version, "V2", 2) == 0) { |  | ||||||
| 	printf ("i386-sequent-ptx2\n"); exit (0); |  | ||||||
|     } |  | ||||||
|     if (strncmp(un.version, "V1", 2) == 0) { /* XXX is V1 correct? */ |  | ||||||
| 	printf ("i386-sequent-ptx1\n"); exit (0); |  | ||||||
|     } |  | ||||||
|     printf ("i386-sequent-ptx\n"); exit (0); |  | ||||||
| 
 |  | ||||||
| #endif |  | ||||||
| 
 |  | ||||||
| #if defined (vax) |  | ||||||
| # if !defined (ultrix) |  | ||||||
| #  include <sys/param.h> |  | ||||||
| #  if defined (BSD) |  | ||||||
| #   if BSD == 43 |  | ||||||
|       printf ("vax-dec-bsd4.3\n"); exit (0); |  | ||||||
| #   else |  | ||||||
| #    if BSD == 199006 |  | ||||||
|       printf ("vax-dec-bsd4.3reno\n"); exit (0); |  | ||||||
| #    else |  | ||||||
|       printf ("vax-dec-bsd\n"); exit (0); |  | ||||||
| #    endif |  | ||||||
| #   endif |  | ||||||
| #  else |  | ||||||
|     printf ("vax-dec-bsd\n"); exit (0); |  | ||||||
| #  endif |  | ||||||
| # else |  | ||||||
|     printf ("vax-dec-ultrix\n"); exit (0); |  | ||||||
| # endif |  | ||||||
| #endif |  | ||||||
| 
 |  | ||||||
| #if defined (alliant) && defined (i860) |  | ||||||
|   printf ("i860-alliant-bsd\n"); exit (0); |  | ||||||
| #endif |  | ||||||
| 
 |  | ||||||
|   exit (1); |  | ||||||
| } |  | ||||||
| EOF |  | ||||||
| 
 |  | ||||||
| $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null && SYSTEM_NAME=`$dummy` && |  | ||||||
| 	{ echo "$SYSTEM_NAME"; exit; } |  | ||||||
| 
 |  | ||||||
| # Apollos put the system type in the environment. |  | ||||||
| 
 |  | ||||||
| test -d /usr/apollo && { echo ${ISP}-apollo-${SYSTYPE}; exit; } |  | ||||||
| 
 |  | ||||||
| # Convex versions that predate uname can use getsysinfo(1) |  | ||||||
| 
 |  | ||||||
| if [ -x /usr/convex/getsysinfo ] |  | ||||||
| then |  | ||||||
|     case `getsysinfo -f cpu_type` in |  | ||||||
|     c1*) |  | ||||||
| 	echo c1-convex-bsd |  | ||||||
| 	exit ;; |  | ||||||
|     c2*) |  | ||||||
| 	if getsysinfo -f scalar_acc |  | ||||||
| 	then echo c32-convex-bsd |  | ||||||
| 	else echo c2-convex-bsd |  | ||||||
| 	fi |  | ||||||
| 	exit ;; |  | ||||||
|     c34*) |  | ||||||
| 	echo c34-convex-bsd |  | ||||||
| 	exit ;; |  | ||||||
|     c38*) |  | ||||||
| 	echo c38-convex-bsd |  | ||||||
| 	exit ;; |  | ||||||
|     c4*) |  | ||||||
| 	echo c4-convex-bsd |  | ||||||
| 	exit ;; |  | ||||||
|     esac |  | ||||||
| fi |  | ||||||
| 
 |  | ||||||
| cat >&2 <<EOF | cat >&2 <<EOF | ||||||
| $0: unable to guess system type | $0: unable to guess system type | ||||||
| 
 | 
 | ||||||
|  | |||||||
							
								
								
									
										130
									
								
								google-breakpad/autotools/config.sub
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										130
									
								
								google-breakpad/autotools/config.sub
									
									
									
									
										vendored
									
									
								
							| @ -1,24 +1,18 @@ | |||||||
| #! /bin/sh | #! /bin/sh | ||||||
| # Configuration validation subroutine script. | # Configuration validation subroutine script. | ||||||
| #   Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, | #   Copyright 1992-2014 Free Software Foundation, Inc. | ||||||
| #   2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, |  | ||||||
| #   2011, 2012 Free Software Foundation, Inc. |  | ||||||
| 
 | 
 | ||||||
| timestamp='2012-06-17' | timestamp='2014-07-28' | ||||||
| 
 | 
 | ||||||
| # This file is (in principle) common to ALL GNU software. | # This file is free software; you can redistribute it and/or modify it | ||||||
| # The presence of a machine in this file suggests that SOME GNU software | # under the terms of the GNU General Public License as published by | ||||||
| # can handle that machine.  It does not imply ALL GNU software can. | # the Free Software Foundation; either version 3 of the License, or | ||||||
| # |  | ||||||
| # This file is free software; you can redistribute it and/or modify |  | ||||||
| # it under the terms of the GNU General Public License as published by |  | ||||||
| # the Free Software Foundation; either version 2 of the License, or |  | ||||||
| # (at your option) any later version. | # (at your option) any later version. | ||||||
| # | # | ||||||
| # This program is distributed in the hope that it will be useful, | # This program is distributed in the hope that it will be useful, but | ||||||
| # but WITHOUT ANY WARRANTY; without even the implied warranty of | # WITHOUT ANY WARRANTY; without even the implied warranty of | ||||||
| # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU | ||||||
| # GNU General Public License for more details. | # General Public License for more details. | ||||||
| # | # | ||||||
| # You should have received a copy of the GNU General Public License | # You should have received a copy of the GNU General Public License | ||||||
| # along with this program; if not, see <http://www.gnu.org/licenses/>. | # along with this program; if not, see <http://www.gnu.org/licenses/>. | ||||||
| @ -26,11 +20,12 @@ timestamp='2012-06-17' | |||||||
| # As a special exception to the GNU General Public License, if you | # As a special exception to the GNU General Public License, if you | ||||||
| # distribute this file as part of a program that contains a | # distribute this file as part of a program that contains a | ||||||
| # configuration script generated by Autoconf, you may include it under | # configuration script generated by Autoconf, you may include it under | ||||||
| # the same distribution terms that you use for the rest of that program. | # the same distribution terms that you use for the rest of that | ||||||
|  | # program.  This Exception is an additional permission under section 7 | ||||||
|  | # of the GNU General Public License, version 3 ("GPLv3"). | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| # Please send patches to <config-patches@gnu.org>.  Submit a context | # Please send patches with a ChangeLog entry to config-patches@gnu.org. | ||||||
| # diff and a properly formatted GNU ChangeLog entry. |  | ||||||
| # | # | ||||||
| # Configuration subroutine to validate and canonicalize a configuration type. | # Configuration subroutine to validate and canonicalize a configuration type. | ||||||
| # Supply the specified configuration type as an argument. | # Supply the specified configuration type as an argument. | ||||||
| @ -73,9 +68,7 @@ Report bugs and patches to <config-patches@gnu.org>." | |||||||
| version="\ | version="\ | ||||||
| GNU config.sub ($timestamp) | GNU config.sub ($timestamp) | ||||||
| 
 | 
 | ||||||
| Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, | Copyright 1992-2014 Free Software Foundation, Inc. | ||||||
| 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012 |  | ||||||
| Free Software Foundation, Inc. |  | ||||||
| 
 | 
 | ||||||
| This is free software; see the source for copying conditions.  There is NO | This is free software; see the source for copying conditions.  There is NO | ||||||
| warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." | warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." | ||||||
| @ -123,7 +116,7 @@ esac | |||||||
| maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'` | maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'` | ||||||
| case $maybe_os in | case $maybe_os in | ||||||
|   nto-qnx* | linux-gnu* | linux-android* | linux-dietlibc | linux-newlib* | \ |   nto-qnx* | linux-gnu* | linux-android* | linux-dietlibc | linux-newlib* | \ | ||||||
|   linux-uclibc* | uclinux-uclibc* | uclinux-gnu* | kfreebsd*-gnu* | \ |   linux-musl* | linux-uclibc* | uclinux-uclibc* | uclinux-gnu* | kfreebsd*-gnu* | \ | ||||||
|   knetbsd*-gnu* | netbsd*-gnu* | \ |   knetbsd*-gnu* | netbsd*-gnu* | \ | ||||||
|   kopensolaris*-gnu* | \ |   kopensolaris*-gnu* | \ | ||||||
|   storm-chaos* | os2-emx* | rtmk-nova*) |   storm-chaos* | os2-emx* | rtmk-nova*) | ||||||
| @ -156,7 +149,7 @@ case $os in | |||||||
| 	-convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\ | 	-convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\ | ||||||
| 	-c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \ | 	-c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \ | ||||||
| 	-harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \ | 	-harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \ | ||||||
| 	-apple | -axis | -knuth | -cray | -microblaze) | 	-apple | -axis | -knuth | -cray | -microblaze*) | ||||||
| 		os= | 		os= | ||||||
| 		basic_machine=$1 | 		basic_machine=$1 | ||||||
| 		;; | 		;; | ||||||
| @ -259,21 +252,24 @@ case $basic_machine in | |||||||
| 	| alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \ | 	| alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \ | ||||||
| 	| alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \ | 	| alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \ | ||||||
| 	| am33_2.0 \ | 	| am33_2.0 \ | ||||||
| 	| arc | arm | arm[bl]e | arme[lb] | armv[2345] | armv[345][lb] | avr | avr32 \ | 	| arc | arceb \ | ||||||
|  | 	| arm | arm[bl]e | arme[lb] | armv[2-8] | armv[3-8][lb] | armv7[arm] \ | ||||||
|  | 	| avr | avr32 \ | ||||||
| 	| be32 | be64 \ | 	| be32 | be64 \ | ||||||
| 	| bfin \ | 	| bfin \ | ||||||
| 	| c4x | clipper \ | 	| c4x | c8051 | clipper \ | ||||||
| 	| d10v | d30v | dlx | dsp16xx \ | 	| d10v | d30v | dlx | dsp16xx | dvp \ | ||||||
| 	| epiphany \ | 	| epiphany \ | ||||||
| 	| fido | fr30 | frv \ | 	| fido | fr30 | frv \ | ||||||
| 	| h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \ | 	| h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \ | ||||||
| 	| hexagon \ | 	| hexagon \ | ||||||
| 	| i370 | i860 | i960 | ia64 \ | 	| i370 | i860 | i960 | ia64 \ | ||||||
| 	| ip2k | iq2000 \ | 	| ip2k | iq2000 \ | ||||||
|  | 	| k1om \ | ||||||
| 	| le32 | le64 \ | 	| le32 | le64 \ | ||||||
| 	| lm32 \ | 	| lm32 \ | ||||||
| 	| m32c | m32r | m32rle | m68000 | m68k | m88k \ | 	| m32c | m32r | m32rle | m68000 | m68k | m88k \ | ||||||
| 	| maxq | mb | microblaze | mcore | mep | metag \ | 	| maxq | mb | microblaze | microblazeel | mcore | mep | metag \ | ||||||
| 	| mips | mipsbe | mipseb | mipsel | mipsle \ | 	| mips | mipsbe | mipseb | mipsel | mipsle \ | ||||||
| 	| mips16 \ | 	| mips16 \ | ||||||
| 	| mips64 | mips64el \ | 	| mips64 | mips64el \ | ||||||
| @ -287,20 +283,22 @@ case $basic_machine in | |||||||
| 	| mips64vr5900 | mips64vr5900el \ | 	| mips64vr5900 | mips64vr5900el \ | ||||||
| 	| mipsisa32 | mipsisa32el \ | 	| mipsisa32 | mipsisa32el \ | ||||||
| 	| mipsisa32r2 | mipsisa32r2el \ | 	| mipsisa32r2 | mipsisa32r2el \ | ||||||
|  | 	| mipsisa32r6 | mipsisa32r6el \ | ||||||
| 	| mipsisa64 | mipsisa64el \ | 	| mipsisa64 | mipsisa64el \ | ||||||
| 	| mipsisa64r2 | mipsisa64r2el \ | 	| mipsisa64r2 | mipsisa64r2el \ | ||||||
|  | 	| mipsisa64r6 | mipsisa64r6el \ | ||||||
| 	| mipsisa64sb1 | mipsisa64sb1el \ | 	| mipsisa64sb1 | mipsisa64sb1el \ | ||||||
| 	| mipsisa64sr71k | mipsisa64sr71kel \ | 	| mipsisa64sr71k | mipsisa64sr71kel \ | ||||||
|  | 	| mipsr5900 | mipsr5900el \ | ||||||
| 	| mipstx39 | mipstx39el \ | 	| mipstx39 | mipstx39el \ | ||||||
| 	| mn10200 | mn10300 \ | 	| mn10200 | mn10300 \ | ||||||
| 	| moxie \ | 	| moxie \ | ||||||
| 	| mt \ | 	| mt \ | ||||||
| 	| msp430 \ | 	| msp430 \ | ||||||
| 	| nds32 | nds32le | nds32be \ | 	| nds32 | nds32le | nds32be \ | ||||||
| 	| nios | nios2 \ | 	| nios | nios2 | nios2eb | nios2el \ | ||||||
| 	| ns16k | ns32k \ | 	| ns16k | ns32k \ | ||||||
| 	| open8 \ | 	| open8 | or1k | or1knd | or32 \ | ||||||
| 	| or32 \ |  | ||||||
| 	| pdp10 | pdp11 | pj | pjl \ | 	| pdp10 | pdp11 | pj | pjl \ | ||||||
| 	| powerpc | powerpc64 | powerpc64le | powerpcle \ | 	| powerpc | powerpc64 | powerpc64le | powerpcle \ | ||||||
| 	| pyramid \ | 	| pyramid \ | ||||||
| @ -328,7 +326,7 @@ case $basic_machine in | |||||||
| 	c6x) | 	c6x) | ||||||
| 		basic_machine=tic6x-unknown | 		basic_machine=tic6x-unknown | ||||||
| 		;; | 		;; | ||||||
| 	m6811 | m68hc11 | m6812 | m68hc12 | m68hcs12x | picochip) | 	m6811 | m68hc11 | m6812 | m68hc12 | m68hcs12x | nvptx | picochip) | ||||||
| 		basic_machine=$basic_machine-unknown | 		basic_machine=$basic_machine-unknown | ||||||
| 		os=-none | 		os=-none | ||||||
| 		;; | 		;; | ||||||
| @ -370,13 +368,13 @@ case $basic_machine in | |||||||
| 	| aarch64-* | aarch64_be-* \ | 	| aarch64-* | aarch64_be-* \ | ||||||
| 	| alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \ | 	| alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \ | ||||||
| 	| alpha64-* | alpha64ev[4-8]-* | alpha64ev56-* | alpha64ev6[78]-* \ | 	| alpha64-* | alpha64ev[4-8]-* | alpha64ev56-* | alpha64ev6[78]-* \ | ||||||
| 	| alphapca5[67]-* | alpha64pca5[67]-* | arc-* \ | 	| alphapca5[67]-* | alpha64pca5[67]-* | arc-* | arceb-* \ | ||||||
| 	| arm-*  | armbe-* | armle-* | armeb-* | armv*-* \ | 	| arm-*  | armbe-* | armle-* | armeb-* | armv*-* \ | ||||||
| 	| avr-* | avr32-* \ | 	| avr-* | avr32-* \ | ||||||
| 	| be32-* | be64-* \ | 	| be32-* | be64-* \ | ||||||
| 	| bfin-* | bs2000-* \ | 	| bfin-* | bs2000-* \ | ||||||
| 	| c[123]* | c30-* | [cjt]90-* | c4x-* \ | 	| c[123]* | c30-* | [cjt]90-* | c4x-* \ | ||||||
| 	| clipper-* | craynv-* | cydra-* \ | 	| c8051-* | clipper-* | craynv-* | cydra-* \ | ||||||
| 	| d10v-* | d30v-* | dlx-* \ | 	| d10v-* | d30v-* | dlx-* \ | ||||||
| 	| elxsi-* \ | 	| elxsi-* \ | ||||||
| 	| f30[01]-* | f700-* | fido-* | fr30-* | frv-* | fx80-* \ | 	| f30[01]-* | f700-* | fido-* | fr30-* | frv-* | fx80-* \ | ||||||
| @ -385,11 +383,13 @@ case $basic_machine in | |||||||
| 	| hexagon-* \ | 	| hexagon-* \ | ||||||
| 	| i*86-* | i860-* | i960-* | ia64-* \ | 	| i*86-* | i860-* | i960-* | ia64-* \ | ||||||
| 	| ip2k-* | iq2000-* \ | 	| ip2k-* | iq2000-* \ | ||||||
|  | 	| k1om-* \ | ||||||
| 	| le32-* | le64-* \ | 	| le32-* | le64-* \ | ||||||
| 	| lm32-* \ | 	| lm32-* \ | ||||||
| 	| m32c-* | m32r-* | m32rle-* \ | 	| m32c-* | m32r-* | m32rle-* \ | ||||||
| 	| m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \ | 	| m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \ | ||||||
| 	| m88110-* | m88k-* | maxq-* | mcore-* | metag-* | microblaze-* \ | 	| m88110-* | m88k-* | maxq-* | mcore-* | metag-* \ | ||||||
|  | 	| microblaze-* | microblazeel-* \ | ||||||
| 	| mips-* | mipsbe-* | mipseb-* | mipsel-* | mipsle-* \ | 	| mips-* | mipsbe-* | mipseb-* | mipsel-* | mipsle-* \ | ||||||
| 	| mips16-* \ | 	| mips16-* \ | ||||||
| 	| mips64-* | mips64el-* \ | 	| mips64-* | mips64el-* \ | ||||||
| @ -403,18 +403,22 @@ case $basic_machine in | |||||||
| 	| mips64vr5900-* | mips64vr5900el-* \ | 	| mips64vr5900-* | mips64vr5900el-* \ | ||||||
| 	| mipsisa32-* | mipsisa32el-* \ | 	| mipsisa32-* | mipsisa32el-* \ | ||||||
| 	| mipsisa32r2-* | mipsisa32r2el-* \ | 	| mipsisa32r2-* | mipsisa32r2el-* \ | ||||||
|  | 	| mipsisa32r6-* | mipsisa32r6el-* \ | ||||||
| 	| mipsisa64-* | mipsisa64el-* \ | 	| mipsisa64-* | mipsisa64el-* \ | ||||||
| 	| mipsisa64r2-* | mipsisa64r2el-* \ | 	| mipsisa64r2-* | mipsisa64r2el-* \ | ||||||
|  | 	| mipsisa64r6-* | mipsisa64r6el-* \ | ||||||
| 	| mipsisa64sb1-* | mipsisa64sb1el-* \ | 	| mipsisa64sb1-* | mipsisa64sb1el-* \ | ||||||
| 	| mipsisa64sr71k-* | mipsisa64sr71kel-* \ | 	| mipsisa64sr71k-* | mipsisa64sr71kel-* \ | ||||||
|  | 	| mipsr5900-* | mipsr5900el-* \ | ||||||
| 	| mipstx39-* | mipstx39el-* \ | 	| mipstx39-* | mipstx39el-* \ | ||||||
| 	| mmix-* \ | 	| mmix-* \ | ||||||
| 	| mt-* \ | 	| mt-* \ | ||||||
| 	| msp430-* \ | 	| msp430-* \ | ||||||
| 	| nds32-* | nds32le-* | nds32be-* \ | 	| nds32-* | nds32le-* | nds32be-* \ | ||||||
| 	| nios-* | nios2-* \ | 	| nios-* | nios2-* | nios2eb-* | nios2el-* \ | ||||||
| 	| none-* | np1-* | ns16k-* | ns32k-* \ | 	| none-* | np1-* | ns16k-* | ns32k-* \ | ||||||
| 	| open8-* \ | 	| open8-* \ | ||||||
|  | 	| or1k*-* \ | ||||||
| 	| orion-* \ | 	| orion-* \ | ||||||
| 	| pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \ | 	| pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \ | ||||||
| 	| powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* \ | 	| powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* \ | ||||||
| @ -788,11 +792,15 @@ case $basic_machine in | |||||||
| 		basic_machine=ns32k-utek | 		basic_machine=ns32k-utek | ||||||
| 		os=-sysv | 		os=-sysv | ||||||
| 		;; | 		;; | ||||||
| 	microblaze) | 	microblaze*) | ||||||
| 		basic_machine=microblaze-xilinx | 		basic_machine=microblaze-xilinx | ||||||
| 		;; | 		;; | ||||||
|  | 	mingw64) | ||||||
|  | 		basic_machine=x86_64-pc | ||||||
|  | 		os=-mingw64 | ||||||
|  | 		;; | ||||||
| 	mingw32) | 	mingw32) | ||||||
| 		basic_machine=i386-pc | 		basic_machine=i686-pc | ||||||
| 		os=-mingw32 | 		os=-mingw32 | ||||||
| 		;; | 		;; | ||||||
| 	mingw32ce) | 	mingw32ce) | ||||||
| @ -806,6 +814,24 @@ case $basic_machine in | |||||||
| 		basic_machine=m68k-atari | 		basic_machine=m68k-atari | ||||||
| 		os=-mint | 		os=-mint | ||||||
| 		;; | 		;; | ||||||
|  | 	mipsEE* | ee | ps2) | ||||||
|  | 		basic_machine=mips64r5900el-scei | ||||||
|  | 		case $os in | ||||||
|  | 		    -linux*) | ||||||
|  | 			;; | ||||||
|  | 		    *) | ||||||
|  | 			os=-elf | ||||||
|  | 			;; | ||||||
|  | 		esac | ||||||
|  | 		;; | ||||||
|  | 	iop) | ||||||
|  | 		basic_machine=mipsel-scei | ||||||
|  | 		os=-irx | ||||||
|  | 		;; | ||||||
|  | 	dvp) | ||||||
|  | 		basic_machine=dvp-scei | ||||||
|  | 		os=-elf | ||||||
|  | 		;; | ||||||
| 	mips3*-*) | 	mips3*-*) | ||||||
| 		basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'` | 		basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'` | ||||||
| 		;; | 		;; | ||||||
| @ -820,6 +846,10 @@ case $basic_machine in | |||||||
| 		basic_machine=powerpc-unknown | 		basic_machine=powerpc-unknown | ||||||
| 		os=-morphos | 		os=-morphos | ||||||
| 		;; | 		;; | ||||||
|  | 	moxiebox) | ||||||
|  | 		basic_machine=moxie-unknown | ||||||
|  | 		os=-moxiebox | ||||||
|  | 		;; | ||||||
| 	msdos) | 	msdos) | ||||||
| 		basic_machine=i386-pc | 		basic_machine=i386-pc | ||||||
| 		os=-msdos | 		os=-msdos | ||||||
| @ -828,7 +858,7 @@ case $basic_machine in | |||||||
| 		basic_machine=`echo $basic_machine | sed -e 's/ms1-/mt-/'` | 		basic_machine=`echo $basic_machine | sed -e 's/ms1-/mt-/'` | ||||||
| 		;; | 		;; | ||||||
| 	msys) | 	msys) | ||||||
| 		basic_machine=i386-pc | 		basic_machine=i686-pc | ||||||
| 		os=-msys | 		os=-msys | ||||||
| 		;; | 		;; | ||||||
| 	mvs) | 	mvs) | ||||||
| @ -1019,7 +1049,11 @@ case $basic_machine in | |||||||
| 		basic_machine=i586-unknown | 		basic_machine=i586-unknown | ||||||
| 		os=-pw32 | 		os=-pw32 | ||||||
| 		;; | 		;; | ||||||
| 	rdos) | 	rdos | rdos64) | ||||||
|  | 		basic_machine=x86_64-pc | ||||||
|  | 		os=-rdos | ||||||
|  | 		;; | ||||||
|  | 	rdos32) | ||||||
| 		basic_machine=i386-pc | 		basic_machine=i386-pc | ||||||
| 		os=-rdos | 		os=-rdos | ||||||
| 		;; | 		;; | ||||||
| @ -1346,7 +1380,7 @@ case $os in | |||||||
| 	-gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \ | 	-gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \ | ||||||
| 	      | -*vms* | -sco* | -esix* | -isc* | -aix* | -cnk* | -sunos | -sunos[34]*\ | 	      | -*vms* | -sco* | -esix* | -isc* | -aix* | -cnk* | -sunos | -sunos[34]*\ | ||||||
| 	      | -hpux* | -unos* | -osf* | -luna* | -dgux* | -auroraux* | -solaris* \ | 	      | -hpux* | -unos* | -osf* | -luna* | -dgux* | -auroraux* | -solaris* \ | ||||||
| 	      | -sym* | -kopensolaris* \ | 	      | -sym* | -kopensolaris* | -plan9* \ | ||||||
| 	      | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \ | 	      | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \ | ||||||
| 	      | -aos* | -aros* \ | 	      | -aos* | -aros* \ | ||||||
| 	      | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \ | 	      | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \ | ||||||
| @ -1359,16 +1393,16 @@ case $os in | |||||||
| 	      | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \ | 	      | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \ | ||||||
| 	      | -chorusos* | -chorusrdb* | -cegcc* \ | 	      | -chorusos* | -chorusrdb* | -cegcc* \ | ||||||
| 	      | -cygwin* | -msys* | -pe* | -psos* | -moss* | -proelf* | -rtems* \ | 	      | -cygwin* | -msys* | -pe* | -psos* | -moss* | -proelf* | -rtems* \ | ||||||
| 	      | -mingw32* | -linux-gnu* | -linux-android* \ | 	      | -mingw32* | -mingw64* | -linux-gnu* | -linux-android* \ | ||||||
| 	      | -linux-newlib* | -linux-uclibc* \ | 	      | -linux-newlib* | -linux-musl* | -linux-uclibc* \ | ||||||
| 	      | -uxpv* | -beos* | -mpeix* | -udk* \ | 	      | -uxpv* | -beos* | -mpeix* | -udk* | -moxiebox* \ | ||||||
| 	      | -interix* | -uwin* | -mks* | -rhapsody* | -darwin* | -opened* \ | 	      | -interix* | -uwin* | -mks* | -rhapsody* | -darwin* | -opened* \ | ||||||
| 	      | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \ | 	      | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \ | ||||||
| 	      | -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* \ | 	      | -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* | -irx* \ | ||||||
| 	      | -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \ | 	      | -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \ | ||||||
| 	      | -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \ | 	      | -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \ | ||||||
| 	      | -powermax* | -dnix* | -nx6 | -nx7 | -sei* | -dragonfly* \ | 	      | -powermax* | -dnix* | -nx6 | -nx7 | -sei* | -dragonfly* \ | ||||||
| 	      | -skyos* | -haiku* | -rdos* | -toppers* | -drops* | -es*) | 	      | -skyos* | -haiku* | -rdos* | -toppers* | -drops* | -es* | -tirtos*) | ||||||
| 	# Remember, each alternative MUST END IN *, to match a version number. | 	# Remember, each alternative MUST END IN *, to match a version number. | ||||||
| 		;; | 		;; | ||||||
| 	-qnx*) | 	-qnx*) | ||||||
| @ -1492,9 +1526,6 @@ case $os in | |||||||
| 	-aros*) | 	-aros*) | ||||||
| 		os=-aros | 		os=-aros | ||||||
| 		;; | 		;; | ||||||
| 	-kaos*) |  | ||||||
| 		os=-kaos |  | ||||||
| 		;; |  | ||||||
| 	-zvmoe) | 	-zvmoe) | ||||||
| 		os=-zvmoe | 		os=-zvmoe | ||||||
| 		;; | 		;; | ||||||
| @ -1543,6 +1574,9 @@ case $basic_machine in | |||||||
| 	c4x-* | tic4x-*) | 	c4x-* | tic4x-*) | ||||||
| 		os=-coff | 		os=-coff | ||||||
| 		;; | 		;; | ||||||
|  | 	c8051-*) | ||||||
|  | 		os=-elf | ||||||
|  | 		;; | ||||||
| 	hexagon-*) | 	hexagon-*) | ||||||
| 		os=-elf | 		os=-elf | ||||||
| 		;; | 		;; | ||||||
|  | |||||||
| @ -1,10 +1,9 @@ | |||||||
| #! /bin/sh | #! /bin/sh | ||||||
| # depcomp - compile a program generating dependencies as side-effects | # depcomp - compile a program generating dependencies as side-effects | ||||||
| 
 | 
 | ||||||
| scriptversion=2006-10-15.18 | scriptversion=2013-05-30.07; # UTC | ||||||
| 
 | 
 | ||||||
| # Copyright (C) 1999, 2000, 2003, 2004, 2005, 2006 Free Software | # Copyright (C) 1999-2013 Free Software Foundation, Inc. | ||||||
| # Foundation, Inc. |  | ||||||
| 
 | 
 | ||||||
| # This program is free software; you can redistribute it and/or modify | # This program is free software; you can redistribute it and/or modify | ||||||
| # it under the terms of the GNU General Public License as published by | # it under the terms of the GNU General Public License as published by | ||||||
| @ -17,9 +16,7 @@ scriptversion=2006-10-15.18 | |||||||
| # GNU General Public License for more details. | # GNU General Public License for more details. | ||||||
| 
 | 
 | ||||||
| # You should have received a copy of the GNU General Public License | # You should have received a copy of the GNU General Public License | ||||||
| # along with this program; if not, write to the Free Software | # along with this program.  If not, see <http://www.gnu.org/licenses/>. | ||||||
| # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA |  | ||||||
| # 02110-1301, USA. |  | ||||||
| 
 | 
 | ||||||
| # As a special exception to the GNU General Public License, if you | # As a special exception to the GNU General Public License, if you | ||||||
| # distribute this file as part of a program that contains a | # distribute this file as part of a program that contains a | ||||||
| @ -30,7 +27,7 @@ scriptversion=2006-10-15.18 | |||||||
| 
 | 
 | ||||||
| case $1 in | case $1 in | ||||||
|   '') |   '') | ||||||
|      echo "$0: No command.  Try \`$0 --help' for more information." 1>&2 |     echo "$0: No command.  Try '$0 --help' for more information." 1>&2 | ||||||
|     exit 1; |     exit 1; | ||||||
|     ;; |     ;; | ||||||
|   -h | --h*) |   -h | --h*) | ||||||
| @ -42,11 +39,11 @@ as side-effects. | |||||||
| 
 | 
 | ||||||
| Environment variables: | Environment variables: | ||||||
|   depmode     Dependency tracking mode. |   depmode     Dependency tracking mode. | ||||||
|   source      Source file read by `PROGRAMS ARGS'. |   source      Source file read by 'PROGRAMS ARGS'. | ||||||
|   object      Object file output by `PROGRAMS ARGS'. |   object      Object file output by 'PROGRAMS ARGS'. | ||||||
|   DEPDIR      directory where to store dependencies. |   DEPDIR      directory where to store dependencies. | ||||||
|   depfile     Dependency file to output. |   depfile     Dependency file to output. | ||||||
|   tmpdepfile  Temporary file to use when outputing dependencies. |   tmpdepfile  Temporary file to use when outputting dependencies. | ||||||
|   libtool     Whether libtool is used (yes/no). |   libtool     Whether libtool is used (yes/no). | ||||||
| 
 | 
 | ||||||
| Report bugs to <bug-automake@gnu.org>. | Report bugs to <bug-automake@gnu.org>. | ||||||
| @ -59,6 +56,66 @@ EOF | |||||||
|     ;; |     ;; | ||||||
| esac | esac | ||||||
| 
 | 
 | ||||||
|  | # Get the directory component of the given path, and save it in the | ||||||
|  | # global variables '$dir'.  Note that this directory component will | ||||||
|  | # be either empty or ending with a '/' character.  This is deliberate. | ||||||
|  | set_dir_from () | ||||||
|  | { | ||||||
|  |   case $1 in | ||||||
|  |     */*) dir=`echo "$1" | sed -e 's|/[^/]*$|/|'`;; | ||||||
|  |       *) dir=;; | ||||||
|  |   esac | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | # Get the suffix-stripped basename of the given path, and save it the | ||||||
|  | # global variable '$base'. | ||||||
|  | set_base_from () | ||||||
|  | { | ||||||
|  |   base=`echo "$1" | sed -e 's|^.*/||' -e 's/\.[^.]*$//'` | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | # If no dependency file was actually created by the compiler invocation, | ||||||
|  | # we still have to create a dummy depfile, to avoid errors with the | ||||||
|  | # Makefile "include basename.Plo" scheme. | ||||||
|  | make_dummy_depfile () | ||||||
|  | { | ||||||
|  |   echo "#dummy" > "$depfile" | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | # Factor out some common post-processing of the generated depfile. | ||||||
|  | # Requires the auxiliary global variable '$tmpdepfile' to be set. | ||||||
|  | aix_post_process_depfile () | ||||||
|  | { | ||||||
|  |   # If the compiler actually managed to produce a dependency file, | ||||||
|  |   # post-process it. | ||||||
|  |   if test -f "$tmpdepfile"; then | ||||||
|  |     # Each line is of the form 'foo.o: dependency.h'. | ||||||
|  |     # Do two passes, one to just change these to | ||||||
|  |     #   $object: dependency.h | ||||||
|  |     # and one to simply output | ||||||
|  |     #   dependency.h: | ||||||
|  |     # which is needed to avoid the deleted-header problem. | ||||||
|  |     { sed -e "s,^.*\.[$lower]*:,$object:," < "$tmpdepfile" | ||||||
|  |       sed -e "s,^.*\.[$lower]*:[$tab ]*,," -e 's,$,:,' < "$tmpdepfile" | ||||||
|  |     } > "$depfile" | ||||||
|  |     rm -f "$tmpdepfile" | ||||||
|  |   else | ||||||
|  |     make_dummy_depfile | ||||||
|  |   fi | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | # A tabulation character. | ||||||
|  | tab='	' | ||||||
|  | # A newline character. | ||||||
|  | nl=' | ||||||
|  | ' | ||||||
|  | # Character ranges might be problematic outside the C locale. | ||||||
|  | # These definitions help. | ||||||
|  | upper=ABCDEFGHIJKLMNOPQRSTUVWXYZ | ||||||
|  | lower=abcdefghijklmnopqrstuvwxyz | ||||||
|  | digits=0123456789 | ||||||
|  | alpha=${upper}${lower} | ||||||
|  | 
 | ||||||
| if test -z "$depmode" || test -z "$source" || test -z "$object"; then | if test -z "$depmode" || test -z "$source" || test -z "$object"; then | ||||||
|   echo "depcomp: Variables source, object and depmode must be set" 1>&2 |   echo "depcomp: Variables source, object and depmode must be set" 1>&2 | ||||||
|   exit 1 |   exit 1 | ||||||
| @ -71,6 +128,9 @@ tmpdepfile=${tmpdepfile-`echo "$depfile" | sed 's/\.\([^.]*\)$/.T\1/'`} | |||||||
| 
 | 
 | ||||||
| rm -f "$tmpdepfile" | rm -f "$tmpdepfile" | ||||||
| 
 | 
 | ||||||
|  | # Avoid interferences from the environment. | ||||||
|  | gccflag= dashmflag= | ||||||
|  | 
 | ||||||
| # Some modes work just like other modes, but use different flags.  We | # Some modes work just like other modes, but use different flags.  We | ||||||
| # parameterize here, but still list the modes in the big case below, | # parameterize here, but still list the modes in the big case below, | ||||||
| # to make depend.m4 easier to write.  Note that we *cannot* use a case | # to make depend.m4 easier to write.  Note that we *cannot* use a case | ||||||
| @ -87,6 +147,29 @@ if test "$depmode" = dashXmstdout; then | |||||||
|   depmode=dashmstdout |   depmode=dashmstdout | ||||||
| fi | fi | ||||||
| 
 | 
 | ||||||
|  | cygpath_u="cygpath -u -f -" | ||||||
|  | if test "$depmode" = msvcmsys; then | ||||||
|  |   # This is just like msvisualcpp but w/o cygpath translation. | ||||||
|  |   # Just convert the backslash-escaped backslashes to single forward | ||||||
|  |   # slashes to satisfy depend.m4 | ||||||
|  |   cygpath_u='sed s,\\\\,/,g' | ||||||
|  |   depmode=msvisualcpp | ||||||
|  | fi | ||||||
|  | 
 | ||||||
|  | if test "$depmode" = msvc7msys; then | ||||||
|  |   # This is just like msvc7 but w/o cygpath translation. | ||||||
|  |   # Just convert the backslash-escaped backslashes to single forward | ||||||
|  |   # slashes to satisfy depend.m4 | ||||||
|  |   cygpath_u='sed s,\\\\,/,g' | ||||||
|  |   depmode=msvc7 | ||||||
|  | fi | ||||||
|  | 
 | ||||||
|  | if test "$depmode" = xlc; then | ||||||
|  |   # IBM C/C++ Compilers xlc/xlC can output gcc-like dependency information. | ||||||
|  |   gccflag=-qmakedep=gcc,-MF | ||||||
|  |   depmode=gcc | ||||||
|  | fi | ||||||
|  | 
 | ||||||
| case "$depmode" in | case "$depmode" in | ||||||
| gcc3) | gcc3) | ||||||
| ## gcc 3 implements dependency tracking that does exactly what | ## gcc 3 implements dependency tracking that does exactly what | ||||||
| @ -107,8 +190,7 @@ gcc3) | |||||||
|   done |   done | ||||||
|   "$@" |   "$@" | ||||||
|   stat=$? |   stat=$? | ||||||
|   if test $stat -eq 0; then : |   if test $stat -ne 0; then | ||||||
|   else |  | ||||||
|     rm -f "$tmpdepfile" |     rm -f "$tmpdepfile" | ||||||
|     exit $stat |     exit $stat | ||||||
|   fi |   fi | ||||||
| @ -116,13 +198,17 @@ gcc3) | |||||||
|   ;; |   ;; | ||||||
| 
 | 
 | ||||||
| gcc) | gcc) | ||||||
|  | ## Note that this doesn't just cater to obsosete pre-3.x GCC compilers. | ||||||
|  | ## but also to in-use compilers like IMB xlc/xlC and the HP C compiler. | ||||||
|  | ## (see the conditional assignment to $gccflag above). | ||||||
| ## There are various ways to get dependency output from gcc.  Here's | ## There are various ways to get dependency output from gcc.  Here's | ||||||
| ## why we pick this rather obscure method: | ## why we pick this rather obscure method: | ||||||
| ## - Don't want to use -MD because we'd like the dependencies to end | ## - Don't want to use -MD because we'd like the dependencies to end | ||||||
| ##   up in a subdir.  Having to rename by hand is ugly. | ##   up in a subdir.  Having to rename by hand is ugly. | ||||||
| ##   (We might end up doing this anyway to support other compilers.) | ##   (We might end up doing this anyway to support other compilers.) | ||||||
| ## - The DEPENDENCIES_OUTPUT environment variable makes gcc act like | ## - The DEPENDENCIES_OUTPUT environment variable makes gcc act like | ||||||
| ##   -MM, not -M (despite what the docs say). | ##   -MM, not -M (despite what the docs say).  Also, it might not be | ||||||
|  | ##   supported by the other compilers which use the 'gcc' depmode. | ||||||
| ## - Using -M directly means running the compiler twice (even worse | ## - Using -M directly means running the compiler twice (even worse | ||||||
| ##   than renaming). | ##   than renaming). | ||||||
|   if test -z "$gccflag"; then |   if test -z "$gccflag"; then | ||||||
| @ -130,31 +216,31 @@ gcc) | |||||||
|   fi |   fi | ||||||
|   "$@" -Wp,"$gccflag$tmpdepfile" |   "$@" -Wp,"$gccflag$tmpdepfile" | ||||||
|   stat=$? |   stat=$? | ||||||
|   if test $stat -eq 0; then : |   if test $stat -ne 0; then | ||||||
|   else |  | ||||||
|     rm -f "$tmpdepfile" |     rm -f "$tmpdepfile" | ||||||
|     exit $stat |     exit $stat | ||||||
|   fi |   fi | ||||||
|   rm -f "$depfile" |   rm -f "$depfile" | ||||||
|   echo "$object : \\" > "$depfile" |   echo "$object : \\" > "$depfile" | ||||||
|   alpha=ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz |   # The second -e expression handles DOS-style file names with drive | ||||||
| ## The second -e expression handles DOS-style file names with drive letters. |   # letters. | ||||||
|   sed -e 's/^[^:]*: / /' \ |   sed -e 's/^[^:]*: / /' \ | ||||||
|       -e 's/^['$alpha']:\/[^:]*: / /' < "$tmpdepfile" >> "$depfile" |       -e 's/^['$alpha']:\/[^:]*: / /' < "$tmpdepfile" >> "$depfile" | ||||||
| ## This next piece of magic avoids the `deleted header file' problem. | ## This next piece of magic avoids the "deleted header file" problem. | ||||||
| ## The problem is that when a header file which appears in a .P file | ## The problem is that when a header file which appears in a .P file | ||||||
| ## is deleted, the dependency causes make to die (because there is | ## is deleted, the dependency causes make to die (because there is | ||||||
| ## typically no way to rebuild the header).  We avoid this by adding | ## typically no way to rebuild the header).  We avoid this by adding | ||||||
| ## dummy dependencies for each header file.  Too bad gcc doesn't do | ## dummy dependencies for each header file.  Too bad gcc doesn't do | ||||||
| ## this for us directly. | ## this for us directly. | ||||||
|   tr ' ' ' | ## Some versions of gcc put a space before the ':'.  On the theory | ||||||
| ' < "$tmpdepfile" | |  | ||||||
| ## Some versions of gcc put a space before the `:'.  On the theory |  | ||||||
| ## that the space means something, we add a space to the output as | ## that the space means something, we add a space to the output as | ||||||
| ## well. | ## well.  hp depmode also adds that space, but also prefixes the VPATH | ||||||
|  | ## to the object.  Take care to not repeat it in the output. | ||||||
| ## Some versions of the HPUX 10.20 sed can't process this invocation | ## Some versions of the HPUX 10.20 sed can't process this invocation | ||||||
| ## correctly.  Breaking it into two sed invocations is a workaround. | ## correctly.  Breaking it into two sed invocations is a workaround. | ||||||
|     sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile" |   tr ' ' "$nl" < "$tmpdepfile" \ | ||||||
|  |     | sed -e 's/^\\$//' -e '/^$/d' -e "s|.*$object$||" -e '/:$/d' \ | ||||||
|  |     | sed -e 's/$/ :/' >> "$depfile" | ||||||
|   rm -f "$tmpdepfile" |   rm -f "$tmpdepfile" | ||||||
|   ;; |   ;; | ||||||
| 
 | 
 | ||||||
| @ -172,8 +258,7 @@ sgi) | |||||||
|     "$@" -MDupdate "$tmpdepfile" |     "$@" -MDupdate "$tmpdepfile" | ||||||
|   fi |   fi | ||||||
|   stat=$? |   stat=$? | ||||||
|   if test $stat -eq 0; then : |   if test $stat -ne 0; then | ||||||
|   else |  | ||||||
|     rm -f "$tmpdepfile" |     rm -f "$tmpdepfile" | ||||||
|     exit $stat |     exit $stat | ||||||
|   fi |   fi | ||||||
| @ -181,99 +266,156 @@ sgi) | |||||||
| 
 | 
 | ||||||
|   if test -f "$tmpdepfile"; then  # yes, the sourcefile depend on other files |   if test -f "$tmpdepfile"; then  # yes, the sourcefile depend on other files | ||||||
|     echo "$object : \\" > "$depfile" |     echo "$object : \\" > "$depfile" | ||||||
| 
 |  | ||||||
|     # Clip off the initial element (the dependent).  Don't try to be |     # Clip off the initial element (the dependent).  Don't try to be | ||||||
|     # clever and replace this with sed code, as IRIX sed won't handle |     # clever and replace this with sed code, as IRIX sed won't handle | ||||||
|     # lines with more than a fixed number of characters (4096 in |     # lines with more than a fixed number of characters (4096 in | ||||||
|     # IRIX 6.2 sed, 8192 in IRIX 6.5).  We also remove comment lines; |     # IRIX 6.2 sed, 8192 in IRIX 6.5).  We also remove comment lines; | ||||||
|     # the IRIX cc adds comments like `#:fec' to the end of the |     # the IRIX cc adds comments like '#:fec' to the end of the | ||||||
|     # dependency line. |     # dependency line. | ||||||
|     tr ' ' ' |     tr ' ' "$nl" < "$tmpdepfile" \ | ||||||
| ' < "$tmpdepfile" \ |       | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' \ | ||||||
|     | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' | \ |       | tr "$nl" ' ' >> "$depfile" | ||||||
|     tr ' |     echo >> "$depfile" | ||||||
| ' ' ' >> $depfile |  | ||||||
|     echo >> $depfile |  | ||||||
| 
 |  | ||||||
|     # The second pass generates a dummy entry for each header file. |     # The second pass generates a dummy entry for each header file. | ||||||
|     tr ' ' ' |     tr ' ' "$nl" < "$tmpdepfile" \ | ||||||
| ' < "$tmpdepfile" \ |  | ||||||
|       | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' -e 's/$/:/' \ |       | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' -e 's/$/:/' \ | ||||||
|    >> $depfile |       >> "$depfile" | ||||||
|   else |   else | ||||||
|     # The sourcefile does not contain any dependencies, so just |     make_dummy_depfile | ||||||
|     # store a dummy comment line, to avoid errors with the Makefile |  | ||||||
|     # "include basename.Plo" scheme. |  | ||||||
|     echo "#dummy" > "$depfile" |  | ||||||
|   fi |   fi | ||||||
|   rm -f "$tmpdepfile" |   rm -f "$tmpdepfile" | ||||||
|   ;; |   ;; | ||||||
| 
 | 
 | ||||||
|  | xlc) | ||||||
|  |   # This case exists only to let depend.m4 do its work.  It works by | ||||||
|  |   # looking at the text of this script.  This case will never be run, | ||||||
|  |   # since it is checked for above. | ||||||
|  |   exit 1 | ||||||
|  |   ;; | ||||||
|  | 
 | ||||||
| aix) | aix) | ||||||
|   # The C for AIX Compiler uses -M and outputs the dependencies |   # The C for AIX Compiler uses -M and outputs the dependencies | ||||||
|   # in a .u file.  In older versions, this file always lives in the |   # in a .u file.  In older versions, this file always lives in the | ||||||
|   # current directory.  Also, the AIX compiler puts `$object:' at the |   # current directory.  Also, the AIX compiler puts '$object:' at the | ||||||
|   # start of each line; $object doesn't have directory information. |   # start of each line; $object doesn't have directory information. | ||||||
|   # Version 6 uses the directory in both cases. |   # Version 6 uses the directory in both cases. | ||||||
|   stripped=`echo "$object" | sed 's/\(.*\)\..*$/\1/'` |   set_dir_from "$object" | ||||||
|   tmpdepfile="$stripped.u" |   set_base_from "$object" | ||||||
|   if test "$libtool" = yes; then |   if test "$libtool" = yes; then | ||||||
|  |     tmpdepfile1=$dir$base.u | ||||||
|  |     tmpdepfile2=$base.u | ||||||
|  |     tmpdepfile3=$dir.libs/$base.u | ||||||
|     "$@" -Wc,-M |     "$@" -Wc,-M | ||||||
|   else |   else | ||||||
|  |     tmpdepfile1=$dir$base.u | ||||||
|  |     tmpdepfile2=$dir$base.u | ||||||
|  |     tmpdepfile3=$dir$base.u | ||||||
|     "$@" -M |     "$@" -M | ||||||
|   fi |   fi | ||||||
|   stat=$? |   stat=$? | ||||||
| 
 |   if test $stat -ne 0; then | ||||||
|   if test -f "$tmpdepfile"; then : |     rm -f "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" | ||||||
|   else |  | ||||||
|     stripped=`echo "$stripped" | sed 's,^.*/,,'` |  | ||||||
|     tmpdepfile="$stripped.u" |  | ||||||
|   fi |  | ||||||
| 
 |  | ||||||
|   if test $stat -eq 0; then : |  | ||||||
|   else |  | ||||||
|     rm -f "$tmpdepfile" |  | ||||||
|     exit $stat |     exit $stat | ||||||
|   fi |   fi | ||||||
| 
 | 
 | ||||||
|   if test -f "$tmpdepfile"; then |   for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" | ||||||
|     outname="$stripped.o" |   do | ||||||
|     # Each line is of the form `foo.o: dependent.h'. |     test -f "$tmpdepfile" && break | ||||||
|     # Do two passes, one to just change these to |   done | ||||||
|     # `$object: dependent.h' and one to simply `dependent.h:'. |   aix_post_process_depfile | ||||||
|     sed -e "s,^$outname:,$object :," < "$tmpdepfile" > "$depfile" |   ;; | ||||||
|     sed -e "s,^$outname: \(.*\)$,\1:," < "$tmpdepfile" >> "$depfile" | 
 | ||||||
|   else | tcc) | ||||||
|     # The sourcefile does not contain any dependencies, so just |   # tcc (Tiny C Compiler) understand '-MD -MF file' since version 0.9.26 | ||||||
|     # store a dummy comment line, to avoid errors with the Makefile |   # FIXME: That version still under development at the moment of writing. | ||||||
|     # "include basename.Plo" scheme. |   #        Make that this statement remains true also for stable, released | ||||||
|     echo "#dummy" > "$depfile" |   #        versions. | ||||||
|  |   # It will wrap lines (doesn't matter whether long or short) with a | ||||||
|  |   # trailing '\', as in: | ||||||
|  |   # | ||||||
|  |   #   foo.o : \ | ||||||
|  |   #    foo.c \ | ||||||
|  |   #    foo.h \ | ||||||
|  |   # | ||||||
|  |   # It will put a trailing '\' even on the last line, and will use leading | ||||||
|  |   # spaces rather than leading tabs (at least since its commit 0394caf7 | ||||||
|  |   # "Emit spaces for -MD"). | ||||||
|  |   "$@" -MD -MF "$tmpdepfile" | ||||||
|  |   stat=$? | ||||||
|  |   if test $stat -ne 0; then | ||||||
|  |     rm -f "$tmpdepfile" | ||||||
|  |     exit $stat | ||||||
|   fi |   fi | ||||||
|  |   rm -f "$depfile" | ||||||
|  |   # Each non-empty line is of the form 'foo.o : \' or ' dep.h \'. | ||||||
|  |   # We have to change lines of the first kind to '$object: \'. | ||||||
|  |   sed -e "s|.*:|$object :|" < "$tmpdepfile" > "$depfile" | ||||||
|  |   # And for each line of the second kind, we have to emit a 'dep.h:' | ||||||
|  |   # dummy dependency, to avoid the deleted-header problem. | ||||||
|  |   sed -n -e 's|^  *\(.*\) *\\$|\1:|p' < "$tmpdepfile" >> "$depfile" | ||||||
|   rm -f "$tmpdepfile" |   rm -f "$tmpdepfile" | ||||||
|   ;; |   ;; | ||||||
| 
 | 
 | ||||||
| icc) | ## The order of this option in the case statement is important, since the | ||||||
|   # Intel's C compiler understands `-MD -MF file'.  However on | ## shell code in configure will try each of these formats in the order | ||||||
|   #    icc -MD -MF foo.d -c -o sub/foo.o sub/foo.c | ## listed in this file.  A plain '-MD' option would be understood by many | ||||||
|   # ICC 7.0 will fill foo.d with something like | ## compilers, so we must ensure this comes after the gcc and icc options. | ||||||
|   #    foo.o: sub/foo.c | pgcc) | ||||||
|   #    foo.o: sub/foo.h |   # Portland's C compiler understands '-MD'. | ||||||
|   # which is wrong.  We want: |   # Will always output deps to 'file.d' where file is the root name of the | ||||||
|   #    sub/foo.o: sub/foo.c |   # source file under compilation, even if file resides in a subdirectory. | ||||||
|   #    sub/foo.o: sub/foo.h |   # The object file name does not affect the name of the '.d' file. | ||||||
|   #    sub/foo.c: |   # pgcc 10.2 will output | ||||||
|   #    sub/foo.h: |  | ||||||
|   # ICC 7.1 will output |  | ||||||
|   #    foo.o: sub/foo.c sub/foo.h |   #    foo.o: sub/foo.c sub/foo.h | ||||||
|   # and will wrap long lines using \ : |   # and will wrap long lines using '\' : | ||||||
|   #    foo.o: sub/foo.c ... \ |   #    foo.o: sub/foo.c ... \ | ||||||
|   #     sub/foo.h ... \ |   #     sub/foo.h ... \ | ||||||
|   #     ... |   #     ... | ||||||
|  |   set_dir_from "$object" | ||||||
|  |   # Use the source, not the object, to determine the base name, since | ||||||
|  |   # that's sadly what pgcc will do too. | ||||||
|  |   set_base_from "$source" | ||||||
|  |   tmpdepfile=$base.d | ||||||
| 
 | 
 | ||||||
|   "$@" -MD -MF "$tmpdepfile" |   # For projects that build the same source file twice into different object | ||||||
|  |   # files, the pgcc approach of using the *source* file root name can cause | ||||||
|  |   # problems in parallel builds.  Use a locking strategy to avoid stomping on | ||||||
|  |   # the same $tmpdepfile. | ||||||
|  |   lockdir=$base.d-lock | ||||||
|  |   trap " | ||||||
|  |     echo '$0: caught signal, cleaning up...' >&2 | ||||||
|  |     rmdir '$lockdir' | ||||||
|  |     exit 1 | ||||||
|  |   " 1 2 13 15 | ||||||
|  |   numtries=100 | ||||||
|  |   i=$numtries | ||||||
|  |   while test $i -gt 0; do | ||||||
|  |     # mkdir is a portable test-and-set. | ||||||
|  |     if mkdir "$lockdir" 2>/dev/null; then | ||||||
|  |       # This process acquired the lock. | ||||||
|  |       "$@" -MD | ||||||
|       stat=$? |       stat=$? | ||||||
|   if test $stat -eq 0; then : |       # Release the lock. | ||||||
|  |       rmdir "$lockdir" | ||||||
|  |       break | ||||||
|     else |     else | ||||||
|  |       # If the lock is being held by a different process, wait | ||||||
|  |       # until the winning process is done or we timeout. | ||||||
|  |       while test -d "$lockdir" && test $i -gt 0; do | ||||||
|  |         sleep 1 | ||||||
|  |         i=`expr $i - 1` | ||||||
|  |       done | ||||||
|  |     fi | ||||||
|  |     i=`expr $i - 1` | ||||||
|  |   done | ||||||
|  |   trap - 1 2 13 15 | ||||||
|  |   if test $i -le 0; then | ||||||
|  |     echo "$0: failed to acquire lock after $numtries attempts" >&2 | ||||||
|  |     echo "$0: check lockdir '$lockdir'" >&2 | ||||||
|  |     exit 1 | ||||||
|  |   fi | ||||||
|  | 
 | ||||||
|  |   if test $stat -ne 0; then | ||||||
|     rm -f "$tmpdepfile" |     rm -f "$tmpdepfile" | ||||||
|     exit $stat |     exit $stat | ||||||
|   fi |   fi | ||||||
| @ -285,8 +427,8 @@ icc) | |||||||
|   sed "s,^[^:]*:,$object :," < "$tmpdepfile" > "$depfile" |   sed "s,^[^:]*:,$object :," < "$tmpdepfile" > "$depfile" | ||||||
|   # Some versions of the HPUX 10.20 sed can't process this invocation |   # Some versions of the HPUX 10.20 sed can't process this invocation | ||||||
|   # correctly.  Breaking it into two sed invocations is a workaround. |   # correctly.  Breaking it into two sed invocations is a workaround. | ||||||
|   sed 's,^[^:]*: \(.*\)$,\1,;s/^\\$//;/^$/d;/:$/d' < "$tmpdepfile" | |   sed 's,^[^:]*: \(.*\)$,\1,;s/^\\$//;/^$/d;/:$/d' < "$tmpdepfile" \ | ||||||
|     sed -e 's/$/ :/' >> "$depfile" |     | sed -e 's/$/ :/' >> "$depfile" | ||||||
|   rm -f "$tmpdepfile" |   rm -f "$tmpdepfile" | ||||||
|   ;; |   ;; | ||||||
| 
 | 
 | ||||||
| @ -297,9 +439,8 @@ hp2) | |||||||
|   # 'foo.d', which lands next to the object file, wherever that |   # 'foo.d', which lands next to the object file, wherever that | ||||||
|   # happens to be. |   # happens to be. | ||||||
|   # Much of this is similar to the tru64 case; see comments there. |   # Much of this is similar to the tru64 case; see comments there. | ||||||
|   dir=`echo "$object" | sed -e 's|/[^/]*$|/|'` |   set_dir_from  "$object" | ||||||
|   test "x$dir" = "x$object" && dir= |   set_base_from "$object" | ||||||
|   base=`echo "$object" | sed -e 's|^.*/||' -e 's/\.o$//' -e 's/\.lo$//'` |  | ||||||
|   if test "$libtool" = yes; then |   if test "$libtool" = yes; then | ||||||
|     tmpdepfile1=$dir$base.d |     tmpdepfile1=$dir$base.d | ||||||
|     tmpdepfile2=$dir.libs/$base.d |     tmpdepfile2=$dir.libs/$base.d | ||||||
| @ -310,8 +451,7 @@ hp2) | |||||||
|     "$@" +Maked |     "$@" +Maked | ||||||
|   fi |   fi | ||||||
|   stat=$? |   stat=$? | ||||||
|   if test $stat -eq 0; then : |   if test $stat -ne 0; then | ||||||
|   else |  | ||||||
|      rm -f "$tmpdepfile1" "$tmpdepfile2" |      rm -f "$tmpdepfile1" "$tmpdepfile2" | ||||||
|      exit $stat |      exit $stat | ||||||
|   fi |   fi | ||||||
| @ -321,71 +461,106 @@ hp2) | |||||||
|     test -f "$tmpdepfile" && break |     test -f "$tmpdepfile" && break | ||||||
|   done |   done | ||||||
|   if test -f "$tmpdepfile"; then |   if test -f "$tmpdepfile"; then | ||||||
|     sed -e "s,^.*\.[a-z]*:,$object:," "$tmpdepfile" > "$depfile" |     sed -e "s,^.*\.[$lower]*:,$object:," "$tmpdepfile" > "$depfile" | ||||||
|     # Add `dependent.h:' lines. |     # Add 'dependent.h:' lines. | ||||||
|     sed -ne '2,${; s/^ *//; s/ \\*$//; s/$/:/; p;}' "$tmpdepfile" >> "$depfile" |     sed -ne '2,${ | ||||||
|  |                s/^ *// | ||||||
|  |                s/ \\*$// | ||||||
|  |                s/$/:/ | ||||||
|  |                p | ||||||
|  |              }' "$tmpdepfile" >> "$depfile" | ||||||
|   else |   else | ||||||
|     echo "#dummy" > "$depfile" |     make_dummy_depfile | ||||||
|   fi |   fi | ||||||
|   rm -f "$tmpdepfile" "$tmpdepfile2" |   rm -f "$tmpdepfile" "$tmpdepfile2" | ||||||
|   ;; |   ;; | ||||||
| 
 | 
 | ||||||
| tru64) | tru64) | ||||||
|   # The Tru64 compiler uses -MD to generate dependencies as a side |   # The Tru64 compiler uses -MD to generate dependencies as a side | ||||||
|    # effect.  `cc -MD -o foo.o ...' puts the dependencies into `foo.o.d'. |   # effect.  'cc -MD -o foo.o ...' puts the dependencies into 'foo.o.d'. | ||||||
|   # At least on Alpha/Redhat 6.1, Compaq CCC V6.2-504 seems to put |   # At least on Alpha/Redhat 6.1, Compaq CCC V6.2-504 seems to put | ||||||
|    # dependencies in `foo.d' instead, so we check for that too. |   # dependencies in 'foo.d' instead, so we check for that too. | ||||||
|   # Subdirectories are respected. |   # Subdirectories are respected. | ||||||
|    dir=`echo "$object" | sed -e 's|/[^/]*$|/|'` |   set_dir_from  "$object" | ||||||
|    test "x$dir" = "x$object" && dir= |   set_base_from "$object" | ||||||
|    base=`echo "$object" | sed -e 's|^.*/||' -e 's/\.o$//' -e 's/\.lo$//'` |  | ||||||
| 
 | 
 | ||||||
|   if test "$libtool" = yes; then |   if test "$libtool" = yes; then | ||||||
|       # With Tru64 cc, shared objects can also be used to make a |     # Libtool generates 2 separate objects for the 2 libraries.  These | ||||||
|       # static library.  This mechanism is used in libtool 1.4 series to |     # two compilations output dependencies in $dir.libs/$base.o.d and | ||||||
|       # handle both shared and static libraries in a single compilation. |  | ||||||
|       # With libtool 1.4, dependencies were output in $dir.libs/$base.lo.d. |  | ||||||
|       # |  | ||||||
|       # With libtool 1.5 this exception was removed, and libtool now |  | ||||||
|       # generates 2 separate objects for the 2 libraries.  These two |  | ||||||
|       # compilations output dependencies in $dir.libs/$base.o.d and |  | ||||||
|     # in $dir$base.o.d.  We have to check for both files, because |     # in $dir$base.o.d.  We have to check for both files, because | ||||||
|     # one of the two compilations can be disabled.  We should prefer |     # one of the two compilations can be disabled.  We should prefer | ||||||
|     # $dir$base.o.d over $dir.libs/$base.o.d because the latter is |     # $dir$base.o.d over $dir.libs/$base.o.d because the latter is | ||||||
|     # automatically cleaned when .libs/ is deleted, while ignoring |     # automatically cleaned when .libs/ is deleted, while ignoring | ||||||
|     # the former would cause a distcleancheck panic. |     # the former would cause a distcleancheck panic. | ||||||
|       tmpdepfile1=$dir.libs/$base.lo.d   # libtool 1.4 |     tmpdepfile1=$dir$base.o.d          # libtool 1.5 | ||||||
|       tmpdepfile2=$dir$base.o.d          # libtool 1.5 |     tmpdepfile2=$dir.libs/$base.o.d    # Likewise. | ||||||
|       tmpdepfile3=$dir.libs/$base.o.d    # libtool 1.5 |     tmpdepfile3=$dir.libs/$base.d      # Compaq CCC V6.2-504 | ||||||
|       tmpdepfile4=$dir.libs/$base.d      # Compaq CCC V6.2-504 |  | ||||||
|     "$@" -Wc,-MD |     "$@" -Wc,-MD | ||||||
|   else |   else | ||||||
|       tmpdepfile1=$dir$base.o.d |     tmpdepfile1=$dir$base.d | ||||||
|     tmpdepfile2=$dir$base.d |     tmpdepfile2=$dir$base.d | ||||||
|     tmpdepfile3=$dir$base.d |     tmpdepfile3=$dir$base.d | ||||||
|       tmpdepfile4=$dir$base.d |  | ||||||
|     "$@" -MD |     "$@" -MD | ||||||
|   fi |   fi | ||||||
| 
 | 
 | ||||||
|   stat=$? |   stat=$? | ||||||
|    if test $stat -eq 0; then : |   if test $stat -ne 0; then | ||||||
|    else |     rm -f "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" | ||||||
|       rm -f "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" "$tmpdepfile4" |  | ||||||
|     exit $stat |     exit $stat | ||||||
|   fi |   fi | ||||||
| 
 | 
 | ||||||
|    for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" "$tmpdepfile4" |   for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" | ||||||
|   do |   do | ||||||
|     test -f "$tmpdepfile" && break |     test -f "$tmpdepfile" && break | ||||||
|   done |   done | ||||||
|    if test -f "$tmpdepfile"; then |   # Same post-processing that is required for AIX mode. | ||||||
|       sed -e "s,^.*\.[a-z]*:,$object:," < "$tmpdepfile" > "$depfile" |   aix_post_process_depfile | ||||||
|       # That's a tab and a space in the []. |   ;; | ||||||
|       sed -e 's,^.*\.[a-z]*:[	 ]*,,' -e 's,$,:,' < "$tmpdepfile" >> "$depfile" | 
 | ||||||
|  | msvc7) | ||||||
|  |   if test "$libtool" = yes; then | ||||||
|  |     showIncludes=-Wc,-showIncludes | ||||||
|   else |   else | ||||||
|       echo "#dummy" > "$depfile" |     showIncludes=-showIncludes | ||||||
|   fi |   fi | ||||||
|  |   "$@" $showIncludes > "$tmpdepfile" | ||||||
|  |   stat=$? | ||||||
|  |   grep -v '^Note: including file: ' "$tmpdepfile" | ||||||
|  |   if test $stat -ne 0; then | ||||||
|     rm -f "$tmpdepfile" |     rm -f "$tmpdepfile" | ||||||
|  |     exit $stat | ||||||
|  |   fi | ||||||
|  |   rm -f "$depfile" | ||||||
|  |   echo "$object : \\" > "$depfile" | ||||||
|  |   # The first sed program below extracts the file names and escapes | ||||||
|  |   # backslashes for cygpath.  The second sed program outputs the file | ||||||
|  |   # name when reading, but also accumulates all include files in the | ||||||
|  |   # hold buffer in order to output them again at the end.  This only | ||||||
|  |   # works with sed implementations that can handle large buffers. | ||||||
|  |   sed < "$tmpdepfile" -n ' | ||||||
|  | /^Note: including file:  *\(.*\)/ { | ||||||
|  |   s//\1/ | ||||||
|  |   s/\\/\\\\/g | ||||||
|  |   p | ||||||
|  | }' | $cygpath_u | sort -u | sed -n ' | ||||||
|  | s/ /\\ /g | ||||||
|  | s/\(.*\)/'"$tab"'\1 \\/p | ||||||
|  | s/.\(.*\) \\/\1:/ | ||||||
|  | H | ||||||
|  | $ { | ||||||
|  |   s/.*/'"$tab"'/ | ||||||
|  |   G | ||||||
|  |   p | ||||||
|  | }' >> "$depfile" | ||||||
|  |   echo >> "$depfile" # make sure the fragment doesn't end with a backslash | ||||||
|  |   rm -f "$tmpdepfile" | ||||||
|  |   ;; | ||||||
|  | 
 | ||||||
|  | msvc7msys) | ||||||
|  |   # This case exists only to let depend.m4 do its work.  It works by | ||||||
|  |   # looking at the text of this script.  This case will never be run, | ||||||
|  |   # since it is checked for above. | ||||||
|  |   exit 1 | ||||||
|   ;; |   ;; | ||||||
| 
 | 
 | ||||||
| #nosideeffect) | #nosideeffect) | ||||||
| @ -399,13 +574,13 @@ dashmstdout) | |||||||
| 
 | 
 | ||||||
|   # Remove the call to Libtool. |   # Remove the call to Libtool. | ||||||
|   if test "$libtool" = yes; then |   if test "$libtool" = yes; then | ||||||
|     while test $1 != '--mode=compile'; do |     while test "X$1" != 'X--mode=compile'; do | ||||||
|       shift |       shift | ||||||
|     done |     done | ||||||
|     shift |     shift | ||||||
|   fi |   fi | ||||||
| 
 | 
 | ||||||
|   # Remove `-o $object'. |   # Remove '-o $object'. | ||||||
|   IFS=" " |   IFS=" " | ||||||
|   for arg |   for arg | ||||||
|   do |   do | ||||||
| @ -425,18 +600,18 @@ dashmstdout) | |||||||
|   done |   done | ||||||
| 
 | 
 | ||||||
|   test -z "$dashmflag" && dashmflag=-M |   test -z "$dashmflag" && dashmflag=-M | ||||||
|   # Require at least two characters before searching for `:' |   # Require at least two characters before searching for ':' | ||||||
|   # in the target name.  This is to cope with DOS-style filenames: |   # in the target name.  This is to cope with DOS-style filenames: | ||||||
|   # a dependency such as `c:/foo/bar' could be seen as target `c' otherwise. |   # a dependency such as 'c:/foo/bar' could be seen as target 'c' otherwise. | ||||||
|   "$@" $dashmflag | |   "$@" $dashmflag | | ||||||
|     sed 's:^[  ]*[^: ][^:][^:]*\:[    ]*:'"$object"'\: :' > "$tmpdepfile" |     sed "s|^[$tab ]*[^:$tab ][^:][^:]*:[$tab ]*|$object: |" > "$tmpdepfile" | ||||||
|   rm -f "$depfile" |   rm -f "$depfile" | ||||||
|   cat < "$tmpdepfile" > "$depfile" |   cat < "$tmpdepfile" > "$depfile" | ||||||
|   tr ' ' ' |   # Some versions of the HPUX 10.20 sed can't process this sed invocation | ||||||
| ' < "$tmpdepfile" | \ |   # correctly.  Breaking it into two sed invocations is a workaround. | ||||||
| ## Some versions of the HPUX 10.20 sed can't process this invocation |   tr ' ' "$nl" < "$tmpdepfile" \ | ||||||
| ## correctly.  Breaking it into two sed invocations is a workaround. |     | sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' \ | ||||||
|     sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile" |     | sed -e 's/$/ :/' >> "$depfile" | ||||||
|   rm -f "$tmpdepfile" |   rm -f "$tmpdepfile" | ||||||
|   ;; |   ;; | ||||||
| 
 | 
 | ||||||
| @ -450,41 +625,51 @@ makedepend) | |||||||
|   "$@" || exit $? |   "$@" || exit $? | ||||||
|   # Remove any Libtool call |   # Remove any Libtool call | ||||||
|   if test "$libtool" = yes; then |   if test "$libtool" = yes; then | ||||||
|     while test $1 != '--mode=compile'; do |     while test "X$1" != 'X--mode=compile'; do | ||||||
|       shift |       shift | ||||||
|     done |     done | ||||||
|     shift |     shift | ||||||
|   fi |   fi | ||||||
|   # X makedepend |   # X makedepend | ||||||
|   shift |   shift | ||||||
|   cleared=no |   cleared=no eat=no | ||||||
|   for arg in "$@"; do |   for arg | ||||||
|  |   do | ||||||
|     case $cleared in |     case $cleared in | ||||||
|     no) |     no) | ||||||
|       set ""; shift |       set ""; shift | ||||||
|       cleared=yes ;; |       cleared=yes ;; | ||||||
|     esac |     esac | ||||||
|  |     if test $eat = yes; then | ||||||
|  |       eat=no | ||||||
|  |       continue | ||||||
|  |     fi | ||||||
|     case "$arg" in |     case "$arg" in | ||||||
|     -D*|-I*) |     -D*|-I*) | ||||||
|       set fnord "$@" "$arg"; shift ;; |       set fnord "$@" "$arg"; shift ;; | ||||||
|     # Strip any option that makedepend may not understand.  Remove |     # Strip any option that makedepend may not understand.  Remove | ||||||
|     # the object too, otherwise makedepend will parse it as a source file. |     # the object too, otherwise makedepend will parse it as a source file. | ||||||
|  |     -arch) | ||||||
|  |       eat=yes ;; | ||||||
|     -*|$object) |     -*|$object) | ||||||
|       ;; |       ;; | ||||||
|     *) |     *) | ||||||
|       set fnord "$@" "$arg"; shift ;; |       set fnord "$@" "$arg"; shift ;; | ||||||
|     esac |     esac | ||||||
|   done |   done | ||||||
|   obj_suffix="`echo $object | sed 's/^.*\././'`" |   obj_suffix=`echo "$object" | sed 's/^.*\././'` | ||||||
|   touch "$tmpdepfile" |   touch "$tmpdepfile" | ||||||
|   ${MAKEDEPEND-makedepend} -o"$obj_suffix" -f"$tmpdepfile" "$@" |   ${MAKEDEPEND-makedepend} -o"$obj_suffix" -f"$tmpdepfile" "$@" | ||||||
|   rm -f "$depfile" |   rm -f "$depfile" | ||||||
|   cat < "$tmpdepfile" > "$depfile" |   # makedepend may prepend the VPATH from the source file name to the object. | ||||||
|   sed '1,2d' "$tmpdepfile" | tr ' ' ' |   # No need to regex-escape $object, excess matching of '.' is harmless. | ||||||
| ' | \ |   sed "s|^.*\($object *:\)|\1|" "$tmpdepfile" > "$depfile" | ||||||
| ## Some versions of the HPUX 10.20 sed can't process this invocation |   # Some versions of the HPUX 10.20 sed can't process the last invocation | ||||||
| ## correctly.  Breaking it into two sed invocations is a workaround. |   # correctly.  Breaking it into two sed invocations is a workaround. | ||||||
|     sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile" |   sed '1,2d' "$tmpdepfile" \ | ||||||
|  |     | tr ' ' "$nl" \ | ||||||
|  |     | sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' \ | ||||||
|  |     | sed -e 's/$/ :/' >> "$depfile" | ||||||
|   rm -f "$tmpdepfile" "$tmpdepfile".bak |   rm -f "$tmpdepfile" "$tmpdepfile".bak | ||||||
|   ;; |   ;; | ||||||
| 
 | 
 | ||||||
| @ -495,13 +680,13 @@ cpp) | |||||||
| 
 | 
 | ||||||
|   # Remove the call to Libtool. |   # Remove the call to Libtool. | ||||||
|   if test "$libtool" = yes; then |   if test "$libtool" = yes; then | ||||||
|     while test $1 != '--mode=compile'; do |     while test "X$1" != 'X--mode=compile'; do | ||||||
|       shift |       shift | ||||||
|     done |     done | ||||||
|     shift |     shift | ||||||
|   fi |   fi | ||||||
| 
 | 
 | ||||||
|   # Remove `-o $object'. |   # Remove '-o $object'. | ||||||
|   IFS=" " |   IFS=" " | ||||||
|   for arg |   for arg | ||||||
|   do |   do | ||||||
| @ -520,10 +705,10 @@ cpp) | |||||||
|     esac |     esac | ||||||
|   done |   done | ||||||
| 
 | 
 | ||||||
|   "$@" -E | |   "$@" -E \ | ||||||
|     sed -n -e '/^# [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' \ |     | sed -n -e '/^# [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' \ | ||||||
|        -e '/^#line [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' | |              -e '/^#line [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' \ | ||||||
|     sed '$ s: \\$::' > "$tmpdepfile" |     | sed '$ s: \\$::' > "$tmpdepfile" | ||||||
|   rm -f "$depfile" |   rm -f "$depfile" | ||||||
|   echo "$object : \\" > "$depfile" |   echo "$object : \\" > "$depfile" | ||||||
|   cat < "$tmpdepfile" >> "$depfile" |   cat < "$tmpdepfile" >> "$depfile" | ||||||
| @ -533,13 +718,27 @@ cpp) | |||||||
| 
 | 
 | ||||||
| msvisualcpp) | msvisualcpp) | ||||||
|   # Important note: in order to support this mode, a compiler *must* |   # Important note: in order to support this mode, a compiler *must* | ||||||
|   # always write the preprocessed file to stdout, regardless of -o, |   # always write the preprocessed file to stdout. | ||||||
|   # because we must use -o when running libtool. |  | ||||||
|   "$@" || exit $? |   "$@" || exit $? | ||||||
|  | 
 | ||||||
|  |   # Remove the call to Libtool. | ||||||
|  |   if test "$libtool" = yes; then | ||||||
|  |     while test "X$1" != 'X--mode=compile'; do | ||||||
|  |       shift | ||||||
|  |     done | ||||||
|  |     shift | ||||||
|  |   fi | ||||||
|  | 
 | ||||||
|   IFS=" " |   IFS=" " | ||||||
|   for arg |   for arg | ||||||
|   do |   do | ||||||
|     case "$arg" in |     case "$arg" in | ||||||
|  |     -o) | ||||||
|  |       shift | ||||||
|  |       ;; | ||||||
|  |     $object) | ||||||
|  |       shift | ||||||
|  |       ;; | ||||||
|     "-Gm"|"/Gm"|"-Gi"|"/Gi"|"-ZI"|"/ZI") |     "-Gm"|"/Gm"|"-Gi"|"/Gi"|"-ZI"|"/ZI") | ||||||
|         set fnord "$@" |         set fnord "$@" | ||||||
|         shift |         shift | ||||||
| @ -552,16 +751,23 @@ msvisualcpp) | |||||||
|         ;; |         ;; | ||||||
|     esac |     esac | ||||||
|   done |   done | ||||||
|   "$@" -E | |   "$@" -E 2>/dev/null | | ||||||
|   sed -n '/^#line [0-9][0-9]* "\([^"]*\)"/ s::echo "`cygpath -u \\"\1\\"`":p' | sort | uniq > "$tmpdepfile" |   sed -n '/^#line [0-9][0-9]* "\([^"]*\)"/ s::\1:p' | $cygpath_u | sort -u > "$tmpdepfile" | ||||||
|   rm -f "$depfile" |   rm -f "$depfile" | ||||||
|   echo "$object : \\" > "$depfile" |   echo "$object : \\" > "$depfile" | ||||||
|   . "$tmpdepfile" | sed 's% %\\ %g' | sed -n '/^\(.*\)$/ s::	\1 \\:p' >> "$depfile" |   sed < "$tmpdepfile" -n -e 's% %\\ %g' -e '/^\(.*\)$/ s::'"$tab"'\1 \\:p' >> "$depfile" | ||||||
|   echo "	" >> "$depfile" |   echo "$tab" >> "$depfile" | ||||||
|   . "$tmpdepfile" | sed 's% %\\ %g' | sed -n '/^\(.*\)$/ s::\1\::p' >> "$depfile" |   sed < "$tmpdepfile" -n -e 's% %\\ %g' -e '/^\(.*\)$/ s::\1\::p' >> "$depfile" | ||||||
|   rm -f "$tmpdepfile" |   rm -f "$tmpdepfile" | ||||||
|   ;; |   ;; | ||||||
| 
 | 
 | ||||||
|  | msvcmsys) | ||||||
|  |   # This case exists only to let depend.m4 do its work.  It works by | ||||||
|  |   # looking at the text of this script.  This case will never be run, | ||||||
|  |   # since it is checked for above. | ||||||
|  |   exit 1 | ||||||
|  |   ;; | ||||||
|  | 
 | ||||||
| none) | none) | ||||||
|   exec "$@" |   exec "$@" | ||||||
|   ;; |   ;; | ||||||
| @ -580,5 +786,6 @@ exit 0 | |||||||
| # eval: (add-hook 'write-file-hooks 'time-stamp) | # eval: (add-hook 'write-file-hooks 'time-stamp) | ||||||
| # time-stamp-start: "scriptversion=" | # time-stamp-start: "scriptversion=" | ||||||
| # time-stamp-format: "%:y-%02m-%02d.%02H" | # time-stamp-format: "%:y-%02m-%02d.%02H" | ||||||
| # time-stamp-end: "$" | # time-stamp-time-zone: "UTC" | ||||||
|  | # time-stamp-end: "; # UTC" | ||||||
| # End: | # End: | ||||||
|  | |||||||
| @ -1,7 +1,7 @@ | |||||||
| #!/bin/sh | #!/bin/sh | ||||||
| # install - install a program, script, or datafile | # install - install a program, script, or datafile | ||||||
| 
 | 
 | ||||||
| scriptversion=2006-10-14.15 | scriptversion=2011-11-20.07; # UTC | ||||||
| 
 | 
 | ||||||
| # This originates from X11R5 (mit/util/scripts/install.sh), which was | # This originates from X11R5 (mit/util/scripts/install.sh), which was | ||||||
| # later released in X11R6 (xc/config/util/install.sh) with the | # later released in X11R6 (xc/config/util/install.sh) with the | ||||||
| @ -35,7 +35,7 @@ scriptversion=2006-10-14.15 | |||||||
| # FSF changes to this file are in the public domain. | # FSF changes to this file are in the public domain. | ||||||
| # | # | ||||||
| # Calling this script install-sh is preferred over install.sh, to prevent | # Calling this script install-sh is preferred over install.sh, to prevent | ||||||
| # `make' implicit rules from creating a file called install from it | # 'make' implicit rules from creating a file called install from it | ||||||
| # when there is no Makefile. | # when there is no Makefile. | ||||||
| # | # | ||||||
| # This script is compatible with the BSD install script, but was written | # This script is compatible with the BSD install script, but was written | ||||||
| @ -48,7 +48,7 @@ IFS=" ""	$nl" | |||||||
| # set DOITPROG to echo to test this script | # set DOITPROG to echo to test this script | ||||||
| 
 | 
 | ||||||
| # Don't use :- since 4.3BSD and earlier shells don't like it. | # Don't use :- since 4.3BSD and earlier shells don't like it. | ||||||
| doit="${DOITPROG-}" | doit=${DOITPROG-} | ||||||
| if test -z "$doit"; then | if test -z "$doit"; then | ||||||
|   doit_exec=exec |   doit_exec=exec | ||||||
| else | else | ||||||
| @ -58,34 +58,49 @@ fi | |||||||
| # Put in absolute file names if you don't have them in your path; | # Put in absolute file names if you don't have them in your path; | ||||||
| # or use environment vars. | # or use environment vars. | ||||||
| 
 | 
 | ||||||
| mvprog="${MVPROG-mv}" | chgrpprog=${CHGRPPROG-chgrp} | ||||||
| cpprog="${CPPROG-cp}" | chmodprog=${CHMODPROG-chmod} | ||||||
| chmodprog="${CHMODPROG-chmod}" | chownprog=${CHOWNPROG-chown} | ||||||
| chownprog="${CHOWNPROG-chown}" | cmpprog=${CMPPROG-cmp} | ||||||
| chgrpprog="${CHGRPPROG-chgrp}" | cpprog=${CPPROG-cp} | ||||||
| stripprog="${STRIPPROG-strip}" | mkdirprog=${MKDIRPROG-mkdir} | ||||||
| rmprog="${RMPROG-rm}" | mvprog=${MVPROG-mv} | ||||||
| mkdirprog="${MKDIRPROG-mkdir}" | rmprog=${RMPROG-rm} | ||||||
|  | stripprog=${STRIPPROG-strip} | ||||||
| 
 | 
 | ||||||
|  | posix_glob='?' | ||||||
|  | initialize_posix_glob=' | ||||||
|  |   test "$posix_glob" != "?" || { | ||||||
|  |     if (set -f) 2>/dev/null; then | ||||||
|       posix_glob= |       posix_glob= | ||||||
|  |     else | ||||||
|  |       posix_glob=: | ||||||
|  |     fi | ||||||
|  |   } | ||||||
|  | ' | ||||||
|  | 
 | ||||||
| posix_mkdir= | posix_mkdir= | ||||||
| 
 | 
 | ||||||
| # Desired mode of installed file. | # Desired mode of installed file. | ||||||
| mode=0755 | mode=0755 | ||||||
| 
 | 
 | ||||||
|  | chgrpcmd= | ||||||
| chmodcmd=$chmodprog | chmodcmd=$chmodprog | ||||||
| chowncmd= | chowncmd= | ||||||
| chgrpcmd= | mvcmd=$mvprog | ||||||
| stripcmd= |  | ||||||
| rmcmd="$rmprog -f" | rmcmd="$rmprog -f" | ||||||
| mvcmd="$mvprog" | stripcmd= | ||||||
|  | 
 | ||||||
| src= | src= | ||||||
| dst= | dst= | ||||||
| dir_arg= | dir_arg= | ||||||
| dstarg= | dst_arg= | ||||||
|  | 
 | ||||||
|  | copy_on_change=false | ||||||
| no_target_directory= | no_target_directory= | ||||||
| 
 | 
 | ||||||
| usage="Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE | usage="\ | ||||||
|  | Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE | ||||||
|    or: $0 [OPTION]... SRCFILES... DIRECTORY |    or: $0 [OPTION]... SRCFILES... DIRECTORY | ||||||
|    or: $0 [OPTION]... -t DIRECTORY SRCFILES... |    or: $0 [OPTION]... -t DIRECTORY SRCFILES... | ||||||
|    or: $0 [OPTION]... -d DIRECTORIES... |    or: $0 [OPTION]... -d DIRECTORIES... | ||||||
| @ -95,7 +110,11 @@ In the 2nd and 3rd, copy all SRCFILES to DIRECTORY. | |||||||
| In the 4th, create DIRECTORIES. | In the 4th, create DIRECTORIES. | ||||||
| 
 | 
 | ||||||
| Options: | Options: | ||||||
|  |      --help     display this help and exit. | ||||||
|  |      --version  display version info and exit. | ||||||
|  | 
 | ||||||
|   -c            (ignored) |   -c            (ignored) | ||||||
|  |   -C            install only if different (preserve the last data modification time) | ||||||
|   -d            create directories instead of installing files. |   -d            create directories instead of installing files. | ||||||
|   -g GROUP      $chgrpprog installed files to GROUP. |   -g GROUP      $chgrpprog installed files to GROUP. | ||||||
|   -m MODE       $chmodprog installed files to MODE. |   -m MODE       $chmodprog installed files to MODE. | ||||||
| @ -103,57 +122,47 @@ Options: | |||||||
|   -s            $stripprog installed files. |   -s            $stripprog installed files. | ||||||
|   -t DIRECTORY  install into DIRECTORY. |   -t DIRECTORY  install into DIRECTORY. | ||||||
|   -T            report an error if DSTFILE is a directory. |   -T            report an error if DSTFILE is a directory. | ||||||
| --help     display this help and exit. |  | ||||||
| --version  display version info and exit. |  | ||||||
| 
 | 
 | ||||||
| Environment variables override the default commands: | Environment variables override the default commands: | ||||||
|   CHGRPPROG CHMODPROG CHOWNPROG CPPROG MKDIRPROG MVPROG RMPROG STRIPPROG |   CHGRPPROG CHMODPROG CHOWNPROG CMPPROG CPPROG MKDIRPROG MVPROG | ||||||
|  |   RMPROG STRIPPROG | ||||||
| " | " | ||||||
| 
 | 
 | ||||||
| while test $# -ne 0; do | while test $# -ne 0; do | ||||||
|   case $1 in |   case $1 in | ||||||
|     -c) shift |     -c) ;; | ||||||
|         continue;; |  | ||||||
| 
 | 
 | ||||||
|     -d) dir_arg=true |     -C) copy_on_change=true;; | ||||||
|         shift | 
 | ||||||
|         continue;; |     -d) dir_arg=true;; | ||||||
| 
 | 
 | ||||||
|     -g) chgrpcmd="$chgrpprog $2" |     -g) chgrpcmd="$chgrpprog $2" | ||||||
|         shift | 	shift;; | ||||||
|         shift |  | ||||||
|         continue;; |  | ||||||
| 
 | 
 | ||||||
|     --help) echo "$usage"; exit $?;; |     --help) echo "$usage"; exit $?;; | ||||||
| 
 | 
 | ||||||
|     -m) mode=$2 |     -m) mode=$2 | ||||||
|         shift |  | ||||||
|         shift |  | ||||||
| 	case $mode in | 	case $mode in | ||||||
| 	  *' '* | *'	'* | *' | 	  *' '* | *'	'* | *' | ||||||
| '*	  | *'*'* | *'?'* | *'['*) | '*	  | *'*'* | *'?'* | *'['*) | ||||||
| 	    echo "$0: invalid mode: $mode" >&2 | 	    echo "$0: invalid mode: $mode" >&2 | ||||||
| 	    exit 1;; | 	    exit 1;; | ||||||
| 	esac | 	esac | ||||||
|         continue;; | 	shift;; | ||||||
| 
 | 
 | ||||||
|     -o) chowncmd="$chownprog $2" |     -o) chowncmd="$chownprog $2" | ||||||
|         shift | 	shift;; | ||||||
|         shift |  | ||||||
|         continue;; |  | ||||||
| 
 | 
 | ||||||
|     -s) stripcmd=$stripprog |     -s) stripcmd=$stripprog;; | ||||||
|         shift |  | ||||||
|         continue;; |  | ||||||
| 
 | 
 | ||||||
|     -t) dstarg=$2 |     -t) dst_arg=$2 | ||||||
| 	shift | 	# Protect names problematic for 'test' and other utilities. | ||||||
| 	shift | 	case $dst_arg in | ||||||
| 	continue;; | 	  -* | [=\(\)!]) dst_arg=./$dst_arg;; | ||||||
|  | 	esac | ||||||
|  | 	shift;; | ||||||
| 
 | 
 | ||||||
|     -T) no_target_directory=true |     -T) no_target_directory=true;; | ||||||
| 	shift |  | ||||||
| 	continue;; |  | ||||||
| 
 | 
 | ||||||
|     --version) echo "$0 $scriptversion"; exit $?;; |     --version) echo "$0 $scriptversion"; exit $?;; | ||||||
| 
 | 
 | ||||||
| @ -165,21 +174,26 @@ while test $# -ne 0; do | |||||||
| 
 | 
 | ||||||
|     *)  break;; |     *)  break;; | ||||||
|   esac |   esac | ||||||
|  |   shift | ||||||
| done | done | ||||||
| 
 | 
 | ||||||
| if test $# -ne 0 && test -z "$dir_arg$dstarg"; then | if test $# -ne 0 && test -z "$dir_arg$dst_arg"; then | ||||||
|   # When -d is used, all remaining arguments are directories to create. |   # When -d is used, all remaining arguments are directories to create. | ||||||
|   # When -t is used, the destination is already specified. |   # When -t is used, the destination is already specified. | ||||||
|   # Otherwise, the last argument is the destination.  Remove it from $@. |   # Otherwise, the last argument is the destination.  Remove it from $@. | ||||||
|   for arg |   for arg | ||||||
|   do |   do | ||||||
|     if test -n "$dstarg"; then |     if test -n "$dst_arg"; then | ||||||
|       # $@ is not empty: it contains at least $arg. |       # $@ is not empty: it contains at least $arg. | ||||||
|       set fnord "$@" "$dstarg" |       set fnord "$@" "$dst_arg" | ||||||
|       shift # fnord |       shift # fnord | ||||||
|     fi |     fi | ||||||
|     shift # arg |     shift # arg | ||||||
|     dstarg=$arg |     dst_arg=$arg | ||||||
|  |     # Protect names problematic for 'test' and other utilities. | ||||||
|  |     case $dst_arg in | ||||||
|  |       -* | [=\(\)!]) dst_arg=./$dst_arg;; | ||||||
|  |     esac | ||||||
|   done |   done | ||||||
| fi | fi | ||||||
| 
 | 
 | ||||||
| @ -188,13 +202,17 @@ if test $# -eq 0; then | |||||||
|     echo "$0: no input file specified." >&2 |     echo "$0: no input file specified." >&2 | ||||||
|     exit 1 |     exit 1 | ||||||
|   fi |   fi | ||||||
|   # It's OK to call `install-sh -d' without argument. |   # It's OK to call 'install-sh -d' without argument. | ||||||
|   # This can happen when creating conditional directories. |   # This can happen when creating conditional directories. | ||||||
|   exit 0 |   exit 0 | ||||||
| fi | fi | ||||||
| 
 | 
 | ||||||
| if test -z "$dir_arg"; then | if test -z "$dir_arg"; then | ||||||
|   trap '(exit $?); exit' 1 2 13 15 |   do_exit='(exit $ret); exit $ret' | ||||||
|  |   trap "ret=129; $do_exit" 1 | ||||||
|  |   trap "ret=130; $do_exit" 2 | ||||||
|  |   trap "ret=141; $do_exit" 13 | ||||||
|  |   trap "ret=143; $do_exit" 15 | ||||||
| 
 | 
 | ||||||
|   # Set umask so as not to create temps with too-generous modes. |   # Set umask so as not to create temps with too-generous modes. | ||||||
|   # However, 'strip' requires both read and write access to temps. |   # However, 'strip' requires both read and write access to temps. | ||||||
| @ -222,9 +240,9 @@ fi | |||||||
| 
 | 
 | ||||||
| for src | for src | ||||||
| do | do | ||||||
|   # Protect names starting with `-'. |   # Protect names problematic for 'test' and other utilities. | ||||||
|   case $src in |   case $src in | ||||||
|     -*) src=./$src ;; |     -* | [=\(\)!]) src=./$src;; | ||||||
|   esac |   esac | ||||||
| 
 | 
 | ||||||
|   if test -n "$dir_arg"; then |   if test -n "$dir_arg"; then | ||||||
| @ -242,22 +260,17 @@ do | |||||||
|       exit 1 |       exit 1 | ||||||
|     fi |     fi | ||||||
| 
 | 
 | ||||||
|     if test -z "$dstarg"; then |     if test -z "$dst_arg"; then | ||||||
|       echo "$0: no destination specified." >&2 |       echo "$0: no destination specified." >&2 | ||||||
|       exit 1 |       exit 1 | ||||||
|     fi |     fi | ||||||
| 
 |     dst=$dst_arg | ||||||
|     dst=$dstarg |  | ||||||
|     # Protect names starting with `-'. |  | ||||||
|     case $dst in |  | ||||||
|       -*) dst=./$dst ;; |  | ||||||
|     esac |  | ||||||
| 
 | 
 | ||||||
|     # If destination is a directory, append the input filename; won't work |     # If destination is a directory, append the input filename; won't work | ||||||
|     # if double slashes aren't ignored. |     # if double slashes aren't ignored. | ||||||
|     if test -d "$dst"; then |     if test -d "$dst"; then | ||||||
|       if test -n "$no_target_directory"; then |       if test -n "$no_target_directory"; then | ||||||
| 	echo "$0: $dstarg: Is a directory" >&2 | 	echo "$0: $dst_arg: Is a directory" >&2 | ||||||
| 	exit 1 | 	exit 1 | ||||||
|       fi |       fi | ||||||
|       dstdir=$dst |       dstdir=$dst | ||||||
| @ -341,7 +354,7 @@ do | |||||||
| 	      if test -z "$dir_arg" || { | 	      if test -z "$dir_arg" || { | ||||||
| 		   # Check for POSIX incompatibilities with -m. | 		   # Check for POSIX incompatibilities with -m. | ||||||
| 		   # HP-UX 11.23 and IRIX 6.5 mkdir -m -p sets group- or | 		   # HP-UX 11.23 and IRIX 6.5 mkdir -m -p sets group- or | ||||||
| 		   # other-writeable bit of parent directory when it shouldn't. | 		   # other-writable bit of parent directory when it shouldn't. | ||||||
| 		   # FreeBSD 6.1 mkdir -m -p sets mode of existing directory. | 		   # FreeBSD 6.1 mkdir -m -p sets mode of existing directory. | ||||||
| 		   ls_ld_tmpdir=`ls -ld "$tmpdir"` | 		   ls_ld_tmpdir=`ls -ld "$tmpdir"` | ||||||
| 		   case $ls_ld_tmpdir in | 		   case $ls_ld_tmpdir in | ||||||
| @ -378,33 +391,26 @@ do | |||||||
|       # directory the slow way, step by step, checking for races as we go. |       # directory the slow way, step by step, checking for races as we go. | ||||||
| 
 | 
 | ||||||
|       case $dstdir in |       case $dstdir in | ||||||
| 	/*) prefix=/ ;; | 	/*) prefix='/';; | ||||||
| 	-*) prefix=./ ;; | 	[-=\(\)!]*) prefix='./';; | ||||||
| 	*)  prefix= ;; | 	*)  prefix='';; | ||||||
|       esac |       esac | ||||||
| 
 | 
 | ||||||
|       case $posix_glob in |       eval "$initialize_posix_glob" | ||||||
|         '') |  | ||||||
| 	  if (set -f) 2>/dev/null; then |  | ||||||
| 	    posix_glob=true |  | ||||||
| 	  else |  | ||||||
| 	    posix_glob=false |  | ||||||
| 	  fi ;; |  | ||||||
|       esac |  | ||||||
| 
 | 
 | ||||||
|       oIFS=$IFS |       oIFS=$IFS | ||||||
|       IFS=/ |       IFS=/ | ||||||
|       $posix_glob && set -f |       $posix_glob set -f | ||||||
|       set fnord $dstdir |       set fnord $dstdir | ||||||
|       shift |       shift | ||||||
|       $posix_glob && set +f |       $posix_glob set +f | ||||||
|       IFS=$oIFS |       IFS=$oIFS | ||||||
| 
 | 
 | ||||||
|       prefixes= |       prefixes= | ||||||
| 
 | 
 | ||||||
|       for d |       for d | ||||||
|       do |       do | ||||||
| 	test -z "$d" && continue | 	test X"$d" = X && continue | ||||||
| 
 | 
 | ||||||
| 	prefix=$prefix$d | 	prefix=$prefix$d | ||||||
| 	if test -d "$prefix"; then | 	if test -d "$prefix"; then | ||||||
| @ -459,41 +465,54 @@ do | |||||||
|     # ignore errors from any of these, just make sure not to ignore |     # ignore errors from any of these, just make sure not to ignore | ||||||
|     # errors from the above "$doit $cpprog $src $dsttmp" command. |     # errors from the above "$doit $cpprog $src $dsttmp" command. | ||||||
|     # |     # | ||||||
|     { test -z "$chowncmd" || $doit $chowncmd "$dsttmp"; } \ |     { test -z "$chowncmd" || $doit $chowncmd "$dsttmp"; } && | ||||||
|       && { test -z "$chgrpcmd" || $doit $chgrpcmd "$dsttmp"; } \ |     { test -z "$chgrpcmd" || $doit $chgrpcmd "$dsttmp"; } && | ||||||
|       && { test -z "$stripcmd" || $doit $stripcmd "$dsttmp"; } \ |     { test -z "$stripcmd" || $doit $stripcmd "$dsttmp"; } && | ||||||
|       && { test -z "$chmodcmd" || $doit $chmodcmd $mode "$dsttmp"; } && |     { test -z "$chmodcmd" || $doit $chmodcmd $mode "$dsttmp"; } && | ||||||
|  | 
 | ||||||
|  |     # If -C, don't bother to copy if it wouldn't change the file. | ||||||
|  |     if $copy_on_change && | ||||||
|  |        old=`LC_ALL=C ls -dlL "$dst"	2>/dev/null` && | ||||||
|  |        new=`LC_ALL=C ls -dlL "$dsttmp"	2>/dev/null` && | ||||||
|  | 
 | ||||||
|  |        eval "$initialize_posix_glob" && | ||||||
|  |        $posix_glob set -f && | ||||||
|  |        set X $old && old=:$2:$4:$5:$6 && | ||||||
|  |        set X $new && new=:$2:$4:$5:$6 && | ||||||
|  |        $posix_glob set +f && | ||||||
|  | 
 | ||||||
|  |        test "$old" = "$new" && | ||||||
|  |        $cmpprog "$dst" "$dsttmp" >/dev/null 2>&1 | ||||||
|  |     then | ||||||
|  |       rm -f "$dsttmp" | ||||||
|  |     else | ||||||
|  |       # Rename the file to the real destination. | ||||||
|  |       $doit $mvcmd -f "$dsttmp" "$dst" 2>/dev/null || | ||||||
| 
 | 
 | ||||||
|     # Now rename the file to the real destination. |  | ||||||
|     { $doit $mvcmd -f "$dsttmp" "$dst" 2>/dev/null \ |  | ||||||
|       || { |  | ||||||
|       # The rename failed, perhaps because mv can't rename something else |       # The rename failed, perhaps because mv can't rename something else | ||||||
|       # to itself, or perhaps because mv is so ancient that it does not |       # to itself, or perhaps because mv is so ancient that it does not | ||||||
|       # support -f. |       # support -f. | ||||||
| 
 |       { | ||||||
| 	# Now remove or move aside any old file at destination location. | 	# Now remove or move aside any old file at destination location. | ||||||
| 	# We try this two ways since rm can't unlink itself on some | 	# We try this two ways since rm can't unlink itself on some | ||||||
| 	# systems and the destination file might be busy for other | 	# systems and the destination file might be busy for other | ||||||
| 	# reasons.  In this case, the final cleanup might fail but the new | 	# reasons.  In this case, the final cleanup might fail but the new | ||||||
| 	# file should still install successfully. | 	# file should still install successfully. | ||||||
| 	{ | 	{ | ||||||
| 	     if test -f "$dst"; then | 	  test ! -f "$dst" || | ||||||
| 	       $doit $rmcmd -f "$dst" 2>/dev/null \ | 	  $doit $rmcmd -f "$dst" 2>/dev/null || | ||||||
| 	       || { $doit $mvcmd -f "$dst" "$rmtmp" 2>/dev/null \ | 	  { $doit $mvcmd -f "$dst" "$rmtmp" 2>/dev/null && | ||||||
| 		     && { $doit $rmcmd -f "$rmtmp" 2>/dev/null; :; }; }\ | 	    { $doit $rmcmd -f "$rmtmp" 2>/dev/null; :; } | ||||||
| 	       || { | 	  } || | ||||||
| 		 echo "$0: cannot unlink or rename $dst" >&2 | 	  { echo "$0: cannot unlink or rename $dst" >&2 | ||||||
| 	    (exit 1); exit 1 | 	    (exit 1); exit 1 | ||||||
| 	  } | 	  } | ||||||
| 	     else |  | ||||||
| 	       : |  | ||||||
| 	     fi |  | ||||||
| 	} && | 	} && | ||||||
| 
 | 
 | ||||||
| 	# Now rename the file to the real destination. | 	# Now rename the file to the real destination. | ||||||
| 	$doit $mvcmd "$dsttmp" "$dst" | 	$doit $mvcmd "$dsttmp" "$dst" | ||||||
|       } |       } | ||||||
|     } || exit 1 |     fi || exit 1 | ||||||
| 
 | 
 | ||||||
|     trap '' 0 |     trap '' 0 | ||||||
|   fi |   fi | ||||||
| @ -503,5 +522,6 @@ done | |||||||
| # eval: (add-hook 'write-file-hooks 'time-stamp) | # eval: (add-hook 'write-file-hooks 'time-stamp) | ||||||
| # time-stamp-start: "scriptversion=" | # time-stamp-start: "scriptversion=" | ||||||
| # time-stamp-format: "%:y-%02m-%02d.%02H" | # time-stamp-format: "%:y-%02m-%02d.%02H" | ||||||
| # time-stamp-end: "$" | # time-stamp-time-zone: "UTC" | ||||||
|  | # time-stamp-end: "; # UTC" | ||||||
| # End: | # End: | ||||||
|  | |||||||
| @ -1,11 +1,10 @@ | |||||||
| #! /bin/sh | #! /bin/sh | ||||||
| # Common stub for a few missing GNU programs while installing. | # Common wrapper for a few potentially missing GNU programs. | ||||||
| 
 | 
 | ||||||
| scriptversion=2006-05-10.23 | scriptversion=2013-10-28.13; # UTC | ||||||
| 
 | 
 | ||||||
| # Copyright (C) 1996, 1997, 1999, 2000, 2002, 2003, 2004, 2005, 2006 | # Copyright (C) 1996-2013 Free Software Foundation, Inc. | ||||||
| #   Free Software Foundation, Inc. | # Originally written by Fran,cois Pinard <pinard@iro.umontreal.ca>, 1996. | ||||||
| # Originally by Fran,cois Pinard <pinard@iro.umontreal.ca>, 1996. |  | ||||||
| 
 | 
 | ||||||
| # This program is free software; you can redistribute it and/or modify | # This program is free software; you can redistribute it and/or modify | ||||||
| # it under the terms of the GNU General Public License as published by | # it under the terms of the GNU General Public License as published by | ||||||
| @ -18,9 +17,7 @@ scriptversion=2006-05-10.23 | |||||||
| # GNU General Public License for more details. | # GNU General Public License for more details. | ||||||
| 
 | 
 | ||||||
| # You should have received a copy of the GNU General Public License | # You should have received a copy of the GNU General Public License | ||||||
| # along with this program; if not, write to the Free Software | # along with this program.  If not, see <http://www.gnu.org/licenses/>. | ||||||
| # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA |  | ||||||
| # 02110-1301, USA. |  | ||||||
| 
 | 
 | ||||||
| # As a special exception to the GNU General Public License, if you | # As a special exception to the GNU General Public License, if you | ||||||
| # distribute this file as part of a program that contains a | # distribute this file as part of a program that contains a | ||||||
| @ -28,66 +25,40 @@ scriptversion=2006-05-10.23 | |||||||
| # the same distribution terms that you use for the rest of that program. | # the same distribution terms that you use for the rest of that program. | ||||||
| 
 | 
 | ||||||
| if test $# -eq 0; then | if test $# -eq 0; then | ||||||
|   echo 1>&2 "Try \`$0 --help' for more information" |   echo 1>&2 "Try '$0 --help' for more information" | ||||||
|   exit 1 |   exit 1 | ||||||
| fi | fi | ||||||
| 
 | 
 | ||||||
| run=: |  | ||||||
| sed_output='s/.* --output[ =]\([^ ]*\).*/\1/p' |  | ||||||
| sed_minuso='s/.* -o \([^ ]*\).*/\1/p' |  | ||||||
| 
 |  | ||||||
| # In the cases where this matters, `missing' is being run in the |  | ||||||
| # srcdir already. |  | ||||||
| if test -f configure.ac; then |  | ||||||
|   configure_ac=configure.ac |  | ||||||
| else |  | ||||||
|   configure_ac=configure.in |  | ||||||
| fi |  | ||||||
| 
 |  | ||||||
| msg="missing on your system" |  | ||||||
| 
 |  | ||||||
| case $1 in | case $1 in | ||||||
|  | 
 | ||||||
|  |   --is-lightweight) | ||||||
|  |     # Used by our autoconf macros to check whether the available missing | ||||||
|  |     # script is modern enough. | ||||||
|  |     exit 0 | ||||||
|  |     ;; | ||||||
|  | 
 | ||||||
|   --run) |   --run) | ||||||
|   # Try to run requested program, and just exit if it succeeds. |     # Back-compat with the calling convention used by older automake. | ||||||
|   run= |  | ||||||
|     shift |     shift | ||||||
|   "$@" && exit 0 |  | ||||||
|   # Exit code 63 means version mismatch.  This often happens |  | ||||||
|   # when the user try to use an ancient version of a tool on |  | ||||||
|   # a file that requires a minimum version.  In this case we |  | ||||||
|   # we should proceed has if the program had been absent, or |  | ||||||
|   # if --run hadn't been passed. |  | ||||||
|   if test $? = 63; then |  | ||||||
|     run=: |  | ||||||
|     msg="probably too old" |  | ||||||
|   fi |  | ||||||
|     ;; |     ;; | ||||||
| 
 | 
 | ||||||
|   -h|--h|--he|--hel|--help) |   -h|--h|--he|--hel|--help) | ||||||
|     echo "\ |     echo "\ | ||||||
| $0 [OPTION]... PROGRAM [ARGUMENT]... | $0 [OPTION]... PROGRAM [ARGUMENT]... | ||||||
| 
 | 
 | ||||||
| Handle \`PROGRAM [ARGUMENT]...' for when PROGRAM is missing, or return an | Run 'PROGRAM [ARGUMENT]...', returning a proper advice when this fails due | ||||||
| error status if there is no known handling for PROGRAM. | to PROGRAM being missing or too old. | ||||||
| 
 | 
 | ||||||
| Options: | Options: | ||||||
|   -h, --help      display this help and exit |   -h, --help      display this help and exit | ||||||
|   -v, --version   output version information and exit |   -v, --version   output version information and exit | ||||||
|   --run           try to run the given command, and emulate it if it fails |  | ||||||
| 
 | 
 | ||||||
| Supported PROGRAM values: | Supported PROGRAM values: | ||||||
|   aclocal      touch file \`aclocal.m4' |   aclocal   autoconf  autoheader   autom4te  automake  makeinfo | ||||||
|   autoconf     touch file \`configure' |   bison     yacc      flex         lex       help2man | ||||||
|   autoheader   touch file \`config.h.in' | 
 | ||||||
|   autom4te     touch the output file, or create a stub one | Version suffixes to PROGRAM as well as the prefixes 'gnu-', 'gnu', and | ||||||
|   automake     touch all \`Makefile.in' files | 'g' are ignored when checking the name. | ||||||
|   bison        create \`y.tab.[ch]', if possible, from existing .[ch] |  | ||||||
|   flex         create \`lex.yy.c', if possible, from existing .c |  | ||||||
|   help2man     touch the output file |  | ||||||
|   lex          create \`lex.yy.c', if possible, from existing .c |  | ||||||
|   makeinfo     touch the output file |  | ||||||
|   tar          try tar, gnutar, gtar, then tar without non-portable flags |  | ||||||
|   yacc         create \`y.tab.[ch]', if possible, from existing .[ch] |  | ||||||
| 
 | 
 | ||||||
| Send bug reports to <bug-automake@gnu.org>." | Send bug reports to <bug-automake@gnu.org>." | ||||||
|     exit $? |     exit $? | ||||||
| @ -99,269 +70,146 @@ Send bug reports to <bug-automake@gnu.org>." | |||||||
|     ;; |     ;; | ||||||
| 
 | 
 | ||||||
|   -*) |   -*) | ||||||
|     echo 1>&2 "$0: Unknown \`$1' option" |     echo 1>&2 "$0: unknown '$1' option" | ||||||
|     echo 1>&2 "Try \`$0 --help' for more information" |     echo 1>&2 "Try '$0 --help' for more information" | ||||||
|     exit 1 |     exit 1 | ||||||
|     ;; |     ;; | ||||||
| 
 | 
 | ||||||
| esac | esac | ||||||
| 
 | 
 | ||||||
| # Now exit if we have it, but it failed.  Also exit now if we | # Run the given program, remember its exit status. | ||||||
| # don't have it and --version was passed (most likely to detect | "$@"; st=$? | ||||||
| # the program). |  | ||||||
| case $1 in |  | ||||||
|   lex|yacc) |  | ||||||
|     # Not GNU programs, they don't have --version. |  | ||||||
|     ;; |  | ||||||
| 
 | 
 | ||||||
|   tar) | # If it succeeded, we are done. | ||||||
|     if test -n "$run"; then | test $st -eq 0 && exit 0 | ||||||
|        echo 1>&2 "ERROR: \`tar' requires --run" | 
 | ||||||
|        exit 1 | # Also exit now if we it failed (or wasn't found), and '--version' was | ||||||
|     elif test "x$2" = "x--version" || test "x$2" = "x--help"; then | # passed; such an option is passed most likely to detect whether the | ||||||
|        exit 1 | # program is present and works. | ||||||
|  | case $2 in --version|--help) exit $st;; esac | ||||||
|  | 
 | ||||||
|  | # Exit code 63 means version mismatch.  This often happens when the user | ||||||
|  | # tries to use an ancient version of a tool on a file that requires a | ||||||
|  | # minimum version. | ||||||
|  | if test $st -eq 63; then | ||||||
|  |   msg="probably too old" | ||||||
|  | elif test $st -eq 127; then | ||||||
|  |   # Program was missing. | ||||||
|  |   msg="missing on your system" | ||||||
|  | else | ||||||
|  |   # Program was found and executed, but failed.  Give up. | ||||||
|  |   exit $st | ||||||
| fi | fi | ||||||
|     ;; |  | ||||||
| 
 | 
 | ||||||
|   *) | perl_URL=http://www.perl.org/ | ||||||
|     if test -z "$run" && ($1 --version) > /dev/null 2>&1; then | flex_URL=http://flex.sourceforge.net/ | ||||||
|        # We have it, but it failed. | gnu_software_URL=http://www.gnu.org/software | ||||||
|        exit 1 |  | ||||||
|     elif test "x$2" = "x--version" || test "x$2" = "x--help"; then |  | ||||||
|        # Could not run --version or --help.  This is probably someone |  | ||||||
|        # running `$TOOL --version' or `$TOOL --help' to check whether |  | ||||||
|        # $TOOL exists and not knowing $TOOL uses missing. |  | ||||||
|        exit 1 |  | ||||||
|     fi |  | ||||||
|     ;; |  | ||||||
| esac |  | ||||||
| 
 | 
 | ||||||
| # If it does not exist, or fails to run (possibly an outdated version), | program_details () | ||||||
| # try to emulate it. | { | ||||||
|   case $1 in |   case $1 in | ||||||
|   aclocal*) |     aclocal|automake) | ||||||
|     echo 1>&2 "\ |       echo "The '$1' program is part of the GNU Automake package:" | ||||||
| WARNING: \`$1' is $msg.  You should only need it if |       echo "<$gnu_software_URL/automake>" | ||||||
|          you modified \`acinclude.m4' or \`${configure_ac}'.  You might want |       echo "It also requires GNU Autoconf, GNU m4 and Perl in order to run:" | ||||||
|          to install the \`Automake' and \`Perl' packages.  Grab them from |       echo "<$gnu_software_URL/autoconf>" | ||||||
|          any GNU archive site." |       echo "<$gnu_software_URL/m4/>" | ||||||
|     touch aclocal.m4 |       echo "<$perl_URL>" | ||||||
|       ;; |       ;; | ||||||
| 
 |     autoconf|autom4te|autoheader) | ||||||
|   autoconf) |       echo "The '$1' program is part of the GNU Autoconf package:" | ||||||
|     echo 1>&2 "\ |       echo "<$gnu_software_URL/autoconf/>" | ||||||
| WARNING: \`$1' is $msg.  You should only need it if |       echo "It also requires GNU m4 and Perl in order to run:" | ||||||
|          you modified \`${configure_ac}'.  You might want to install the |       echo "<$gnu_software_URL/m4/>" | ||||||
|          \`Autoconf' and \`GNU m4' packages.  Grab them from any GNU |       echo "<$perl_URL>" | ||||||
|          archive site." |  | ||||||
|     touch configure |  | ||||||
|       ;; |       ;; | ||||||
| 
 |  | ||||||
|   autoheader) |  | ||||||
|     echo 1>&2 "\ |  | ||||||
| WARNING: \`$1' is $msg.  You should only need it if |  | ||||||
|          you modified \`acconfig.h' or \`${configure_ac}'.  You might want |  | ||||||
|          to install the \`Autoconf' and \`GNU m4' packages.  Grab them |  | ||||||
|          from any GNU archive site." |  | ||||||
|     files=`sed -n 's/^[ ]*A[CM]_CONFIG_HEADER(\([^)]*\)).*/\1/p' ${configure_ac}` |  | ||||||
|     test -z "$files" && files="config.h" |  | ||||||
|     touch_files= |  | ||||||
|     for f in $files; do |  | ||||||
|       case $f in |  | ||||||
|       *:*) touch_files="$touch_files "`echo "$f" | |  | ||||||
| 				       sed -e 's/^[^:]*://' -e 's/:.*//'`;; |  | ||||||
|       *) touch_files="$touch_files $f.in";; |  | ||||||
|   esac |   esac | ||||||
|     done | } | ||||||
|     touch $touch_files |  | ||||||
|     ;; |  | ||||||
| 
 | 
 | ||||||
|  | give_advice () | ||||||
|  | { | ||||||
|  |   # Normalize program name to check for. | ||||||
|  |   normalized_program=`echo "$1" | sed ' | ||||||
|  |     s/^gnu-//; t | ||||||
|  |     s/^gnu//; t | ||||||
|  |     s/^g//; t'` | ||||||
|  | 
 | ||||||
|  |   printf '%s\n' "'$1' is $msg." | ||||||
|  | 
 | ||||||
|  |   configure_deps="'configure.ac' or m4 files included by 'configure.ac'" | ||||||
|  |   case $normalized_program in | ||||||
|  |     autoconf*) | ||||||
|  |       echo "You should only need it if you modified 'configure.ac'," | ||||||
|  |       echo "or m4 files included by it." | ||||||
|  |       program_details 'autoconf' | ||||||
|  |       ;; | ||||||
|  |     autoheader*) | ||||||
|  |       echo "You should only need it if you modified 'acconfig.h' or" | ||||||
|  |       echo "$configure_deps." | ||||||
|  |       program_details 'autoheader' | ||||||
|  |       ;; | ||||||
|     automake*) |     automake*) | ||||||
|     echo 1>&2 "\ |       echo "You should only need it if you modified 'Makefile.am' or" | ||||||
| WARNING: \`$1' is $msg.  You should only need it if |       echo "$configure_deps." | ||||||
|          you modified \`Makefile.am', \`acinclude.m4' or \`${configure_ac}'. |       program_details 'automake' | ||||||
|          You might want to install the \`Automake' and \`Perl' packages. |  | ||||||
|          Grab them from any GNU archive site." |  | ||||||
|     find . -type f -name Makefile.am -print | |  | ||||||
| 	   sed 's/\.am$/.in/' | |  | ||||||
| 	   while read f; do touch "$f"; done |  | ||||||
|       ;; |       ;; | ||||||
| 
 |     aclocal*) | ||||||
|   autom4te) |       echo "You should only need it if you modified 'acinclude.m4' or" | ||||||
|     echo 1>&2 "\ |       echo "$configure_deps." | ||||||
| WARNING: \`$1' is needed, but is $msg. |       program_details 'aclocal' | ||||||
|          You might have modified some files without having the |  | ||||||
|          proper tools for further handling them. |  | ||||||
|          You can get \`$1' as part of \`Autoconf' from any GNU |  | ||||||
|          archive site." |  | ||||||
| 
 |  | ||||||
|     file=`echo "$*" | sed -n "$sed_output"` |  | ||||||
|     test -z "$file" && file=`echo "$*" | sed -n "$sed_minuso"` |  | ||||||
|     if test -f "$file"; then |  | ||||||
| 	touch $file |  | ||||||
|     else |  | ||||||
| 	test -z "$file" || exec >$file |  | ||||||
| 	echo "#! /bin/sh" |  | ||||||
| 	echo "# Created by GNU Automake missing as a replacement of" |  | ||||||
| 	echo "#  $ $@" |  | ||||||
| 	echo "exit 0" |  | ||||||
| 	chmod +x $file |  | ||||||
| 	exit 1 |  | ||||||
|     fi |  | ||||||
|       ;; |       ;; | ||||||
| 
 |    autom4te*) | ||||||
|   bison|yacc) |       echo "You might have modified some maintainer files that require" | ||||||
|     echo 1>&2 "\ |       echo "the 'autom4te' program to be rebuilt." | ||||||
| WARNING: \`$1' $msg.  You should only need it if |       program_details 'autom4te' | ||||||
|          you modified a \`.y' file.  You may need the \`Bison' package |  | ||||||
|          in order for those modifications to take effect.  You can get |  | ||||||
|          \`Bison' from any GNU archive site." |  | ||||||
|     rm -f y.tab.c y.tab.h |  | ||||||
|     if test $# -ne 1; then |  | ||||||
|         eval LASTARG="\${$#}" |  | ||||||
| 	case $LASTARG in |  | ||||||
| 	*.y) |  | ||||||
| 	    SRCFILE=`echo "$LASTARG" | sed 's/y$/c/'` |  | ||||||
| 	    if test -f "$SRCFILE"; then |  | ||||||
| 	         cp "$SRCFILE" y.tab.c |  | ||||||
| 	    fi |  | ||||||
| 	    SRCFILE=`echo "$LASTARG" | sed 's/y$/h/'` |  | ||||||
| 	    if test -f "$SRCFILE"; then |  | ||||||
| 	         cp "$SRCFILE" y.tab.h |  | ||||||
| 	    fi |  | ||||||
|       ;; |       ;; | ||||||
| 	esac |     bison*|yacc*) | ||||||
|     fi |       echo "You should only need it if you modified a '.y' file." | ||||||
|     if test ! -f y.tab.h; then |       echo "You may want to install the GNU Bison package:" | ||||||
| 	echo >y.tab.h |       echo "<$gnu_software_URL/bison/>" | ||||||
|     fi |  | ||||||
|     if test ! -f y.tab.c; then |  | ||||||
| 	echo 'main() { return 0; }' >y.tab.c |  | ||||||
|     fi |  | ||||||
|       ;; |       ;; | ||||||
| 
 |     lex*|flex*) | ||||||
|   lex|flex) |       echo "You should only need it if you modified a '.l' file." | ||||||
|     echo 1>&2 "\ |       echo "You may want to install the Fast Lexical Analyzer package:" | ||||||
| WARNING: \`$1' is $msg.  You should only need it if |       echo "<$flex_URL>" | ||||||
|          you modified a \`.l' file.  You may need the \`Flex' package |  | ||||||
|          in order for those modifications to take effect.  You can get |  | ||||||
|          \`Flex' from any GNU archive site." |  | ||||||
|     rm -f lex.yy.c |  | ||||||
|     if test $# -ne 1; then |  | ||||||
|         eval LASTARG="\${$#}" |  | ||||||
| 	case $LASTARG in |  | ||||||
| 	*.l) |  | ||||||
| 	    SRCFILE=`echo "$LASTARG" | sed 's/l$/c/'` |  | ||||||
| 	    if test -f "$SRCFILE"; then |  | ||||||
| 	         cp "$SRCFILE" lex.yy.c |  | ||||||
| 	    fi |  | ||||||
|       ;; |       ;; | ||||||
| 	esac |     help2man*) | ||||||
|     fi |       echo "You should only need it if you modified a dependency" \ | ||||||
|     if test ! -f lex.yy.c; then |            "of a man page." | ||||||
| 	echo 'main() { return 0; }' >lex.yy.c |       echo "You may want to install the GNU Help2man package:" | ||||||
|     fi |       echo "<$gnu_software_URL/help2man/>" | ||||||
|     ;; |     ;; | ||||||
| 
 |     makeinfo*) | ||||||
|   help2man) |       echo "You should only need it if you modified a '.texi' file, or" | ||||||
|     echo 1>&2 "\ |       echo "any other file indirectly affecting the aspect of the manual." | ||||||
| WARNING: \`$1' is $msg.  You should only need it if |       echo "You might want to install the Texinfo package:" | ||||||
| 	 you modified a dependency of a manual page.  You may need the |       echo "<$gnu_software_URL/texinfo/>" | ||||||
| 	 \`Help2man' package in order for those modifications to take |       echo "The spurious makeinfo call might also be the consequence of" | ||||||
| 	 effect.  You can get \`Help2man' from any GNU archive site." |       echo "using a buggy 'make' (AIX, DU, IRIX), in which case you might" | ||||||
| 
 |       echo "want to install GNU make:" | ||||||
|     file=`echo "$*" | sed -n "$sed_output"` |       echo "<$gnu_software_URL/make/>" | ||||||
|     test -z "$file" && file=`echo "$*" | sed -n "$sed_minuso"` |  | ||||||
|     if test -f "$file"; then |  | ||||||
| 	touch $file |  | ||||||
|     else |  | ||||||
| 	test -z "$file" || exec >$file |  | ||||||
| 	echo ".ab help2man is required to generate this page" |  | ||||||
| 	exit 1 |  | ||||||
|     fi |  | ||||||
|       ;; |       ;; | ||||||
| 
 |  | ||||||
|   makeinfo) |  | ||||||
|     echo 1>&2 "\ |  | ||||||
| WARNING: \`$1' is $msg.  You should only need it if |  | ||||||
|          you modified a \`.texi' or \`.texinfo' file, or any other file |  | ||||||
|          indirectly affecting the aspect of the manual.  The spurious |  | ||||||
|          call might also be the consequence of using a buggy \`make' (AIX, |  | ||||||
|          DU, IRIX).  You might want to install the \`Texinfo' package or |  | ||||||
|          the \`GNU make' package.  Grab either from any GNU archive site." |  | ||||||
|     # The file to touch is that specified with -o ... |  | ||||||
|     file=`echo "$*" | sed -n "$sed_output"` |  | ||||||
|     test -z "$file" && file=`echo "$*" | sed -n "$sed_minuso"` |  | ||||||
|     if test -z "$file"; then |  | ||||||
|       # ... or it is the one specified with @setfilename ... |  | ||||||
|       infile=`echo "$*" | sed 's/.* \([^ ]*\) *$/\1/'` |  | ||||||
|       file=`sed -n ' |  | ||||||
| 	/^@setfilename/{ |  | ||||||
| 	  s/.* \([^ ]*\) *$/\1/ |  | ||||||
| 	  p |  | ||||||
| 	  q |  | ||||||
| 	}' $infile` |  | ||||||
|       # ... or it is derived from the source name (dir/f.texi becomes f.info) |  | ||||||
|       test -z "$file" && file=`echo "$infile" | sed 's,.*/,,;s,.[^.]*$,,'`.info |  | ||||||
|     fi |  | ||||||
|     # If the file does not exist, the user really needs makeinfo; |  | ||||||
|     # let's fail without touching anything. |  | ||||||
|     test -f $file || exit 1 |  | ||||||
|     touch $file |  | ||||||
|     ;; |  | ||||||
| 
 |  | ||||||
|   tar) |  | ||||||
|     shift |  | ||||||
| 
 |  | ||||||
|     # We have already tried tar in the generic part. |  | ||||||
|     # Look for gnutar/gtar before invocation to avoid ugly error |  | ||||||
|     # messages. |  | ||||||
|     if (gnutar --version > /dev/null 2>&1); then |  | ||||||
|        gnutar "$@" && exit 0 |  | ||||||
|     fi |  | ||||||
|     if (gtar --version > /dev/null 2>&1); then |  | ||||||
|        gtar "$@" && exit 0 |  | ||||||
|     fi |  | ||||||
|     firstarg="$1" |  | ||||||
|     if shift; then |  | ||||||
| 	case $firstarg in |  | ||||||
| 	*o*) |  | ||||||
| 	    firstarg=`echo "$firstarg" | sed s/o//` |  | ||||||
| 	    tar "$firstarg" "$@" && exit 0 |  | ||||||
| 	    ;; |  | ||||||
| 	esac |  | ||||||
| 	case $firstarg in |  | ||||||
| 	*h*) |  | ||||||
| 	    firstarg=`echo "$firstarg" | sed s/h//` |  | ||||||
| 	    tar "$firstarg" "$@" && exit 0 |  | ||||||
| 	    ;; |  | ||||||
| 	esac |  | ||||||
|     fi |  | ||||||
| 
 |  | ||||||
|     echo 1>&2 "\ |  | ||||||
| WARNING: I can't seem to be able to run \`tar' with the given arguments. |  | ||||||
|          You may want to install GNU tar or Free paxutils, or check the |  | ||||||
|          command line arguments." |  | ||||||
|     exit 1 |  | ||||||
|     ;; |  | ||||||
| 
 |  | ||||||
|     *) |     *) | ||||||
|     echo 1>&2 "\ |       echo "You might have modified some files without having the proper" | ||||||
| WARNING: \`$1' is needed, and is $msg. |       echo "tools for further handling them.  Check the 'README' file, it" | ||||||
|          You might have modified some files without having the |       echo "often tells you about the needed prerequisites for installing" | ||||||
|          proper tools for further handling them.  Check the \`README' file, |       echo "this package.  You may also peek at any GNU archive site, in" | ||||||
|          it often tells you about the needed prerequisites for installing |       echo "case some other package contains this missing '$1' program." | ||||||
|          this package.  You may also peek at any GNU archive site, in case |  | ||||||
|          some other package would contain this missing \`$1' program." |  | ||||||
|     exit 1 |  | ||||||
|       ;; |       ;; | ||||||
|   esac |   esac | ||||||
|  | } | ||||||
| 
 | 
 | ||||||
| exit 0 | give_advice "$1" | sed -e '1s/^/WARNING: /' \ | ||||||
|  |                        -e '2,$s/^/         /' >&2 | ||||||
|  | 
 | ||||||
|  | # Propagate the correct exit status (expected to be 127 for a program | ||||||
|  | # not found, 63 for a program that failed due to version mismatch). | ||||||
|  | exit $st | ||||||
| 
 | 
 | ||||||
| # Local variables: | # Local variables: | ||||||
| # eval: (add-hook 'write-file-hooks 'time-stamp) | # eval: (add-hook 'write-file-hooks 'time-stamp) | ||||||
| # time-stamp-start: "scriptversion=" | # time-stamp-start: "scriptversion=" | ||||||
| # time-stamp-format: "%:y-%02m-%02d.%02H" | # time-stamp-format: "%:y-%02m-%02d.%02H" | ||||||
| # time-stamp-end: "$" | # time-stamp-time-zone: "UTC" | ||||||
|  | # time-stamp-end: "; # UTC" | ||||||
| # End: | # End: | ||||||
|  | |||||||
							
								
								
									
										139
									
								
								google-breakpad/autotools/test-driver
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										139
									
								
								google-breakpad/autotools/test-driver
									
									
									
									
									
										Executable file
									
								
							| @ -0,0 +1,139 @@ | |||||||
|  | #! /bin/sh | ||||||
|  | # test-driver - basic testsuite driver script. | ||||||
|  | 
 | ||||||
|  | scriptversion=2013-07-13.22; # UTC | ||||||
|  | 
 | ||||||
|  | # Copyright (C) 2011-2013 Free Software Foundation, Inc. | ||||||
|  | # | ||||||
|  | # This program is free software; you can redistribute it and/or modify | ||||||
|  | # it under the terms of the GNU General Public License as published by | ||||||
|  | # the Free Software Foundation; either version 2, or (at your option) | ||||||
|  | # any later version. | ||||||
|  | # | ||||||
|  | # This program is distributed in the hope that it will be useful, | ||||||
|  | # but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||||
|  | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||||
|  | # GNU General Public License for more details. | ||||||
|  | # | ||||||
|  | # You should have received a copy of the GNU General Public License | ||||||
|  | # along with this program.  If not, see <http://www.gnu.org/licenses/>. | ||||||
|  | 
 | ||||||
|  | # As a special exception to the GNU General Public License, if you | ||||||
|  | # distribute this file as part of a program that contains a | ||||||
|  | # configuration script generated by Autoconf, you may include it under | ||||||
|  | # the same distribution terms that you use for the rest of that program. | ||||||
|  | 
 | ||||||
|  | # This file is maintained in Automake, please report | ||||||
|  | # bugs to <bug-automake@gnu.org> or send patches to | ||||||
|  | # <automake-patches@gnu.org>. | ||||||
|  | 
 | ||||||
|  | # Make unconditional expansion of undefined variables an error.  This | ||||||
|  | # helps a lot in preventing typo-related bugs. | ||||||
|  | set -u | ||||||
|  | 
 | ||||||
|  | usage_error () | ||||||
|  | { | ||||||
|  |   echo "$0: $*" >&2 | ||||||
|  |   print_usage >&2 | ||||||
|  |   exit 2 | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | print_usage () | ||||||
|  | { | ||||||
|  |   cat <<END | ||||||
|  | Usage: | ||||||
|  |   test-driver --test-name=NAME --log-file=PATH --trs-file=PATH | ||||||
|  |               [--expect-failure={yes|no}] [--color-tests={yes|no}] | ||||||
|  |               [--enable-hard-errors={yes|no}] [--] | ||||||
|  |               TEST-SCRIPT [TEST-SCRIPT-ARGUMENTS] | ||||||
|  | The '--test-name', '--log-file' and '--trs-file' options are mandatory. | ||||||
|  | END | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | test_name= # Used for reporting. | ||||||
|  | log_file=  # Where to save the output of the test script. | ||||||
|  | trs_file=  # Where to save the metadata of the test run. | ||||||
|  | expect_failure=no | ||||||
|  | color_tests=no | ||||||
|  | enable_hard_errors=yes | ||||||
|  | while test $# -gt 0; do | ||||||
|  |   case $1 in | ||||||
|  |   --help) print_usage; exit $?;; | ||||||
|  |   --version) echo "test-driver $scriptversion"; exit $?;; | ||||||
|  |   --test-name) test_name=$2; shift;; | ||||||
|  |   --log-file) log_file=$2; shift;; | ||||||
|  |   --trs-file) trs_file=$2; shift;; | ||||||
|  |   --color-tests) color_tests=$2; shift;; | ||||||
|  |   --expect-failure) expect_failure=$2; shift;; | ||||||
|  |   --enable-hard-errors) enable_hard_errors=$2; shift;; | ||||||
|  |   --) shift; break;; | ||||||
|  |   -*) usage_error "invalid option: '$1'";; | ||||||
|  |    *) break;; | ||||||
|  |   esac | ||||||
|  |   shift | ||||||
|  | done | ||||||
|  | 
 | ||||||
|  | missing_opts= | ||||||
|  | test x"$test_name" = x && missing_opts="$missing_opts --test-name" | ||||||
|  | test x"$log_file"  = x && missing_opts="$missing_opts --log-file" | ||||||
|  | test x"$trs_file"  = x && missing_opts="$missing_opts --trs-file" | ||||||
|  | if test x"$missing_opts" != x; then | ||||||
|  |   usage_error "the following mandatory options are missing:$missing_opts" | ||||||
|  | fi | ||||||
|  | 
 | ||||||
|  | if test $# -eq 0; then | ||||||
|  |   usage_error "missing argument" | ||||||
|  | fi | ||||||
|  | 
 | ||||||
|  | if test $color_tests = yes; then | ||||||
|  |   # Keep this in sync with 'lib/am/check.am:$(am__tty_colors)'. | ||||||
|  |   red='[0;31m' # Red. | ||||||
|  |   grn='[0;32m' # Green. | ||||||
|  |   lgn='[1;32m' # Light green. | ||||||
|  |   blu='[1;34m' # Blue. | ||||||
|  |   mgn='[0;35m' # Magenta. | ||||||
|  |   std='[m'     # No color. | ||||||
|  | else | ||||||
|  |   red= grn= lgn= blu= mgn= std= | ||||||
|  | fi | ||||||
|  | 
 | ||||||
|  | do_exit='rm -f $log_file $trs_file; (exit $st); exit $st' | ||||||
|  | trap "st=129; $do_exit" 1 | ||||||
|  | trap "st=130; $do_exit" 2 | ||||||
|  | trap "st=141; $do_exit" 13 | ||||||
|  | trap "st=143; $do_exit" 15 | ||||||
|  | 
 | ||||||
|  | # Test script is run here. | ||||||
|  | "$@" >$log_file 2>&1 | ||||||
|  | estatus=$? | ||||||
|  | if test $enable_hard_errors = no && test $estatus -eq 99; then | ||||||
|  |   estatus=1 | ||||||
|  | fi | ||||||
|  | 
 | ||||||
|  | case $estatus:$expect_failure in | ||||||
|  |   0:yes) col=$red res=XPASS recheck=yes gcopy=yes;; | ||||||
|  |   0:*)   col=$grn res=PASS  recheck=no  gcopy=no;; | ||||||
|  |   77:*)  col=$blu res=SKIP  recheck=no  gcopy=yes;; | ||||||
|  |   99:*)  col=$mgn res=ERROR recheck=yes gcopy=yes;; | ||||||
|  |   *:yes) col=$lgn res=XFAIL recheck=no  gcopy=yes;; | ||||||
|  |   *:*)   col=$red res=FAIL  recheck=yes gcopy=yes;; | ||||||
|  | esac | ||||||
|  | 
 | ||||||
|  | # Report outcome to console. | ||||||
|  | echo "${col}${res}${std}: $test_name" | ||||||
|  | 
 | ||||||
|  | # Register the test result, and other relevant metadata. | ||||||
|  | echo ":test-result: $res" > $trs_file | ||||||
|  | echo ":global-test-result: $res" >> $trs_file | ||||||
|  | echo ":recheck: $recheck" >> $trs_file | ||||||
|  | echo ":copy-in-global-log: $gcopy" >> $trs_file | ||||||
|  | 
 | ||||||
|  | # Local Variables: | ||||||
|  | # mode: shell-script | ||||||
|  | # sh-indentation: 2 | ||||||
|  | # eval: (add-hook 'write-file-hooks 'time-stamp) | ||||||
|  | # time-stamp-start: "scriptversion=" | ||||||
|  | # time-stamp-format: "%:y-%02m-%02d.%02H" | ||||||
|  | # time-stamp-time-zone: "UTC" | ||||||
|  | # time-stamp-end: "; # UTC" | ||||||
|  | # End: | ||||||
							
								
								
									
										10
									
								
								google-breakpad/breakpad-client.pc.in
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								google-breakpad/breakpad-client.pc.in
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,10 @@ | |||||||
|  | prefix=@prefix@ | ||||||
|  | exec_prefix=@exec_prefix@ | ||||||
|  | libdir=@libdir@ | ||||||
|  | includedir=@includedir@/@PACKAGE_NAME@ | ||||||
|  | 
 | ||||||
|  | Name: google-breakpad-client | ||||||
|  | Description: An open-source multi-platform crash reporting system | ||||||
|  | Version: @PACKAGE_VERSION@ | ||||||
|  | Libs: -L${libdir} -lbreakpad_client @PTHREAD_LIBS@ | ||||||
|  | Cflags: -I${includedir} @PTHREAD_CFLAGS@ | ||||||
							
								
								
									
										10
									
								
								google-breakpad/breakpad.pc.in
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								google-breakpad/breakpad.pc.in
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,10 @@ | |||||||
|  | prefix=@prefix@ | ||||||
|  | exec_prefix=@exec_prefix@ | ||||||
|  | libdir=@libdir@ | ||||||
|  | includedir=@includedir@/@PACKAGE_NAME@ | ||||||
|  | 
 | ||||||
|  | Name: google-breakpad | ||||||
|  | Description: An open-source multi-platform crash reporting system | ||||||
|  | Version: @PACKAGE_VERSION@ | ||||||
|  | Libs: -L${libdir} -lbreakpad @PTHREAD_LIBS@ | ||||||
|  | Cflags: -I${includedir} @PTHREAD_CFLAGS@ | ||||||
							
								
								
									
										5
									
								
								google-breakpad/codereview.settings
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								google-breakpad/codereview.settings
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,5 @@ | |||||||
|  | # This file is used by gcl to get repository specific information. | ||||||
|  | CODE_REVIEW_SERVER: breakpad.appspot.com | ||||||
|  | CC_LIST: google-breakpad-dev@googlegroups.com | ||||||
|  | TRY_ON_UPLOAD: False | ||||||
|  | VIEW_VC: http://code.google.com/p/google-breakpad/source/detail?r= | ||||||
							
								
								
									
										1557
									
								
								google-breakpad/configure
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1557
									
								
								google-breakpad/configure
									
									
									
									
										vendored
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @ -39,6 +39,7 @@ AC_CANONICAL_HOST | |||||||
| 
 | 
 | ||||||
| AM_INIT_AUTOMAKE(subdir-objects tar-ustar 1.11.1) | AM_INIT_AUTOMAKE(subdir-objects tar-ustar 1.11.1) | ||||||
| AM_CONFIG_HEADER(src/config.h) | AM_CONFIG_HEADER(src/config.h) | ||||||
|  | AM_MAINTAINER_MODE | ||||||
| 
 | 
 | ||||||
| AM_PROG_AS | AM_PROG_AS | ||||||
| AC_PROG_CC | AC_PROG_CC | ||||||
| @ -48,7 +49,28 @@ AC_PROG_CXX | |||||||
| AC_PROG_RANLIB | AC_PROG_RANLIB | ||||||
| AM_CONDITIONAL(GCC, test "$GCC" = yes)   # let the Makefile know if we're gcc | AM_CONDITIONAL(GCC, test "$GCC" = yes)   # let the Makefile know if we're gcc | ||||||
| 
 | 
 | ||||||
|  | dnl This must come before all the feature tests below. | ||||||
|  | AC_ARG_ENABLE(m32, | ||||||
|  |               AS_HELP_STRING([--enable-m32], | ||||||
|  |                              [Compile/build with -m32] | ||||||
|  |                              [(default is no)]), | ||||||
|  |               [case "${enableval}" in | ||||||
|  |                  yes) | ||||||
|  |                    CFLAGS="${CFLAGS} -m32" | ||||||
|  |                    CXXFLAGS="${CXXFLAGS} -m32" | ||||||
|  |                    usem32=true | ||||||
|  |                    ;; | ||||||
|  |                  no) | ||||||
|  |                    usem32=false | ||||||
|  |                    ;; | ||||||
|  |                  *) | ||||||
|  |                    AC_MSG_ERROR(bad value ${enableval} for --enable-m32) | ||||||
|  |                    ;; | ||||||
|  |                esac], | ||||||
|  |               [usem32=false]) | ||||||
|  | 
 | ||||||
| AC_HEADER_STDC | AC_HEADER_STDC | ||||||
|  | AC_SYS_LARGEFILE | ||||||
| m4_include(m4/ax_pthread.m4) | m4_include(m4/ax_pthread.m4) | ||||||
| AX_PTHREAD | AX_PTHREAD | ||||||
| AC_CHECK_HEADERS([a.out.h]) | AC_CHECK_HEADERS([a.out.h]) | ||||||
| @ -69,25 +91,6 @@ case $host in | |||||||
| esac | esac | ||||||
| AM_CONDITIONAL(ANDROID_HOST, test x$ANDROID_HOST = xtrue) | AM_CONDITIONAL(ANDROID_HOST, test x$ANDROID_HOST = xtrue) | ||||||
| 
 | 
 | ||||||
| AC_ARG_ENABLE(m32, |  | ||||||
|               AS_HELP_STRING([--enable-m32], |  | ||||||
|                              [Compile/build with -m32] |  | ||||||
|                              [(default is no)]), |  | ||||||
|               [case "${enableval}" in |  | ||||||
|                  yes) |  | ||||||
|                    CFLAGS="${CFLAGS} -m32" |  | ||||||
|                    CXXFLAGS="${CXXFLAGS} -m32" |  | ||||||
|                    usem32=true |  | ||||||
|                    ;; |  | ||||||
|                  no) |  | ||||||
|                    usem32=false |  | ||||||
|                    ;; |  | ||||||
|                  *) |  | ||||||
|                    AC_MSG_ERROR(bad value ${enableval} for --enable-m32) |  | ||||||
|                    ;; |  | ||||||
|                esac], |  | ||||||
|               [usem32=false]) |  | ||||||
| 
 |  | ||||||
| AC_ARG_ENABLE(processor, | AC_ARG_ENABLE(processor, | ||||||
|               AS_HELP_STRING([--disable-processor], |               AS_HELP_STRING([--disable-processor], | ||||||
|                              [Don't build processor library] |                              [Don't build processor library] | ||||||
| @ -147,5 +150,10 @@ AC_ARG_ENABLE(selftest, | |||||||
|               [selftest=false]) |               [selftest=false]) | ||||||
| AM_CONDITIONAL(SELFTEST, test x$selftest = xtrue) | AM_CONDITIONAL(SELFTEST, test x$selftest = xtrue) | ||||||
| 
 | 
 | ||||||
| AC_CONFIG_FILES([Makefile]) | AC_CONFIG_FILES(m4_flatten([ | ||||||
|  |   breakpad.pc | ||||||
|  |   breakpad-client.pc | ||||||
|  |   Makefile | ||||||
|  | ])) | ||||||
|  | 
 | ||||||
| AC_OUTPUT | AC_OUTPUT | ||||||
|  | |||||||
| @ -33,4 +33,25 @@ | |||||||
| #include "testing/gtest/include/gtest/gtest.h" | #include "testing/gtest/include/gtest/gtest.h" | ||||||
| #include "testing/include/gmock/gmock.h" | #include "testing/include/gmock/gmock.h" | ||||||
| 
 | 
 | ||||||
|  | // If AddressSanitizer is used, NULL pointer dereferences generate SIGILL
 | ||||||
|  | // (illegal instruction) instead of SIGSEGV (segmentation fault).  Also,
 | ||||||
|  | // the number of memory regions differs, so there is no point in running
 | ||||||
|  | // this test if AddressSanitizer is used.
 | ||||||
|  | //
 | ||||||
|  | // Ideally we'd use this attribute to disable ASAN on a per-func basis,
 | ||||||
|  | // but this doesn't seem to actually work, and it's changed names over
 | ||||||
|  | // time.  So just stick with disabling the actual tests.
 | ||||||
|  | // http://crbug.com/304575
 | ||||||
|  | //#define NO_ASAN __attribute__((no_sanitize_address))
 | ||||||
|  | #if defined(__clang__) && defined(__has_feature) | ||||||
|  | // Have to keep this check sep from above as newer gcc will barf on it.
 | ||||||
|  | # if __has_feature(address_sanitizer) | ||||||
|  | #  define ADDRESS_SANITIZER | ||||||
|  | # endif | ||||||
|  | #elif defined(__GNUC__) && defined(__SANITIZE_ADDRESS__) | ||||||
|  | # define ADDRESS_SANITIZER | ||||||
|  | #else | ||||||
|  | # undef ADDRESS_SANITIZER | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
| #endif  // BREAKPAD_GOOGLETEST_INCLUDES_H__
 | #endif  // BREAKPAD_GOOGLETEST_INCLUDES_H__
 | ||||||
|  | |||||||
							
								
								
									
										41
									
								
								google-breakpad/src/build/all.gyp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										41
									
								
								google-breakpad/src/build/all.gyp
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,41 @@ | |||||||
|  | # Copyright 2014 Google Inc. All rights reserved. | ||||||
|  | # | ||||||
|  | # Redistribution and use in source and binary forms, with or without | ||||||
|  | # modification, are permitted provided that the following conditions are | ||||||
|  | # met: | ||||||
|  | # | ||||||
|  | #     * Redistributions of source code must retain the above copyright | ||||||
|  | # notice, this list of conditions and the following disclaimer. | ||||||
|  | #     * Redistributions in binary form must reproduce the above | ||||||
|  | # copyright notice, this list of conditions and the following disclaimer | ||||||
|  | # in the documentation and/or other materials provided with the | ||||||
|  | # distribution. | ||||||
|  | #     * Neither the name of Google Inc. nor the names of its | ||||||
|  | # contributors may be used to endorse or promote products derived from | ||||||
|  | # this software without specific prior written permission. | ||||||
|  | # | ||||||
|  | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||||||
|  | # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||||||
|  | # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | ||||||
|  | # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | ||||||
|  | # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | ||||||
|  | # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | ||||||
|  | # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | ||||||
|  | # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | ||||||
|  | # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||||||
|  | # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | ||||||
|  | # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||||||
|  | 
 | ||||||
|  | { | ||||||
|  |   'targets': [ | ||||||
|  |     { | ||||||
|  |       'target_name': 'All', | ||||||
|  |       'type': 'none', | ||||||
|  |       'dependencies': [ | ||||||
|  |         '../common/common.gyp:*', | ||||||
|  |         '../processor/processor.gyp:*', | ||||||
|  |         '../tools/tools.gyp:*', | ||||||
|  |       ], | ||||||
|  |     }, | ||||||
|  |   ], | ||||||
|  | } | ||||||
| @ -1,5 +1,4 @@ | |||||||
| # Copyright (c) 2010, Google Inc. | # Copyright 2010 Google Inc. All rights reserved. | ||||||
| # All rights reserved. |  | ||||||
| # | # | ||||||
| # Redistribution and use in source and binary forms, with or without | # Redistribution and use in source and binary forms, with or without | ||||||
| # modification, are permitted provided that the following conditions are | # modification, are permitted provided that the following conditions are | ||||||
| @ -32,34 +31,13 @@ | |||||||
| # since gyp_chromium is automatically forcing its inclusion. | # since gyp_chromium is automatically forcing its inclusion. | ||||||
| { | { | ||||||
|   'variables': { |   'variables': { | ||||||
|     # .gyp files or targets should set chromium_code to 1 if they build |  | ||||||
|     # Chromium-specific code, as opposed to external code.  This variable is |  | ||||||
|     # used to control such things as the set of warnings to enable, and |  | ||||||
|     # whether warnings are treated as errors. |  | ||||||
|     'chromium_code%': 0, |  | ||||||
| 
 |  | ||||||
|     # Variables expected to be overriden on the GYP command line (-D) or by |     # Variables expected to be overriden on the GYP command line (-D) or by | ||||||
|     # ~/.gyp/include.gypi. |     # ~/.gyp/include.gypi. | ||||||
| 
 | 
 | ||||||
|     # Putting a variables dict inside another variables dict looks kind of |     # Putting a variables dict inside another variables dict looks kind of | ||||||
|     # weird.  This is done so that "branding" and "buildtype" are defined as |     # weird. This is necessary to get these variables defined for the conditions | ||||||
|     # variables within the outer variables dict here.  This is necessary |     # within this variables dict that operate on these variables. | ||||||
|     # to get these variables defined for the conditions within this variables |  | ||||||
|     # dict that operate on these variables. |  | ||||||
|     'variables': { |     'variables': { | ||||||
|       # Override branding to select the desired branding flavor. |  | ||||||
|       'branding%': 'Chromium', |  | ||||||
| 
 |  | ||||||
|       # Override buildtype to select the desired build flavor. |  | ||||||
|       # Dev - everyday build for development/testing |  | ||||||
|       # Official - release build (generally implies additional processing) |  | ||||||
|       # TODO(mmoss) Once 'buildtype' is fully supported (e.g. Windows gyp |  | ||||||
|       # conversion is done), some of the things which are now controlled by |  | ||||||
|       # 'branding', such as symbol generation, will need to be refactored based |  | ||||||
|       # on 'buildtype' (i.e. we don't care about saving symbols for non-Official |  | ||||||
|       # builds). |  | ||||||
|       'buildtype%': 'Dev', |  | ||||||
| 
 |  | ||||||
|       'variables': { |       'variables': { | ||||||
|         # Compute the architecture that we're building on. |         # Compute the architecture that we're building on. | ||||||
|         'conditions': [ |         'conditions': [ | ||||||
| @ -73,49 +51,19 @@ | |||||||
|             'host_arch%': 'ia32', |             'host_arch%': 'ia32', | ||||||
|           }], |           }], | ||||||
|         ], |         ], | ||||||
| 
 |  | ||||||
|         # Whether we're building a ChromeOS build.  We set the initial |  | ||||||
|         # value at this level of nesting so it's available for the |  | ||||||
|         # toolkit_views test below. |  | ||||||
|         'chromeos%': '0', |  | ||||||
|       }, |       }, | ||||||
| 
 | 
 | ||||||
|       # Set default value of toolkit_views on for Windows and Chrome OS. |  | ||||||
|       # We set it at this level of nesting so the value is available for |  | ||||||
|       # other conditionals below. |  | ||||||
|       'conditions': [ |  | ||||||
|         ['OS=="win" or chromeos==1', { |  | ||||||
|           'toolkit_views%': 1, |  | ||||||
|         }, { |  | ||||||
|           'toolkit_views%': 0, |  | ||||||
|         }], |  | ||||||
|       ], |  | ||||||
| 
 |  | ||||||
|       'host_arch%': '<(host_arch)', |       'host_arch%': '<(host_arch)', | ||||||
| 
 | 
 | ||||||
|       # Default architecture we're building for is the architecture we're |       # Default architecture we're building for is the architecture we're | ||||||
|       # building on. |       # building on. | ||||||
|       'target_arch%': '<(host_arch)', |       'target_arch%': '<(host_arch)', | ||||||
| 
 | 
 | ||||||
|       # We do want to build Chromium with Breakpad support in certain |  | ||||||
|       # situations. I.e. for Chrome bot. |  | ||||||
|       'linux_chromium_breakpad%': 0, |  | ||||||
|       # And if we want to dump symbols. |  | ||||||
|       'linux_chromium_dump_symbols%': 0, |  | ||||||
|       # Also see linux_strip_binary below. |  | ||||||
| 
 |  | ||||||
|       # Copy conditionally-set chromeos variable out one scope. |  | ||||||
|       'chromeos%': '<(chromeos)', |  | ||||||
| 
 |  | ||||||
|       # This variable tells WebCore.gyp and JavaScriptCore.gyp whether they are |       # This variable tells WebCore.gyp and JavaScriptCore.gyp whether they are | ||||||
|       # are built under a chromium full build (1) or a webkit.org chromium |       # are built under a chromium full build (1) or a webkit.org chromium | ||||||
|       # build (0). |       # build (0). | ||||||
|       'inside_chromium_build%': 1, |       'inside_chromium_build%': 1, | ||||||
| 
 | 
 | ||||||
|       # Set to 1 to enable fast builds. It disables debug info for fastest |  | ||||||
|       # compilation. |  | ||||||
|       'fastbuild%': 0, |  | ||||||
| 
 |  | ||||||
|       # Set to 1 compile with -fPIC cflag on linux. This is a must for shared |       # Set to 1 compile with -fPIC cflag on linux. This is a must for shared | ||||||
|       # libraries on linux x86-64 and arm. |       # libraries on linux x86-64 and arm. | ||||||
|       'linux_fpic%': 0, |       'linux_fpic%': 0, | ||||||
| @ -123,10 +71,10 @@ | |||||||
|       # Python version. |       # Python version. | ||||||
|       'python_ver%': '2.5', |       'python_ver%': '2.5', | ||||||
| 
 | 
 | ||||||
|       # Set ARM-v7 compilation flags |       # Determine ARM compilation flags. | ||||||
|       'armv7%': 0, |       'arm_version%': 7, | ||||||
| 
 | 
 | ||||||
|       # Set Neon compilation flags (only meaningful if armv7==1). |       # Set Neon compilation flags (only meaningful if arm_version==7). | ||||||
|       'arm_neon%': 1, |       'arm_neon%': 1, | ||||||
| 
 | 
 | ||||||
|       # The system root for cross-compiles. Default: none. |       # The system root for cross-compiles. Default: none. | ||||||
| @ -136,19 +84,12 @@ | |||||||
|       'disable_sse2%': 0, |       'disable_sse2%': 0, | ||||||
|     }, |     }, | ||||||
| 
 | 
 | ||||||
|     # Define branding and buildtype on the basis of their settings within the |  | ||||||
|     # variables sub-dict above, unless overridden. |  | ||||||
|     'branding%': '<(branding)', |  | ||||||
|     'buildtype%': '<(buildtype)', |  | ||||||
|     'target_arch%': '<(target_arch)', |     'target_arch%': '<(target_arch)', | ||||||
|     'host_arch%': '<(host_arch)', |     'host_arch%': '<(host_arch)', | ||||||
|     'toolkit_views%': '<(toolkit_views)', |  | ||||||
|     'chromeos%': '<(chromeos)', |  | ||||||
|     'inside_chromium_build%': '<(inside_chromium_build)', |     'inside_chromium_build%': '<(inside_chromium_build)', | ||||||
|     'fastbuild%': '<(fastbuild)', |  | ||||||
|     'linux_fpic%': '<(linux_fpic)', |     'linux_fpic%': '<(linux_fpic)', | ||||||
|     'python_ver%': '<(python_ver)', |     'python_ver%': '<(python_ver)', | ||||||
|     'armv7%': '<(armv7)', |     'arm_version%': '<(arm_version)', | ||||||
|     'arm_neon%': '<(arm_neon)', |     'arm_neon%': '<(arm_neon)', | ||||||
|     'sysroot%': '<(sysroot)', |     'sysroot%': '<(sysroot)', | ||||||
|     'disable_sse2%': '<(disable_sse2)', |     'disable_sse2%': '<(disable_sse2)', | ||||||
| @ -245,7 +186,7 @@ | |||||||
|     'linux_use_seccomp_sandbox%': 0, |     'linux_use_seccomp_sandbox%': 0, | ||||||
| 
 | 
 | ||||||
|     # Set to select the Title Case versions of strings in GRD files. |     # Set to select the Title Case versions of strings in GRD files. | ||||||
|     'use_titlecase_in_grd_files%': 0, |     'use_titlecase_in_grd%': 0, | ||||||
| 
 | 
 | ||||||
|     # Used to disable Native Client at compile time, for platforms where it |     # Used to disable Native Client at compile time, for platforms where it | ||||||
|     # isn't supported |     # isn't supported | ||||||
| @ -254,7 +195,7 @@ | |||||||
|     # Set Thumb compilation flags. |     # Set Thumb compilation flags. | ||||||
|     'arm_thumb%': 0, |     'arm_thumb%': 0, | ||||||
| 
 | 
 | ||||||
|     # Set ARM fpu compilation flags (only meaningful if armv7==1 and |     # Set ARM fpu compilation flags (only meaningful if arm_version==7 and | ||||||
|     # arm_neon==0). |     # arm_neon==0). | ||||||
|     'arm_fpu%': 'vfpv3', |     'arm_fpu%': 'vfpv3', | ||||||
| 
 | 
 | ||||||
| @ -262,62 +203,6 @@ | |||||||
|     'enable_new_npdevice_api%': 0, |     'enable_new_npdevice_api%': 0, | ||||||
| 
 | 
 | ||||||
|     'conditions': [ |     'conditions': [ | ||||||
|       ['OS=="linux" or OS=="freebsd" or OS=="openbsd"', { |  | ||||||
|         # This will set gcc_version to XY if you are running gcc X.Y.*. |  | ||||||
|         # This is used to tweak build flags for gcc 4.4. |  | ||||||
|         'gcc_version%': '<!(python <(DEPTH)/build/compiler_version.py)', |  | ||||||
|         # Figure out the python architecture to decide if we build pyauto. |  | ||||||
|         'python_arch%': '<!(<(DEPTH)/build/linux/python_arch.sh <(sysroot)/usr/lib/libpython<(python_ver).so.1.0)', |  | ||||||
|         'conditions': [ |  | ||||||
|           ['branding=="Chrome" or linux_chromium_breakpad==1', { |  | ||||||
|             'linux_breakpad%': 1, |  | ||||||
|           }, { |  | ||||||
|             'linux_breakpad%': 0, |  | ||||||
|           }], |  | ||||||
|           # All Chrome builds have breakpad symbols, but only process the |  | ||||||
|           # symbols from official builds. |  | ||||||
|           # TODO(mmoss) dump_syms segfaults on x64. Enable once dump_syms and |  | ||||||
|           # crash server handle 64-bit symbols. |  | ||||||
|           ['linux_chromium_dump_symbols==1 or ' |  | ||||||
|            '(branding=="Chrome" and buildtype=="Official" and ' |  | ||||||
|            'target_arch=="ia32")', { |  | ||||||
|             'linux_dump_symbols%': 1, |  | ||||||
|           }, { |  | ||||||
|             'linux_dump_symbols%': 0, |  | ||||||
|           }], |  | ||||||
|           ['toolkit_views==0', { |  | ||||||
|             # GTK wants Title Case strings |  | ||||||
|             'use_titlecase_in_grd_files%': 1, |  | ||||||
|           }], |  | ||||||
|         ], |  | ||||||
|       }],  # OS=="linux" or OS=="freebsd" or OS=="openbsd" |  | ||||||
|       ['OS=="mac"', { |  | ||||||
|         # Mac wants Title Case strings |  | ||||||
|         'use_titlecase_in_grd_files%': 1, |  | ||||||
|         'conditions': [ |  | ||||||
|           # mac_product_name is set to the name of the .app bundle as it should |  | ||||||
|           # appear on disk.  This duplicates data from |  | ||||||
|           # chrome/app/theme/chromium/BRANDING and |  | ||||||
|           # chrome/app/theme/google_chrome/BRANDING, but is necessary to get |  | ||||||
|           # these names into the build system. |  | ||||||
|           ['branding=="Chrome"', { |  | ||||||
|             'mac_product_name%': 'Google Chrome', |  | ||||||
|           }, { # else: branding!="Chrome" |  | ||||||
|             'mac_product_name%': 'Chromium', |  | ||||||
|           }], |  | ||||||
| 
 |  | ||||||
|           # Feature variables for enabling Mac Breakpad and Keystone auto-update |  | ||||||
|           # support.  Both features are on by default in official builds with |  | ||||||
|           # Chrome branding. |  | ||||||
|           ['branding=="Chrome" and buildtype=="Official"', { |  | ||||||
|             'mac_breakpad%': 1, |  | ||||||
|             'mac_keystone%': 1, |  | ||||||
|           }, { # else: branding!="Chrome" or buildtype!="Official" |  | ||||||
|             'mac_breakpad%': 0, |  | ||||||
|             'mac_keystone%': 0, |  | ||||||
|           }], |  | ||||||
|         ], |  | ||||||
|       }],  # OS=="mac" |  | ||||||
|       # Whether to use multiple cores to compile with visual studio. This is |       # Whether to use multiple cores to compile with visual studio. This is | ||||||
|       # optional because it sometimes causes corruption on VS 2005. |       # optional because it sometimes causes corruption on VS 2005. | ||||||
|       # It is on by default on VS 2008 and off on VS 2005. |       # It is on by default on VS 2008 and off on VS 2005. | ||||||
| @ -341,24 +226,6 @@ | |||||||
|           'NACL_WIN64', |           'NACL_WIN64', | ||||||
|         ], |         ], | ||||||
|       }], |       }], | ||||||
|       # Compute based on OS and target architecture whether the GPU |  | ||||||
|       # plugin / process is supported. |  | ||||||
|       [ 'OS=="win" or (OS=="linux" and target_arch!="arm") or OS=="mac"', { |  | ||||||
|         # Enable a variable used elsewhere throughout the GYP files to determine |  | ||||||
|         # whether to compile in the sources for the GPU plugin / process. |  | ||||||
|         'enable_gpu%': 1, |  | ||||||
|       }, {  # GPU plugin not supported |  | ||||||
|         'enable_gpu%': 0, |  | ||||||
|       }], |  | ||||||
|       # Compute based on OS, target architecture and device whether GLES |  | ||||||
|       # is supported |  | ||||||
|       [ 'OS=="linux" and target_arch=="arm" and chromeos==1', { |  | ||||||
|         # Enable a variable used elsewhere throughout the GYP files to determine |  | ||||||
|         # whether to compile in the sources for the GLES support. |  | ||||||
|         'enable_gles%': 1, |  | ||||||
|       }, {  # GLES not supported |  | ||||||
|         'enable_gles%': 0, |  | ||||||
|       }], |  | ||||||
|     ], |     ], | ||||||
| 
 | 
 | ||||||
|     # NOTE: When these end up in the Mac bundle, we need to replace '-' for '_' |     # NOTE: When these end up in the Mac bundle, we need to replace '-' for '_' | ||||||
| @ -373,18 +240,10 @@ | |||||||
|     ], |     ], | ||||||
|   }, |   }, | ||||||
|   'target_defaults': { |   'target_defaults': { | ||||||
|  |     'includes': [ | ||||||
|  |       'filename_rules.gypi', | ||||||
|  |     ], | ||||||
|     'variables': { |     'variables': { | ||||||
|       # The condition that operates on chromium_code is in a target_conditions |  | ||||||
|       # section, and will not have access to the default fallback value of |  | ||||||
|       # chromium_code at the top of this file, or to the chromium_code |  | ||||||
|       # variable placed at the root variables scope of .gyp files, because |  | ||||||
|       # those variables are not set at target scope.  As a workaround, |  | ||||||
|       # if chromium_code is not set at target scope, define it in target scope |  | ||||||
|       # to contain whatever value it has during early variable expansion. |  | ||||||
|       # That's enough to make it available during target conditional |  | ||||||
|       # processing. |  | ||||||
|       'chromium_code%': '<(chromium_code)', |  | ||||||
| 
 |  | ||||||
|       # See http://gcc.gnu.org/onlinedocs/gcc-4.4.2/gcc/Optimize-Options.html |       # See http://gcc.gnu.org/onlinedocs/gcc-4.4.2/gcc/Optimize-Options.html | ||||||
|       'mac_release_optimization%': '3', # Use -O3 unless overridden |       'mac_release_optimization%': '3', # Use -O3 unless overridden | ||||||
|       'mac_debug_optimization%': '0',   # Use -O0 unless overridden |       'mac_debug_optimization%': '0',   # Use -O0 unless overridden | ||||||
| @ -400,34 +259,6 @@ | |||||||
|       'release_valgrind_build%': 0, |       'release_valgrind_build%': 0, | ||||||
|     }, |     }, | ||||||
|     'conditions': [ |     'conditions': [ | ||||||
|       ['branding=="Chrome"', { |  | ||||||
|         'defines': ['GOOGLE_CHROME_BUILD'], |  | ||||||
|       }, {  # else: branding!="Chrome" |  | ||||||
|         'defines': ['CHROMIUM_BUILD'], |  | ||||||
|       }], |  | ||||||
|       ['toolkit_views==1', { |  | ||||||
|         'defines': ['TOOLKIT_VIEWS=1'], |  | ||||||
|       }], |  | ||||||
|       ['chromeos==1', { |  | ||||||
|         'defines': ['OS_CHROMEOS=1'], |  | ||||||
|       }], |  | ||||||
|       ['fastbuild!=0', { |  | ||||||
|         'conditions': [ |  | ||||||
|           # Finally, for Windows, we simply turn on profiling. |  | ||||||
|           ['OS=="win"', { |  | ||||||
|             'msvs_settings': { |  | ||||||
|               'VCLinkerTool': { |  | ||||||
|                 'GenerateDebugInformation': 'false', |  | ||||||
|               }, |  | ||||||
|               'VCCLCompilerTool': { |  | ||||||
|                 'DebugInformationFormat': '0', |  | ||||||
|               } |  | ||||||
|             } |  | ||||||
|           }, { # else: OS != "win" |  | ||||||
|             'cflags': [ '-g1' ], |  | ||||||
|           }], |  | ||||||
|         ],  # conditions for fastbuild. |  | ||||||
|       }],  # fastbuild!=0 |  | ||||||
|       ['selinux==1', { |       ['selinux==1', { | ||||||
|         'defines': ['CHROMIUM_SELINUX=1'], |         'defines': ['CHROMIUM_SELINUX=1'], | ||||||
|       }], |       }], | ||||||
| @ -438,16 +269,6 @@ | |||||||
|           }], |           }], | ||||||
|         ], |         ], | ||||||
|       }], |       }], | ||||||
|       ['enable_gpu==1', { |  | ||||||
|         'defines': [ |  | ||||||
|           'ENABLE_GPU=1', |  | ||||||
|         ], |  | ||||||
|       }], |  | ||||||
|       ['enable_gles==1', { |  | ||||||
|         'defines': [ |  | ||||||
|           'ENABLE_GLES=1', |  | ||||||
|         ], |  | ||||||
|       }], |  | ||||||
|       ['coverage!=0', { |       ['coverage!=0', { | ||||||
|         'conditions': [ |         'conditions': [ | ||||||
|           ['OS=="mac"', { |           ['OS=="mac"', { | ||||||
| @ -489,8 +310,6 @@ | |||||||
|       }],  # coverage!=0 |       }],  # coverage!=0 | ||||||
|     ],  # conditions for 'target_defaults' |     ],  # conditions for 'target_defaults' | ||||||
|     'target_conditions': [ |     'target_conditions': [ | ||||||
|       ['chromium_code==0', { |  | ||||||
|         'conditions': [ |  | ||||||
|       [ 'OS=="linux" or OS=="freebsd" or OS=="openbsd"', { |       [ 'OS=="linux" or OS=="freebsd" or OS=="openbsd"', { | ||||||
|         'cflags!': [ |         'cflags!': [ | ||||||
|           '-Wall', |           '-Wall', | ||||||
| @ -503,11 +322,13 @@ | |||||||
|           '_CRT_SECURE_NO_DEPRECATE', |           '_CRT_SECURE_NO_DEPRECATE', | ||||||
|           '_CRT_NONSTDC_NO_WARNINGS', |           '_CRT_NONSTDC_NO_WARNINGS', | ||||||
|           '_CRT_NONSTDC_NO_DEPRECATE', |           '_CRT_NONSTDC_NO_DEPRECATE', | ||||||
|  |           # This is required for ATL to use XP-safe versions of its functions. | ||||||
|  |           '_USING_V110_SDK71_', | ||||||
|         ], |         ], | ||||||
|         'msvs_disabled_warnings': [4800], |         'msvs_disabled_warnings': [4800], | ||||||
|         'msvs_settings': { |         'msvs_settings': { | ||||||
|           'VCCLCompilerTool': { |           'VCCLCompilerTool': { | ||||||
|                 'WarnAsError': 'false', |             'WarnAsError': 'true', | ||||||
|             'Detect64BitPortabilityProblems': 'false', |             'Detect64BitPortabilityProblems': 'false', | ||||||
|           }, |           }, | ||||||
|         }, |         }, | ||||||
| @ -518,54 +339,6 @@ | |||||||
|           'WARNING_CFLAGS!': ['-Wall'], |           'WARNING_CFLAGS!': ['-Wall'], | ||||||
|         }, |         }, | ||||||
|       }], |       }], | ||||||
|         ], |  | ||||||
|       }, { |  | ||||||
|         # In Chromium code, we define __STDC_FORMAT_MACROS in order to get the |  | ||||||
|         # C99 macros on Mac and Linux. |  | ||||||
|         'defines': [ |  | ||||||
|           '__STDC_FORMAT_MACROS', |  | ||||||
|         ], |  | ||||||
|         'conditions': [ |  | ||||||
|           ['OS!="win"', { |  | ||||||
|             'sources/': [ ['exclude', '_win(_unittest)?\\.cc$'], |  | ||||||
|                           ['exclude', '/win/'], |  | ||||||
|                           ['exclude', '/win_[^/]*\\.cc$'] ], |  | ||||||
|           }], |  | ||||||
|           ['OS!="mac"', { |  | ||||||
|             'sources/': [ ['exclude', '_(cocoa|mac)(_unittest)?\\.cc$'], |  | ||||||
|                           ['exclude', '/(cocoa|mac)/'], |  | ||||||
|                           ['exclude', '\.mm?$' ] ], |  | ||||||
|           }], |  | ||||||
|           ['OS!="linux" and OS!="freebsd" and OS!="openbsd"', { |  | ||||||
|             'sources/': [ |  | ||||||
|               ['exclude', '_(chromeos|gtk|x|x11|xdg)(_unittest)?\\.cc$'], |  | ||||||
|               ['exclude', '/gtk/'], |  | ||||||
|               ['exclude', '/(gtk|x11)_[^/]*\\.cc$'], |  | ||||||
|             ], |  | ||||||
|           }], |  | ||||||
|           ['OS!="linux"', { |  | ||||||
|             'sources/': [ |  | ||||||
|               ['exclude', '_linux(_unittest)?\\.cc$'], |  | ||||||
|               ['exclude', '/linux/'], |  | ||||||
|             ], |  | ||||||
|           }], |  | ||||||
|           # We use "POSIX" to refer to all non-Windows operating systems. |  | ||||||
|           ['OS=="win"', { |  | ||||||
|             'sources/': [ ['exclude', '_posix\\.cc$'] ], |  | ||||||
|           }], |  | ||||||
|           # Though Skia is conceptually shared by Linux and Windows, |  | ||||||
|           # the only _skia files in our tree are Linux-specific. |  | ||||||
|           ['OS!="linux" and OS!="freebsd" and OS!="openbsd"', { |  | ||||||
|             'sources/': [ ['exclude', '_skia\\.cc$'] ], |  | ||||||
|           }], |  | ||||||
|           ['chromeos!=1', { |  | ||||||
|             'sources/': [ ['exclude', '_chromeos\\.cc$'] ] |  | ||||||
|           }], |  | ||||||
|           ['toolkit_views==0', { |  | ||||||
|             'sources/': [ ['exclude', '_views\\.cc$'] ] |  | ||||||
|           }], |  | ||||||
|         ], |  | ||||||
|       }], |  | ||||||
|     ],  # target_conditions for 'target_defaults' |     ],  # target_conditions for 'target_defaults' | ||||||
|     'default_configuration': 'Debug', |     'default_configuration': 'Debug', | ||||||
|     'configurations': { |     'configurations': { | ||||||
| @ -590,6 +363,7 @@ | |||||||
|         'abstract': 1, |         'abstract': 1, | ||||||
|         'msvs_settings': { |         'msvs_settings': { | ||||||
|           'VCLinkerTool': { |           'VCLinkerTool': { | ||||||
|  |             'MinimumRequiredVersion': '5.01',  # XP. | ||||||
|             'TargetMachine': '1', |             'TargetMachine': '1', | ||||||
|           }, |           }, | ||||||
|         }, |         }, | ||||||
| @ -715,7 +489,30 @@ | |||||||
|         'inherit_from': ['Common_Base', 'x86_Base', 'Release_Base'], |         'inherit_from': ['Common_Base', 'x86_Base', 'Release_Base'], | ||||||
|         'conditions': [ |         'conditions': [ | ||||||
|           ['msvs_use_common_release', { |           ['msvs_use_common_release', { | ||||||
|             'includes': ['release.gypi'], |             'defines': ['OFFICIAL_BUILD'], | ||||||
|  |             'msvs_settings': { | ||||||
|  |               'VCCLCompilerTool': { | ||||||
|  |                 'Optimization': '3', | ||||||
|  |                 'StringPooling': 'true', | ||||||
|  |                 'OmitFramePointers': 'true', | ||||||
|  |                 'InlineFunctionExpansion': '2', | ||||||
|  |                 'EnableIntrinsicFunctions': 'true', | ||||||
|  |                 'FavorSizeOrSpeed': '2', | ||||||
|  |                 'OmitFramePointers': 'true', | ||||||
|  |                 'EnableFiberSafeOptimizations': 'true', | ||||||
|  |                 'WholeProgramOptimization': 'true', | ||||||
|  |               }, | ||||||
|  |               'VCLibrarianTool': { | ||||||
|  |                 'AdditionalOptions': ['/ltcg', '/expectedoutputsize:120000000'], | ||||||
|  |               }, | ||||||
|  |               'VCLinkerTool': { | ||||||
|  |                 'LinkIncremental': '1', | ||||||
|  |                 'OptimizeReferences': '2', | ||||||
|  |                 'EnableCOMDATFolding': '2', | ||||||
|  |                 'OptimizeForWindows98': '1', | ||||||
|  |                 'LinkTimeCodeGeneration': '1', | ||||||
|  |               }, | ||||||
|  |             }, | ||||||
|           }], |           }], | ||||||
|         ] |         ] | ||||||
|       }, |       }, | ||||||
| @ -773,7 +570,7 @@ | |||||||
|           '-fvisibility=hidden', |           '-fvisibility=hidden', | ||||||
|         ], |         ], | ||||||
|         'cflags_cc': [ |         'cflags_cc': [ | ||||||
|           '-fno-rtti', |           '-frtti', | ||||||
|           '-fno-threadsafe-statics', |           '-fno-threadsafe-statics', | ||||||
|           # Make inline functions have hidden visiblity by default. |           # Make inline functions have hidden visiblity by default. | ||||||
|           # Surprisingly, not covered by -fvisibility=hidden. |           # Surprisingly, not covered by -fvisibility=hidden. | ||||||
| @ -821,12 +618,6 @@ | |||||||
|                            '$_LIBDIRFLAGS', '$LDMODULEFLAGS', '$SOURCES', |                            '$_LIBDIRFLAGS', '$LDMODULEFLAGS', '$SOURCES', | ||||||
|                            '-Wl,--start-group', '$_LIBFLAGS', '-Wl,--end-group']], |                            '-Wl,--start-group', '$_LIBFLAGS', '-Wl,--end-group']], | ||||||
|           'IMPLICIT_COMMAND_DEPENDENCIES': 0, |           'IMPLICIT_COMMAND_DEPENDENCIES': 0, | ||||||
|           # -rpath is only used when building with shared libraries. |  | ||||||
|           'conditions': [ |  | ||||||
|             [ 'component=="shared_library"', { |  | ||||||
|               'RPATH': '$LIB_DIR', |  | ||||||
|             }], |  | ||||||
|           ], |  | ||||||
|         }, |         }, | ||||||
|         'scons_import_variables': [ |         'scons_import_variables': [ | ||||||
|           'AS', |           'AS', | ||||||
| @ -932,22 +723,13 @@ | |||||||
|             # compiler optimized the code, since the value is always kept |             # compiler optimized the code, since the value is always kept | ||||||
|             # in its specified precision. |             # in its specified precision. | ||||||
|             'conditions': [ |             'conditions': [ | ||||||
|               ['branding=="Chromium" and disable_sse2==0', { |               ['disable_sse2==0', { | ||||||
|                 'cflags': [ |                 'cflags': [ | ||||||
|                   '-march=pentium4', |                   '-march=pentium4', | ||||||
|                   '-msse2', |                   '-msse2', | ||||||
|                   '-mfpmath=sse', |                   '-mfpmath=sse', | ||||||
|                 ], |                 ], | ||||||
|               }], |               }], | ||||||
|               # ChromeOS targets Pinetrail, which is sse3, but most of the |  | ||||||
|               # benefit comes from sse2 so this setting allows ChromeOS |  | ||||||
|               # to build on other CPUs.  In the future -march=atom would help |  | ||||||
|               # but requires a newer compiler. |  | ||||||
|               ['chromeos==1 and disable_sse2==0', { |  | ||||||
|                 'cflags': [ |  | ||||||
|                   '-msse2', |  | ||||||
|                 ], |  | ||||||
|               }], |  | ||||||
|             ], |             ], | ||||||
|             # -mmmx allows mmintrin.h to be used for mmx intrinsics. |             # -mmmx allows mmintrin.h to be used for mmx intrinsics. | ||||||
|             # video playback is mmx and sse2 optimized. |             # video playback is mmx and sse2 optimized. | ||||||
| @ -980,7 +762,7 @@ | |||||||
|                     '-Wa,-mimplicit-it=thumb', |                     '-Wa,-mimplicit-it=thumb', | ||||||
|                     ] |                     ] | ||||||
|                   }], |                   }], | ||||||
|                   ['armv7==1', { |                   ['arm_version==7', { | ||||||
|                     'cflags': [ |                     'cflags': [ | ||||||
|                       '-march=armv7-a', |                       '-march=armv7-a', | ||||||
|                       '-mtune=cortex-a8', |                       '-mtune=cortex-a8', | ||||||
| @ -1019,24 +801,6 @@ | |||||||
|               '-fno-strict-aliasing', |               '-fno-strict-aliasing', | ||||||
|             ], |             ], | ||||||
|           }], |           }], | ||||||
|           ['linux_breakpad==1', { |  | ||||||
|             'cflags': [ '-gstabs' ], |  | ||||||
|             'defines': ['USE_LINUX_BREAKPAD'], |  | ||||||
|           }], |  | ||||||
|           ['linux_use_seccomp_sandbox==1 and buildtype!="Official"', { |  | ||||||
|             'defines': ['USE_SECCOMP_SANDBOX'], |  | ||||||
|           }], |  | ||||||
|           ['library=="shared_library"', { |  | ||||||
|             # When building with shared libraries, remove the visiblity-hiding |  | ||||||
|             # flag. |  | ||||||
|             'cflags!': [ '-fvisibility=hidden' ], |  | ||||||
|             'conditions': [ |  | ||||||
|               ['target_arch=="x64" or target_arch=="arm"', { |  | ||||||
|                 # Shared libraries need -fPIC on x86-64 and arm |  | ||||||
|                 'cflags': ['-fPIC'] |  | ||||||
|               }] |  | ||||||
|             ], |  | ||||||
|           }], |  | ||||||
|           ['linux_use_heapchecker==1', { |           ['linux_use_heapchecker==1', { | ||||||
|             'variables': {'linux_use_tcmalloc%': 1}, |             'variables': {'linux_use_tcmalloc%': 1}, | ||||||
|           }], |           }], | ||||||
| @ -1078,7 +842,7 @@ | |||||||
|           'GCC_DYNAMIC_NO_PIC': 'NO',               # No -mdynamic-no-pic |           'GCC_DYNAMIC_NO_PIC': 'NO',               # No -mdynamic-no-pic | ||||||
|                                                     # (Equivalent to -fPIC) |                                                     # (Equivalent to -fPIC) | ||||||
|           'GCC_ENABLE_CPP_EXCEPTIONS': 'NO',        # -fno-exceptions |           'GCC_ENABLE_CPP_EXCEPTIONS': 'NO',        # -fno-exceptions | ||||||
|           'GCC_ENABLE_CPP_RTTI': 'NO',              # -fno-rtti |           'GCC_ENABLE_CPP_RTTI': 'YES',             # -frtti | ||||||
|           'GCC_ENABLE_PASCAL_STRINGS': 'NO',        # No -mpascal-strings |           'GCC_ENABLE_PASCAL_STRINGS': 'NO',        # No -mpascal-strings | ||||||
|           # GCC_INLINES_ARE_PRIVATE_EXTERN maps to -fvisibility-inlines-hidden |           # GCC_INLINES_ARE_PRIVATE_EXTERN maps to -fvisibility-inlines-hidden | ||||||
|           'GCC_INLINES_ARE_PRIVATE_EXTERN': 'YES', |           'GCC_INLINES_ARE_PRIVATE_EXTERN': 'YES', | ||||||
| @ -1106,51 +870,6 @@ | |||||||
|           ['_mac_bundle', { |           ['_mac_bundle', { | ||||||
|             'xcode_settings': {'OTHER_LDFLAGS': ['-Wl,-ObjC']}, |             'xcode_settings': {'OTHER_LDFLAGS': ['-Wl,-ObjC']}, | ||||||
|           }], |           }], | ||||||
|           ['_type=="executable" or _type=="shared_library"', { |  | ||||||
|             'target_conditions': [ |  | ||||||
|               ['mac_real_dsym == 1', { |  | ||||||
|                 # To get a real .dSYM bundle produced by dsymutil, set the |  | ||||||
|                 # debug information format to dwarf-with-dsym.  Since |  | ||||||
|                 # strip_from_xcode will not be used, set Xcode to do the |  | ||||||
|                 # stripping as well. |  | ||||||
|                 'configurations': { |  | ||||||
|                   'Release_Base': { |  | ||||||
|                     'xcode_settings': { |  | ||||||
|                       'DEBUG_INFORMATION_FORMAT': 'dwarf-with-dsym', |  | ||||||
|                       'DEPLOYMENT_POSTPROCESSING': 'YES', |  | ||||||
|                       'STRIP_INSTALLED_PRODUCT': 'YES', |  | ||||||
|                       'target_conditions': [ |  | ||||||
|                         ['_type=="shared_library"', { |  | ||||||
|                           # The Xcode default is to strip debugging symbols |  | ||||||
|                           # only (-S).  Local symbols should be stripped as |  | ||||||
|                           # well, which will be handled by -x.  Xcode will |  | ||||||
|                           # continue to insert -S when stripping even when |  | ||||||
|                           # additional flags are added with STRIPFLAGS. |  | ||||||
|                           'STRIPFLAGS': '-x', |  | ||||||
|                         }],  # _type=="shared_library" |  | ||||||
|                       ],  # target_conditions |  | ||||||
|                     },  # xcode_settings |  | ||||||
|                   },  # configuration "Release" |  | ||||||
|                 },  # configurations |  | ||||||
|               }, {  # mac_real_dsym != 1 |  | ||||||
|                 # To get a fast fake .dSYM bundle, use a post-build step to |  | ||||||
|                 # produce the .dSYM and strip the executable.  strip_from_xcode |  | ||||||
|                 # only operates in the Release configuration. |  | ||||||
|                 'postbuilds': [ |  | ||||||
|                   { |  | ||||||
|                     'variables': { |  | ||||||
|                       # Define strip_from_xcode in a variable ending in _path |  | ||||||
|                       # so that gyp understands it's a path and performs proper |  | ||||||
|                       # relativization during dict merging. |  | ||||||
|                       'strip_from_xcode_path': 'mac/strip_from_xcode', |  | ||||||
|                     }, |  | ||||||
|                     'postbuild_name': 'Strip If Needed', |  | ||||||
|                     'action': ['<(strip_from_xcode_path)'], |  | ||||||
|                   }, |  | ||||||
|                 ],  # postbuilds |  | ||||||
|               }],  # mac_real_dsym |  | ||||||
|             ],  # target_conditions |  | ||||||
|           }],  # _type=="executable" or _type=="shared_library" |  | ||||||
|         ],  # target_conditions |         ],  # target_conditions | ||||||
|       },  # target_defaults |       },  # target_defaults | ||||||
|     }],  # OS=="mac" |     }],  # OS=="mac" | ||||||
| @ -1174,7 +893,9 @@ | |||||||
|           '$(VSInstallDir)/VC/atlmfc/include', |           '$(VSInstallDir)/VC/atlmfc/include', | ||||||
|         ], |         ], | ||||||
|         'msvs_cygwin_dirs': ['<(DEPTH)/third_party/cygwin'], |         'msvs_cygwin_dirs': ['<(DEPTH)/third_party/cygwin'], | ||||||
|         'msvs_disabled_warnings': [4396, 4503, 4819], |         'msvs_disabled_warnings': [ | ||||||
|  |           4100, 4127, 4396, 4503, 4512, 4819, 4995, 4702 | ||||||
|  |         ], | ||||||
|         'msvs_settings': { |         'msvs_settings': { | ||||||
|           'VCCLCompilerTool': { |           'VCCLCompilerTool': { | ||||||
|             'MinimalRebuild': 'false', |             'MinimalRebuild': 'false', | ||||||
| @ -1182,7 +903,7 @@ | |||||||
|             'BufferSecurityCheck': 'true', |             'BufferSecurityCheck': 'true', | ||||||
|             'EnableFunctionLevelLinking': 'true', |             'EnableFunctionLevelLinking': 'true', | ||||||
|             'RuntimeTypeInfo': 'false', |             'RuntimeTypeInfo': 'false', | ||||||
|             'WarningLevel': '3', |             'WarningLevel': '4', | ||||||
|             'WarnAsError': 'true', |             'WarnAsError': 'true', | ||||||
|             'DebugInformationFormat': '3', |             'DebugInformationFormat': '3', | ||||||
|             'conditions': [ |             'conditions': [ | ||||||
| @ -1322,9 +1043,3 @@ | |||||||
|     'SYMROOT': '<(DEPTH)/xcodebuild', |     'SYMROOT': '<(DEPTH)/xcodebuild', | ||||||
|   }, |   }, | ||||||
| } | } | ||||||
| 
 |  | ||||||
| # Local Variables: |  | ||||||
| # tab-width:2 |  | ||||||
| # indent-tabs-mode:nil |  | ||||||
| # End: |  | ||||||
| # vim: set expandtab tabstop=2 shiftwidth=2: |  | ||||||
							
								
								
									
										57
									
								
								google-breakpad/src/build/filename_rules.gypi
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										57
									
								
								google-breakpad/src/build/filename_rules.gypi
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,57 @@ | |||||||
|  | # Copyright 2014 Google Inc. All rights reserved. | ||||||
|  | # | ||||||
|  | # Redistribution and use in source and binary forms, with or without | ||||||
|  | # modification, are permitted provided that the following conditions are | ||||||
|  | # met: | ||||||
|  | # | ||||||
|  | #     * Redistributions of source code must retain the above copyright | ||||||
|  | # notice, this list of conditions and the following disclaimer. | ||||||
|  | #     * Redistributions in binary form must reproduce the above | ||||||
|  | # copyright notice, this list of conditions and the following disclaimer | ||||||
|  | # in the documentation and/or other materials provided with the | ||||||
|  | # distribution. | ||||||
|  | #     * Neither the name of Google Inc. nor the names of its | ||||||
|  | # contributors may be used to endorse or promote products derived from | ||||||
|  | # this software without specific prior written permission. | ||||||
|  | # | ||||||
|  | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||||||
|  | # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||||||
|  | # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | ||||||
|  | # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | ||||||
|  | # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | ||||||
|  | # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | ||||||
|  | # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | ||||||
|  | # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | ||||||
|  | # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||||||
|  | # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | ||||||
|  | # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||||||
|  | 
 | ||||||
|  | { | ||||||
|  |   'target_conditions': [ | ||||||
|  |     ['OS!="win"', { | ||||||
|  |       'sources/': [ | ||||||
|  |         ['exclude', '(^|/)windows/'], | ||||||
|  |       ], | ||||||
|  |     }], | ||||||
|  |     ['OS!="linux"', { | ||||||
|  |       'sources/': [ | ||||||
|  |         ['exclude', '(^|/)linux/'], | ||||||
|  |       ], | ||||||
|  |     }], | ||||||
|  |     ['OS!="mac"', { | ||||||
|  |       'sources/': [ | ||||||
|  |         ['exclude', '(^|/)mac/'], | ||||||
|  |       ], | ||||||
|  |     }], | ||||||
|  |     ['OS!="android"', { | ||||||
|  |       'sources/': [ | ||||||
|  |         ['exclude', '(^|/)android/'], | ||||||
|  |       ], | ||||||
|  |     }], | ||||||
|  |     ['OS!="solaris"', { | ||||||
|  |       'sources/': [ | ||||||
|  |         ['exclude', '(^|/)solaris/'], | ||||||
|  |       ], | ||||||
|  |     }], | ||||||
|  |   ], | ||||||
|  | } | ||||||
							
								
								
									
										67
									
								
								google-breakpad/src/build/gyp_breakpad
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										67
									
								
								google-breakpad/src/build/gyp_breakpad
									
									
									
									
									
										Executable file
									
								
							| @ -0,0 +1,67 @@ | |||||||
|  | #!/usr/bin/env python | ||||||
|  | 
 | ||||||
|  | # Copyright 2014 Google Inc. All rights reserved. | ||||||
|  | # | ||||||
|  | # Redistribution and use in source and binary forms, with or without | ||||||
|  | # modification, are permitted provided that the following conditions are | ||||||
|  | # met: | ||||||
|  | # | ||||||
|  | #     * Redistributions of source code must retain the above copyright | ||||||
|  | # notice, this list of conditions and the following disclaimer. | ||||||
|  | #     * Redistributions in binary form must reproduce the above | ||||||
|  | # copyright notice, this list of conditions and the following disclaimer | ||||||
|  | # in the documentation and/or other materials provided with the | ||||||
|  | # distribution. | ||||||
|  | #     * Neither the name of Google Inc. nor the names of its | ||||||
|  | # contributors may be used to endorse or promote products derived from | ||||||
|  | # this software without specific prior written permission. | ||||||
|  | # | ||||||
|  | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||||||
|  | # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||||||
|  | # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | ||||||
|  | # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | ||||||
|  | # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | ||||||
|  | # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | ||||||
|  | # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | ||||||
|  | # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | ||||||
|  | # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||||||
|  | # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | ||||||
|  | # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||||||
|  | 
 | ||||||
|  | import os | ||||||
|  | import platform | ||||||
|  | import sys | ||||||
|  | 
 | ||||||
|  | script_dir = os.path.dirname(os.path.realpath(__file__)) | ||||||
|  | breakpad_root = os.path.abspath(os.path.join(script_dir, os.pardir)) | ||||||
|  | 
 | ||||||
|  | sys.path.insert(0, os.path.join(breakpad_root, 'tools', 'gyp', 'pylib')) | ||||||
|  | import gyp | ||||||
|  | 
 | ||||||
|  | def run_gyp(args): | ||||||
|  |   rc = gyp.main(args) | ||||||
|  |   if rc != 0: | ||||||
|  |     print 'Error running GYP' | ||||||
|  |     sys.exit(rc) | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | def main(): | ||||||
|  |   args = sys.argv[1:] | ||||||
|  |   args.append(os.path.join(script_dir, 'all.gyp')) | ||||||
|  | 
 | ||||||
|  |   args.append('-I') | ||||||
|  |   args.append(os.path.join(breakpad_root, 'build', 'common.gypi')) | ||||||
|  | 
 | ||||||
|  |   args.extend(['-D', 'gyp_output_dir=out']) | ||||||
|  | 
 | ||||||
|  |   # Set the GYP DEPTH variable to the root of the project. | ||||||
|  |   args.append('--depth=' + os.path.relpath(breakpad_root)) | ||||||
|  | 
 | ||||||
|  |   print 'Updating projects from gyp files...' | ||||||
|  |   sys.stdout.flush() | ||||||
|  | 
 | ||||||
|  |   run_gyp(args) | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | if __name__ == '__main__': | ||||||
|  |   sys.exit(main()) | ||||||
							
								
								
									
										90
									
								
								google-breakpad/src/build/testing.gypi
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										90
									
								
								google-breakpad/src/build/testing.gypi
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,90 @@ | |||||||
|  | # Copyright 2014 Google Inc. All rights reserved. | ||||||
|  | # | ||||||
|  | # Redistribution and use in source and binary forms, with or without | ||||||
|  | # modification, are permitted provided that the following conditions are | ||||||
|  | # met: | ||||||
|  | # | ||||||
|  | #     * Redistributions of source code must retain the above copyright | ||||||
|  | # notice, this list of conditions and the following disclaimer. | ||||||
|  | #     * Redistributions in binary form must reproduce the above | ||||||
|  | # copyright notice, this list of conditions and the following disclaimer | ||||||
|  | # in the documentation and/or other materials provided with the | ||||||
|  | # distribution. | ||||||
|  | #     * Neither the name of Google Inc. nor the names of its | ||||||
|  | # contributors may be used to endorse or promote products derived from | ||||||
|  | # this software without specific prior written permission. | ||||||
|  | # | ||||||
|  | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||||||
|  | # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||||||
|  | # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | ||||||
|  | # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | ||||||
|  | # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | ||||||
|  | # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | ||||||
|  | # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | ||||||
|  | # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | ||||||
|  | # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||||||
|  | # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | ||||||
|  | # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||||||
|  | 
 | ||||||
|  | { | ||||||
|  |   'targets': [ | ||||||
|  |     { | ||||||
|  |       'target_name': 'gtest', | ||||||
|  |       'type': 'static_library', | ||||||
|  |       'sources': [ | ||||||
|  |         '../testing/gtest/src/gtest-all.cc', | ||||||
|  |       ], | ||||||
|  |       'include_dirs': [ | ||||||
|  |         '../testing/gtest', | ||||||
|  |         '../testing/gtest/include', | ||||||
|  |       ], | ||||||
|  |       'direct_dependent_settings': { | ||||||
|  |         'include_dirs': [ | ||||||
|  |           '../testing/gtest/include', | ||||||
|  |         ], | ||||||
|  |       }, | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |       'target_name': 'gtest_main', | ||||||
|  |       'type': 'static_library', | ||||||
|  |       'dependencies': [ | ||||||
|  |         'gtest', | ||||||
|  |       ], | ||||||
|  |       'sources': [ | ||||||
|  |         'gtest/src/gtest_main.cc', | ||||||
|  |       ], | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |       'target_name': 'gmock', | ||||||
|  |       'type': 'static_library', | ||||||
|  |       'dependencies': [ | ||||||
|  |         'gtest', | ||||||
|  |       ], | ||||||
|  |       'sources': [ | ||||||
|  |         '../testing/src/gmock-all.cc', | ||||||
|  |       ], | ||||||
|  |       'include_dirs': [ | ||||||
|  |         '../testing', | ||||||
|  |         '../testing/include', | ||||||
|  |       ], | ||||||
|  |       'direct_dependent_settings': { | ||||||
|  |         'include_dirs': [ | ||||||
|  |           '../testing/include', | ||||||
|  |         ], | ||||||
|  |       }, | ||||||
|  |       'export_dependent_settings': [ | ||||||
|  |         'gtest', | ||||||
|  |       ], | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |       'target_name': 'gmock_main', | ||||||
|  |       'type': 'static_library', | ||||||
|  |       'dependencies': [ | ||||||
|  |         'gmock', | ||||||
|  |       ], | ||||||
|  |       'sources': [ | ||||||
|  |         '../testing/src/gmock_main.cc', | ||||||
|  |       ], | ||||||
|  |     }, | ||||||
|  |   ], | ||||||
|  | } | ||||||
| @ -27,37 +27,41 @@ | |||||||
| // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 | ||||||
| // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 | ||||||
| 
 | 
 | ||||||
|  | #include "client/linux/crash_generation/crash_generation_client.h" | ||||||
|  | 
 | ||||||
| #include <stdio.h> | #include <stdio.h> | ||||||
| #include <sys/socket.h> | #include <sys/socket.h> | ||||||
| #include <sys/types.h> | #include <sys/types.h> | ||||||
| 
 | 
 | ||||||
| #include <algorithm> | #include <algorithm> | ||||||
| 
 | 
 | ||||||
| #include "client/linux/crash_generation/crash_generation_client.h" |  | ||||||
| #include "common/linux/eintr_wrapper.h" | #include "common/linux/eintr_wrapper.h" | ||||||
| #include "common/linux/ignore_ret.h" | #include "common/linux/ignore_ret.h" | ||||||
| #include "common/linux/linux_libc_support.h" |  | ||||||
| #include "third_party/lss/linux_syscall_support.h" | #include "third_party/lss/linux_syscall_support.h" | ||||||
| 
 | 
 | ||||||
| namespace google_breakpad { | namespace google_breakpad { | ||||||
| 
 | 
 | ||||||
| bool | namespace { | ||||||
| CrashGenerationClient::RequestDump(const void* blob, size_t blob_size) | 
 | ||||||
| { | class CrashGenerationClientImpl : public CrashGenerationClient { | ||||||
|  |  public: | ||||||
|  |   explicit CrashGenerationClientImpl(int server_fd) : server_fd_(server_fd) {} | ||||||
|  |   virtual ~CrashGenerationClientImpl() {} | ||||||
|  | 
 | ||||||
|  |   virtual bool RequestDump(const void* blob, size_t blob_size) { | ||||||
|     int fds[2]; |     int fds[2]; | ||||||
|   sys_socketpair(AF_UNIX, SOCK_STREAM, 0, fds); |     if (sys_pipe(fds) < 0) | ||||||
|  |       return false; | ||||||
|     static const unsigned kControlMsgSize = CMSG_SPACE(sizeof(int)); |     static const unsigned kControlMsgSize = CMSG_SPACE(sizeof(int)); | ||||||
| 
 | 
 | ||||||
|   struct kernel_msghdr msg; |     struct kernel_iovec iov; | ||||||
|   my_memset(&msg, 0, sizeof(struct kernel_msghdr)); |     iov.iov_base = const_cast<void*>(blob); | ||||||
|   struct kernel_iovec iov[1]; |     iov.iov_len = blob_size; | ||||||
|   iov[0].iov_base = const_cast<void*>(blob); |  | ||||||
|   iov[0].iov_len = blob_size; |  | ||||||
| 
 | 
 | ||||||
|   msg.msg_iov = iov; |     struct kernel_msghdr msg = { 0 }; | ||||||
|   msg.msg_iovlen = sizeof(iov) / sizeof(iov[0]); |     msg.msg_iov = &iov; | ||||||
|   char cmsg[kControlMsgSize]; |     msg.msg_iovlen = 1; | ||||||
|   my_memset(cmsg, 0, kControlMsgSize); |     char cmsg[kControlMsgSize] = ""; | ||||||
|     msg.msg_control = cmsg; |     msg.msg_control = cmsg; | ||||||
|     msg.msg_controllen = sizeof(cmsg); |     msg.msg_controllen = sizeof(cmsg); | ||||||
| 
 | 
 | ||||||
| @ -70,23 +74,32 @@ CrashGenerationClient::RequestDump(const void* blob, size_t blob_size) | |||||||
| 
 | 
 | ||||||
|     ssize_t ret = HANDLE_EINTR(sys_sendmsg(server_fd_, &msg, 0)); |     ssize_t ret = HANDLE_EINTR(sys_sendmsg(server_fd_, &msg, 0)); | ||||||
|     sys_close(fds[1]); |     sys_close(fds[1]); | ||||||
|   if (ret <= 0) |     if (ret < 0) { | ||||||
|  |       sys_close(fds[0]); | ||||||
|       return false; |       return false; | ||||||
|  |     } | ||||||
| 
 | 
 | ||||||
|   // wait for an ACK from the server
 |     // Wait for an ACK from the server.
 | ||||||
|     char b; |     char b; | ||||||
|     IGNORE_RET(HANDLE_EINTR(sys_read(fds[0], &b, 1))); |     IGNORE_RET(HANDLE_EINTR(sys_read(fds[0], &b, 1))); | ||||||
|  |     sys_close(fds[0]); | ||||||
| 
 | 
 | ||||||
|     return true; |     return true; | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|  |  private: | ||||||
|  |   int server_fd_; | ||||||
|  | 
 | ||||||
|  |   DISALLOW_COPY_AND_ASSIGN(CrashGenerationClientImpl); | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | }  // namespace
 | ||||||
|  | 
 | ||||||
| // static
 | // static
 | ||||||
| CrashGenerationClient* | CrashGenerationClient* CrashGenerationClient::TryCreate(int server_fd) { | ||||||
| CrashGenerationClient::TryCreate(int server_fd) |   if (server_fd < 0) | ||||||
| { |  | ||||||
|   if (0 > server_fd) |  | ||||||
|     return NULL; |     return NULL; | ||||||
|   return new CrashGenerationClient(server_fd); |   return new CrashGenerationClientImpl(server_fd); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| } | }  // namespace google_breakpad
 | ||||||
|  | |||||||
| @ -30,38 +30,34 @@ | |||||||
| #ifndef CLIENT_LINUX_CRASH_GENERATION_CRASH_GENERATION_CLIENT_H_ | #ifndef CLIENT_LINUX_CRASH_GENERATION_CRASH_GENERATION_CLIENT_H_ | ||||||
| #define CLIENT_LINUX_CRASH_GENERATION_CRASH_GENERATION_CLIENT_H_ | #define CLIENT_LINUX_CRASH_GENERATION_CRASH_GENERATION_CLIENT_H_ | ||||||
| 
 | 
 | ||||||
|  | #include "common/basictypes.h" | ||||||
|  | 
 | ||||||
| #include <stddef.h> | #include <stddef.h> | ||||||
| 
 | 
 | ||||||
| namespace google_breakpad { | namespace google_breakpad { | ||||||
| 
 | 
 | ||||||
|  | // CrashGenerationClient is an interface for implementing out-of-process crash
 | ||||||
|  | // dumping.  The default implementation, accessed via the TryCreate() factory,
 | ||||||
|  | // works in conjunction with the CrashGenerationServer to generate a minidump
 | ||||||
|  | // via a remote process.
 | ||||||
| class CrashGenerationClient { | class CrashGenerationClient { | ||||||
|  public: |  public: | ||||||
|   ~CrashGenerationClient() |   CrashGenerationClient() {} | ||||||
|   { |   virtual ~CrashGenerationClient() {} | ||||||
|   } |  | ||||||
| 
 | 
 | ||||||
|   // Request the crash server to generate a dump.  |blob| is a hack,
 |   // Request the crash server to generate a dump.  |blob| is an opaque
 | ||||||
|   // see exception_handler.h and minidump_writer.h
 |   // CrashContext pointer from exception_handler.h.
 | ||||||
|   //
 |   // Returns true if the dump was successful; false otherwise.
 | ||||||
|   // Return true if the dump was successful; false otherwise.
 |   virtual bool RequestDump(const void* blob, size_t blob_size) = 0; | ||||||
|   bool RequestDump(const void* blob, size_t blob_size); |  | ||||||
| 
 | 
 | ||||||
|   // Return a new CrashGenerationClient if |server_fd| is valid and
 |   // Returns a new CrashGenerationClient if |server_fd| is valid and
 | ||||||
|   // connects to a CrashGenerationServer.  Otherwise, return NULL.
 |   // connects to a CrashGenerationServer.  Otherwise, return NULL.
 | ||||||
|   // The returned CrashGenerationClient* is owned by the caller of
 |   // The returned CrashGenerationClient* is owned by the caller of
 | ||||||
|   // this function.
 |   // this function.
 | ||||||
|   static CrashGenerationClient* TryCreate(int server_fd); |   static CrashGenerationClient* TryCreate(int server_fd); | ||||||
| 
 | 
 | ||||||
|  private: |  private: | ||||||
|   CrashGenerationClient(int server_fd) : server_fd_(server_fd) |   DISALLOW_COPY_AND_ASSIGN(CrashGenerationClient); | ||||||
|   { |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   int server_fd_; |  | ||||||
| 
 |  | ||||||
|   // prevent copy construction and assignment
 |  | ||||||
|   CrashGenerationClient(const CrashGenerationClient&); |  | ||||||
|   CrashGenerationClient& operator=(const CrashGenerationClient&); |  | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| }  // namespace google_breakpad
 | }  // namespace google_breakpad
 | ||||||
|  | |||||||
| @ -51,116 +51,6 @@ | |||||||
| 
 | 
 | ||||||
| static const char kCommandQuit = 'x'; | static const char kCommandQuit = 'x'; | ||||||
| 
 | 
 | ||||||
| static bool |  | ||||||
| GetInodeForFileDescriptor(ino_t* inode_out, int fd) |  | ||||||
| { |  | ||||||
|   assert(inode_out); |  | ||||||
| 
 |  | ||||||
|   struct stat buf; |  | ||||||
|   if (fstat(fd, &buf) < 0) |  | ||||||
|     return false; |  | ||||||
| 
 |  | ||||||
|   if (!S_ISSOCK(buf.st_mode)) |  | ||||||
|     return false; |  | ||||||
| 
 |  | ||||||
|   *inode_out = buf.st_ino; |  | ||||||
|   return true; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // expected prefix of the target of the /proc/self/fd/%d link for a socket
 |  | ||||||
| static const char kSocketLinkPrefix[] = "socket:["; |  | ||||||
| 
 |  | ||||||
| // Parse a symlink in /proc/pid/fd/$x and return the inode number of the
 |  | ||||||
| // socket.
 |  | ||||||
| //   inode_out: (output) set to the inode number on success
 |  | ||||||
| //   path: e.g. /proc/1234/fd/5 (must be a UNIX domain socket descriptor)
 |  | ||||||
| static bool |  | ||||||
| GetInodeForProcPath(ino_t* inode_out, const char* path) |  | ||||||
| { |  | ||||||
|   assert(inode_out); |  | ||||||
|   assert(path); |  | ||||||
| 
 |  | ||||||
|   char buf[PATH_MAX]; |  | ||||||
|   if (!google_breakpad::SafeReadLink(path, buf)) { |  | ||||||
|     return false; |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   if (0 != memcmp(kSocketLinkPrefix, buf, sizeof(kSocketLinkPrefix) - 1)) { |  | ||||||
|     return false; |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   char* endptr; |  | ||||||
|   const uint64_t inode_ul = |  | ||||||
|       strtoull(buf + sizeof(kSocketLinkPrefix) - 1, &endptr, 10); |  | ||||||
|   if (*endptr != ']') |  | ||||||
|     return false; |  | ||||||
| 
 |  | ||||||
|   if (inode_ul == ULLONG_MAX) { |  | ||||||
|     return false; |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   *inode_out = inode_ul; |  | ||||||
|   return true; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| static bool |  | ||||||
| FindProcessHoldingSocket(pid_t* pid_out, ino_t socket_inode) |  | ||||||
| { |  | ||||||
|   assert(pid_out); |  | ||||||
|   bool already_found = false; |  | ||||||
| 
 |  | ||||||
|   DIR* proc = opendir("/proc"); |  | ||||||
|   if (!proc) { |  | ||||||
|     return false; |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   std::vector<pid_t> pids; |  | ||||||
| 
 |  | ||||||
|   struct dirent* dent; |  | ||||||
|   while ((dent = readdir(proc))) { |  | ||||||
|     char* endptr; |  | ||||||
|     const unsigned long int pid_ul = strtoul(dent->d_name, &endptr, 10); |  | ||||||
|     if (pid_ul == ULONG_MAX || '\0' != *endptr) |  | ||||||
|       continue; |  | ||||||
|     pids.push_back(pid_ul); |  | ||||||
|   } |  | ||||||
|   closedir(proc); |  | ||||||
| 
 |  | ||||||
|   for (std::vector<pid_t>::const_iterator |  | ||||||
|        i = pids.begin(); i != pids.end(); ++i) { |  | ||||||
|     const pid_t current_pid = *i; |  | ||||||
|     char buf[PATH_MAX]; |  | ||||||
|     snprintf(buf, sizeof(buf), "/proc/%d/fd", current_pid); |  | ||||||
|     DIR* fd = opendir(buf); |  | ||||||
|     if (!fd) |  | ||||||
|       continue; |  | ||||||
| 
 |  | ||||||
|     while ((dent = readdir(fd))) { |  | ||||||
|       if (snprintf(buf, sizeof(buf), "/proc/%d/fd/%s", current_pid, |  | ||||||
|                    dent->d_name) >= static_cast<int>(sizeof(buf))) { |  | ||||||
|         continue; |  | ||||||
|       } |  | ||||||
| 
 |  | ||||||
|       ino_t fd_inode; |  | ||||||
|       if (GetInodeForProcPath(&fd_inode, buf) |  | ||||||
|           && fd_inode == socket_inode) { |  | ||||||
|         if (already_found) { |  | ||||||
|           closedir(fd); |  | ||||||
|           return false; |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         already_found = true; |  | ||||||
|         *pid_out = current_pid; |  | ||||||
|         break; |  | ||||||
|       } |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     closedir(fd); |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   return already_found; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| namespace google_breakpad { | namespace google_breakpad { | ||||||
| 
 | 
 | ||||||
| CrashGenerationServer::CrashGenerationServer( | CrashGenerationServer::CrashGenerationServer( | ||||||
| @ -349,7 +239,7 @@ CrashGenerationServer::ClientEvent(short revents) | |||||||
|         // A nasty process could try and send us too many descriptors and
 |         // A nasty process could try and send us too many descriptors and
 | ||||||
|         // force a leak.
 |         // force a leak.
 | ||||||
|         for (unsigned i = 0; i < num_fds; ++i) |         for (unsigned i = 0; i < num_fds; ++i) | ||||||
|           HANDLE_EINTR(close(reinterpret_cast<int*>(CMSG_DATA(hdr))[i])); |           close(reinterpret_cast<int*>(CMSG_DATA(hdr))[i]); | ||||||
|         return true; |         return true; | ||||||
|       } else { |       } else { | ||||||
|         signal_fd = reinterpret_cast<int*>(CMSG_DATA(hdr))[0]; |         signal_fd = reinterpret_cast<int*>(CMSG_DATA(hdr))[0]; | ||||||
| @ -363,24 +253,7 @@ CrashGenerationServer::ClientEvent(short revents) | |||||||
| 
 | 
 | ||||||
|   if (crashing_pid == -1 || signal_fd == -1) { |   if (crashing_pid == -1 || signal_fd == -1) { | ||||||
|     if (signal_fd) |     if (signal_fd) | ||||||
|       HANDLE_EINTR(close(signal_fd)); |       close(signal_fd); | ||||||
|     return true; |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   // Kernel bug workaround (broken in 2.6.30 at least):
 |  | ||||||
|   // The kernel doesn't translate PIDs in SCM_CREDENTIALS across PID
 |  | ||||||
|   // namespaces. Thus |crashing_pid| might be garbage from our point of view.
 |  | ||||||
|   // In the future we can remove this workaround, but we have to wait a couple
 |  | ||||||
|   // of years to be sure that it's worked its way out into the world.
 |  | ||||||
| 
 |  | ||||||
|   ino_t inode_number; |  | ||||||
|   if (!GetInodeForFileDescriptor(&inode_number, signal_fd)) { |  | ||||||
|     HANDLE_EINTR(close(signal_fd)); |  | ||||||
|     return true; |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   if (!FindProcessHoldingSocket(&crashing_pid, inode_number - 1)) { |  | ||||||
|     HANDLE_EINTR(close(signal_fd)); |  | ||||||
|     return true; |     return true; | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
| @ -391,7 +264,7 @@ CrashGenerationServer::ClientEvent(short revents) | |||||||
|   if (!google_breakpad::WriteMinidump(minidump_filename.c_str(), |   if (!google_breakpad::WriteMinidump(minidump_filename.c_str(), | ||||||
|                                       crashing_pid, crash_context, |                                       crashing_pid, crash_context, | ||||||
|                                       kCrashContextSize)) { |                                       kCrashContextSize)) { | ||||||
|     HANDLE_EINTR(close(signal_fd)); |     close(signal_fd); | ||||||
|     return true; |     return true; | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
| @ -402,15 +275,8 @@ CrashGenerationServer::ClientEvent(short revents) | |||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   // Send the done signal to the process: it can exit now.
 |   // Send the done signal to the process: it can exit now.
 | ||||||
|   memset(&msg, 0, sizeof(msg)); |   // (Closing this will make the child's sys_read unblock and return 0.)
 | ||||||
|   struct iovec done_iov; |   close(signal_fd); | ||||||
|   done_iov.iov_base = const_cast<char*>("\x42"); |  | ||||||
|   done_iov.iov_len = 1; |  | ||||||
|   msg.msg_iov = &done_iov; |  | ||||||
|   msg.msg_iovlen = 1; |  | ||||||
| 
 |  | ||||||
|   HANDLE_EINTR(sendmsg(signal_fd, &msg, MSG_DONTWAIT | MSG_NOSIGNAL)); |  | ||||||
|   HANDLE_EINTR(close(signal_fd)); |  | ||||||
| 
 | 
 | ||||||
|   return true; |   return true; | ||||||
| } | } | ||||||
|  | |||||||
| @ -0,0 +1,61 @@ | |||||||
|  | // Copyright (c) 2014, Google Inc.
 | ||||||
|  | // All rights reserved.
 | ||||||
|  | //
 | ||||||
|  | // Redistribution and use in source and binary forms, with or without
 | ||||||
|  | // modification, are permitted provided that the following conditions are
 | ||||||
|  | // met:
 | ||||||
|  | //
 | ||||||
|  | //     * Redistributions of source code must retain the above copyright
 | ||||||
|  | // notice, this list of conditions and the following disclaimer.
 | ||||||
|  | //     * Redistributions in binary form must reproduce the above
 | ||||||
|  | // copyright notice, this list of conditions and the following disclaimer
 | ||||||
|  | // in the documentation and/or other materials provided with the
 | ||||||
|  | // distribution.
 | ||||||
|  | //     * Neither the name of Google Inc. nor the names of its
 | ||||||
|  | // contributors may be used to endorse or promote products derived from
 | ||||||
|  | // this software without specific prior written permission.
 | ||||||
|  | //
 | ||||||
|  | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 | ||||||
|  | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 | ||||||
|  | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 | ||||||
|  | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 | ||||||
|  | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 | ||||||
|  | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 | ||||||
|  | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 | ||||||
|  | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 | ||||||
|  | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 | ||||||
|  | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 | ||||||
|  | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 | ||||||
|  | 
 | ||||||
|  | #ifndef CLIENT_LINUX_DUMP_WRITER_COMMON_MAPPING_INFO_H_ | ||||||
|  | #define CLIENT_LINUX_DUMP_WRITER_COMMON_MAPPING_INFO_H_ | ||||||
|  | 
 | ||||||
|  | #include <limits.h> | ||||||
|  | #include <list> | ||||||
|  | #include <stdint.h> | ||||||
|  | 
 | ||||||
|  | #include "google_breakpad/common/minidump_format.h" | ||||||
|  | 
 | ||||||
|  | namespace google_breakpad { | ||||||
|  | 
 | ||||||
|  | // One of these is produced for each mapping in the process (i.e. line in
 | ||||||
|  | // /proc/$x/maps).
 | ||||||
|  | struct MappingInfo { | ||||||
|  |   uintptr_t start_addr; | ||||||
|  |   size_t size; | ||||||
|  |   size_t offset;  // offset into the backed file.
 | ||||||
|  |   bool exec;  // true if the mapping has the execute bit set.
 | ||||||
|  |   char name[NAME_MAX]; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | struct MappingEntry { | ||||||
|  |   MappingInfo first; | ||||||
|  |   uint8_t second[sizeof(MDGUID)]; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | // A list of <MappingInfo, GUID>
 | ||||||
|  | typedef std::list<MappingEntry> MappingList; | ||||||
|  | 
 | ||||||
|  | }  // namespace google_breakpad
 | ||||||
|  | 
 | ||||||
|  | #endif  // CLIENT_LINUX_DUMP_WRITER_COMMON_MAPPING_INFO_H_
 | ||||||
| @ -0,0 +1,53 @@ | |||||||
|  | // Copyright (c) 2014, Google Inc.
 | ||||||
|  | // All rights reserved.
 | ||||||
|  | //
 | ||||||
|  | // Redistribution and use in source and binary forms, with or without
 | ||||||
|  | // modification, are permitted provided that the following conditions are
 | ||||||
|  | // met:
 | ||||||
|  | //
 | ||||||
|  | //     * Redistributions of source code must retain the above copyright
 | ||||||
|  | // notice, this list of conditions and the following disclaimer.
 | ||||||
|  | //     * Redistributions in binary form must reproduce the above
 | ||||||
|  | // copyright notice, this list of conditions and the following disclaimer
 | ||||||
|  | // in the documentation and/or other materials provided with the
 | ||||||
|  | // distribution.
 | ||||||
|  | //     * Neither the name of Google Inc. nor the names of its
 | ||||||
|  | // contributors may be used to endorse or promote products derived from
 | ||||||
|  | // this software without specific prior written permission.
 | ||||||
|  | //
 | ||||||
|  | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 | ||||||
|  | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 | ||||||
|  | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 | ||||||
|  | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 | ||||||
|  | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 | ||||||
|  | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 | ||||||
|  | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 | ||||||
|  | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 | ||||||
|  | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 | ||||||
|  | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 | ||||||
|  | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 | ||||||
|  | 
 | ||||||
|  | #ifndef CLIENT_LINUX_DUMP_WRITER_COMMON_RAW_CONTEXT_CPU_H | ||||||
|  | #define CLIENT_LINUX_DUMP_WRITER_COMMON_RAW_CONTEXT_CPU_H | ||||||
|  | 
 | ||||||
|  | #include "google_breakpad/common/minidump_format.h" | ||||||
|  | 
 | ||||||
|  | namespace google_breakpad { | ||||||
|  | 
 | ||||||
|  | #if defined(__i386__) | ||||||
|  | typedef MDRawContextX86 RawContextCPU; | ||||||
|  | #elif defined(__x86_64) | ||||||
|  | typedef MDRawContextAMD64 RawContextCPU; | ||||||
|  | #elif defined(__ARM_EABI__) | ||||||
|  | typedef MDRawContextARM RawContextCPU; | ||||||
|  | #elif defined(__aarch64__) | ||||||
|  | typedef MDRawContextARM64 RawContextCPU; | ||||||
|  | #elif defined(__mips__) | ||||||
|  | typedef MDRawContextMIPS RawContextCPU; | ||||||
|  | #else | ||||||
|  | #error "This code has not been ported to your platform yet." | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|  | }  // namespace google_breakpad
 | ||||||
|  | 
 | ||||||
|  | #endif  // CLIENT_LINUX_DUMP_WRITER_COMMON_RAW_CONTEXT_CPU_H
 | ||||||
| @ -0,0 +1,154 @@ | |||||||
|  | // Copyright (c) 2014, Google Inc.
 | ||||||
|  | // All rights reserved.
 | ||||||
|  | //
 | ||||||
|  | // Redistribution and use in source and binary forms, with or without
 | ||||||
|  | // modification, are permitted provided that the following conditions are
 | ||||||
|  | // met:
 | ||||||
|  | //
 | ||||||
|  | //     * Redistributions of source code must retain the above copyright
 | ||||||
|  | // notice, this list of conditions and the following disclaimer.
 | ||||||
|  | //     * Redistributions in binary form must reproduce the above
 | ||||||
|  | // copyright notice, this list of conditions and the following disclaimer
 | ||||||
|  | // in the documentation and/or other materials provided with the
 | ||||||
|  | // distribution.
 | ||||||
|  | //     * Neither the name of Google Inc. nor the names of its
 | ||||||
|  | // contributors may be used to endorse or promote products derived from
 | ||||||
|  | // this software without specific prior written permission.
 | ||||||
|  | //
 | ||||||
|  | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 | ||||||
|  | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 | ||||||
|  | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 | ||||||
|  | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 | ||||||
|  | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 | ||||||
|  | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 | ||||||
|  | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 | ||||||
|  | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 | ||||||
|  | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 | ||||||
|  | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 | ||||||
|  | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 | ||||||
|  | 
 | ||||||
|  | #include "client/linux/dump_writer_common/seccomp_unwinder.h" | ||||||
|  | 
 | ||||||
|  | #include <string.h> | ||||||
|  | 
 | ||||||
|  | #include "google_breakpad/common/minidump_format.h" | ||||||
|  | #include "common/linux/linux_libc_support.h" | ||||||
|  | 
 | ||||||
|  | namespace google_breakpad { | ||||||
|  | 
 | ||||||
|  | void SeccompUnwinder::PopSeccompStackFrame(RawContextCPU* cpu, | ||||||
|  |                                            const MDRawThread& thread, | ||||||
|  |                                            uint8_t* stack_copy) { | ||||||
|  | #if defined(__x86_64) | ||||||
|  |   uint64_t bp = cpu->rbp; | ||||||
|  |   uint64_t top = thread.stack.start_of_memory_range; | ||||||
|  |   for (int i = 4; i--; ) { | ||||||
|  |     if (bp < top || | ||||||
|  |         bp + sizeof(bp) > thread.stack.start_of_memory_range + | ||||||
|  |         thread.stack.memory.data_size || | ||||||
|  |         bp & 1) { | ||||||
|  |       break; | ||||||
|  |     } | ||||||
|  |     uint64_t old_top = top; | ||||||
|  |     top = bp; | ||||||
|  |     uint8_t* bp_addr = stack_copy + bp - thread.stack.start_of_memory_range; | ||||||
|  |     my_memcpy(&bp, bp_addr, sizeof(bp)); | ||||||
|  |     if (bp == 0xDEADBEEFDEADBEEFull) { | ||||||
|  |       struct { | ||||||
|  |         uint64_t r15; | ||||||
|  |         uint64_t r14; | ||||||
|  |         uint64_t r13; | ||||||
|  |         uint64_t r12; | ||||||
|  |         uint64_t r11; | ||||||
|  |         uint64_t r10; | ||||||
|  |         uint64_t r9; | ||||||
|  |         uint64_t r8; | ||||||
|  |         uint64_t rdi; | ||||||
|  |         uint64_t rsi; | ||||||
|  |         uint64_t rdx; | ||||||
|  |         uint64_t rcx; | ||||||
|  |         uint64_t rbx; | ||||||
|  |         uint64_t deadbeef; | ||||||
|  |         uint64_t rbp; | ||||||
|  |         uint64_t fakeret; | ||||||
|  |         uint64_t ret; | ||||||
|  |         /* char redzone[128]; */ | ||||||
|  |       } seccomp_stackframe; | ||||||
|  |       if (top - offsetof(typeof(seccomp_stackframe), deadbeef) < old_top || | ||||||
|  |           top - offsetof(typeof(seccomp_stackframe), deadbeef) + | ||||||
|  |           sizeof(seccomp_stackframe) > | ||||||
|  |           thread.stack.start_of_memory_range+thread.stack.memory.data_size) { | ||||||
|  |         break; | ||||||
|  |       } | ||||||
|  |       my_memcpy(&seccomp_stackframe, | ||||||
|  |                 bp_addr - offsetof(typeof(seccomp_stackframe), deadbeef), | ||||||
|  |                 sizeof(seccomp_stackframe)); | ||||||
|  |       cpu->rbx = seccomp_stackframe.rbx; | ||||||
|  |       cpu->rcx = seccomp_stackframe.rcx; | ||||||
|  |       cpu->rdx = seccomp_stackframe.rdx; | ||||||
|  |       cpu->rsi = seccomp_stackframe.rsi; | ||||||
|  |       cpu->rdi = seccomp_stackframe.rdi; | ||||||
|  |       cpu->rbp = seccomp_stackframe.rbp; | ||||||
|  |       cpu->rsp = top + 4*sizeof(uint64_t) + 128; | ||||||
|  |       cpu->r8  = seccomp_stackframe.r8; | ||||||
|  |       cpu->r9  = seccomp_stackframe.r9; | ||||||
|  |       cpu->r10 = seccomp_stackframe.r10; | ||||||
|  |       cpu->r11 = seccomp_stackframe.r11; | ||||||
|  |       cpu->r12 = seccomp_stackframe.r12; | ||||||
|  |       cpu->r13 = seccomp_stackframe.r13; | ||||||
|  |       cpu->r14 = seccomp_stackframe.r14; | ||||||
|  |       cpu->r15 = seccomp_stackframe.r15; | ||||||
|  |       cpu->rip = seccomp_stackframe.fakeret; | ||||||
|  |       return; | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | #elif defined(__i386__) | ||||||
|  |   uint32_t bp = cpu->ebp; | ||||||
|  |   uint32_t top = thread.stack.start_of_memory_range; | ||||||
|  |   for (int i = 4; i--; ) { | ||||||
|  |     if (bp < top || | ||||||
|  |         bp + sizeof(bp) > thread.stack.start_of_memory_range + | ||||||
|  |         thread.stack.memory.data_size || | ||||||
|  |         bp & 1) { | ||||||
|  |       break; | ||||||
|  |     } | ||||||
|  |     uint32_t old_top = top; | ||||||
|  |     top = bp; | ||||||
|  |     uint8_t* bp_addr = stack_copy + bp - thread.stack.start_of_memory_range; | ||||||
|  |     my_memcpy(&bp, bp_addr, sizeof(bp)); | ||||||
|  |     if (bp == 0xDEADBEEFu) { | ||||||
|  |       struct { | ||||||
|  |         uint32_t edi; | ||||||
|  |         uint32_t esi; | ||||||
|  |         uint32_t edx; | ||||||
|  |         uint32_t ecx; | ||||||
|  |         uint32_t ebx; | ||||||
|  |         uint32_t deadbeef; | ||||||
|  |         uint32_t ebp; | ||||||
|  |         uint32_t fakeret; | ||||||
|  |         uint32_t ret; | ||||||
|  |       } seccomp_stackframe; | ||||||
|  |       if (top - offsetof(typeof(seccomp_stackframe), deadbeef) < old_top || | ||||||
|  |           top - offsetof(typeof(seccomp_stackframe), deadbeef) + | ||||||
|  |           sizeof(seccomp_stackframe) > | ||||||
|  |           thread.stack.start_of_memory_range+thread.stack.memory.data_size) { | ||||||
|  |         break; | ||||||
|  |       } | ||||||
|  |       my_memcpy(&seccomp_stackframe, | ||||||
|  |                 bp_addr - offsetof(typeof(seccomp_stackframe), deadbeef), | ||||||
|  |                 sizeof(seccomp_stackframe)); | ||||||
|  |       cpu->ebx = seccomp_stackframe.ebx; | ||||||
|  |       cpu->ecx = seccomp_stackframe.ecx; | ||||||
|  |       cpu->edx = seccomp_stackframe.edx; | ||||||
|  |       cpu->esi = seccomp_stackframe.esi; | ||||||
|  |       cpu->edi = seccomp_stackframe.edi; | ||||||
|  |       cpu->ebp = seccomp_stackframe.ebp; | ||||||
|  |       cpu->esp = top + 4*sizeof(void*); | ||||||
|  |       cpu->eip = seccomp_stackframe.fakeret; | ||||||
|  |       return; | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | #endif | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | }  // namespace google_breakpad
 | ||||||
| @ -0,0 +1,50 @@ | |||||||
|  | // Copyright (c) 2014, Google Inc.
 | ||||||
|  | // All rights reserved.
 | ||||||
|  | //
 | ||||||
|  | // Redistribution and use in source and binary forms, with or without
 | ||||||
|  | // modification, are permitted provided that the following conditions are
 | ||||||
|  | // met:
 | ||||||
|  | //
 | ||||||
|  | //     * Redistributions of source code must retain the above copyright
 | ||||||
|  | // notice, this list of conditions and the following disclaimer.
 | ||||||
|  | //     * Redistributions in binary form must reproduce the above
 | ||||||
|  | // copyright notice, this list of conditions and the following disclaimer
 | ||||||
|  | // in the documentation and/or other materials provided with the
 | ||||||
|  | // distribution.
 | ||||||
|  | //     * Neither the name of Google Inc. nor the names of its
 | ||||||
|  | // contributors may be used to endorse or promote products derived from
 | ||||||
|  | // this software without specific prior written permission.
 | ||||||
|  | //
 | ||||||
|  | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 | ||||||
|  | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 | ||||||
|  | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 | ||||||
|  | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 | ||||||
|  | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 | ||||||
|  | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 | ||||||
|  | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 | ||||||
|  | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 | ||||||
|  | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 | ||||||
|  | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 | ||||||
|  | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 | ||||||
|  | 
 | ||||||
|  | #ifndef CLIENT_LINUX_DUMP_WRITER_COMMON_SECCOMP_UNWINDER_H | ||||||
|  | #define CLIENT_LINUX_DUMP_WRITER_COMMON_SECCOMP_UNWINDER_H | ||||||
|  | 
 | ||||||
|  | #include "client/linux/dump_writer_common/raw_context_cpu.h" | ||||||
|  | #include "google_breakpad/common/minidump_format.h" | ||||||
|  | 
 | ||||||
|  | namespace google_breakpad { | ||||||
|  | 
 | ||||||
|  | struct SeccompUnwinder { | ||||||
|  | 
 | ||||||
|  |   // Check if the top of the stack is part of a system call that has been
 | ||||||
|  |   // redirected by the seccomp sandbox. If so, try to pop the stack frames
 | ||||||
|  |   // all the way back to the point where the interception happened.
 | ||||||
|  |   static void PopSeccompStackFrame(RawContextCPU* cpu, | ||||||
|  |                                    const MDRawThread& thread, | ||||||
|  |                                    uint8_t* stack_copy); | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | }  // namespace google_breakpad
 | ||||||
|  | 
 | ||||||
|  | #endif  // CLIENT_LINUX_DUMP_WRITER_COMMON_SECCOMP_UNWINDER_H
 | ||||||
| @ -0,0 +1,268 @@ | |||||||
|  | // Copyright (c) 2014, Google Inc.
 | ||||||
|  | // All rights reserved.
 | ||||||
|  | //
 | ||||||
|  | // Redistribution and use in source and binary forms, with or without
 | ||||||
|  | // modification, are permitted provided that the following conditions are
 | ||||||
|  | // met:
 | ||||||
|  | //
 | ||||||
|  | //     * Redistributions of source code must retain the above copyright
 | ||||||
|  | // notice, this list of conditions and the following disclaimer.
 | ||||||
|  | //     * Redistributions in binary form must reproduce the above
 | ||||||
|  | // copyright notice, this list of conditions and the following disclaimer
 | ||||||
|  | // in the documentation and/or other materials provided with the
 | ||||||
|  | // distribution.
 | ||||||
|  | //     * Neither the name of Google Inc. nor the names of its
 | ||||||
|  | // contributors may be used to endorse or promote products derived from
 | ||||||
|  | // this software without specific prior written permission.
 | ||||||
|  | //
 | ||||||
|  | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 | ||||||
|  | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 | ||||||
|  | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 | ||||||
|  | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 | ||||||
|  | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 | ||||||
|  | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 | ||||||
|  | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 | ||||||
|  | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 | ||||||
|  | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 | ||||||
|  | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 | ||||||
|  | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 | ||||||
|  | 
 | ||||||
|  | #include "client/linux/dump_writer_common/thread_info.h" | ||||||
|  | 
 | ||||||
|  | #include <string.h> | ||||||
|  | 
 | ||||||
|  | #include "common/linux/linux_libc_support.h" | ||||||
|  | #include "google_breakpad/common/minidump_format.h" | ||||||
|  | 
 | ||||||
|  | namespace { | ||||||
|  | 
 | ||||||
|  | #if defined(__i386__) | ||||||
|  | // Write a uint16_t to memory
 | ||||||
|  | //   out: memory location to write to
 | ||||||
|  | //   v: value to write.
 | ||||||
|  | void U16(void* out, uint16_t v) { | ||||||
|  |   my_memcpy(out, &v, sizeof(v)); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // Write a uint32_t to memory
 | ||||||
|  | //   out: memory location to write to
 | ||||||
|  | //   v: value to write.
 | ||||||
|  | void U32(void* out, uint32_t v) { | ||||||
|  |   my_memcpy(out, &v, sizeof(v)); | ||||||
|  | } | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | namespace google_breakpad { | ||||||
|  | 
 | ||||||
|  | #if defined(__i386__) | ||||||
|  | 
 | ||||||
|  | uintptr_t ThreadInfo::GetInstructionPointer() const { | ||||||
|  |   return regs.eip; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void ThreadInfo::FillCPUContext(RawContextCPU* out) const { | ||||||
|  |   out->context_flags = MD_CONTEXT_X86_ALL; | ||||||
|  | 
 | ||||||
|  |   out->dr0 = dregs[0]; | ||||||
|  |   out->dr1 = dregs[1]; | ||||||
|  |   out->dr2 = dregs[2]; | ||||||
|  |   out->dr3 = dregs[3]; | ||||||
|  |   // 4 and 5 deliberatly omitted because they aren't included in the minidump
 | ||||||
|  |   // format.
 | ||||||
|  |   out->dr6 = dregs[6]; | ||||||
|  |   out->dr7 = dregs[7]; | ||||||
|  | 
 | ||||||
|  |   out->gs = regs.xgs; | ||||||
|  |   out->fs = regs.xfs; | ||||||
|  |   out->es = regs.xes; | ||||||
|  |   out->ds = regs.xds; | ||||||
|  | 
 | ||||||
|  |   out->edi = regs.edi; | ||||||
|  |   out->esi = regs.esi; | ||||||
|  |   out->ebx = regs.ebx; | ||||||
|  |   out->edx = regs.edx; | ||||||
|  |   out->ecx = regs.ecx; | ||||||
|  |   out->eax = regs.eax; | ||||||
|  | 
 | ||||||
|  |   out->ebp = regs.ebp; | ||||||
|  |   out->eip = regs.eip; | ||||||
|  |   out->cs = regs.xcs; | ||||||
|  |   out->eflags = regs.eflags; | ||||||
|  |   out->esp = regs.esp; | ||||||
|  |   out->ss = regs.xss; | ||||||
|  | 
 | ||||||
|  |   out->float_save.control_word = fpregs.cwd; | ||||||
|  |   out->float_save.status_word = fpregs.swd; | ||||||
|  |   out->float_save.tag_word = fpregs.twd; | ||||||
|  |   out->float_save.error_offset = fpregs.fip; | ||||||
|  |   out->float_save.error_selector = fpregs.fcs; | ||||||
|  |   out->float_save.data_offset = fpregs.foo; | ||||||
|  |   out->float_save.data_selector = fpregs.fos; | ||||||
|  | 
 | ||||||
|  |   // 8 registers * 10 bytes per register.
 | ||||||
|  |   my_memcpy(out->float_save.register_area, fpregs.st_space, 10 * 8); | ||||||
|  | 
 | ||||||
|  |   // This matches the Intel fpsave format.
 | ||||||
|  |   U16(out->extended_registers + 0, fpregs.cwd); | ||||||
|  |   U16(out->extended_registers + 2, fpregs.swd); | ||||||
|  |   U16(out->extended_registers + 4, fpregs.twd); | ||||||
|  |   U16(out->extended_registers + 6, fpxregs.fop); | ||||||
|  |   U32(out->extended_registers + 8, fpxregs.fip); | ||||||
|  |   U16(out->extended_registers + 12, fpxregs.fcs); | ||||||
|  |   U32(out->extended_registers + 16, fpregs.foo); | ||||||
|  |   U16(out->extended_registers + 20, fpregs.fos); | ||||||
|  |   U32(out->extended_registers + 24, fpxregs.mxcsr); | ||||||
|  | 
 | ||||||
|  |   my_memcpy(out->extended_registers + 32, &fpxregs.st_space, 128); | ||||||
|  |   my_memcpy(out->extended_registers + 160, &fpxregs.xmm_space, 128); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #elif defined(__x86_64) | ||||||
|  | 
 | ||||||
|  | uintptr_t ThreadInfo::GetInstructionPointer() const { | ||||||
|  |   return regs.rip; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void ThreadInfo::FillCPUContext(RawContextCPU* out) const { | ||||||
|  |   out->context_flags = MD_CONTEXT_AMD64_FULL | | ||||||
|  |                        MD_CONTEXT_AMD64_SEGMENTS; | ||||||
|  | 
 | ||||||
|  |   out->cs = regs.cs; | ||||||
|  | 
 | ||||||
|  |   out->ds = regs.ds; | ||||||
|  |   out->es = regs.es; | ||||||
|  |   out->fs = regs.fs; | ||||||
|  |   out->gs = regs.gs; | ||||||
|  | 
 | ||||||
|  |   out->ss = regs.ss; | ||||||
|  |   out->eflags = regs.eflags; | ||||||
|  | 
 | ||||||
|  |   out->dr0 = dregs[0]; | ||||||
|  |   out->dr1 = dregs[1]; | ||||||
|  |   out->dr2 = dregs[2]; | ||||||
|  |   out->dr3 = dregs[3]; | ||||||
|  |   // 4 and 5 deliberatly omitted because they aren't included in the minidump
 | ||||||
|  |   // format.
 | ||||||
|  |   out->dr6 = dregs[6]; | ||||||
|  |   out->dr7 = dregs[7]; | ||||||
|  | 
 | ||||||
|  |   out->rax = regs.rax; | ||||||
|  |   out->rcx = regs.rcx; | ||||||
|  |   out->rdx = regs.rdx; | ||||||
|  |   out->rbx = regs.rbx; | ||||||
|  | 
 | ||||||
|  |   out->rsp = regs.rsp; | ||||||
|  | 
 | ||||||
|  |   out->rbp = regs.rbp; | ||||||
|  |   out->rsi = regs.rsi; | ||||||
|  |   out->rdi = regs.rdi; | ||||||
|  |   out->r8 = regs.r8; | ||||||
|  |   out->r9 = regs.r9; | ||||||
|  |   out->r10 = regs.r10; | ||||||
|  |   out->r11 = regs.r11; | ||||||
|  |   out->r12 = regs.r12; | ||||||
|  |   out->r13 = regs.r13; | ||||||
|  |   out->r14 = regs.r14; | ||||||
|  |   out->r15 = regs.r15; | ||||||
|  | 
 | ||||||
|  |   out->rip = regs.rip; | ||||||
|  | 
 | ||||||
|  |   out->flt_save.control_word = fpregs.cwd; | ||||||
|  |   out->flt_save.status_word = fpregs.swd; | ||||||
|  |   out->flt_save.tag_word = fpregs.ftw; | ||||||
|  |   out->flt_save.error_opcode = fpregs.fop; | ||||||
|  |   out->flt_save.error_offset = fpregs.rip; | ||||||
|  |   out->flt_save.error_selector = 0;  // We don't have this.
 | ||||||
|  |   out->flt_save.data_offset = fpregs.rdp; | ||||||
|  |   out->flt_save.data_selector = 0;   // We don't have this.
 | ||||||
|  |   out->flt_save.mx_csr = fpregs.mxcsr; | ||||||
|  | #if defined (__ANDROID__) | ||||||
|  |   // Internal bug b/18097559
 | ||||||
|  |   out->flt_save.mx_csr_mask = fpregs.mxcsr_mask; | ||||||
|  | #else | ||||||
|  |   out->flt_save.mx_csr_mask = fpregs.mxcr_mask; | ||||||
|  | #endif | ||||||
|  |   my_memcpy(&out->flt_save.float_registers, &fpregs.st_space, 8 * 16); | ||||||
|  |   my_memcpy(&out->flt_save.xmm_registers, &fpregs.xmm_space, 16 * 16); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #elif defined(__ARM_EABI__) | ||||||
|  | 
 | ||||||
|  | uintptr_t ThreadInfo::GetInstructionPointer() const { | ||||||
|  |   return regs.uregs[15]; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void ThreadInfo::FillCPUContext(RawContextCPU* out) const { | ||||||
|  |   out->context_flags = MD_CONTEXT_ARM_FULL; | ||||||
|  | 
 | ||||||
|  |   for (int i = 0; i < MD_CONTEXT_ARM_GPR_COUNT; ++i) | ||||||
|  |     out->iregs[i] = regs.uregs[i]; | ||||||
|  |   // No CPSR register in ThreadInfo(it's not accessible via ptrace)
 | ||||||
|  |   out->cpsr = 0; | ||||||
|  | #if !defined(__ANDROID__) | ||||||
|  |   out->float_save.fpscr = fpregs.fpsr | | ||||||
|  |     (static_cast<uint64_t>(fpregs.fpcr) << 32); | ||||||
|  |   // TODO: sort this out, actually collect floating point registers
 | ||||||
|  |   my_memset(&out->float_save.regs, 0, sizeof(out->float_save.regs)); | ||||||
|  |   my_memset(&out->float_save.extra, 0, sizeof(out->float_save.extra)); | ||||||
|  | #endif | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #elif defined(__aarch64__) | ||||||
|  | 
 | ||||||
|  | uintptr_t ThreadInfo::GetInstructionPointer() const { | ||||||
|  |   return regs.pc; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void ThreadInfo::FillCPUContext(RawContextCPU* out) const { | ||||||
|  |   out->context_flags = MD_CONTEXT_ARM64_FULL; | ||||||
|  | 
 | ||||||
|  |   out->cpsr = static_cast<uint32_t>(regs.pstate); | ||||||
|  |   for (int i = 0; i < MD_CONTEXT_ARM64_REG_SP; ++i) | ||||||
|  |     out->iregs[i] = regs.regs[i]; | ||||||
|  |   out->iregs[MD_CONTEXT_ARM64_REG_SP] = regs.sp; | ||||||
|  |   out->iregs[MD_CONTEXT_ARM64_REG_PC] = regs.pc; | ||||||
|  | 
 | ||||||
|  |   out->float_save.fpsr = fpregs.fpsr; | ||||||
|  |   out->float_save.fpcr = fpregs.fpcr; | ||||||
|  |   my_memcpy(&out->float_save.regs, &fpregs.vregs, | ||||||
|  |       MD_FLOATINGSAVEAREA_ARM64_FPR_COUNT * 16); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #elif defined(__mips__) | ||||||
|  | 
 | ||||||
|  | uintptr_t ThreadInfo::GetInstructionPointer() const { | ||||||
|  |   return regs.epc; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void ThreadInfo::FillCPUContext(RawContextCPU* out) const { | ||||||
|  |   out->context_flags = MD_CONTEXT_MIPS_FULL; | ||||||
|  | 
 | ||||||
|  |   for (int i = 0; i < MD_CONTEXT_MIPS_GPR_COUNT; ++i) | ||||||
|  |     out->iregs[i] = regs.regs[i]; | ||||||
|  | 
 | ||||||
|  |   out->mdhi = regs.hi; | ||||||
|  |   out->mdlo = regs.lo; | ||||||
|  | 
 | ||||||
|  |   for (int i = 0; i < MD_CONTEXT_MIPS_DSP_COUNT; ++i) { | ||||||
|  |     out->hi[i] = hi[i]; | ||||||
|  |     out->lo[i] = lo[i]; | ||||||
|  |   } | ||||||
|  |   out->dsp_control = dsp_control; | ||||||
|  | 
 | ||||||
|  |   out->epc = regs.epc; | ||||||
|  |   out->badvaddr = regs.badvaddr; | ||||||
|  |   out->status = regs.status; | ||||||
|  |   out->cause = regs.cause; | ||||||
|  | 
 | ||||||
|  |   for (int i = 0; i < MD_FLOATINGSAVEAREA_MIPS_FPR_COUNT; ++i) | ||||||
|  |     out->float_save.regs[i] = fpregs.regs[i]; | ||||||
|  | 
 | ||||||
|  |   out->float_save.fpcsr = fpregs.fpcsr; | ||||||
|  |   out->float_save.fir = fpregs.fir; | ||||||
|  | } | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|  | }  // namespace google_breakpad
 | ||||||
| @ -0,0 +1,88 @@ | |||||||
|  | // Copyright (c) 2014, Google Inc.
 | ||||||
|  | // All rights reserved.
 | ||||||
|  | //
 | ||||||
|  | // Redistribution and use in source and binary forms, with or without
 | ||||||
|  | // modification, are permitted provided that the following conditions are
 | ||||||
|  | // met:
 | ||||||
|  | //
 | ||||||
|  | //     * Redistributions of source code must retain the above copyright
 | ||||||
|  | // notice, this list of conditions and the following disclaimer.
 | ||||||
|  | //     * Redistributions in binary form must reproduce the above
 | ||||||
|  | // copyright notice, this list of conditions and the following disclaimer
 | ||||||
|  | // in the documentation and/or other materials provided with the
 | ||||||
|  | // distribution.
 | ||||||
|  | //     * Neither the name of Google Inc. nor the names of its
 | ||||||
|  | // contributors may be used to endorse or promote products derived from
 | ||||||
|  | // this software without specific prior written permission.
 | ||||||
|  | //
 | ||||||
|  | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 | ||||||
|  | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 | ||||||
|  | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 | ||||||
|  | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 | ||||||
|  | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 | ||||||
|  | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 | ||||||
|  | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 | ||||||
|  | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 | ||||||
|  | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 | ||||||
|  | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 | ||||||
|  | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 | ||||||
|  | 
 | ||||||
|  | #ifndef CLIENT_LINUX_DUMP_WRITER_COMMON_THREAD_INFO_H_ | ||||||
|  | #define CLIENT_LINUX_DUMP_WRITER_COMMON_THREAD_INFO_H_ | ||||||
|  | 
 | ||||||
|  | #include <sys/ucontext.h> | ||||||
|  | #include <sys/user.h> | ||||||
|  | 
 | ||||||
|  | #include "client/linux/dump_writer_common/raw_context_cpu.h" | ||||||
|  | #include "common/memory.h" | ||||||
|  | #include "google_breakpad/common/minidump_format.h" | ||||||
|  | 
 | ||||||
|  | namespace google_breakpad { | ||||||
|  | 
 | ||||||
|  | #if defined(__i386) || defined(__x86_64) | ||||||
|  | typedef typeof(((struct user*) 0)->u_debugreg[0]) debugreg_t; | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|  | // We produce one of these structures for each thread in the crashed process.
 | ||||||
|  | struct ThreadInfo { | ||||||
|  |   pid_t tgid;   // thread group id
 | ||||||
|  |   pid_t ppid;   // parent process
 | ||||||
|  | 
 | ||||||
|  |   uintptr_t stack_pointer;  // thread stack pointer
 | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | #if defined(__i386) || defined(__x86_64) | ||||||
|  |   user_regs_struct regs; | ||||||
|  |   user_fpregs_struct fpregs; | ||||||
|  |   static const unsigned kNumDebugRegisters = 8; | ||||||
|  |   debugreg_t dregs[8]; | ||||||
|  | #if defined(__i386) | ||||||
|  |   user_fpxregs_struct fpxregs; | ||||||
|  | #endif  // defined(__i386)
 | ||||||
|  | 
 | ||||||
|  | #elif defined(__ARM_EABI__) | ||||||
|  |   // Mimicking how strace does this(see syscall.c, search for GETREGS)
 | ||||||
|  |   struct user_regs regs; | ||||||
|  |   struct user_fpregs fpregs; | ||||||
|  | #elif defined(__aarch64__) | ||||||
|  |   // Use the structures defined in <asm/ptrace.h>
 | ||||||
|  |   struct user_pt_regs regs; | ||||||
|  |   struct user_fpsimd_state fpregs; | ||||||
|  | #elif defined(__mips__) | ||||||
|  |   user_regs_struct regs; | ||||||
|  |   user_fpregs_struct fpregs; | ||||||
|  |   uint32_t hi[3]; | ||||||
|  |   uint32_t lo[3]; | ||||||
|  |   uint32_t dsp_control; | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|  |   // Returns the instruction pointer (platform-dependent impl.).
 | ||||||
|  |   uintptr_t GetInstructionPointer() const; | ||||||
|  | 
 | ||||||
|  |   // Fills a RawContextCPU using the context in the ThreadInfo object.
 | ||||||
|  |   void FillCPUContext(RawContextCPU* out) const; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | }  // namespace google_breakpad
 | ||||||
|  | 
 | ||||||
|  | #endif  // CLIENT_LINUX_DUMP_WRITER_COMMON_THREAD_INFO_H_
 | ||||||
| @ -0,0 +1,251 @@ | |||||||
|  | // Copyright (c) 2014, Google Inc.
 | ||||||
|  | // All rights reserved.
 | ||||||
|  | //
 | ||||||
|  | // Redistribution and use in source and binary forms, with or without
 | ||||||
|  | // modification, are permitted provided that the following conditions are
 | ||||||
|  | // met:
 | ||||||
|  | //
 | ||||||
|  | //     * Redistributions of source code must retain the above copyright
 | ||||||
|  | // notice, this list of conditions and the following disclaimer.
 | ||||||
|  | //     * Redistributions in binary form must reproduce the above
 | ||||||
|  | // copyright notice, this list of conditions and the following disclaimer
 | ||||||
|  | // in the documentation and/or other materials provided with the
 | ||||||
|  | // distribution.
 | ||||||
|  | //     * Neither the name of Google Inc. nor the names of its
 | ||||||
|  | // contributors may be used to endorse or promote products derived from
 | ||||||
|  | // this software without specific prior written permission.
 | ||||||
|  | //
 | ||||||
|  | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 | ||||||
|  | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 | ||||||
|  | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 | ||||||
|  | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 | ||||||
|  | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 | ||||||
|  | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 | ||||||
|  | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 | ||||||
|  | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 | ||||||
|  | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 | ||||||
|  | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 | ||||||
|  | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 | ||||||
|  | 
 | ||||||
|  | #include "client/linux/dump_writer_common/ucontext_reader.h" | ||||||
|  | 
 | ||||||
|  | #include "common/linux/linux_libc_support.h" | ||||||
|  | #include "google_breakpad/common/minidump_format.h" | ||||||
|  | 
 | ||||||
|  | namespace google_breakpad { | ||||||
|  | 
 | ||||||
|  | // Minidump defines register structures which are different from the raw
 | ||||||
|  | // structures which we get from the kernel. These are platform specific
 | ||||||
|  | // functions to juggle the ucontext and user structures into minidump format.
 | ||||||
|  | 
 | ||||||
|  | #if defined(__i386__) | ||||||
|  | 
 | ||||||
|  | uintptr_t UContextReader::GetStackPointer(const struct ucontext* uc) { | ||||||
|  |   return uc->uc_mcontext.gregs[REG_ESP]; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | uintptr_t UContextReader::GetInstructionPointer(const struct ucontext* uc) { | ||||||
|  |   return uc->uc_mcontext.gregs[REG_EIP]; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void UContextReader::FillCPUContext(RawContextCPU *out, const ucontext *uc, | ||||||
|  |                                     const struct _libc_fpstate* fp) { | ||||||
|  |   const greg_t* regs = uc->uc_mcontext.gregs; | ||||||
|  | 
 | ||||||
|  |   out->context_flags = MD_CONTEXT_X86_FULL | | ||||||
|  |                        MD_CONTEXT_X86_FLOATING_POINT; | ||||||
|  | 
 | ||||||
|  |   out->gs = regs[REG_GS]; | ||||||
|  |   out->fs = regs[REG_FS]; | ||||||
|  |   out->es = regs[REG_ES]; | ||||||
|  |   out->ds = regs[REG_DS]; | ||||||
|  | 
 | ||||||
|  |   out->edi = regs[REG_EDI]; | ||||||
|  |   out->esi = regs[REG_ESI]; | ||||||
|  |   out->ebx = regs[REG_EBX]; | ||||||
|  |   out->edx = regs[REG_EDX]; | ||||||
|  |   out->ecx = regs[REG_ECX]; | ||||||
|  |   out->eax = regs[REG_EAX]; | ||||||
|  | 
 | ||||||
|  |   out->ebp = regs[REG_EBP]; | ||||||
|  |   out->eip = regs[REG_EIP]; | ||||||
|  |   out->cs = regs[REG_CS]; | ||||||
|  |   out->eflags = regs[REG_EFL]; | ||||||
|  |   out->esp = regs[REG_UESP]; | ||||||
|  |   out->ss = regs[REG_SS]; | ||||||
|  | 
 | ||||||
|  |   out->float_save.control_word = fp->cw; | ||||||
|  |   out->float_save.status_word = fp->sw; | ||||||
|  |   out->float_save.tag_word = fp->tag; | ||||||
|  |   out->float_save.error_offset = fp->ipoff; | ||||||
|  |   out->float_save.error_selector = fp->cssel; | ||||||
|  |   out->float_save.data_offset = fp->dataoff; | ||||||
|  |   out->float_save.data_selector = fp->datasel; | ||||||
|  | 
 | ||||||
|  |   // 8 registers * 10 bytes per register.
 | ||||||
|  |   my_memcpy(out->float_save.register_area, fp->_st, 10 * 8); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #elif defined(__x86_64) | ||||||
|  | 
 | ||||||
|  | uintptr_t UContextReader::GetStackPointer(const struct ucontext* uc) { | ||||||
|  |   return uc->uc_mcontext.gregs[REG_RSP]; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | uintptr_t UContextReader::GetInstructionPointer(const struct ucontext* uc) { | ||||||
|  |   return uc->uc_mcontext.gregs[REG_RIP]; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void UContextReader::FillCPUContext(RawContextCPU *out, const ucontext *uc, | ||||||
|  |                                     const struct _libc_fpstate* fpregs) { | ||||||
|  |   const greg_t* regs = uc->uc_mcontext.gregs; | ||||||
|  | 
 | ||||||
|  |   out->context_flags = MD_CONTEXT_AMD64_FULL; | ||||||
|  | 
 | ||||||
|  |   out->cs = regs[REG_CSGSFS] & 0xffff; | ||||||
|  | 
 | ||||||
|  |   out->fs = (regs[REG_CSGSFS] >> 32) & 0xffff; | ||||||
|  |   out->gs = (regs[REG_CSGSFS] >> 16) & 0xffff; | ||||||
|  | 
 | ||||||
|  |   out->eflags = regs[REG_EFL]; | ||||||
|  | 
 | ||||||
|  |   out->rax = regs[REG_RAX]; | ||||||
|  |   out->rcx = regs[REG_RCX]; | ||||||
|  |   out->rdx = regs[REG_RDX]; | ||||||
|  |   out->rbx = regs[REG_RBX]; | ||||||
|  | 
 | ||||||
|  |   out->rsp = regs[REG_RSP]; | ||||||
|  |   out->rbp = regs[REG_RBP]; | ||||||
|  |   out->rsi = regs[REG_RSI]; | ||||||
|  |   out->rdi = regs[REG_RDI]; | ||||||
|  |   out->r8 = regs[REG_R8]; | ||||||
|  |   out->r9 = regs[REG_R9]; | ||||||
|  |   out->r10 = regs[REG_R10]; | ||||||
|  |   out->r11 = regs[REG_R11]; | ||||||
|  |   out->r12 = regs[REG_R12]; | ||||||
|  |   out->r13 = regs[REG_R13]; | ||||||
|  |   out->r14 = regs[REG_R14]; | ||||||
|  |   out->r15 = regs[REG_R15]; | ||||||
|  | 
 | ||||||
|  |   out->rip = regs[REG_RIP]; | ||||||
|  | 
 | ||||||
|  |   out->flt_save.control_word = fpregs->cwd; | ||||||
|  |   out->flt_save.status_word = fpregs->swd; | ||||||
|  |   out->flt_save.tag_word = fpregs->ftw; | ||||||
|  |   out->flt_save.error_opcode = fpregs->fop; | ||||||
|  |   out->flt_save.error_offset = fpregs->rip; | ||||||
|  |   out->flt_save.data_offset = fpregs->rdp; | ||||||
|  |   out->flt_save.error_selector = 0;  // We don't have this.
 | ||||||
|  |   out->flt_save.data_selector = 0;  // We don't have this.
 | ||||||
|  |   out->flt_save.mx_csr = fpregs->mxcsr; | ||||||
|  |   out->flt_save.mx_csr_mask = fpregs->mxcr_mask; | ||||||
|  |   my_memcpy(&out->flt_save.float_registers, &fpregs->_st, 8 * 16); | ||||||
|  |   my_memcpy(&out->flt_save.xmm_registers, &fpregs->_xmm, 16 * 16); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #elif defined(__ARM_EABI__) | ||||||
|  | 
 | ||||||
|  | uintptr_t UContextReader::GetStackPointer(const struct ucontext* uc) { | ||||||
|  |   return uc->uc_mcontext.arm_sp; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | uintptr_t UContextReader::GetInstructionPointer(const struct ucontext* uc) { | ||||||
|  |   return uc->uc_mcontext.arm_pc; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void UContextReader::FillCPUContext(RawContextCPU *out, const ucontext *uc) { | ||||||
|  |   out->context_flags = MD_CONTEXT_ARM_FULL; | ||||||
|  | 
 | ||||||
|  |   out->iregs[0] = uc->uc_mcontext.arm_r0; | ||||||
|  |   out->iregs[1] = uc->uc_mcontext.arm_r1; | ||||||
|  |   out->iregs[2] = uc->uc_mcontext.arm_r2; | ||||||
|  |   out->iregs[3] = uc->uc_mcontext.arm_r3; | ||||||
|  |   out->iregs[4] = uc->uc_mcontext.arm_r4; | ||||||
|  |   out->iregs[5] = uc->uc_mcontext.arm_r5; | ||||||
|  |   out->iregs[6] = uc->uc_mcontext.arm_r6; | ||||||
|  |   out->iregs[7] = uc->uc_mcontext.arm_r7; | ||||||
|  |   out->iregs[8] = uc->uc_mcontext.arm_r8; | ||||||
|  |   out->iregs[9] = uc->uc_mcontext.arm_r9; | ||||||
|  |   out->iregs[10] = uc->uc_mcontext.arm_r10; | ||||||
|  | 
 | ||||||
|  |   out->iregs[11] = uc->uc_mcontext.arm_fp; | ||||||
|  |   out->iregs[12] = uc->uc_mcontext.arm_ip; | ||||||
|  |   out->iregs[13] = uc->uc_mcontext.arm_sp; | ||||||
|  |   out->iregs[14] = uc->uc_mcontext.arm_lr; | ||||||
|  |   out->iregs[15] = uc->uc_mcontext.arm_pc; | ||||||
|  | 
 | ||||||
|  |   out->cpsr = uc->uc_mcontext.arm_cpsr; | ||||||
|  | 
 | ||||||
|  |   // TODO: fix this after fixing ExceptionHandler
 | ||||||
|  |   out->float_save.fpscr = 0; | ||||||
|  |   my_memset(&out->float_save.regs, 0, sizeof(out->float_save.regs)); | ||||||
|  |   my_memset(&out->float_save.extra, 0, sizeof(out->float_save.extra)); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #elif defined(__aarch64__) | ||||||
|  | 
 | ||||||
|  | uintptr_t UContextReader::GetStackPointer(const struct ucontext* uc) { | ||||||
|  |   return uc->uc_mcontext.sp; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | uintptr_t UContextReader::GetInstructionPointer(const struct ucontext* uc) { | ||||||
|  |   return uc->uc_mcontext.pc; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void UContextReader::FillCPUContext(RawContextCPU *out, const ucontext *uc, | ||||||
|  |                                     const struct fpsimd_context* fpregs) { | ||||||
|  |   out->context_flags = MD_CONTEXT_ARM64_FULL; | ||||||
|  | 
 | ||||||
|  |   out->cpsr = static_cast<uint32_t>(uc->uc_mcontext.pstate); | ||||||
|  |   for (int i = 0; i < MD_CONTEXT_ARM64_REG_SP; ++i) | ||||||
|  |     out->iregs[i] = uc->uc_mcontext.regs[i]; | ||||||
|  |   out->iregs[MD_CONTEXT_ARM64_REG_SP] = uc->uc_mcontext.sp; | ||||||
|  |   out->iregs[MD_CONTEXT_ARM64_REG_PC] = uc->uc_mcontext.pc; | ||||||
|  | 
 | ||||||
|  |   out->float_save.fpsr = fpregs->fpsr; | ||||||
|  |   out->float_save.fpcr = fpregs->fpcr; | ||||||
|  |   my_memcpy(&out->float_save.regs, &fpregs->vregs, | ||||||
|  |       MD_FLOATINGSAVEAREA_ARM64_FPR_COUNT * 16); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #elif defined(__mips__) | ||||||
|  | 
 | ||||||
|  | uintptr_t UContextReader::GetStackPointer(const struct ucontext* uc) { | ||||||
|  |   return uc->uc_mcontext.gregs[MD_CONTEXT_MIPS_REG_SP]; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | uintptr_t UContextReader::GetInstructionPointer(const struct ucontext* uc) { | ||||||
|  |   return uc->uc_mcontext.pc; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void UContextReader::FillCPUContext(RawContextCPU *out, const ucontext *uc) { | ||||||
|  |   out->context_flags = MD_CONTEXT_MIPS_FULL; | ||||||
|  | 
 | ||||||
|  |   for (int i = 0; i < MD_CONTEXT_MIPS_GPR_COUNT; ++i) | ||||||
|  |     out->iregs[i] = uc->uc_mcontext.gregs[i]; | ||||||
|  | 
 | ||||||
|  |   out->mdhi = uc->uc_mcontext.mdhi; | ||||||
|  |   out->mdlo = uc->uc_mcontext.mdlo; | ||||||
|  | 
 | ||||||
|  |   out->hi[0] = uc->uc_mcontext.hi1; | ||||||
|  |   out->hi[1] = uc->uc_mcontext.hi2; | ||||||
|  |   out->hi[2] = uc->uc_mcontext.hi3; | ||||||
|  |   out->lo[0] = uc->uc_mcontext.lo1; | ||||||
|  |   out->lo[1] = uc->uc_mcontext.lo2; | ||||||
|  |   out->lo[2] = uc->uc_mcontext.lo3; | ||||||
|  |   out->dsp_control = uc->uc_mcontext.dsp; | ||||||
|  | 
 | ||||||
|  |   out->epc = uc->uc_mcontext.pc; | ||||||
|  |   out->badvaddr = 0;  // Not reported in signal context.
 | ||||||
|  |   out->status = 0;  // Not reported in signal context.
 | ||||||
|  |   out->cause = 0;  // Not reported in signal context.
 | ||||||
|  | 
 | ||||||
|  |   for (int i = 0; i < MD_FLOATINGSAVEAREA_MIPS_FPR_COUNT; ++i) | ||||||
|  |     out->float_save.regs[i] = uc->uc_mcontext.fpregs.fp_r.fp_dregs[i]; | ||||||
|  | 
 | ||||||
|  |   out->float_save.fpcsr = uc->uc_mcontext.fpc_csr; | ||||||
|  |   out->float_save.fir = uc->uc_mcontext.fpc_eir;  // Unused.
 | ||||||
|  | } | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|  | }  // namespace google_breakpad
 | ||||||
| @ -0,0 +1,64 @@ | |||||||
|  | // Copyright (c) 2014, Google Inc.
 | ||||||
|  | // All rights reserved.
 | ||||||
|  | //
 | ||||||
|  | // Redistribution and use in source and binary forms, with or without
 | ||||||
|  | // modification, are permitted provided that the following conditions are
 | ||||||
|  | // met:
 | ||||||
|  | //
 | ||||||
|  | //     * Redistributions of source code must retain the above copyright
 | ||||||
|  | // notice, this list of conditions and the following disclaimer.
 | ||||||
|  | //     * Redistributions in binary form must reproduce the above
 | ||||||
|  | // copyright notice, this list of conditions and the following disclaimer
 | ||||||
|  | // in the documentation and/or other materials provided with the
 | ||||||
|  | // distribution.
 | ||||||
|  | //     * Neither the name of Google Inc. nor the names of its
 | ||||||
|  | // contributors may be used to endorse or promote products derived from
 | ||||||
|  | // this software without specific prior written permission.
 | ||||||
|  | //
 | ||||||
|  | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 | ||||||
|  | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 | ||||||
|  | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 | ||||||
|  | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 | ||||||
|  | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 | ||||||
|  | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 | ||||||
|  | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 | ||||||
|  | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 | ||||||
|  | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 | ||||||
|  | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 | ||||||
|  | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 | ||||||
|  | 
 | ||||||
|  | #ifndef CLIENT_LINUX_DUMP_WRITER_COMMON_UCONTEXT_READER_H | ||||||
|  | #define CLIENT_LINUX_DUMP_WRITER_COMMON_UCONTEXT_READER_H | ||||||
|  | 
 | ||||||
|  | #include <sys/ucontext.h> | ||||||
|  | #include <sys/user.h> | ||||||
|  | 
 | ||||||
|  | #include "client/linux/dump_writer_common/raw_context_cpu.h" | ||||||
|  | #include "common/memory.h" | ||||||
|  | #include "google_breakpad/common/minidump_format.h" | ||||||
|  | 
 | ||||||
|  | namespace google_breakpad { | ||||||
|  | 
 | ||||||
|  | // Wraps platform-dependent implementations of accessors to ucontext structs.
 | ||||||
|  | struct UContextReader { | ||||||
|  |   static uintptr_t GetStackPointer(const struct ucontext* uc); | ||||||
|  | 
 | ||||||
|  |   static uintptr_t GetInstructionPointer(const struct ucontext* uc); | ||||||
|  | 
 | ||||||
|  |   // Juggle a arch-specific ucontext into a minidump format
 | ||||||
|  |   //   out: the minidump structure
 | ||||||
|  |   //   info: the collection of register structures.
 | ||||||
|  | #if defined(__i386__) || defined(__x86_64) | ||||||
|  |   static void FillCPUContext(RawContextCPU *out, const ucontext *uc, | ||||||
|  |                              const struct _libc_fpstate* fp); | ||||||
|  | #elif defined(__aarch64__) | ||||||
|  |   static void FillCPUContext(RawContextCPU *out, const ucontext *uc, | ||||||
|  |                              const struct fpsimd_context* fpregs); | ||||||
|  | #else | ||||||
|  |   static void FillCPUContext(RawContextCPU *out, const ucontext *uc); | ||||||
|  | #endif | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | }  // namespace google_breakpad
 | ||||||
|  | 
 | ||||||
|  | #endif  // CLIENT_LINUX_DUMP_WRITER_COMMON_UCONTEXT_READER_H
 | ||||||
| @ -68,6 +68,7 @@ | |||||||
| #include <errno.h> | #include <errno.h> | ||||||
| #include <fcntl.h> | #include <fcntl.h> | ||||||
| #include <linux/limits.h> | #include <linux/limits.h> | ||||||
|  | #include <pthread.h> | ||||||
| #include <sched.h> | #include <sched.h> | ||||||
| #include <signal.h> | #include <signal.h> | ||||||
| #include <stdio.h> | #include <stdio.h> | ||||||
| @ -86,9 +87,11 @@ | |||||||
| #include <utility> | #include <utility> | ||||||
| #include <vector> | #include <vector> | ||||||
| 
 | 
 | ||||||
|  | #include "common/basictypes.h" | ||||||
| #include "common/linux/linux_libc_support.h" | #include "common/linux/linux_libc_support.h" | ||||||
| #include "common/memory.h" | #include "common/memory.h" | ||||||
| #include "client/linux/log/log.h" | #include "client/linux/log/log.h" | ||||||
|  | #include "client/linux/microdump_writer/microdump_writer.h" | ||||||
| #include "client/linux/minidump_writer/linux_dumper.h" | #include "client/linux/minidump_writer/linux_dumper.h" | ||||||
| #include "client/linux/minidump_writer/minidump_writer.h" | #include "client/linux/minidump_writer/minidump_writer.h" | ||||||
| #include "common/linux/eintr_wrapper.h" | #include "common/linux/eintr_wrapper.h" | ||||||
| @ -141,13 +144,13 @@ void InstallAlternateStackLocked() { | |||||||
|   // SIGSTKSZ may be too small to prevent the signal handlers from overrunning
 |   // SIGSTKSZ may be too small to prevent the signal handlers from overrunning
 | ||||||
|   // the alternative stack. Ensure that the size of the alternative stack is
 |   // the alternative stack. Ensure that the size of the alternative stack is
 | ||||||
|   // large enough.
 |   // large enough.
 | ||||||
|   static const unsigned kSigStackSize = std::max(8192, SIGSTKSZ); |   static const unsigned kSigStackSize = std::max(16384, SIGSTKSZ); | ||||||
| 
 | 
 | ||||||
|   // Only set an alternative stack if there isn't already one, or if the current
 |   // Only set an alternative stack if there isn't already one, or if the current
 | ||||||
|   // one is too small.
 |   // one is too small.
 | ||||||
|   if (sys_sigaltstack(NULL, &old_stack) == -1 || !old_stack.ss_sp || |   if (sys_sigaltstack(NULL, &old_stack) == -1 || !old_stack.ss_sp || | ||||||
|       old_stack.ss_size < kSigStackSize) { |       old_stack.ss_size < kSigStackSize) { | ||||||
|     new_stack.ss_sp = malloc(kSigStackSize); |     new_stack.ss_sp = calloc(1, kSigStackSize); | ||||||
|     new_stack.ss_size = kSigStackSize; |     new_stack.ss_size = kSigStackSize; | ||||||
| 
 | 
 | ||||||
|     if (sys_sigaltstack(&new_stack, NULL) == -1) { |     if (sys_sigaltstack(&new_stack, NULL) == -1) { | ||||||
| @ -185,13 +188,13 @@ void RestoreAlternateStackLocked() { | |||||||
|   stack_installed = false; |   stack_installed = false; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| }  // namespace
 | // The global exception handler stack. This is needed because there may exist
 | ||||||
|  | // multiple ExceptionHandler instances in a process. Each will have itself
 | ||||||
|  | // registered in this stack.
 | ||||||
|  | std::vector<ExceptionHandler*>* g_handler_stack_ = NULL; | ||||||
|  | pthread_mutex_t g_handler_stack_mutex_ = PTHREAD_MUTEX_INITIALIZER; | ||||||
| 
 | 
 | ||||||
| // We can stack multiple exception handlers. In that case, this is the global
 | }  // namespace
 | ||||||
| // which holds the stack.
 |  | ||||||
| std::vector<ExceptionHandler*>* ExceptionHandler::handler_stack_ = NULL; |  | ||||||
| pthread_mutex_t ExceptionHandler::handler_stack_mutex_ = |  | ||||||
|     PTHREAD_MUTEX_INITIALIZER; |  | ||||||
| 
 | 
 | ||||||
| // Runs before crashing: normal context.
 | // Runs before crashing: normal context.
 | ||||||
| ExceptionHandler::ExceptionHandler(const MinidumpDescriptor& descriptor, | ExceptionHandler::ExceptionHandler(const MinidumpDescriptor& descriptor, | ||||||
| @ -208,31 +211,34 @@ ExceptionHandler::ExceptionHandler(const MinidumpDescriptor& descriptor, | |||||||
|   if (server_fd >= 0) |   if (server_fd >= 0) | ||||||
|     crash_generation_client_.reset(CrashGenerationClient::TryCreate(server_fd)); |     crash_generation_client_.reset(CrashGenerationClient::TryCreate(server_fd)); | ||||||
| 
 | 
 | ||||||
|   if (!IsOutOfProcess() && !minidump_descriptor_.IsFD()) |   if (!IsOutOfProcess() && !minidump_descriptor_.IsFD() && | ||||||
|  |       !minidump_descriptor_.IsMicrodumpOnConsole()) | ||||||
|     minidump_descriptor_.UpdatePath(); |     minidump_descriptor_.UpdatePath(); | ||||||
| 
 | 
 | ||||||
|   pthread_mutex_lock(&handler_stack_mutex_); |   pthread_mutex_lock(&g_handler_stack_mutex_); | ||||||
|   if (!handler_stack_) |   if (!g_handler_stack_) | ||||||
|     handler_stack_ = new std::vector<ExceptionHandler*>; |     g_handler_stack_ = new std::vector<ExceptionHandler*>; | ||||||
|   if (install_handler) { |   if (install_handler) { | ||||||
|     InstallAlternateStackLocked(); |     InstallAlternateStackLocked(); | ||||||
|     InstallHandlersLocked(); |     InstallHandlersLocked(); | ||||||
|   } |   } | ||||||
|   handler_stack_->push_back(this); |   g_handler_stack_->push_back(this); | ||||||
|   pthread_mutex_unlock(&handler_stack_mutex_); |   pthread_mutex_unlock(&g_handler_stack_mutex_); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // Runs before crashing: normal context.
 | // Runs before crashing: normal context.
 | ||||||
| ExceptionHandler::~ExceptionHandler() { | ExceptionHandler::~ExceptionHandler() { | ||||||
|   pthread_mutex_lock(&handler_stack_mutex_); |   pthread_mutex_lock(&g_handler_stack_mutex_); | ||||||
|   std::vector<ExceptionHandler*>::iterator handler = |   std::vector<ExceptionHandler*>::iterator handler = | ||||||
|       std::find(handler_stack_->begin(), handler_stack_->end(), this); |       std::find(g_handler_stack_->begin(), g_handler_stack_->end(), this); | ||||||
|   handler_stack_->erase(handler); |   g_handler_stack_->erase(handler); | ||||||
|   if (handler_stack_->empty()) { |   if (g_handler_stack_->empty()) { | ||||||
|  |     delete g_handler_stack_; | ||||||
|  |     g_handler_stack_ = NULL; | ||||||
|     RestoreAlternateStackLocked(); |     RestoreAlternateStackLocked(); | ||||||
|     RestoreHandlersLocked(); |     RestoreHandlersLocked(); | ||||||
|   } |   } | ||||||
|   pthread_mutex_unlock(&handler_stack_mutex_); |   pthread_mutex_unlock(&g_handler_stack_mutex_); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // Runs before crashing: normal context.
 | // Runs before crashing: normal context.
 | ||||||
| @ -292,7 +298,7 @@ void ExceptionHandler::RestoreHandlersLocked() { | |||||||
| // static
 | // static
 | ||||||
| void ExceptionHandler::SignalHandler(int sig, siginfo_t* info, void* uc) { | void ExceptionHandler::SignalHandler(int sig, siginfo_t* info, void* uc) { | ||||||
|   // All the exception signals are blocked at this point.
 |   // All the exception signals are blocked at this point.
 | ||||||
|   pthread_mutex_lock(&handler_stack_mutex_); |   pthread_mutex_lock(&g_handler_stack_mutex_); | ||||||
| 
 | 
 | ||||||
|   // Sometimes, Breakpad runs inside a process where some other buggy code
 |   // Sometimes, Breakpad runs inside a process where some other buggy code
 | ||||||
|   // saves and restores signal handlers temporarily with 'signal'
 |   // saves and restores signal handlers temporarily with 'signal'
 | ||||||
| @ -319,13 +325,13 @@ void ExceptionHandler::SignalHandler(int sig, siginfo_t* info, void* uc) { | |||||||
|       // default one to avoid an infinite loop here.
 |       // default one to avoid an infinite loop here.
 | ||||||
|       signal(sig, SIG_DFL); |       signal(sig, SIG_DFL); | ||||||
|     } |     } | ||||||
|     pthread_mutex_unlock(&handler_stack_mutex_); |     pthread_mutex_unlock(&g_handler_stack_mutex_); | ||||||
|     return; |     return; | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   bool handled = false; |   bool handled = false; | ||||||
|   for (int i = handler_stack_->size() - 1; !handled && i >= 0; --i) { |   for (int i = g_handler_stack_->size() - 1; !handled && i >= 0; --i) { | ||||||
|     handled = (*handler_stack_)[i]->HandleSignal(sig, info, uc); |     handled = (*g_handler_stack_)[i]->HandleSignal(sig, info, uc); | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   // Upon returning from this signal handler, sig will become unmasked and then
 |   // Upon returning from this signal handler, sig will become unmasked and then
 | ||||||
| @ -339,12 +345,13 @@ void ExceptionHandler::SignalHandler(int sig, siginfo_t* info, void* uc) { | |||||||
|     RestoreHandlersLocked(); |     RestoreHandlersLocked(); | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   pthread_mutex_unlock(&handler_stack_mutex_); |   pthread_mutex_unlock(&g_handler_stack_mutex_); | ||||||
| 
 | 
 | ||||||
|   if (info->si_pid) { |   if (info->si_pid || sig == SIGABRT) { | ||||||
|     // This signal was triggered by somebody sending us the signal with kill().
 |     // This signal was triggered by somebody sending us the signal with kill().
 | ||||||
|     // In order to retrigger it, we have to queue a new signal by calling
 |     // In order to retrigger it, we have to queue a new signal by calling
 | ||||||
|     // kill() ourselves.
 |     // kill() ourselves.  The special case (si_pid == 0 && sig == SIGABRT) is
 | ||||||
|  |     // due to the kernel sending a SIGABRT from a user request via SysRQ.
 | ||||||
|     if (tgkill(getpid(), syscall(__NR_gettid), sig) < 0) { |     if (tgkill(getpid(), syscall(__NR_gettid), sig) < 0) { | ||||||
|       // If we failed to kill ourselves (e.g. because a sandbox disallows us
 |       // If we failed to kill ourselves (e.g. because a sandbox disallows us
 | ||||||
|       // to do so), we instead resort to terminating our process. This will
 |       // to do so), we instead resort to terminating our process. This will
 | ||||||
| @ -391,13 +398,24 @@ bool ExceptionHandler::HandleSignal(int sig, siginfo_t* info, void* uc) { | |||||||
|   bool signal_pid_trusted = info->si_code == SI_USER || |   bool signal_pid_trusted = info->si_code == SI_USER || | ||||||
|       info->si_code == SI_TKILL; |       info->si_code == SI_TKILL; | ||||||
|   if (signal_trusted || (signal_pid_trusted && info->si_pid == getpid())) { |   if (signal_trusted || (signal_pid_trusted && info->si_pid == getpid())) { | ||||||
|     sys_prctl(PR_SET_DUMPABLE, 1); |     sys_prctl(PR_SET_DUMPABLE, 1, 0, 0, 0); | ||||||
|   } |   } | ||||||
|   CrashContext context; |   CrashContext context; | ||||||
|  |   // Fill in all the holes in the struct to make Valgrind happy.
 | ||||||
|  |   memset(&context, 0, sizeof(context)); | ||||||
|   memcpy(&context.siginfo, info, sizeof(siginfo_t)); |   memcpy(&context.siginfo, info, sizeof(siginfo_t)); | ||||||
|   memcpy(&context.context, uc, sizeof(struct ucontext)); |   memcpy(&context.context, uc, sizeof(struct ucontext)); | ||||||
| #if !defined(__ARM_EABI__) | #if defined(__aarch64__) | ||||||
|  |   struct ucontext *uc_ptr = (struct ucontext*)uc; | ||||||
|  |   struct fpsimd_context *fp_ptr = | ||||||
|  |       (struct fpsimd_context*)&uc_ptr->uc_mcontext.__reserved; | ||||||
|  |   if (fp_ptr->head.magic == FPSIMD_MAGIC) { | ||||||
|  |     memcpy(&context.float_state, fp_ptr, sizeof(context.float_state)); | ||||||
|  |   } | ||||||
|  | #elif !defined(__ARM_EABI__)  && !defined(__mips__) | ||||||
|   // FP state is not part of user ABI on ARM Linux.
 |   // FP state is not part of user ABI on ARM Linux.
 | ||||||
|  |   // In case of MIPS Linux FP state is already part of struct ucontext
 | ||||||
|  |   // and 'float_state' is not a member of CrashContext.
 | ||||||
|   struct ucontext *uc_ptr = (struct ucontext*)uc; |   struct ucontext *uc_ptr = (struct ucontext*)uc; | ||||||
|   if (uc_ptr->uc_mcontext.fpregs) { |   if (uc_ptr->uc_mcontext.fpregs) { | ||||||
|     memcpy(&context.float_state, |     memcpy(&context.float_state, | ||||||
| @ -432,9 +450,11 @@ bool ExceptionHandler::GenerateDump(CrashContext *context) { | |||||||
|   if (IsOutOfProcess()) |   if (IsOutOfProcess()) | ||||||
|     return crash_generation_client_->RequestDump(context, sizeof(*context)); |     return crash_generation_client_->RequestDump(context, sizeof(*context)); | ||||||
| 
 | 
 | ||||||
|   static const unsigned kChildStackSize = 8000; |   // Allocating too much stack isn't a problem, and better to err on the side
 | ||||||
|  |   // of caution than smash it into random locations.
 | ||||||
|  |   static const unsigned kChildStackSize = 16000; | ||||||
|   PageAllocator allocator; |   PageAllocator allocator; | ||||||
|   uint8_t* stack = (uint8_t*) allocator.Alloc(kChildStackSize); |   uint8_t* stack = reinterpret_cast<uint8_t*>(allocator.Alloc(kChildStackSize)); | ||||||
|   if (!stack) |   if (!stack) | ||||||
|     return false; |     return false; | ||||||
|   // clone() needs the top-most address. (scrub just to be safe)
 |   // clone() needs the top-most address. (scrub just to be safe)
 | ||||||
| @ -456,24 +476,30 @@ bool ExceptionHandler::GenerateDump(CrashContext *context) { | |||||||
|     // Creating the pipe failed. We'll log an error but carry on anyway,
 |     // Creating the pipe failed. We'll log an error but carry on anyway,
 | ||||||
|     // as we'll probably still get a useful crash report. All that will happen
 |     // as we'll probably still get a useful crash report. All that will happen
 | ||||||
|     // is the write() and read() calls will fail with EBADF
 |     // is the write() and read() calls will fail with EBADF
 | ||||||
|     static const char no_pipe_msg[] = "ExceptionHandler::GenerateDump \
 |     static const char no_pipe_msg[] = "ExceptionHandler::GenerateDump " | ||||||
|                                        sys_pipe failed:"; |                                       "sys_pipe failed:"; | ||||||
|     logger::write(no_pipe_msg, sizeof(no_pipe_msg) - 1); |     logger::write(no_pipe_msg, sizeof(no_pipe_msg) - 1); | ||||||
|     logger::write(strerror(errno), strlen(strerror(errno))); |     logger::write(strerror(errno), strlen(strerror(errno))); | ||||||
|     logger::write("\n", 1); |     logger::write("\n", 1); | ||||||
|  | 
 | ||||||
|  |     // Ensure fdes[0] and fdes[1] are invalid file descriptors.
 | ||||||
|  |     fdes[0] = fdes[1] = -1; | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   const pid_t child = sys_clone( |   const pid_t child = sys_clone( | ||||||
|       ThreadEntry, stack, CLONE_FILES | CLONE_FS | CLONE_UNTRACED, |       ThreadEntry, stack, CLONE_FILES | CLONE_FS | CLONE_UNTRACED, | ||||||
|       &thread_arg, NULL, NULL, NULL); |       &thread_arg, NULL, NULL, NULL); | ||||||
|  |   if (child == -1) { | ||||||
|  |     sys_close(fdes[0]); | ||||||
|  |     sys_close(fdes[1]); | ||||||
|  |     return false; | ||||||
|  |   } | ||||||
| 
 | 
 | ||||||
|   int r, status; |  | ||||||
|   // Allow the child to ptrace us
 |   // Allow the child to ptrace us
 | ||||||
|   sys_prctl(PR_SET_PTRACER, child); |   sys_prctl(PR_SET_PTRACER, child, 0, 0, 0); | ||||||
|   SendContinueSignalToChild(); |   SendContinueSignalToChild(); | ||||||
|   do { |   int status; | ||||||
|     r = sys_waitpid(child, &status, __WALL); |   const int r = HANDLE_EINTR(sys_waitpid(child, &status, __WALL)); | ||||||
|   } while (r == -1 && errno == EINTR); |  | ||||||
| 
 | 
 | ||||||
|   sys_close(fdes[0]); |   sys_close(fdes[0]); | ||||||
|   sys_close(fdes[1]); |   sys_close(fdes[1]); | ||||||
| @ -497,8 +523,8 @@ void ExceptionHandler::SendContinueSignalToChild() { | |||||||
|   int r; |   int r; | ||||||
|   r = HANDLE_EINTR(sys_write(fdes[1], &okToContinueMessage, sizeof(char))); |   r = HANDLE_EINTR(sys_write(fdes[1], &okToContinueMessage, sizeof(char))); | ||||||
|   if (r == -1) { |   if (r == -1) { | ||||||
|     static const char msg[] = "ExceptionHandler::SendContinueSignalToChild \
 |     static const char msg[] = "ExceptionHandler::SendContinueSignalToChild " | ||||||
|                                sys_write failed:"; |                               "sys_write failed:"; | ||||||
|     logger::write(msg, sizeof(msg) - 1); |     logger::write(msg, sizeof(msg) - 1); | ||||||
|     logger::write(strerror(errno), strlen(strerror(errno))); |     logger::write(strerror(errno), strlen(strerror(errno))); | ||||||
|     logger::write("\n", 1); |     logger::write("\n", 1); | ||||||
| @ -512,8 +538,8 @@ void ExceptionHandler::WaitForContinueSignal() { | |||||||
|   char receivedMessage; |   char receivedMessage; | ||||||
|   r = HANDLE_EINTR(sys_read(fdes[0], &receivedMessage, sizeof(char))); |   r = HANDLE_EINTR(sys_read(fdes[0], &receivedMessage, sizeof(char))); | ||||||
|   if (r == -1) { |   if (r == -1) { | ||||||
|     static const char msg[] = "ExceptionHandler::WaitForContinueSignal \
 |     static const char msg[] = "ExceptionHandler::WaitForContinueSignal " | ||||||
|                                sys_read failed:"; |                               "sys_read failed:"; | ||||||
|     logger::write(msg, sizeof(msg) - 1); |     logger::write(msg, sizeof(msg) - 1); | ||||||
|     logger::write(strerror(errno), strlen(strerror(errno))); |     logger::write(strerror(errno), strlen(strerror(errno))); | ||||||
|     logger::write("\n", 1); |     logger::write("\n", 1); | ||||||
| @ -524,6 +550,12 @@ void ExceptionHandler::WaitForContinueSignal() { | |||||||
| // Runs on the cloned process.
 | // Runs on the cloned process.
 | ||||||
| bool ExceptionHandler::DoDump(pid_t crashing_process, const void* context, | bool ExceptionHandler::DoDump(pid_t crashing_process, const void* context, | ||||||
|                               size_t context_size) { |                               size_t context_size) { | ||||||
|  |   if (minidump_descriptor_.IsMicrodumpOnConsole()) { | ||||||
|  |     return google_breakpad::WriteMicrodump(crashing_process, | ||||||
|  |                                            context, | ||||||
|  |                                            context_size, | ||||||
|  |                                            mapping_list_); | ||||||
|  |   } | ||||||
|   if (minidump_descriptor_.IsFD()) { |   if (minidump_descriptor_.IsFD()) { | ||||||
|     return google_breakpad::WriteMinidump(minidump_descriptor_.fd(), |     return google_breakpad::WriteMinidump(minidump_descriptor_.fd(), | ||||||
|                                           minidump_descriptor_.size_limit(), |                                           minidump_descriptor_.size_limit(), | ||||||
| @ -559,7 +591,8 @@ bool ExceptionHandler::WriteMinidump(const string& dump_path, | |||||||
| __attribute__((optimize("no-omit-frame-pointer"))) | __attribute__((optimize("no-omit-frame-pointer"))) | ||||||
| #endif | #endif | ||||||
| bool ExceptionHandler::WriteMinidump() { | bool ExceptionHandler::WriteMinidump() { | ||||||
|   if (!IsOutOfProcess() && !minidump_descriptor_.IsFD()) { |   if (!IsOutOfProcess() && !minidump_descriptor_.IsFD() && | ||||||
|  |       !minidump_descriptor_.IsMicrodumpOnConsole()) { | ||||||
|     // Update the path of the minidump so that this can be called multiple times
 |     // Update the path of the minidump so that this can be called multiple times
 | ||||||
|     // and new files are created for each minidump.  This is done before the
 |     // and new files are created for each minidump.  This is done before the
 | ||||||
|     // generation happens, as clients may want to access the MinidumpDescriptor
 |     // generation happens, as clients may want to access the MinidumpDescriptor
 | ||||||
| @ -569,11 +602,11 @@ bool ExceptionHandler::WriteMinidump() { | |||||||
|     // Reposition the FD to its beginning and resize it to get rid of the
 |     // Reposition the FD to its beginning and resize it to get rid of the
 | ||||||
|     // previous minidump info.
 |     // previous minidump info.
 | ||||||
|     lseek(minidump_descriptor_.fd(), 0, SEEK_SET); |     lseek(minidump_descriptor_.fd(), 0, SEEK_SET); | ||||||
|     static_cast<void>(ftruncate(minidump_descriptor_.fd(), 0)); |     ignore_result(ftruncate(minidump_descriptor_.fd(), 0)); | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   // Allow this process to be dumped.
 |   // Allow this process to be dumped.
 | ||||||
|   sys_prctl(PR_SET_DUMPABLE, 1); |   sys_prctl(PR_SET_DUMPABLE, 1, 0, 0, 0); | ||||||
| 
 | 
 | ||||||
|   CrashContext context; |   CrashContext context; | ||||||
|   int getcontext_result = getcontext(&context.context); |   int getcontext_result = getcontext(&context.context); | ||||||
| @ -602,7 +635,7 @@ bool ExceptionHandler::WriteMinidump() { | |||||||
|   } |   } | ||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
| #if !defined(__ARM_EABI__) | #if !defined(__ARM_EABI__) && !defined(__aarch64__) && !defined(__mips__) | ||||||
|   // FPU state is not part of ARM EABI ucontext_t.
 |   // FPU state is not part of ARM EABI ucontext_t.
 | ||||||
|   memcpy(&context.float_state, context.context.uc_mcontext.fpregs, |   memcpy(&context.float_state, context.context.uc_mcontext.fpregs, | ||||||
|          sizeof(context.float_state)); |          sizeof(context.float_state)); | ||||||
| @ -621,6 +654,12 @@ bool ExceptionHandler::WriteMinidump() { | |||||||
| #elif defined(__arm__) | #elif defined(__arm__) | ||||||
|   context.siginfo.si_addr = |   context.siginfo.si_addr = | ||||||
|       reinterpret_cast<void*>(context.context.uc_mcontext.arm_pc); |       reinterpret_cast<void*>(context.context.uc_mcontext.arm_pc); | ||||||
|  | #elif defined(__aarch64__) | ||||||
|  |   context.siginfo.si_addr = | ||||||
|  |       reinterpret_cast<void*>(context.context.uc_mcontext.pc); | ||||||
|  | #elif defined(__mips__) | ||||||
|  |   context.siginfo.si_addr = | ||||||
|  |       reinterpret_cast<void*>(context.context.uc_mcontext.pc); | ||||||
| #else | #else | ||||||
| #error "This code has not been ported to your platform yet." | #error "This code has not been ported to your platform yet." | ||||||
| #endif | #endif | ||||||
|  | |||||||
| @ -30,15 +30,13 @@ | |||||||
| #ifndef CLIENT_LINUX_HANDLER_EXCEPTION_HANDLER_H_ | #ifndef CLIENT_LINUX_HANDLER_EXCEPTION_HANDLER_H_ | ||||||
| #define CLIENT_LINUX_HANDLER_EXCEPTION_HANDLER_H_ | #define CLIENT_LINUX_HANDLER_EXCEPTION_HANDLER_H_ | ||||||
| 
 | 
 | ||||||
| #include <string> |  | ||||||
| #include <vector> |  | ||||||
| 
 |  | ||||||
| #include <pthread.h> |  | ||||||
| #include <signal.h> | #include <signal.h> | ||||||
| #include <stdint.h> | #include <stdint.h> | ||||||
| #include <stdio.h> | #include <stdio.h> | ||||||
| #include <sys/ucontext.h> | #include <sys/ucontext.h> | ||||||
| 
 | 
 | ||||||
|  | #include <string> | ||||||
|  | 
 | ||||||
| #include "client/linux/crash_generation/crash_generation_client.h" | #include "client/linux/crash_generation/crash_generation_client.h" | ||||||
| #include "client/linux/handler/minidump_descriptor.h" | #include "client/linux/handler/minidump_descriptor.h" | ||||||
| #include "client/linux/minidump_writer/minidump_writer.h" | #include "client/linux/minidump_writer/minidump_writer.h" | ||||||
| @ -146,6 +144,10 @@ class ExceptionHandler { | |||||||
|     crash_handler_ = callback; |     crash_handler_ = callback; | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|  |   void set_crash_generation_client(CrashGenerationClient* client) { | ||||||
|  |     crash_generation_client_.reset(client); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|   // Writes a minidump immediately.  This can be used to capture the execution
 |   // Writes a minidump immediately.  This can be used to capture the execution
 | ||||||
|   // state independently of a crash.
 |   // state independently of a crash.
 | ||||||
|   // Returns true on success.
 |   // Returns true on success.
 | ||||||
| @ -190,9 +192,11 @@ class ExceptionHandler { | |||||||
|     siginfo_t siginfo; |     siginfo_t siginfo; | ||||||
|     pid_t tid;  // the crashing thread.
 |     pid_t tid;  // the crashing thread.
 | ||||||
|     struct ucontext context; |     struct ucontext context; | ||||||
| #if !defined(__ARM_EABI__) | #if !defined(__ARM_EABI__) && !defined(__mips__) | ||||||
|     // #ifdef this out because FP state is not part of user ABI for Linux ARM.
 |     // #ifdef this out because FP state is not part of user ABI for Linux ARM.
 | ||||||
|     struct _libc_fpstate float_state; |     // In case of MIPS Linux FP state is already part of struct
 | ||||||
|  |     // ucontext so 'float_state' is not required.
 | ||||||
|  |     fpstate_t float_state; | ||||||
| #endif | #endif | ||||||
|   }; |   }; | ||||||
| 
 | 
 | ||||||
| @ -219,6 +223,10 @@ class ExceptionHandler { | |||||||
| 
 | 
 | ||||||
|   // Force signal handling for the specified signal.
 |   // Force signal handling for the specified signal.
 | ||||||
|   bool SimulateSignalDelivery(int sig); |   bool SimulateSignalDelivery(int sig); | ||||||
|  | 
 | ||||||
|  |   // Report a crash signal from an SA_SIGINFO signal handler.
 | ||||||
|  |   bool HandleSignal(int sig, siginfo_t* info, void* uc); | ||||||
|  | 
 | ||||||
|  private: |  private: | ||||||
|   // Save the old signal handlers and install new ones.
 |   // Save the old signal handlers and install new ones.
 | ||||||
|   static bool InstallHandlersLocked(); |   static bool InstallHandlersLocked(); | ||||||
| @ -231,7 +239,6 @@ class ExceptionHandler { | |||||||
|   void WaitForContinueSignal(); |   void WaitForContinueSignal(); | ||||||
| 
 | 
 | ||||||
|   static void SignalHandler(int sig, siginfo_t* info, void* uc); |   static void SignalHandler(int sig, siginfo_t* info, void* uc); | ||||||
|   bool HandleSignal(int sig, siginfo_t* info, void* uc); |  | ||||||
|   static int ThreadEntry(void* arg); |   static int ThreadEntry(void* arg); | ||||||
|   bool DoDump(pid_t crashing_process, const void* context, |   bool DoDump(pid_t crashing_process, const void* context, | ||||||
|               size_t context_size); |               size_t context_size); | ||||||
| @ -244,13 +251,11 @@ class ExceptionHandler { | |||||||
| 
 | 
 | ||||||
|   MinidumpDescriptor minidump_descriptor_; |   MinidumpDescriptor minidump_descriptor_; | ||||||
| 
 | 
 | ||||||
|   HandlerCallback crash_handler_; |   // Must be volatile. The compiler is unaware of the code which runs in
 | ||||||
| 
 |   // the signal handler which reads this variable. Without volatile the
 | ||||||
|   // The global exception handler stack. This is need becuase there may exist
 |   // compiler is free to optimise away writes to this variable which it
 | ||||||
|   // multiple ExceptionHandler instances in a process. Each will have itself
 |   // believes are never read.
 | ||||||
|   // registered in this stack.
 |   volatile HandlerCallback crash_handler_; | ||||||
|   static std::vector<ExceptionHandler*> *handler_stack_; |  | ||||||
|   static pthread_mutex_t handler_stack_mutex_; |  | ||||||
| 
 | 
 | ||||||
|   // We need to explicitly enable ptrace of parent processes on some
 |   // We need to explicitly enable ptrace of parent processes on some
 | ||||||
|   // kernels, but we need to know the PID of the cloned process before we
 |   // kernels, but we need to know the PID of the cloned process before we
 | ||||||
|  | |||||||
| @ -35,6 +35,9 @@ | |||||||
| #include <sys/socket.h> | #include <sys/socket.h> | ||||||
| #include <sys/uio.h> | #include <sys/uio.h> | ||||||
| #include <sys/wait.h> | #include <sys/wait.h> | ||||||
|  | #if defined(__mips__) | ||||||
|  | #include <sys/cachectl.h> | ||||||
|  | #endif | ||||||
| 
 | 
 | ||||||
| #include <string> | #include <string> | ||||||
| 
 | 
 | ||||||
| @ -55,7 +58,7 @@ using namespace google_breakpad; | |||||||
| namespace { | namespace { | ||||||
| 
 | 
 | ||||||
| // Flush the instruction cache for a given memory range.
 | // Flush the instruction cache for a given memory range.
 | ||||||
| // Only required on ARM.
 | // Only required on ARM and mips.
 | ||||||
| void FlushInstructionCache(const char* memory, uint32_t memory_size) { | void FlushInstructionCache(const char* memory, uint32_t memory_size) { | ||||||
| #if defined(__arm__) | #if defined(__arm__) | ||||||
|   long begin = reinterpret_cast<long>(memory); |   long begin = reinterpret_cast<long>(memory); | ||||||
| @ -72,6 +75,18 @@ void FlushInstructionCache(const char* memory, uint32_t memory_size) { | |||||||
| # else | # else | ||||||
| #   error "Your operating system is not supported yet" | #   error "Your operating system is not supported yet" | ||||||
| # endif | # endif | ||||||
|  | #elif defined(__mips__) | ||||||
|  | # if defined(__ANDROID__) | ||||||
|  |   // Provided by Android's <unistd.h>
 | ||||||
|  |   long begin = reinterpret_cast<long>(memory); | ||||||
|  |   long end = begin + static_cast<long>(memory_size); | ||||||
|  |   cacheflush(begin, end, 0); | ||||||
|  | # elif defined(__linux__) | ||||||
|  |   // See http://www.linux-mips.org/wiki/Cacheflush_Syscall.
 | ||||||
|  |   cacheflush(const_cast<char*>(memory), memory_size, ICACHE); | ||||||
|  | # else | ||||||
|  | #   error "Your operating system is not supported yet" | ||||||
|  | # endif | ||||||
| #endif | #endif | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -176,6 +191,22 @@ static bool DoneCallback(const MinidumpDescriptor& descriptor, | |||||||
|   return true; |   return true; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | #ifndef ADDRESS_SANITIZER | ||||||
|  | 
 | ||||||
|  | // This is a replacement for "*reinterpret_cast<volatile int*>(NULL) = 0;"
 | ||||||
|  | // It is needed because GCC is allowed to assume that the program will
 | ||||||
|  | // not execute any undefined behavior (UB) operation. Further, when GCC
 | ||||||
|  | // observes that UB statement is reached, it can assume that all statements
 | ||||||
|  | // leading to the UB one are never executed either, and can completely
 | ||||||
|  | // optimize them out. In the case of ExceptionHandlerTest::ExternalDumper,
 | ||||||
|  | // GCC-4.9 optimized out the entire set up of ExceptionHandler, causing
 | ||||||
|  | // test failure.
 | ||||||
|  | volatile int *p_null;  // external linkage, so GCC can't tell that it
 | ||||||
|  |                        // remains NULL. Volatile just for a good measure.
 | ||||||
|  | static void DoNullPointerDereference() { | ||||||
|  |   *p_null = 1; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| void ChildCrash(bool use_fd) { | void ChildCrash(bool use_fd) { | ||||||
|   AutoTempDir temp_dir; |   AutoTempDir temp_dir; | ||||||
|   int fds[2] = {0}; |   int fds[2] = {0}; | ||||||
| @ -202,7 +233,7 @@ void ChildCrash(bool use_fd) { | |||||||
|                                            true, -1)); |                                            true, -1)); | ||||||
|       } |       } | ||||||
|       // Crash with the exception handler in scope.
 |       // Crash with the exception handler in scope.
 | ||||||
|       *reinterpret_cast<volatile int*>(NULL) = 0; |       DoNullPointerDereference(); | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
|   if (!use_fd) |   if (!use_fd) | ||||||
| @ -227,6 +258,8 @@ TEST(ExceptionHandlerTest, ChildCrashWithFD) { | |||||||
|   ASSERT_NO_FATAL_FAILURE(ChildCrash(true)); |   ASSERT_NO_FATAL_FAILURE(ChildCrash(true)); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | #endif  // !ADDRESS_SANITIZER
 | ||||||
|  | 
 | ||||||
| static bool DoneCallbackReturnFalse(const MinidumpDescriptor& descriptor, | static bool DoneCallbackReturnFalse(const MinidumpDescriptor& descriptor, | ||||||
|                                     void* context, |                                     void* context, | ||||||
|                                     bool succeeded) { |                                     bool succeeded) { | ||||||
| @ -268,13 +301,15 @@ static bool InstallRaiseSIGKILL() { | |||||||
|   return sigaction(SIGSEGV, &sa, NULL) != -1; |   return sigaction(SIGSEGV, &sa, NULL) != -1; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | #ifndef ADDRESS_SANITIZER | ||||||
|  | 
 | ||||||
| static void CrashWithCallbacks(ExceptionHandler::FilterCallback filter, | static void CrashWithCallbacks(ExceptionHandler::FilterCallback filter, | ||||||
|                                ExceptionHandler::MinidumpCallback done, |                                ExceptionHandler::MinidumpCallback done, | ||||||
|                                string path) { |                                string path) { | ||||||
|   ExceptionHandler handler( |   ExceptionHandler handler( | ||||||
|       MinidumpDescriptor(path), filter, done, NULL, true, -1); |       MinidumpDescriptor(path), filter, done, NULL, true, -1); | ||||||
|   // Crash with the exception handler in scope.
 |   // Crash with the exception handler in scope.
 | ||||||
|   *reinterpret_cast<volatile int*>(NULL) = 0; |   DoNullPointerDereference(); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| TEST(ExceptionHandlerTest, RedeliveryOnFilterCallbackFalse) { | TEST(ExceptionHandlerTest, RedeliveryOnFilterCallbackFalse) { | ||||||
| @ -365,7 +400,7 @@ TEST(ExceptionHandlerTest, RedeliveryOnBadSignalHandlerFlag) { | |||||||
|               reinterpret_cast<void*>(SIG_ERR)); |               reinterpret_cast<void*>(SIG_ERR)); | ||||||
| 
 | 
 | ||||||
|     // Crash with the exception handler in scope.
 |     // Crash with the exception handler in scope.
 | ||||||
|     *reinterpret_cast<volatile int*>(NULL) = 0; |     DoNullPointerDereference(); | ||||||
|   } |   } | ||||||
|   // SIGKILL means Breakpad's signal handler didn't crash.
 |   // SIGKILL means Breakpad's signal handler didn't crash.
 | ||||||
|   ASSERT_NO_FATAL_FAILURE(WaitForProcessToTerminate(child, SIGKILL)); |   ASSERT_NO_FATAL_FAILURE(WaitForProcessToTerminate(child, SIGKILL)); | ||||||
| @ -435,6 +470,18 @@ TEST(ExceptionHandlerTest, StackedHandlersUnhandledToBottom) { | |||||||
|   ASSERT_NO_FATAL_FAILURE(WaitForProcessToTerminate(child, SIGKILL)); |   ASSERT_NO_FATAL_FAILURE(WaitForProcessToTerminate(child, SIGKILL)); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | #endif  // !ADDRESS_SANITIZER
 | ||||||
|  | 
 | ||||||
|  | const unsigned char kIllegalInstruction[] = { | ||||||
|  | #if defined(__mips__) | ||||||
|  |   // mfc2 zero,Impl - usually illegal in userspace.
 | ||||||
|  |   0x48, 0x00, 0x00, 0x48 | ||||||
|  | #else | ||||||
|  |   // This crashes with SIGILL on x86/x86-64/arm.
 | ||||||
|  |   0xff, 0xff, 0xff, 0xff | ||||||
|  | #endif | ||||||
|  | }; | ||||||
|  | 
 | ||||||
| // Test that memory around the instruction pointer is written
 | // Test that memory around the instruction pointer is written
 | ||||||
| // to the dump as a MinidumpMemoryRegion.
 | // to the dump as a MinidumpMemoryRegion.
 | ||||||
| TEST(ExceptionHandlerTest, InstructionPointerMemory) { | TEST(ExceptionHandlerTest, InstructionPointerMemory) { | ||||||
| @ -446,8 +493,6 @@ TEST(ExceptionHandlerTest, InstructionPointerMemory) { | |||||||
|   // data from the minidump afterwards.
 |   // data from the minidump afterwards.
 | ||||||
|   const uint32_t kMemorySize = 256;  // bytes
 |   const uint32_t kMemorySize = 256;  // bytes
 | ||||||
|   const int kOffset = kMemorySize / 2; |   const int kOffset = kMemorySize / 2; | ||||||
|   // This crashes with SIGILL on x86/x86-64/arm.
 |  | ||||||
|   const unsigned char instructions[] = { 0xff, 0xff, 0xff, 0xff }; |  | ||||||
| 
 | 
 | ||||||
|   const pid_t child = fork(); |   const pid_t child = fork(); | ||||||
|   if (child == 0) { |   if (child == 0) { | ||||||
| @ -469,7 +514,7 @@ TEST(ExceptionHandlerTest, InstructionPointerMemory) { | |||||||
|     // Write some instructions that will crash. Put them in the middle
 |     // Write some instructions that will crash. Put them in the middle
 | ||||||
|     // of the block of memory, because the minidump should contain 128
 |     // of the block of memory, because the minidump should contain 128
 | ||||||
|     // bytes on either side of the instruction pointer.
 |     // bytes on either side of the instruction pointer.
 | ||||||
|     memcpy(memory + kOffset, instructions, sizeof(instructions)); |     memcpy(memory + kOffset, kIllegalInstruction, sizeof(kIllegalInstruction)); | ||||||
|     FlushInstructionCache(memory, kMemorySize); |     FlushInstructionCache(memory, kMemorySize); | ||||||
| 
 | 
 | ||||||
|     // Now execute the instructions, which should crash.
 |     // Now execute the instructions, which should crash.
 | ||||||
| @ -517,12 +562,13 @@ TEST(ExceptionHandlerTest, InstructionPointerMemory) { | |||||||
|   ASSERT_TRUE(bytes); |   ASSERT_TRUE(bytes); | ||||||
| 
 | 
 | ||||||
|   uint8_t prefix_bytes[kOffset]; |   uint8_t prefix_bytes[kOffset]; | ||||||
|   uint8_t suffix_bytes[kMemorySize - kOffset - sizeof(instructions)]; |   uint8_t suffix_bytes[kMemorySize - kOffset - sizeof(kIllegalInstruction)]; | ||||||
|   memset(prefix_bytes, 0, sizeof(prefix_bytes)); |   memset(prefix_bytes, 0, sizeof(prefix_bytes)); | ||||||
|   memset(suffix_bytes, 0, sizeof(suffix_bytes)); |   memset(suffix_bytes, 0, sizeof(suffix_bytes)); | ||||||
|   EXPECT_TRUE(memcmp(bytes, prefix_bytes, sizeof(prefix_bytes)) == 0); |   EXPECT_TRUE(memcmp(bytes, prefix_bytes, sizeof(prefix_bytes)) == 0); | ||||||
|   EXPECT_TRUE(memcmp(bytes + kOffset, instructions, sizeof(instructions)) == 0); |   EXPECT_TRUE(memcmp(bytes + kOffset, kIllegalInstruction,  | ||||||
|   EXPECT_TRUE(memcmp(bytes + kOffset + sizeof(instructions), |                      sizeof(kIllegalInstruction)) == 0); | ||||||
|  |   EXPECT_TRUE(memcmp(bytes + kOffset + sizeof(kIllegalInstruction), | ||||||
|                      suffix_bytes, sizeof(suffix_bytes)) == 0); |                      suffix_bytes, sizeof(suffix_bytes)) == 0); | ||||||
| 
 | 
 | ||||||
|   unlink(minidump_path.c_str()); |   unlink(minidump_path.c_str()); | ||||||
| @ -539,8 +585,6 @@ TEST(ExceptionHandlerTest, InstructionPointerMemoryMinBound) { | |||||||
|   // data from the minidump afterwards.
 |   // data from the minidump afterwards.
 | ||||||
|   const uint32_t kMemorySize = 256;  // bytes
 |   const uint32_t kMemorySize = 256;  // bytes
 | ||||||
|   const int kOffset = 0; |   const int kOffset = 0; | ||||||
|   // This crashes with SIGILL on x86/x86-64/arm.
 |  | ||||||
|   const unsigned char instructions[] = { 0xff, 0xff, 0xff, 0xff }; |  | ||||||
| 
 | 
 | ||||||
|   const pid_t child = fork(); |   const pid_t child = fork(); | ||||||
|   if (child == 0) { |   if (child == 0) { | ||||||
| @ -562,7 +606,7 @@ TEST(ExceptionHandlerTest, InstructionPointerMemoryMinBound) { | |||||||
|     // Write some instructions that will crash. Put them in the middle
 |     // Write some instructions that will crash. Put them in the middle
 | ||||||
|     // of the block of memory, because the minidump should contain 128
 |     // of the block of memory, because the minidump should contain 128
 | ||||||
|     // bytes on either side of the instruction pointer.
 |     // bytes on either side of the instruction pointer.
 | ||||||
|     memcpy(memory + kOffset, instructions, sizeof(instructions)); |     memcpy(memory + kOffset, kIllegalInstruction, sizeof(kIllegalInstruction)); | ||||||
|     FlushInstructionCache(memory, kMemorySize); |     FlushInstructionCache(memory, kMemorySize); | ||||||
| 
 | 
 | ||||||
|     // Now execute the instructions, which should crash.
 |     // Now execute the instructions, which should crash.
 | ||||||
| @ -609,10 +653,11 @@ TEST(ExceptionHandlerTest, InstructionPointerMemoryMinBound) { | |||||||
|   const uint8_t* bytes = region->GetMemory(); |   const uint8_t* bytes = region->GetMemory(); | ||||||
|   ASSERT_TRUE(bytes); |   ASSERT_TRUE(bytes); | ||||||
| 
 | 
 | ||||||
|   uint8_t suffix_bytes[kMemorySize / 2 - sizeof(instructions)]; |   uint8_t suffix_bytes[kMemorySize / 2 - sizeof(kIllegalInstruction)]; | ||||||
|   memset(suffix_bytes, 0, sizeof(suffix_bytes)); |   memset(suffix_bytes, 0, sizeof(suffix_bytes)); | ||||||
|   EXPECT_TRUE(memcmp(bytes + kOffset, instructions, sizeof(instructions)) == 0); |   EXPECT_TRUE(memcmp(bytes + kOffset, kIllegalInstruction,  | ||||||
|   EXPECT_TRUE(memcmp(bytes + kOffset + sizeof(instructions), |                      sizeof(kIllegalInstruction)) == 0); | ||||||
|  |   EXPECT_TRUE(memcmp(bytes + kOffset + sizeof(kIllegalInstruction), | ||||||
|                      suffix_bytes, sizeof(suffix_bytes)) == 0); |                      suffix_bytes, sizeof(suffix_bytes)) == 0); | ||||||
|   unlink(minidump_path.c_str()); |   unlink(minidump_path.c_str()); | ||||||
| } | } | ||||||
| @ -630,9 +675,7 @@ TEST(ExceptionHandlerTest, InstructionPointerMemoryMaxBound) { | |||||||
|   // if a smaller size is requested, and this test wants to
 |   // if a smaller size is requested, and this test wants to
 | ||||||
|   // test the upper bound of the memory range.
 |   // test the upper bound of the memory range.
 | ||||||
|   const uint32_t kMemorySize = 4096;  // bytes
 |   const uint32_t kMemorySize = 4096;  // bytes
 | ||||||
|   // This crashes with SIGILL on x86/x86-64/arm.
 |   const int kOffset = kMemorySize - sizeof(kIllegalInstruction); | ||||||
|   const unsigned char instructions[] = { 0xff, 0xff, 0xff, 0xff }; |  | ||||||
|   const int kOffset = kMemorySize - sizeof(instructions); |  | ||||||
| 
 | 
 | ||||||
|   const pid_t child = fork(); |   const pid_t child = fork(); | ||||||
|   if (child == 0) { |   if (child == 0) { | ||||||
| @ -654,7 +697,7 @@ TEST(ExceptionHandlerTest, InstructionPointerMemoryMaxBound) { | |||||||
|     // Write some instructions that will crash. Put them in the middle
 |     // Write some instructions that will crash. Put them in the middle
 | ||||||
|     // of the block of memory, because the minidump should contain 128
 |     // of the block of memory, because the minidump should contain 128
 | ||||||
|     // bytes on either side of the instruction pointer.
 |     // bytes on either side of the instruction pointer.
 | ||||||
|     memcpy(memory + kOffset, instructions, sizeof(instructions)); |     memcpy(memory + kOffset, kIllegalInstruction, sizeof(kIllegalInstruction)); | ||||||
|     FlushInstructionCache(memory, kMemorySize); |     FlushInstructionCache(memory, kMemorySize); | ||||||
| 
 | 
 | ||||||
|     // Now execute the instructions, which should crash.
 |     // Now execute the instructions, which should crash.
 | ||||||
| @ -697,7 +740,7 @@ TEST(ExceptionHandlerTest, InstructionPointerMemoryMaxBound) { | |||||||
|   ASSERT_TRUE(region); |   ASSERT_TRUE(region); | ||||||
| 
 | 
 | ||||||
|   const size_t kPrefixSize = 128;  // bytes
 |   const size_t kPrefixSize = 128;  // bytes
 | ||||||
|   EXPECT_EQ(kPrefixSize + sizeof(instructions), region->GetSize()); |   EXPECT_EQ(kPrefixSize + sizeof(kIllegalInstruction), region->GetSize()); | ||||||
|   const uint8_t* bytes = region->GetMemory(); |   const uint8_t* bytes = region->GetMemory(); | ||||||
|   ASSERT_TRUE(bytes); |   ASSERT_TRUE(bytes); | ||||||
| 
 | 
 | ||||||
| @ -705,15 +748,11 @@ TEST(ExceptionHandlerTest, InstructionPointerMemoryMaxBound) { | |||||||
|   memset(prefix_bytes, 0, sizeof(prefix_bytes)); |   memset(prefix_bytes, 0, sizeof(prefix_bytes)); | ||||||
|   EXPECT_TRUE(memcmp(bytes, prefix_bytes, sizeof(prefix_bytes)) == 0); |   EXPECT_TRUE(memcmp(bytes, prefix_bytes, sizeof(prefix_bytes)) == 0); | ||||||
|   EXPECT_TRUE(memcmp(bytes + kPrefixSize, |   EXPECT_TRUE(memcmp(bytes + kPrefixSize, | ||||||
|                      instructions, sizeof(instructions)) == 0); |                      kIllegalInstruction, sizeof(kIllegalInstruction)) == 0); | ||||||
| 
 | 
 | ||||||
|   unlink(minidump_path.c_str()); |   unlink(minidump_path.c_str()); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // If AddressSanitizer is used, NULL pointer dereferences generate SIGILL
 |  | ||||||
| // (illegal instruction) instead of SIGSEGV (segmentation fault).  Also,
 |  | ||||||
| // the number of memory regions differs, so there is no point in running
 |  | ||||||
| // this test if AddressSanitizer is used.
 |  | ||||||
| #ifndef ADDRESS_SANITIZER | #ifndef ADDRESS_SANITIZER | ||||||
| 
 | 
 | ||||||
| // Ensure that an extra memory block doesn't get added when the instruction
 | // Ensure that an extra memory block doesn't get added when the instruction
 | ||||||
| @ -760,6 +799,7 @@ TEST(ExceptionHandlerTest, InstructionPointerMemoryNullPointer) { | |||||||
| 
 | 
 | ||||||
|   unlink(minidump_path.c_str()); |   unlink(minidump_path.c_str()); | ||||||
| } | } | ||||||
|  | 
 | ||||||
| #endif  // !ADDRESS_SANITIZER
 | #endif  // !ADDRESS_SANITIZER
 | ||||||
| 
 | 
 | ||||||
| // Test that anonymous memory maps can be annotated with names and IDs.
 | // Test that anonymous memory maps can be annotated with names and IDs.
 | ||||||
| @ -881,6 +921,8 @@ CrashHandler(const void* crash_context, size_t crash_context_size, | |||||||
|   return true; |   return true; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | #ifndef ADDRESS_SANITIZER | ||||||
|  | 
 | ||||||
| TEST(ExceptionHandlerTest, ExternalDumper) { | TEST(ExceptionHandlerTest, ExternalDumper) { | ||||||
|   int fds[2]; |   int fds[2]; | ||||||
|   ASSERT_NE(socketpair(AF_UNIX, SOCK_DGRAM, 0, fds), -1); |   ASSERT_NE(socketpair(AF_UNIX, SOCK_DGRAM, 0, fds), -1); | ||||||
| @ -894,7 +936,7 @@ TEST(ExceptionHandlerTest, ExternalDumper) { | |||||||
|     ExceptionHandler handler(MinidumpDescriptor("/tmp1"), NULL, NULL, |     ExceptionHandler handler(MinidumpDescriptor("/tmp1"), NULL, NULL, | ||||||
|                              reinterpret_cast<void*>(fds[1]), true, -1); |                              reinterpret_cast<void*>(fds[1]), true, -1); | ||||||
|     handler.set_crash_handler(CrashHandler); |     handler.set_crash_handler(CrashHandler); | ||||||
|     *reinterpret_cast<volatile int*>(NULL) = 0; |     DoNullPointerDereference(); | ||||||
|   } |   } | ||||||
|   close(fds[1]); |   close(fds[1]); | ||||||
|   struct msghdr msg = {0}; |   struct msghdr msg = {0}; | ||||||
| @ -953,6 +995,8 @@ TEST(ExceptionHandlerTest, ExternalDumper) { | |||||||
|   unlink(templ.c_str()); |   unlink(templ.c_str()); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | #endif  // !ADDRESS_SANITIZER
 | ||||||
|  | 
 | ||||||
| TEST(ExceptionHandlerTest, WriteMinidumpExceptionStream) { | TEST(ExceptionHandlerTest, WriteMinidumpExceptionStream) { | ||||||
|   AutoTempDir temp_dir; |   AutoTempDir temp_dir; | ||||||
|   ExceptionHandler handler(MinidumpDescriptor(temp_dir.path()), NULL, NULL, |   ExceptionHandler handler(MinidumpDescriptor(temp_dir.path()), NULL, NULL, | ||||||
|  | |||||||
| @ -35,8 +35,12 @@ | |||||||
| 
 | 
 | ||||||
| namespace google_breakpad { | namespace google_breakpad { | ||||||
| 
 | 
 | ||||||
|  | //static
 | ||||||
|  | const MinidumpDescriptor::MicrodumpOnConsole kMicrodumpOnConsole = {}; | ||||||
|  | 
 | ||||||
| MinidumpDescriptor::MinidumpDescriptor(const MinidumpDescriptor& descriptor) | MinidumpDescriptor::MinidumpDescriptor(const MinidumpDescriptor& descriptor) | ||||||
|     : fd_(descriptor.fd_), |     : mode_(descriptor.mode_), | ||||||
|  |       fd_(descriptor.fd_), | ||||||
|       directory_(descriptor.directory_), |       directory_(descriptor.directory_), | ||||||
|       c_path_(NULL), |       c_path_(NULL), | ||||||
|       size_limit_(descriptor.size_limit_) { |       size_limit_(descriptor.size_limit_) { | ||||||
| @ -50,6 +54,7 @@ MinidumpDescriptor& MinidumpDescriptor::operator=( | |||||||
|     const MinidumpDescriptor& descriptor) { |     const MinidumpDescriptor& descriptor) { | ||||||
|   assert(descriptor.path_.empty()); |   assert(descriptor.path_.empty()); | ||||||
| 
 | 
 | ||||||
|  |   mode_ = descriptor.mode_; | ||||||
|   fd_ = descriptor.fd_; |   fd_ = descriptor.fd_; | ||||||
|   directory_ = descriptor.directory_; |   directory_ = descriptor.directory_; | ||||||
|   path_.clear(); |   path_.clear(); | ||||||
| @ -63,7 +68,7 @@ MinidumpDescriptor& MinidumpDescriptor::operator=( | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void MinidumpDescriptor::UpdatePath() { | void MinidumpDescriptor::UpdatePath() { | ||||||
|   assert(fd_ == -1 && !directory_.empty()); |   assert(mode_ == kWriteMinidumpToFile && !directory_.empty()); | ||||||
| 
 | 
 | ||||||
|   GUID guid; |   GUID guid; | ||||||
|   char guid_str[kGUIDStringLength + 1]; |   char guid_str[kGUIDStringLength + 1]; | ||||||
|  | |||||||
| @ -37,18 +37,25 @@ | |||||||
| 
 | 
 | ||||||
| #include "common/using_std_string.h" | #include "common/using_std_string.h" | ||||||
| 
 | 
 | ||||||
| // The MinidumpDescriptor describes how to access a minidump: it can contain
 | // This class describes how a crash dump should be generated, either:
 | ||||||
| // either a file descriptor or a path.
 | // - Writing a full minidump to a file in a given directory (the actual path,
 | ||||||
| // Note that when using files, it is created with the path to a directory.
 | //   inside the directory, is determined by this class).
 | ||||||
| // The actual path where the minidump is generated is created by this class.
 | // - Writing a full minidump to a given fd.
 | ||||||
|  | // - Writing a reduced microdump to the console (logcat on Android).
 | ||||||
| namespace google_breakpad { | namespace google_breakpad { | ||||||
| 
 | 
 | ||||||
| class MinidumpDescriptor { | class MinidumpDescriptor { | ||||||
|  public: |  public: | ||||||
|   MinidumpDescriptor() : fd_(-1), size_limit_(-1) {} |   struct MicrodumpOnConsole {}; | ||||||
|  |   static const MicrodumpOnConsole kMicrodumpOnConsole; | ||||||
|  | 
 | ||||||
|  |   MinidumpDescriptor() : mode_(kUninitialized), | ||||||
|  |                          fd_(-1), | ||||||
|  |                          size_limit_(-1) {} | ||||||
| 
 | 
 | ||||||
|   explicit MinidumpDescriptor(const string& directory) |   explicit MinidumpDescriptor(const string& directory) | ||||||
|       : fd_(-1), |       : mode_(kWriteMinidumpToFile), | ||||||
|  |         fd_(-1), | ||||||
|         directory_(directory), |         directory_(directory), | ||||||
|         c_path_(NULL), |         c_path_(NULL), | ||||||
|         size_limit_(-1) { |         size_limit_(-1) { | ||||||
| @ -56,16 +63,24 @@ class MinidumpDescriptor { | |||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   explicit MinidumpDescriptor(int fd) |   explicit MinidumpDescriptor(int fd) | ||||||
|       : fd_(fd), |       : mode_(kWriteMinidumpToFd), | ||||||
|  |         fd_(fd), | ||||||
|         c_path_(NULL), |         c_path_(NULL), | ||||||
|         size_limit_(-1) { |         size_limit_(-1) { | ||||||
|     assert(fd != -1); |     assert(fd != -1); | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|  |   explicit MinidumpDescriptor(const MicrodumpOnConsole&) | ||||||
|  |       : mode_(kWriteMicrodumpToConsole), | ||||||
|  |         fd_(-1), | ||||||
|  |         size_limit_(-1) {} | ||||||
|  | 
 | ||||||
|   explicit MinidumpDescriptor(const MinidumpDescriptor& descriptor); |   explicit MinidumpDescriptor(const MinidumpDescriptor& descriptor); | ||||||
|   MinidumpDescriptor& operator=(const MinidumpDescriptor& descriptor); |   MinidumpDescriptor& operator=(const MinidumpDescriptor& descriptor); | ||||||
| 
 | 
 | ||||||
|   bool IsFD() const { return fd_ != -1; } |   static MinidumpDescriptor getMicrodumpDescriptor(); | ||||||
|  | 
 | ||||||
|  |   bool IsFD() const { return mode_ == kWriteMinidumpToFd; } | ||||||
| 
 | 
 | ||||||
|   int fd() const { return fd_; } |   int fd() const { return fd_; } | ||||||
| 
 | 
 | ||||||
| @ -73,6 +88,10 @@ class MinidumpDescriptor { | |||||||
| 
 | 
 | ||||||
|   const char* path() const { return c_path_; } |   const char* path() const { return c_path_; } | ||||||
| 
 | 
 | ||||||
|  |   bool IsMicrodumpOnConsole() const { | ||||||
|  |     return mode_ == kWriteMicrodumpToConsole; | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|   // Updates the path so it is unique.
 |   // Updates the path so it is unique.
 | ||||||
|   // Should be called from a normal context: this methods uses the heap.
 |   // Should be called from a normal context: this methods uses the heap.
 | ||||||
|   void UpdatePath(); |   void UpdatePath(); | ||||||
| @ -81,6 +100,16 @@ class MinidumpDescriptor { | |||||||
|   void set_size_limit(off_t limit) { size_limit_ = limit; } |   void set_size_limit(off_t limit) { size_limit_ = limit; } | ||||||
| 
 | 
 | ||||||
|  private: |  private: | ||||||
|  |   enum DumpMode { | ||||||
|  |     kUninitialized = 0, | ||||||
|  |     kWriteMinidumpToFile, | ||||||
|  |     kWriteMinidumpToFd, | ||||||
|  |     kWriteMicrodumpToConsole | ||||||
|  |   }; | ||||||
|  | 
 | ||||||
|  |   // Specifies the dump mode (see DumpMode).
 | ||||||
|  |   DumpMode mode_; | ||||||
|  | 
 | ||||||
|   // The file descriptor where the minidump is generated.
 |   // The file descriptor where the minidump is generated.
 | ||||||
|   int fd_; |   int fd_; | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -0,0 +1,364 @@ | |||||||
|  | // Copyright (c) 2014, Google Inc.
 | ||||||
|  | // All rights reserved.
 | ||||||
|  | //
 | ||||||
|  | // Redistribution and use in source and binary forms, with or without
 | ||||||
|  | // modification, are permitted provided that the following conditions are
 | ||||||
|  | // met:
 | ||||||
|  | //
 | ||||||
|  | //     * Redistributions of source code must retain the above copyright
 | ||||||
|  | // notice, this list of conditions and the following disclaimer.
 | ||||||
|  | //     * Redistributions in binary form must reproduce the above
 | ||||||
|  | // copyright notice, this list of conditions and the following disclaimer
 | ||||||
|  | // in the documentation and/or other materials provided with the
 | ||||||
|  | // distribution.
 | ||||||
|  | //     * Neither the name of Google Inc. nor the names of its
 | ||||||
|  | // contributors may be used to endorse or promote products derived from
 | ||||||
|  | // this software without specific prior written permission.
 | ||||||
|  | //
 | ||||||
|  | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 | ||||||
|  | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 | ||||||
|  | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 | ||||||
|  | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 | ||||||
|  | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 | ||||||
|  | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 | ||||||
|  | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 | ||||||
|  | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 | ||||||
|  | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 | ||||||
|  | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 | ||||||
|  | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 | ||||||
|  | 
 | ||||||
|  | // This translation unit generates microdumps into the console (logcat on
 | ||||||
|  | // Android). See crbug.com/410294 for more info and design docs.
 | ||||||
|  | 
 | ||||||
|  | #include "client/linux/microdump_writer/microdump_writer.h" | ||||||
|  | 
 | ||||||
|  | #include <sys/utsname.h> | ||||||
|  | 
 | ||||||
|  | #include "client/linux/dump_writer_common/seccomp_unwinder.h" | ||||||
|  | #include "client/linux/dump_writer_common/thread_info.h" | ||||||
|  | #include "client/linux/dump_writer_common/ucontext_reader.h" | ||||||
|  | #include "client/linux/handler/exception_handler.h" | ||||||
|  | #include "client/linux/minidump_writer/linux_ptrace_dumper.h" | ||||||
|  | #include "common/linux/linux_libc_support.h" | ||||||
|  | #include "client/linux/log/log.h" | ||||||
|  | 
 | ||||||
|  | namespace { | ||||||
|  | 
 | ||||||
|  | using google_breakpad::ExceptionHandler; | ||||||
|  | using google_breakpad::LinuxDumper; | ||||||
|  | using google_breakpad::LinuxPtraceDumper; | ||||||
|  | using google_breakpad::MappingInfo; | ||||||
|  | using google_breakpad::MappingList; | ||||||
|  | using google_breakpad::RawContextCPU; | ||||||
|  | using google_breakpad::SeccompUnwinder; | ||||||
|  | using google_breakpad::ThreadInfo; | ||||||
|  | using google_breakpad::UContextReader; | ||||||
|  | 
 | ||||||
|  | class MicrodumpWriter { | ||||||
|  |  public: | ||||||
|  |   MicrodumpWriter(const ExceptionHandler::CrashContext* context, | ||||||
|  |                   const MappingList& mappings, | ||||||
|  |                   LinuxDumper* dumper) | ||||||
|  |       : ucontext_(context ? &context->context : NULL), | ||||||
|  | #if !defined(__ARM_EABI__) && !defined(__mips__) | ||||||
|  |         float_state_(context ? &context->float_state : NULL), | ||||||
|  | #endif | ||||||
|  |         dumper_(dumper), | ||||||
|  |         mapping_list_(mappings) { } | ||||||
|  | 
 | ||||||
|  |   ~MicrodumpWriter() { dumper_->ThreadsResume(); } | ||||||
|  | 
 | ||||||
|  |   bool Init() { | ||||||
|  |     if (!dumper_->Init()) | ||||||
|  |       return false; | ||||||
|  |     return dumper_->ThreadsSuspend(); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   bool Dump() { | ||||||
|  |     bool success; | ||||||
|  |     LogLine("-----BEGIN BREAKPAD MICRODUMP-----"); | ||||||
|  |     success = DumpOSInformation(); | ||||||
|  |     if (success) | ||||||
|  |       success = DumpCrashingThread(); | ||||||
|  |     if (success) | ||||||
|  |       success = DumpMappings(); | ||||||
|  |     LogLine("-----END BREAKPAD MICRODUMP-----"); | ||||||
|  |     dumper_->ThreadsResume(); | ||||||
|  |     return success; | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |  private: | ||||||
|  |   // Writes one line to the system log.
 | ||||||
|  |   void LogLine(const char* msg) { | ||||||
|  |     logger::write(msg, my_strlen(msg)); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   // Stages the given string in the current line buffer.
 | ||||||
|  |   void LogAppend(const char* str) { | ||||||
|  |     my_strlcat(log_line_, str, sizeof(log_line_)); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   // As above (required to take precedence over template specialization below).
 | ||||||
|  |   void LogAppend(char* str) { | ||||||
|  |     LogAppend(const_cast<const char*>(str)); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   // Stages the hex repr. of the given int type in the current line buffer.
 | ||||||
|  |   template<typename T> | ||||||
|  |   void LogAppend(T value) { | ||||||
|  |     // Make enough room to hex encode the largest int type + NUL.
 | ||||||
|  |     static const char HEX[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', | ||||||
|  |                                'A', 'B', 'C', 'D', 'E', 'F'}; | ||||||
|  |     char hexstr[sizeof(T) * 2 + 1]; | ||||||
|  |     for (int i = sizeof(T) * 2 - 1; i >= 0; --i, value >>= 4) | ||||||
|  |       hexstr[i] = HEX[static_cast<uint8_t>(value) & 0x0F]; | ||||||
|  |     hexstr[sizeof(T) * 2] = '\0'; | ||||||
|  |     LogAppend(hexstr); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   // Stages the buffer content hex-encoded in the current line buffer.
 | ||||||
|  |   void LogAppend(const void* buf, size_t length) { | ||||||
|  |     const uint8_t* ptr = reinterpret_cast<const uint8_t*>(buf); | ||||||
|  |     for (size_t i = 0; i < length; ++i, ++ptr) | ||||||
|  |       LogAppend(*ptr); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   // Writes out the current line buffer on the system log.
 | ||||||
|  |   void LogCommitLine() { | ||||||
|  |     logger::write(log_line_, my_strlen(log_line_)); | ||||||
|  |     my_strlcpy(log_line_, "", sizeof(log_line_)); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   bool DumpOSInformation() { | ||||||
|  |     struct utsname uts; | ||||||
|  |     if (uname(&uts)) | ||||||
|  |       return false; | ||||||
|  | 
 | ||||||
|  | #if defined(__ANDROID__) | ||||||
|  |     const char kOSId[] = "A"; | ||||||
|  | #else | ||||||
|  |     const char kOSId[] = "L"; | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|  |     LogAppend("O "); | ||||||
|  |     LogAppend(kOSId); | ||||||
|  |     LogAppend(" \""); | ||||||
|  |     LogAppend(uts.machine); | ||||||
|  |     LogAppend("\" \""); | ||||||
|  |     LogAppend(uts.release); | ||||||
|  |     LogAppend(" \""); | ||||||
|  |     LogAppend(uts.version); | ||||||
|  |     LogAppend("\""); | ||||||
|  |     LogCommitLine(); | ||||||
|  |     return true; | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   bool DumpThreadStack(uint32_t thread_id, | ||||||
|  |                        uintptr_t stack_pointer, | ||||||
|  |                        int max_stack_len, | ||||||
|  |                        uint8_t** stack_copy) { | ||||||
|  |     *stack_copy = NULL; | ||||||
|  |     const void* stack; | ||||||
|  |     size_t stack_len; | ||||||
|  | 
 | ||||||
|  |     if (!dumper_->GetStackInfo(&stack, &stack_len, stack_pointer)) { | ||||||
|  |       assert(false); | ||||||
|  |       return false; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     LogAppend("S 0 "); | ||||||
|  |     LogAppend(stack_pointer); | ||||||
|  |     LogAppend(" "); | ||||||
|  |     LogAppend(reinterpret_cast<uintptr_t>(stack)); | ||||||
|  |     LogAppend(" "); | ||||||
|  |     LogAppend(stack_len); | ||||||
|  |     LogCommitLine(); | ||||||
|  | 
 | ||||||
|  |     if (max_stack_len >= 0 && | ||||||
|  |         stack_len > static_cast<unsigned int>(max_stack_len)) { | ||||||
|  |       stack_len = max_stack_len; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     *stack_copy = reinterpret_cast<uint8_t*>(Alloc(stack_len)); | ||||||
|  |     dumper_->CopyFromProcess(*stack_copy, thread_id, stack, stack_len); | ||||||
|  | 
 | ||||||
|  |     // Dump the content of the stack, splicing it into chunks which size is
 | ||||||
|  |     // compatible with the max logcat line size (see LOGGER_ENTRY_MAX_PAYLOAD).
 | ||||||
|  |     const size_t STACK_DUMP_CHUNK_SIZE = 384; | ||||||
|  |     for (size_t stack_off = 0; stack_off < stack_len; | ||||||
|  |          stack_off += STACK_DUMP_CHUNK_SIZE) { | ||||||
|  |       LogAppend("S "); | ||||||
|  |       LogAppend(reinterpret_cast<uintptr_t>(stack) + stack_off); | ||||||
|  |       LogAppend(" "); | ||||||
|  |       LogAppend(*stack_copy + stack_off, | ||||||
|  |                 std::min(STACK_DUMP_CHUNK_SIZE, stack_len - stack_off)); | ||||||
|  |       LogCommitLine(); | ||||||
|  |     } | ||||||
|  |     return true; | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   // Write information about the crashing thread.
 | ||||||
|  |   bool DumpCrashingThread() { | ||||||
|  |     const unsigned num_threads = dumper_->threads().size(); | ||||||
|  | 
 | ||||||
|  |     for (unsigned i = 0; i < num_threads; ++i) { | ||||||
|  |       MDRawThread thread; | ||||||
|  |       my_memset(&thread, 0, sizeof(thread)); | ||||||
|  |       thread.thread_id = dumper_->threads()[i]; | ||||||
|  | 
 | ||||||
|  |       // Dump only the crashing thread.
 | ||||||
|  |       if (static_cast<pid_t>(thread.thread_id) != dumper_->crash_thread()) | ||||||
|  |         continue; | ||||||
|  | 
 | ||||||
|  |       assert(ucontext_); | ||||||
|  |       assert(!dumper_->IsPostMortem()); | ||||||
|  | 
 | ||||||
|  |       uint8_t* stack_copy; | ||||||
|  |       const uintptr_t stack_ptr = UContextReader::GetStackPointer(ucontext_); | ||||||
|  |       if (!DumpThreadStack(thread.thread_id, stack_ptr, -1, &stack_copy)) | ||||||
|  |         return false; | ||||||
|  | 
 | ||||||
|  |       RawContextCPU cpu; | ||||||
|  |       my_memset(&cpu, 0, sizeof(RawContextCPU)); | ||||||
|  | #if !defined(__ARM_EABI__) && !defined(__mips__) | ||||||
|  |       UContextReader::FillCPUContext(&cpu, ucontext_, float_state_); | ||||||
|  | #else | ||||||
|  |       UContextReader::FillCPUContext(&cpu, ucontext_); | ||||||
|  | #endif | ||||||
|  |       if (stack_copy) | ||||||
|  |         SeccompUnwinder::PopSeccompStackFrame(&cpu, thread, stack_copy); | ||||||
|  |       DumpCPUState(&cpu); | ||||||
|  |     } | ||||||
|  |     return true; | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   void DumpCPUState(RawContextCPU* cpu) { | ||||||
|  |     LogAppend("C "); | ||||||
|  |     LogAppend(cpu, sizeof(*cpu)); | ||||||
|  |     LogCommitLine(); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   // If there is caller-provided information about this mapping
 | ||||||
|  |   // in the mapping_list_ list, return true. Otherwise, return false.
 | ||||||
|  |   bool HaveMappingInfo(const MappingInfo& mapping) { | ||||||
|  |     for (MappingList::const_iterator iter = mapping_list_.begin(); | ||||||
|  |          iter != mapping_list_.end(); | ||||||
|  |          ++iter) { | ||||||
|  |       // Ignore any mappings that are wholly contained within
 | ||||||
|  |       // mappings in the mapping_info_ list.
 | ||||||
|  |       if (mapping.start_addr >= iter->first.start_addr && | ||||||
|  |           (mapping.start_addr + mapping.size) <= | ||||||
|  |               (iter->first.start_addr + iter->first.size)) { | ||||||
|  |         return true; | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |     return false; | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   // Dump information about the provided |mapping|. If |identifier| is non-NULL,
 | ||||||
|  |   // use it instead of calculating a file ID from the mapping.
 | ||||||
|  |   void DumpModule(const MappingInfo& mapping, | ||||||
|  |                   bool member, | ||||||
|  |                   unsigned int mapping_id, | ||||||
|  |                   const uint8_t* identifier) { | ||||||
|  |     MDGUID module_identifier; | ||||||
|  |     if (identifier) { | ||||||
|  |       // GUID was provided by caller.
 | ||||||
|  |       my_memcpy(&module_identifier, identifier, sizeof(MDGUID)); | ||||||
|  |     } else { | ||||||
|  |       dumper_->ElfFileIdentifierForMapping( | ||||||
|  |           mapping, | ||||||
|  |           member, | ||||||
|  |           mapping_id, | ||||||
|  |           reinterpret_cast<uint8_t*>(&module_identifier)); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     char file_name[NAME_MAX]; | ||||||
|  |     char file_path[NAME_MAX]; | ||||||
|  |     LinuxDumper::GetMappingEffectiveNameAndPath( | ||||||
|  |         mapping, file_path, sizeof(file_path), file_name, sizeof(file_name)); | ||||||
|  | 
 | ||||||
|  |     LogAppend("M "); | ||||||
|  |     LogAppend(static_cast<uintptr_t>(mapping.start_addr)); | ||||||
|  |     LogAppend(" "); | ||||||
|  |     LogAppend(mapping.offset); | ||||||
|  |     LogAppend(" "); | ||||||
|  |     LogAppend(mapping.size); | ||||||
|  |     LogAppend(" "); | ||||||
|  |     LogAppend(module_identifier.data1); | ||||||
|  |     LogAppend(module_identifier.data2); | ||||||
|  |     LogAppend(module_identifier.data3); | ||||||
|  |     LogAppend(module_identifier.data4[0]); | ||||||
|  |     LogAppend(module_identifier.data4[1]); | ||||||
|  |     LogAppend(module_identifier.data4[2]); | ||||||
|  |     LogAppend(module_identifier.data4[3]); | ||||||
|  |     LogAppend(module_identifier.data4[4]); | ||||||
|  |     LogAppend(module_identifier.data4[5]); | ||||||
|  |     LogAppend(module_identifier.data4[6]); | ||||||
|  |     LogAppend(module_identifier.data4[7]); | ||||||
|  |     LogAppend(" "); | ||||||
|  |     LogAppend(file_name); | ||||||
|  |     LogCommitLine(); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   // Write information about the mappings in effect.
 | ||||||
|  |   bool DumpMappings() { | ||||||
|  |     // First write all the mappings from the dumper
 | ||||||
|  |     for (unsigned i = 0; i < dumper_->mappings().size(); ++i) { | ||||||
|  |       const MappingInfo& mapping = *dumper_->mappings()[i]; | ||||||
|  |       // Skip mappings which don't look like libraries.
 | ||||||
|  |       if (!strstr(mapping.name, ".so") ||  // dump only libs (skip fonts, apks).
 | ||||||
|  |           mapping.size < 4096) { // too small to get a signature for.
 | ||||||
|  |         continue; | ||||||
|  |       } | ||||||
|  | 
 | ||||||
|  |       if (HaveMappingInfo(mapping)) | ||||||
|  |         continue; | ||||||
|  | 
 | ||||||
|  |       DumpModule(mapping, true, i, NULL); | ||||||
|  |     } | ||||||
|  |     // Next write all the mappings provided by the caller
 | ||||||
|  |     for (MappingList::const_iterator iter = mapping_list_.begin(); | ||||||
|  |          iter != mapping_list_.end(); | ||||||
|  |          ++iter) { | ||||||
|  |       DumpModule(iter->first, false, 0, iter->second); | ||||||
|  |     } | ||||||
|  |     return true; | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   void* Alloc(unsigned bytes) { return dumper_->allocator()->Alloc(bytes); } | ||||||
|  | 
 | ||||||
|  |   const struct ucontext* const ucontext_; | ||||||
|  | #if !defined(__ARM_EABI__) && !defined(__mips__) | ||||||
|  |   const google_breakpad::fpstate_t* const float_state_; | ||||||
|  | #endif | ||||||
|  |   LinuxDumper* dumper_; | ||||||
|  |   const MappingList& mapping_list_; | ||||||
|  |   char log_line_[512]; | ||||||
|  | }; | ||||||
|  | }  // namespace
 | ||||||
|  | 
 | ||||||
|  | namespace google_breakpad { | ||||||
|  | 
 | ||||||
|  | bool WriteMicrodump(pid_t crashing_process, | ||||||
|  |                     const void* blob, | ||||||
|  |                     size_t blob_size, | ||||||
|  |                     const MappingList& mappings) { | ||||||
|  |   LinuxPtraceDumper dumper(crashing_process); | ||||||
|  |   const ExceptionHandler::CrashContext* context = NULL; | ||||||
|  |   if (blob) { | ||||||
|  |     if (blob_size != sizeof(ExceptionHandler::CrashContext)) | ||||||
|  |       return false; | ||||||
|  |     context = reinterpret_cast<const ExceptionHandler::CrashContext*>(blob); | ||||||
|  |     dumper.set_crash_address( | ||||||
|  |         reinterpret_cast<uintptr_t>(context->siginfo.si_addr)); | ||||||
|  |     dumper.set_crash_signal(context->siginfo.si_signo); | ||||||
|  |     dumper.set_crash_thread(context->tid); | ||||||
|  |   } | ||||||
|  |   MicrodumpWriter writer(context, mappings, &dumper); | ||||||
|  |   if (!writer.Init()) | ||||||
|  |     return false; | ||||||
|  |   return writer.Dump(); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | }  // namespace google_breakpad
 | ||||||
| @ -0,0 +1,58 @@ | |||||||
|  | // Copyright (c) 2014, Google Inc.
 | ||||||
|  | // All rights reserved.
 | ||||||
|  | //
 | ||||||
|  | // Redistribution and use in source and binary forms, with or without
 | ||||||
|  | // modification, are permitted provided that the following conditions are
 | ||||||
|  | // met:
 | ||||||
|  | //
 | ||||||
|  | //     * Redistributions of source code must retain the above copyright
 | ||||||
|  | // notice, this list of conditions and the following disclaimer.
 | ||||||
|  | //     * Redistributions in binary form must reproduce the above
 | ||||||
|  | // copyright notice, this list of conditions and the following disclaimer
 | ||||||
|  | // in the documentation and/or other materials provided with the
 | ||||||
|  | // distribution.
 | ||||||
|  | //     * Neither the name of Google Inc. nor the names of its
 | ||||||
|  | // contributors may be used to endorse or promote products derived from
 | ||||||
|  | // this software without specific prior written permission.
 | ||||||
|  | //
 | ||||||
|  | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 | ||||||
|  | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 | ||||||
|  | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 | ||||||
|  | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 | ||||||
|  | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 | ||||||
|  | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 | ||||||
|  | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 | ||||||
|  | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 | ||||||
|  | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 | ||||||
|  | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 | ||||||
|  | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 | ||||||
|  | 
 | ||||||
|  | #ifndef CLIENT_LINUX_MINIDUMP_WRITER_MICRODUMP_WRITER_H_ | ||||||
|  | #define CLIENT_LINUX_MINIDUMP_WRITER_MICRODUMP_WRITER_H_ | ||||||
|  | 
 | ||||||
|  | #include <stdint.h> | ||||||
|  | #include <sys/types.h> | ||||||
|  | 
 | ||||||
|  | #include "client/linux/dump_writer_common/mapping_info.h" | ||||||
|  | 
 | ||||||
|  | namespace google_breakpad { | ||||||
|  | 
 | ||||||
|  | // Writes a microdump (a reduced dump containing only the state of the crashing
 | ||||||
|  | // thread) on the console (logcat on Android). These functions do not malloc nor
 | ||||||
|  | // use libc functions which may. Thus, it can be used in contexts where the
 | ||||||
|  | // state of the heap may be corrupt.
 | ||||||
|  | // Args:
 | ||||||
|  | //   crashing_process: the pid of the crashing process. This must be trusted.
 | ||||||
|  | //   blob: a blob of data from the crashing process. See exception_handler.h
 | ||||||
|  | //   blob_size: the length of |blob| in bytes.
 | ||||||
|  | //   mappings: a list of additional mappings provided by the application.
 | ||||||
|  | //
 | ||||||
|  | // Returns true iff successful.
 | ||||||
|  | bool WriteMicrodump(pid_t crashing_process, | ||||||
|  |                     const void* blob, | ||||||
|  |                     size_t blob_size, | ||||||
|  |                     const MappingList& mappings); | ||||||
|  | 
 | ||||||
|  | }  // namespace google_breakpad
 | ||||||
|  | 
 | ||||||
|  | #endif  // CLIENT_LINUX_MINIDUMP_WRITER_MICRODUMP_WRITER_H_
 | ||||||
| @ -36,8 +36,7 @@ | |||||||
| 
 | 
 | ||||||
| #include "breakpad_googletest_includes.h" | #include "breakpad_googletest_includes.h" | ||||||
| #include "client/linux/minidump_writer/cpu_set.h" | #include "client/linux/minidump_writer/cpu_set.h" | ||||||
| #include "common/linux/eintr_wrapper.h" | #include "common/linux/tests/auto_testfile.h" | ||||||
| #include "common/tests/auto_testfile.h" |  | ||||||
| 
 | 
 | ||||||
| using namespace google_breakpad; | using namespace google_breakpad; | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -33,8 +33,7 @@ | |||||||
| 
 | 
 | ||||||
| #include "client/linux/minidump_writer/line_reader.h" | #include "client/linux/minidump_writer/line_reader.h" | ||||||
| #include "breakpad_googletest_includes.h" | #include "breakpad_googletest_includes.h" | ||||||
| #include "common/linux/eintr_wrapper.h" | #include "common/linux/tests/auto_testfile.h" | ||||||
| #include "common/tests/auto_testfile.h" |  | ||||||
| 
 | 
 | ||||||
| using namespace google_breakpad; | using namespace google_breakpad; | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -99,6 +99,11 @@ bool LinuxCoreDumper::GetThreadInfoByIndex(size_t index, ThreadInfo* info) { | |||||||
|   memcpy(&stack_pointer, &info->regs.rsp, sizeof(info->regs.rsp)); |   memcpy(&stack_pointer, &info->regs.rsp, sizeof(info->regs.rsp)); | ||||||
| #elif defined(__ARM_EABI__) | #elif defined(__ARM_EABI__) | ||||||
|   memcpy(&stack_pointer, &info->regs.ARM_sp, sizeof(info->regs.ARM_sp)); |   memcpy(&stack_pointer, &info->regs.ARM_sp, sizeof(info->regs.ARM_sp)); | ||||||
|  | #elif defined(__aarch64__) | ||||||
|  |   memcpy(&stack_pointer, &info->regs.sp, sizeof(info->regs.sp)); | ||||||
|  | #elif defined(__mips__) | ||||||
|  |   stack_pointer = | ||||||
|  |       reinterpret_cast<uint8_t*>(info->regs.regs[MD_CONTEXT_MIPS_REG_SP]); | ||||||
| #else | #else | ||||||
| #error "This code hasn't been ported to your platform yet." | #error "This code hasn't been ported to your platform yet." | ||||||
| #endif | #endif | ||||||
| @ -119,7 +124,7 @@ bool LinuxCoreDumper::ThreadsResume() { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| bool LinuxCoreDumper::EnumerateThreads() { | bool LinuxCoreDumper::EnumerateThreads() { | ||||||
|   if (!mapped_core_file_.Map(core_path_)) { |   if (!mapped_core_file_.Map(core_path_, 0)) { | ||||||
|     fprintf(stderr, "Could not map core dump file into memory\n"); |     fprintf(stderr, "Could not map core dump file into memory\n"); | ||||||
|     return false; |     return false; | ||||||
|   } |   } | ||||||
| @ -183,7 +188,19 @@ bool LinuxCoreDumper::EnumerateThreads() { | |||||||
|         memset(&info, 0, sizeof(ThreadInfo)); |         memset(&info, 0, sizeof(ThreadInfo)); | ||||||
|         info.tgid = status->pr_pgrp; |         info.tgid = status->pr_pgrp; | ||||||
|         info.ppid = status->pr_ppid; |         info.ppid = status->pr_ppid; | ||||||
|  | #if defined(__mips__) | ||||||
|  |         for (int i = EF_REG0; i <= EF_REG31; i++) | ||||||
|  |           info.regs.regs[i - EF_REG0] = status->pr_reg[i]; | ||||||
|  | 
 | ||||||
|  |         info.regs.lo = status->pr_reg[EF_LO]; | ||||||
|  |         info.regs.hi = status->pr_reg[EF_HI]; | ||||||
|  |         info.regs.epc = status->pr_reg[EF_CP0_EPC]; | ||||||
|  |         info.regs.badvaddr = status->pr_reg[EF_CP0_BADVADDR]; | ||||||
|  |         info.regs.status = status->pr_reg[EF_CP0_STATUS]; | ||||||
|  |         info.regs.cause = status->pr_reg[EF_CP0_CAUSE]; | ||||||
|  | #else | ||||||
|         memcpy(&info.regs, status->pr_reg, sizeof(info.regs)); |         memcpy(&info.regs, status->pr_reg, sizeof(info.regs)); | ||||||
|  | #endif | ||||||
|         if (first_thread) { |         if (first_thread) { | ||||||
|           crash_thread_ = pid; |           crash_thread_ = pid; | ||||||
|           crash_signal_ = status->pr_info.si_signo; |           crash_signal_ = status->pr_info.si_signo; | ||||||
|  | |||||||
| @ -74,18 +74,23 @@ TEST(LinuxCoreDumperTest, VerifyDumpWithMultipleThreads) { | |||||||
|   const unsigned kCrashThread = 1; |   const unsigned kCrashThread = 1; | ||||||
|   const int kCrashSignal = SIGABRT; |   const int kCrashSignal = SIGABRT; | ||||||
|   pid_t child_pid; |   pid_t child_pid; | ||||||
|   // TODO(benchan): Revert to use ASSERT_TRUE once the flakiness in
 |   ASSERT_TRUE(crash_generator.CreateChildCrash(kNumOfThreads, kCrashThread, | ||||||
|   // CrashGenerator is identified and fixed.
 |                                                kCrashSignal, &child_pid)); | ||||||
|   if (!crash_generator.CreateChildCrash(kNumOfThreads, kCrashThread, |  | ||||||
|                                         kCrashSignal, &child_pid)) { |  | ||||||
|     fprintf(stderr, "LinuxCoreDumperTest.VerifyDumpWithMultipleThreads test " |  | ||||||
|             "is skipped due to no core dump generated\n"); |  | ||||||
|     return; |  | ||||||
|   } |  | ||||||
| 
 | 
 | ||||||
|   const string core_file = crash_generator.GetCoreFilePath(); |   const string core_file = crash_generator.GetCoreFilePath(); | ||||||
|   const string procfs_path = crash_generator.GetDirectoryOfProcFilesCopy(); |   const string procfs_path = crash_generator.GetDirectoryOfProcFilesCopy(); | ||||||
|  | 
 | ||||||
|  | #if defined(__ANDROID__) | ||||||
|  |   struct stat st; | ||||||
|  |   if (stat(core_file.c_str(), &st) != 0) { | ||||||
|  |     fprintf(stderr, "LinuxCoreDumperTest.VerifyDumpWithMultipleThreads test is " | ||||||
|  |             "skipped due to no core file being generated"); | ||||||
|  |     return; | ||||||
|  |   } | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|   LinuxCoreDumper dumper(child_pid, core_file.c_str(), procfs_path.c_str()); |   LinuxCoreDumper dumper(child_pid, core_file.c_str(), procfs_path.c_str()); | ||||||
|  | 
 | ||||||
|   EXPECT_TRUE(dumper.Init()); |   EXPECT_TRUE(dumper.Init()); | ||||||
| 
 | 
 | ||||||
|   EXPECT_TRUE(dumper.IsPostMortem()); |   EXPECT_TRUE(dumper.IsPostMortem()); | ||||||
|  | |||||||
| @ -38,12 +38,14 @@ | |||||||
| #include "client/linux/minidump_writer/linux_dumper.h" | #include "client/linux/minidump_writer/linux_dumper.h" | ||||||
| 
 | 
 | ||||||
| #include <assert.h> | #include <assert.h> | ||||||
|  | #include <elf.h> | ||||||
| #include <fcntl.h> | #include <fcntl.h> | ||||||
| #include <limits.h> | #include <limits.h> | ||||||
| #include <stddef.h> | #include <stddef.h> | ||||||
| #include <string.h> | #include <string.h> | ||||||
| 
 | 
 | ||||||
| #include "client/linux/minidump_writer/line_reader.h" | #include "client/linux/minidump_writer/line_reader.h" | ||||||
|  | #include "common/linux/elfutils.h" | ||||||
| #include "common/linux/file_id.h" | #include "common/linux/file_id.h" | ||||||
| #include "common/linux/linux_libc_support.h" | #include "common/linux/linux_libc_support.h" | ||||||
| #include "common/linux/memory_mapped_file.h" | #include "common/linux/memory_mapped_file.h" | ||||||
| @ -52,6 +54,7 @@ | |||||||
| 
 | 
 | ||||||
| static const char kMappedFileUnsafePrefix[] = "/dev/"; | static const char kMappedFileUnsafePrefix[] = "/dev/"; | ||||||
| static const char kDeletedSuffix[] = " (deleted)"; | static const char kDeletedSuffix[] = " (deleted)"; | ||||||
|  | static const char kReservedFlags[] = " ---p"; | ||||||
| 
 | 
 | ||||||
| inline static bool IsMappedFileOpenUnsafe( | inline static bool IsMappedFileOpenUnsafe( | ||||||
|     const google_breakpad::MappingInfo& mapping) { |     const google_breakpad::MappingInfo& mapping) { | ||||||
| @ -73,10 +76,13 @@ LinuxDumper::LinuxDumper(pid_t pid) | |||||||
|     : pid_(pid), |     : pid_(pid), | ||||||
|       crash_address_(0), |       crash_address_(0), | ||||||
|       crash_signal_(0), |       crash_signal_(0), | ||||||
|       crash_thread_(0), |       crash_thread_(pid), | ||||||
|       threads_(&allocator_, 8), |       threads_(&allocator_, 8), | ||||||
|       mappings_(&allocator_), |       mappings_(&allocator_), | ||||||
|       auxv_(&allocator_, AT_MAX + 1) { |       auxv_(&allocator_, AT_MAX + 1) { | ||||||
|  |   // The passed-in size to the constructor (above) is only a hint.
 | ||||||
|  |   // Must call .resize() to do actual initialization of the elements.
 | ||||||
|  |   auxv_.resize(AT_MAX + 1); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| LinuxDumper::~LinuxDumper() { | LinuxDumper::~LinuxDumper() { | ||||||
| @ -90,8 +96,7 @@ bool | |||||||
| LinuxDumper::ElfFileIdentifierForMapping(const MappingInfo& mapping, | LinuxDumper::ElfFileIdentifierForMapping(const MappingInfo& mapping, | ||||||
|                                          bool member, |                                          bool member, | ||||||
|                                          unsigned int mapping_id, |                                          unsigned int mapping_id, | ||||||
|                                          uint8_t identifier[sizeof(MDGUID)]) |                                          uint8_t identifier[sizeof(MDGUID)]) { | ||||||
| { |  | ||||||
|   assert(!member || mapping_id < mappings_.size()); |   assert(!member || mapping_id < mappings_.size()); | ||||||
|   my_memset(identifier, 0, sizeof(MDGUID)); |   my_memset(identifier, 0, sizeof(MDGUID)); | ||||||
|   if (IsMappedFileOpenUnsafe(mapping)) |   if (IsMappedFileOpenUnsafe(mapping)) | ||||||
| @ -113,15 +118,16 @@ LinuxDumper::ElfFileIdentifierForMapping(const MappingInfo& mapping, | |||||||
| 
 | 
 | ||||||
|   char filename[NAME_MAX]; |   char filename[NAME_MAX]; | ||||||
|   size_t filename_len = my_strlen(mapping.name); |   size_t filename_len = my_strlen(mapping.name); | ||||||
|   assert(filename_len < NAME_MAX); |   if (filename_len >= NAME_MAX) { | ||||||
|   if (filename_len >= NAME_MAX) |     assert(false); | ||||||
|     return false; |     return false; | ||||||
|  |   } | ||||||
|   my_memcpy(filename, mapping.name, filename_len); |   my_memcpy(filename, mapping.name, filename_len); | ||||||
|   filename[filename_len] = '\0'; |   filename[filename_len] = '\0'; | ||||||
|   bool filename_modified = HandleDeletedFileInMapping(filename); |   bool filename_modified = HandleDeletedFileInMapping(filename); | ||||||
| 
 | 
 | ||||||
|   MemoryMappedFile mapped_file(filename); |   MemoryMappedFile mapped_file(filename, mapping.offset); | ||||||
|   if (!mapped_file.data())  // Should probably check if size >= ElfW(Ehdr)?
 |   if (!mapped_file.data() || mapped_file.size() < SELFMAG) | ||||||
|     return false; |     return false; | ||||||
| 
 | 
 | ||||||
|   bool success = |   bool success = | ||||||
| @ -134,6 +140,120 @@ LinuxDumper::ElfFileIdentifierForMapping(const MappingInfo& mapping, | |||||||
|   return success; |   return success; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | namespace { | ||||||
|  | bool ElfFileSoNameFromMappedFile( | ||||||
|  |     const void* elf_base, char* soname, size_t soname_size) { | ||||||
|  |   if (!IsValidElf(elf_base)) { | ||||||
|  |     // Not ELF
 | ||||||
|  |     return false; | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   const void* segment_start; | ||||||
|  |   size_t segment_size; | ||||||
|  |   int elf_class; | ||||||
|  |   if (!FindElfSection(elf_base, ".dynamic", SHT_DYNAMIC, | ||||||
|  |                       &segment_start, &segment_size, &elf_class)) { | ||||||
|  |     // No dynamic section
 | ||||||
|  |     return false; | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   const void* dynstr_start; | ||||||
|  |   size_t dynstr_size; | ||||||
|  |   if (!FindElfSection(elf_base, ".dynstr", SHT_STRTAB, | ||||||
|  |                       &dynstr_start, &dynstr_size, &elf_class)) { | ||||||
|  |     // No dynstr section
 | ||||||
|  |     return false; | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   const ElfW(Dyn)* dynamic = static_cast<const ElfW(Dyn)*>(segment_start); | ||||||
|  |   size_t dcount = segment_size / sizeof(ElfW(Dyn)); | ||||||
|  |   for (const ElfW(Dyn)* dyn = dynamic; dyn < dynamic + dcount; ++dyn) { | ||||||
|  |     if (dyn->d_tag == DT_SONAME) { | ||||||
|  |       const char* dynstr = static_cast<const char*>(dynstr_start); | ||||||
|  |       if (dyn->d_un.d_val >= dynstr_size) { | ||||||
|  |         // Beyond the end of the dynstr section
 | ||||||
|  |         return false; | ||||||
|  |       } | ||||||
|  |       const char* str = dynstr + dyn->d_un.d_val; | ||||||
|  |       const size_t maxsize = dynstr_size - dyn->d_un.d_val; | ||||||
|  |       my_strlcpy(soname, str, maxsize < soname_size ? maxsize : soname_size); | ||||||
|  |       return true; | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   // Did not find SONAME
 | ||||||
|  |   return false; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // Find the shared object name (SONAME) by examining the ELF information
 | ||||||
|  | // for |mapping|. If the SONAME is found copy it into the passed buffer
 | ||||||
|  | // |soname| and return true. The size of the buffer is |soname_size|.
 | ||||||
|  | // The SONAME will be truncated if it is too long to fit in the buffer.
 | ||||||
|  | bool ElfFileSoName( | ||||||
|  |     const MappingInfo& mapping, char* soname, size_t soname_size) { | ||||||
|  |   if (IsMappedFileOpenUnsafe(mapping)) { | ||||||
|  |     // Not safe
 | ||||||
|  |     return false; | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   char filename[NAME_MAX]; | ||||||
|  |   size_t filename_len = my_strlen(mapping.name); | ||||||
|  |   if (filename_len >= NAME_MAX) { | ||||||
|  |     assert(false); | ||||||
|  |     // name too long
 | ||||||
|  |     return false; | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   my_memcpy(filename, mapping.name, filename_len); | ||||||
|  |   filename[filename_len] = '\0'; | ||||||
|  | 
 | ||||||
|  |   MemoryMappedFile mapped_file(filename, mapping.offset); | ||||||
|  |   if (!mapped_file.data() || mapped_file.size() < SELFMAG) { | ||||||
|  |     // mmap failed
 | ||||||
|  |     return false; | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   return ElfFileSoNameFromMappedFile(mapped_file.data(), soname, soname_size); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | }  // namespace
 | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | // static
 | ||||||
|  | void LinuxDumper::GetMappingEffectiveNameAndPath(const MappingInfo& mapping, | ||||||
|  |                                                  char* file_path, | ||||||
|  |                                                  size_t file_path_size, | ||||||
|  |                                                  char* file_name, | ||||||
|  |                                                  size_t file_name_size) { | ||||||
|  |   my_strlcpy(file_path, mapping.name, file_path_size); | ||||||
|  | 
 | ||||||
|  |   // If an executable is mapped from a non-zero offset, this is likely because
 | ||||||
|  |   // the executable was loaded directly from inside an archive file (e.g., an
 | ||||||
|  |   // apk on Android). We try to find the name of the shared object (SONAME) by
 | ||||||
|  |   // looking in the file for ELF sections.
 | ||||||
|  |   bool mapped_from_archive = false; | ||||||
|  |   if (mapping.exec && mapping.offset != 0) | ||||||
|  |     mapped_from_archive = ElfFileSoName(mapping, file_name, file_name_size); | ||||||
|  | 
 | ||||||
|  |   if (mapped_from_archive) { | ||||||
|  |     // Some tools (e.g., stackwalk) extract the basename from the pathname. In
 | ||||||
|  |     // this case, we append the file_name to the mapped archive path as follows:
 | ||||||
|  |     //   file_name := libname.so
 | ||||||
|  |     //   file_path := /path/to/ARCHIVE.APK/libname.so
 | ||||||
|  |     if (my_strlen(file_path) + 1 + my_strlen(file_name) < file_path_size) { | ||||||
|  |       my_strlcat(file_path, "/", file_path_size); | ||||||
|  |       my_strlcat(file_path, file_name, file_path_size); | ||||||
|  |     } | ||||||
|  |   } else { | ||||||
|  |     // Common case:
 | ||||||
|  |     //   file_path := /path/to/libname.so
 | ||||||
|  |     //   file_name := libname.so
 | ||||||
|  |     const char* basename = my_strrchr(file_path, '/'); | ||||||
|  |     basename = basename == NULL ? file_path : (basename + 1); | ||||||
|  |     my_strlcpy(file_name, basename, file_name_size); | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | 
 | ||||||
| bool LinuxDumper::ReadAuxv() { | bool LinuxDumper::ReadAuxv() { | ||||||
|   char auxv_path[NAME_MAX]; |   char auxv_path[NAME_MAX]; | ||||||
|   if (!BuildProcPath(auxv_path, pid_, "auxv")) { |   if (!BuildProcPath(auxv_path, pid_, "auxv")) { | ||||||
| @ -193,6 +313,7 @@ bool LinuxDumper::EnumerateMappings() { | |||||||
|     if (*i1 == '-') { |     if (*i1 == '-') { | ||||||
|       const char* i2 = my_read_hex_ptr(&end_addr, i1 + 1); |       const char* i2 = my_read_hex_ptr(&end_addr, i1 + 1); | ||||||
|       if (*i2 == ' ') { |       if (*i2 == ' ') { | ||||||
|  |         bool exec = (*(i2 + 3) == 'x'); | ||||||
|         const char* i3 = my_read_hex_ptr(&offset, i2 + 6 /* skip ' rwxp ' */); |         const char* i3 = my_read_hex_ptr(&offset, i2 + 6 /* skip ' rwxp ' */); | ||||||
|         if (*i3 == ' ') { |         if (*i3 == ' ') { | ||||||
|           const char* name = NULL; |           const char* name = NULL; | ||||||
| @ -216,11 +337,29 @@ bool LinuxDumper::EnumerateMappings() { | |||||||
|               continue; |               continue; | ||||||
|             } |             } | ||||||
|           } |           } | ||||||
|  |           // Also merge mappings that result from address ranges that the
 | ||||||
|  |           // linker reserved but which a loaded library did not use. These
 | ||||||
|  |           // appear as an anonymous private mapping with no access flags set
 | ||||||
|  |           // and which directly follow an executable mapping.
 | ||||||
|  |           if (!name && !mappings_.empty()) { | ||||||
|  |             MappingInfo* module = mappings_.back(); | ||||||
|  |             if ((start_addr == module->start_addr + module->size) && | ||||||
|  |                 module->exec && | ||||||
|  |                 module->name[0] == '/' && | ||||||
|  |                 offset == 0 && my_strncmp(i2, | ||||||
|  |                                           kReservedFlags, | ||||||
|  |                                           sizeof(kReservedFlags) - 1) == 0) { | ||||||
|  |               module->size = end_addr - module->start_addr; | ||||||
|  |               line_reader->PopLine(line_len); | ||||||
|  |               continue; | ||||||
|  |             } | ||||||
|  |           } | ||||||
|           MappingInfo* const module = new(allocator_) MappingInfo; |           MappingInfo* const module = new(allocator_) MappingInfo; | ||||||
|           my_memset(module, 0, sizeof(MappingInfo)); |           my_memset(module, 0, sizeof(MappingInfo)); | ||||||
|           module->start_addr = start_addr; |           module->start_addr = start_addr; | ||||||
|           module->size = end_addr - start_addr; |           module->size = end_addr - start_addr; | ||||||
|           module->offset = offset; |           module->offset = offset; | ||||||
|  |           module->exec = exec; | ||||||
|           if (name != NULL) { |           if (name != NULL) { | ||||||
|             const unsigned l = my_strlen(name); |             const unsigned l = my_strlen(name); | ||||||
|             if (l < sizeof(module->name)) |             if (l < sizeof(module->name)) | ||||||
| @ -273,7 +412,8 @@ bool LinuxDumper::GetStackInfo(const void** stack, size_t* stack_len, | |||||||
|   const MappingInfo* mapping = FindMapping(stack_pointer); |   const MappingInfo* mapping = FindMapping(stack_pointer); | ||||||
|   if (!mapping) |   if (!mapping) | ||||||
|     return false; |     return false; | ||||||
|   const ptrdiff_t offset = stack_pointer - (uint8_t*) mapping->start_addr; |   const ptrdiff_t offset = stack_pointer - | ||||||
|  |       reinterpret_cast<uint8_t*>(mapping->start_addr); | ||||||
|   const ptrdiff_t distance_to_end = |   const ptrdiff_t distance_to_end = | ||||||
|       static_cast<ptrdiff_t>(mapping->size) - offset; |       static_cast<ptrdiff_t>(mapping->size) - offset; | ||||||
|   *stack_len = distance_to_end > kStackToCapture ? |   *stack_len = distance_to_end > kStackToCapture ? | ||||||
|  | |||||||
| @ -44,19 +44,17 @@ | |||||||
| #include <sys/types.h> | #include <sys/types.h> | ||||||
| #include <sys/user.h> | #include <sys/user.h> | ||||||
| 
 | 
 | ||||||
|  | #include "client/linux/dump_writer_common/mapping_info.h" | ||||||
|  | #include "client/linux/dump_writer_common/thread_info.h" | ||||||
| #include "common/memory.h" | #include "common/memory.h" | ||||||
| #include "google_breakpad/common/minidump_format.h" | #include "google_breakpad/common/minidump_format.h" | ||||||
| 
 | 
 | ||||||
| namespace google_breakpad { | namespace google_breakpad { | ||||||
| 
 | 
 | ||||||
| #if defined(__i386) || defined(__x86_64) |  | ||||||
| typedef typeof(((struct user*) 0)->u_debugreg[0]) debugreg_t; |  | ||||||
| #endif |  | ||||||
| 
 |  | ||||||
| // Typedef for our parsing of the auxv variables in /proc/pid/auxv.
 | // Typedef for our parsing of the auxv variables in /proc/pid/auxv.
 | ||||||
| #if defined(__i386) || defined(__ARM_EABI__) | #if defined(__i386) || defined(__ARM_EABI__) || defined(__mips__) | ||||||
| typedef Elf32_auxv_t elf_aux_entry; | typedef Elf32_auxv_t elf_aux_entry; | ||||||
| #elif defined(__x86_64) | #elif defined(__x86_64) || defined(__aarch64__) | ||||||
| typedef Elf64_auxv_t elf_aux_entry; | typedef Elf64_auxv_t elf_aux_entry; | ||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
| @ -67,39 +65,6 @@ typedef typeof(((elf_aux_entry*) 0)->a_un.a_val) elf_aux_val_t; | |||||||
| // This should always be less than NAME_MAX!
 | // This should always be less than NAME_MAX!
 | ||||||
| const char kLinuxGateLibraryName[] = "linux-gate.so"; | const char kLinuxGateLibraryName[] = "linux-gate.so"; | ||||||
| 
 | 
 | ||||||
| // We produce one of these structures for each thread in the crashed process.
 |  | ||||||
| struct ThreadInfo { |  | ||||||
|   pid_t tgid;   // thread group id
 |  | ||||||
|   pid_t ppid;   // parent process
 |  | ||||||
| 
 |  | ||||||
|   uintptr_t stack_pointer;  // thread stack pointer
 |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| #if defined(__i386) || defined(__x86_64) |  | ||||||
|   user_regs_struct regs; |  | ||||||
|   user_fpregs_struct fpregs; |  | ||||||
|   static const unsigned kNumDebugRegisters = 8; |  | ||||||
|   debugreg_t dregs[8]; |  | ||||||
| #if defined(__i386) |  | ||||||
|   user_fpxregs_struct fpxregs; |  | ||||||
| #endif  // defined(__i386)
 |  | ||||||
| 
 |  | ||||||
| #elif defined(__ARM_EABI__) |  | ||||||
|   // Mimicking how strace does this(see syscall.c, search for GETREGS)
 |  | ||||||
|   struct user_regs regs; |  | ||||||
|   struct user_fpregs fpregs; |  | ||||||
| #endif |  | ||||||
| }; |  | ||||||
| 
 |  | ||||||
| // One of these is produced for each mapping in the process (i.e. line in
 |  | ||||||
| // /proc/$x/maps).
 |  | ||||||
| struct MappingInfo { |  | ||||||
|   uintptr_t start_addr; |  | ||||||
|   size_t size; |  | ||||||
|   size_t offset;  // offset into the backed file.
 |  | ||||||
|   char name[NAME_MAX]; |  | ||||||
| }; |  | ||||||
| 
 |  | ||||||
| class LinuxDumper { | class LinuxDumper { | ||||||
|  public: |  public: | ||||||
|   explicit LinuxDumper(pid_t pid); |   explicit LinuxDumper(pid_t pid); | ||||||
| @ -146,7 +111,8 @@ class LinuxDumper { | |||||||
|   virtual bool BuildProcPath(char* path, pid_t pid, const char* node) const = 0; |   virtual bool BuildProcPath(char* path, pid_t pid, const char* node) const = 0; | ||||||
| 
 | 
 | ||||||
|   // Generate a File ID from the .text section of a mapped entry.
 |   // Generate a File ID from the .text section of a mapped entry.
 | ||||||
|   // If not a member, mapping_id is ignored.
 |   // If not a member, mapping_id is ignored. This method can also manipulate the
 | ||||||
|  |   // |mapping|.name to truncate "(deleted)" from the file name if necessary.
 | ||||||
|   bool ElfFileIdentifierForMapping(const MappingInfo& mapping, |   bool ElfFileIdentifierForMapping(const MappingInfo& mapping, | ||||||
|                                    bool member, |                                    bool member, | ||||||
|                                    unsigned int mapping_id, |                                    unsigned int mapping_id, | ||||||
| @ -163,6 +129,17 @@ class LinuxDumper { | |||||||
|   pid_t crash_thread() const { return crash_thread_; } |   pid_t crash_thread() const { return crash_thread_; } | ||||||
|   void set_crash_thread(pid_t crash_thread) { crash_thread_ = crash_thread; } |   void set_crash_thread(pid_t crash_thread) { crash_thread_ = crash_thread; } | ||||||
| 
 | 
 | ||||||
|  |   // Extracts the effective path and file name of from |mapping|. In most cases
 | ||||||
|  |   // the effective name/path are just the mapping's path and basename. In some
 | ||||||
|  |   // other cases, however, a library can be mapped from an archive (e.g., when
 | ||||||
|  |   // loading .so libs from an apk on Android) and this method is able to
 | ||||||
|  |   // reconstruct the original file name.
 | ||||||
|  |   static void GetMappingEffectiveNameAndPath(const MappingInfo& mapping, | ||||||
|  |                                              char* file_path, | ||||||
|  |                                              size_t file_path_size, | ||||||
|  |                                              char* file_name, | ||||||
|  |                                              size_t file_name_size); | ||||||
|  | 
 | ||||||
|  protected: |  protected: | ||||||
|   bool ReadAuxv(); |   bool ReadAuxv(); | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -43,10 +43,14 @@ | |||||||
| 
 | 
 | ||||||
| #if defined(__ARM_EABI__) | #if defined(__ARM_EABI__) | ||||||
| #define TID_PTR_REGISTER "r3" | #define TID_PTR_REGISTER "r3" | ||||||
|  | #elif defined(__aarch64__) | ||||||
|  | #define TID_PTR_REGISTER "x3" | ||||||
| #elif defined(__i386) | #elif defined(__i386) | ||||||
| #define TID_PTR_REGISTER "ecx" | #define TID_PTR_REGISTER "ecx" | ||||||
| #elif defined(__x86_64) | #elif defined(__x86_64) | ||||||
| #define TID_PTR_REGISTER "rcx" | #define TID_PTR_REGISTER "rcx" | ||||||
|  | #elif defined(__mips__) | ||||||
|  | #define TID_PTR_REGISTER "$1" | ||||||
| #else | #else | ||||||
| #error This test has not been ported to this platform. | #error This test has not been ported to this platform. | ||||||
| #endif | #endif | ||||||
|  | |||||||
| @ -47,8 +47,13 @@ | |||||||
| #include <stdlib.h> | #include <stdlib.h> | ||||||
| #include <string.h> | #include <string.h> | ||||||
| #include <sys/ptrace.h> | #include <sys/ptrace.h> | ||||||
|  | #include <sys/uio.h> | ||||||
| #include <sys/wait.h> | #include <sys/wait.h> | ||||||
| 
 | 
 | ||||||
|  | #if defined(__i386) | ||||||
|  | #include <cpuid.h> | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
| #include "client/linux/minidump_writer/directory_reader.h" | #include "client/linux/minidump_writer/directory_reader.h" | ||||||
| #include "client/linux/minidump_writer/line_reader.h" | #include "client/linux/minidump_writer/line_reader.h" | ||||||
| #include "common/linux/linux_libc_support.h" | #include "common/linux/linux_libc_support.h" | ||||||
| @ -182,6 +187,20 @@ bool LinuxPtraceDumper::GetThreadInfoByIndex(size_t index, ThreadInfo* info) { | |||||||
|   if (info->ppid == -1 || info->tgid == -1) |   if (info->ppid == -1 || info->tgid == -1) | ||||||
|     return false; |     return false; | ||||||
| 
 | 
 | ||||||
|  | #ifdef PTRACE_GETREGSET | ||||||
|  |   struct iovec io; | ||||||
|  |   io.iov_base = &info->regs; | ||||||
|  |   io.iov_len = sizeof(info->regs); | ||||||
|  |   if (sys_ptrace(PTRACE_GETREGSET, tid, (void*)NT_PRSTATUS, (void*)&io) == -1) { | ||||||
|  |     return false; | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   io.iov_base = &info->fpregs; | ||||||
|  |   io.iov_len = sizeof(info->fpregs); | ||||||
|  |   if (sys_ptrace(PTRACE_GETREGSET, tid, (void*)NT_FPREGSET, (void*)&io) == -1) { | ||||||
|  |     return false; | ||||||
|  |   } | ||||||
|  | #else | ||||||
|   if (sys_ptrace(PTRACE_GETREGS, tid, NULL, &info->regs) == -1) { |   if (sys_ptrace(PTRACE_GETREGS, tid, NULL, &info->regs) == -1) { | ||||||
|     return false; |     return false; | ||||||
|   } |   } | ||||||
| @ -189,11 +208,23 @@ bool LinuxPtraceDumper::GetThreadInfoByIndex(size_t index, ThreadInfo* info) { | |||||||
|   if (sys_ptrace(PTRACE_GETFPREGS, tid, NULL, &info->fpregs) == -1) { |   if (sys_ptrace(PTRACE_GETFPREGS, tid, NULL, &info->fpregs) == -1) { | ||||||
|     return false; |     return false; | ||||||
|   } |   } | ||||||
|  | #endif | ||||||
| 
 | 
 | ||||||
| #if defined(__i386) | #if defined(__i386) | ||||||
|   if (sys_ptrace(PTRACE_GETFPXREGS, tid, NULL, &info->fpxregs) == -1) | #if !defined(bit_FXSAVE)  // e.g. Clang
 | ||||||
|     return false; | #define bit_FXSAVE bit_FXSR | ||||||
| #endif | #endif | ||||||
|  |   // Detect if the CPU supports the FXSAVE/FXRSTOR instructions
 | ||||||
|  |   int eax, ebx, ecx, edx; | ||||||
|  |   __cpuid(1, eax, ebx, ecx, edx); | ||||||
|  |   if (edx & bit_FXSAVE) { | ||||||
|  |     if (sys_ptrace(PTRACE_GETFPXREGS, tid, NULL, &info->fpxregs) == -1) { | ||||||
|  |       return false; | ||||||
|  |     } | ||||||
|  |   } else { | ||||||
|  |     memset(&info->fpxregs, 0, sizeof(info->fpxregs)); | ||||||
|  |   } | ||||||
|  | #endif  // defined(__i386)
 | ||||||
| 
 | 
 | ||||||
| #if defined(__i386) || defined(__x86_64) | #if defined(__i386) || defined(__x86_64) | ||||||
|   for (unsigned i = 0; i < ThreadInfo::kNumDebugRegisters; ++i) { |   for (unsigned i = 0; i < ThreadInfo::kNumDebugRegisters; ++i) { | ||||||
| @ -208,6 +239,17 @@ bool LinuxPtraceDumper::GetThreadInfoByIndex(size_t index, ThreadInfo* info) { | |||||||
|   } |   } | ||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
|  | #if defined(__mips__) | ||||||
|  |   for (int i = 0; i < 3; ++i) { | ||||||
|  |     sys_ptrace(PTRACE_PEEKUSER, tid, | ||||||
|  |                reinterpret_cast<void*>(DSP_BASE + (i * 2)), &info->hi[i]); | ||||||
|  |     sys_ptrace(PTRACE_PEEKUSER, tid, | ||||||
|  |                reinterpret_cast<void*>(DSP_BASE + (i * 2) + 1), &info->lo[i]); | ||||||
|  |   } | ||||||
|  |   sys_ptrace(PTRACE_PEEKUSER, tid, | ||||||
|  |              reinterpret_cast<void*>(DSP_CONTROL), &info->dsp_control); | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|   const uint8_t* stack_pointer; |   const uint8_t* stack_pointer; | ||||||
| #if defined(__i386) | #if defined(__i386) | ||||||
|   my_memcpy(&stack_pointer, &info->regs.esp, sizeof(info->regs.esp)); |   my_memcpy(&stack_pointer, &info->regs.esp, sizeof(info->regs.esp)); | ||||||
| @ -215,6 +257,11 @@ bool LinuxPtraceDumper::GetThreadInfoByIndex(size_t index, ThreadInfo* info) { | |||||||
|   my_memcpy(&stack_pointer, &info->regs.rsp, sizeof(info->regs.rsp)); |   my_memcpy(&stack_pointer, &info->regs.rsp, sizeof(info->regs.rsp)); | ||||||
| #elif defined(__ARM_EABI__) | #elif defined(__ARM_EABI__) | ||||||
|   my_memcpy(&stack_pointer, &info->regs.ARM_sp, sizeof(info->regs.ARM_sp)); |   my_memcpy(&stack_pointer, &info->regs.ARM_sp, sizeof(info->regs.ARM_sp)); | ||||||
|  | #elif defined(__aarch64__) | ||||||
|  |   my_memcpy(&stack_pointer, &info->regs.sp, sizeof(info->regs.sp)); | ||||||
|  | #elif defined(__mips__) | ||||||
|  |   stack_pointer = | ||||||
|  |       reinterpret_cast<uint8_t*>(info->regs.regs[MD_CONTEXT_MIPS_REG_SP]); | ||||||
| #else | #else | ||||||
| #error "This code hasn't been ported to your platform yet." | #error "This code hasn't been ported to your platform yet." | ||||||
| #endif | #endif | ||||||
|  | |||||||
| @ -28,7 +28,7 @@ | |||||||
| // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 | ||||||
| 
 | 
 | ||||||
| // linux_ptrace_dumper_unittest.cc:
 | // linux_ptrace_dumper_unittest.cc:
 | ||||||
| // Unit tests for google_breakpad::LinuxPtraceDumoer.
 | // Unit tests for google_breakpad::LinuxPtraceDumper.
 | ||||||
| //
 | //
 | ||||||
| // This file was renamed from linux_dumper_unittest.cc and modified due
 | // This file was renamed from linux_dumper_unittest.cc and modified due
 | ||||||
| // to LinuxDumper being splitted into two classes.
 | // to LinuxDumper being splitted into two classes.
 | ||||||
| @ -41,6 +41,7 @@ | |||||||
| #include <stdint.h> | #include <stdint.h> | ||||||
| #include <string.h> | #include <string.h> | ||||||
| #include <sys/mman.h> | #include <sys/mman.h> | ||||||
|  | #include <sys/prctl.h> | ||||||
| #include <sys/poll.h> | #include <sys/poll.h> | ||||||
| #include <sys/stat.h> | #include <sys/stat.h> | ||||||
| #include <sys/types.h> | #include <sys/types.h> | ||||||
| @ -57,20 +58,72 @@ | |||||||
| #include "common/memory.h" | #include "common/memory.h" | ||||||
| #include "common/using_std_string.h" | #include "common/using_std_string.h" | ||||||
| 
 | 
 | ||||||
|  | #ifndef PR_SET_PTRACER | ||||||
|  | #define PR_SET_PTRACER 0x59616d61 | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
| using namespace google_breakpad; | using namespace google_breakpad; | ||||||
| 
 | 
 | ||||||
| namespace { | namespace { | ||||||
| 
 | 
 | ||||||
| typedef testing::Test LinuxPtraceDumperTest; | typedef testing::Test LinuxPtraceDumperTest; | ||||||
| 
 | 
 | ||||||
| }  // namespace
 | /* Fixture for running tests in a child process. */ | ||||||
| 
 | class LinuxPtraceDumperChildTest : public testing::Test { | ||||||
| TEST(LinuxPtraceDumperTest, Setup) { |  protected: | ||||||
|   LinuxPtraceDumper dumper(getpid()); |   virtual void SetUp() { | ||||||
|  |     child_pid_ = fork(); | ||||||
|  | #ifndef __ANDROID__ | ||||||
|  |     prctl(PR_SET_PTRACER, child_pid_); | ||||||
|  | #endif | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
| TEST(LinuxPtraceDumperTest, FindMappings) { |   /* Gtest is calling TestBody from this class, which sets up a child
 | ||||||
|   LinuxPtraceDumper dumper(getpid()); |    * process in which the RealTestBody virtual member is called. | ||||||
|  |    * As such, TestBody is not supposed to be overridden in derived classes. | ||||||
|  |    */ | ||||||
|  |   virtual void TestBody() /* final */ { | ||||||
|  |     if (child_pid_ == 0) { | ||||||
|  |       // child process
 | ||||||
|  |       RealTestBody(); | ||||||
|  |       exit(HasFatalFailure() ? kFatalFailure : | ||||||
|  |            (HasNonfatalFailure() ? kNonFatalFailure : 0)); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     ASSERT_TRUE(child_pid_ > 0); | ||||||
|  |     int status; | ||||||
|  |     waitpid(child_pid_, &status, 0); | ||||||
|  |     if (WEXITSTATUS(status) == kFatalFailure) { | ||||||
|  |       GTEST_FATAL_FAILURE_("Test failed in child process"); | ||||||
|  |     } else if (WEXITSTATUS(status) == kNonFatalFailure) { | ||||||
|  |       GTEST_NONFATAL_FAILURE_("Test failed in child process"); | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   /* Gtest defines TestBody functions through its macros, but classes
 | ||||||
|  |    * derived from this one need to define RealTestBody instead. | ||||||
|  |    * This is achieved by defining a TestBody macro further below. | ||||||
|  |    */ | ||||||
|  |   virtual void RealTestBody() = 0; | ||||||
|  |  private: | ||||||
|  |   static const int kFatalFailure = 1; | ||||||
|  |   static const int kNonFatalFailure = 2; | ||||||
|  | 
 | ||||||
|  |   pid_t child_pid_; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | }  // namespace
 | ||||||
|  | 
 | ||||||
|  | /* Replace TestBody declarations within TEST*() with RealTestBody
 | ||||||
|  |  * declarations */ | ||||||
|  | #define TestBody RealTestBody | ||||||
|  | 
 | ||||||
|  | TEST_F(LinuxPtraceDumperChildTest, Setup) { | ||||||
|  |   LinuxPtraceDumper dumper(getppid()); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | TEST_F(LinuxPtraceDumperChildTest, FindMappings) { | ||||||
|  |   LinuxPtraceDumper dumper(getppid()); | ||||||
|   ASSERT_TRUE(dumper.Init()); |   ASSERT_TRUE(dumper.Init()); | ||||||
| 
 | 
 | ||||||
|   ASSERT_TRUE(dumper.FindMapping(reinterpret_cast<void*>(getpid))); |   ASSERT_TRUE(dumper.FindMapping(reinterpret_cast<void*>(getpid))); | ||||||
| @ -78,14 +131,14 @@ TEST(LinuxPtraceDumperTest, FindMappings) { | |||||||
|   ASSERT_FALSE(dumper.FindMapping(NULL)); |   ASSERT_FALSE(dumper.FindMapping(NULL)); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| TEST(LinuxPtraceDumperTest, ThreadList) { | TEST_F(LinuxPtraceDumperChildTest, ThreadList) { | ||||||
|   LinuxPtraceDumper dumper(getpid()); |   LinuxPtraceDumper dumper(getppid()); | ||||||
|   ASSERT_TRUE(dumper.Init()); |   ASSERT_TRUE(dumper.Init()); | ||||||
| 
 | 
 | ||||||
|   ASSERT_GE(dumper.threads().size(), (size_t)1); |   ASSERT_GE(dumper.threads().size(), (size_t)1); | ||||||
|   bool found = false; |   bool found = false; | ||||||
|   for (size_t i = 0; i < dumper.threads().size(); ++i) { |   for (size_t i = 0; i < dumper.threads().size(); ++i) { | ||||||
|     if (dumper.threads()[i] == getpid()) { |     if (dumper.threads()[i] == getppid()) { | ||||||
|       ASSERT_FALSE(found); |       ASSERT_FALSE(found); | ||||||
|       found = true; |       found = true; | ||||||
|     } |     } | ||||||
| @ -97,12 +150,22 @@ TEST(LinuxPtraceDumperTest, ThreadList) { | |||||||
| // a mmap'ed mapping.
 | // a mmap'ed mapping.
 | ||||||
| class StackHelper { | class StackHelper { | ||||||
|  public: |  public: | ||||||
|   StackHelper(int fd, char* mapping, size_t size) |   StackHelper() | ||||||
|     : fd_(fd), mapping_(mapping), size_(size) {} |     : fd_(-1), mapping_(NULL), size_(0) {} | ||||||
|   ~StackHelper() { |   ~StackHelper() { | ||||||
|  |     if (size_) | ||||||
|       munmap(mapping_, size_); |       munmap(mapping_, size_); | ||||||
|  |     if (fd_ >= 0) | ||||||
|       close(fd_); |       close(fd_); | ||||||
|   } |   } | ||||||
|  |   void Init(int fd, char* mapping, size_t size) { | ||||||
|  |     fd_ = fd; | ||||||
|  |     mapping_ = mapping; | ||||||
|  |     size_ = size; | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   char* mapping() const { return mapping_; } | ||||||
|  |   size_t size() const { return size_; } | ||||||
| 
 | 
 | ||||||
|  private: |  private: | ||||||
|   int fd_; |   int fd_; | ||||||
| @ -110,19 +173,28 @@ class StackHelper { | |||||||
|   size_t size_; |   size_t size_; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| TEST(LinuxPtraceDumperTest, MergedMappings) { | class LinuxPtraceDumperMappingsTest : public LinuxPtraceDumperChildTest { | ||||||
|   string helper_path(GetHelperBinary()); |  protected: | ||||||
|   if (helper_path.empty()) { |   virtual void SetUp(); | ||||||
|  | 
 | ||||||
|  |   string helper_path_; | ||||||
|  |   size_t page_size_; | ||||||
|  |   StackHelper helper_; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | void LinuxPtraceDumperMappingsTest::SetUp() { | ||||||
|  |   helper_path_ = GetHelperBinary(); | ||||||
|  |   if (helper_path_.empty()) { | ||||||
|     FAIL() << "Couldn't find helper binary"; |     FAIL() << "Couldn't find helper binary"; | ||||||
|     exit(1); |     exit(1); | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   // mmap two segments out of the helper binary, one
 |   // mmap two segments out of the helper binary, one
 | ||||||
|   // enclosed in the other, but with different protections.
 |   // enclosed in the other, but with different protections.
 | ||||||
|   const size_t kPageSize = sysconf(_SC_PAGESIZE); |   page_size_ = sysconf(_SC_PAGESIZE); | ||||||
|   const size_t kMappingSize = 3 * kPageSize; |   const size_t kMappingSize = 3 * page_size_; | ||||||
|   int fd = open(helper_path.c_str(), O_RDONLY); |   int fd = open(helper_path_.c_str(), O_RDONLY); | ||||||
|   ASSERT_NE(-1, fd) << "Failed to open file: " << helper_path |   ASSERT_NE(-1, fd) << "Failed to open file: " << helper_path_ | ||||||
|                     << ", Error: " << strerror(errno); |                     << ", Error: " << strerror(errno); | ||||||
|   char* mapping = |   char* mapping = | ||||||
|     reinterpret_cast<char*>(mmap(NULL, |     reinterpret_cast<char*>(mmap(NULL, | ||||||
| @ -133,34 +205,37 @@ TEST(LinuxPtraceDumperTest, MergedMappings) { | |||||||
|                                  0)); |                                  0)); | ||||||
|   ASSERT_TRUE(mapping); |   ASSERT_TRUE(mapping); | ||||||
| 
 | 
 | ||||||
|   const uintptr_t kMappingAddress = reinterpret_cast<uintptr_t>(mapping); |  | ||||||
| 
 |  | ||||||
|   // Ensure that things get cleaned up.
 |   // Ensure that things get cleaned up.
 | ||||||
|   StackHelper helper(fd, mapping, kMappingSize); |   helper_.Init(fd, mapping, kMappingSize); | ||||||
| 
 | 
 | ||||||
|   // Carve a page out of the first mapping with different permissions.
 |   // Carve a page out of the first mapping with different permissions.
 | ||||||
|   char* inside_mapping =  reinterpret_cast<char*>( |   char* inside_mapping =  reinterpret_cast<char*>( | ||||||
|       mmap(mapping + 2 *kPageSize, |       mmap(mapping + 2 * page_size_, | ||||||
|            kPageSize, |            page_size_, | ||||||
|            PROT_NONE, |            PROT_NONE, | ||||||
|            MAP_SHARED | MAP_FIXED, |            MAP_SHARED | MAP_FIXED, | ||||||
|            fd, |            fd, | ||||||
|            // Map a different offset just to
 |            // Map a different offset just to
 | ||||||
|            // better test real-world conditions.
 |            // better test real-world conditions.
 | ||||||
|            kPageSize)); |            page_size_)); | ||||||
|   ASSERT_TRUE(inside_mapping); |   ASSERT_TRUE(inside_mapping); | ||||||
| 
 | 
 | ||||||
|  |   LinuxPtraceDumperChildTest::SetUp(); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | TEST_F(LinuxPtraceDumperMappingsTest, MergedMappings) { | ||||||
|   // Now check that LinuxPtraceDumper interpreted the mappings properly.
 |   // Now check that LinuxPtraceDumper interpreted the mappings properly.
 | ||||||
|   LinuxPtraceDumper dumper(getpid()); |   LinuxPtraceDumper dumper(getppid()); | ||||||
|   ASSERT_TRUE(dumper.Init()); |   ASSERT_TRUE(dumper.Init()); | ||||||
|   int mapping_count = 0; |   int mapping_count = 0; | ||||||
|   for (unsigned i = 0; i < dumper.mappings().size(); ++i) { |   for (unsigned i = 0; i < dumper.mappings().size(); ++i) { | ||||||
|     const MappingInfo& mapping = *dumper.mappings()[i]; |     const MappingInfo& mapping = *dumper.mappings()[i]; | ||||||
|     if (strcmp(mapping.name, helper_path.c_str()) == 0) { |     if (strcmp(mapping.name, this->helper_path_.c_str()) == 0) { | ||||||
|       // This mapping should encompass the entire original mapped
 |       // This mapping should encompass the entire original mapped
 | ||||||
|       // range.
 |       // range.
 | ||||||
|       EXPECT_EQ(kMappingAddress, mapping.start_addr); |       EXPECT_EQ(reinterpret_cast<uintptr_t>(this->helper_.mapping()), | ||||||
|       EXPECT_EQ(kMappingSize, mapping.size); |                 mapping.start_addr); | ||||||
|  |       EXPECT_EQ(this->helper_.size(), mapping.size); | ||||||
|       EXPECT_EQ(0U, mapping.offset); |       EXPECT_EQ(0U, mapping.offset); | ||||||
|       mapping_count++; |       mapping_count++; | ||||||
|     } |     } | ||||||
| @ -168,6 +243,124 @@ TEST(LinuxPtraceDumperTest, MergedMappings) { | |||||||
|   EXPECT_EQ(1, mapping_count); |   EXPECT_EQ(1, mapping_count); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | TEST_F(LinuxPtraceDumperChildTest, BuildProcPath) { | ||||||
|  |   const pid_t pid = getppid(); | ||||||
|  |   LinuxPtraceDumper dumper(pid); | ||||||
|  | 
 | ||||||
|  |   char maps_path[NAME_MAX] = ""; | ||||||
|  |   char maps_path_expected[NAME_MAX]; | ||||||
|  |   snprintf(maps_path_expected, sizeof(maps_path_expected), | ||||||
|  |            "/proc/%d/maps", pid); | ||||||
|  |   EXPECT_TRUE(dumper.BuildProcPath(maps_path, pid, "maps")); | ||||||
|  |   EXPECT_STREQ(maps_path_expected, maps_path); | ||||||
|  | 
 | ||||||
|  |   EXPECT_FALSE(dumper.BuildProcPath(NULL, pid, "maps")); | ||||||
|  |   EXPECT_FALSE(dumper.BuildProcPath(maps_path, 0, "maps")); | ||||||
|  |   EXPECT_FALSE(dumper.BuildProcPath(maps_path, pid, "")); | ||||||
|  |   EXPECT_FALSE(dumper.BuildProcPath(maps_path, pid, NULL)); | ||||||
|  | 
 | ||||||
|  |   char long_node[NAME_MAX]; | ||||||
|  |   size_t long_node_len = NAME_MAX - strlen("/proc/123") - 1; | ||||||
|  |   memset(long_node, 'a', long_node_len); | ||||||
|  |   long_node[long_node_len] = '\0'; | ||||||
|  |   EXPECT_FALSE(dumper.BuildProcPath(maps_path, 123, long_node)); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #if !defined(__ARM_EABI__) && !defined(__mips__) | ||||||
|  | // Ensure that the linux-gate VDSO is included in the mapping list.
 | ||||||
|  | TEST_F(LinuxPtraceDumperChildTest, MappingsIncludeLinuxGate) { | ||||||
|  |   LinuxPtraceDumper dumper(getppid()); | ||||||
|  |   ASSERT_TRUE(dumper.Init()); | ||||||
|  | 
 | ||||||
|  |   void* linux_gate_loc = | ||||||
|  |     reinterpret_cast<void *>(dumper.auxv()[AT_SYSINFO_EHDR]); | ||||||
|  |   ASSERT_TRUE(linux_gate_loc); | ||||||
|  |   bool found_linux_gate = false; | ||||||
|  | 
 | ||||||
|  |   const wasteful_vector<MappingInfo*> mappings = dumper.mappings(); | ||||||
|  |   const MappingInfo* mapping; | ||||||
|  |   for (unsigned i = 0; i < mappings.size(); ++i) { | ||||||
|  |     mapping = mappings[i]; | ||||||
|  |     if (!strcmp(mapping->name, kLinuxGateLibraryName)) { | ||||||
|  |       found_linux_gate = true; | ||||||
|  |       break; | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |   EXPECT_TRUE(found_linux_gate); | ||||||
|  |   EXPECT_EQ(linux_gate_loc, reinterpret_cast<void*>(mapping->start_addr)); | ||||||
|  |   EXPECT_EQ(0, memcmp(linux_gate_loc, ELFMAG, SELFMAG)); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // Ensure that the linux-gate VDSO can generate a non-zeroed File ID.
 | ||||||
|  | TEST_F(LinuxPtraceDumperChildTest, LinuxGateMappingID) { | ||||||
|  |   LinuxPtraceDumper dumper(getppid()); | ||||||
|  |   ASSERT_TRUE(dumper.Init()); | ||||||
|  | 
 | ||||||
|  |   bool found_linux_gate = false; | ||||||
|  |   const wasteful_vector<MappingInfo*> mappings = dumper.mappings(); | ||||||
|  |   unsigned index = 0; | ||||||
|  |   for (unsigned i = 0; i < mappings.size(); ++i) { | ||||||
|  |     if (!strcmp(mappings[i]->name, kLinuxGateLibraryName)) { | ||||||
|  |       found_linux_gate = true; | ||||||
|  |       index = i; | ||||||
|  |       break; | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |   ASSERT_TRUE(found_linux_gate); | ||||||
|  | 
 | ||||||
|  |   // Need to suspend the child so ptrace actually works.
 | ||||||
|  |   ASSERT_TRUE(dumper.ThreadsSuspend()); | ||||||
|  |   uint8_t identifier[sizeof(MDGUID)]; | ||||||
|  |   ASSERT_TRUE(dumper.ElfFileIdentifierForMapping(*mappings[index], | ||||||
|  |                                                  true, | ||||||
|  |                                                  index, | ||||||
|  |                                                  identifier)); | ||||||
|  |   uint8_t empty_identifier[sizeof(MDGUID)]; | ||||||
|  |   memset(empty_identifier, 0, sizeof(empty_identifier)); | ||||||
|  |   EXPECT_NE(0, memcmp(empty_identifier, identifier, sizeof(identifier))); | ||||||
|  |   EXPECT_TRUE(dumper.ThreadsResume()); | ||||||
|  | } | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|  | TEST_F(LinuxPtraceDumperChildTest, FileIDsMatch) { | ||||||
|  |   // Calculate the File ID of our binary using both
 | ||||||
|  |   // FileID::ElfFileIdentifier and LinuxDumper::ElfFileIdentifierForMapping
 | ||||||
|  |   // and ensure that we get the same result from both.
 | ||||||
|  |   char exe_name[PATH_MAX]; | ||||||
|  |   ASSERT_TRUE(SafeReadLink("/proc/self/exe", exe_name)); | ||||||
|  | 
 | ||||||
|  |   LinuxPtraceDumper dumper(getppid()); | ||||||
|  |   ASSERT_TRUE(dumper.Init()); | ||||||
|  |   const wasteful_vector<MappingInfo*> mappings = dumper.mappings(); | ||||||
|  |   bool found_exe = false; | ||||||
|  |   unsigned i; | ||||||
|  |   for (i = 0; i < mappings.size(); ++i) { | ||||||
|  |     const MappingInfo* mapping = mappings[i]; | ||||||
|  |     if (!strcmp(mapping->name, exe_name)) { | ||||||
|  |       found_exe = true; | ||||||
|  |       break; | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |   ASSERT_TRUE(found_exe); | ||||||
|  | 
 | ||||||
|  |   uint8_t identifier1[sizeof(MDGUID)]; | ||||||
|  |   uint8_t identifier2[sizeof(MDGUID)]; | ||||||
|  |   EXPECT_TRUE(dumper.ElfFileIdentifierForMapping(*mappings[i], true, i, | ||||||
|  |                                                  identifier1)); | ||||||
|  |   FileID fileid(exe_name); | ||||||
|  |   EXPECT_TRUE(fileid.ElfFileIdentifier(identifier2)); | ||||||
|  |   char identifier_string1[37]; | ||||||
|  |   char identifier_string2[37]; | ||||||
|  |   FileID::ConvertIdentifierToString(identifier1, identifier_string1, | ||||||
|  |                                     37); | ||||||
|  |   FileID::ConvertIdentifierToString(identifier2, identifier_string2, | ||||||
|  |                                     37); | ||||||
|  |   EXPECT_STREQ(identifier_string1, identifier_string2); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /* Get back to normal behavior of TEST*() macros wrt TestBody. */ | ||||||
|  | #undef TestBody | ||||||
|  | 
 | ||||||
| TEST(LinuxPtraceDumperTest, VerifyStackReadWithMultipleThreads) { | TEST(LinuxPtraceDumperTest, VerifyStackReadWithMultipleThreads) { | ||||||
|   static const int kNumberOfThreadsInHelperProgram = 5; |   static const int kNumberOfThreadsInHelperProgram = 5; | ||||||
|   char kNumberOfThreadsArgument[2]; |   char kNumberOfThreadsArgument[2]; | ||||||
| @ -240,10 +433,15 @@ TEST(LinuxPtraceDumperTest, VerifyStackReadWithMultipleThreads) { | |||||||
|     // specific register. Check that we can recover its value.
 |     // specific register. Check that we can recover its value.
 | ||||||
| #if defined(__ARM_EABI__) | #if defined(__ARM_EABI__) | ||||||
|     pid_t* process_tid_location = (pid_t*)(one_thread.regs.uregs[3]); |     pid_t* process_tid_location = (pid_t*)(one_thread.regs.uregs[3]); | ||||||
|  | #elif defined(__aarch64__) | ||||||
|  |     pid_t* process_tid_location = (pid_t*)(one_thread.regs.regs[3]); | ||||||
| #elif defined(__i386) | #elif defined(__i386) | ||||||
|     pid_t* process_tid_location = (pid_t*)(one_thread.regs.ecx); |     pid_t* process_tid_location = (pid_t*)(one_thread.regs.ecx); | ||||||
| #elif defined(__x86_64) | #elif defined(__x86_64) | ||||||
|     pid_t* process_tid_location = (pid_t*)(one_thread.regs.rcx); |     pid_t* process_tid_location = (pid_t*)(one_thread.regs.rcx); | ||||||
|  | #elif defined(__mips__) | ||||||
|  |     pid_t* process_tid_location = | ||||||
|  |         reinterpret_cast<pid_t*>(one_thread.regs.regs[1]); | ||||||
| #else | #else | ||||||
| #error This test has not been ported to this platform. | #error This test has not been ported to this platform. | ||||||
| #endif | #endif | ||||||
| @ -263,178 +461,3 @@ TEST(LinuxPtraceDumperTest, VerifyStackReadWithMultipleThreads) { | |||||||
|   ASSERT_TRUE(WIFSIGNALED(status)); |   ASSERT_TRUE(WIFSIGNALED(status)); | ||||||
|   ASSERT_EQ(SIGKILL, WTERMSIG(status)); |   ASSERT_EQ(SIGKILL, WTERMSIG(status)); | ||||||
| } | } | ||||||
| 
 |  | ||||||
| TEST(LinuxPtraceDumperTest, BuildProcPath) { |  | ||||||
|   const pid_t pid = getpid(); |  | ||||||
|   LinuxPtraceDumper dumper(pid); |  | ||||||
| 
 |  | ||||||
|   char maps_path[NAME_MAX] = ""; |  | ||||||
|   char maps_path_expected[NAME_MAX]; |  | ||||||
|   snprintf(maps_path_expected, sizeof(maps_path_expected), |  | ||||||
|            "/proc/%d/maps", pid); |  | ||||||
|   EXPECT_TRUE(dumper.BuildProcPath(maps_path, pid, "maps")); |  | ||||||
|   EXPECT_STREQ(maps_path_expected, maps_path); |  | ||||||
| 
 |  | ||||||
|   EXPECT_FALSE(dumper.BuildProcPath(NULL, pid, "maps")); |  | ||||||
|   EXPECT_FALSE(dumper.BuildProcPath(maps_path, 0, "maps")); |  | ||||||
|   EXPECT_FALSE(dumper.BuildProcPath(maps_path, pid, "")); |  | ||||||
|   EXPECT_FALSE(dumper.BuildProcPath(maps_path, pid, NULL)); |  | ||||||
| 
 |  | ||||||
|   char long_node[NAME_MAX]; |  | ||||||
|   size_t long_node_len = NAME_MAX - strlen("/proc/123") - 1; |  | ||||||
|   memset(long_node, 'a', long_node_len); |  | ||||||
|   long_node[long_node_len] = '\0'; |  | ||||||
|   EXPECT_FALSE(dumper.BuildProcPath(maps_path, 123, long_node)); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| #if !defined(__ARM_EABI__) |  | ||||||
| // Ensure that the linux-gate VDSO is included in the mapping list.
 |  | ||||||
| TEST(LinuxPtraceDumperTest, MappingsIncludeLinuxGate) { |  | ||||||
|   LinuxPtraceDumper dumper(getpid()); |  | ||||||
|   ASSERT_TRUE(dumper.Init()); |  | ||||||
| 
 |  | ||||||
|   void* linux_gate_loc = |  | ||||||
|     reinterpret_cast<void *>(dumper.auxv()[AT_SYSINFO_EHDR]); |  | ||||||
|   ASSERT_TRUE(linux_gate_loc); |  | ||||||
|   bool found_linux_gate = false; |  | ||||||
| 
 |  | ||||||
|   const wasteful_vector<MappingInfo*> mappings = dumper.mappings(); |  | ||||||
|   const MappingInfo* mapping; |  | ||||||
|   for (unsigned i = 0; i < mappings.size(); ++i) { |  | ||||||
|     mapping = mappings[i]; |  | ||||||
|     if (!strcmp(mapping->name, kLinuxGateLibraryName)) { |  | ||||||
|       found_linux_gate = true; |  | ||||||
|       break; |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
|   EXPECT_TRUE(found_linux_gate); |  | ||||||
|   EXPECT_EQ(linux_gate_loc, reinterpret_cast<void*>(mapping->start_addr)); |  | ||||||
|   EXPECT_EQ(0, memcmp(linux_gate_loc, ELFMAG, SELFMAG)); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // Ensure that the linux-gate VDSO can generate a non-zeroed File ID.
 |  | ||||||
| TEST(LinuxPtraceDumperTest, LinuxGateMappingID) { |  | ||||||
|   LinuxPtraceDumper dumper(getpid()); |  | ||||||
|   ASSERT_TRUE(dumper.Init()); |  | ||||||
| 
 |  | ||||||
|   bool found_linux_gate = false; |  | ||||||
|   const wasteful_vector<MappingInfo*> mappings = dumper.mappings(); |  | ||||||
|   unsigned index = 0; |  | ||||||
|   for (unsigned i = 0; i < mappings.size(); ++i) { |  | ||||||
|     if (!strcmp(mappings[i]->name, kLinuxGateLibraryName)) { |  | ||||||
|       found_linux_gate = true; |  | ||||||
|       index = i; |  | ||||||
|       break; |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
|   ASSERT_TRUE(found_linux_gate); |  | ||||||
| 
 |  | ||||||
|   uint8_t identifier[sizeof(MDGUID)]; |  | ||||||
|   ASSERT_TRUE(dumper.ElfFileIdentifierForMapping(*mappings[index], |  | ||||||
|                                                  true, |  | ||||||
|                                                  index, |  | ||||||
|                                                  identifier)); |  | ||||||
|   uint8_t empty_identifier[sizeof(MDGUID)]; |  | ||||||
|   memset(empty_identifier, 0, sizeof(empty_identifier)); |  | ||||||
|   EXPECT_NE(0, memcmp(empty_identifier, identifier, sizeof(identifier))); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // Ensure that the linux-gate VDSO can generate a non-zeroed File ID
 |  | ||||||
| // from a child process.
 |  | ||||||
| TEST(LinuxPtraceDumperTest, LinuxGateMappingIDChild) { |  | ||||||
|   int fds[2]; |  | ||||||
|   ASSERT_NE(-1, pipe(fds)); |  | ||||||
| 
 |  | ||||||
|   // Fork a child so ptrace works.
 |  | ||||||
|   const pid_t child = fork(); |  | ||||||
|   if (child == 0) { |  | ||||||
|     close(fds[1]); |  | ||||||
|     // Now wait forever for the parent.
 |  | ||||||
|     char b; |  | ||||||
|     IGNORE_RET(HANDLE_EINTR(read(fds[0], &b, sizeof(b)))); |  | ||||||
|     close(fds[0]); |  | ||||||
|     syscall(__NR_exit); |  | ||||||
|   } |  | ||||||
|   close(fds[0]); |  | ||||||
| 
 |  | ||||||
|   LinuxPtraceDumper dumper(child); |  | ||||||
|   ASSERT_TRUE(dumper.Init()); |  | ||||||
| 
 |  | ||||||
|   bool found_linux_gate = false; |  | ||||||
|   const wasteful_vector<MappingInfo*> mappings = dumper.mappings(); |  | ||||||
|   unsigned index = 0; |  | ||||||
|   for (unsigned i = 0; i < mappings.size(); ++i) { |  | ||||||
|     if (!strcmp(mappings[i]->name, kLinuxGateLibraryName)) { |  | ||||||
|       found_linux_gate = true; |  | ||||||
|       index = i; |  | ||||||
|       break; |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
|   ASSERT_TRUE(found_linux_gate); |  | ||||||
| 
 |  | ||||||
|   // Need to suspend the child so ptrace actually works.
 |  | ||||||
|   ASSERT_TRUE(dumper.ThreadsSuspend()); |  | ||||||
|   uint8_t identifier[sizeof(MDGUID)]; |  | ||||||
|   ASSERT_TRUE(dumper.ElfFileIdentifierForMapping(*mappings[index], |  | ||||||
|                                                  true, |  | ||||||
|                                                  index, |  | ||||||
|                                                  identifier)); |  | ||||||
|   uint8_t empty_identifier[sizeof(MDGUID)]; |  | ||||||
|   memset(empty_identifier, 0, sizeof(empty_identifier)); |  | ||||||
|   EXPECT_NE(0, memcmp(empty_identifier, identifier, sizeof(identifier))); |  | ||||||
|   EXPECT_TRUE(dumper.ThreadsResume()); |  | ||||||
|   close(fds[1]); |  | ||||||
| } |  | ||||||
| #endif |  | ||||||
| 
 |  | ||||||
| TEST(LinuxPtraceDumperTest, FileIDsMatch) { |  | ||||||
|   // Calculate the File ID of our binary using both
 |  | ||||||
|   // FileID::ElfFileIdentifier and LinuxDumper::ElfFileIdentifierForMapping
 |  | ||||||
|   // and ensure that we get the same result from both.
 |  | ||||||
|   char exe_name[PATH_MAX]; |  | ||||||
|   ASSERT_TRUE(SafeReadLink("/proc/self/exe", exe_name)); |  | ||||||
| 
 |  | ||||||
|   int fds[2]; |  | ||||||
|   ASSERT_NE(-1, pipe(fds)); |  | ||||||
| 
 |  | ||||||
|   // Fork a child so ptrace works.
 |  | ||||||
|   const pid_t child = fork(); |  | ||||||
|   if (child == 0) { |  | ||||||
|     close(fds[1]); |  | ||||||
|     // Now wait forever for the parent.
 |  | ||||||
|     char b; |  | ||||||
|     IGNORE_RET(HANDLE_EINTR(read(fds[0], &b, sizeof(b)))); |  | ||||||
|     close(fds[0]); |  | ||||||
|     syscall(__NR_exit); |  | ||||||
|   } |  | ||||||
|   close(fds[0]); |  | ||||||
| 
 |  | ||||||
|   LinuxPtraceDumper dumper(child); |  | ||||||
|   ASSERT_TRUE(dumper.Init()); |  | ||||||
|   const wasteful_vector<MappingInfo*> mappings = dumper.mappings(); |  | ||||||
|   bool found_exe = false; |  | ||||||
|   unsigned i; |  | ||||||
|   for (i = 0; i < mappings.size(); ++i) { |  | ||||||
|     const MappingInfo* mapping = mappings[i]; |  | ||||||
|     if (!strcmp(mapping->name, exe_name)) { |  | ||||||
|       found_exe = true; |  | ||||||
|       break; |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
|   ASSERT_TRUE(found_exe); |  | ||||||
| 
 |  | ||||||
|   uint8_t identifier1[sizeof(MDGUID)]; |  | ||||||
|   uint8_t identifier2[sizeof(MDGUID)]; |  | ||||||
|   EXPECT_TRUE(dumper.ElfFileIdentifierForMapping(*mappings[i], true, i, |  | ||||||
|                                                  identifier1)); |  | ||||||
|   FileID fileid(exe_name); |  | ||||||
|   EXPECT_TRUE(fileid.ElfFileIdentifier(identifier2)); |  | ||||||
|   char identifier_string1[37]; |  | ||||||
|   char identifier_string2[37]; |  | ||||||
|   FileID::ConvertIdentifierToString(identifier1, identifier_string1, |  | ||||||
|                                     37); |  | ||||||
|   FileID::ConvertIdentifierToString(identifier2, identifier_string2, |  | ||||||
|                                     37); |  | ||||||
|   EXPECT_STREQ(identifier_string1, identifier_string2); |  | ||||||
|   close(fds[1]); |  | ||||||
| } |  | ||||||
|  | |||||||
| @ -59,10 +59,14 @@ | |||||||
| #include <sys/ucontext.h> | #include <sys/ucontext.h> | ||||||
| #include <sys/user.h> | #include <sys/user.h> | ||||||
| #include <sys/utsname.h> | #include <sys/utsname.h> | ||||||
|  | #include <time.h> | ||||||
| #include <unistd.h> | #include <unistd.h> | ||||||
| 
 | 
 | ||||||
| #include <algorithm> | #include <algorithm> | ||||||
| 
 | 
 | ||||||
|  | #include "client/linux/dump_writer_common/seccomp_unwinder.h" | ||||||
|  | #include "client/linux/dump_writer_common/thread_info.h" | ||||||
|  | #include "client/linux/dump_writer_common/ucontext_reader.h" | ||||||
| #include "client/linux/handler/exception_handler.h" | #include "client/linux/handler/exception_handler.h" | ||||||
| #include "client/linux/minidump_writer/cpu_set.h" | #include "client/linux/minidump_writer/cpu_set.h" | ||||||
| #include "client/linux/minidump_writer/line_reader.h" | #include "client/linux/minidump_writer/line_reader.h" | ||||||
| @ -88,295 +92,14 @@ using google_breakpad::MappingList; | |||||||
| using google_breakpad::MinidumpFileWriter; | using google_breakpad::MinidumpFileWriter; | ||||||
| using google_breakpad::PageAllocator; | using google_breakpad::PageAllocator; | ||||||
| using google_breakpad::ProcCpuInfoReader; | using google_breakpad::ProcCpuInfoReader; | ||||||
|  | using google_breakpad::RawContextCPU; | ||||||
|  | using google_breakpad::SeccompUnwinder; | ||||||
| using google_breakpad::ThreadInfo; | using google_breakpad::ThreadInfo; | ||||||
| using google_breakpad::TypedMDRVA; | using google_breakpad::TypedMDRVA; | ||||||
|  | using google_breakpad::UContextReader; | ||||||
| using google_breakpad::UntypedMDRVA; | using google_breakpad::UntypedMDRVA; | ||||||
| using google_breakpad::wasteful_vector; | using google_breakpad::wasteful_vector; | ||||||
| 
 | 
 | ||||||
| // Minidump defines register structures which are different from the raw
 |  | ||||||
| // structures which we get from the kernel. These are platform specific
 |  | ||||||
| // functions to juggle the ucontext and user structures into minidump format.
 |  | ||||||
| #if defined(__i386__) |  | ||||||
| typedef MDRawContextX86 RawContextCPU; |  | ||||||
| 
 |  | ||||||
| // Write a uint16_t to memory
 |  | ||||||
| //   out: memory location to write to
 |  | ||||||
| //   v: value to write.
 |  | ||||||
| void U16(void* out, uint16_t v) { |  | ||||||
|   my_memcpy(out, &v, sizeof(v)); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // Write a uint32_t to memory
 |  | ||||||
| //   out: memory location to write to
 |  | ||||||
| //   v: value to write.
 |  | ||||||
| void U32(void* out, uint32_t v) { |  | ||||||
|   my_memcpy(out, &v, sizeof(v)); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // Juggle an x86 user_(fp|fpx|)regs_struct into minidump format
 |  | ||||||
| //   out: the minidump structure
 |  | ||||||
| //   info: the collection of register structures.
 |  | ||||||
| void CPUFillFromThreadInfo(MDRawContextX86 *out, |  | ||||||
|                            const google_breakpad::ThreadInfo &info) { |  | ||||||
|   out->context_flags = MD_CONTEXT_X86_ALL; |  | ||||||
| 
 |  | ||||||
|   out->dr0 = info.dregs[0]; |  | ||||||
|   out->dr1 = info.dregs[1]; |  | ||||||
|   out->dr2 = info.dregs[2]; |  | ||||||
|   out->dr3 = info.dregs[3]; |  | ||||||
|   // 4 and 5 deliberatly omitted because they aren't included in the minidump
 |  | ||||||
|   // format.
 |  | ||||||
|   out->dr6 = info.dregs[6]; |  | ||||||
|   out->dr7 = info.dregs[7]; |  | ||||||
| 
 |  | ||||||
|   out->gs = info.regs.xgs; |  | ||||||
|   out->fs = info.regs.xfs; |  | ||||||
|   out->es = info.regs.xes; |  | ||||||
|   out->ds = info.regs.xds; |  | ||||||
| 
 |  | ||||||
|   out->edi = info.regs.edi; |  | ||||||
|   out->esi = info.regs.esi; |  | ||||||
|   out->ebx = info.regs.ebx; |  | ||||||
|   out->edx = info.regs.edx; |  | ||||||
|   out->ecx = info.regs.ecx; |  | ||||||
|   out->eax = info.regs.eax; |  | ||||||
| 
 |  | ||||||
|   out->ebp = info.regs.ebp; |  | ||||||
|   out->eip = info.regs.eip; |  | ||||||
|   out->cs = info.regs.xcs; |  | ||||||
|   out->eflags = info.regs.eflags; |  | ||||||
|   out->esp = info.regs.esp; |  | ||||||
|   out->ss = info.regs.xss; |  | ||||||
| 
 |  | ||||||
|   out->float_save.control_word = info.fpregs.cwd; |  | ||||||
|   out->float_save.status_word = info.fpregs.swd; |  | ||||||
|   out->float_save.tag_word = info.fpregs.twd; |  | ||||||
|   out->float_save.error_offset = info.fpregs.fip; |  | ||||||
|   out->float_save.error_selector = info.fpregs.fcs; |  | ||||||
|   out->float_save.data_offset = info.fpregs.foo; |  | ||||||
|   out->float_save.data_selector = info.fpregs.fos; |  | ||||||
| 
 |  | ||||||
|   // 8 registers * 10 bytes per register.
 |  | ||||||
|   my_memcpy(out->float_save.register_area, info.fpregs.st_space, 10 * 8); |  | ||||||
| 
 |  | ||||||
|   // This matches the Intel fpsave format.
 |  | ||||||
|   U16(out->extended_registers + 0, info.fpregs.cwd); |  | ||||||
|   U16(out->extended_registers + 2, info.fpregs.swd); |  | ||||||
|   U16(out->extended_registers + 4, info.fpregs.twd); |  | ||||||
|   U16(out->extended_registers + 6, info.fpxregs.fop); |  | ||||||
|   U32(out->extended_registers + 8, info.fpxregs.fip); |  | ||||||
|   U16(out->extended_registers + 12, info.fpxregs.fcs); |  | ||||||
|   U32(out->extended_registers + 16, info.fpregs.foo); |  | ||||||
|   U16(out->extended_registers + 20, info.fpregs.fos); |  | ||||||
|   U32(out->extended_registers + 24, info.fpxregs.mxcsr); |  | ||||||
| 
 |  | ||||||
|   my_memcpy(out->extended_registers + 32, &info.fpxregs.st_space, 128); |  | ||||||
|   my_memcpy(out->extended_registers + 160, &info.fpxregs.xmm_space, 128); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // Juggle an x86 ucontext into minidump format
 |  | ||||||
| //   out: the minidump structure
 |  | ||||||
| //   info: the collection of register structures.
 |  | ||||||
| void CPUFillFromUContext(MDRawContextX86 *out, const ucontext *uc, |  | ||||||
|                          const struct _libc_fpstate* fp) { |  | ||||||
|   const greg_t* regs = uc->uc_mcontext.gregs; |  | ||||||
| 
 |  | ||||||
|   out->context_flags = MD_CONTEXT_X86_FULL | |  | ||||||
|                        MD_CONTEXT_X86_FLOATING_POINT; |  | ||||||
| 
 |  | ||||||
|   out->gs = regs[REG_GS]; |  | ||||||
|   out->fs = regs[REG_FS]; |  | ||||||
|   out->es = regs[REG_ES]; |  | ||||||
|   out->ds = regs[REG_DS]; |  | ||||||
| 
 |  | ||||||
|   out->edi = regs[REG_EDI]; |  | ||||||
|   out->esi = regs[REG_ESI]; |  | ||||||
|   out->ebx = regs[REG_EBX]; |  | ||||||
|   out->edx = regs[REG_EDX]; |  | ||||||
|   out->ecx = regs[REG_ECX]; |  | ||||||
|   out->eax = regs[REG_EAX]; |  | ||||||
| 
 |  | ||||||
|   out->ebp = regs[REG_EBP]; |  | ||||||
|   out->eip = regs[REG_EIP]; |  | ||||||
|   out->cs = regs[REG_CS]; |  | ||||||
|   out->eflags = regs[REG_EFL]; |  | ||||||
|   out->esp = regs[REG_UESP]; |  | ||||||
|   out->ss = regs[REG_SS]; |  | ||||||
| 
 |  | ||||||
|   out->float_save.control_word = fp->cw; |  | ||||||
|   out->float_save.status_word = fp->sw; |  | ||||||
|   out->float_save.tag_word = fp->tag; |  | ||||||
|   out->float_save.error_offset = fp->ipoff; |  | ||||||
|   out->float_save.error_selector = fp->cssel; |  | ||||||
|   out->float_save.data_offset = fp->dataoff; |  | ||||||
|   out->float_save.data_selector = fp->datasel; |  | ||||||
| 
 |  | ||||||
|   // 8 registers * 10 bytes per register.
 |  | ||||||
|   my_memcpy(out->float_save.register_area, fp->_st, 10 * 8); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| #elif defined(__x86_64) |  | ||||||
| typedef MDRawContextAMD64 RawContextCPU; |  | ||||||
| 
 |  | ||||||
| void CPUFillFromThreadInfo(MDRawContextAMD64 *out, |  | ||||||
|                            const google_breakpad::ThreadInfo &info) { |  | ||||||
|   out->context_flags = MD_CONTEXT_AMD64_FULL | |  | ||||||
|                        MD_CONTEXT_AMD64_SEGMENTS; |  | ||||||
| 
 |  | ||||||
|   out->cs = info.regs.cs; |  | ||||||
| 
 |  | ||||||
|   out->ds = info.regs.ds; |  | ||||||
|   out->es = info.regs.es; |  | ||||||
|   out->fs = info.regs.fs; |  | ||||||
|   out->gs = info.regs.gs; |  | ||||||
| 
 |  | ||||||
|   out->ss = info.regs.ss; |  | ||||||
|   out->eflags = info.regs.eflags; |  | ||||||
| 
 |  | ||||||
|   out->dr0 = info.dregs[0]; |  | ||||||
|   out->dr1 = info.dregs[1]; |  | ||||||
|   out->dr2 = info.dregs[2]; |  | ||||||
|   out->dr3 = info.dregs[3]; |  | ||||||
|   // 4 and 5 deliberatly omitted because they aren't included in the minidump
 |  | ||||||
|   // format.
 |  | ||||||
|   out->dr6 = info.dregs[6]; |  | ||||||
|   out->dr7 = info.dregs[7]; |  | ||||||
| 
 |  | ||||||
|   out->rax = info.regs.rax; |  | ||||||
|   out->rcx = info.regs.rcx; |  | ||||||
|   out->rdx = info.regs.rdx; |  | ||||||
|   out->rbx = info.regs.rbx; |  | ||||||
| 
 |  | ||||||
|   out->rsp = info.regs.rsp; |  | ||||||
| 
 |  | ||||||
|   out->rbp = info.regs.rbp; |  | ||||||
|   out->rsi = info.regs.rsi; |  | ||||||
|   out->rdi = info.regs.rdi; |  | ||||||
|   out->r8 = info.regs.r8; |  | ||||||
|   out->r9 = info.regs.r9; |  | ||||||
|   out->r10 = info.regs.r10; |  | ||||||
|   out->r11 = info.regs.r11; |  | ||||||
|   out->r12 = info.regs.r12; |  | ||||||
|   out->r13 = info.regs.r13; |  | ||||||
|   out->r14 = info.regs.r14; |  | ||||||
|   out->r15 = info.regs.r15; |  | ||||||
| 
 |  | ||||||
|   out->rip = info.regs.rip; |  | ||||||
| 
 |  | ||||||
|   out->flt_save.control_word = info.fpregs.cwd; |  | ||||||
|   out->flt_save.status_word = info.fpregs.swd; |  | ||||||
|   out->flt_save.tag_word = info.fpregs.ftw; |  | ||||||
|   out->flt_save.error_opcode = info.fpregs.fop; |  | ||||||
|   out->flt_save.error_offset = info.fpregs.rip; |  | ||||||
|   out->flt_save.error_selector = 0;  // We don't have this.
 |  | ||||||
|   out->flt_save.data_offset = info.fpregs.rdp; |  | ||||||
|   out->flt_save.data_selector = 0;   // We don't have this.
 |  | ||||||
|   out->flt_save.mx_csr = info.fpregs.mxcsr; |  | ||||||
|   out->flt_save.mx_csr_mask = info.fpregs.mxcr_mask; |  | ||||||
|   my_memcpy(&out->flt_save.float_registers, &info.fpregs.st_space, 8 * 16); |  | ||||||
|   my_memcpy(&out->flt_save.xmm_registers, &info.fpregs.xmm_space, 16 * 16); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void CPUFillFromUContext(MDRawContextAMD64 *out, const ucontext *uc, |  | ||||||
|                          const struct _libc_fpstate* fpregs) { |  | ||||||
|   const greg_t* regs = uc->uc_mcontext.gregs; |  | ||||||
| 
 |  | ||||||
|   out->context_flags = MD_CONTEXT_AMD64_FULL; |  | ||||||
| 
 |  | ||||||
|   out->cs = regs[REG_CSGSFS] & 0xffff; |  | ||||||
| 
 |  | ||||||
|   out->fs = (regs[REG_CSGSFS] >> 32) & 0xffff; |  | ||||||
|   out->gs = (regs[REG_CSGSFS] >> 16) & 0xffff; |  | ||||||
| 
 |  | ||||||
|   out->eflags = regs[REG_EFL]; |  | ||||||
| 
 |  | ||||||
|   out->rax = regs[REG_RAX]; |  | ||||||
|   out->rcx = regs[REG_RCX]; |  | ||||||
|   out->rdx = regs[REG_RDX]; |  | ||||||
|   out->rbx = regs[REG_RBX]; |  | ||||||
| 
 |  | ||||||
|   out->rsp = regs[REG_RSP]; |  | ||||||
|   out->rbp = regs[REG_RBP]; |  | ||||||
|   out->rsi = regs[REG_RSI]; |  | ||||||
|   out->rdi = regs[REG_RDI]; |  | ||||||
|   out->r8 = regs[REG_R8]; |  | ||||||
|   out->r9 = regs[REG_R9]; |  | ||||||
|   out->r10 = regs[REG_R10]; |  | ||||||
|   out->r11 = regs[REG_R11]; |  | ||||||
|   out->r12 = regs[REG_R12]; |  | ||||||
|   out->r13 = regs[REG_R13]; |  | ||||||
|   out->r14 = regs[REG_R14]; |  | ||||||
|   out->r15 = regs[REG_R15]; |  | ||||||
| 
 |  | ||||||
|   out->rip = regs[REG_RIP]; |  | ||||||
| 
 |  | ||||||
|   out->flt_save.control_word = fpregs->cwd; |  | ||||||
|   out->flt_save.status_word = fpregs->swd; |  | ||||||
|   out->flt_save.tag_word = fpregs->ftw; |  | ||||||
|   out->flt_save.error_opcode = fpregs->fop; |  | ||||||
|   out->flt_save.error_offset = fpregs->rip; |  | ||||||
|   out->flt_save.data_offset = fpregs->rdp; |  | ||||||
|   out->flt_save.error_selector = 0;  // We don't have this.
 |  | ||||||
|   out->flt_save.data_selector = 0;  // We don't have this.
 |  | ||||||
|   out->flt_save.mx_csr = fpregs->mxcsr; |  | ||||||
|   out->flt_save.mx_csr_mask = fpregs->mxcr_mask; |  | ||||||
|   my_memcpy(&out->flt_save.float_registers, &fpregs->_st, 8 * 16); |  | ||||||
|   my_memcpy(&out->flt_save.xmm_registers, &fpregs->_xmm, 16 * 16); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| #elif defined(__ARMEL__) |  | ||||||
| typedef MDRawContextARM RawContextCPU; |  | ||||||
| 
 |  | ||||||
| void CPUFillFromThreadInfo(MDRawContextARM* out, |  | ||||||
|                            const google_breakpad::ThreadInfo& info) { |  | ||||||
|   out->context_flags = MD_CONTEXT_ARM_FULL; |  | ||||||
| 
 |  | ||||||
|   for (int i = 0; i < MD_CONTEXT_ARM_GPR_COUNT; ++i) |  | ||||||
|     out->iregs[i] = info.regs.uregs[i]; |  | ||||||
|   // No CPSR register in ThreadInfo(it's not accessible via ptrace)
 |  | ||||||
|   out->cpsr = 0; |  | ||||||
| #if !defined(__ANDROID__) |  | ||||||
|   out->float_save.fpscr = info.fpregs.fpsr | |  | ||||||
|     (static_cast<uint64_t>(info.fpregs.fpcr) << 32); |  | ||||||
|   // TODO: sort this out, actually collect floating point registers
 |  | ||||||
|   my_memset(&out->float_save.regs, 0, sizeof(out->float_save.regs)); |  | ||||||
|   my_memset(&out->float_save.extra, 0, sizeof(out->float_save.extra)); |  | ||||||
| #endif |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void CPUFillFromUContext(MDRawContextARM* out, const ucontext* uc, |  | ||||||
|                          const struct _libc_fpstate* fpregs) { |  | ||||||
|   out->context_flags = MD_CONTEXT_ARM_FULL; |  | ||||||
| 
 |  | ||||||
|   out->iregs[0] = uc->uc_mcontext.arm_r0; |  | ||||||
|   out->iregs[1] = uc->uc_mcontext.arm_r1; |  | ||||||
|   out->iregs[2] = uc->uc_mcontext.arm_r2; |  | ||||||
|   out->iregs[3] = uc->uc_mcontext.arm_r3; |  | ||||||
|   out->iregs[4] = uc->uc_mcontext.arm_r4; |  | ||||||
|   out->iregs[5] = uc->uc_mcontext.arm_r5; |  | ||||||
|   out->iregs[6] = uc->uc_mcontext.arm_r6; |  | ||||||
|   out->iregs[7] = uc->uc_mcontext.arm_r7; |  | ||||||
|   out->iregs[8] = uc->uc_mcontext.arm_r8; |  | ||||||
|   out->iregs[9] = uc->uc_mcontext.arm_r9; |  | ||||||
|   out->iregs[10] = uc->uc_mcontext.arm_r10; |  | ||||||
| 
 |  | ||||||
|   out->iregs[11] = uc->uc_mcontext.arm_fp; |  | ||||||
|   out->iregs[12] = uc->uc_mcontext.arm_ip; |  | ||||||
|   out->iregs[13] = uc->uc_mcontext.arm_sp; |  | ||||||
|   out->iregs[14] = uc->uc_mcontext.arm_lr; |  | ||||||
|   out->iregs[15] = uc->uc_mcontext.arm_pc; |  | ||||||
| 
 |  | ||||||
|   out->cpsr = uc->uc_mcontext.arm_cpsr; |  | ||||||
| 
 |  | ||||||
|   // TODO: fix this after fixing ExceptionHandler
 |  | ||||||
|   out->float_save.fpscr = 0; |  | ||||||
|   my_memset(&out->float_save.regs, 0, sizeof(out->float_save.regs)); |  | ||||||
|   my_memset(&out->float_save.extra, 0, sizeof(out->float_save.extra)); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| #else |  | ||||||
| #error "This code has not been ported to your platform yet." |  | ||||||
| #endif |  | ||||||
| 
 | 
 | ||||||
| class MinidumpWriter { | class MinidumpWriter { | ||||||
|  public: |  public: | ||||||
| @ -405,11 +128,8 @@ class MinidumpWriter { | |||||||
|       : fd_(minidump_fd), |       : fd_(minidump_fd), | ||||||
|         path_(minidump_path), |         path_(minidump_path), | ||||||
|         ucontext_(context ? &context->context : NULL), |         ucontext_(context ? &context->context : NULL), | ||||||
| #if !defined(__ARM_EABI__) | #if !defined(__ARM_EABI__) && !defined(__mips__) | ||||||
|         float_state_(context ? &context->float_state : NULL), |         float_state_(context ? &context->float_state : NULL), | ||||||
| #else |  | ||||||
|         // TODO: fix this after fixing ExceptionHandler
 |  | ||||||
|         float_state_(NULL), |  | ||||||
| #endif | #endif | ||||||
|         dumper_(dumper), |         dumper_(dumper), | ||||||
|         minidump_size_limit_(-1), |         minidump_size_limit_(-1), | ||||||
| @ -533,123 +253,6 @@ class MinidumpWriter { | |||||||
|     return true; |     return true; | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   // Check if the top of the stack is part of a system call that has been
 |  | ||||||
|   // redirected by the seccomp sandbox. If so, try to pop the stack frames
 |  | ||||||
|   // all the way back to the point where the interception happened.
 |  | ||||||
|   void PopSeccompStackFrame(RawContextCPU* cpu, const MDRawThread& thread, |  | ||||||
|                             uint8_t* stack_copy) { |  | ||||||
| #if defined(__x86_64) |  | ||||||
|     uint64_t bp = cpu->rbp; |  | ||||||
|     uint64_t top = thread.stack.start_of_memory_range; |  | ||||||
|     for (int i = 4; i--; ) { |  | ||||||
|       if (bp < top || |  | ||||||
|           bp + sizeof(bp) > thread.stack.start_of_memory_range + |  | ||||||
|           thread.stack.memory.data_size || |  | ||||||
|           bp & 1) { |  | ||||||
|         break; |  | ||||||
|       } |  | ||||||
|       uint64_t old_top = top; |  | ||||||
|       top = bp; |  | ||||||
|       uint8_t* bp_addr = stack_copy + bp - thread.stack.start_of_memory_range; |  | ||||||
|       my_memcpy(&bp, bp_addr, sizeof(bp)); |  | ||||||
|       if (bp == 0xDEADBEEFDEADBEEFull) { |  | ||||||
|         struct { |  | ||||||
|           uint64_t r15; |  | ||||||
|           uint64_t r14; |  | ||||||
|           uint64_t r13; |  | ||||||
|           uint64_t r12; |  | ||||||
|           uint64_t r11; |  | ||||||
|           uint64_t r10; |  | ||||||
|           uint64_t r9; |  | ||||||
|           uint64_t r8; |  | ||||||
|           uint64_t rdi; |  | ||||||
|           uint64_t rsi; |  | ||||||
|           uint64_t rdx; |  | ||||||
|           uint64_t rcx; |  | ||||||
|           uint64_t rbx; |  | ||||||
|           uint64_t deadbeef; |  | ||||||
|           uint64_t rbp; |  | ||||||
|           uint64_t fakeret; |  | ||||||
|           uint64_t ret; |  | ||||||
|           /* char redzone[128]; */ |  | ||||||
|         } seccomp_stackframe; |  | ||||||
|         if (top - offsetof(typeof(seccomp_stackframe), deadbeef) < old_top || |  | ||||||
|             top - offsetof(typeof(seccomp_stackframe), deadbeef) + |  | ||||||
|             sizeof(seccomp_stackframe) > |  | ||||||
|             thread.stack.start_of_memory_range+thread.stack.memory.data_size) { |  | ||||||
|           break; |  | ||||||
|         } |  | ||||||
|         my_memcpy(&seccomp_stackframe, |  | ||||||
|                   bp_addr - offsetof(typeof(seccomp_stackframe), deadbeef), |  | ||||||
|                   sizeof(seccomp_stackframe)); |  | ||||||
|         cpu->rbx = seccomp_stackframe.rbx; |  | ||||||
|         cpu->rcx = seccomp_stackframe.rcx; |  | ||||||
|         cpu->rdx = seccomp_stackframe.rdx; |  | ||||||
|         cpu->rsi = seccomp_stackframe.rsi; |  | ||||||
|         cpu->rdi = seccomp_stackframe.rdi; |  | ||||||
|         cpu->rbp = seccomp_stackframe.rbp; |  | ||||||
|         cpu->rsp = top + 4*sizeof(uint64_t) + 128; |  | ||||||
|         cpu->r8  = seccomp_stackframe.r8; |  | ||||||
|         cpu->r9  = seccomp_stackframe.r9; |  | ||||||
|         cpu->r10 = seccomp_stackframe.r10; |  | ||||||
|         cpu->r11 = seccomp_stackframe.r11; |  | ||||||
|         cpu->r12 = seccomp_stackframe.r12; |  | ||||||
|         cpu->r13 = seccomp_stackframe.r13; |  | ||||||
|         cpu->r14 = seccomp_stackframe.r14; |  | ||||||
|         cpu->r15 = seccomp_stackframe.r15; |  | ||||||
|         cpu->rip = seccomp_stackframe.fakeret; |  | ||||||
|         return; |  | ||||||
|       } |  | ||||||
|     } |  | ||||||
| #elif defined(__i386__) |  | ||||||
|     uint32_t bp = cpu->ebp; |  | ||||||
|     uint32_t top = thread.stack.start_of_memory_range; |  | ||||||
|     for (int i = 4; i--; ) { |  | ||||||
|       if (bp < top || |  | ||||||
|           bp + sizeof(bp) > thread.stack.start_of_memory_range + |  | ||||||
|           thread.stack.memory.data_size || |  | ||||||
|           bp & 1) { |  | ||||||
|         break; |  | ||||||
|       } |  | ||||||
|       uint32_t old_top = top; |  | ||||||
|       top = bp; |  | ||||||
|       uint8_t* bp_addr = stack_copy + bp - thread.stack.start_of_memory_range; |  | ||||||
|       my_memcpy(&bp, bp_addr, sizeof(bp)); |  | ||||||
|       if (bp == 0xDEADBEEFu) { |  | ||||||
|         struct { |  | ||||||
|           uint32_t edi; |  | ||||||
|           uint32_t esi; |  | ||||||
|           uint32_t edx; |  | ||||||
|           uint32_t ecx; |  | ||||||
|           uint32_t ebx; |  | ||||||
|           uint32_t deadbeef; |  | ||||||
|           uint32_t ebp; |  | ||||||
|           uint32_t fakeret; |  | ||||||
|           uint32_t ret; |  | ||||||
|         } seccomp_stackframe; |  | ||||||
|         if (top - offsetof(typeof(seccomp_stackframe), deadbeef) < old_top || |  | ||||||
|             top - offsetof(typeof(seccomp_stackframe), deadbeef) + |  | ||||||
|             sizeof(seccomp_stackframe) > |  | ||||||
|             thread.stack.start_of_memory_range+thread.stack.memory.data_size) { |  | ||||||
|           break; |  | ||||||
|         } |  | ||||||
|         my_memcpy(&seccomp_stackframe, |  | ||||||
|                   bp_addr - offsetof(typeof(seccomp_stackframe), deadbeef), |  | ||||||
|                   sizeof(seccomp_stackframe)); |  | ||||||
|         cpu->ebx = seccomp_stackframe.ebx; |  | ||||||
|         cpu->ecx = seccomp_stackframe.ecx; |  | ||||||
|         cpu->edx = seccomp_stackframe.edx; |  | ||||||
|         cpu->esi = seccomp_stackframe.esi; |  | ||||||
|         cpu->edi = seccomp_stackframe.edi; |  | ||||||
|         cpu->ebp = seccomp_stackframe.ebp; |  | ||||||
|         cpu->esp = top + 4*sizeof(void*); |  | ||||||
|         cpu->eip = seccomp_stackframe.fakeret; |  | ||||||
|         return; |  | ||||||
|       } |  | ||||||
|     } |  | ||||||
| #endif |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   bool FillThreadStack(MDRawThread* thread, uintptr_t stack_pointer, |   bool FillThreadStack(MDRawThread* thread, uintptr_t stack_pointer, | ||||||
|                        int max_stack_len, uint8_t** stack_copy) { |                        int max_stack_len, uint8_t** stack_copy) { | ||||||
|     *stack_copy = NULL; |     *stack_copy = NULL; | ||||||
| @ -720,12 +323,13 @@ class MinidumpWriter { | |||||||
|           ucontext_ && |           ucontext_ && | ||||||
|           !dumper_->IsPostMortem()) { |           !dumper_->IsPostMortem()) { | ||||||
|         uint8_t* stack_copy; |         uint8_t* stack_copy; | ||||||
|         if (!FillThreadStack(&thread, GetStackPointer(), -1, &stack_copy)) |         const uintptr_t stack_ptr = UContextReader::GetStackPointer(ucontext_); | ||||||
|  |         if (!FillThreadStack(&thread, stack_ptr, -1, &stack_copy)) | ||||||
|           return false; |           return false; | ||||||
| 
 | 
 | ||||||
|         // Copy 256 bytes around crashing instruction pointer to minidump.
 |         // Copy 256 bytes around crashing instruction pointer to minidump.
 | ||||||
|         const size_t kIPMemorySize = 256; |         const size_t kIPMemorySize = 256; | ||||||
|         uint64_t ip = GetInstructionPointer(); |         uint64_t ip = UContextReader::GetInstructionPointer(ucontext_); | ||||||
|         // Bound it to the upper and lower bounds of the memory map
 |         // Bound it to the upper and lower bounds of the memory map
 | ||||||
|         // it's contained within. If it's not in mapped memory,
 |         // it's contained within. If it's not in mapped memory,
 | ||||||
|         // don't bother trying to write it.
 |         // don't bother trying to write it.
 | ||||||
| @ -770,9 +374,13 @@ class MinidumpWriter { | |||||||
|         if (!cpu.Allocate()) |         if (!cpu.Allocate()) | ||||||
|           return false; |           return false; | ||||||
|         my_memset(cpu.get(), 0, sizeof(RawContextCPU)); |         my_memset(cpu.get(), 0, sizeof(RawContextCPU)); | ||||||
|         CPUFillFromUContext(cpu.get(), ucontext_, float_state_); | #if !defined(__ARM_EABI__) && !defined(__mips__) | ||||||
|  |         UContextReader::FillCPUContext(cpu.get(), ucontext_, float_state_); | ||||||
|  | #else | ||||||
|  |         UContextReader::FillCPUContext(cpu.get(), ucontext_); | ||||||
|  | #endif | ||||||
|         if (stack_copy) |         if (stack_copy) | ||||||
|           PopSeccompStackFrame(cpu.get(), thread, stack_copy); |           SeccompUnwinder::PopSeccompStackFrame(cpu.get(), thread, stack_copy); | ||||||
|         thread.thread_context = cpu.location(); |         thread.thread_context = cpu.location(); | ||||||
|         crashing_thread_context_ = cpu.location(); |         crashing_thread_context_ = cpu.location(); | ||||||
|       } else { |       } else { | ||||||
| @ -792,9 +400,9 @@ class MinidumpWriter { | |||||||
|         if (!cpu.Allocate()) |         if (!cpu.Allocate()) | ||||||
|           return false; |           return false; | ||||||
|         my_memset(cpu.get(), 0, sizeof(RawContextCPU)); |         my_memset(cpu.get(), 0, sizeof(RawContextCPU)); | ||||||
|         CPUFillFromThreadInfo(cpu.get(), info); |         info.FillCPUContext(cpu.get()); | ||||||
|         if (stack_copy) |         if (stack_copy) | ||||||
|           PopSeccompStackFrame(cpu.get(), thread, stack_copy); |           SeccompUnwinder::PopSeccompStackFrame(cpu.get(), thread, stack_copy); | ||||||
|         thread.thread_context = cpu.location(); |         thread.thread_context = cpu.location(); | ||||||
|         if (dumper_->threads()[i] == GetCrashThread()) { |         if (dumper_->threads()[i] == GetCrashThread()) { | ||||||
|           crashing_thread_context_ = cpu.location(); |           crashing_thread_context_ = cpu.location(); | ||||||
| @ -802,7 +410,7 @@ class MinidumpWriter { | |||||||
|             // This is the crashing thread of a live process, but
 |             // This is the crashing thread of a live process, but
 | ||||||
|             // no context was provided, so set the crash address
 |             // no context was provided, so set the crash address
 | ||||||
|             // while the instruction pointer is already here.
 |             // while the instruction pointer is already here.
 | ||||||
|             dumper_->set_crash_address(GetInstructionPointer(info)); |             dumper_->set_crash_address(info.GetInstructionPointer()); | ||||||
|           } |           } | ||||||
|         } |         } | ||||||
|       } |       } | ||||||
| @ -839,7 +447,9 @@ class MinidumpWriter { | |||||||
| 
 | 
 | ||||||
|   static bool ShouldIncludeMapping(const MappingInfo& mapping) { |   static bool ShouldIncludeMapping(const MappingInfo& mapping) { | ||||||
|     if (mapping.name[0] == 0 ||  // only want modules with filenames.
 |     if (mapping.name[0] == 0 ||  // only want modules with filenames.
 | ||||||
|         mapping.offset ||  // only want to include one mapping per shared lib.
 |         // Only want to include one mapping per shared lib.
 | ||||||
|  |         // Avoid filtering executable mappings.
 | ||||||
|  |         (mapping.offset != 0 && !mapping.exec) || | ||||||
|         mapping.size < 4096) {  // too small to get a signature for.
 |         mapping.size < 4096) {  // too small to get a signature for.
 | ||||||
|       return false; |       return false; | ||||||
|     } |     } | ||||||
| @ -930,24 +540,9 @@ class MinidumpWriter { | |||||||
| 
 | 
 | ||||||
|     mod.base_of_image = mapping.start_addr; |     mod.base_of_image = mapping.start_addr; | ||||||
|     mod.size_of_image = mapping.size; |     mod.size_of_image = mapping.size; | ||||||
|     const size_t filepath_len = my_strlen(mapping.name); |  | ||||||
| 
 |  | ||||||
|     // Figure out file name from path
 |  | ||||||
|     const char* filename_ptr = mapping.name + filepath_len - 1; |  | ||||||
|     while (filename_ptr >= mapping.name) { |  | ||||||
|       if (*filename_ptr == '/') |  | ||||||
|         break; |  | ||||||
|       filename_ptr--; |  | ||||||
|     } |  | ||||||
|     filename_ptr++; |  | ||||||
| 
 |  | ||||||
|     const size_t filename_len = mapping.name + filepath_len - filename_ptr; |  | ||||||
| 
 | 
 | ||||||
|     uint8_t cv_buf[MDCVInfoPDB70_minsize + NAME_MAX]; |     uint8_t cv_buf[MDCVInfoPDB70_minsize + NAME_MAX]; | ||||||
|     uint8_t* cv_ptr = cv_buf; |     uint8_t* cv_ptr = cv_buf; | ||||||
|     UntypedMDRVA cv(&minidump_writer_); |  | ||||||
|     if (!cv.Allocate(MDCVInfoPDB70_minsize + filename_len + 1)) |  | ||||||
|       return false; |  | ||||||
| 
 | 
 | ||||||
|     const uint32_t cv_signature = MD_CVINFOPDB70_SIGNATURE; |     const uint32_t cv_signature = MD_CVINFOPDB70_SIGNATURE; | ||||||
|     my_memcpy(cv_ptr, &cv_signature, sizeof(cv_signature)); |     my_memcpy(cv_ptr, &cv_signature, sizeof(cv_signature)); | ||||||
| @ -958,20 +553,31 @@ class MinidumpWriter { | |||||||
|       // GUID was provided by caller.
 |       // GUID was provided by caller.
 | ||||||
|       my_memcpy(signature, identifier, sizeof(MDGUID)); |       my_memcpy(signature, identifier, sizeof(MDGUID)); | ||||||
|     } else { |     } else { | ||||||
|  |       // Note: ElfFileIdentifierForMapping() can manipulate the |mapping.name|.
 | ||||||
|       dumper_->ElfFileIdentifierForMapping(mapping, member, |       dumper_->ElfFileIdentifierForMapping(mapping, member, | ||||||
|                                            mapping_id, signature); |                                            mapping_id, signature); | ||||||
|     } |     } | ||||||
|     my_memset(cv_ptr, 0, sizeof(uint32_t));  // Set age to 0 on Linux.
 |     my_memset(cv_ptr, 0, sizeof(uint32_t));  // Set age to 0 on Linux.
 | ||||||
|     cv_ptr += sizeof(uint32_t); |     cv_ptr += sizeof(uint32_t); | ||||||
| 
 | 
 | ||||||
|  |     char file_name[NAME_MAX]; | ||||||
|  |     char file_path[NAME_MAX]; | ||||||
|  |     LinuxDumper::GetMappingEffectiveNameAndPath( | ||||||
|  |         mapping, file_path, sizeof(file_path), file_name, sizeof(file_name)); | ||||||
|  | 
 | ||||||
|  |     const size_t file_name_len = my_strlen(file_name); | ||||||
|  |     UntypedMDRVA cv(&minidump_writer_); | ||||||
|  |     if (!cv.Allocate(MDCVInfoPDB70_minsize + file_name_len + 1)) | ||||||
|  |       return false; | ||||||
|  | 
 | ||||||
|     // Write pdb_file_name
 |     // Write pdb_file_name
 | ||||||
|     my_memcpy(cv_ptr, filename_ptr, filename_len + 1); |     my_memcpy(cv_ptr, file_name, file_name_len + 1); | ||||||
|     cv.Copy(cv_buf, MDCVInfoPDB70_minsize + filename_len + 1); |     cv.Copy(cv_buf, MDCVInfoPDB70_minsize + file_name_len + 1); | ||||||
| 
 | 
 | ||||||
|     mod.cv_record = cv.location(); |     mod.cv_record = cv.location(); | ||||||
| 
 | 
 | ||||||
|     MDLocationDescriptor ld; |     MDLocationDescriptor ld; | ||||||
|     if (!minidump_writer_.WriteString(mapping.name, filepath_len, &ld)) |     if (!minidump_writer_.WriteString(file_path, my_strlen(file_path), &ld)) | ||||||
|       return false; |       return false; | ||||||
|     mod.module_name_rva = ld.rva; |     mod.module_name_rva = ld.rva; | ||||||
|     return true; |     return true; | ||||||
| @ -1127,8 +733,8 @@ class MinidumpWriter { | |||||||
|           return false; |           return false; | ||||||
|         MDRawLinkMap entry; |         MDRawLinkMap entry; | ||||||
|         entry.name = location.rva; |         entry.name = location.rva; | ||||||
|         entry.addr = (void*)map.l_addr; |         entry.addr = reinterpret_cast<void*>(map.l_addr); | ||||||
|         entry.ld = (void*)map.l_ld; |         entry.ld = reinterpret_cast<void*>(map.l_ld); | ||||||
|         linkmap.CopyIndex(idx++, &entry); |         linkmap.CopyIndex(idx++, &entry); | ||||||
|       } |       } | ||||||
|     } |     } | ||||||
| @ -1144,11 +750,14 @@ class MinidumpWriter { | |||||||
|     debug.get()->version = debug_entry.r_version; |     debug.get()->version = debug_entry.r_version; | ||||||
|     debug.get()->map = linkmap_rva; |     debug.get()->map = linkmap_rva; | ||||||
|     debug.get()->dso_count = dso_count; |     debug.get()->dso_count = dso_count; | ||||||
|     debug.get()->brk = (void*)debug_entry.r_brk; |     debug.get()->brk = reinterpret_cast<void*>(debug_entry.r_brk); | ||||||
|     debug.get()->ldbase = (void*)debug_entry.r_ldbase; |     debug.get()->ldbase = reinterpret_cast<void*>(debug_entry.r_ldbase); | ||||||
|     debug.get()->dynamic = dynamic; |     debug.get()->dynamic = dynamic; | ||||||
| 
 | 
 | ||||||
|     wasteful_vector<char> dso_debug_data(dumper_->allocator(), dynamic_length); |     wasteful_vector<char> dso_debug_data(dumper_->allocator(), dynamic_length); | ||||||
|  |     // The passed-in size to the constructor (above) is only a hint.
 | ||||||
|  |     // Must call .resize() to do actual initialization of the elements.
 | ||||||
|  |     dso_debug_data.resize(dynamic_length); | ||||||
|     dumper_->CopyFromProcess(&dso_debug_data[0], GetCrashThread(), dynamic, |     dumper_->CopyFromProcess(&dso_debug_data[0], GetCrashThread(), dynamic, | ||||||
|                              dynamic_length); |                              dynamic_length); | ||||||
|     debug.CopyIndexAfterObject(0, &dso_debug_data[0], dynamic_length); |     debug.CopyIndexAfterObject(0, &dso_debug_data[0], dynamic_length); | ||||||
| @ -1167,53 +776,13 @@ class MinidumpWriter { | |||||||
|     return dumper_->crash_thread(); |     return dumper_->crash_thread(); | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
| #if defined(__i386__) |  | ||||||
|   uintptr_t GetStackPointer() { |  | ||||||
|     return ucontext_->uc_mcontext.gregs[REG_ESP]; |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   uintptr_t GetInstructionPointer() { |  | ||||||
|     return ucontext_->uc_mcontext.gregs[REG_EIP]; |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   uintptr_t GetInstructionPointer(const ThreadInfo& info) { |  | ||||||
|     return info.regs.eip; |  | ||||||
|   } |  | ||||||
| #elif defined(__x86_64) |  | ||||||
|   uintptr_t GetStackPointer() { |  | ||||||
|     return ucontext_->uc_mcontext.gregs[REG_RSP]; |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   uintptr_t GetInstructionPointer() { |  | ||||||
|     return ucontext_->uc_mcontext.gregs[REG_RIP]; |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   uintptr_t GetInstructionPointer(const ThreadInfo& info) { |  | ||||||
|     return info.regs.rip; |  | ||||||
|   } |  | ||||||
| #elif defined(__ARM_EABI__) |  | ||||||
|   uintptr_t GetStackPointer() { |  | ||||||
|     return ucontext_->uc_mcontext.arm_sp; |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   uintptr_t GetInstructionPointer() { |  | ||||||
|     return ucontext_->uc_mcontext.arm_pc; |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   uintptr_t GetInstructionPointer(const ThreadInfo& info) { |  | ||||||
|     return info.regs.uregs[15]; |  | ||||||
|   } |  | ||||||
| #else |  | ||||||
| #error "This code has not been ported to your platform yet." |  | ||||||
| #endif |  | ||||||
| 
 |  | ||||||
|   void NullifyDirectoryEntry(MDRawDirectory* dirent) { |   void NullifyDirectoryEntry(MDRawDirectory* dirent) { | ||||||
|     dirent->stream_type = 0; |     dirent->stream_type = 0; | ||||||
|     dirent->location.data_size = 0; |     dirent->location.data_size = 0; | ||||||
|     dirent->location.rva = 0; |     dirent->location.rva = 0; | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
| #if defined(__i386__) || defined(__x86_64__) | #if defined(__i386__) || defined(__x86_64__) || defined(__mips__) | ||||||
|   bool WriteCPUInformation(MDRawSystemInfo* sys_info) { |   bool WriteCPUInformation(MDRawSystemInfo* sys_info) { | ||||||
|     char vendor_id[sizeof(sys_info->cpu.x86_cpu_info.vendor_id) + 1] = {0}; |     char vendor_id[sizeof(sys_info->cpu.x86_cpu_info.vendor_id) + 1] = {0}; | ||||||
|     static const char vendor_id_name[] = "vendor_id"; |     static const char vendor_id_name[] = "vendor_id"; | ||||||
| @ -1224,14 +793,18 @@ class MinidumpWriter { | |||||||
|       bool found; |       bool found; | ||||||
|     } cpu_info_table[] = { |     } cpu_info_table[] = { | ||||||
|       { "processor", -1, false }, |       { "processor", -1, false }, | ||||||
|  | #if defined(__i386__) || defined(__x86_64__) | ||||||
|       { "model", 0, false }, |       { "model", 0, false }, | ||||||
|       { "stepping",  0, false }, |       { "stepping",  0, false }, | ||||||
|       { "cpu family", 0, false }, |       { "cpu family", 0, false }, | ||||||
|  | #endif | ||||||
|     }; |     }; | ||||||
| 
 | 
 | ||||||
|     // processor_architecture should always be set, do this first
 |     // processor_architecture should always be set, do this first
 | ||||||
|     sys_info->processor_architecture = |     sys_info->processor_architecture = | ||||||
| #if defined(__i386__) | #if defined(__mips__) | ||||||
|  |         MD_CPU_ARCHITECTURE_MIPS; | ||||||
|  | #elif defined(__i386__) | ||||||
|         MD_CPU_ARCHITECTURE_X86; |         MD_CPU_ARCHITECTURE_X86; | ||||||
| #else | #else | ||||||
|         MD_CPU_ARCHITECTURE_AMD64; |         MD_CPU_ARCHITECTURE_AMD64; | ||||||
| @ -1294,9 +867,11 @@ class MinidumpWriter { | |||||||
|     cpu_info_table[0].value++; |     cpu_info_table[0].value++; | ||||||
| 
 | 
 | ||||||
|     sys_info->number_of_processors = cpu_info_table[0].value; |     sys_info->number_of_processors = cpu_info_table[0].value; | ||||||
|  | #if defined(__i386__) || defined(__x86_64__) | ||||||
|     sys_info->processor_level      = cpu_info_table[3].value; |     sys_info->processor_level      = cpu_info_table[3].value; | ||||||
|     sys_info->processor_revision   = cpu_info_table[1].value << 8 | |     sys_info->processor_revision   = cpu_info_table[1].value << 8 | | ||||||
|                                      cpu_info_table[2].value; |                                      cpu_info_table[2].value; | ||||||
|  | #endif | ||||||
| 
 | 
 | ||||||
|     if (vendor_id[0] != '\0') { |     if (vendor_id[0] != '\0') { | ||||||
|       my_memcpy(sys_info->cpu.x86_cpu_info.vendor_id, vendor_id, |       my_memcpy(sys_info->cpu.x86_cpu_info.vendor_id, vendor_id, | ||||||
| @ -1304,7 +879,7 @@ class MinidumpWriter { | |||||||
|     } |     } | ||||||
|     return true; |     return true; | ||||||
|   } |   } | ||||||
| #elif defined(__arm__) | #elif defined(__arm__) || defined(__aarch64__) | ||||||
|   bool WriteCPUInformation(MDRawSystemInfo* sys_info) { |   bool WriteCPUInformation(MDRawSystemInfo* sys_info) { | ||||||
|     // The CPUID value is broken up in several entries in /proc/cpuinfo.
 |     // The CPUID value is broken up in several entries in /proc/cpuinfo.
 | ||||||
|     // This table is used to rebuild it from the entries.
 |     // This table is used to rebuild it from the entries.
 | ||||||
| @ -1326,6 +901,7 @@ class MinidumpWriter { | |||||||
|       const char* tag; |       const char* tag; | ||||||
|       uint32_t hwcaps; |       uint32_t hwcaps; | ||||||
|     } cpu_features_entries[] = { |     } cpu_features_entries[] = { | ||||||
|  | #if defined(__arm__) | ||||||
|       { "swp",  MD_CPU_ARM_ELF_HWCAP_SWP }, |       { "swp",  MD_CPU_ARM_ELF_HWCAP_SWP }, | ||||||
|       { "half", MD_CPU_ARM_ELF_HWCAP_HALF }, |       { "half", MD_CPU_ARM_ELF_HWCAP_HALF }, | ||||||
|       { "thumb", MD_CPU_ARM_ELF_HWCAP_THUMB }, |       { "thumb", MD_CPU_ARM_ELF_HWCAP_THUMB }, | ||||||
| @ -1346,10 +922,18 @@ class MinidumpWriter { | |||||||
|       { "idiva", MD_CPU_ARM_ELF_HWCAP_IDIVA }, |       { "idiva", MD_CPU_ARM_ELF_HWCAP_IDIVA }, | ||||||
|       { "idivt", MD_CPU_ARM_ELF_HWCAP_IDIVT }, |       { "idivt", MD_CPU_ARM_ELF_HWCAP_IDIVT }, | ||||||
|       { "idiv", MD_CPU_ARM_ELF_HWCAP_IDIVA | MD_CPU_ARM_ELF_HWCAP_IDIVT }, |       { "idiv", MD_CPU_ARM_ELF_HWCAP_IDIVA | MD_CPU_ARM_ELF_HWCAP_IDIVT }, | ||||||
|  | #elif defined(__aarch64__) | ||||||
|  |       // No hwcaps on aarch64.
 | ||||||
|  | #endif | ||||||
|     }; |     }; | ||||||
| 
 | 
 | ||||||
|     // processor_architecture should always be set, do this first
 |     // processor_architecture should always be set, do this first
 | ||||||
|     sys_info->processor_architecture = MD_CPU_ARCHITECTURE_ARM; |     sys_info->processor_architecture = | ||||||
|  | #if defined(__aarch64__) | ||||||
|  |         MD_CPU_ARCHITECTURE_ARM64; | ||||||
|  | #else | ||||||
|  |         MD_CPU_ARCHITECTURE_ARM; | ||||||
|  | #endif | ||||||
| 
 | 
 | ||||||
|     // /proc/cpuinfo is not readable under various sandboxed environments
 |     // /proc/cpuinfo is not readable under various sandboxed environments
 | ||||||
|     // (e.g. Android services with the android:isolatedProcess attribute)
 |     // (e.g. Android services with the android:isolatedProcess attribute)
 | ||||||
| @ -1420,10 +1004,11 @@ class MinidumpWriter { | |||||||
|           const char* p = value; |           const char* p = value; | ||||||
|           if (value[0] == '0' && value[1] == 'x') { |           if (value[0] == '0' && value[1] == 'x') { | ||||||
|             p = my_read_hex_ptr(&result, value+2); |             p = my_read_hex_ptr(&result, value+2); | ||||||
|           } else if (entry->format == 'x') |           } else if (entry->format == 'x') { | ||||||
|             p = my_read_hex_ptr(&result, value); |             p = my_read_hex_ptr(&result, value); | ||||||
|           else |           } else { | ||||||
|             p = my_read_decimal_ptr(&result, value); |             p = my_read_decimal_ptr(&result, value); | ||||||
|  |           } | ||||||
|           if (p == value) |           if (p == value) | ||||||
|             continue; |             continue; | ||||||
| 
 | 
 | ||||||
| @ -1432,13 +1017,14 @@ class MinidumpWriter { | |||||||
|           sys_info->cpu.arm_cpu_info.cpuid |= |           sys_info->cpu.arm_cpu_info.cpuid |= | ||||||
|               static_cast<uint32_t>(result); |               static_cast<uint32_t>(result); | ||||||
|         } |         } | ||||||
|  | #if defined(__arm__) | ||||||
|         // Get the architecture version from the "Processor" field.
 |         // Get the architecture version from the "Processor" field.
 | ||||||
|         // Note that it is also available in the "CPU architecture" field,
 |         // Note that it is also available in the "CPU architecture" field,
 | ||||||
|         // however, some existing kernels are misconfigured and will report
 |         // however, some existing kernels are misconfigured and will report
 | ||||||
|         // invalid values here (e.g. 6, while the CPU is ARMv7-A based).
 |         // invalid values here (e.g. 6, while the CPU is ARMv7-A based).
 | ||||||
|         // The "Processor" field doesn't have this issue.
 |         // The "Processor" field doesn't have this issue.
 | ||||||
|         if (!my_strcmp(field, "Processor")) { |         if (!my_strcmp(field, "Processor")) { | ||||||
|           unsigned value_len; |           size_t value_len; | ||||||
|           const char* value = reader->GetValueAndLen(&value_len); |           const char* value = reader->GetValueAndLen(&value_len); | ||||||
|           // Expected format: <text> (v<level><endian>)
 |           // Expected format: <text> (v<level><endian>)
 | ||||||
|           // Where <text> is some text like "ARMv7 Processor rev 2"
 |           // Where <text> is some text like "ARMv7 Processor rev 2"
 | ||||||
| @ -1457,9 +1043,23 @@ class MinidumpWriter { | |||||||
|             sys_info->processor_level = static_cast<uint16_t>(arch_level); |             sys_info->processor_level = static_cast<uint16_t>(arch_level); | ||||||
|           } |           } | ||||||
|         } |         } | ||||||
|  | #elif defined(__aarch64__) | ||||||
|  |         // The aarch64 architecture does not provide the architecture level
 | ||||||
|  |         // in the Processor field, so we instead check the "CPU architecture"
 | ||||||
|  |         // field.
 | ||||||
|  |         if (!my_strcmp(field, "CPU architecture")) { | ||||||
|  |           uintptr_t arch_level = 0; | ||||||
|  |           const char* value = reader->GetValue(); | ||||||
|  |           const char* p = value; | ||||||
|  |           p = my_read_decimal_ptr(&arch_level, value); | ||||||
|  |           if (p == value) | ||||||
|  |             continue; | ||||||
|  |           sys_info->processor_level = static_cast<uint16_t>(arch_level); | ||||||
|  |         } | ||||||
|  | #endif | ||||||
|         // Rebuild the ELF hwcaps from the 'Features' field.
 |         // Rebuild the ELF hwcaps from the 'Features' field.
 | ||||||
|         if (!my_strcmp(field, "Features")) { |         if (!my_strcmp(field, "Features")) { | ||||||
|           unsigned value_len; |           size_t value_len; | ||||||
|           const char* value = reader->GetValueAndLen(&value_len); |           const char* value = reader->GetValueAndLen(&value_len); | ||||||
| 
 | 
 | ||||||
|           // Parse each space-separated tag.
 |           // Parse each space-separated tag.
 | ||||||
| @ -1601,23 +1201,6 @@ class MinidumpWriter { | |||||||
|       space_left -= info_len; |       space_left -= info_len; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| #ifdef __ANDROID__ |  | ||||||
|     // On Android, try to get the build fingerprint and append it.
 |  | ||||||
|     // Fail gracefully because there is no guarantee that the system
 |  | ||||||
|     // property will always be available or accessible.
 |  | ||||||
|     char fingerprint[PROP_VALUE_MAX]; |  | ||||||
|     int fingerprint_len = __system_property_get("ro.build.fingerprint", |  | ||||||
|                                                 fingerprint); |  | ||||||
|     // System property values shall always be zero-terminated.
 |  | ||||||
|     // Be paranoid and don't trust the system.
 |  | ||||||
|     if (fingerprint_len > 0 && fingerprint_len < PROP_VALUE_MAX) { |  | ||||||
|       const char* separator = " "; |  | ||||||
|       if (!first_item) |  | ||||||
|         my_strlcat(buf, separator, sizeof(buf)); |  | ||||||
|       my_strlcat(buf, fingerprint, sizeof(buf)); |  | ||||||
|     } |  | ||||||
| #endif |  | ||||||
| 
 |  | ||||||
|     MDLocationDescriptor location; |     MDLocationDescriptor location; | ||||||
|     if (!minidump_writer_.WriteString(buf, 0, &location)) |     if (!minidump_writer_.WriteString(buf, 0, &location)) | ||||||
|       return false; |       return false; | ||||||
| @ -1639,7 +1222,9 @@ class MinidumpWriter { | |||||||
|   const char* path_;  // Path to the file where the minidum should be written.
 |   const char* path_;  // Path to the file where the minidum should be written.
 | ||||||
| 
 | 
 | ||||||
|   const struct ucontext* const ucontext_;  // also from the signal handler
 |   const struct ucontext* const ucontext_;  // also from the signal handler
 | ||||||
|   const struct _libc_fpstate* const float_state_;  // ditto
 | #if !defined(__ARM_EABI__) && !defined(__mips__) | ||||||
|  |   const google_breakpad::fpstate_t* const float_state_;  // ditto
 | ||||||
|  | #endif | ||||||
|   LinuxDumper* dumper_; |   LinuxDumper* dumper_; | ||||||
|   MinidumpFileWriter minidump_writer_; |   MinidumpFileWriter minidump_writer_; | ||||||
|   off_t minidump_size_limit_; |   off_t minidump_size_limit_; | ||||||
|  | |||||||
| @ -32,6 +32,7 @@ | |||||||
| 
 | 
 | ||||||
| #include <stdint.h> | #include <stdint.h> | ||||||
| #include <sys/types.h> | #include <sys/types.h> | ||||||
|  | #include <sys/ucontext.h> | ||||||
| #include <unistd.h> | #include <unistd.h> | ||||||
| 
 | 
 | ||||||
| #include <list> | #include <list> | ||||||
| @ -44,13 +45,11 @@ namespace google_breakpad { | |||||||
| 
 | 
 | ||||||
| class ExceptionHandler; | class ExceptionHandler; | ||||||
| 
 | 
 | ||||||
| struct MappingEntry { | #if defined(__aarch64__) | ||||||
|   MappingInfo first; | typedef struct fpsimd_context fpstate_t; | ||||||
|   uint8_t second[sizeof(MDGUID)]; | #elif !defined(__ARM_EABI__) && !defined(__mips__) | ||||||
| }; | typedef struct _libc_fpstate fpstate_t; | ||||||
| 
 | #endif | ||||||
| // A list of <MappingInfo, GUID>
 |  | ||||||
| typedef std::list<MappingEntry> MappingList; |  | ||||||
| 
 | 
 | ||||||
| // These entries store a list of memory regions that the client wants included
 | // These entries store a list of memory regions that the client wants included
 | ||||||
| // in the minidump.
 | // in the minidump.
 | ||||||
|  | |||||||
| @ -84,7 +84,7 @@ TEST(MinidumpWriterTest, SetupWithPath) { | |||||||
|   AutoTempDir temp_dir; |   AutoTempDir temp_dir; | ||||||
|   string templ = temp_dir.path() + kMDWriterUnitTestFileName; |   string templ = temp_dir.path() + kMDWriterUnitTestFileName; | ||||||
|   // Set a non-zero tid to avoid tripping asserts.
 |   // Set a non-zero tid to avoid tripping asserts.
 | ||||||
|   context.tid = 1; |   context.tid = child; | ||||||
|   ASSERT_TRUE(WriteMinidump(templ.c_str(), child, &context, sizeof(context))); |   ASSERT_TRUE(WriteMinidump(templ.c_str(), child, &context, sizeof(context))); | ||||||
|   struct stat st; |   struct stat st; | ||||||
|   ASSERT_EQ(0, stat(templ.c_str(), &st)); |   ASSERT_EQ(0, stat(templ.c_str(), &st)); | ||||||
| @ -114,7 +114,7 @@ TEST(MinidumpWriterTest, SetupWithFD) { | |||||||
|   string templ = temp_dir.path() + kMDWriterUnitTestFileName; |   string templ = temp_dir.path() + kMDWriterUnitTestFileName; | ||||||
|   int fd = open(templ.c_str(), O_CREAT | O_WRONLY, S_IRWXU); |   int fd = open(templ.c_str(), O_CREAT | O_WRONLY, S_IRWXU); | ||||||
|   // Set a non-zero tid to avoid tripping asserts.
 |   // Set a non-zero tid to avoid tripping asserts.
 | ||||||
|   context.tid = 1; |   context.tid = child; | ||||||
|   ASSERT_TRUE(WriteMinidump(fd, child, &context, sizeof(context))); |   ASSERT_TRUE(WriteMinidump(fd, child, &context, sizeof(context))); | ||||||
|   struct stat st; |   struct stat st; | ||||||
|   ASSERT_EQ(0, stat(templ.c_str(), &st)); |   ASSERT_EQ(0, stat(templ.c_str(), &st)); | ||||||
| @ -391,7 +391,7 @@ TEST(MinidumpWriterTest, DeletedBinary) { | |||||||
| 
 | 
 | ||||||
|   string templ = temp_dir.path() + kMDWriterUnitTestFileName; |   string templ = temp_dir.path() + kMDWriterUnitTestFileName; | ||||||
|   // Set a non-zero tid to avoid tripping asserts.
 |   // Set a non-zero tid to avoid tripping asserts.
 | ||||||
|   context.tid = 1; |   context.tid = child_pid; | ||||||
|   ASSERT_TRUE(WriteMinidump(templ.c_str(), child_pid, &context, |   ASSERT_TRUE(WriteMinidump(templ.c_str(), child_pid, &context, | ||||||
|                             sizeof(context))); |                             sizeof(context))); | ||||||
|   kill(child_pid, SIGKILL); |   kill(child_pid, SIGKILL); | ||||||
| @ -525,21 +525,20 @@ TEST(MinidumpWriterTest, InvalidStackPointer) { | |||||||
| 
 | 
 | ||||||
|   // Fake the child's stack pointer for its crashing thread.  NOTE: This must
 |   // Fake the child's stack pointer for its crashing thread.  NOTE: This must
 | ||||||
|   // be an invalid memory address for the child process (stack or otherwise).
 |   // be an invalid memory address for the child process (stack or otherwise).
 | ||||||
| #if defined(__i386) |  | ||||||
|   // Try 1MB below the current stack.
 |   // Try 1MB below the current stack.
 | ||||||
|   uintptr_t invalid_stack_pointer = |   uintptr_t invalid_stack_pointer = | ||||||
|       reinterpret_cast<uintptr_t>(&context) - 1024*1024; |       reinterpret_cast<uintptr_t>(&context) - 1024*1024; | ||||||
|  | #if defined(__i386) | ||||||
|   context.context.uc_mcontext.gregs[REG_ESP] = invalid_stack_pointer; |   context.context.uc_mcontext.gregs[REG_ESP] = invalid_stack_pointer; | ||||||
| #elif defined(__x86_64) | #elif defined(__x86_64) | ||||||
|   // Try 1MB below the current stack.
 |  | ||||||
|   uintptr_t invalid_stack_pointer = |  | ||||||
|       reinterpret_cast<uintptr_t>(&context) - 1024*1024; |  | ||||||
|   context.context.uc_mcontext.gregs[REG_RSP] = invalid_stack_pointer; |   context.context.uc_mcontext.gregs[REG_RSP] = invalid_stack_pointer; | ||||||
| #elif defined(__ARM_EABI__) | #elif defined(__ARM_EABI__) | ||||||
|   // Try 1MB below the current stack.
 |  | ||||||
|   uintptr_t invalid_stack_pointer = |  | ||||||
|       reinterpret_cast<uintptr_t>(&context) - 1024*1024; |  | ||||||
|   context.context.uc_mcontext.arm_sp = invalid_stack_pointer; |   context.context.uc_mcontext.arm_sp = invalid_stack_pointer; | ||||||
|  | #elif defined(__aarch64__) | ||||||
|  |   context.context.uc_mcontext.sp = invalid_stack_pointer; | ||||||
|  | #elif defined(__mips__) | ||||||
|  |   context.context.uc_mcontext.gregs[MD_CONTEXT_MIPS_REG_SP] = | ||||||
|  |       invalid_stack_pointer; | ||||||
| #else | #else | ||||||
| # error "This code has not been ported to your platform yet." | # error "This code has not been ported to your platform yet." | ||||||
| #endif | #endif | ||||||
|  | |||||||
| @ -36,8 +36,7 @@ | |||||||
| 
 | 
 | ||||||
| #include "client/linux/minidump_writer/proc_cpuinfo_reader.h" | #include "client/linux/minidump_writer/proc_cpuinfo_reader.h" | ||||||
| #include "breakpad_googletest_includes.h" | #include "breakpad_googletest_includes.h" | ||||||
| #include "common/linux/eintr_wrapper.h" | #include "common/linux/tests/auto_testfile.h" | ||||||
| #include "common/tests/auto_testfile.h" |  | ||||||
| 
 | 
 | ||||||
| using namespace google_breakpad; | using namespace google_breakpad; | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -100,5 +100,5 @@ int main(int argc, char *argv[]) { | |||||||
|                                              FLAGS_crash_server, |                                              FLAGS_crash_server, | ||||||
|                                              FLAGS_proxy_host, |                                              FLAGS_proxy_host, | ||||||
|                                              FLAGS_proxy_userpasswd); |                                              FLAGS_proxy_userpasswd); | ||||||
|   g.Upload(); |   g.Upload(NULL, NULL, NULL); | ||||||
| } | } | ||||||
|  | |||||||
| @ -40,7 +40,7 @@ | |||||||
| #include "client/minidump_file_writer-inl.h" | #include "client/minidump_file_writer-inl.h" | ||||||
| #include "common/linux/linux_libc_support.h" | #include "common/linux/linux_libc_support.h" | ||||||
| #include "common/string_conversion.h" | #include "common/string_conversion.h" | ||||||
| #if __linux__ | #if defined(__linux__) && __linux__ | ||||||
| #include "third_party/lss/linux_syscall_support.h" | #include "third_party/lss/linux_syscall_support.h" | ||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
| @ -62,7 +62,7 @@ MinidumpFileWriter::~MinidumpFileWriter() { | |||||||
| 
 | 
 | ||||||
| bool MinidumpFileWriter::Open(const char *path) { | bool MinidumpFileWriter::Open(const char *path) { | ||||||
|   assert(file_ == -1); |   assert(file_ == -1); | ||||||
| #if __linux__ | #if defined(__linux__) && __linux__ | ||||||
|   file_ = sys_open(path, O_WRONLY | O_CREAT | O_EXCL, 0600); |   file_ = sys_open(path, O_WRONLY | O_CREAT | O_EXCL, 0600); | ||||||
| #else | #else | ||||||
|   file_ = open(path, O_WRONLY | O_CREAT | O_EXCL, 0600); |   file_ = open(path, O_WRONLY | O_CREAT | O_EXCL, 0600); | ||||||
| @ -84,7 +84,7 @@ bool MinidumpFileWriter::Close() { | |||||||
|     if (-1 == ftruncate(file_, position_)) { |     if (-1 == ftruncate(file_, position_)) { | ||||||
|        return false; |        return false; | ||||||
|     } |     } | ||||||
| #if __linux__ | #if defined(__linux__) && __linux__ | ||||||
|     result = (sys_close(file_) == 0); |     result = (sys_close(file_) == 0); | ||||||
| #else | #else | ||||||
|     result = (close(file_) == 0); |     result = (close(file_) == 0); | ||||||
| @ -253,7 +253,7 @@ bool MinidumpFileWriter::Copy(MDRVA position, const void *src, ssize_t size) { | |||||||
|     return false; |     return false; | ||||||
| 
 | 
 | ||||||
|   // Seek and write the data
 |   // Seek and write the data
 | ||||||
| #if __linux__ | #if defined(__linux__) && __linux__ | ||||||
|   if (sys_lseek(file_, position, SEEK_SET) == static_cast<off_t>(position)) { |   if (sys_lseek(file_, position, SEEK_SET) == static_cast<off_t>(position)) { | ||||||
|     if (sys_write(file_, src, size) == size) { |     if (sys_write(file_, src, size) == size) { | ||||||
| #else | #else | ||||||
|  | |||||||
| @ -74,8 +74,8 @@ public: | |||||||
|   MinidumpFileWriter(); |   MinidumpFileWriter(); | ||||||
|   ~MinidumpFileWriter(); |   ~MinidumpFileWriter(); | ||||||
| 
 | 
 | ||||||
|   // Open |path| as the destination of the minidump data.  Any existing file
 |   // Open |path| as the destination of the minidump data. If |path| already
 | ||||||
|   // will be overwritten.
 |   // exists, then Open() will fail.
 | ||||||
|   // Return true on success, or false on failure.
 |   // Return true on success, or false on failure.
 | ||||||
|   bool Open(const char *path); |   bool Open(const char *path); | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -1,5 +1,4 @@ | |||||||
| # Copyright (c) 2010, Google Inc. | # Copyright 2010 Google Inc. All rights reserved. | ||||||
| # All rights reserved. |  | ||||||
| # | # | ||||||
| # Redistribution and use in source and binary forms, with or without | # Redistribution and use in source and binary forms, with or without | ||||||
| # modification, are permitted provided that the following conditions are | # modification, are permitted provided that the following conditions are | ||||||
| @ -29,9 +28,21 @@ | |||||||
| 
 | 
 | ||||||
| { | { | ||||||
|   'includes': [ |   'includes': [ | ||||||
|     'build/common.gypi', |     '../../build/common.gypi', | ||||||
|   ], |   ], | ||||||
|   'targets': [ |   'targets': [ | ||||||
|  |     { | ||||||
|  |       'target_name': 'build_all', | ||||||
|  |       'type': 'none', | ||||||
|  |       'dependencies': [ | ||||||
|  |         './crash_generation/crash_generation.gyp:*', | ||||||
|  |         './handler/exception_handler.gyp:*', | ||||||
|  |         './sender/crash_report_sender.gyp:*', | ||||||
|  |         './unittests/client_tests.gyp:*', | ||||||
|  |         './unittests/testing.gyp:*', | ||||||
|  |         './tests/crash_generation_app/crash_generation_app.gyp:*', | ||||||
|  |       ] | ||||||
|  |     }, | ||||||
|     { |     { | ||||||
|       'target_name': 'common', |       'target_name': 'common', | ||||||
|       'type': 'static_library', |       'type': 'static_library', | ||||||
|  | |||||||
| @ -1,15 +0,0 @@ | |||||||
| { |  | ||||||
|   'msvs_settings': { |  | ||||||
|     'VCCLCompilerTool': { |  | ||||||
|       'Optimization': '2', |  | ||||||
|       'StringPooling': 'true', |  | ||||||
|       'OmitFramePointers': 'true', |  | ||||||
|     }, |  | ||||||
|     'VCLinkerTool': { |  | ||||||
|       'LinkIncremental': '1', |  | ||||||
|       'OptimizeReferences': '2', |  | ||||||
|       'EnableCOMDATFolding': '2', |  | ||||||
|       'OptimizeForWindows98': '1', |  | ||||||
|     }, |  | ||||||
|   }, |  | ||||||
| } |  | ||||||
| @ -1,3 +0,0 @@ | |||||||
| { |  | ||||||
|   'includes': ['release_defaults.gypi'], |  | ||||||
| } |  | ||||||
| @ -1,21 +0,0 @@ | |||||||
| { |  | ||||||
|   'includes': ['release_defaults.gypi'], |  | ||||||
|   'defines': ['OFFICIAL_BUILD'], |  | ||||||
|   'msvs_settings': { |  | ||||||
|     'VCCLCompilerTool': { |  | ||||||
|       'Optimization': '3', |  | ||||||
|       'InlineFunctionExpansion': '2', |  | ||||||
|       'EnableIntrinsicFunctions': 'true', |  | ||||||
|       'FavorSizeOrSpeed': '2', |  | ||||||
|       'OmitFramePointers': 'true', |  | ||||||
|       'EnableFiberSafeOptimizations': 'true', |  | ||||||
|       'WholeProgramOptimization': 'true', |  | ||||||
|     }, |  | ||||||
|     'VCLibrarianTool': { |  | ||||||
|       'AdditionalOptions': ['/ltcg', '/expectedoutputsize:120000000'], |  | ||||||
|     }, |  | ||||||
|     'VCLinkerTool': { |  | ||||||
|       'LinkTimeCodeGeneration': '1', |  | ||||||
|     }, |  | ||||||
|   }, |  | ||||||
| } |  | ||||||
| @ -1,19 +0,0 @@ | |||||||
| { |  | ||||||
|   'conditions': [ |  | ||||||
|     # Handle build types. |  | ||||||
|     ['buildtype=="Dev"', { |  | ||||||
|       'includes': ['internal/release_impl.gypi'], |  | ||||||
|     }], |  | ||||||
|     ['buildtype=="Official"', { |  | ||||||
|       'includes': ['internal/release_impl_official.gypi'], |  | ||||||
|     }], |  | ||||||
|     # TODO(bradnelson): may also need: |  | ||||||
|     #     checksenabled |  | ||||||
|     #     coverage |  | ||||||
|     #     dom_stats |  | ||||||
|     #     pgo_instrument |  | ||||||
|     #     pgo_optimize |  | ||||||
|     #     purify |  | ||||||
|   ], |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| @ -30,7 +30,7 @@ | |||||||
| #ifndef CLIENT_WINDOWS_COMMON_AUTO_CRITICAL_SECTION_H__ | #ifndef CLIENT_WINDOWS_COMMON_AUTO_CRITICAL_SECTION_H__ | ||||||
| #define CLIENT_WINDOWS_COMMON_AUTO_CRITICAL_SECTION_H__ | #define CLIENT_WINDOWS_COMMON_AUTO_CRITICAL_SECTION_H__ | ||||||
| 
 | 
 | ||||||
| #include <Windows.h> | #include <windows.h> | ||||||
| 
 | 
 | ||||||
| namespace google_breakpad { | namespace google_breakpad { | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -30,8 +30,8 @@ | |||||||
| #ifndef CLIENT_WINDOWS_COMMON_IPC_PROTOCOL_H__ | #ifndef CLIENT_WINDOWS_COMMON_IPC_PROTOCOL_H__ | ||||||
| #define CLIENT_WINDOWS_COMMON_IPC_PROTOCOL_H__ | #define CLIENT_WINDOWS_COMMON_IPC_PROTOCOL_H__ | ||||||
| 
 | 
 | ||||||
| #include <Windows.h> | #include <windows.h> | ||||||
| #include <DbgHelp.h> | #include <dbghelp.h> | ||||||
| #include <string> | #include <string> | ||||||
| #include <utility> | #include <utility> | ||||||
| #include "common/windows/string_utils-inl.h" | #include "common/windows/string_utils-inl.h" | ||||||
|  | |||||||
| @ -67,8 +67,10 @@ bool ClientInfo::Initialize() { | |||||||
|   // The crash_id will be the low order word of the process creation time.
 |   // The crash_id will be the low order word of the process creation time.
 | ||||||
|   FILETIME creation_time, exit_time, kernel_time, user_time; |   FILETIME creation_time, exit_time, kernel_time, user_time; | ||||||
|   if (GetProcessTimes(process_handle_, &creation_time, &exit_time, |   if (GetProcessTimes(process_handle_, &creation_time, &exit_time, | ||||||
|                       &kernel_time, &user_time)) |                       &kernel_time, &user_time)) { | ||||||
|     crash_id_ = creation_time.dwLowDateTime; |     start_time_ = creation_time; | ||||||
|  |   } | ||||||
|  |   crash_id_ = start_time_.dwLowDateTime; | ||||||
| 
 | 
 | ||||||
|   dump_requested_handle_ = CreateEvent(NULL,    // Security attributes.
 |   dump_requested_handle_ = CreateEvent(NULL,    // Security attributes.
 | ||||||
|                                        TRUE,    // Manual reset.
 |                                        TRUE,    // Manual reset.
 | ||||||
| @ -206,7 +208,7 @@ bool ClientInfo::PopulateCustomInfo() { | |||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   SetProcessUptime(); |   SetProcessUptime(); | ||||||
|   return (bytes_count != read_count); |   return (bytes_count == read_count); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| CustomClientInfo ClientInfo::GetCustomInfo() const { | CustomClientInfo ClientInfo::GetCustomInfo() const { | ||||||
|  | |||||||
| @ -30,8 +30,8 @@ | |||||||
| #ifndef CLIENT_WINDOWS_CRASH_GENERATION_CLIENT_INFO_H__ | #ifndef CLIENT_WINDOWS_CRASH_GENERATION_CLIENT_INFO_H__ | ||||||
| #define CLIENT_WINDOWS_CRASH_GENERATION_CLIENT_INFO_H__ | #define CLIENT_WINDOWS_CRASH_GENERATION_CLIENT_INFO_H__ | ||||||
| 
 | 
 | ||||||
| #include <Windows.h> | #include <windows.h> | ||||||
| #include <DbgHelp.h> | #include <dbghelp.h> | ||||||
| #include "client/windows/common/ipc_protocol.h" | #include "client/windows/common/ipc_protocol.h" | ||||||
| #include "common/scoped_ptr.h" | #include "common/scoped_ptr.h" | ||||||
| #include "google_breakpad/common/minidump_format.h" | #include "google_breakpad/common/minidump_format.h" | ||||||
| @ -66,6 +66,9 @@ class ClientInfo { | |||||||
|   HANDLE dump_requested_handle() const { return dump_requested_handle_; } |   HANDLE dump_requested_handle() const { return dump_requested_handle_; } | ||||||
|   HANDLE dump_generated_handle() const { return dump_generated_handle_; } |   HANDLE dump_generated_handle() const { return dump_generated_handle_; } | ||||||
|   DWORD crash_id() const { return crash_id_; } |   DWORD crash_id() const { return crash_id_; } | ||||||
|  |   const CustomClientInfo& custom_client_info() const { | ||||||
|  |     return custom_client_info_; | ||||||
|  |   } | ||||||
| 
 | 
 | ||||||
|   void set_dump_request_wait_handle(HANDLE value) { |   void set_dump_request_wait_handle(HANDLE value) { | ||||||
|     dump_request_wait_handle_ = value; |     dump_request_wait_handle_ = value; | ||||||
|  | |||||||
| @ -1,5 +1,4 @@ | |||||||
| # Copyright (c) 2010, Google Inc. | # Copyright 2010 Google Inc. All rights reserved. | ||||||
| # All rights reserved. |  | ||||||
| # | # | ||||||
| # Redistribution and use in source and binary forms, with or without | # Redistribution and use in source and binary forms, with or without | ||||||
| # modification, are permitted provided that the following conditions are | # modification, are permitted provided that the following conditions are | ||||||
| @ -29,7 +28,7 @@ | |||||||
| 
 | 
 | ||||||
| { | { | ||||||
|   'includes': [ |   'includes': [ | ||||||
|     '../build/common.gypi', |     '../../../build/common.gypi', | ||||||
|   ], |   ], | ||||||
|   'targets': [ |   'targets': [ | ||||||
|     { |     { | ||||||
|  | |||||||
| @ -85,6 +85,15 @@ static bool IsClientRequestValid(const ProtocolMessage& msg) { | |||||||
|           msg.assert_info != NULL); |           msg.assert_info != NULL); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | #ifdef _DEBUG | ||||||
|  | static bool CheckForIOIncomplete(bool success) { | ||||||
|  |   // We should never get an I/O incomplete since we should not execute this
 | ||||||
|  |   // unless the operation has finished and the overlapped event is signaled. If
 | ||||||
|  |   // we do get INCOMPLETE, we have a bug in our code.
 | ||||||
|  |   return success ? false : (GetLastError() == ERROR_IO_INCOMPLETE); | ||||||
|  | } | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
| CrashGenerationServer::CrashGenerationServer( | CrashGenerationServer::CrashGenerationServer( | ||||||
|     const std::wstring& pipe_name, |     const std::wstring& pipe_name, | ||||||
|     SECURITY_ATTRIBUTES* pipe_sec_attrs, |     SECURITY_ATTRIBUTES* pipe_sec_attrs, | ||||||
| @ -112,16 +121,13 @@ CrashGenerationServer::CrashGenerationServer( | |||||||
|       upload_request_callback_(upload_request_callback), |       upload_request_callback_(upload_request_callback), | ||||||
|       upload_context_(upload_context), |       upload_context_(upload_context), | ||||||
|       generate_dumps_(generate_dumps), |       generate_dumps_(generate_dumps), | ||||||
|       dump_generator_(NULL), |       dump_path_(dump_path ? *dump_path : L""), | ||||||
|       server_state_(IPC_SERVER_STATE_UNINITIALIZED), |       server_state_(IPC_SERVER_STATE_UNINITIALIZED), | ||||||
|       shutting_down_(false), |       shutting_down_(false), | ||||||
|       overlapped_(), |       overlapped_(), | ||||||
|       client_info_(NULL) { |       client_info_(NULL), | ||||||
|  |       pre_fetch_custom_info_(true) { | ||||||
|   InitializeCriticalSection(&sync_); |   InitializeCriticalSection(&sync_); | ||||||
| 
 |  | ||||||
|   if (dump_path) { |  | ||||||
|     dump_generator_.reset(new MinidumpGenerator(*dump_path)); |  | ||||||
|   } |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // This should never be called from the OnPipeConnected callback.
 | // This should never be called from the OnPipeConnected callback.
 | ||||||
| @ -387,18 +393,13 @@ void CrashGenerationServer::HandleReadingState() { | |||||||
|                                      &overlapped_, |                                      &overlapped_, | ||||||
|                                      &bytes_count, |                                      &bytes_count, | ||||||
|                                      FALSE) != FALSE; |                                      FALSE) != FALSE; | ||||||
|   DWORD error_code = success ? ERROR_SUCCESS : GetLastError(); |  | ||||||
| 
 |  | ||||||
|   if (success && bytes_count == sizeof(ProtocolMessage)) { |   if (success && bytes_count == sizeof(ProtocolMessage)) { | ||||||
|     EnterStateImmediately(IPC_SERVER_STATE_READ_DONE); |     EnterStateImmediately(IPC_SERVER_STATE_READ_DONE); | ||||||
|   } else { |     return; | ||||||
|     // We should never get an I/O incomplete since we should not execute this
 |  | ||||||
|     // unless the Read has finished and the overlapped event is signaled. If
 |  | ||||||
|     // we do get INCOMPLETE, we have a bug in our code.
 |  | ||||||
|     assert(error_code != ERROR_IO_INCOMPLETE); |  | ||||||
| 
 |  | ||||||
|     EnterStateImmediately(IPC_SERVER_STATE_DISCONNECTING); |  | ||||||
|   } |   } | ||||||
|  | 
 | ||||||
|  |   assert(!CheckForIOIncomplete(success)); | ||||||
|  |   EnterStateImmediately(IPC_SERVER_STATE_DISCONNECTING); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // When the server thread serving the client is in the READ_DONE state,
 | // When the server thread serving the client is in the READ_DONE state,
 | ||||||
| @ -467,18 +468,12 @@ void CrashGenerationServer::HandleWritingState() { | |||||||
|                                      &overlapped_, |                                      &overlapped_, | ||||||
|                                      &bytes_count, |                                      &bytes_count, | ||||||
|                                      FALSE) != FALSE; |                                      FALSE) != FALSE; | ||||||
|   DWORD error_code = success ? ERROR_SUCCESS : GetLastError(); |  | ||||||
| 
 |  | ||||||
|   if (success) { |   if (success) { | ||||||
|     EnterStateImmediately(IPC_SERVER_STATE_WRITE_DONE); |     EnterStateImmediately(IPC_SERVER_STATE_WRITE_DONE); | ||||||
|     return; |     return; | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   // We should never get an I/O incomplete since we should not execute this
 |   assert(!CheckForIOIncomplete(success)); | ||||||
|   // unless the Write has finished and the overlapped event is signaled. If
 |  | ||||||
|   // we do get INCOMPLETE, we have a bug in our code.
 |  | ||||||
|   assert(error_code != ERROR_IO_INCOMPLETE); |  | ||||||
| 
 |  | ||||||
|   EnterStateImmediately(IPC_SERVER_STATE_DISCONNECTING); |   EnterStateImmediately(IPC_SERVER_STATE_DISCONNECTING); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -516,8 +511,6 @@ void CrashGenerationServer::HandleReadingAckState() { | |||||||
|                                      &overlapped_, |                                      &overlapped_, | ||||||
|                                      &bytes_count, |                                      &bytes_count, | ||||||
|                                      FALSE) != FALSE; |                                      FALSE) != FALSE; | ||||||
|   DWORD error_code = success ? ERROR_SUCCESS : GetLastError(); |  | ||||||
| 
 |  | ||||||
|   if (success) { |   if (success) { | ||||||
|     // The connection handshake with the client is now complete; perform
 |     // The connection handshake with the client is now complete; perform
 | ||||||
|     // the callback.
 |     // the callback.
 | ||||||
| @ -550,10 +543,7 @@ void CrashGenerationServer::HandleReadingAckState() { | |||||||
|       } |       } | ||||||
|     } |     } | ||||||
|   } else { |   } else { | ||||||
|     // We should never get an I/O incomplete since we should not execute this
 |     assert(!CheckForIOIncomplete(success)); | ||||||
|     // unless the Read has finished and the overlapped event is signaled. If
 |  | ||||||
|     // we do get INCOMPLETE, we have a bug in our code.
 |  | ||||||
|     assert(error_code != ERROR_IO_INCOMPLETE); |  | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   EnterStateImmediately(IPC_SERVER_STATE_DISCONNECTING); |   EnterStateImmediately(IPC_SERVER_STATE_DISCONNECTING); | ||||||
| @ -831,10 +821,12 @@ void CALLBACK CrashGenerationServer::OnPipeConnected(void* context, BOOLEAN) { | |||||||
| void CALLBACK CrashGenerationServer::OnDumpRequest(void* context, BOOLEAN) { | void CALLBACK CrashGenerationServer::OnDumpRequest(void* context, BOOLEAN) { | ||||||
|   assert(context); |   assert(context); | ||||||
|   ClientInfo* client_info = reinterpret_cast<ClientInfo*>(context); |   ClientInfo* client_info = reinterpret_cast<ClientInfo*>(context); | ||||||
|   client_info->PopulateCustomInfo(); |  | ||||||
| 
 | 
 | ||||||
|   CrashGenerationServer* crash_server = client_info->crash_server(); |   CrashGenerationServer* crash_server = client_info->crash_server(); | ||||||
|   assert(crash_server); |   assert(crash_server); | ||||||
|  |   if (crash_server->pre_fetch_custom_info_) { | ||||||
|  |     client_info->PopulateCustomInfo(); | ||||||
|  |   } | ||||||
|   crash_server->HandleDumpRequest(*client_info); |   crash_server->HandleDumpRequest(*client_info); | ||||||
| 
 | 
 | ||||||
|   ResetEvent(client_info->dump_requested_handle()); |   ResetEvent(client_info->dump_requested_handle()); | ||||||
| @ -921,15 +913,19 @@ bool CrashGenerationServer::GenerateDump(const ClientInfo& client, | |||||||
|     return false; |     return false; | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   return dump_generator_->WriteMinidump(client.process_handle(), |   MinidumpGenerator dump_generator(dump_path_, | ||||||
|  |                                    client.process_handle(), | ||||||
|                                    client.pid(), |                                    client.pid(), | ||||||
|                                    client_thread_id, |                                    client_thread_id, | ||||||
|                                    GetCurrentThreadId(), |                                    GetCurrentThreadId(), | ||||||
|                                    client_ex_info, |                                    client_ex_info, | ||||||
|                                    client.assert_info(), |                                    client.assert_info(), | ||||||
|                                    client.dump_type(), |                                    client.dump_type(), | ||||||
|                                         true, |                                    true); | ||||||
|                                         dump_path); |   if (!dump_generator.GenerateDumpFile(dump_path)) { | ||||||
|  |     return false; | ||||||
|  |   } | ||||||
|  |   return dump_generator.WriteMinidump(); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| }  // namespace google_breakpad
 | }  // namespace google_breakpad
 | ||||||
|  | |||||||
| @ -102,6 +102,10 @@ class CrashGenerationServer { | |||||||
|   // Returns true if initialization is successful; false otherwise.
 |   // Returns true if initialization is successful; false otherwise.
 | ||||||
|   bool Start(); |   bool Start(); | ||||||
| 
 | 
 | ||||||
|  |   void pre_fetch_custom_info(bool do_pre_fetch) { | ||||||
|  |     pre_fetch_custom_info_ = do_pre_fetch; | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  private: |  private: | ||||||
|   // Various states the client can be in during the handshake with
 |   // Various states the client can be in during the handshake with
 | ||||||
|   // the server.
 |   // the server.
 | ||||||
| @ -261,8 +265,11 @@ class CrashGenerationServer { | |||||||
|   // Whether to generate dumps.
 |   // Whether to generate dumps.
 | ||||||
|   bool generate_dumps_; |   bool generate_dumps_; | ||||||
| 
 | 
 | ||||||
|   // Instance of a mini dump generator.
 |   // Wether to populate custom information up-front.
 | ||||||
|   scoped_ptr<MinidumpGenerator> dump_generator_; |   bool pre_fetch_custom_info_; | ||||||
|  | 
 | ||||||
|  |   // The dump path for the server.
 | ||||||
|  |   const std::wstring dump_path_; | ||||||
| 
 | 
 | ||||||
|   // State of the server in performing the IPC with the client.
 |   // State of the server in performing the IPC with the client.
 | ||||||
|   // Note that since we restrict the pipe to one instance, we
 |   // Note that since we restrict the pipe to one instance, we
 | ||||||
|  | |||||||
| @ -38,6 +38,7 @@ | |||||||
| #include <vector> | #include <vector> | ||||||
| 
 | 
 | ||||||
| #include "client/windows/common/auto_critical_section.h" | #include "client/windows/common/auto_critical_section.h" | ||||||
|  | #include "common/scoped_ptr.h" | ||||||
| #include "common/windows/guid_string.h" | #include "common/windows/guid_string.h" | ||||||
| 
 | 
 | ||||||
| using std::wstring; | using std::wstring; | ||||||
| @ -175,9 +176,14 @@ bool HandleTraceData::CollectHandleData( | |||||||
|   stream_data->Reserved = 0; |   stream_data->Reserved = 0; | ||||||
|   std::copy(operations_.begin(), |   std::copy(operations_.begin(), | ||||||
|             operations_.end(), |             operations_.end(), | ||||||
|  | #ifdef _MSC_VER | ||||||
|             stdext::checked_array_iterator<AVRF_HANDLE_OPERATION*>( |             stdext::checked_array_iterator<AVRF_HANDLE_OPERATION*>( | ||||||
|                 reinterpret_cast<AVRF_HANDLE_OPERATION*>(stream_data + 1), |                 reinterpret_cast<AVRF_HANDLE_OPERATION*>(stream_data + 1), | ||||||
|                 operations_.size())); |                 operations_.size()) | ||||||
|  | #else | ||||||
|  |             reinterpret_cast<AVRF_HANDLE_OPERATION*>(stream_data + 1) | ||||||
|  | #endif | ||||||
|  |             ); | ||||||
| 
 | 
 | ||||||
|   return true; |   return true; | ||||||
| } | } | ||||||
| @ -242,10 +248,33 @@ ULONG CALLBACK HandleTraceData::RecordHandleOperations( | |||||||
| 
 | 
 | ||||||
| namespace google_breakpad { | namespace google_breakpad { | ||||||
| 
 | 
 | ||||||
| MinidumpGenerator::MinidumpGenerator(const wstring& dump_path) | MinidumpGenerator::MinidumpGenerator( | ||||||
|  |     const std::wstring& dump_path, | ||||||
|  |     const HANDLE process_handle, | ||||||
|  |     const DWORD process_id, | ||||||
|  |     const DWORD thread_id, | ||||||
|  |     const DWORD requesting_thread_id, | ||||||
|  |     EXCEPTION_POINTERS* exception_pointers, | ||||||
|  |     MDRawAssertionInfo* assert_info, | ||||||
|  |     const MINIDUMP_TYPE dump_type, | ||||||
|  |     const bool is_client_pointers) | ||||||
|     : dbghelp_module_(NULL), |     : dbghelp_module_(NULL), | ||||||
|       rpcrt4_module_(NULL), |       rpcrt4_module_(NULL), | ||||||
|       dump_path_(dump_path), |       dump_path_(dump_path), | ||||||
|  |       process_handle_(process_handle), | ||||||
|  |       process_id_(process_id), | ||||||
|  |       thread_id_(thread_id), | ||||||
|  |       requesting_thread_id_(requesting_thread_id), | ||||||
|  |       exception_pointers_(exception_pointers), | ||||||
|  |       assert_info_(assert_info), | ||||||
|  |       dump_type_(dump_type), | ||||||
|  |       is_client_pointers_(is_client_pointers), | ||||||
|  |       dump_file_(INVALID_HANDLE_VALUE), | ||||||
|  |       full_dump_file_(INVALID_HANDLE_VALUE), | ||||||
|  |       dump_file_is_internal_(false), | ||||||
|  |       full_dump_file_is_internal_(false), | ||||||
|  |       additional_streams_(NULL), | ||||||
|  |       callback_info_(NULL), | ||||||
|       write_dump_(NULL), |       write_dump_(NULL), | ||||||
|       create_uuid_(NULL) { |       create_uuid_(NULL) { | ||||||
|   InitializeCriticalSection(&module_load_sync_); |   InitializeCriticalSection(&module_load_sync_); | ||||||
| @ -253,6 +282,14 @@ MinidumpGenerator::MinidumpGenerator(const wstring& dump_path) | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| MinidumpGenerator::~MinidumpGenerator() { | MinidumpGenerator::~MinidumpGenerator() { | ||||||
|  |   if (dump_file_is_internal_ && dump_file_ != INVALID_HANDLE_VALUE) { | ||||||
|  |     CloseHandle(dump_file_); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   if (full_dump_file_is_internal_ && full_dump_file_ != INVALID_HANDLE_VALUE) { | ||||||
|  |     CloseHandle(full_dump_file_); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|   if (dbghelp_module_) { |   if (dbghelp_module_) { | ||||||
|     FreeLibrary(dbghelp_module_); |     FreeLibrary(dbghelp_module_); | ||||||
|   } |   } | ||||||
| @ -265,91 +302,28 @@ MinidumpGenerator::~MinidumpGenerator() { | |||||||
|   DeleteCriticalSection(&module_load_sync_); |   DeleteCriticalSection(&module_load_sync_); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| bool MinidumpGenerator::WriteMinidump(HANDLE process_handle, | bool MinidumpGenerator::WriteMinidump() { | ||||||
|                                       DWORD process_id, |   bool full_memory_dump = (dump_type_ & MiniDumpWithFullMemory) != 0; | ||||||
|                                       DWORD thread_id, |   if (dump_file_ == INVALID_HANDLE_VALUE || | ||||||
|                                       DWORD requesting_thread_id, |       (full_memory_dump && full_dump_file_ == INVALID_HANDLE_VALUE)) { | ||||||
|                                       EXCEPTION_POINTERS* exception_pointers, |     return false; | ||||||
|                                       MDRawAssertionInfo* assert_info, |  | ||||||
|                                       MINIDUMP_TYPE dump_type, |  | ||||||
|                                       bool is_client_pointers, |  | ||||||
|                                       wstring* dump_path) { |  | ||||||
|   // Just call the full WriteMinidump with NULL as the full_dump_path.
 |  | ||||||
|   return this->WriteMinidump(process_handle, process_id, thread_id, |  | ||||||
|                              requesting_thread_id, exception_pointers, |  | ||||||
|                              assert_info, dump_type, is_client_pointers, |  | ||||||
|                              dump_path, NULL); |  | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
| bool MinidumpGenerator::WriteMinidump(HANDLE process_handle, |  | ||||||
|                                       DWORD process_id, |  | ||||||
|                                       DWORD thread_id, |  | ||||||
|                                       DWORD requesting_thread_id, |  | ||||||
|                                       EXCEPTION_POINTERS* exception_pointers, |  | ||||||
|                                       MDRawAssertionInfo* assert_info, |  | ||||||
|                                       MINIDUMP_TYPE dump_type, |  | ||||||
|                                       bool is_client_pointers, |  | ||||||
|                                       wstring* dump_path, |  | ||||||
|                                       wstring* full_dump_path) { |  | ||||||
|   MiniDumpWriteDumpType write_dump = GetWriteDump(); |   MiniDumpWriteDumpType write_dump = GetWriteDump(); | ||||||
|   if (!write_dump) { |   if (!write_dump) { | ||||||
|     return false; |     return false; | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   wstring dump_file_path; |  | ||||||
|   if (!GenerateDumpFilePath(&dump_file_path)) { |  | ||||||
|     return false; |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   // If the client requests a full memory dump, we will write a normal mini
 |  | ||||||
|   // dump and a full memory dump. Both dump files use the same uuid as file
 |  | ||||||
|   // name prefix.
 |  | ||||||
|   bool full_memory_dump = (dump_type & MiniDumpWithFullMemory) != 0; |  | ||||||
|   wstring full_dump_file_path; |  | ||||||
|   if (full_memory_dump) { |  | ||||||
|     full_dump_file_path.assign(dump_file_path); |  | ||||||
|     full_dump_file_path.resize(full_dump_file_path.size() - 4);  // strip .dmp
 |  | ||||||
|     full_dump_file_path.append(TEXT("-full.dmp")); |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   HANDLE dump_file = CreateFile(dump_file_path.c_str(), |  | ||||||
|                                 GENERIC_WRITE, |  | ||||||
|                                 0, |  | ||||||
|                                 NULL, |  | ||||||
|                                 CREATE_NEW, |  | ||||||
|                                 FILE_ATTRIBUTE_NORMAL, |  | ||||||
|                                 NULL); |  | ||||||
| 
 |  | ||||||
|   if (dump_file == INVALID_HANDLE_VALUE) { |  | ||||||
|     return false; |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   HANDLE full_dump_file = INVALID_HANDLE_VALUE; |  | ||||||
|   if (full_memory_dump) { |  | ||||||
|     full_dump_file = CreateFile(full_dump_file_path.c_str(), |  | ||||||
|                                 GENERIC_WRITE, |  | ||||||
|                                 0, |  | ||||||
|                                 NULL, |  | ||||||
|                                 CREATE_NEW, |  | ||||||
|                                 FILE_ATTRIBUTE_NORMAL, |  | ||||||
|                                 NULL); |  | ||||||
| 
 |  | ||||||
|     if (full_dump_file == INVALID_HANDLE_VALUE) { |  | ||||||
|       CloseHandle(dump_file); |  | ||||||
|       return false; |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   MINIDUMP_EXCEPTION_INFORMATION* dump_exception_pointers = NULL; |   MINIDUMP_EXCEPTION_INFORMATION* dump_exception_pointers = NULL; | ||||||
|   MINIDUMP_EXCEPTION_INFORMATION dump_exception_info; |   MINIDUMP_EXCEPTION_INFORMATION dump_exception_info; | ||||||
| 
 | 
 | ||||||
|   // Setup the exception information object only if it's a dump
 |   // Setup the exception information object only if it's a dump
 | ||||||
|   // due to an exception.
 |   // due to an exception.
 | ||||||
|   if (exception_pointers) { |   if (exception_pointers_) { | ||||||
|     dump_exception_pointers = &dump_exception_info; |     dump_exception_pointers = &dump_exception_info; | ||||||
|     dump_exception_info.ThreadId = thread_id; |     dump_exception_info.ThreadId = thread_id_; | ||||||
|     dump_exception_info.ExceptionPointers = exception_pointers; |     dump_exception_info.ExceptionPointers = exception_pointers_; | ||||||
|     dump_exception_info.ClientPointers = is_client_pointers; |     dump_exception_info.ClientPointers = is_client_pointers_; | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   // Add an MDRawBreakpadInfo stream to the minidump, to provide additional
 |   // Add an MDRawBreakpadInfo stream to the minidump, to provide additional
 | ||||||
| @ -359,49 +333,54 @@ bool MinidumpGenerator::WriteMinidump(HANDLE process_handle, | |||||||
|   // can function better with Breakpad-generated dumps when it is present.
 |   // can function better with Breakpad-generated dumps when it is present.
 | ||||||
|   // The native debugger is not harmed by the presence of this information.
 |   // The native debugger is not harmed by the presence of this information.
 | ||||||
|   MDRawBreakpadInfo breakpad_info = {0}; |   MDRawBreakpadInfo breakpad_info = {0}; | ||||||
|   if (!is_client_pointers) { |   if (!is_client_pointers_) { | ||||||
|     // Set the dump thread id and requesting thread id only in case of
 |     // Set the dump thread id and requesting thread id only in case of
 | ||||||
|     // in-process dump generation.
 |     // in-process dump generation.
 | ||||||
|     breakpad_info.validity = MD_BREAKPAD_INFO_VALID_DUMP_THREAD_ID | |     breakpad_info.validity = MD_BREAKPAD_INFO_VALID_DUMP_THREAD_ID | | ||||||
|                              MD_BREAKPAD_INFO_VALID_REQUESTING_THREAD_ID; |                              MD_BREAKPAD_INFO_VALID_REQUESTING_THREAD_ID; | ||||||
|     breakpad_info.dump_thread_id = thread_id; |     breakpad_info.dump_thread_id = thread_id_; | ||||||
|     breakpad_info.requesting_thread_id = requesting_thread_id; |     breakpad_info.requesting_thread_id = requesting_thread_id_; | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   // Leave room in user_stream_array for possible assertion info and handle
 |   int additional_streams_count = additional_streams_ ? | ||||||
|   // operations streams.
 |       additional_streams_->UserStreamCount : 0; | ||||||
|   MINIDUMP_USER_STREAM user_stream_array[3]; |   scoped_array<MINIDUMP_USER_STREAM> user_stream_array( | ||||||
|  |       new MINIDUMP_USER_STREAM[3 + additional_streams_count]); | ||||||
|   user_stream_array[0].Type = MD_BREAKPAD_INFO_STREAM; |   user_stream_array[0].Type = MD_BREAKPAD_INFO_STREAM; | ||||||
|   user_stream_array[0].BufferSize = sizeof(breakpad_info); |   user_stream_array[0].BufferSize = sizeof(breakpad_info); | ||||||
|   user_stream_array[0].Buffer = &breakpad_info; |   user_stream_array[0].Buffer = &breakpad_info; | ||||||
| 
 | 
 | ||||||
|   MINIDUMP_USER_STREAM_INFORMATION user_streams; |   MINIDUMP_USER_STREAM_INFORMATION user_streams; | ||||||
|   user_streams.UserStreamCount = 1; |   user_streams.UserStreamCount = 1; | ||||||
|   user_streams.UserStreamArray = user_stream_array; |   user_streams.UserStreamArray = user_stream_array.get(); | ||||||
| 
 | 
 | ||||||
|   MDRawAssertionInfo* actual_assert_info = assert_info; |   MDRawAssertionInfo* actual_assert_info = assert_info_; | ||||||
|   MDRawAssertionInfo client_assert_info = {0}; |   MDRawAssertionInfo client_assert_info = {{0}}; | ||||||
| 
 | 
 | ||||||
|   if (assert_info) { |   if (assert_info_) { | ||||||
|     // If the assertion info object lives in the client process,
 |     // If the assertion info object lives in the client process,
 | ||||||
|     // read the memory of the client process.
 |     // read the memory of the client process.
 | ||||||
|     if (is_client_pointers) { |     if (is_client_pointers_) { | ||||||
|       SIZE_T bytes_read = 0; |       SIZE_T bytes_read = 0; | ||||||
|       if (!ReadProcessMemory(process_handle, |       if (!ReadProcessMemory(process_handle_, | ||||||
|                              assert_info, |                              assert_info_, | ||||||
|                              &client_assert_info, |                              &client_assert_info, | ||||||
|                              sizeof(client_assert_info), |                              sizeof(client_assert_info), | ||||||
|                              &bytes_read)) { |                              &bytes_read)) { | ||||||
|         CloseHandle(dump_file); |         if (dump_file_is_internal_) | ||||||
|         if (full_dump_file != INVALID_HANDLE_VALUE) |           CloseHandle(dump_file_); | ||||||
|           CloseHandle(full_dump_file); |         if (full_dump_file_is_internal_ && | ||||||
|  |             full_dump_file_ != INVALID_HANDLE_VALUE) | ||||||
|  |           CloseHandle(full_dump_file_); | ||||||
|         return false; |         return false; | ||||||
|       } |       } | ||||||
| 
 | 
 | ||||||
|       if (bytes_read != sizeof(client_assert_info)) { |       if (bytes_read != sizeof(client_assert_info)) { | ||||||
|         CloseHandle(dump_file); |         if (dump_file_is_internal_) | ||||||
|         if (full_dump_file != INVALID_HANDLE_VALUE) |           CloseHandle(dump_file_); | ||||||
|           CloseHandle(full_dump_file); |         if (full_dump_file_is_internal_ && | ||||||
|  |             full_dump_file_ != INVALID_HANDLE_VALUE) | ||||||
|  |           CloseHandle(full_dump_file_); | ||||||
|         return false; |         return false; | ||||||
|       } |       } | ||||||
| 
 | 
 | ||||||
| @ -414,16 +393,31 @@ bool MinidumpGenerator::WriteMinidump(HANDLE process_handle, | |||||||
|     ++user_streams.UserStreamCount; |     ++user_streams.UserStreamCount; | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|  |   if (additional_streams_) { | ||||||
|  |     for (size_t i = 0; | ||||||
|  |          i < additional_streams_->UserStreamCount; | ||||||
|  |          i++, user_streams.UserStreamCount++) { | ||||||
|  |       user_stream_array[user_streams.UserStreamCount].Type = | ||||||
|  |           additional_streams_->UserStreamArray[i].Type; | ||||||
|  |       user_stream_array[user_streams.UserStreamCount].BufferSize = | ||||||
|  |           additional_streams_->UserStreamArray[i].BufferSize; | ||||||
|  |       user_stream_array[user_streams.UserStreamCount].Buffer = | ||||||
|  |           additional_streams_->UserStreamArray[i].Buffer; | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|   // If the process is terminated by STATUS_INVALID_HANDLE exception store
 |   // If the process is terminated by STATUS_INVALID_HANDLE exception store
 | ||||||
|   // the trace of operatios for the offending handle value. Do nothing special
 |   // the trace of operations for the offending handle value. Do nothing special
 | ||||||
|   // if the client already requested the handle trace to be stored in the dump.
 |   // if the client already requested the handle trace to be stored in the dump.
 | ||||||
|   HandleTraceData handle_trace_data; |   HandleTraceData handle_trace_data; | ||||||
|   if (exception_pointers && (dump_type & MiniDumpWithHandleData) == 0) { |   if (exception_pointers_ && (dump_type_ & MiniDumpWithHandleData) == 0) { | ||||||
|     if (!handle_trace_data.CollectHandleData(process_handle, |     if (!handle_trace_data.CollectHandleData(process_handle_, | ||||||
|                                              exception_pointers)) { |                                              exception_pointers_)) { | ||||||
|       CloseHandle(dump_file); |       if (dump_file_is_internal_) | ||||||
|       if (full_dump_file != INVALID_HANDLE_VALUE) |         CloseHandle(dump_file_); | ||||||
|         CloseHandle(full_dump_file); |       if (full_dump_file_is_internal_ && | ||||||
|  |           full_dump_file_ != INVALID_HANDLE_VALUE) | ||||||
|  |         CloseHandle(full_dump_file_); | ||||||
|       return false; |       return false; | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
| @ -431,12 +425,12 @@ bool MinidumpGenerator::WriteMinidump(HANDLE process_handle, | |||||||
|   bool result_full_memory = true; |   bool result_full_memory = true; | ||||||
|   if (full_memory_dump) { |   if (full_memory_dump) { | ||||||
|     result_full_memory = write_dump( |     result_full_memory = write_dump( | ||||||
|         process_handle, |         process_handle_, | ||||||
|         process_id, |         process_id_, | ||||||
|         full_dump_file, |         full_dump_file_, | ||||||
|         static_cast<MINIDUMP_TYPE>((dump_type & (~MiniDumpNormal)) |         static_cast<MINIDUMP_TYPE>((dump_type_ & (~MiniDumpNormal)) | ||||||
|                                     | MiniDumpWithHandleData), |                                     | MiniDumpWithHandleData), | ||||||
|         exception_pointers ? &dump_exception_info : NULL, |         exception_pointers_ ? &dump_exception_info : NULL, | ||||||
|         &user_streams, |         &user_streams, | ||||||
|         NULL) != FALSE; |         NULL) != FALSE; | ||||||
|   } |   } | ||||||
| @ -448,31 +442,79 @@ bool MinidumpGenerator::WriteMinidump(HANDLE process_handle, | |||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   bool result_minidump = write_dump( |   bool result_minidump = write_dump( | ||||||
|       process_handle, |       process_handle_, | ||||||
|       process_id, |       process_id_, | ||||||
|       dump_file, |       dump_file_, | ||||||
|       static_cast<MINIDUMP_TYPE>((dump_type & (~MiniDumpWithFullMemory)) |       static_cast<MINIDUMP_TYPE>((dump_type_ & (~MiniDumpWithFullMemory)) | ||||||
|                                   | MiniDumpNormal), |                                   | MiniDumpNormal), | ||||||
|       exception_pointers ? &dump_exception_info : NULL, |       exception_pointers_ ? &dump_exception_info : NULL, | ||||||
|       &user_streams, |       &user_streams, | ||||||
|       NULL) != FALSE; |       callback_info_) != FALSE; | ||||||
| 
 | 
 | ||||||
|   bool result = result_minidump && result_full_memory; |   return result_minidump && result_full_memory; | ||||||
|  | } | ||||||
| 
 | 
 | ||||||
|   CloseHandle(dump_file); | bool MinidumpGenerator::GenerateDumpFile(wstring* dump_path) { | ||||||
|   if (full_dump_file != INVALID_HANDLE_VALUE) |   // The dump file was already set by handle or this function was previously
 | ||||||
|     CloseHandle(full_dump_file); |   // called.
 | ||||||
|  |   if (dump_file_ != INVALID_HANDLE_VALUE) { | ||||||
|  |     return false; | ||||||
|  |   } | ||||||
| 
 | 
 | ||||||
|   // Store the path of the dump file in the out parameter if dump generation
 |   wstring dump_file_path; | ||||||
|   // succeeded.
 |   if (!GenerateDumpFilePath(&dump_file_path)) { | ||||||
|   if (result && dump_path) { |     return false; | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   dump_file_ = CreateFile(dump_file_path.c_str(), | ||||||
|  |                           GENERIC_WRITE, | ||||||
|  |                           0, | ||||||
|  |                           NULL, | ||||||
|  |                           CREATE_NEW, | ||||||
|  |                           FILE_ATTRIBUTE_NORMAL, | ||||||
|  |                           NULL); | ||||||
|  |   if (dump_file_ == INVALID_HANDLE_VALUE) { | ||||||
|  |     return false; | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   dump_file_is_internal_ = true; | ||||||
|   *dump_path = dump_file_path; |   *dump_path = dump_file_path; | ||||||
|   } |   return true; | ||||||
|   if (result && full_memory_dump && full_dump_path) { |  | ||||||
|     *full_dump_path = full_dump_file_path; |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|   return result; | bool MinidumpGenerator::GenerateFullDumpFile(wstring* full_dump_path) { | ||||||
|  |   // A full minidump was not requested.
 | ||||||
|  |   if ((dump_type_ & MiniDumpWithFullMemory) == 0) { | ||||||
|  |     return false; | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   // The dump file was already set by handle or this function was previously
 | ||||||
|  |   // called.
 | ||||||
|  |   if (full_dump_file_ != INVALID_HANDLE_VALUE) { | ||||||
|  |     return false; | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   wstring full_dump_file_path; | ||||||
|  |   if (!GenerateDumpFilePath(&full_dump_file_path)) { | ||||||
|  |     return false; | ||||||
|  |   } | ||||||
|  |   full_dump_file_path.resize(full_dump_file_path.size() - 4);  // strip .dmp
 | ||||||
|  |   full_dump_file_path.append(TEXT("-full.dmp")); | ||||||
|  | 
 | ||||||
|  |   full_dump_file_ = CreateFile(full_dump_file_path.c_str(), | ||||||
|  |                                GENERIC_WRITE, | ||||||
|  |                                0, | ||||||
|  |                                NULL, | ||||||
|  |                                CREATE_NEW, | ||||||
|  |                                FILE_ATTRIBUTE_NORMAL, | ||||||
|  |                                NULL); | ||||||
|  |   if (full_dump_file_ == INVALID_HANDLE_VALUE) { | ||||||
|  |     return false; | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   full_dump_file_is_internal_ = true; | ||||||
|  |   *full_dump_path = full_dump_file_path; | ||||||
|  |   return true; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| HMODULE MinidumpGenerator::GetDbghelpModule() { | HMODULE MinidumpGenerator::GetDbghelpModule() { | ||||||
|  | |||||||
| @ -34,6 +34,7 @@ | |||||||
| #include <dbghelp.h> | #include <dbghelp.h> | ||||||
| #include <rpc.h> | #include <rpc.h> | ||||||
| #include <list> | #include <list> | ||||||
|  | #include <string> | ||||||
| #include "google_breakpad/common/minidump_format.h" | #include "google_breakpad/common/minidump_format.h" | ||||||
| 
 | 
 | ||||||
| namespace google_breakpad { | namespace google_breakpad { | ||||||
| @ -44,37 +45,55 @@ namespace google_breakpad { | |||||||
| // the clients to generate minidumps.
 | // the clients to generate minidumps.
 | ||||||
| class MinidumpGenerator { | class MinidumpGenerator { | ||||||
|  public: |  public: | ||||||
|   // Creates an instance with the given dump path.
 |   // Creates an instance with the given parameters.
 | ||||||
|   explicit MinidumpGenerator(const std::wstring& dump_path); |   // is_client_pointers specifies whether the exception_pointers and
 | ||||||
|  |   // assert_info point into the process that is being dumped.
 | ||||||
|  |   // Before calling WriteMinidump on the returned instance a dump file muct be
 | ||||||
|  |   // specified by a call to either SetDumpFile() or GenerateDumpFile().
 | ||||||
|  |   // If a full dump file will be requested via a subsequent call to either
 | ||||||
|  |   // SetFullDumpFile or GenerateFullDumpFile() dump_type must include
 | ||||||
|  |   // MiniDumpWithFullMemory.
 | ||||||
|  |   MinidumpGenerator(const std::wstring& dump_path, | ||||||
|  |                     const HANDLE process_handle, | ||||||
|  |                     const DWORD process_id, | ||||||
|  |                     const DWORD thread_id, | ||||||
|  |                     const DWORD requesting_thread_id, | ||||||
|  |                     EXCEPTION_POINTERS* exception_pointers, | ||||||
|  |                     MDRawAssertionInfo* assert_info, | ||||||
|  |                     const MINIDUMP_TYPE dump_type, | ||||||
|  |                     const bool is_client_pointers); | ||||||
| 
 | 
 | ||||||
|   ~MinidumpGenerator(); |   ~MinidumpGenerator(); | ||||||
| 
 | 
 | ||||||
|  |   void SetDumpFile(const HANDLE dump_file) { dump_file_ = dump_file; } | ||||||
|  |   void SetFullDumpFile(const HANDLE full_dump_file) { | ||||||
|  |     full_dump_file_ = full_dump_file; | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   // Generate the name for the dump file that will be written to once
 | ||||||
|  |   // WriteMinidump() is called. Can only be called once and cannot be called
 | ||||||
|  |   // if the dump file is set via SetDumpFile().
 | ||||||
|  |   bool GenerateDumpFile(std::wstring* dump_path); | ||||||
|  | 
 | ||||||
|  |   // Generate the name for the full dump file that will be written to once
 | ||||||
|  |   // WriteMinidump() is called. Cannot be called unless the minidump type
 | ||||||
|  |   // includes MiniDumpWithFullMemory. Can only be called once and cannot be
 | ||||||
|  |   // called if the dump file is set via SetFullDumpFile().
 | ||||||
|  |   bool GenerateFullDumpFile(std::wstring* full_dump_path); | ||||||
|  | 
 | ||||||
|  |   void SetAdditionalStreams( | ||||||
|  |       MINIDUMP_USER_STREAM_INFORMATION* additional_streams) { | ||||||
|  |     additional_streams_ = additional_streams; | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   void SetCallback(MINIDUMP_CALLBACK_INFORMATION* callback_info) { | ||||||
|  |     callback_info_ = callback_info; | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|   // Writes the minidump with the given parameters. Stores the
 |   // Writes the minidump with the given parameters. Stores the
 | ||||||
|   // dump file path in the dump_path parameter if dump generation
 |   // dump file path in the dump_path parameter if dump generation
 | ||||||
|   // succeeds.
 |   // succeeds.
 | ||||||
|   bool WriteMinidump(HANDLE process_handle, |   bool WriteMinidump(); | ||||||
|                      DWORD process_id, |  | ||||||
|                      DWORD thread_id, |  | ||||||
|                      DWORD requesting_thread_id, |  | ||||||
|                      EXCEPTION_POINTERS* exception_pointers, |  | ||||||
|                      MDRawAssertionInfo* assert_info, |  | ||||||
|                      MINIDUMP_TYPE dump_type, |  | ||||||
|                      bool is_client_pointers, |  | ||||||
|                      std::wstring* dump_path); |  | ||||||
| 
 |  | ||||||
|   // Writes the minidump with the given parameters. Stores the dump file
 |  | ||||||
|   // path in the dump_path (and full_dump_path) parameter if dump
 |  | ||||||
|   // generation succeeds. full_dump_path and dump_path can be NULL.
 |  | ||||||
|   bool WriteMinidump(HANDLE process_handle, |  | ||||||
|                      DWORD process_id, |  | ||||||
|                      DWORD thread_id, |  | ||||||
|                      DWORD requesting_thread_id, |  | ||||||
|                      EXCEPTION_POINTERS* exception_pointers, |  | ||||||
|                      MDRawAssertionInfo* assert_info, |  | ||||||
|                      MINIDUMP_TYPE dump_type, |  | ||||||
|                      bool is_client_pointers, |  | ||||||
|                      std::wstring* dump_path, |  | ||||||
|                      std::wstring* full_dump_path); |  | ||||||
| 
 | 
 | ||||||
|  private: |  private: | ||||||
|   // Function pointer type for MiniDumpWriteDump, which is looked up
 |   // Function pointer type for MiniDumpWriteDump, which is looked up
 | ||||||
| @ -120,9 +139,53 @@ class MinidumpGenerator { | |||||||
|   // Pointer to the UuidCreate function.
 |   // Pointer to the UuidCreate function.
 | ||||||
|   UuidCreateType create_uuid_; |   UuidCreateType create_uuid_; | ||||||
| 
 | 
 | ||||||
|  |   // Handle for the process to dump.
 | ||||||
|  |   HANDLE process_handle_; | ||||||
|  | 
 | ||||||
|  |   // Process ID for the process to dump.
 | ||||||
|  |   DWORD process_id_; | ||||||
|  | 
 | ||||||
|  |   // The crashing thread ID.
 | ||||||
|  |   DWORD thread_id_; | ||||||
|  | 
 | ||||||
|  |   // The thread ID which is requesting the dump.
 | ||||||
|  |   DWORD requesting_thread_id_; | ||||||
|  | 
 | ||||||
|  |   // Pointer to the exception information for the crash. This may point to an
 | ||||||
|  |   // address in the crashing process so it should not be dereferenced.
 | ||||||
|  |   EXCEPTION_POINTERS* exception_pointers_; | ||||||
|  | 
 | ||||||
|  |   // Assertion info for the report.
 | ||||||
|  |   MDRawAssertionInfo* assert_info_; | ||||||
|  | 
 | ||||||
|  |   // Type of minidump to generate.
 | ||||||
|  |   MINIDUMP_TYPE dump_type_; | ||||||
|  | 
 | ||||||
|  |   // Specifies whether the exception_pointers_ reference memory in the crashing
 | ||||||
|  |   // process.
 | ||||||
|  |   bool is_client_pointers_; | ||||||
|  | 
 | ||||||
|   // Folder path to store dump files.
 |   // Folder path to store dump files.
 | ||||||
|   std::wstring dump_path_; |   std::wstring dump_path_; | ||||||
| 
 | 
 | ||||||
|  |   // The file where the dump will be written.
 | ||||||
|  |   HANDLE dump_file_; | ||||||
|  | 
 | ||||||
|  |   // The file where the full dump will be written.
 | ||||||
|  |   HANDLE full_dump_file_; | ||||||
|  | 
 | ||||||
|  |   // Tracks whether the dump file handle is managed externally.
 | ||||||
|  |   bool dump_file_is_internal_; | ||||||
|  | 
 | ||||||
|  |   // Tracks whether the full dump file handle is managed externally.
 | ||||||
|  |   bool full_dump_file_is_internal_; | ||||||
|  | 
 | ||||||
|  |   // Additional streams to be written to the dump.
 | ||||||
|  |   MINIDUMP_USER_STREAM_INFORMATION* additional_streams_; | ||||||
|  | 
 | ||||||
|  |   // The user defined callback for the various stages of the dump process.
 | ||||||
|  |   MINIDUMP_CALLBACK_INFORMATION* callback_info_; | ||||||
|  | 
 | ||||||
|   // Critical section to sychronize action of loading modules dynamically.
 |   // Critical section to sychronize action of loading modules dynamically.
 | ||||||
|   CRITICAL_SECTION module_load_sync_; |   CRITICAL_SECTION module_load_sync_; | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -27,7 +27,7 @@ | |||||||
| // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 | ||||||
| // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 | ||||||
| 
 | 
 | ||||||
| #include <ObjBase.h> | #include <objbase.h> | ||||||
| 
 | 
 | ||||||
| #include <algorithm> | #include <algorithm> | ||||||
| #include <cassert> | #include <cassert> | ||||||
| @ -104,19 +104,19 @@ ExceptionHandler::ExceptionHandler( | |||||||
|     MinidumpCallback callback, |     MinidumpCallback callback, | ||||||
|     void* callback_context, |     void* callback_context, | ||||||
|     int handler_types, |     int handler_types, | ||||||
|     MINIDUMP_TYPE dump_type, |     CrashGenerationClient* crash_generation_client) { | ||||||
|     CrashGenerationClient* crash_generation_client, |   // The dump_type, pipe_name and custom_info that are passed in to Initialize()
 | ||||||
|     const CustomClientInfo* custom_info) { |   // are not used.  The ones set in crash_generation_client are used instead.
 | ||||||
|   Initialize(dump_path, |   Initialize(dump_path, | ||||||
|              filter, |              filter, | ||||||
|              callback, |              callback, | ||||||
|              callback_context, |              callback_context, | ||||||
|              handler_types, |              handler_types, | ||||||
|              MiniDumpNormal, |              MiniDumpNormal,           // dump_type - not used
 | ||||||
|              NULL,  // pipe_name
 |              NULL,                     // pipe_name - not used
 | ||||||
|              NULL,                     // pipe_handle
 |              NULL,                     // pipe_handle
 | ||||||
|              crash_generation_client, |              crash_generation_client, | ||||||
|              custom_info); |              NULL);                    // custom_info - not used
 | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| ExceptionHandler::ExceptionHandler(const wstring &dump_path, | ExceptionHandler::ExceptionHandler(const wstring &dump_path, | ||||||
|  | |||||||
| @ -1,5 +1,4 @@ | |||||||
| # Copyright (c) 2010, Google Inc. | # Copyright 2010 Google Inc. All rights reserved. | ||||||
| # All rights reserved. |  | ||||||
| # | # | ||||||
| # Redistribution and use in source and binary forms, with or without | # Redistribution and use in source and binary forms, with or without | ||||||
| # modification, are permitted provided that the following conditions are | # modification, are permitted provided that the following conditions are | ||||||
| @ -29,7 +28,7 @@ | |||||||
| 
 | 
 | ||||||
| { | { | ||||||
|   'includes': [ |   'includes': [ | ||||||
|     '../build/common.gypi', |     '../../../build/common.gypi', | ||||||
|   ], |   ], | ||||||
|   'targets': [ |   'targets': [ | ||||||
|     { |     { | ||||||
| @ -41,7 +40,7 @@ | |||||||
|       ], |       ], | ||||||
|       'dependencies': [ |       'dependencies': [ | ||||||
|         '../breakpad_client.gyp:common', |         '../breakpad_client.gyp:common', | ||||||
|         '../crash_generation/crash_generation.gyp:crash_generation_client', |         '../crash_generation/crash_generation.gyp:crash_generation_server', | ||||||
|       ] |       ] | ||||||
|     }, |     }, | ||||||
|   ], |   ], | ||||||
|  | |||||||
| @ -57,8 +57,8 @@ | |||||||
| #define CLIENT_WINDOWS_HANDLER_EXCEPTION_HANDLER_H__ | #define CLIENT_WINDOWS_HANDLER_EXCEPTION_HANDLER_H__ | ||||||
| 
 | 
 | ||||||
| #include <stdlib.h> | #include <stdlib.h> | ||||||
| #include <Windows.h> | #include <windows.h> | ||||||
| #include <DbgHelp.h> | #include <dbghelp.h> | ||||||
| #include <rpc.h> | #include <rpc.h> | ||||||
| 
 | 
 | ||||||
| #pragma warning(push) | #pragma warning(push) | ||||||
| @ -212,9 +212,7 @@ class ExceptionHandler { | |||||||
|                    MinidumpCallback callback, |                    MinidumpCallback callback, | ||||||
|                    void* callback_context, |                    void* callback_context, | ||||||
|                    int handler_types, |                    int handler_types, | ||||||
|                    MINIDUMP_TYPE dump_type, |                    CrashGenerationClient* crash_generation_client); | ||||||
|                    CrashGenerationClient* crash_generation_client, |  | ||||||
|                    const CustomClientInfo* custom_info); |  | ||||||
| 
 | 
 | ||||||
|   ~ExceptionHandler(); |   ~ExceptionHandler(); | ||||||
| 
 | 
 | ||||||
| @ -497,7 +495,7 @@ class ExceptionHandler { | |||||||
|   static CRITICAL_SECTION handler_stack_critical_section_; |   static CRITICAL_SECTION handler_stack_critical_section_; | ||||||
| 
 | 
 | ||||||
|   // The number of instances of this class.
 |   // The number of instances of this class.
 | ||||||
|   volatile static LONG instance_count_; |   static volatile LONG instance_count_; | ||||||
| 
 | 
 | ||||||
|   // disallow copy ctor and operator=
 |   // disallow copy ctor and operator=
 | ||||||
|   explicit ExceptionHandler(const ExceptionHandler &); |   explicit ExceptionHandler(const ExceptionHandler &); | ||||||
|  | |||||||
| @ -38,4 +38,21 @@ | |||||||
|   void operator=(const TypeName&) |   void operator=(const TypeName&) | ||||||
| #endif  // DISALLOW_COPY_AND_ASSIGN
 | #endif  // DISALLOW_COPY_AND_ASSIGN
 | ||||||
| 
 | 
 | ||||||
|  | namespace google_breakpad { | ||||||
|  | 
 | ||||||
|  | // Used to explicitly mark the return value of a function as unused. If you are
 | ||||||
|  | // really sure you don't want to do anything with the return value of a function
 | ||||||
|  | // that has been marked with __attribute__((warn_unused_result)), wrap it with
 | ||||||
|  | // this. Example:
 | ||||||
|  | //
 | ||||||
|  | //   scoped_ptr<MyType> my_var = ...;
 | ||||||
|  | //   if (TakeOwnership(my_var.get()) == SUCCESS)
 | ||||||
|  | //     ignore_result(my_var.release());
 | ||||||
|  | //
 | ||||||
|  | template<typename T> | ||||||
|  | inline void ignore_result(const T&) { | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | }  // namespace google_breakpad
 | ||||||
|  | 
 | ||||||
| #endif  // COMMON_BASICTYPES_H_
 | #endif  // COMMON_BASICTYPES_H_
 | ||||||
|  | |||||||
							
								
								
									
										242
									
								
								google-breakpad/src/common/common.gyp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										242
									
								
								google-breakpad/src/common/common.gyp
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,242 @@ | |||||||
|  | # Copyright 2014 Google Inc. All rights reserved. | ||||||
|  | # | ||||||
|  | # Redistribution and use in source and binary forms, with or without | ||||||
|  | # modification, are permitted provided that the following conditions are | ||||||
|  | # met: | ||||||
|  | # | ||||||
|  | #     * Redistributions of source code must retain the above copyright | ||||||
|  | # notice, this list of conditions and the following disclaimer. | ||||||
|  | #     * Redistributions in binary form must reproduce the above | ||||||
|  | # copyright notice, this list of conditions and the following disclaimer | ||||||
|  | # in the documentation and/or other materials provided with the | ||||||
|  | # distribution. | ||||||
|  | #     * Neither the name of Google Inc. nor the names of its | ||||||
|  | # contributors may be used to endorse or promote products derived from | ||||||
|  | # this software without specific prior written permission. | ||||||
|  | # | ||||||
|  | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||||||
|  | # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||||||
|  | # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | ||||||
|  | # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | ||||||
|  | # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | ||||||
|  | # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | ||||||
|  | # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | ||||||
|  | # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | ||||||
|  | # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||||||
|  | # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | ||||||
|  | # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||||||
|  | 
 | ||||||
|  | { | ||||||
|  |   'target_defaults': { | ||||||
|  |     'target_conditions': [ | ||||||
|  |       ['OS=="mac"', { | ||||||
|  |         'defines': ['HAVE_MACH_O_NLIST_H'], | ||||||
|  |       }], | ||||||
|  |       ['OS=="linux"', { | ||||||
|  |         'defines': ['HAVE_A_OUT_H'], | ||||||
|  |       }], | ||||||
|  |     ], | ||||||
|  |   }, | ||||||
|  |   'targets': [ | ||||||
|  |     { | ||||||
|  |       'target_name': 'common', | ||||||
|  |       'type': 'static_library', | ||||||
|  |       'sources': [ | ||||||
|  |         'android/breakpad_getcontext.S', | ||||||
|  |         'android/include/elf.h', | ||||||
|  |         'android/include/link.h', | ||||||
|  |         'android/include/sgidefs.h', | ||||||
|  |         'android/include/stab.h', | ||||||
|  |         'android/include/sys/procfs.h', | ||||||
|  |         'android/include/sys/signal.h', | ||||||
|  |         'android/include/sys/user.h', | ||||||
|  |         'android/include/ucontext.h', | ||||||
|  |         'android/testing/include/wchar.h', | ||||||
|  |         'android/testing/mkdtemp.h', | ||||||
|  |         'android/testing/pthread_fixes.h', | ||||||
|  |         'android/ucontext_constants.h', | ||||||
|  |         'basictypes.h', | ||||||
|  |         'byte_cursor.h', | ||||||
|  |         'convert_UTF.c', | ||||||
|  |         'convert_UTF.h', | ||||||
|  |         'dwarf/bytereader-inl.h', | ||||||
|  |         'dwarf/bytereader.cc', | ||||||
|  |         'dwarf/bytereader.h', | ||||||
|  |         'dwarf/cfi_assembler.cc', | ||||||
|  |         'dwarf/cfi_assembler.h', | ||||||
|  |         'dwarf/dwarf2diehandler.cc', | ||||||
|  |         'dwarf/dwarf2diehandler.h', | ||||||
|  |         'dwarf/dwarf2enums.h', | ||||||
|  |         'dwarf/dwarf2reader.cc', | ||||||
|  |         'dwarf/dwarf2reader.h', | ||||||
|  |         'dwarf/dwarf2reader_test_common.h', | ||||||
|  |         'dwarf/functioninfo.cc', | ||||||
|  |         'dwarf/functioninfo.h', | ||||||
|  |         'dwarf/line_state_machine.h', | ||||||
|  |         'dwarf/types.h', | ||||||
|  |         'dwarf_cfi_to_module.cc', | ||||||
|  |         'dwarf_cfi_to_module.h', | ||||||
|  |         'dwarf_cu_to_module.cc', | ||||||
|  |         'dwarf_cu_to_module.h', | ||||||
|  |         'dwarf_line_to_module.cc', | ||||||
|  |         'dwarf_line_to_module.h', | ||||||
|  |         'language.cc', | ||||||
|  |         'language.h', | ||||||
|  |         'linux/crc32.cc', | ||||||
|  |         'linux/crc32.h', | ||||||
|  |         'linux/dump_symbols.cc', | ||||||
|  |         'linux/dump_symbols.h', | ||||||
|  |         'linux/eintr_wrapper.h', | ||||||
|  |         'linux/elf_core_dump.cc', | ||||||
|  |         'linux/elf_core_dump.h', | ||||||
|  |         'linux/elf_gnu_compat.h', | ||||||
|  |         'linux/elf_symbols_to_module.cc', | ||||||
|  |         'linux/elf_symbols_to_module.h', | ||||||
|  |         'linux/elfutils-inl.h', | ||||||
|  |         'linux/elfutils.cc', | ||||||
|  |         'linux/elfutils.h', | ||||||
|  |         'linux/file_id.cc', | ||||||
|  |         'linux/file_id.h', | ||||||
|  |         'linux/google_crashdump_uploader.cc', | ||||||
|  |         'linux/google_crashdump_uploader.h', | ||||||
|  |         'linux/guid_creator.cc', | ||||||
|  |         'linux/guid_creator.h', | ||||||
|  |         'linux/http_upload.cc', | ||||||
|  |         'linux/http_upload.h', | ||||||
|  |         'linux/ignore_ret.h', | ||||||
|  |         'linux/libcurl_wrapper.cc', | ||||||
|  |         'linux/libcurl_wrapper.h', | ||||||
|  |         'linux/linux_libc_support.cc', | ||||||
|  |         'linux/linux_libc_support.h', | ||||||
|  |         'linux/memory_mapped_file.cc', | ||||||
|  |         'linux/memory_mapped_file.h', | ||||||
|  |         'linux/safe_readlink.cc', | ||||||
|  |         'linux/safe_readlink.h', | ||||||
|  |         'linux/synth_elf.cc', | ||||||
|  |         'linux/synth_elf.h', | ||||||
|  |         'mac/arch_utilities.cc', | ||||||
|  |         'mac/arch_utilities.h', | ||||||
|  |         'mac/bootstrap_compat.cc', | ||||||
|  |         'mac/bootstrap_compat.h', | ||||||
|  |         'mac/byteswap.h', | ||||||
|  |         'mac/dump_syms.h', | ||||||
|  |         'mac/dump_syms.mm', | ||||||
|  |         'mac/file_id.cc', | ||||||
|  |         'mac/file_id.h', | ||||||
|  |         'mac/GTMDefines.h', | ||||||
|  |         'mac/GTMLogger.h', | ||||||
|  |         'mac/GTMLogger.m', | ||||||
|  |         'mac/HTTPMultipartUpload.h', | ||||||
|  |         'mac/HTTPMultipartUpload.m', | ||||||
|  |         'mac/MachIPC.h', | ||||||
|  |         'mac/MachIPC.mm', | ||||||
|  |         'mac/macho_id.cc', | ||||||
|  |         'mac/macho_id.h', | ||||||
|  |         'mac/macho_reader.cc', | ||||||
|  |         'mac/macho_reader.h', | ||||||
|  |         'mac/macho_utilities.cc', | ||||||
|  |         'mac/macho_utilities.h', | ||||||
|  |         'mac/macho_walker.cc', | ||||||
|  |         'mac/macho_walker.h', | ||||||
|  |         'mac/scoped_task_suspend-inl.h', | ||||||
|  |         'mac/string_utilities.cc', | ||||||
|  |         'mac/string_utilities.h', | ||||||
|  |         'md5.cc', | ||||||
|  |         'md5.h', | ||||||
|  |         'memory.h', | ||||||
|  |         'memory_range.h', | ||||||
|  |         'module.cc', | ||||||
|  |         'module.h', | ||||||
|  |         'scoped_ptr.h', | ||||||
|  |         'simple_string_dictionary.cc', | ||||||
|  |         'simple_string_dictionary.h', | ||||||
|  |         'solaris/dump_symbols.cc', | ||||||
|  |         'solaris/dump_symbols.h', | ||||||
|  |         'solaris/file_id.cc', | ||||||
|  |         'solaris/file_id.h', | ||||||
|  |         'solaris/guid_creator.cc', | ||||||
|  |         'solaris/guid_creator.h', | ||||||
|  |         'solaris/message_output.h', | ||||||
|  |         'stabs_reader.cc', | ||||||
|  |         'stabs_reader.h', | ||||||
|  |         'stabs_to_module.cc', | ||||||
|  |         'stabs_to_module.h', | ||||||
|  |         'string_conversion.cc', | ||||||
|  |         'string_conversion.h', | ||||||
|  |         'symbol_data.h', | ||||||
|  |         'test_assembler.cc', | ||||||
|  |         'test_assembler.h', | ||||||
|  |         'unordered.h', | ||||||
|  |         'using_std_string.h', | ||||||
|  |         'windows/common_windows.gyp', | ||||||
|  |         'windows/dia_util.cc', | ||||||
|  |         'windows/dia_util.h', | ||||||
|  |         'windows/guid_string.cc', | ||||||
|  |         'windows/guid_string.h', | ||||||
|  |         'windows/http_upload.cc', | ||||||
|  |         'windows/http_upload.h', | ||||||
|  |         'windows/omap.cc', | ||||||
|  |         'windows/omap.h', | ||||||
|  |         'windows/omap_internal.h', | ||||||
|  |         'windows/pdb_source_line_writer.cc', | ||||||
|  |         'windows/pdb_source_line_writer.h', | ||||||
|  |         'windows/string_utils-inl.h', | ||||||
|  |         'windows/string_utils.cc', | ||||||
|  |       ], | ||||||
|  |       'include_dirs': [ | ||||||
|  |         '..', | ||||||
|  |       ], | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |       'target_name': 'common_unittests', | ||||||
|  |       'type': 'executable', | ||||||
|  |       'sources': [ | ||||||
|  |         'android/breakpad_getcontext_unittest.cc', | ||||||
|  |         'byte_cursor_unittest.cc', | ||||||
|  |         'dwarf/bytereader_unittest.cc', | ||||||
|  |         'dwarf/dwarf2diehandler_unittest.cc', | ||||||
|  |         'dwarf/dwarf2reader_cfi_unittest.cc', | ||||||
|  |         'dwarf/dwarf2reader_die_unittest.cc', | ||||||
|  |         'dwarf_cfi_to_module_unittest.cc', | ||||||
|  |         'dwarf_cu_to_module_unittest.cc', | ||||||
|  |         'dwarf_line_to_module_unittest.cc', | ||||||
|  |         'linux/dump_symbols_unittest.cc', | ||||||
|  |         'linux/elf_core_dump_unittest.cc', | ||||||
|  |         'linux/elf_symbols_to_module_unittest.cc', | ||||||
|  |         'linux/file_id_unittest.cc', | ||||||
|  |         'linux/google_crashdump_uploader_test.cc', | ||||||
|  |         'linux/linux_libc_support_unittest.cc', | ||||||
|  |         'linux/memory_mapped_file_unittest.cc', | ||||||
|  |         'linux/safe_readlink_unittest.cc', | ||||||
|  |         'linux/synth_elf_unittest.cc', | ||||||
|  |         'linux/tests/auto_testfile.h', | ||||||
|  |         'linux/tests/crash_generator.cc', | ||||||
|  |         'linux/tests/crash_generator.h', | ||||||
|  |         'mac/macho_reader_unittest.cc', | ||||||
|  |         'memory_range_unittest.cc', | ||||||
|  |         'memory_unittest.cc', | ||||||
|  |         'module_unittest.cc', | ||||||
|  |         'simple_string_dictionary_unittest.cc', | ||||||
|  |         'stabs_reader_unittest.cc', | ||||||
|  |         'stabs_to_module_unittest.cc', | ||||||
|  |         'test_assembler_unittest.cc', | ||||||
|  |         'tests/auto_tempdir.h', | ||||||
|  |         'tests/file_utils.cc', | ||||||
|  |         'tests/file_utils.h', | ||||||
|  |         'windows/omap_unittest.cc', | ||||||
|  |       ], | ||||||
|  |       'include_dirs': [ | ||||||
|  |         '..', | ||||||
|  |       ], | ||||||
|  |       'dependencies': [ | ||||||
|  |         'common', | ||||||
|  |         '../build/testing.gypi:gmock_main', | ||||||
|  |         '../build/testing.gypi:gmock', | ||||||
|  |         '../build/testing.gypi:gtest', | ||||||
|  |       ], | ||||||
|  |       'libraries': [ | ||||||
|  |         '-ldl', | ||||||
|  |       ], | ||||||
|  |     }, | ||||||
|  |   ], | ||||||
|  | } | ||||||
| @ -53,8 +53,13 @@ static const UTF32 halfMask = 0x3FFUL; | |||||||
| #define UNI_SUR_HIGH_END    (UTF32)0xDBFF | #define UNI_SUR_HIGH_END    (UTF32)0xDBFF | ||||||
| #define UNI_SUR_LOW_START   (UTF32)0xDC00 | #define UNI_SUR_LOW_START   (UTF32)0xDC00 | ||||||
| #define UNI_SUR_LOW_END     (UTF32)0xDFFF | #define UNI_SUR_LOW_END     (UTF32)0xDFFF | ||||||
|  | 
 | ||||||
|  | #ifndef false | ||||||
| #define false	   0 | #define false	   0 | ||||||
|  | #endif | ||||||
|  | #ifndef true | ||||||
| #define true	    1 | #define true	    1 | ||||||
|  | #endif | ||||||
| 
 | 
 | ||||||
| /* --------------------------------------------------------------------- */ | /* --------------------------------------------------------------------- */ | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -20,6 +20,9 @@ | |||||||
|  * remains attached. |  * remains attached. | ||||||
|  */ |  */ | ||||||
| 
 | 
 | ||||||
|  | #ifndef COMMON_CONVERT_UTF_H_ | ||||||
|  | #define COMMON_CONVERT_UTF_H_ | ||||||
|  | 
 | ||||||
| /* ---------------------------------------------------------------------
 | /* ---------------------------------------------------------------------
 | ||||||
| 
 | 
 | ||||||
| Conversions between UTF32, UTF-16, and UTF-8.  Header file. | Conversions between UTF32, UTF-16, and UTF-8.  Header file. | ||||||
| @ -141,3 +144,5 @@ Boolean isLegalUTF8Sequence(const UTF8 *source, const UTF8 *sourceEnd); | |||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
| /* --------------------------------------------------------------------- */ | /* --------------------------------------------------------------------- */ | ||||||
|  | 
 | ||||||
|  | #endif  // COMMON_CONVERT_UTF_H_
 | ||||||
|  | |||||||
| @ -1512,16 +1512,19 @@ bool CallFrameInfo::State::DoInstruction() { | |||||||
| 
 | 
 | ||||||
|     // Change the base register used to compute the CFA.
 |     // Change the base register used to compute the CFA.
 | ||||||
|     case DW_CFA_def_cfa_register: { |     case DW_CFA_def_cfa_register: { | ||||||
|  |       if (!ParseOperands("r", &ops)) return false; | ||||||
|       Rule *cfa_rule = rules_.CFARule(); |       Rule *cfa_rule = rules_.CFARule(); | ||||||
|       if (!cfa_rule) { |       if (!cfa_rule) { | ||||||
|  |         if (!DoDefCFA(ops.register_number, ops.offset)) { | ||||||
|           reporter_->NoCFARule(entry_->offset, entry_->kind, CursorOffset()); |           reporter_->NoCFARule(entry_->offset, entry_->kind, CursorOffset()); | ||||||
|           return false; |           return false; | ||||||
|         } |         } | ||||||
|       if (!ParseOperands("r", &ops)) return false; |       } else { | ||||||
|         cfa_rule->SetBaseRegister(ops.register_number); |         cfa_rule->SetBaseRegister(ops.register_number); | ||||||
|         if (!cfa_rule->Handle(handler_, address_, |         if (!cfa_rule->Handle(handler_, address_, | ||||||
|                               Handler::kCFARegister)) |                               Handler::kCFARegister)) | ||||||
|         return false; |         return false; | ||||||
|  |       } | ||||||
|       break; |       break; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -105,6 +105,43 @@ vector<string> DwarfCFIToModule::RegisterNames::ARM() { | |||||||
|   return MakeVector(names, sizeof(names) / sizeof(names[0])); |   return MakeVector(names, sizeof(names) / sizeof(names[0])); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | // Per ARM IHI 0057A, section 3.1
 | ||||||
|  | vector<string> DwarfCFIToModule::RegisterNames::ARM64() { | ||||||
|  |   static const char *const names[] = { | ||||||
|  |     "x0",  "x1",  "x2",  "x3",  "x4",  "x5",  "x6",  "x7", | ||||||
|  |     "x8",  "x9",  "x10", "x11", "x12", "x13", "x14", "x15", | ||||||
|  |     "x16", "x17", "x18", "x19", "x20", "x21", "x22", "x23", | ||||||
|  |     "x24", "x25", "x26", "x27", "x28", "x29", "x30", "sp", | ||||||
|  |     "",    "",    "",    "",    "",    "",    "",    "", | ||||||
|  |     "",    "",    "",    "",    "",    "",    "",    "", | ||||||
|  |     "",    "",    "",    "",    "",    "",    "",    "", | ||||||
|  |     "",    "",    "",    "",    "",    "",    "",    "", | ||||||
|  |     "v0",  "v1",  "v2",  "v3",  "v4",  "v5",  "v6",  "v7", | ||||||
|  |     "v8",  "v9",  "v10", "v11", "v12", "v13", "v14", "v15", | ||||||
|  |     "v16", "v17", "v18", "v19", "v20", "v21", "v22", "v23", | ||||||
|  |     "v24", "v25", "v26", "v27", "v28", "v29", "v30", "v31" | ||||||
|  |   }; | ||||||
|  | 
 | ||||||
|  |   return MakeVector(names, sizeof(names) / sizeof(names[0])); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | vector<string> DwarfCFIToModule::RegisterNames::MIPS() { | ||||||
|  |   static const char* const kRegisterNames[] = { | ||||||
|  |     "$zero", "$at",  "$v0",  "$v1",  "$a0",   "$a1",  "$a2",  "$a3", | ||||||
|  |     "$t0",   "$t1",  "$t2",  "$t3",  "$t4",   "$t5",  "$t6",  "$t7", | ||||||
|  |     "$s0",   "$s1",  "$s2",  "$s3",  "$s4",   "$s5",  "$s6",  "$s7", | ||||||
|  |     "$t8",   "$t9",  "$k0",  "$k1",  "$gp",   "$sp",  "$fp",  "$ra", | ||||||
|  |     "$lo",   "$hi",  "$pc",  "$f0",  "$f2",   "$f3",  "$f4",  "$f5", | ||||||
|  |     "$f6",   "$f7",  "$f8",  "$f9",  "$f10",  "$f11", "$f12", "$f13", | ||||||
|  |     "$f14",  "$f15", "$f16", "$f17", "$f18",  "$f19", "$f20", | ||||||
|  |     "$f21",  "$f22", "$f23", "$f24", "$f25",  "$f26", "$f27", | ||||||
|  |     "$f28",  "$f29", "$f30", "$f31", "$fcsr", "$fir" | ||||||
|  |   }; | ||||||
|  | 
 | ||||||
|  |   return MakeVector(kRegisterNames, | ||||||
|  |                     sizeof(kRegisterNames) / sizeof(kRegisterNames[0])); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| bool DwarfCFIToModule::Entry(size_t offset, uint64 address, uint64 length, | bool DwarfCFIToModule::Entry(size_t offset, uint64 address, uint64 length, | ||||||
|                              uint8 version, const string &augmentation, |                              uint8 version, const string &augmentation, | ||||||
|                              unsigned return_address) { |                              unsigned return_address) { | ||||||
|  | |||||||
| @ -109,6 +109,12 @@ class DwarfCFIToModule: public CallFrameInfo::Handler { | |||||||
|     // ARM.
 |     // ARM.
 | ||||||
|     static vector<string> ARM(); |     static vector<string> ARM(); | ||||||
| 
 | 
 | ||||||
|  |     // ARM64, aka AARCH64.
 | ||||||
|  |     static vector<string> ARM64(); | ||||||
|  | 
 | ||||||
|  |     // MIPS.
 | ||||||
|  |     static vector<string> MIPS(); | ||||||
|  | 
 | ||||||
|    private: |    private: | ||||||
|     // Given STRINGS, an array of C strings with SIZE elements, return an
 |     // Given STRINGS, an array of C strings with SIZE elements, return an
 | ||||||
|     // equivalent vector<string>.
 |     // equivalent vector<string>.
 | ||||||
|  | |||||||
| @ -46,16 +46,15 @@ | |||||||
| #include <stdio.h> | #include <stdio.h> | ||||||
| 
 | 
 | ||||||
| #include <algorithm> | #include <algorithm> | ||||||
| #include <set> |  | ||||||
| #include <utility> | #include <utility> | ||||||
| 
 | 
 | ||||||
| #include "common/dwarf_line_to_module.h" | #include "common/dwarf_line_to_module.h" | ||||||
|  | #include "common/unordered.h" | ||||||
| 
 | 
 | ||||||
| namespace google_breakpad { | namespace google_breakpad { | ||||||
| 
 | 
 | ||||||
| using std::map; | using std::map; | ||||||
| using std::pair; | using std::pair; | ||||||
| using std::set; |  | ||||||
| using std::sort; | using std::sort; | ||||||
| using std::vector; | using std::vector; | ||||||
| 
 | 
 | ||||||
| @ -118,7 +117,7 @@ struct DwarfCUToModule::FilePrivate { | |||||||
|   // so this set will actually hold yet another copy of the string (although
 |   // so this set will actually hold yet another copy of the string (although
 | ||||||
|   // everything will still work). To improve memory consumption portably,
 |   // everything will still work). To improve memory consumption portably,
 | ||||||
|   // we will probably need to use pointers to strings held in this set.
 |   // we will probably need to use pointers to strings held in this set.
 | ||||||
|   set<string> common_strings; |   unordered_set<string> common_strings; | ||||||
| 
 | 
 | ||||||
|   // A map from offsets of DIEs within the .debug_info section to
 |   // A map from offsets of DIEs within the .debug_info section to
 | ||||||
|   // Specifications describing those DIEs. Specification references can
 |   // Specifications describing those DIEs. Specification references can
 | ||||||
| @ -337,7 +336,7 @@ void DwarfCUToModule::GenericDIEHandler::ProcessAttributeReference( | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| string DwarfCUToModule::GenericDIEHandler::AddStringToPool(const string &str) { | string DwarfCUToModule::GenericDIEHandler::AddStringToPool(const string &str) { | ||||||
|   pair<set<string>::iterator, bool> result = |   pair<unordered_set<string>::iterator, bool> result = | ||||||
|     cu_context_->file_context->file_private_->common_strings.insert(str); |     cu_context_->file_context->file_private_->common_strings.insert(str); | ||||||
|   return *result.first; |   return *result.first; | ||||||
| } | } | ||||||
| @ -531,7 +530,7 @@ void DwarfCUToModule::FuncHandler::Finish() { | |||||||
|   if (low_pc_ < high_pc_) { |   if (low_pc_ < high_pc_) { | ||||||
|     // Create a Module::Function based on the data we've gathered, and
 |     // Create a Module::Function based on the data we've gathered, and
 | ||||||
|     // add it to the functions_ list.
 |     // add it to the functions_ list.
 | ||||||
|     Module::Function *func = new Module::Function; |     scoped_ptr<Module::Function> func(new Module::Function); | ||||||
|     // Malformed DWARF may omit the name, but all Module::Functions must
 |     // Malformed DWARF may omit the name, but all Module::Functions must
 | ||||||
|     // have names.
 |     // have names.
 | ||||||
|     if (!name_.empty()) { |     if (!name_.empty()) { | ||||||
| @ -546,7 +545,7 @@ void DwarfCUToModule::FuncHandler::Finish() { | |||||||
|     if (func->address) { |     if (func->address) { | ||||||
|        // If the function address is zero this is a sign that this function
 |        // If the function address is zero this is a sign that this function
 | ||||||
|        // description is just empty debug data and should just be discarded.
 |        // description is just empty debug data and should just be discarded.
 | ||||||
|        cu_context_->functions.push_back(func); |        cu_context_->functions.push_back(func.release()); | ||||||
|      } |      } | ||||||
|   } else if (inline_) { |   } else if (inline_) { | ||||||
|     AbstractOrigin origin(name_); |     AbstractOrigin origin(name_); | ||||||
|  | |||||||
							
								
								
									
										70
									
								
								google-breakpad/src/common/linux/crc32.cc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										70
									
								
								google-breakpad/src/common/linux/crc32.cc
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,70 @@ | |||||||
|  | // Copyright 2014 Google Inc.
 | ||||||
|  | // All rights reserved.
 | ||||||
|  | //
 | ||||||
|  | // Redistribution and use in source and binary forms, with or without
 | ||||||
|  | // modification, are permitted provided that the following conditions are
 | ||||||
|  | // met:
 | ||||||
|  | //
 | ||||||
|  | //     * Redistributions of source code must retain the above copyright
 | ||||||
|  | // notice, this list of conditions and the following disclaimer.
 | ||||||
|  | //     * Redistributions in binary form must reproduce the above
 | ||||||
|  | // copyright notice, this list of conditions and the following disclaimer
 | ||||||
|  | // in the documentation and/or other materials provided with the
 | ||||||
|  | // distribution.
 | ||||||
|  | //     * Neither the name of Google Inc. nor the names of its
 | ||||||
|  | // contributors may be used to endorse or promote products derived from
 | ||||||
|  | // this software without specific prior written permission.
 | ||||||
|  | //
 | ||||||
|  | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 | ||||||
|  | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 | ||||||
|  | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 | ||||||
|  | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 | ||||||
|  | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 | ||||||
|  | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 | ||||||
|  | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 | ||||||
|  | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 | ||||||
|  | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 | ||||||
|  | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 | ||||||
|  | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 | ||||||
|  | 
 | ||||||
|  | #include "common/linux/crc32.h" | ||||||
|  | 
 | ||||||
|  | namespace google_breakpad { | ||||||
|  | 
 | ||||||
|  | // This implementation is based on the sample implementation in RFC 1952.
 | ||||||
|  | 
 | ||||||
|  | // CRC32 polynomial, in reversed form.
 | ||||||
|  | // See RFC 1952, or http://en.wikipedia.org/wiki/Cyclic_redundancy_check
 | ||||||
|  | static const uint32_t kCrc32Polynomial = 0xEDB88320; | ||||||
|  | static uint32_t kCrc32Table[256] = { 0 }; | ||||||
|  | 
 | ||||||
|  | #define arraysize(f) (sizeof(f) / sizeof(*f)) | ||||||
|  | 
 | ||||||
|  | static void EnsureCrc32TableInited() { | ||||||
|  |   if (kCrc32Table[arraysize(kCrc32Table) - 1]) | ||||||
|  |     return;  // already inited
 | ||||||
|  |   for (uint32_t i = 0; i < arraysize(kCrc32Table); ++i) { | ||||||
|  |     uint32_t c = i; | ||||||
|  |     for (size_t j = 0; j < 8; ++j) { | ||||||
|  |       if (c & 1) { | ||||||
|  |         c = kCrc32Polynomial ^ (c >> 1); | ||||||
|  |       } else { | ||||||
|  |         c >>= 1; | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |     kCrc32Table[i] = c; | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | uint32_t UpdateCrc32(uint32_t start, const void* buf, size_t len) { | ||||||
|  |   EnsureCrc32TableInited(); | ||||||
|  | 
 | ||||||
|  |   uint32_t c = start ^ 0xFFFFFFFF; | ||||||
|  |   const uint8_t* u = static_cast<const uint8_t*>(buf); | ||||||
|  |   for (size_t i = 0; i < len; ++i) { | ||||||
|  |     c = kCrc32Table[(c ^ u[i]) & 0xFF] ^ (c >> 8); | ||||||
|  |   } | ||||||
|  |   return c ^ 0xFFFFFFFF; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | }  // namespace google_breakpad
 | ||||||
							
								
								
									
										53
									
								
								google-breakpad/src/common/linux/crc32.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										53
									
								
								google-breakpad/src/common/linux/crc32.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,53 @@ | |||||||
|  | // Copyright 2014 Google Inc.
 | ||||||
|  | // All rights reserved.
 | ||||||
|  | //
 | ||||||
|  | // Redistribution and use in source and binary forms, with or without
 | ||||||
|  | // modification, are permitted provided that the following conditions are
 | ||||||
|  | // met:
 | ||||||
|  | //
 | ||||||
|  | //     * Redistributions of source code must retain the above copyright
 | ||||||
|  | // notice, this list of conditions and the following disclaimer.
 | ||||||
|  | //     * Redistributions in binary form must reproduce the above
 | ||||||
|  | // copyright notice, this list of conditions and the following disclaimer
 | ||||||
|  | // in the documentation and/or other materials provided with the
 | ||||||
|  | // distribution.
 | ||||||
|  | //     * Neither the name of Google Inc. nor the names of its
 | ||||||
|  | // contributors may be used to endorse or promote products derived from
 | ||||||
|  | // this software without specific prior written permission.
 | ||||||
|  | //
 | ||||||
|  | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 | ||||||
|  | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 | ||||||
|  | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 | ||||||
|  | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 | ||||||
|  | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 | ||||||
|  | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 | ||||||
|  | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 | ||||||
|  | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 | ||||||
|  | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 | ||||||
|  | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 | ||||||
|  | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 | ||||||
|  | 
 | ||||||
|  | #ifndef COMMON_LINUX_CRC32_H_ | ||||||
|  | #define COMMON_LINUX_CRC32_H_ | ||||||
|  | 
 | ||||||
|  | #include <stdint.h> | ||||||
|  | 
 | ||||||
|  | #include <string> | ||||||
|  | 
 | ||||||
|  | namespace google_breakpad { | ||||||
|  | 
 | ||||||
|  | // Updates a CRC32 checksum with |len| bytes from |buf|. |initial| holds the
 | ||||||
|  | // checksum result from the previous update; for the first call, it should be 0.
 | ||||||
|  | uint32_t UpdateCrc32(uint32_t initial, const void* buf, size_t len); | ||||||
|  | 
 | ||||||
|  | // Computes a CRC32 checksum using |len| bytes from |buf|.
 | ||||||
|  | inline uint32_t ComputeCrc32(const void* buf, size_t len) { | ||||||
|  |   return UpdateCrc32(0, buf, len); | ||||||
|  | } | ||||||
|  | inline uint32_t ComputeCrc32(const std::string& str) { | ||||||
|  |   return ComputeCrc32(str.c_str(), str.size()); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | }  // namespace google_breakpad
 | ||||||
|  | 
 | ||||||
|  | #endif  // COMMON_LINUX_CRC32_H_
 | ||||||
| @ -57,6 +57,8 @@ | |||||||
| #include "common/dwarf_cfi_to_module.h" | #include "common/dwarf_cfi_to_module.h" | ||||||
| #include "common/dwarf_cu_to_module.h" | #include "common/dwarf_cu_to_module.h" | ||||||
| #include "common/dwarf_line_to_module.h" | #include "common/dwarf_line_to_module.h" | ||||||
|  | #include "common/linux/crc32.h" | ||||||
|  | #include "common/linux/eintr_wrapper.h" | ||||||
| #include "common/linux/elfutils.h" | #include "common/linux/elfutils.h" | ||||||
| #include "common/linux/elfutils-inl.h" | #include "common/linux/elfutils-inl.h" | ||||||
| #include "common/linux/elf_symbols_to_module.h" | #include "common/linux/elf_symbols_to_module.h" | ||||||
| @ -88,6 +90,11 @@ using google_breakpad::StabsToModule; | |||||||
| #endif | #endif | ||||||
| using google_breakpad::scoped_ptr; | using google_breakpad::scoped_ptr; | ||||||
| 
 | 
 | ||||||
|  | // Define AARCH64 ELF architecture if host machine does not include this define.
 | ||||||
|  | #ifndef EM_AARCH64 | ||||||
|  | #define EM_AARCH64      183 | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
| //
 | //
 | ||||||
| // FDWrapper
 | // FDWrapper
 | ||||||
| //
 | //
 | ||||||
| @ -291,6 +298,12 @@ bool DwarfCFIRegisterNames(const typename ElfClass::Ehdr* elf_header, | |||||||
|     case EM_ARM: |     case EM_ARM: | ||||||
|       *register_names = DwarfCFIToModule::RegisterNames::ARM(); |       *register_names = DwarfCFIToModule::RegisterNames::ARM(); | ||||||
|       return true; |       return true; | ||||||
|  |     case EM_AARCH64: | ||||||
|  |       *register_names = DwarfCFIToModule::RegisterNames::ARM64(); | ||||||
|  |       return true; | ||||||
|  |     case EM_MIPS: | ||||||
|  |       *register_names = DwarfCFIToModule::RegisterNames::MIPS(); | ||||||
|  |       return true; | ||||||
|     case EM_X86_64: |     case EM_X86_64: | ||||||
|       *register_names = DwarfCFIToModule::RegisterNames::X86_64(); |       *register_names = DwarfCFIToModule::RegisterNames::X86_64(); | ||||||
|       return true; |       return true; | ||||||
| @ -402,19 +415,19 @@ bool ElfEndianness(const typename ElfClass::Ehdr* elf_header, | |||||||
| 
 | 
 | ||||||
| // Read the .gnu_debuglink and get the debug file name. If anything goes
 | // Read the .gnu_debuglink and get the debug file name. If anything goes
 | ||||||
| // wrong, return an empty string.
 | // wrong, return an empty string.
 | ||||||
| template<typename ElfClass> |  | ||||||
| string ReadDebugLink(const char* debuglink, | string ReadDebugLink(const char* debuglink, | ||||||
|                      size_t debuglink_size, |                      const size_t debuglink_size, | ||||||
|  |                      const bool big_endian, | ||||||
|                      const string& obj_file, |                      const string& obj_file, | ||||||
|                      const std::vector<string>& debug_dirs) { |                      const std::vector<string>& debug_dirs) { | ||||||
|   size_t debuglink_len = strlen(debuglink) + 5;  // '\0' + CRC32.
 |   size_t debuglink_len = strlen(debuglink) + 5;  // Include '\0' + CRC32.
 | ||||||
|   debuglink_len = 4 * ((debuglink_len + 3) / 4);  // Round to nearest 4 bytes.
 |   debuglink_len = 4 * ((debuglink_len + 3) / 4);  // Round up to 4 bytes.
 | ||||||
| 
 | 
 | ||||||
|   // Sanity check.
 |   // Sanity check.
 | ||||||
|   if (debuglink_len != debuglink_size) { |   if (debuglink_len != debuglink_size) { | ||||||
|     fprintf(stderr, "Mismatched .gnu_debuglink string / section size: " |     fprintf(stderr, "Mismatched .gnu_debuglink string / section size: " | ||||||
|             "%zx %zx\n", debuglink_len, debuglink_size); |             "%zx %zx\n", debuglink_len, debuglink_size); | ||||||
|     return ""; |     return string(); | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   bool found = false; |   bool found = false; | ||||||
| @ -425,11 +438,40 @@ string ReadDebugLink(const char* debuglink, | |||||||
|     const string& debug_dir = *it; |     const string& debug_dir = *it; | ||||||
|     debuglink_path = debug_dir + "/" + debuglink; |     debuglink_path = debug_dir + "/" + debuglink; | ||||||
|     debuglink_fd = open(debuglink_path.c_str(), O_RDONLY); |     debuglink_fd = open(debuglink_path.c_str(), O_RDONLY); | ||||||
|     if (debuglink_fd >= 0) { |     if (debuglink_fd < 0) | ||||||
|  |       continue; | ||||||
|  | 
 | ||||||
|  |     FDWrapper debuglink_fd_wrapper(debuglink_fd); | ||||||
|  | 
 | ||||||
|  |     // The CRC is the last 4 bytes in |debuglink|.
 | ||||||
|  |     const dwarf2reader::Endianness endianness = big_endian ? | ||||||
|  |         dwarf2reader::ENDIANNESS_BIG : dwarf2reader::ENDIANNESS_LITTLE; | ||||||
|  |     dwarf2reader::ByteReader byte_reader(endianness); | ||||||
|  |     uint32_t expected_crc = | ||||||
|  |         byte_reader.ReadFourBytes(&debuglink[debuglink_size - 4]); | ||||||
|  | 
 | ||||||
|  |     uint32_t actual_crc = 0; | ||||||
|  |     while (true) { | ||||||
|  |       const size_t kReadSize = 4096; | ||||||
|  |       char buf[kReadSize]; | ||||||
|  |       ssize_t bytes_read = HANDLE_EINTR(read(debuglink_fd, &buf, kReadSize)); | ||||||
|  |       if (bytes_read < 0) { | ||||||
|  |         fprintf(stderr, "Error reading debug ELF file %s.\n", | ||||||
|  |                 debuglink_path.c_str()); | ||||||
|  |         return string(); | ||||||
|  |       } | ||||||
|  |       if (bytes_read == 0) | ||||||
|  |         break; | ||||||
|  |       actual_crc = google_breakpad::UpdateCrc32(actual_crc, buf, bytes_read); | ||||||
|  |     } | ||||||
|  |     if (actual_crc != expected_crc) { | ||||||
|  |       fprintf(stderr, "Error reading debug ELF file - CRC32 mismatch: %s\n", | ||||||
|  |               debuglink_path.c_str()); | ||||||
|  |       continue; | ||||||
|  |     } | ||||||
|     found = true; |     found = true; | ||||||
|     break; |     break; | ||||||
|   } |   } | ||||||
|   } |  | ||||||
| 
 | 
 | ||||||
|   if (!found) { |   if (!found) { | ||||||
|     fprintf(stderr, "Failed to find debug ELF file for '%s' after trying:\n", |     fprintf(stderr, "Failed to find debug ELF file for '%s' after trying:\n", | ||||||
| @ -438,13 +480,9 @@ string ReadDebugLink(const char* debuglink, | |||||||
|       const string debug_dir = *it; |       const string debug_dir = *it; | ||||||
|       fprintf(stderr, "  %s/%s\n", debug_dir.c_str(), debuglink); |       fprintf(stderr, "  %s/%s\n", debug_dir.c_str(), debuglink); | ||||||
|     } |     } | ||||||
|     return ""; |     return string(); | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   FDWrapper debuglink_fd_wrapper(debuglink_fd); |  | ||||||
|   // TODO(thestig) check the CRC-32 at the end of the .gnu_debuglink
 |  | ||||||
|   // section.
 |  | ||||||
| 
 |  | ||||||
|   return debuglink_path; |   return debuglink_path; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -534,6 +572,7 @@ bool LoadSymbols(const string& obj_file, | |||||||
|   typedef typename ElfClass::Addr Addr; |   typedef typename ElfClass::Addr Addr; | ||||||
|   typedef typename ElfClass::Phdr Phdr; |   typedef typename ElfClass::Phdr Phdr; | ||||||
|   typedef typename ElfClass::Shdr Shdr; |   typedef typename ElfClass::Shdr Shdr; | ||||||
|  |   typedef typename ElfClass::Word Word; | ||||||
| 
 | 
 | ||||||
|   Addr loading_addr = GetLoadingAddress<ElfClass>( |   Addr loading_addr = GetLoadingAddress<ElfClass>( | ||||||
|       GetOffset<ElfClass, Phdr>(elf_header, elf_header->e_phoff), |       GetOffset<ElfClass, Phdr>(elf_header, elf_header->e_phoff), | ||||||
| @ -541,6 +580,8 @@ bool LoadSymbols(const string& obj_file, | |||||||
|   module->SetLoadAddress(loading_addr); |   module->SetLoadAddress(loading_addr); | ||||||
|   info->set_loading_addr(loading_addr, obj_file); |   info->set_loading_addr(loading_addr, obj_file); | ||||||
| 
 | 
 | ||||||
|  |   Word debug_section_type = | ||||||
|  |       elf_header->e_machine == EM_MIPS ? SHT_MIPS_DWARF : SHT_PROGBITS; | ||||||
|   const Shdr* sections = |   const Shdr* sections = | ||||||
|       GetOffset<ElfClass, Shdr>(elf_header, elf_header->e_shoff); |       GetOffset<ElfClass, Shdr>(elf_header, elf_header->e_shoff); | ||||||
|   const Shdr* section_names = sections + elf_header->e_shstrndx; |   const Shdr* section_names = sections + elf_header->e_shstrndx; | ||||||
| @ -574,7 +615,7 @@ bool LoadSymbols(const string& obj_file, | |||||||
| 
 | 
 | ||||||
|     // Look for DWARF debugging information, and load it if present.
 |     // Look for DWARF debugging information, and load it if present.
 | ||||||
|     const Shdr* dwarf_section = |     const Shdr* dwarf_section = | ||||||
|       FindElfSectionByName<ElfClass>(".debug_info", SHT_PROGBITS, |       FindElfSectionByName<ElfClass>(".debug_info", debug_section_type, | ||||||
|                                      sections, names, names_end, |                                      sections, names, names_end, | ||||||
|                                      elf_header->e_shnum); |                                      elf_header->e_shnum); | ||||||
|     if (dwarf_section) { |     if (dwarf_section) { | ||||||
| @ -593,7 +634,7 @@ bool LoadSymbols(const string& obj_file, | |||||||
|     // Dwarf Call Frame Information (CFI) is actually independent from
 |     // Dwarf Call Frame Information (CFI) is actually independent from
 | ||||||
|     // the other DWARF debugging information, and can be used alone.
 |     // the other DWARF debugging information, and can be used alone.
 | ||||||
|     const Shdr* dwarf_cfi_section = |     const Shdr* dwarf_cfi_section = | ||||||
|         FindElfSectionByName<ElfClass>(".debug_frame", SHT_PROGBITS, |         FindElfSectionByName<ElfClass>(".debug_frame", debug_section_type, | ||||||
|                                        sections, names, names_end, |                                        sections, names, names_end, | ||||||
|                                        elf_header->e_shnum); |                                        elf_header->e_shnum); | ||||||
|     if (dwarf_cfi_section) { |     if (dwarf_cfi_section) { | ||||||
| @ -648,13 +689,17 @@ bool LoadSymbols(const string& obj_file, | |||||||
|                                            names_end, elf_header->e_shnum); |                                            names_end, elf_header->e_shnum); | ||||||
|       if (gnu_debuglink_section) { |       if (gnu_debuglink_section) { | ||||||
|         if (!info->debug_dirs().empty()) { |         if (!info->debug_dirs().empty()) { | ||||||
|  |           found_debug_info_section = true; | ||||||
|  | 
 | ||||||
|           const char* debuglink_contents = |           const char* debuglink_contents = | ||||||
|               GetOffset<ElfClass, char>(elf_header, |               GetOffset<ElfClass, char>(elf_header, | ||||||
|                                         gnu_debuglink_section->sh_offset); |                                         gnu_debuglink_section->sh_offset); | ||||||
|           string debuglink_file |           string debuglink_file = | ||||||
|               = ReadDebugLink<ElfClass>(debuglink_contents, |               ReadDebugLink(debuglink_contents, | ||||||
|                             gnu_debuglink_section->sh_size, |                             gnu_debuglink_section->sh_size, | ||||||
|                                         obj_file, info->debug_dirs()); |                             big_endian, | ||||||
|  |                             obj_file, | ||||||
|  |                             info->debug_dirs()); | ||||||
|           info->set_debuglink_file(debuglink_file); |           info->set_debuglink_file(debuglink_file); | ||||||
|         } else { |         } else { | ||||||
|           fprintf(stderr, ".gnu_debuglink section found in '%s', " |           fprintf(stderr, ".gnu_debuglink section found in '%s', " | ||||||
| @ -664,10 +709,10 @@ bool LoadSymbols(const string& obj_file, | |||||||
|         fprintf(stderr, "%s does not contain a .gnu_debuglink section.\n", |         fprintf(stderr, "%s does not contain a .gnu_debuglink section.\n", | ||||||
|                 obj_file.c_str()); |                 obj_file.c_str()); | ||||||
|       } |       } | ||||||
|     } else { |     } | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|   if (options.symbol_data != ONLY_CFI) { |   if (options.symbol_data != ONLY_CFI) { | ||||||
|         // The caller doesn't want to consult .gnu_debuglink.
 |  | ||||||
|         // See if there are export symbols available.
 |  | ||||||
|     const Shdr* dynsym_section = |     const Shdr* dynsym_section = | ||||||
|       FindElfSectionByName<ElfClass>(".dynsym", SHT_DYNSYM, |       FindElfSectionByName<ElfClass>(".dynsym", SHT_DYNSYM, | ||||||
|                                      sections, names, names_end, |                                      sections, names, names_end, | ||||||
| @ -697,19 +742,14 @@ bool LoadSymbols(const string& obj_file, | |||||||
|     } |     } | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|       // Return true if some usable information was found, since
 |   if (read_gnu_debug_link) { | ||||||
|       // the caller doesn't want to use .gnu_debuglink.
 |     return found_debug_info_section; | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   // Return true if some usable information was found
 | ||||||
|   return found_usable_info; |   return found_usable_info; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|     // No debug info was found, let the user try again with .gnu_debuglink
 |  | ||||||
|     // if present.
 |  | ||||||
|     return false; |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   return true; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // Return the breakpad symbol file identifier for the architecture of
 | // Return the breakpad symbol file identifier for the architecture of
 | ||||||
| // ELF_HEADER.
 | // ELF_HEADER.
 | ||||||
| template<typename ElfClass> | template<typename ElfClass> | ||||||
| @ -719,6 +759,7 @@ const char* ElfArchitecture(const typename ElfClass::Ehdr* elf_header) { | |||||||
|   switch (arch) { |   switch (arch) { | ||||||
|     case EM_386:        return "x86"; |     case EM_386:        return "x86"; | ||||||
|     case EM_ARM:        return "arm"; |     case EM_ARM:        return "arm"; | ||||||
|  |     case EM_AARCH64:    return "arm64"; | ||||||
|     case EM_MIPS:       return "mips"; |     case EM_MIPS:       return "mips"; | ||||||
|     case EM_PPC64:      return "ppc64"; |     case EM_PPC64:      return "ppc64"; | ||||||
|     case EM_PPC:        return "ppc"; |     case EM_PPC:        return "ppc"; | ||||||
|  | |||||||
| @ -37,11 +37,22 @@ | |||||||
| //
 | //
 | ||||||
| 
 | 
 | ||||||
| #define HANDLE_EINTR(x) ({ \ | #define HANDLE_EINTR(x) ({ \ | ||||||
|   typeof(x) __eintr_result__; \ |   typeof(x) eintr_wrapper_result; \ | ||||||
|   do { \ |   do { \ | ||||||
|     __eintr_result__ = x; \ |     eintr_wrapper_result = (x); \ | ||||||
|   } while (__eintr_result__ == -1 && errno == EINTR); \ |   } while (eintr_wrapper_result == -1 && errno == EINTR); \ | ||||||
|   __eintr_result__;\ |   eintr_wrapper_result; \ | ||||||
|  | }) | ||||||
|  | 
 | ||||||
|  | #define IGNORE_EINTR(x) ({ \ | ||||||
|  |   typeof(x) eintr_wrapper_result; \ | ||||||
|  |   do { \ | ||||||
|  |     eintr_wrapper_result = (x); \ | ||||||
|  |     if (eintr_wrapper_result == -1 && errno == EINTR) { \ | ||||||
|  |       eintr_wrapper_result = 0; \ | ||||||
|  |     } \ | ||||||
|  |   } while (0); \ | ||||||
|  |   eintr_wrapper_result; \ | ||||||
| }) | }) | ||||||
| 
 | 
 | ||||||
| #endif  // COMMON_LINUX_EINTR_WRAPPER_H_
 | #endif  // COMMON_LINUX_EINTR_WRAPPER_H_
 | ||||||
|  | |||||||
| @ -70,7 +70,7 @@ TEST(ElfCoreDumpTest, TestElfHeader) { | |||||||
|   ElfCoreDump core; |   ElfCoreDump core; | ||||||
| 
 | 
 | ||||||
|   ASSERT_TRUE(WriteFile(core_file, &header, sizeof(header) - 1)); |   ASSERT_TRUE(WriteFile(core_file, &header, sizeof(header) - 1)); | ||||||
|   ASSERT_TRUE(mapped_core_file.Map(core_file)); |   ASSERT_TRUE(mapped_core_file.Map(core_file, 0)); | ||||||
|   core.SetContent(mapped_core_file.content()); |   core.SetContent(mapped_core_file.content()); | ||||||
|   EXPECT_FALSE(core.IsValid()); |   EXPECT_FALSE(core.IsValid()); | ||||||
|   EXPECT_EQ(NULL, core.GetHeader()); |   EXPECT_EQ(NULL, core.GetHeader()); | ||||||
| @ -80,49 +80,49 @@ TEST(ElfCoreDumpTest, TestElfHeader) { | |||||||
|   EXPECT_FALSE(core.GetFirstNote().IsValid()); |   EXPECT_FALSE(core.GetFirstNote().IsValid()); | ||||||
| 
 | 
 | ||||||
|   ASSERT_TRUE(WriteFile(core_file, &header, sizeof(header))); |   ASSERT_TRUE(WriteFile(core_file, &header, sizeof(header))); | ||||||
|   ASSERT_TRUE(mapped_core_file.Map(core_file)); |   ASSERT_TRUE(mapped_core_file.Map(core_file, 0)); | ||||||
|   core.SetContent(mapped_core_file.content()); |   core.SetContent(mapped_core_file.content()); | ||||||
|   EXPECT_FALSE(core.IsValid()); |   EXPECT_FALSE(core.IsValid()); | ||||||
| 
 | 
 | ||||||
|   header.e_ident[0] = ELFMAG0; |   header.e_ident[0] = ELFMAG0; | ||||||
|   ASSERT_TRUE(WriteFile(core_file, &header, sizeof(header))); |   ASSERT_TRUE(WriteFile(core_file, &header, sizeof(header))); | ||||||
|   ASSERT_TRUE(mapped_core_file.Map(core_file)); |   ASSERT_TRUE(mapped_core_file.Map(core_file, 0)); | ||||||
|   core.SetContent(mapped_core_file.content()); |   core.SetContent(mapped_core_file.content()); | ||||||
|   EXPECT_FALSE(core.IsValid()); |   EXPECT_FALSE(core.IsValid()); | ||||||
| 
 | 
 | ||||||
|   header.e_ident[1] = ELFMAG1; |   header.e_ident[1] = ELFMAG1; | ||||||
|   ASSERT_TRUE(WriteFile(core_file, &header, sizeof(header))); |   ASSERT_TRUE(WriteFile(core_file, &header, sizeof(header))); | ||||||
|   ASSERT_TRUE(mapped_core_file.Map(core_file)); |   ASSERT_TRUE(mapped_core_file.Map(core_file, 0)); | ||||||
|   core.SetContent(mapped_core_file.content()); |   core.SetContent(mapped_core_file.content()); | ||||||
|   EXPECT_FALSE(core.IsValid()); |   EXPECT_FALSE(core.IsValid()); | ||||||
| 
 | 
 | ||||||
|   header.e_ident[2] = ELFMAG2; |   header.e_ident[2] = ELFMAG2; | ||||||
|   ASSERT_TRUE(WriteFile(core_file, &header, sizeof(header))); |   ASSERT_TRUE(WriteFile(core_file, &header, sizeof(header))); | ||||||
|   ASSERT_TRUE(mapped_core_file.Map(core_file)); |   ASSERT_TRUE(mapped_core_file.Map(core_file, 0)); | ||||||
|   core.SetContent(mapped_core_file.content()); |   core.SetContent(mapped_core_file.content()); | ||||||
|   EXPECT_FALSE(core.IsValid()); |   EXPECT_FALSE(core.IsValid()); | ||||||
| 
 | 
 | ||||||
|   header.e_ident[3] = ELFMAG3; |   header.e_ident[3] = ELFMAG3; | ||||||
|   ASSERT_TRUE(WriteFile(core_file, &header, sizeof(header))); |   ASSERT_TRUE(WriteFile(core_file, &header, sizeof(header))); | ||||||
|   ASSERT_TRUE(mapped_core_file.Map(core_file)); |   ASSERT_TRUE(mapped_core_file.Map(core_file, 0)); | ||||||
|   core.SetContent(mapped_core_file.content()); |   core.SetContent(mapped_core_file.content()); | ||||||
|   EXPECT_FALSE(core.IsValid()); |   EXPECT_FALSE(core.IsValid()); | ||||||
| 
 | 
 | ||||||
|   header.e_ident[4] = ElfCoreDump::kClass; |   header.e_ident[4] = ElfCoreDump::kClass; | ||||||
|   ASSERT_TRUE(WriteFile(core_file, &header, sizeof(header))); |   ASSERT_TRUE(WriteFile(core_file, &header, sizeof(header))); | ||||||
|   ASSERT_TRUE(mapped_core_file.Map(core_file)); |   ASSERT_TRUE(mapped_core_file.Map(core_file, 0)); | ||||||
|   core.SetContent(mapped_core_file.content()); |   core.SetContent(mapped_core_file.content()); | ||||||
|   EXPECT_FALSE(core.IsValid()); |   EXPECT_FALSE(core.IsValid()); | ||||||
| 
 | 
 | ||||||
|   header.e_version = EV_CURRENT; |   header.e_version = EV_CURRENT; | ||||||
|   ASSERT_TRUE(WriteFile(core_file, &header, sizeof(header))); |   ASSERT_TRUE(WriteFile(core_file, &header, sizeof(header))); | ||||||
|   ASSERT_TRUE(mapped_core_file.Map(core_file)); |   ASSERT_TRUE(mapped_core_file.Map(core_file, 0)); | ||||||
|   core.SetContent(mapped_core_file.content()); |   core.SetContent(mapped_core_file.content()); | ||||||
|   EXPECT_FALSE(core.IsValid()); |   EXPECT_FALSE(core.IsValid()); | ||||||
| 
 | 
 | ||||||
|   header.e_type = ET_CORE; |   header.e_type = ET_CORE; | ||||||
|   ASSERT_TRUE(WriteFile(core_file, &header, sizeof(header))); |   ASSERT_TRUE(WriteFile(core_file, &header, sizeof(header))); | ||||||
|   ASSERT_TRUE(mapped_core_file.Map(core_file)); |   ASSERT_TRUE(mapped_core_file.Map(core_file, 0)); | ||||||
|   core.SetContent(mapped_core_file.content()); |   core.SetContent(mapped_core_file.content()); | ||||||
|   EXPECT_TRUE(core.IsValid()); |   EXPECT_TRUE(core.IsValid()); | ||||||
| } | } | ||||||
| @ -138,22 +138,26 @@ TEST(ElfCoreDumpTest, ValidCoreFile) { | |||||||
|   const unsigned kNumOfThreads = 3; |   const unsigned kNumOfThreads = 3; | ||||||
|   const unsigned kCrashThread = 1; |   const unsigned kCrashThread = 1; | ||||||
|   const int kCrashSignal = SIGABRT; |   const int kCrashSignal = SIGABRT; | ||||||
|   // TODO(benchan): Revert to use ASSERT_TRUE once the flakiness in
 |   ASSERT_TRUE(crash_generator.CreateChildCrash(kNumOfThreads, kCrashThread, | ||||||
|   // CrashGenerator is identified and fixed.
 |                                                kCrashSignal, NULL)); | ||||||
|   if (!crash_generator.CreateChildCrash(kNumOfThreads, kCrashThread, |  | ||||||
|                                         kCrashSignal, NULL)) { |  | ||||||
|     fprintf(stderr, "ElfCoreDumpTest.ValidCoreFile test is skipped " |  | ||||||
|             "due to no core dump generated"); |  | ||||||
|     return; |  | ||||||
|   } |  | ||||||
|   pid_t expected_crash_thread_id = crash_generator.GetThreadId(kCrashThread); |   pid_t expected_crash_thread_id = crash_generator.GetThreadId(kCrashThread); | ||||||
|   set<pid_t> expected_thread_ids; |   set<pid_t> expected_thread_ids; | ||||||
|   for (unsigned i = 0; i < kNumOfThreads; ++i) { |   for (unsigned i = 0; i < kNumOfThreads; ++i) { | ||||||
|     expected_thread_ids.insert(crash_generator.GetThreadId(i)); |     expected_thread_ids.insert(crash_generator.GetThreadId(i)); | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|  | #if defined(__ANDROID__) | ||||||
|  |   struct stat st; | ||||||
|  |   if (stat(crash_generator.GetCoreFilePath().c_str(), &st) != 0) { | ||||||
|  |     fprintf(stderr, "ElfCoreDumpTest.ValidCoreFile test is skipped " | ||||||
|  |             "due to no core file being generated"); | ||||||
|  |     return; | ||||||
|  |   } | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|   MemoryMappedFile mapped_core_file; |   MemoryMappedFile mapped_core_file; | ||||||
|   ASSERT_TRUE(mapped_core_file.Map(crash_generator.GetCoreFilePath().c_str())); |   ASSERT_TRUE( | ||||||
|  |       mapped_core_file.Map(crash_generator.GetCoreFilePath().c_str(), 0)); | ||||||
| 
 | 
 | ||||||
|   ElfCoreDump core; |   ElfCoreDump core; | ||||||
|   core.SetContent(mapped_core_file.content()); |   core.SetContent(mapped_core_file.content()); | ||||||
| @ -182,6 +186,7 @@ TEST(ElfCoreDumpTest, ValidCoreFile) { | |||||||
| 
 | 
 | ||||||
|   size_t num_nt_prpsinfo = 0; |   size_t num_nt_prpsinfo = 0; | ||||||
|   size_t num_nt_prstatus = 0; |   size_t num_nt_prstatus = 0; | ||||||
|  |   size_t num_pr_fpvalid = 0; | ||||||
| #if defined(__i386__) || defined(__x86_64__) | #if defined(__i386__) || defined(__x86_64__) | ||||||
|   size_t num_nt_fpregset = 0; |   size_t num_nt_fpregset = 0; | ||||||
| #endif | #endif | ||||||
| @ -213,6 +218,8 @@ TEST(ElfCoreDumpTest, ValidCoreFile) { | |||||||
|           EXPECT_EQ(kCrashSignal, status->pr_info.si_signo); |           EXPECT_EQ(kCrashSignal, status->pr_info.si_signo); | ||||||
|         } |         } | ||||||
|         ++num_nt_prstatus; |         ++num_nt_prstatus; | ||||||
|  |         if (status->pr_fpvalid) | ||||||
|  |           ++num_pr_fpvalid; | ||||||
|         break; |         break; | ||||||
|       } |       } | ||||||
| #if defined(__i386__) || defined(__x86_64__) | #if defined(__i386__) || defined(__x86_64__) | ||||||
| @ -241,9 +248,9 @@ TEST(ElfCoreDumpTest, ValidCoreFile) { | |||||||
|   EXPECT_EQ(1U, num_nt_prpsinfo); |   EXPECT_EQ(1U, num_nt_prpsinfo); | ||||||
|   EXPECT_EQ(kNumOfThreads, num_nt_prstatus); |   EXPECT_EQ(kNumOfThreads, num_nt_prstatus); | ||||||
| #if defined(__i386__) || defined(__x86_64__) | #if defined(__i386__) || defined(__x86_64__) | ||||||
|   EXPECT_EQ(kNumOfThreads, num_nt_fpregset); |   EXPECT_EQ(num_pr_fpvalid, num_nt_fpregset); | ||||||
| #endif | #endif | ||||||
| #if defined(__i386__) | #if defined(__i386__) | ||||||
|   EXPECT_EQ(kNumOfThreads, num_nt_prxfpreg); |   EXPECT_EQ(num_pr_fpvalid, num_nt_prxfpreg); | ||||||
| #endif | #endif | ||||||
| } | } | ||||||
|  | |||||||
| @ -44,7 +44,7 @@ void FindElfClassSection(const char *elf_base, | |||||||
|                          const char *section_name, |                          const char *section_name, | ||||||
|                          typename ElfClass::Word section_type, |                          typename ElfClass::Word section_type, | ||||||
|                          const void **section_start, |                          const void **section_start, | ||||||
|                          int *section_size) { |                          size_t *section_size) { | ||||||
|   typedef typename ElfClass::Ehdr Ehdr; |   typedef typename ElfClass::Ehdr Ehdr; | ||||||
|   typedef typename ElfClass::Shdr Shdr; |   typedef typename ElfClass::Shdr Shdr; | ||||||
| 
 | 
 | ||||||
| @ -79,7 +79,7 @@ template<typename ElfClass> | |||||||
| void FindElfClassSegment(const char *elf_base, | void FindElfClassSegment(const char *elf_base, | ||||||
|                          typename ElfClass::Word segment_type, |                          typename ElfClass::Word segment_type, | ||||||
|                          const void **segment_start, |                          const void **segment_start, | ||||||
|                          int *segment_size) { |                          size_t *segment_size) { | ||||||
|   typedef typename ElfClass::Ehdr Ehdr; |   typedef typename ElfClass::Ehdr Ehdr; | ||||||
|   typedef typename ElfClass::Phdr Phdr; |   typedef typename ElfClass::Phdr Phdr; | ||||||
| 
 | 
 | ||||||
| @ -122,7 +122,7 @@ bool FindElfSection(const void *elf_mapped_base, | |||||||
|                     const char *section_name, |                     const char *section_name, | ||||||
|                     uint32_t section_type, |                     uint32_t section_type, | ||||||
|                     const void **section_start, |                     const void **section_start, | ||||||
|                     int *section_size, |                     size_t *section_size, | ||||||
|                     int *elfclass) { |                     int *elfclass) { | ||||||
|   assert(elf_mapped_base); |   assert(elf_mapped_base); | ||||||
|   assert(section_start); |   assert(section_start); | ||||||
| @ -158,7 +158,7 @@ bool FindElfSection(const void *elf_mapped_base, | |||||||
| bool FindElfSegment(const void *elf_mapped_base, | bool FindElfSegment(const void *elf_mapped_base, | ||||||
|                     uint32_t segment_type, |                     uint32_t segment_type, | ||||||
|                     const void **segment_start, |                     const void **segment_start, | ||||||
|                     int *segment_size, |                     size_t *segment_size, | ||||||
|                     int *elfclass) { |                     int *elfclass) { | ||||||
|   assert(elf_mapped_base); |   assert(elf_mapped_base); | ||||||
|   assert(segment_start); |   assert(segment_start); | ||||||
|  | |||||||
| @ -30,8 +30,8 @@ | |||||||
| // elfutils.h: Utilities for dealing with ELF files.
 | // elfutils.h: Utilities for dealing with ELF files.
 | ||||||
| //
 | //
 | ||||||
| 
 | 
 | ||||||
| #ifndef COMMON_LINUX_ELFUTILS_H__ | #ifndef COMMON_LINUX_ELFUTILS_H_ | ||||||
| #define COMMON_LINUX_ELFUTILS_H__ | #define COMMON_LINUX_ELFUTILS_H_ | ||||||
| 
 | 
 | ||||||
| #include <elf.h> | #include <elf.h> | ||||||
| #include <link.h> | #include <link.h> | ||||||
| @ -79,7 +79,7 @@ bool FindElfSection(const void *elf_mapped_base, | |||||||
|                     const char *section_name, |                     const char *section_name, | ||||||
|                     uint32_t section_type, |                     uint32_t section_type, | ||||||
|                     const void **section_start, |                     const void **section_start, | ||||||
|                     int *section_size, |                     size_t *section_size, | ||||||
|                     int *elfclass); |                     int *elfclass); | ||||||
| 
 | 
 | ||||||
| // Internal helper method, exposed for convenience for callers
 | // Internal helper method, exposed for convenience for callers
 | ||||||
| @ -101,7 +101,7 @@ FindElfSectionByName(const char* name, | |||||||
| bool FindElfSegment(const void *elf_mapped_base, | bool FindElfSegment(const void *elf_mapped_base, | ||||||
|                     uint32_t segment_type, |                     uint32_t segment_type, | ||||||
|                     const void **segment_start, |                     const void **segment_start, | ||||||
|                     int *segment_size, |                     size_t *segment_size, | ||||||
|                     int *elfclass); |                     int *elfclass); | ||||||
| 
 | 
 | ||||||
| // Convert an offset from an Elf header into a pointer to the mapped
 | // Convert an offset from an Elf header into a pointer to the mapped
 | ||||||
| @ -115,4 +115,4 @@ GetOffset(const typename ElfClass::Ehdr* elf_header, | |||||||
| 
 | 
 | ||||||
| }  // namespace google_breakpad
 | }  // namespace google_breakpad
 | ||||||
| 
 | 
 | ||||||
| #endif  // COMMON_LINUX_ELFUTILS_H__
 | #endif  // COMMON_LINUX_ELFUTILS_H_
 | ||||||
|  | |||||||
| @ -48,9 +48,7 @@ | |||||||
| 
 | 
 | ||||||
| namespace google_breakpad { | namespace google_breakpad { | ||||||
| 
 | 
 | ||||||
| FileID::FileID(const char* path) { | FileID::FileID(const char* path) : path_(path) {} | ||||||
|   strncpy(path_, path, sizeof(path_)); |  | ||||||
| } |  | ||||||
| 
 | 
 | ||||||
| // ELF note name and desc are 32-bits word padded.
 | // ELF note name and desc are 32-bits word padded.
 | ||||||
| #define NOTE_PADDING(a) ((a + 3) & ~3) | #define NOTE_PADDING(a) ((a + 3) & ~3) | ||||||
| @ -59,7 +57,7 @@ FileID::FileID(const char* path) { | |||||||
| // and use the syscall/libc wrappers instead of direct syscalls or libc.
 | // and use the syscall/libc wrappers instead of direct syscalls or libc.
 | ||||||
| 
 | 
 | ||||||
| template<typename ElfClass> | template<typename ElfClass> | ||||||
| static bool ElfClassBuildIDNoteIdentifier(const void *section, int length, | static bool ElfClassBuildIDNoteIdentifier(const void *section, size_t length, | ||||||
|                                           uint8_t identifier[kMDGUIDSize]) { |                                           uint8_t identifier[kMDGUIDSize]) { | ||||||
|   typedef typename ElfClass::Nhdr Nhdr; |   typedef typename ElfClass::Nhdr Nhdr; | ||||||
| 
 | 
 | ||||||
| @ -94,7 +92,8 @@ static bool ElfClassBuildIDNoteIdentifier(const void *section, int length, | |||||||
| static bool FindElfBuildIDNote(const void *elf_mapped_base, | static bool FindElfBuildIDNote(const void *elf_mapped_base, | ||||||
|                                uint8_t identifier[kMDGUIDSize]) { |                                uint8_t identifier[kMDGUIDSize]) { | ||||||
|   void* note_section; |   void* note_section; | ||||||
|   int note_size, elfclass; |   size_t note_size; | ||||||
|  |   int elfclass; | ||||||
|   if ((!FindElfSegment(elf_mapped_base, PT_NOTE, |   if ((!FindElfSegment(elf_mapped_base, PT_NOTE, | ||||||
|                        (const void**)¬e_section, ¬e_size, &elfclass) || |                        (const void**)¬e_section, ¬e_size, &elfclass) || | ||||||
|       note_size == 0)  && |       note_size == 0)  && | ||||||
| @ -120,7 +119,7 @@ static bool FindElfBuildIDNote(const void *elf_mapped_base, | |||||||
| static bool HashElfTextSection(const void *elf_mapped_base, | static bool HashElfTextSection(const void *elf_mapped_base, | ||||||
|                                uint8_t identifier[kMDGUIDSize]) { |                                uint8_t identifier[kMDGUIDSize]) { | ||||||
|   void* text_section; |   void* text_section; | ||||||
|   int text_size; |   size_t text_size; | ||||||
|   if (!FindElfSection(elf_mapped_base, ".text", SHT_PROGBITS, |   if (!FindElfSection(elf_mapped_base, ".text", SHT_PROGBITS, | ||||||
|                       (const void**)&text_section, &text_size, NULL) || |                       (const void**)&text_section, &text_size, NULL) || | ||||||
|       text_size == 0) { |       text_size == 0) { | ||||||
| @ -129,7 +128,7 @@ static bool HashElfTextSection(const void *elf_mapped_base, | |||||||
| 
 | 
 | ||||||
|   my_memset(identifier, 0, kMDGUIDSize); |   my_memset(identifier, 0, kMDGUIDSize); | ||||||
|   const uint8_t* ptr = reinterpret_cast<const uint8_t*>(text_section); |   const uint8_t* ptr = reinterpret_cast<const uint8_t*>(text_section); | ||||||
|   const uint8_t* ptr_end = ptr + std::min(text_size, 4096); |   const uint8_t* ptr_end = ptr + std::min(text_size, static_cast<size_t>(4096)); | ||||||
|   while (ptr < ptr_end) { |   while (ptr < ptr_end) { | ||||||
|     for (unsigned i = 0; i < kMDGUIDSize; i++) |     for (unsigned i = 0; i < kMDGUIDSize; i++) | ||||||
|       identifier[i] ^= ptr[i]; |       identifier[i] ^= ptr[i]; | ||||||
| @ -150,7 +149,7 @@ bool FileID::ElfFileIdentifierFromMappedFile(const void* base, | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| bool FileID::ElfFileIdentifier(uint8_t identifier[kMDGUIDSize]) { | bool FileID::ElfFileIdentifier(uint8_t identifier[kMDGUIDSize]) { | ||||||
|   MemoryMappedFile mapped_file(path_); |   MemoryMappedFile mapped_file(path_.c_str(), 0); | ||||||
|   if (!mapped_file.data())  // Should probably check if size >= ElfW(Ehdr)?
 |   if (!mapped_file.data())  // Should probably check if size >= ElfW(Ehdr)?
 | ||||||
|     return false; |     return false; | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -34,6 +34,7 @@ | |||||||
| #define COMMON_LINUX_FILE_ID_H__ | #define COMMON_LINUX_FILE_ID_H__ | ||||||
| 
 | 
 | ||||||
| #include <limits.h> | #include <limits.h> | ||||||
|  | #include <string> | ||||||
| 
 | 
 | ||||||
| #include "common/linux/guid_creator.h" | #include "common/linux/guid_creator.h" | ||||||
| 
 | 
 | ||||||
| @ -69,7 +70,7 @@ class FileID { | |||||||
| 
 | 
 | ||||||
|  private: |  private: | ||||||
|   // Storage for the path specified
 |   // Storage for the path specified
 | ||||||
|   char path_[PATH_MAX]; |   std::string path_; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| }  // namespace google_breakpad
 | }  // namespace google_breakpad
 | ||||||
|  | |||||||
| @ -66,6 +66,9 @@ void PopulateSection(Section* section, int size, int prime_number) { | |||||||
| 
 | 
 | ||||||
| }  // namespace
 | }  // namespace
 | ||||||
| 
 | 
 | ||||||
|  | #ifndef __ANDROID__ | ||||||
|  | // This test is disabled on Android: It will always fail, since there is no
 | ||||||
|  | // 'strip' binary installed on test devices.
 | ||||||
| TEST(FileIDStripTest, StripSelf) { | TEST(FileIDStripTest, StripSelf) { | ||||||
|   // Calculate the File ID of this binary using
 |   // Calculate the File ID of this binary using
 | ||||||
|   // FileID::ElfFileIdentifier, then make a copy of this binary,
 |   // FileID::ElfFileIdentifier, then make a copy of this binary,
 | ||||||
| @ -98,6 +101,7 @@ TEST(FileIDStripTest, StripSelf) { | |||||||
|                                     37); |                                     37); | ||||||
|   EXPECT_STREQ(identifier_string1, identifier_string2); |   EXPECT_STREQ(identifier_string1, identifier_string2); | ||||||
| } | } | ||||||
|  | #endif  // !__ANDROID__
 | ||||||
| 
 | 
 | ||||||
| template<typename ElfClass> | template<typename ElfClass> | ||||||
| class FileIDTest : public testing::Test { | class FileIDTest : public testing::Test { | ||||||
|  | |||||||
| @ -29,7 +29,6 @@ | |||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| #include "common/linux/google_crashdump_uploader.h" | #include "common/linux/google_crashdump_uploader.h" | ||||||
| #include "common/linux/libcurl_wrapper.h" |  | ||||||
| 
 | 
 | ||||||
| #include <sys/types.h> | #include <sys/types.h> | ||||||
| #include <sys/stat.h> | #include <sys/stat.h> | ||||||
| @ -112,7 +111,7 @@ void GoogleCrashdumpUploader::Init(const string& product, | |||||||
|   ctime_ = ctime; |   ctime_ = ctime; | ||||||
|   email_ = email; |   email_ = email; | ||||||
|   comments_ = comments; |   comments_ = comments; | ||||||
|   http_layer_ = http_layer; |   http_layer_.reset(http_layer); | ||||||
| 
 | 
 | ||||||
|   crash_server_ = crash_server; |   crash_server_ = crash_server; | ||||||
|   proxy_host_ = proxy_host; |   proxy_host_ = proxy_host; | ||||||
| @ -162,7 +161,9 @@ bool GoogleCrashdumpUploader::CheckRequiredParametersArePresent() { | |||||||
| 
 | 
 | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| bool GoogleCrashdumpUploader::Upload() { | bool GoogleCrashdumpUploader::Upload(int* http_status_code, | ||||||
|  |                                      string* http_response_header, | ||||||
|  |                                      string* http_response_body) { | ||||||
|   bool ok = http_layer_->Init(); |   bool ok = http_layer_->Init(); | ||||||
|   if (!ok) { |   if (!ok) { | ||||||
|     std::cout << "http layer init failed"; |     std::cout << "http layer init failed"; | ||||||
| @ -194,6 +195,8 @@ bool GoogleCrashdumpUploader::Upload() { | |||||||
|   std::cout << "Sending request to " << crash_server_; |   std::cout << "Sending request to " << crash_server_; | ||||||
|   return http_layer_->SendRequest(crash_server_, |   return http_layer_->SendRequest(crash_server_, | ||||||
|                                   parameters_, |                                   parameters_, | ||||||
|                                   NULL); |                                   http_status_code, | ||||||
|  |                                   http_response_header, | ||||||
|  |                                   http_response_body); | ||||||
| } | } | ||||||
| } | } | ||||||
|  | |||||||
| @ -28,15 +28,18 @@ | |||||||
| // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | #ifndef COMMON_LINUX_GOOGLE_CRASHDUMP_UPLOADER_H_ | ||||||
|  | #define COMMON_LINUX_GOOGLE_CRASHDUMP_UPLOADER_H_ | ||||||
|  | 
 | ||||||
| #include <string> | #include <string> | ||||||
| #include <map> | #include <map> | ||||||
| 
 | 
 | ||||||
|  | #include "common/linux/libcurl_wrapper.h" | ||||||
|  | #include "common/scoped_ptr.h" | ||||||
| #include "common/using_std_string.h" | #include "common/using_std_string.h" | ||||||
| 
 | 
 | ||||||
| namespace google_breakpad { | namespace google_breakpad { | ||||||
| 
 | 
 | ||||||
| class LibcurlWrapper; |  | ||||||
| 
 |  | ||||||
| class GoogleCrashdumpUploader { | class GoogleCrashdumpUploader { | ||||||
|  public: |  public: | ||||||
|   GoogleCrashdumpUploader(const string& product, |   GoogleCrashdumpUploader(const string& product, | ||||||
| @ -76,12 +79,14 @@ class GoogleCrashdumpUploader { | |||||||
|             const string& proxy_host, |             const string& proxy_host, | ||||||
|             const string& proxy_userpassword, |             const string& proxy_userpassword, | ||||||
|             LibcurlWrapper* http_layer); |             LibcurlWrapper* http_layer); | ||||||
|   bool Upload(); |   bool Upload(int* http_status_code, | ||||||
|  |               string* http_response_header, | ||||||
|  |               string* http_response_body); | ||||||
| 
 | 
 | ||||||
|  private: |  private: | ||||||
|   bool CheckRequiredParametersArePresent(); |   bool CheckRequiredParametersArePresent(); | ||||||
| 
 | 
 | ||||||
|   LibcurlWrapper* http_layer_; |   scoped_ptr<LibcurlWrapper> http_layer_; | ||||||
|   string product_; |   string product_; | ||||||
|   string version_; |   string version_; | ||||||
|   string guid_; |   string guid_; | ||||||
| @ -98,3 +103,5 @@ class GoogleCrashdumpUploader { | |||||||
|   std::map<string, string> parameters_; |   std::map<string, string> parameters_; | ||||||
| }; | }; | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | #endif  // COMMON_LINUX_GOOGLE_CRASHDUMP_UPLOADER_H_
 | ||||||
|  | |||||||
| @ -32,7 +32,6 @@ | |||||||
| #include <string> | #include <string> | ||||||
| 
 | 
 | ||||||
| #include "common/linux/google_crashdump_uploader.h" | #include "common/linux/google_crashdump_uploader.h" | ||||||
| #include "common/linux/libcurl_wrapper.h" |  | ||||||
| #include "breakpad_googletest_includes.h" | #include "breakpad_googletest_includes.h" | ||||||
| #include "common/using_std_string.h" | #include "common/using_std_string.h" | ||||||
| 
 | 
 | ||||||
| @ -48,10 +47,12 @@ class MockLibcurlWrapper : public LibcurlWrapper { | |||||||
|                               const string& proxy_userpwd)); |                               const string& proxy_userpwd)); | ||||||
|   MOCK_METHOD2(AddFile, bool(const string& upload_file_path, |   MOCK_METHOD2(AddFile, bool(const string& upload_file_path, | ||||||
|                              const string& basename)); |                              const string& basename)); | ||||||
|   MOCK_METHOD3(SendRequest, |   MOCK_METHOD5(SendRequest, | ||||||
|                bool(const string& url, |                bool(const string& url, | ||||||
|                     const std::map<string, string>& parameters, |                     const std::map<string, string>& parameters, | ||||||
|                     string* server_response)); |                     int* http_status_code, | ||||||
|  |                     string* http_header_data, | ||||||
|  |                     string* http_response_data)); | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| class GoogleCrashdumpUploaderTest : public ::testing::Test { | class GoogleCrashdumpUploaderTest : public ::testing::Test { | ||||||
| @ -72,7 +73,7 @@ TEST_F(GoogleCrashdumpUploaderTest, InitFailsCausesUploadFailure) { | |||||||
|                                                                   "", |                                                                   "", | ||||||
|                                                                   "", |                                                                   "", | ||||||
|                                                                   &m); |                                                                   &m); | ||||||
|   ASSERT_FALSE(uploader->Upload()); |   ASSERT_FALSE(uploader->Upload(NULL, NULL, NULL)); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| TEST_F(GoogleCrashdumpUploaderTest, TestSendRequestHappensWithValidParameters) { | TEST_F(GoogleCrashdumpUploaderTest, TestSendRequestHappensWithValidParameters) { | ||||||
| @ -86,7 +87,7 @@ TEST_F(GoogleCrashdumpUploaderTest, TestSendRequestHappensWithValidParameters) { | |||||||
|   EXPECT_CALL(m, Init()).Times(1).WillOnce(Return(true)); |   EXPECT_CALL(m, Init()).Times(1).WillOnce(Return(true)); | ||||||
|   EXPECT_CALL(m, AddFile(tempfn, _)).WillOnce(Return(true)); |   EXPECT_CALL(m, AddFile(tempfn, _)).WillOnce(Return(true)); | ||||||
|   EXPECT_CALL(m, |   EXPECT_CALL(m, | ||||||
|               SendRequest("http://foo.com",_,_)).Times(1).WillOnce(Return(true)); |               SendRequest("http://foo.com",_,_,_,_)).Times(1).WillOnce(Return(true)); | ||||||
|   GoogleCrashdumpUploader *uploader = new GoogleCrashdumpUploader("foobar", |   GoogleCrashdumpUploader *uploader = new GoogleCrashdumpUploader("foobar", | ||||||
|                                                                   "1.0", |                                                                   "1.0", | ||||||
|                                                                   "AAA-BBB", |                                                                   "AAA-BBB", | ||||||
| @ -99,14 +100,14 @@ TEST_F(GoogleCrashdumpUploaderTest, TestSendRequestHappensWithValidParameters) { | |||||||
|                                                                   "", |                                                                   "", | ||||||
|                                                                   "", |                                                                   "", | ||||||
|                                                                   &m); |                                                                   &m); | ||||||
|   ASSERT_TRUE(uploader->Upload()); |   ASSERT_TRUE(uploader->Upload(NULL, NULL, NULL)); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| TEST_F(GoogleCrashdumpUploaderTest, InvalidPathname) { | TEST_F(GoogleCrashdumpUploaderTest, InvalidPathname) { | ||||||
|   MockLibcurlWrapper m; |   MockLibcurlWrapper m; | ||||||
|   EXPECT_CALL(m, Init()).Times(1).WillOnce(Return(true)); |   EXPECT_CALL(m, Init()).Times(1).WillOnce(Return(true)); | ||||||
|   EXPECT_CALL(m, SendRequest(_,_,_)).Times(0); |   EXPECT_CALL(m, SendRequest(_,_,_,_,_)).Times(0); | ||||||
|   GoogleCrashdumpUploader *uploader = new GoogleCrashdumpUploader("foobar", |   GoogleCrashdumpUploader *uploader = new GoogleCrashdumpUploader("foobar", | ||||||
|                                                                   "1.0", |                                                                   "1.0", | ||||||
|                                                                   "AAA-BBB", |                                                                   "AAA-BBB", | ||||||
| @ -119,7 +120,7 @@ TEST_F(GoogleCrashdumpUploaderTest, InvalidPathname) { | |||||||
|                                                                   "", |                                                                   "", | ||||||
|                                                                   "", |                                                                   "", | ||||||
|                                                                   &m); |                                                                   &m); | ||||||
|   ASSERT_FALSE(uploader->Upload()); |   ASSERT_FALSE(uploader->Upload(NULL, NULL, NULL)); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| TEST_F(GoogleCrashdumpUploaderTest, TestRequiredParametersMustBePresent) { | TEST_F(GoogleCrashdumpUploaderTest, TestRequiredParametersMustBePresent) { | ||||||
| @ -135,7 +136,7 @@ TEST_F(GoogleCrashdumpUploaderTest, TestRequiredParametersMustBePresent) { | |||||||
|                                    "http://foo.com", |                                    "http://foo.com", | ||||||
|                                    "", |                                    "", | ||||||
|                                    ""); |                                    ""); | ||||||
|   ASSERT_FALSE(uploader.Upload()); |   ASSERT_FALSE(uploader.Upload(NULL, NULL, NULL)); | ||||||
| 
 | 
 | ||||||
|   // Test with empty product version.
 |   // Test with empty product version.
 | ||||||
|   GoogleCrashdumpUploader uploader1("product", |   GoogleCrashdumpUploader uploader1("product", | ||||||
| @ -150,7 +151,7 @@ TEST_F(GoogleCrashdumpUploaderTest, TestRequiredParametersMustBePresent) { | |||||||
|                                     "", |                                     "", | ||||||
|                                     ""); |                                     ""); | ||||||
| 
 | 
 | ||||||
|   ASSERT_FALSE(uploader1.Upload()); |   ASSERT_FALSE(uploader1.Upload(NULL, NULL, NULL)); | ||||||
| 
 | 
 | ||||||
|   // Test with empty client GUID.
 |   // Test with empty client GUID.
 | ||||||
|   GoogleCrashdumpUploader uploader2("product", |   GoogleCrashdumpUploader uploader2("product", | ||||||
| @ -164,6 +165,6 @@ TEST_F(GoogleCrashdumpUploaderTest, TestRequiredParametersMustBePresent) { | |||||||
|                                     "", |                                     "", | ||||||
|                                     "", |                                     "", | ||||||
|                                     ""); |                                     ""); | ||||||
|   ASSERT_FALSE(uploader2.Upload()); |   ASSERT_FALSE(uploader2.Upload(NULL, NULL, NULL)); | ||||||
| } | } | ||||||
| } | } | ||||||
|  | |||||||
| @ -70,7 +70,17 @@ bool HTTPUpload::SendRequest(const string &url, | |||||||
|   if (!CheckParameters(parameters)) |   if (!CheckParameters(parameters)) | ||||||
|     return false; |     return false; | ||||||
| 
 | 
 | ||||||
|   void *curl_lib = dlopen("libcurl.so", RTLD_NOW); |   // We may have been linked statically; if curl_easy_init is in the
 | ||||||
|  |   // current binary, no need to search for a dynamic version.
 | ||||||
|  |   void* curl_lib = dlopen(NULL, RTLD_NOW); | ||||||
|  |   if (!curl_lib || dlsym(curl_lib, "curl_easy_init") == NULL) { | ||||||
|  |     dlerror();  // Clear dlerror before attempting to open libraries.
 | ||||||
|  |     dlclose(curl_lib); | ||||||
|  |     curl_lib = NULL; | ||||||
|  |   } | ||||||
|  |   if (!curl_lib) { | ||||||
|  |     curl_lib = dlopen("libcurl.so", RTLD_NOW); | ||||||
|  |   } | ||||||
|   if (!curl_lib) { |   if (!curl_lib) { | ||||||
|     if (error_description != NULL) |     if (error_description != NULL) | ||||||
|       *error_description = dlerror(); |       *error_description = dlerror(); | ||||||
|  | |||||||
| @ -57,6 +57,8 @@ LibcurlWrapper::LibcurlWrapper() | |||||||
|   return; |   return; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | LibcurlWrapper::~LibcurlWrapper() {} | ||||||
|  | 
 | ||||||
| bool LibcurlWrapper::SetProxy(const string& proxy_host, | bool LibcurlWrapper::SetProxy(const string& proxy_host, | ||||||
|                               const string& proxy_userpwd) { |                               const string& proxy_userpwd) { | ||||||
|   if (!init_ok_) { |   if (!init_ok_) { | ||||||
| @ -108,7 +110,9 @@ static size_t WriteCallback(void *ptr, size_t size, | |||||||
| 
 | 
 | ||||||
| bool LibcurlWrapper::SendRequest(const string& url, | bool LibcurlWrapper::SendRequest(const string& url, | ||||||
|                                  const std::map<string, string>& parameters, |                                  const std::map<string, string>& parameters, | ||||||
|                                  string* server_response) { |                                  int* http_status_code, | ||||||
|  |                                  string* http_header_data, | ||||||
|  |                                  string* http_response_data) { | ||||||
|   (*easy_setopt_)(curl_, CURLOPT_URL, url.c_str()); |   (*easy_setopt_)(curl_, CURLOPT_URL, url.c_str()); | ||||||
|   std::map<string, string>::const_iterator iter = parameters.begin(); |   std::map<string, string>::const_iterator iter = parameters.begin(); | ||||||
|   for (; iter != parameters.end(); ++iter) |   for (; iter != parameters.end(); ++iter) | ||||||
| @ -118,10 +122,17 @@ bool LibcurlWrapper::SendRequest(const string& url, | |||||||
|                 CURLFORM_END); |                 CURLFORM_END); | ||||||
| 
 | 
 | ||||||
|   (*easy_setopt_)(curl_, CURLOPT_HTTPPOST, formpost_); |   (*easy_setopt_)(curl_, CURLOPT_HTTPPOST, formpost_); | ||||||
|   if (server_response != NULL) { |   if (http_response_data != NULL) { | ||||||
|  |     http_response_data->clear(); | ||||||
|     (*easy_setopt_)(curl_, CURLOPT_WRITEFUNCTION, WriteCallback); |     (*easy_setopt_)(curl_, CURLOPT_WRITEFUNCTION, WriteCallback); | ||||||
|     (*easy_setopt_)(curl_, CURLOPT_WRITEDATA, |     (*easy_setopt_)(curl_, CURLOPT_WRITEDATA, | ||||||
|                      reinterpret_cast<void *>(server_response)); |                      reinterpret_cast<void *>(http_response_data)); | ||||||
|  |   } | ||||||
|  |   if (http_header_data != NULL) { | ||||||
|  |     http_header_data->clear(); | ||||||
|  |     (*easy_setopt_)(curl_, CURLOPT_HEADERFUNCTION, WriteCallback); | ||||||
|  |     (*easy_setopt_)(curl_, CURLOPT_HEADERDATA, | ||||||
|  |                      reinterpret_cast<void *>(http_header_data)); | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   CURLcode err_code = CURLE_OK; |   CURLcode err_code = CURLE_OK; | ||||||
| @ -129,6 +140,10 @@ bool LibcurlWrapper::SendRequest(const string& url, | |||||||
|   easy_strerror_ = reinterpret_cast<const char* (*)(CURLcode)> |   easy_strerror_ = reinterpret_cast<const char* (*)(CURLcode)> | ||||||
|                        (dlsym(curl_lib_, "curl_easy_strerror")); |                        (dlsym(curl_lib_, "curl_easy_strerror")); | ||||||
| 
 | 
 | ||||||
|  |   if (http_status_code != NULL) { | ||||||
|  |     (*easy_getinfo_)(curl_, CURLINFO_RESPONSE_CODE, http_status_code); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
| #ifndef NDEBUG | #ifndef NDEBUG | ||||||
|   if (err_code != CURLE_OK) |   if (err_code != CURLE_OK) | ||||||
|     fprintf(stderr, "Failed to send http request to %s, error: %s\n", |     fprintf(stderr, "Failed to send http request to %s, error: %s\n", | ||||||
| @ -209,6 +224,10 @@ bool LibcurlWrapper::SetFunctionPointers() { | |||||||
|                                  "curl_easy_cleanup", |                                  "curl_easy_cleanup", | ||||||
|                                  void(*)(CURL*)); |                                  void(*)(CURL*)); | ||||||
| 
 | 
 | ||||||
|  |   SET_AND_CHECK_FUNCTION_POINTER(easy_getinfo_, | ||||||
|  |                                  "curl_easy_getinfo", | ||||||
|  |                                  CURLcode(*)(CURL *, CURLINFO info, ...)); | ||||||
|  | 
 | ||||||
|   SET_AND_CHECK_FUNCTION_POINTER(slist_free_all_, |   SET_AND_CHECK_FUNCTION_POINTER(slist_free_all_, | ||||||
|                                  "curl_slist_free_all", |                                  "curl_slist_free_all", | ||||||
|                                  void(*)(curl_slist*)); |                                  void(*)(curl_slist*)); | ||||||
|  | |||||||
Some files were not shown because too many files have changed in this diff Show More
		Loading…
	
		Reference in New Issue
	
	Block a user