508 Commits

Author SHA1 Message Date
mark@chromium.org
3a642b92dc Merge trunk r875 to the chrome_15 branch.
Fix some shadow variables, including one in file_id.cc that causes all files to
generate the same hash. Add a test to make sure this doesn't happen again.

Review URL: http://breakpad.appspot.com/316002

Original patch by Lei Zhang <thestig@chromium.org>
Review URL: http://breakpad.appspot.com/320001

git-svn-id: http://google-breakpad.googlecode.com/svn/branches/chrome_15@877 4c0a9323-5329-0410-9bdc-e9ce6186880e
2011-10-20 21:38:01 +00:00
mark@chromium.org
cc8194139c Branch Breakpad trunk r844 for Chrome 15
git-svn-id: http://google-breakpad.googlecode.com/svn/branches/chrome_15@876 4c0a9323-5329-0410-9bdc-e9ce6186880e
2011-10-20 21:29:56 +00:00
mark@chromium.org
405bb7aff7 Address review comments from r843 (http://breakpad.appspot.com/307001)
Review URL: http://breakpad.appspot.com/308001

git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@844 4c0a9323-5329-0410-9bdc-e9ce6186880e
2011-10-05 22:32:27 +00:00
mark@chromium.org
1e9dbde88a Ensure crash reports will be uploaded on the Mac.
Regression from Breakpad r842 (Chromium r103778) - browser crash reports were
uploaded, but renderer crash reports were not. Messages such as these may have
been logged:

com.apple.launchd.peruser.x[y] could not lookup DNS configuration info
service: (ipc/send) invalid destination port
com.apple.launchd.peruser.x[y] Breakpad Reporter: Send Error: Error
Domain=NSURLErrorDomain Code=-1009 UserInfo=z "This computer’s Internet
connection appears to be offline." Underlying Error=(Error
Domain=kCFErrorDomainCFNetwork Code=-1009 UserInfo=w "This computer’s Internet
connection appears to be offline.")

When OnDemandServer establishes the bootstrap subset, it will now register the
parent bootstrap port in the subset namespace so that the Inspector can
recover this port and switch to it. The Sender, launched by the Inspector,
relies on the bootstrap port being set properly.

BUG=chromium:99252
TEST=All test cases from Chromium r103778 (bug chromium:28547) plus:
     about:crash should generate a crash report which should be uploaded,
     provided that throttling is not in effect. Remove or edit
     ~/Library/Preferences/com.Breakpad.crash_report_sender.plist to defeat
     throttling. Also verify that about:inducebrowsercrashforrealz works.
Review URL: http://breakpad.appspot.com/307001

git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@843 4c0a9323-5329-0410-9bdc-e9ce6186880e
2011-10-05 21:58:10 +00:00
mark@chromium.org
e7b75dbcc3 Use a bootstrap subset port for the inspector, tying the subset to the
lifetime of the task to be monitored, the invoking task. This allows the
bootstrap server (in launchd) to automatically clean up the Mach server
registration when the task being monitored exits, avoiding leaks of
com.Breakpad.Inspector(pid) ports in "launchctl bslist".

BUG=chromium:28547
TEST=Handler should still crash catches, but inspector ports should no longer
     show up in "launchctl bslist". They should show up under a subset port in
     "launchctl bstree" instead. "launchctl bstree" must be invoked as root.
Review URL: http://breakpad.appspot.com/306001

git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@842 4c0a9323-5329-0410-9bdc-e9ce6186880e
2011-10-03 19:54:28 +00:00
mark@chromium.org
9dfe692010 Fix some compilation warnings and other errors due to API changes
Review URL: http://breakpad.appspot.com/305002

git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@841 4c0a9323-5329-0410-9bdc-e9ce6186880e
2011-09-29 16:14:01 +00:00
mark@chromium.org
742e915661 Build the Mac Breakpad utilities with the 10.5 SDK in x86_64 Debug mode. This
was already the SDK being used for x86_64 Release mode. The 10.6 SDK is not
necessary.

Explicitly set the file encoding to UTF-16 on the sender app's lproj's
InfoPlist.strings and Localizable.strings files.

git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@840 4c0a9323-5329-0410-9bdc-e9ce6186880e
2011-09-28 20:10:34 +00:00
mark@chromium.org
86901970f2 Fix encoding of breakpad/src/client/mac/testapp/English.lproj/InfoPlist.strings
in breakpad/src/client/mac/Breakpad.xcodeproj - it's UTF-16, not UTF-8.


git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@839 4c0a9323-5329-0410-9bdc-e9ce6186880e
2011-09-27 22:01:13 +00:00
mark@chromium.org
494fa83886 Fix some newlines.
git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@838 4c0a9323-5329-0410-9bdc-e9ce6186880e
2011-09-27 21:32:40 +00:00
mark@chromium.org
1f17be3171 Fix totally busted-up project file that was, for the most part, wrong for
non-Debug configurations and was probably even a little wrong for Debug too.


git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@837 4c0a9323-5329-0410-9bdc-e9ce6186880e
2011-09-27 21:17:04 +00:00
mark@chromium.org
86643aa489 Fix breakpad/src/tools/mac/crash_report/on_demand_symbol_supplier.mm following
r835.


git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@836 4c0a9323-5329-0410-9bdc-e9ce6186880e
2011-09-27 21:02:31 +00:00
thestig@chromium.org
8d54c75092 Linux/Mac: Add option to omit the CFI section in dump_syms.
Review URL: http://breakpad.appspot.com/304001

git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@835 4c0a9323-5329-0410-9bdc-e9ce6186880e
2011-09-14 01:02:55 +00:00
mihaip@chromium.org
912c99fc8e Remove javascript_engine GYP variable.
(it's no longer needed in Chromium as of http://crrev.com/100692)

Review URL: http://breakpad.appspot.com/303001


git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@834 4c0a9323-5329-0410-9bdc-e9ce6186880e
2011-09-13 16:05:17 +00:00
ted.mielczarek
f3b59ca226 Fix 64-bit literals in test data
git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@833 4c0a9323-5329-0410-9bdc-e9ce6186880e
2011-09-01 19:43:27 +00:00
ted.mielczarek
9f042be4a7 issue 438 - fix array index bug in libdisasm
P=matthewbg@google.com R=ted

git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@832 4c0a9323-5329-0410-9bdc-e9ce6186880e
2011-08-31 16:38:40 +00:00
ted.mielczarek
1a1890a52a Adjust MD_CONTEXT_CPU_MASK to reflect reality, fix some code so it can handle dumps using the old value for MD_CONTEXT_ARM
The value of MD_CONTEXT_CPU_MASK in use assumes that only the lower 6 bits are used for flags, and the upper 26 bits are for the CPU type. However, as of Windows 7 SP1, the 7th bit is being used as a flag (per http://msdn.microsoft.com/en-us/library/hh134238%28v=vs.85%29.aspx and the Windows SDK headers). Adjusting MD_CONTEXT_CPU_MASK works, but unfortunately that masks off the existing value of MD_CONTEXT_ARM. This patch also changes the value of MD_CONTEXT_ARM and adjusts the minidump context reading machinery to gracefully handle minidumps with the old value.
R=mark at http://breakpad.appspot.com/302001

git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@831 4c0a9323-5329-0410-9bdc-e9ce6186880e
2011-08-30 22:22:08 +00:00
ted.mielczarek
8ade75f955 issue 243 - Linux dumper should use build id produced by ld --build-id if available
R=thestig at http://breakpad.appspot.com/185001

git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@830 4c0a9323-5329-0410-9bdc-e9ce6186880e
2011-08-30 15:21:07 +00:00
ted.mielczarek
68e380d5a7 Fix libcurl include in http_upload (trivial, no bug)
git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@829 4c0a9323-5329-0410-9bdc-e9ce6186880e
2011-08-30 15:20:56 +00:00
mark@chromium.org
93257311a1 Fix a Breakpad crash during teardown when USE_PROTECTED_ALLOCATIONS is in
effect.

BUG=none
TEST=Apple Crash Reporter logs from processes in which Breakpad handles the
     crash should point the finger at the actual crash source, not the
     Breakpad thread's attempt to write to unwritable memory.
Review URL: http://breakpad.appspot.com/301001

git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@828 4c0a9323-5329-0410-9bdc-e9ce6186880e
2011-08-26 22:29:33 +00:00
mark@chromium.org
ce8d2156e8 Add missing (parentehses.)
BUG=247, chromium:94107
TEST=Minidump file sizes should be manageable
Review URL: http://breakpad.appspot.com/300002

git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@827 4c0a9323-5329-0410-9bdc-e9ce6186880e
2011-08-26 21:37:59 +00:00
mark@chromium.org
60a883212f Fix CalculateStackSize to behave properly when the main thread's stack is
split up into multiple regions.

An older workaround relyied on known fixed stack locations and only filled in
the initial page of the stack if it was in a distinct region. The new approach
looks upwards for additional regions that appear to be part of the same stack.

With PIE on Lion, the stack no longer begins at a fixed address, so the older
workaround became ineffective.

BUG=247, chromium:94107
TEST=Stacks should run through to _main/start and then stop when examining
     Chrome on Lion with PIE and "slid" stacks.
Review URL: http://breakpad.appspot.com/300001

git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@826 4c0a9323-5329-0410-9bdc-e9ce6186880e
2011-08-25 21:19:29 +00:00
mark@chromium.org
7b8b8632d3 The process_id field is unsigned, so we need this cast in c++0x.
Patch by Rafael Ávila de Espí­ndola <respindola@mozilla.com>

https://bugzilla.mozilla.org/show_bug.cgi?id=677644


git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@825 4c0a9323-5329-0410-9bdc-e9ce6186880e
2011-08-11 13:47:38 +00:00
mark@chromium.org
e6c0689091 The first field in a MDLocationDescriptor is a u_int32_t, so change this cast
to the correct type. This fixes an error newer clang versions find in c++ 0x
mode.

Patch by Rafael Ávila de Espí­ndola <respindola@mozilla.com>

https://bugzilla.mozilla.org/show_bug.cgi?id=677641


git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@824 4c0a9323-5329-0410-9bdc-e9ce6186880e
2011-08-11 13:45:30 +00:00
mark@chromium.org
8f2b058398 Fix clang warnings.
Review URL: http://breakpad.appspot.com/298002

git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@823 4c0a9323-5329-0410-9bdc-e9ce6186880e
2011-08-11 13:40:13 +00:00
mark@chromium.org
3c59c247e2 Zero out the entire context on MD5_Final, not just the number of bytes in a
pointer.
Review URL: http://breakpad.appspot.com/298001

git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@822 4c0a9323-5329-0410-9bdc-e9ce6186880e
2011-08-11 13:39:44 +00:00
mark@chromium.org
ba5ee2c8f5 Remove a bogus const.
git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@821 4c0a9323-5329-0410-9bdc-e9ce6186880e
2011-08-10 15:29:52 +00:00
ted.mielczarek
1b9920afa7 Fix a typo in r817
git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@820 4c0a9323-5329-0410-9bdc-e9ce6186880e
2011-07-27 18:29:37 +00:00
mark@chromium.org
e919fdd63b Wean Mac Breakpad off of its OpenSSL libcrypto dependency.
This libcrypto dependency sucks. Linking against OpenSSL is sort of broken in
certain Mac OS X SDKs. libcrypto was only being used to provide an MD5
implementation. Breakpad already has its own MD5 implementation, so just use
that instead.

To be perfectly honest, on modern systems, nothing should be making MD5
hashes of modules anyway, because everything has an embedded LC_UUID.

The project file changes just remove libcrypto and add md5.c as needed.

A bonus (and untested) fix for on_demand_symbol_supplier.mm is included to
account for changes in r794.
Review URL: http://breakpad.appspot.com/296001

git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@819 4c0a9323-5329-0410-9bdc-e9ce6186880e
2011-07-27 14:30:58 +00:00
ted.mielczarek
48550041f9 Switch mac DumpSymbols::WriteSymbolFile to take an ostream instead of a FILE* to match the changes to Module::Write
R=mark at http://breakpad.appspot.com/294001/show

git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@818 4c0a9323-5329-0410-9bdc-e9ce6186880e
2011-07-26 14:03:09 +00:00
ted.mielczarek@gmail.com
d01a9f8bc4 Fix compilation using the OS X 10.7 SDK by #ifdefing out PPC support when targeting 10.7, as PPC support has been removed from the 10.7 SDK
A=Rafael Ávila de Espíndola <respindola@mozilla.com>, R=ted at https://bugzilla.mozilla.org/show_bug.cgi?id=673789

git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@817 4c0a9323-5329-0410-9bdc-e9ce6186880e
2011-07-26 12:00:20 +00:00
jessicag.feedback@gmail.com
1cbdeae78d Fix a sizeof(pointer) vs sizeof(pointee) issue caught by client.
git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@815 4c0a9323-5329-0410-9bdc-e9ce6186880e
2011-07-21 21:38:01 +00:00
ted.mielczarek
32d04cdbbc Remove curl/types.h include, since this header has been deprecated for a long time and removed in a recent curl release.
P=Evan Shaw <edsrzf@gmail.com> R=ted

git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@814 4c0a9323-5329-0410-9bdc-e9ce6186880e
2011-07-21 17:44:48 +00:00
ted.mielczarek
69607b678f Remove NetworkSourceLine{Resolver,Server} and related code. It never wound up being useful enough to use in production, so let's drop the maintenence burden
R=jessicag at http://breakpad.appspot.com/292001/show

git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@795 4c0a9323-5329-0410-9bdc-e9ce6186880e
2011-07-07 20:53:52 +00:00
ted.mielczarek
3ca4a120de Add some unit tests for Linux WriteSymbolFile
This patch adds synth_elf::{StringTable,SymbolTable,ELF} classes to
produce in-memory ELF files to properly test the Linux symbol dumping
code. It also uses those classes to add some basic tests for
the WriteSymbolFile function.

R=jimb at http://breakpad.appspot.com/277001/show

git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@794 4c0a9323-5329-0410-9bdc-e9ce6186880e
2011-07-06 17:05:59 +00:00
ted.mielczarek
b2f96f314c Dump PUBLIC + CFI records from libraries without debug info on Linux, use .dynsym for symbol names if there are no usable debug symbols.
R=jimb at http://breakpad.appspot.com/275001/show

git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@793 4c0a9323-5329-0410-9bdc-e9ce6186880e
2011-07-06 17:05:49 +00:00
mmentovai
be55cc8cf0 Fix an assertion encountered in UntypedMDRVA::Copy().
Fix an assertion where a zero-length buffer was being passed to
UntypedMDRVA::Copy().  This occurred when WriteFile() was given a file whose
size was a multiple of the temporary buffer size.  In this issue's case, the
procfs file "environ" happened to be 2032 bytes, while the temporary buffer
was 1016 bytes.

Patch by Michael Krebs <mkrebs@chromium.org>


git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@792 4c0a9323-5329-0410-9bdc-e9ce6186880e
2011-07-01 01:20:27 +00:00
jessicag.feedback@gmail.com
df33e47bb4 Delete OS failing test cases and note failure in relevant .h file.
git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@791 4c0a9323-5329-0410-9bdc-e9ce6186880e
2011-06-21 18:34:01 +00:00
ted.mielczarek@gmail.com
dcebaf42ba Add some headers necessary to build the Linux client code with the Android NDK r5
P=Alon Zakai <azakai@mozilla.com>, R=ted

git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@790 4c0a9323-5329-0410-9bdc-e9ce6186880e
2011-05-31 12:12:30 +00:00
cdn@chromium.org
94074a84d0 Fix null derefs in x86 dissasembler code.
BUG=428
TEST=N/A
Review URL: http://breakpad.appspot.com/285001

git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@789 4c0a9323-5329-0410-9bdc-e9ce6186880e
2011-05-12 19:11:26 +00:00
ted.mielczarek
1807e385d7 Fix linux-gate handling in LinuxDumper so it gets a valid debug ID
A=ted R=nealsid at http://breakpad.appspot.com/284001

git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@788 4c0a9323-5329-0410-9bdc-e9ce6186880e
2011-05-06 23:23:31 +00:00
vitalybuka@chromium.org
04023b1f6a Fixed message about unregistered msdia*dll. Builds with different DiaSDK need different dll.
Rebuilt with Visual Studio 2008.
Slightly improved refresh_binaries.bat.

BUG=none
TEST=none
Review URL: http://breakpad.appspot.com/281001

git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@787 4c0a9323-5329-0410-9bdc-e9ce6186880e
2011-04-26 20:52:48 +00:00
mmentovai
fd557e4a97 Use task_info(..., TASK_DYLD_INFO, ...) on 10.6 and later in preference to
looking up the _dyld_all_image_infos symbol in /usr/lib/dyld.
Review URL: http://breakpad.appspot.com/276001

git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@786 4c0a9323-5329-0410-9bdc-e9ce6186880e
2011-04-05 16:05:17 +00:00
jessicag.feedback@gmail.com
23c82999a8 Another attempt at signed / unsigned int resolution for linux minidump writer.
git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@785 4c0a9323-5329-0410-9bdc-e9ce6186880e
2011-03-30 21:42:27 +00:00
jessicag.feedback@gmail.com
3b3f0c3f61 Adding header files at the request of Chrome.
git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@784 4c0a9323-5329-0410-9bdc-e9ce6186880e
2011-03-22 02:50:41 +00:00
jessicag.feedback@gmail.com
322818287c Add trusted check
git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@783 4c0a9323-5329-0410-9bdc-e9ce6186880e
2011-03-22 00:29:37 +00:00
jimblandy
a4a9922512 Issue 417: update unit tests after adding unnamed function detection
In r779, at the last moment, I added a default call count expectation for
the UnnamedFunction warning to the CUFixtureBase constructor, but didn't
re-run the tests. This patch adjusts all affected tests.

a=jimblandy, r=ted.mielczarek


git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@782 4c0a9323-5329-0410-9bdc-e9ce6186880e
2011-03-14 17:35:26 +00:00
ted.mielczarek
b0201df935 Merge adjacent mappings with the same name into one module in LinuxDumper.
A=Mike Hommey <mh+mozilla@glandium.org> R=ted at https://bugzilla.mozilla.org/show_bug.cgi?id=637316

git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@781 4c0a9323-5329-0410-9bdc-e9ce6186880e
2011-03-14 17:04:09 +00:00
SiyangXie@gmail.com
88fa7cfc6b Protect "std::max", "std::min" against MACROs defined in WinDef.h.
git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@780 4c0a9323-5329-0410-9bdc-e9ce6186880e
2011-03-11 22:47:07 +00:00
jimblandy
fd18beeb5c Google Breakpad Issue 417: Handle DWARF that omits function names.
This patch makes sure dump_syms behaves properly when presented with
malformed DWARF data that provides no name for a function. We print a
warning message to stderr, and subsitute "<name omitted>" for the empty
string, so that the "FUNC" record written to the symbol file for the
function is still well-formed. (We may have line number data covering the
function, so it would be a shame to omit the function altogether.)

Unit tests included.
a=jimblandy, r=ted.mielczarek


git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@779 4c0a9323-5329-0410-9bdc-e9ce6186880e
2011-03-11 22:16:12 +00:00
ted.mielczarek
bf25801d83 Put PUBLIC lines in Mac symbol files.
Exported symbols on Mach-O binaries are defined in a STABS section. This patch makes stabs_reader handle them, adds support for Extern symbols in the Module class (which are output as PUBLIC lines in symbol files), and the proper processing in stabs_to_module to hook it all up.

A=mark R=jimb at http://breakpad.appspot.com/163001 and http://breakpad.appspot.com/267001

git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@778 4c0a9323-5329-0410-9bdc-e9ce6186880e
2011-03-04 16:08:39 +00:00
jessicag.feedback@gmail.com
68b256aed3 Updating to ints from unsigned ints so -1 will be an acceptable value.
git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@777 4c0a9323-5329-0410-9bdc-e9ce6186880e
2011-03-03 00:42:11 +00:00
jessicag.feedback@gmail.com
248d340b71 Fix compiler warning.
git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@776 4c0a9323-5329-0410-9bdc-e9ce6186880e
2011-03-01 20:47:27 +00:00
ted.mielczarek
dbf409ca20 Make programs in src/tools/linux build via the automake build system
R=jimb at http://breakpad.appspot.com/265001

git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@775 4c0a9323-5329-0410-9bdc-e9ce6186880e
2011-02-28 14:05:22 +00:00
mmentovai
d2b6b9ae82 Fix breakpad compilation on ubuntu 10.10.
Patch by Marc-Antoine Ruel <maruel@chromium.org>

Review URL: http://breakpad.appspot.com/264001


git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@774 4c0a9323-5329-0410-9bdc-e9ce6186880e
2011-02-18 19:12:06 +00:00
ted.mielczarek
cff9fdbd94 enable writing INFO CODE_ID line in symbol files
R=mark (originally from http://breakpad.appspot.com/180001)

git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@773 4c0a9323-5329-0410-9bdc-e9ce6186880e
2011-02-15 13:39:08 +00:00
ted.mielczarek
1530800640 Fix printing of x86_64 registers from minidump_stackwalk
R=mark at http://breakpad.appspot.com/262001

git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@772 4c0a9323-5329-0410-9bdc-e9ce6186880e
2011-02-14 19:23:35 +00:00
SiyangXie@gmail.com
0afda6b2c2 Fix(part II) for r768 about external item "src/third_party/glog".
git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@770 4c0a9323-5329-0410-9bdc-e9ce6186880e
2011-02-02 22:48:26 +00:00
SiyangXie@gmail.com
5a73dd4a2b Fix(part I) for r768 about external item "src/third_party/glog".
git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@769 4c0a9323-5329-0410-9bdc-e9ce6186880e
2011-02-02 22:39:50 +00:00
SiyangXie@gmail.com
ee8c48cc20 Update svn:externals property to add glog to correct path.
git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@768 4c0a9323-5329-0410-9bdc-e9ce6186880e
2011-02-01 19:49:48 +00:00
ted.mielczarek
ad35fbc56a Dump MD_LINUX_MAPS from minidump_dump
R=kmixter at http://breakpad.appspot.com/261001

git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@767 4c0a9323-5329-0410-9bdc-e9ce6186880e
2011-01-28 18:53:02 +00:00
ted.mielczarek
ed1c70b5b8 Expose actual instruction from DisassemblerX86
R=cdn at http://breakpad.appspot.com/260001

git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@766 4c0a9323-5329-0410-9bdc-e9ce6186880e
2011-01-26 22:13:37 +00:00
ted.mielczarek
d328f2011f Rename duplicate argument names to make it compile with CLang.
P=rafael.espindola R=ted at http://breakpad.appspot.com/248001

git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@765 4c0a9323-5329-0410-9bdc-e9ce6186880e
2011-01-25 20:01:26 +00:00
ted.mielczarek
eba8cc5172 Add missing constructor to CPPLanguage class to make it compile with CLang.
P=rafael.espindola R=jimb at https://bugzilla.mozilla.org/show_bug.cgi?id=623121

git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@764 4c0a9323-5329-0410-9bdc-e9ce6186880e
2011-01-25 20:01:22 +00:00
ted.mielczarek
0df0555e75 Use a MinidumpCallback to force minidumps on Windows to include memory around the faulting instruction pointer. Older versions of DbgHelp don't seem to do this correctly (on Windows XP, for example)
R=mark at http://breakpad.appspot.com/259001

git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@763 4c0a9323-5329-0410-9bdc-e9ce6186880e
2011-01-25 19:19:19 +00:00
ted.mielczarek
9220e0baf1 Round-trip client/processor unittests for Windows
R=mark at http://breakpad.appspot.com/258001

git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@762 4c0a9323-5329-0410-9bdc-e9ce6186880e
2011-01-24 19:59:14 +00:00
ted.mielczarek
281d52d944 Fix some apparently longstanding crash bugs in Stackwalker implementations when resolver is NULL.
R=mark at http://breakpad.appspot.com/257001

git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@761 4c0a9323-5329-0410-9bdc-e9ce6186880e
2011-01-24 19:59:09 +00:00
mmentovai
b904343e14 Fix clang warning / miscompile.
Patch by Nico Weber <thakis@chromium.org>

Review URL: http://breakpad.appspot.com/256001


git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@760 4c0a9323-5329-0410-9bdc-e9ce6186880e
2011-01-24 19:20:10 +00:00
ted.mielczarek
b7fdc7396d Add module_serializer.cc to libbreakpad.a. Not sure why it wasn't there in the first place. Trivial patch, landing without review.
git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@759 4c0a9323-5329-0410-9bdc-e9ce6186880e
2011-01-19 17:02:10 +00:00
ted.mielczarek
7b8e2b7e09 Add MinidumpMemoryInfo / MinidumpMemoryInfoList classes to expose MDRawMemoryInfo / MDRawMemoryInfoList via the Minidump class
R=mark at http://breakpad.appspot.com/255001

git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@755 4c0a9323-5329-0410-9bdc-e9ce6186880e
2011-01-13 19:05:33 +00:00
ted.mielczarek
80745c59de Add structure definitions for the memory info list, as well as some other new enum values.
R=mark at http://breakpad.appspot.com/254001

git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@754 4c0a9323-5329-0410-9bdc-e9ce6186880e
2011-01-13 19:05:29 +00:00
thestig@chromium.org
972ae49d47 Fix compile by adding needed includes.
Review URL: http://breakpad.appspot.com/253001

git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@753 4c0a9323-5329-0410-9bdc-e9ce6186880e
2011-01-12 00:14:27 +00:00
ted.mielczarek
78aaf6a665 Fix review comment that I missed.
git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@752 4c0a9323-5329-0410-9bdc-e9ce6186880e
2011-01-11 20:31:53 +00:00
ted.mielczarek
c77fc8a32c Make some parts of the processor compile on Win32/MSVC
R=mark at http://breakpad.appspot.com/250001

git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@751 4c0a9323-5329-0410-9bdc-e9ce6186880e
2011-01-11 20:27:29 +00:00
thestig@chromium.org
fd00ae5f55 Fixing typos that will soon be gyp errors.
A=bradnelson
R=thestig
Original review: http://breakpad.appspot.com/251001
Review URL: http://breakpad.appspot.com/252001

git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@750 4c0a9323-5329-0410-9bdc-e9ce6186880e
2011-01-11 19:50:45 +00:00
stuart.morgan
816f25011c Make localization resizing of Mac uploader email line more robust. Review URL: http://breakpad.appspot.com/247001
git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@749 4c0a9323-5329-0410-9bdc-e9ce6186880e
2011-01-05 05:34:47 +00:00
stuartmorgan
717bf0ded2 Keep a log of uploaded crash IDs on the Mac. Review URL: http://breakpad.appspot.com/245001
git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@748 4c0a9323-5329-0410-9bdc-e9ce6186880e
2010-12-17 20:41:22 +00:00
ted.mielczarek@gmail.com
c45b12b422 Fix MinidumpGenerator::WriteExceptionStream for writing cross-architecture dumps
R=mark at http://breakpad.appspot.com/244001

git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@747 4c0a9323-5329-0410-9bdc-e9ce6186880e
2010-12-16 22:52:38 +00:00
ted.mielczarek@gmail.com
0344a368de Allow out-of-process minidump generation to work on processes of a different CPU architecture
R=mark at http://breakpad.appspot.com/241001

git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@746 4c0a9323-5329-0410-9bdc-e9ce6186880e
2010-12-15 21:55:56 +00:00
ted.mielczarek@gmail.com
0d9bd40775 Allow writing on-request minidumps with an exception stream
R=mark at http://breakpad.appspot.com/172001/show

git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@745 4c0a9323-5329-0410-9bdc-e9ce6186880e
2010-12-15 16:28:28 +00:00
ted.mielczarek@gmail.com
cae59b4ae4 issue 334 - Fix a race condition between ExceptionHandler::Teardown and ExceptionHandler::WaitForMessage on OS X
R=mark at http://breakpad.appspot.com/165001/show

git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@744 4c0a9323-5329-0410-9bdc-e9ce6186880e
2010-12-15 16:28:22 +00:00
ted.mielczarek@gmail.com
7405ecd046 allow uploading zero-byte files in HTTPUpload
R=mark at http://breakpad.appspot.com/243001/show

git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@743 4c0a9323-5329-0410-9bdc-e9ce6186880e
2010-12-15 16:19:32 +00:00
ted.mielczarek
efbe428d83 Add some unit tests for the mac MinidumpGenerator
R=mark at http://breakpad.appspot.com/240001/show

git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@742 4c0a9323-5329-0410-9bdc-e9ce6186880e
2010-12-13 22:10:32 +00:00
ted.mielczarek
ef7262d477 allow passing info about known memory mappings to MinidumpWriter and ExceptionHandler
r=thestig at http://breakpad.appspot.com/242001/show

git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@741 4c0a9323-5329-0410-9bdc-e9ce6186880e
2010-12-13 22:10:23 +00:00
kmixter@chromium.org
b5dfa2834d Reuse code and fix inconsistent array boundaries.
R=ted.mielczarek
Review URL: http://breakpad.appspot.com/237001

git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@740 4c0a9323-5329-0410-9bdc-e9ce6186880e
2010-12-08 22:26:20 +00:00
kmixter@chromium.org
8322cd6586 Propagate failure if http uploads fail with http error codes.
R=ted.mielczarek
BUG=413
Review URL: http://breakpad.appspot.com/236001


git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@739 4c0a9323-5329-0410-9bdc-e9ce6186880e
2010-12-08 22:24:29 +00:00
kmixter@chromium.org
e41dc09252 Enable dumping of the Linux extension streams.
We now dump information about process's environment/command line/status, Linux release, and CPU info.
Review URL: http://breakpad.appspot.com/238001

git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@738 4c0a9323-5329-0410-9bdc-e9ce6186880e
2010-12-08 18:48:28 +00:00
kmixter@chromium.org
6c05f5ddd9 Fix segv in network_source_line_resolver_server_unittest
R=siyangxie
BUG=409


git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@737 4c0a9323-5329-0410-9bdc-e9ce6186880e
2010-12-08 02:14:17 +00:00
cdn@chromium.org
fb7fdb9426 Added null checks to disassembler_x86
Review URL: http://breakpad.appspot.com/239001

git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@736 4c0a9323-5329-0410-9bdc-e9ce6186880e
2010-12-03 22:28:58 +00:00
ted.mielczarek
30b075c4a5 Fix WriteMemoryListStream to remove an extraneous loop index variable increment.
Patch by timeless <timeless@mozdev.org>, R=me, unittest by me.
See https://bugzilla.mozilla.org/show_bug.cgi?id=615534

git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@735 4c0a9323-5329-0410-9bdc-e9ce6186880e
2010-11-30 19:19:31 +00:00
thestig@chromium.org
ccc2446863 Fix 64-bit build on Linux.
BUG=412
Review URL: http://breakpad.appspot.com/233001

git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@734 4c0a9323-5329-0410-9bdc-e9ce6186880e
2010-11-22 22:54:51 +00:00
thestig@chromium.org
3665a7d09b Linux: Attempt to generate an ELF identifier for deleted running binaries.
Review URL: http://breakpad.appspot.com/228001

git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@733 4c0a9323-5329-0410-9bdc-e9ce6186880e
2010-11-19 19:57:07 +00:00
nealsid
d9d863e153 Add specific curl headers to facilitate building on Ubuntu Lucid
git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@732 4c0a9323-5329-0410-9bdc-e9ce6186880e
2010-11-17 18:45:20 +00:00
thestig@chromium.org
916a34a982 Fix assert failure in dump_syms caused by binary linked with gold.
Original review: http://breakpad.appspot.com/224001
A=raymes
R=ccoutant
Review URL: http://breakpad.appspot.com/227001

git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@729 4c0a9323-5329-0410-9bdc-e9ce6186880e
2010-11-08 19:52:16 +00:00
thestig@chromium.org
43e6db7e72 Change the bug reporting email address.
Review URL: http://breakpad.appspot.com/226001

git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@728 4c0a9323-5329-0410-9bdc-e9ce6186880e
2010-11-08 19:49:41 +00:00
thestig@chromium.org
f66ff1afd2 Delete an old Makefile and fix lots of lint errors.
Review URL: http://breakpad.appspot.com/225001

git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@727 4c0a9323-5329-0410-9bdc-e9ce6186880e
2010-11-08 19:49:25 +00:00
mmentovai
67b65a379c Use STABS as the debugging format when using GCC 4.0 and the 10.4 SDK.
Ref. http://groups.google.com/group/google-breakpad-dev/browse_thread/thread/51c7715953b3904d


git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@726 4c0a9323-5329-0410-9bdc-e9ce6186880e
2010-11-08 19:46:52 +00:00
SiyangXie@gmail.com
4adb6f4f7b Fix for issue 222001.
git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@725 4c0a9323-5329-0410-9bdc-e9ce6186880e
2010-11-04 02:40:06 +00:00
SiyangXie@gmail.com
bbd8e82a7f Make memory allocation/deallocation consistent: use new char[] instead of operator new()
git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@724 4c0a9323-5329-0410-9bdc-e9ce6186880e
2010-11-03 23:54:01 +00:00
SiyangXie@gmail.com
3b4ac42ff8 Fix broken build of mac crash report tool.
git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@723 4c0a9323-5329-0410-9bdc-e9ce6186880e
2010-11-03 23:49:41 +00:00
SiyangXie@gmail.com
3382d1e0a6 Tiny fix for memory allocation/deallocation mismatch
git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@722 4c0a9323-5329-0410-9bdc-e9ce6186880e
2010-11-01 22:10:10 +00:00
SiyangXie@gmail.com
a8c1c466a1 Restrict ownership of symbol data buffers to symbol supplier.
git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@721 4c0a9323-5329-0410-9bdc-e9ce6186880e
2010-11-01 17:31:31 +00:00
SiyangXie@gmail.com
eabfff133d Add missing module_serializer.h and module_serializer.cc for class ModuleSerializer.
git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@720 4c0a9323-5329-0410-9bdc-e9ce6186880e
2010-10-25 22:24:35 +00:00
SiyangXie@gmail.com
41f998fe5a FastSourceLineResolver implementation for optimization purpose.
git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@719 4c0a9323-5329-0410-9bdc-e9ce6186880e
2010-10-21 17:13:01 +00:00
ted.mielczarek
43378265bf Add asm/ptrace.h include to linux_dumper.cc to fix the silly scratchbox toolchain we're using for Maemo builds. Also shuffle around the include order to comply with style guidelines, while I'm here.
git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@718 4c0a9323-5329-0410-9bdc-e9ce6186880e
2010-10-21 13:55:07 +00:00
mmentovai
ac05fa05b5 Fix crash_report tool.
git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@717 4c0a9323-5329-0410-9bdc-e9ce6186880e
2010-10-20 21:57:35 +00:00
ted.mielczarek
cfc8628092 Add support for building the Linux client code using the Android NDK
r=mwu at http://breakpad.appspot.com/212001/show

git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@716 4c0a9323-5329-0410-9bdc-e9ce6186880e
2010-10-20 15:51:38 +00:00
ted.mielczarek
9c30407f7f Double stack scanning length in stackwalker
R=jimb at http://breakpad.appspot.com/215001/show

git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@715 4c0a9323-5329-0410-9bdc-e9ce6186880e
2010-10-19 13:12:29 +00:00
SiyangXie@gmail.com
08730fc9a6 Add static version of map wrappers and corresponding serializers.
git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@714 4c0a9323-5329-0410-9bdc-e9ce6186880e
2010-10-15 20:36:31 +00:00
SiyangXie@gmail.com
361f24eac7 Fix some compiler warnings: char*->const char*, default in swtch.
git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@713 4c0a9323-5329-0410-9bdc-e9ce6186880e
2010-10-15 19:43:07 +00:00
SiyangXie@gmail.com
d95350e97a Fix for bug: debug checks for vector::operator[] fail in breakpad.
git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@712 4c0a9323-5329-0410-9bdc-e9ce6186880e
2010-10-13 23:45:20 +00:00
SiyangXie@gmail.com
5b117cf53a Refactor source line resolver, add interface in supplier and resolver.
git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@711 4c0a9323-5329-0410-9bdc-e9ce6186880e
2010-10-07 20:31:36 +00:00
ted.mielczarek
d35f113d02 Make dump_syms output an INFO CODE_ID line that includes the code file and code identifier. (Currently disabled to give Breakpad users time to update their processor code.)
R=mark at http://breakpad.appspot.com/180001/show

git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@710 4c0a9323-5329-0410-9bdc-e9ce6186880e
2010-10-05 19:39:23 +00:00
ted.mielczarek
d192a71e24 ditch libtool, only build static libs
R=mark at http://breakpad.appspot.com/210001/show

git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@709 4c0a9323-5329-0410-9bdc-e9ce6186880e
2010-10-05 19:38:51 +00:00
ted.mielczarek
e574a2adc6 add a --disable-processor configure arg to skip building processor libs and just build client libs
R=nealsid at http://breakpad.appspot.com/209001/show

git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@708 4c0a9323-5329-0410-9bdc-e9ce6186880e
2010-10-05 19:38:22 +00:00
cdn@chromium.org
f801709a68 missed test crashdumps in revision 706.
Review URL: http://breakpad.appspot.com/208001

git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@707 4c0a9323-5329-0410-9bdc-e9ce6186880e
2010-10-02 00:30:32 +00:00
cdn@chromium.org
8b2e6865e5 Added method to exploitability class which checks if a given address contains all ascii characters.
BUG=NONE
TEST=ExploitabilityTest.TestWindowsEngine
Review URL: http://breakpad.appspot.com/207001

git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@706 4c0a9323-5329-0410-9bdc-e9ce6186880e
2010-10-01 23:25:48 +00:00
cdn@chromium.org
2b4274afc4 Added libdisasm to the repository. This library is no longer under development so there
is no reason not to keep it locally. Implemented a basic disassembler which can be used
to scan bytecode for interesting conditions. This should be pretty easy to add to for
things other than exploitability if there is a desire. This also adds several tests to
the windows exploitability ranking code to take advantage of the disassembler for x86
code.

BUG=None
TEST=DisassemblerX86Test.*

Review URL: http://breakpad.appspot.com/203001

git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@705 4c0a9323-5329-0410-9bdc-e9ce6186880e
2010-10-01 22:38:10 +00:00
ted.mielczarek
c653618a91 Add stack-scanning fallback to Stackwalker{AMD64,ARM}.
R=jimb at http://breakpad.appspot.com/206001/show

git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@704 4c0a9323-5329-0410-9bdc-e9ce6186880e
2010-10-01 13:04:16 +00:00
ted.mielczarek
8c33b3e9c9 Refactor some bits of StackWalkerX86 / StackFrameX86 out into their respective parent classes so they can be used by other architecture implementations.
R=jimb at http://breakpad.appspot.com/205001/show

git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@703 4c0a9323-5329-0410-9bdc-e9ce6186880e
2010-10-01 13:01:57 +00:00
SiyangXie@gmail.com
de2c055770 Fix a segmentation fault bug in MinidumpAssertion::Read().
git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@702 4c0a9323-5329-0410-9bdc-e9ce6186880e
2010-09-30 00:05:25 +00:00
ted.mielczarek
82a0188946 add top_srcdir/src to CPPFLAGS for all unittests to fix compilation of unittests when configuring outside the srcdir
git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@701 4c0a9323-5329-0410-9bdc-e9ce6186880e
2010-09-29 14:02:09 +00:00
thestig@chromium.org
8d1130a89e Only include linux_syscall_support.h on Linux in cross platform files.
TBR=nealsid
Review URL: http://breakpad.appspot.com/204001

git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@700 4c0a9323-5329-0410-9bdc-e9ce6186880e
2010-09-24 21:51:09 +00:00
ted.mielczarek
4621ee0691 Write a window of memory around the instruction pointer from the crashing thread to the minidump on OS X.
R=nealsid at http://breakpad.appspot.com/200001/show

git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@699 4c0a9323-5329-0410-9bdc-e9ce6186880e
2010-09-23 14:55:50 +00:00
cdn@chromium.org
cec12872c4 Added the base exploitability module for windows. This only adds the very basic exception type based analysis for now.
BUG=NONE
TEST=MinidumpProcessorTest.TestExploitilityEngine

Review URL: http://breakpad.appspot.com/189001

git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@698 4c0a9323-5329-0410-9bdc-e9ce6186880e
2010-09-22 02:37:19 +00:00
thestig@chromium.org
9a57c16c97 Pull in linux_syscall_support.h r3 - remove duplicate ARM code.
git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@697 4c0a9323-5329-0410-9bdc-e9ce6186880e
2010-09-21 18:19:47 +00:00
erikwright@chromium.org
a91e414f84 Modify crash_generation_app to use GYP instead of VS .sln file for ease of maintenance.
Backed out r684 (added glog include dir to client gyp files). It was obviated by r685, which removed the dependency on glog from the client projects.

BUG=None
TEST="gclient runhooks --force"; build crash_generation_app; launch crash_generation_app.
r=hansl at http://breakpad.appspot.com/191001/show


git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@696 4c0a9323-5329-0410-9bdc-e9ce6186880e
2010-09-21 17:27:07 +00:00
erikwright@chromium.org
b6ee7dcb22 Fix CrashGenerationServer to recover from protocol errors and a test for same.
R=siggi at http://breakpad.appspot.com/196001/show


git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@695 4c0a9323-5329-0410-9bdc-e9ce6186880e
2010-09-20 21:35:24 +00:00
SiyangXie@gmail.com
378e28e301 Add StaticMap implementation and unittest to breakpad.
StaticMap is a fundamental component class for in-memory representation of loaded symbol.


git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@694 4c0a9323-5329-0410-9bdc-e9ce6186880e
2010-09-20 17:45:15 +00:00
ted.mielczarek
efa30c13f2 Write a window of memory around the instruction pointer from the crashing thread to the minidump on Linux.
R=nealsid at http://breakpad.appspot.com/194001/show

git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@693 4c0a9323-5329-0410-9bdc-e9ce6186880e
2010-09-17 13:36:11 +00:00
thestig@chromium.org
c40bcc74d9 Fix ./configure --enable-m32
Review URL: http://breakpad.appspot.com/197001

git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@692 4c0a9323-5329-0410-9bdc-e9ce6186880e
2010-09-16 23:29:13 +00:00
thestig@chromium.org
1efa3f9e10 Fix compilation for minidump-2-core.
Review URL: http://breakpad.appspot.com/199001

git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@691 4c0a9323-5329-0410-9bdc-e9ce6186880e
2010-09-16 23:29:04 +00:00
nealsid
4b7f1eba64 Actually treat fatal error codes as fatal
git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@690 4c0a9323-5329-0410-9bdc-e9ce6186880e
2010-09-16 23:06:43 +00:00
thestig@chromium.org
1fa7c1c4c4 Fix compilation of file_id_unittest.
Review URL: http://breakpad.appspot.com/198001

git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@689 4c0a9323-5329-0410-9bdc-e9ce6186880e
2010-09-16 22:37:24 +00:00
jessicag.feedback@gmail.com
df9901a45d Initialize variables that currently may theoretically be used uninitialized
git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@688 4c0a9323-5329-0410-9bdc-e9ce6186880e
2010-09-16 20:52:06 +00:00
thestig@chromium.org
fda6a1e6fe Add a free() to ExceptionHandlerTest.ChildCrash.
Review URL: http://breakpad.appspot.com/193001

git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@687 4c0a9323-5329-0410-9bdc-e9ce6186880e
2010-09-16 01:24:32 +00:00
thestig@chromium.org
0e3b7020b8 Import linux_syscall_support.h from linux-syscall-support.googlecode.com instead of using our own copy.
Review URL: http://breakpad.appspot.com/192001

git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@686 4c0a9323-5329-0410-9bdc-e9ce6186880e
2010-09-15 22:31:57 +00:00
erikwright@chromium.org
7fde9a879d Revert revision 658 ('Add glog style logging to symupload').
R=nealsid at http://breakpad.appspot.com/190001


git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@685 4c0a9323-5329-0410-9bdc-e9ce6186880e
2010-09-15 17:38:03 +00:00
ted.mielczarek
90a41b68ad Fix include paths in breakpad_client.gyp to make the build work
git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@684 4c0a9323-5329-0410-9bdc-e9ce6186880e
2010-09-15 14:46:32 +00:00
SiyangXie@gmail.com
b5b5f9e520 Fix a bug in range_map-inl.h and add a unittest to expose the exisiting bug.
git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@683 4c0a9323-5329-0410-9bdc-e9ce6186880e
2010-09-15 01:11:34 +00:00
jessicag.feedback@gmail.com
9fc5812260 Fix a handful of comment spelling errors (Issue 385)
git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@682 4c0a9323-5329-0410-9bdc-e9ce6186880e
2010-09-09 21:37:54 +00:00
jessicag.feedback@gmail.com
bb87ebd809 Reducing severity of most commonly logged ERRORS.
git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@681 4c0a9323-5329-0410-9bdc-e9ce6186880e
2010-09-09 21:15:32 +00:00
jessicag.feedback@gmail.com
f24c2e1952 Remove proto generated source files from svn.
git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@680 4c0a9323-5329-0410-9bdc-e9ce6186880e
2010-09-08 23:36:54 +00:00
ted.mielczarek
53a8b1a204 Issue 378 - Don't compile Linux client libraries on non-Linux systems
R=nealsid at http://breakpad.appspot.com/173001/show

git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@679 4c0a9323-5329-0410-9bdc-e9ce6186880e
2010-08-31 15:09:01 +00:00
ted.mielczarek
6c7d641dc9 Issue 370 - fix PDBSourceLineWriter::GetModuleInfo's CPU detection
R=nealsid at http://breakpad.appspot.com/181001

git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@678 4c0a9323-5329-0410-9bdc-e9ce6186880e
2010-08-31 15:08:49 +00:00
mark@chromium.org
3a7466663c Linux FileID should work with ELFCLASS32 and ELFCLASS64 regardless of what's
native.

BUG=399
TEST=none
Review URL: http://breakpad.appspot.com/178001

git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@677 4c0a9323-5329-0410-9bdc-e9ce6186880e
2010-08-27 18:52:09 +00:00
mark@chromium.org
8ca54e486c Use <inttypes.h> macros for formatting fixed-width types.
Review URL: http://breakpad.appspot.com/162002

git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@676 4c0a9323-5329-0410-9bdc-e9ce6186880e
2010-08-27 18:50:59 +00:00
jessicag.feedback@gmail.com
7d279feb8f Adding sytax setting to proto file
git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@675 4c0a9323-5329-0410-9bdc-e9ce6186880e
2010-08-27 18:15:29 +00:00
ted.mielczarek
513083b598 Fix memory leak in BasicSourceLineResolver::UnloadModule
R=nealsid at http://breakpad.appspot.com/179001/show

git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@674 4c0a9323-5329-0410-9bdc-e9ce6186880e
2010-08-27 13:32:19 +00:00
ted.mielczarek
662b6da59d Allow Linux dumper to work on PTRACE-hardened kernels
A=Chris Coulson <chris.coulson@canonical.com>
R=nealsid at http://breakpad.appspot.com/166001/show

git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@673 4c0a9323-5329-0410-9bdc-e9ce6186880e
2010-08-27 13:18:49 +00:00
thestig@chromium.org
8e77c078d6 Limit the number of frames we try to walk to prevent runaway processors.
Review URL: http://breakpad.appspot.com/175001

git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@672 4c0a9323-5329-0410-9bdc-e9ce6186880e
2010-08-26 21:38:51 +00:00
jessicag.feedback@gmail.com
64506d2ed7 Issue 176001: Add package to process_state.proto to prevent name clashes.
git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@671 4c0a9323-5329-0410-9bdc-e9ce6186880e
2010-08-26 20:27:24 +00:00
thestig@chromium.org
aadace2751 Cleanup: Remove a useless check.
Review URL: http://breakpad.appspot.com/174001

git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@670 4c0a9323-5329-0410-9bdc-e9ce6186880e
2010-08-26 18:16:35 +00:00
ted.mielczarek
34d3a2e0f3 Update Makefile.am from r662 (which only updated Makefile.in)
git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@669 4c0a9323-5329-0410-9bdc-e9ce6186880e
2010-08-25 20:16:17 +00:00
mmentovai
2452f06b16 In on_demand_symbol_supplier, recognize architecture x86 and transform it to
i386 when requesting an on-demand dump of symbols. The string is passed to
system routines that understand this architecture as i386.
Review URL: http://breakpad.appspot.com/162001

git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@668 4c0a9323-5329-0410-9bdc-e9ce6186880e
2010-08-25 16:19:58 +00:00
jimblandy
c2c4192c1b Breakpad DWARF Reader: Ignore padding at the end of the compilation unit.
After the final DIE in a compilation unit, there may be any number of
zero bytes present. This is meant to allow producers to align
compilation unit starting points when necessary.

This patch changes the dwarf2reader::CompilationUnit class to skip
those zero bytes, rather than interpreting them as 'end of children'
markers for DIEs that do not exist. Without this change, the padding
bytes will cause the reader to attempt to pop an offset from an empty
stack, and call EndDIE with a garbage offset.

a=jimblandy, r=mmentovai


git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@667 4c0a9323-5329-0410-9bdc-e9ce6186880e
2010-08-25 15:11:15 +00:00
jimblandy
42943c2391 Breakpad DWARF parser: Don't use auto_ptr<stack<uint64> > where stack<uint64> would do.
Perhaps there once was some reason one needed the DIE offset stack to
have an unusual lifetime, but there is none now.

a=jimblandy, r=mmentovai


git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@666 4c0a9323-5329-0410-9bdc-e9ce6186880e
2010-08-25 15:10:19 +00:00
jimblandy
16f2f37682 Breakpad DWARF reader: Use uint64, not uint64_t in DWARF reader code.
The 64-bit cleanups made last month (http://breakpad.appspot.com/133001/show)
introduced unit test suite failures when built for a 32-bit architecture. The
fix for those test suite failures (http://breakpad.appspot.com/140001/show)
introduce build failures on Linux.

a=jimblandy


git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@665 4c0a9323-5329-0410-9bdc-e9ce6186880e
2010-08-25 00:54:26 +00:00
jimblandy
a453cc24f4 Commit issue 140001: fixes for 64-bit build cleanups.
a=dmaclach, r=jimb


git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@664 4c0a9323-5329-0410-9bdc-e9ce6186880e
2010-08-25 00:41:25 +00:00
jessicag.feedback@gmail.com
f8bca185b9 Adding process_state protobuf and derived C++ files. Included README as well.
git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@663 4c0a9323-5329-0410-9bdc-e9ce6186880e
2010-08-24 17:32:45 +00:00
nealsid
8d2c518c0b Patch from CDN to add support for an exploitability engine
A=cdn
R=nealsid



git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@662 4c0a9323-5329-0410-9bdc-e9ce6186880e
2010-08-24 14:28:10 +00:00
ted.mielczarek
3b7d8ee362 Disable cookies in Windows HTTPUpload
R=nealsid at http://breakpad.appspot.com/161001/show

git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@661 4c0a9323-5329-0410-9bdc-e9ce6186880e
2010-08-20 12:19:38 +00:00
jessicag.feedback@gmail.com
07a1c07b7b Clean up old glog code and move deps to new reference in third_party.
git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@660 4c0a9323-5329-0410-9bdc-e9ce6186880e
2010-08-19 22:23:03 +00:00
nealsid@gmail.com
2072e7e7a9 This checkin of the binaries was created by refresh_binaries.bat.
Date: Thu 08/19/2010 15:00:49.53 
Repository information (output of 'svn info') follows: 
Path: .
URL: https://google-breakpad.googlecode.com/svn/trunk/src
Repository Root: https://google-breakpad.googlecode.com/svn
Repository UUID: 4c0a9323-5329-0410-9bdc-e9ce6186880e
Revision: 658
Node Kind: directory
Schedule: normal
Last Changed Author: nealsid@gmail.com
Last Changed Rev: 658
Last Changed Date: 2010-08-19 14:53:35 -0700 (Thu, 19 Aug 2010)



git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@659 4c0a9323-5329-0410-9bdc-e9ce6186880e
2010-08-19 22:01:09 +00:00
nealsid@gmail.com
e167e9e61f Add glog style logging to symupload
git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@658 4c0a9323-5329-0410-9bdc-e9ce6186880e
2010-08-19 21:53:35 +00:00
ted.mielczarek
39edd96373 fix symupload / minidump_upload to match changes to HTTPUpload::SendRequest from r640
git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@657 4c0a9323-5329-0410-9bdc-e9ce6186880e
2010-08-18 12:24:55 +00:00
thestig@chromium.org
0b12b34928 When done with crash-dumping, we need to terminate the application. Calling
tgkill() is not necessarily possible, as a sandbox might block this call.
This changelist tries different approaches depending on whether we received
a synchronous or an asynchronous signal. This fixes unittest failures and
also runs correctly in sandbox'd environments.

TEST=ran unittest, and opened about:crash in sandbox'd Chrome
BUG=395
A=markus@chromium.org
Original review: http://breakpad.appspot.com/159001
Review URL: http://breakpad.appspot.com/146002

git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@656 4c0a9323-5329-0410-9bdc-e9ce6186880e
2010-08-17 02:59:01 +00:00
ted.mielczarek
2b7ae09319 remove trailing comma that makes gcc -pedantic unhappy
git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@653 4c0a9323-5329-0410-9bdc-e9ce6186880e
2010-08-16 18:23:52 +00:00
ted.mielczarek
31b4957eea Add missing stdint.h include to fix compilation on newer GCC.
git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@652 4c0a9323-5329-0410-9bdc-e9ce6186880e
2010-08-16 17:28:14 +00:00
ted.mielczarek@gmail.com
14889c340f Change ClientInfo into a class to match other platforms, rename the current ClientInfo to ExceptionInfo
R=mark at http://breakpad.appspot.com/156001/show

git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@651 4c0a9323-5329-0410-9bdc-e9ce6186880e
2010-08-16 16:48:59 +00:00
ted.mielczarek@gmail.com
a599ae80aa Put MachIPC into the google_breakpad namespace
R=mark at http://breakpad.appspot.com/151001/show

git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@650 4c0a9323-5329-0410-9bdc-e9ce6186880e
2010-08-16 16:44:47 +00:00
thestig@chromium.org
f5c8f6fb61 Fix a couple of bugs where we generate incorrect minidump files on Linux.o
Patch by Markus Gutschke <markus@chromium.org>.  R=thestig

Review URL: http://breakpad.appspot.com/150001
Review URL: http://breakpad.appspot.com/155001

git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@649 4c0a9323-5329-0410-9bdc-e9ce6186880e
2010-08-14 01:41:39 +00:00
thestig@chromium.org
3a69e0e1d1 Miscellaneous improvements to minidump-2-core.
Patch by Markus Gutschke <markus@chromium.org>.  R=agl
See http://breakpad.appspot.com/148002 and http://codereview.chromium.org/3152010.
Review URL: http://breakpad.appspot.com/152001

git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@648 4c0a9323-5329-0410-9bdc-e9ce6186880e
2010-08-14 01:32:54 +00:00
ted.mielczarek@gmail.com
144938cf22 Allow dumping live processes on OS X
R=mark at http://breakpad.appspot.com/148001/show

git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@647 4c0a9323-5329-0410-9bdc-e9ce6186880e
2010-08-13 20:19:32 +00:00
ted.mielczarek@gmail.com
315fd78199 Implement CrashGeneration{Client,Server} for OOP dump generation on OS X, enable OOP dump generation in ExceptionHandler
R=mark at http://breakpad.appspot.com/146001

git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@646 4c0a9323-5329-0410-9bdc-e9ce6186880e
2010-08-13 20:18:58 +00:00
jessicag.feedback@gmail.com
863aa2a74a Add protobuf external reference to third_party.
git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@645 4c0a9323-5329-0410-9bdc-e9ce6186880e
2010-08-13 18:53:15 +00:00
jessicag.feedback
25b9371026 Update readme and fix glog properties.
git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@644 4c0a9323-5329-0410-9bdc-e9ce6186880e
2010-08-13 18:49:03 +00:00
jessicag.feedback@gmail.com
e4f52d1c27 Add glog external reference to third party.
git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@643 4c0a9323-5329-0410-9bdc-e9ce6186880e
2010-08-13 18:44:36 +00:00
ted.mielczarek@gmail.com
26ff18d101 fix typo in previous commit
git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@642 4c0a9323-5329-0410-9bdc-e9ce6186880e
2010-08-12 01:21:58 +00:00
ted.mielczarek@gmail.com
44af96cd2d Change exception_handler_test.cc to use Google Test
git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@641 4c0a9323-5329-0410-9bdc-e9ce6186880e
2010-08-12 00:22:50 +00:00
ted.mielczarek
7cdcc98395 Allow passing certificate path to HTTPUpload::SendRequest
R=nealsid at http://breakpad.appspot.com/121002/show

git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@640 4c0a9323-5329-0410-9bdc-e9ce6186880e
2010-08-11 19:05:53 +00:00
mark@chromium.org
2543651766 Remove i386 from the set of architectures that the Mac crash_report tool's
on_demand_symbol_supplier will accept. These should always use x86. See r638.

git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@639 4c0a9323-5329-0410-9bdc-e9ce6186880e
2010-08-06 19:49:17 +00:00
mark@chromium.org
0ab73db415 Breakpad uses x86 as the architecture name, not i386. Most tools don't care
what architecture name is shown in a symbol file's MODULE line, but the Mac
crash_report tool's on_demand_symbol_supplier does. The new Mac dumper
inadvertently used i386. Correct that to make it x86. Temporarily make the
on_demand_symbol_supplier accept symbol files whose architecture is i386.
Also add x86_64 to the set of architectures that the on_demand_symbol_supplier
considers valid.

BUG=none
TEST=none
Review URL: http://breakpad.appspot.com/143001

git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@638 4c0a9323-5329-0410-9bdc-e9ce6186880e
2010-08-06 19:47:16 +00:00
ted.mielczarek
0fdc829d32 Fix HandleInvalidParameter/HandlePureVirtualCall to dynamically lookup the RtlCaptureContext symbol so the Windows exception handler will continue to work on Windows 2000. Patch by Jim Mathies <jmathies@mozilla.com> and Timothy Nikkel <tnikkel@gmail.com>. r=ted
git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@637 4c0a9323-5329-0410-9bdc-e9ce6186880e
2010-08-02 13:56:29 +00:00
dmaclach
0b814c1d2b review: http://breakpad.appspot.com/139001
git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@636 4c0a9323-5329-0410-9bdc-e9ce6186880e
2010-07-29 15:34:01 +00:00
dmaclach
1b8c24f337 review: http://breakpad.appspot.com/138001
git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@635 4c0a9323-5329-0410-9bdc-e9ce6186880e
2010-07-29 05:25:43 +00:00
dmaclach
97918069d8 Review: http://breakpad.appspot.com/137001
git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@634 4c0a9323-5329-0410-9bdc-e9ce6186880e
2010-07-28 19:06:30 +00:00
dmaclach
6e3869c19f Review: http://breakpad.appspot.com/136001
git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@633 4c0a9323-5329-0410-9bdc-e9ce6186880e
2010-07-28 18:23:15 +00:00
dmaclach
b5b8051a23 Review: http://breakpad.appspot.com/135001
BUG: none
TEST: Build GoogleTalk



git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@632 4c0a9323-5329-0410-9bdc-e9ce6186880e
2010-07-27 23:21:19 +00:00
dmaclach
a2d5da4831 Fixes up some style nits, and gets us compiling on Leopard again.
Review: http://breakpad.appspot.com/133001
BUG:none
TEST:Compile on Leopard



git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@631 4c0a9323-5329-0410-9bdc-e9ce6186880e
2010-07-27 16:33:22 +00:00
stuart.morgan
23eabdedab Adding 11 languages to the crash uploader app on the Mac, contributed by the Camino localization teams
git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@630 4c0a9323-5329-0410-9bdc-e9ce6186880e
2010-07-25 23:05:09 +00:00
ted.mielczarek
6f598cc435 Fix unit tests that have not built since @610
A=kmixter R=ted
http://breakpad.appspot.com/132001

git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@629 4c0a9323-5329-0410-9bdc-e9ce6186880e
2010-07-23 17:20:42 +00:00
mark@chromium.org
615d2c0d6d Separate the "hello" message from the parameter messages in
Inspector::ReadMessages as was done before r627. The "hello" message contains
the parameter count and is referenced while the message reader loops through
parameter messages. Prior to r627, both messages were named |message|, which
was confusing, probably caused a compiler warning, and apparently provided the
motivation to share them. This caused the crash inspector to fail to properly
collect the parameters. The common failure mode (although others are possible)
was for the inspector to attempt tor read more parameter messages than were
available, resulting in an IPC timeout and inspector death. No crash report
would be written, and the application expecting its crash to be inspected
would time out waiting for a response from the inspector and then _exit. This
is effectively a failure to properly handle crashes.

The inner message is reintroduced, and named parameter_message for
disambiguation.

BUG=chromium:49821
TEST=Crashes catchable by the Mac Breakpad framework
Review URL: http://breakpad.appspot.com/123002

git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@628 4c0a9323-5329-0410-9bdc-e9ce6186880e
2010-07-21 21:21:07 +00:00
dmaclach
4ac61acb3a Clean up build for 64 bit.
Fix up some broken mac projects.
Consolidate project settings in xcconfig files.

http://breakpad.appspot.com/130001



git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@627 4c0a9323-5329-0410-9bdc-e9ce6186880e
2010-07-19 20:43:49 +00:00
jimblandy
786275e719 Breakpad Linux/Mac symbol dumper: Share duplicate strings that arise in DWARF data.
This patch avoids allocating many copies of identical strings appearing in
debugging information. Without this patch, running dump_syms on Mozilla's
libxul.so (with 173MiB of debugging information) has a peak resident set of
around 450MiB. With this patch, the peak is around 365MiB.

a=jimblandy, r=mark


git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@626 4c0a9323-5329-0410-9bdc-e9ce6186880e
2010-07-17 15:14:30 +00:00
jimblandy
c5f5e0ae65 Breakpad Linux dumper: Don't map file into memory a second time just to compute file ID
At present, the Linux symbol dumper maps the ELF file into memory to
examine the debugging information it contains, but then also calls
google_breakpad::FileID::ElfFileIdentifier, which maps the ELF file into
memory again. Some of our object files are large; Mozilla's libxul.so is
1.1GiB. Trying to map such files twice can interfere with tools like
valgrind that map themselves into high addresses (in an attempt to stay out
of the way of ordinary programs).

The FileID class has another method, ElfFileIdentifierFromMappedFile, that
operates on an already-loaded image of the file; use that instead.

a=jimblandy, r=thestig


git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@625 4c0a9323-5329-0410-9bdc-e9ce6186880e
2010-07-17 05:08:04 +00:00
thestig@chromium.org
56eac4dd7a Add functionality to read the .gnu_debuglink section and load symbols from a debug ELF file.
Review URL: http://breakpad.appspot.com/126001

git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@624 4c0a9323-5329-0410-9bdc-e9ce6186880e
2010-07-16 00:43:42 +00:00
thestig@chromium.org
0dd6c95b3f Remove duplicate FUNC entries from dump_syms output.
Review URL: http://breakpad.appspot.com/128001

git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@623 4c0a9323-5329-0410-9bdc-e9ce6186880e
2010-07-13 18:14:27 +00:00
ted.mielczarek@gmail.com
8014071440 Fix a couple of tiny things for GCC pedantry
git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@622 4c0a9323-5329-0410-9bdc-e9ce6186880e
2010-07-08 15:30:17 +00:00
thestig@chromium.org
1c87cc86e3 Remove some duplicate endianness code.
Review URL: http://breakpad.appspot.com/125001

git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@621 4c0a9323-5329-0410-9bdc-e9ce6186880e
2010-07-06 05:13:21 +00:00
thestig@chromium.org
7fbd77715f Linux: Skip sections of type SHT_NOBITS when loading symbols.
Review URL: http://breakpad.appspot.com/120001

git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@620 4c0a9323-5329-0410-9bdc-e9ce6186880e
2010-07-06 05:11:50 +00:00
ted.mielczarek
e193098543 Breakpad: Avoid using the C++ <cfoo> headers.
This patch avoids unnecessary use of the <cfoo> headers in files that don't
actually use the identifiers they declare in the std:: namespace.

It also changes some files to better conform with the "Names and Order of
Includes" rules in the Google C++ Style Guide.

A=jimb R=mark

git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@619 4c0a9323-5329-0410-9bdc-e9ce6186880e
2010-06-25 16:57:07 +00:00
ted.mielczarek
4f456b8c0d Breakpad DWARF CFI support: Cleanups requested by Neal
I came across a bunch of comments Neal had made on issue 55011 that I
hadn't addressed.  This patch takes care of them.
A=jimb R=thestig

git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@618 4c0a9323-5329-0410-9bdc-e9ce6186880e
2010-06-25 16:57:02 +00:00
ted.mielczarek
b80b13fd2f Breakpad Linux symbol dumper: Remove unneeded objects from test executables
The dwarf_cu_to_module_unittest and bytereader_unittest test executables
include object files from which they use no code.
A=jimb R=thestig

git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@617 4c0a9323-5329-0410-9bdc-e9ce6186880e
2010-06-25 16:56:58 +00:00
ted.mielczarek
f16fbd5e96 Breakpad CFI parser: Add unit tests to XCode project.
This patch adds all the appropriate symbol dumper unit tests to the Mac
XCode dump_syms project. This allows us to test this code on a 64-bit
platform.
A=jimb R=mark

git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@616 4c0a9323-5329-0410-9bdc-e9ce6186880e
2010-06-25 16:56:53 +00:00
ted.mielczarek
6869f2e1b3 Breakpad DWARF CFI parser: Use the proper type for offsets in CallFrameInfo::Rule subclasses.
The subclasses of CallFrameInfo::Rule store the rule currently in
force for recovering a register or computing the canonical frame
address. Their sole responsibility is to accurately convey rules from
the parser, which creates them, to a CallFrameInfo::Handler member
function, which consumes them. So, the types of their data members
should match those of the corresponding arguments of the corresponding
Handler member function.

CallFrameInfo::OffsetRule and CallFrameInfo::ValOffsetRule use an
'int' to store the rule's offset value, but
CallFrameInfo::Handler::OffsetRule and ...::ValOffsetRule expect a
'long'.  On ABIs where 'long' is larger than 'int', this can cause
values to be truncated or sign-extended unexpectedly.

This patch changes those members to 'long'.

Fortunately, offsets appearing in real DWARF call frame information
never even come close to the limits of a 32-bit int, so this bug is
unlikely to cause any practical problems.
A=jimb R=thestig

git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@615 4c0a9323-5329-0410-9bdc-e9ce6186880e
2010-06-25 16:56:48 +00:00
ted.mielczarek
1adc07f0ff Breakpad Mac symbol dumper: Unify with Linux dumper; support DWARF CFI.
This patch rewrites the Mac symbol dumper to use the same set of classes
the Linux dumper does for reading debugging information from various
sources, consolidating them into a single table, and writing that out as a
Breakpad symbol file.

In the process, it also adds support for dumping DWARF call frame
information and .eh_frame exception-handling information as Breakpad 'STACK
CFI' records. This allows the Breakpad processor to generate stack traces
from code compiled with -fomit-frame-pointer.

The patch also replaces the DumpSymbols Objective C++ class with
google_breakpad::DumpSymbols, a plain C++ class. The code still uses some
Objective C++ to use the Foundation facilities for dealing with file names
in a file-system-independent fashion, and for examining the contents of
.dSYM bundles.

Since the code has been entirely rewritten, I have changed the author
lines.
A=jimb R=mark

git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@614 4c0a9323-5329-0410-9bdc-e9ce6186880e
2010-06-25 16:56:42 +00:00
ted.mielczarek
9c1e16eaaa Breakpad DWARF support: Stop #including unneeded headers.
The #inclusions of <elf.h> and <link.h> were inherited from older code, but
the current code doesn't need anything from them, so they should be
removed.
A=jimb R=thestig

git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@613 4c0a9323-5329-0410-9bdc-e9ce6186880e
2010-06-25 16:56:37 +00:00
ted.mielczarek
bd0a7f9da1 Breakpad DWARF support: Check for DWARF line info under Mac OS X section names.
For some reason, Mac OS X places DWARF debugging information in sections
whose names begin with "__", rather than the names beginning with "." given
in the DWARF spec. This patch changes google_breakpad::DwarfCUToModule to
look for line number information under both names.
A=jimb R=mark

git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@612 4c0a9323-5329-0410-9bdc-e9ce6186880e
2010-06-25 16:56:32 +00:00
ted.mielczarek
75ce593891 Breakpad Mac dumper: Change the dumper to be more C++-ish.
Instead of using bzero in main, use constructors to initialize the
Options structure.

Use C++ bool, not Objective-C BOOL.

Use a const NXArchInfo * to represent the architecture name, so that we can
use the NXGetLocalArchInfo, NXGetArchInfoFromName, etc. to handle things.

Delete the 'uuidStr' member; it is unused.

Leave Options::srcPath as an NSString, so that we can continue to use the
filesystem path abstraction methods provided by the Foundation framework.
A=jimb R=mark

git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@611 4c0a9323-5329-0410-9bdc-e9ce6186880e
2010-06-25 16:56:27 +00:00
ted.mielczarek
35c41e00ee Breakpad Mac symbol dumper: Add new Mach-O reader class.
This patch adds files defining new classes in the google_breakpad::Mach_O
namespace for parsing fat binaries and Mach-O files. These are used in the
new dumper to handle STABS debugging information, DWARF call frame
information, and .eh_frame exception handling stack walking information.

These new classes are independent of endianness and word size, and
therefore can be used on binaries of all the relevant architectures: x86,
x86_64, ppc, and ARM.

The patch adds a complete set of unit tests for the new classes.
A=jimb R=mark (http://breakpad.appspot.com/93001/show, http://breakpad.appspot.com/115001/show)

git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@610 4c0a9323-5329-0410-9bdc-e9ce6186880e
2010-06-25 16:56:16 +00:00
mark@chromium.org
8ffb12eb35 Convert files in .nib format to .xib format.
Review URL: http://breakpad.appspot.com/122001

git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@609 4c0a9323-5329-0410-9bdc-e9ce6186880e
2010-06-23 20:06:13 +00:00
thestig@chromium.org
a4067bc197 Add codereview.settings so we can use gcl.
git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@608 4c0a9323-5329-0410-9bdc-e9ce6186880e
2010-06-19 02:48:54 +00:00
nealsid
e4cc9b12ec Fix test breakage caused by my last checkin :-(
git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@607 4c0a9323-5329-0410-9bdc-e9ce6186880e
2010-06-04 20:53:20 +00:00
nealsid
4f182c746b Add access violation detail for windows (read/write/dep). Add stack buffer overrun and heap corruption exceptions for windows. Additional detail requested to improve Chrome crash analysis
A=cdn
R=nealsid
http://codereview.chromium.org/2429003/show



git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@606 4c0a9323-5329-0410-9bdc-e9ce6186880e
2010-06-04 16:59:23 +00:00
ted.mielczarek
c0fc538ae4 Fix compilation on gcc 4.5 by adding a missing #include. Patch by Benoit Jacob <bjacob@mozilla.com>, r=me at https://bugzilla.mozilla.org/show_bug.cgi?id=569836
git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@605 4c0a9323-5329-0410-9bdc-e9ce6186880e
2010-06-03 15:29:46 +00:00
nealsid
8e3c63b7f9 Remove LOG statements from linux utilities so there's no dependency on log library
A=Zhurun
R=nealsid




git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@604 4c0a9323-5329-0410-9bdc-e9ce6186880e
2010-05-27 19:37:24 +00:00
ted.mielczarek
b0059c54da Issue 384 - UnregisterWait error handling is incorrect. Patch by Benjamin Smedberg <benjamin@smedbergs.us>, r=doshimun at http://breakpad.appspot.com/107001
git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@603 4c0a9323-5329-0410-9bdc-e9ce6186880e
2010-05-19 13:40:59 +00:00
nealsid
0b54af4f91 Patch from Vitaly to remove synchronization and make exception handling code single-threaded
git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@602 4c0a9323-5329-0410-9bdc-e9ce6186880e
2010-05-18 17:50:25 +00:00
nealsid
4abf9d9ebd Updated binaries to use a statically linked CRT
git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@601 4c0a9323-5329-0410-9bdc-e9ce6186880e
2010-05-18 17:47:59 +00:00
thestig@chromium.org
1273651fcf Delete svn:executable from the DEPS file. Hans has a badly configured client on Windows?
git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@600 4c0a9323-5329-0410-9bdc-e9ce6186880e
2010-05-18 01:46:59 +00:00
hansl@google.com
7b106e34ba Changed two files end-line to make it work better with GYP. They were DOS (CR/LF), now they are UNIX (CR).
It seems like the base gyp scripts on Windows were confused about this and didn't handle it well, while using gyp through gclient worked perfectly. I did not investigate the causes further.

Review URL: http://codereview.chromium.org/2128003

git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@599 4c0a9323-5329-0410-9bdc-e9ce6186880e
2010-05-14 18:43:43 +00:00
nealsid
951583a8ca Fix for uninitialized variable in basic_source_line_resolver.cc
R=TBR
A=nealsid



git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@598 4c0a9323-5329-0410-9bdc-e9ce6186880e
2010-05-13 22:21:00 +00:00
hansl@google.com
bcf885c807 Added a death test for the pure virtual function call.
Added a test for the minidump generated by a pure virtual function call.
Changed the pure virtual function call handler so that it creates a minidump with Exception info and a stack.

Review URL: http://codereview.chromium.org/2050013

git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@597 4c0a9323-5329-0410-9bdc-e9ce6186880e
2010-05-13 21:00:43 +00:00
hansl@google.com
8cf0a52bec Moved exception_handler_test to the more aptly named exception_handler_death_test. It doesn't test anything else than death and exit.
Created the exception_handler_test that test the generation of dump and the dumps themselves.
Moved all dump analysis code from minidump to its right class DumpAnalysis. The class is used by both minidump_test and exception_handler_test. The tests are way simpler that way (ie. no handling of HANDLE).
minidump_test now uses the minidump_generator class instead of using Win32. It works well and pass all tests.
exception_handler now passes both the exception and assertion infos to the client to generate the dump. If one is NULL it's going to be handled correctly.
crash_generation_client can now RequestDump with both exception and assertion info.
minidump_generator returns both the mini and full dump string pointers, and output both (or either) depending on which was generated.
All original interfaces and method signature are still there, but call the new functions if possible.

Review URL: http://codereview.chromium.org/1994015

git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@596 4c0a9323-5329-0410-9bdc-e9ce6186880e
2010-05-12 17:51:21 +00:00
nealsid
7d0d107b17 Adding prebuilt dump_syms.exe.
Http://breakpad.appspot.com/issues/111001

A=nealsid
R=mark mentovai



git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@595 4c0a9323-5329-0410-9bdc-e9ce6186880e
2010-05-11 21:25:13 +00:00
nealsid
3d0b3be6c0 This checkin of the binaries was created by refresh_binaries.bat.
Date: Mon 05/10/2010 15:55:34.46 
Repository information (output of 'svn info') follows: 
Path: .
URL: https://google-breakpad.googlecode.com/svn/trunk/src
Repository Root: https://google-breakpad.googlecode.com/svn
Repository UUID: 4c0a9323-5329-0410-9bdc-e9ce6186880e
Revision: 593
Node Kind: directory
Schedule: normal
Last Changed Author: nealsid
Last Changed Rev: 593
Last Changed Date: 2010-05-10 13:35:54 -0700 (Mon, 10 May 2010)



git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@594 4c0a9323-5329-0410-9bdc-e9ce6186880e
2010-05-10 22:55:45 +00:00
nealsid
6bc523c618 Changes to fix build warnings on newer versions of GCC, and a fix to not try to open certain mapped files.
A=ZhurunZ, Tristan Schmelcher
R=nealsid



git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@593 4c0a9323-5329-0410-9bdc-e9ce6186880e
2010-05-10 20:35:54 +00:00
hansl@google.com
297b1e5a06 Copied minidump_test.cc from chrome_frame (see http://src.chromium.org/viewvc/chrome/trunk/src/chrome_frame/crash_reporting/minidump_test.cc).
I had to remove the dependency from base (was using FilePath and ScopedHandle, replaced them by standard std::wstring and HANDLE). Also removed the logging and the main from the original files.

This will serve as a base for testing breakpad's dump generation. It is kept like this for easier tracking.

Review URL: http://codereview.chromium.org/1964006

git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@592 4c0a9323-5329-0410-9bdc-e9ce6186880e
2010-05-05 21:38:18 +00:00
jimblandy
f6163f1e29 Breakpad Mac dumper: Clean up XCode project file.
The XCode project file has become encrufted with duplicate Executable
entres and some strange settings. This patch deletes and recreates various
entries to make things neat again. It should have no effect on the
project's visible behavior.

a=jimblandy, r=thestig


git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@591 4c0a9323-5329-0410-9bdc-e9ce6186880e
2010-05-05 18:18:28 +00:00
jimblandy
073a7f6695 Breakpad unit tests: Add support for clipped-size null-terminated strings
to TestAssembler::Section.

This patch helps the TestAssembler classes generate Mach-O object files for
use as test input.

This patch adds a new AppendCString overloading to TestAssembler::Section
for emitting null-terminated strings in fixed-length buffers, where the
string is truncated and the terminating null character omitted if the
string is too large for the buffer.

The patch includes unit tests for the new AppendCString overloading. It
also provides some for the existing overloading, which had been neglected.

a=jimblandy, r=mark


git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@590 4c0a9323-5329-0410-9bdc-e9ce6186880e
2010-05-05 17:37:58 +00:00
jimblandy
52a508dfe2 Breakpad Mac Dumper: Fix compilation warnings on OS X 10.6
Breakpad's Macintosh symbol dumper uses deprecated functions for
dealing with mixed-endianness code. This patch provides an overloaded
function, ByteSwap, that automatically chooses the OSSwap* functions
from <libkern/OSByteOrder.h> appropriate for its argument's
size.

This patch does *not* address warnings in src/common/mac/dump_syms.mm,
because that code is about to be replaced entirely; there's no reason to
bother reviewing a big, detailed patch against it.

a=jimblandy, r=mark


git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@589 4c0a9323-5329-0410-9bdc-e9ce6186880e
2010-05-05 17:36:16 +00:00
jimblandy
25b512d64d Breakpad symbol dumper: Promise that Module::SetLoadAddress can be called at any time.
It's possible to imagine an implementation of google_breakpad::Module in
which calling SetLoadAddress at different times as the Module is populated
would produce different output. For the Mac dumper, we'd like to depend on
its current behavior --- that the load address is subtracted off only when
writing the symbol file, and can be set at any time prior to that.

This patch makes that promise part of Module's contract, and adjusts the
test suite to verify that that promise is met.

a=jimblandy, r=thestig


git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@588 4c0a9323-5329-0410-9bdc-e9ce6186880e
2010-05-05 17:35:10 +00:00
jimblandy
775c6f7640 Breakpad Linux dumper: Handle STABS-in-symbol-table, and line number records outside functions.
This patch addresses two differences between Linux and Macintosh OS X STABS
data:

- StabsReader assumes that the STABS entries follow the conventions for
  storing STABS data in object file sections (that is, .stabs and
  .stabstr), rather than in the object files's linker symbol table. On Mac
  OS X, STABS entries live in the Mach-O file's LC_SYMTAB load command,
  along with all the other linker symbols; they are not grouped into units
  by N_UNDF entries.

  This patch adds a boolean argument to the StabsReader constructor
  indicating whether the parser should treat N_UNDF entries as unit
  boundaries; this argument should be true on Linux, and false on Mac. The
  patch changes src/common/linux/dump_symbols.cc to pass this new argument.

- Mac OS X STABS place SLINE (line number) records immediately before the
  FUN record for the function to which they belong, and the values of such
  records are absolute, not relative to the function start.

  This patch extends the parser to queue up such records and report them to
  the handler when we do see the FUN record. The meaning of
  StabsHandler::Line remains unchanged; existing handlers do not need to be
  adjusted.

This patch also adds unit tests for the new parser behaviors.

a=jimblandy, r=mark


git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@587 4c0a9323-5329-0410-9bdc-e9ce6186880e
2010-05-05 17:34:19 +00:00
jimblandy
d3e4bbb9c7 Breakpad STABS parser: Use a test fixture in StabsReader unit tests.
This patch factors out some of the common code in the StabsReader unit
tests into a fixture class. Pretty mechanical.

a=jimblandy, r=thestig


git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@586 4c0a9323-5329-0410-9bdc-e9ce6186880e
2010-05-05 17:25:47 +00:00
jimblandy
deb500f6c8 Breakpad STABS reader: Properly compute function end addresses.
An N_FUN stabs with no name is an explicit end-of-function marker, whose
value is the size of the function. This patch changes the stabs reader to
recognize these and use them to compute the function's ending address,
instead of treating them as functions with no names and mysterious
addresses. It also adds appropriate unit tests.

a=jimblandy, r=thestig


git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@585 4c0a9323-5329-0410-9bdc-e9ce6186880e
2010-05-05 17:13:42 +00:00
jimblandy
b28be1254c Breakpad Linux dumper: Rename DumpStabsHandler to StabsToModule.
All the other classes which receive debugging data from some sort of parser
and use it to populate a Module have names ending in "ToModule":
DwarfCUToModule, DwarfCFIToModule. Also, DumpStabsHandler doesn't actually
dump anything.

This patch renames the DumpStabsHandler class to StabsToModule, which is
more consistent and descriptive.

a=jimblandy, r=thestig


git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@584 4c0a9323-5329-0410-9bdc-e9ce6186880e
2010-05-05 17:12:38 +00:00
jimblandy
b0ec96cee2 Breakpad Linux dumper: Make StabsReader independent of endianness and word size.
StabsReader simply applies a reinterpret_cast to treat the stab entry data
as an array of 'struct nlist' structures, making the parser specific on the
host endianness, word size, and alignment rules. On Mac OS X, a single fat
binary file may contain object files of different ABIs, of which the user
chooses one at run time.

This patch changes the parser to read the data using the google_breakpad::
ByteCursor class, which can handle different endiannesses and word sizes.
The StabsReader constructor now takes arguments indicating the endianness
of the data and the size of each entry's value field. The patch changes
src/common/linux/dump_symbols.cc to pass the new argument.

This patch changes the StabsReader unit tests to use the google_breakpad::
TestAssembler classes to generate test data, rather than reading it from a
file. This makes it easy to generate test data in various endiannesses and
word sizes. It also adds tests for the new parser behaviors.

a=jimblandy, r=thestig


git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@583 4c0a9323-5329-0410-9bdc-e9ce6186880e
2010-05-05 17:09:20 +00:00
jimblandy
6c97801617 Breakpad symbol dumper: Define the ByteBuffer and ByteCursor classes.
The ByteBuffer and ByteCursor classes are utility classes for reading
binary files, handling endianness and word size issues in a portable way.

a=jimblandy, r=thestig


git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@582 4c0a9323-5329-0410-9bdc-e9ce6186880e
2010-05-05 17:07:23 +00:00
hansl@google.com
ffedcd4945 Replacing solutions with gyp files. Moving tests for windows clients in unittests.
Review URL: http://codereview.chromium.org/1687018

git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@581 4c0a9323-5329-0410-9bdc-e9ce6186880e
2010-05-03 20:21:40 +00:00
nealsid
eee511f1df Fix dependency on Visual C++ 9 introduced by revision 557.
A=nealsid
r=mmentovai

http://breakpad.appspot.com/105001/



git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@580 4c0a9323-5329-0410-9bdc-e9ce6186880e
2010-04-29 22:32:32 +00:00
ted.mielczarek
c90769edd6 Fix assembly in the ARM sys_clone implementation to indicate that r7 is clobbered, and also remove some extraneous semicolons from ARM portions of linux_syscall_support. r=jimb at https://bugzilla.mozilla.org/show_bug.cgi?id=555674
git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@579 4c0a9323-5329-0410-9bdc-e9ce6186880e
2010-04-29 18:24:04 +00:00
ted.mielczarek
131c0c6a83 issue 372 - fix Mac OS X minidump generation code to handle x86-64 properly. r=mark at http://breakpad.appspot.com/103001
git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@578 4c0a9323-5329-0410-9bdc-e9ce6186880e
2010-04-29 18:02:42 +00:00
nealsid
f2dfb88b2a Fix include paths to be consistent with rest of project
http://breakpad.appspot.com/104001

A=nealsid



git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@577 4c0a9323-5329-0410-9bdc-e9ce6186880e
2010-04-28 23:03:59 +00:00
jimblandy
56e7a3c65d Breakpad Linux Dumper: Have DumpStabsHandler free accumulated functions if Finalize is not called
The DumpStabsHandler class creates Module::Function objects as it processes
data from the StabsReader, but waits to add the Functions to the Module
until all parsing is complete and its Finalize member function is called,
so that it can compute line and function end addresses that the STABS data
may have left implicit.

If the DumpStabsHandler is destructed before its Finalize method is called,
it fails to free the Functions it has created, but not yet added to the
Module. (Adding a Function to a Module transfers ownership of the Function
to the Module.)

This adds a destructor to DumpStabsHandler which takes care of freeing any
Functions that it still owns.

a=jimblandy, r=thestig


git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@576 4c0a9323-5329-0410-9bdc-e9ce6186880e
2010-04-28 18:16:00 +00:00
jimblandy
504280af60 Breakpad Dumper: Move CFI register names to DwarfCFIToModule class.
At the moment, the mappings from register numbers appearing in DWARF CFI
and .eh_frame exception handling sections to the appropriate
processor-specific names are in src/common/linux/dump_syms.cc. However, the
numberings are (for the most part) the same on all platforms using DWARF,
so there's no reason those tables shouldn't be shared between the Linux and
Mac symbol dumpers.

This patch moves the tables into a nested class of DwarfCFIToModule, so
they the Mac dumper can use them when it is changed to use
DwarfCFIToModule.

a=jimblandy, r=thestig


git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@575 4c0a9323-5329-0410-9bdc-e9ce6186880e
2010-04-28 18:14:59 +00:00
jimblandy
865df5af57 Breakpad test support: Move test_assembler.{h,cc} from src/processor to src/common.
The google_breakpad::TestAssembler classes are used in both the processor's
and the Linux dumper's test suites, and will soon be used in the Mac
dumper's tests as well. This patch moves their source files from
src/processor to src/common.

a=jimblandy, r=thestig


git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@574 4c0a9323-5329-0410-9bdc-e9ce6186880e
2010-04-27 19:17:59 +00:00
nealsid
d5b689e7af Patch from Zhurun to fix build breaks in gcc 4.4.1
CR URL: http://breakpad.appspot.com/100001/show

A=Zhurun
R=nealsid


git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@573 4c0a9323-5329-0410-9bdc-e9ce6186880e
2010-04-26 23:52:50 +00:00
jimblandy
089003b7f6 Breakpad processor: Work around overload resolution problems in stream pos_type comparisons
When building with G++ 4.1.2, src/processor/cfi_frame_info.cc fails to
build with the error below. G++ 4.2.1 and later do not seem to report this
problem.

This patch works around the problem by casting stream.tellp() to
std::streamoff before doing the comparison.

src/processor/cfi_frame_info.cc: In member function `std::string google_breakpad::CFIFrameInfo::Serialize() const':
src/processor/cfi_frame_info.cc:105: error: ambiguous overload for `operator!=' in `stream.std::basic_ostringstream<char, std::char_traits<char>, std::allocator<char> >::<anonymous>.std::basic_ostream<_CharT, _Traits>::tellp [with _CharT = char, _Traits = std::char_traits<char>]() != 0'
src/processor/cfi_frame_info.cc:105: note: candidates are: operator!=(std::streamoff, int) <built-in>
/usr/lib/gcc/x86_64-redhat-linux/4.1.2/../../../../include/c++/4.1.2/bits/postypes.h:143: note:                 bool std::fpos<_StateT>::operator!=(const std::fpos<_StateT>&) const [with _StateT = __mbstate_t]

a=jimblandy, r=mmentovai


git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@572 4c0a9323-5329-0410-9bdc-e9ce6186880e
2010-04-20 15:56:32 +00:00
jimblandy
1e73bad86e Breakpad stack walker: remove embedded newlines from module names.
pdb filenames in crash reports may contain embedded newlines. When
minidump-stackwalk prints these lines, it ends up with:

Module|olek8r4u.dll|6.0.6000.16386|\\xc2\\xeb\\x17\\x04J\\xb6:\\xbaT\\xf3\\xef\\xe8Y\\x90\\x86\\xaa\\xe5\\x16n\\xb1\\x80\\x85\\t\\x12!\\x16\\x0f\\x98\\xf8\\x89\\x16"\\x96\\xd4\\x84\\x88\\xea\\xe3\\r\\r\\x1b\\xca\\x85*^h\\xf5\\xdc\n\\xd9\\xf4}j\\x1d7\\xe39o\\x1f\\xc5\\xc4\\xa6x\\x8ba\\xe8\\xd6K\\x89H\\xe1\\xff\\xe7\\xf5\\xf0Y\\xfd\\xf5\\xdbu\\x0c\\x07\\x86\\xed|29E0B04FCCBE47EB86A6C819E8B89D051|0x00f60000|0x00ff2fff|0\n

Which has an embedded newline and the machine parser can't handle it. This
patch just strips the embedded newline, just as we strip embedded |
separator characters.

a=bsmedberg, r=jimblandy


git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@571 4c0a9323-5329-0410-9bdc-e9ce6186880e
2010-04-15 19:00:28 +00:00
jessicag.feedback@gmail.com
a62dc27d23 Mac now takes response code into account when determining success of a symupload.
git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@570 4c0a9323-5329-0410-9bdc-e9ce6186880e
2010-04-13 19:00:49 +00:00
ted.mielczarek
b223627d81 provide a network source line resolver + server. r=mark,jimb at http://breakpad.appspot.com/36001
git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@569 4c0a9323-5329-0410-9bdc-e9ce6186880e
2010-04-08 23:06:23 +00:00
mmentovai
c0ec51afe0 Include what you use.
Patch by Adam Langley <agl@chromium.org>.  r=me


git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@568 4c0a9323-5329-0410-9bdc-e9ce6186880e
2010-04-05 19:54:48 +00:00
jimblandy
87855248f1 Breakpad symbol dumper: Move Linux dumping classes into src/common.
The Linux symbol dumper's classes are reasonably portable, and should be
usable for the Mac dumper as well. Move them to src/common, along with
their unit tests. Update #include directives and Makefile.

a=jimblandy, r=nealsid


git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@567 4c0a9323-5329-0410-9bdc-e9ce6186880e
2010-04-05 19:40:17 +00:00
jimblandy
9e6b619ad0 Breakpad Linux Dumper: Disable warnings about unpaired functions and lines by default.
In the process of pairing up DWARF source lines with the functions they
belong to, the dumper detects and warns about regions of functions that
have no source line information, and vice versa. However, this seems to
occur in real code frequently enough (although not often) that the warnings
may obscure more serious problems.

This patch makes those warnings disabled by default in
DwarfCUToModule::WarningReporter. It does not add a way for the dump_syms
user to enable them.

a=jimblandy, r=nealsid


git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@566 4c0a9323-5329-0410-9bdc-e9ce6186880e
2010-04-05 19:35:10 +00:00
mmentovai
5c27539f91 Add gettimeofday to linux_syscall_support.h
Patch by Adam Langley <agl@chromium.org>.
R=me


git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@565 4c0a9323-5329-0410-9bdc-e9ce6186880e
2010-04-02 16:46:13 +00:00
jimblandy
b34b1d8525 Breakpad Linux dumper: Use the correct section's base address.
In order to dump call frame information held in .eh_frame sections, the
dumper needs to know the proper base address to use for pointers encoded
using the DW_EH_PE_textrel encoding. This should be the start of the .text
section. However, due to a cut-and-paste typo, the dumper was supplying the
base address of the ".got" section instead.

a=jimblandy, r=nealsid


git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@564 4c0a9323-5329-0410-9bdc-e9ce6186880e
2010-04-01 22:58:18 +00:00
jimblandy
2a18f064ce Breakpad Linux dumper: Generate make dependencies on header files automatically.
The Linux dumper's Makefile doesn't record the object files' dependence on
header files at all, just because I was too lazy to write them out and knew
I would forget to keep them up to date anyway. But I've wasted too much
time tracking down mysterious segmentation faults and other problems after
changing header files, and I know it's wasted others' time, too.

a=jimblandy, r=nealsid,dmuir


git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@563 4c0a9323-5329-0410-9bdc-e9ce6186880e
2010-04-01 22:57:06 +00:00
jimblandy
a0aca73851 Breakpad Linux dumper: Include filename in error messages.
a=jimblandy, r=nealsid


git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@562 4c0a9323-5329-0410-9bdc-e9ce6186880e
2010-03-31 15:32:31 +00:00
jimblandy
608d142aaa Breakpad DWARF parser: correct comments regarding dynamic_cast.
The comments don't accurately describe what the style guide says.

Regardless of what the style guide says, RTTI seems to make trouble in
practice, because so many people build with it disabled. Since only the
symbol dumper uses RTTI, not the client library, it may be practical for
people to simply enable RTTI for the dumper. Failing that, it may be best
in the long run to violate the style guide and make the code work sans
RTTI.

a=jimblandy, r=mmentovai


git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@561 4c0a9323-5329-0410-9bdc-e9ce6186880e
2010-03-30 21:36:58 +00:00
jimblandy
00dbb73752 Breakpad Linux dumper: Make changes requested by Neal Sidhwaney in issue 59002.
- Use manifest constants for 'z' augmentation letters.
- Fix typos and rearrange some code for legibility.

a=jimblandy, r=nealsid


git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@560 4c0a9323-5329-0410-9bdc-e9ce6186880e
2010-03-29 18:31:53 +00:00
jimblandy
f3319839c4 [ Mistakenly committed older version of patch. This is the right one. ]
Breakpad Linux client: Simplify VerifyStackReadWithMultipleThreads unit test.

As written, the VerifyStackReadWithMultipleThreads unit test makes
assumptions about the layout of thread_function's stack frame. As a result,
the test will fail when compiled with some compilers, or built with certain
optimization levels.

As an extension to C++, the GNU compilers allow you to request that a
variable be placed in a specific register. Using this, we can have
thread_function put the thread id in place where the test can find it
reliably.

a=jimblandy, r=nealsid


git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@559 4c0a9323-5329-0410-9bdc-e9ce6186880e
2010-03-29 18:27:11 +00:00
jimblandy
b68b800189 Breakpad Linux client: Simplify VerifyStackReadWithMultipleThreads unit test.
As written, the VerifyStackReadWithMultipleThreads unit test makes
assumptions about the layout of thread_function's stack frame. As a result,
the test will fail when compiled with some compilers, or built with certain
optimization levels.

As an extension to C++, the GNU compilers allow you to request that a
variable be placed in a specific register. Using this, we can have
thread_function put the thread id in place where the test can find it
reliably.

a=jimblandy, r=nealsid


git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@558 4c0a9323-5329-0410-9bdc-e9ce6186880e
2010-03-29 18:23:42 +00:00
siggi@chromium.org
18dd9d0104 Fix HandleInvalidParameter to provide a locally created exception record for the minidump.
Having an exception of interest makes the resultant minidumps look just like
crash dumps, in that the processor can identify the "crashing" tread. 
This means such minidumps can be classified by the stack signature, in contrast to the current state of things, in which all such dumps get lumped on a single pile.


git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@557 4c0a9323-5329-0410-9bdc-e9ce6186880e
2010-03-26 16:03:58 +00:00
jimblandy
43135e6e46 Add omitted newline to warning message in StabsReader::SymbolString.
a=jimblandy, no reviewer


git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@555 4c0a9323-5329-0410-9bdc-e9ce6186880e
2010-03-18 18:59:27 +00:00
jimblandy
e7e1e1ebf5 Breakpad processor: Support AMD64 stack unwinding driven by DWARF CFI.
This adds support for 'STACK CFI' records (DWARF CFI) to the AMD64
stack walker. This is necessary for the stack trace to include any
frames other than the youngest. Unit tests are included.

a=jimblandy, r=mmentovai


git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@554 4c0a9323-5329-0410-9bdc-e9ce6186880e
2010-03-16 16:49:53 +00:00
jimblandy
c609f474a9 Breakpad: Support DWARF CFI-driven stack walking on ARM.
This patch allows the Breakpad minidump processor to use data from
STACK CFI records to generate stack traces for the ARM processor.

In the symbol dumper, we need a table mapping DWARF CFI register
numbers to their names: STACK CFI records refer to registers by name.

In the processor, we expand StackwalkerARM::GetCallerFrame to see if
there are STACK CFI records covering the callee, and then use those to
recover the caller's register values.

There's no good reason the ARM walker couldn't use the SimpleCFIWalker
interface declared in cfi_frame_info.h. Unfortunately, that interface
assumes that one can map register names to member pointers of the raw
context type, while MDRawContextARM uses an array to hold the
registers' values: C++ pointer-to-member types can't refer to elements
of member arrays. So we have to write out SimpleCFIWalker::FindCallerRegisters
in StackwalkerARM::GetCallerFrame.

We define enum MDARMRegisterNumbers in minidump_cpu_arm.h, for
convenience in referring to certain ARM registers with dedicated
purposes, like the stack pointer and the PC.

We define validity flags in StackFrameARM for all the registers, since
CFI could theoretically recover any of them. In the same vein, we
expand minidump_stackwalk.cc to print the values of all valid
callee-saves registers in the context --- and use the proper names for
special-purpose registers.

We provide unit tests that give full code and branch coverage (with
minor exceptions). We add a testing interface to StackwalkerARM that
allows us to create context frames that lack some register values.

a=jimblandy, r=mmentovai


git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@553 4c0a9323-5329-0410-9bdc-e9ce6186880e
2010-03-16 16:46:22 +00:00
jimblandy
a76aaa1442 Breakpad Linux dumper: Parse the .eh_frame section.
Extend google_breakpad::CFISection with the ability to produce
.eh_frame data. Entry headers have a different format, and pointers
can be encoded in new and fascinating ways.

Extend dwarf2reader::CallFrameInfo to be able to parse either DWARF
CFI or .eh_frame data, as determined by an argument to the
constructor. Cope with variations in header formats, encoded pointers,
and additional data in 'z' augmentation data blocks. Extend the unit
tests appropriately.

Extend dump_syms to look for a .eh_frame section, and if it is
present, find the necessary base addresess and parse its contents.

There's no need for DwarfCFIToModule to check the version numbers; if
CallFrameInfo can parse it, DwarfCFIToModule should be able to handle
it. Adjust tests accordingly.

a=jimblandy, r=nealsid


git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@552 4c0a9323-5329-0410-9bdc-e9ce6186880e
2010-03-16 16:37:50 +00:00
jimblandy
0de9f43b87 Breakpad DWARF parser: Add support for parsing .eh_frame encoded pointers.
The Linux C++ exception handling data format (.eh_frame) can specify a
number of different encodings for the addresses it contains. This
patch extends dwarf2reader::ByteReader to read pointers encoded in
these ways.

a=jimblandy, r=nealsid


git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@551 4c0a9323-5329-0410-9bdc-e9ce6186880e
2010-03-16 16:34:52 +00:00
jimblandy
3e768ed9c0 Breakpad Linux dumper: Add support for dumping DWARF CFI as STACK CFI records.
Define a new DWARF parser class, dwarf2reader::CallFrameInfo.

Extend google_breakpad::Module to store and write out 'STACK CFI' records.

Define a new google_breakpad::DwarfCFIToModule class, to accept DWARF
CFI data from the parser and populate a Module with the equivalent
STACK CFI records.

Extend the Linux symbol dumping tool, dump_syms, to use
dwarf2reader::CallFrameInfo, google_breakpad::DwarfCFIToModule, and
google_breakpad::Module to extract DWARF CFI from the executable or
shared library files and write it to the Breakpad symbol file.

Define CFISection, a new class derived from TestAssembler::Section,
for use in creating DWARF CFI data for test cases.

a=jimblandy, r=nealsid


git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@550 4c0a9323-5329-0410-9bdc-e9ce6186880e
2010-03-16 16:31:49 +00:00
jimblandy
6d3a825dbf Breakpad: Add minidump processor support for DWARF Call Frame Information.
Add a CFIFrameInfo class (named for symmetry with WindowsFrameInfo) to
represent the set of STACK CFI rules in effect at a given instruction,
and apply them to a set of register values. Provide a SimpleCFIWalker
class template, to allow the essential CFI code to be shared amongst
the different architectures.

Teach BasicSourceLineResolver to partially parse 'STACK CFI' records,
and produce the set of rules in effect at a given instruction on
demand, by combining the initial rule set and the appropriate rule
deltas in a CFIFrameInfo object.

Adapt StackwalkerX86 and StackFrameX86 to retrieve, store, and apply
CFI stack walking information.

Add validity flags for all the general-purpose registers to
StackFrameX86::ContextValidity.

a=jimblandy, r=mmentovai


git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@549 4c0a9323-5329-0410-9bdc-e9ce6186880e
2010-03-16 16:28:32 +00:00
jimblandy
a7eb2329de Breakpad processor: Unit tests for StackwalkerX86.
Issue 53001 (http://breakpad.appspot.com/53001) defines the
TestAssembler classes; those, along with a new set of mock classes
defined in stackwalker_unittest_utils.h, make it possible for us to
actually do proper unit testing of a stack walker. These tests get us
full code coverage for stackwalker_x86.cc.

a=jimblandy, r=mmentovai


git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@548 4c0a9323-5329-0410-9bdc-e9ce6186880e
2010-03-16 16:25:30 +00:00
jimblandy
9244496c6f Breakpad Processor: Add new unit tests for google_breakpad::Minidump
This also adds two new test utility class groups, TestAssembler and
SynthMinidump. These are overkill for what I'm doing with them here
(and may simply be overkill, period), but they make it easy to write
unit tests for code that works on binary files or raw memory contents
in a cross-platform way. I'm planning to use them for the DWARF CFI
unwinding tests and the DWARF CFI parser tests.

a=jimblandy, r=nealsid


git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@547 4c0a9323-5329-0410-9bdc-e9ce6186880e
2010-03-16 16:20:34 +00:00
ted.mielczarek
5431f41508 add missing <string> include from r541
git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@544 4c0a9323-5329-0410-9bdc-e9ce6186880e
2010-03-03 15:36:35 +00:00
nealsid
19374d2636 Fix to cache NOT_FOUND results from symbol supplier on a per-minidump basis
http://breakpad.appspot.com/64001

R=ted.mielczarek, brdevmn
A=nealsid



git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@543 4c0a9323-5329-0410-9bdc-e9ce6186880e
2010-03-03 01:29:04 +00:00
jimblandy
81aadb99a6 Breakpad Linux dumper: Tolerate STABS data from code linked with --gc-sections.
Programs compiled with -ffunction-sections -Wl,--gc-sections may have
SO entries for the start of the compilation unit whose addresses are
zero, even when the compilation unit contains non-omitted functions at
non-zero addresses. The breakpad dumper should not assume that the
compilation unit starting address is always non-zero.

a=jimblandy, r=nealsid


git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@542 4c0a9323-5329-0410-9bdc-e9ce6186880e
2010-03-02 19:39:18 +00:00
nealsid
de545c09d0 ARM support, with some build system changes to support x86-64, arm, and i386 in an autoconf style build in Linux. The O2 build for the unit tests is still broken but I'm checking this in to unblock people
A=nealsid
R=ajwong, hannahtang, ted.mielczarek



git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@541 4c0a9323-5329-0410-9bdc-e9ce6186880e
2010-03-02 00:39:48 +00:00
jimblandy
841ad48a37 Breakpad Linux symbol dumper: Handle programs linked with --gc-sections.
As explained in the code:

Given the right options, the GNU toolchain will omit unreferenced
functions from the final executable. Unfortunately, when it does so,
it does not remove the associated portions of the line number program;
instead, it lets the symbol references in the DW_LNE_set_address
instructions pointing to the now-deleted code resolve to zero. Given
this input, the DWARF line parser will call AddLine with a series of
lines starting at address zero.

Rather than collecting series of lines describing code that is not
there, we should drop them. Since the linker doesn't explicitly
distinguish references to dropped sections from genuine references to
zero, we must use a heuristic. We have chosen:

 - If a line starts at address zero, omit it. (On the platforms
   breakpad targets, it is extremely unlikely that there will be code
   at address zero.)

 - If a line starts immediately after an omitted line, omit it too.

a=jimblandy, r=nealsid


git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@538 4c0a9323-5329-0410-9bdc-e9ce6186880e
2010-02-24 22:36:20 +00:00
jimblandy
5cf2e760b6 Breakpad processor: Support negative literals in the postfix evaluator.
Some versions of the libstdc++, the GNU standard C++ library, have
stream extractors for unsigned integer values that permit a leading
'-' sign (6.0.13); others do not (6.0.9). Regardless of the behavior
of the extractors, Breakpad postfix expressions should support
negative literals.

a=jimblandy, r=nealsid


git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@537 4c0a9323-5329-0410-9bdc-e9ce6186880e
2010-02-24 19:17:54 +00:00
jimblandy
19d77e0c33 Breakpad Linux dumper: Add missing newlines to error messages.
Some of the error messages that could be generated in the process of
parsing DWARF debugging information lack terminating newlines.

a=jimblandly, r=nealsid


git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@536 4c0a9323-5329-0410-9bdc-e9ce6186880e
2010-02-23 01:23:36 +00:00
jimblandy
d6fb5a7c51 Breakpad Linux dumper: Record AbstractOrigin entries for all DIEs that need them.
Any DIE with an DW_AT_inline attribute can be cited by
DW_AT_abstract_origin attributes --- even if the value of the
DW_AT_inline attribute is DW_INL_not_inlined. Thus, we need to set the
inline_ flag on all such DIEs, regardless of the attribute's value.
This allows us to find names in situations like this:

 <1><30cf>: Abbrev Number: 57 (DW_TAG_subprogram)
    <30d0>   DW_AT_specification: <0x3013>
    <30d4>   DW_AT_decl_file   : 1
    <30d5>   DW_AT_decl_line   : 92
    <30d6>   DW_AT_inline      : 0        (not inlined)
    <30d7>   DW_AT_sibling     : <0x30f0>
...
 <1><30f5>: Abbrev Number: 59 (DW_TAG_subprogram)
    <30f6>   DW_AT_abstract_origin: <0x30cf>
    <30fa>   DW_AT_low_pc      : 0x13bc
    <30fe>   DW_AT_high_pc     : 0x13ec
    <3102>   DW_AT_frame_base  : 0x2c     (location list)
    <3106>   DW_AT_sibling     : <0x3113>

a=jimblandy, r=nealsid,dmuir


git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@526 4c0a9323-5329-0410-9bdc-e9ce6186880e
2010-02-20 00:51:22 +00:00
jimblandy
6de1b75da4 Breakpad Linux dumper: Compare section names correctly.
FindSectionByName will return the first section whose name starts with
NAME, because strncmp stops the comparison once NAME's characters have
been found to match. The comparison stops before the terminating '\0'.
For example, if we search for the section named ".eh_frame", we may
get the section named ".eh_frame_hdr".

Instead, check that the section name section has enough space to store
the complete name with its terminating '\0', and then use strcmp,
which will never examine more than strlen(NAME) + 1 bytes from the
section name section, regardless of its contents, and will require the
terminating '\0' to match as well.

a=jimblandy, r=nealsid


git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@525 4c0a9323-5329-0410-9bdc-e9ce6186880e
2010-02-18 07:57:53 +00:00
jimblandy
89f1396fd1 Breakpad DWARF parser: Expand comments for ByteReader class.
This is preparation for adding support for reading Linux C++ exception
handling data's encoded pointers. The change should have no user-visible
effect; it simply expands the comments for dwarf2reader::ByteReader, and
regroups the member functions.

a=jimblandy, r=nealsid


git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@522 4c0a9323-5329-0410-9bdc-e9ce6186880e
2010-02-11 22:44:01 +00:00
jimblandy
71f7580891 Breakpad: Require Automake 1.11.1.
Change configure.ac to note that Breakpad requires automake version
1.11.1 or later. This will cause older versions of automake to refuse
to process the Makefile.am file.

Earlier versions of automake generate 'make dist' rules that have a
security flaw; see:

http://web.nvd.nist.gov/view/vuln/detail?vulnId=CVE-2009-4029

However, note that that notice itself has a flaw: the bug is *fixed
in* automake 1.11.1, not present. See:

http://lists.gnu.org/archive/html/automake/2009-12/msg00012.html

(The change to Makefile.in is a consequence of my having neglected to
rebuild Makefile.in after landing r517.)

a=jimblandy, r=mmentovai


git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@521 4c0a9323-5329-0410-9bdc-e9ce6186880e
2010-02-11 19:31:48 +00:00
jimblandy
dd5067f391 Linux DWARF reader: Follow DW_AT_abstract_origin links to find function names.
Without this patch, debugging information like the following will produce
FUNC records with no names, because the dumper (correctly) ignores the
DW_TAG_subprogram DIEs that lack DW_AT_low_pc/DW_AT_high_pc attributes, but
won't follow the DW_AT_abstract_origin link from the DIE that does have
code addresses to find its name.

 <1><168>: Abbrev Number: 5 (DW_TAG_class_type)
    <169>   DW_AT_name        : Foo	
 <2><183>: Abbrev Number: 7 (DW_TAG_subprogram)
    <185>   DW_AT_name        : Foo	
    <18b>   DW_AT_declaration : 1	
 <1><1b7>: Abbrev Number: 12 (DW_TAG_subprogram)
    <1b8>   DW_AT_specification: <0x183>	
    <1bc>   DW_AT_inline      : 2	(declared as inline but ignored)
 <1><1dc>: Abbrev Number: 16 (DW_TAG_subprogram)
    <1dd>   DW_AT_abstract_origin: <0x1b7>	
    <1e1>   DW_AT_low_pc      : 0x8048578	
    <1e5>   DW_AT_high_pc     : 0x8048588	

a=dmuir, r=jimblandy


git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@520 4c0a9323-5329-0410-9bdc-e9ce6186880e
2010-02-10 17:55:24 +00:00
jimblandy
952f3c7b73 Breakpad Linux dumper: Don't be silly about global functions.
Yes, classes are useful. But that doesn't mean that every function has
to gratuitously become a member function. The Google C++ Style Guide
does not require this silliness, since the function is in the
google_breakpad namespace anyway.

a=jimblandy, r=nealsid


git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@519 4c0a9323-5329-0410-9bdc-e9ce6186880e
2010-02-09 17:13:17 +00:00
jimblandy
c50e7c604c Breakpad Linux dumper: Add file comments as required by the style guide.
This also includes some comments I promised Cary Coutant I'd write
about the appropriateness of processing attributes in EndAttributes
calls.

The Google C++ Style Guide requires each file to have an author notice
and a comment explaining the file's general purpose. For the record, I
don't think putting an author notice on the files is a good idea; it's
odd to have the original author retain prominence even if the file has
been heavily edited by others; the version control system answers this
question more accurately. This is only for Style Guide compliance. The
Apache group decided to discourage author annotations, partially for
these reasons:

http://mail-archives.apache.org/mod_mbox/jakarta-jmeter-dev/200402.mbox/%3C4039F65E.7020406@atg.com%3E

a=jimblandy, r=nealsid


git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@518 4c0a9323-5329-0410-9bdc-e9ce6186880e
2010-02-09 17:10:57 +00:00
jimblandy
83e085b7a3 Breakpad: Update copyright notice years on all files changed in 2010.
We've gotten mixed advice from the lawyery types about whether this
matters. But it's easy enough to do.

a=jimblandy, r=nealsid


git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@517 4c0a9323-5329-0410-9bdc-e9ce6186880e
2010-02-09 17:08:56 +00:00
ted.mielczarek
bad560bb69 Print ARM register values in minidump_stackwalk. r=nealsid at http://breakpad.appspot.com/57002
git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@516 4c0a9323-5329-0410-9bdc-e9ce6186880e
2010-02-09 12:16:45 +00:00
ted.mielczarek
f480ba1169 Refactor Chrome's out-of-process Linux code into CrashGeneration{Server,Client} classes. Upstreamed from the Mozilla repository. Patch by Chris Jones <jones.chris.g@gmail.com> r=me at https://bugzilla.mozilla.org/show_bug.cgi?id=516759
git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@515 4c0a9323-5329-0410-9bdc-e9ce6186880e
2010-02-05 18:21:31 +00:00
jimblandy
bd76cd035c Breakpad processor: Move STACK WIN record parsing into its own function.
This looks a little odd right now, since ParseStackInfo has only one
alternative to handle, but I think breaking this out should make the
subsequent addition of STACK CFI record support easier to review.

a=jimblandy, r=mmentovai


git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@514 4c0a9323-5329-0410-9bdc-e9ce6186880e
2010-02-05 18:10:51 +00:00
jimblandy
2b48a6a89f Breakpad processor: Give Windows stack data Windows-specific names.
Rename BasicSourceLineResolver::Module::StackInfoTypes to
WindowsFrameInfoTypes. This enum really describes the forms of
Windows-specific stack unwinding data (STACK WIN records), and its
name should reflect that, especially since we'll be adding support for
other kinds of stack walking information.

The 'stack' -> 'frame' shift matches the naming of the
WindowsFrameInfo type.

Similarly, rename BasicSourceLineResolver::Module::stack_info_ to
windows_frame_info_.

Do similar renamings in basic_source_line_resolver_unittest.cc.

a=jimblandy, r=mmentovai


git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@513 4c0a9323-5329-0410-9bdc-e9ce6186880e
2010-02-05 18:09:17 +00:00
jimblandy
7f1455601d Breakpad processor: Segregate STACK WIN vs. traditional stack walking.
This patch moves the code for finding caller frames using STACK WIN
data and the code to do so using the traditional frame layout (%ebp
points at saved %ebp, pushed just after return address) into their own
functions. In addition to making things a little clearer, this is
preparation for adding support for STACK CFI records into the mix.

a=jimblandy, r=mmentovai


git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@512 4c0a9323-5329-0410-9bdc-e9ce6186880e
2010-02-05 18:04:56 +00:00
jimblandy
89e07bf2c7 Breakpad processor: Support evaluating a postfix expression to produce a value.
This adds an EvaluateForValue member function to PostfixEvaluator, and
along with appropriate unit tests.

a=jimblandy, r=nealsid


git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@511 4c0a9323-5329-0410-9bdc-e9ce6186880e
2010-02-05 17:51:35 +00:00
jimblandy
6a9ffff696 Breakpad x86 Stack Walker: Pass "out" parameters by address, not reference.
The Google C++ Style Guide requires all parameters passed by reference
to be labeled 'const', and says that pointers should be used for
output arguments. This patch brings google_breakpad::StackwalkerX86
into line.

a=jimblandy, r=mmentovai


git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@510 4c0a9323-5329-0410-9bdc-e9ce6186880e
2010-02-05 17:46:41 +00:00
jimblandy
2214cb9bc1 Breakpad processor: Make PostfixEvaluator treat the MemoryRegion as const.
In order to be able to treat any MemoryRegion as const, the accessor
functions need to be declared this-const, which means annotations on
all the subclasses, etc. etc.

Since MinidumpMemoryRegion fills its memory_ member on demand, that
member needs to be marked 'mutable', but this is exactly the sort of
situation the 'mutable' keyword was intended for, so that seems all
right.

a=jimblandy, r=nealsid


git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@509 4c0a9323-5329-0410-9bdc-e9ce6186880e
2010-02-05 17:17:24 +00:00
jimblandy
e87521a989 Breakpad processor: Save Windows unwinding data earlier in x86 walker.
At the moment, StackwalkerX86::GetCallerFrame doesn't save the
WindowsFrameInfo that it finds for a frame unless it successfully
constructs the caller frame. This means that the windows_frame_info
field of the last frame on the stack is left unset, even when that
frame does have windows unwinding information.

This is not user-visible behavior, so it doesn't matter, but it is a
blemish on the interface, and unit tests (added in a later patch)
expect it.

This patch saves the information in the frame as soon as we find it.

a=jimblandy, r=mmentovai


git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@508 4c0a9323-5329-0410-9bdc-e9ce6186880e
2010-02-05 17:14:12 +00:00
jimblandy
e53e6af0c1 Breakpad Linux dumper: Recognize more processor architectures.
This extends the ElfArchitecture function to recognize the
architectures it seemed to me that breakpad was most likely to see.

Also: the dumper has historically not provided very helpful error
messages. This patch adds a few that were convenient, but we should do
an audit for this.

a=jimblandy, r=ted.mielczarek


git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@507 4c0a9323-5329-0410-9bdc-e9ce6186880e
2010-02-02 20:19:01 +00:00
jimblandy
dc4029a5c2 Regenerate using automake-1.11.1, autoconf 2.65, and libtool 2.2.6b,
to provide a fix for Breakpad issue 365:

http://code.google.com/p/google-breakpad/issues/detail?id=365


git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@506 4c0a9323-5329-0410-9bdc-e9ce6186880e
2010-02-02 17:39:51 +00:00
jimblandy
3e60d65111 Breakpad Linux Dumper: Rename structure members to follow the Google C++ Style Guide.
The Google C++ Style Guide says that members of structures needn't
have names ending in underscores. The structure types in
google_breakpad::Module don't follow this rule.

a=jimblandy, r=nealsid


git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@505 4c0a9323-5329-0410-9bdc-e9ce6186880e
2010-01-28 22:59:15 +00:00
jimblandy
1ac84da26d Breakpad DWARF parser: Add method to read DWARF "Initial length".
This patch moves the ReadInitialFunction from dwarf2reader.cc, where
it was a static function, to being a member function of
google_breakpad::ByteReader.

a=jimblandy, r=nealsid


git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@504 4c0a9323-5329-0410-9bdc-e9ce6186880e
2010-01-28 22:56:28 +00:00
jimblandy
03ebc1d245 Breakpad processor: Fix function and public symbol lookup.
In r480, I botched the change to make the comparisons that decide
whether an address falls within a function's range safe from overflow.
The original code said:

  address >= function_base && address < function_base + function_size

which is fine unless the function abuts the end of the address space,
in which case the addition overflows and you get a false negative.

My change subtracted function_size from both sides of the latter
comparison, which is meaning-preserving in true math, and gets you:

  address >= function_base && address - function_size < function_base

This not only reads strangely, but also still overflows if
function_size is greater than address. That's rare, but I've added a
case to the unit tests that checks it.

My intent had been to replace the addition which could overflow with a
subtraction that was known not to overflow, namely:

  address >= function_base && address - function_base < function_size

This is equivalent to the original in true math, and because of the
first comparison, we know the subtraction won't underflow in MemAddr
math.

The patch includes similar fixes to the public symbol lookup code, and
to FindWindowsFrameInfo, which was the only other function affected by
r480.

a=jimblandy, r=mmentovai


git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@503 4c0a9323-5329-0410-9bdc-e9ce6186880e
2010-01-28 05:17:23 +00:00
jimblandy
384b1c7d7d Breakpad Linux symbol dumper: Don't disable asserts.
Having NDEBUG be the default has wasted my time more often than I'm
proud to admit. There are no expensive asserts in the Linux symbol
dumper.

a=jimblandy, r=nealsid


git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@502 4c0a9323-5329-0410-9bdc-e9ce6186880e
2010-01-27 19:10:56 +00:00
jimblandy
97f1da43ae Breakpad processor: Have RetrieveNearestRange correctly return range extent.
RangeMaps use the range's upper end as the key in the underlying map,
but RetrieveNearestRange was treating the key as the lower end.

a=jimblandy, r=mmentovai


git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@501 4c0a9323-5329-0410-9bdc-e9ce6186880e
2010-01-27 19:10:06 +00:00
jimblandy
057aa1f617 Breakpad Linux Dumper: Add DWARF support.
This adds DWARF support to the Breakpad Linux dumper. This is
implemented as two handler classes: google_breakpad::DwarfCUToModule
accepts data from dwarf2reader::CompilationUnit, and
google_breakpad::DwarfLineToModule accepts data from a
dwarf2reader::LineInfo, each populating a google_breakpad::Module with
the results. Behaviors specific to particular source languages are
handled by instances of a new class, google_breakpad::Language.

An input executable may contain both STABS and DWARF debugging
information: the dumper automatically recognizes what sorts of
information are available, and integrates the data into a single
output file.

All classes have unit tests, providing line and branch coverage of all
interesting code. Unit tests are written using the Google C++ Testing
Framework, and the Google C++ Mocking Framework where appropriate.

a=jimblandy, r=ccoutant


git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@497 4c0a9323-5329-0410-9bdc-e9ce6186880e
2010-01-23 05:29:16 +00:00
jimblandy
32d1b2882b Typo: "An" -> "A".
git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@496 4c0a9323-5329-0410-9bdc-e9ce6186880e
2010-01-23 01:22:32 +00:00
jimblandy
bc64ee962f Breakpad DWARF Parser: Improved DWARF-processing interface.
dwarf2reader::CompilationUnit is a simple and direct parser for DWARF
data, but its handler interface is not convenient to use. In
particular, the same handler object receives data about all DIEs
processed. One can't use distinct classes to separate the information
needed to handle different kinds of data.

This patch defines a new adapter type, dwarf2reader::DIEHandler, which
implements the existing DWARF parser's handler interface, given a
handler written to a more comfortable, object-orient interface. The
comments in dwarf2diehandler.h provide more detail.

a=jimblandy, r=ccoutant


git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@495 4c0a9323-5329-0410-9bdc-e9ce6186880e
2010-01-23 01:20:55 +00:00
jimblandy
8bfcc2683f Breakpad DWARF Reader: Change LineInfoHandler::AddLine to provide the line's length.
Breakpad's DWARF line number info parser provides a code address,
file, and line number for each code/source pairing, but doesn't
provide the length of the machine code. This makes that change, as
discussed in the following thread:

http://groups.google.com/group/google-breakpad-dev/browse_thread/thread/ed8d2fde79319368p

This patch also makes the corresponding changes to the functioninfo.cc
module, used by the Mac dumper. This patch has no effect on the Mac
dumper's output.

a=jimblandy, r=ccoutant


git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@494 4c0a9323-5329-0410-9bdc-e9ce6186880e
2010-01-22 23:30:36 +00:00
jimblandy
e15bffe466 Breakpad DWARF Reader: Also look for DWARF in sections with the proper names.
The DWARF specification specifices which names the sections containing
DWARF information should have. OSX uses slightly different names. This
patch changes the DWARF reader to look for the sections under both
sets of names.

a=jimblandy, r=ccoutant


git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@493 4c0a9323-5329-0410-9bdc-e9ce6186880e
2010-01-22 23:26:12 +00:00
jimblandy
f4a106d4b5 Add new file missed in r490.
git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@492 4c0a9323-5329-0410-9bdc-e9ce6186880e
2010-01-14 23:08:24 +00:00
jimblandy
2684b4dc19 Breakpad processor: Don't pass Windows stack walking information to all walkers.
At the moment, the StackWalker GetCallerFrame member function expects
a vector of WindowsFrameInfo structures, even though WindowsFrameInfo
is only used or useful on one one implementation (StackWalkerX86).

This patch changes StackWalker::GetCallerFrame to no longer expect the
WindowsFrameInfo structures, and changes all implementations to match.

In particular, StackWalkerX86 is changed to find the WindowsFrameInfo
data itself, and store a pointer to whatever it got in the StackFrame
object itself (which is really a StackFrameX86).

To allow GetCallerFrame implementations to look up stack walking data,
StackWalker::resolver_ needs to be made protected, not private.

a=jimblandy, r=mmentovai


git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@491 4c0a9323-5329-0410-9bdc-e9ce6186880e
2010-01-14 19:17:36 +00:00
jimblandy
5251e64f48 Breakpad Linux dumper: STABS reader incorrectly assumes a single compilation unit
The stabs reading code in google-breakpad incorrectly assumes that the
stabs data is a single compilation unit. Specifically, it ignores
N_UNDF stabs and assumes that all string indices are relative to the
beginning of the .stabstr section.

This is true when linking with the GNU linker by default, because the
GNU linker optimizes stabs debug info. The gold linker does not do
this optimization. It can be disabled when using the GNU linker with
the --traditional-format command line option.

For more details of the problem, see:

http://sourceware.org/bugzilla/show_bug.cgi?id=10338
http://code.google.com/p/google-breakpad/issues/detail?id=359

This patch adds unit tests that reproduce the failure, and fixes the
stabs parser.

a=jimblandy, r=nealsid


git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@490 4c0a9323-5329-0410-9bdc-e9ce6186880e
2010-01-14 17:19:34 +00:00
jimblandy
7b873221e6 Linux Breakpad Dumper: support running unit tests under valgrind or other wrapper programs.
This adds a new variable, TEST_WRAPPER, to src/tools/linux/dump_syms.
Comments in the patch provide details.

This patch also moves the public variable section to sit after the
public phony targets.

a=jimblandy, r=nealsid


git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@486 4c0a9323-5329-0410-9bdc-e9ce6186880e
2010-01-13 07:41:22 +00:00
jimblandy
eef5ccc61f Breakpad processor: Opening a map file is not an error.
a=jimblandy, r=nealsid


git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@485 4c0a9323-5329-0410-9bdc-e9ce6186880e
2010-01-13 07:39:24 +00:00
jimblandy
cf55ca5b5c Breakpad: Fix Emacs mode settings mingled with copyright notice text.
a=jimblandy, r=mmentovai


git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@484 4c0a9323-5329-0410-9bdc-e9ce6186880e
2010-01-12 19:51:14 +00:00
nealsid
e7b2043dd2 Move file_id.cc from test_src to lib_src
A=nealsid
R=ted.mielczarek



git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@483 4c0a9323-5329-0410-9bdc-e9ce6186880e
2010-01-12 19:20:39 +00:00
jimblandy
330ca2f7c7 Google Breakpad DWARF reader: Add a handler function for DIE references.
Add a new member function to dwarf2reader::Dwarf2Handler,
ProcessAttributeReference, for reporting attribute values that are
references to other DIEs. This handler member function always receives
an absolute offset (that is, relative to the start of the .debug_info
section, not to the start of the compilation unit), regardless of the
form the attribute uses. (Some forms are CU-relative, some are
absolute.)

a=jimblandy, r=nealsid


git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@482 4c0a9323-5329-0410-9bdc-e9ce6186880e
2010-01-12 16:53:02 +00:00
jimblandy
0441036f9e Breakpad: Avoid warnings building with G++ 4.4.1 using -O3 -Wall.
src/processor/minidump.cc:1067: warning: format ‘%llx’ expects type ‘long long unsigned int’, but argument 3 has type ‘unsigned int’
src/processor/stackwalker_arm.cc:83: warning: unused variable ‘last_frame’
src/processor/minidump_stackwalk.cc:163: warning: ‘trust_name’ may be used uninitialized in this function

a=jimblandy, r=ted.mielczarek


git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@481 4c0a9323-5329-0410-9bdc-e9ce6186880e
2010-01-12 16:41:13 +00:00
jimblandy
e9faf54828 Issue 49013: Breakpad Processor: Use a separate API to retrieve Windows stack debugging info.
At the moment, FillSourceLineInfo returns Windows DIA-based stack
walking data. In addition to being ugly, this makes it difficult to
provide access to DWARF CFI-based stack walking data in a symmetrical
way.

This patch changes FillSourceLineInfo to do the single job its name
suggests, and adds a second member function to
SourceLineResolverInterface to retrieve Windows DIA stack walking
information. A sibling member function will provide access to DWARF
CFI stack walking data.

a=jimblandy, r=mmentovai


git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@480 4c0a9323-5329-0410-9bdc-e9ce6186880e
2010-01-11 22:31:50 +00:00
jimblandy
5b787b1911 Breakpad DWARF Reader: Add DWARF language enumeration values.
a=jimblandy, r=nealsid


git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@479 4c0a9323-5329-0410-9bdc-e9ce6186880e
2010-01-11 22:23:05 +00:00
nealsid
2832dc011c Patch from Kris Rambish to keep memory usage flat when processing a directory full of minidump files
A=krisr
R=nealsid



git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@478 4c0a9323-5329-0410-9bdc-e9ce6186880e
2010-01-11 21:24:43 +00:00
nealsid
c65d3e6206 INclude stackwalker_arm.{cc,h} in crash_report build
git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@477 4c0a9323-5329-0410-9bdc-e9ce6186880e
2010-01-11 20:26:22 +00:00
nealsid
718478d95d Fix solaris build break
git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@476 4c0a9323-5329-0410-9bdc-e9ce6186880e
2010-01-08 23:04:14 +00:00
stuart.morgan
910f68a5d4 Make Mac comment and email text field placeholders localizable. r=nealsid
git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@475 4c0a9323-5329-0410-9bdc-e9ce6186880e
2010-01-01 00:21:18 +00:00
stuart.morgan
6f50ca38bb Add email mapping for Socorro. r=nealsid
git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@474 4c0a9323-5329-0410-9bdc-e9ce6186880e
2010-01-01 00:17:33 +00:00
jimblandy
b64d76a3b8 Issue 49012: Breakpad Processor: Rename 'StackFrameInfo' structure to 'WindowsFrameInfo'.
Also, rename stack_frame_info.h to windows_frame_info.h.

If it seems odd to have functions like FillSourceLineInfo returning
Windows-specific data structures... well, it is! This patch just makes
it more obvious what's going on.

a=jimblandy, r=nealsid


git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@471 4c0a9323-5329-0410-9bdc-e9ce6186880e
2009-12-23 22:32:14 +00:00
jimblandy
92b1f834d1 Breakpad: Regenerate build files with latest versions of autotools.
This patch refreshes the build system files to those generated by:
- Libtool 2.2.6
- Automake 1.11
- Autoconf 2.64

a=jimblandy, r=nealsid


git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@470 4c0a9323-5329-0410-9bdc-e9ce6186880e
2009-12-23 22:23:49 +00:00
jimblandy
5ebd6507e3 Breakpad processor: Use unsigned constants in comparisons, to quiet compiler warnings.
This patch avoids comparisons between signed and unsigned values, as
warned about by G++ 4.4.1.

a=jimblandy, r=nealsid


git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@469 4c0a9323-5329-0410-9bdc-e9ce6186880e
2009-12-23 22:01:57 +00:00
jimblandy
0468306245 Breakpad Linux Dumper: Fix up comments in google_breakpad::Module interface.
Use the term "own", since ownership is the concept at work here.

a=jimblandy, r=nealsid


git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@468 4c0a9323-5329-0410-9bdc-e9ce6186880e
2009-12-23 21:56:41 +00:00
jimblandy
c823931376 Issue 49003: Breakpad Linux Dumper: Add unit tests for STABS dumper.
Previous patches added unit tests for the STABS parser and the
Breakpad symbol file writer; this adds unit tests for the "dumper"
class that sits between them, receiving data from the parser and
handing it to the writer.  So now the whole pathway has coverage.

a=jimblandy, r=nealsid


git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@467 4c0a9323-5329-0410-9bdc-e9ce6186880e
2009-12-23 21:50:01 +00:00
jimblandy
52cb2c6f42 Breakpad Linux dumper: Add unit tests for google_breakpad::Module.
Adjust Module's interface a bit to facilitate testing:
- Make AssignSourceIds something a client can call --- it's perfectly
  well-defined, so this is an okay change.
- Add GetFunctions, GetFiles and FindExistingfile member functions,
  which the test harness will use to get results to examine.

a=jimblandy, r=nealsid


git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@466 4c0a9323-5329-0410-9bdc-e9ce6186880e
2009-12-23 21:46:00 +00:00
jimblandy
6ed5383245 Breakpad Linux Dumper: Use proper sizes and radixes when writing Breakpad symbol files.
A FUNC record's parameter size is also hexadecimal, and all values are
64 bits wide.

A line record's address and size are 64 bits wide.

a=jimblandy, r=nealsid


git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@465 4c0a9323-5329-0410-9bdc-e9ce6186880e
2009-12-23 21:15:23 +00:00
jimblandy
5a6e1d3f03 Breakpad Linux dumper: move DumpStabsHandler into its own file, for testing.
This will make it easier to write unit tests for DumpStabsHandler.

a=jimblandy, r=nealsid


git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@464 4c0a9323-5329-0410-9bdc-e9ce6186880e
2009-12-23 21:13:11 +00:00
ted.mielczarek
9f211b4283 fix compilation on 64-bit, followup from issue 357
git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@463 4c0a9323-5329-0410-9bdc-e9ce6186880e
2009-12-23 20:44:32 +00:00
ted.mielczarek
0a5fc5d663 Issue 357: New Linux file_id code doesn't persist across strip. r=agl,nealsid at http://breakpad.appspot.com/49008
git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@461 4c0a9323-5329-0410-9bdc-e9ce6186880e
2009-12-23 17:09:27 +00:00
ted.mielczarek
1adb184d42 fix a badly-applied patch, and also re-run automake which I forgot to do
git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@455 4c0a9323-5329-0410-9bdc-e9ce6186880e
2009-12-21 13:12:20 +00:00
ted.mielczarek
9276b0d301 Basic arm cpu support for processor. r=mark at http://breakpad.appspot.com/49011
git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@454 4c0a9323-5329-0410-9bdc-e9ce6186880e
2009-12-19 21:43:53 +00:00
jimblandy@gmail.com
7a77f45f79 Breakpad DWARF parser: Fix up documentation for DWARF reader classes.
Fix typos.

For CompilationUnit::Start, I was confused by the '-' in the original
comment, taking it for a parenthetic clause marker, assuming an
implicit "of the next compilation unit" at the end of the sentence.

The comments should refer to the ".debug_info" section, not the
"debug_info" section. The latter is not the section name actually used
on any system (ELF or Mach-O), and the former is the name prescribed
by the DWARF spec.

Some of the comments for ProcessAttribute* member functions claim that
OFFSET is from the start of the compilation unit, but that's not so:
the code has always passed an offset relative to the start of the
.debug_info section.

a=jimblandy, r=nealsid


git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@453 4c0a9323-5329-0410-9bdc-e9ce6186880e
2009-12-18 22:57:54 +00:00
nealsid
e4ffacd0d8 Fix build break for 64-bit compilation.
A=Gregory Dardyk
R=nealsid



git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@452 4c0a9323-5329-0410-9bdc-e9ce6186880e
2009-12-17 23:00:12 +00:00
brdevmn
f7f9dfcab6 Added on-demand minidump generation for Linux, and a Linux test app.
A=brdevmn
R=mochalatte

Code review: http://breakpad.appspot.com/48001/show



git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@451 4c0a9323-5329-0410-9bdc-e9ce6186880e
2009-12-16 20:10:57 +00:00
jimblandy@gmail.com
5fb436d5bb Issue 41004: Breakpad DWARF parser: fixes to compile without warnings under GNU C++ 4.3.3.
a=jimblandy, r=nealsid


git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@450 4c0a9323-5329-0410-9bdc-e9ce6186880e
2009-12-15 17:25:27 +00:00
jimblandy@gmail.com
315c4f6b20 Issue 41003: Breakpad DWARF parser: Include <cstdio>, since we use it
src/common/dwarf/dwarf2reader.cc uses the old-fashioned <stdio.h>
facilities to report errors. Ideally, we would add a 'Warning' message
to the handler and make the client responsible for dealing with the
errors, but this at least allows us to compile.

Ubuntu 9.10 uses GCC 4.4.1; under older versions of GCC, this wasn't a
problem, probably because stdio.h was being brought in inadvertently
somewhere else.

a=jimblandy, r=nealsid


git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@449 4c0a9323-5329-0410-9bdc-e9ce6186880e
2009-12-15 17:23:43 +00:00
jimblandy@gmail.com
bdd7ca54cd Issue 42002: Breakpad DWARF parser: avoid using <stdint.h> type
It seems that a use of the <stdint.h> type uintptr_t has crept into
the DWARF parser. This defines a workaround for the GNU compilers
(tested on both Mac and Linux) which will raise an error if it doesn't
work.

My personal preference would be just to assume that the <stdint.h>
header is available and use the standard types everywhere, but 1) that
would be a large change, likely to make merges with the other branches
of the DWARF parser more difficult, and 2) it would make it quite
difficult to build under Microsoft Visual Studio, which doesn't have
the <stdint.h> header; Microsoft has said they have no plans to
provide it, as they would rather "focus their efforts" on C++ and
.NET.

a=jimblandy, r=nealsid


git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@448 4c0a9323-5329-0410-9bdc-e9ce6186880e
2009-12-15 17:21:14 +00:00
jimblandy@gmail.com
07466260e2 Issue 42001: Breakpad Linux Dumper: remove compilation warnings in guid_creator.cc.
Building on Ubuntu 9.10 with the distributed compiler (GCC 4.4.1), we get
warnings like the following:

guid_creator.cc:56: warning: dereferencing type-punned pointer will break strict-aliasing rules

It doesn't matter in this case, but there's no crying need to use
reinterpret casts in an endian-dependent way when there are plenty of
well-defined ways to get the same effect.

a=jimblandy, r=nealsid


git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@447 4c0a9323-5329-0410-9bdc-e9ce6186880e
2009-12-15 17:11:54 +00:00
jimblandy@gmail.com
4969cfc647 Issue 39002: Breakpad DWARF parser: Move DWARF parser to platform-independent directory.
Move the DWARF parser, and the functioninfo.cc DWARF consumer, from
src/common/mac/dwarf to src/commmon/dwarf, so that it can be shared
between the Mac and Linux dumpers.

Fix up #include directives, multiple inclusion protection macros, and
Xcode build files.

a=jimblandy, r=nealsid


git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@446 4c0a9323-5329-0410-9bdc-e9ce6186880e
2009-12-15 17:06:21 +00:00
jimblandy@gmail.com
08fecb2e43 Issue 26001: Linux dumper: fix comments in STABS reader
Typos; ambiguities; dangling references to arguments whose names got
changed.

a=jimblandy, r=nealsid


git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@445 4c0a9323-5329-0410-9bdc-e9ce6186880e
2009-12-15 16:58:37 +00:00
jimblandy@gmail.com
7f941f990a Linux dumper: Add unit tests for google_breakpad::StabsReader.
The test system is based on Google C++ Testing Framework and the
Google C++ Mocking Framework.

This includes a parser that turns human-readable input files ("mock
stabs") into .stab and .stabstr section contents, which we can then
pass to a StabsReader instance, using a handler object written with
GoogleMock. The 'make check' target in src/tools/linux/dump_syms runs
this.

The supplied input file is pretty small, but I've done coverage
testing, and it does cover the parser.

I thought the mock stabs parser would be less elaborate than it turned
out to be. Lesson learned.

a=jimblandy, r=nealsid


git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@444 4c0a9323-5329-0410-9bdc-e9ce6186880e
2009-12-15 16:54:44 +00:00
jimblandy@gmail.com
0397da8e08 Issue 25003: Linux dumper: Fix infinite loop in stabs parser.
If the input passed to a StabsReader instance contains a compilation
unit whose first entry is an N_SO with no name, the parser enters an
infinite loop.  Since such entries mark the end of a compilation unit,
ProcessCompilationUnit should skip them.

a=jimblandy, r=nealsid


git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@443 4c0a9323-5329-0410-9bdc-e9ce6186880e
2009-12-15 16:34:02 +00:00
jimblandy@gmail.com
bb846bdc98 Issue 25002: Linux symbol dumper: Require STABS consumers to provide a Warning member.
The StabsHandler class should not provide a fallback definition for
its Warning member function that just throws away warning messages.
It should require the consumer to provide an appropriate definition.

a=jimblandy, r=nealsid


git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@442 4c0a9323-5329-0410-9bdc-e9ce6186880e
2009-12-15 16:32:32 +00:00
jimblandy@gmail.com
1c9c0568e0 Issue 39001: Breakpad Linux dumper: Refactor Makefile.
Use GNU Make features to make the dumper, unit tests, and maintenance
targets more independent, so I get fewer conflicts as I work on
different parts of the patch series.

In particular:
- Provide targets to run tests and produce test coverage reports.
- Gather C and C++ build rules in one place.
- Avoid variables that list object files, as pattern rules can compute
  these values directly from the dependencies.
- Use VPATH to find sources in other directories.

a=jimb, r=nealsid


git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@441 4c0a9323-5329-0410-9bdc-e9ce6186880e
2009-12-15 16:28:43 +00:00
ted.mielczarek
9dcc03f47d Mozilla bug 532713 - OS X client code doesn't decoded extended family ids in CPU info. Patch by Jeff Muizelaar <jmuizelaar@mozilla.com>, r=me
git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@440 4c0a9323-5329-0410-9bdc-e9ce6186880e
2009-12-14 11:47:53 +00:00
nealsid
bb618860df Fix some build warnings
A=zhurunz
R=nealsid



git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@439 4c0a9323-5329-0410-9bdc-e9ce6186880e
2009-12-10 19:15:44 +00:00
ted.mielczarek
0cbd50c975 Allow Minidump class to be instantiated with stream instead of file. r=mark at http://breakpad.appspot.com/46001
git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@438 4c0a9323-5329-0410-9bdc-e9ce6186880e
2009-12-09 01:24:37 +00:00
ted.mielczarek
d95a88c3f1 remove trailing comma from enum definition to make it compile with -pedantic
git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@437 4c0a9323-5329-0410-9bdc-e9ce6186880e
2009-12-03 20:58:31 +00:00
ted.mielczarek
72a2bff592 issue 330 - linux_syscall_support.h has extra semicolons causing compilation to fail with certain gcc options. Patch by Josh Aas <joshmoz@gmail.com>, r=me
git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@436 4c0a9323-5329-0410-9bdc-e9ce6186880e
2009-12-03 18:16:31 +00:00
ted.mielczarek
3b9b206b5f issue 336 - Look for libcurl-gnutls in addition to libcurl.so. Patch by Karl Tomlinson <karlt@mozbugz.karlt.net>, r=me
git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@435 4c0a9323-5329-0410-9bdc-e9ce6186880e
2009-12-03 16:31:25 +00:00
ted.mielczarek
b1f271a4ec remove empty file, leftover from r384
git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@434 4c0a9323-5329-0410-9bdc-e9ce6186880e
2009-12-03 13:59:55 +00:00
ted.mielczarek
0314e487e4 issue 170 - Report assertion type in minidump_stackwalk output. r=mark at http://breakpad.appspot.com/45001
git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@433 4c0a9323-5329-0410-9bdc-e9ce6186880e
2009-12-02 17:43:57 +00:00
nealsid
096992fac7 Upstreaming several patches from Chrome:
Build fix for systems where sys/user.h needs sys/types.h....
http://breakpad.appspot.com/40002
MDRawSystemInfo.processor_level refers to the CPU family, not the cpuid level..
http://breakpad.appspot.com/40003
Use MD_MODULE_SIZE in place of sizeof(MDRawModule).
http://breakpad.appspot.com/39003
Linux x64 compile fix.
http://breakpad.appspot.com/40004
Include linux_syscall_support.h to get definition of NT_PRXFPREG. This is
Chromium commit 23659.
http://breakpad.appspot.com/40005
Build breakpad / crash reporting on Linux 64-bit. This is Chromium commit
23396.
http://breakpad.appspot.com/40006
Fix #includes in a couple unit tests.
http://breakpad.appspot.com/41001
Clean up unused headers / files for Linux dump_syms.
http://breakpad.appspot.com/40002




git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@432 4c0a9323-5329-0410-9bdc-e9ce6186880e
2009-12-01 21:35:52 +00:00
ted.mielczarek
873064894b don't output duplicate filenames in PDBSourceLineWriter. r=mark at http://breakpad.appspot.com/43001
git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@431 4c0a9323-5329-0410-9bdc-e9ce6186880e
2009-11-23 14:50:55 +00:00
ted.mielczarek
927cc8fa2a output function names for PGO-optimized cold function blocks. r=mark at http://breakpad.appspot.com/40007
git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@430 4c0a9323-5329-0410-9bdc-e9ce6186880e
2009-11-20 18:24:41 +00:00
nealsid
2712a8c712 Forward exceptions in child processes to Apple's Crash Reporter
http://breakpad.appspot.com/38001/show
R=mmentovai, jeremy
A=nealsid



git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@429 4c0a9323-5329-0410-9bdc-e9ce6186880e
2009-11-18 13:59:01 +00:00
mmentovai
ebebd0fcef Always export catch_exception_raise.
Patch by Jeremy Moskovich <jeremy@chromium.org>

Code review URL: http://breakpad.appspot.com/37001


git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@428 4c0a9323-5329-0410-9bdc-e9ce6186880e
2009-11-11 14:47:01 +00:00
nealsid
0e76d1fdf3 Fix when walking stack when no module list is present and the return address has to be
scanned.

http://breakpad.appspot.com/36002

R=doshimun
A=nealsid



git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@420 4c0a9323-5329-0410-9bdc-e9ce6186880e
2009-10-30 23:30:39 +00:00
jschuh@chromium.org
96c69639ee Fixed style error
git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@419 4c0a9323-5329-0410-9bdc-e9ce6186880e
2009-10-19 18:53:26 +00:00
jschuh@chromium.org
5f4fa55598 Issue 35001: Fallback to Thread Context on bad Exception Context
git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@418 4c0a9323-5329-0410-9bdc-e9ce6186880e
2009-10-19 18:10:49 +00:00
mmentovai
a3043159f3 Allow the Breakpad Mac framework to be built without -fexceptions.
Review URL: http://breakpad.appspot.com/34003

git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@417 4c0a9323-5329-0410-9bdc-e9ce6186880e
2009-10-15 22:42:54 +00:00
nealsid
cb33b20f75 Raise minidump processing limits
A=justin schuh
R=nealsid



git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@416 4c0a9323-5329-0410-9bdc-e9ce6186880e
2009-10-14 22:01:35 +00:00
jimblandy@gmail.com
e4be54eb3e Issue 32002: Breakpad DWARF parser: Update char decls to be signed
a=jimblandy
r=nealsid


git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@410 4c0a9323-5329-0410-9bdc-e9ce6186880e
2009-10-08 17:15:33 +00:00
ted.mielczarek
8d70618ffc Let x86 stackwalker scan stack in cases where program evaluation fails. Original patch by Jeff Muizelaar <jmuizelaar@mozilla.com> with some changes by me. r=mento at http://breakpad.appspot.com/32003/show
git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@409 4c0a9323-5329-0410-9bdc-e9ce6186880e
2009-10-08 14:21:50 +00:00
mmentovai
760d66430e 10.6 SDK compatibility fixes. No bug.
git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@407 4c0a9323-5329-0410-9bdc-e9ce6186880e
2009-10-06 18:16:36 +00:00
nealsid
c84c9e7bb3 Modification to crash_report to process a directory of .DMP files
http://breakpad.appspot.com/31001

R=nealsid
A=krisr



git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@405 4c0a9323-5329-0410-9bdc-e9ce6186880e
2009-09-30 21:40:41 +00:00
ted.mielczarek
b73230385c Fix compilation of OS X handler on PPC with 10.5 SDK. r=nealsid at http://breakpad.appspot.com/30001
git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@404 4c0a9323-5329-0410-9bdc-e9ce6186880e
2009-09-30 12:01:15 +00:00
nealsid
895d3d17ee New uploader for Linux with unit tests, and gflags/glog libraries
http://breakpad.appspot.com/29004

A=nealsid
R=chris masone at chromium org



git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@403 4c0a9323-5329-0410-9bdc-e9ce6186880e
2009-09-29 21:55:19 +00:00
mmentovai
4ee3ddcd33 Check RegisterWaitForSingleObject return in CrashGenerationServer::Start.
Patch by Matt Mueller <mattm@chromium.org>

Review URL: http://codereview.chromium.org/244028


git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@402 4c0a9323-5329-0410-9bdc-e9ce6186880e
2009-09-28 23:53:28 +00:00
nealsid
ce9178abaa A better makefile for building the Linux client.
http://breakpad.appspot.com/29003

A=nealsid
R=chris masone



git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@400 4c0a9323-5329-0410-9bdc-e9ce6186880e
2009-09-18 20:43:35 +00:00
ted.mielczarek
b2bc3bcc84 Issue 328 - should have constant for VC++ exceptions, and stringify in MinidumpProcessor::GetCrashReason
r=nealsid at http://breakpad.appspot.com/25001/show



git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@394 4c0a9323-5329-0410-9bdc-e9ce6186880e
2009-09-04 20:00:33 +00:00
jimblandy@gmail.com
c426b3d98a Breakpad: Don't use the deprecated __gnu_cxx::hash_map container.
Modern GNU compilers warn about the #inclusion of <ext/hash_map>; that
container is deprecated, and code should use <tr1/unordered_map>
instead.  However, to stay within the boundaries of C++ '98, it's
probably fine just to use plain old std::map.

Breakpad uses hash_map in three cases:

o The DWARF reader's SectionMap type maps object file section names to
  data.  This map is consulted once per section kind per DWARF
  compilation unit; it is not performance-critical.

o The Mac dump_syms tool uses it to map machine architectures to
  section maps in Universal binaries.  It's hard to imagine there
  ever being more than two entries in such a map.

o The processor's BasicSourceLineResolver uses a hash_map to map file
  numbers to file names.  This is the map that will probably have the
  most entries, but it's only accessed once per frame, after we've
  found the frame's line entry.

a=jimblandy
r=nealsid


git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@393 4c0a9323-5329-0410-9bdc-e9ce6186880e
2009-09-03 18:27:16 +00:00
stuartmorgan
ddd71b75f7 Fix text field resizing for 10.5+ SDK
git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@392 4c0a9323-5329-0410-9bdc-e9ce6186880e
2009-08-28 22:08:34 +00:00
mmentovai
ebe77d7e3b Provide a real std::string hash, not just a forward declaration for something
that doesn't exist.

TBR=nealsid

Code review URL: http://groups.google.com/group/google-breakpad-dev/browse_thread/thread/292f9ed79dfdbdde


git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@391 4c0a9323-5329-0410-9bdc-e9ce6186880e
2009-08-20 19:29:41 +00:00
nealsid
b0baafc4da Merge of Breakpad Chrome Linux fork
A=agl, Lei Zhang
R=nealsid, agl



git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@384 4c0a9323-5329-0410-9bdc-e9ce6186880e
2009-08-17 23:12:53 +00:00
mmentovai
7c48629d49 Fix build errors with gcc 4.4. Patch by Silvius Rus <rus@google.com>.
git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@383 4c0a9323-5329-0410-9bdc-e9ce6186880e
2009-08-14 18:46:43 +00:00
jimblandy@gmail.com
d4a212a099 Linux dumper: fix comments in src/common/linux/module.h
Fix some typos and references to member functions that didn't make the
final cut.

a=jimblandy
r=nealsid


git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@381 4c0a9323-5329-0410-9bdc-e9ce6186880e
2009-08-07 22:11:32 +00:00
jimblandy@gmail.com
eab03fdb72 Linux dumper: Move the data structures representing the breakpad data into their own class.
src/linux/common/module.h defines a new class, google_breakpad::Module,
that can represent the contents of a breakpad symbol file.  Module::Write
writes a well-formed symbol file to the given stream.

src/linux/common/dump_symbols.cc can now lose its symbol-file-writing
code, and change DumpStabsHandler to populate a Module object, rather
than the old SymbolInfo/SourceFileInfo/... collection of types.

The code to compute function and line sizes, even in the absence of
reliable size data in STABS, is moved into a new Finalize method of
DumpStabsHandler, which is responsible for completing the Module's
contents.

a=jimblandy
r=nealsid


git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@380 4c0a9323-5329-0410-9bdc-e9ce6186880e
2009-08-07 19:28:45 +00:00
jimblandy@gmail.com
f7cc9ef6f5 Add files left behind by previous commit.
git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@379 4c0a9323-5329-0410-9bdc-e9ce6186880e
2009-08-07 19:26:55 +00:00
jimblandy@gmail.com
54bc5cfa2d Linux dumper: Move STABS parsing into its own class.
With this patch, dump_symbols.cc no longer knows about the details of
the STABS debugging format; that is handled by the StabsReader class.
dump_symbols.cc provides a subclass of StabsHandler that builds
dump_symbols' own representation of the data.

a=jimblandy
r=nealsid


git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@378 4c0a9323-5329-0410-9bdc-e9ce6186880e
2009-08-07 19:24:32 +00:00
jimblandy@gmail.com
68c8481df6 Linux dumper: Make the 'name' field of FuncInfo a std::string instead of a char *.
Because the actual N_FUN strings in the .stabstr section contain type
information after the mangled name, representing this information
using a pointer into .stabstr, while efficient with memory, makes the
FuncInfo data structure STABS-specific: one must know the details of a
STABS N_FUN string's syntax to interpret FuncInfo::name.  This patch
removes this STABS dependency from the data structure, and moves us
closer to having an appropriate structure for representing unified
STABS and DWARF data.

a=jimblandy
r=nealsid


git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@375 4c0a9323-5329-0410-9bdc-e9ce6186880e
2009-08-05 00:57:48 +00:00
jimblandy@gmail.com
3c4de8e8a7 Linux dumper: Properly separate function names from STABS type data.
STABS strings for N_FUN entries contain a mangled function name,
followed by a colon, followed by type information.  The type
information itself may contain colons; mangled names never contain
colons (they need to be legal assembly-language identifiers).  So the
current code in src/common/linux/dump_symbols.cc:WriteOneFunction that
attempts to separate the mangled name from the STABS junk will
incorrectly include STABS junk in the name, causing demangling to
fail.

Applying the patch below results in changes like these in the symbol
file produced, where an unmangled name followed by STABS junk becomes
a properly demangled name:

## --- base/libxul.so.syms	2009-07-13 21:46:33.000000000 -0700
## +++ tip/libxul.so.syms	2009-07-13 21:51:04.000000000 -0700
## @@ -3907,7 +3907,7 @@
##  FILE 3905 /home/jimb/mc/in/gfx/cairo/libpixman/src/pixman-region.c
##  FILE 3906 combine.inc
##  FILE 3907 /home/jimb/mc/in/gfx/cairo/libpixman/src/pixman-edge-imp.h
## -FUNC 19898c 54 0 _Z20NS_GetCaseConversionv:F(0,1201)=*(0,1202)=xsnsICaseConvers
## ion
## +FUNC 19898c 54 0 NS_GetCaseConversion()
##  19898c 12 54 1
##  19899e 9 56 1
##  1989a7 6 60 1
## @@ -214776,7 +214776,7 @@
##  3847c9 9 57 506
##  3847d2 13 58 506
##  3847e5 7 59 506
## -FUNC 387e89 27 0 _ZN20nsGenericHTMLElement11FromContentEP10nsIContent:F(0,8117)
## =*(0,8118)=xsnsGenericHTMLElement
## +FUNC 387e89 27 0 nsGenericHTMLElement::FromContent(nsIContent*)
##  387e89 7 80 2584
##  387e90 3 80 2584
##  387e93 e 82 2584
## @@ -250473,7 +250473,7 @@
##  3d0d88 7 82 548
##  3d0d8f 25 84 548
##  3d0db4 5 85 548
## -FUNC 3d0e0c 40 0 _ZL21GetEnclosingListFrameP8nsIFrame:f(0,7182)=*(0,7183)=xsnsL
## istControlFrame
## +FUNC 3d0e0c 40 0 GetEnclosingListFrame(nsIFrame*)
##  3d0e0c 5 146 549
##  3d0e11 3 722 2645
##  3d0e14 d 146 549

a=jimblandy
r=nealsid


git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@374 4c0a9323-5329-0410-9bdc-e9ce6186880e
2009-08-05 00:56:29 +00:00
jimblandy@gmail.com
15117f9ae0 Linux dumper: Don't switch to wrong source file when starting new function.
In STABS, if one function's line number information contains an N_SOL
entry to switch to a new source file, then the next function's line
data should pick up in the same source file where the prior function
left off.  However, the Linux dumper restarts each function in the
compilation unit's main source file.  This patch fixes that, so that
the output attributes the lines in subsequent functions to the correct
source files.

a=jimblandy
r=nealsid


git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@373 4c0a9323-5329-0410-9bdc-e9ce6186880e
2009-08-05 00:54:47 +00:00
jimblandy@gmail.com
f6c98159e2 Linux dumper: Delete non-functional stack parameter size computation.
Delete code to compute function stack parameter size.  It never did anything.

a=jimblandy
r=nealsid


git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@372 4c0a9323-5329-0410-9bdc-e9ce6186880e
2009-08-05 00:53:23 +00:00
jimblandy@gmail.com
133c66ca40 Linux dumper: Let LineInfo structures point directly to their SourceLineInfo structures
Let LineInfo structures point directly to their SourceLineInfo
structures, rather than holding the index of the file's name in the
.stabstr section in the early phases, and then later the holding
source_id of the file.

This is another step in the process of moving STABS-specific values
out of the types that represent the breakpad symbol data.  When we're
done, the non-STABS structures will be something that we can populate
with both STABS and DWARF data --- or at least it will be more easily
replaced with such.

a=jimblandy
r=nealsid


git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@371 4c0a9323-5329-0410-9bdc-e9ce6186880e
2009-08-05 00:51:15 +00:00
nealsid
f3f7df33de Fix an INVALIDATE_ITERATOR defect reported by Coverity.
std::vector::erase() invalidates the iterator, so we need
to advance the iterator by using the return value of erase().

R=nealsid
A=wtc



git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@370 4c0a9323-5329-0410-9bdc-e9ce6186880e
2009-07-30 22:53:09 +00:00
jimblandy@gmail.com
0d23e8c686 Linux dumper: Don't record file boundary addresses as null-name SourceFileInfoList entries.
STABS information introduces a compilation unit with an N_SO entry
whose address is the start address of the file and whose string is the
name of the compilation unit's main source file.  However, STABS
entries can only hold one address, so STABS indicates the compilation
unit's ending address with an N_SO entry whose name is empty.

Currently, the dumper's data structures simply create SourceFileInfo
structures with empty names for these end-of-unit N_SO entries.  We
want to remove STABS-specific characteristics from these structures so
that we can replace them with an input-format-independent structure.

This moves end-of-compilation-unit addresses out of the symbol table
structure, and into their own list of boundary addresses.

a=jimblandy
r=nealsid


git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@369 4c0a9323-5329-0410-9bdc-e9ce6186880e
2009-07-30 17:54:40 +00:00
jimblandy@gmail.com
e0a2512369 Linux dumper: Use pointers to SourceFileInfo structures.
Use a list of pointers to SourceFileInfo structures, not a list of the
structures themselves.  This is preparation for a subsequent patch
which makes the data structures less STABS-specific.

This patch introduces a memory leak.  If an included file is
referenced only by line entries for functions that LoadFuncSymbols
elected to omit from the func_info list, then its SourceFileInfo
structure is leaked when we destroy the name_to_file map.  This leak
is fixed in a subsequent patch by letting the map of files by name own
the file objects.

a=jimblandy
r=nealsid


git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@368 4c0a9323-5329-0410-9bdc-e9ce6186880e
2009-07-30 17:39:42 +00:00
jimblandy@gmail.com
4a6e708ed6 Linux dumper: Use a sorted array of addresses in computing function and line sizes.
Replace the sorted lists of files and functions with an array of
boundary addresses.  This replaces CompareAddress with the default
comparison, and SortByAddress and NextAddress with the stock STL sort
and upper_bound algorithms, losing ~50 lines of code.

a=jimblandy
r=nealsid


git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@367 4c0a9323-5329-0410-9bdc-e9ce6186880e
2009-07-30 17:36:23 +00:00
nealsid
7a5e320f84 Add tool dependencies to the 'Build All' target of Breakpad, so that everything can be built at once!
R=stuart.morgan
A=nealsid



git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@366 4c0a9323-5329-0410-9bdc-e9ce6186880e
2009-07-28 21:13:13 +00:00
jimblandy@gmail.com
0eb3c6e5e2 Linux dumper: Correctly find boundary address when computing line and function sizes.
In NextAddress, check both the file list and the function list for the
nearest boundary.  Don't assume that, if we find any bounding entry in
the function list, that must be the nearest thing.

A=jimblandy
R=nealsid


git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@365 4c0a9323-5329-0410-9bdc-e9ce6186880e
2009-07-27 21:33:25 +00:00
jimblandy@gmail.com
1147cc4920 The has_sol field of struct FuncInfo is unused. This patch removes it.
A=jimblandy
R=nealsid


git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@364 4c0a9323-5329-0410-9bdc-e9ce6186880e
2009-07-27 21:32:31 +00:00
jimblandy@gmail.com
53cb8044fd The 'no_next_addr_count' variable in ComputeSizeAndRVA shouldn't be static.
The current arrangement would produce needless warnings if
WriteSymbolFile were ever used twice in the same program invocation.
Even if it weren't wrong, it's unnecessary, and local non-const static
variables require extra care when reading to be sure of their effect.

A=jimblandy
R=nealsid


git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@363 4c0a9323-5329-0410-9bdc-e9ce6186880e
2009-07-27 21:30:56 +00:00
jimblandy@gmail.com
722afebee0 Use a std::map instead of a linear search to look up files for line records.
With this patch, the time required to generate Breakpad symbols for
Firefox's libxul.so on a MacBook Pro 3,1 drops from 32s to 2s.

I verified that this patch had no effect on the output of dump_syms
when applied to firefox-bin and its libraries when built with -gstabs+.

A=jimblandy
R=nealsid


git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@362 4c0a9323-5329-0410-9bdc-e9ce6186880e
2009-07-27 21:30:02 +00:00
jimblandy@gmail.com
515f92cd61 Remove warnings about uninitialized fields.
A=jimblandy
R=nealsid


git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@361 4c0a9323-5329-0410-9bdc-e9ce6186880e
2009-07-27 21:28:57 +00:00
nealsid
22734848ea Port fixes from internal Google Breakpad to SVN.
A=preston, nealsid
R=Stuart, Preston



git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@360 4c0a9323-5329-0410-9bdc-e9ce6186880e
2009-07-21 00:10:57 +00:00
nealsid
23c364a2b4 Fix for http://breakpad.appspot.com/18009 - run dump_syms on both PPC & i386 machines correctly, and process STABS/DWARF information in the same binary
R=stuart morgan
A=nealsid



git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@359 4c0a9323-5329-0410-9bdc-e9ce6186880e
2009-07-17 20:32:08 +00:00
nealsid
f4f249e544 Integration test for Windows exception handler/minidump generation.
R=hannah tang
A=nealsid



git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@358 4c0a9323-5329-0410-9bdc-e9ce6186880e
2009-07-17 01:15:48 +00:00
nealsid
6e525cbfbb Add stack-dumping logic to crash_report with -t switch
R=jeremy
A=nealsid



git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@357 4c0a9323-5329-0410-9bdc-e9ce6186880e
2009-07-02 00:30:44 +00:00
nealsid
df55cf4313 Updated google mock external revision so we can use their own tuple implementation, so we can compile test cases under vs 2005
git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@356 4c0a9323-5329-0410-9bdc-e9ce6186880e
2009-06-26 21:50:48 +00:00
nealsid
90a6505b03 The symbol files necessary for the processor to walk stacks on Linux that have __kernel_vsyscall at innermost frame. Special symbol files ar eneeded because EBP does not point to the frame when a thread is inside a system call.
git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@353 4c0a9323-5329-0410-9bdc-e9ce6186880e
2009-06-25 21:36:39 +00:00
nealsid
ae4d8370ee Fix for crashs generation test app to not deadlock
git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@352 4c0a9323-5329-0410-9bdc-e9ce6186880e
2009-06-22 21:45:31 +00:00
nealsid
1d8cba25c7 Fix build break in crash_report caused by my checkin that moved minidump processing error codes to a different namespace
R=preston
A=nealsid



git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@351 4c0a9323-5329-0410-9bdc-e9ce6186880e
2009-06-16 22:31:51 +00:00
ted.mielczarek
61e88c7ad7 issue 323 - OS X exception handler / minidump generator should set exception address correctly for EXC_BAD_ACCESS . r=nealsid at http://breakpad.appspot.com/15002
git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@350 4c0a9323-5329-0410-9bdc-e9ce6186880e
2009-06-12 20:36:53 +00:00
nealsid
c52715f32f Fix for generating dumps on-demand to set the requesting thread to the current thread
R=stuartmorgan
A=nealsid



git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@349 4c0a9323-5329-0410-9bdc-e9ce6186880e
2009-06-12 18:16:09 +00:00
nealsid
dae47f0d16 Support overriding makefile variables, changed defaults compilation flags. This patch from Jim Blandy was Merged with a previous change from nealsid to force 32-bit compilation even on 64-bit machines.
A=jim blandy
R=nealsid



git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@348 4c0a9323-5329-0410-9bdc-e9ce6186880e
2009-06-05 23:06:54 +00:00
nealsid
0eb52ff8cc Use ctsdio streams for dump_syms for significant speedup. Also contains a makefile fix to build in 32-bit mode, even on 64-bit systems.
A=jim blandy
R=nealsid



git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@347 4c0a9323-5329-0410-9bdc-e9ce6186880e
2009-06-05 22:40:28 +00:00
nealsid
2eb356a68d Support custom URL parameters. Added unit tests for Breakpad. Added
a way to specify server parameters in app plist file, as well.

R=stuartmorgan, jeremy
A=nealsid



git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@346 4c0a9323-5329-0410-9bdc-e9ce6186880e
2009-06-03 21:51:33 +00:00
nealsid
1a997295b6 Removed logging init macro from minidump_processor_unittest, since with the Google Test integration, logging is handled through it's facilities
git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@345 4c0a9323-5329-0410-9bdc-e9ce6186880e
2009-05-29 20:49:04 +00:00
nealsid
e328c2dc58 Updated autoconf build files, and fixed externals dependency at revision 158(current as of 5/28)
git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@344 4c0a9323-5329-0410-9bdc-e9ce6186880e
2009-05-29 01:07:25 +00:00
nealsid
b56cfa067a Add more error information to minidump processing return code. Also added dependency on google test, and modified minidump processing unit tests to use google test
R=brdevmn
A=nealsid



git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@343 4c0a9323-5329-0410-9bdc-e9ce6186880e
2009-05-29 00:53:02 +00:00
ted.mielczarek
aaecb48b3b Fix minidump_stackwalk compilation on gcc 4.3. Patch by Jim Blandy
git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@342 4c0a9323-5329-0410-9bdc-e9ce6186880e
2009-05-28 17:50:33 +00:00
stuartmorgan
2a78191cab Show the reporter UI for Breakpad.framework regardless of whether continuing the crashed process succeeded (issue 319)
git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@341 4c0a9323-5329-0410-9bdc-e9ce6186880e
2009-05-28 16:26:30 +00:00
nealsid
2a4698319a Fix up warnings when building http_upload.cc. Changed warning level to /W4, and also turned off deprecated 64-bit compatability warning flag(since some people are regularly building Breakpad in 64-bit mode, if we turn off this flag we get rid of a warning in 32 bit mode under VS2008)
R=mmentovai
A=nealsid



git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@340 4c0a9323-5329-0410-9bdc-e9ce6186880e
2009-05-27 16:54:23 +00:00
nealsid
bec07f6972 Patch from Jeremy to have better error reporting, and workaround a Cocoa bug in different locales
R=nealsid
A=jeremy


git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@339 4c0a9323-5329-0410-9bdc-e9ce6186880e
2009-05-15 17:54:20 +00:00
nealsid
fc26f4a9b5 Fix memory leak in test case when calling into basic source line resolver.
R=brdevmn
A=nealsid



git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@338 4c0a9323-5329-0410-9bdc-e9ce6186880e
2009-05-14 21:31:03 +00:00
nealsid
dad1acc2d0 Deleting obsolete file(when I added DWARF support I had to make this a .MM but I forgot to delete the old file)
git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@337 4c0a9323-5329-0410-9bdc-e9ce6186880e
2009-05-12 17:19:59 +00:00
stuartmorgan
f9c5540ea6 Add a missing include (for gettimeofday) to Inspector.mm
git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@336 4c0a9323-5329-0410-9bdc-e9ce6186880e
2009-04-30 01:11:36 +00:00
stuartmorgan
33e8fad61d Mac reporter improvements:
- Made localization for UI entirely string-based, with flexible layout based on the size of the strings inserted.
- Made the request for an email address optional.
- Fixed a bug that would prevent comments or email from being collected if the text field were still focused.
- Refactored askUserPermissionToSend.


git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@335 4c0a9323-5329-0410-9bdc-e9ce6186880e
2009-04-29 13:50:53 +00:00
stuart.morgan
73afbc7302 Mac framework fixes: Propagate server type from plist, and fix precedence of defaults vs. plist
git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@334 4c0a9323-5329-0410-9bdc-e9ce6186880e
2009-04-29 13:27:16 +00:00
nealsid
ed1f6e754a Code review issue 9002: Add paranoid logging to Inspector & Reporter
A=jeremy moskovich
R=nealsid



git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@333 4c0a9323-5329-0410-9bdc-e9ce6186880e
2009-04-23 07:56:16 +00:00
stuartmorgan
e438d9cc0b Add a parameter to control the Mac reporter timeout.
git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@332 4c0a9323-5329-0410-9bdc-e9ce6186880e
2009-04-22 13:22:08 +00:00
nealsid
1cb4ad73a6 Fix to support extensible parameter handling, and add process crashtime/uptime support
R=stuart morgan
A=nealsid



git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@331 4c0a9323-5329-0410-9bdc-e9ce6186880e
2009-04-22 06:25:21 +00:00
stuartmorgan
04a7df7acf Give the Mac reporter app a localized name of 'Crash Reporter'
git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@330 4c0a9323-5329-0410-9bdc-e9ce6186880e
2009-04-22 03:10:03 +00:00
nealsid
ad6543e4e7 Fix memory leak when using the basic source line resolver, plus the optimization to load using in-memory buffers. Moved from manually allocating/deallocating memory to using a scoped_array
A=nealsid
R=tiger feng



git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@329 4c0a9323-5329-0410-9bdc-e9ce6186880e
2009-04-22 00:55:31 +00:00
nealsid
a0a0de39a8 Patch from Jeremy Moskovich to build with 10.5 SDK correctly. Also removed externals directory.
A=jeremy
R=nealsid



git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@328 4c0a9323-5329-0410-9bdc-e9ce6186880e
2009-04-21 08:29:46 +00:00
doshimun
ea78675fbd AppVerifier leak test fix for Windows 7.
git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@327 4c0a9323-5329-0410-9bdc-e9ce6186880e
2009-04-08 18:58:12 +00:00
stuart.morgan
841f5f7390 Sender tweaks; strip whitespace from server-returned ID, and change the title of the dialog a bit.
git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@326 4c0a9323-5329-0410-9bdc-e9ce6186880e
2009-04-07 16:31:27 +00:00
stuart.morgan
9290b7062f Fix framework bundle ID and remove useless autogenerated InfoPlist.strings
git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@325 4c0a9323-5329-0410-9bdc-e9ce6186880e
2009-04-06 20:17:09 +00:00
nealsid
77d851c356 Fix my build break due to misnamed constant
git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@324 4c0a9323-5329-0410-9bdc-e9ce6186880e
2009-04-06 00:57:06 +00:00
nealsid
a3d4c97336 Incorporate feedback from first Breakpad integration.
This upload fixes five issues:

1) Preston's email was hardcoded in the xib :-(
2) Changed from xib to NIB to facilitate Tiger building
3) Changed the logs location to be user specifiable by BreakpadMinidumpLocation
key, or ~/Library/Breakpad/<BREAKPAD_PRODUCT> by default
4) Fixed GTM Defines problem in order to build on Tiger
5) Also set CFBundleIcon in the sender program correctly, and updated plist, and
renamed ReporterIcons to crash_report_sendER.ICNS.  However the rietveld upload
script doesn't appear to pick up renamed files correctly, so that file doesn't
show up in the patch upload.

Also various comments were updated for accuracy.



git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@323 4c0a9323-5329-0410-9bdc-e9ce6186880e
2009-04-06 00:25:29 +00:00
nealsid
3ebdb1bd7a Open sourcing the Breakpad framework from Google.
A=many, many people
R=nealsid, jeremy moskovich(from Chromium project)



git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@322 4c0a9323-5329-0410-9bdc-e9ce6186880e
2009-04-01 03:18:49 +00:00
ted.mielczarek
0abe34ce5d issue 305 - breakpad Linux handler doesn't build with compiler built from latest GCC sources. Trivial patch by Jim Blandy
git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@321 4c0a9323-5329-0410-9bdc-e9ce6186880e
2009-03-24 19:57:46 +00:00
nealsid
a18f4f9a06 Removing SVN external of GOogle Toolbox for mac, since we only need a few files that don't change very often
git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@320 4c0a9323-5329-0410-9bdc-e9ce6186880e
2009-03-23 20:22:45 +00:00
nealsid
3366749ee7 Fix for issue 304: symupload needs to support timeout specifications(wininet can timeout when sending large symbol files).
R=doshimun
W=nealsid



git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@319 4c0a9323-5329-0410-9bdc-e9ce6186880e
2009-03-20 19:02:12 +00:00
nealsid
2ad976ef0b Fix for issues 296, 297. Various symbol supplier classes need to be updated with new overload('make check' was failing, as well as crash_report), and remove logging that was flooding output
git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@318 4c0a9323-5329-0410-9bdc-e9ce6186880e
2009-02-27 23:59:40 +00:00
nealsid
02c244f1b2 Fix for issue 242, plus a redo of how old exception handlers are tracked, and called.
R=Craig.Schlenter, luly81



git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@315 4c0a9323-5329-0410-9bdc-e9ce6186880e
2009-02-26 21:31:53 +00:00
nealsid
4af5fe0b59 Fix build breaks on Solaris using Sun Studio.
Written by Ginn Chen & Eagle.Lu@
R=nealsid (although I don't have a Solaris machine to build on, & these changes look localized to Sun-only builds)



git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@314 4c0a9323-5329-0410-9bdc-e9ce6186880e
2009-02-23 09:28:29 +00:00
nealsid
e1a7efca7d See https://bugzilla.mozilla.org/show_bug.cgi?id=397200
The method of calculating a binary ID using the LC_ID command isn't compatible with non-default build processes, most Mac consumers
use LC_UUID anyway but for those that don't, MD5 is a better choice
R=nealsid
W=Ted.Mielczarek



git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@313 4c0a9323-5329-0410-9bdc-e9ce6186880e
2009-02-22 08:16:05 +00:00
nealsid
cadc8ddde9 Issue 294: mmap error checking is not correct.
R=Liu



git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@312 4c0a9323-5329-0410-9bdc-e9ce6186880e
2009-02-22 01:31:43 +00:00
nealsid
0fd2f1ae21 Modify symbol supplier interface to support an overload that takes a symbol data buffer, to get around an extraneous read/write of symbol data
R=doshimun



git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@311 4c0a9323-5329-0410-9bdc-e9ce6186880e
2009-02-19 21:26:20 +00:00
nealsid
a285652cba Issue 275: patch to include list of loaded modules in crash_report output
Written by: jum@mac.com
R=nealsid



git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@310 4c0a9323-5329-0410-9bdc-e9ce6186880e
2009-02-10 21:29:54 +00:00
doshimun
c9944d96e8 Reinstnate the call to TerminateThread inside ExceptionHandler destructor and put
the graceful code inside a #ifdef.

The problem is:
If ExceptionHandler is created and destroyed in DllMain, then the previous change to
remove the call to TerminateThread will lead to a deadlock. This is because inside
DllMain the loader lock is acquired, and the previous change waits for the handler
thread to exit in the destructor, that is with the loader lock acquired. But the
handler thread cannot finish until it gets the loader lock to call DllMain for
THREAD_DETACH.

With this change, we add conditional compilation so that clients that want to
avoid the call to terminate thread can do it by defining the appropriate preprocessor
variable.



git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@309 4c0a9323-5329-0410-9bdc-e9ce6186880e
2009-01-20 20:45:28 +00:00
doshimun
104e4e0114 Fix an AppVerifier STOP in OOP server code. In the destructor of
the OOP server, we need to wait for any pending I/O to be done.



git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@308 4c0a9323-5329-0410-9bdc-e9ce6186880e
2009-01-16 22:37:48 +00:00
doshimun
308947d1ce Fix some typos in comments.
git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@307 4c0a9323-5329-0410-9bdc-e9ce6186880e
2009-01-14 21:54:08 +00:00
doshimun
a6f58a1ac8 Minor fixes to windows exception handler.
git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@306 4c0a9323-5329-0410-9bdc-e9ce6186880e
2009-01-14 20:51:51 +00:00
nealsid
8b6271ce2c New test data to reflect Ted's changes that add function parameters to symbols when using DWARF
R=ted.mielczarek



git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@305 4c0a9323-5329-0410-9bdc-e9ce6186880e
2008-12-19 22:28:45 +00:00
nealsid
ab819f0680 Updating externals to include all of Google Toolbox for Mac
git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@304 4c0a9323-5329-0410-9bdc-e9ce6186880e
2008-12-11 03:25:39 +00:00
ted.mielczarek
3751b05354 Issue 283 - DWARF dumper doesn't handle DW_AT_specification. r=nealsid
git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@303 4c0a9323-5329-0410-9bdc-e9ce6186880e
2008-12-08 13:12:45 +00:00
ted.mielczarek
d3441c2c96 Issue 284 - DWARF dumper doesn't output function names including arguments. r=nealsid
git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@302 4c0a9323-5329-0410-9bdc-e9ce6186880e
2008-12-08 13:00:29 +00:00
ted.mielczarek
7837cb7236 issue 286 - clean up some demangling code in dump_syms.mm. r=chris rogers
git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@301 4c0a9323-5329-0410-9bdc-e9ce6186880e
2008-12-03 18:23:09 +00:00
mmentovai
e5c401467b ExceptionHandler class is not handling initialization errors, such as the
handler thread not being created.  Protect the exception handler against
failure to create semaphores and a thread handle.

Patch by Marc-André (MAD) Decoste, r=me

http://code.google.com/p/google-breakpad/issues/detail?id=285
http://codereview.chromium.org/13065


git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@300 4c0a9323-5329-0410-9bdc-e9ce6186880e
2008-12-03 17:21:34 +00:00
ted.mielczarek
af553e22cb follow up for issue 281 - dump_syms fails to find dylib symbol file inside of a bundle. handle files without an extension properly
git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@299 4c0a9323-5329-0410-9bdc-e9ce6186880e
2008-12-01 18:42:16 +00:00
ted.mielczarek
7b8eb04745 issue 281 - dump_syms fails to find dylib symbol file inside of a bundle. r=nealsid
git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@298 4c0a9323-5329-0410-9bdc-e9ce6186880e
2008-12-01 17:05:43 +00:00
ted.mielczarek
5f27d9125c Followup to address some review comments from Issue 259
git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@297 4c0a9323-5329-0410-9bdc-e9ce6186880e
2008-11-25 13:41:41 +00:00
ted.mielczarek
324d84c2f6 Issue 259 - crash when generating large .sym files with dump_syms on Linux. Patch by login_ing@yahoo.com, r=Liu Li
git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@296 4c0a9323-5329-0410-9bdc-e9ce6186880e
2008-11-24 20:47:37 +00:00
nealsid
e055207058 Added some sanity checks when iterating over threads in a crashed process. In same cases the ESP could be 0. In other cases it would be borked completely(i.e. pointing to an invalid range).
R=Jeremy Moskovich



git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@295 4c0a9323-5329-0410-9bdc-e9ce6186880e
2008-11-19 19:07:34 +00:00
nealsid
f32d028110 Committing an externals directory to pull in google toolbox for mac
git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@294 4c0a9323-5329-0410-9bdc-e9ce6186880e
2008-11-14 20:16:13 +00:00
nealsid
c85fb043ed Fix for dump_syms to ignore line number information for addresses that don't have an enclosing function
git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@293 4c0a9323-5329-0410-9bdc-e9ce6186880e
2008-11-03 23:23:50 +00:00
nealsid
3a283d8f8b Undo suspend/resume feature since it was meant as a workaround to a bug in how we handled child process exceptions. Currently we don't return to the kernel when we take an exception from a child process, causing a hang. Now we return KERN_FAILURE, indicating to the kernel to move on to the host-level exception handler(usually Crash Reporter)
git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@292 4c0a9323-5329-0410-9bdc-e9ce6186880e
2008-10-27 04:52:16 +00:00
nealsid
32441cc060 Issue 181: Add version info for Mac OS X modules. Found by iterating over load commands until I found LC_ID_DYLIB. Also modified crash_report to generate version number. Also added suspend/resume capability to exception handler, necessary because exception handling can behave strangely across fork() calls. Also added fix for filtering out functions with no line number information, and for filtering out some multiple inheritance glue the compiler generates.
git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@291 4c0a9323-5329-0410-9bdc-e9ce6186880e
2008-10-22 05:08:50 +00:00
ted.mielczarek
c5f46b2f4b Issue 276 - generate GUIDs ahead of time in Linux handler. r=Liu Li
git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@290 4c0a9323-5329-0410-9bdc-e9ce6186880e
2008-10-14 11:21:34 +00:00
nealsid
1de70760db Fix for DWARF processing when inline functions were encountered. Inline functions were part of the debugging information as sequential in the PC range of the function but the source file was where the function was written(as you might expect). However the old dump_syms code, once it switched files as it was iterating over a range of addresses, never switched back, causing inline functions to cause all file numbers for addresses after the PC of the inline function to be wrong
git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@289 4c0a9323-5329-0410-9bdc-e9ce6186880e
2008-10-14 01:24:02 +00:00
nealsid
bb067bf185 Fix warning when converting int to bool
git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@288 4c0a9323-5329-0410-9bdc-e9ce6186880e
2008-10-10 17:51:32 +00:00
ted.mielczarek
596e476fc2 fix a typo in the makefile, HANDLER_SRC->HANDLER_OBJ
git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@287 4c0a9323-5329-0410-9bdc-e9ce6186880e
2008-10-10 15:48:06 +00:00
nealsid
cb4aa6b804 Added DWARF support to Breakpad client. Thanks to Google for open sourcing their DWARF code!
Modified dump_syms to detect dSYM bundles or a binary with DWARF data appropriately, and convert data from DWARF reader to dump_syms native structures

R=danny.berlin (original writer of DWARF code)



git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@286 4c0a9323-5329-0410-9bdc-e9ce6186880e
2008-10-08 23:56:02 +00:00
mmentovai
a509f4ec4b Generate Windows full memory dumps as a separate file. Patch by Huan Ren
<huanr@google.com>.  r=me


git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@285 4c0a9323-5329-0410-9bdc-e9ce6186880e
2008-09-16 18:50:02 +00:00
mmentovai
9fcf4db315 Include what you use: include <algorithm> and <string.h> as needed. Patch by
Robert Henry.  r=me


git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@284 4c0a9323-5329-0410-9bdc-e9ce6186880e
2008-09-15 18:16:49 +00:00
doshimun
11dc028694 Log a failure message in case of LOCATE_NOT_FOUND error.
Without this change, no error is logged in this case.



git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@283 4c0a9323-5329-0410-9bdc-e9ce6186880e
2008-07-30 19:39:48 +00:00
nealsid
85534c2eaf Now we provide our own implementation of the MIG function exc_server, as recommended by Apple.
See 
http://groups.google.com/group/google-breakpad-dev/browse_thread/thread/8b363b1f8a404714
For more information



git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@282 4c0a9323-5329-0410-9bdc-e9ce6186880e
2008-07-11 17:39:52 +00:00
doshimun
2d7664e8d4 In the destructor of ClientInfo, currently the wait on the clent_crashed_event is
unregistered after the handle is closed. MSDN clearly says that the behavior is
undefined in this case. See http://msdn.microsoft.com/en-us/library/ms685061(VS.85).aspx
 
This change contains the fix for that bug. See attched diff.



git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@281 4c0a9323-5329-0410-9bdc-e9ce6186880e
2008-06-09 23:38:24 +00:00
doshimun
3a516e4177 Client process uptime is a very useful metric for crashes. Instead of each client process having to keep track of uptime and report it whenever a crash happens, integrate this feature into breakpad OOP code so that all clients get it for free.
I tested this using the test app I have to test OOP stuff.



git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@280 4c0a9323-5329-0410-9bdc-e9ce6186880e
2008-06-06 21:41:32 +00:00
nealsid
38bc56cfa8 Modified symupload to correctly handle spaces in module names when processing symbol file
Reviewer=mmentovai



git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@279 4c0a9323-5329-0410-9bdc-e9ce6186880e
2008-06-05 21:20:53 +00:00
doshimun
cc6cd1ff37 Fix the following bug:
The sender updates the checkpoint file even when the report is not
successfully sent.



git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@278 4c0a9323-5329-0410-9bdc-e9ce6186880e
2008-06-05 20:59:35 +00:00
nealsid
d55398a492 Filter out duplicates from the image list when creating a minidump. See issue 266 for more details.
Reviewer = mmentovai



git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@277 4c0a9323-5329-0410-9bdc-e9ce6186880e
2008-06-04 22:57:09 +00:00
doshimun
f6b3e16ef8 Set the dump thread id and the requesting thread id properties of MDRawBreakpadInfo
only in case of in-process dump generation; otherwise the dump processing code of
breakpad doesn't identify the crashing thread properly.

I am checking this in to-be-reviewed since it is needed urgently in one of the
products at Google.



git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@276 4c0a9323-5329-0410-9bdc-e9ce6186880e
2008-05-31 19:23:20 +00:00
nealsid
b91bb881d5 Fix to ignore source files that have a text address of 0 in their stabs entry
git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@275 4c0a9323-5329-0410-9bdc-e9ce6186880e
2008-05-19 17:27:40 +00:00
doshimun
72bafd378d Microsoft broke PROCESS_ALL_ACCESS when we build with WINVER=0x600. See http://nsylvain.blogspot.com/2008/01/winverwin32winnt-mayhem.html for
details (second half of the post).

Changing PROCESS_ALL_ACCESS to GENERIC_ALL in ClientInfo class when
opening the client process handle on the OOP server side.

A minor change to pipe name in the test app also.



git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@274 4c0a9323-5329-0410-9bdc-e9ce6186880e
2008-05-15 04:12:34 +00:00
mmentovai
808ff9bc70 64-bit processor can't handle 32-bit ppc minidumps due to struct padding
differences on 64- and 32-bit CPUs.  Force 32-bit alignment rules for
32-bit ppc context struct.  r=nealsid

http://groups.google.com/group/google-breakpad-dev/browse_thread/thread/21a8e99c4800b51d


git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@273 4c0a9323-5329-0410-9bdc-e9ce6186880e
2008-05-14 18:24:23 +00:00
nealsid
d318f9efee Fix to stop unit tests from being compiled & run for non-native architectures
git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@272 4c0a9323-5329-0410-9bdc-e9ce6186880e
2008-05-08 23:15:00 +00:00
doshimun
7ab126ecdd Replace the user of wcscpy_s with safe_wcscpy in common/windows/string_utils-inl.h to
make the code compatible for teams that still use VS 2003 to build.

Fix a bug in client ClientInfo class that returned CustomClientInfo struct containing
a pointer in the client process address space instead of pointer to in-process data
structure.



git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@271 4c0a9323-5329-0410-9bdc-e9ce6186880e
2008-05-08 18:15:07 +00:00
doshimun
8602aa71ec Some style guide compliance changes and changed the prototype of the method to get custom client info in ClientInfo class.
git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@270 4c0a9323-5329-0410-9bdc-e9ce6186880e
2008-05-07 21:54:12 +00:00
nealsid
c2bdaa613c Bug fix for issue 263: mach_vm_region_recurse calls have invalid parameter specified, which succeeds on Leopard but fails on Tiger
Reviewer: Chris Rogers(ladderbreaker)


git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@269 4c0a9323-5329-0410-9bdc-e9ce6186880e
2008-05-07 21:15:12 +00:00
doshimun
3d4dc1f201 Add a convenience method to CustomClientInfo struct to set both name and value in one call.
git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@268 4c0a9323-5329-0410-9bdc-e9ce6186880e
2008-05-05 21:03:51 +00:00
doshimun
0ded3d718f Add a way for the client apps to specify custom information in case of out-of-process
scenarios that the OOP server can use in whatever way it wants to.

Fix a bug in CrashGenerationserver where CreateNamedPipe failure was not checked correctly.

TODO in near future: Add a custom stream to minidump files for the custom information.



git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@267 4c0a9323-5329-0410-9bdc-e9ce6186880e
2008-05-05 20:03:56 +00:00
nealsid
47df365bf8 Issue 261/262: 64-bit bug fix when iterating through load commands of a 64-bit binary, and added new test case for ReadImageInfoForTask
git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@266 4c0a9323-5329-0410-9bdc-e9ce6186880e
2008-05-05 18:20:04 +00:00
nealsid
d6f0f92de3 Style changes
git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@265 4c0a9323-5329-0410-9bdc-e9ce6186880e
2008-04-30 00:56:17 +00:00
nealsid
d906d0f7c9 Updated code to be compliant with style guidelines
git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@264 4c0a9323-5329-0410-9bdc-e9ce6186880e
2008-04-29 23:49:39 +00:00
nealsid
4c39c138fe Issue 258: Added test cases for ReadTaskMemory, reorganized project file, renamed filenames inside comments
git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@263 4c0a9323-5329-0410-9bdc-e9ce6186880e
2008-04-25 00:37:19 +00:00
doshimun
9033edcd7b Add one more parameter to the ClientDumpRequestCallback in crash generation server
to pass in the path of the dump file if the dump was generated successfully.



git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@262 4c0a9323-5329-0410-9bdc-e9ce6186880e
2008-04-17 21:21:48 +00:00
nealsid
9609db8173 Fix a bug in start address calculation
git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@261 4c0a9323-5329-0410-9bdc-e9ce6186880e
2008-04-17 04:15:30 +00:00
nealsid
5da03791a7 As part of resolving issue 256 I'd like to check in some unit
tests(ok, just one) for the private copy of nlist that I checked in
last week, plus lay some of the ground work for collecting code
coverage numbers.  Both of these are accomplished by leveraging the
built-in facilities of Xcode & Developer Tools(namely, CPlusTest and
gcov integration; however, eventually I will also add a way to get
lcov results from the gcov results).  I also:

 - renamed breakpad_nlist_64.c to breakpad_nlist_64.cc to be more
consistent(even though it's not C++ code it still only gets called by
C++ code so I don't have to deal with extern "C" constructs).
 - I created a new target (minidump_tests) that has a "Coverage"
configuration with the appropriate GCC flags turned on.  It is only
compiled in 64-bit configurations and has 10.5 as a minimum
deployment target as well as uses the 10.5 SDK.


git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@260 4c0a9323-5329-0410-9bdc-e9ce6186880e
2008-04-15 23:09:30 +00:00
nealsid
b0d807666f Issue 254: The problem is that nlist() is compiled out of libc in
64-bit builds of Leopard.  I ported the code over myself and will
check it into the Breakpad tree until we decide there's a better
longer-term solution.  If you want to diff the changes, the Apple
source is in libc/gen/nlist.c(I used 498 from 10.5.2).



git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@259 4c0a9323-5329-0410-9bdc-e9ce6186880e
2008-04-12 01:16:18 +00:00
doshimun
35c34d6bb9 Add a parameter to CrashGenerationServer to let the callers set the
security attributes on the pipe. This is useful when the process
hosting the crash server wants to let processes from other users to
connect to it and generate dumps for them.



git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@258 4c0a9323-5329-0410-9bdc-e9ce6186880e
2008-04-12 00:00:34 +00:00
doshimun
05ec557277 Some cosmetic/style changes to conform to style guidelines. This time
I waited for the style reviewer to approve all my code so hopefully there
should be no more style related check-ins.



git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@256 4c0a9323-5329-0410-9bdc-e9ce6186880e
2008-04-08 19:03:57 +00:00
mmentovai
eeca9921c5 Fix newlines (#253). rs=ted.mielczarek
http://groups.google.com/group/google-breakpad-dev/browse_thread/thread/7e62a299ce3fa222


git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@255 4c0a9323-5329-0410-9bdc-e9ce6186880e
2008-04-07 21:50:57 +00:00
mmentovai
61ea8bf0d5 Processor crashes on some truncated minidumps after #222. r=ted.mielczarek
http://groups.google.com/group/google-breakpad-dev/browse_thread/thread/a451668b1ece259f


git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@254 4c0a9323-5329-0410-9bdc-e9ce6186880e
2008-04-04 21:41:50 +00:00
nealsid
867df1c652 Issue 246: Dynamic_images.* needs to be 64-bit ready. Created types that are typedefed to the appropriate types depending on 32/64-bit compilation and modified dynamic_images to use these new types. Tested 32-bit minidump-generation. Also did some code cleanup along the way. Removed all blank lines that had spaces.
git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@253 4c0a9323-5329-0410-9bdc-e9ce6186880e
2008-04-04 21:35:41 +00:00
doshimun
fc816a3b3a Minor style changes to comply with Google style guidelines.
git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@252 4c0a9323-5329-0410-9bdc-e9ce6186880e
2008-04-03 21:46:58 +00:00
ted.mielczarek
dd2ff4a21c issue 223 - Fixes for SOlaris handler during integration with Firefox. patch by Alfred Peng, r=mento,me
git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@250 4c0a9323-5329-0410-9bdc-e9ce6186880e
2008-03-18 16:10:10 +00:00
nealsid
a194d6f1ac Issue 245: refactoring minidump_format.h into architecture & platform specific files
git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@249 4c0a9323-5329-0410-9bdc-e9ce6186880e
2008-03-17 05:24:12 +00:00
doshimun@gmail.com
5066fcdb42 TO BE REVIEWED.
Have sent an email for code review already but this check-in is urgent
to fix potential build breaks.

It contains the following changes:
- Change project settings for exception_handler.vcproj so that it links in
  crash_generation.lib so that the applications using exception_handler.lib
  do not have to link to crash_generation.lib. Make these changes for all 4
  build configurations.
- Change the test app project settings to not link to crash_generation.lib
  and only link to exception_handler.lib; again for all four configurations.

These changes help the applications that are currently linking to exception_handler.lib
in that they don't have to link to one more lib to get out-of-process dump generation
functionality. In fact, even if they do not use out-of-process dump generation functionality,
after those changes, the apps will need to link with crash_generation.lib anyway in order to
build correctly. This change will eliminate that need.



git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@248 4c0a9323-5329-0410-9bdc-e9ce6186880e
2008-03-11 22:28:48 +00:00
doshimun@gmail.com
a8b48f29dd This changelist contains the changes to the configuration of Visual Studio solution and project files that I
added in my last check-in for out-of-process dump generation. My last check-in broke the breakpad_client.sln
build for non debug builds since for the new project that I added (crash_generation.vcproj) to that solution,
I always only changed project properties for debug build. In fact, I didn't have the static-crt build configurations
for the new project either. Similar problems existed for the test application I added, windows/test/crash_generation_app).
 
This changelist contains changes to 2 solution files, 2 vcproj files and 1 .cc file. The fixes to .cc file are to avoid
warnings on variables used only in debug modes (in asserts) when building in release modes.



git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@247 4c0a9323-5329-0410-9bdc-e9ce6186880e
2008-03-10 22:37:07 +00:00
528 changed files with 181295 additions and 62757 deletions

44
DEPS Normal file
View File

@@ -0,0 +1,44 @@
# Copyright (c) 2010, 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.
# We only use this file to ease the steps of generating projects after
# syncing, if we use gclient. All dependencies are svn:externals instead.
# If you're not using gclient, you need to run the gyp python script to
# generate the projects.
# This can be done by the following command (assuming current directory):
# src\tools\gyp\gyp.bat src\client\windows\breakpad_client.gyp
hooks = [
{
# A change to a .gyp, .gypi, or to GYP itself should run the generator.
"pattern": ".",
"action": ["python",
"src/src/tools/gyp/gyp",
"src/src/client/windows/breakpad_client.gyp"],
},
]

View File

@@ -1,6 +1,6 @@
## Process this file with automake to produce Makefile.in
# Copyright (c) 2006, Google Inc.
# Copyright (c) 2010, Google Inc.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
@@ -33,6 +33,8 @@
# This allows #includes to be relative to src/
AM_CPPFLAGS = -I$(top_srcdir)/src
# Specify include paths for ac macros
ACLOCAL_AMFLAGS = -I m4
## Documentation
docdir = $(prefix)/share/doc/$(PACKAGE)-$(VERSION)
@@ -47,9 +49,34 @@ dist_doc_DATA = \
## Libraries
lib_LTLIBRARIES = src/libbreakpad.la
noinst_LIBRARIES =
lib_LIBRARIES =
bin_PROGRAMS =
check_PROGRAMS =
src_libbreakpad_la_SOURCES = \
if !DISABLE_PROCESSOR
lib_LIBRARIES += src/libbreakpad.a
noinst_LIBRARIES += src/third_party/libdisasm/libdisasm.a
endif
if LINUX_HOST
lib_LIBRARIES += src/client/linux/libbreakpad_client.a
src_client_linux_libbreakpad_client_a_SOURCES = \
src/client/linux/crash_generation/crash_generation_client.cc \
src/client/linux/handler/exception_handler.cc \
src/client/linux/minidump_writer/linux_dumper.cc \
src/client/linux/minidump_writer/minidump_writer.cc \
src/client/minidump_file_writer.cc \
src/common/convert_UTF.c \
src/common/md5.c \
src/common/string_conversion.cc \
src/common/linux/file_id.cc \
src/common/linux/guid_creator.cc
endif LINUX_HOST
if !DISABLE_PROCESSOR
src_libbreakpad_a_SOURCES = \
src/google_breakpad/common/breakpad_types.h \
src/google_breakpad/common/minidump_format.h \
src/google_breakpad/common/minidump_size.h \
@@ -57,10 +84,13 @@ src_libbreakpad_la_SOURCES = \
src/google_breakpad/processor/call_stack.h \
src/google_breakpad/processor/code_module.h \
src/google_breakpad/processor/code_modules.h \
src/google_breakpad/processor/exploitability.h \
src/google_breakpad/processor/fast_source_line_resolver.h \
src/google_breakpad/processor/memory_region.h \
src/google_breakpad/processor/minidump.h \
src/google_breakpad/processor/minidump_processor.h \
src/google_breakpad/processor/process_state.h \
src/google_breakpad/processor/source_line_resolver_base.h \
src/google_breakpad/processor/source_line_resolver_interface.h \
src/google_breakpad/processor/stack_frame.h \
src/google_breakpad/processor/stack_frame_cpu.h \
@@ -72,15 +102,34 @@ src_libbreakpad_la_SOURCES = \
src/processor/basic_code_module.h \
src/processor/basic_code_modules.cc \
src/processor/basic_code_modules.h \
src/processor/basic_source_line_resolver_types.h \
src/processor/basic_source_line_resolver.cc \
src/processor/binarystream.h \
src/processor/binarystream.cc \
src/processor/call_stack.cc \
src/processor/cfi_frame_info.cc \
src/processor/cfi_frame_info.h \
src/processor/contained_range_map-inl.h \
src/processor/contained_range_map.h \
src/processor/disassembler_x86.h \
src/processor/disassembler_x86.cc \
src/processor/exploitability.cc \
src/processor/exploitability_win.h \
src/processor/exploitability_win.cc \
src/processor/fast_source_line_resolver_types.h \
src/processor/fast_source_line_resolver.cc \
src/processor/linked_ptr.h \
src/processor/logging.h \
src/processor/logging.cc \
src/processor/map_serializers-inl.h \
src/processor/map_serializers.h \
src/processor/minidump.cc \
src/processor/minidump_processor.cc \
src/processor/module_comparer.cc \
src/processor/module_comparer.h \
src/processor/module_factory.h \
src/processor/module_serializer.cc \
src/processor/module_serializer.h \
src/processor/pathname_stripper.cc \
src/processor/pathname_stripper.h \
src/processor/postfix_evaluator-inl.h \
@@ -89,116 +138,621 @@ src_libbreakpad_la_SOURCES = \
src/processor/range_map-inl.h \
src/processor/range_map.h \
src/processor/scoped_ptr.h \
src/processor/simple_serializer-inl.h \
src/processor/simple_serializer.h \
src/processor/simple_symbol_supplier.cc \
src/processor/simple_symbol_supplier.h \
src/processor/stack_frame_info.h \
src/processor/windows_frame_info.h \
src/processor/source_line_resolver_base_types.h \
src/processor/source_line_resolver_base.cc \
src/processor/stackwalker.cc \
src/processor/stackwalker_amd64.cc \
src/processor/stackwalker_amd64.h \
src/processor/stackwalker_arm.cc \
src/processor/stackwalker_arm.h \
src/processor/stackwalker_ppc.cc \
src/processor/stackwalker_ppc.h \
src/processor/stackwalker_sparc.cc \
src/processor/stackwalker_sparc.h \
src/processor/stackwalker_x86.cc \
src/processor/stackwalker_x86.h
src/processor/stackwalker_x86.h \
src/processor/static_address_map-inl.h \
src/processor/static_address_map.h \
src/processor/static_contained_range_map-inl.h \
src/processor/static_contained_range_map.h \
src/processor/static_map_iterator-inl.h \
src/processor/static_map_iterator.h \
src/processor/static_map-inl.h \
src/processor/static_map.h \
src/processor/static_range_map-inl.h \
src/processor/static_range_map.h \
src/processor/tokenize.cc \
src/processor/tokenize.h
src_libbreakpad_a_LIBADD = src/third_party/libdisasm/libdisasm.a
src_third_party_libdisasm_libdisasm_a_SOURCES = \
src/third_party/libdisasm/ia32_implicit.c \
src/third_party/libdisasm/ia32_implicit.h \
src/third_party/libdisasm/ia32_insn.c \
src/third_party/libdisasm/ia32_insn.h \
src/third_party/libdisasm/ia32_invariant.c \
src/third_party/libdisasm/ia32_invariant.h \
src/third_party/libdisasm/ia32_modrm.c \
src/third_party/libdisasm/ia32_modrm.h \
src/third_party/libdisasm/ia32_opcode_tables.c \
src/third_party/libdisasm/ia32_opcode_tables.h \
src/third_party/libdisasm/ia32_operand.c \
src/third_party/libdisasm/ia32_operand.h \
src/third_party/libdisasm/ia32_reg.c \
src/third_party/libdisasm/ia32_reg.h \
src/third_party/libdisasm/ia32_settings.c \
src/third_party/libdisasm/ia32_settings.h \
src/third_party/libdisasm/libdis.h \
src/third_party/libdisasm/qword.h \
src/third_party/libdisasm/x86_disasm.c \
src/third_party/libdisasm/x86_format.c \
src/third_party/libdisasm/x86_imm.c \
src/third_party/libdisasm/x86_imm.h \
src/third_party/libdisasm/x86_insn.c \
src/third_party/libdisasm/x86_misc.c \
src/third_party/libdisasm/x86_operand_list.c \
src/third_party/libdisasm/x86_operand_list.h
## Programs
bin_PROGRAMS = \
bin_PROGRAMS += \
src/processor/minidump_dump \
src/processor/minidump_stackwalk
endif !DISABLE_PROCESSOR
if LINUX_HOST
bin_PROGRAMS += \
src/client/linux/linux_dumper_unittest_helper
if !DISABLE_TOOLS
bin_PROGRAMS += \
src/tools/linux/dump_syms/dump_syms \
src/tools/linux/md2core/minidump-2-core \
src/tools/linux/symupload/minidump_upload \
src/tools/linux/symupload/sym_upload
endif
endif LINUX_HOST
## Tests
check_PROGRAMS = \
if !DISABLE_PROCESSOR
check_PROGRAMS += \
src/common/test_assembler_unittest \
src/processor/address_map_unittest \
src/processor/binarystream_unittest \
src/processor/basic_source_line_resolver_unittest \
src/processor/cfi_frame_info_unittest \
src/processor/contained_range_map_unittest \
src/processor/disassembler_x86_unittest \
src/processor/exploitability_unittest \
src/processor/fast_source_line_resolver_unittest \
src/processor/map_serializers_unittest \
src/processor/minidump_processor_unittest \
src/processor/minidump_unittest \
src/processor/static_address_map_unittest \
src/processor/static_contained_range_map_unittest \
src/processor/static_map_unittest \
src/processor/static_range_map_unittest \
src/processor/pathname_stripper_unittest \
src/processor/postfix_evaluator_unittest \
src/processor/range_map_unittest
src/processor/range_map_unittest \
src/processor/stackwalker_amd64_unittest \
src/processor/stackwalker_arm_unittest \
src/processor/stackwalker_x86_unittest \
src/processor/synth_minidump_unittest
endif
if LINUX_HOST
check_PROGRAMS += \
src/client/linux/linux_client_unittest
if !DISABLE_TOOLS
check_PROGRAMS += \
src/common/dumper_unittest
endif
endif LINUX_HOST
if !DISABLE_PROCESSOR
if SELFTEST
check_PROGRAMS += \
src/processor/stackwalker_selftest
endif SELFTEST
endif !DISABLE_PROCESSOR
if !DISABLE_PROCESSOR
check_SCRIPTS = \
src/processor/minidump_dump_test \
src/processor/minidump_stackwalk_test \
src/processor/minidump_stackwalk_machine_readable_test
endif
TESTS = $(check_PROGRAMS) $(check_SCRIPTS)
TESTS_ENVIRONMENT =
if LINUX_HOST
src_client_linux_linux_dumper_unittest_helper_SOURCES = \
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_CC=$(PTHREAD_CC)
src_client_linux_linux_client_unittest_SOURCES = \
src/client/linux/handler/exception_handler_unittest.cc \
src/client/linux/minidump_writer/directory_reader_unittest.cc \
src/client/linux/minidump_writer/line_reader_unittest.cc \
src/client/linux/minidump_writer/linux_dumper_unittest.cc \
src/client/linux/minidump_writer/minidump_writer_unittest.cc \
src/common/memory_unittest.cc \
src/testing/gtest/src/gtest-all.cc \
src/testing/gtest/src/gtest_main.cc \
src/testing/src/gmock-all.cc \
src/processor/basic_code_modules.cc \
src/processor/logging.cc \
src/processor/minidump.cc \
src/processor/pathname_stripper.cc
src_client_linux_linux_client_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_client_linux_linux_client_unittest_LDADD = \
src/client/linux/handler/exception_handler.o \
src/client/linux/crash_generation/crash_generation_client.o \
src/client/linux/minidump_writer/linux_dumper.o \
src/client/linux/minidump_writer/minidump_writer.o \
src/client/minidump_file_writer.o \
src/common/convert_UTF.o \
src/common/md5.o \
src/common/linux/file_id.o \
src/common/linux/guid_creator.o \
src/common/string_conversion.o
src_client_linux_linux_client_unittest_DEPENDENCIES = src/client/linux/linux_dumper_unittest_helper src/client/linux/libbreakpad_client.a src/libbreakpad.a
if !DISABLE_TOOLS
src_tools_linux_dump_syms_dump_syms_SOURCES = \
src/common/dwarf_cfi_to_module.cc \
src/common/dwarf_cu_to_module.cc \
src/common/dwarf_line_to_module.cc \
src/common/language.cc \
src/common/module.cc \
src/common/stabs_reader.cc \
src/common/stabs_to_module.cc \
src/common/dwarf/bytereader.cc \
src/common/dwarf/dwarf2diehandler.cc \
src/common/dwarf/dwarf2reader.cc \
src/common/linux/dump_symbols.cc \
src/common/linux/elf_symbols_to_module.cc \
src/common/linux/file_id.cc \
src/tools/linux/dump_syms/dump_syms.cc
src_tools_linux_md2core_minidump_2_core_SOURCES = \
src/tools/linux/md2core/minidump-2-core.cc
src_tools_linux_symupload_minidump_upload_SOURCES = \
src/common/linux/http_upload.cc \
src/tools/linux/symupload/minidump_upload.cc
src_tools_linux_symupload_minidump_upload_LDFLAGS = -ldl
src_tools_linux_symupload_sym_upload_SOURCES = \
src/common/linux/http_upload.cc \
src/tools/linux/symupload/sym_upload.cc
src_tools_linux_symupload_sym_upload_LDFLAGS = -ldl
src_common_dumper_unittest_SOURCES = \
src/common/byte_cursor_unittest.cc \
src/common/dwarf_cfi_to_module.cc \
src/common/dwarf_cfi_to_module_unittest.cc \
src/common/dwarf_cu_to_module.cc \
src/common/dwarf_cu_to_module_unittest.cc \
src/common/dwarf_line_to_module.cc \
src/common/dwarf_line_to_module_unittest.cc \
src/common/language.cc \
src/common/module.cc \
src/common/module_unittest.cc \
src/common/stabs_reader.cc \
src/common/stabs_reader_unittest.cc \
src/common/stabs_to_module.cc \
src/common/stabs_to_module_unittest.cc \
src/common/test_assembler.cc \
src/common/dwarf/bytereader.cc \
src/common/dwarf/bytereader_unittest.cc \
src/common/dwarf/cfi_assembler.cc \
src/common/dwarf/dwarf2diehandler.cc \
src/common/dwarf/dwarf2diehandler_unittest.cc \
src/common/dwarf/dwarf2reader.cc \
src/common/dwarf/dwarf2reader_cfi_unittest.cc \
src/common/linux/dump_symbols.cc \
src/common/linux/dump_symbols_unittest.cc \
src/common/linux/elf_symbols_to_module.cc \
src/common/linux/elf_symbols_to_module_unittest.cc \
src/common/linux/synth_elf.cc \
src/common/linux/synth_elf_unittest.cc \
src/common/linux/file_id.cc \
src/common/linux/file_id_unittest.cc \
src/testing/gtest/src/gtest-all.cc \
src/testing/gtest/src/gtest_main.cc \
src/testing/src/gmock-all.cc
src_common_dumper_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
endif
endif LINUX_HOST
if !DISABLE_PROCESSOR
src_processor_address_map_unittest_SOURCES = \
src/processor/address_map_unittest.cc
src_processor_address_map_unittest_LDADD = \
src/processor/logging.lo \
src/processor/pathname_stripper.lo
src/processor/logging.o \
src/processor/pathname_stripper.o
src_processor_binarystream_unittest_SOURCES = \
src/processor/binarystream_unittest.cc \
src/testing/gtest/src/gtest-all.cc \
src/testing/src/gmock-all.cc
src_processor_binarystream_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_binarystream_unittest_LDADD = \
src/processor/binarystream.o
src_processor_basic_source_line_resolver_unittest_SOURCES = \
src/processor/basic_source_line_resolver_unittest.cc
src/processor/basic_source_line_resolver_unittest.cc \
src/testing/gtest/src/gtest-all.cc \
src/testing/src/gmock-all.cc
src_processor_basic_source_line_resolver_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_basic_source_line_resolver_unittest_LDADD = \
src/processor/basic_source_line_resolver.lo \
src/processor/pathname_stripper.lo \
src/processor/logging.lo
src/processor/basic_source_line_resolver.o \
src/processor/cfi_frame_info.o \
src/processor/pathname_stripper.o \
src/processor/logging.o \
src/processor/source_line_resolver_base.o \
src/processor/tokenize.o
src_processor_cfi_frame_info_unittest_SOURCES = \
src/processor/cfi_frame_info_unittest.cc \
src/testing/gtest/src/gtest-all.cc \
src/testing/gtest/src/gtest_main.cc \
src/testing/src/gmock-all.cc
src_processor_cfi_frame_info_unittest_LDADD = \
src/processor/cfi_frame_info.o \
src/processor/logging.o \
src/processor/pathname_stripper.o
src_processor_cfi_frame_info_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_contained_range_map_unittest_SOURCES = \
src/processor/contained_range_map_unittest.cc
src_processor_contained_range_map_unittest_LDADD = \
src/processor/logging.lo \
src/processor/pathname_stripper.lo
src/processor/logging.o \
src/processor/pathname_stripper.o
src_processor_exploitability_unittest_SOURCES = \
src/processor/exploitability_unittest.cc \
src/testing/gtest/src/gtest-all.cc \
src/testing/gtest/src/gtest_main.cc \
src/testing/src/gmock-all.cc
src_processor_exploitability_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_exploitability_unittest_LDADD = \
src/processor/minidump_processor.o \
src/processor/process_state.o \
src/processor/disassembler_x86.o \
src/processor/exploitability.o \
src/processor/exploitability_win.o \
src/processor/basic_code_modules.o \
src/processor/basic_source_line_resolver.o \
src/processor/call_stack.o \
src/processor/cfi_frame_info.o \
src/processor/logging.o \
src/processor/minidump.o \
src/processor/pathname_stripper.o \
src/processor/source_line_resolver_base.o \
src/processor/stackwalker.o \
src/processor/stackwalker_amd64.o \
src/processor/stackwalker_arm.o \
src/processor/stackwalker_ppc.o \
src/processor/stackwalker_sparc.o \
src/processor/stackwalker_x86.o \
src/processor/tokenize.o \
src/third_party/libdisasm/libdisasm.a
src_processor_disassembler_x86_unittest_SOURCES = \
src/processor/disassembler_x86_unittest.cc \
src/testing/gtest/src/gtest-all.cc \
src/testing/gtest/src/gtest_main.cc \
src/testing/src/gmock-all.cc
src_processor_disassembler_x86_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_disassembler_x86_unittest_LDADD = \
src/processor/disassembler_x86.o \
src/third_party/libdisasm/libdisasm.a
src_processor_fast_source_line_resolver_unittest_SOURCES = \
src/processor/fast_source_line_resolver_unittest.cc \
src/testing/gtest/src/gtest-all.cc \
src/testing/src/gmock-all.cc
src_processor_fast_source_line_resolver_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_fast_source_line_resolver_unittest_LDADD = \
src/processor/fast_source_line_resolver.o \
src/processor/basic_source_line_resolver.o \
src/processor/cfi_frame_info.o \
src/processor/module_comparer.o \
src/processor/module_serializer.o \
src/processor/pathname_stripper.o \
src/processor/logging.o \
src/processor/source_line_resolver_base.o \
src/processor/tokenize.o
src_processor_map_serializers_unittest_SOURCES = \
src/processor/map_serializers_unittest.cc \
src/testing/gtest/src/gtest-all.cc \
src/testing/src/gmock-all.cc
src_processor_map_serializers_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_map_serializers_unittest_LDADD = \
src/processor/logging.o \
src/processor/pathname_stripper.o
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/src/gmock-all.cc
src_processor_minidump_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_minidump_processor_unittest_LDADD = \
src/processor/basic_code_modules.lo \
src/processor/basic_source_line_resolver.lo \
src/processor/call_stack.lo \
src/processor/logging.lo \
src/processor/minidump_processor.lo \
src/processor/minidump.lo \
src/processor/pathname_stripper.lo \
src/processor/process_state.lo \
src/processor/stackwalker.lo \
src/processor/stackwalker_amd64.lo \
src/processor/stackwalker_ppc.lo \
src/processor/stackwalker_sparc.lo \
src/processor/stackwalker_x86.lo
src/processor/basic_code_modules.o \
src/processor/basic_source_line_resolver.o \
src/processor/call_stack.o \
src/processor/cfi_frame_info.o \
src/processor/disassembler_x86.o \
src/processor/exploitability.o \
src/processor/exploitability_win.o \
src/processor/logging.o \
src/processor/minidump_processor.o \
src/processor/minidump.o \
src/processor/pathname_stripper.o \
src/processor/process_state.o \
src/processor/source_line_resolver_base.o \
src/processor/stackwalker.o \
src/processor/stackwalker_amd64.o \
src/processor/stackwalker_arm.o \
src/processor/stackwalker_ppc.o \
src/processor/stackwalker_sparc.o \
src/processor/stackwalker_x86.o \
src/processor/tokenize.o \
src/third_party/libdisasm/libdisasm.a
src_processor_minidump_unittest_SOURCES = \
src/common/test_assembler.cc \
src/processor/minidump_unittest.cc \
src/processor/synth_minidump.cc \
src/testing/gtest/src/gtest-all.cc \
src/testing/gtest/src/gtest_main.cc \
src/testing/src/gmock-all.cc
src_processor_minidump_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_minidump_unittest_LDADD = \
src/processor/basic_code_modules.o \
src/processor/logging.o \
src/processor/minidump.o \
src/processor/pathname_stripper.o
src_processor_static_address_map_unittest_SOURCES = \
src/processor/static_address_map_unittest.cc \
src/testing/gtest/src/gtest-all.cc \
src/testing/src/gmock-all.cc
src_processor_static_address_map_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_static_address_map_unittest_LDADD = \
src/processor/logging.o \
src/processor/pathname_stripper.o
src_processor_static_contained_range_map_unittest_SOURCES = \
src/processor/static_contained_range_map_unittest.cc \
src/testing/gtest/src/gtest-all.cc \
src/testing/src/gmock-all.cc
src_processor_static_contained_range_map_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_static_contained_range_map_unittest_LDADD = \
src/processor/logging.o \
src/processor/pathname_stripper.o
src_processor_static_map_unittest_SOURCES = \
src/processor/static_map_unittest.cc \
src/testing/gtest/src/gtest-all.cc \
src/testing/src/gmock-all.cc
src_processor_static_map_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_static_map_unittest_LDADD = \
src/processor/logging.o \
src/processor/pathname_stripper.o
src_processor_static_range_map_unittest_SOURCES = \
src/processor/static_range_map_unittest.cc \
src/testing/gtest/src/gtest-all.cc \
src/testing/src/gmock-all.cc
src_processor_static_range_map_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_static_range_map_unittest_LDADD = \
src/processor/logging.o \
src/processor/pathname_stripper.o
src_processor_pathname_stripper_unittest_SOURCES = \
src/processor/pathname_stripper_unittest.cc
src_processor_pathname_stripper_unittest_LDADD = \
src/processor/pathname_stripper.lo
src/processor/pathname_stripper.o
src_processor_postfix_evaluator_unittest_SOURCES = \
src/processor/postfix_evaluator_unittest.cc
src_processor_postfix_evaluator_unittest_LDADD = \
src/processor/logging.lo \
src/processor/pathname_stripper.lo
src/processor/logging.o \
src/processor/pathname_stripper.o
src_processor_range_map_unittest_SOURCES = \
src/processor/range_map_unittest.cc
src_processor_range_map_unittest_LDADD = \
src/processor/logging.lo \
src/processor/pathname_stripper.lo
src/processor/logging.o \
src/processor/pathname_stripper.o
src_processor_stackwalker_selftest_SOURCES = \
src/processor/stackwalker_selftest.cc
src_processor_stackwalker_selftest_LDADD = \
src/processor/basic_code_modules.lo \
src/processor/basic_source_line_resolver.lo \
src/processor/call_stack.lo \
src/processor/logging.lo \
src/processor/minidump.lo \
src/processor/pathname_stripper.lo \
src/processor/stackwalker.lo \
src/processor/stackwalker_amd64.lo \
src/processor/stackwalker_ppc.lo \
src/processor/stackwalker_sparc.lo \
src/processor/stackwalker_x86.lo
src/processor/basic_code_modules.o \
src/processor/basic_source_line_resolver.o \
src/processor/call_stack.o \
src/processor/disassembler_x86.o \
src/processor/exploitability.o \
src/processor/exploitability_win.o \
src/processor/logging.o \
src/processor/minidump.o \
src/processor/pathname_stripper.o \
src/processor/source_line_resolver_base.o \
src/processor/stackwalker.o \
src/processor/stackwalker_amd64.o \
src/processor/stackwalker_arm.o \
src/processor/stackwalker_ppc.o \
src/processor/stackwalker_sparc.o \
src/processor/stackwalker_x86.o \
src/processor/tokenize.o
src_processor_stackwalker_amd64_unittest_SOURCES = \
src/common/test_assembler.cc \
src/processor/stackwalker_amd64_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_amd64_unittest_LDADD = \
src/libbreakpad.a
src_processor_stackwalker_amd64_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_arm_unittest_SOURCES = \
src/common/test_assembler.cc \
src/processor/stackwalker_arm_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_arm_unittest_LDADD = \
src/libbreakpad.a
src_processor_stackwalker_arm_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/common/test_assembler.cc \
src/processor/stackwalker_x86_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_x86_unittest_LDADD = \
src/libbreakpad.a
src_processor_stackwalker_x86_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_synth_minidump_unittest_SOURCES = \
src/common/test_assembler.cc \
src/common/test_assembler.h \
src/processor/synth_minidump_unittest.cc \
src/testing/gtest/src/gtest-all.cc \
src/testing/gtest/src/gtest_main.cc \
src/testing/src/gmock-all.cc \
src/processor/synth_minidump.cc \
src/processor/synth_minidump.h
src_processor_synth_minidump_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_common_test_assembler_unittest_SOURCES = \
src/common/test_assembler.cc \
src/common/test_assembler.h \
src/common/test_assembler_unittest.cc \
src/testing/gtest/src/gtest-all.cc \
src/testing/gtest/src/gtest_main.cc \
src/testing/src/gmock-all.cc
src_common_test_assembler_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
## Non-installables
noinst_PROGRAMS =
@@ -207,29 +761,39 @@ noinst_SCRIPTS = $(check_SCRIPTS)
src_processor_minidump_dump_SOURCES = \
src/processor/minidump_dump.cc
src_processor_minidump_dump_LDADD = \
src/processor/basic_code_modules.lo \
src/processor/logging.lo \
src/processor/minidump.lo \
src/processor/pathname_stripper.lo
src/processor/basic_code_modules.o \
src/processor/logging.o \
src/processor/minidump.o \
src/processor/pathname_stripper.o
src_processor_minidump_stackwalk_SOURCES = \
src/processor/minidump_stackwalk.cc
src_processor_minidump_stackwalk_LDADD = \
src/processor/basic_code_modules.lo \
src/processor/basic_source_line_resolver.lo \
src/processor/call_stack.lo \
src/processor/logging.lo \
src/processor/minidump.lo \
src/processor/minidump_processor.lo \
src/processor/pathname_stripper.lo \
src/processor/process_state.lo \
src/processor/simple_symbol_supplier.lo \
src/processor/stackwalker.lo \
src/processor/stackwalker_amd64.lo \
src/processor/stackwalker_ppc.lo \
src/processor/stackwalker_sparc.lo \
src/processor/stackwalker_x86.lo
src/processor/basic_code_modules.o \
src/processor/basic_source_line_resolver.o \
src/processor/binarystream.o \
src/processor/call_stack.o \
src/processor/cfi_frame_info.o \
src/processor/disassembler_x86.o \
src/processor/exploitability.o \
src/processor/exploitability_win.o \
src/processor/logging.o \
src/processor/minidump.o \
src/processor/minidump_processor.o \
src/processor/pathname_stripper.o \
src/processor/process_state.o \
src/processor/simple_symbol_supplier.o \
src/processor/source_line_resolver_base.o \
src/processor/stackwalker.o \
src/processor/stackwalker_amd64.o \
src/processor/stackwalker_arm.o \
src/processor/stackwalker_ppc.o \
src/processor/stackwalker_sparc.o \
src/processor/stackwalker_x86.o \
src/processor/tokenize.o \
src/third_party/libdisasm/libdisasm.a
endif !DISABLE_PROCESSOR
## Additional files to be included in a source distribution
##
@@ -284,6 +848,8 @@ EXTRA_DIST = \
src/common/convert_UTF.h \
src/common/linux/dump_symbols.cc \
src/common/linux/dump_symbols.h \
src/common/linux/elf_symbols_to_module.cc \
src/common/linux/elf_symbols_to_module.h \
src/common/linux/file_id.cc \
src/common/linux/file_id.h \
src/common/linux/guid_creator.cc \
@@ -366,8 +932,3 @@ EXTRA_DIST = \
src/tools/windows/dump_syms/testdata/dump_syms_regtest.sym \
src/tools/windows/symupload/symupload.cc \
src/tools/windows/symupload/symupload.vcproj
## Additional rules
libtool: $(LIBTOOL_DEPS)
$(SHELL) ./config.status --recheck

File diff suppressed because it is too large Load Diff

41
README
View File

@@ -1,2 +1,43 @@
Breakpad is a set of client and server components which implement a
crash-reporting system.
-----
Getting started in 32-bit mode (from trunk)
Configure: CXXFLAGS=-m32 CFLAGS=-m32 CPPFLAGS=-m32 ./configure
Build: make
Test: make check
Install: make install
If you need to reconfigure your build be sure to run "make distclean" first.
-----
To request change review:
0. Get access to a read-write copy of source.
Owners at http://code.google.com/p/google-breakpad/ are able to grant
this access.
1. Check out a read-write copy of source using instructions at
http://code.google.com/p/google-breakpad/source/checkout
2. Make changes. Build and test your changes.
For core code like processor use methods above.
For linux/mac/windows, there are test targets in each project file.
3. Download http://codereview.appspot.com/static/upload.py
4. Run upload.py from the 'src' directory:
upload.py --server=breakpad.appspot.com
You will be prompted for credential and a description.
5. At http://breakpad.appspot.com you'll find your issue listed; click on it,
and select Publish+Mail, and enter in the code reviewer and CC
google-breakpad-dev@googlegroups.com
6. When applying code review feedback, specify the '-i' option when running
upload.py again and pass the issue number so it updates the existing issue,
rather than creating a new one.
Be sure to rerun upload.py from the same directory as you did for previous
uploads to allow for proper diff calculations.

6731
aclocal.m4 vendored

File diff suppressed because it is too large Load Diff

1
autotools/compile Symbolic link
View File

@@ -0,0 +1 @@
/usr/share/automake-1.11/compile

File diff suppressed because it is too large Load Diff

5
codereview.settings Normal file
View 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=

20454
configure vendored

File diff suppressed because it is too large Load Diff

View File

@@ -30,22 +30,93 @@
AC_PREREQ(2.57)
AC_INIT(breakpad, 0.1, opensource@google.com)
AC_INIT(breakpad, 0.1, google-breakpad-dev@googlegroups.com)
dnl Sanity check: the argument is just a file that should exist.
AC_CONFIG_SRCDIR(README)
AC_CONFIG_AUX_DIR(autotools)
AC_CONFIG_MACRO_DIR([m4])
AC_CANONICAL_HOST
AM_INIT_AUTOMAKE(subdir-objects tar-ustar)
AM_INIT_AUTOMAKE(subdir-objects tar-ustar 1.11.1)
AM_CONFIG_HEADER(src/config.h)
AC_PROG_CC
AM_PROG_CC_C_O
AC_PROG_CPP
AC_PROG_CXX
AC_PROG_LIBTOOL
AC_SUBST(LIBTOOL_DEPS)
AC_PROG_RANLIB
AC_HEADER_STDC
m4_include(m4/ax_pthread.m4)
AX_PTHREAD
AC_CHECK_HEADERS([a.out.h])
# Only build Linux client libs when compiling for Linux
case $host in
*-*-linux* | *-android* )
LINUX_HOST=true
;;
esac
AM_CONDITIONAL(LINUX_HOST, test x$LINUX_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,
AS_HELP_STRING([--disable-processor],
[Don't build processor library]
[(default is no)]),
[case "${enableval}" in
yes)
disable_processor=false
;;
no)
disable_processor=true
;;
*)
AC_MSG_ERROR(bad value ${enableval} for --disable-processor)
;;
esac],
[disable_processor=false])
AM_CONDITIONAL(DISABLE_PROCESSOR, test x$disable_processor = xtrue)
AC_ARG_ENABLE(tools,
AS_HELP_STRING([--disable-tools],
[Don't build tool binaries]
[(default is no)]),
[case "${enableval}" in
yes)
disable_tools=false
;;
no)
disable_tools=true
;;
*)
AC_MSG_ERROR(bad value ${enableval} for --disable-tools)
;;
esac],
[disable_tools=false])
AM_CONDITIONAL(DISABLE_TOOLS, test x$disable_tools = xtrue)
if test x$LINUX_HOST = xfalse -a x$disable_processor = xtrue -a x$disable_tools = xtrue; then
AC_MSG_ERROR([--disable-processor and --disable-tools were specified, and not building for Linux. Nothing to build!])
fi
AC_ARG_ENABLE(selftest,
AS_HELP_STRING([--enable-selftest],

283
m4/ax_pthread.m4 Normal file
View File

@@ -0,0 +1,283 @@
# ===========================================================================
# http://www.nongnu.org/autoconf-archive/ax_pthread.html
# ===========================================================================
#
# SYNOPSIS
#
# AX_PTHREAD([ACTION-IF-FOUND[, ACTION-IF-NOT-FOUND]])
#
# DESCRIPTION
#
# This macro figures out how to build C programs using POSIX threads. It
# sets the PTHREAD_LIBS output variable to the threads library and linker
# flags, and the PTHREAD_CFLAGS output variable to any special C compiler
# flags that are needed. (The user can also force certain compiler
# flags/libs to be tested by setting these environment variables.)
#
# Also sets PTHREAD_CC to any special C compiler that is needed for
# multi-threaded programs (defaults to the value of CC otherwise). (This
# is necessary on AIX to use the special cc_r compiler alias.)
#
# NOTE: You are assumed to not only compile your program with these flags,
# but also link it with them as well. e.g. you should link with
# $PTHREAD_CC $CFLAGS $PTHREAD_CFLAGS $LDFLAGS ... $PTHREAD_LIBS $LIBS
#
# If you are only building threads programs, you may wish to use these
# variables in your default LIBS, CFLAGS, and CC:
#
# LIBS="$PTHREAD_LIBS $LIBS"
# CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
# CC="$PTHREAD_CC"
#
# In addition, if the PTHREAD_CREATE_JOINABLE thread-attribute constant
# has a nonstandard name, defines PTHREAD_CREATE_JOINABLE to that name
# (e.g. PTHREAD_CREATE_UNDETACHED on AIX).
#
# ACTION-IF-FOUND is a list of shell commands to run if a threads library
# is found, and ACTION-IF-NOT-FOUND is a list of commands to run it if it
# is not found. If ACTION-IF-FOUND is not specified, the default action
# will define HAVE_PTHREAD.
#
# Please let the authors know if this macro fails on any platform, or if
# you have any other suggestions or comments. This macro was based on work
# by SGJ on autoconf scripts for FFTW (http://www.fftw.org/) (with help
# from M. Frigo), as well as ac_pthread and hb_pthread macros posted by
# Alejandro Forero Cuervo to the autoconf macro repository. We are also
# grateful for the helpful feedback of numerous users.
#
# LICENSE
#
# Copyright (c) 2008 Steven G. Johnson <stevenj@alum.mit.edu>
#
# 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 3 of the License, 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, the respective Autoconf Macro's copyright owner
# gives unlimited permission to copy, distribute and modify the configure
# scripts that are the output of Autoconf when processing the Macro. You
# need not follow the terms of the GNU General Public License when using
# or distributing such scripts, even though portions of the text of the
# Macro appear in them. The GNU General Public License (GPL) does govern
# all other use of the material that constitutes the Autoconf Macro.
#
# This special exception to the GPL applies to versions of the Autoconf
# Macro released by the Autoconf Archive. When you make and distribute a
# modified version of the Autoconf Macro, you may extend this special
# exception to the GPL to apply to your modified version as well.
#serial 6
AU_ALIAS([ACX_PTHREAD], [AX_PTHREAD])
AC_DEFUN([AX_PTHREAD], [
AC_REQUIRE([AC_CANONICAL_HOST])
AC_LANG_SAVE
AC_LANG_C
ax_pthread_ok=no
# We used to check for pthread.h first, but this fails if pthread.h
# requires special compiler flags (e.g. on True64 or Sequent).
# It gets checked for in the link test anyway.
# First of all, check if the user has set any of the PTHREAD_LIBS,
# etcetera environment variables, and if threads linking works using
# them:
if test x"$PTHREAD_LIBS$PTHREAD_CFLAGS" != x; then
save_CFLAGS="$CFLAGS"
CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
save_LIBS="$LIBS"
LIBS="$PTHREAD_LIBS $LIBS"
AC_MSG_CHECKING([for pthread_join in LIBS=$PTHREAD_LIBS with CFLAGS=$PTHREAD_CFLAGS])
AC_TRY_LINK_FUNC(pthread_join, ax_pthread_ok=yes)
AC_MSG_RESULT($ax_pthread_ok)
if test x"$ax_pthread_ok" = xno; then
PTHREAD_LIBS=""
PTHREAD_CFLAGS=""
fi
LIBS="$save_LIBS"
CFLAGS="$save_CFLAGS"
fi
# We must check for the threads library under a number of different
# names; the ordering is very important because some systems
# (e.g. DEC) have both -lpthread and -lpthreads, where one of the
# libraries is broken (non-POSIX).
# Create a list of thread flags to try. Items starting with a "-" are
# C compiler flags, and other items are library names, except for "none"
# which indicates that we try without any flags at all, and "pthread-config"
# which is a program returning the flags for the Pth emulation library.
ax_pthread_flags="pthreads none -Kthread -kthread lthread -pthread -pthreads -mthreads pthread --thread-safe -mt pthread-config"
# The ordering *is* (sometimes) important. Some notes on the
# individual items follow:
# pthreads: AIX (must check this before -lpthread)
# none: in case threads are in libc; should be tried before -Kthread and
# other compiler flags to prevent continual compiler warnings
# -Kthread: Sequent (threads in libc, but -Kthread needed for pthread.h)
# -kthread: FreeBSD kernel threads (preferred to -pthread since SMP-able)
# lthread: LinuxThreads port on FreeBSD (also preferred to -pthread)
# -pthread: Linux/gcc (kernel threads), BSD/gcc (userland threads)
# -pthreads: Solaris/gcc
# -mthreads: Mingw32/gcc, Lynx/gcc
# -mt: Sun Workshop C (may only link SunOS threads [-lthread], but it
# doesn't hurt to check since this sometimes defines pthreads too;
# also defines -D_REENTRANT)
# ... -mt is also the pthreads flag for HP/aCC
# pthread: Linux, etcetera
# --thread-safe: KAI C++
# pthread-config: use pthread-config program (for GNU Pth library)
case "${host_cpu}-${host_os}" in
*solaris*)
# On Solaris (at least, for some versions), libc contains stubbed
# (non-functional) versions of the pthreads routines, so link-based
# tests will erroneously succeed. (We need to link with -pthreads/-mt/
# -lpthread.) (The stubs are missing pthread_cleanup_push, or rather
# a function called by this macro, so we could check for that, but
# who knows whether they'll stub that too in a future libc.) So,
# we'll just look for -pthreads and -lpthread first:
ax_pthread_flags="-pthreads pthread -mt -pthread $ax_pthread_flags"
;;
*-darwin*)
acx_pthread_flags="-pthread $acx_pthread_flags"
;;
esac
if test x"$ax_pthread_ok" = xno; then
for flag in $ax_pthread_flags; do
case $flag in
none)
AC_MSG_CHECKING([whether pthreads work without any flags])
;;
-*)
AC_MSG_CHECKING([whether pthreads work with $flag])
PTHREAD_CFLAGS="$flag"
;;
pthread-config)
AC_CHECK_PROG(ax_pthread_config, pthread-config, yes, no)
if test x"$ax_pthread_config" = xno; then continue; fi
PTHREAD_CFLAGS="`pthread-config --cflags`"
PTHREAD_LIBS="`pthread-config --ldflags` `pthread-config --libs`"
;;
*)
AC_MSG_CHECKING([for the pthreads library -l$flag])
PTHREAD_LIBS="-l$flag"
;;
esac
save_LIBS="$LIBS"
save_CFLAGS="$CFLAGS"
LIBS="$PTHREAD_LIBS $LIBS"
CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
# Check for various functions. We must include pthread.h,
# since some functions may be macros. (On the Sequent, we
# need a special flag -Kthread to make this header compile.)
# We check for pthread_join because it is in -lpthread on IRIX
# while pthread_create is in libc. We check for pthread_attr_init
# due to DEC craziness with -lpthreads. We check for
# pthread_cleanup_push because it is one of the few pthread
# functions on Solaris that doesn't have a non-functional libc stub.
# We try pthread_create on general principles.
AC_TRY_LINK([#include <pthread.h>
static void routine(void* a) {a=0;}
static void* start_routine(void* a) {return a;}],
[pthread_t th; pthread_attr_t attr;
pthread_join(th, 0);
pthread_attr_init(&attr);
pthread_cleanup_push(routine, 0);
pthread_create(&th,0,start_routine,0);
pthread_cleanup_pop(0); ],
[ax_pthread_ok=yes])
LIBS="$save_LIBS"
CFLAGS="$save_CFLAGS"
AC_MSG_RESULT($ax_pthread_ok)
if test "x$ax_pthread_ok" = xyes; then
break;
fi
PTHREAD_LIBS=""
PTHREAD_CFLAGS=""
done
fi
# Various other checks:
if test "x$ax_pthread_ok" = xyes; then
save_LIBS="$LIBS"
LIBS="$PTHREAD_LIBS $LIBS"
save_CFLAGS="$CFLAGS"
CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
# Detect AIX lossage: JOINABLE attribute is called UNDETACHED.
AC_MSG_CHECKING([for joinable pthread attribute])
attr_name=unknown
for attr in PTHREAD_CREATE_JOINABLE PTHREAD_CREATE_UNDETACHED; do
AC_TRY_LINK([#include <pthread.h>], [int attr=$attr; return attr;],
[attr_name=$attr; break])
done
AC_MSG_RESULT($attr_name)
if test "$attr_name" != PTHREAD_CREATE_JOINABLE; then
AC_DEFINE_UNQUOTED(PTHREAD_CREATE_JOINABLE, $attr_name,
[Define to necessary symbol if this constant
uses a non-standard name on your system.])
fi
AC_MSG_CHECKING([if more special flags are required for pthreads])
flag=no
case "${host_cpu}-${host_os}" in
*-aix* | *-freebsd* | *-darwin*) flag="-D_THREAD_SAFE";;
*solaris* | *-osf* | *-hpux*) flag="-D_REENTRANT";;
esac
AC_MSG_RESULT(${flag})
if test "x$flag" != xno; then
PTHREAD_CFLAGS="$flag $PTHREAD_CFLAGS"
fi
LIBS="$save_LIBS"
CFLAGS="$save_CFLAGS"
# More AIX lossage: must compile with xlc_r or cc_r
if test x"$GCC" != xyes; then
AC_CHECK_PROGS(PTHREAD_CC, xlc_r cc_r, ${CC})
else
PTHREAD_CC=$CC
fi
else
PTHREAD_CC="$CC"
fi
AC_SUBST(PTHREAD_LIBS)
AC_SUBST(PTHREAD_CFLAGS)
AC_SUBST(PTHREAD_CC)
# Finally, execute ACTION-IF-FOUND/ACTION-IF-NOT-FOUND:
if test x"$ax_pthread_ok" = xyes; then
ifelse([$1],,AC_DEFINE(HAVE_PTHREAD,1,[Define if you have POSIX threads libraries and header files.]),[$1])
:
else
ax_pthread_ok=no
$2
fi
AC_LANG_RESTORE
])dnl AX_PTHREAD

7377
m4/libtool.m4 vendored Normal file

File diff suppressed because it is too large Load Diff

368
m4/ltoptions.m4 vendored Normal file
View File

@@ -0,0 +1,368 @@
# Helper functions for option handling. -*- Autoconf -*-
#
# Copyright (C) 2004, 2005, 2007, 2008 Free Software Foundation, Inc.
# Written by Gary V. Vaughan, 2004
#
# This file is free software; the Free Software Foundation gives
# unlimited permission to copy and/or distribute it, with or without
# modifications, as long as this notice is preserved.
# serial 6 ltoptions.m4
# This is to help aclocal find these macros, as it can't see m4_define.
AC_DEFUN([LTOPTIONS_VERSION], [m4_if([1])])
# _LT_MANGLE_OPTION(MACRO-NAME, OPTION-NAME)
# ------------------------------------------
m4_define([_LT_MANGLE_OPTION],
[[_LT_OPTION_]m4_bpatsubst($1__$2, [[^a-zA-Z0-9_]], [_])])
# _LT_SET_OPTION(MACRO-NAME, OPTION-NAME)
# ---------------------------------------
# Set option OPTION-NAME for macro MACRO-NAME, and if there is a
# matching handler defined, dispatch to it. Other OPTION-NAMEs are
# saved as a flag.
m4_define([_LT_SET_OPTION],
[m4_define(_LT_MANGLE_OPTION([$1], [$2]))dnl
m4_ifdef(_LT_MANGLE_DEFUN([$1], [$2]),
_LT_MANGLE_DEFUN([$1], [$2]),
[m4_warning([Unknown $1 option `$2'])])[]dnl
])
# _LT_IF_OPTION(MACRO-NAME, OPTION-NAME, IF-SET, [IF-NOT-SET])
# ------------------------------------------------------------
# Execute IF-SET if OPTION is set, IF-NOT-SET otherwise.
m4_define([_LT_IF_OPTION],
[m4_ifdef(_LT_MANGLE_OPTION([$1], [$2]), [$3], [$4])])
# _LT_UNLESS_OPTIONS(MACRO-NAME, OPTION-LIST, IF-NOT-SET)
# -------------------------------------------------------
# Execute IF-NOT-SET unless all options in OPTION-LIST for MACRO-NAME
# are set.
m4_define([_LT_UNLESS_OPTIONS],
[m4_foreach([_LT_Option], m4_split(m4_normalize([$2])),
[m4_ifdef(_LT_MANGLE_OPTION([$1], _LT_Option),
[m4_define([$0_found])])])[]dnl
m4_ifdef([$0_found], [m4_undefine([$0_found])], [$3
])[]dnl
])
# _LT_SET_OPTIONS(MACRO-NAME, OPTION-LIST)
# ----------------------------------------
# OPTION-LIST is a space-separated list of Libtool options associated
# with MACRO-NAME. If any OPTION has a matching handler declared with
# LT_OPTION_DEFINE, dispatch to that macro; otherwise complain about
# the unknown option and exit.
m4_defun([_LT_SET_OPTIONS],
[# Set options
m4_foreach([_LT_Option], m4_split(m4_normalize([$2])),
[_LT_SET_OPTION([$1], _LT_Option)])
m4_if([$1],[LT_INIT],[
dnl
dnl Simply set some default values (i.e off) if boolean options were not
dnl specified:
_LT_UNLESS_OPTIONS([LT_INIT], [dlopen], [enable_dlopen=no
])
_LT_UNLESS_OPTIONS([LT_INIT], [win32-dll], [enable_win32_dll=no
])
dnl
dnl If no reference was made to various pairs of opposing options, then
dnl we run the default mode handler for the pair. For example, if neither
dnl `shared' nor `disable-shared' was passed, we enable building of shared
dnl archives by default:
_LT_UNLESS_OPTIONS([LT_INIT], [shared disable-shared], [_LT_ENABLE_SHARED])
_LT_UNLESS_OPTIONS([LT_INIT], [static disable-static], [_LT_ENABLE_STATIC])
_LT_UNLESS_OPTIONS([LT_INIT], [pic-only no-pic], [_LT_WITH_PIC])
_LT_UNLESS_OPTIONS([LT_INIT], [fast-install disable-fast-install],
[_LT_ENABLE_FAST_INSTALL])
])
])# _LT_SET_OPTIONS
## --------------------------------- ##
## Macros to handle LT_INIT options. ##
## --------------------------------- ##
# _LT_MANGLE_DEFUN(MACRO-NAME, OPTION-NAME)
# -----------------------------------------
m4_define([_LT_MANGLE_DEFUN],
[[_LT_OPTION_DEFUN_]m4_bpatsubst(m4_toupper([$1__$2]), [[^A-Z0-9_]], [_])])
# LT_OPTION_DEFINE(MACRO-NAME, OPTION-NAME, CODE)
# -----------------------------------------------
m4_define([LT_OPTION_DEFINE],
[m4_define(_LT_MANGLE_DEFUN([$1], [$2]), [$3])[]dnl
])# LT_OPTION_DEFINE
# dlopen
# ------
LT_OPTION_DEFINE([LT_INIT], [dlopen], [enable_dlopen=yes
])
AU_DEFUN([AC_LIBTOOL_DLOPEN],
[_LT_SET_OPTION([LT_INIT], [dlopen])
AC_DIAGNOSE([obsolete],
[$0: Remove this warning and the call to _LT_SET_OPTION when you
put the `dlopen' option into LT_INIT's first parameter.])
])
dnl aclocal-1.4 backwards compatibility:
dnl AC_DEFUN([AC_LIBTOOL_DLOPEN], [])
# win32-dll
# ---------
# Declare package support for building win32 dll's.
LT_OPTION_DEFINE([LT_INIT], [win32-dll],
[enable_win32_dll=yes
case $host in
*-*-cygwin* | *-*-mingw* | *-*-pw32* | *-cegcc*)
AC_CHECK_TOOL(AS, as, false)
AC_CHECK_TOOL(DLLTOOL, dlltool, false)
AC_CHECK_TOOL(OBJDUMP, objdump, false)
;;
esac
test -z "$AS" && AS=as
_LT_DECL([], [AS], [0], [Assembler program])dnl
test -z "$DLLTOOL" && DLLTOOL=dlltool
_LT_DECL([], [DLLTOOL], [0], [DLL creation program])dnl
test -z "$OBJDUMP" && OBJDUMP=objdump
_LT_DECL([], [OBJDUMP], [0], [Object dumper program])dnl
])# win32-dll
AU_DEFUN([AC_LIBTOOL_WIN32_DLL],
[AC_REQUIRE([AC_CANONICAL_HOST])dnl
_LT_SET_OPTION([LT_INIT], [win32-dll])
AC_DIAGNOSE([obsolete],
[$0: Remove this warning and the call to _LT_SET_OPTION when you
put the `win32-dll' option into LT_INIT's first parameter.])
])
dnl aclocal-1.4 backwards compatibility:
dnl AC_DEFUN([AC_LIBTOOL_WIN32_DLL], [])
# _LT_ENABLE_SHARED([DEFAULT])
# ----------------------------
# implement the --enable-shared flag, and supports the `shared' and
# `disable-shared' LT_INIT options.
# DEFAULT is either `yes' or `no'. If omitted, it defaults to `yes'.
m4_define([_LT_ENABLE_SHARED],
[m4_define([_LT_ENABLE_SHARED_DEFAULT], [m4_if($1, no, no, yes)])dnl
AC_ARG_ENABLE([shared],
[AS_HELP_STRING([--enable-shared@<:@=PKGS@:>@],
[build shared libraries @<:@default=]_LT_ENABLE_SHARED_DEFAULT[@:>@])],
[p=${PACKAGE-default}
case $enableval in
yes) enable_shared=yes ;;
no) enable_shared=no ;;
*)
enable_shared=no
# Look at the argument we got. We use all the common list separators.
lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR,"
for pkg in $enableval; do
IFS="$lt_save_ifs"
if test "X$pkg" = "X$p"; then
enable_shared=yes
fi
done
IFS="$lt_save_ifs"
;;
esac],
[enable_shared=]_LT_ENABLE_SHARED_DEFAULT)
_LT_DECL([build_libtool_libs], [enable_shared], [0],
[Whether or not to build shared libraries])
])# _LT_ENABLE_SHARED
LT_OPTION_DEFINE([LT_INIT], [shared], [_LT_ENABLE_SHARED([yes])])
LT_OPTION_DEFINE([LT_INIT], [disable-shared], [_LT_ENABLE_SHARED([no])])
# Old names:
AC_DEFUN([AC_ENABLE_SHARED],
[_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[shared])
])
AC_DEFUN([AC_DISABLE_SHARED],
[_LT_SET_OPTION([LT_INIT], [disable-shared])
])
AU_DEFUN([AM_ENABLE_SHARED], [AC_ENABLE_SHARED($@)])
AU_DEFUN([AM_DISABLE_SHARED], [AC_DISABLE_SHARED($@)])
dnl aclocal-1.4 backwards compatibility:
dnl AC_DEFUN([AM_ENABLE_SHARED], [])
dnl AC_DEFUN([AM_DISABLE_SHARED], [])
# _LT_ENABLE_STATIC([DEFAULT])
# ----------------------------
# implement the --enable-static flag, and support the `static' and
# `disable-static' LT_INIT options.
# DEFAULT is either `yes' or `no'. If omitted, it defaults to `yes'.
m4_define([_LT_ENABLE_STATIC],
[m4_define([_LT_ENABLE_STATIC_DEFAULT], [m4_if($1, no, no, yes)])dnl
AC_ARG_ENABLE([static],
[AS_HELP_STRING([--enable-static@<:@=PKGS@:>@],
[build static libraries @<:@default=]_LT_ENABLE_STATIC_DEFAULT[@:>@])],
[p=${PACKAGE-default}
case $enableval in
yes) enable_static=yes ;;
no) enable_static=no ;;
*)
enable_static=no
# Look at the argument we got. We use all the common list separators.
lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR,"
for pkg in $enableval; do
IFS="$lt_save_ifs"
if test "X$pkg" = "X$p"; then
enable_static=yes
fi
done
IFS="$lt_save_ifs"
;;
esac],
[enable_static=]_LT_ENABLE_STATIC_DEFAULT)
_LT_DECL([build_old_libs], [enable_static], [0],
[Whether or not to build static libraries])
])# _LT_ENABLE_STATIC
LT_OPTION_DEFINE([LT_INIT], [static], [_LT_ENABLE_STATIC([yes])])
LT_OPTION_DEFINE([LT_INIT], [disable-static], [_LT_ENABLE_STATIC([no])])
# Old names:
AC_DEFUN([AC_ENABLE_STATIC],
[_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[static])
])
AC_DEFUN([AC_DISABLE_STATIC],
[_LT_SET_OPTION([LT_INIT], [disable-static])
])
AU_DEFUN([AM_ENABLE_STATIC], [AC_ENABLE_STATIC($@)])
AU_DEFUN([AM_DISABLE_STATIC], [AC_DISABLE_STATIC($@)])
dnl aclocal-1.4 backwards compatibility:
dnl AC_DEFUN([AM_ENABLE_STATIC], [])
dnl AC_DEFUN([AM_DISABLE_STATIC], [])
# _LT_ENABLE_FAST_INSTALL([DEFAULT])
# ----------------------------------
# implement the --enable-fast-install flag, and support the `fast-install'
# and `disable-fast-install' LT_INIT options.
# DEFAULT is either `yes' or `no'. If omitted, it defaults to `yes'.
m4_define([_LT_ENABLE_FAST_INSTALL],
[m4_define([_LT_ENABLE_FAST_INSTALL_DEFAULT], [m4_if($1, no, no, yes)])dnl
AC_ARG_ENABLE([fast-install],
[AS_HELP_STRING([--enable-fast-install@<:@=PKGS@:>@],
[optimize for fast installation @<:@default=]_LT_ENABLE_FAST_INSTALL_DEFAULT[@:>@])],
[p=${PACKAGE-default}
case $enableval in
yes) enable_fast_install=yes ;;
no) enable_fast_install=no ;;
*)
enable_fast_install=no
# Look at the argument we got. We use all the common list separators.
lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR,"
for pkg in $enableval; do
IFS="$lt_save_ifs"
if test "X$pkg" = "X$p"; then
enable_fast_install=yes
fi
done
IFS="$lt_save_ifs"
;;
esac],
[enable_fast_install=]_LT_ENABLE_FAST_INSTALL_DEFAULT)
_LT_DECL([fast_install], [enable_fast_install], [0],
[Whether or not to optimize for fast installation])dnl
])# _LT_ENABLE_FAST_INSTALL
LT_OPTION_DEFINE([LT_INIT], [fast-install], [_LT_ENABLE_FAST_INSTALL([yes])])
LT_OPTION_DEFINE([LT_INIT], [disable-fast-install], [_LT_ENABLE_FAST_INSTALL([no])])
# Old names:
AU_DEFUN([AC_ENABLE_FAST_INSTALL],
[_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[fast-install])
AC_DIAGNOSE([obsolete],
[$0: Remove this warning and the call to _LT_SET_OPTION when you put
the `fast-install' option into LT_INIT's first parameter.])
])
AU_DEFUN([AC_DISABLE_FAST_INSTALL],
[_LT_SET_OPTION([LT_INIT], [disable-fast-install])
AC_DIAGNOSE([obsolete],
[$0: Remove this warning and the call to _LT_SET_OPTION when you put
the `disable-fast-install' option into LT_INIT's first parameter.])
])
dnl aclocal-1.4 backwards compatibility:
dnl AC_DEFUN([AC_ENABLE_FAST_INSTALL], [])
dnl AC_DEFUN([AM_DISABLE_FAST_INSTALL], [])
# _LT_WITH_PIC([MODE])
# --------------------
# implement the --with-pic flag, and support the `pic-only' and `no-pic'
# LT_INIT options.
# MODE is either `yes' or `no'. If omitted, it defaults to `both'.
m4_define([_LT_WITH_PIC],
[AC_ARG_WITH([pic],
[AS_HELP_STRING([--with-pic],
[try to use only PIC/non-PIC objects @<:@default=use both@:>@])],
[pic_mode="$withval"],
[pic_mode=default])
test -z "$pic_mode" && pic_mode=m4_default([$1], [default])
_LT_DECL([], [pic_mode], [0], [What type of objects to build])dnl
])# _LT_WITH_PIC
LT_OPTION_DEFINE([LT_INIT], [pic-only], [_LT_WITH_PIC([yes])])
LT_OPTION_DEFINE([LT_INIT], [no-pic], [_LT_WITH_PIC([no])])
# Old name:
AU_DEFUN([AC_LIBTOOL_PICMODE],
[_LT_SET_OPTION([LT_INIT], [pic-only])
AC_DIAGNOSE([obsolete],
[$0: Remove this warning and the call to _LT_SET_OPTION when you
put the `pic-only' option into LT_INIT's first parameter.])
])
dnl aclocal-1.4 backwards compatibility:
dnl AC_DEFUN([AC_LIBTOOL_PICMODE], [])
## ----------------- ##
## LTDL_INIT Options ##
## ----------------- ##
m4_define([_LTDL_MODE], [])
LT_OPTION_DEFINE([LTDL_INIT], [nonrecursive],
[m4_define([_LTDL_MODE], [nonrecursive])])
LT_OPTION_DEFINE([LTDL_INIT], [recursive],
[m4_define([_LTDL_MODE], [recursive])])
LT_OPTION_DEFINE([LTDL_INIT], [subproject],
[m4_define([_LTDL_MODE], [subproject])])
m4_define([_LTDL_TYPE], [])
LT_OPTION_DEFINE([LTDL_INIT], [installable],
[m4_define([_LTDL_TYPE], [installable])])
LT_OPTION_DEFINE([LTDL_INIT], [convenience],
[m4_define([_LTDL_TYPE], [convenience])])

123
m4/ltsugar.m4 vendored Normal file
View File

@@ -0,0 +1,123 @@
# ltsugar.m4 -- libtool m4 base layer. -*-Autoconf-*-
#
# Copyright (C) 2004, 2005, 2007, 2008 Free Software Foundation, Inc.
# Written by Gary V. Vaughan, 2004
#
# This file is free software; the Free Software Foundation gives
# unlimited permission to copy and/or distribute it, with or without
# modifications, as long as this notice is preserved.
# serial 6 ltsugar.m4
# This is to help aclocal find these macros, as it can't see m4_define.
AC_DEFUN([LTSUGAR_VERSION], [m4_if([0.1])])
# lt_join(SEP, ARG1, [ARG2...])
# -----------------------------
# Produce ARG1SEPARG2...SEPARGn, omitting [] arguments and their
# associated separator.
# Needed until we can rely on m4_join from Autoconf 2.62, since all earlier
# versions in m4sugar had bugs.
m4_define([lt_join],
[m4_if([$#], [1], [],
[$#], [2], [[$2]],
[m4_if([$2], [], [], [[$2]_])$0([$1], m4_shift(m4_shift($@)))])])
m4_define([_lt_join],
[m4_if([$#$2], [2], [],
[m4_if([$2], [], [], [[$1$2]])$0([$1], m4_shift(m4_shift($@)))])])
# lt_car(LIST)
# lt_cdr(LIST)
# ------------
# Manipulate m4 lists.
# These macros are necessary as long as will still need to support
# Autoconf-2.59 which quotes differently.
m4_define([lt_car], [[$1]])
m4_define([lt_cdr],
[m4_if([$#], 0, [m4_fatal([$0: cannot be called without arguments])],
[$#], 1, [],
[m4_dquote(m4_shift($@))])])
m4_define([lt_unquote], $1)
# lt_append(MACRO-NAME, STRING, [SEPARATOR])
# ------------------------------------------
# Redefine MACRO-NAME to hold its former content plus `SEPARATOR'`STRING'.
# Note that neither SEPARATOR nor STRING are expanded; they are appended
# to MACRO-NAME as is (leaving the expansion for when MACRO-NAME is invoked).
# No SEPARATOR is output if MACRO-NAME was previously undefined (different
# than defined and empty).
#
# This macro is needed until we can rely on Autoconf 2.62, since earlier
# versions of m4sugar mistakenly expanded SEPARATOR but not STRING.
m4_define([lt_append],
[m4_define([$1],
m4_ifdef([$1], [m4_defn([$1])[$3]])[$2])])
# lt_combine(SEP, PREFIX-LIST, INFIX, SUFFIX1, [SUFFIX2...])
# ----------------------------------------------------------
# Produce a SEP delimited list of all paired combinations of elements of
# PREFIX-LIST with SUFFIX1 through SUFFIXn. Each element of the list
# has the form PREFIXmINFIXSUFFIXn.
# Needed until we can rely on m4_combine added in Autoconf 2.62.
m4_define([lt_combine],
[m4_if(m4_eval([$# > 3]), [1],
[m4_pushdef([_Lt_sep], [m4_define([_Lt_sep], m4_defn([lt_car]))])]]dnl
[[m4_foreach([_Lt_prefix], [$2],
[m4_foreach([_Lt_suffix],
]m4_dquote(m4_dquote(m4_shift(m4_shift(m4_shift($@)))))[,
[_Lt_sep([$1])[]m4_defn([_Lt_prefix])[$3]m4_defn([_Lt_suffix])])])])])
# lt_if_append_uniq(MACRO-NAME, VARNAME, [SEPARATOR], [UNIQ], [NOT-UNIQ])
# -----------------------------------------------------------------------
# Iff MACRO-NAME does not yet contain VARNAME, then append it (delimited
# by SEPARATOR if supplied) and expand UNIQ, else NOT-UNIQ.
m4_define([lt_if_append_uniq],
[m4_ifdef([$1],
[m4_if(m4_index([$3]m4_defn([$1])[$3], [$3$2$3]), [-1],
[lt_append([$1], [$2], [$3])$4],
[$5])],
[lt_append([$1], [$2], [$3])$4])])
# lt_dict_add(DICT, KEY, VALUE)
# -----------------------------
m4_define([lt_dict_add],
[m4_define([$1($2)], [$3])])
# lt_dict_add_subkey(DICT, KEY, SUBKEY, VALUE)
# --------------------------------------------
m4_define([lt_dict_add_subkey],
[m4_define([$1($2:$3)], [$4])])
# lt_dict_fetch(DICT, KEY, [SUBKEY])
# ----------------------------------
m4_define([lt_dict_fetch],
[m4_ifval([$3],
m4_ifdef([$1($2:$3)], [m4_defn([$1($2:$3)])]),
m4_ifdef([$1($2)], [m4_defn([$1($2)])]))])
# lt_if_dict_fetch(DICT, KEY, [SUBKEY], VALUE, IF-TRUE, [IF-FALSE])
# -----------------------------------------------------------------
m4_define([lt_if_dict_fetch],
[m4_if(lt_dict_fetch([$1], [$2], [$3]), [$4],
[$5],
[$6])])
# lt_dict_filter(DICT, [SUBKEY], VALUE, [SEPARATOR], KEY, [...])
# --------------------------------------------------------------
m4_define([lt_dict_filter],
[m4_if([$5], [], [],
[lt_join(m4_quote(m4_default([$4], [[, ]])),
lt_unquote(m4_split(m4_normalize(m4_foreach(_Lt_key, lt_car([m4_shiftn(4, $@)]),
[lt_if_dict_fetch([$1], _Lt_key, [$2], [$3], [_Lt_key ])])))))])[]dnl
])

23
m4/ltversion.m4 vendored Normal file
View File

@@ -0,0 +1,23 @@
# ltversion.m4 -- version numbers -*- Autoconf -*-
#
# Copyright (C) 2004 Free Software Foundation, Inc.
# Written by Scott James Remnant, 2004
#
# This file is free software; the Free Software Foundation gives
# unlimited permission to copy and/or distribute it, with or without
# modifications, as long as this notice is preserved.
# Generated from ltversion.in.
# serial 3017 ltversion.m4
# This file is part of GNU Libtool
m4_define([LT_PACKAGE_VERSION], [2.2.6b])
m4_define([LT_PACKAGE_REVISION], [1.3017])
AC_DEFUN([LTVERSION_VERSION],
[macro_version='2.2.6b'
macro_revision='1.3017'
_LT_DECL(, macro_version, 0, [Which release of libtool.m4 was used?])
_LT_DECL(, macro_revision, 0)
])

92
m4/lt~obsolete.m4 vendored Normal file
View File

@@ -0,0 +1,92 @@
# lt~obsolete.m4 -- aclocal satisfying obsolete definitions. -*-Autoconf-*-
#
# Copyright (C) 2004, 2005, 2007 Free Software Foundation, Inc.
# Written by Scott James Remnant, 2004.
#
# This file is free software; the Free Software Foundation gives
# unlimited permission to copy and/or distribute it, with or without
# modifications, as long as this notice is preserved.
# serial 4 lt~obsolete.m4
# These exist entirely to fool aclocal when bootstrapping libtool.
#
# In the past libtool.m4 has provided macros via AC_DEFUN (or AU_DEFUN)
# which have later been changed to m4_define as they aren't part of the
# exported API, or moved to Autoconf or Automake where they belong.
#
# The trouble is, aclocal is a bit thick. It'll see the old AC_DEFUN
# in /usr/share/aclocal/libtool.m4 and remember it, then when it sees us
# using a macro with the same name in our local m4/libtool.m4 it'll
# pull the old libtool.m4 in (it doesn't see our shiny new m4_define
# and doesn't know about Autoconf macros at all.)
#
# So we provide this file, which has a silly filename so it's always
# included after everything else. This provides aclocal with the
# AC_DEFUNs it wants, but when m4 processes it, it doesn't do anything
# because those macros already exist, or will be overwritten later.
# We use AC_DEFUN over AU_DEFUN for compatibility with aclocal-1.6.
#
# Anytime we withdraw an AC_DEFUN or AU_DEFUN, remember to add it here.
# Yes, that means every name once taken will need to remain here until
# we give up compatibility with versions before 1.7, at which point
# we need to keep only those names which we still refer to.
# This is to help aclocal find these macros, as it can't see m4_define.
AC_DEFUN([LTOBSOLETE_VERSION], [m4_if([1])])
m4_ifndef([AC_LIBTOOL_LINKER_OPTION], [AC_DEFUN([AC_LIBTOOL_LINKER_OPTION])])
m4_ifndef([AC_PROG_EGREP], [AC_DEFUN([AC_PROG_EGREP])])
m4_ifndef([_LT_AC_PROG_ECHO_BACKSLASH], [AC_DEFUN([_LT_AC_PROG_ECHO_BACKSLASH])])
m4_ifndef([_LT_AC_SHELL_INIT], [AC_DEFUN([_LT_AC_SHELL_INIT])])
m4_ifndef([_LT_AC_SYS_LIBPATH_AIX], [AC_DEFUN([_LT_AC_SYS_LIBPATH_AIX])])
m4_ifndef([_LT_PROG_LTMAIN], [AC_DEFUN([_LT_PROG_LTMAIN])])
m4_ifndef([_LT_AC_TAGVAR], [AC_DEFUN([_LT_AC_TAGVAR])])
m4_ifndef([AC_LTDL_ENABLE_INSTALL], [AC_DEFUN([AC_LTDL_ENABLE_INSTALL])])
m4_ifndef([AC_LTDL_PREOPEN], [AC_DEFUN([AC_LTDL_PREOPEN])])
m4_ifndef([_LT_AC_SYS_COMPILER], [AC_DEFUN([_LT_AC_SYS_COMPILER])])
m4_ifndef([_LT_AC_LOCK], [AC_DEFUN([_LT_AC_LOCK])])
m4_ifndef([AC_LIBTOOL_SYS_OLD_ARCHIVE], [AC_DEFUN([AC_LIBTOOL_SYS_OLD_ARCHIVE])])
m4_ifndef([_LT_AC_TRY_DLOPEN_SELF], [AC_DEFUN([_LT_AC_TRY_DLOPEN_SELF])])
m4_ifndef([AC_LIBTOOL_PROG_CC_C_O], [AC_DEFUN([AC_LIBTOOL_PROG_CC_C_O])])
m4_ifndef([AC_LIBTOOL_SYS_HARD_LINK_LOCKS], [AC_DEFUN([AC_LIBTOOL_SYS_HARD_LINK_LOCKS])])
m4_ifndef([AC_LIBTOOL_OBJDIR], [AC_DEFUN([AC_LIBTOOL_OBJDIR])])
m4_ifndef([AC_LTDL_OBJDIR], [AC_DEFUN([AC_LTDL_OBJDIR])])
m4_ifndef([AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH], [AC_DEFUN([AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH])])
m4_ifndef([AC_LIBTOOL_SYS_LIB_STRIP], [AC_DEFUN([AC_LIBTOOL_SYS_LIB_STRIP])])
m4_ifndef([AC_PATH_MAGIC], [AC_DEFUN([AC_PATH_MAGIC])])
m4_ifndef([AC_PROG_LD_GNU], [AC_DEFUN([AC_PROG_LD_GNU])])
m4_ifndef([AC_PROG_LD_RELOAD_FLAG], [AC_DEFUN([AC_PROG_LD_RELOAD_FLAG])])
m4_ifndef([AC_DEPLIBS_CHECK_METHOD], [AC_DEFUN([AC_DEPLIBS_CHECK_METHOD])])
m4_ifndef([AC_LIBTOOL_PROG_COMPILER_NO_RTTI], [AC_DEFUN([AC_LIBTOOL_PROG_COMPILER_NO_RTTI])])
m4_ifndef([AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE], [AC_DEFUN([AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE])])
m4_ifndef([AC_LIBTOOL_PROG_COMPILER_PIC], [AC_DEFUN([AC_LIBTOOL_PROG_COMPILER_PIC])])
m4_ifndef([AC_LIBTOOL_PROG_LD_SHLIBS], [AC_DEFUN([AC_LIBTOOL_PROG_LD_SHLIBS])])
m4_ifndef([AC_LIBTOOL_POSTDEP_PREDEP], [AC_DEFUN([AC_LIBTOOL_POSTDEP_PREDEP])])
m4_ifndef([LT_AC_PROG_EGREP], [AC_DEFUN([LT_AC_PROG_EGREP])])
m4_ifndef([LT_AC_PROG_SED], [AC_DEFUN([LT_AC_PROG_SED])])
m4_ifndef([_LT_CC_BASENAME], [AC_DEFUN([_LT_CC_BASENAME])])
m4_ifndef([_LT_COMPILER_BOILERPLATE], [AC_DEFUN([_LT_COMPILER_BOILERPLATE])])
m4_ifndef([_LT_LINKER_BOILERPLATE], [AC_DEFUN([_LT_LINKER_BOILERPLATE])])
m4_ifndef([_AC_PROG_LIBTOOL], [AC_DEFUN([_AC_PROG_LIBTOOL])])
m4_ifndef([AC_LIBTOOL_SETUP], [AC_DEFUN([AC_LIBTOOL_SETUP])])
m4_ifndef([_LT_AC_CHECK_DLFCN], [AC_DEFUN([_LT_AC_CHECK_DLFCN])])
m4_ifndef([AC_LIBTOOL_SYS_DYNAMIC_LINKER], [AC_DEFUN([AC_LIBTOOL_SYS_DYNAMIC_LINKER])])
m4_ifndef([_LT_AC_TAGCONFIG], [AC_DEFUN([_LT_AC_TAGCONFIG])])
m4_ifndef([AC_DISABLE_FAST_INSTALL], [AC_DEFUN([AC_DISABLE_FAST_INSTALL])])
m4_ifndef([_LT_AC_LANG_CXX], [AC_DEFUN([_LT_AC_LANG_CXX])])
m4_ifndef([_LT_AC_LANG_F77], [AC_DEFUN([_LT_AC_LANG_F77])])
m4_ifndef([_LT_AC_LANG_GCJ], [AC_DEFUN([_LT_AC_LANG_GCJ])])
m4_ifndef([AC_LIBTOOL_RC], [AC_DEFUN([AC_LIBTOOL_RC])])
m4_ifndef([AC_LIBTOOL_LANG_C_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_C_CONFIG])])
m4_ifndef([_LT_AC_LANG_C_CONFIG], [AC_DEFUN([_LT_AC_LANG_C_CONFIG])])
m4_ifndef([AC_LIBTOOL_LANG_CXX_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_CXX_CONFIG])])
m4_ifndef([_LT_AC_LANG_CXX_CONFIG], [AC_DEFUN([_LT_AC_LANG_CXX_CONFIG])])
m4_ifndef([AC_LIBTOOL_LANG_F77_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_F77_CONFIG])])
m4_ifndef([_LT_AC_LANG_F77_CONFIG], [AC_DEFUN([_LT_AC_LANG_F77_CONFIG])])
m4_ifndef([AC_LIBTOOL_LANG_GCJ_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_GCJ_CONFIG])])
m4_ifndef([_LT_AC_LANG_GCJ_CONFIG], [AC_DEFUN([_LT_AC_LANG_GCJ_CONFIG])])
m4_ifndef([AC_LIBTOOL_LANG_RC_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_RC_CONFIG])])
m4_ifndef([_LT_AC_LANG_RC_CONFIG], [AC_DEFUN([_LT_AC_LANG_RC_CONFIG])])
m4_ifndef([AC_LIBTOOL_CONFIG], [AC_DEFUN([AC_LIBTOOL_CONFIG])])
m4_ifndef([_LT_AC_FILE_LTDLL_C], [AC_DEFUN([_LT_AC_FILE_LTDLL_C])])

View File

@@ -0,0 +1,36 @@
// Copyright (c) 2009, 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 BREAKPAD_GOOGLETEST_INCLUDES_H__
#define BREAKPAD_GOOGLETEST_INCLUDES_H__
#include "testing/gtest/include/gtest/gtest.h"
#include "testing/include/gmock/gmock.h"
#endif // BREAKPAD_GOOGLETEST_INCLUDES_H__

View File

@@ -0,0 +1,44 @@
// Copyright (c) 2010, 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.
// The Android NDK doesn't have link.h. Fortunately, the only thing
// that Breakpad uses from it is the ElfW macro, so define it here.
#ifndef GOOGLE_BREAKPAD_CLIENT_LINUX_ANDROID_LINK_H_
#define GOOGLE_BREAKPAD_CLIENT_LINUX_ANDROID_LINK_H_
#include <sys/exec_elf.h>
#ifndef ElfW
#define ElfW(type) _ElfW (Elf, ELFSIZE, type)
#define _ElfW(e,w,t) _ElfW_1 (e, w, _##t)
#define _ElfW_1(e,w,t) e##w##t
#endif
#endif // GOOGLE_BREAKPAD_CLIENT_LINUX_ANDROID_LINK_H_

View File

@@ -0,0 +1,77 @@
// Copyright (c) 2009, 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.
// Android runs a fairly new Linux kernel, so signal info is there,
// but the NDK doesn't have the structs defined, so define
// them here.
// Adapted from platform-linux.cc in V8
#ifndef GOOGLE_BREAKPAD_CLIENT_LINUX_ANDROID_UCONTEXT_H_
#define GOOGLE_BREAKPAD_CLIENT_LINUX_ANDROID_UCONTEXT_H_
#include <signal.h>
#if !defined(__GLIBC__) && (defined(__arm__) || defined(__thumb__))
struct sigcontext {
uint32_t trap_no;
uint32_t error_code;
uint32_t oldmask;
uint32_t arm_r0;
uint32_t arm_r1;
uint32_t arm_r2;
uint32_t arm_r3;
uint32_t arm_r4;
uint32_t arm_r5;
uint32_t arm_r6;
uint32_t arm_r7;
uint32_t arm_r8;
uint32_t arm_r9;
uint32_t arm_r10;
uint32_t arm_fp;
uint32_t arm_ip;
uint32_t arm_sp;
uint32_t arm_lr;
uint32_t arm_pc;
uint32_t arm_cpsr;
uint32_t fault_address;
};
typedef uint32_t __sigset_t;
typedef struct sigcontext mcontext_t;
typedef struct ucontext {
uint32_t uc_flags;
struct ucontext* uc_link;
stack_t uc_stack;
mcontext_t uc_mcontext;
__sigset_t uc_sigmask;
} ucontext_t;
#endif
#endif // GOOGLE_BREAKPAD_CLIENT_LINUX_ANDROID_UCONTEXT_H_

View File

@@ -0,0 +1,44 @@
// Copyright (c) 2010 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_CRASH_GENERATION_CLIENT_INFO_H_
#define CLIENT_LINUX_CRASH_GENERATION_CLIENT_INFO_H_
namespace google_breakpad {
class CrashGenerationServer;
struct ClientInfo {
CrashGenerationServer* crash_server_;
pid_t pid_;
};
}
#endif // CLIENT_LINUX_CRASH_GENERATION_CLIENT_INFO_H_

View File

@@ -0,0 +1,89 @@
// Copyright (c) 2010 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 <stdio.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <algorithm>
#include "client/linux/crash_generation/crash_generation_client.h"
#include "common/linux/eintr_wrapper.h"
#include "common/linux/linux_libc_support.h"
#include "third_party/lss/linux_syscall_support.h"
namespace google_breakpad {
bool
CrashGenerationClient::RequestDump(const void* blob, size_t blob_size)
{
int fds[2];
sys_socketpair(AF_UNIX, SOCK_STREAM, 0, fds);
static const unsigned kControlMsgSize = CMSG_SPACE(sizeof(int));
struct kernel_msghdr msg;
my_memset(&msg, 0, sizeof(struct kernel_msghdr));
struct kernel_iovec iov[1];
iov[0].iov_base = const_cast<void*>(blob);
iov[0].iov_len = blob_size;
msg.msg_iov = iov;
msg.msg_iovlen = sizeof(iov) / sizeof(iov[0]);
char cmsg[kControlMsgSize];
my_memset(cmsg, 0, kControlMsgSize);
msg.msg_control = cmsg;
msg.msg_controllen = sizeof(cmsg);
struct cmsghdr* hdr = CMSG_FIRSTHDR(&msg);
hdr->cmsg_level = SOL_SOCKET;
hdr->cmsg_type = SCM_RIGHTS;
hdr->cmsg_len = CMSG_LEN(sizeof(int));
int* p = reinterpret_cast<int*>(CMSG_DATA(hdr));
*p = fds[1];
HANDLE_EINTR(sys_sendmsg(server_fd_, &msg, 0));
sys_close(fds[1]);
// wait for an ACK from the server
char b;
HANDLE_EINTR(sys_read(fds[0], &b, 1));
return true;
}
//static
CrashGenerationClient*
CrashGenerationClient::TryCreate(int server_fd)
{
if (0 > server_fd)
return NULL;
return new CrashGenerationClient(server_fd);
}
}

View File

@@ -0,0 +1,69 @@
// Copyright (c) 2010 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_CRASH_GENERATION_CRASH_GENERATION_CLIENT_H_
#define CLIENT_LINUX_CRASH_GENERATION_CRASH_GENERATION_CLIENT_H_
#include <stddef.h>
namespace google_breakpad {
class CrashGenerationClient {
public:
~CrashGenerationClient()
{
}
// Request the crash server to generate a dump. |blob| is a hack,
// see exception_handler.h and minidump_writer.h
//
// Return true if the dump was successful; false otherwise.
bool RequestDump(const void* blob, size_t blob_size);
// Return a new CrashGenerationClient if |server_fd| is valid and
// connects to a CrashGenerationServer. Otherwise, return NULL.
// The returned CrashGenerationClient* is owned by the caller of
// this function.
static CrashGenerationClient* TryCreate(int server_fd);
private:
CrashGenerationClient(int server_fd) : server_fd_(server_fd)
{
}
int server_fd_;
// prevent copy construction and assignment
CrashGenerationClient(const CrashGenerationClient&);
CrashGenerationClient& operator=(const CrashGenerationClient&);
};
} // namespace google_breakpad
#endif // CLIENT_LINUX_CRASH_GENERATION_CRASH_GENERATION_CLIENT_H_

View File

@@ -0,0 +1,468 @@
// Copyright (c) 2010 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 <assert.h>
#include <dirent.h>
#include <fcntl.h>
#include <limits.h>
#include <poll.h>
#include <stdio.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <vector>
#include "client/linux/crash_generation/crash_generation_server.h"
#include "client/linux/crash_generation/client_info.h"
#include "client/linux/handler/exception_handler.h"
#include "client/linux/minidump_writer/minidump_writer.h"
#include "common/linux/eintr_wrapper.h"
#include "common/linux/guid_creator.h"
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[256];
const ssize_t n = readlink(path, buf, sizeof(buf) - 1);
if (n == -1) {
return false;
}
buf[n] = 0;
if (0 != memcmp(kSocketLinkPrefix, buf, sizeof(kSocketLinkPrefix) - 1)) {
return false;
}
char* endptr;
const u_int64_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[256];
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 {
CrashGenerationServer::CrashGenerationServer(
const int listen_fd,
OnClientDumpRequestCallback dump_callback,
void* dump_context,
OnClientExitingCallback exit_callback,
void* exit_context,
bool generate_dumps,
const std::string* dump_path) :
server_fd_(listen_fd),
dump_callback_(dump_callback),
dump_context_(dump_context),
exit_callback_(exit_callback),
exit_context_(exit_context),
generate_dumps_(generate_dumps),
started_(false)
{
if (dump_path)
dump_dir_ = *dump_path;
else
dump_dir_ = "/tmp";
}
CrashGenerationServer::~CrashGenerationServer()
{
if (started_)
Stop();
}
bool
CrashGenerationServer::Start()
{
if (started_ || 0 > server_fd_)
return false;
int control_pipe[2];
if (pipe(control_pipe))
return false;
if (fcntl(control_pipe[0], F_SETFD, FD_CLOEXEC))
return false;
if (fcntl(control_pipe[1], F_SETFD, FD_CLOEXEC))
return false;
if (fcntl(control_pipe[0], F_SETFL, O_NONBLOCK))
return false;
control_pipe_in_ = control_pipe[0];
control_pipe_out_ = control_pipe[1];
if (pthread_create(&thread_, NULL,
ThreadMain, reinterpret_cast<void*>(this)))
return false;
started_ = true;
return true;
}
void
CrashGenerationServer::Stop()
{
assert(pthread_self() != thread_);
if (!started_)
return;
HANDLE_EINTR(write(control_pipe_out_, &kCommandQuit, 1));
void* dummy;
pthread_join(thread_, &dummy);
started_ = false;
}
//static
bool
CrashGenerationServer::CreateReportChannel(int* server_fd, int* client_fd)
{
int fds[2];
if (socketpair(AF_UNIX, SOCK_SEQPACKET, 0, fds))
return false;
static const int on = 1;
// Enable passcred on the server end of the socket
if (setsockopt(fds[1], SOL_SOCKET, SO_PASSCRED, &on, sizeof(on)))
return false;
if (fcntl(fds[1], F_SETFL, O_NONBLOCK))
return false;
if (fcntl(fds[1], F_SETFD, FD_CLOEXEC))
return false;
*client_fd = fds[0];
*server_fd = fds[1];
return true;
}
// The following methods/functions execute on the server thread
void
CrashGenerationServer::Run()
{
struct pollfd pollfds[2];
memset(&pollfds, 0, sizeof(pollfds));
pollfds[0].fd = server_fd_;
pollfds[0].events = POLLIN;
pollfds[1].fd = control_pipe_in_;
pollfds[1].events = POLLIN;
while (true) {
// infinite timeout
int nevents = poll(pollfds, sizeof(pollfds)/sizeof(pollfds[0]), -1);
if (-1 == nevents) {
if (EINTR == errno) {
continue;
} else {
return;
}
}
if (pollfds[0].revents && !ClientEvent(pollfds[0].revents))
return;
if (pollfds[1].revents && !ControlEvent(pollfds[1].revents))
return;
}
}
bool
CrashGenerationServer::ClientEvent(short revents)
{
if (POLLHUP & revents)
return false;
assert(POLLIN & revents);
// A process has crashed and has signaled us by writing a datagram
// to the death signal socket. The datagram contains the crash context needed
// for writing the minidump as well as a file descriptor and a credentials
// block so that they can't lie about their pid.
// The length of the control message:
static const unsigned kControlMsgSize =
CMSG_SPACE(sizeof(int)) + CMSG_SPACE(sizeof(struct ucred));
// The length of the regular payload:
static const unsigned kCrashContextSize =
sizeof(google_breakpad::ExceptionHandler::CrashContext);
struct msghdr msg = {0};
struct iovec iov[1];
char crash_context[kCrashContextSize];
char control[kControlMsgSize];
const ssize_t expected_msg_size = sizeof(crash_context);
iov[0].iov_base = crash_context;
iov[0].iov_len = sizeof(crash_context);
msg.msg_iov = iov;
msg.msg_iovlen = sizeof(iov)/sizeof(iov[0]);
msg.msg_control = control;
msg.msg_controllen = kControlMsgSize;
const ssize_t msg_size = HANDLE_EINTR(recvmsg(server_fd_, &msg, 0));
if (msg_size != expected_msg_size)
return true;
if (msg.msg_controllen != kControlMsgSize ||
msg.msg_flags & ~MSG_TRUNC)
return true;
// Walk the control payload and extract the file descriptor and validated pid.
pid_t crashing_pid = -1;
int signal_fd = -1;
for (struct cmsghdr *hdr = CMSG_FIRSTHDR(&msg); hdr;
hdr = CMSG_NXTHDR(&msg, hdr)) {
if (hdr->cmsg_level != SOL_SOCKET)
continue;
if (hdr->cmsg_type == SCM_RIGHTS) {
const unsigned len = hdr->cmsg_len -
(((uint8_t*)CMSG_DATA(hdr)) - (uint8_t*)hdr);
assert(len % sizeof(int) == 0u);
const unsigned num_fds = len / sizeof(int);
if (num_fds > 1 || num_fds == 0) {
// A nasty process could try and send us too many descriptors and
// force a leak.
for (unsigned i = 0; i < num_fds; ++i)
HANDLE_EINTR(close(reinterpret_cast<int*>(CMSG_DATA(hdr))[i]));
return true;
} else {
signal_fd = reinterpret_cast<int*>(CMSG_DATA(hdr))[0];
}
} else if (hdr->cmsg_type == SCM_CREDENTIALS) {
const struct ucred *cred =
reinterpret_cast<struct ucred*>(CMSG_DATA(hdr));
crashing_pid = cred->pid;
}
}
if (crashing_pid == -1 || signal_fd == -1) {
if (signal_fd)
HANDLE_EINTR(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;
}
std::string minidump_filename;
if (!MakeMinidumpFilename(minidump_filename))
return true;
if (!google_breakpad::WriteMinidump(minidump_filename.c_str(),
crashing_pid, crash_context,
kCrashContextSize)) {
HANDLE_EINTR(close(signal_fd));
return true;
}
if (dump_callback_) {
ClientInfo info;
info.crash_server_ = this;
info.pid_ = crashing_pid;
dump_callback_(dump_context_, &info, &minidump_filename);
}
// Send the done signal to the process: it can exit now.
memset(&msg, 0, sizeof(msg));
struct iovec done_iov;
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;
}
bool
CrashGenerationServer::ControlEvent(short revents)
{
if (POLLHUP & revents)
return false;
assert(POLLIN & revents);
char command;
if (read(control_pipe_in_, &command, 1))
return false;
switch (command) {
case kCommandQuit:
return false;
default:
assert(0);
}
return true;
}
bool
CrashGenerationServer::MakeMinidumpFilename(std::string& outFilename)
{
GUID guid;
char guidString[kGUIDStringLength+1];
if (!(CreateGUID(&guid)
&& GUIDToString(&guid, guidString, sizeof(guidString))))
return false;
char path[PATH_MAX];
snprintf(path, sizeof(path), "%s/%s.dmp", dump_dir_.c_str(), guidString);
outFilename = path;
return true;
}
// static
void*
CrashGenerationServer::ThreadMain(void *arg)
{
reinterpret_cast<CrashGenerationServer*>(arg)->Run();
return NULL;
}
} // namespace google_breakpad

View File

@@ -0,0 +1,133 @@
// Copyright (c) 2010 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_CRASH_GENERATION_CRASH_GENERATION_SERVER_H_
#define CLIENT_LINUX_CRASH_GENERATION_CRASH_GENERATION_SERVER_H_
#include <pthread.h>
#include <string>
namespace google_breakpad {
class ClientInfo;
class CrashGenerationServer {
public:
// WARNING: callbacks may be invoked on a different thread
// than that which creates the CrashGenerationServer. They must
// be thread safe.
typedef void (*OnClientDumpRequestCallback)(void* context,
const ClientInfo* client_info,
const std::string* file_path);
typedef void (*OnClientExitingCallback)(void* context,
const ClientInfo* client_info);
// Create an instance with the given parameters.
//
// Parameter listen_fd: The server fd created by CreateReportChannel().
// Parameter dump_callback: Callback for a client crash dump request.
// Parameter dump_context: Context for client crash dump request callback.
// Parameter exit_callback: Callback for client process exit.
// Parameter exit_context: Context for client exit callback.
// Parameter generate_dumps: Whether to automatically generate dumps.
// Client code of this class might want to generate dumps explicitly
// in the crash dump request callback. In that case, false can be
// passed for this parameter.
// Parameter dump_path: Path for generating dumps; required only if true is
// passed for generateDumps parameter; NULL can be passed otherwise.
CrashGenerationServer(const int listen_fd,
OnClientDumpRequestCallback dump_callback,
void* dump_context,
OnClientExitingCallback exit_callback,
void* exit_context,
bool generate_dumps,
const std::string* dump_path);
~CrashGenerationServer();
// Perform initialization steps needed to start listening to clients.
//
// Return true if initialization is successful; false otherwise.
bool Start();
// Stop the server.
void Stop();
// Create a "channel" that can be used by clients to report crashes
// to a CrashGenerationServer. |*server_fd| should be passed to
// this class's constructor, and |*client_fd| should be passed to
// the ExceptionHandler constructor in the client process.
static bool CreateReportChannel(int* server_fd, int* client_fd);
private:
// Run the server's event loop
void Run();
// Invoked when an child process (client) event occurs
// Returning true => "keep running", false => "exit loop"
bool ClientEvent(short revents);
// Invoked when the controlling thread (main) event occurs
// Returning true => "keep running", false => "exit loop"
bool ControlEvent(short revents);
// Return a unique filename at which a minidump can be written
bool MakeMinidumpFilename(std::string& outFilename);
// Trampoline to |Run()|
static void* ThreadMain(void* arg);
int server_fd_;
OnClientDumpRequestCallback dump_callback_;
void* dump_context_;
OnClientExitingCallback exit_callback_;
void* exit_context_;
bool generate_dumps_;
std::string dump_dir_;
bool started_;
pthread_t thread_;
int control_pipe_in_;
int control_pipe_out_;
// disable these
CrashGenerationServer(const CrashGenerationServer&);
CrashGenerationServer& operator=(const CrashGenerationServer&);
};
} // namespace google_breakpad
#endif // CLIENT_LINUX_CRASH_GENERATION_CRASH_GENERATION_SERVER_H_

View File

@@ -0,0 +1,3 @@
MODULE Linux x86 B8CFDE93002D54DA1900A40AA1BD67690 linux-gate.so
PUBLIC 400 0 __kernel_vsyscall
STACK WIN 4 400 100 1 1 0 0 0 0 0 1

View File

@@ -0,0 +1,3 @@
MODULE Linux x86 4FBDA58B5A1DF5A379E3CF19A235EA090 linux-gate.so
PUBLIC 400 0 __kernel_vsyscall
STACK WIN 4 400 200 3 3 0 0 0 0 0 1

View File

@@ -1,55 +0,0 @@
CXX=g++
CC=gcc
CXXFLAGS=-gstabs -I../../.. -Wall -D_REENTRANT
LDFLAGS=-lpthread
OBJ_DIR=.
BIN_DIR=.
THREAD_SRC=linux_thread.cc
SHARE_SRC=../../minidump_file_writer.cc\
../../../common/string_conversion.cc\
../../../common/linux/file_id.cc\
minidump_generator.cc
HANDLER_SRC=exception_handler.cc\
../../../common/linux/guid_creator.cc
SHARE_C_SRC=../../../common/convert_UTF.c
THREAD_TEST_SRC=linux_thread_test.cc
MINIDUMP_TEST_SRC=minidump_test.cc
EXCEPTION_TEST_SRC=exception_handler_test.cc
THREAD_OBJ=$(patsubst %.cc,$(OBJ_DIR)/%.o,$(THREAD_SRC))
SHARE_OBJ=$(patsubst %.cc,$(OBJ_DIR)/%.o,$(SHARE_SRC))
HANDLER_OBJ=$(patsubst %.cc,$(OBJ_DIR)/%.o,$(HANDLER_SRC))
SHARE_C_OBJ=$(patsubst %.c,$(OBJ_DIR)/%.o,$(SHARE_C_SRC)) md5.o
THREAD_TEST_OBJ=$(patsubst %.cc,$(OBJ_DIR)/%.o, $(THREAD_TEST_SRC))\
$(THREAD_OBJ)
MINIDUMP_TEST_OBJ=$(patsubst %.cc,$(OBJ_DIR)/%.o, $(MINIDUMP_TEST_SRC))\
$(THREAD_OBJ) $(SHARE_OBJ) $(SHARE_C_OBJ)
EXCEPTION_TEST_OBJ=$(patsubst %.cc,$(OBJ_DIR)/%.o, $(EXCEPTION_TEST_SRC))\
$(THREAD_OBJ) $(SHARE_OBJ) $(SHARE_C_OBJ) $(HANDLER_SRC)
BIN=$(BIN_DIR)/minidump_test\
$(BIN_DIR)/linux_thread_test\
$(BIN_DIR)/exception_handler_test
.PHONY:all clean
all:$(BIN)
$(BIN_DIR)/linux_thread_test:$(THREAD_TEST_OBJ)
$(CXX) $(CXXFLAGS) $(LDFLAGS) $^ -o $@
$(BIN_DIR)/minidump_test:$(MINIDUMP_TEST_OBJ)
$(CXX) $(CXXFLAGS) $(LDFLAGS) $^ -o $@
$(BIN_DIR)/exception_handler_test:$(EXCEPTION_TEST_OBJ)
$(CXX) $(CXXFLAGS) $(LDFLAGS) $^ -o $@
md5.o:../../../common/md5.c
$(CC) $(CXXFLAGS) -c $^
clean:
rm -f $(BIN) *.o *.dmp

View File

@@ -1,8 +1,6 @@
// Copyright (c) 2006, Google Inc.
// Copyright (c) 2010 Google Inc.
// All rights reserved.
//
// Author: Li Liu
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
@@ -29,238 +27,488 @@
// (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 <signal.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
// The ExceptionHandler object installs signal handlers for a number of
// signals. We rely on the signal handler running on the thread which crashed
// in order to identify it. This is true of the synchronous signals (SEGV etc),
// but not true of ABRT. Thus, if you send ABRT to yourself in a program which
// uses ExceptionHandler, you need to use tgkill to direct it to the current
// thread.
//
// The signal flow looks like this:
//
// SignalHandler (uses a global stack of ExceptionHandler objects to find
// | one to handle the signal. If the first rejects it, try
// | the second etc...)
// V
// HandleSignal ----------------------------| (clones a new process which
// | | shares an address space with
// (wait for cloned | the crashed process. This
// process) | allows us to ptrace the crashed
// | | process)
// V V
// (set signal handler to ThreadEntry (static function to bounce
// SIG_DFL and rethrow, | back into the object)
// killing the crashed |
// process) V
// DoDump (writes minidump)
// |
// V
// sys_exit
//
#include <cassert>
#include <cstdlib>
#include <ctime>
#include <linux/limits.h>
// This code is a little fragmented. Different functions of the ExceptionHandler
// class run in a number of different contexts. Some of them run in a normal
// context and are easy to code, others run in a compromised context and the
// restrictions at the top of minidump_writer.cc apply: no libc and use the
// alternative malloc. Each function should have comment above it detailing the
// context which it runs in.
#include "client/linux/handler/exception_handler.h"
#include <errno.h>
#include <fcntl.h>
#include <linux/limits.h>
#include <sched.h>
#include <signal.h>
#include <stdio.h>
#include <sys/mman.h>
#include <sys/prctl.h>
#if !defined(__ANDROID__)
#include <sys/signal.h>
#endif
#include <sys/syscall.h>
#if !defined(__ANDROID__)
#include <sys/ucontext.h>
#include <sys/user.h>
#endif
#include <sys/wait.h>
#if !defined(__ANDROID__)
#include <ucontext.h>
#endif
#include <unistd.h>
#include <algorithm>
#include <utility>
#include <vector>
#include "common/linux/linux_libc_support.h"
#include "common/memory.h"
#include "client/linux/minidump_writer/linux_dumper.h"
#include "client/linux/minidump_writer/minidump_writer.h"
#include "common/linux/guid_creator.h"
#include "google_breakpad/common/minidump_format.h"
#include "common/linux/eintr_wrapper.h"
#include "third_party/lss/linux_syscall_support.h"
#include "linux/sched.h"
#ifndef PR_SET_PTRACER
#define PR_SET_PTRACER 0x59616d61
#endif
// A wrapper for the tgkill syscall: send a signal to a specific thread.
static int tgkill(pid_t tgid, pid_t tid, int sig) {
return syscall(__NR_tgkill, tgid, tid, sig);
return 0;
}
namespace google_breakpad {
// Signals that we are interested.
int SigTable[] = {
#if defined(SIGSEGV)
SIGSEGV,
#endif
#ifdef SIGABRT
SIGABRT,
#endif
#ifdef SIGFPE
SIGFPE,
#endif
#ifdef SIGILL
SIGILL,
#endif
#ifdef SIGBUS
SIGBUS,
#endif
// The list of signals which we consider to be crashes. The default action for
// all these signals must be Core (see man 7 signal) because we rethrow the
// signal after handling it and expect that it'll be fatal.
static const int kExceptionSignals[] = {
SIGSEGV, SIGABRT, SIGFPE, SIGILL, SIGBUS, -1
};
std::vector<ExceptionHandler*> *ExceptionHandler::handler_stack_ = NULL;
int ExceptionHandler::handler_stack_index_ = 0;
// We can stack multiple exception handlers. In that case, this is the global
// which holds the stack.
std::vector<ExceptionHandler*>* ExceptionHandler::handler_stack_ = NULL;
unsigned ExceptionHandler::handler_stack_index_ = 0;
pthread_mutex_t ExceptionHandler::handler_stack_mutex_ =
PTHREAD_MUTEX_INITIALIZER;
PTHREAD_MUTEX_INITIALIZER;
ExceptionHandler::ExceptionHandler(const string &dump_path,
// Runs before crashing: normal context.
ExceptionHandler::ExceptionHandler(const std::string &dump_path,
FilterCallback filter,
MinidumpCallback callback,
void *callback_context,
bool install_handler)
: filter_(filter),
callback_(callback),
callback_context_(callback_context),
dump_path_(),
installed_handler_(install_handler) {
set_dump_path(dump_path);
if (install_handler) {
SetupHandler();
pthread_mutex_lock(&handler_stack_mutex_);
if (handler_stack_ == NULL)
handler_stack_ = new std::vector<ExceptionHandler *>;
handler_stack_->push_back(this);
pthread_mutex_unlock(&handler_stack_mutex_);
}
: filter_(filter),
callback_(callback),
callback_context_(callback_context),
handler_installed_(install_handler)
{
Init(dump_path, -1);
}
ExceptionHandler::ExceptionHandler(const std::string &dump_path,
FilterCallback filter,
MinidumpCallback callback,
void* callback_context,
bool install_handler,
const int server_fd)
: filter_(filter),
callback_(callback),
callback_context_(callback_context),
handler_installed_(install_handler)
{
Init(dump_path, server_fd);
}
// Runs before crashing: normal context.
ExceptionHandler::~ExceptionHandler() {
TeardownAllHandler();
pthread_mutex_lock(&handler_stack_mutex_);
if (handler_stack_->back() == this) {
handler_stack_->pop_back();
} else {
fprintf(stderr, "warning: removing Breakpad handler out of order\n");
for (std::vector<ExceptionHandler *>::iterator iterator =
handler_stack_->begin();
iterator != handler_stack_->end();
++iterator) {
if (*iterator == this) {
handler_stack_->erase(iterator);
}
}
}
UninstallHandlers();
}
if (handler_stack_->empty()) {
// When destroying the last ExceptionHandler that installed a handler,
// clean up the handler stack.
delete handler_stack_;
handler_stack_ = NULL;
}
void ExceptionHandler::Init(const std::string &dump_path,
const int server_fd)
{
crash_handler_ = NULL;
if (0 <= server_fd)
crash_generation_client_
.reset(CrashGenerationClient::TryCreate(server_fd));
if (handler_installed_)
InstallHandlers();
if (!IsOutOfProcess())
set_dump_path(dump_path);
pthread_mutex_lock(&handler_stack_mutex_);
if (handler_stack_ == NULL)
handler_stack_ = new std::vector<ExceptionHandler *>;
handler_stack_->push_back(this);
pthread_mutex_unlock(&handler_stack_mutex_);
}
bool ExceptionHandler::WriteMinidump() {
return InternalWriteMinidump(0, 0, NULL);
}
// Runs before crashing: normal context.
bool ExceptionHandler::InstallHandlers() {
// We run the signal handlers on an alternative stack because we might have
// crashed because of a stack overflow.
// static
bool ExceptionHandler::WriteMinidump(const string &dump_path,
MinidumpCallback callback,
void *callback_context) {
ExceptionHandler handler(dump_path, NULL, callback,
callback_context, false);
return handler.InternalWriteMinidump(0, 0, NULL);
}
// We use this value rather than SIGSTKSZ because we would end up overrunning
// such a small stack.
static const unsigned kSigStackSize = 8192;
void ExceptionHandler::SetupHandler() {
// Signal on a different stack to avoid using the stack
// of the crashing thread.
struct sigaltstack sig_stack;
sig_stack.ss_sp = malloc(MINSIGSTKSZ);
if (sig_stack.ss_sp == NULL)
return;
sig_stack.ss_size = MINSIGSTKSZ;
sig_stack.ss_flags = 0;
signal_stack = malloc(kSigStackSize);
stack_t stack;
memset(&stack, 0, sizeof(stack));
stack.ss_sp = signal_stack;
stack.ss_size = kSigStackSize;
if (sigaltstack(&sig_stack, NULL) < 0)
return;
for (size_t i = 0; i < sizeof(SigTable) / sizeof(SigTable[0]); ++i)
SetupHandler(SigTable[i]);
}
void ExceptionHandler::SetupHandler(int signo) {
struct sigaction act, old_act;
act.sa_handler = HandleException;
act.sa_flags = SA_ONSTACK;
if (sigaction(signo, &act, &old_act) < 0)
return;
old_handlers_[signo] = old_act.sa_handler;
}
void ExceptionHandler::TeardownHandler(int signo) {
if (old_handlers_.find(signo) != old_handlers_.end()) {
struct sigaction act;
act.sa_handler = old_handlers_[signo];
act.sa_flags = 0;
sigaction(signo, &act, 0);
}
}
void ExceptionHandler::TeardownAllHandler() {
for (size_t i = 0; i < sizeof(SigTable) / sizeof(SigTable[0]); ++i) {
TeardownHandler(SigTable[i]);
}
}
// static
void ExceptionHandler::HandleException(int signo) {
// In Linux, the context information about the signal is put on the stack of
// the signal handler frame as value parameter. For some reasons, the
// prototype of the handler doesn't declare this information as parameter, we
// will do it by hand. It is the second parameter above the signal number.
// However, if we are being called by another signal handler passing the
// signal up the chain, then we may not have this random extra parameter,
// so we may have to walk the stack to find it. We do the actual work
// on another thread, where it's a little safer, but we want the ebp
// from this frame to find it.
uintptr_t current_ebp = 0;
asm volatile ("movl %%ebp, %0"
:"=m"(current_ebp));
pthread_mutex_lock(&handler_stack_mutex_);
ExceptionHandler *current_handler =
handler_stack_->at(handler_stack_->size() - ++handler_stack_index_);
pthread_mutex_unlock(&handler_stack_mutex_);
// Restore original handler.
current_handler->TeardownHandler(signo);
struct sigcontext *sig_ctx = NULL;
if (current_handler->InternalWriteMinidump(signo, current_ebp, &sig_ctx)) {
// Fully handled this exception, safe to exit.
exit(EXIT_FAILURE);
} else {
// Exception not fully handled, will call the next handler in stack to
// process it.
typedef void (*SignalHandler)(int signo, struct sigcontext);
SignalHandler old_handler =
reinterpret_cast<SignalHandler>(current_handler->old_handlers_[signo]);
if (old_handler != NULL && sig_ctx != NULL)
old_handler(signo, *sig_ctx);
}
pthread_mutex_lock(&handler_stack_mutex_);
current_handler->SetupHandler(signo);
--handler_stack_index_;
// All the handlers in stack have been invoked to handle the exception,
// normally the process should be terminated and should not reach here.
// In case we got here, ask the OS to handle it to avoid endless loop,
// normally the OS will generate a core and termiate the process. This
// may be desired to debug the program.
if (handler_stack_index_ == 0)
signal(signo, SIG_DFL);
pthread_mutex_unlock(&handler_stack_mutex_);
}
bool ExceptionHandler::InternalWriteMinidump(int signo,
uintptr_t sighandler_ebp,
struct sigcontext **sig_ctx) {
if (filter_ && !filter_(callback_context_))
if (sys_sigaltstack(&stack, NULL) == -1)
return false;
struct sigaction sa;
memset(&sa, 0, sizeof(sa));
sigemptyset(&sa.sa_mask);
// mask all exception signals when we're handling one of them.
for (unsigned i = 0; kExceptionSignals[i] != -1; ++i)
sigaddset(&sa.sa_mask, kExceptionSignals[i]);
sa.sa_sigaction = SignalHandler;
sa.sa_flags = SA_ONSTACK | SA_SIGINFO;
for (unsigned i = 0; kExceptionSignals[i] != -1; ++i) {
struct sigaction* old = new struct sigaction;
if (sigaction(kExceptionSignals[i], &sa, old) == -1)
return false;
old_handlers_.push_back(std::make_pair(kExceptionSignals[i], old));
}
return true;
}
// Runs before crashing: normal context.
void ExceptionHandler::UninstallHandlers() {
for (unsigned i = 0; i < old_handlers_.size(); ++i) {
struct sigaction *action =
reinterpret_cast<struct sigaction*>(old_handlers_[i].second);
sigaction(old_handlers_[i].first, action, NULL);
delete action;
}
pthread_mutex_lock(&handler_stack_mutex_);
std::vector<ExceptionHandler*>::iterator handler =
std::find(handler_stack_->begin(), handler_stack_->end(), this);
handler_stack_->erase(handler);
pthread_mutex_unlock(&handler_stack_mutex_);
old_handlers_.clear();
}
// Runs before crashing: normal context.
void ExceptionHandler::UpdateNextID() {
GUID guid;
bool success = false;;
char guid_str[kGUIDStringLength + 1];
if (CreateGUID(&guid) && GUIDToString(&guid, guid_str, sizeof(guid_str))) {
next_minidump_id_ = guid_str;
next_minidump_id_c_ = next_minidump_id_.c_str();
char minidump_path[PATH_MAX];
snprintf(minidump_path, sizeof(minidump_path), "%s/%s.dmp",
dump_path_c_,
guid_str);
// Block all the signals we want to process when writting minidump.
// We don't want it to be interrupted.
sigset_t sig_blocked, sig_old;
bool blocked = true;
sigfillset(&sig_blocked);
for (size_t i = 0; i < sizeof(SigTable) / sizeof(SigTable[0]); ++i)
sigdelset(&sig_blocked, SigTable[i]);
if (sigprocmask(SIG_BLOCK, &sig_blocked, &sig_old) != 0) {
blocked = false;
fprintf(stderr, "google_breakpad::ExceptionHandler::HandleException: "
"failed to block signals.\n");
}
success = minidump_generator_.WriteMinidumpToFile(
minidump_path, signo, sighandler_ebp, sig_ctx);
// Unblock the signals.
if (blocked) {
sigprocmask(SIG_SETMASK, &sig_old, &sig_old);
}
if (callback_)
success = callback_(dump_path_c_, guid_str,
callback_context_, success);
next_minidump_path_ = minidump_path;
next_minidump_path_c_ = next_minidump_path_.c_str();
}
}
// void ExceptionHandler::set_crash_handler(HandlerCallback callback) {
// crash_handler_ = callback;
// }
// This function runs in a compromised context: see the top of the file.
// Runs on the crashing thread.
// static
void ExceptionHandler::SignalHandler(int sig, siginfo_t* info, void* uc) {
// All the exception signals are blocked at this point.
pthread_mutex_lock(&handler_stack_mutex_);
if (!handler_stack_->size()) {
pthread_mutex_unlock(&handler_stack_mutex_);
return;
}
for (int i = handler_stack_->size() - 1; i >= 0; --i) {
if ((*handler_stack_)[i]->HandleSignal(sig, info, uc)) {
// successfully handled: We are in an invalid state since an exception
// signal has been delivered. We don't call the exit handlers because
// they could end up corrupting on-disk state.
break;
}
}
pthread_mutex_unlock(&handler_stack_mutex_);
if (info->si_pid) {
// 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
// kill() ourselves.
if (tgkill(getpid(), syscall(__NR_gettid), sig) < 0) {
// 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
// result in an incorrect exit code.
_exit(1);
}
} else {
// This was a synchronous signal triggered by a hard fault (e.g. SIGSEGV).
// No need to reissue the signal. It will automatically trigger again,
// when we return from the signal handler.
}
// As soon as we return from the signal handler, our signal will become
// unmasked. At that time, we will get terminated with the same signal that
// was triggered originally. This allows our parent to know that we crashed.
// The default action for all the signals which we catch is Core, so
// this is the end of us.
signal(sig, SIG_DFL);
}
struct ThreadArgument {
pid_t pid; // the crashing process
ExceptionHandler* handler;
const void* context; // a CrashContext structure
size_t context_size;
};
// This is the entry function for the cloned process. We are in a compromised
// context here: see the top of the file.
// static
int ExceptionHandler::ThreadEntry(void *arg) {
const ThreadArgument *thread_arg = reinterpret_cast<ThreadArgument*>(arg);
// Block here until the crashing process unblocks us when
// we're allowed to use ptrace
thread_arg->handler->WaitForContinueSignal();
return thread_arg->handler->DoDump(thread_arg->pid, thread_arg->context,
thread_arg->context_size) == false;
}
// This function runs in a compromised context: see the top of the file.
// Runs on the crashing thread.
bool ExceptionHandler::HandleSignal(int sig, siginfo_t* info, void* uc) {
if (filter_ && !filter_(callback_context_))
return false;
// Allow ourselves to be dumped if the signal is trusted.
bool signal_trusted = info->si_code > 0;
bool signal_pid_trusted = info->si_code == SI_USER ||
info->si_code == SI_TKILL;
if (signal_trusted || (signal_pid_trusted && info->si_pid == getpid())) {
sys_prctl(PR_SET_DUMPABLE, 1);
}
CrashContext context;
memcpy(&context.siginfo, info, sizeof(siginfo_t));
memcpy(&context.context, uc, sizeof(struct ucontext));
#if !defined(__ARM_EABI__)
// FP state is not part of user ABI on ARM Linux.
struct ucontext *uc_ptr = (struct ucontext*)uc;
if (uc_ptr->uc_mcontext.fpregs) {
memcpy(&context.float_state,
uc_ptr->uc_mcontext.fpregs,
sizeof(context.float_state));
}
#endif
context.tid = syscall(__NR_gettid);
if (crash_handler_ != NULL) {
if (crash_handler_(&context, sizeof(context),
callback_context_)) {
return true;
}
}
return GenerateDump(&context);
}
// This function may run in a compromised context: see the top of the file.
bool ExceptionHandler::GenerateDump(CrashContext *context) {
if (IsOutOfProcess())
return crash_generation_client_->RequestDump(context, sizeof(*context));
static const unsigned kChildStackSize = 8000;
PageAllocator allocator;
uint8_t* stack = (uint8_t*) allocator.Alloc(kChildStackSize);
if (!stack)
return false;
// clone() needs the top-most address. (scrub just to be safe)
stack += kChildStackSize;
my_memset(stack - 16, 0, 16);
ThreadArgument thread_arg;
thread_arg.handler = this;
thread_arg.pid = getpid();
thread_arg.context = context;
thread_arg.context_size = sizeof(*context);
// 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
// can do this. Create a pipe here which we can use to block the
// cloned process after creating it, until we have explicitly enabled ptrace
if(sys_pipe(fdes) == -1) {
// 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
// is the write() and read() calls will fail with EBADF
static const char no_pipe_msg[] = "ExceptionHandler::GenerateDump \
sys_pipe failed:";
sys_write(2, no_pipe_msg, sizeof(no_pipe_msg) - 1);
sys_write(2, strerror(errno), strlen(strerror(errno)));
sys_write(2, "\n", 1);
}
const pid_t child = sys_clone(
ThreadEntry, stack, CLONE_FILES | CLONE_FS | CLONE_UNTRACED,
&thread_arg, NULL, NULL, NULL);
int r, status;
// Allow the child to ptrace us
prctl(PR_SET_PTRACER, child, 0, 0, 0);
SendContinueSignalToChild();
do {
r = sys_waitpid(child, &status, __WALL);
} while (r == -1 && errno == EINTR);
sys_close(fdes[0]);
sys_close(fdes[1]);
if (r == -1) {
static const char msg[] = "ExceptionHandler::GenerateDump waitpid failed:";
sys_write(2, msg, sizeof(msg) - 1);
sys_write(2, strerror(errno), strlen(strerror(errno)));
sys_write(2, "\n", 1);
}
bool success = r != -1 && WIFEXITED(status) && WEXITSTATUS(status) == 0;
if (callback_)
success = callback_(dump_path_c_, next_minidump_id_c_,
callback_context_, success);
return success;
}
// This function runs in a compromised context: see the top of the file.
void ExceptionHandler::SendContinueSignalToChild() {
static const char okToContinueMessage = 'a';
int r;
r = HANDLE_EINTR(sys_write(fdes[1], &okToContinueMessage, sizeof(char)));
if(r == -1) {
static const char msg[] = "ExceptionHandler::SendContinueSignalToChild \
sys_write failed:";
sys_write(2, msg, sizeof(msg) - 1);
sys_write(2, strerror(errno), strlen(strerror(errno)));
sys_write(2, "\n", 1);
}
}
// This function runs in a compromised context: see the top of the file.
// Runs on the cloned process.
void ExceptionHandler::WaitForContinueSignal() {
int r;
char receivedMessage;
r = HANDLE_EINTR(sys_read(fdes[0], &receivedMessage, sizeof(char)));
if(r == -1) {
static const char msg[] = "ExceptionHandler::WaitForContinueSignal \
sys_read failed:";
sys_write(2, msg, sizeof(msg) - 1);
sys_write(2, strerror(errno), strlen(strerror(errno)));
sys_write(2, "\n", 1);
}
}
// This function runs in a compromised context: see the top of the file.
// Runs on the cloned process.
bool ExceptionHandler::DoDump(pid_t crashing_process, const void* context,
size_t context_size) {
return google_breakpad::WriteMinidump(next_minidump_path_c_,
crashing_process,
context,
context_size,
mapping_list_);
}
// static
bool ExceptionHandler::WriteMinidump(const std::string &dump_path,
MinidumpCallback callback,
void* callback_context) {
ExceptionHandler eh(dump_path, NULL, callback, callback_context, false);
return eh.WriteMinidump();
}
bool ExceptionHandler::WriteMinidump() {
#if !defined(__ARM_EABI__)
// Allow ourselves to be dumped.
sys_prctl(PR_SET_DUMPABLE, 1);
CrashContext context;
int getcontext_result = getcontext(&context.context);
if (getcontext_result)
return false;
memcpy(&context.float_state, context.context.uc_mcontext.fpregs,
sizeof(context.float_state));
context.tid = sys_gettid();
bool success = GenerateDump(&context);
UpdateNextID();
return success;
#else
return false;
#endif // !defined(__ARM_EABI__)
}
void ExceptionHandler::AddMappingInfo(const std::string& name,
const u_int8_t identifier[sizeof(MDGUID)],
uintptr_t start_address,
size_t mapping_size,
size_t file_offset) {
MappingInfo info;
info.start_addr = start_address;
info.size = mapping_size;
info.offset = file_offset;
strncpy(info.name, name.c_str(), std::min(name.size(), sizeof(info)));
MappingEntry mapping;
mapping.first = info;
memcpy(mapping.second, identifier, sizeof(MDGUID));
mapping_list_.push_back(mapping);
}
} // namespace google_breakpad

View File

@@ -1,8 +1,6 @@
// Copyright (c) 2006, Google Inc.
// Copyright (c) 2010 Google Inc.
// All rights reserved.
//
// Author: Li Liu
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
@@ -29,25 +27,31 @@
// (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_HANDLER_EXCEPTION_HANDLER_H__
#define CLIENT_LINUX_HANDLER_EXCEPTION_HANDLER_H__
#ifndef CLIENT_LINUX_HANDLER_EXCEPTION_HANDLER_H_
#define CLIENT_LINUX_HANDLER_EXCEPTION_HANDLER_H_
#include <pthread.h>
#include <map>
#include <string>
#include <vector>
#include "client/linux/handler/minidump_generator.h"
#include <pthread.h>
#include <signal.h>
#include <stdint.h>
#include <stdio.h>
// Context information when exception occured.
struct sigcontex;
#if defined(__ANDROID__)
#include "client/linux/android_ucontext.h"
#endif
#include "client/linux/crash_generation/crash_generation_client.h"
#include "client/linux/minidump_writer/minidump_writer.h"
#include "google_breakpad/common/minidump_format.h"
#include "processor/scoped_ptr.h"
struct sigaction;
namespace google_breakpad {
using std::string;
class ExceptionHandler;
//
// ExceptionHandler
//
// ExceptionHandler can write a minidump file when an exception occurs,
@@ -72,7 +76,6 @@ using std::string;
//
// Caller should try to make the callbacks as crash-friendly as possible,
// it should avoid use heap memory allocation as much as possible.
//
class ExceptionHandler {
public:
// A callback function to run before Breakpad performs any substantial
@@ -107,6 +110,15 @@ class ExceptionHandler {
void *context,
bool succeeded);
// In certain cases, a user may wish to handle the generation of the minidump
// themselves. In this case, they can install a handler callback which is
// called when a crash has occurred. If this function returns true, no other
// processing of occurs and the process will shortly be crashed. If this
// returns false, the normal processing continues.
typedef bool (*HandlerCallback)(const void* crash_context,
size_t crash_context_size,
void* context);
// Creates a new ExceptionHandler instance to handle writing minidumps.
// Before writing a minidump, the optional filter callback will be called.
// Its return value determines whether or not Breakpad should write a
@@ -115,17 +127,34 @@ class ExceptionHandler {
// If install_handler is true, then a minidump will be written whenever
// an unhandled exception occurs. If it is false, minidumps will only
// be written when WriteMinidump is called.
ExceptionHandler(const string &dump_path,
ExceptionHandler(const std::string &dump_path,
FilterCallback filter, MinidumpCallback callback,
void *callback_context,
bool install_handler);
// Creates a new ExceptionHandler instance that can attempt to
// perform out-of-process dump generation if server_fd is valid. If
// server_fd is invalid, in-process dump generation will be
// used. See the above ctor for a description of the other
// parameters.
ExceptionHandler(const std::string& dump_path,
FilterCallback filter, MinidumpCallback callback,
void* callback_context,
bool install_handler,
const int server_fd);
~ExceptionHandler();
// Get and set the minidump path.
string dump_path() const { return dump_path_; }
void set_dump_path(const string &dump_path) {
std::string dump_path() const { return dump_path_; }
void set_dump_path(const std::string &dump_path) {
dump_path_ = dump_path;
dump_path_c_ = dump_path_.c_str();
UpdateNextID();
}
void set_crash_handler(HandlerCallback callback) {
crash_handler_ = callback;
}
// Writes a minidump immediately. This can be used to capture the
@@ -134,68 +163,97 @@ class ExceptionHandler {
// Convenience form of WriteMinidump which does not require an
// ExceptionHandler instance.
static bool WriteMinidump(const string &dump_path,
static bool WriteMinidump(const std::string &dump_path,
MinidumpCallback callback,
void *callback_context);
private:
// Setup crash handler.
void SetupHandler();
// Setup signal handler for a signal.
void SetupHandler(int signo);
// Teardown the handler for a signal.
void TeardownHandler(int signo);
// Teardown all handlers.
void TeardownAllHandler();
// This structure is passed to minidump_writer.h:WriteMinidump via an opaque
// blob. It shouldn't be needed in any user code.
struct CrashContext {
siginfo_t siginfo;
pid_t tid; // the crashing thread.
struct ucontext context;
#if !defined(__ARM_EABI__)
// #ifdef this out because FP state is not part of user ABI for Linux ARM.
struct _libc_fpstate float_state;
#endif
};
// Signal handler.
static void HandleException(int signo);
// Returns whether out-of-process dump generation is used or not.
bool IsOutOfProcess() const {
return crash_generation_client_.get() != NULL;
}
// If called from a signal handler, sighandler_ebp is the ebp of
// that signal handler's frame, and sig_ctx is an out parameter
// that will be set to point at the sigcontext that was placed
// on the stack by the kernel. You can pass zero and NULL
// for the second and third parameters if you are not calling
// this from a signal handler.
bool InternalWriteMinidump(int signo, uintptr_t sighandler_ebp,
struct sigcontext **sig_ctx);
// Add information about a memory mapping. This can be used if
// a custom library loader is used that maps things in a way
// that the linux dumper can't handle by reading the maps file.
void AddMappingInfo(const std::string& name,
const u_int8_t identifier[sizeof(MDGUID)],
uintptr_t start_address,
size_t mapping_size,
size_t file_offset);
private:
FilterCallback filter_;
MinidumpCallback callback_;
void *callback_context_;
void Init(const std::string &dump_path,
const int server_fd);
bool InstallHandlers();
void UninstallHandlers();
void PreresolveSymbols();
bool GenerateDump(CrashContext *context);
void SendContinueSignalToChild();
void WaitForContinueSignal();
// The directory in which a minidump will be written, set by the dump_path
// argument to the constructor, or set_dump_path.
string dump_path_;
// C style dump path. Keep this when setting dump path, since calling
// c_str() of std::string when crashing may not be safe.
const char *dump_path_c_;
void UpdateNextID();
static void SignalHandler(int sig, siginfo_t* info, void* uc);
bool HandleSignal(int sig, siginfo_t* info, void* uc);
static int ThreadEntry(void* arg);
bool DoDump(pid_t crashing_process, const void* context,
size_t context_size);
// True if the ExceptionHandler installed an unhandled exception filter
// when created (with an install_handler parameter set to true).
bool installed_handler_;
const FilterCallback filter_;
const MinidumpCallback callback_;
void* const callback_context_;
// Keep the previous handlers for the signal.
typedef void (*sighandler_t)(int);
std::map<int, sighandler_t> old_handlers_;
scoped_ptr<CrashGenerationClient> crash_generation_client_;
std::string dump_path_;
std::string next_minidump_path_;
std::string next_minidump_id_;
// Pointers to C-string representations of the above. These are set
// when the above are set so we can avoid calling c_str during
// an exception.
const char* dump_path_c_;
const char* next_minidump_path_c_;
const char* next_minidump_id_c_;
const bool handler_installed_;
void* signal_stack; // the handler stack.
HandlerCallback crash_handler_;
// The global exception handler stack. This is need becuase there may exist
// multiple ExceptionHandler instances in a process. Each will have itself
// registered in this stack.
static std::vector<ExceptionHandler *> *handler_stack_;
static std::vector<ExceptionHandler*> *handler_stack_;
// The index of the handler that should handle the next exception.
static int handler_stack_index_;
static unsigned handler_stack_index_;
static pthread_mutex_t handler_stack_mutex_;
// The minidump generator.
MinidumpGenerator minidump_generator_;
// A vector of the old signal handlers.
std::vector<std::pair<int, struct sigaction *> > old_handlers_;
// disallow copy ctor and operator=
explicit ExceptionHandler(const ExceptionHandler &);
void operator=(const ExceptionHandler &);
// 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
// can do this. We create a pipe which we can use to block the
// cloned process after creating it, until we have explicitly enabled
// ptrace. This is used to store the file descriptors for the pipe
int fdes[2];
// Callers can add extra info about mappings for cases where the
// dumper code cannot extract enough information from /proc/<pid>/maps.
MappingList mapping_list_;
};
} // namespace google_breakpad
#endif // CLIENT_LINUX_HANDLER_EXCEPTION_HANDLER_H__
#endif // CLIENT_LINUX_HANDLER_EXCEPTION_HANDLER_H_

View File

@@ -1,124 +0,0 @@
// Copyright (c) 2006, Google Inc.
// All rights reserved.
//
// Author: Li Liu
//
// 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 <pthread.h>
#include <unistd.h>
#include <cassert>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include "client/linux/handler/exception_handler.h"
#include "client/linux/handler/linux_thread.h"
using namespace google_breakpad;
// Thread use this to see if it should stop working.
static bool should_exit = false;
static int foo2(int arg) {
// Stack variable, used for debugging stack dumps.
/*DDDebug*/printf("%s:%d\n", __FUNCTION__, __LINE__);
int c = 0xcccccccc;
fprintf(stderr, "Thread trying to crash: %x\n", getpid());
c = *reinterpret_cast<int *>(0x5);
return c;
}
static int foo(int arg) {
// Stack variable, used for debugging stack dumps.
int b = 0xbbbbbbbb;
b = foo2(b);
return b;
}
static void *thread_crash(void *) {
// Stack variable, used for debugging stack dumps.
int a = 0xaaaaaaaa;
sleep(1);
a = foo(a);
printf("%x\n", a);
return NULL;
}
static void *thread_main(void *) {
while (!should_exit)
sleep(1);
return NULL;
}
static void CreateCrashThread() {
pthread_t h;
pthread_create(&h, NULL, thread_crash, NULL);
pthread_detach(h);
}
// Create working threads.
static void CreateThread(int num) {
pthread_t h;
for (int i = 0; i < num; ++i) {
pthread_create(&h, NULL, thread_main, NULL);
pthread_detach(h);
}
}
// Callback when minidump written.
static bool MinidumpCallback(const char *dump_path,
const char *minidump_id,
void *context,
bool succeeded) {
int index = reinterpret_cast<int>(context);
printf("%d %s: %s is dumped\n", index, __FUNCTION__, minidump_id);
if (index == 0) {
should_exit = true;
return true;
}
// Don't process it.
return false;
}
int main(int argc, char *argv[]) {
int handler_index = 0;
ExceptionHandler handler_ignore(".", NULL, MinidumpCallback,
(void*)handler_index, true);
++handler_index;
ExceptionHandler handler_process(".", NULL, MinidumpCallback,
(void*)handler_index, true);
CreateCrashThread();
CreateThread(10);
while (true)
sleep(1);
should_exit = true;
return 0;
}

View File

@@ -0,0 +1,775 @@
// Copyright (c) 2010 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 <stdint.h>
#include <unistd.h>
#include <signal.h>
#include <sys/mman.h>
#include <sys/poll.h>
#include <sys/socket.h>
#include <sys/uio.h>
#include <sys/wait.h>
#include <string>
#include "breakpad_googletest_includes.h"
#include "client/linux/handler/exception_handler.h"
#include "client/linux/minidump_writer/minidump_writer.h"
#include "common/linux/eintr_wrapper.h"
#include "common/linux/file_id.h"
#include "common/linux/linux_libc_support.h"
#include "third_party/lss/linux_syscall_support.h"
#include "google_breakpad/processor/minidump.h"
using namespace google_breakpad;
#if !defined(__ANDROID__)
#define TEMPDIR "/tmp"
#else
#define TEMPDIR "/data/local/tmp"
#endif
// Length of a formatted GUID string =
// sizeof(MDGUID) * 2 + 4 (for dashes) + 1 (null terminator)
const int kGUIDStringSize = 37;
static void sigchld_handler(int signo) { }
class ExceptionHandlerTest : public ::testing::Test {
protected:
void SetUp() {
// We need to be able to wait for children, so SIGCHLD cannot be SIG_IGN.
struct sigaction sa;
memset(&sa, 0, sizeof(sa));
sa.sa_handler = sigchld_handler;
ASSERT_NE(sigaction(SIGCHLD, &sa, &old_action), -1);
}
void TearDown() {
sigaction(SIGCHLD, &old_action, NULL);
}
struct sigaction old_action;
};
TEST(ExceptionHandlerTest, Simple) {
ExceptionHandler handler(TEMPDIR, NULL, NULL, NULL, true);
}
static bool DoneCallback(const char* dump_path,
const char* minidump_id,
void* context,
bool succeeded) {
if (!succeeded)
return succeeded;
int fd = (intptr_t) context;
uint32_t len = my_strlen(minidump_id);
HANDLE_EINTR(sys_write(fd, &len, sizeof(len)));
HANDLE_EINTR(sys_write(fd, minidump_id, len));
sys_close(fd);
return true;
}
TEST(ExceptionHandlerTest, ChildCrash) {
int fds[2];
ASSERT_NE(pipe(fds), -1);
const pid_t child = fork();
if (child == 0) {
close(fds[0]);
ExceptionHandler handler(TEMPDIR, NULL, DoneCallback, (void*) fds[1],
true);
*reinterpret_cast<volatile int*>(NULL) = 0;
}
close(fds[1]);
int status;
ASSERT_NE(HANDLE_EINTR(waitpid(child, &status, 0)), -1);
ASSERT_TRUE(WIFSIGNALED(status));
ASSERT_EQ(WTERMSIG(status), SIGSEGV);
struct pollfd pfd;
memset(&pfd, 0, sizeof(pfd));
pfd.fd = fds[0];
pfd.events = POLLIN | POLLERR;
const int r = HANDLE_EINTR(poll(&pfd, 1, 0));
ASSERT_EQ(r, 1);
ASSERT_TRUE(pfd.revents & POLLIN);
uint32_t len;
ASSERT_EQ(read(fds[0], &len, sizeof(len)), (ssize_t)sizeof(len));
ASSERT_LT(len, (uint32_t)2048);
char* filename = reinterpret_cast<char*>(malloc(len + 1));
ASSERT_EQ(read(fds[0], filename, len), len);
filename[len] = 0;
close(fds[0]);
const std::string minidump_filename = std::string(TEMPDIR) + "/" + filename +
".dmp";
struct stat st;
ASSERT_EQ(stat(minidump_filename.c_str(), &st), 0);
ASSERT_GT(st.st_size, 0u);
unlink(minidump_filename.c_str());
}
// Test that memory around the instruction pointer is written
// to the dump as a MinidumpMemoryRegion.
TEST(ExceptionHandlerTest, InstructionPointerMemory) {
int fds[2];
ASSERT_NE(pipe(fds), -1);
// These are defined here so the parent can use them to check the
// data from the minidump afterwards.
const u_int32_t kMemorySize = 256; // bytes
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();
if (child == 0) {
close(fds[0]);
ExceptionHandler handler(TEMPDIR, NULL, DoneCallback, (void*) fds[1],
true);
// Get some executable memory.
char* memory =
reinterpret_cast<char*>(mmap(NULL,
kMemorySize,
PROT_READ | PROT_WRITE | PROT_EXEC,
MAP_PRIVATE | MAP_ANON,
-1,
0));
if (!memory)
exit(0);
// Write some instructions that will crash. Put them in the middle
// of the block of memory, because the minidump should contain 128
// bytes on either side of the instruction pointer.
memcpy(memory + kOffset, instructions, sizeof(instructions));
// Now execute the instructions, which should crash.
typedef void (*void_function)(void);
void_function memory_function =
reinterpret_cast<void_function>(memory + kOffset);
memory_function();
}
close(fds[1]);
int status;
ASSERT_NE(HANDLE_EINTR(waitpid(child, &status, 0)), -1);
ASSERT_TRUE(WIFSIGNALED(status));
ASSERT_EQ(WTERMSIG(status), SIGILL);
struct pollfd pfd;
memset(&pfd, 0, sizeof(pfd));
pfd.fd = fds[0];
pfd.events = POLLIN | POLLERR;
const int r = HANDLE_EINTR(poll(&pfd, 1, 0));
ASSERT_EQ(r, 1);
ASSERT_TRUE(pfd.revents & POLLIN);
uint32_t len;
ASSERT_EQ(read(fds[0], &len, sizeof(len)), (ssize_t)sizeof(len));
ASSERT_LT(len, (uint32_t)2048);
char* filename = reinterpret_cast<char*>(malloc(len + 1));
ASSERT_EQ(read(fds[0], filename, len), len);
filename[len] = 0;
close(fds[0]);
const std::string minidump_filename = std::string(TEMPDIR) + "/" + filename +
".dmp";
struct stat st;
ASSERT_EQ(stat(minidump_filename.c_str(), &st), 0);
ASSERT_GT(st.st_size, 0u);
// Read the minidump. Locate the exception record and the
// memory list, and then ensure that there is a memory region
// in the memory list that covers the instruction pointer from
// the exception record.
Minidump minidump(minidump_filename);
ASSERT_TRUE(minidump.Read());
MinidumpException* exception = minidump.GetException();
MinidumpMemoryList* memory_list = minidump.GetMemoryList();
ASSERT_TRUE(exception);
ASSERT_TRUE(memory_list);
ASSERT_LT(0, memory_list->region_count());
MinidumpContext* context = exception->GetContext();
ASSERT_TRUE(context);
u_int64_t instruction_pointer;
switch (context->GetContextCPU()) {
case MD_CONTEXT_X86:
instruction_pointer = context->GetContextX86()->eip;
break;
case MD_CONTEXT_AMD64:
instruction_pointer = context->GetContextAMD64()->rip;
break;
case MD_CONTEXT_ARM:
instruction_pointer = context->GetContextARM()->iregs[15];
break;
default:
FAIL() << "Unknown context CPU: " << context->GetContextCPU();
break;
}
MinidumpMemoryRegion* region =
memory_list->GetMemoryRegionForAddress(instruction_pointer);
ASSERT_TRUE(region);
EXPECT_EQ(kMemorySize, region->GetSize());
const u_int8_t* bytes = region->GetMemory();
ASSERT_TRUE(bytes);
u_int8_t prefix_bytes[kOffset];
u_int8_t suffix_bytes[kMemorySize - kOffset - sizeof(instructions)];
memset(prefix_bytes, 0, sizeof(prefix_bytes));
memset(suffix_bytes, 0, sizeof(suffix_bytes));
EXPECT_TRUE(memcmp(bytes, prefix_bytes, sizeof(prefix_bytes)) == 0);
EXPECT_TRUE(memcmp(bytes + kOffset, instructions, sizeof(instructions)) == 0);
EXPECT_TRUE(memcmp(bytes + kOffset + sizeof(instructions),
suffix_bytes, sizeof(suffix_bytes)) == 0);
unlink(minidump_filename.c_str());
free(filename);
}
// Test that the memory region around the instruction pointer is
// bounded correctly on the low end.
TEST(ExceptionHandlerTest, InstructionPointerMemoryMinBound) {
int fds[2];
ASSERT_NE(pipe(fds), -1);
// These are defined here so the parent can use them to check the
// data from the minidump afterwards.
const u_int32_t kMemorySize = 256; // bytes
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();
if (child == 0) {
close(fds[0]);
ExceptionHandler handler(TEMPDIR, NULL, DoneCallback, (void*) fds[1],
true);
// Get some executable memory.
char* memory =
reinterpret_cast<char*>(mmap(NULL,
kMemorySize,
PROT_READ | PROT_WRITE | PROT_EXEC,
MAP_PRIVATE | MAP_ANON,
-1,
0));
if (!memory)
exit(0);
// Write some instructions that will crash. Put them in the middle
// of the block of memory, because the minidump should contain 128
// bytes on either side of the instruction pointer.
memcpy(memory + kOffset, instructions, sizeof(instructions));
// Now execute the instructions, which should crash.
typedef void (*void_function)(void);
void_function memory_function =
reinterpret_cast<void_function>(memory + kOffset);
memory_function();
}
close(fds[1]);
int status;
ASSERT_NE(HANDLE_EINTR(waitpid(child, &status, 0)), -1);
ASSERT_TRUE(WIFSIGNALED(status));
ASSERT_EQ(WTERMSIG(status), SIGILL);
struct pollfd pfd;
memset(&pfd, 0, sizeof(pfd));
pfd.fd = fds[0];
pfd.events = POLLIN | POLLERR;
const int r = HANDLE_EINTR(poll(&pfd, 1, 0));
ASSERT_EQ(r, 1);
ASSERT_TRUE(pfd.revents & POLLIN);
uint32_t len;
ASSERT_EQ(read(fds[0], &len, sizeof(len)), (ssize_t)sizeof(len));
ASSERT_LT(len, (uint32_t)2048);
char* filename = reinterpret_cast<char*>(malloc(len + 1));
ASSERT_EQ(read(fds[0], filename, len), len);
filename[len] = 0;
close(fds[0]);
const std::string minidump_filename = std::string(TEMPDIR) + "/" + filename +
".dmp";
struct stat st;
ASSERT_EQ(stat(minidump_filename.c_str(), &st), 0);
ASSERT_GT(st.st_size, 0u);
// Read the minidump. Locate the exception record and the
// memory list, and then ensure that there is a memory region
// in the memory list that covers the instruction pointer from
// the exception record.
Minidump minidump(minidump_filename);
ASSERT_TRUE(minidump.Read());
MinidumpException* exception = minidump.GetException();
MinidumpMemoryList* memory_list = minidump.GetMemoryList();
ASSERT_TRUE(exception);
ASSERT_TRUE(memory_list);
ASSERT_LT(0, memory_list->region_count());
MinidumpContext* context = exception->GetContext();
ASSERT_TRUE(context);
u_int64_t instruction_pointer;
switch (context->GetContextCPU()) {
case MD_CONTEXT_X86:
instruction_pointer = context->GetContextX86()->eip;
break;
case MD_CONTEXT_AMD64:
instruction_pointer = context->GetContextAMD64()->rip;
break;
case MD_CONTEXT_ARM:
instruction_pointer = context->GetContextARM()->iregs[15];
break;
default:
FAIL() << "Unknown context CPU: " << context->GetContextCPU();
break;
}
MinidumpMemoryRegion* region =
memory_list->GetMemoryRegionForAddress(instruction_pointer);
ASSERT_TRUE(region);
EXPECT_EQ(kMemorySize / 2, region->GetSize());
const u_int8_t* bytes = region->GetMemory();
ASSERT_TRUE(bytes);
u_int8_t suffix_bytes[kMemorySize / 2 - sizeof(instructions)];
memset(suffix_bytes, 0, sizeof(suffix_bytes));
EXPECT_TRUE(memcmp(bytes + kOffset, instructions, sizeof(instructions)) == 0);
EXPECT_TRUE(memcmp(bytes + kOffset + sizeof(instructions),
suffix_bytes, sizeof(suffix_bytes)) == 0);
unlink(minidump_filename.c_str());
free(filename);
}
// Test that the memory region around the instruction pointer is
// bounded correctly on the high end.
TEST(ExceptionHandlerTest, InstructionPointerMemoryMaxBound) {
int fds[2];
ASSERT_NE(pipe(fds), -1);
// These are defined here so the parent can use them to check the
// data from the minidump afterwards.
// Use 4k here because the OS will hand out a single page even
// if a smaller size is requested, and this test wants to
// test the upper bound of the memory range.
const u_int32_t kMemorySize = 4096; // bytes
// This crashes with SIGILL on x86/x86-64/arm.
const unsigned char instructions[] = { 0xff, 0xff, 0xff, 0xff };
const int kOffset = kMemorySize - sizeof(instructions);
const pid_t child = fork();
if (child == 0) {
close(fds[0]);
ExceptionHandler handler(TEMPDIR, NULL, DoneCallback, (void*) fds[1],
true);
// Get some executable memory.
char* memory =
reinterpret_cast<char*>(mmap(NULL,
kMemorySize,
PROT_READ | PROT_WRITE | PROT_EXEC,
MAP_PRIVATE | MAP_ANON,
-1,
0));
if (!memory)
exit(0);
// Write some instructions that will crash. Put them in the middle
// of the block of memory, because the minidump should contain 128
// bytes on either side of the instruction pointer.
memcpy(memory + kOffset, instructions, sizeof(instructions));
// Now execute the instructions, which should crash.
typedef void (*void_function)(void);
void_function memory_function =
reinterpret_cast<void_function>(memory + kOffset);
memory_function();
}
close(fds[1]);
int status;
ASSERT_NE(HANDLE_EINTR(waitpid(child, &status, 0)), -1);
ASSERT_TRUE(WIFSIGNALED(status));
ASSERT_EQ(WTERMSIG(status), SIGILL);
struct pollfd pfd;
memset(&pfd, 0, sizeof(pfd));
pfd.fd = fds[0];
pfd.events = POLLIN | POLLERR;
const int r = HANDLE_EINTR(poll(&pfd, 1, 0));
ASSERT_EQ(r, 1);
ASSERT_TRUE(pfd.revents & POLLIN);
uint32_t len;
ASSERT_EQ(read(fds[0], &len, sizeof(len)), (ssize_t)sizeof(len));
ASSERT_LT(len, (uint32_t)2048);
char* filename = reinterpret_cast<char*>(malloc(len + 1));
ASSERT_EQ(read(fds[0], filename, len), len);
filename[len] = 0;
close(fds[0]);
const std::string minidump_filename = std::string(TEMPDIR) + "/" + filename +
".dmp";
struct stat st;
ASSERT_EQ(stat(minidump_filename.c_str(), &st), 0);
ASSERT_GT(st.st_size, 0u);
// Read the minidump. Locate the exception record and the
// memory list, and then ensure that there is a memory region
// in the memory list that covers the instruction pointer from
// the exception record.
Minidump minidump(minidump_filename);
ASSERT_TRUE(minidump.Read());
MinidumpException* exception = minidump.GetException();
MinidumpMemoryList* memory_list = minidump.GetMemoryList();
ASSERT_TRUE(exception);
ASSERT_TRUE(memory_list);
ASSERT_LT(0, memory_list->region_count());
MinidumpContext* context = exception->GetContext();
ASSERT_TRUE(context);
u_int64_t instruction_pointer;
switch (context->GetContextCPU()) {
case MD_CONTEXT_X86:
instruction_pointer = context->GetContextX86()->eip;
break;
case MD_CONTEXT_AMD64:
instruction_pointer = context->GetContextAMD64()->rip;
break;
case MD_CONTEXT_ARM:
instruction_pointer = context->GetContextARM()->iregs[15];
break;
default:
FAIL() << "Unknown context CPU: " << context->GetContextCPU();
break;
}
MinidumpMemoryRegion* region =
memory_list->GetMemoryRegionForAddress(instruction_pointer);
ASSERT_TRUE(region);
const size_t kPrefixSize = 128; // bytes
EXPECT_EQ(kPrefixSize + sizeof(instructions), region->GetSize());
const u_int8_t* bytes = region->GetMemory();
ASSERT_TRUE(bytes);
u_int8_t prefix_bytes[kPrefixSize];
memset(prefix_bytes, 0, sizeof(prefix_bytes));
EXPECT_TRUE(memcmp(bytes, prefix_bytes, sizeof(prefix_bytes)) == 0);
EXPECT_TRUE(memcmp(bytes + kPrefixSize,
instructions, sizeof(instructions)) == 0);
unlink(minidump_filename.c_str());
free(filename);
}
// Ensure that an extra memory block doesn't get added when the
// instruction pointer is not in mapped memory.
TEST(ExceptionHandlerTest, InstructionPointerMemoryNullPointer) {
int fds[2];
ASSERT_NE(pipe(fds), -1);
const pid_t child = fork();
if (child == 0) {
close(fds[0]);
ExceptionHandler handler(TEMPDIR, NULL, DoneCallback, (void*) fds[1],
true);
// Try calling a NULL pointer.
typedef void (*void_function)(void);
void_function memory_function =
reinterpret_cast<void_function>(NULL);
memory_function();
}
close(fds[1]);
int status;
ASSERT_NE(HANDLE_EINTR(waitpid(child, &status, 0)), -1);
ASSERT_TRUE(WIFSIGNALED(status));
ASSERT_EQ(WTERMSIG(status), SIGSEGV);
struct pollfd pfd;
memset(&pfd, 0, sizeof(pfd));
pfd.fd = fds[0];
pfd.events = POLLIN | POLLERR;
const int r = HANDLE_EINTR(poll(&pfd, 1, 0));
ASSERT_EQ(r, 1);
ASSERT_TRUE(pfd.revents & POLLIN);
uint32_t len;
ASSERT_EQ(read(fds[0], &len, sizeof(len)), (ssize_t)sizeof(len));
ASSERT_LT(len, (uint32_t)2048);
char* filename = reinterpret_cast<char*>(malloc(len + 1));
ASSERT_EQ(read(fds[0], filename, len), len);
filename[len] = 0;
close(fds[0]);
const std::string minidump_filename = std::string(TEMPDIR) + "/" + filename +
".dmp";
struct stat st;
ASSERT_EQ(stat(minidump_filename.c_str(), &st), 0);
ASSERT_GT(st.st_size, 0u);
// Read the minidump. Locate the exception record and the
// memory list, and then ensure that there is a memory region
// in the memory list that covers the instruction pointer from
// the exception record.
Minidump minidump(minidump_filename);
ASSERT_TRUE(minidump.Read());
MinidumpException* exception = minidump.GetException();
MinidumpMemoryList* memory_list = minidump.GetMemoryList();
ASSERT_TRUE(exception);
ASSERT_TRUE(memory_list);
ASSERT_EQ((unsigned int)1, memory_list->region_count());
unlink(minidump_filename.c_str());
free(filename);
}
static bool SimpleCallback(const char* dump_path,
const char* minidump_id,
void* context,
bool succeeded) {
if (!succeeded)
return succeeded;
string* minidump_file = reinterpret_cast<string*>(context);
minidump_file->append(dump_path);
minidump_file->append("/");
minidump_file->append(minidump_id);
minidump_file->append(".dmp");
return true;
}
// Test that anonymous memory maps can be annotated with names and IDs.
TEST(ExceptionHandlerTest, ModuleInfo) {
// These are defined here so the parent can use them to check the
// data from the minidump afterwards.
const u_int32_t kMemorySize = sysconf(_SC_PAGESIZE);
const char* kMemoryName = "a fake module";
const u_int8_t kModuleGUID[sizeof(MDGUID)] = {
0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF
};
char module_identifier_buffer[kGUIDStringSize];
FileID::ConvertIdentifierToString(kModuleGUID,
module_identifier_buffer,
sizeof(module_identifier_buffer));
string module_identifier(module_identifier_buffer);
// Strip out dashes
size_t pos;
while ((pos = module_identifier.find('-')) != string::npos) {
module_identifier.erase(pos, 1);
}
// And append a zero, because module IDs include an "age" field
// which is always zero on Linux.
module_identifier += "0";
// Get some memory.
char* memory =
reinterpret_cast<char*>(mmap(NULL,
kMemorySize,
PROT_READ | PROT_WRITE,
MAP_PRIVATE | MAP_ANON,
-1,
0));
const u_int64_t kMemoryAddress = reinterpret_cast<u_int64_t>(memory);
ASSERT_TRUE(memory);
string minidump_filename;
ExceptionHandler handler(TEMPDIR, NULL, SimpleCallback,
(void*)&minidump_filename, true);
// Add info about the anonymous memory mapping.
handler.AddMappingInfo(kMemoryName,
kModuleGUID,
kMemoryAddress,
kMemorySize,
0);
handler.WriteMinidump();
// Read the minidump. Load the module list, and ensure that
// the mmap'ed |memory| is listed with the given module name
// and debug ID.
Minidump minidump(minidump_filename);
ASSERT_TRUE(minidump.Read());
MinidumpModuleList* module_list = minidump.GetModuleList();
ASSERT_TRUE(module_list);
const MinidumpModule* module =
module_list->GetModuleForAddress(kMemoryAddress);
ASSERT_TRUE(module);
EXPECT_EQ(kMemoryAddress, module->base_address());
EXPECT_EQ(kMemorySize, module->size());
EXPECT_EQ(kMemoryName, module->code_file());
EXPECT_EQ(module_identifier, module->debug_identifier());
unlink(minidump_filename.c_str());
}
static const unsigned kControlMsgSize =
CMSG_SPACE(sizeof(int)) + CMSG_SPACE(sizeof(struct ucred));
static bool
CrashHandler(const void* crash_context, size_t crash_context_size,
void* context) {
const int fd = (intptr_t) context;
int fds[2];
pipe(fds);
struct kernel_msghdr msg = {0};
struct kernel_iovec iov;
iov.iov_base = const_cast<void*>(crash_context);
iov.iov_len = crash_context_size;
msg.msg_iov = &iov;
msg.msg_iovlen = 1;
char cmsg[kControlMsgSize];
memset(cmsg, 0, kControlMsgSize);
msg.msg_control = cmsg;
msg.msg_controllen = sizeof(cmsg);
struct cmsghdr *hdr = CMSG_FIRSTHDR(&msg);
hdr->cmsg_level = SOL_SOCKET;
hdr->cmsg_type = SCM_RIGHTS;
hdr->cmsg_len = CMSG_LEN(sizeof(int));
*((int*) CMSG_DATA(hdr)) = fds[1];
hdr = CMSG_NXTHDR((struct msghdr*) &msg, hdr);
hdr->cmsg_level = SOL_SOCKET;
hdr->cmsg_type = SCM_CREDENTIALS;
hdr->cmsg_len = CMSG_LEN(sizeof(struct ucred));
struct ucred *cred = reinterpret_cast<struct ucred*>(CMSG_DATA(hdr));
cred->uid = getuid();
cred->gid = getgid();
cred->pid = getpid();
HANDLE_EINTR(sys_sendmsg(fd, &msg, 0));
sys_close(fds[1]);
char b;
HANDLE_EINTR(sys_read(fds[0], &b, 1));
return true;
}
TEST(ExceptionHandlerTest, ExternalDumper) {
int fds[2];
ASSERT_NE(socketpair(AF_UNIX, SOCK_DGRAM, 0, fds), -1);
static const int on = 1;
setsockopt(fds[0], SOL_SOCKET, SO_PASSCRED, &on, sizeof(on));
setsockopt(fds[1], SOL_SOCKET, SO_PASSCRED, &on, sizeof(on));
const pid_t child = fork();
if (child == 0) {
close(fds[0]);
ExceptionHandler handler("/tmp1", NULL, NULL, (void*) fds[1], true);
handler.set_crash_handler(CrashHandler);
*reinterpret_cast<volatile int*>(NULL) = 0;
}
close(fds[1]);
struct msghdr msg = {0};
struct iovec iov;
static const unsigned kCrashContextSize =
sizeof(ExceptionHandler::CrashContext);
char context[kCrashContextSize];
char control[kControlMsgSize];
iov.iov_base = context;
iov.iov_len = kCrashContextSize;
msg.msg_iov = &iov;
msg.msg_iovlen = 1;
msg.msg_control = control;
msg.msg_controllen = kControlMsgSize;
const ssize_t n = HANDLE_EINTR(recvmsg(fds[0], &msg, 0));
ASSERT_EQ(n, kCrashContextSize);
ASSERT_EQ(msg.msg_controllen, kControlMsgSize);
ASSERT_EQ(msg.msg_flags, 0);
pid_t crashing_pid = -1;
int signal_fd = -1;
for (struct cmsghdr *hdr = CMSG_FIRSTHDR(&msg); hdr;
hdr = CMSG_NXTHDR(&msg, hdr)) {
if (hdr->cmsg_level != SOL_SOCKET)
continue;
if (hdr->cmsg_type == SCM_RIGHTS) {
const unsigned len = hdr->cmsg_len -
(((uint8_t*)CMSG_DATA(hdr)) - (uint8_t*)hdr);
ASSERT_EQ(len, sizeof(int));
signal_fd = *((int *) CMSG_DATA(hdr));
} else if (hdr->cmsg_type == SCM_CREDENTIALS) {
const struct ucred *cred =
reinterpret_cast<struct ucred*>(CMSG_DATA(hdr));
crashing_pid = cred->pid;
}
}
ASSERT_NE(crashing_pid, -1);
ASSERT_NE(signal_fd, -1);
char templ[] = TEMPDIR "/exception-handler-unittest-XXXXXX";
mktemp(templ);
ASSERT_TRUE(WriteMinidump(templ, crashing_pid, context,
kCrashContextSize));
static const char b = 0;
HANDLE_EINTR(write(signal_fd, &b, 1));
int status;
ASSERT_NE(HANDLE_EINTR(waitpid(child, &status, 0)), -1);
ASSERT_TRUE(WIFSIGNALED(status));
ASSERT_EQ(WTERMSIG(status), SIGSEGV);
struct stat st;
ASSERT_EQ(stat(templ, &st), 0);
ASSERT_GT(st.st_size, 0u);
unlink(templ);
}

View File

@@ -1,411 +0,0 @@
// Copyright (c) 2006, Google Inc.
// All rights reserved.
//
// Author: Li Liu
//
// 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 <errno.h>
#include <dirent.h>
#include <fcntl.h>
#include <sys/ptrace.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/wait.h>
#include <string.h>
#include <algorithm>
#include <cassert>
#include <cstdio>
#include <cstdlib>
#include <functional>
#include "client/linux/handler/linux_thread.h"
using namespace google_breakpad;
// This unamed namespace contains helper function.
namespace {
// Context information for the callbacks when validating address by listing
// modules.
struct AddressValidatingContext {
uintptr_t address;
bool is_mapped;
AddressValidatingContext() : address(0UL), is_mapped(false) {
}
};
// Convert from string to int.
bool LocalAtoi(char *s, int *r) {
assert(s != NULL);
assert(r != NULL);
char *endptr = NULL;
int ret = strtol(s, &endptr, 10);
if (endptr == s)
return false;
*r = ret;
return true;
}
// Fill the proc path of a thread given its id.
void FillProcPath(int pid, char *path, int path_size) {
char pid_str[32];
snprintf(pid_str, sizeof(pid_str), "%d", pid);
snprintf(path, path_size, "/proc/%s/", pid_str);
}
// Read thread info from /proc/$pid/status.
bool ReadThreadInfo(int pid, ThreadInfo *info) {
assert(info != NULL);
char status_path[80];
// Max size we want to read from status file.
static const int kStatusMaxSize = 1024;
char status_content[kStatusMaxSize];
FillProcPath(pid, status_path, sizeof(status_path));
strcat(status_path, "status");
int fd = open(status_path, O_RDONLY, 0);
if (fd < 0)
return false;
int num_read = read(fd, status_content, kStatusMaxSize - 1);
if (num_read < 0) {
close(fd);
return false;
}
close(fd);
status_content[num_read] = '\0';
char *tgid_start = strstr(status_content, "Tgid:");
if (tgid_start)
sscanf(tgid_start, "Tgid:\t%d\n", &(info->tgid));
else
// tgid not supported by kernel??
info->tgid = 0;
tgid_start = strstr(status_content, "Pid:");
if (tgid_start) {
sscanf(tgid_start, "Pid:\t%d\n" "PPid:\t%d\n", &(info->pid),
&(info->ppid));
return true;
}
return false;
}
// Callback invoked for each mapped module.
// It use the module's adderss range to validate the address.
bool IsAddressInModuleCallback(const ModuleInfo &module_info,
void *context) {
AddressValidatingContext *addr =
reinterpret_cast<AddressValidatingContext *>(context);
addr->is_mapped = ((addr->address >= module_info.start_addr) &&
(addr->address <= module_info.start_addr +
module_info.size));
return !addr->is_mapped;
}
#if defined(__i386__) && !defined(NO_FRAME_POINTER)
void *GetNextFrame(void **last_ebp) {
void *sp = *last_ebp;
if ((unsigned long)sp == (unsigned long)last_ebp)
return NULL;
if ((unsigned long)sp & (sizeof(void *) - 1))
return NULL;
if ((unsigned long)sp - (unsigned long)last_ebp > 100000)
return NULL;
return sp;
}
#else
void *GetNextFrame(void **last_ebp) {
return reinterpret_cast<void*>(last_ebp);
}
#endif
// Suspend a thread by attaching to it.
bool SuspendThread(int pid, void *context) {
// This may fail if the thread has just died or debugged.
errno = 0;
if (ptrace(PTRACE_ATTACH, pid, NULL, NULL) != 0 &&
errno != 0) {
return false;
}
while (waitpid(pid, NULL, __WALL) < 0) {
if (errno != EINTR) {
ptrace(PTRACE_DETACH, pid, NULL, NULL);
return false;
}
}
return true;
}
// Resume a thread by detaching from it.
bool ResumeThread(int pid, void *context) {
return ptrace(PTRACE_DETACH, pid, NULL, NULL) >= 0;
}
// Callback to get the thread information.
// Will be called for each thread found.
bool ThreadInfoCallback(int pid, void *context) {
CallbackParam<ThreadCallback> *thread_callback =
reinterpret_cast<CallbackParam<ThreadCallback> *>(context);
ThreadInfo thread_info;
if (ReadThreadInfo(pid, &thread_info) && thread_callback) {
// Invoke callback from caller.
return (thread_callback->call_back)(thread_info, thread_callback->context);
}
return false;
}
} // namespace
namespace google_breakpad {
LinuxThread::LinuxThread(int pid) : pid_(pid) , threads_suspened_(false) {
}
LinuxThread::~LinuxThread() {
if (threads_suspened_)
ResumeAllThreads();
}
int LinuxThread::SuspendAllThreads() {
CallbackParam<PidCallback> callback_param(SuspendThread, NULL);
int thread_count = 0;
if ((thread_count = IterateProcSelfTask(pid_, &callback_param)) > 0)
threads_suspened_ = true;
return thread_count;
}
void LinuxThread::ResumeAllThreads() const {
CallbackParam<PidCallback> callback_param(ResumeThread, NULL);
IterateProcSelfTask(pid_, &callback_param);
}
int LinuxThread::GetThreadCount() const {
return IterateProcSelfTask(pid_, NULL);
}
int LinuxThread::ListThreads(
CallbackParam<ThreadCallback> *thread_callback_param) const {
CallbackParam<PidCallback> callback_param(ThreadInfoCallback,
thread_callback_param);
return IterateProcSelfTask(pid_, &callback_param);
}
bool LinuxThread::GetRegisters(int pid, user_regs_struct *regs) const {
assert(regs);
return (regs != NULL &&
(ptrace(PTRACE_GETREGS, pid, NULL, regs) == 0) &&
errno == 0);
}
// Get the floating-point registers of a thread.
// The caller must get the thread pid by ListThreads.
bool LinuxThread::GetFPRegisters(int pid, user_fpregs_struct *regs) const {
assert(regs);
return (regs != NULL &&
(ptrace(PTRACE_GETREGS, pid, NULL, regs) ==0) &&
errno == 0);
}
bool LinuxThread::GetFPXRegisters(int pid, user_fpxregs_struct *regs) const {
assert(regs);
return (regs != NULL &&
(ptrace(PTRACE_GETFPREGS, pid, NULL, regs) != 0) &&
errno == 0);
}
bool LinuxThread::GetDebugRegisters(int pid, DebugRegs *regs) const {
assert(regs);
#define GET_DR(name, num)\
name->dr##num = ptrace(PTRACE_PEEKUSER, pid,\
offsetof(struct user, u_debugreg[num]), NULL)
GET_DR(regs, 0);
GET_DR(regs, 1);
GET_DR(regs, 2);
GET_DR(regs, 3);
GET_DR(regs, 4);
GET_DR(regs, 5);
GET_DR(regs, 6);
GET_DR(regs, 7);
return true;
}
int LinuxThread::GetThreadStackDump(uintptr_t current_ebp,
uintptr_t current_esp,
void *buf,
int buf_size) const {
assert(buf);
assert(buf_size > 0);
uintptr_t stack_bottom = GetThreadStackBottom(current_ebp);
int size = stack_bottom - current_esp;
size = buf_size > size ? size : buf_size;
if (size > 0)
memcpy(buf, reinterpret_cast<void*>(current_esp), size);
return size;
}
// Get the stack bottom of a thread by stack walking. It works
// unless the stack has been corrupted or the frame pointer has been omited.
// This is just a temporary solution before we get better ideas about how
// this can be done.
//
// We will check each frame address by checking into module maps.
// TODO(liuli): Improve it.
uintptr_t LinuxThread::GetThreadStackBottom(uintptr_t current_ebp) const {
void **sp = reinterpret_cast<void **>(current_ebp);
void **previous_sp = sp;
while (sp && IsAddressMapped((uintptr_t)sp)) {
previous_sp = sp;
sp = reinterpret_cast<void **>(GetNextFrame(sp));
}
return (uintptr_t)previous_sp;
}
int LinuxThread::GetModuleCount() const {
return ListModules(NULL);
}
int LinuxThread::ListModules(
CallbackParam<ModuleCallback> *callback_param) const {
char line[512];
const char *maps_path = "/proc/self/maps";
int module_count = 0;
FILE *fp = fopen(maps_path, "r");
if (fp == NULL)
return -1;
uintptr_t start_addr;
uintptr_t end_addr;
while (fgets(line, sizeof(line), fp) != NULL) {
if (sscanf(line, "%x-%x", &start_addr, &end_addr) == 2) {
ModuleInfo module;
memset(&module, 0, sizeof(module));
module.start_addr = start_addr;
module.size = end_addr - start_addr;
char *name = NULL;
assert(module.size > 0);
// Only copy name if the name is a valid path name.
if ((name = strchr(line, '/')) != NULL) {
// Get rid of the last '\n' in line
char *last_return = strchr(line, '\n');
if (last_return != NULL)
*last_return = '\0';
// Keep a space for the ending 0.
strncpy(module.name, name, sizeof(module.name) - 1);
++module_count;
}
if (callback_param &&
!(callback_param->call_back(module, callback_param->context)))
break;
}
}
fclose(fp);
return module_count;
}
// Parse /proc/$pid/tasks to list all the threads of the process identified by
// pid.
int LinuxThread::IterateProcSelfTask(int pid,
CallbackParam<PidCallback> *callback_param) const {
char task_path[80];
FillProcPath(pid, task_path, sizeof(task_path));
strcat(task_path, "task");
DIR *dir = opendir(task_path);
if (dir == NULL)
return -1;
int pid_number = 0;
// Record the last pid we've found. This is used for duplicated thread
// removal. Duplicated thread information can be found in /proc/$pid/tasks.
int last_pid = -1;
struct dirent *entry = NULL;
while ((entry = readdir(dir)) != NULL) {
if (strcmp(entry->d_name, ".") &&
strcmp(entry->d_name, "..")) {
int tpid = 0;
if (LocalAtoi(entry->d_name, &tpid) &&
last_pid != tpid) {
last_pid = tpid;
++pid_number;
// Invoke the callback.
if (callback_param &&
!(callback_param->call_back)(tpid, callback_param->context))
break;
}
}
}
closedir(dir);
return pid_number;
}
// Check if the address is a valid virtual address.
// If the address is in any of the mapped modules, we take it as valid.
// Otherwise it is invalid.
bool LinuxThread::IsAddressMapped(uintptr_t address) const {
AddressValidatingContext addr;
addr.address = address;
CallbackParam<ModuleCallback> callback_param(IsAddressInModuleCallback,
&addr);
ListModules(&callback_param);
return addr.is_mapped;
}
bool LinuxThread::FindSigContext(uintptr_t sighandler_ebp,
struct sigcontext **sig_ctx) {
uintptr_t previous_ebp;
const int MAX_STACK_DEPTH = 10;
int depth_counter = 0;
do {
// We're looking for a |struct sigcontext| as the second parameter
// to a signal handler function call. Luckily, the sigcontext
// has an ebp member which should match the ebp pointed to
// by the ebp of the signal handler frame.
previous_ebp = reinterpret_cast<uintptr_t>(GetNextFrame(
reinterpret_cast<void**>(sighandler_ebp)));
// The stack looks like this:
// | previous ebp | previous eip | first param | second param |,
// so we need to offset by 3 to get to the second parameter.
*sig_ctx = reinterpret_cast<struct sigcontext*>(sighandler_ebp +
3 * sizeof(uintptr_t));
sighandler_ebp = previous_ebp;
depth_counter++;
} while(previous_ebp != (*sig_ctx)->ebp && sighandler_ebp != 0 &&
IsAddressMapped(sighandler_ebp) && depth_counter < MAX_STACK_DEPTH);
return previous_ebp == (*sig_ctx)->ebp && previous_ebp != 0;
}
} // namespace google_breakpad

View File

@@ -1,204 +0,0 @@
// Copyright (c) 2006, Google Inc.
// All rights reserved.
//
// Author: Li Liu
//
// 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_HANDLER_LINUX_THREAD_H__
#define CLIENT_LINUX_HANDLER_LINUX_THREAD_H__
#include <stdint.h>
#include <sys/user.h>
namespace google_breakpad {
// Max module path name length.
#define kMaxModuleNameLength 256
// Holding information about a thread in the process.
struct ThreadInfo {
// Id of the thread group.
int tgid;
// Id of the thread.
int pid;
// Id of the parent process.
int ppid;
};
// Holding infomaton about a module in the process.
struct ModuleInfo {
char name[kMaxModuleNameLength];
uintptr_t start_addr;
int size;
};
// Holding debug registers.
struct DebugRegs {
int dr0;
int dr1;
int dr2;
int dr3;
int dr4;
int dr5;
int dr6;
int dr7;
};
// A callback to run when got a thread in the process.
// Return true will go on to the next thread while return false will stop the
// iteration.
typedef bool (*ThreadCallback)(const ThreadInfo &thread_info, void *context);
// A callback to run when a new module is found in the process.
// Return true will go on to the next module while return false will stop the
// iteration.
typedef bool (*ModuleCallback)(const ModuleInfo &module_info, void *context);
// Holding the callback information.
template<class CallbackFunc>
struct CallbackParam {
// Callback function address.
CallbackFunc call_back;
// Callback context;
void *context;
CallbackParam() : call_back(NULL), context(NULL) {
}
CallbackParam(CallbackFunc func, void *func_context) :
call_back(func), context(func_context) {
}
};
///////////////////////////////////////////////////////////////////////////////
//
// LinuxThread
//
// Provides handy support for operation on linux threads.
// It uses ptrace to get thread registers. Since ptrace only works in a
// different process other than the one being ptraced, user of this class
// should create another process before using the class.
//
// The process should be created in the following way:
// int cloned_pid = clone(ProcessEntryFunction, stack_address,
// CLONE_VM | CLONE_FILES | CLONE_FS | CLONE_UNTRACED,
// (void*)&arguments);
// waitpid(cloned_pid, NULL, __WALL);
//
// If CLONE_VM is not used, GetThreadStackBottom, GetThreadStackDump
// will not work since it just use memcpy to get the stack dump.
//
class LinuxThread {
public:
// Create a LinuxThread instance to list all the threads in a process.
explicit LinuxThread(int pid);
~LinuxThread();
// Stop all the threads in the process.
// Return the number of stopped threads in the process.
// Return -1 means failed to stop threads.
int SuspendAllThreads();
// Resume all the suspended threads.
void ResumeAllThreads() const;
// Get the count of threads in the process.
// Return -1 means error.
int GetThreadCount() const;
// List the threads of process.
// Whenever there is a thread found, the callback will be invoked to process
// the information.
// Return number of threads listed.
int ListThreads(CallbackParam<ThreadCallback> *thread_callback_param) const;
// Get the general purpose registers of a thread.
// The caller must get the thread pid by ListThreads.
bool GetRegisters(int pid, user_regs_struct *regs) const;
// Get the floating-point registers of a thread.
// The caller must get the thread pid by ListThreads.
bool GetFPRegisters(int pid, user_fpregs_struct *regs) const;
// Get all the extended floating-point registers. May not work on all
// machines.
// The caller must get the thread pid by ListThreads.
bool GetFPXRegisters(int pid, user_fpxregs_struct *regs) const;
// Get the debug registers.
// The caller must get the thread pid by ListThreads.
bool GetDebugRegisters(int pid, DebugRegs *regs) const;
// Get the stack memory dump.
int GetThreadStackDump(uintptr_t current_ebp,
uintptr_t current_esp,
void *buf,
int buf_size) const;
// Get the module count of the current process.
int GetModuleCount() const;
// Get the mapped modules in the address space.
// Whenever a module is found, the callback will be invoked to process the
// information.
// Return how may modules are found.
int ListModules(CallbackParam<ModuleCallback> *callback_param) const;
// Get the bottom of the stack from ebp.
uintptr_t GetThreadStackBottom(uintptr_t current_ebp) const;
// Finds a sigcontext on the stack given the ebp of our signal handler.
bool FindSigContext(uintptr_t sighandler_ebp, struct sigcontext **sig_ctx);
private:
// This callback will run when a new thread has been found.
typedef bool (*PidCallback)(int pid, void *context);
// Read thread information from /proc/$pid/task.
// Whenever a thread has been found, and callback will be invoked with
// the pid of the thread.
// Return number of threads found.
// Return -1 means the directory doesn't exist.
int IterateProcSelfTask(int pid,
CallbackParam<PidCallback> *callback_param) const;
// Check if the address is a valid virtual address.
bool IsAddressMapped(uintptr_t address) const;
private:
// The pid of the process we are listing threads.
int pid_;
// Mark if we have suspended the threads.
bool threads_suspened_;
};
} // namespace google_breakpad
#endif // CLIENT_LINUX_HANDLER_LINUX_THREAD_H__

View File

@@ -1,224 +0,0 @@
// Copyright (c) 2006, Google Inc.
// All rights reserved.
//
// Author: Li Liu
//
// 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 <pthread.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/wait.h>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include "client/linux/handler/linux_thread.h"
using namespace google_breakpad;
// Thread use this to see if it should stop working.
static bool should_exit = false;
static void foo2(int *a) {
// Stack variable, used for debugging stack dumps.
int c = 0xcccccccc;
c = c;
while (!should_exit)
sleep(1);
}
static void foo() {
// Stack variable, used for debugging stack dumps.
int a = 0xaaaaaaaa;
foo2(&a);
}
static void *thread_main(void *) {
// Stack variable, used for debugging stack dumps.
int b = 0xbbbbbbbb;
b = b;
while (!should_exit) {
foo();
}
return NULL;
}
static void CreateThreads(int num) {
pthread_t handle;
for (int i = 0; i < num; i++) {
if (0 != pthread_create(&handle, NULL, thread_main, NULL))
fprintf(stderr, "Failed to create thread.\n");
else
pthread_detach(handle);
}
}
static bool ProcessOneModule(const struct ModuleInfo &module_info,
void *context) {
printf("0x%x[%8d] %s\n", module_info.start_addr, module_info.size,
module_info.name);
return true;
}
static bool ProcessOneThread(const struct ThreadInfo &thread_info,
void *context) {
printf("\n\nPID: %d, TGID: %d, PPID: %d\n",
thread_info.pid,
thread_info.tgid,
thread_info.ppid);
struct user_regs_struct regs;
struct user_fpregs_struct fp_regs;
struct user_fpxregs_struct fpx_regs;
struct DebugRegs dbg_regs;
LinuxThread *threads = reinterpret_cast<LinuxThread *>(context);
memset(&regs, 0, sizeof(regs));
if (threads->GetRegisters(thread_info.pid, &regs)) {
printf(" gs = 0x%lx\n", regs.xgs);
printf(" fs = 0x%lx\n", regs.xfs);
printf(" es = 0x%lx\n", regs.xes);
printf(" ds = 0x%lx\n", regs.xds);
printf(" edi = 0x%lx\n", regs.edi);
printf(" esi = 0x%lx\n", regs.esi);
printf(" ebx = 0x%lx\n", regs.ebx);
printf(" edx = 0x%lx\n", regs.edx);
printf(" ecx = 0x%lx\n", regs.ecx);
printf(" eax = 0x%lx\n", regs.eax);
printf(" ebp = 0x%lx\n", regs.ebp);
printf(" eip = 0x%lx\n", regs.eip);
printf(" cs = 0x%lx\n", regs.xcs);
printf(" eflags = 0x%lx\n", regs.eflags);
printf(" esp = 0x%lx\n", regs.esp);
printf(" ss = 0x%lx\n", regs.xss);
} else {
fprintf(stderr, "ERROR: Failed to get general purpose registers\n");
}
memset(&fp_regs, 0, sizeof(fp_regs));
if (threads->GetFPRegisters(thread_info.pid, &fp_regs)) {
printf("\n Floating point registers:\n");
printf(" fctl = 0x%lx\n", fp_regs.cwd);
printf(" fstat = 0x%lx\n", fp_regs.swd);
printf(" ftag = 0x%lx\n", fp_regs.twd);
printf(" fioff = 0x%lx\n", fp_regs.fip);
printf(" fiseg = 0x%lx\n", fp_regs.fcs);
printf(" fooff = 0x%lx\n", fp_regs.foo);
printf(" foseg = 0x%lx\n", fp_regs.fos);
int st_space_size = sizeof(fp_regs.st_space) / sizeof(fp_regs.st_space[0]);
printf(" st_space[%2d] = 0x", st_space_size);
for (int i = 0; i < st_space_size; ++i)
printf("%02lx", fp_regs.st_space[i]);
printf("\n");
} else {
fprintf(stderr, "ERROR: Failed to get floating-point registers\n");
}
memset(&fpx_regs, 0, sizeof(fpx_regs));
if (threads->GetFPXRegisters(thread_info.pid, &fpx_regs)) {
printf("\n Extended floating point registers:\n");
printf(" fctl = 0x%x\n", fpx_regs.cwd);
printf(" fstat = 0x%x\n", fpx_regs.swd);
printf(" ftag = 0x%x\n", fpx_regs.twd);
printf(" fioff = 0x%lx\n", fpx_regs.fip);
printf(" fiseg = 0x%lx\n", fpx_regs.fcs);
printf(" fooff = 0x%lx\n", fpx_regs.foo);
printf(" foseg = 0x%lx\n", fpx_regs.fos);
printf(" fop = 0x%x\n", fpx_regs.fop);
printf(" mxcsr = 0x%lx\n", fpx_regs.mxcsr);
int space_size = sizeof(fpx_regs.st_space) / sizeof(fpx_regs.st_space[0]);
printf(" st_space[%2d] = 0x", space_size);
for (int i = 0; i < space_size; ++i)
printf("%02lx", fpx_regs.st_space[i]);
printf("\n");
space_size = sizeof(fpx_regs.xmm_space) / sizeof(fpx_regs.xmm_space[0]);
printf(" xmm_space[%2d] = 0x", space_size);
for (int i = 0; i < space_size; ++i)
printf("%02lx", fpx_regs.xmm_space[i]);
printf("\n");
}
if (threads->GetDebugRegisters(thread_info.pid, &dbg_regs)) {
printf("\n Debug registers:\n");
printf(" dr0 = 0x%x\n", dbg_regs.dr0);
printf(" dr1 = 0x%x\n", dbg_regs.dr1);
printf(" dr2 = 0x%x\n", dbg_regs.dr2);
printf(" dr3 = 0x%x\n", dbg_regs.dr3);
printf(" dr4 = 0x%x\n", dbg_regs.dr4);
printf(" dr5 = 0x%x\n", dbg_regs.dr5);
printf(" dr6 = 0x%x\n", dbg_regs.dr6);
printf(" dr7 = 0x%x\n", dbg_regs.dr7);
printf("\n");
}
if (regs.esp != 0) {
// Print the stack content.
int size = 1024 * 2;
char *buf = new char[size];
size = threads->GetThreadStackDump(regs.ebp,
regs.esp,
(void*)buf, size);
printf(" Stack content: = 0x");
size /= sizeof(unsigned long);
unsigned long *p_buf = (unsigned long *)(buf);
for (int i = 0; i < size; i += 1)
printf("%.8lx ", p_buf[i]);
delete []buf;
printf("\n");
}
return true;
}
static int PrintAllThreads(void *argument) {
int pid = (int)argument;
LinuxThread threads(pid);
int total_thread = threads.SuspendAllThreads();
printf("There are %d threads in the process: %d\n", total_thread, pid);
int total_module = threads.GetModuleCount();
printf("There are %d modules in the process: %d\n", total_module, pid);
CallbackParam<ModuleCallback> module_callback(ProcessOneModule, &threads);
threads.ListModules(&module_callback);
CallbackParam<ThreadCallback> thread_callback(ProcessOneThread, &threads);
threads.ListThreads(&thread_callback);
return 0;
}
int main(int argc, char **argv) {
int pid = getpid();
printf("Main thread is %d\n", pid);
CreateThreads(1);
// Create stack for the process.
char *stack = new char[1024 * 100];
int cloned_pid = clone(PrintAllThreads, stack + 1024 * 100,
CLONE_VM | CLONE_FILES | CLONE_FS | CLONE_UNTRACED,
(void*)getpid());
waitpid(cloned_pid, NULL, __WALL);
should_exit = true;
printf("Test finished.\n");
delete []stack;
return 0;
}

View File

@@ -1,815 +0,0 @@
// Copyright (c) 2006, Google Inc.
// All rights reserved.
//
// Author: Li Liu
//
// 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 <fcntl.h>
#include <pthread.h>
#include <signal.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/utsname.h>
#include <sys/wait.h>
#include <cstdlib>
#include <ctime>
#include <string.h>
#include "common/linux/file_id.h"
#include "client/linux/handler/linux_thread.h"
#include "client/minidump_file_writer.h"
#include "client/minidump_file_writer-inl.h"
#include "google_breakpad/common/minidump_format.h"
#include "client/linux/handler/minidump_generator.h"
#ifndef CLONE_UNTRACED
#define CLONE_UNTRACED 0x00800000
#endif
// This unnamed namespace contains helper functions.
namespace {
using namespace google_breakpad;
// Argument for the writer function.
struct WriterArgument {
MinidumpFileWriter *minidump_writer;
// Context for the callback.
void *version_context;
// Pid of the thread who called WriteMinidumpToFile
int requester_pid;
// The stack bottom of the thread which caused the dump.
// Mainly used to find the thread id of the crashed thread since signal
// handler may not be called in the thread who caused it.
uintptr_t crashed_stack_bottom;
// Pid of the crashing thread.
int crashed_pid;
// Signal number when crash happed. Can be 0 if this is a requested dump.
int signo;
// The ebp of the signal handler frame. Can be zero if this
// is a requested dump.
uintptr_t sighandler_ebp;
// Signal context when crash happed. Can be NULL if this is a requested dump.
// This is actually an out parameter, but it will be filled in at the start
// of the writer thread.
struct sigcontext *sig_ctx;
// Used to get information about the threads.
LinuxThread *thread_lister;
};
// Holding context information for the callback of finding the crashing thread.
struct FindCrashThreadContext {
const LinuxThread *thread_lister;
uintptr_t crashing_stack_bottom;
int crashing_thread_pid;
FindCrashThreadContext() :
thread_lister(NULL),
crashing_stack_bottom(0UL),
crashing_thread_pid(-1) {
}
};
// Callback for list threads.
// It will compare the stack bottom of the provided thread with the stack
// bottom of the crashed thread, it they are eqaul, this is thread is the one
// who crashed.
bool IsThreadCrashedCallback(const ThreadInfo &thread_info, void *context) {
FindCrashThreadContext *crashing_context =
static_cast<FindCrashThreadContext *>(context);
const LinuxThread *thread_lister = crashing_context->thread_lister;
struct user_regs_struct regs;
if (thread_lister->GetRegisters(thread_info.pid, &regs)) {
uintptr_t last_ebp = regs.ebp;
uintptr_t stack_bottom = thread_lister->GetThreadStackBottom(last_ebp);
if (stack_bottom > last_ebp &&
stack_bottom == crashing_context->crashing_stack_bottom) {
// Got it. Stop iteration.
crashing_context->crashing_thread_pid = thread_info.pid;
return false;
}
}
return true;
}
// Find the crashing thread id.
// This is done based on stack bottom comparing.
int FindCrashingThread(uintptr_t crashing_stack_bottom,
int requester_pid,
const LinuxThread *thread_lister) {
FindCrashThreadContext context;
context.thread_lister = thread_lister;
context.crashing_stack_bottom = crashing_stack_bottom;
CallbackParam<ThreadCallback> callback_param(IsThreadCrashedCallback,
&context);
thread_lister->ListThreads(&callback_param);
return context.crashing_thread_pid;
}
// Write the thread stack info minidump.
bool WriteThreadStack(uintptr_t last_ebp,
uintptr_t last_esp,
const LinuxThread *thread_lister,
UntypedMDRVA *memory,
MDMemoryDescriptor *loc) {
// Maximum stack size for a thread.
uintptr_t stack_bottom = thread_lister->GetThreadStackBottom(last_ebp);
if (stack_bottom > last_esp) {
int size = stack_bottom - last_esp;
if (size > 0) {
if (!memory->Allocate(size))
return false;
memory->Copy(reinterpret_cast<void*>(last_esp), size);
loc->start_of_memory_range = 0 | last_esp;
loc->memory = memory->location();
}
return true;
}
return false;
}
// Write CPU context based on signal context.
bool WriteContext(MDRawContextX86 *context, const struct sigcontext *sig_ctx,
const DebugRegs *debug_regs) {
assert(sig_ctx != NULL);
context->context_flags = MD_CONTEXT_X86_FULL;
context->gs = sig_ctx->gs;
context->fs = sig_ctx->fs;
context->es = sig_ctx->es;
context->ds = sig_ctx->ds;
context->cs = sig_ctx->cs;
context->ss = sig_ctx->ss;
context->edi = sig_ctx->edi;
context->esi = sig_ctx->esi;
context->ebp = sig_ctx->ebp;
context->esp = sig_ctx->esp;
context->ebx = sig_ctx->ebx;
context->edx = sig_ctx->edx;
context->ecx = sig_ctx->ecx;
context->eax = sig_ctx->eax;
context->eip = sig_ctx->eip;
context->eflags = sig_ctx->eflags;
if (sig_ctx->fpstate != NULL) {
context->context_flags = MD_CONTEXT_X86_FULL |
MD_CONTEXT_X86_FLOATING_POINT;
context->float_save.control_word = sig_ctx->fpstate->cw;
context->float_save.status_word = sig_ctx->fpstate->sw;
context->float_save.tag_word = sig_ctx->fpstate->tag;
context->float_save.error_offset = sig_ctx->fpstate->ipoff;
context->float_save.error_selector = sig_ctx->fpstate->cssel;
context->float_save.data_offset = sig_ctx->fpstate->dataoff;
context->float_save.data_selector = sig_ctx->fpstate->datasel;
memcpy(context->float_save.register_area, sig_ctx->fpstate->_st,
sizeof(context->float_save.register_area));
}
if (debug_regs != NULL) {
context->context_flags |= MD_CONTEXT_X86_DEBUG_REGISTERS;
context->dr0 = debug_regs->dr0;
context->dr1 = debug_regs->dr1;
context->dr2 = debug_regs->dr2;
context->dr3 = debug_regs->dr3;
context->dr6 = debug_regs->dr6;
context->dr7 = debug_regs->dr7;
}
return true;
}
// Write CPU context based on provided registers.
bool WriteContext(MDRawContextX86 *context,
const struct user_regs_struct *regs,
const struct user_fpregs_struct *fp_regs,
const DebugRegs *dbg_regs) {
if (!context || !regs)
return false;
context->context_flags = MD_CONTEXT_X86_FULL;
context->cs = regs->xcs;
context->ds = regs->xds;
context->es = regs->xes;
context->fs = regs->xfs;
context->gs = regs->xgs;
context->ss = regs->xss;
context->edi = regs->edi;
context->esi = regs->esi;
context->ebx = regs->ebx;
context->edx = regs->edx;
context->ecx = regs->ecx;
context->eax = regs->eax;
context->ebp = regs->ebp;
context->eip = regs->eip;
context->esp = regs->esp;
context->eflags = regs->eflags;
if (dbg_regs != NULL) {
context->context_flags |= MD_CONTEXT_X86_DEBUG_REGISTERS;
context->dr0 = dbg_regs->dr0;
context->dr1 = dbg_regs->dr1;
context->dr2 = dbg_regs->dr2;
context->dr3 = dbg_regs->dr3;
context->dr6 = dbg_regs->dr6;
context->dr7 = dbg_regs->dr7;
}
if (fp_regs != NULL) {
context->context_flags |= MD_CONTEXT_X86_FLOATING_POINT;
context->float_save.control_word = fp_regs->cwd;
context->float_save.status_word = fp_regs->swd;
context->float_save.tag_word = fp_regs->twd;
context->float_save.error_offset = fp_regs->fip;
context->float_save.error_selector = fp_regs->fcs;
context->float_save.data_offset = fp_regs->foo;
context->float_save.data_selector = fp_regs->fos;
context->float_save.data_selector = fp_regs->fos;
memcpy(context->float_save.register_area, fp_regs->st_space,
sizeof(context->float_save.register_area));
}
return true;
}
// Write information about a crashed thread.
// When a thread crash, kernel will write something on the stack for processing
// signal. This makes the current stack not reliable, and our stack walker
// won't figure out the whole call stack for this. So we write the stack at the
// time of the crash into the minidump file, not the current stack.
bool WriteCrashedThreadStream(MinidumpFileWriter *minidump_writer,
const WriterArgument *writer_args,
const ThreadInfo &thread_info,
MDRawThread *thread) {
assert(writer_args->sig_ctx != NULL);
thread->thread_id = thread_info.pid;
UntypedMDRVA memory(minidump_writer);
if (!WriteThreadStack(writer_args->sig_ctx->ebp,
writer_args->sig_ctx->esp,
writer_args->thread_lister,
&memory,
&thread->stack))
return false;
TypedMDRVA<MDRawContextX86> context(minidump_writer);
if (!context.Allocate())
return false;
thread->thread_context = context.location();
memset(context.get(), 0, sizeof(MDRawContextX86));
return WriteContext(context.get(), writer_args->sig_ctx, NULL);
}
// Write information about a thread.
// This function only processes thread running normally at the crash.
bool WriteThreadStream(MinidumpFileWriter *minidump_writer,
const LinuxThread *thread_lister,
const ThreadInfo &thread_info,
MDRawThread *thread) {
thread->thread_id = thread_info.pid;
struct user_regs_struct regs;
memset(&regs, 0, sizeof(regs));
if (!thread_lister->GetRegisters(thread_info.pid, &regs)) {
perror(NULL);
return false;
}
UntypedMDRVA memory(minidump_writer);
if (!WriteThreadStack(regs.ebp,
regs.esp,
thread_lister,
&memory,
&thread->stack))
return false;
struct user_fpregs_struct fp_regs;
DebugRegs dbg_regs;
memset(&fp_regs, 0, sizeof(fp_regs));
// Get all the registers.
thread_lister->GetFPRegisters(thread_info.pid, &fp_regs);
thread_lister->GetDebugRegisters(thread_info.pid, &dbg_regs);
// Write context
TypedMDRVA<MDRawContextX86> context(minidump_writer);
if (!context.Allocate())
return false;
thread->thread_context = context.location();
memset(context.get(), 0, sizeof(MDRawContextX86));
return WriteContext(context.get(), &regs, &fp_regs, &dbg_regs);
}
bool WriteCPUInformation(MDRawSystemInfo *sys_info) {
const char *proc_cpu_path = "/proc/cpuinfo";
char line[128];
char vendor_id[13];
const char vendor_id_name[] = "vendor_id";
const size_t vendor_id_name_length = sizeof(vendor_id_name) - 1;
struct CpuInfoEntry {
const char *info_name;
int value;
} cpu_info_table[] = {
{ "processor", -1 },
{ "model", 0 },
{ "stepping", 0 },
{ "cpuid level", 0 },
{ NULL, -1 },
};
memset(vendor_id, 0, sizeof(vendor_id));
FILE *fp = fopen(proc_cpu_path, "r");
if (fp != NULL) {
while (fgets(line, sizeof(line), fp)) {
CpuInfoEntry *entry = &cpu_info_table[0];
while (entry->info_name != NULL) {
if (!strncmp(line, entry->info_name, strlen(entry->info_name))) {
char *value = strchr(line, ':');
value++;
if (value != NULL)
sscanf(value, " %d", &(entry->value));
}
entry++;
}
// special case for vendor_id
if (!strncmp(line, vendor_id_name, vendor_id_name_length)) {
char *value = strchr(line, ':');
if (value == NULL)
continue;
value++;
while (*value && isspace(*value))
value++;
if (*value) {
size_t length = strlen(value);
// we don't want the trailing newline
if (value[length - 1] == '\n')
length--;
// ensure we have space for the value
if (length < sizeof(vendor_id))
strncpy(vendor_id, value, length);
}
}
}
fclose(fp);
}
// /proc/cpuinfo contains cpu id, change it into number by adding one.
cpu_info_table[0].value++;
sys_info->number_of_processors = cpu_info_table[0].value;
sys_info->processor_level = cpu_info_table[3].value;
sys_info->processor_revision = cpu_info_table[1].value << 8 |
cpu_info_table[2].value;
sys_info->processor_architecture = MD_CPU_ARCHITECTURE_UNKNOWN;
struct utsname uts;
if (uname(&uts) == 0) {
// Match i*86 and x86* as X86 architecture.
if ((strstr(uts.machine, "x86") == uts.machine) ||
(strlen(uts.machine) == 4 &&
uts.machine[0] == 'i' &&
uts.machine[2] == '8' &&
uts.machine[3] == '6')) {
sys_info->processor_architecture = MD_CPU_ARCHITECTURE_X86;
if (vendor_id[0] != '\0')
memcpy(sys_info->cpu.x86_cpu_info.vendor_id, vendor_id,
sizeof(sys_info->cpu.x86_cpu_info.vendor_id));
}
}
return true;
}
bool WriteOSInformation(MinidumpFileWriter *minidump_writer,
MDRawSystemInfo *sys_info) {
sys_info->platform_id = MD_OS_LINUX;
struct utsname uts;
if (uname(&uts) == 0) {
char os_version[512];
size_t space_left = sizeof(os_version);
memset(os_version, 0, space_left);
const char *os_info_table[] = {
uts.sysname,
uts.release,
uts.version,
uts.machine,
"GNU/Linux",
NULL
};
for (const char **cur_os_info = os_info_table;
*cur_os_info != NULL;
cur_os_info++) {
if (cur_os_info != os_info_table && space_left > 1) {
strcat(os_version, " ");
space_left--;
}
if (space_left > strlen(*cur_os_info)) {
strcat(os_version, *cur_os_info);
space_left -= strlen(*cur_os_info);
} else {
break;
}
}
MDLocationDescriptor location;
if (!minidump_writer->WriteString(os_version, 0, &location))
return false;
sys_info->csd_version_rva = location.rva;
}
return true;
}
// Callback context for get writting thread information.
struct ThreadInfoCallbackCtx {
MinidumpFileWriter *minidump_writer;
const WriterArgument *writer_args;
TypedMDRVA<MDRawThreadList> *list;
int thread_index;
};
// Callback run for writing threads information in the process.
bool ThreadInfomationCallback(const ThreadInfo &thread_info,
void *context) {
ThreadInfoCallbackCtx *callback_context =
static_cast<ThreadInfoCallbackCtx *>(context);
bool success = true;
MDRawThread thread;
memset(&thread, 0, sizeof(MDRawThread));
if (thread_info.pid != callback_context->writer_args->crashed_pid ||
callback_context->writer_args->sig_ctx == NULL) {
success = WriteThreadStream(callback_context->minidump_writer,
callback_context->writer_args->thread_lister,
thread_info, &thread);
} else {
success = WriteCrashedThreadStream(callback_context->minidump_writer,
callback_context->writer_args,
thread_info, &thread);
}
if (success) {
callback_context->list->CopyIndexAfterObject(
callback_context->thread_index++,
&thread, sizeof(MDRawThread));
}
return success;
}
// Stream writers
bool WriteThreadListStream(MinidumpFileWriter *minidump_writer,
const WriterArgument *writer_args,
MDRawDirectory *dir) {
// Get the thread information.
const LinuxThread *thread_lister = writer_args->thread_lister;
int thread_count = thread_lister->GetThreadCount();
if (thread_count < 0)
return false;
TypedMDRVA<MDRawThreadList> list(minidump_writer);
if (!list.AllocateObjectAndArray(thread_count, sizeof(MDRawThread)))
return false;
dir->stream_type = MD_THREAD_LIST_STREAM;
dir->location = list.location();
list.get()->number_of_threads = thread_count;
ThreadInfoCallbackCtx context;
context.minidump_writer = minidump_writer;
context.writer_args = writer_args;
context.list = &list;
context.thread_index = 0;
CallbackParam<ThreadCallback> callback_param(ThreadInfomationCallback,
&context);
int written = thread_lister->ListThreads(&callback_param);
return written == thread_count;
}
bool WriteCVRecord(MinidumpFileWriter *minidump_writer,
MDRawModule *module,
const char *module_path) {
TypedMDRVA<MDCVInfoPDB70> cv(minidump_writer);
// Only return the last path component of the full module path
const char *module_name = strrchr(module_path, '/');
// Increment past the slash
if (module_name)
++module_name;
else
module_name = "<Unknown>";
size_t module_name_length = strlen(module_name);
if (!cv.AllocateObjectAndArray(module_name_length + 1, sizeof(u_int8_t)))
return false;
if (!cv.CopyIndexAfterObject(0, const_cast<char *>(module_name),
module_name_length))
return false;
module->cv_record = cv.location();
MDCVInfoPDB70 *cv_ptr = cv.get();
memset(cv_ptr, 0, sizeof(MDCVInfoPDB70));
cv_ptr->cv_signature = MD_CVINFOPDB70_SIGNATURE;
cv_ptr->age = 0;
// Get the module identifier
FileID file_id(module_path);
unsigned char identifier[16];
if (file_id.ElfFileIdentifier(identifier)) {
cv_ptr->signature.data1 = (uint32_t)identifier[0] << 24 |
(uint32_t)identifier[1] << 16 | (uint32_t)identifier[2] << 8 |
(uint32_t)identifier[3];
cv_ptr->signature.data2 = (uint32_t)identifier[4] << 8 | identifier[5];
cv_ptr->signature.data3 = (uint32_t)identifier[6] << 8 | identifier[7];
cv_ptr->signature.data4[0] = identifier[8];
cv_ptr->signature.data4[1] = identifier[9];
cv_ptr->signature.data4[2] = identifier[10];
cv_ptr->signature.data4[3] = identifier[11];
cv_ptr->signature.data4[4] = identifier[12];
cv_ptr->signature.data4[5] = identifier[13];
cv_ptr->signature.data4[6] = identifier[14];
cv_ptr->signature.data4[7] = identifier[15];
}
return true;
}
struct ModuleInfoCallbackCtx {
MinidumpFileWriter *minidump_writer;
const WriterArgument *writer_args;
TypedMDRVA<MDRawModuleList> *list;
int module_index;
};
bool ModuleInfoCallback(const ModuleInfo &module_info,
void *context) {
ModuleInfoCallbackCtx *callback_context =
static_cast<ModuleInfoCallbackCtx *>(context);
// Skip those modules without name, or those that are not modules.
if (strlen(module_info.name) == 0 ||
!strchr(module_info.name, '/'))
return true;
MDRawModule module;
memset(&module, 0, sizeof(module));
MDLocationDescriptor loc;
if (!callback_context->minidump_writer->WriteString(module_info.name, 0,
&loc))
return false;
module.base_of_image = (u_int64_t)module_info.start_addr;
module.size_of_image = module_info.size;
module.module_name_rva = loc.rva;
if (!WriteCVRecord(callback_context->minidump_writer, &module,
module_info.name))
return false;
callback_context->list->CopyIndexAfterObject(
callback_context->module_index++, &module, MD_MODULE_SIZE);
return true;
}
bool WriteModuleListStream(MinidumpFileWriter *minidump_writer,
const WriterArgument *writer_args,
MDRawDirectory *dir) {
TypedMDRVA<MDRawModuleList> list(minidump_writer);
int module_count = writer_args->thread_lister->GetModuleCount();
if (module_count <= 0 ||
!list.AllocateObjectAndArray(module_count, MD_MODULE_SIZE))
return false;
dir->stream_type = MD_MODULE_LIST_STREAM;
dir->location = list.location();
list.get()->number_of_modules = module_count;
ModuleInfoCallbackCtx context;
context.minidump_writer = minidump_writer;
context.writer_args = writer_args;
context.list = &list;
context.module_index = 0;
CallbackParam<ModuleCallback> callback(ModuleInfoCallback, &context);
return writer_args->thread_lister->ListModules(&callback) == module_count;
}
bool WriteSystemInfoStream(MinidumpFileWriter *minidump_writer,
const WriterArgument *writer_args,
MDRawDirectory *dir) {
TypedMDRVA<MDRawSystemInfo> sys_info(minidump_writer);
if (!sys_info.Allocate())
return false;
dir->stream_type = MD_SYSTEM_INFO_STREAM;
dir->location = sys_info.location();
return WriteCPUInformation(sys_info.get()) &&
WriteOSInformation(minidump_writer, sys_info.get());
}
bool WriteExceptionStream(MinidumpFileWriter *minidump_writer,
const WriterArgument *writer_args,
MDRawDirectory *dir) {
// This happenes when this is not a crash, but a requested dump.
if (writer_args->sig_ctx == NULL)
return false;
TypedMDRVA<MDRawExceptionStream> exception(minidump_writer);
if (!exception.Allocate())
return false;
dir->stream_type = MD_EXCEPTION_STREAM;
dir->location = exception.location();
exception.get()->thread_id = writer_args->crashed_pid;
exception.get()->exception_record.exception_code = writer_args->signo;
exception.get()->exception_record.exception_flags = 0;
if (writer_args->sig_ctx != NULL) {
exception.get()->exception_record.exception_address =
writer_args->sig_ctx->eip;
} else {
return true;
}
// Write context of the exception.
TypedMDRVA<MDRawContextX86> context(minidump_writer);
if (!context.Allocate())
return false;
exception.get()->thread_context = context.location();
memset(context.get(), 0, sizeof(MDRawContextX86));
return WriteContext(context.get(), writer_args->sig_ctx, NULL);
}
bool WriteMiscInfoStream(MinidumpFileWriter *minidump_writer,
const WriterArgument *writer_args,
MDRawDirectory *dir) {
TypedMDRVA<MDRawMiscInfo> info(minidump_writer);
if (!info.Allocate())
return false;
dir->stream_type = MD_MISC_INFO_STREAM;
dir->location = info.location();
info.get()->size_of_info = sizeof(MDRawMiscInfo);
info.get()->flags1 = MD_MISCINFO_FLAGS1_PROCESS_ID;
info.get()->process_id = writer_args->requester_pid;
return true;
}
bool WriteBreakpadInfoStream(MinidumpFileWriter *minidump_writer,
const WriterArgument *writer_args,
MDRawDirectory *dir) {
TypedMDRVA<MDRawBreakpadInfo> info(minidump_writer);
if (!info.Allocate())
return false;
dir->stream_type = MD_BREAKPAD_INFO_STREAM;
dir->location = info.location();
info.get()->validity = MD_BREAKPAD_INFO_VALID_DUMP_THREAD_ID |
MD_BREAKPAD_INFO_VALID_REQUESTING_THREAD_ID;
info.get()->dump_thread_id = getpid();
info.get()->requesting_thread_id = writer_args->requester_pid;
return true;
}
// Prototype of writer functions.
typedef bool (*WriteStringFN)(MinidumpFileWriter *,
const WriterArgument *,
MDRawDirectory *);
// Function table to writer a full minidump.
WriteStringFN writers[] = {
WriteThreadListStream,
WriteModuleListStream,
WriteSystemInfoStream,
WriteExceptionStream,
WriteMiscInfoStream,
WriteBreakpadInfoStream,
};
// Will call each writer function in the writers table.
// It runs in a different process from the crashing process, but sharing
// the same address space. This enables it to use ptrace functions.
int Write(void *argument) {
WriterArgument *writer_args =
static_cast<WriterArgument *>(argument);
if (!writer_args->thread_lister->SuspendAllThreads())
return -1;
if (writer_args->sighandler_ebp != 0 &&
writer_args->thread_lister->FindSigContext(writer_args->sighandler_ebp,
&writer_args->sig_ctx)) {
writer_args->crashed_stack_bottom =
writer_args->thread_lister->GetThreadStackBottom(
writer_args->sig_ctx->ebp);
int crashed_pid = FindCrashingThread(writer_args->crashed_stack_bottom,
writer_args->requester_pid,
writer_args->thread_lister);
if (crashed_pid > 0)
writer_args->crashed_pid = crashed_pid;
}
MinidumpFileWriter *minidump_writer = writer_args->minidump_writer;
TypedMDRVA<MDRawHeader> header(minidump_writer);
TypedMDRVA<MDRawDirectory> dir(minidump_writer);
if (!header.Allocate())
return 0;
int writer_count = sizeof(writers) / sizeof(writers[0]);
// Need directory space for all writers.
if (!dir.AllocateArray(writer_count))
return 0;
header.get()->signature = MD_HEADER_SIGNATURE;
header.get()->version = MD_HEADER_VERSION;
header.get()->time_date_stamp = time(NULL);
header.get()->stream_count = writer_count;
header.get()->stream_directory_rva = dir.position();
int dir_index = 0;
MDRawDirectory local_dir;
for (int i = 0; i < writer_count; ++i) {
if (writers[i](minidump_writer, writer_args, &local_dir))
dir.CopyIndex(dir_index++, &local_dir);
}
writer_args->thread_lister->ResumeAllThreads();
return 0;
}
} // namespace
namespace google_breakpad {
MinidumpGenerator::MinidumpGenerator() {
AllocateStack();
}
MinidumpGenerator::~MinidumpGenerator() {
}
void MinidumpGenerator::AllocateStack() {
stack_.reset(new char[kStackSize]);
}
bool MinidumpGenerator::WriteMinidumpToFile(const char *file_pathname,
int signo,
uintptr_t sighandler_ebp,
struct sigcontext **sig_ctx) const {
assert(file_pathname != NULL);
assert(stack_ != NULL);
if (stack_ == NULL || file_pathname == NULL)
return false;
MinidumpFileWriter minidump_writer;
if (minidump_writer.Open(file_pathname)) {
WriterArgument argument;
memset(&argument, 0, sizeof(argument));
LinuxThread thread_lister(getpid());
argument.thread_lister = &thread_lister;
argument.minidump_writer = &minidump_writer;
argument.requester_pid = getpid();
argument.crashed_pid = getpid();
argument.signo = signo;
argument.sighandler_ebp = sighandler_ebp;
argument.sig_ctx = NULL;
int cloned_pid = clone(Write, stack_.get() + kStackSize,
CLONE_VM | CLONE_FILES | CLONE_FS | CLONE_UNTRACED,
(void*)&argument);
waitpid(cloned_pid, NULL, __WALL);
if (sig_ctx != NULL)
*sig_ctx = argument.sig_ctx;
return true;
}
return false;
}
} // namespace google_breakpad

View File

@@ -0,0 +1,105 @@
// Copyright (c) 2009, 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_DIRECTORY_READER_H_
#define CLIENT_LINUX_MINIDUMP_WRITER_DIRECTORY_READER_H_
#include <stdint.h>
#include <unistd.h>
#include <limits.h>
#include <assert.h>
#include <errno.h>
#include <string.h>
#include "third_party/lss/linux_syscall_support.h"
namespace google_breakpad {
// A class for enumerating a directory without using diropen/readdir or other
// functions which may allocate memory.
class DirectoryReader {
public:
DirectoryReader(int fd)
: fd_(fd),
buf_used_(0) {
}
// Return the next entry from the directory
// name: (output) the NUL terminated entry name
//
// Returns true iff successful (false on EOF).
//
// After calling this, one must call |PopEntry| otherwise you'll get the same
// entry over and over.
bool GetNextEntry(const char** name) {
struct kernel_dirent* const dent =
reinterpret_cast<kernel_dirent*>(buf_);
if (buf_used_ == 0) {
// need to read more entries.
const int n = sys_getdents(fd_, dent, sizeof(buf_));
if (n < 0) {
return false;
} else if (n == 0) {
hit_eof_ = true;
} else {
buf_used_ += n;
}
}
if (buf_used_ == 0 && hit_eof_)
return false;
assert(buf_used_ > 0);
*name = dent->d_name;
return true;
}
void PopEntry() {
if (!buf_used_)
return;
const struct kernel_dirent* const dent =
reinterpret_cast<kernel_dirent*>(buf_);
buf_used_ -= dent->d_reclen;
memmove(buf_, buf_ + dent->d_reclen, buf_used_);
}
private:
const int fd_;
bool hit_eof_;
unsigned buf_used_;
uint8_t buf_[sizeof(struct kernel_dirent) + NAME_MAX + 1];
};
} // namespace google_breakpad
#endif // CLIENT_LINUX_MINIDUMP_WRITER_DIRECTORY_READER_H_

View File

@@ -0,0 +1,77 @@
// Copyright (c) 2009, 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 <set>
#include <string>
#include <dirent.h>
#include <fcntl.h>
#include <sys/types.h>
#include "client/linux/minidump_writer/directory_reader.h"
#include "breakpad_googletest_includes.h"
using namespace google_breakpad;
namespace {
typedef testing::Test DirectoryReaderTest;
}
TEST(DirectoryReaderTest, CompareResults) {
std::set<std::string> dent_set;
DIR *const dir = opendir("/proc/self");
ASSERT_TRUE(dir != NULL);
struct dirent* dent;
while ((dent = readdir(dir)))
dent_set.insert(dent->d_name);
closedir(dir);
const int fd = open("/proc/self", O_DIRECTORY | O_RDONLY);
ASSERT_GE(fd, 0);
DirectoryReader dir_reader(fd);
unsigned seen = 0;
const char* name;
while (dir_reader.GetNextEntry(&name)) {
ASSERT_TRUE(dent_set.find(name) != dent_set.end());
seen++;
dir_reader.PopEntry();
}
ASSERT_TRUE(dent_set.find("status") != dent_set.end());
ASSERT_TRUE(dent_set.find("stat") != dent_set.end());
ASSERT_TRUE(dent_set.find("cmdline") != dent_set.end());
ASSERT_EQ(dent_set.size(), seen);
close(fd);
}

View File

@@ -0,0 +1,130 @@
// Copyright (c) 2009, 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_LINE_READER_H_
#define CLIENT_LINUX_MINIDUMP_WRITER_LINE_READER_H_
#include <stdint.h>
#include <assert.h>
#include <string.h>
#include "third_party/lss/linux_syscall_support.h"
namespace google_breakpad {
// A class for reading a file, line by line, without using fopen/fgets or other
// functions which may allocate memory.
class LineReader {
public:
LineReader(int fd)
: fd_(fd),
hit_eof_(false),
buf_used_(0) {
}
// The maximum length of a line.
static const size_t kMaxLineLen = 512;
// Return the next line from the file.
// line: (output) a pointer to the start of the line. The line is NUL
// terminated.
// len: (output) the length of the line (not inc the NUL byte)
//
// Returns true iff successful (false on EOF).
//
// One must call |PopLine| after this function, otherwise you'll continue to
// get the same line over and over.
bool GetNextLine(const char **line, unsigned *len) {
for (;;) {
if (buf_used_ == 0 && hit_eof_)
return false;
for (unsigned i = 0; i < buf_used_; ++i) {
if (buf_[i] == '\n' || buf_[i] == 0) {
buf_[i] = 0;
*len = i;
*line = buf_;
return true;
}
}
if (buf_used_ == sizeof(buf_)) {
// we scanned the whole buffer and didn't find an end-of-line marker.
// This line is too long to process.
return false;
}
// We didn't find any end-of-line terminators in the buffer. However, if
// this is the last line in the file it might not have one:
if (hit_eof_) {
assert(buf_used_);
// There's room for the NUL because of the buf_used_ == sizeof(buf_)
// check above.
buf_[buf_used_] = 0;
*len = buf_used_;
buf_used_ += 1; // since we appended the NUL.
*line = buf_;
return true;
}
// Otherwise, we should pull in more data from the file
const ssize_t n = sys_read(fd_, buf_ + buf_used_,
sizeof(buf_) - buf_used_);
if (n < 0) {
return false;
} else if (n == 0) {
hit_eof_ = true;
} else {
buf_used_ += n;
}
// At this point, we have either set the hit_eof_ flag, or we have more
// data to process...
}
}
void PopLine(unsigned len) {
// len doesn't include the NUL byte at the end.
assert(buf_used_ >= len + 1);
buf_used_ -= len + 1;
memmove(buf_, buf_ + len + 1, buf_used_);
}
private:
const int fd_;
bool hit_eof_;
unsigned buf_used_;
char buf_[kMaxLineLen];
};
} // namespace google_breakpad
#endif // CLIENT_LINUX_MINIDUMP_WRITER_LINE_READER_H_

View File

@@ -0,0 +1,190 @@
// Copyright (c) 2009, 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 <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include "client/linux/minidump_writer/line_reader.h"
#include "breakpad_googletest_includes.h"
using namespace google_breakpad;
#if !defined(__ANDROID__)
#define TEMPDIR "/tmp"
#else
#define TEMPDIR "/data/local/tmp"
#endif
static int TemporaryFile() {
static const char templ[] = TEMPDIR "/line-reader-unittest-XXXXXX";
char templ_copy[sizeof(templ)];
memcpy(templ_copy, templ, sizeof(templ));
const int fd = mkstemp(templ_copy);
if (fd >= 0)
unlink(templ_copy);
return fd;
}
namespace {
typedef testing::Test LineReaderTest;
}
TEST(LineReaderTest, EmptyFile) {
const int fd = TemporaryFile();
LineReader reader(fd);
const char *line;
unsigned len;
ASSERT_FALSE(reader.GetNextLine(&line, &len));
close(fd);
}
TEST(LineReaderTest, OneLineTerminated) {
const int fd = TemporaryFile();
write(fd, "a\n", 2);
lseek(fd, 0, SEEK_SET);
LineReader reader(fd);
const char *line;
unsigned int len;
ASSERT_TRUE(reader.GetNextLine(&line, &len));
ASSERT_EQ(len, (unsigned int)1);
ASSERT_EQ(line[0], 'a');
ASSERT_EQ(line[1], 0);
reader.PopLine(len);
ASSERT_FALSE(reader.GetNextLine(&line, &len));
close(fd);
}
TEST(LineReaderTest, OneLine) {
const int fd = TemporaryFile();
write(fd, "a", 1);
lseek(fd, 0, SEEK_SET);
LineReader reader(fd);
const char *line;
unsigned len;
ASSERT_TRUE(reader.GetNextLine(&line, &len));
ASSERT_EQ(len, (unsigned)1);
ASSERT_EQ(line[0], 'a');
ASSERT_EQ(line[1], 0);
reader.PopLine(len);
ASSERT_FALSE(reader.GetNextLine(&line, &len));
close(fd);
}
TEST(LineReaderTest, TwoLinesTerminated) {
const int fd = TemporaryFile();
write(fd, "a\nb\n", 4);
lseek(fd, 0, SEEK_SET);
LineReader reader(fd);
const char *line;
unsigned len;
ASSERT_TRUE(reader.GetNextLine(&line, &len));
ASSERT_EQ(len, (unsigned)1);
ASSERT_EQ(line[0], 'a');
ASSERT_EQ(line[1], 0);
reader.PopLine(len);
ASSERT_TRUE(reader.GetNextLine(&line, &len));
ASSERT_EQ(len, (unsigned)1);
ASSERT_EQ(line[0], 'b');
ASSERT_EQ(line[1], 0);
reader.PopLine(len);
ASSERT_FALSE(reader.GetNextLine(&line, &len));
close(fd);
}
TEST(LineReaderTest, TwoLines) {
const int fd = TemporaryFile();
write(fd, "a\nb", 3);
lseek(fd, 0, SEEK_SET);
LineReader reader(fd);
const char *line;
unsigned len;
ASSERT_TRUE(reader.GetNextLine(&line, &len));
ASSERT_EQ(len, (unsigned)1);
ASSERT_EQ(line[0], 'a');
ASSERT_EQ(line[1], 0);
reader.PopLine(len);
ASSERT_TRUE(reader.GetNextLine(&line, &len));
ASSERT_EQ(len, (unsigned)1);
ASSERT_EQ(line[0], 'b');
ASSERT_EQ(line[1], 0);
reader.PopLine(len);
ASSERT_FALSE(reader.GetNextLine(&line, &len));
close(fd);
}
TEST(LineReaderTest, MaxLength) {
const int fd = TemporaryFile();
char l[LineReader::kMaxLineLen - 1];
memset(l, 'a', sizeof(l));
write(fd, l, sizeof(l));
lseek(fd, 0, SEEK_SET);
LineReader reader(fd);
const char *line;
unsigned len;
ASSERT_TRUE(reader.GetNextLine(&line, &len));
ASSERT_EQ(len, sizeof(l));
ASSERT_TRUE(memcmp(l, line, sizeof(l)) == 0);
ASSERT_EQ(line[len], 0);
close(fd);
}
TEST(LineReaderTest, TooLong) {
const int fd = TemporaryFile();
char l[LineReader::kMaxLineLen];
memset(l, 'a', sizeof(l));
write(fd, l, sizeof(l));
lseek(fd, 0, SEEK_SET);
LineReader reader(fd);
const char *line;
unsigned len;
ASSERT_FALSE(reader.GetNextLine(&line, &len));
close(fd);
}

View File

@@ -0,0 +1,571 @@
// Copyright (c) 2010, 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 code deals with the mechanics of getting information about a crashed
// process. Since this code may run in a compromised address space, the same
// rules apply as detailed at the top of minidump_writer.h: no libc calls and
// use the alternative allocator.
#include "client/linux/minidump_writer/linux_dumper.h"
#include <asm/ptrace.h>
#include <assert.h>
#include <errno.h>
#include <fcntl.h>
#include <limits.h>
#if !defined(__ANDROID__)
#include <link.h>
#endif
#include <stddef.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/ptrace.h>
#include <sys/wait.h>
#include <unistd.h>
#include <algorithm>
#include "client/linux/minidump_writer/directory_reader.h"
#include "client/linux/minidump_writer/line_reader.h"
#include "common/linux/file_id.h"
#include "common/linux/linux_libc_support.h"
#include "third_party/lss/linux_syscall_support.h"
static const char kMappedFileUnsafePrefix[] = "/dev/";
static const char kDeletedSuffix[] = " (deleted)";
// Suspend a thread by attaching to it.
static bool SuspendThread(pid_t pid) {
// This may fail if the thread has just died or debugged.
errno = 0;
if (sys_ptrace(PTRACE_ATTACH, pid, NULL, NULL) != 0 &&
errno != 0) {
return false;
}
while (sys_waitpid(pid, NULL, __WALL) < 0) {
if (errno != EINTR) {
sys_ptrace(PTRACE_DETACH, pid, NULL, NULL);
return false;
}
}
#if defined(__i386) || defined(__x86_64)
// On x86, the stack pointer is NULL or -1, when executing trusted code in
// the seccomp sandbox. Not only does this cause difficulties down the line
// when trying to dump the thread's stack, it also results in the minidumps
// containing information about the trusted threads. This information is
// generally completely meaningless and just pollutes the minidumps.
// We thus test the stack pointer and exclude any threads that are part of
// the seccomp sandbox's trusted code.
user_regs_struct regs;
if (sys_ptrace(PTRACE_GETREGS, pid, NULL, &regs) == -1 ||
#if defined(__i386)
!regs.esp
#elif defined(__x86_64)
!regs.rsp
#endif
) {
sys_ptrace(PTRACE_DETACH, pid, NULL, NULL);
return false;
}
#endif
return true;
}
// Resume a thread by detaching from it.
static bool ResumeThread(pid_t pid) {
return sys_ptrace(PTRACE_DETACH, pid, NULL, NULL) >= 0;
}
inline static bool IsMappedFileOpenUnsafe(
const google_breakpad::MappingInfo& mapping) {
// It is unsafe to attempt to open a mapped file that lives under /dev,
// because the semantics of the open may be driver-specific so we'd risk
// hanging the crash dumper. And a file in /dev/ almost certainly has no
// ELF file identifier anyways.
return my_strncmp(mapping.name,
kMappedFileUnsafePrefix,
sizeof(kMappedFileUnsafePrefix) - 1) == 0;
}
namespace google_breakpad {
LinuxDumper::LinuxDumper(int pid)
: pid_(pid),
threads_suspended_(false),
threads_(&allocator_, 8),
mappings_(&allocator_) {
}
bool LinuxDumper::Init() {
return EnumerateThreads(&threads_) &&
EnumerateMappings(&mappings_);
}
bool LinuxDumper::ThreadsSuspend() {
if (threads_suspended_)
return true;
for (size_t i = 0; i < threads_.size(); ++i) {
if (!SuspendThread(threads_[i])) {
// If the thread either disappeared before we could attach to it, or if
// it was part of the seccomp sandbox's trusted code, it is OK to
// silently drop it from the minidump.
memmove(&threads_[i], &threads_[i+1],
(threads_.size() - i - 1) * sizeof(threads_[i]));
threads_.resize(threads_.size() - 1);
--i;
}
}
threads_suspended_ = true;
return threads_.size() > 0;
}
bool LinuxDumper::ThreadsResume() {
if (!threads_suspended_)
return false;
bool good = true;
for (size_t i = 0; i < threads_.size(); ++i)
good &= ResumeThread(threads_[i]);
threads_suspended_ = false;
return good;
}
void
LinuxDumper::BuildProcPath(char* path, pid_t pid, const char* node) const {
assert(path);
if (!path) {
return;
}
path[0] = '\0';
const unsigned pid_len = my_int_len(pid);
assert(node);
if (!node) {
return;
}
size_t node_len = my_strlen(node);
assert(node_len < NAME_MAX);
if (node_len >= NAME_MAX) {
return;
}
assert(node_len > 0);
if (node_len == 0) {
return;
}
assert(pid > 0);
if (pid <= 0) {
return;
}
const size_t total_length = 6 + pid_len + 1 + node_len;
assert(total_length < NAME_MAX);
if (total_length >= NAME_MAX) {
return;
}
memcpy(path, "/proc/", 6);
my_itos(path + 6, pid, pid_len);
memcpy(path + 6 + pid_len, "/", 1);
memcpy(path + 6 + pid_len + 1, node, node_len);
path[total_length] = '\0';
}
bool
LinuxDumper::ElfFileIdentifierForMapping(const MappingInfo& mapping,
bool member,
unsigned int mapping_id,
uint8_t identifier[sizeof(MDGUID)])
{
assert(!member || mapping_id < mappings_.size());
my_memset(identifier, 0, sizeof(MDGUID));
if (IsMappedFileOpenUnsafe(mapping))
return false;
// Special-case linux-gate because it's not a real file.
if (my_strcmp(mapping.name, kLinuxGateLibraryName) == 0) {
const uintptr_t kPageSize = getpagesize();
void* linux_gate = NULL;
if (pid_ == sys_getpid()) {
linux_gate = reinterpret_cast<void*>(mapping.start_addr);
} else {
linux_gate = allocator_.Alloc(kPageSize);
CopyFromProcess(linux_gate, pid_,
reinterpret_cast<const void*>(mapping.start_addr),
kPageSize);
}
return FileID::ElfFileIdentifierFromMappedFile(linux_gate, identifier);
}
char filename[NAME_MAX];
size_t filename_len = my_strlen(mapping.name);
assert(filename_len < NAME_MAX);
if (filename_len >= NAME_MAX)
return false;
memcpy(filename, mapping.name, filename_len);
filename[filename_len] = '\0';
bool filename_modified = HandleDeletedFileInMapping(filename);
int fd = sys_open(filename, O_RDONLY, 0);
if (fd < 0)
return false;
struct kernel_stat st;
if (sys_fstat(fd, &st) != 0) {
sys_close(fd);
return false;
}
#if defined(__x86_64)
#define sys_mmap2 sys_mmap
#endif
void* base = sys_mmap2(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
sys_close(fd);
if (base == MAP_FAILED)
return false;
bool success = FileID::ElfFileIdentifierFromMappedFile(base, identifier);
sys_munmap(base, st.st_size);
if (success && member && filename_modified) {
mappings_[mapping_id]->name[filename_len -
sizeof(kDeletedSuffix) + 1] = '\0';
}
return success;
}
void*
LinuxDumper::FindBeginningOfLinuxGateSharedLibrary(const pid_t pid) const {
char auxv_path[NAME_MAX];
BuildProcPath(auxv_path, pid, "auxv");
// If BuildProcPath errors out due to invalid input, we'll handle it when
// we try to sys_open the file.
// Find the AT_SYSINFO_EHDR entry for linux-gate.so
// See http://www.trilithium.com/johan/2005/08/linux-gate/ for more
// information.
int fd = sys_open(auxv_path, O_RDONLY, 0);
if (fd < 0) {
return NULL;
}
elf_aux_entry one_aux_entry;
while (sys_read(fd,
&one_aux_entry,
sizeof(elf_aux_entry)) == sizeof(elf_aux_entry) &&
one_aux_entry.a_type != AT_NULL) {
if (one_aux_entry.a_type == AT_SYSINFO_EHDR) {
close(fd);
return reinterpret_cast<void*>(one_aux_entry.a_un.a_val);
}
}
close(fd);
return NULL;
}
bool
LinuxDumper::EnumerateMappings(wasteful_vector<MappingInfo*>* result) const {
char maps_path[NAME_MAX];
BuildProcPath(maps_path, pid_, "maps");
// linux_gate_loc is the beginning of the kernel's mapping of
// linux-gate.so in the process. It doesn't actually show up in the
// maps list as a filename, so we use the aux vector to find it's
// load location and special case it's entry when creating the list
// of mappings.
const void* linux_gate_loc;
linux_gate_loc = FindBeginningOfLinuxGateSharedLibrary(pid_);
const int fd = sys_open(maps_path, O_RDONLY, 0);
if (fd < 0)
return false;
LineReader* const line_reader = new(allocator_) LineReader(fd);
const char* line;
unsigned line_len;
while (line_reader->GetNextLine(&line, &line_len)) {
uintptr_t start_addr, end_addr, offset;
const char* i1 = my_read_hex_ptr(&start_addr, line);
if (*i1 == '-') {
const char* i2 = my_read_hex_ptr(&end_addr, i1 + 1);
if (*i2 == ' ') {
const char* i3 = my_read_hex_ptr(&offset, i2 + 6 /* skip ' rwxp ' */);
if (*i3 == ' ') {
const char* name = NULL;
// Only copy name if the name is a valid path name, or if
// it's the VDSO image.
if (((name = my_strchr(line, '/')) == NULL) &&
linux_gate_loc &&
reinterpret_cast<void*>(start_addr) == linux_gate_loc) {
name = kLinuxGateLibraryName;
offset = 0;
}
// Merge adjacent mappings with the same name into one module,
// assuming they're a single library mapped by the dynamic linker
if (name && result->size()) {
MappingInfo* module = (*result)[result->size() - 1];
if ((start_addr == module->start_addr + module->size) &&
(my_strlen(name) == my_strlen(module->name)) &&
(my_strncmp(name, module->name, my_strlen(name)) == 0)) {
module->size = end_addr - module->start_addr;
line_reader->PopLine(line_len);
continue;
}
}
MappingInfo* const module = new(allocator_) MappingInfo;
memset(module, 0, sizeof(MappingInfo));
module->start_addr = start_addr;
module->size = end_addr - start_addr;
module->offset = offset;
if (name != NULL) {
const unsigned l = my_strlen(name);
if (l < sizeof(module->name))
memcpy(module->name, name, l);
}
result->push_back(module);
}
}
}
line_reader->PopLine(line_len);
}
sys_close(fd);
return result->size() > 0;
}
// Parse /proc/$pid/task to list all the threads of the process identified by
// pid.
bool LinuxDumper::EnumerateThreads(wasteful_vector<pid_t>* result) const {
char task_path[NAME_MAX];
BuildProcPath(task_path, pid_, "task");
const int fd = sys_open(task_path, O_RDONLY | O_DIRECTORY, 0);
if (fd < 0)
return false;
DirectoryReader* dir_reader = new(allocator_) DirectoryReader(fd);
// The directory may contain duplicate entries which we filter by assuming
// that they are consecutive.
int last_tid = -1;
const char* dent_name;
while (dir_reader->GetNextEntry(&dent_name)) {
if (my_strcmp(dent_name, ".") &&
my_strcmp(dent_name, "..")) {
int tid = 0;
if (my_strtoui(&tid, dent_name) &&
last_tid != tid) {
last_tid = tid;
result->push_back(tid);
}
}
dir_reader->PopEntry();
}
sys_close(fd);
return true;
}
// Read thread info from /proc/$pid/status.
// Fill out the |tgid|, |ppid| and |pid| members of |info|. If unavailable,
// these members are set to -1. Returns true iff all three members are
// available.
bool LinuxDumper::ThreadInfoGet(pid_t tid, ThreadInfo* info) {
assert(info != NULL);
char status_path[NAME_MAX];
BuildProcPath(status_path, tid, "status");
const int fd = open(status_path, O_RDONLY);
if (fd < 0)
return false;
LineReader* const line_reader = new(allocator_) LineReader(fd);
const char* line;
unsigned line_len;
info->ppid = info->tgid = -1;
while (line_reader->GetNextLine(&line, &line_len)) {
if (my_strncmp("Tgid:\t", line, 6) == 0) {
my_strtoui(&info->tgid, line + 6);
} else if (my_strncmp("PPid:\t", line, 6) == 0) {
my_strtoui(&info->ppid, line + 6);
}
line_reader->PopLine(line_len);
}
if (info->ppid == -1 || info->tgid == -1)
return false;
if (sys_ptrace(PTRACE_GETREGS, tid, NULL, &info->regs) == -1) {
return false;
}
#if !defined(__ANDROID__)
if (sys_ptrace(PTRACE_GETFPREGS, tid, NULL, &info->fpregs) == -1) {
return false;
}
#endif
#if defined(__i386)
if (sys_ptrace(PTRACE_GETFPXREGS, tid, NULL, &info->fpxregs) == -1)
return false;
#endif
#if defined(__i386) || defined(__x86_64)
for (unsigned i = 0; i < ThreadInfo::kNumDebugRegisters; ++i) {
if (sys_ptrace(
PTRACE_PEEKUSER, tid,
reinterpret_cast<void*> (offsetof(struct user,
u_debugreg[0]) + i *
sizeof(debugreg_t)),
&info->dregs[i]) == -1) {
return false;
}
}
#endif
const uint8_t* stack_pointer;
#if defined(__i386)
memcpy(&stack_pointer, &info->regs.esp, sizeof(info->regs.esp));
#elif defined(__x86_64)
memcpy(&stack_pointer, &info->regs.rsp, sizeof(info->regs.rsp));
#elif defined(__ARM_EABI__)
memcpy(&stack_pointer, &info->regs.ARM_sp, sizeof(info->regs.ARM_sp));
#else
#error "This code hasn't been ported to your platform yet."
#endif
return GetStackInfo(&info->stack, &info->stack_len,
(uintptr_t) stack_pointer);
}
// Get information about the stack, given the stack pointer. We don't try to
// walk the stack since we might not have all the information needed to do
// unwind. So we just grab, up to, 32k of stack.
bool LinuxDumper::GetStackInfo(const void** stack, size_t* stack_len,
uintptr_t int_stack_pointer) {
// Move the stack pointer to the bottom of the page that it's in.
const uintptr_t page_size = getpagesize();
uint8_t* const stack_pointer =
reinterpret_cast<uint8_t*>(int_stack_pointer & ~(page_size - 1));
// The number of bytes of stack which we try to capture.
static const ptrdiff_t kStackToCapture = 32 * 1024;
const MappingInfo* mapping = FindMapping(stack_pointer);
if (!mapping)
return false;
const ptrdiff_t offset = stack_pointer - (uint8_t*) mapping->start_addr;
const ptrdiff_t distance_to_end =
static_cast<ptrdiff_t>(mapping->size) - offset;
*stack_len = distance_to_end > kStackToCapture ?
kStackToCapture : distance_to_end;
*stack = stack_pointer;
return true;
}
// static
void LinuxDumper::CopyFromProcess(void* dest, pid_t child, const void* src,
size_t length) {
unsigned long tmp = 55;
size_t done = 0;
static const size_t word_size = sizeof(tmp);
uint8_t* const local = (uint8_t*) dest;
uint8_t* const remote = (uint8_t*) src;
while (done < length) {
const size_t l = length - done > word_size ? word_size : length - done;
if (sys_ptrace(PTRACE_PEEKDATA, child, remote + done, &tmp) == -1) {
tmp = 0;
}
memcpy(local + done, &tmp, l);
done += l;
}
}
// Find the mapping which the given memory address falls in.
const MappingInfo* LinuxDumper::FindMapping(const void* address) const {
const uintptr_t addr = (uintptr_t) address;
for (size_t i = 0; i < mappings_.size(); ++i) {
const uintptr_t start = static_cast<uintptr_t>(mappings_[i]->start_addr);
if (addr >= start && addr - start < mappings_[i]->size)
return mappings_[i];
}
return NULL;
}
bool LinuxDumper::HandleDeletedFileInMapping(char* path) const {
static const size_t kDeletedSuffixLen = sizeof(kDeletedSuffix) - 1;
// Check for ' (deleted)' in |path|.
// |path| has to be at least as long as "/x (deleted)".
const size_t path_len = my_strlen(path);
if (path_len < kDeletedSuffixLen + 2)
return false;
if (my_strncmp(path + path_len - kDeletedSuffixLen, kDeletedSuffix,
kDeletedSuffixLen) != 0) {
return false;
}
// Check |path| against the /proc/pid/exe 'symlink'.
char exe_link[NAME_MAX];
char new_path[NAME_MAX];
BuildProcPath(exe_link, pid_, "exe");
ssize_t new_path_len = sys_readlink(exe_link, new_path, NAME_MAX);
if (new_path_len <= 0 || new_path_len == NAME_MAX)
return false;
new_path[new_path_len] = '\0';
if (my_strcmp(path, new_path) != 0)
return false;
// Check to see if someone actually named their executable 'foo (deleted)'.
struct kernel_stat exe_stat;
struct kernel_stat new_path_stat;
if (sys_stat(exe_link, &exe_stat) == 0 &&
sys_stat(new_path, &new_path_stat) == 0 &&
exe_stat.st_dev == new_path_stat.st_dev &&
exe_stat.st_ino == new_path_stat.st_ino) {
return false;
}
memcpy(path, exe_link, NAME_MAX);
return true;
}
} // namespace google_breakpad

View File

@@ -0,0 +1,193 @@
// Copyright (c) 2010, 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_LINUX_DUMPER_H_
#define CLIENT_LINUX_MINIDUMP_WRITER_LINUX_DUMPER_H_
#include <elf.h>
#include <linux/limits.h>
#include <stdint.h>
#include <sys/types.h>
#if !defined(__ANDROID__)
#include <sys/user.h>
#endif
#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
// Typedef for our parsing of the auxv variables in /proc/pid/auxv.
#if defined(__i386) || defined(__ARM_EABI__)
#if !defined(__ANDROID__)
typedef Elf32_auxv_t elf_aux_entry;
#else
// Android is missing this structure definition
typedef struct
{
uint32_t a_type; /* Entry type */
union
{
uint32_t a_val; /* Integer value */
} a_un;
} elf_aux_entry;
#if !defined(AT_SYSINFO_EHDR)
#define AT_SYSINFO_EHDR 33
#endif
#endif // __ANDROID__
#elif defined(__x86_64__)
typedef Elf64_auxv_t elf_aux_entry;
#endif
// When we find the VDSO mapping in the process's address space, this
// is the name we use for it when writing it to the minidump.
// This should always be less than NAME_MAX!
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
// Even on platforms where the stack grows down, the following will point to
// the smallest address in the stack.
const void* stack; // pointer to the stack area
size_t stack_len; // length of the stack to copy
#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)
#if defined(__ANDROID__)
struct pt_regs regs;
#else
struct user_regs regs;
struct user_fpregs fpregs;
#endif // __ANDROID__
#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 {
public:
explicit LinuxDumper(pid_t pid);
// Parse the data for |threads| and |mappings|.
bool Init();
// Suspend/resume all threads in the given process.
bool ThreadsSuspend();
bool ThreadsResume();
// Read information about the given thread. Returns true on success. One must
// have called |ThreadsSuspend| first.
bool ThreadInfoGet(pid_t tid, ThreadInfo* info);
// These are only valid after a call to |Init|.
const wasteful_vector<pid_t> &threads() { return threads_; }
const wasteful_vector<MappingInfo*> &mappings() { return mappings_; }
const MappingInfo* FindMapping(const void* address) const;
// Find a block of memory to take as the stack given the top of stack pointer.
// stack: (output) the lowest address in the memory area
// stack_len: (output) the length of the memory area
// stack_top: the current top of the stack
bool GetStackInfo(const void** stack, size_t* stack_len, uintptr_t stack_top);
PageAllocator* allocator() { return &allocator_; }
// memcpy from a remote process.
static void CopyFromProcess(void* dest, pid_t child, const void* src,
size_t length);
// Builds a proc path for a certain pid for a node. path is a
// character array that is overwritten, and node is the final node
// without any slashes.
void BuildProcPath(char* path, pid_t pid, const char* node) const;
// Generate a File ID from the .text section of a mapped entry.
// If not a member, mapping_id is ignored.
bool ElfFileIdentifierForMapping(const MappingInfo& mapping,
bool member,
unsigned int mapping_id,
uint8_t identifier[sizeof(MDGUID)]);
// Utility method to find the location of where the kernel has
// mapped linux-gate.so in memory(shows up in /proc/pid/maps as
// [vdso], but we can't guarantee that it's the only virtual dynamic
// shared object. Parsing the auxilary vector for AT_SYSINFO_EHDR
// is the safest way to go.)
void* FindBeginningOfLinuxGateSharedLibrary(const pid_t pid) const;
private:
bool EnumerateMappings(wasteful_vector<MappingInfo*>* result) const;
bool EnumerateThreads(wasteful_vector<pid_t>* result) const;
// For the case where a running program has been deleted, it'll show up in
// /proc/pid/maps as "/path/to/program (deleted)". If this is the case, then
// see if '/path/to/program (deleted)' matches /proc/pid/exe and return
// /proc/pid/exe in |path| so ELF identifier generation works correctly. This
// also checks to see if '/path/to/program (deleted)' exists, so it does not
// get fooled by a poorly named binary.
// For programs that don't end with ' (deleted)', this is a no-op.
// This assumes |path| is a buffer with length NAME_MAX.
// Returns true if |path| is modified.
bool HandleDeletedFileInMapping(char* path) const;
const pid_t pid_;
mutable PageAllocator allocator_;
bool threads_suspended_;
wasteful_vector<pid_t> threads_; // the ids of all the threads
wasteful_vector<MappingInfo*> mappings_; // info from /proc/<pid>/maps
};
} // namespace google_breakpad
#endif // CLIENT_LINUX_HANDLER_LINUX_DUMPER_H_

View File

@@ -0,0 +1,429 @@
// Copyright (c) 2009, 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 <string>
#include <fcntl.h>
#include <limits.h>
#include <unistd.h>
#include <signal.h>
#include <stdint.h>
#include <sys/mman.h>
#include <sys/poll.h>
#include <sys/stat.h>
#include <sys/types.h>
#include "breakpad_googletest_includes.h"
#include "client/linux/minidump_writer/linux_dumper.h"
#include "common/linux/eintr_wrapper.h"
#include "common/linux/file_id.h"
#include "common/memory.h"
using std::string;
using namespace google_breakpad;
namespace {
typedef testing::Test LinuxDumperTest;
string GetHelperBinary() {
// Locate helper binary next to the current binary.
char self_path[PATH_MAX];
if (readlink("/proc/self/exe", self_path, sizeof(self_path) - 1) == -1) {
return "";
}
string helper_path(self_path);
size_t pos = helper_path.rfind('/');
if (pos == string::npos) {
return "";
}
helper_path.erase(pos + 1);
helper_path += "linux_dumper_unittest_helper";
return helper_path;
}
}
TEST(LinuxDumperTest, Setup) {
LinuxDumper dumper(getpid());
}
TEST(LinuxDumperTest, FindMappings) {
LinuxDumper dumper(getpid());
ASSERT_TRUE(dumper.Init());
ASSERT_TRUE(dumper.FindMapping(reinterpret_cast<void*>(getpid)));
ASSERT_TRUE(dumper.FindMapping(reinterpret_cast<void*>(printf)));
ASSERT_FALSE(dumper.FindMapping(NULL));
}
TEST(LinuxDumperTest, ThreadList) {
LinuxDumper dumper(getpid());
ASSERT_TRUE(dumper.Init());
ASSERT_GE(dumper.threads().size(), (size_t)1);
bool found = false;
for (size_t i = 0; i < dumper.threads().size(); ++i) {
if (dumper.threads()[i] == getpid()) {
found = true;
break;
}
}
}
// Helper stack class to close a file descriptor and unmap
// a mmap'ed mapping.
class StackHelper {
public:
StackHelper(int fd, char* mapping, size_t size)
: fd_(fd), mapping_(mapping), size_(size) {}
~StackHelper() {
munmap(mapping_, size_);
close(fd_);
}
private:
int fd_;
char* mapping_;
size_t size_;
};
TEST(LinuxDumperTest, MergedMappings) {
string helper_path(GetHelperBinary());
if (helper_path.empty()) {
FAIL() << "Couldn't find helper binary";
exit(1);
}
// mmap two segments out of the helper binary, one
// enclosed in the other, but with different protections.
const size_t kPageSize = sysconf(_SC_PAGESIZE);
const size_t kMappingSize = 3 * kPageSize;
int fd = open(helper_path.c_str(), O_RDONLY);
ASSERT_NE(-1, fd);
char* mapping =
reinterpret_cast<char*>(mmap(NULL,
kMappingSize,
PROT_READ,
MAP_SHARED,
fd,
0));
ASSERT_TRUE(mapping);
const u_int64_t kMappingAddress = reinterpret_cast<u_int64_t>(mapping);
// Ensure that things get cleaned up.
StackHelper helper(fd, mapping, kMappingSize);
// Carve a page out of the first mapping with different permissions.
char* inside_mapping = reinterpret_cast<char*>(mmap(mapping + 2 *kPageSize,
kPageSize,
PROT_NONE,
MAP_SHARED | MAP_FIXED,
fd,
// Map a different offset just to
// better test real-world conditions.
kPageSize));
ASSERT_TRUE(inside_mapping);
// Now check that LinuxDumper interpreted the mappings properly.
LinuxDumper dumper(getpid());
ASSERT_TRUE(dumper.Init());
int mapping_count = 0;
for (unsigned i = 0; i < dumper.mappings().size(); ++i) {
const MappingInfo& mapping = *dumper.mappings()[i];
if (strcmp(mapping.name, helper_path.c_str()) == 0) {
// This mapping should encompass the entire original mapped
// range.
EXPECT_EQ(kMappingAddress, mapping.start_addr);
EXPECT_EQ(kMappingSize, mapping.size);
EXPECT_EQ(0, mapping.offset);
mapping_count++;
}
}
EXPECT_EQ(1, mapping_count);
}
TEST(LinuxDumperTest, VerifyStackReadWithMultipleThreads) {
static const int kNumberOfThreadsInHelperProgram = 5;
char kNumberOfThreadsArgument[2];
sprintf(kNumberOfThreadsArgument, "%d", kNumberOfThreadsInHelperProgram);
int fds[2];
ASSERT_NE(-1, pipe(fds));
pid_t child_pid = fork();
if (child_pid == 0) {
// In child process.
close(fds[0]);
string helper_path(GetHelperBinary());
if (helper_path.empty()) {
FAIL() << "Couldn't find helper binary";
exit(1);
}
// Pass the pipe fd and the number of threads as arguments.
char pipe_fd_string[8];
sprintf(pipe_fd_string, "%d", fds[1]);
execl(helper_path.c_str(),
"linux_dumper_unittest_helper",
pipe_fd_string,
kNumberOfThreadsArgument,
NULL);
// Kill if we get here.
printf("Errno from exec: %d", errno);
FAIL() << "Exec of " << helper_path << " failed: " << strerror(errno);
exit(0);
}
close(fds[1]);
// Wait for the child process to signal that it's ready.
struct pollfd pfd;
memset(&pfd, 0, sizeof(pfd));
pfd.fd = fds[0];
pfd.events = POLLIN | POLLERR;
const int r = HANDLE_EINTR(poll(&pfd, 1, 1000));
ASSERT_EQ(1, r);
ASSERT_TRUE(pfd.revents & POLLIN);
uint8_t junk;
read(fds[0], &junk, sizeof(junk));
close(fds[0]);
// Child is ready now.
LinuxDumper dumper(child_pid);
ASSERT_TRUE(dumper.Init());
EXPECT_EQ((size_t)kNumberOfThreadsInHelperProgram, dumper.threads().size());
EXPECT_TRUE(dumper.ThreadsSuspend());
ThreadInfo one_thread;
for(size_t i = 0; i < dumper.threads().size(); ++i) {
EXPECT_TRUE(dumper.ThreadInfoGet(dumper.threads()[i], &one_thread));
// In the helper program, we stored a pointer to the thread id in a
// specific register. Check that we can recover its value.
#if defined(__ARM_EABI__)
pid_t *process_tid_location = (pid_t *)(one_thread.regs.uregs[3]);
#elif defined(__i386)
pid_t *process_tid_location = (pid_t *)(one_thread.regs.ecx);
#elif defined(__x86_64)
pid_t *process_tid_location = (pid_t *)(one_thread.regs.rcx);
#else
#error This test has not been ported to this platform.
#endif
pid_t one_thread_id;
dumper.CopyFromProcess(&one_thread_id,
dumper.threads()[i],
process_tid_location,
4);
EXPECT_EQ(dumper.threads()[i], one_thread_id);
}
kill(child_pid, SIGKILL);
}
TEST(LinuxDumperTest, BuildProcPath) {
const pid_t pid = getpid();
LinuxDumper dumper(pid);
char maps_path[256] = "dummymappath";
char maps_path_expected[256];
snprintf(maps_path_expected, sizeof(maps_path_expected),
"/proc/%d/maps", pid);
dumper.BuildProcPath(maps_path, pid, "maps");
ASSERT_STREQ(maps_path, maps_path_expected);
// In release mode, we expect BuildProcPath to handle the invalid
// parameters correctly and fill map_path with an empty
// NULL-terminated string.
#ifdef NDEBUG
snprintf(maps_path, sizeof(maps_path), "dummymappath");
dumper.BuildProcPath(maps_path, 0, "maps");
EXPECT_STREQ(maps_path, "");
snprintf(maps_path, sizeof(maps_path), "dummymappath");
dumper.BuildProcPath(maps_path, getpid(), "");
EXPECT_STREQ(maps_path, "");
snprintf(maps_path, sizeof(maps_path), "dummymappath");
dumper.BuildProcPath(maps_path, getpid(), NULL);
EXPECT_STREQ(maps_path, "");
#endif
}
#if !defined(__ARM_EABI__)
// Ensure that the linux-gate VDSO is included in the mapping list.
TEST(LinuxDumperTest, MappingsIncludeLinuxGate) {
LinuxDumper dumper(getpid());
ASSERT_TRUE(dumper.Init());
void* linux_gate_loc = dumper.FindBeginningOfLinuxGateSharedLibrary(getpid());
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(LinuxDumperTest, LinuxGateMappingID) {
LinuxDumper 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(LinuxDumperTest, 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;
HANDLE_EINTR(read(fds[0], &b, sizeof(b)));
close(fds[0]);
syscall(__NR_exit);
}
close(fds[0]);
LinuxDumper 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(LinuxDumperTest, 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];
ssize_t len = readlink("/proc/self/exe", exe_name, PATH_MAX - 1);
ASSERT_NE(len, -1);
exe_name[len] = '\0';
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;
HANDLE_EINTR(read(fds[0], &b, sizeof(b)));
close(fds[0]);
syscall(__NR_exit);
}
close(fds[0]);
LinuxDumper 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]);
}

View File

@@ -1,4 +1,4 @@
// Copyright (c) 2006, Google Inc.
// Copyright (c) 2010, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
@@ -26,82 +26,60 @@
// 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.
/*
g++ -framework CoreFoundation -I../../.. \
../../minidump_file_writer.cc \
../../../common/convert_UTF.c \
../../../common/string_conversion.cc \
../../../common/mac/string_utilities.cc \
exception_handler.cc \
minidump_generator.cc \
exception_handler_test.cc \
-o exception_handler_test
*/
//
// Helper program for the linux_dumper class, which creates a bunch of
// threads. The first word of each thread's stack is set to the thread
// id.
#include <pthread.h>
#include <pwd.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/syscall.h>
#include <unistd.h>
#include <CoreFoundation/CoreFoundation.h>
#include "third_party/lss/linux_syscall_support.h"
#include "exception_handler.h"
#include "minidump_generator.h"
#if defined(__ARM_EABI__)
#define TID_PTR_REGISTER "r3"
#elif defined(__i386)
#define TID_PTR_REGISTER "ecx"
#elif defined(__x86_64)
#define TID_PTR_REGISTER "rcx"
#else
#error This test has not been ported to this platform.
#endif
using std::string;
using google_breakpad::ExceptionHandler;
void *thread_function(void *data) {
volatile pid_t thread_id = syscall(__NR_gettid);
register volatile pid_t *thread_id_ptr asm(TID_PTR_REGISTER) = &thread_id;
while (true)
asm volatile ("" : : "r" (thread_id_ptr));
return NULL;
}
static void *SleepyFunction(void *) {
while (1) {
sleep(10000);
int main(int argc, char *argv[]) {
if (argc < 2) {
fprintf(stderr,
"usage: linux_dumper_unittest_helper <pipe fd> <# of threads\n");
return 1;
}
}
static void Crasher() {
int *a = NULL;
fprintf(stdout, "Going to crash...\n");
fprintf(stdout, "A = %d", *a);
}
static void SoonToCrash() {
Crasher();
}
bool MDCallback(const char *dump_dir, const char *file_name,
void *context, bool success) {
string path(dump_dir);
string dest(dump_dir);
path.append(file_name);
path.append(".dmp");
fprintf(stdout, "Minidump: %s\n", path.c_str());
// Indicate that we've handled the callback
return true;
}
int main(int argc, char * const argv[]) {
char buffer[PATH_MAX];
struct passwd *user = getpwuid(getuid());
// Home dir
snprintf(buffer, sizeof(buffer), "/Users/%s/Desktop/", user->pw_name);
string path(buffer);
ExceptionHandler eh(path, NULL, MDCallback, NULL, true);
pthread_t t;
if (pthread_create(&t, NULL, SleepyFunction, NULL) == 0) {
pthread_detach(t);
} else {
perror("pthread_create");
int pipefd = atoi(argv[1]);
int num_threads = atoi(argv[2]);
if (num_threads < 1) {
fprintf(stderr, "ERROR: number of threads is 0");
return 1;
}
// Dump a test
eh.WriteMinidump();
// Test the handler
SoonToCrash();
pthread_t threads[num_threads];
pthread_attr_t thread_attributes;
pthread_attr_init(&thread_attributes);
pthread_attr_setdetachstate(&thread_attributes, PTHREAD_CREATE_DETACHED);
for (int i = 1; i < num_threads; i++) {
pthread_create(&threads[i], &thread_attributes, &thread_function, NULL);
}
// Signal parent that this process has started all threads.
uint8_t byte = 1;
write(pipefd, &byte, sizeof(byte));
thread_function(NULL);
return 0;
}

View File

@@ -0,0 +1,75 @@
/* Copyright (c) 2010, 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. */
/* minidump_extension_linux.h: A definition of exception codes for
* Linux
*
* (This is C99 source, please don't corrupt it with C++.)
*
* Author: Adam Langley
* Split into its own file: Markus Gutschke */
#ifndef SRC_CLIENT_LINUX_MINIDUMP_WRITER_MINIDUMP_EXTENSION_LINUX_H_
#define SRC_CLIENT_LINUX_MINIDUMP_WRITER_MINIDUMP_EXTENSION_LINUX_H_
#include <stddef.h>
#include "google_breakpad/common/breakpad_types.h"
#include "google_breakpad/common/minidump_format.h"
// These are additional minidump stream values which are specific to the linux
// breakpad implementation.
enum {
MD_LINUX_CPU_INFO = 0x47670003, /* /proc/cpuinfo */
MD_LINUX_PROC_STATUS = 0x47670004, /* /proc/$x/status */
MD_LINUX_LSB_RELEASE = 0x47670005, /* /etc/lsb-release */
MD_LINUX_CMD_LINE = 0x47670006, /* /proc/$x/cmdline */
MD_LINUX_ENVIRON = 0x47670007, /* /proc/$x/environ */
MD_LINUX_AUXV = 0x47670008, /* /proc/$x/auxv */
MD_LINUX_MAPS = 0x47670009, /* /proc/$x/maps */
MD_LINUX_DSO_DEBUG = 0x4767000A /* DSO data */
};
typedef struct {
void* addr;
MDRVA name;
void* ld;
} MDRawLinkMap;
typedef struct {
u_int32_t version;
MDRVA map;
u_int32_t dso_count;
void* brk;
void* ldbase;
void* dynamic;
} MDRawDebug;
#endif // SRC_CLIENT_LINUX_MINIDUMP_WRITER_MINIDUMP_EXTENSION_LINUX_H_

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,67 @@
// Copyright (c) 2009, 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_MINIDUMP_WRITER_H_
#define CLIENT_LINUX_MINIDUMP_WRITER_MINIDUMP_WRITER_H_
#include <stdint.h>
#include <unistd.h>
#include <list>
#include <utility>
#include "google_breakpad/common/minidump_format.h"
namespace google_breakpad {
// A list of <MappingInfo, GUID>
typedef std::pair<struct MappingInfo, u_int8_t[sizeof(MDGUID)]> MappingEntry;
typedef std::list<MappingEntry> MappingList;
// Write a minidump to the filesystem. This function does not malloc nor use
// libc functions which may. Thus, it can be used in contexts where the state
// of the heap may be corrupt.
// filename: the filename to write to. This is opened O_EXCL and fails if
// open fails.
// 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
//
// Returns true iff successful.
bool WriteMinidump(const char* filename, pid_t crashing_process,
const void* blob, size_t blob_size);
// This overload also allows passing a list of known mappings.
bool WriteMinidump(const char* filename, pid_t crashing_process,
const void* blob, size_t blob_size,
const MappingList& mappings);
} // namespace google_breakpad
#endif // CLIENT_LINUX_MINIDUMP_WRITER_MINIDUMP_WRITER_H_

View File

@@ -0,0 +1,396 @@
// Copyright (c) 2011 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 <fcntl.h>
#include <sys/poll.h>
#include <sys/stat.h>
#include <sys/syscall.h>
#include <sys/types.h>
#include <unistd.h>
#include <string>
#include "breakpad_googletest_includes.h"
#include "client/linux/handler/exception_handler.h"
#include "client/linux/minidump_writer/linux_dumper.h"
#include "client/linux/minidump_writer/minidump_writer.h"
#include "common/linux/eintr_wrapper.h"
#include "common/linux/file_id.h"
#include "google_breakpad/processor/minidump.h"
using namespace google_breakpad;
#if !defined(__ANDROID__)
#define TEMPDIR "/tmp"
#else
#define TEMPDIR "/data/local/tmp"
#endif
// Length of a formatted GUID string =
// sizeof(MDGUID) * 2 + 4 (for dashes) + 1 (null terminator)
const int kGUIDStringSize = 37;
namespace {
typedef testing::Test MinidumpWriterTest;
}
TEST(MinidumpWriterTest, Setup) {
int fds[2];
ASSERT_NE(-1, pipe(fds));
const pid_t child = fork();
if (child == 0) {
close(fds[1]);
char b;
HANDLE_EINTR(read(fds[0], &b, sizeof(b)));
close(fds[0]);
syscall(__NR_exit);
}
close(fds[0]);
ExceptionHandler::CrashContext context;
memset(&context, 0, sizeof(context));
char templ[] = TEMPDIR "/minidump-writer-unittest-XXXXXX";
mktemp(templ);
// Set a non-zero tid to avoid tripping asserts.
context.tid = 1;
ASSERT_TRUE(WriteMinidump(templ, child, &context, sizeof(context)));
struct stat st;
ASSERT_EQ(stat(templ, &st), 0);
ASSERT_GT(st.st_size, 0u);
unlink(templ);
close(fds[1]);
}
// Test that mapping info can be specified when writing a minidump,
// and that it ends up in the module list of the minidump.
TEST(MinidumpWriterTest, MappingInfo) {
int fds[2];
ASSERT_NE(-1, pipe(fds));
// These are defined here so the parent can use them to check the
// data from the minidump afterwards.
const u_int32_t kMemorySize = sysconf(_SC_PAGESIZE);
const char* kMemoryName = "a fake module";
const u_int8_t kModuleGUID[sizeof(MDGUID)] = {
0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF
};
char module_identifier_buffer[kGUIDStringSize];
FileID::ConvertIdentifierToString(kModuleGUID,
module_identifier_buffer,
sizeof(module_identifier_buffer));
string module_identifier(module_identifier_buffer);
// Strip out dashes
size_t pos;
while ((pos = module_identifier.find('-')) != string::npos) {
module_identifier.erase(pos, 1);
}
// And append a zero, because module IDs include an "age" field
// which is always zero on Linux.
module_identifier += "0";
// Get some memory.
char* memory =
reinterpret_cast<char*>(mmap(NULL,
kMemorySize,
PROT_READ | PROT_WRITE,
MAP_PRIVATE | MAP_ANON,
-1,
0));
const u_int64_t kMemoryAddress = reinterpret_cast<u_int64_t>(memory);
ASSERT_TRUE(memory);
const pid_t child = fork();
if (child == 0) {
close(fds[1]);
char b;
HANDLE_EINTR(read(fds[0], &b, sizeof(b)));
close(fds[0]);
syscall(__NR_exit);
}
close(fds[0]);
ExceptionHandler::CrashContext context;
memset(&context, 0, sizeof(context));
context.tid = 1;
char templ[] = TEMPDIR "/minidump-writer-unittest-XXXXXX";
mktemp(templ);
// Add information about the mapped memory.
MappingInfo info;
info.start_addr = kMemoryAddress;
info.size = kMemorySize;
info.offset = 0;
strcpy(info.name, kMemoryName);
MappingList mappings;
MappingEntry mapping;
mapping.first = info;
memcpy(mapping.second, kModuleGUID, sizeof(MDGUID));
mappings.push_back(mapping);
ASSERT_TRUE(WriteMinidump(templ, child, &context, sizeof(context), mappings));
// Read the minidump. Load the module list, and ensure that
// the mmap'ed |memory| is listed with the given module name
// and debug ID.
Minidump minidump(templ);
ASSERT_TRUE(minidump.Read());
MinidumpModuleList* module_list = minidump.GetModuleList();
ASSERT_TRUE(module_list);
const MinidumpModule* module =
module_list->GetModuleForAddress(kMemoryAddress);
ASSERT_TRUE(module);
EXPECT_EQ(kMemoryAddress, module->base_address());
EXPECT_EQ(kMemorySize, module->size());
EXPECT_EQ(kMemoryName, module->code_file());
EXPECT_EQ(module_identifier, module->debug_identifier());
unlink(templ);
close(fds[1]);
}
// Test that mapping info can be specified, and that it overrides
// existing mappings that are wholly contained within the specified
// range.
TEST(MinidumpWriterTest, MappingInfoContained) {
int fds[2];
ASSERT_NE(-1, pipe(fds));
// These are defined here so the parent can use them to check the
// data from the minidump afterwards.
const u_int32_t kMemorySize = sysconf(_SC_PAGESIZE);
const char* kMemoryName = "a fake module";
const u_int8_t kModuleGUID[sizeof(MDGUID)] = {
0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF
};
char module_identifier_buffer[kGUIDStringSize];
FileID::ConvertIdentifierToString(kModuleGUID,
module_identifier_buffer,
sizeof(module_identifier_buffer));
string module_identifier(module_identifier_buffer);
// Strip out dashes
size_t pos;
while ((pos = module_identifier.find('-')) != string::npos) {
module_identifier.erase(pos, 1);
}
// And append a zero, because module IDs include an "age" field
// which is always zero on Linux.
module_identifier += "0";
// mmap a file
char tempfile[] = TEMPDIR "/minidump-writer-unittest-temp-XXXXXX";
mktemp(tempfile);
int fd = open(tempfile, O_RDWR | O_CREAT, 0);
ASSERT_NE(-1, fd);
unlink(tempfile);
// fill with zeros
char buffer[kMemorySize];
memset(buffer, 0, kMemorySize);
ASSERT_EQ(kMemorySize, write(fd, buffer, kMemorySize));
lseek(fd, 0, SEEK_SET);
char* memory =
reinterpret_cast<char*>(mmap(NULL,
kMemorySize,
PROT_READ | PROT_WRITE,
MAP_PRIVATE,
fd,
0));
const u_int64_t kMemoryAddress = reinterpret_cast<u_int64_t>(memory);
ASSERT_TRUE(memory);
close(fd);
const pid_t child = fork();
if (child == 0) {
close(fds[1]);
char b;
HANDLE_EINTR(read(fds[0], &b, sizeof(b)));
close(fds[0]);
syscall(__NR_exit);
}
close(fds[0]);
ExceptionHandler::CrashContext context;
memset(&context, 0, sizeof(context));
context.tid = 1;
char dumpfile[] = TEMPDIR "/minidump-writer-unittest-XXXXXX";
mktemp(dumpfile);
// Add information about the mapped memory. Report it as being larger than
// it actually is.
MappingInfo info;
info.start_addr = kMemoryAddress - kMemorySize;
info.size = kMemorySize * 3;
info.offset = 0;
strcpy(info.name, kMemoryName);
MappingList mappings;
MappingEntry mapping;
mapping.first = info;
memcpy(mapping.second, kModuleGUID, sizeof(MDGUID));
mappings.push_back(mapping);
ASSERT_TRUE(
WriteMinidump(dumpfile, child, &context, sizeof(context), mappings));
// Read the minidump. Load the module list, and ensure that
// the mmap'ed |memory| is listed with the given module name
// and debug ID.
Minidump minidump(dumpfile);
ASSERT_TRUE(minidump.Read());
MinidumpModuleList* module_list = minidump.GetModuleList();
ASSERT_TRUE(module_list);
const MinidumpModule* module =
module_list->GetModuleForAddress(kMemoryAddress);
ASSERT_TRUE(module);
EXPECT_EQ(info.start_addr, module->base_address());
EXPECT_EQ(info.size, module->size());
EXPECT_EQ(kMemoryName, module->code_file());
EXPECT_EQ(module_identifier, module->debug_identifier());
unlink(dumpfile);
close(fds[1]);
}
TEST(MinidumpWriterTest, DeletedBinary) {
static const int kNumberOfThreadsInHelperProgram = 1;
char kNumberOfThreadsArgument[2];
sprintf(kNumberOfThreadsArgument, "%d", kNumberOfThreadsInHelperProgram);
// Locate helper binary next to the current binary.
char self_path[PATH_MAX];
if (readlink("/proc/self/exe", self_path, sizeof(self_path) - 1) == -1) {
FAIL() << "readlink failed: " << strerror(errno);
exit(1);
}
string helper_path(self_path);
size_t pos = helper_path.rfind('/');
if (pos == string::npos) {
FAIL() << "no trailing slash in path: " << helper_path;
exit(1);
}
helper_path.erase(pos + 1);
helper_path += "linux_dumper_unittest_helper";
// Copy binary to a temp file.
char binpath[] = TEMPDIR "/linux-dumper-unittest-helper-XXXXXX";
mktemp(binpath);
char cmdline[2 * PATH_MAX];
sprintf(cmdline, "/bin/cp \"%s\" \"%s\"", helper_path.c_str(), binpath);
ASSERT_EQ(0, system(cmdline));
ASSERT_EQ(0, chmod(binpath, 0755));
int fds[2];
ASSERT_NE(-1, pipe(fds));
pid_t child_pid = fork();
if (child_pid == 0) {
// In child process.
close(fds[0]);
// Pass the pipe fd and the number of threads as arguments.
char pipe_fd_string[8];
sprintf(pipe_fd_string, "%d", fds[1]);
execl(binpath,
binpath,
pipe_fd_string,
kNumberOfThreadsArgument,
NULL);
}
close(fds[1]);
// Wait for the child process to signal that it's ready.
struct pollfd pfd;
memset(&pfd, 0, sizeof(pfd));
pfd.fd = fds[0];
pfd.events = POLLIN | POLLERR;
const int r = HANDLE_EINTR(poll(&pfd, 1, 1000));
ASSERT_EQ(1, r);
ASSERT_TRUE(pfd.revents & POLLIN);
uint8_t junk;
read(fds[0], &junk, sizeof(junk));
close(fds[0]);
// Child is ready now.
// Unlink the test binary.
unlink(binpath);
ExceptionHandler::CrashContext context;
memset(&context, 0, sizeof(context));
char templ[] = TEMPDIR "/minidump-writer-unittest-XXXXXX";
mktemp(templ);
// Set a non-zero tid to avoid tripping asserts.
context.tid = 1;
ASSERT_TRUE(WriteMinidump(templ, child_pid, &context, sizeof(context)));
kill(child_pid, SIGKILL);
struct stat st;
ASSERT_EQ(stat(templ, &st), 0);
ASSERT_GT(st.st_size, 0u);
Minidump minidump(templ);
ASSERT_TRUE(minidump.Read());
// Check that the main module filename is correct.
MinidumpModuleList* module_list = minidump.GetModuleList();
ASSERT_TRUE(module_list);
const MinidumpModule* module = module_list->GetMainModule();
EXPECT_STREQ(binpath, module->code_file().c_str());
// Check that the file ID is correct.
FileID fileid(helper_path.c_str());
uint8_t identifier[sizeof(MDGUID)];
EXPECT_TRUE(fileid.ElfFileIdentifier(identifier));
char identifier_string[kGUIDStringSize];
FileID::ConvertIdentifierToString(identifier,
identifier_string,
kGUIDStringSize);
string module_identifier(identifier_string);
// Strip out dashes
while ((pos = module_identifier.find('-')) != string::npos) {
module_identifier.erase(pos, 1);
}
// And append a zero, because module IDs include an "age" field
// which is always zero on Linux.
module_identifier += "0";
EXPECT_EQ(module_identifier, module->debug_identifier());
unlink(templ);
}

View File

@@ -0,0 +1,104 @@
// Copyright (c) 2009, 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/google_crashdump_uploader.h"
#include "third_party/linux/include/gflags/gflags.h"
#include <string>
#include <iostream>
using std::string;
DEFINE_string(crash_server, "http://clients2.google.com/cr",
"The crash server to upload minidumps to.");
DEFINE_string(product_name, "",
"The product name that the minidump corresponds to.");
DEFINE_string(product_version, "",
"The version of the product that produced the minidump.");
DEFINE_string(client_id, "",
"The client GUID");
DEFINE_string(minidump_path, "",
"The path of the minidump file.");
DEFINE_string(ptime, "",
"The process uptime in milliseconds.");
DEFINE_string(ctime, "",
"The cumulative process uptime in milliseconds.");
DEFINE_string(email, "",
"The user's email address.");
DEFINE_string(comments, "",
"Extra user comments");
DEFINE_string(proxy_host, "",
"Proxy host");
DEFINE_string(proxy_userpasswd, "",
"Proxy username/password in user:pass format.");
bool CheckForRequiredFlagsOrDie() {
std::string error_text = "";
if (FLAGS_product_name.empty()) {
error_text.append("\nProduct name must be specified.");
}
if (FLAGS_product_version.empty()) {
error_text.append("\nProduct version must be specified.");
}
if (FLAGS_client_id.empty()) {
error_text.append("\nClient ID must be specified.");
}
if (FLAGS_minidump_path.empty()) {
error_text.append("\nMinidump pathname must be specified.");
}
if (!error_text.empty()) {
std::cout << error_text;
return false;
}
return true;
}
int main(int argc, char *argv[]) {
google::InitGoogleLogging(argv[0]);
google::ParseCommandLineFlags(&argc, &argv, true);
if (!CheckForRequiredFlagsOrDie()) {
return 1;
}
google_breakpad::GoogleCrashdumpUploader g(FLAGS_product_name,
FLAGS_product_version,
FLAGS_client_id,
FLAGS_ptime,
FLAGS_ctime,
FLAGS_email,
FLAGS_comments,
FLAGS_minidump_path,
FLAGS_crash_server,
FLAGS_proxy_host,
FLAGS_proxy_userpasswd);
g.Upload();
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,320 @@
// Copyright (c) 2006, 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.
//
// Framework to provide a simple C API to crash reporting for
// applications. By default, if any machine-level exception (e.g.,
// EXC_BAD_ACCESS) occurs, it will be handled by the BreakpadRef
// object as follows:
//
// 1. Create a minidump file (see Breakpad for details)
// 2. Prompt the user (using CFUserNotification)
// 3. Invoke a command line reporting tool to send the minidump to a
// server
//
// By specifying parameters to the BreakpadCreate function, you can
// modify the default behavior to suit your needs and wants and
// desires.
typedef void *BreakpadRef;
#ifdef __cplusplus
extern "C" {
#endif
#include <CoreFoundation/CoreFoundation.h>
#include <Foundation/Foundation.h>
// Keys for configuration file
#define kReporterMinidumpDirectoryKey "MinidumpDir"
#define kReporterMinidumpIDKey "MinidumpID"
// Filename for recording uploaded IDs
#define kReporterLogFilename "uploads.log"
// The default subdirectory of the Library to put crash dumps in
// The subdirectory is
// ~/Library/<kDefaultLibrarySubdirectory>/<GoogleBreakpadProduct>
#define kDefaultLibrarySubdirectory "Breakpad"
// Specify some special keys to be used in the configuration file that is
// generated by Breakpad and consumed by the crash_sender.
#define BREAKPAD_PRODUCT "BreakpadProduct"
#define BREAKPAD_PRODUCT_DISPLAY "BreakpadProductDisplay"
#define BREAKPAD_VERSION "BreakpadVersion"
#define BREAKPAD_VENDOR "BreakpadVendor"
#define BREAKPAD_URL "BreakpadURL"
#define BREAKPAD_REPORT_INTERVAL "BreakpadReportInterval"
#define BREAKPAD_SKIP_CONFIRM "BreakpadSkipConfirm"
#define BREAKPAD_CONFIRM_TIMEOUT "BreakpadConfirmTimeout"
#define BREAKPAD_SEND_AND_EXIT "BreakpadSendAndExit"
#define BREAKPAD_DUMP_DIRECTORY "BreakpadMinidumpLocation"
#define BREAKPAD_INSPECTOR_LOCATION "BreakpadInspectorLocation"
#define BREAKPAD_REPORTER_EXE_LOCATION \
"BreakpadReporterExeLocation"
#define BREAKPAD_LOGFILES "BreakpadLogFiles"
#define BREAKPAD_LOGFILE_UPLOAD_SIZE "BreakpadLogFileTailSize"
#define BREAKPAD_REQUEST_COMMENTS "BreakpadRequestComments"
#define BREAKPAD_COMMENTS "BreakpadComments"
#define BREAKPAD_REQUEST_EMAIL "BreakpadRequestEmail"
#define BREAKPAD_EMAIL "BreakpadEmail"
#define BREAKPAD_SERVER_TYPE "BreakpadServerType"
#define BREAKPAD_SERVER_PARAMETER_DICT "BreakpadServerParameters"
// The keys below are NOT user supplied, and are used internally.
#define BREAKPAD_PROCESS_START_TIME "BreakpadProcStartTime"
#define BREAKPAD_PROCESS_UP_TIME "BreakpadProcessUpTime"
#define BREAKPAD_PROCESS_CRASH_TIME "BreakpadProcessCrashTime"
#define BREAKPAD_LOGFILE_KEY_PREFIX "BreakpadAppLogFile"
#define BREAKPAD_SERVER_PARAMETER_PREFIX "BreakpadServerParameterPrefix_"
#define BREAKPAD_ON_DEMAND "BreakpadOnDemand"
// A service name associated with the original bootstrap parent port, saved in
// OnDemandServer and restored in Inspector.
#define BREAKPAD_BOOTSTRAP_PARENT_PORT "com.Breakpad.BootstrapParent"
// Optional user-defined function to dec to decide if we should handle
// this crash or forward it along.
// Return true if you want Breakpad to handle it.
// Return false if you want Breakpad to skip it
// The exception handler always returns false, as if SEND_AND_EXIT were false
// (which means the next exception handler will take the exception)
typedef bool (*BreakpadFilterCallback)(int exception_type,
int exception_code,
mach_port_t crashing_thread,
void *context);
// Create a new BreakpadRef object and install it as an exception
// handler. The |parameters| will typically be the contents of your
// bundle's Info.plist.
//
// You can also specify these additional keys for customizable behavior:
// Key: Value:
// BREAKPAD_PRODUCT Product name (e.g., "MyAwesomeProduct")
// This one is used as the key to identify
// the product when uploading. Falls back to
// CFBundleName if not specified.
// REQUIRED
//
// BREAKPAD_PRODUCT_DISPLAY This is the display name, e.g. a pretty
// name for the product when the crash_sender
// pops up UI for the user. Falls back first to
// CFBundleDisplayName and then to
// BREAKPAD_PRODUCT if not specified.
//
// BREAKPAD_VERSION Product version (e.g., 1.2.3), used
// as metadata for crash report. Falls back to
// CFBundleVersion if not specified.
// REQUIRED
//
// BREAKPAD_VENDOR Vendor name, used in UI (e.g. "A report has
// been created that you can send to <vendor>")
//
// BREAKPAD_URL URL destination for reporting
// REQUIRED
//
// BREAKPAD_REPORT_INTERVAL # of seconds between sending
// reports. If an additional report is
// generated within this time, it will
// be ignored. Default: 3600sec.
// Specify 0 to send all reports.
//
// BREAKPAD_SKIP_CONFIRM If true, the reporter will send the report
// without any user intervention.
// Defaults to NO
//
// BREAKPAD_CONFIRM_TIMEOUT Number of seconds before the upload
// confirmation dialog will be automatically
// dismissed (cancelling the upload).
// Default: 300 seconds (min of 60).
// Specify 0 to prevent timeout.
//
// BREAKPAD_SEND_AND_EXIT If true, the handler will exit after sending.
// This will prevent any other handler (e.g.,
// CrashReporter) from getting the crash.
// Defaults TO YES
//
// BREAKPAD_DUMP_DIRECTORY The directory to store crash-dumps
// in. By default, we use
// ~/Library/Breakpad/<BREAKPAD_PRODUCT>
// The path you specify here is tilde-expanded.
//
// BREAKPAD_INSPECTOR_LOCATION The full path to the Inspector executable.
// Defaults to <Framework resources>/Inspector
//
// BREAKPAD_REPORTER_EXE_LOCATION The full path to the Reporter/sender
// executable.
// Default:
// <Framework Resources>/crash_report_sender.app
//
// BREAKPAD_LOGFILES Indicates an array of log file paths that
// should be uploaded at crash time.
//
// BREAKPAD_REQUEST_COMMENTS If true, the message dialog will have a
// text box for the user to enter comments.
// Default: NO
//
// BREAKPAD_REQUEST_EMAIL If true and BREAKPAD_REQUEST_COMMENTS is also
// true, the message dialog will have a text
// box for the user to enter their email address.
// Default: NO
//
// BREAKPAD_SERVER_TYPE A parameter that tells Breakpad how to
// rewrite the upload parameters for a specific
// server type. The currently valid values are
// 'socorro' or 'google'. If you want to add
// other types, see the function in
// crash_report_sender.m that maps parameters to
// URL parameters. Defaults to 'google'.
//
// BREAKPAD_SERVER_PARAMETER_DICT A plist dictionary of static
// parameters that are uploaded to the
// server. The parameters are sent as
// is to the crash server. Their
// content isn't added to the minidump
// but pass as URL parameters when
// uploading theminidump to the crash
// server.
//=============================================================================
// The BREAKPAD_PRODUCT, BREAKPAD_VERSION and BREAKPAD_URL are
// required to have non-NULL values. By default, the BREAKPAD_PRODUCT
// will be the CFBundleName and the BREAKPAD_VERSION will be the
// CFBundleVersion when these keys are present in the bundle's
// Info.plist, which is usually passed in to BreakpadCreate() as an
// NSDictionary (you could also pass in another dictionary that had
// the same keys configured). If the BREAKPAD_PRODUCT or
// BREAKPAD_VERSION are ultimately undefined, BreakpadCreate() will
// fail. You have been warned.
//
// If you are running in a debugger, Breakpad will not install, unless the
// BREAKPAD_IGNORE_DEBUGGER envionment variable is set and/or non-zero.
//
// The BREAKPAD_SKIP_CONFIRM and BREAKPAD_SEND_AND_EXIT default
// values are NO and YES. However, they can be controlled by setting their
// values in a user or global plist.
//
// It's easiest to use Breakpad via the Framework, but if you're compiling the
// code in directly, BREAKPAD_INSPECTOR_LOCATION and
// BREAKPAD_REPORTER_EXE_LOCATION allow you to specify custom paths
// to the helper executables.
//
//=============================================================================
// The following are NOT user-supplied but are documented here for
// completeness. They are calculated by Breakpad during initialization &
// crash-dump generation, or entered in by the user.
//
// BREAKPAD_PROCESS_START_TIME The time the process started.
//
// BREAKPAD_PROCESS_CRASH_TIME The time the process crashed.
//
// BREAKPAD_PROCESS_UP_TIME The total time the process has been
// running. This parameter is not set
// until the crash-dump-generation phase.
//
// BREAKPAD_LOGFILE_KEY_PREFIX Used to find out which parameters in the
// parameter dictionary correspond to log
// file paths.
//
// BREAKPAD_SERVER_PARAMETER_PREFIX This prefix is used by Breakpad
// internally, because Breakpad uses
// the same dictionary internally to
// track both its internal
// configuration parameters and
// parameters meant to be uploaded
// to the server. This string is
// used internally by Breakpad to
// prefix user-supplied parameter
// names so those can be sent to the
// server without leaking Breakpad's
// internal values.
//
// BREAKPAD_ON_DEMAND Used internally to indicate to the
// Reporter that we're sending on-demand,
// not as result of a crash.
//
// BREAKPAD_COMMENTS The text the user provided as comments.
// Only used in crash_report_sender.
// Returns a new BreakpadRef object on success, NULL otherwise.
BreakpadRef BreakpadCreate(NSDictionary *parameters);
// Uninstall and release the data associated with |ref|.
void BreakpadRelease(BreakpadRef ref);
// Clients may set an optional callback which gets called when a crash
// occurs. The callback function should return |true| if we should
// handle the crash, generate a crash report, etc. or |false| if we
// should ignore it and forward the crash (normally to CrashReporter).
// Context is a pointer to arbitrary data to make the callback with.
void BreakpadSetFilterCallback(BreakpadRef ref,
BreakpadFilterCallback callback,
void *context);
// User defined key and value string storage. Generally this is used
// to configure Breakpad's internal operation, such as whether the
// crash_sender should prompt the user, or the filesystem location for
// the minidump file. See Breakpad.h for some parameters that can be
// set. Anything longer than 255 bytes will be truncated. Note that
// the string is converted to UTF8 before truncation, so any multibyte
// character that straddles the 255(256 - 1 for terminator) byte limit
// will be mangled.
//
// A maximum number of 64 key/value pairs are supported. An assert()
// will fire if more than this number are set. Unfortunately, right
// now, the same dictionary is used for both Breakpad's parameters AND
// the Upload parameters.
//
// TODO (nealsid): Investigate how necessary this is if we don't
// automatically upload parameters to the server anymore.
// TODO (nealsid): separate server parameter dictionary from the
// dictionary used to configure Breakpad, and document limits for each
// independently.
void BreakpadSetKeyValue(BreakpadRef ref, NSString *key, NSString *value);
NSString *BreakpadKeyValue(BreakpadRef ref, NSString *key);
void BreakpadRemoveKeyValue(BreakpadRef ref, NSString *key);
// You can use this method to specify parameters that will be uploaded
// to the crash server. They will be automatically encoded as
// necessary. Note that as mentioned above there are limits on both
// the number of keys and their length.
void BreakpadAddUploadParameter(BreakpadRef ref, NSString *key,
NSString *value);
// This method will remove a previously-added parameter from the
// upload parameter set.
void BreakpadRemoveUploadParameter(BreakpadRef ref, NSString *key);
// Add a log file for Breakpad to read and send upon crash dump
void BreakpadAddLogFile(BreakpadRef ref, NSString *logPathname);
// Generate a minidump and send
void BreakpadGenerateAndSendReport(BreakpadRef ref);
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,996 @@
// Copyright (c) 2006, 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.
//
#define VERBOSE 0
#if VERBOSE
static bool gDebugLog = true;
#else
static bool gDebugLog = false;
#endif
#define DEBUGLOG if (gDebugLog) fprintf
#define IGNORE_DEBUGGER "BREAKPAD_IGNORE_DEBUGGER"
#import "common/mac/MachIPC.h"
#import "common/mac/SimpleStringDictionary.h"
#import "client/mac/crash_generation/Inspector.h"
#import "client/mac/handler/exception_handler.h"
#import "client/mac/Framework/Breakpad.h"
#import "client/mac/Framework/OnDemandServer.h"
#import "client/mac/handler/protected_memory_allocator.h"
#import <sys/stat.h>
#import <sys/sysctl.h>
#import <Foundation/Foundation.h>
using google_breakpad::KeyValueEntry;
using google_breakpad::MachPortSender;
using google_breakpad::MachReceiveMessage;
using google_breakpad::MachSendMessage;
using google_breakpad::ReceivePort;
using google_breakpad::SimpleStringDictionary;
using google_breakpad::SimpleStringDictionaryIterator;
//=============================================================================
// We want any memory allocations which are used by breakpad during the
// exception handling process (after a crash has happened) to be read-only
// to prevent them from being smashed before a crash occurs. Unfortunately
// we cannot protect against smashes to our exception handling thread's
// stack.
//
// NOTE: Any memory allocations which are not used during the exception
// handling process may be allocated in the normal ways.
//
// The ProtectedMemoryAllocator class provides an Allocate() method which
// we'll using in conjunction with placement operator new() to control
// allocation of C++ objects. Note that we don't use operator delete()
// but instead call the objects destructor directly: object->~ClassName();
//
ProtectedMemoryAllocator *gMasterAllocator = NULL;
ProtectedMemoryAllocator *gKeyValueAllocator = NULL;
ProtectedMemoryAllocator *gBreakpadAllocator = NULL;
// Mutex for thread-safe access to the key/value dictionary used by breakpad.
// It's a global instead of an instance variable of Breakpad
// since it can't live in a protected memory area.
pthread_mutex_t gDictionaryMutex;
//=============================================================================
// Stack-based object for thread-safe access to a memory-protected region.
// It's assumed that normally the memory block (allocated by the allocator)
// is protected (read-only). Creating a stack-based instance of
// ProtectedMemoryLocker will unprotect this block after taking the lock.
// Its destructor will first re-protect the memory then release the lock.
class ProtectedMemoryLocker {
public:
// allocator may be NULL, in which case no Protect() or Unprotect() calls
// will be made, but a lock will still be taken
ProtectedMemoryLocker(pthread_mutex_t *mutex,
ProtectedMemoryAllocator *allocator)
: mutex_(mutex), allocator_(allocator) {
// Lock the mutex
assert(pthread_mutex_lock(mutex_) == 0);
// Unprotect the memory
if (allocator_ ) {
allocator_->Unprotect();
}
}
~ProtectedMemoryLocker() {
// First protect the memory
if (allocator_) {
allocator_->Protect();
}
// Then unlock the mutex
assert(pthread_mutex_unlock(mutex_) == 0);
};
private:
// Keep anybody from ever creating one of these things not on the stack.
ProtectedMemoryLocker() { }
ProtectedMemoryLocker(const ProtectedMemoryLocker&);
ProtectedMemoryLocker & operator=(ProtectedMemoryLocker&);
pthread_mutex_t *mutex_;
ProtectedMemoryAllocator *allocator_;
};
//=============================================================================
class Breakpad {
public:
// factory method
static Breakpad *Create(NSDictionary *parameters) {
// Allocate from our special allocation pool
Breakpad *breakpad =
new (gBreakpadAllocator->Allocate(sizeof(Breakpad)))
Breakpad();
if (!breakpad)
return NULL;
if (!breakpad->Initialize(parameters)) {
// Don't use operator delete() here since we allocated from special pool
breakpad->~Breakpad();
return NULL;
}
return breakpad;
}
~Breakpad();
void SetKeyValue(NSString *key, NSString *value);
NSString *KeyValue(NSString *key);
void RemoveKeyValue(NSString *key);
void GenerateAndSendReport();
void SetFilterCallback(BreakpadFilterCallback callback, void *context) {
filter_callback_ = callback;
filter_callback_context_ = context;
}
private:
Breakpad()
: handler_(NULL),
config_params_(NULL),
send_and_exit_(true),
filter_callback_(NULL),
filter_callback_context_(NULL) {
inspector_path_[0] = 0;
}
bool Initialize(NSDictionary *parameters);
bool ExtractParameters(NSDictionary *parameters);
// Dispatches to HandleException()
static bool ExceptionHandlerDirectCallback(void *context,
int exception_type,
int exception_code,
int exception_subcode,
mach_port_t crashing_thread);
bool HandleException(int exception_type,
int exception_code,
int exception_subcode,
mach_port_t crashing_thread);
// Since ExceptionHandler (w/o namespace) is defined as typedef in OSX's
// MachineExceptions.h, we have to explicitly name the handler.
google_breakpad::ExceptionHandler *handler_; // The actual handler (STRONG)
char inspector_path_[PATH_MAX]; // Path to inspector tool
SimpleStringDictionary *config_params_; // Create parameters (STRONG)
OnDemandServer inspector_;
bool send_and_exit_; // Exit after sending, if true
BreakpadFilterCallback filter_callback_;
void *filter_callback_context_;
};
#pragma mark -
#pragma mark Helper functions
//=============================================================================
// Helper functions
//=============================================================================
static BOOL IsDebuggerActive() {
BOOL result = NO;
NSUserDefaults *stdDefaults = [NSUserDefaults standardUserDefaults];
// We check both defaults and the environment variable here
BOOL ignoreDebugger = [stdDefaults boolForKey:@IGNORE_DEBUGGER];
if (!ignoreDebugger) {
char *ignoreDebuggerStr = getenv(IGNORE_DEBUGGER);
ignoreDebugger = (ignoreDebuggerStr ? strtol(ignoreDebuggerStr, NULL, 10) : 0) != 0;
}
if (!ignoreDebugger) {
pid_t pid = getpid();
int mib[4] = {CTL_KERN, KERN_PROC, KERN_PROC_PID, pid};
int mibSize = sizeof(mib) / sizeof(int);
size_t actualSize;
if (sysctl(mib, mibSize, NULL, &actualSize, NULL, 0) == 0) {
struct kinfo_proc *info = (struct kinfo_proc *)malloc(actualSize);
if (info) {
// This comes from looking at the Darwin xnu Kernel
if (sysctl(mib, mibSize, info, &actualSize, NULL, 0) == 0)
result = (info->kp_proc.p_flag & P_TRACED) ? YES : NO;
free(info);
}
}
}
return result;
}
//=============================================================================
bool Breakpad::ExceptionHandlerDirectCallback(void *context,
int exception_type,
int exception_code,
int exception_subcode,
mach_port_t crashing_thread) {
Breakpad *breakpad = (Breakpad *)context;
// If our context is damaged or something, just return false to indicate that
// the handler should continue without us.
if (!breakpad)
return false;
return breakpad->HandleException( exception_type,
exception_code,
exception_subcode,
crashing_thread);
}
//=============================================================================
#pragma mark -
#include <dlfcn.h>
//=============================================================================
// Returns the pathname to the Resources directory for this version of
// Breakpad which we are now running.
//
// Don't make the function static, since _dyld_lookup_and_bind_fully needs a
// simple non-static C name
//
extern "C" {
NSString * GetResourcePath();
NSString * GetResourcePath() {
NSString *resourcePath = nil;
// If there are multiple breakpads installed then calling bundleWithIdentifier
// will not work properly, so only use that as a backup plan.
// We want to find the bundle containing the code where this function lives
// and work from there
//
// Get the pathname to the code which contains this function
Dl_info info;
if (dladdr((const void*)GetResourcePath, &info) != 0) {
NSFileManager *filemgr = [NSFileManager defaultManager];
NSString *filePath =
[filemgr stringWithFileSystemRepresentation:info.dli_fname
length:strlen(info.dli_fname)];
NSString *bundlePath = [filePath stringByDeletingLastPathComponent];
// The "Resources" directory should be in the same directory as the
// executable code, since that's how the Breakpad framework is built.
resourcePath = [bundlePath stringByAppendingPathComponent:@"Resources/"];
} else {
DEBUGLOG(stderr, "Could not find GetResourcePath\n");
// fallback plan
NSBundle *bundle =
[NSBundle bundleWithIdentifier:@"com.Google.BreakpadFramework"];
resourcePath = [bundle resourcePath];
}
return resourcePath;
}
} // extern "C"
//=============================================================================
bool Breakpad::Initialize(NSDictionary *parameters) {
// Initialize
config_params_ = NULL;
handler_ = NULL;
// Check for debugger
if (IsDebuggerActive()) {
DEBUGLOG(stderr, "Debugger is active: Not installing handler\n");
return true;
}
// Gather any user specified parameters
if (!ExtractParameters(parameters)) {
return false;
}
// Get path to Inspector executable.
NSString *inspectorPathString = KeyValue(@BREAKPAD_INSPECTOR_LOCATION);
// Standardize path (resolve symlinkes, etc.) and escape spaces
inspectorPathString = [inspectorPathString stringByStandardizingPath];
inspectorPathString = [[inspectorPathString componentsSeparatedByString:@" "]
componentsJoinedByString:@"\\ "];
// Create an on-demand server object representing the Inspector.
// In case of a crash, we simply need to call the LaunchOnDemand()
// method on it, then send a mach message to its service port.
// It will then launch and perform a process inspection of our crashed state.
// See the HandleException() method for the details.
#define RECEIVE_PORT_NAME "com.Breakpad.Inspector"
name_t portName;
snprintf(portName, sizeof(name_t), "%s%d", RECEIVE_PORT_NAME, getpid());
// Save the location of the Inspector
strlcpy(inspector_path_, [inspectorPathString fileSystemRepresentation],
sizeof(inspector_path_));
// Append a single command-line argument to the Inspector path
// representing the bootstrap name of the launch-on-demand receive port.
// When the Inspector is launched, it can use this to lookup the port
// by calling bootstrap_check_in().
strlcat(inspector_path_, " ", sizeof(inspector_path_));
strlcat(inspector_path_, portName, sizeof(inspector_path_));
kern_return_t kr = inspector_.Initialize(inspector_path_,
portName,
true); // shutdown on exit
if (kr != KERN_SUCCESS) {
return false;
}
// Create the handler (allocating it in our special protected pool)
handler_ =
new (gBreakpadAllocator->Allocate(
sizeof(google_breakpad::ExceptionHandler)))
google_breakpad::ExceptionHandler(
Breakpad::ExceptionHandlerDirectCallback, this, true);
return true;
}
//=============================================================================
Breakpad::~Breakpad() {
// Note that we don't use operator delete() on these pointers,
// since they were allocated by ProtectedMemoryAllocator objects.
//
if (config_params_) {
config_params_->~SimpleStringDictionary();
}
if (handler_)
handler_->~ExceptionHandler();
}
//=============================================================================
bool Breakpad::ExtractParameters(NSDictionary *parameters) {
NSUserDefaults *stdDefaults = [NSUserDefaults standardUserDefaults];
NSString *skipConfirm = [stdDefaults stringForKey:@BREAKPAD_SKIP_CONFIRM];
NSString *sendAndExit = [stdDefaults stringForKey:@BREAKPAD_SEND_AND_EXIT];
NSString *serverType = [parameters objectForKey:@BREAKPAD_SERVER_TYPE];
NSString *display = [parameters objectForKey:@BREAKPAD_PRODUCT_DISPLAY];
NSString *product = [parameters objectForKey:@BREAKPAD_PRODUCT];
NSString *version = [parameters objectForKey:@BREAKPAD_VERSION];
NSString *urlStr = [parameters objectForKey:@BREAKPAD_URL];
NSString *interval = [parameters objectForKey:@BREAKPAD_REPORT_INTERVAL];
NSString *inspectorPathString =
[parameters objectForKey:@BREAKPAD_INSPECTOR_LOCATION];
NSString *reporterPathString =
[parameters objectForKey:@BREAKPAD_REPORTER_EXE_LOCATION];
NSString *timeout = [parameters objectForKey:@BREAKPAD_CONFIRM_TIMEOUT];
NSArray *logFilePaths = [parameters objectForKey:@BREAKPAD_LOGFILES];
NSString *logFileTailSize =
[parameters objectForKey:@BREAKPAD_LOGFILE_UPLOAD_SIZE];
NSString *requestUserText =
[parameters objectForKey:@BREAKPAD_REQUEST_COMMENTS];
NSString *requestEmail = [parameters objectForKey:@BREAKPAD_REQUEST_EMAIL];
NSString *vendor =
[parameters objectForKey:@BREAKPAD_VENDOR];
NSString *dumpSubdirectory =
[parameters objectForKey:@BREAKPAD_DUMP_DIRECTORY];
NSDictionary *serverParameters =
[parameters objectForKey:@BREAKPAD_SERVER_PARAMETER_DICT];
// These may have been set above as user prefs, which take priority.
if (!skipConfirm) {
skipConfirm = [parameters objectForKey:@BREAKPAD_SKIP_CONFIRM];
}
if (!sendAndExit) {
sendAndExit = [parameters objectForKey:@BREAKPAD_SEND_AND_EXIT];
}
if (!product)
product = [parameters objectForKey:@"CFBundleName"];
if (!display) {
display = [parameters objectForKey:@"CFBundleDisplayName"];
if (!display) {
display = product;
}
}
if (!version)
version = [parameters objectForKey:@"CFBundleVersion"];
if (!interval)
interval = @"3600";
if (!timeout)
timeout = @"300";
if (!logFileTailSize)
logFileTailSize = @"200000";
if (!vendor) {
vendor = @"Vendor not specified";
}
// Normalize the values.
if (skipConfirm) {
skipConfirm = [skipConfirm uppercaseString];
if ([skipConfirm isEqualToString:@"YES"] ||
[skipConfirm isEqualToString:@"TRUE"] ||
[skipConfirm isEqualToString:@"1"])
skipConfirm = @"YES";
else
skipConfirm = @"NO";
} else {
skipConfirm = @"NO";
}
send_and_exit_ = true;
if (sendAndExit) {
sendAndExit = [sendAndExit uppercaseString];
if ([sendAndExit isEqualToString:@"NO"] ||
[sendAndExit isEqualToString:@"FALSE"] ||
[sendAndExit isEqualToString:@"0"])
send_and_exit_ = false;
}
if (requestUserText) {
requestUserText = [requestUserText uppercaseString];
if ([requestUserText isEqualToString:@"YES"] ||
[requestUserText isEqualToString:@"TRUE"] ||
[requestUserText isEqualToString:@"1"])
requestUserText = @"YES";
else
requestUserText = @"NO";
} else {
requestUserText = @"NO";
}
// Find the helper applications if not specified in user config.
NSString *resourcePath = nil;
if (!inspectorPathString || !reporterPathString) {
resourcePath = GetResourcePath();
if (!resourcePath) {
DEBUGLOG(stderr, "Could not get resource path\n");
return false;
}
}
// Find Inspector.
if (!inspectorPathString) {
inspectorPathString =
[resourcePath stringByAppendingPathComponent:@"Inspector"];
}
// Verify that there is an Inspector tool.
if (![[NSFileManager defaultManager] fileExistsAtPath:inspectorPathString]) {
DEBUGLOG(stderr, "Cannot find Inspector tool\n");
return false;
}
// Find Reporter.
if (!reporterPathString) {
reporterPathString =
[resourcePath
stringByAppendingPathComponent:@"crash_report_sender.app"];
reporterPathString =
[[NSBundle bundleWithPath:reporterPathString] executablePath];
}
// Verify that there is a Reporter application.
if (![[NSFileManager defaultManager]
fileExistsAtPath:reporterPathString]) {
DEBUGLOG(stderr, "Cannot find Reporter tool\n");
return false;
}
if (!dumpSubdirectory) {
dumpSubdirectory = @"";
}
// The product, version, and URL are required values.
if (![product length]) {
DEBUGLOG(stderr, "Missing required product key.\n");
return false;
}
if (![version length]) {
DEBUGLOG(stderr, "Missing required version key.\n");
return false;
}
if (![urlStr length]) {
DEBUGLOG(stderr, "Missing required URL key.\n");
return false;
}
config_params_ =
new (gKeyValueAllocator->Allocate(sizeof(SimpleStringDictionary)) )
SimpleStringDictionary();
SimpleStringDictionary &dictionary = *config_params_;
dictionary.SetKeyValue(BREAKPAD_SERVER_TYPE, [serverType UTF8String]);
dictionary.SetKeyValue(BREAKPAD_PRODUCT_DISPLAY, [display UTF8String]);
dictionary.SetKeyValue(BREAKPAD_PRODUCT, [product UTF8String]);
dictionary.SetKeyValue(BREAKPAD_VERSION, [version UTF8String]);
dictionary.SetKeyValue(BREAKPAD_URL, [urlStr UTF8String]);
dictionary.SetKeyValue(BREAKPAD_REPORT_INTERVAL, [interval UTF8String]);
dictionary.SetKeyValue(BREAKPAD_SKIP_CONFIRM, [skipConfirm UTF8String]);
dictionary.SetKeyValue(BREAKPAD_CONFIRM_TIMEOUT, [timeout UTF8String]);
dictionary.SetKeyValue(BREAKPAD_INSPECTOR_LOCATION,
[inspectorPathString fileSystemRepresentation]);
dictionary.SetKeyValue(BREAKPAD_REPORTER_EXE_LOCATION,
[reporterPathString fileSystemRepresentation]);
dictionary.SetKeyValue(BREAKPAD_LOGFILE_UPLOAD_SIZE,
[logFileTailSize UTF8String]);
dictionary.SetKeyValue(BREAKPAD_REQUEST_COMMENTS,
[requestUserText UTF8String]);
dictionary.SetKeyValue(BREAKPAD_REQUEST_EMAIL, [requestEmail UTF8String]);
dictionary.SetKeyValue(BREAKPAD_VENDOR, [vendor UTF8String]);
dictionary.SetKeyValue(BREAKPAD_DUMP_DIRECTORY,
[dumpSubdirectory UTF8String]);
struct timeval tv;
gettimeofday(&tv, NULL);
char timeStartedString[32];
sprintf(timeStartedString, "%zd", tv.tv_sec);
dictionary.SetKeyValue(BREAKPAD_PROCESS_START_TIME,
timeStartedString);
if (logFilePaths) {
char logFileKey[255];
for(unsigned int i = 0; i < [logFilePaths count]; i++) {
sprintf(logFileKey,"%s%d", BREAKPAD_LOGFILE_KEY_PREFIX, i);
dictionary.SetKeyValue(logFileKey,
[[logFilePaths objectAtIndex:i]
fileSystemRepresentation]);
}
}
if (serverParameters) {
// For each key-value pair, call BreakpadAddUploadParameter()
NSEnumerator *keyEnumerator = [serverParameters keyEnumerator];
NSString *aParameter;
while ((aParameter = [keyEnumerator nextObject])) {
BreakpadAddUploadParameter(this, aParameter,
[serverParameters objectForKey:aParameter]);
}
}
return true;
}
//=============================================================================
void Breakpad::SetKeyValue(NSString *key, NSString *value) {
// We allow nil values. This is the same as removing the keyvalue.
if (!config_params_ || !key)
return;
config_params_->SetKeyValue([key UTF8String], [value UTF8String]);
}
//=============================================================================
NSString *Breakpad::KeyValue(NSString *key) {
if (!config_params_ || !key)
return nil;
const char *value = config_params_->GetValueForKey([key UTF8String]);
return value ? [NSString stringWithUTF8String:value] : nil;
}
//=============================================================================
void Breakpad::RemoveKeyValue(NSString *key) {
if (!config_params_ || !key) return;
config_params_->RemoveKey([key UTF8String]);
}
//=============================================================================
void Breakpad::GenerateAndSendReport() {
config_params_->SetKeyValue(BREAKPAD_ON_DEMAND, "YES");
HandleException(0, 0, 0, mach_thread_self());
config_params_->SetKeyValue(BREAKPAD_ON_DEMAND, "NO");
}
//=============================================================================
bool Breakpad::HandleException(int exception_type,
int exception_code,
int exception_subcode,
mach_port_t crashing_thread) {
DEBUGLOG(stderr, "Breakpad: an exception occurred\n");
if (filter_callback_) {
bool should_handle = filter_callback_(exception_type,
exception_code,
crashing_thread,
filter_callback_context_);
if (!should_handle) return false;
}
// We need to reset the memory protections to be read/write,
// since LaunchOnDemand() requires changing state.
gBreakpadAllocator->Unprotect();
// Configure the server to launch when we message the service port.
// The reason we do this here, rather than at startup, is that we
// can leak a bootstrap service entry if this method is called and
// there never ends up being a crash.
inspector_.LaunchOnDemand();
gBreakpadAllocator->Protect();
// The Inspector should send a message to this port to verify it
// received our information and has finished the inspection.
ReceivePort acknowledge_port;
// Send initial information to the Inspector.
MachSendMessage message(kMsgType_InspectorInitialInfo);
message.AddDescriptor(mach_task_self()); // our task
message.AddDescriptor(crashing_thread); // crashing thread
message.AddDescriptor(mach_thread_self()); // exception-handling thread
message.AddDescriptor(acknowledge_port.GetPort());// message receive port
InspectorInfo info;
info.exception_type = exception_type;
info.exception_code = exception_code;
info.exception_subcode = exception_subcode;
info.parameter_count = config_params_->GetCount();
message.SetData(&info, sizeof(info));
MachPortSender sender(inspector_.GetServicePort());
kern_return_t result = sender.SendMessage(message, 2000);
if (result == KERN_SUCCESS) {
// Now, send a series of key-value pairs to the Inspector.
const KeyValueEntry *entry = NULL;
SimpleStringDictionaryIterator iter(*config_params_);
while ( (entry = iter.Next()) ) {
KeyValueMessageData keyvalue_data(*entry);
MachSendMessage keyvalue_message(kMsgType_InspectorKeyValuePair);
keyvalue_message.SetData(&keyvalue_data, sizeof(keyvalue_data));
result = sender.SendMessage(keyvalue_message, 2000);
if (result != KERN_SUCCESS) {
break;
}
}
if (result == KERN_SUCCESS) {
// Wait for acknowledgement that the inspection has finished.
MachReceiveMessage acknowledge_messsage;
result = acknowledge_port.WaitForMessage(&acknowledge_messsage, 5000);
}
}
#if VERBOSE
PRINT_MACH_RESULT(result, "Breakpad: SendMessage ");
printf("Breakpad: Inspector service port = %#x\n",
inspector_.GetServicePort());
#endif
// If we don't want any forwarding, return true here to indicate that we've
// processed things as much as we want.
if (send_and_exit_) return true;
return false;
}
//=============================================================================
//=============================================================================
#pragma mark -
#pragma mark Public API
//=============================================================================
BreakpadRef BreakpadCreate(NSDictionary *parameters) {
try {
// This is confusing. Our two main allocators for breakpad memory are:
// - gKeyValueAllocator for the key/value memory
// - gBreakpadAllocator for the Breakpad, ExceptionHandler, and other
// breakpad allocations which are accessed at exception handling time.
//
// But in order to avoid these two allocators themselves from being smashed,
// we'll protect them as well by allocating them with gMasterAllocator.
//
// gMasterAllocator itself will NOT be protected, but this doesn't matter,
// since once it does its allocations and locks the memory, smashes to itself
// don't affect anything we care about.
gMasterAllocator =
new ProtectedMemoryAllocator(sizeof(ProtectedMemoryAllocator) * 2);
gKeyValueAllocator =
new (gMasterAllocator->Allocate(sizeof(ProtectedMemoryAllocator)))
ProtectedMemoryAllocator(sizeof(SimpleStringDictionary));
// Create a mutex for use in accessing the SimpleStringDictionary
int mutexResult = pthread_mutex_init(&gDictionaryMutex, NULL);
if (mutexResult == 0) {
// With the current compiler, gBreakpadAllocator is allocating 1444 bytes.
// Let's round up to the nearest page size.
//
int breakpad_pool_size = 4096;
/*
sizeof(Breakpad)
+ sizeof(google_breakpad::ExceptionHandler)
+ sizeof( STUFF ALLOCATED INSIDE ExceptionHandler )
*/
gBreakpadAllocator =
new (gMasterAllocator->Allocate(sizeof(ProtectedMemoryAllocator)))
ProtectedMemoryAllocator(breakpad_pool_size);
// Stack-based autorelease pool for Breakpad::Create() obj-c code.
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
Breakpad *breakpad = Breakpad::Create(parameters);
if (breakpad) {
// Make read-only to protect against memory smashers
gMasterAllocator->Protect();
gKeyValueAllocator->Protect();
gBreakpadAllocator->Protect();
// Can uncomment this line to figure out how much space was actually
// allocated using this allocator
// printf("gBreakpadAllocator allocated size = %d\n",
// gBreakpadAllocator->GetAllocatedSize() );
[pool release];
return (BreakpadRef)breakpad;
}
[pool release];
}
} catch(...) { // don't let exceptions leave this C API
fprintf(stderr, "BreakpadCreate() : error\n");
}
if (gKeyValueAllocator) {
gKeyValueAllocator->~ProtectedMemoryAllocator();
gKeyValueAllocator = NULL;
}
if (gBreakpadAllocator) {
gBreakpadAllocator->~ProtectedMemoryAllocator();
gBreakpadAllocator = NULL;
}
delete gMasterAllocator;
gMasterAllocator = NULL;
return NULL;
}
//=============================================================================
void BreakpadRelease(BreakpadRef ref) {
try {
Breakpad *breakpad = (Breakpad *)ref;
if (gMasterAllocator) {
gMasterAllocator->Unprotect();
gKeyValueAllocator->Unprotect();
gBreakpadAllocator->Unprotect();
breakpad->~Breakpad();
// Unfortunately, it's not possible to deallocate this stuff
// because the exception handling thread is still finishing up
// asynchronously at this point... OK, it could be done with
// locks, etc. But since BreakpadRelease() should usually only
// be called right before the process exits, it's not worth
// deallocating this stuff.
#if 0
gKeyValueAllocator->~ProtectedMemoryAllocator();
gBreakpadAllocator->~ProtectedMemoryAllocator();
delete gMasterAllocator;
gMasterAllocator = NULL;
gKeyValueAllocator = NULL;
gBreakpadAllocator = NULL;
#endif
pthread_mutex_destroy(&gDictionaryMutex);
}
} catch(...) { // don't let exceptions leave this C API
fprintf(stderr, "BreakpadRelease() : error\n");
}
}
//=============================================================================
void BreakpadSetKeyValue(BreakpadRef ref, NSString *key, NSString *value) {
try {
// Not called at exception time
Breakpad *breakpad = (Breakpad *)ref;
if (breakpad && key && gKeyValueAllocator) {
ProtectedMemoryLocker locker(&gDictionaryMutex, gKeyValueAllocator);
breakpad->SetKeyValue(key, value);
}
} catch(...) { // don't let exceptions leave this C API
fprintf(stderr, "BreakpadSetKeyValue() : error\n");
}
}
void BreakpadAddUploadParameter(BreakpadRef ref,
NSString *key,
NSString *value) {
// The only difference, internally, between an upload parameter and
// a key value one that is set with BreakpadSetKeyValue is that we
// prepend the keyname with a special prefix. This informs the
// crash sender that the parameter should be sent along with the
// POST of the crash dump upload.
try {
Breakpad *breakpad = (Breakpad *)ref;
if (breakpad && key && gKeyValueAllocator) {
ProtectedMemoryLocker locker(&gDictionaryMutex, gKeyValueAllocator);
NSString *prefixedKey = [@BREAKPAD_SERVER_PARAMETER_PREFIX
stringByAppendingString:key];
breakpad->SetKeyValue(prefixedKey, value);
}
} catch(...) { // don't let exceptions leave this C API
fprintf(stderr, "BreakpadSetKeyValue() : error\n");
}
}
void BreakpadRemoveUploadParameter(BreakpadRef ref,
NSString *key) {
try {
// Not called at exception time
Breakpad *breakpad = (Breakpad *)ref;
if (breakpad && key && gKeyValueAllocator) {
ProtectedMemoryLocker locker(&gDictionaryMutex, gKeyValueAllocator);
NSString *prefixedKey = [NSString stringWithFormat:@"%@%@",
@BREAKPAD_SERVER_PARAMETER_PREFIX, key];
breakpad->RemoveKeyValue(prefixedKey);
}
} catch(...) { // don't let exceptions leave this C API
fprintf(stderr, "BreakpadRemoveKeyValue() : error\n");
}
}
//=============================================================================
NSString *BreakpadKeyValue(BreakpadRef ref, NSString *key) {
NSString *value = nil;
try {
// Not called at exception time
Breakpad *breakpad = (Breakpad *)ref;
if (!breakpad || !key || !gKeyValueAllocator)
return nil;
ProtectedMemoryLocker locker(&gDictionaryMutex, gKeyValueAllocator);
value = breakpad->KeyValue(key);
} catch(...) { // don't let exceptions leave this C API
fprintf(stderr, "BreakpadKeyValue() : error\n");
}
return value;
}
//=============================================================================
void BreakpadRemoveKeyValue(BreakpadRef ref, NSString *key) {
try {
// Not called at exception time
Breakpad *breakpad = (Breakpad *)ref;
if (breakpad && key && gKeyValueAllocator) {
ProtectedMemoryLocker locker(&gDictionaryMutex, gKeyValueAllocator);
breakpad->RemoveKeyValue(key);
}
} catch(...) { // don't let exceptions leave this C API
fprintf(stderr, "BreakpadRemoveKeyValue() : error\n");
}
}
//=============================================================================
void BreakpadGenerateAndSendReport(BreakpadRef ref) {
try {
Breakpad *breakpad = (Breakpad *)ref;
if (breakpad && gKeyValueAllocator) {
ProtectedMemoryLocker locker(&gDictionaryMutex, gKeyValueAllocator);
gBreakpadAllocator->Unprotect();
breakpad->GenerateAndSendReport();
gBreakpadAllocator->Protect();
}
} catch(...) { // don't let exceptions leave this C API
fprintf(stderr, "BreakpadGenerateAndSendReport() : error\n");
}
}
//=============================================================================
void BreakpadSetFilterCallback(BreakpadRef ref,
BreakpadFilterCallback callback,
void *context) {
try {
Breakpad *breakpad = (Breakpad *)ref;
if (breakpad && gBreakpadAllocator) {
// share the dictionary mutex here (we really don't need a mutex)
ProtectedMemoryLocker locker(&gDictionaryMutex, gBreakpadAllocator);
breakpad->SetFilterCallback(callback, context);
}
} catch(...) { // don't let exceptions leave this C API
fprintf(stderr, "BreakpadSetFilterCallback() : error\n");
}
}
//============================================================================
void BreakpadAddLogFile(BreakpadRef ref, NSString *logPathname) {
int logFileCounter = 0;
NSString *logFileKey = [NSString stringWithFormat:@"%@%d",
@BREAKPAD_LOGFILE_KEY_PREFIX,
logFileCounter];
NSString *existingLogFilename = nil;
existingLogFilename = BreakpadKeyValue(ref, logFileKey);
// Find the first log file key that we can use by testing for existence
while (existingLogFilename) {
if ([existingLogFilename isEqualToString:logPathname]) {
return;
}
logFileCounter++;
logFileKey = [NSString stringWithFormat:@"%@%d",
@BREAKPAD_LOGFILE_KEY_PREFIX,
logFileCounter];
existingLogFilename = BreakpadKeyValue(ref, logFileKey);
}
BreakpadSetKeyValue(ref, logFileKey, logPathname);
}

View File

@@ -0,0 +1,8 @@
//
// Prefix header for all source files of the 'Breakpad' target in the
// 'Breakpad' project.
//
#ifdef __OBJC__
#import <Cocoa/Cocoa.h>
#endif

View File

@@ -0,0 +1,26 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>English</string>
<key>CFBundleExecutable</key>
<string>${EXECUTABLE_NAME}</string>
<key>CFBundleName</key>
<string>${PRODUCT_NAME}</string>
<key>CFBundleIconFile</key>
<string></string>
<key>CFBundleIdentifier</key>
<string>com.googlecode.google-breakpad</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundlePackageType</key>
<string>FMWK</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>1.0</string>
<key>NSPrincipalClass</key>
<string></string>
</dict>
</plist>

View File

@@ -0,0 +1,146 @@
// Copyright (c) 2007, 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 <iostream>
#import <mach/mach.h>
#import <servers/bootstrap.h>
#import <stdio.h>
#import <stdlib.h>
#import <sys/stat.h>
#import <unistd.h>
//==============================================================================
// class OnDemandServer :
// A basic on-demand server launcher supporting a single named service port
//
// Example Usage :
//
// kern_return_t result;
// OnDemandServer *server = OnDemandServer::Create("/tmp/myserver",
// "com.MyCompany.MyServiceName",
// true,
// &result);
//
// if (server) {
// server->LaunchOnDemand();
// mach_port_t service_port = GetServicePort();
//
// // Send a mach message to service_port and "myserver" will be launched
// }
//
//
// ---- Now in the server code ----
//
// // "myserver" should get the service port and read the message which
// // launched it:
// mach_port_t service_rcv_port_;
// kern_return_t kr = bootstrap_check_in(bootstrap_port,
// "com.MyCompany.MyServiceName",
// &service_rcv_port_);
// // mach_msg() read service_rcv_port_ ....
//
// ....
//
// // Later "myserver" may want to unregister the service if it doesn't
// // want its bootstrap service to stick around after it exits.
//
// // DO NOT use mach_port_deallocate() here -- it will fail and the
// // following bootstrap_register() will also fail leaving our service
// // name hanging around forever (until reboot)
// kern_return_t kr = mach_port_destroy(mach_task_self(), service_rcv_port_);
//
// kr = bootstrap_register(bootstrap_port,
// "com.MyCompany.MyServiceName",
// MACH_PORT_NULL);
class OnDemandServer {
public:
// must call Initialize() to be useful
OnDemandServer()
: server_port_(MACH_PORT_NULL),
service_port_(MACH_PORT_NULL),
unregister_on_cleanup_(true) {
}
// Creates the bootstrap server and service
kern_return_t Initialize(const char *server_command,
const char *service_name,
bool unregister_on_cleanup);
// Returns an OnDemandServer object if successful, or NULL if there's
// an error. The error result will be returned in out_result.
//
// server_command : the full path name including optional command-line
// arguments to the executable representing the server
//
// service_name : represents service name
// something like "com.company.ServiceName"
//
// unregister_on_cleanup : if true, unregisters the service name
// when the OnDemandServer is deleted -- unregistering will
// ONLY be possible if LaunchOnDemand() has NOT been called.
// If false, then the service will continue to be registered
// even after the current process quits.
//
// out_result : if non-NULL, returns the result
// this value will be KERN_SUCCESS if Create() returns non-NULL
//
static OnDemandServer *Create(const char *server_command,
const char *service_name,
bool unregister_on_cleanup,
kern_return_t *out_result);
// Cleans up and if LaunchOnDemand() has not yet been called then
// the bootstrap service will be unregistered.
~OnDemandServer();
// This must be called if we intend to commit to launching the server
// by sending a mach message to our service port. Do not call it otherwise
// or it will be difficult (impossible?) to unregister the service name.
void LaunchOnDemand();
// This is the port we need to send a mach message to after calling
// LaunchOnDemand(). Sending a message causing an immediate launch
// of the server
mach_port_t GetServicePort() { return service_port_; };
private:
// Disallow copy constructor
OnDemandServer(const OnDemandServer&);
// Cleans up and if LaunchOnDemand() has not yet been called then
// the bootstrap service will be unregistered.
void Unregister();
name_t service_name_;
mach_port_t server_port_;
mach_port_t service_port_;
bool unregister_on_cleanup_;
};

View File

@@ -0,0 +1,177 @@
// Copyright (c) 2007, 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 "OnDemandServer.h"
#import "Breakpad.h"
#if DEBUG
#define PRINT_MACH_RESULT(result_, message_) \
printf(message_"%s (%d)\n", mach_error_string(result_), result_ );
#define PRINT_BOOTSTRAP_RESULT(result_, message_) \
printf(message_"%s (%d)\n", bootstrap_strerror(result_), result_ );
#else
#define PRINT_MACH_RESULT(result_, message_)
#define PRINT_BOOTSTRAP_RESULT(result_, message_)
#endif
//==============================================================================
OnDemandServer *OnDemandServer::Create(const char *server_command,
const char *service_name,
bool unregister_on_cleanup,
kern_return_t *out_result) {
OnDemandServer *server = new OnDemandServer();
if (!server) return NULL;
kern_return_t result = server->Initialize(server_command,
service_name,
unregister_on_cleanup);
if (out_result) {
*out_result = result;
}
if (result == KERN_SUCCESS) {
return server;
}
delete server;
return NULL;
};
//==============================================================================
kern_return_t OnDemandServer::Initialize(const char *server_command,
const char *service_name,
bool unregister_on_cleanup) {
unregister_on_cleanup_ = unregister_on_cleanup;
mach_port_t self_task = mach_task_self();
mach_port_t bootstrap_port;
kern_return_t kr = task_get_bootstrap_port(self_task, &bootstrap_port);
if (kr != KERN_SUCCESS) {
PRINT_MACH_RESULT(kr, "task_get_bootstrap_port(): ");
return kr;
}
mach_port_t bootstrap_subset_port;
kr = bootstrap_subset(bootstrap_port, self_task, &bootstrap_subset_port);
if (kr != BOOTSTRAP_SUCCESS) {
PRINT_BOOTSTRAP_RESULT(kr, "bootstrap_subset(): ");
return kr;
}
// The inspector will be invoked with its bootstrap port set to the subset,
// but the sender will need access to the original bootstrap port. Although
// the original port is the subset's parent, bootstrap_parent can't be used
// because it requires extra privileges. Stash the original bootstrap port
// in the subset by registering it under a known name. The inspector will
// recover this port and set it as its own bootstrap port in Inspector.mm
// Inspector::ResetBootstrapPort.
kr = bootstrap_register(bootstrap_subset_port,
const_cast<char*>(BREAKPAD_BOOTSTRAP_PARENT_PORT),
bootstrap_port);
if (kr != BOOTSTRAP_SUCCESS) {
PRINT_BOOTSTRAP_RESULT(kr, "bootstrap_register(): ");
return kr;
}
kr = bootstrap_create_server(bootstrap_subset_port,
const_cast<char*>(server_command),
geteuid(), // server uid
true,
&server_port_);
if (kr != BOOTSTRAP_SUCCESS) {
PRINT_BOOTSTRAP_RESULT(kr, "bootstrap_create_server(): ");
return kr;
}
strlcpy(service_name_, service_name, sizeof(service_name_));
// Create a service called service_name, and return send rights to
// that port in service_port_.
kr = bootstrap_create_service(server_port_,
const_cast<char*>(service_name),
&service_port_);
if (kr != BOOTSTRAP_SUCCESS) {
PRINT_BOOTSTRAP_RESULT(kr, "bootstrap_create_service(): ");
// perhaps the service has already been created - try to look it up
kr = bootstrap_look_up(bootstrap_port, (char*)service_name, &service_port_);
if (kr != BOOTSTRAP_SUCCESS) {
PRINT_BOOTSTRAP_RESULT(kr, "bootstrap_look_up(): ");
Unregister(); // clean up server port
return kr;
}
}
return KERN_SUCCESS;
}
//==============================================================================
OnDemandServer::~OnDemandServer() {
if (unregister_on_cleanup_) {
Unregister();
}
}
//==============================================================================
void OnDemandServer::LaunchOnDemand() {
// We need to do this, since the launched server is another process
// and holding on to this port delays launching until the current process
// exits!
mach_port_deallocate(mach_task_self(), server_port_);
server_port_ = MACH_PORT_DEAD;
// Now, the service is still registered and all we need to do is send
// a mach message to the service port in order to launch the server.
}
//==============================================================================
void OnDemandServer::Unregister() {
if (service_port_ != MACH_PORT_NULL) {
mach_port_deallocate(mach_task_self(), service_port_);
service_port_ = MACH_PORT_NULL;
}
if (server_port_ != MACH_PORT_NULL) {
// unregister the service
kern_return_t kr = bootstrap_register(server_port_,
service_name_,
MACH_PORT_NULL);
if (kr != KERN_SUCCESS) {
PRINT_MACH_RESULT(kr, "Breakpad UNREGISTER : bootstrap_register() : ");
}
mach_port_deallocate(mach_task_self(), server_port_);
server_port_ = MACH_PORT_NULL;
}
}

View File

@@ -0,0 +1,20 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>English</string>
<key>CFBundleExecutable</key>
<string>${EXECUTABLE_NAME}</string>
<key>CFBundleIdentifier</key>
<string>com.yourcompany.${PRODUCT_NAME:identifier}</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundlePackageType</key>
<string>BNDL</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>1.0</string>
</dict>
</plist>

View File

@@ -0,0 +1,211 @@
// Copyright (c) 2007, 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.
//
// Interface file between the Breakpad.framework and
// the Inspector process.
#import "common/mac/SimpleStringDictionary.h"
#import <Foundation/Foundation.h>
#include <mach/mach.h>
#import "client/mac/handler/minidump_generator.h"
#define VERBOSE 0
extern bool gDebugLog;
#define DEBUGLOG if (gDebugLog) fprintf
// Types of mach messsages (message IDs)
enum {
kMsgType_InspectorInitialInfo = 0, // data is InspectorInfo
kMsgType_InspectorKeyValuePair = 1, // data is KeyValueMessageData
kMsgType_InspectorAcknowledgement = 2 // no data sent
};
// Initial information sent from the crashed process by
// Breakpad.framework to the Inspector process
// The mach message with this struct as data will also include
// several descriptors for sending mach port rights to the crashed
// task, etc.
struct InspectorInfo {
int exception_type;
int exception_code;
int exception_subcode;
unsigned int parameter_count; // key-value pairs
};
// Key/value message data to be sent to the Inspector
struct KeyValueMessageData {
public:
KeyValueMessageData() {}
KeyValueMessageData(const google_breakpad::KeyValueEntry &inEntry) {
strlcpy(key, inEntry.GetKey(), sizeof(key) );
strlcpy(value, inEntry.GetValue(), sizeof(value) );
}
char key[google_breakpad::KeyValueEntry::MAX_STRING_STORAGE_SIZE];
char value[google_breakpad::KeyValueEntry::MAX_STRING_STORAGE_SIZE];
};
using std::string;
using google_breakpad::MinidumpGenerator;
namespace google_breakpad {
BOOL EnsureDirectoryPathExists(NSString *dirPath);
//=============================================================================
class ConfigFile {
public:
ConfigFile() {
config_file_ = -1;
config_file_path_[0] = 0;
has_created_file_ = false;
};
~ConfigFile() {
};
void WriteFile(const SimpleStringDictionary *configurationParameters,
const char *dump_dir,
const char *minidump_id);
const char *GetFilePath() { return config_file_path_; }
void Unlink() {
if (config_file_ != -1)
unlink(config_file_path_);
config_file_ = -1;
}
private:
BOOL WriteData(const void *data, size_t length);
BOOL AppendConfigData(const char *key,
const void *data,
size_t length);
BOOL AppendConfigString(const char *key,
const char *value);
int config_file_; // descriptor for config file
char config_file_path_[PATH_MAX]; // Path to configuration file
bool has_created_file_;
};
//=============================================================================
class MinidumpLocation {
public:
MinidumpLocation(NSString *minidumpDir) {
// Ensure that the path exists. Fallback to /tmp if unable to locate path.
assert(minidumpDir);
if (!EnsureDirectoryPathExists(minidumpDir)) {
DEBUGLOG(stderr, "Unable to create: %s\n", [minidumpDir UTF8String]);
minidumpDir = @"/tmp";
}
strlcpy(minidump_dir_path_, [minidumpDir fileSystemRepresentation],
sizeof(minidump_dir_path_));
// now generate a unique ID
string dump_path(minidump_dir_path_);
string next_minidump_id;
string next_minidump_path_ =
(MinidumpGenerator::UniqueNameInDirectory(dump_path, &next_minidump_id));
strlcpy(minidump_id_, next_minidump_id.c_str(), sizeof(minidump_id_));
};
const char *GetPath() { return minidump_dir_path_; }
const char *GetID() { return minidump_id_; }
private:
char minidump_dir_path_[PATH_MAX]; // Path to minidump directory
char minidump_id_[128];
};
//=============================================================================
class Inspector {
public:
Inspector() {};
// given a bootstrap service name, receives mach messages
// from a crashed process, then inspects it, creates a minidump file
// and asks the user if he wants to upload it to a server.
void Inspect(const char *receive_port_name);
private:
// The Inspector is invoked with its bootstrap port set to the bootstrap
// subset established in OnDemandServer.mm OnDemandServer::Initialize.
// For proper communication with the system, the sender (which will inherit
// the Inspector's bootstrap port) needs the per-session bootstrap namespace
// available directly in its bootstrap port. OnDemandServer stashed this
// port into the subset namespace under a special name. ResetBootstrapPort
// recovers this port and switches this task to use it as its own bootstrap
// (ensuring that children like the sender will inherit it), and saves the
// subset in bootstrap_subset_port_ for use by ServiceCheckIn and
// ServiceCheckOut.
kern_return_t ResetBootstrapPort();
kern_return_t ServiceCheckIn(const char *receive_port_name);
kern_return_t ServiceCheckOut(const char *receive_port_name);
kern_return_t ReadMessages();
bool InspectTask();
kern_return_t SendAcknowledgement();
void LaunchReporter(const char *inConfigFilePath);
void SetCrashTimeParameters();
// The bootstrap port in which the inspector is registered and into which it
// must check in.
mach_port_t bootstrap_subset_port_;
mach_port_t service_rcv_port_;
int exception_type_;
int exception_code_;
int exception_subcode_;
mach_port_t remote_task_;
mach_port_t crashing_thread_;
mach_port_t handler_thread_;
mach_port_t ack_port_;
SimpleStringDictionary config_params_;
ConfigFile config_file_;
};
} // namespace google_breakpad

View File

@@ -0,0 +1,599 @@
// Copyright (c) 2007, 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.
//
// Utility that can inspect another process and write a crash dump
#include <cstdio>
#include <iostream>
#include <stdio.h>
#include <string.h>
#include <string>
#include <sys/time.h>
#import "client/mac/crash_generation/Inspector.h"
#import "client/mac/Framework/Breakpad.h"
#import "client/mac/handler/minidump_generator.h"
#import "common/mac/SimpleStringDictionary.h"
#import "common/mac/MachIPC.h"
#import "GTMDefines.h"
#import <Foundation/Foundation.h>
#if VERBOSE
bool gDebugLog = true;
#else
bool gDebugLog = false;
#endif
namespace google_breakpad {
//=============================================================================
BOOL EnsureDirectoryPathExists(NSString *dirPath) {
NSFileManager *mgr = [NSFileManager defaultManager];
// If we got a relative path, prepend the current directory
if (![dirPath isAbsolutePath])
dirPath = [[mgr currentDirectoryPath] stringByAppendingPathComponent:dirPath];
NSString *path = dirPath;
// Ensure that no file exists within the path which would block creation
while (1) {
BOOL isDir;
if ([mgr fileExistsAtPath:path isDirectory:&isDir]) {
if (isDir)
break;
return NO;
}
path = [path stringByDeletingLastPathComponent];
}
// Path now contains the first valid directory (or is empty)
if (![path length])
return NO;
NSString *common =
[dirPath commonPrefixWithString:path options:NSLiteralSearch];
// If everything is good
if ([common isEqualToString:dirPath])
return YES;
// Break up the difference into components
NSString *diff = [dirPath substringFromIndex:[common length] + 1];
NSArray *components = [diff pathComponents];
NSUInteger count = [components count];
// Rebuild the path one component at a time
NSDictionary *attrs =
[NSDictionary dictionaryWithObject:[NSNumber numberWithUnsignedLong:0750]
forKey:NSFilePosixPermissions];
path = common;
for (NSUInteger i = 0; i < count; ++i) {
path = [path stringByAppendingPathComponent:[components objectAtIndex:i]];
if (![mgr createDirectoryAtPath:path attributes:attrs])
return NO;
}
return YES;
}
//=============================================================================
BOOL ConfigFile::WriteData(const void *data, size_t length) {
size_t result = write(config_file_, data, length);
return result == length;
}
//=============================================================================
BOOL ConfigFile::AppendConfigData(const char *key,
const void *data, size_t length) {
assert(config_file_ != -1);
if (!key) {
DEBUGLOG(stderr, "Breakpad: Missing Key\n");
return NO;
}
if (!data) {
DEBUGLOG(stderr, "Breakpad: Missing data for key: %s\n", key ? key :
"<Unknown Key>");
return NO;
}
// Write the key, \n, length of data (ascii integer), \n, data
char buffer[16];
char nl = '\n';
BOOL result = WriteData(key, strlen(key));
snprintf(buffer, sizeof(buffer) - 1, "\n%lu\n", length);
result &= WriteData(buffer, strlen(buffer));
result &= WriteData(data, length);
result &= WriteData(&nl, 1);
return result;
}
//=============================================================================
BOOL ConfigFile::AppendConfigString(const char *key,
const char *value) {
return AppendConfigData(key, value, strlen(value));
}
//=============================================================================
void ConfigFile::WriteFile(const SimpleStringDictionary *configurationParameters,
const char *dump_dir,
const char *minidump_id) {
assert(config_file_ == -1);
// Open and write out configuration file preamble
strlcpy(config_file_path_, "/tmp/Config-XXXXXX",
sizeof(config_file_path_));
config_file_ = mkstemp(config_file_path_);
if (config_file_ == -1) {
DEBUGLOG(stderr,
"mkstemp(config_file_path_) == -1 (%s)\n",
strerror(errno));
return;
}
else {
DEBUGLOG(stderr, "Writing config file to (%s)\n", config_file_path_);
}
has_created_file_ = true;
// Add the minidump dir
AppendConfigString(kReporterMinidumpDirectoryKey, dump_dir);
AppendConfigString(kReporterMinidumpIDKey, minidump_id);
// Write out the configuration parameters
BOOL result = YES;
const SimpleStringDictionary &dictionary = *configurationParameters;
const KeyValueEntry *entry = NULL;
SimpleStringDictionaryIterator iter(dictionary);
while ((entry = iter.Next())) {
DEBUGLOG(stderr,
"config: (%s) -> (%s)\n",
entry->GetKey(),
entry->GetValue());
result = AppendConfigString(entry->GetKey(), entry->GetValue());
if (!result)
break;
}
close(config_file_);
config_file_ = -1;
}
//=============================================================================
void Inspector::Inspect(const char *receive_port_name) {
kern_return_t result = ResetBootstrapPort();
if (result != KERN_SUCCESS) {
return;
}
result = ServiceCheckIn(receive_port_name);
if (result == KERN_SUCCESS) {
result = ReadMessages();
if (result == KERN_SUCCESS) {
// Inspect the task and write a minidump file.
bool wrote_minidump = InspectTask();
// Send acknowledgement to the crashed process that the inspection
// has finished. It will then be able to cleanly exit.
// The return value is ignored because failure isn't fatal. If the process
// didn't get the message there's nothing we can do, and we still want to
// send the report.
SendAcknowledgement();
if (wrote_minidump) {
// Ask the user if he wants to upload the crash report to a server,
// and do so if he agrees.
LaunchReporter(config_file_.GetFilePath());
} else {
fprintf(stderr, "Inspection of crashed process failed\n");
}
// Now that we're done reading messages, cleanup the service, but only
// if there was an actual exception
// Otherwise, it means the dump was generated on demand and the process
// lives on, and we might be needed again in the future.
if (exception_code_) {
ServiceCheckOut(receive_port_name);
}
} else {
PRINT_MACH_RESULT(result, "Inspector: WaitForMessage()");
}
}
}
//=============================================================================
kern_return_t Inspector::ResetBootstrapPort() {
// A reasonable default, in case anything fails.
bootstrap_subset_port_ = bootstrap_port;
mach_port_t self_task = mach_task_self();
kern_return_t kr = task_get_bootstrap_port(self_task,
&bootstrap_subset_port_);
if (kr != KERN_SUCCESS) {
NSLog(@"ResetBootstrapPort: task_get_bootstrap_port failed: %s (%d)",
mach_error_string(kr), kr);
return kr;
}
mach_port_t bootstrap_parent_port;
kr = bootstrap_look_up(bootstrap_subset_port_,
const_cast<char*>(BREAKPAD_BOOTSTRAP_PARENT_PORT),
&bootstrap_parent_port);
if (kr != BOOTSTRAP_SUCCESS) {
NSLog(@"ResetBootstrapPort: bootstrap_look_up failed: %s (%d)",
bootstrap_strerror(kr), kr);
return kr;
}
kr = task_set_bootstrap_port(self_task, bootstrap_parent_port);
if (kr != KERN_SUCCESS) {
NSLog(@"ResetBootstrapPort: task_set_bootstrap_port failed: %s (%d)",
mach_error_string(kr), kr);
return kr;
}
// Some things access the bootstrap port through this global variable
// instead of calling task_get_bootstrap_port.
bootstrap_port = bootstrap_parent_port;
return KERN_SUCCESS;
}
//=============================================================================
kern_return_t Inspector::ServiceCheckIn(const char *receive_port_name) {
// We need to get the mach port representing this service, so we can
// get information from the crashed process.
kern_return_t kr = bootstrap_check_in(bootstrap_subset_port_,
(char*)receive_port_name,
&service_rcv_port_);
if (kr != KERN_SUCCESS) {
#if VERBOSE
PRINT_MACH_RESULT(kr, "Inspector: bootstrap_check_in()");
#endif
}
return kr;
}
//=============================================================================
kern_return_t Inspector::ServiceCheckOut(const char *receive_port_name) {
// We're done receiving mach messages from the crashed process,
// so clean up a bit.
kern_return_t kr;
// DO NOT use mach_port_deallocate() here -- it will fail and the
// following bootstrap_register() will also fail leaving our service
// name hanging around forever (until reboot)
kr = mach_port_destroy(mach_task_self(), service_rcv_port_);
if (kr != KERN_SUCCESS) {
PRINT_MACH_RESULT(kr,
"Inspector: UNREGISTERING: service_rcv_port mach_port_deallocate()");
return kr;
}
// Unregister the service associated with the receive port.
kr = bootstrap_register(bootstrap_subset_port_,
(char*)receive_port_name,
MACH_PORT_NULL);
if (kr != KERN_SUCCESS) {
PRINT_MACH_RESULT(kr, "Inspector: UNREGISTERING: bootstrap_register()");
}
return kr;
}
//=============================================================================
kern_return_t Inspector::ReadMessages() {
// Wait for an initial message from the crashed process containing basic
// information about the crash.
ReceivePort receive_port(service_rcv_port_);
MachReceiveMessage message;
kern_return_t result = receive_port.WaitForMessage(&message, 1000);
if (result == KERN_SUCCESS) {
InspectorInfo &info = (InspectorInfo &)*message.GetData();
exception_type_ = info.exception_type;
exception_code_ = info.exception_code;
exception_subcode_ = info.exception_subcode;
#if VERBOSE
printf("message ID = %d\n", message.GetMessageID());
#endif
remote_task_ = message.GetTranslatedPort(0);
crashing_thread_ = message.GetTranslatedPort(1);
handler_thread_ = message.GetTranslatedPort(2);
ack_port_ = message.GetTranslatedPort(3);
#if VERBOSE
printf("exception_type = %d\n", exception_type_);
printf("exception_code = %d\n", exception_code_);
printf("exception_subcode = %d\n", exception_subcode_);
printf("remote_task = %d\n", remote_task_);
printf("crashing_thread = %d\n", crashing_thread_);
printf("handler_thread = %d\n", handler_thread_);
printf("ack_port_ = %d\n", ack_port_);
printf("parameter count = %d\n", info.parameter_count);
#endif
// In certain situations where multiple crash requests come
// through quickly, we can end up with the mach IPC messages not
// coming through correctly. Since we don't know what parameters
// we've missed, we can't do much besides abort the crash dump
// situation in this case.
unsigned int parameters_read = 0;
// The initial message contains the number of key value pairs that
// we are expected to read.
// Read each key/value pair, one mach message per key/value pair.
for (unsigned int i = 0; i < info.parameter_count; ++i) {
MachReceiveMessage parameter_message;
result = receive_port.WaitForMessage(&parameter_message, 1000);
if(result == KERN_SUCCESS) {
KeyValueMessageData &key_value_data =
(KeyValueMessageData&)*parameter_message.GetData();
// If we get a blank key, make sure we don't increment the
// parameter count; in some cases (notably on-demand generation
// many times in a short period of time) caused the Mach IPC
// messages to not come through correctly.
if (strlen(key_value_data.key) == 0) {
continue;
}
parameters_read++;
config_params_.SetKeyValue(key_value_data.key, key_value_data.value);
} else {
PRINT_MACH_RESULT(result, "Inspector: key/value message");
break;
}
}
if (parameters_read != info.parameter_count) {
DEBUGLOG(stderr, "Only read %d parameters instead of %d, aborting crash "
"dump generation.", parameters_read, info.parameter_count);
return KERN_FAILURE;
}
}
return result;
}
//=============================================================================
// Sets keys in the parameters dictionary that are specific to process uptime.
// The two we set are process up time, and process crash time.
void Inspector::SetCrashTimeParameters() {
// Set process uptime parameter
struct timeval tv;
gettimeofday(&tv, NULL);
char processUptimeString[32], processCrashtimeString[32];
const char *processStartTimeString =
config_params_.GetValueForKey(BREAKPAD_PROCESS_START_TIME);
// Set up time if we've received the start time.
if (processStartTimeString) {
time_t processStartTime = strtol(processStartTimeString, NULL, 10);
time_t processUptime = tv.tv_sec - processStartTime;
sprintf(processUptimeString, "%zd", processUptime);
config_params_.SetKeyValue(BREAKPAD_PROCESS_UP_TIME, processUptimeString);
}
sprintf(processCrashtimeString, "%zd", tv.tv_sec);
config_params_.SetKeyValue(BREAKPAD_PROCESS_CRASH_TIME,
processCrashtimeString);
}
bool Inspector::InspectTask() {
// keep the task quiet while we're looking at it
task_suspend(remote_task_);
DEBUGLOG(stderr, "Suspended Remote task\n");
NSString *minidumpDir;
const char *minidumpDirectory =
config_params_.GetValueForKey(BREAKPAD_DUMP_DIRECTORY);
SetCrashTimeParameters();
// If the client app has not specified a minidump directory,
// use a default of Library/<kDefaultLibrarySubdirectory>/<Product Name>
if (!minidumpDirectory || 0 == strlen(minidumpDirectory)) {
NSArray *libraryDirectories =
NSSearchPathForDirectoriesInDomains(NSLibraryDirectory,
NSUserDomainMask,
YES);
NSString *applicationSupportDirectory =
[libraryDirectories objectAtIndex:0];
NSString *library_subdirectory = [NSString
stringWithUTF8String:kDefaultLibrarySubdirectory];
NSString *breakpad_product = [NSString
stringWithUTF8String:config_params_.GetValueForKey(BREAKPAD_PRODUCT)];
NSArray *path_components = [NSArray
arrayWithObjects:applicationSupportDirectory,
library_subdirectory,
breakpad_product,
nil];
minidumpDir = [NSString pathWithComponents:path_components];
} else {
minidumpDir = [[NSString stringWithUTF8String:minidumpDirectory]
stringByExpandingTildeInPath];
}
DEBUGLOG(stderr,
"Writing minidump to directory (%s)\n",
[minidumpDir UTF8String]);
MinidumpLocation minidumpLocation(minidumpDir);
// Obscure bug alert:
// Don't use [NSString stringWithFormat] to build up the path here since it
// assumes system encoding and in RTL locales will prepend an LTR override
// character for paths beginning with '/' which fileSystemRepresentation does
// not remove. Filed as rdar://6889706 .
NSString *path_ns = [NSString
stringWithUTF8String:minidumpLocation.GetPath()];
NSString *pathid_ns = [NSString
stringWithUTF8String:minidumpLocation.GetID()];
NSString *minidumpPath = [path_ns stringByAppendingPathComponent:pathid_ns];
minidumpPath = [minidumpPath
stringByAppendingPathExtension:@"dmp"];
DEBUGLOG(stderr,
"minidump path (%s)\n",
[minidumpPath UTF8String]);
config_file_.WriteFile( &config_params_,
minidumpLocation.GetPath(),
minidumpLocation.GetID());
MinidumpGenerator generator(remote_task_, handler_thread_);
if (exception_type_ && exception_code_) {
generator.SetExceptionInformation(exception_type_,
exception_code_,
exception_subcode_,
crashing_thread_);
}
bool result = generator.Write([minidumpPath fileSystemRepresentation]);
if (result) {
DEBUGLOG(stderr, "Wrote minidump - OK\n");
} else {
DEBUGLOG(stderr, "Error writing minidump - errno=%s\n", strerror(errno));
}
// let the task continue
task_resume(remote_task_);
DEBUGLOG(stderr, "Resumed remote task\n");
return result;
}
//=============================================================================
// The crashed task needs to be told that the inspection has finished.
// It will wait on a mach port (with timeout) until we send acknowledgement.
kern_return_t Inspector::SendAcknowledgement() {
if (ack_port_ != MACH_PORT_DEAD) {
MachPortSender sender(ack_port_);
MachSendMessage ack_message(kMsgType_InspectorAcknowledgement);
DEBUGLOG(stderr, "Inspector: trying to send acknowledgement to port %d\n",
ack_port_);
kern_return_t result = sender.SendMessage(ack_message, 2000);
#if VERBOSE
PRINT_MACH_RESULT(result, "Inspector: sent acknowledgement");
#endif
return result;
}
DEBUGLOG(stderr, "Inspector: port translation failure!\n");
return KERN_INVALID_NAME;
}
//=============================================================================
void Inspector::LaunchReporter(const char *inConfigFilePath) {
// Extract the path to the reporter executable.
const char *reporterExecutablePath =
config_params_.GetValueForKey(BREAKPAD_REPORTER_EXE_LOCATION);
DEBUGLOG(stderr, "reporter path = %s\n", reporterExecutablePath);
// Setup and launch the crash dump sender.
const char *argv[3];
argv[0] = reporterExecutablePath;
argv[1] = inConfigFilePath;
argv[2] = NULL;
// Launch the reporter
pid_t pid = fork();
// If we're in the child, load in our new executable and run.
// The parent will not wait for the child to complete.
if (pid == 0) {
execv(argv[0], (char * const *)argv);
config_file_.Unlink(); // launch failed - get rid of config file
DEBUGLOG(stderr, "Inspector: unable to launch reporter app\n");
_exit(1);
}
// Wait until the Reporter child process exits.
//
// We'll use a timeout of one minute.
int timeoutCount = 60; // 60 seconds
while (timeoutCount-- > 0) {
int status;
pid_t result = waitpid(pid, &status, WNOHANG);
if (result == 0) {
// The child has not yet finished.
sleep(1);
} else if (result == -1) {
DEBUGLOG(stderr, "Inspector: waitpid error (%d) waiting for reporter app\n",
errno);
break;
} else {
// child has finished
break;
}
}
}
} // namespace google_breakpad

View File

@@ -0,0 +1,65 @@
// Copyright (c) 2007, 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.
//
// Main driver for Inspector
#import "client/mac/crash_generation/Inspector.h"
#import <Cocoa/Cocoa.h>
namespace google_breakpad {
//=============================================================================
extern "C" {
int main(int argc, char *const argv[]) {
#if DEBUG
// Since we're launched on-demand, this is necessary to see debugging
// output in the console window.
freopen("/dev/console", "w", stdout);
freopen("/dev/console", "w", stderr);
#endif
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
if (argc != 2) {
exit(0);
}
// Our first command-line argument contains the name of the service
// that we're providing.
google_breakpad::Inspector inspector;
inspector.Inspect(argv[1]);
[pool release];
return 0;
}
} // extern "C"
} // namespace google_breakpad

View File

@@ -0,0 +1,47 @@
// Copyright (c) 2010 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_MAC_CRASH_GENERATION_CLIENT_INFO_H_
#define CLIENT_MAC_CRASH_GENERATION_CLIENT_INFO_H_
namespace google_breakpad {
class ClientInfo {
public:
explicit ClientInfo(pid_t pid) : pid_(pid) {}
pid_t pid() const { return pid_; }
private:
pid_t pid_;
};
} // namespace google_breakpad
#endif // CLIENT_MAC_CRASH_GENERATION_CLIENT_INFO_H_

View File

@@ -0,0 +1,72 @@
// Copyright (c) 2010 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/mac/crash_generation/crash_generation_client.h"
#include "client/mac/crash_generation/crash_generation_server.h"
#include "common/mac/MachIPC.h"
namespace google_breakpad {
bool CrashGenerationClient::RequestDumpForException(
int exception_type,
int exception_code,
int exception_subcode,
mach_port_t crashing_thread) {
// The server will send a message to this port indicating that it
// has finished its work.
ReceivePort acknowledge_port;
MachSendMessage message(kDumpRequestMessage);
message.AddDescriptor(mach_task_self()); // this task
message.AddDescriptor(crashing_thread); // crashing thread
message.AddDescriptor(mach_thread_self()); // handler thread
message.AddDescriptor(acknowledge_port.GetPort()); // message receive port
ExceptionInfo info;
info.exception_type = exception_type;
info.exception_code = exception_code;
info.exception_subcode = exception_subcode;
message.SetData(&info, sizeof(info));
const mach_msg_timeout_t kSendTimeoutMs = 2 * 1000;
kern_return_t result = sender_.SendMessage(message, kSendTimeoutMs);
if (result != KERN_SUCCESS)
return false;
// Give the server slightly longer to reply since it has to
// inspect this task and write the minidump.
const mach_msg_timeout_t kReceiveTimeoutMs = 5 * 1000;
MachReceiveMessage acknowledge_message;
result = acknowledge_port.WaitForMessage(&acknowledge_message,
kReceiveTimeoutMs);
return result == KERN_SUCCESS;
}
} // namespace google_breakpad

View File

@@ -0,0 +1,65 @@
// Copyright (c) 2010 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 GOOGLE_BREAKPAD_CLIENT_MAC_CRASH_GENERATION_CRASH_GENERATION_CLIENT_H_
#define GOOGLE_BREAKPAD_CLIENT_MAC_CRASH_GENERATION_CRASH_GENERATION_CLIENT_H_
#include "common/mac/MachIPC.h"
namespace google_breakpad {
class CrashGenerationClient {
public:
explicit CrashGenerationClient(const char* mach_port_name)
: sender_(mach_port_name) {
}
// Request the crash server to generate a dump.
//
// Return true if the dump was successful; false otherwise.
bool RequestDumpForException(int exception_type,
int exception_code,
int exception_subcode,
mach_port_t crashing_thread);
bool RequestDump() {
return RequestDumpForException(0, 0, 0, MACH_PORT_NULL);
}
private:
MachPortSender sender_;
// Prevent copy construction and assignment.
CrashGenerationClient(const CrashGenerationClient&);
CrashGenerationClient& operator=(const CrashGenerationClient&);
};
} // namespace google_breakpad
#endif // GOOGLE_BREAKPAD_CLIENT_MAC_CRASH_GENERATION_CRASH_GENERATION_CLIENT_H_

View File

@@ -0,0 +1,160 @@
// Copyright (c) 2010 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/mac/crash_generation/crash_generation_server.h"
#include "client/mac/crash_generation/client_info.h"
#include "client/mac/handler/minidump_generator.h"
#include "common/mac/scoped_task_suspend-inl.h"
namespace google_breakpad {
CrashGenerationServer::CrashGenerationServer(
const char *mach_port_name,
OnClientDumpRequestCallback dump_callback,
void *dump_context,
OnClientExitingCallback exit_callback,
void *exit_context,
bool generate_dumps,
const std::string &dump_path)
: dump_callback_(dump_callback),
dump_context_(dump_context),
exit_callback_(exit_callback),
exit_context_(exit_context),
generate_dumps_(generate_dumps),
dump_dir_(dump_path.empty() ? "/tmp" : dump_path),
started_(false),
receive_port_(mach_port_name),
mach_port_name_(mach_port_name) {
}
CrashGenerationServer::~CrashGenerationServer() {
if (started_)
Stop();
}
bool CrashGenerationServer::Start() {
int thread_create_result = pthread_create(&server_thread_, NULL,
&WaitForMessages, this);
started_ = thread_create_result == 0;
return started_;
}
bool CrashGenerationServer::Stop() {
if (!started_)
return false;
// Send a quit message to the background thread, and then join it.
MachPortSender sender(mach_port_name_.c_str());
MachSendMessage quit_message(kQuitMessage);
const mach_msg_timeout_t kSendTimeoutMs = 2 * 1000;
kern_return_t result = sender.SendMessage(quit_message, kSendTimeoutMs);
if (result == KERN_SUCCESS) {
int thread_join_result = pthread_join(server_thread_, NULL);
started_ = thread_join_result != 0;
}
return !started_;
}
// static
void *CrashGenerationServer::WaitForMessages(void *server) {
CrashGenerationServer *self =
reinterpret_cast<CrashGenerationServer*>(server);
while (self->WaitForOneMessage()) {}
return NULL;
}
bool CrashGenerationServer::WaitForOneMessage() {
MachReceiveMessage message;
kern_return_t result = receive_port_.WaitForMessage(&message,
MACH_MSG_TIMEOUT_NONE);
if (result == KERN_SUCCESS) {
switch (message.GetMessageID()) {
case kDumpRequestMessage: {
ExceptionInfo &info = (ExceptionInfo &)*message.GetData();
mach_port_t remote_task = message.GetTranslatedPort(0);
mach_port_t crashing_thread = message.GetTranslatedPort(1);
mach_port_t handler_thread = message.GetTranslatedPort(2);
mach_port_t ack_port = message.GetTranslatedPort(3);
pid_t remote_pid = -1;
pid_for_task(remote_task, &remote_pid);
ClientInfo client(remote_pid);
bool result;
std::string dump_path;
if (generate_dumps_) {
ScopedTaskSuspend suspend(remote_task);
MinidumpGenerator generator(remote_task, handler_thread);
dump_path = generator.UniqueNameInDirectory(dump_dir_, NULL);
if (info.exception_type && info.exception_code) {
generator.SetExceptionInformation(info.exception_type,
info.exception_code,
info.exception_subcode,
crashing_thread);
}
result = generator.Write(dump_path.c_str());
} else {
result = true;
}
if (result && dump_callback_) {
dump_callback_(dump_context_, client, dump_path);
}
// TODO(ted): support a way for the client to send additional data,
// perhaps with a callback so users of the server can read the data
// themselves?
if (ack_port != MACH_PORT_DEAD && ack_port != MACH_PORT_NULL) {
MachPortSender sender(ack_port);
MachSendMessage ack_message(kAcknowledgementMessage);
const mach_msg_timeout_t kSendTimeoutMs = 2 * 1000;
sender.SendMessage(ack_message, kSendTimeoutMs);
}
if (exit_callback_) {
exit_callback_(exit_context_, client);
}
break;
}
case kQuitMessage:
return false;
}
} else { // result != KERN_SUCCESS
return false;
}
return true;
}
} // namespace google_breakpad

View File

@@ -0,0 +1,141 @@
// Copyright (c) 2010 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 GOOGLE_BREAKPAD_CLIENT_MAC_CRASH_GENERATION_CRASH_GENERATION_SERVER_H_
#define GOOGLE_BREAKPAD_CLIENT_MAC_CRASH_GENERATION_CRASH_GENERATION_SERVER_H_
#include <stdint.h>
#include <string>
#include "common/mac/MachIPC.h"
namespace google_breakpad {
class ClientInfo;
// Messages the server can read via its mach port
enum {
kDumpRequestMessage = 1,
kAcknowledgementMessage = 2,
kQuitMessage = 3
};
// Exception details sent by the client when requesting a dump.
struct ExceptionInfo {
int32_t exception_type;
int32_t exception_code;
int32_t exception_subcode;
};
class CrashGenerationServer {
public:
// WARNING: callbacks may be invoked on a different thread
// than that which creates the CrashGenerationServer. They must
// be thread safe.
typedef void (*OnClientDumpRequestCallback)(void *context,
const ClientInfo &client_info,
const std::string &file_path);
typedef void (*OnClientExitingCallback)(void *context,
const ClientInfo &client_info);
// Create an instance with the given parameters.
//
// mach_port_name: Named server port to listen on.
// dump_callback: Callback for a client crash dump request.
// dump_context: Context for client crash dump request callback.
// exit_callback: Callback for client process exit.
// exit_context: Context for client exit callback.
// generate_dumps: Whether to automatically generate dumps.
// Client code of this class might want to generate dumps explicitly
// in the crash dump request callback. In that case, false can be
// passed for this parameter.
// dump_path: Path for generating dumps; required only if true is
// passed for generateDumps parameter; NULL can be passed otherwise.
CrashGenerationServer(const char *mach_port_name,
OnClientDumpRequestCallback dump_callback,
void *dump_context,
OnClientExitingCallback exit_callback,
void *exit_context,
bool generate_dumps,
const std::string &dump_path);
~CrashGenerationServer();
// Perform initialization steps needed to start listening to clients.
//
// Return true if initialization is successful; false otherwise.
bool Start();
// Stop the server.
bool Stop();
private:
// Return a unique filename at which a minidump can be written.
bool MakeMinidumpFilename(std::string &outFilename);
// Loop reading client messages and responding to them until
// a quit message is received.
static void *WaitForMessages(void *server);
// Wait for a single client message and respond to it. Returns false
// if a quit message was received or if an error occurred.
bool WaitForOneMessage();
OnClientDumpRequestCallback dump_callback_;
void *dump_context_;
OnClientExitingCallback exit_callback_;
void *exit_context_;
bool generate_dumps_;
std::string dump_dir_;
bool started_;
// The mach port that receives requests to dump from child processes.
ReceivePort receive_port_;
// The name of the mach port. Stored so the Stop method can message
// the background thread to shut it down.
std::string mach_port_name_;
// The thread that waits on the receive port.
pthread_t server_thread_;
// Disable copy constructor and operator=.
CrashGenerationServer(const CrashGenerationServer&);
CrashGenerationServer& operator=(const CrashGenerationServer&);
};
} // namespace google_breakpad
#endif // GOOGLE_BREAKPAD_CLIENT_MAC_CRASH_GENERATION_CRASH_GENERATION_SERVER_H_

Binary file not shown.

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,258 @@
#ifndef _exc_user_
#define _exc_user_
/* Module exc */
#include <string.h>
#include <mach/ndr.h>
#include <mach/boolean.h>
#include <mach/kern_return.h>
#include <mach/notify.h>
#include <mach/mach_types.h>
#include <mach/message.h>
#include <mach/mig_errors.h>
#include <mach/port.h>
#ifdef AUTOTEST
#ifndef FUNCTION_PTR_T
#define FUNCTION_PTR_T
typedef void (*function_ptr_t)(mach_port_t, char *, mach_msg_type_number_t);
typedef struct {
char *name;
function_ptr_t function;
} function_table_entry;
typedef function_table_entry *function_table_t;
#endif /* FUNCTION_PTR_T */
#endif /* AUTOTEST */
#ifndef exc_MSG_COUNT
#define exc_MSG_COUNT 3
#endif /* exc_MSG_COUNT */
#include <mach/std_types.h>
#include <mach/mig.h>
#include <mach/mig.h>
#include <mach/mach_types.h>
#ifdef __BeforeMigUserHeader
__BeforeMigUserHeader
#endif /* __BeforeMigUserHeader */
#include <sys/cdefs.h>
__BEGIN_DECLS
/* Routine exception_raise */
#ifdef mig_external
mig_external
#else
extern
#endif /* mig_external */
kern_return_t exception_raise
(
mach_port_t exception_port,
mach_port_t thread,
mach_port_t task,
exception_type_t exception,
exception_data_t code,
mach_msg_type_number_t codeCnt
);
/* Routine exception_raise_state */
#ifdef mig_external
mig_external
#else
extern
#endif /* mig_external */
kern_return_t exception_raise_state
(
mach_port_t exception_port,
exception_type_t exception,
const exception_data_t code,
mach_msg_type_number_t codeCnt,
int *flavor,
const thread_state_t old_state,
mach_msg_type_number_t old_stateCnt,
thread_state_t new_state,
mach_msg_type_number_t *new_stateCnt
);
/* Routine exception_raise_state_identity */
#ifdef mig_external
mig_external
#else
extern
#endif /* mig_external */
kern_return_t exception_raise_state_identity
(
mach_port_t exception_port,
mach_port_t thread,
mach_port_t task,
exception_type_t exception,
exception_data_t code,
mach_msg_type_number_t codeCnt,
int *flavor,
thread_state_t old_state,
mach_msg_type_number_t old_stateCnt,
thread_state_t new_state,
mach_msg_type_number_t *new_stateCnt
);
__END_DECLS
/********************** Caution **************************/
/* The following data types should be used to calculate */
/* maximum message sizes only. The actual message may be */
/* smaller, and the position of the arguments within the */
/* message layout may vary from what is presented here. */
/* For example, if any of the arguments are variable- */
/* sized, and less than the maximum is sent, the data */
/* will be packed tight in the actual message to reduce */
/* the presence of holes. */
/********************** Caution **************************/
/* typedefs for all requests */
#ifndef __Request__exc_subsystem__defined
#define __Request__exc_subsystem__defined
#ifdef __MigPackStructs
#pragma pack(4)
#endif
typedef struct {
mach_msg_header_t Head;
/* start of the kernel processed data */
mach_msg_body_t msgh_body;
mach_msg_port_descriptor_t thread;
mach_msg_port_descriptor_t task;
/* end of the kernel processed data */
NDR_record_t NDR;
exception_type_t exception;
mach_msg_type_number_t codeCnt;
integer_t code[2];
} __Request__exception_raise_t;
#ifdef __MigPackStructs
#pragma pack()
#endif
#ifdef __MigPackStructs
#pragma pack(4)
#endif
typedef struct {
mach_msg_header_t Head;
NDR_record_t NDR;
exception_type_t exception;
mach_msg_type_number_t codeCnt;
integer_t code[2];
int flavor;
mach_msg_type_number_t old_stateCnt;
natural_t old_state[144];
} __Request__exception_raise_state_t;
#ifdef __MigPackStructs
#pragma pack()
#endif
#ifdef __MigPackStructs
#pragma pack(4)
#endif
typedef struct {
mach_msg_header_t Head;
/* start of the kernel processed data */
mach_msg_body_t msgh_body;
mach_msg_port_descriptor_t thread;
mach_msg_port_descriptor_t task;
/* end of the kernel processed data */
NDR_record_t NDR;
exception_type_t exception;
mach_msg_type_number_t codeCnt;
integer_t code[2];
int flavor;
mach_msg_type_number_t old_stateCnt;
natural_t old_state[144];
} __Request__exception_raise_state_identity_t;
#ifdef __MigPackStructs
#pragma pack()
#endif
#endif /* !__Request__exc_subsystem__defined */
/* union of all requests */
#ifndef __RequestUnion__exc_subsystem__defined
#define __RequestUnion__exc_subsystem__defined
union __RequestUnion__exc_subsystem {
__Request__exception_raise_t Request_exception_raise;
__Request__exception_raise_state_t Request_exception_raise_state;
__Request__exception_raise_state_identity_t Request_exception_raise_state_identity;
};
#endif /* !__RequestUnion__exc_subsystem__defined */
/* typedefs for all replies */
#ifndef __Reply__exc_subsystem__defined
#define __Reply__exc_subsystem__defined
#ifdef __MigPackStructs
#pragma pack(4)
#endif
typedef struct {
mach_msg_header_t Head;
NDR_record_t NDR;
kern_return_t RetCode;
} __Reply__exception_raise_t;
#ifdef __MigPackStructs
#pragma pack()
#endif
#ifdef __MigPackStructs
#pragma pack(4)
#endif
typedef struct {
mach_msg_header_t Head;
NDR_record_t NDR;
kern_return_t RetCode;
int flavor;
mach_msg_type_number_t new_stateCnt;
natural_t new_state[144];
} __Reply__exception_raise_state_t;
#ifdef __MigPackStructs
#pragma pack()
#endif
#ifdef __MigPackStructs
#pragma pack(4)
#endif
typedef struct {
mach_msg_header_t Head;
NDR_record_t NDR;
kern_return_t RetCode;
int flavor;
mach_msg_type_number_t new_stateCnt;
natural_t new_state[144];
} __Reply__exception_raise_state_identity_t;
#ifdef __MigPackStructs
#pragma pack()
#endif
#endif /* !__Reply__exc_subsystem__defined */
/* union of all replies */
#ifndef __ReplyUnion__exc_subsystem__defined
#define __ReplyUnion__exc_subsystem__defined
union __ReplyUnion__exc_subsystem {
__Reply__exception_raise_t Reply_exception_raise;
__Reply__exception_raise_state_t Reply_exception_raise_state;
__Reply__exception_raise_state_identity_t Reply_exception_raise_state_identity;
};
#endif /* !__RequestUnion__exc_subsystem__defined */
#ifndef subsystem_to_name_map_exc
#define subsystem_to_name_map_exc \
{ "exception_raise", 2401 },\
{ "exception_raise_state", 2402 },\
{ "exception_raise_state_identity", 2403 }
#endif
#ifdef __AfterMigUserHeader
__AfterMigUserHeader
#endif /* __AfterMigUserHeader */
#endif /* _exc_user_ */

View File

@@ -0,0 +1,412 @@
/*
* Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
* This file contains Original Code and/or Modifications of Original Code
* as defined in and that are subject to the Apple Public Source License
* Version 2.0 (the 'License'). You may not use this file except in
* compliance with the License. Please obtain a copy of the License at
* http://www.opensource.apple.com/apsl/ and read it before using this
* file.
*
* The Original Code and all software distributed under the License are
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
*
* @APPLE_LICENSE_HEADER_END@
*/
/*
* Copyright (c) 1989, 1993
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. 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.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University 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 REGENTS 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 REGENTS 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 file was copied from libc/gen/nlist.c from Darwin's source code
* The version of nlist used as a base is from 10.5.2, libc-498
* http://www.opensource.apple.com/darwinsource/10.5.2/Libc-498/gen/nlist.c
*
* The full tarball is at:
* http://www.opensource.apple.com/darwinsource/tarballs/apsl/Libc-498.tar.gz
*
* I've modified it to be compatible with 64-bit images.
*/
#include "breakpad_nlist_64.h"
#include <fcntl.h>
#include <mach-o/nlist.h>
#include <mach-o/loader.h>
#include <mach-o/fat.h>
#include <mach/mach.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/uio.h>
#include <TargetConditionals.h>
#include <unistd.h>
/* Stuff lifted from <a.out.h> and <sys/exec.h> since they are gone */
/*
* Header prepended to each a.out file.
*/
struct exec {
unsigned short a_machtype; /* machine type */
unsigned short a_magic; /* magic number */
unsigned long a_text; /* size of text segment */
unsigned long a_data; /* size of initialized data */
unsigned long a_bss; /* size of uninitialized data */
unsigned long a_syms; /* size of symbol table */
unsigned long a_entry; /* entry point */
unsigned long a_trsize; /* size of text relocation */
unsigned long a_drsize; /* size of data relocation */
};
#define OMAGIC 0407 /* old impure format */
#define NMAGIC 0410 /* read-only text */
#define ZMAGIC 0413 /* demand load format */
#define N_BADMAG(x) \
(((x).a_magic)!=OMAGIC && ((x).a_magic)!=NMAGIC && ((x).a_magic)!=ZMAGIC)
#define N_TXTOFF(x) \
((x).a_magic==ZMAGIC ? 0 : sizeof (struct exec))
#define N_SYMOFF(x) \
(N_TXTOFF(x) + (x).a_text+(x).a_data + (x).a_trsize+(x).a_drsize)
// Traits structs for specializing function templates to handle
// 32-bit/64-bit Mach-O files.
template<typename T>
struct MachBits {};
typedef struct nlist nlist32;
typedef struct nlist_64 nlist64;
template<>
struct MachBits<nlist32> {
typedef mach_header mach_header_type;
typedef uint32_t word_type;
static const uint32_t magic = MH_MAGIC;
};
template<>
struct MachBits<nlist64> {
typedef mach_header_64 mach_header_type;
typedef uint64_t word_type;
static const uint32_t magic = MH_MAGIC_64;
};
template<typename nlist_type>
int
__breakpad_fdnlist(int fd, nlist_type *list, const char **symbolNames,
cpu_type_t cpu_type);
/*
* nlist - retreive attributes from name list (string table version)
*/
template <typename nlist_type>
int breakpad_nlist_common(const char *name,
nlist_type *list,
const char **symbolNames,
cpu_type_t cpu_type) {
int fd = open(name, O_RDONLY, 0);
if (fd < 0)
return -1;
int n = __breakpad_fdnlist(fd, list, symbolNames, cpu_type);
close(fd);
return n;
}
int breakpad_nlist(const char *name,
struct nlist *list,
const char **symbolNames,
cpu_type_t cpu_type) {
return breakpad_nlist_common(name, list, symbolNames, cpu_type);
}
int breakpad_nlist(const char *name,
struct nlist_64 *list,
const char **symbolNames,
cpu_type_t cpu_type) {
return breakpad_nlist_common(name, list, symbolNames, cpu_type);
}
/* Note: __fdnlist() is called from kvm_nlist in libkvm's kvm.c */
template<typename nlist_type>
int __breakpad_fdnlist(int fd, nlist_type *list, const char **symbolNames,
cpu_type_t cpu_type) {
typedef typename MachBits<nlist_type>::mach_header_type mach_header_type;
typedef typename MachBits<nlist_type>::word_type word_type;
const uint32_t magic = MachBits<nlist_type>::magic;
int maxlen = 500;
int nreq = 0;
for (nlist_type* q = list;
symbolNames[q-list] && symbolNames[q-list][0];
q++, nreq++) {
q->n_type = 0;
q->n_value = 0;
q->n_desc = 0;
q->n_sect = 0;
q->n_un.n_strx = 0;
}
struct exec buf;
if (read(fd, (char *)&buf, sizeof(buf)) != sizeof(buf) ||
(N_BADMAG(buf) && *((uint32_t *)&buf) != magic &&
NXSwapBigLongToHost(*((long *)&buf)) != FAT_MAGIC) &&
/* The following is the big-endian ppc64 check */
(*((uint32_t*)&buf)) != FAT_MAGIC) {
return -1;
}
/* Deal with fat file if necessary */
unsigned arch_offset = 0;
if (NXSwapBigLongToHost(*((long *)&buf)) == FAT_MAGIC ||
/* The following is the big-endian ppc64 check */
*((unsigned int *)&buf) == FAT_MAGIC) {
/* Get host info */
host_t host = mach_host_self();
unsigned i = HOST_BASIC_INFO_COUNT;
struct host_basic_info hbi;
kern_return_t kr;
if ((kr = host_info(host, HOST_BASIC_INFO,
(host_info_t)(&hbi), &i)) != KERN_SUCCESS) {
return -1;
}
mach_port_deallocate(mach_task_self(), host);
/* Read in the fat header */
struct fat_header fh;
if (lseek(fd, 0, SEEK_SET) == -1) {
return -1;
}
if (read(fd, (char *)&fh, sizeof(fh)) != sizeof(fh)) {
return -1;
}
/* Convert fat_narchs to host byte order */
fh.nfat_arch = NXSwapBigIntToHost(fh.nfat_arch);
/* Read in the fat archs */
struct fat_arch *fat_archs =
(struct fat_arch *)malloc(fh.nfat_arch * sizeof(struct fat_arch));
if (fat_archs == NULL) {
return -1;
}
if (read(fd, (char *)fat_archs,
sizeof(struct fat_arch) * fh.nfat_arch) !=
(ssize_t)(sizeof(struct fat_arch) * fh.nfat_arch)) {
free(fat_archs);
return -1;
}
/*
* Convert archs to host byte ordering (a constraint of
* cpusubtype_getbestarch()
*/
for (unsigned i = 0; i < fh.nfat_arch; i++) {
fat_archs[i].cputype =
NXSwapBigIntToHost(fat_archs[i].cputype);
fat_archs[i].cpusubtype =
NXSwapBigIntToHost(fat_archs[i].cpusubtype);
fat_archs[i].offset =
NXSwapBigIntToHost(fat_archs[i].offset);
fat_archs[i].size =
NXSwapBigIntToHost(fat_archs[i].size);
fat_archs[i].align =
NXSwapBigIntToHost(fat_archs[i].align);
}
struct fat_arch *fap = NULL;
for (unsigned i = 0; i < fh.nfat_arch; i++) {
if (fat_archs[i].cputype == cpu_type) {
fap = &fat_archs[i];
break;
}
}
if (!fap) {
free(fat_archs);
return -1;
}
arch_offset = fap->offset;
free(fat_archs);
/* Read in the beginning of the architecture-specific file */
if (lseek(fd, arch_offset, SEEK_SET) == -1) {
return -1;
}
if (read(fd, (char *)&buf, sizeof(buf)) != sizeof(buf)) {
return -1;
}
}
off_t sa; /* symbol address */
off_t ss; /* start of strings */
register register_t n;
if (*((unsigned int *)&buf) == magic) {
if (lseek(fd, arch_offset, SEEK_SET) == -1) {
return -1;
}
mach_header_type mh;
if (read(fd, (char *)&mh, sizeof(mh)) != sizeof(mh)) {
return -1;
}
struct load_command *load_commands =
(struct load_command *)malloc(mh.sizeofcmds);
if (load_commands == NULL) {
return -1;
}
if (read(fd, (char *)load_commands, mh.sizeofcmds) !=
(ssize_t)mh.sizeofcmds) {
free(load_commands);
return -1;
}
struct symtab_command *stp = NULL;
struct load_command *lcp = load_commands;
// iterate through all load commands, looking for
// LC_SYMTAB load command
for (uint32_t i = 0; i < mh.ncmds; i++) {
if (lcp->cmdsize % sizeof(word_type) != 0 ||
lcp->cmdsize <= 0 ||
(char *)lcp + lcp->cmdsize >
(char *)load_commands + mh.sizeofcmds) {
free(load_commands);
return -1;
}
if (lcp->cmd == LC_SYMTAB) {
if (lcp->cmdsize !=
sizeof(struct symtab_command)) {
free(load_commands);
return -1;
}
stp = (struct symtab_command *)lcp;
break;
}
lcp = (struct load_command *)
((char *)lcp + lcp->cmdsize);
}
if (stp == NULL) {
free(load_commands);
return -1;
}
// sa points to the beginning of the symbol table
sa = stp->symoff + arch_offset;
// ss points to the beginning of the string table
ss = stp->stroff + arch_offset;
// n is the number of bytes in the symbol table
// each symbol table entry is an nlist structure
n = stp->nsyms * sizeof(nlist_type);
free(load_commands);
} else {
sa = N_SYMOFF(buf) + arch_offset;
ss = sa + buf.a_syms + arch_offset;
n = buf.a_syms;
}
if (lseek(fd, sa, SEEK_SET) == -1) {
return -1;
}
// the algorithm here is to read the nlist entries in m-sized
// chunks into q. q is then iterated over. for each entry in q,
// use the string table index(q->n_un.n_strx) to read the symbol
// name, then scan the nlist entries passed in by the user(via p),
// and look for a match
while (n) {
nlist_type space[BUFSIZ/sizeof (nlist_type)];
register register_t m = sizeof (space);
if (n < m)
m = n;
if (read(fd, (char *)space, m) != m)
break;
n -= m;
long savpos = lseek(fd, 0, SEEK_CUR);
if (savpos == -1) {
return -1;
}
for (nlist_type* q = space; (m -= sizeof(nlist_type)) >= 0; q++) {
char nambuf[BUFSIZ];
if (q->n_un.n_strx == 0 || q->n_type & N_STAB)
continue;
// seek to the location in the binary where the symbol
// name is stored & read it into memory
if (lseek(fd, ss+q->n_un.n_strx, SEEK_SET) == -1) {
return -1;
}
if (read(fd, nambuf, maxlen+1) == -1) {
return -1;
}
const char *s2 = nambuf;
for (nlist_type *p = list;
symbolNames[p-list] && symbolNames[p-list][0];
p++) {
// get the symbol name the user has passed in that
// corresponds to the nlist entry that we're looking at
const char *s1 = symbolNames[p - list];
while (*s1) {
if (*s1++ != *s2++)
goto cont;
}
if (*s2)
goto cont;
p->n_value = q->n_value;
p->n_type = q->n_type;
p->n_desc = q->n_desc;
p->n_sect = q->n_sect;
p->n_un.n_strx = q->n_un.n_strx;
if (--nreq == 0)
return nreq;
break;
cont: ;
}
}
if (lseek(fd, savpos, SEEK_SET) == -1) {
return -1;
}
}
return nreq;
}

View File

@@ -0,0 +1,47 @@
// Copyright (c) 2008, 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.
// breakpad_nlist.h
//
// This file is meant to provide a header for clients of the modified
// nlist function implemented to work on 64-bit.
#ifndef CLIENT_MAC_HANDLER_BREAKPAD_NLIST_H__
#include <mach/machine.h>
int breakpad_nlist(const char *name,
struct nlist *list,
const char **symbolNames,
cpu_type_t cpu_type);
int breakpad_nlist(const char *name,
struct nlist_64 *list,
const char **symbolNames,
cpu_type_t cpu_type);
#endif /* CLIENT_MAC_HANDLER_BREAKPAD_NLIST_H__ */

View File

@@ -27,17 +27,51 @@
// (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/mac/handler/dynamic_images.h"
extern "C" { // needed to compile on Leopard
#include <mach-o/nlist.h>
#include <stdlib.h>
#include <stdio.h>
}
#include "breakpad_nlist_64.h"
#include <AvailabilityMacros.h>
#include <assert.h>
#include <CoreServices/CoreServices.h>
#include <dlfcn.h>
#include <mach/mach_vm.h>
#include <mach/task_info.h>
#include <sys/sysctl.h>
#include <algorithm>
#include "client/mac/handler/dynamic_images.h"
#include <string>
#include <vector>
#ifndef MAC_OS_X_VERSION_10_6
#define MAC_OS_X_VERSION_10_6 1060
#endif
#if MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_6
// Fallback declarations for TASK_DYLD_INFO and friends, introduced in
// <mach/task_info.h> in the Mac OS X 10.6 SDK.
#define TASK_DYLD_INFO 17
struct task_dyld_info {
mach_vm_address_t all_image_info_addr;
mach_vm_size_t all_image_info_size;
};
typedef struct task_dyld_info task_dyld_info_data_t;
typedef struct task_dyld_info *task_dyld_info_t;
#define TASK_DYLD_INFO_COUNT (sizeof(task_dyld_info_data_t) / sizeof(natural_t))
#endif
namespace google_breakpad {
using std::string;
using std::vector;
//==============================================================================
// Returns the size of the memory region containing |address| and the
// number of bytes from |address| to the end of the region.
@@ -46,27 +80,30 @@ namespace google_breakpad {
// first in order to handle cases when we're reading strings and they
// straddle two vm regions.
//
static vm_size_t GetMemoryRegionSize(task_port_t target_task,
const void* address,
vm_size_t *size_to_end) {
vm_address_t region_base = (vm_address_t)address;
vm_size_t region_size;
static mach_vm_size_t GetMemoryRegionSize(task_port_t target_task,
const uint64_t address,
mach_vm_size_t *size_to_end) {
mach_vm_address_t region_base = (mach_vm_address_t)address;
mach_vm_size_t region_size;
natural_t nesting_level = 0;
vm_region_submap_info submap_info;
mach_msg_type_number_t info_count = VM_REGION_SUBMAP_INFO_COUNT;
vm_region_submap_info_64 submap_info;
mach_msg_type_number_t info_count = VM_REGION_SUBMAP_INFO_COUNT_64;
// Get information about the vm region containing |address|
kern_return_t result =
vm_region_recurse(target_task,
&region_base,
&region_size,
&nesting_level,
reinterpret_cast<vm_region_recurse_info_t>(&submap_info),
&info_count);
vm_region_recurse_info_t region_info;
region_info = reinterpret_cast<vm_region_recurse_info_t>(&submap_info);
kern_return_t result =
mach_vm_region_recurse(target_task,
&region_base,
&region_size,
&nesting_level,
region_info,
&info_count);
if (result == KERN_SUCCESS) {
// Get distance from |address| to the end of this region
*size_to_end = region_base + region_size -(vm_address_t)address;
*size_to_end = region_base + region_size -(mach_vm_address_t)address;
// If we want to handle strings as long as 4096 characters we may need
// to check if there's a vm region immediately following the first one.
@@ -74,20 +111,19 @@ static vm_size_t GetMemoryRegionSize(task_port_t target_task,
// of the second region.
if (*size_to_end < 4096) {
// Second region starts where the first one ends
vm_address_t region_base2 =
(vm_address_t)(region_base + region_size);
vm_size_t region_size2;
mach_vm_address_t region_base2 =
(mach_vm_address_t)(region_base + region_size);
mach_vm_size_t region_size2;
// Get information about the following vm region
result =
vm_region_recurse(
target_task,
&region_base2,
&region_size2,
&nesting_level,
reinterpret_cast<vm_region_recurse_info_t>(&submap_info),
&info_count);
result =
mach_vm_region_recurse(target_task,
&region_base2,
&region_size2,
&nesting_level,
region_info,
&info_count);
// Extend region_size to go all the way to the end of the 2nd region
if (result == KERN_SUCCESS
&& region_base2 == region_base + region_size) {
@@ -95,13 +131,13 @@ static vm_size_t GetMemoryRegionSize(task_port_t target_task,
}
}
*size_to_end = region_base + region_size -(vm_address_t)address;
*size_to_end = region_base + region_size -(mach_vm_address_t)address;
} else {
region_size = 0;
*size_to_end = 0;
}
return region_size;
return region_size;
}
#define kMaxStringLength 8192
@@ -110,104 +146,183 @@ static vm_size_t GetMemoryRegionSize(task_port_t target_task,
//
// Warning! This will not read any strings longer than kMaxStringLength-1
//
static void* ReadTaskString(task_port_t target_task,
const void* address) {
static string ReadTaskString(task_port_t target_task,
const uint64_t address) {
// The problem is we don't know how much to read until we know how long
// the string is. And we don't know how long the string is, until we've read
// the memory! So, we'll try to read kMaxStringLength bytes
// (or as many bytes as we can until we reach the end of the vm region).
vm_size_t size_to_end;
// (or as many bytes as we can until we reach the end of the vm region).
mach_vm_size_t size_to_end;
GetMemoryRegionSize(target_task, address, &size_to_end);
if (size_to_end > 0) {
vm_size_t size_to_read =
mach_vm_size_t size_to_read =
size_to_end > kMaxStringLength ? kMaxStringLength : size_to_end;
return ReadTaskMemory(target_task, address, size_to_read);
vector<uint8_t> bytes;
if (ReadTaskMemory(target_task, address, (size_t)size_to_read, bytes) !=
KERN_SUCCESS)
return string();
return string(reinterpret_cast<const char*>(&bytes[0]));
}
return NULL;
return string();
}
//==============================================================================
// Reads an address range from another task. A block of memory is malloced
// and should be freed by the caller.
void* ReadTaskMemory(task_port_t target_task,
const void* address,
size_t length) {
void* result = NULL;
vm_address_t page_address = reinterpret_cast<vm_address_t>(address) & (-4096);
vm_address_t last_page_address =
(reinterpret_cast<vm_address_t>(address) + length + 4095) & (-4096);
vm_size_t page_size = last_page_address - page_address;
// Reads an address range from another task. The bytes read will be returned
// in bytes, which will be resized as necessary.
kern_return_t ReadTaskMemory(task_port_t target_task,
const uint64_t address,
size_t length,
vector<uint8_t> &bytes) {
int systemPageSize = getpagesize();
// use the negative of the page size for the mask to find the page address
mach_vm_address_t page_address = address & (-systemPageSize);
mach_vm_address_t last_page_address =
(address + length + (systemPageSize - 1)) & (-systemPageSize);
mach_vm_size_t page_size = last_page_address - page_address;
uint8_t* local_start;
uint32_t local_length;
kern_return_t r = vm_read(target_task,
page_address,
page_size,
reinterpret_cast<vm_offset_t*>(&local_start),
&local_length);
kern_return_t r = mach_vm_read(target_task,
page_address,
page_size,
reinterpret_cast<vm_offset_t*>(&local_start),
&local_length);
if (r == KERN_SUCCESS) {
result = malloc(length);
if (result != NULL) {
memcpy(result, &local_start[(uint32_t)address - page_address], length);
}
vm_deallocate(mach_task_self(), (uintptr_t)local_start, local_length);
}
return result;
if (r != KERN_SUCCESS)
return r;
bytes.resize(length);
memcpy(&bytes[0],
&local_start[(mach_vm_address_t)address - page_address],
length);
mach_vm_deallocate(mach_task_self(), (uintptr_t)local_start, local_length);
return KERN_SUCCESS;
}
#pragma mark -
//==============================================================================
// Initializes vmaddr_, vmsize_, and slide_
void DynamicImage::CalculateMemoryInfo() {
mach_header *header = GetMachHeader();
// Traits structs for specializing function templates to handle
// 32-bit/64-bit Mach-O files.
struct MachO32 {
typedef mach_header mach_header_type;
typedef segment_command mach_segment_command_type;
typedef dyld_image_info32 dyld_image_info;
typedef dyld_all_image_infos32 dyld_all_image_infos;
typedef struct nlist nlist_type;
static const uint32_t magic = MH_MAGIC;
static const uint32_t segment_load_command = LC_SEGMENT;
};
struct MachO64 {
typedef mach_header_64 mach_header_type;
typedef segment_command_64 mach_segment_command_type;
typedef dyld_image_info64 dyld_image_info;
typedef dyld_all_image_infos64 dyld_all_image_infos;
typedef struct nlist_64 nlist_type;
static const uint32_t magic = MH_MAGIC_64;
static const uint32_t segment_load_command = LC_SEGMENT_64;
};
template<typename MachBits>
bool FindTextSection(DynamicImage& image) {
typedef typename MachBits::mach_header_type mach_header_type;
typedef typename MachBits::mach_segment_command_type
mach_segment_command_type;
const mach_header_type* header =
reinterpret_cast<const mach_header_type*>(&image.header_[0]);
if(header->magic != MachBits::magic) {
return false;
}
const struct load_command *cmd =
reinterpret_cast<const struct load_command *>(header + 1);
reinterpret_cast<const struct load_command *>(header + 1);
bool found_text_section = false;
bool found_dylib_id_command = false;
for (unsigned int i = 0; cmd && (i < header->ncmds); ++i) {
if (cmd->cmd == LC_SEGMENT) {
const struct segment_command *seg =
reinterpret_cast<const struct segment_command *>(cmd);
if (!found_text_section) {
if (cmd->cmd == MachBits::segment_load_command) {
const mach_segment_command_type *seg =
reinterpret_cast<const mach_segment_command_type *>(cmd);
if (!strcmp(seg->segname, "__TEXT")) {
vmaddr_ = seg->vmaddr;
vmsize_ = seg->vmsize;
slide_ = 0;
if (seg->fileoff == 0 && seg->filesize != 0) {
slide_ = (uintptr_t)GetLoadAddress() - (uintptr_t)seg->vmaddr;
if (!strcmp(seg->segname, "__TEXT")) {
image.vmaddr_ = seg->vmaddr;
image.vmsize_ = seg->vmsize;
image.slide_ = 0;
if (seg->fileoff == 0 && seg->filesize != 0) {
image.slide_ =
(uintptr_t)image.GetLoadAddress() - (uintptr_t)seg->vmaddr;
}
found_text_section = true;
}
return;
}
}
if (!found_dylib_id_command) {
if (cmd->cmd == LC_ID_DYLIB) {
const struct dylib_command *dc =
reinterpret_cast<const struct dylib_command *>(cmd);
image.version_ = dc->dylib.current_version;
found_dylib_id_command = true;
}
}
if (found_dylib_id_command && found_text_section) {
return true;
}
cmd = reinterpret_cast<const struct load_command *>
(reinterpret_cast<const char *>(cmd) + cmd->cmdsize);
(reinterpret_cast<const char *>(cmd) + cmd->cmdsize);
}
// we failed - a call to IsValid() will return false
return false;
}
//==============================================================================
// Initializes vmaddr_, vmsize_, and slide_
void DynamicImage::CalculateMemoryAndVersionInfo() {
// unless we can process the header, ensure that calls to
// IsValid() will return false
vmaddr_ = 0;
vmsize_ = 0;
slide_ = 0;
version_ = 0;
// The function template above does all the real work.
if (Is64Bit())
FindTextSection<MachO64>(*this);
else
FindTextSection<MachO32>(*this);
}
void DynamicImage::Print() {
const char *path = GetFilePath();
if (!path) {
path = "(unknown)";
}
printf("%p: %s\n", GetLoadAddress(), path);
mach_header *header = GetMachHeader();
MachHeader(*header).Print();
printf("vmaddr\t\t: %p\n", reinterpret_cast<void*>(GetVMAddr()));
printf("vmsize\t\t: %d\n", GetVMSize());
printf("slide\t\t: %d\n", GetVMAddrSlide());
//==============================================================================
// The helper function template abstracts the 32/64-bit differences.
template<typename MachBits>
uint32_t GetFileTypeFromHeader(DynamicImage& image) {
typedef typename MachBits::mach_header_type mach_header_type;
const mach_header_type* header =
reinterpret_cast<const mach_header_type*>(&image.header_[0]);
return header->filetype;
}
uint32_t DynamicImage::GetFileType() {
if (Is64Bit())
return GetFileTypeFromHeader<MachO64>(*this);
return GetFileTypeFromHeader<MachO32>(*this);
}
#pragma mark -
@@ -215,113 +330,199 @@ void DynamicImage::Print() {
//==============================================================================
// Loads information about dynamically loaded code in the given task.
DynamicImages::DynamicImages(mach_port_t task)
: task_(task) {
: task_(task),
cpu_type_(DetermineTaskCPUType(task)),
image_list_() {
ReadImageInfoForTask();
}
template<typename MachBits>
static uint64_t LookupSymbol(const char* symbol_name,
const char* filename,
cpu_type_t cpu_type) {
typedef typename MachBits::nlist_type nlist_type;
nlist_type symbol_info[8] = {};
const char *symbolNames[2] = { symbol_name, "\0" };
nlist_type &list = symbol_info[0];
int invalidEntriesCount = breakpad_nlist(filename,
&list,
symbolNames,
cpu_type);
if(invalidEntriesCount != 0) {
return 0;
}
assert(list.n_value);
return list.n_value;
}
static SInt32 GetOSVersionInternal() {
SInt32 os_version = 0;
Gestalt(gestaltSystemVersion, &os_version);
return os_version;
}
static SInt32 GetOSVersion() {
static SInt32 os_version = GetOSVersionInternal();
return os_version;
}
static bool IsSnowLeopardOrLater() {
#if MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_6
return true;
#else
return GetOSVersion() >= 0x1060;
#endif
}
uint64_t DynamicImages::GetDyldAllImageInfosPointer() {
if (IsSnowLeopardOrLater()) {
task_dyld_info_data_t task_dyld_info;
mach_msg_type_number_t count = TASK_DYLD_INFO_COUNT;
if (task_info(task_, TASK_DYLD_INFO, (task_info_t)&task_dyld_info,
&count) != KERN_SUCCESS) {
return NULL;
}
return (uint64_t)task_dyld_info.all_image_info_addr;
} else {
const char *imageSymbolName = "_dyld_all_image_infos";
const char *dyldPath = "/usr/lib/dyld";
if (Is64Bit())
return LookupSymbol<MachO64>(imageSymbolName, dyldPath, cpu_type_);
return LookupSymbol<MachO32>(imageSymbolName, dyldPath, cpu_type_);
}
}
//==============================================================================
// This code was written using dyld_debug.c (from Darwin) as a guide.
void DynamicImages::ReadImageInfoForTask() {
struct nlist l[8];
memset(l, 0, sizeof(l) );
// First we lookup the address of the "_dyld_all_image_infos" struct
// which lives in "dyld". This structure contains information about all
// of the loaded dynamic images.
struct nlist &list = l[0];
list.n_un.n_name = const_cast<char *>("_dyld_all_image_infos");
nlist("/usr/lib/dyld", &list);
if (list.n_value) {
// Read the structure inside of dyld that contains information about
// loaded images. We're reading from the desired task's address space.
template<typename MachBits>
void ReadImageInfo(DynamicImages& images,
uint64_t image_list_address) {
typedef typename MachBits::dyld_image_info dyld_image_info;
typedef typename MachBits::dyld_all_image_infos dyld_all_image_infos;
typedef typename MachBits::mach_header_type mach_header_type;
// Here we make the assumption that dyld loaded at the same address in
// the crashed process vs. this one. This is an assumption made in
// "dyld_debug.c" and is said to be nearly always valid.
dyld_all_image_infos *dyldInfo = reinterpret_cast<dyld_all_image_infos*>
(ReadTaskMemory(task_,
reinterpret_cast<void*>(list.n_value),
sizeof(dyld_all_image_infos)));
// Read the structure inside of dyld that contains information about
// loaded images. We're reading from the desired task's address space.
if (dyldInfo) {
// number of loaded images
int count = dyldInfo->infoArrayCount;
// Here we make the assumption that dyld loaded at the same address in
// the crashed process vs. this one. This is an assumption made in
// "dyld_debug.c" and is said to be nearly always valid.
vector<uint8_t> dyld_all_info_bytes;
if (ReadTaskMemory(images.task_,
image_list_address,
sizeof(dyld_all_image_infos),
dyld_all_info_bytes) != KERN_SUCCESS)
return;
// Read an array of dyld_image_info structures each containing
// information about a loaded image.
dyld_image_info *infoArray = reinterpret_cast<dyld_image_info*>
(ReadTaskMemory(task_,
dyldInfo->infoArray,
count*sizeof(dyld_image_info)));
dyld_all_image_infos *dyldInfo =
reinterpret_cast<dyld_all_image_infos*>(&dyld_all_info_bytes[0]);
image_list_.reserve(count);
// number of loaded images
int count = dyldInfo->infoArrayCount;
for (int i = 0; i < count; ++i) {
dyld_image_info &info = infoArray[i];
// Read an array of dyld_image_info structures each containing
// information about a loaded image.
vector<uint8_t> dyld_info_array_bytes;
if (ReadTaskMemory(images.task_,
dyldInfo->infoArray,
count * sizeof(dyld_image_info),
dyld_info_array_bytes) != KERN_SUCCESS)
return;
// First read just the mach_header from the image in the task.
mach_header *header = reinterpret_cast<mach_header*>
(ReadTaskMemory(task_, info.load_address_, sizeof(mach_header)));
dyld_image_info *infoArray =
reinterpret_cast<dyld_image_info*>(&dyld_info_array_bytes[0]);
images.image_list_.reserve(count);
if (!header)
break; // bail on this dynamic image
// Now determine the total amount we really want to read based on the
// size of the load commands. We need the header plus all of the
// load commands.
unsigned int header_size = sizeof(mach_header) + header->sizeofcmds;
free(header);
for (int i = 0; i < count; ++i) {
dyld_image_info &info = infoArray[i];
header = reinterpret_cast<mach_header*>
(ReadTaskMemory(task_, info.load_address_, header_size));
// First read just the mach_header from the image in the task.
vector<uint8_t> mach_header_bytes;
if (ReadTaskMemory(images.task_,
info.load_address_,
sizeof(mach_header_type),
mach_header_bytes) != KERN_SUCCESS)
continue; // bail on this dynamic image
// Read the file name from the task's memory space.
char *file_path = NULL;
if (info.file_path_) {
// Although we're reading kMaxStringLength bytes, it's copied in the
// the DynamicImage constructor below with the correct string length,
// so it's not really wasting memory.
file_path = reinterpret_cast<char*>
(ReadTaskString(task_, info.file_path_));
}
// Create an object representing this image and add it to our list.
DynamicImage *new_image = new DynamicImage(header,
header_size,
info.load_address_,
file_path,
info.file_mod_date_,
task_);
mach_header_type *header =
reinterpret_cast<mach_header_type*>(&mach_header_bytes[0]);
if (new_image->IsValid()) {
image_list_.push_back(DynamicImageRef(new_image));
} else {
delete new_image;
}
if (file_path) {
free(file_path);
}
// Now determine the total amount necessary to read the header
// plus all of the load commands.
size_t header_size =
sizeof(mach_header_type) + header->sizeofcmds;
if (ReadTaskMemory(images.task_,
info.load_address_,
header_size,
mach_header_bytes) != KERN_SUCCESS)
continue;
header = reinterpret_cast<mach_header_type*>(&mach_header_bytes[0]);
// Read the file name from the task's memory space.
string file_path;
if (info.file_path_) {
// Although we're reading kMaxStringLength bytes, it's copied in the
// the DynamicImage constructor below with the correct string length,
// so it's not really wasting memory.
file_path = ReadTaskString(images.task_, info.file_path_);
}
// Create an object representing this image and add it to our list.
DynamicImage *new_image;
new_image = new DynamicImage(&mach_header_bytes[0],
header_size,
info.load_address_,
file_path,
info.file_mod_date_,
images.task_,
images.cpu_type_);
if (new_image->IsValid()) {
images.image_list_.push_back(DynamicImageRef(new_image));
} else {
delete new_image;
}
free(dyldInfo);
free(infoArray);
// sorts based on loading address
sort(image_list_.begin(), image_list_.end() );
}
}
// sorts based on loading address
sort(images.image_list_.begin(), images.image_list_.end());
// remove duplicates - this happens in certain strange cases
// You can see it in DashboardClient when Google Gadgets plugin
// is installed. Apple's crash reporter log and gdb "info shared"
// both show the same library multiple times at the same address
vector<DynamicImageRef>::iterator it = unique(images.image_list_.begin(),
images.image_list_.end());
images.image_list_.erase(it, images.image_list_.end());
}
void DynamicImages::ReadImageInfoForTask() {
uint64_t imageList = GetDyldAllImageInfosPointer();
if (imageList) {
if (Is64Bit())
ReadImageInfo<MachO64>(*this, imageList);
else
ReadImageInfo<MachO32>(*this, imageList);
}
}
//==============================================================================
DynamicImage *DynamicImages::GetExecutableImage() {
int executable_index = GetExecutableImageIndex();
if (executable_index >= 0) {
return GetImage(executable_index);
}
return NULL;
}
@@ -332,7 +533,7 @@ int DynamicImages::GetExecutableImageIndex() {
for (int i = 0; i < image_count; ++i) {
DynamicImage *image = GetImage(i);
if (image->GetMachHeader()->filetype == MH_EXECUTE) {
if (image->GetFileType() == MH_EXECUTE) {
return i;
}
}
@@ -340,4 +541,27 @@ int DynamicImages::GetExecutableImageIndex() {
return -1;
}
//==============================================================================
// static
cpu_type_t DynamicImages::DetermineTaskCPUType(task_t task) {
if (task == mach_task_self())
return GetNativeCPUType();
int mib[CTL_MAXNAME];
size_t mibLen = CTL_MAXNAME;
int err = sysctlnametomib("sysctl.proc_cputype", mib, &mibLen);
if (err == 0) {
assert(mibLen < CTL_MAXNAME);
pid_for_task(task, &mib[mibLen]);
mibLen += 1;
cpu_type_t cpu_type;
size_t cpuTypeSize = sizeof(cpu_type);
sysctl(mib, mibLen, &cpu_type, &cpuTypeSize, 0, 0);
return cpu_type;
}
return GetNativeCPUType();
}
} // namespace google_breakpad

View File

@@ -41,165 +41,158 @@
#include <mach-o/dyld.h>
#include <mach-o/loader.h>
#include <sys/types.h>
#include <string>
#include <vector>
namespace google_breakpad {
using std::string;
using std::vector;
//==============================================================================
// The memory layout of this struct matches the dyld_image_info struct
// defined in "dyld_gdb.h" in the darwin source.
typedef struct dyld_image_info {
struct mach_header *load_address_;
char *file_path_;
uintptr_t file_mod_date_;
} dyld_image_info;
typedef struct dyld_image_info32 {
uint32_t load_address_; // struct mach_header*
uint32_t file_path_; // char*
uint32_t file_mod_date_;
} dyld_image_info32;
typedef struct dyld_image_info64 {
uint64_t load_address_; // struct mach_header*
uint64_t file_path_; // char*
uint64_t file_mod_date_;
} dyld_image_info64;
//==============================================================================
// This is as defined in "dyld_gdb.h" in the darwin source.
// _dyld_all_image_infos (in dyld) is a structure of this type
// which will be used to determine which dynamic code has been loaded.
typedef struct dyld_all_image_infos {
typedef struct dyld_all_image_infos32 {
uint32_t version; // == 1 in Mac OS X 10.4
uint32_t infoArrayCount;
const struct dyld_image_info *infoArray;
void* notification;
uint32_t infoArray; // const struct dyld_image_info*
uint32_t notification;
bool processDetachedFromSharedRegion;
} dyld_all_image_infos;
} dyld_all_image_infos32;
//==============================================================================
// A simple wrapper for a mach_header
//
// This could be fleshed out with some more interesting methods.
class MachHeader {
public:
explicit MachHeader(const mach_header &header) : header_(header) {}
typedef struct dyld_all_image_infos64 {
uint32_t version; // == 1 in Mac OS X 10.4
uint32_t infoArrayCount;
uint64_t infoArray; // const struct dyld_image_info*
uint64_t notification;
bool processDetachedFromSharedRegion;
} dyld_all_image_infos64;
void Print() {
printf("magic\t\t: %4x\n", header_.magic);
printf("cputype\t\t: %d\n", header_.cputype);
printf("cpusubtype\t: %d\n", header_.cpusubtype);
printf("filetype\t: %d\n", header_.filetype);
printf("ncmds\t\t: %d\n", header_.ncmds);
printf("sizeofcmds\t: %d\n", header_.sizeofcmds);
printf("flags\t\t: %d\n", header_.flags);
}
// some typedefs to isolate 64/32 bit differences
#ifdef __LP64__
typedef mach_header_64 breakpad_mach_header;
typedef segment_command_64 breakpad_mach_segment_command;
#else
typedef mach_header breakpad_mach_header;
typedef segment_command breakpad_mach_segment_command;
#endif
mach_header header_;
};
// Helper functions to deal with 32-bit/64-bit Mach-O differences.
class DynamicImage;
template<typename MachBits>
bool FindTextSection(DynamicImage& image);
template<typename MachBits>
uint32_t GetFileTypeFromHeader(DynamicImage& image);
//==============================================================================
// Represents a single dynamically loaded mach-o image
class DynamicImage {
public:
DynamicImage(mach_header *header, // we take ownership
int header_size, // includes load commands
mach_header *load_address,
char *inFilePath,
DynamicImage(uint8_t *header, // data is copied
size_t header_size, // includes load commands
uint64_t load_address,
string file_path,
uintptr_t image_mod_date,
mach_port_t task)
: header_(header),
mach_port_t task,
cpu_type_t cpu_type)
: header_(header, header + header_size),
header_size_(header_size),
load_address_(load_address),
vmaddr_(0),
vmsize_(0),
slide_(0),
version_(0),
file_path_(file_path),
file_mod_date_(image_mod_date),
task_(task) {
InitializeFilePath(inFilePath);
CalculateMemoryInfo();
task_(task),
cpu_type_(cpu_type) {
CalculateMemoryAndVersionInfo();
}
~DynamicImage() {
if (file_path_) {
free(file_path_);
}
free(header_);
}
// Returns pointer to a local copy of the mach_header plus load commands
mach_header *GetMachHeader() {return header_;}
// Size of mach_header plus load commands
int GetHeaderSize() const {return header_size_;}
size_t GetHeaderSize() const {return header_.size();}
// Full path to mach-o binary
char *GetFilePath() {return file_path_;}
string GetFilePath() {return file_path_;}
uintptr_t GetModDate() const {return file_mod_date_;}
uint64_t GetModDate() const {return file_mod_date_;}
// Actual address where the image was loaded
mach_header *GetLoadAddress() const {return load_address_;}
uint64_t GetLoadAddress() const {return load_address_;}
// Address where the image should be loaded
uint32_t GetVMAddr() const {return vmaddr_;}
mach_vm_address_t GetVMAddr() const {return vmaddr_;}
// Difference between GetLoadAddress() and GetVMAddr()
ptrdiff_t GetVMAddrSlide() const {return slide_;}
// Size of the image
uint32_t GetVMSize() const {return vmsize_;}
mach_vm_size_t GetVMSize() const {return vmsize_;}
// Task owning this loaded image
mach_port_t GetTask() {return task_;}
// CPU type of the task
cpu_type_t GetCPUType() {return cpu_type_;}
// filetype from the Mach-O header.
uint32_t GetFileType();
// Return true if the task is a 64-bit architecture.
bool Is64Bit() { return (GetCPUType() & CPU_ARCH_ABI64) == CPU_ARCH_ABI64; }
uint32_t GetVersion() {return version_;}
// For sorting
bool operator<(const DynamicImage &inInfo) {
return GetLoadAddress() < inInfo.GetLoadAddress();
}
// Debugging
void Print();
private:
friend class DynamicImages;
// Sanity checking
bool IsValid() {return GetVMSize() != 0;}
// Makes local copy of file path to mach-o binary
void InitializeFilePath(char *inFilePath) {
if (inFilePath) {
size_t path_size = 1 + strlen(inFilePath);
file_path_ = reinterpret_cast<char*>(malloc(path_size));
strlcpy(file_path_, inFilePath, path_size);
} else {
file_path_ = NULL;
}
}
private:
DynamicImage(const DynamicImage &);
DynamicImage &operator=(const DynamicImage &);
friend class DynamicImages;
template<typename MachBits>
friend bool FindTextSection(DynamicImage& image);
template<typename MachBits>
friend uint32_t GetFileTypeFromHeader(DynamicImage& image);
// Initializes vmaddr_, vmsize_, and slide_
void CalculateMemoryInfo();
void CalculateMemoryAndVersionInfo();
#if 0 // currently not needed
// Copy constructor: we don't want this to be invoked,
// but here's the code in case we need to make it public some day.
DynamicImage(DynamicImage &inInfo)
: load_address_(inInfo.load_address_),
vmaddr_(inInfo.vmaddr_),
vmsize_(inInfo.vmsize_),
slide_(inInfo.slide_),
file_mod_date_(inInfo.file_mod_date_),
task_(inInfo.task_) {
// copy file path string
InitializeFilePath(inInfo.GetFilePath());
const vector<uint8_t> header_; // our local copy of the header
size_t header_size_; // mach_header plus load commands
uint64_t load_address_; // base address image is mapped into
mach_vm_address_t vmaddr_;
mach_vm_size_t vmsize_;
ptrdiff_t slide_;
uint32_t version_; // Dylib version
string file_path_; // path dyld used to load the image
uintptr_t file_mod_date_; // time_t of image file
// copy mach_header and load commands
header_ = reinterpret_cast<mach_header*>(malloc(inInfo.header_size_));
memcpy(header_, inInfo.header_, inInfo.header_size_);
header_size_ = inInfo.header_size_;
}
#endif
mach_header *header_; // our local copy of the header
int header_size_; // mach_header plus load commands
mach_header *load_address_; // base address image is mapped into
uint32_t vmaddr_;
uint32_t vmsize_;
ptrdiff_t slide_;
char *file_path_; // path dyld used to load the image
uintptr_t file_mod_date_; // time_t of image file
mach_port_t task_;
mach_port_t task_;
cpu_type_t cpu_type_; // CPU type of task_
};
//==============================================================================
@@ -211,13 +204,19 @@ class DynamicImage {
class DynamicImageRef {
public:
explicit DynamicImageRef(DynamicImage *inP) : p(inP) {}
DynamicImageRef(const DynamicImageRef &inRef) : p(inRef.p) {} // STL required
// The copy constructor is required by STL
DynamicImageRef(const DynamicImageRef &inRef) : p(inRef.p) {}
bool operator<(const DynamicImageRef &inRef) const {
return (*const_cast<DynamicImageRef*>(this)->p)
< (*const_cast<DynamicImageRef&>(inRef).p);
}
bool operator==(const DynamicImageRef &inInfo) const {
return (*const_cast<DynamicImageRef*>(this)->p).GetLoadAddress() ==
(*const_cast<DynamicImageRef&>(inInfo)).GetLoadAddress();
}
// Be just like DynamicImage*
DynamicImage *operator->() {return p;}
operator DynamicImage*() {return p;}
@@ -226,6 +225,11 @@ class DynamicImageRef {
DynamicImage *p;
};
// Helper function to deal with 32-bit/64-bit Mach-O differences.
class DynamicImages;
template<typename MachBits>
void ReadImageInfo(DynamicImages& images, uint64_t image_list_address);
//==============================================================================
// An object of type DynamicImages may be created to allow introspection of
// an arbitrary task's dynamically loaded mach-o binaries. This makes the
@@ -235,13 +239,13 @@ class DynamicImages {
explicit DynamicImages(mach_port_t task);
~DynamicImages() {
for (int i = 0; i < (int)image_list_.size(); ++i) {
for (int i = 0; i < GetImageCount(); ++i) {
delete image_list_[i];
}
}
// Returns the number of dynamically loaded mach-o images.
int GetImageCount() const {return image_list_.size();}
int GetImageCount() const {return static_cast<int>(image_list_.size());}
// Returns an individual image.
DynamicImage *GetImage(int i) {
@@ -258,35 +262,51 @@ class DynamicImages {
// Returns the task which we're looking at.
mach_port_t GetTask() const {return task_;}
// Debugging
void Print() {
for (int i = 0; i < (int)image_list_.size(); ++i) {
image_list_[i]->Print();
}
}
// CPU type of the task
cpu_type_t GetCPUType() {return cpu_type_;}
void TestPrint() {
for (int i = 0; i < (int)image_list_.size(); ++i) {
printf("dyld: %p: name = %s\n", _dyld_get_image_header(i),
_dyld_get_image_name(i) );
const mach_header *header = _dyld_get_image_header(i);
MachHeader(*header).Print();
}
// Return true if the task is a 64-bit architecture.
bool Is64Bit() { return (GetCPUType() & CPU_ARCH_ABI64) == CPU_ARCH_ABI64; }
// Determine the CPU type of the task being dumped.
static cpu_type_t DetermineTaskCPUType(task_t task);
// Get the native CPU type of this task.
static cpu_type_t GetNativeCPUType() {
#if defined(__i386__)
return CPU_TYPE_I386;
#elif defined(__x86_64__)
return CPU_TYPE_X86_64;
#elif defined(__ppc__)
return CPU_TYPE_POWERPC;
#elif defined(__ppc64__)
return CPU_TYPE_POWERPC64;
#else
#error "GetNativeCPUType not implemented for this architecture"
#endif
}
private:
template<typename MachBits>
friend void ReadImageInfo(DynamicImages& images, uint64_t image_list_address);
bool IsOurTask() {return task_ == mach_task_self();}
// Initialization
void ReadImageInfoForTask();
uint64_t GetDyldAllImageInfosPointer();
mach_port_t task_;
cpu_type_t cpu_type_; // CPU type of task_
vector<DynamicImageRef> image_list_;
};
// Returns a malloced block containing the contents of memory at a particular
// Fill bytes with the contents of memory at a particular
// location in another task.
void* ReadTaskMemory(task_port_t target_task, const void* address, size_t len);
kern_return_t ReadTaskMemory(task_port_t target_task,
const uint64_t address,
size_t length,
vector<uint8_t> &bytes);
} // namespace google_breakpad

View File

@@ -33,6 +33,7 @@
#include "client/mac/handler/exception_handler.h"
#include "client/mac/handler/minidump_generator.h"
#include "common/mac/macho_utilities.h"
#include "common/mac/scoped_task_suspend-inl.h"
#ifndef USE_PROTECTED_ALLOCATIONS
#define USE_PROTECTED_ALLOCATIONS 0
@@ -83,7 +84,7 @@ struct ExceptionReplyMessage {
// Only catch these three exceptions. The other ones are nebulously defined
// and may result in treating a non-fatal exception as fatal.
exception_mask_t s_exception_mask = EXC_MASK_BAD_ACCESS |
exception_mask_t s_exception_mask = EXC_MASK_BAD_ACCESS |
EXC_MASK_BAD_INSTRUCTION | EXC_MASK_ARITHMETIC | EXC_MASK_BREAKPOINT;
extern "C"
@@ -92,12 +93,15 @@ extern "C"
boolean_t exc_server(mach_msg_header_t *request,
mach_msg_header_t *reply);
// This symbol must be visible to dlsym() - see
// http://code.google.com/p/google-breakpad/issues/detail?id=345 for details.
kern_return_t catch_exception_raise(mach_port_t target_port,
mach_port_t failed_thread,
mach_port_t task,
exception_type_t exception,
exception_data_t code,
mach_msg_type_number_t code_count);
mach_msg_type_number_t code_count)
__attribute__((visibility("default")));
kern_return_t ForwardException(mach_port_t task,
mach_port_t failed_thread,
@@ -120,10 +124,10 @@ extern "C"
exception_data_t exception_code,
mach_msg_type_number_t code_count,
thread_state_flavor_t *target_flavor,
thread_state_t thread_state,
mach_msg_type_number_t thread_state_count,
thread_state_t thread_state,
mach_msg_type_number_t *thread_state_count);
thread_state_t in_thread_state,
mach_msg_type_number_t in_thread_state_count,
thread_state_t out_thread_state,
mach_msg_type_number_t *out_thread_state_count);
kern_return_t
exception_raise_state_identity(mach_port_t target_port,
@@ -133,24 +137,100 @@ extern "C"
exception_data_t exception_code,
mach_msg_type_number_t exception_code_count,
thread_state_flavor_t *target_flavor,
thread_state_t thread_state,
mach_msg_type_number_t thread_state_count,
thread_state_t thread_state,
mach_msg_type_number_t *thread_state_count);
thread_state_t in_thread_state,
mach_msg_type_number_t in_thread_state_count,
thread_state_t out_thread_state,
mach_msg_type_number_t *out_thread_state_count);
kern_return_t breakpad_exception_raise_state(mach_port_t exception_port,
exception_type_t exception,
const exception_data_t code,
mach_msg_type_number_t codeCnt,
int *flavor,
const thread_state_t old_state,
mach_msg_type_number_t old_stateCnt,
thread_state_t new_state,
mach_msg_type_number_t *new_stateCnt
);
kern_return_t breakpad_exception_raise_state_identity(mach_port_t exception_port,
mach_port_t thread,
mach_port_t task,
exception_type_t exception,
exception_data_t code,
mach_msg_type_number_t codeCnt,
int *flavor,
thread_state_t old_state,
mach_msg_type_number_t old_stateCnt,
thread_state_t new_state,
mach_msg_type_number_t *new_stateCnt
);
kern_return_t breakpad_exception_raise(mach_port_t port, mach_port_t failed_thread,
mach_port_t task,
exception_type_t exception,
exception_data_t code,
mach_msg_type_number_t code_count);
}
kern_return_t breakpad_exception_raise_state(mach_port_t exception_port,
exception_type_t exception,
const exception_data_t code,
mach_msg_type_number_t codeCnt,
int *flavor,
const thread_state_t old_state,
mach_msg_type_number_t old_stateCnt,
thread_state_t new_state,
mach_msg_type_number_t *new_stateCnt
)
{
return KERN_SUCCESS;
}
kern_return_t breakpad_exception_raise_state_identity(mach_port_t exception_port,
mach_port_t thread,
mach_port_t task,
exception_type_t exception,
exception_data_t code,
mach_msg_type_number_t codeCnt,
int *flavor,
thread_state_t old_state,
mach_msg_type_number_t old_stateCnt,
thread_state_t new_state,
mach_msg_type_number_t *new_stateCnt
)
{
return KERN_SUCCESS;
}
kern_return_t breakpad_exception_raise(mach_port_t port, mach_port_t failed_thread,
mach_port_t task,
exception_type_t exception,
exception_data_t code,
mach_msg_type_number_t code_count) {
if (task != mach_task_self()) {
return KERN_FAILURE;
}
return ForwardException(task, failed_thread, exception, code, code_count);
}
ExceptionHandler::ExceptionHandler(const string &dump_path,
FilterCallback filter,
MinidumpCallback callback,
void *callback_context,
bool install_handler)
bool install_handler,
const char *port_name)
: dump_path_(),
filter_(filter),
callback_(callback),
callback_context_(callback_context),
directCallback_(NULL),
handler_thread_(NULL),
handler_port_(0),
handler_port_(MACH_PORT_NULL),
previous_(NULL),
installed_exception_handler_(false),
is_in_teardown_(false),
@@ -159,6 +239,8 @@ ExceptionHandler::ExceptionHandler(const string &dump_path,
// This will update to the ID and C-string pointers
set_dump_path(dump_path);
MinidumpGenerator::GatherSystemInformation();
if (port_name)
crash_generation_client_.reset(new CrashGenerationClient(port_name));
Setup(install_handler);
}
@@ -173,7 +255,7 @@ ExceptionHandler::ExceptionHandler(DirectCallback callback,
callback_context_(callback_context),
directCallback_(callback),
handler_thread_(NULL),
handler_port_(0),
handler_port_(MACH_PORT_NULL),
previous_(NULL),
installed_exception_handler_(false),
is_in_teardown_(false),
@@ -187,7 +269,7 @@ ExceptionHandler::~ExceptionHandler() {
Teardown();
}
bool ExceptionHandler::WriteMinidump() {
bool ExceptionHandler::WriteMinidump(bool write_exception_stream) {
// If we're currently writing, just return
if (use_minidump_write_mutex_)
return false;
@@ -199,13 +281,15 @@ bool ExceptionHandler::WriteMinidump() {
if (pthread_mutex_lock(&minidump_write_mutex_) == 0) {
// Send an empty message to the handle port so that a minidump will
// be written
SendEmptyMachMessage();
SendMessageToHandlerThread(write_exception_stream ?
kWriteDumpWithExceptionMessage :
kWriteDumpMessage);
// Wait for the minidump writer to complete its writing. It will unlock
// the mutex when completed
pthread_mutex_lock(&minidump_write_mutex_);
}
use_minidump_write_mutex_ = false;
UpdateNextID();
return last_minidump_write_result_;
@@ -213,25 +297,73 @@ bool ExceptionHandler::WriteMinidump() {
// static
bool ExceptionHandler::WriteMinidump(const string &dump_path,
bool write_exception_stream,
MinidumpCallback callback,
void *callback_context) {
ExceptionHandler handler(dump_path, NULL, callback, callback_context, false);
return handler.WriteMinidump();
ExceptionHandler handler(dump_path, NULL, callback, callback_context, false,
NULL);
return handler.WriteMinidump(write_exception_stream);
}
// static
bool ExceptionHandler::WriteMinidumpForChild(mach_port_t child,
mach_port_t child_blamed_thread,
const string &dump_path,
MinidumpCallback callback,
void *callback_context) {
ScopedTaskSuspend suspend(child);
MinidumpGenerator generator(child, MACH_PORT_NULL);
string dump_id;
string dump_filename = generator.UniqueNameInDirectory(dump_path, &dump_id);
generator.SetExceptionInformation(EXC_BREAKPOINT,
#if defined (__i386__) || defined(__x86_64__)
EXC_I386_BPT,
#elif defined (__ppc__) || defined (__ppc64__)
EXC_PPC_BREAKPOINT,
#else
#error architecture not supported
#endif
0,
child_blamed_thread);
bool result = generator.Write(dump_filename.c_str());
if (callback) {
return callback(dump_path.c_str(), dump_id.c_str(),
callback_context, result);
}
return result;
}
bool ExceptionHandler::WriteMinidumpWithException(int exception_type,
int exception_code,
mach_port_t thread_name) {
int exception_subcode,
mach_port_t thread_name,
bool exit_after_write) {
bool result = false;
if (directCallback_) {
if (directCallback_(callback_context_,
exception_type,
exception_code,
exception_subcode,
thread_name) ) {
if (exception_type && exception_code)
if (exit_after_write)
_exit(exception_type);
}
} else if (IsOutOfProcess()) {
if (exception_type && exception_code) {
// If this is a real exception, give the filter (if any) a chance to
// decide if this should be sent.
if (filter_ && !filter_(callback_context_))
return false;
return crash_generation_client_->RequestDumpForException(
exception_type,
exception_code,
exception_subcode,
thread_name);
}
} else {
string minidump_id;
@@ -241,11 +373,12 @@ bool ExceptionHandler::WriteMinidumpWithException(int exception_type,
MinidumpGenerator md;
if (exception_type && exception_code) {
// If this is a real exception, give the filter (if any) a chance to
// decided if this should be sent
// decide if this should be sent.
if (filter_ && !filter_(callback_context_))
return false;
md.SetExceptionInformation(exception_type, exception_code, thread_name);
md.SetExceptionInformation(exception_type, exception_code,
exception_subcode, thread_name);
}
result = md.Write(next_minidump_path_c_);
@@ -256,14 +389,14 @@ bool ExceptionHandler::WriteMinidumpWithException(int exception_type,
// If the user callback returned true and we're handling an exception
// (rather than just writing out the file), then we should exit without
// forwarding the exception to the next handler.
if (callback_(dump_path_c_, next_minidump_id_c_, callback_context_,
if (callback_(dump_path_c_, next_minidump_id_c_, callback_context_,
result)) {
if (exception_type && exception_code)
if (exit_after_write)
_exit(exception_type);
}
}
}
return result;
}
@@ -272,20 +405,20 @@ kern_return_t ForwardException(mach_port_t task, mach_port_t failed_thread,
exception_data_t code,
mach_msg_type_number_t code_count) {
// At this time, we should have called Uninstall() on the exception handler
// so that the current exception ports are the ones that we should be
// so that the current exception ports are the ones that we should be
// forwarding to.
ExceptionParameters current;
current.count = EXC_TYPES_COUNT;
mach_port_t current_task = mach_task_self();
kern_return_t result = task_get_exception_ports(current_task,
kern_return_t result = task_get_exception_ports(current_task,
s_exception_mask,
current.masks,
&current.count,
current.ports,
current.behaviors,
current.flavors);
// Find the first exception handler that matches the exception
unsigned int found;
for (found = 0; found < current.count; ++found) {
@@ -357,6 +490,9 @@ kern_return_t catch_exception_raise(mach_port_t port, mach_port_t failed_thread,
exception_type_t exception,
exception_data_t code,
mach_msg_type_number_t code_count) {
if (task != mach_task_self()) {
return KERN_FAILURE;
}
return ForwardException(task, failed_thread, exception, code, code_count);
}
@@ -369,18 +505,19 @@ void *ExceptionHandler::WaitForMessage(void *exception_handler_class) {
// Wait for the exception info
while (1) {
receive.header.msgh_local_port = self->handler_port_;
receive.header.msgh_size = sizeof(receive);
receive.header.msgh_size = static_cast<mach_msg_size_t>(sizeof(receive));
kern_return_t result = mach_msg(&(receive.header),
MACH_RCV_MSG | MACH_RCV_LARGE, 0,
sizeof(receive), self->handler_port_,
receive.header.msgh_size,
self->handler_port_,
MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL);
if (result == KERN_SUCCESS) {
// Uninstall our handler so that we don't get in a loop if the process of
// writing out a minidump causes an exception. However, if the exception
// was caused by a fork'd process, don't uninstall things
if (receive.task.name == mach_task_self())
// If the actual exception code is zero, then we're calling this handler
// in a way that indicates that we want to either exit this thread or
// generate a minidump
@@ -389,7 +526,9 @@ void *ExceptionHandler::WaitForMessage(void *exception_handler_class) {
// to avoid misleading stacks. If appropriate they will be resumed
// afterwards.
if (!receive.exception) {
if (self->is_in_teardown_)
// Don't touch self, since this message could have been sent
// from its destructor.
if (receive.header.msgh_id == kShutdownMessage)
return NULL;
self->SuspendThreads();
@@ -399,11 +538,26 @@ void *ExceptionHandler::WaitForMessage(void *exception_handler_class) {
gBreakpadAllocator->Unprotect();
#endif
mach_port_t thread = MACH_PORT_NULL;
int exception_type = 0;
int exception_code = 0;
if (receive.header.msgh_id == kWriteDumpWithExceptionMessage) {
thread = receive.thread.name;
exception_type = EXC_BREAKPOINT;
#if defined (__i386__) || defined(__x86_64__)
exception_code = EXC_I386_BPT;
#elif defined (__ppc__) || defined (__ppc64__)
exception_code = EXC_PPC_BREAKPOINT;
#else
#error architecture not supported
#endif
}
// Write out the dump and save the result for later retrieval
self->last_minidump_write_result_ =
self->WriteMinidumpWithException(0, 0, 0);
self->UninstallHandler(false);
self->WriteMinidumpWithException(exception_type, exception_code,
0, thread,
false);
#if USE_PROTECTED_ALLOCATIONS
if(gBreakpadAllocator)
@@ -415,45 +569,56 @@ void *ExceptionHandler::WaitForMessage(void *exception_handler_class) {
if (self->use_minidump_write_mutex_)
pthread_mutex_unlock(&self->minidump_write_mutex_);
} else {
// When forking a child process with the exception handler installed,
// if the child crashes, it will send the exception back to the parent
// process. The check for task == self_task() ensures that only
// exceptions that occur in the parent process are caught and
// processed.
// process. The check for task == self_task() ensures that only
// exceptions that occur in the parent process are caught and
// processed. If the exception was not caused by this task, we
// still need to call into the exception server and have it return
// KERN_FAILURE (see breakpad_exception_raise) in order for the kernel
// to move onto the host exception handler for the child task
if (receive.task.name == mach_task_self()) {
self->SuspendThreads();
#if USE_PROTECTED_ALLOCATIONS
if(gBreakpadAllocator)
gBreakpadAllocator->Unprotect();
#endif
// Generate the minidump with the exception data.
self->WriteMinidumpWithException(receive.exception, receive.code[0],
receive.thread.name);
self->UninstallHandler(true);
int subcode = 0;
if (receive.exception == EXC_BAD_ACCESS && receive.code_count > 1)
subcode = receive.code[1];
// Generate the minidump with the exception data.
self->WriteMinidumpWithException(receive.exception, receive.code[0],
subcode, receive.thread.name, true);
#if USE_PROTECTED_ALLOCATIONS
// This may have become protected again within
// WriteMinidumpWithException, but it needs to be unprotected for
// UninstallHandler.
if(gBreakpadAllocator)
gBreakpadAllocator->Unprotect();
#endif
self->UninstallHandler(true);
#if USE_PROTECTED_ALLOCATIONS
if(gBreakpadAllocator)
gBreakpadAllocator->Protect();
#endif
// Pass along the exception to the server, which will setup the
// message and call catch_exception_raise() and put the KERN_SUCCESS
// into the reply.
ExceptionReplyMessage reply;
if (!exc_server(&receive.header, &reply.header))
exit(1);
// Send a reply and exit
result = mach_msg(&(reply.header), MACH_SEND_MSG,
reply.header.msgh_size, 0, MACH_PORT_NULL,
MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL);
} else {
// An exception occurred in a child process
}
// Pass along the exception to the server, which will setup the
// message and call breakpad_exception_raise() and put the return
// code into the reply.
ExceptionReplyMessage reply;
if (!exc_server(&receive.header, &reply.header))
exit(1);
// Send a reply and exit
result = mach_msg(&(reply.header), MACH_SEND_MSG,
reply.header.msgh_size, 0, MACH_PORT_NULL,
MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL);
}
}
}
@@ -465,11 +630,11 @@ bool ExceptionHandler::InstallHandler() {
try {
#if USE_PROTECTED_ALLOCATIONS
previous_ = new (gBreakpadAllocator->Allocate(sizeof(ExceptionParameters)) )
ExceptionParameters();
ExceptionParameters();
#else
previous_ = new ExceptionParameters();
#endif
}
catch (std::bad_alloc) {
return false;
@@ -478,14 +643,14 @@ bool ExceptionHandler::InstallHandler() {
// Save the current exception ports so that we can forward to them
previous_->count = EXC_TYPES_COUNT;
mach_port_t current_task = mach_task_self();
kern_return_t result = task_get_exception_ports(current_task,
kern_return_t result = task_get_exception_ports(current_task,
s_exception_mask,
previous_->masks,
&previous_->count,
previous_->ports,
previous_->behaviors,
previous_->flavors);
// Setup the exception ports on this task
if (result == KERN_SUCCESS)
result = task_set_exception_ports(current_task, s_exception_mask,
@@ -499,10 +664,10 @@ bool ExceptionHandler::InstallHandler() {
bool ExceptionHandler::UninstallHandler(bool in_exception) {
kern_return_t result = KERN_SUCCESS;
if (installed_exception_handler_) {
mach_port_t current_task = mach_task_self();
// Restore the previous ports
for (unsigned int i = 0; i < previous_->count; ++i) {
result = task_set_exception_ports(current_task, previous_->masks[i],
@@ -512,20 +677,20 @@ bool ExceptionHandler::UninstallHandler(bool in_exception) {
if (result != KERN_SUCCESS)
return false;
}
// this delete should NOT happen if an exception just occurred!
if (!in_exception) {
#if USE_PROTECTED_ALLOCATIONS
previous_->~ExceptionParameters();
#else
delete previous_;
delete previous_;
#endif
}
previous_ = NULL;
installed_exception_handler_ = false;
}
return result == KERN_SUCCESS;
}
@@ -552,7 +717,7 @@ bool ExceptionHandler::Setup(bool install_handler) {
pthread_attr_t attr;
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
int thread_create_result = pthread_create(&handler_thread_, &attr,
int thread_create_result = pthread_create(&handler_thread_, &attr,
&WaitForMessage, this);
pthread_attr_destroy(&attr);
result = thread_create_result ? KERN_FAILURE : KERN_SUCCESS;
@@ -567,9 +732,9 @@ bool ExceptionHandler::Teardown() {
if (!UninstallHandler(false))
return false;
// Send an empty message so that the handler_thread exits
if (SendEmptyMachMessage()) {
if (SendMessageToHandlerThread(kShutdownMessage)) {
mach_port_t current_task = mach_task_self();
result = mach_port_deallocate(current_task, handler_port_);
if (result != KERN_SUCCESS)
@@ -577,7 +742,7 @@ bool ExceptionHandler::Teardown() {
} else {
return false;
}
handler_thread_ = NULL;
handler_port_ = NULL;
pthread_mutex_destroy(&minidump_write_mutex_);
@@ -585,16 +750,25 @@ bool ExceptionHandler::Teardown() {
return result == KERN_SUCCESS;
}
bool ExceptionHandler::SendEmptyMachMessage() {
ExceptionMessage empty;
memset(&empty, 0, sizeof(empty));
empty.header.msgh_size = sizeof(empty) - sizeof(empty.padding);
empty.header.msgh_remote_port = handler_port_;
empty.header.msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND,
bool ExceptionHandler::SendMessageToHandlerThread(
HandlerThreadMessage message_id) {
ExceptionMessage msg;
memset(&msg, 0, sizeof(msg));
msg.header.msgh_id = message_id;
if (message_id == kWriteDumpMessage ||
message_id == kWriteDumpWithExceptionMessage) {
// Include this thread's port.
msg.thread.name = mach_thread_self();
msg.thread.disposition = MACH_MSG_TYPE_PORT_SEND;
msg.thread.type = MACH_MSG_PORT_DESCRIPTOR;
}
msg.header.msgh_size = sizeof(msg) - sizeof(msg.padding);
msg.header.msgh_remote_port = handler_port_;
msg.header.msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND,
MACH_MSG_TYPE_MAKE_SEND_ONCE);
kern_return_t result = mach_msg(&(empty.header),
kern_return_t result = mach_msg(&(msg.header),
MACH_SEND_MSG | MACH_SEND_TIMEOUT,
empty.header.msgh_size, 0, 0,
msg.header.msgh_size, 0, 0,
MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL);
return result == KERN_SUCCESS;
@@ -622,7 +796,7 @@ bool ExceptionHandler::SuspendThreads() {
return false;
}
}
return true;
}
@@ -640,7 +814,7 @@ bool ExceptionHandler::ResumeThreads() {
return false;
}
}
return true;
}

View File

@@ -40,12 +40,25 @@
#include <string>
#include "client/mac/crash_generation/crash_generation_client.h"
#include "processor/scoped_ptr.h"
namespace google_breakpad {
using std::string;
struct ExceptionParameters;
enum HandlerThreadMessage {
// Message ID telling the handler thread to write a dump.
kWriteDumpMessage = 0,
// Message ID telling the handler thread to write a dump and include
// an exception stream.
kWriteDumpWithExceptionMessage = 1,
// Message ID telling the handler thread to quit.
kShutdownMessage = 2
};
class ExceptionHandler {
public:
// A callback function to run before Breakpad performs any substantial
@@ -58,14 +71,14 @@ class ExceptionHandler {
// will immediately report the exception as unhandled without writing a
// minidump, allowing another handler the opportunity to handle it.
typedef bool (*FilterCallback)(void *context);
// A callback function to run after the minidump has been written.
// |minidump_id| is a unique id for the dump, so the minidump
// file is <dump_dir>/<minidump_id>.dmp.
// |context| is the value passed into the constructor.
// |context| is the value passed into the constructor.
// |succeeded| indicates whether a minidump file was successfully written.
// Return true if the exception was fully handled and breakpad should exit.
// Return false to allow any other exception handlers to process the
// Return false to allow any other exception handlers to process the
// exception.
typedef bool (*MinidumpCallback)(const char *dump_dir,
const char *minidump_id,
@@ -77,6 +90,7 @@ class ExceptionHandler {
typedef bool (*DirectCallback)( void *context,
int exception_type,
int exception_code,
int exception_subcode,
mach_port_t thread_name);
// Creates a new ExceptionHandler instance to handle writing minidumps.
@@ -85,9 +99,12 @@ class ExceptionHandler {
// If install_handler is true, then a minidump will be written whenever
// an unhandled exception occurs. If it is false, minidumps will only
// be written when WriteMinidump is called.
ExceptionHandler(const string &dump_path,
// If port_name is non-NULL, attempt to perform out-of-process dump generation
// If port_name is NULL, in-process dump generation will be used.
ExceptionHandler(const string &dump_path,
FilterCallback filter, MinidumpCallback callback,
void *callback_context, bool install_handler);
void *callback_context, bool install_handler,
const char *port_name);
// A special constructor if we want to bypass minidump writing and
// simply get a callback with the exception information.
@@ -104,38 +121,65 @@ class ExceptionHandler {
dump_path_c_ = dump_path_.c_str();
UpdateNextID(); // Necessary to put dump_path_ in next_minidump_path_.
}
// Writes a minidump immediately. This can be used to capture the
// execution state independently of a crash. Returns true on success.
bool WriteMinidump();
bool WriteMinidump() {
return WriteMinidump(false);
}
bool WriteMinidump(bool write_exception_stream);
// Convenience form of WriteMinidump which does not require an
// ExceptionHandler instance.
static bool WriteMinidump(const string &dump_path, MinidumpCallback callback,
void *callback_context) {
return WriteMinidump(dump_path, false, callback, callback_context);
}
static bool WriteMinidump(const string &dump_path,
bool write_exception_stream,
MinidumpCallback callback,
void *callback_context);
// Write a minidump of child immediately. This can be used to capture
// the execution state of a child process independently of a crash.
static bool WriteMinidumpForChild(mach_port_t child,
mach_port_t child_blamed_thread,
const std::string &dump_path,
MinidumpCallback callback,
void *callback_context);
// Returns whether out-of-process dump generation is used or not.
bool IsOutOfProcess() const {
return crash_generation_client_.get() != NULL;
}
private:
// Install the mach exception handler
bool InstallHandler();
// Uninstall the mach exception handler (if any)
bool UninstallHandler(bool in_exception);
// Setup the handler thread, and if |install_handler| is true, install the
// mach exception port handler
bool Setup(bool install_handler);
// Uninstall the mach exception handler (if any) and terminate the helper
// thread
bool Teardown();
// Send an "empty" mach message to the exception handler. Return true on
// success, false otherwise
bool SendEmptyMachMessage();
// Send a mach message to the exception handler. Return true on
// success, false otherwise.
bool SendMessageToHandlerThread(HandlerThreadMessage message_id);
// All minidump writing goes through this one routine
bool WriteMinidumpWithException(int exception_type, int exception_code,
mach_port_t thread_name);
bool WriteMinidumpWithException(int exception_type,
int exception_code,
int exception_subcode,
mach_port_t thread_name,
bool exit_after_write);
// When installed, this static function will be call from a newly created
// pthread with |this| as the argument
@@ -149,20 +193,20 @@ class ExceptionHandler {
// path of the next minidump to be written in next_minidump_path_.
void UpdateNextID();
// These functions will suspend/resume all threads except for the
// These functions will suspend/resume all threads except for the
// reporting thread
bool SuspendThreads();
bool ResumeThreads();
// The destination directory for the minidump
string dump_path_;
// The basename of the next minidump w/o extension
string next_minidump_id_;
// The full path to the next minidump to be written, including extension
string next_minidump_path_;
// Pointers to the UTF-8 versions of above
const char *dump_path_c_;
const char *next_minidump_id_c_;
@@ -191,20 +235,23 @@ class ExceptionHandler {
// True, if we've installed the exception handler
bool installed_exception_handler_;
// True, if we're in the process of uninstalling the exception handler and
// the thread.
bool is_in_teardown_;
// Save the last result of the last minidump
bool last_minidump_write_result_;
// A mutex for use when writing out a minidump that was requested on a
// A mutex for use when writing out a minidump that was requested on a
// thread other than the exception handler.
pthread_mutex_t minidump_write_mutex_;
// True, if we're using the mutext to indicate when mindump writing occurs
bool use_minidump_write_mutex_;
// Client for out-of-process dump generation.
scoped_ptr<CrashGenerationClient> crash_generation_client_;
};
} // namespace google_breakpad

File diff suppressed because it is too large Load Diff

View File

@@ -37,15 +37,32 @@
#include <string>
#include "client/minidump_file_writer.h"
#include "google_breakpad/common/minidump_format.h"
#include "common/memory.h"
#include "common/mac/macho_utilities.h"
#include "google_breakpad/common/minidump_format.h"
#include "dynamic_images.h"
#if MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_7
#define HAS_PPC_SUPPORT
#endif
namespace google_breakpad {
using std::string;
// Use the REGISTER_FROM_THREADSTATE to access a register name from the
// breakpad_thread_state_t structure.
#if __DARWIN_UNIX03 || TARGET_CPU_X86_64 || TARGET_CPU_PPC64
// In The 10.5 SDK Headers Apple prepended __ to the variable names in the
// i386_thread_state_t structure. There's no good way to tell what version of
// the SDK we're compiling against so we just toggle on the same preprocessor
// symbol Apple's headers use.
#define REGISTER_FROM_THREADSTATE(a, b) ((a)->__ ## b)
#else
#define REGISTER_FROM_THREADSTATE(a, b) (a->b)
#endif
// Creates a minidump file of the current process. If there is exception data,
// use SetExceptionInformation() to add this to the minidump. The minidump
// file is generated by the Write() function.
@@ -70,9 +87,11 @@ class MinidumpGenerator {
bool Write(const char *path);
// Specify some exception information, if applicable
void SetExceptionInformation(int type, int code, mach_port_t thread_name) {
void SetExceptionInformation(int type, int code, int subcode,
mach_port_t thread_name) {
exception_type_ = type;
exception_code_ = code;
exception_subcode_ = subcode;
exception_thread_ = thread_name;
}
@@ -85,6 +104,7 @@ class MinidumpGenerator {
// Stream writers
bool WriteThreadListStream(MDRawDirectory *thread_list_stream);
bool WriteMemoryListStream(MDRawDirectory *memory_list_stream);
bool WriteExceptionStream(MDRawDirectory *exception_stream);
bool WriteSystemInfoStream(MDRawDirectory *system_info_stream);
bool WriteModuleListStream(MDRawDirectory *module_list_stream);
@@ -93,7 +113,9 @@ class MinidumpGenerator {
// Helpers
u_int64_t CurrentPCForStack(breakpad_thread_state_data_t state);
bool WriteStackFromStartAddress(vm_address_t start_addr,
bool GetThreadState(thread_act_t target_thread, thread_state_t state,
mach_msg_type_number_t *count);
bool WriteStackFromStartAddress(mach_vm_address_t start_addr,
MDMemoryDescriptor *stack_location);
bool WriteStack(breakpad_thread_state_data_t state,
MDMemoryDescriptor *stack_location);
@@ -103,9 +125,33 @@ class MinidumpGenerator {
bool WriteCVRecord(MDRawModule *module, int cpu_type,
const char *module_path);
bool WriteModuleStream(unsigned int index, MDRawModule *module);
size_t CalculateStackSize(vm_address_t start_addr);
size_t CalculateStackSize(mach_vm_address_t start_addr);
int FindExecutableModule();
// Per-CPU implementations of these methods
#ifdef HAS_PPC_SUPPORT
bool WriteStackPPC(breakpad_thread_state_data_t state,
MDMemoryDescriptor *stack_location);
bool WriteContextPPC(breakpad_thread_state_data_t state,
MDLocationDescriptor *register_location);
u_int64_t CurrentPCForStackPPC(breakpad_thread_state_data_t state);
bool WriteStackPPC64(breakpad_thread_state_data_t state,
MDMemoryDescriptor *stack_location);
bool WriteContextPPC64(breakpad_thread_state_data_t state,
MDLocationDescriptor *register_location);
u_int64_t CurrentPCForStackPPC64(breakpad_thread_state_data_t state);
#endif
bool WriteStackX86(breakpad_thread_state_data_t state,
MDMemoryDescriptor *stack_location);
bool WriteContextX86(breakpad_thread_state_data_t state,
MDLocationDescriptor *register_location);
u_int64_t CurrentPCForStackX86(breakpad_thread_state_data_t state);
bool WriteStackX86_64(breakpad_thread_state_data_t state,
MDMemoryDescriptor *stack_location);
bool WriteContextX86_64(breakpad_thread_state_data_t state,
MDLocationDescriptor *register_location);
u_int64_t CurrentPCForStackX86_64(breakpad_thread_state_data_t state);
// disallow copy ctor and operator=
explicit MinidumpGenerator(const MinidumpGenerator &);
void operator=(const MinidumpGenerator &);
@@ -116,9 +162,13 @@ class MinidumpGenerator {
// Exception information
int exception_type_;
int exception_code_;
int exception_subcode_;
mach_port_t exception_thread_;
mach_port_t crashing_task_;
mach_port_t handler_thread_;
// CPU type of the task being dumped.
cpu_type_t cpu_type_;
// System information
static char build_string_[16];
@@ -128,6 +178,15 @@ class MinidumpGenerator {
// Information about dynamically loaded code
DynamicImages *dynamic_images_;
// PageAllocator makes it possible to allocate memory
// directly from the system, even while handling an exception.
mutable PageAllocator allocator_;
// Blocks of memory written to the dump. These are all currently
// written while writing the thread list stream, but saved here
// so a memory list stream can be written afterwards.
wasteful_vector<MDMemoryDescriptor> memory_blocks_;
};
} // namespace google_breakpad

View File

@@ -3,10 +3,24 @@
archiveVersion = 1;
classes = {
};
objectVersion = 42;
objectVersion = 46;
objects = {
/* Begin PBXBuildFile section */
8BFC813F11FF9A58002CB4DC /* libcrypto.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 8BFC813E11FF9A58002CB4DC /* libcrypto.dylib */; };
8BFC814411FF9A9C002CB4DC /* libcrypto.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 8BFC813E11FF9A58002CB4DC /* libcrypto.dylib */; };
8BFC814511FF9A9D002CB4DC /* libcrypto.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 8BFC813E11FF9A58002CB4DC /* libcrypto.dylib */; };
8BFC814811FF9B13002CB4DC /* libcrypto.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 8BFC813E11FF9A58002CB4DC /* libcrypto.dylib */; };
8BFC814911FF9B13002CB4DC /* libcrypto.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 8BFC813E11FF9A58002CB4DC /* libcrypto.dylib */; };
8BFC814A11FF9B13002CB4DC /* libcrypto.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 8BFC813E11FF9A58002CB4DC /* libcrypto.dylib */; };
8BFC814B11FF9B3F002CB4DC /* SenTestingKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F9721FA10E8B0E2300D7E813 /* SenTestingKit.framework */; };
8BFC814C11FF9B3F002CB4DC /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F9721F6B0E8B0D7000D7E813 /* Cocoa.framework */; };
8BFC81A211FF9C2E002CB4DC /* CPlusTest.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8BFC819211FF9C23002CB4DC /* CPlusTest.framework */; };
8BFC81A311FF9C2F002CB4DC /* CPlusTest.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8BFC819211FF9C23002CB4DC /* CPlusTest.framework */; };
8BFC81AD11FF9C8A002CB4DC /* breakpad_nlist_64.cc in Sources */ = {isa = PBXBuildFile; fileRef = F98208A10DB32CAE0017AECA /* breakpad_nlist_64.cc */; };
8BFC81AE11FF9C8C002CB4DC /* breakpad_nlist_64.cc in Sources */ = {isa = PBXBuildFile; fileRef = F98208A10DB32CAE0017AECA /* breakpad_nlist_64.cc */; };
8BFC81AF11FF9C8C002CB4DC /* breakpad_nlist_64.cc in Sources */ = {isa = PBXBuildFile; fileRef = F98208A10DB32CAE0017AECA /* breakpad_nlist_64.cc */; };
8BFC81B011FF9C8D002CB4DC /* breakpad_nlist_64.cc in Sources */ = {isa = PBXBuildFile; fileRef = F98208A10DB32CAE0017AECA /* breakpad_nlist_64.cc */; };
9B35FF5A0B267D5F008DE8C7 /* convert_UTF.c in Sources */ = {isa = PBXBuildFile; fileRef = 9B35FF560B267D5F008DE8C7 /* convert_UTF.c */; };
9B35FF5B0B267D5F008DE8C7 /* string_conversion.cc in Sources */ = {isa = PBXBuildFile; fileRef = 9B35FF580B267D5F008DE8C7 /* string_conversion.cc */; };
9B37CEEC0AF98ECD00FA4BD4 /* CoreFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9B37CEEB0AF98ECD00FA4BD4 /* CoreFoundation.framework */; };
@@ -49,6 +63,24 @@
D2F6511E0BEF973600920385 /* macho_id.cc in Sources */ = {isa = PBXBuildFile; fileRef = D2F650FC0BEF947200920385 /* macho_id.cc */; };
D2F6511F0BEF973900920385 /* macho_utilities.cc in Sources */ = {isa = PBXBuildFile; fileRef = D2F650FE0BEF947200920385 /* macho_utilities.cc */; };
D2F651210BEF975400920385 /* macho_walker.cc in Sources */ = {isa = PBXBuildFile; fileRef = D2F6510C0BEF94EB00920385 /* macho_walker.cc */; };
F93A887D0E8B4C8C0026AF89 /* macho_walker.cc in Sources */ = {isa = PBXBuildFile; fileRef = D2F6510C0BEF94EB00920385 /* macho_walker.cc */; };
F93A887E0E8B4C8C0026AF89 /* macho_id.cc in Sources */ = {isa = PBXBuildFile; fileRef = D2F650FC0BEF947200920385 /* macho_id.cc */; };
F93A887F0E8B4C8C0026AF89 /* macho_utilities.cc in Sources */ = {isa = PBXBuildFile; fileRef = D2F650FE0BEF947200920385 /* macho_utilities.cc */; };
F93A88800E8B4C8C0026AF89 /* file_id.cc in Sources */ = {isa = PBXBuildFile; fileRef = D2F650FA0BEF947200920385 /* file_id.cc */; };
F93A88860E8B4C9A0026AF89 /* dwarftests.mm in Sources */ = {isa = PBXBuildFile; fileRef = F9721F310E8B07E800D7E813 /* dwarftests.mm */; };
F93A88870E8B4C9A0026AF89 /* dump_syms.mm in Sources */ = {isa = PBXBuildFile; fileRef = F9721F390E8B0D0D00D7E813 /* dump_syms.mm */; };
F93A88880E8B4C9A0026AF89 /* bytereader.cc in Sources */ = {isa = PBXBuildFile; fileRef = F9721F760E8B0DC700D7E813 /* bytereader.cc */; };
F93A88890E8B4C9A0026AF89 /* dwarf2reader.cc in Sources */ = {isa = PBXBuildFile; fileRef = F9721F770E8B0DC700D7E813 /* dwarf2reader.cc */; };
F93A888A0E8B4C9A0026AF89 /* functioninfo.cc in Sources */ = {isa = PBXBuildFile; fileRef = F9721F780E8B0DC700D7E813 /* functioninfo.cc */; };
F93A888B0E8B4C9A0026AF89 /* md5.c in Sources */ = {isa = PBXBuildFile; fileRef = F9721FA80E8B0E4800D7E813 /* md5.c */; };
F9721F6C0E8B0D7000D7E813 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F9721F6B0E8B0D7000D7E813 /* Cocoa.framework */; };
F9721FA20E8B0E2300D7E813 /* SenTestingKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F9721FA10E8B0E2300D7E813 /* SenTestingKit.framework */; };
F982089C0DB3280D0017AECA /* breakpad_nlist_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = F982089B0DB3280D0017AECA /* breakpad_nlist_test.cc */; };
F98208A30DB32CAE0017AECA /* breakpad_nlist_64.cc in Sources */ = {isa = PBXBuildFile; fileRef = F98208A10DB32CAE0017AECA /* breakpad_nlist_64.cc */; };
F9AE5B390DBFDBDB00505983 /* dynamic_images.cc in Sources */ = {isa = PBXBuildFile; fileRef = D2F651070BEF949A00920385 /* dynamic_images.cc */; };
F9AE5B3A0DBFDBDB00505983 /* DynamicImagesTests.cc in Sources */ = {isa = PBXBuildFile; fileRef = F9C5A4210DB82DD800209C76 /* DynamicImagesTests.cc */; };
F9B34E870DBC1E1600306484 /* dynamic_images.cc in Sources */ = {isa = PBXBuildFile; fileRef = D2F651070BEF949A00920385 /* dynamic_images.cc */; };
F9C5A4220DB82DD800209C76 /* DynamicImagesTests.cc in Sources */ = {isa = PBXBuildFile; fileRef = F9C5A4210DB82DD800209C76 /* DynamicImagesTests.cc */; };
/* End PBXBuildFile section */
/* Begin PBXCopyFilesBuildPhase section */
@@ -76,12 +108,18 @@
/* End PBXCopyFilesBuildPhase section */
/* Begin PBXFileReference section */
8BFC812011FF99D5002CB4DC /* Breakpad.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Breakpad.xcconfig; path = ../../../common/mac/Breakpad.xcconfig; sourceTree = SOURCE_ROOT; };
8BFC812111FF99D5002CB4DC /* BreakpadDebug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = BreakpadDebug.xcconfig; path = ../../../common/mac/BreakpadDebug.xcconfig; sourceTree = SOURCE_ROOT; };
8BFC812211FF99D5002CB4DC /* BreakpadRelease.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = BreakpadRelease.xcconfig; path = ../../../common/mac/BreakpadRelease.xcconfig; sourceTree = SOURCE_ROOT; };
8BFC813E11FF9A58002CB4DC /* libcrypto.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libcrypto.dylib; path = usr/lib/libcrypto.dylib; sourceTree = SDKROOT; };
8BFC815411FF9B7F002CB4DC /* Carbon.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Carbon.framework; path = System/Library/Frameworks/Carbon.framework; sourceTree = SDKROOT; };
8BFC819211FF9C23002CB4DC /* CPlusTest.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CPlusTest.framework; path = Library/Frameworks/CPlusTest.framework; sourceTree = DEVELOPER_DIR; };
8DD76F6C0486A84900D96B5E /* generator_test */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = generator_test; sourceTree = BUILT_PRODUCTS_DIR; };
9B35FF560B267D5F008DE8C7 /* convert_UTF.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = convert_UTF.c; path = ../../../common/convert_UTF.c; sourceTree = SOURCE_ROOT; };
9B35FF570B267D5F008DE8C7 /* convert_UTF.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = convert_UTF.h; path = ../../../common/convert_UTF.h; sourceTree = SOURCE_ROOT; };
9B35FF580B267D5F008DE8C7 /* string_conversion.cc */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = string_conversion.cc; path = ../../../common/string_conversion.cc; sourceTree = SOURCE_ROOT; };
9B35FF590B267D5F008DE8C7 /* string_conversion.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = string_conversion.h; path = ../../../common/string_conversion.h; sourceTree = SOURCE_ROOT; };
9B37CEEB0AF98ECD00FA4BD4 /* CoreFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreFoundation.framework; path = /System/Library/Frameworks/CoreFoundation.framework; sourceTree = "<absolute>"; };
9B37CEEB0AF98ECD00FA4BD4 /* CoreFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreFoundation.framework; path = System/Library/Frameworks/CoreFoundation.framework; sourceTree = SDKROOT; };
9B7CA84E0B1297F200CD3A1D /* unit_test */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = unit_test; sourceTree = BUILT_PRODUCTS_DIR; };
9B7CA8530B12989000CD3A1D /* minidump_file_writer_unittest.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = minidump_file_writer_unittest.cc; path = ../../minidump_file_writer_unittest.cc; sourceTree = "<group>"; };
9BD82A9B0B00267E0055103E /* handler_test */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = handler_test; sourceTree = BUILT_PRODUCTS_DIR; };
@@ -106,6 +144,30 @@
D2F651080BEF949A00920385 /* dynamic_images.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = dynamic_images.h; sourceTree = "<group>"; };
D2F6510C0BEF94EB00920385 /* macho_walker.cc */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = macho_walker.cc; path = ../../../common/mac/macho_walker.cc; sourceTree = SOURCE_ROOT; };
D2F6510D0BEF94EB00920385 /* macho_walker.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = macho_walker.h; path = ../../../common/mac/macho_walker.h; sourceTree = SOURCE_ROOT; };
F917C4F70E03265A00F86017 /* breakpad_exc_server.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = breakpad_exc_server.c; sourceTree = "<group>"; };
F917C4F80E03265A00F86017 /* breakpad_exc_server.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = breakpad_exc_server.h; sourceTree = "<group>"; };
F93A88750E8B4C700026AF89 /* octestcases.octest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = octestcases.octest; sourceTree = BUILT_PRODUCTS_DIR; };
F93A88760E8B4C700026AF89 /* obj-cTestCases-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "obj-cTestCases-Info.plist"; sourceTree = "<group>"; };
F9721F300E8B07E800D7E813 /* dwarftests.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = dwarftests.h; sourceTree = "<group>"; };
F9721F310E8B07E800D7E813 /* dwarftests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = dwarftests.mm; sourceTree = "<group>"; };
F9721F380E8B0CFC00D7E813 /* dump_syms.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = dump_syms.h; path = ../../../common/mac/dump_syms.h; sourceTree = SOURCE_ROOT; };
F9721F390E8B0D0D00D7E813 /* dump_syms.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = dump_syms.mm; path = ../../../common/mac/dump_syms.mm; sourceTree = SOURCE_ROOT; };
F9721F6B0E8B0D7000D7E813 /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = System/Library/Frameworks/Cocoa.framework; sourceTree = SDKROOT; };
F9721F760E8B0DC700D7E813 /* bytereader.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = bytereader.cc; path = ../../../common/dwarf/bytereader.cc; sourceTree = SOURCE_ROOT; };
F9721F770E8B0DC700D7E813 /* dwarf2reader.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = dwarf2reader.cc; path = ../../../common/dwarf/dwarf2reader.cc; sourceTree = SOURCE_ROOT; };
F9721F780E8B0DC700D7E813 /* functioninfo.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = functioninfo.cc; path = ../../../common/dwarf/functioninfo.cc; sourceTree = SOURCE_ROOT; };
F9721FA10E8B0E2300D7E813 /* SenTestingKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SenTestingKit.framework; path = Library/Frameworks/SenTestingKit.framework; sourceTree = DEVELOPER_DIR; };
F9721FA80E8B0E4800D7E813 /* md5.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = md5.c; path = ../../../common/md5.c; sourceTree = SOURCE_ROOT; };
F982089A0DB3280D0017AECA /* breakpad_nlist_test.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = breakpad_nlist_test.h; sourceTree = "<group>"; };
F982089B0DB3280D0017AECA /* breakpad_nlist_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = breakpad_nlist_test.cc; sourceTree = "<group>"; };
F98208A10DB32CAE0017AECA /* breakpad_nlist_64.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = breakpad_nlist_64.cc; sourceTree = "<group>"; };
F98208A20DB32CAE0017AECA /* breakpad_nlist_64.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = breakpad_nlist_64.h; sourceTree = "<group>"; };
F9AE19B50DB040E300C98454 /* minidump_tests32-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "minidump_tests32-Info.plist"; sourceTree = "<group>"; };
F9AE19C30DB04A9500C98454 /* minidump_tests64.cptest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = minidump_tests64.cptest; sourceTree = BUILT_PRODUCTS_DIR; };
F9AE5B330DBFDBA300505983 /* minidump_tests32.cptest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = minidump_tests32.cptest; sourceTree = BUILT_PRODUCTS_DIR; };
F9AE5B340DBFDBA300505983 /* minidump_tests64-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "minidump_tests64-Info.plist"; sourceTree = "<group>"; };
F9C5A4200DB82DD800209C76 /* DynamicImagesTests.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DynamicImagesTests.h; sourceTree = "<group>"; };
F9C5A4210DB82DD800209C76 /* DynamicImagesTests.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DynamicImagesTests.cc; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
@@ -114,6 +176,7 @@
buildActionMask = 2147483647;
files = (
9B37CEEC0AF98ECD00FA4BD4 /* CoreFoundation.framework in Frameworks */,
8BFC813F11FF9A58002CB4DC /* libcrypto.dylib in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -121,6 +184,7 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
8BFC814511FF9A9D002CB4DC /* libcrypto.dylib in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -129,6 +193,37 @@
buildActionMask = 2147483647;
files = (
9BD82AC10B0029DF0055103E /* CoreFoundation.framework in Frameworks */,
8BFC814411FF9A9C002CB4DC /* libcrypto.dylib in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
F93A88720E8B4C700026AF89 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
8BFC814A11FF9B13002CB4DC /* libcrypto.dylib in Frameworks */,
8BFC814B11FF9B3F002CB4DC /* SenTestingKit.framework in Frameworks */,
8BFC814C11FF9B3F002CB4DC /* Cocoa.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
F9AE19C00DB04A9500C98454 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
8BFC814811FF9B13002CB4DC /* libcrypto.dylib in Frameworks */,
8BFC81A211FF9C2E002CB4DC /* CPlusTest.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
F9AE5B300DBFDBA300505983 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
F9721F6C0E8B0D7000D7E813 /* Cocoa.framework in Frameworks */,
F9721FA20E8B0E2300D7E813 /* SenTestingKit.framework in Frameworks */,
8BFC814911FF9B13002CB4DC /* libcrypto.dylib in Frameworks */,
8BFC81A311FF9C2F002CB4DC /* CPlusTest.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -138,6 +233,19 @@
08FB7794FE84155DC02AAC07 /* MinidumpWriter */ = {
isa = PBXGroup;
children = (
8BFC812011FF99D5002CB4DC /* Breakpad.xcconfig */,
8BFC812111FF99D5002CB4DC /* BreakpadDebug.xcconfig */,
8BFC812211FF99D5002CB4DC /* BreakpadRelease.xcconfig */,
F9721FA80E8B0E4800D7E813 /* md5.c */,
F9721F760E8B0DC700D7E813 /* bytereader.cc */,
F9721F770E8B0DC700D7E813 /* dwarf2reader.cc */,
F9721F780E8B0DC700D7E813 /* functioninfo.cc */,
F9721F390E8B0D0D00D7E813 /* dump_syms.mm */,
F9721F380E8B0CFC00D7E813 /* dump_syms.h */,
F917C4F70E03265A00F86017 /* breakpad_exc_server.c */,
F917C4F80E03265A00F86017 /* breakpad_exc_server.h */,
F98208A10DB32CAE0017AECA /* breakpad_nlist_64.cc */,
F98208A20DB32CAE0017AECA /* breakpad_nlist_64.h */,
D2F6510C0BEF94EB00920385 /* macho_walker.cc */,
D2F6510D0BEF94EB00920385 /* macho_walker.h */,
D2F651070BEF949A00920385 /* dynamic_images.cc */,
@@ -148,10 +256,14 @@
D2F650FD0BEF947200920385 /* macho_id.h */,
D2F650FE0BEF947200920385 /* macho_utilities.cc */,
D2F650FF0BEF947200920385 /* macho_utilities.h */,
F9C5A41F0DB82DB000209C76 /* testcases */,
9BD82C040B0133420055103E /* Breakpad */,
08FB7795FE84155DC02AAC07 /* Source */,
9B37CEEA0AF98EB600FA4BD4 /* Frameworks */,
1AB674ADFE9D54B511CA2CBB /* Products */,
F9AE19B50DB040E300C98454 /* minidump_tests32-Info.plist */,
F9AE5B340DBFDBA300505983 /* minidump_tests64-Info.plist */,
F93A88760E8B4C700026AF89 /* obj-cTestCases-Info.plist */,
);
name = MinidumpWriter;
sourceTree = "<group>";
@@ -172,6 +284,9 @@
8DD76F6C0486A84900D96B5E /* generator_test */,
9BD82A9B0B00267E0055103E /* handler_test */,
9B7CA84E0B1297F200CD3A1D /* unit_test */,
F9AE19C30DB04A9500C98454 /* minidump_tests64.cptest */,
F9AE5B330DBFDBA300505983 /* minidump_tests32.cptest */,
F93A88750E8B4C700026AF89 /* octestcases.octest */,
);
name = Products;
sourceTree = "<group>";
@@ -179,7 +294,12 @@
9B37CEEA0AF98EB600FA4BD4 /* Frameworks */ = {
isa = PBXGroup;
children = (
8BFC813E11FF9A58002CB4DC /* libcrypto.dylib */,
8BFC815411FF9B7F002CB4DC /* Carbon.framework */,
F9721FA10E8B0E2300D7E813 /* SenTestingKit.framework */,
F9721F6B0E8B0D7000D7E813 /* Cocoa.framework */,
9B37CEEB0AF98ECD00FA4BD4 /* CoreFoundation.framework */,
8BFC819211FF9C23002CB4DC /* CPlusTest.framework */,
);
name = Frameworks;
sourceTree = "<group>";
@@ -204,6 +324,19 @@
name = Breakpad;
sourceTree = "<group>";
};
F9C5A41F0DB82DB000209C76 /* testcases */ = {
isa = PBXGroup;
children = (
F982089A0DB3280D0017AECA /* breakpad_nlist_test.h */,
F982089B0DB3280D0017AECA /* breakpad_nlist_test.cc */,
F9C5A4200DB82DD800209C76 /* DynamicImagesTests.h */,
F9C5A4210DB82DD800209C76 /* DynamicImagesTests.cc */,
F9721F300E8B07E800D7E813 /* dwarftests.h */,
F9721F310E8B07E800D7E813 /* dwarftests.mm */,
);
path = testcases;
sourceTree = "<group>";
};
/* End PBXGroup section */
/* Begin PBXNativeTarget section */
@@ -257,23 +390,148 @@
productReference = 9BD82A9B0B00267E0055103E /* handler_test */;
productType = "com.apple.product-type.tool";
};
F93A88740E8B4C700026AF89 /* obj-c_TestCases */ = {
isa = PBXNativeTarget;
buildConfigurationList = F93A88790E8B4C700026AF89 /* Build configuration list for PBXNativeTarget "obj-c_TestCases" */;
buildPhases = (
F93A88700E8B4C700026AF89 /* Resources */,
F93A88710E8B4C700026AF89 /* Sources */,
F93A88720E8B4C700026AF89 /* Frameworks */,
F93A88730E8B4C700026AF89 /* ShellScript */,
);
buildRules = (
);
dependencies = (
);
name = "obj-c_TestCases";
productName = octestcases;
productReference = F93A88750E8B4C700026AF89 /* octestcases.octest */;
productType = "com.apple.product-type.bundle";
};
F9AE19C20DB04A9500C98454 /* minidump_tests64 */ = {
isa = PBXNativeTarget;
buildConfigurationList = F9AE19C70DB04AA200C98454 /* Build configuration list for PBXNativeTarget "minidump_tests64" */;
buildPhases = (
F9AE19BE0DB04A9500C98454 /* Resources */,
F9AE19BF0DB04A9500C98454 /* Sources */,
F9AE19C00DB04A9500C98454 /* Frameworks */,
F9AE19C10DB04A9500C98454 /* ShellScript */,
);
buildRules = (
);
dependencies = (
);
name = minidump_tests64;
productName = minidump_tests;
productReference = F9AE19C30DB04A9500C98454 /* minidump_tests64.cptest */;
productType = "com.apple.product-type.bundle";
};
F9AE5B320DBFDBA300505983 /* minidump_tests32 */ = {
isa = PBXNativeTarget;
buildConfigurationList = F9AE5B380DBFDBA300505983 /* Build configuration list for PBXNativeTarget "minidump_tests32" */;
buildPhases = (
F9AE5B2E0DBFDBA300505983 /* Resources */,
F9AE5B2F0DBFDBA300505983 /* Sources */,
F9AE5B300DBFDBA300505983 /* Frameworks */,
F9AE5B310DBFDBA300505983 /* ShellScript */,
);
buildRules = (
);
dependencies = (
);
name = minidump_tests32;
productName = Untitled;
productReference = F9AE5B330DBFDBA300505983 /* minidump_tests32.cptest */;
productType = "com.apple.product-type.bundle";
};
/* End PBXNativeTarget section */
/* Begin PBXProject section */
08FB7793FE84155DC02AAC07 /* Project object */ = {
isa = PBXProject;
buildConfigurationList = 1DEB923508733DC60010E9CD /* Build configuration list for PBXProject "minidump_test" */;
compatibilityVersion = "Xcode 3.2";
hasScannedForEncodings = 1;
mainGroup = 08FB7794FE84155DC02AAC07 /* MinidumpWriter */;
projectDirPath = "";
projectRoot = "";
targets = (
8DD76F620486A84900D96B5E /* generator_test */,
9BD82A9A0B00267E0055103E /* handler_test */,
9B7CA84D0B1297F200CD3A1D /* unit_test */,
F9AE19C20DB04A9500C98454 /* minidump_tests64 */,
F9AE5B320DBFDBA300505983 /* minidump_tests32 */,
F93A88740E8B4C700026AF89 /* obj-c_TestCases */,
);
};
/* End PBXProject section */
/* Begin PBXResourcesBuildPhase section */
F93A88700E8B4C700026AF89 /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
F9AE19BE0DB04A9500C98454 /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
F9AE5B2E0DBFDBA300505983 /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXResourcesBuildPhase section */
/* Begin PBXShellScriptBuildPhase section */
F93A88730E8B4C700026AF89 /* ShellScript */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
);
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "# Run the unit tests in this test bundle.\n\"${SYSTEM_DEVELOPER_DIR}/Tools/RunUnitTests\"\n";
};
F9AE19C10DB04A9500C98454 /* ShellScript */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
);
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "# Run the unit tests in this test bundle.\n\"${SYSTEM_DEVELOPER_DIR}/Tools/RunUnitTests\"\n# Run gcov on the framework getting tested\nif [ \"${CONFIGURATION}\" = 'Coverage' ];\nthen\n FRAMEWORK_NAME=minidump_tests64\n FRAMEWORK_OBJ_DIR=${OBJROOT}/${PROJECT_NAME}.build/${CONFIGURATION}/${FRAMEWORK_NAME}.build/Objects-normal/${NATIVE_ARCH_ACTUAL}\n mkdir -p coverage\n pushd coverage\n echo find ${OBJROOT} -name *.gcda -exec gcov -o ${FRAMEWORK_OBJ_DIR} {} \\;\n find ${OBJROOT} -name *.gcda -exec gcov -o ${FRAMEWORK_OBJ_DIR} {} \\;\n popd\nfi ";
};
F9AE5B310DBFDBA300505983 /* ShellScript */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
);
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "# Run the unit tests in this test bundle.\n\"${SYSTEM_DEVELOPER_DIR}/Tools/RunUnitTests\"\n\n";
};
/* End PBXShellScriptBuildPhase section */
/* Begin PBXSourcesBuildPhase section */
8DD76F640486A84900D96B5E /* Sources */ = {
isa = PBXSourcesBuildPhase;
@@ -291,6 +549,7 @@
D2F6510E0BEF94EB00920385 /* macho_walker.cc in Sources */,
D2F651110BEF951700920385 /* string_conversion.cc in Sources */,
D2F651150BEF953000920385 /* convert_UTF.c in Sources */,
8BFC81B011FF9C8D002CB4DC /* breakpad_nlist_64.cc in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -302,6 +561,7 @@
9B7CA8550B1298A100CD3A1D /* minidump_file_writer.cc in Sources */,
9BC1D2940B336F2300F2A2B4 /* convert_UTF.c in Sources */,
9BC1D2950B336F2500F2A2B4 /* string_conversion.cc in Sources */,
8BFC81AE11FF9C8C002CB4DC /* breakpad_nlist_64.cc in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -321,6 +581,45 @@
D2F6511E0BEF973600920385 /* macho_id.cc in Sources */,
D2F6511F0BEF973900920385 /* macho_utilities.cc in Sources */,
D2F651210BEF975400920385 /* macho_walker.cc in Sources */,
8BFC81AF11FF9C8C002CB4DC /* breakpad_nlist_64.cc in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
F93A88710E8B4C700026AF89 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
F93A88860E8B4C9A0026AF89 /* dwarftests.mm in Sources */,
F93A88870E8B4C9A0026AF89 /* dump_syms.mm in Sources */,
F93A88880E8B4C9A0026AF89 /* bytereader.cc in Sources */,
F93A88890E8B4C9A0026AF89 /* dwarf2reader.cc in Sources */,
F93A888A0E8B4C9A0026AF89 /* functioninfo.cc in Sources */,
F93A888B0E8B4C9A0026AF89 /* md5.c in Sources */,
F93A887D0E8B4C8C0026AF89 /* macho_walker.cc in Sources */,
F93A887E0E8B4C8C0026AF89 /* macho_id.cc in Sources */,
F93A887F0E8B4C8C0026AF89 /* macho_utilities.cc in Sources */,
F93A88800E8B4C8C0026AF89 /* file_id.cc in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
F9AE19BF0DB04A9500C98454 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
F9B34E870DBC1E1600306484 /* dynamic_images.cc in Sources */,
F982089C0DB3280D0017AECA /* breakpad_nlist_test.cc in Sources */,
F98208A30DB32CAE0017AECA /* breakpad_nlist_64.cc in Sources */,
F9C5A4220DB82DD800209C76 /* DynamicImagesTests.cc in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
F9AE5B2F0DBFDBA300505983 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
F9AE5B390DBFDBDB00505983 /* dynamic_images.cc in Sources */,
F9AE5B3A0DBFDBDB00505983 /* DynamicImagesTests.cc in Sources */,
8BFC81AD11FF9C8A002CB4DC /* breakpad_nlist_64.cc in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -330,129 +629,136 @@
1DEB923208733DC60010E9CD /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
COPY_PHASE_STRIP = NO;
GCC_CW_ASM_SYNTAX = NO;
GCC_DYNAMIC_NO_PIC = NO;
GCC_ENABLE_FIX_AND_CONTINUE = YES;
GCC_ENABLE_PASCAL_STRINGS = NO;
GCC_MODEL_TUNING = G5;
GCC_OPTIMIZATION_LEVEL = 0;
GCC_THREADSAFE_STATICS = NO;
INSTALL_PATH = "$(HOME)/bin";
FRAMEWORK_SEARCH_PATHS = (
"$(inherited)",
"\"$(DEVELOPER_FRAMEWORKS_DIR)\"",
);
PRODUCT_NAME = generator_test;
USER_HEADER_SEARCH_PATHS = "../../../** $(inherited)";
ZERO_LINK = NO;
};
name = Debug;
};
1DEB923308733DC60010E9CD /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ARCHS = (
ppc,
i386,
FRAMEWORK_SEARCH_PATHS = (
"$(inherited)",
"\"$(DEVELOPER_FRAMEWORKS_DIR)\"",
);
GCC_CW_ASM_SYNTAX = NO;
GCC_ENABLE_PASCAL_STRINGS = NO;
GCC_GENERATE_DEBUGGING_SYMBOLS = NO;
GCC_MODEL_TUNING = G5;
GCC_THREADSAFE_STATICS = NO;
INSTALL_PATH = "$(HOME)/bin";
PRODUCT_NAME = generator_test;
USER_HEADER_SEARCH_PATHS = "../../../** $(inherited)";
ZERO_LINK = NO;
};
name = Release;
};
1DEB923608733DC60010E9CD /* Debug */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 8BFC812111FF99D5002CB4DC /* BreakpadDebug.xcconfig */;
buildSettings = {
GCC_WARN_ABOUT_RETURN_TYPE = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
OTHER_LDFLAGS = "-lcrypto";
PREBINDING = NO;
SDKROOT = /Developer/SDKs/MacOSX10.4u.sdk;
};
name = Debug;
};
1DEB923708733DC60010E9CD /* Release */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 8BFC812211FF99D5002CB4DC /* BreakpadRelease.xcconfig */;
buildSettings = {
GCC_WARN_ABOUT_RETURN_TYPE = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
OTHER_LDFLAGS = "-lcrypto";
PREBINDING = NO;
SDKROOT = /Developer/SDKs/MacOSX10.4u.sdk;
};
name = Release;
};
9B7CA8510B12984300CD3A1D /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
COPY_PHASE_STRIP = NO;
GCC_DYNAMIC_NO_PIC = NO;
GCC_ENABLE_FIX_AND_CONTINUE = YES;
GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
GCC_MODEL_TUNING = G5;
GCC_OPTIMIZATION_LEVEL = 0;
INSTALL_PATH = "$(HOME)/bin";
PREBINDING = NO;
PRODUCT_NAME = unit_test;
USER_HEADER_SEARCH_PATHS = "../../../** $(inherited)";
ZERO_LINK = NO;
};
name = Debug;
};
9B7CA8520B12984300CD3A1D /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
COPY_PHASE_STRIP = YES;
GCC_ENABLE_FIX_AND_CONTINUE = NO;
GCC_GENERATE_DEBUGGING_SYMBOLS = NO;
GCC_MODEL_TUNING = G5;
INSTALL_PATH = "$(HOME)/bin";
PREBINDING = NO;
PRODUCT_NAME = unit_test;
USER_HEADER_SEARCH_PATHS = "../../../** $(inherited)";
ZERO_LINK = NO;
};
name = Release;
};
9BD82AA70B0026BF0055103E /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ARCHS = "$(NATIVE_ARCH)";
COPY_PHASE_STRIP = NO;
GCC_DYNAMIC_NO_PIC = NO;
GCC_ENABLE_FIX_AND_CONTINUE = YES;
GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
GCC_MODEL_TUNING = G5;
GCC_OPTIMIZATION_LEVEL = 0;
GCC_SYMBOLS_PRIVATE_EXTERN = NO;
INSTALL_PATH = "$(HOME)/bin";
OTHER_CFLAGS = "-Wall";
PREBINDING = NO;
PRODUCT_NAME = handler_test;
USER_HEADER_SEARCH_PATHS = "../../.. $(inherited)";
ZERO_LINK = NO;
};
name = Debug;
};
9BD82AA80B0026BF0055103E /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ARCHS = "$(NATIVE_ARCH)";
COPY_PHASE_STRIP = YES;
GCC_ENABLE_FIX_AND_CONTINUE = NO;
GCC_GENERATE_DEBUGGING_SYMBOLS = NO;
GCC_MODEL_TUNING = G5;
GCC_SYMBOLS_PRIVATE_EXTERN = NO;
INSTALL_PATH = "$(HOME)/bin";
OTHER_CFLAGS = "-Wall";
PREBINDING = NO;
PRODUCT_NAME = handler_test;
USER_HEADER_SEARCH_PATHS = "../../.. $(inherited)";
ZERO_LINK = NO;
};
name = Release;
};
F93A88770E8B4C700026AF89 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
FRAMEWORK_SEARCH_PATHS = "$(DEVELOPER_LIBRARY_DIR)/Frameworks";
INFOPLIST_FILE = "obj-cTestCases-Info.plist";
PRODUCT_NAME = octestcases;
USER_HEADER_SEARCH_PATHS = "../../../..//**";
WRAPPER_EXTENSION = octest;
};
name = Debug;
};
F93A88780E8B4C700026AF89 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
FRAMEWORK_SEARCH_PATHS = "$(DEVELOPER_LIBRARY_DIR)/Frameworks";
INFOPLIST_FILE = "obj-cTestCases-Info.plist";
PRODUCT_NAME = octestcases;
USER_HEADER_SEARCH_PATHS = "../../../..//**";
WRAPPER_EXTENSION = octest;
};
name = Release;
};
F9AE19C40DB04A9500C98454 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
FRAMEWORK_SEARCH_PATHS = "$(DEVELOPER_LIBRARY_DIR)/Frameworks";
INFOPLIST_FILE = "minidump_tests64-Info.plist";
PRODUCT_NAME = minidump_tests64;
USER_HEADER_SEARCH_PATHS = "../../../**";
WRAPPER_EXTENSION = cptest;
};
name = Debug;
};
F9AE19C50DB04A9500C98454 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
FRAMEWORK_SEARCH_PATHS = "$(DEVELOPER_LIBRARY_DIR)/Frameworks";
INFOPLIST_FILE = "minidump_tests64-Info.plist";
PRODUCT_NAME = minidump_tests64;
USER_HEADER_SEARCH_PATHS = "../../../**";
WRAPPER_EXTENSION = cptest;
};
name = Release;
};
F9AE5B350DBFDBA300505983 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
FRAMEWORK_SEARCH_PATHS = "$(DEVELOPER_LIBRARY_DIR)/Frameworks";
INFOPLIST_FILE = "minidump_tests32-Info.plist";
PRODUCT_NAME = minidump_tests32;
USER_HEADER_SEARCH_PATHS = "../../../**";
WRAPPER_EXTENSION = cptest;
};
name = Debug;
};
F9AE5B370DBFDBA300505983 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
FRAMEWORK_SEARCH_PATHS = "$(DEVELOPER_LIBRARY_DIR)/Frameworks";
INFOPLIST_FILE = "minidump_tests32-Info.plist";
PRODUCT_NAME = minidump_tests32;
USER_HEADER_SEARCH_PATHS = "../../../**";
WRAPPER_EXTENSION = cptest;
};
name = Release;
};
@@ -495,6 +801,33 @@
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
F93A88790E8B4C700026AF89 /* Build configuration list for PBXNativeTarget "obj-c_TestCases" */ = {
isa = XCConfigurationList;
buildConfigurations = (
F93A88770E8B4C700026AF89 /* Debug */,
F93A88780E8B4C700026AF89 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
F9AE19C70DB04AA200C98454 /* Build configuration list for PBXNativeTarget "minidump_tests64" */ = {
isa = XCConfigurationList;
buildConfigurations = (
F9AE19C40DB04A9500C98454 /* Debug */,
F9AE19C50DB04A9500C98454 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
F9AE5B380DBFDBA300505983 /* Build configuration list for PBXNativeTarget "minidump_tests32" */ = {
isa = XCConfigurationList;
buildConfigurations = (
F9AE5B350DBFDBA300505983 /* Debug */,
F9AE5B370DBFDBA300505983 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
/* End XCConfigurationList section */
};
rootObject = 08FB7793FE84155DC02AAC07 /* Project object */;

View File

@@ -0,0 +1,20 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>English</string>
<key>CFBundleExecutable</key>
<string>${EXECUTABLE_NAME}</string>
<key>CFBundleIdentifier</key>
<string>com.google.breakpad.minidump_tests32</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundlePackageType</key>
<string>BNDL</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>1.0</string>
</dict>
</plist>

View File

@@ -0,0 +1,22 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>English</string>
<key>CFBundleExecutable</key>
<string>${EXECUTABLE_NAME}</string>
<key>CFBundleIdentifier</key>
<string>com.google.breakpad.minidump_tests64</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundlePackageType</key>
<string>BNDL</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>1.0</string>
<key>CSResourcesFileMapped</key>
<string>yes</string>
</dict>
</plist>

View File

@@ -0,0 +1,20 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>English</string>
<key>CFBundleExecutable</key>
<string>${EXECUTABLE_NAME}</string>
<key>CFBundleIdentifier</key>
<string>com.yourcompany.${PRODUCT_NAME:identifier}</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundlePackageType</key>
<string>BNDL</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>1.0</string>
</dict>
</plist>

View File

@@ -59,7 +59,7 @@ ProtectedMemoryAllocator::~ProtectedMemoryAllocator() {
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
char *ProtectedMemoryAllocator::Allocate(size_t bytes) {
char *ProtectedMemoryAllocator::Allocate(vm_size_t bytes) {
if (valid_ && next_alloc_offset_ + bytes <= pool_size_) {
char *p = (char*)base_address_ + next_alloc_offset_;
next_alloc_offset_ += bytes;

View File

@@ -53,7 +53,7 @@ class ProtectedMemoryAllocator {
// Fails by returning NULL is no more space is available.
// Please note that the pointers returned from this method should not
// be freed in any way (for example by calling free() on them ).
char * Allocate(size_t n);
char * Allocate(vm_size_t n);
// Returns the base address of the allocation pool.
char * GetBaseAddress() { return (char*)base_address_; }
@@ -78,7 +78,7 @@ class ProtectedMemoryAllocator {
private:
vm_size_t pool_size_;
vm_address_t base_address_;
int next_alloc_offset_;
vm_size_t next_alloc_offset_;
bool valid_;
};

View File

@@ -0,0 +1,79 @@
// Copyright (c) 2008, 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.
//
// DynamicImagesTests.cpp
// minidump_test
//
// Created by Neal Sidhwaney on 4/17/08.
// Copyright 2008 Google Inc. All rights reserved.
//
#include "client/mac/handler/testcases/DynamicImagesTests.h"
#include "client/mac/handler/dynamic_images.h"
DynamicImagesTests test2(TEST_INVOCATION(DynamicImagesTests,
ReadTaskMemoryTest));
DynamicImagesTests test3(TEST_INVOCATION(DynamicImagesTests,
ReadLibrariesFromLocalTaskTest));
DynamicImagesTests::DynamicImagesTests(TestInvocation *invocation)
: TestCase(invocation) {
}
DynamicImagesTests::~DynamicImagesTests() {
}
void DynamicImagesTests::ReadTaskMemoryTest() {
kern_return_t kr;
// pick test2 as a symbol we know to be valid to read
// anything will work, really
void *addr = reinterpret_cast<void*>(&test2);
std::vector<uint8_t> buf(getpagesize());
fprintf(stderr, "reading 0x%p\n", addr);
kr = google_breakpad::ReadTaskMemory(mach_task_self(),
(uint64_t)addr,
getpagesize(),
buf);
CPTAssert(kr == KERN_SUCCESS);
CPTAssert(0 == memcmp(&buf[0], (const void*)addr, getpagesize()));
}
void DynamicImagesTests::ReadLibrariesFromLocalTaskTest() {
mach_port_t me = mach_task_self();
google_breakpad::DynamicImages *d = new google_breakpad::DynamicImages(me);
fprintf(stderr,"Local task image count: %d\n", d->GetImageCount());
CPTAssert(d->GetImageCount() > 0);
}

View File

@@ -0,0 +1,52 @@
// Copyright (c) 2008, 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.
//
// DynamicImagesTests.h
// minidump_test
//
// Created by Neal Sidhwaney on 4/17/08.
// Copyright 2008 Google Inc. All rights reserved.
//
//
#ifndef _CLIENT_MAC_HANDLER_TESTCASES_DYNAMICIMAGESTESTS_H__
#define _CLIENT_MAC_HANDLER_TESTCASES_DYNAMICIMAGESTESTS_H__
#include <CPlusTest/CPlusTest.h>
class DynamicImagesTests : public TestCase {
public:
explicit DynamicImagesTests(TestInvocation* invocation);
virtual ~DynamicImagesTests();
void ReadTaskMemoryTest();
void ReadLibrariesFromLocalTaskTest();
};
#endif /* _CLIENT_MAC_HANDLER_TESTCASES_DYNAMICIMAGESTESTS_H__ */

View File

@@ -0,0 +1,106 @@
// Copyright (c) 2008, 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.
//
// breakpad_nlist_test.cc
// minidump_test
//
// Created by Neal Sidhwaney on 4/13/08.
// Copyright 2008 Google Inc. All rights reserved.
//
#include "client/mac/handler/testcases/breakpad_nlist_test.h"
#include <mach-o/nlist.h>
#include "client/mac/handler/breakpad_nlist_64.h"
BreakpadNlistTest test1(TEST_INVOCATION(BreakpadNlistTest, CompareToNM));
BreakpadNlistTest::BreakpadNlistTest(TestInvocation *invocation)
: TestCase(invocation) {
}
BreakpadNlistTest::~BreakpadNlistTest() {
}
void BreakpadNlistTest::CompareToNM() {
#if TARGET_CPU_X86_64
system("/usr/bin/nm -arch x86_64 /usr/lib/dyld > /tmp/dyld-namelist.txt");
#elif TARGET_CPU_PPC64
system("/usr/bin/nm -arch ppc64 /usr/lib/dyld > /tmp/dyld-namelist.txt");
#endif
FILE *fd = fopen("/tmp/dyld-namelist.txt", "rt");
char oneNMAddr[30];
char symbolType;
char symbolName[500];
while (!feof(fd)) {
fscanf(fd, "%s %c %s", oneNMAddr, &symbolType, symbolName);
breakpad_nlist symbolList[2];
breakpad_nlist &list = symbolList[0];
memset(symbolList, 0, sizeof(breakpad_nlist)*2);
const char *symbolNames[2];
symbolNames[0] = (const char*)symbolName;
symbolNames[1] = "\0";
breakpad_nlist_64("/usr/lib/dyld", &list, symbolNames);
uint64_t nmAddr = strtol(oneNMAddr, NULL, 16);
if (!IsSymbolMoreThanOnceInDyld(symbolName)) {
CPTAssert(nmAddr == symbolList[0].n_value);
}
}
fclose(fd);
}
bool BreakpadNlistTest::IsSymbolMoreThanOnceInDyld(const char *symbolName) {
// These are the symbols that occur more than once when nm dumps
// the symbol table of /usr/lib/dyld. Our nlist program returns
// the first address because it's doing a search so we need to exclude
// these from causing the test to fail
const char *multipleSymbols[] = {
"__Z41__static_initialization_and_destruction_0ii",
"___tcf_0",
"___tcf_1",
"_read_encoded_value_with_base",
"_read_sleb128",
"_read_uleb128",
"\0"};
bool found = false;
for (int i = 0; multipleSymbols[i][0]; i++) {
if (!strcmp(multipleSymbols[i], symbolName)) {
found = true;
break;
}
}
return found;
}

View File

@@ -0,0 +1,62 @@
// Copyright (c) 2008, 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.
//
// breakpad_nlist_test.h
// minidump_test
//
// Created by Neal Sidhwaney on 4/13/08.
// Copyright 2008 Google Inc. All rights reserved.
//
//
#ifndef CLIENT_MAC_HANDLER_TESTCASES_BREAKPAD_NLIST_TEST_H__
#define CLIENT_MAC_HANDLER_TESTCASES_BREAKPAD_NLIST_TEST_H__
#include <CPlusTest/CPlusTest.h>
class BreakpadNlistTest : public TestCase {
private:
// nm dumps multiple addresses for the same symbol in
// /usr/lib/dyld. So we track those so we don't report failures
// in mismatches between what our nlist returns and what nm has
// for the duplicate symbols.
bool IsSymbolMoreThanOnceInDyld(const char *symbolName);
public:
explicit BreakpadNlistTest(TestInvocation* invocation);
virtual ~BreakpadNlistTest();
/* This test case runs nm on /usr/lib/dyld and then compares the
output of every symbol to what our nlist implementation returns */
void CompareToNM();
};
#endif /* CLIENT_MAC_HANDLER_TESTCASES_BREAKPAD_NLIST_TEST_H__*/

View File

@@ -0,0 +1,46 @@
// Copyright (c) 2008, 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.
//
// dwarftests.h
// minidump_test
//
// Created by Neal Sidhwaney on 9/24/08.
// Copyright 2008 Google Inc. All rights reserved.
//
#import <SenTestingKit/SenTestingKit.h>
@interface dwarftests : SenTestCase {
}
- (void) testDWARFSymbolFileGeneration;
@end

View File

@@ -0,0 +1,60 @@
// Copyright (c) 2008, 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.
//
// dwarftests.m
// minidump_test
//
// Created by Neal Sidhwaney on 9/24/08.
// Copyright 2008 Google Inc. All rights reserved.
//
#import "dwarftests.h"
#import "dump_syms.h"
@implementation dwarftests
- (void) testDWARFSymbolFileGeneration {
NSString *inputBreakpadSymbolFile = @"testcases/testdata/dump_syms_i386_breakpad.sym";
NSString *outputBreakpadSymbolFile = @"/tmp/dump_syms_i386.breakpad";
DumpSymbols *dump = [[DumpSymbols alloc] initWithContentsOfFile:@"testcases/testdata/dump_syms_dwarf_data"];
STAssertNotNil(dump, @"DumpSymbols is nil");
[dump setArchitecture:@"i386"];
[dump writeSymbolFile:outputBreakpadSymbolFile];
NSData *d = [[NSData alloc] initWithContentsOfFile:inputBreakpadSymbolFile];
STAssertNotNil(d, @"Input breakpad symbol file not found");
NSData *d1 = [[NSData alloc] initWithContentsOfFile:outputBreakpadSymbolFile];
STAssertNotNil(d1, @"Output breakpad symbol file not found");
STAssertTrue([d isEqualToData:d1],
@"Symbol files were not equal!",nil);
}
@end

Binary file not shown.

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

Binary file not shown.

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,32 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>English</string>
<key>CFBundleDisplayName</key>
<string>${EXECUTABLE_NAME}</string>
<key>CFBundleExecutable</key>
<string>${EXECUTABLE_NAME}</string>
<key>CFBundleIconFile</key>
<string>crash_report_sender</string>
<key>CFBundleIdentifier</key>
<string>com.Breakpad.${PRODUCT_NAME:identifier}</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>${EXECUTABLE_NAME}</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>1.0</string>
<key>LSHasLocalizedDisplayName</key>
<true/>
<key>NSMainNibFile</key>
<string>MainMenu</string>
<key>NSPrincipalClass</key>
<string>NSApplication</string>
</dict>
</plist>

View File

@@ -0,0 +1,140 @@
// Copyright (c) 2006, 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 component uses the HTTPMultipartUpload of the breakpad project to send
// the minidump and associated data to the crash reporting servers.
// It will perform throttling based on the parameters passed to it and will
// prompt the user to send the minidump.
#include <Foundation/Foundation.h>
#include "client/mac/Framework/Breakpad.h"
#import "GTMDefines.h"
#define kClientIdPreferenceKey @"clientid"
extern NSString *const kGoogleServerType;
extern NSString *const kSocorroServerType;
extern NSString *const kDefaultServerType;
// We're sublcassing NSTextField in order to override a particular
// method (see the implementation) that lets us reject changes if they
// are longer than a particular length. Bindings would normally solve
// this problem, but when we implemented a validation method, and
// returned NO for strings that were too long, the UI was not updated
// right away, which was a poor user experience. The UI would be
// updated as soon as the text field lost first responder status,
// which isn't soon enough. It is a known bug that the UI KVO didn't
// work in the middle of a validation.
@interface LengthLimitingTextField : NSTextField {
@private
NSUInteger maximumLength_;
}
- (void)setMaximumLength:(NSUInteger)maxLength;
@end
@interface Reporter : NSObject {
@public
IBOutlet NSWindow *alertWindow_; // The alert window
// Grouping boxes used for resizing.
IBOutlet NSBox *headerBox_;
IBOutlet NSBox *preEmailBox_;
IBOutlet NSBox *emailSectionBox_;
// Localized elements (or things that need to be moved during localization).
IBOutlet NSTextField *dialogTitle_;
IBOutlet NSTextField *commentMessage_;
IBOutlet NSTextField *emailMessage_;
IBOutlet NSTextField *emailLabel_;
IBOutlet NSTextField *privacyLinkLabel_;
IBOutlet NSButton *sendButton_;
IBOutlet NSButton *cancelButton_;
IBOutlet LengthLimitingTextField *emailEntryField_;
IBOutlet LengthLimitingTextField *commentsEntryField_;
IBOutlet NSTextField *countdownLabel_;
IBOutlet NSView *privacyLinkArrow_;
// Text field bindings, for user input.
NSString *commentsValue_; // Comments from the user
NSString *emailValue_; // Email from the user
NSString *countdownMessage_; // Message indicating time
// left for input.
@private
int configFile_; // File descriptor for config file
NSMutableDictionary *parameters_; // Key value pairs of data (STRONG)
NSData *minidumpContents_; // The data in the minidump (STRONG)
NSData *logFileData_; // An NSdata for the tar,
// bz2'd log file.
NSTimeInterval remainingDialogTime_; // Keeps track of how long
// we have until we cancel
// the dialog
NSTimer *messageTimer_; // Timer we use to update
// the dialog
NSMutableDictionary *serverDictionary_; // The dictionary mapping a
// server type name to a
// dictionary of server
// parameter names.
NSMutableDictionary *socorroDictionary_; // The dictionary for
// Socorro.
NSMutableDictionary *googleDictionary_; // The dictionary for
// Google.
NSMutableDictionary *extraServerVars_; // A dictionary containing
// extra key/value pairs
// that are uploaded to the
// crash server with the
// minidump.
}
// Stops the modal panel with an NSAlertDefaultReturn value. This is the action
// invoked by the "Send Report" button.
- (IBAction)sendReport:(id)sender;
// Stops the modal panel with an NSAlertAlternateReturn value. This is the
// action invoked by the "Cancel" button.
- (IBAction)cancel:(id)sender;
// Opens the Privacy Policy url in the default web browser.
- (IBAction)showPrivacyPolicy:(id)sender;
// Delegate methods for the NSTextField for comments. We want to capture the
// Return key and use it to send the message when no text has been entered.
// Otherwise, we want Return to add a carriage return to the comments field.
- (BOOL)control:(NSControl *)control textView:(NSTextView *)textView
doCommandBySelector:(SEL)commandSelector;
// Accessors to make bindings work
- (NSString *)commentsValue;
- (void)setCommentsValue:(NSString *)value;
- (NSString *)emailValue;
- (void)setEmailValue:(NSString *)value;
- (NSString *)countdownMessage;
- (void)setCountdownMessage:(NSString *)value;
@end

Binary file not shown.

File diff suppressed because it is too large Load Diff

Binary file not shown.

Binary file not shown.

Binary file not shown.

Some files were not shown because too many files have changed in this diff Show More