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
This commit is contained in:
ted.mielczarek@gmail.com 2010-08-13 20:18:58 +00:00
parent 863aa2a74a
commit 315fd78199
13 changed files with 984 additions and 12 deletions

View file

@ -51,6 +51,9 @@
8B4BDABE12012CEF009C7060 /* libcrypto.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 8B4BDAA7120124EA009C7060 /* libcrypto.dylib */; };
8B4BDAC512012D05009C7060 /* libcrypto.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 8B4BDAA7120124EA009C7060 /* libcrypto.dylib */; };
8DC2EF570486A6940098B216 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1058C7B1FEA5585E11CA2CBB /* Cocoa.framework */; };
D24BBBFD121050F000F3D417 /* breakpadUtilities.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = F92C563C0ECD10B3009BE4BA /* breakpadUtilities.dylib */; };
D24BBD291211EDB100F3D417 /* MachIPC.mm in Sources */ = {isa = PBXBuildFile; fileRef = F92C53790ECCE635009BE4BA /* MachIPC.mm */; };
D24BBD321212CACF00F3D417 /* MachIPC.mm in Sources */ = {isa = PBXBuildFile; fileRef = F92C53790ECCE635009BE4BA /* MachIPC.mm */; };
D2A5DD301188633800081F03 /* breakpad_nlist_64.cc in Sources */ = {isa = PBXBuildFile; fileRef = F92C53690ECCE3FD009BE4BA /* breakpad_nlist_64.cc */; };
D2A5DD401188640400081F03 /* breakpad_nlist_64.cc in Sources */ = {isa = PBXBuildFile; fileRef = F92C53690ECCE3FD009BE4BA /* breakpad_nlist_64.cc */; };
D2A5DD411188642E00081F03 /* breakpad_nlist_64.cc in Sources */ = {isa = PBXBuildFile; fileRef = F92C53690ECCE3FD009BE4BA /* breakpad_nlist_64.cc */; };
@ -59,6 +62,34 @@
D2F9A44012131F65002747C1 /* gtest_main.cc in Sources */ = {isa = PBXBuildFile; fileRef = D2F9A43E12131F65002747C1 /* gtest_main.cc */; };
D2F9A44112131F65002747C1 /* gtest-all.cc in Sources */ = {isa = PBXBuildFile; fileRef = D2F9A43F12131F65002747C1 /* gtest-all.cc */; };
D2F9A44412131F84002747C1 /* libgtest.a in Frameworks */ = {isa = PBXBuildFile; fileRef = D2F9A41512131EF0002747C1 /* libgtest.a */; };
D2F9A4C9121336C7002747C1 /* client_info.h in Headers */ = {isa = PBXBuildFile; fileRef = D2F9A4C4121336C7002747C1 /* client_info.h */; };
D2F9A4CA121336C7002747C1 /* crash_generation_client.h in Headers */ = {isa = PBXBuildFile; fileRef = D2F9A4C5121336C7002747C1 /* crash_generation_client.h */; };
D2F9A4CB121336C7002747C1 /* crash_generation_client.cc in Sources */ = {isa = PBXBuildFile; fileRef = D2F9A4C6121336C7002747C1 /* crash_generation_client.cc */; };
D2F9A4CC121336C7002747C1 /* crash_generation_server.h in Headers */ = {isa = PBXBuildFile; fileRef = D2F9A4C7121336C7002747C1 /* crash_generation_server.h */; };
D2F9A4CD121336C7002747C1 /* crash_generation_server.cc in Sources */ = {isa = PBXBuildFile; fileRef = D2F9A4C8121336C7002747C1 /* crash_generation_server.cc */; };
D2F9A4DF12133AD9002747C1 /* crash_generation_client.cc in Sources */ = {isa = PBXBuildFile; fileRef = D2F9A4C6121336C7002747C1 /* crash_generation_client.cc */; };
D2F9A4E012133AD9002747C1 /* crash_generation_server.cc in Sources */ = {isa = PBXBuildFile; fileRef = D2F9A4C8121336C7002747C1 /* crash_generation_server.cc */; };
D2F9A4E112133AE2002747C1 /* crash_generation_client.cc in Sources */ = {isa = PBXBuildFile; fileRef = D2F9A4C6121336C7002747C1 /* crash_generation_client.cc */; };
D2F9A4E212133AE2002747C1 /* crash_generation_server.cc in Sources */ = {isa = PBXBuildFile; fileRef = D2F9A4C8121336C7002747C1 /* crash_generation_server.cc */; };
D2F9A52E121383A1002747C1 /* crash_generation_client.cc in Sources */ = {isa = PBXBuildFile; fileRef = D2F9A4C6121336C7002747C1 /* crash_generation_client.cc */; };
D2F9A52F121383A1002747C1 /* crash_generation_server.cc in Sources */ = {isa = PBXBuildFile; fileRef = D2F9A4C8121336C7002747C1 /* crash_generation_server.cc */; };
D2F9A530121383A1002747C1 /* MachIPC.mm in Sources */ = {isa = PBXBuildFile; fileRef = F92C53790ECCE635009BE4BA /* MachIPC.mm */; };
D2F9A531121383A1002747C1 /* breakpad_nlist_64.cc in Sources */ = {isa = PBXBuildFile; fileRef = F92C53690ECCE3FD009BE4BA /* breakpad_nlist_64.cc */; };
D2F9A532121383A1002747C1 /* dynamic_images.cc in Sources */ = {isa = PBXBuildFile; fileRef = F92C536B0ECCE3FD009BE4BA /* dynamic_images.cc */; };
D2F9A533121383A1002747C1 /* exception_handler.cc in Sources */ = {isa = PBXBuildFile; fileRef = F92C536D0ECCE3FD009BE4BA /* exception_handler.cc */; };
D2F9A534121383A1002747C1 /* minidump_generator.cc in Sources */ = {isa = PBXBuildFile; fileRef = F92C536F0ECCE3FD009BE4BA /* minidump_generator.cc */; };
D2F9A535121383A1002747C1 /* minidump_file_writer.cc in Sources */ = {isa = PBXBuildFile; fileRef = F92C538F0ECCE70A009BE4BA /* minidump_file_writer.cc */; };
D2F9A536121383A1002747C1 /* convert_UTF.c in Sources */ = {isa = PBXBuildFile; fileRef = F92C53870ECCE6C0009BE4BA /* convert_UTF.c */; };
D2F9A537121383A1002747C1 /* string_conversion.cc in Sources */ = {isa = PBXBuildFile; fileRef = F92C53850ECCE6AD009BE4BA /* string_conversion.cc */; };
D2F9A538121383A1002747C1 /* file_id.cc in Sources */ = {isa = PBXBuildFile; fileRef = F92C53740ECCE635009BE4BA /* file_id.cc */; };
D2F9A539121383A1002747C1 /* macho_id.cc in Sources */ = {isa = PBXBuildFile; fileRef = F92C537A0ECCE635009BE4BA /* macho_id.cc */; };
D2F9A53A121383A1002747C1 /* macho_utilities.cc in Sources */ = {isa = PBXBuildFile; fileRef = F92C537C0ECCE635009BE4BA /* macho_utilities.cc */; };
D2F9A53B121383A1002747C1 /* macho_walker.cc in Sources */ = {isa = PBXBuildFile; fileRef = F92C537E0ECCE635009BE4BA /* macho_walker.cc */; };
D2F9A53C121383A1002747C1 /* string_utilities.cc in Sources */ = {isa = PBXBuildFile; fileRef = F92C53820ECCE635009BE4BA /* string_utilities.cc */; };
D2F9A53F121383A1002747C1 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0867D69BFE84028FC02AAC07 /* Foundation.framework */; };
D2F9A540121383A1002747C1 /* libcrypto.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 8B4BDAA7120124EA009C7060 /* libcrypto.dylib */; };
D2F9A541121383A1002747C1 /* libgtest.a in Frameworks */ = {isa = PBXBuildFile; fileRef = D2F9A41512131EF0002747C1 /* libgtest.a */; };
D2F9A553121383DC002747C1 /* crash_generation_server_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = D2F9A4CE121336F7002747C1 /* crash_generation_server_test.cc */; };
F91AF5D00FD60393009D8BE2 /* BreakpadFramework_Test.mm in Sources */ = {isa = PBXBuildFile; fileRef = F91AF5CF0FD60393009D8BE2 /* BreakpadFramework_Test.mm */; };
F91AF6210FD60784009D8BE2 /* Breakpad.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8DC2EF5B0486A6940098B216 /* Breakpad.framework */; };
F9286B3A0F7EB25800A4DCC8 /* InspectorMain.mm in Sources */ = {isa = PBXBuildFile; fileRef = F9286B390F7EB25800A4DCC8 /* InspectorMain.mm */; };
@ -280,9 +311,23 @@
isa = PBXContainerItemProxy;
containerPortal = 0867D690FE84028FC02AAC07 /* Project object */;
proxyType = 1;
remoteGlobalIDString = D2F9A41412131EF0002747C1 /* gtest */;
remoteGlobalIDString = D2F9A41412131EF0002747C1;
remoteInfo = gtest;
};
D2F9A52C121383A1002747C1 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 0867D690FE84028FC02AAC07 /* Project object */;
proxyType = 1;
remoteGlobalIDString = D2F9A41412131EF0002747C1;
remoteInfo = gtest;
};
D2F9A5DE12142A6A002747C1 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 0867D690FE84028FC02AAC07 /* Project object */;
proxyType = 1;
remoteGlobalIDString = D2F9A52A121383A1002747C1;
remoteInfo = crash_generation_server_test;
};
F91AF6370FD60A74009D8BE2 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 0867D690FE84028FC02AAC07 /* Project object */;
@ -467,6 +512,13 @@
D2F9A43C12131F55002747C1 /* gmock-all.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = "gmock-all.cc"; path = "../../testing/src/gmock-all.cc"; sourceTree = SOURCE_ROOT; };
D2F9A43E12131F65002747C1 /* gtest_main.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = gtest_main.cc; path = ../../testing/gtest/src/gtest_main.cc; sourceTree = "<group>"; };
D2F9A43F12131F65002747C1 /* gtest-all.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = "gtest-all.cc"; path = "../../testing/gtest/src/gtest-all.cc"; sourceTree = "<group>"; };
D2F9A4C4121336C7002747C1 /* client_info.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = client_info.h; path = crash_generation/client_info.h; sourceTree = "<group>"; };
D2F9A4C5121336C7002747C1 /* crash_generation_client.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = crash_generation_client.h; path = crash_generation/crash_generation_client.h; sourceTree = "<group>"; };
D2F9A4C6121336C7002747C1 /* crash_generation_client.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = crash_generation_client.cc; path = crash_generation/crash_generation_client.cc; sourceTree = "<group>"; };
D2F9A4C7121336C7002747C1 /* crash_generation_server.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = crash_generation_server.h; path = crash_generation/crash_generation_server.h; sourceTree = "<group>"; };
D2F9A4C8121336C7002747C1 /* crash_generation_server.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = crash_generation_server.cc; path = crash_generation/crash_generation_server.cc; sourceTree = "<group>"; };
D2F9A4CE121336F7002747C1 /* crash_generation_server_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = crash_generation_server_test.cc; path = tests/crash_generation_server_test.cc; sourceTree = "<group>"; };
D2F9A546121383A1002747C1 /* crash_generation_server_test */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = crash_generation_server_test; sourceTree = BUILT_PRODUCTS_DIR; };
DE43467411C72855004F095F /* da */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = da; path = sender/da.lproj/Localizable.strings; sourceTree = "<group>"; };
DE43467511C72857004F095F /* de */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = de; path = sender/de.lproj/Localizable.strings; sourceTree = "<group>"; };
DE43467611C7285B004F095F /* es */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = es; path = sender/es.lproj/Localizable.strings; sourceTree = "<group>"; };
@ -589,6 +641,16 @@
);
runOnlyForDeploymentPostprocessing = 0;
};
D2F9A53E121383A1002747C1 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
D2F9A53F121383A1002747C1 /* Foundation.framework in Frameworks */,
D2F9A540121383A1002747C1 /* libcrypto.dylib in Frameworks */,
D2F9A541121383A1002747C1 /* libgtest.a in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
F92C53520ECCE349009BE4BA /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
@ -661,6 +723,7 @@
F91AF6210FD60784009D8BE2 /* Breakpad.framework in Frameworks */,
8B3101EA11F0CDE300FCF3E4 /* SenTestingKit.framework in Frameworks */,
8B3102EB11F0D78000FCF3E4 /* Foundation.framework in Frameworks */,
D24BBBFD121050F000F3D417 /* breakpadUtilities.dylib in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@ -680,6 +743,7 @@
F93DE2D10F82A67300608B94 /* minidump_file_writer_unittest */,
F93DE32C0F82C55600608B94 /* handler_test */,
D2F9A41512131EF0002747C1 /* libgtest.a */,
D2F9A546121383A1002747C1 /* crash_generation_server_test */,
);
name = Products;
sourceTree = "<group>";
@ -814,6 +878,11 @@
F92C53B50ECCE799009BE4BA /* crash_generation */ = {
isa = PBXGroup;
children = (
D2F9A4C4121336C7002747C1 /* client_info.h */,
D2F9A4C5121336C7002747C1 /* crash_generation_client.h */,
D2F9A4C6121336C7002747C1 /* crash_generation_client.cc */,
D2F9A4C7121336C7002747C1 /* crash_generation_server.h */,
D2F9A4C8121336C7002747C1 /* crash_generation_server.cc */,
F9286B380F7EB25800A4DCC8 /* Inspector.h */,
F9286B390F7EB25800A4DCC8 /* InspectorMain.mm */,
F92C53B70ECCE7B3009BE4BA /* Inspector.mm */,
@ -917,6 +986,7 @@
F9C77DDF0F7DD7CF0045F7DB /* tests */ = {
isa = PBXGroup;
children = (
D2F9A4CE121336F7002747C1 /* crash_generation_server_test.cc */,
D2F9A3D41212F87C002747C1 /* exception_handler_test.cc */,
F9C77DE00F7DD7E30045F7DB /* SimpleStringDictionaryTest.h */,
F9C77DE10F7DD7E30045F7DB /* SimpleStringDictionaryTest.mm */,
@ -943,6 +1013,9 @@
files = (
F92C55D00ECD0064009BE4BA /* Breakpad.h in Headers */,
F92C56330ECD0DF1009BE4BA /* OnDemandServer.h in Headers */,
D2F9A4C9121336C7002747C1 /* client_info.h in Headers */,
D2F9A4CA121336C7002747C1 /* crash_generation_client.h in Headers */,
D2F9A4CC121336C7002747C1 /* crash_generation_server.h in Headers */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@ -1003,6 +1076,23 @@
productReference = D2F9A41512131EF0002747C1 /* libgtest.a */;
productType = "com.apple.product-type.library.static";
};
D2F9A52A121383A1002747C1 /* crash_generation_server_test */ = {
isa = PBXNativeTarget;
buildConfigurationList = D2F9A542121383A1002747C1 /* Build configuration list for PBXNativeTarget "crash_generation_server_test" */;
buildPhases = (
D2F9A52D121383A1002747C1 /* Sources */,
D2F9A53E121383A1002747C1 /* Frameworks */,
);
buildRules = (
);
dependencies = (
D2F9A52B121383A1002747C1 /* PBXTargetDependency */,
);
name = crash_generation_server_test;
productName = handler_test;
productReference = D2F9A546121383A1002747C1 /* crash_generation_server_test */;
productType = "com.apple.product-type.tool";
};
F92C53530ECCE349009BE4BA /* Inspector */ = {
isa = PBXNativeTarget;
buildConfigurationList = F92C53580ECCE36D009BE4BA /* Build configuration list for PBXNativeTarget "Inspector" */;
@ -1138,6 +1228,7 @@
F93DE2FC0F82C3C600608B94 /* PBXTargetDependency */,
F93DE3700F82CC1300608B94 /* PBXTargetDependency */,
F91AF6380FD60A74009D8BE2 /* PBXTargetDependency */,
D2F9A5DF12142A6A002747C1 /* PBXTargetDependency */,
);
name = UnitTests;
productName = UnitTests;
@ -1196,6 +1287,7 @@
F93DE2D00F82A67300608B94 /* minidump_file_writer_unittest */,
F93DE32B0F82C55600608B94 /* handler_test */,
D2F9A41412131EF0002747C1 /* gtest */,
D2F9A52A121383A1002747C1 /* crash_generation_server_test */,
);
};
/* End PBXProject section */
@ -1412,7 +1504,7 @@
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "# Run the unit tests in this test bundle.\n\"${SYSTEM_DEVELOPER_DIR}/Tools/RunUnitTests\"\n\necho running minidump generator tests...\n\"${BUILT_PRODUCTS_DIR}/generator_test\"\necho Running exception handler tests...\n\"${BUILT_PRODUCTS_DIR}/handler_test\"\n";
shellScript = "# Run the unit tests in this test bundle.\n\"${SYSTEM_DEVELOPER_DIR}/Tools/RunUnitTests\"\n\necho running minidump generator tests...\n\"${BUILT_PRODUCTS_DIR}/generator_test\"\necho Running exception handler tests...\n\"${BUILT_PRODUCTS_DIR}/handler_test\"\necho Running crash generation server tests...\n\"${BUILT_PRODUCTS_DIR}/crash_generation_server_test\"\n";
};
/* End PBXShellScriptBuildPhase section */
@ -1425,6 +1517,8 @@
F92C56630ECD1179009BE4BA /* exception_handler.cc in Sources */,
F92C55D10ECD0064009BE4BA /* Breakpad.mm in Sources */,
F92C56340ECD0DF1009BE4BA /* OnDemandServer.mm in Sources */,
D2F9A4CB121336C7002747C1 /* crash_generation_client.cc in Sources */,
D2F9A4CD121336C7002747C1 /* crash_generation_server.cc in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@ -1438,6 +1532,29 @@
);
runOnlyForDeploymentPostprocessing = 0;
};
D2F9A52D121383A1002747C1 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
D2F9A553121383DC002747C1 /* crash_generation_server_test.cc in Sources */,
D2F9A52E121383A1002747C1 /* crash_generation_client.cc in Sources */,
D2F9A52F121383A1002747C1 /* crash_generation_server.cc in Sources */,
D2F9A530121383A1002747C1 /* MachIPC.mm in Sources */,
D2F9A531121383A1002747C1 /* breakpad_nlist_64.cc in Sources */,
D2F9A532121383A1002747C1 /* dynamic_images.cc in Sources */,
D2F9A533121383A1002747C1 /* exception_handler.cc in Sources */,
D2F9A534121383A1002747C1 /* minidump_generator.cc in Sources */,
D2F9A535121383A1002747C1 /* minidump_file_writer.cc in Sources */,
D2F9A536121383A1002747C1 /* convert_UTF.c in Sources */,
D2F9A537121383A1002747C1 /* string_conversion.cc in Sources */,
D2F9A538121383A1002747C1 /* file_id.cc in Sources */,
D2F9A539121383A1002747C1 /* macho_id.cc in Sources */,
D2F9A53A121383A1002747C1 /* macho_utilities.cc in Sources */,
D2F9A53B121383A1002747C1 /* macho_walker.cc in Sources */,
D2F9A53C121383A1002747C1 /* string_utilities.cc in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
F92C53510ECCE349009BE4BA /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
@ -1481,6 +1598,9 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
D2F9A4DF12133AD9002747C1 /* crash_generation_client.cc in Sources */,
D2F9A4E012133AD9002747C1 /* crash_generation_server.cc in Sources */,
D24BBD291211EDB100F3D417 /* MachIPC.mm in Sources */,
D2A5DD401188640400081F03 /* breakpad_nlist_64.cc in Sources */,
F93803CD0F8083B7004D428B /* dynamic_images.cc in Sources */,
F93803CE0F8083B7004D428B /* exception_handler.cc in Sources */,
@ -1512,6 +1632,9 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
D2F9A4E112133AE2002747C1 /* crash_generation_client.cc in Sources */,
D2F9A4E212133AE2002747C1 /* crash_generation_server.cc in Sources */,
D24BBD321212CACF00F3D417 /* MachIPC.mm in Sources */,
D2A5DD411188642E00081F03 /* breakpad_nlist_64.cc in Sources */,
F93DE3350F82C66B00608B94 /* dynamic_images.cc in Sources */,
F93DE3360F82C66B00608B94 /* exception_handler.cc in Sources */,
@ -1587,6 +1710,16 @@
target = D2F9A41412131EF0002747C1 /* gtest */;
targetProxy = D2F9A44212131F80002747C1 /* PBXContainerItemProxy */;
};
D2F9A52B121383A1002747C1 /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
target = D2F9A41412131EF0002747C1 /* gtest */;
targetProxy = D2F9A52C121383A1002747C1 /* PBXContainerItemProxy */;
};
D2F9A5DF12142A6A002747C1 /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
target = D2F9A52A121383A1002747C1 /* crash_generation_server_test */;
targetProxy = D2F9A5DE12142A6A002747C1 /* PBXContainerItemProxy */;
};
F91AF6380FD60A74009D8BE2 /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
target = 8DC2EF4F0486A6940098B216 /* Breakpad */;
@ -1821,6 +1954,51 @@
};
name = Release;
};
D2F9A543121383A1002747C1 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
DEBUG_INFORMATION_FORMAT = dwarf;
GCC_INLINES_ARE_PRIVATE_EXTERN = NO;
GCC_SYMBOLS_PRIVATE_EXTERN = NO;
HEADER_SEARCH_PATHS = (
../..,
../../testing,
../../testing/include,
../../testing/gtest,
../../testing/gtest/include,
);
LIBRARY_SEARCH_PATHS = (
"$(inherited)",
"\"$(SRCROOT)/build/Debug\"",
);
PRODUCT_NAME = crash_generation_server_test;
};
name = Debug;
};
D2F9A544121383A1002747C1 /* Debug With Code Coverage */ = {
isa = XCBuildConfiguration;
buildSettings = {
HEADER_SEARCH_PATHS = ../..;
LIBRARY_SEARCH_PATHS = (
"$(inherited)",
"\\\"$(SRCROOT)/build/Debug\\\"",
);
PRODUCT_NAME = handler_test;
};
name = "Debug With Code Coverage";
};
D2F9A545121383A1002747C1 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
HEADER_SEARCH_PATHS = ../..;
LIBRARY_SEARCH_PATHS = (
"$(inherited)",
"\\\"$(SRCROOT)/build/Debug\\\"",
);
PRODUCT_NAME = handler_test;
};
name = Release;
};
F92C53560ECCE34A009BE4BA /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
@ -1921,6 +2099,8 @@
isa = XCBuildConfiguration;
buildSettings = {
DEBUG_INFORMATION_FORMAT = dwarf;
GCC_INLINES_ARE_PRIVATE_EXTERN = NO;
GCC_SYMBOLS_PRIVATE_EXTERN = NO;
HEADER_SEARCH_PATHS = (
../..,
../../testing,
@ -2028,6 +2208,7 @@
"\"$(DEVELOPER_FRAMEWORKS_DIR)\"",
);
GCC_ENABLE_OBJC_EXCEPTIONS = YES;
HEADER_SEARCH_PATHS = ../..;
INFOPLIST_FILE = "UnitTests-Info.plist";
PRODUCT_NAME = UnitTests;
WRAPPER_EXTENSION = octest;
@ -2155,6 +2336,16 @@
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
D2F9A542121383A1002747C1 /* Build configuration list for PBXNativeTarget "crash_generation_server_test" */ = {
isa = XCConfigurationList;
buildConfigurations = (
D2F9A543121383A1002747C1 /* Debug */,
D2F9A544121383A1002747C1 /* Debug With Code Coverage */,
D2F9A545121383A1002747C1 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
F92C53580ECCE36D009BE4BA /* Build configuration list for PBXNativeTarget "Inspector" */ = {
isa = XCConfigurationList;
buildConfigurations = (

View file

@ -0,0 +1,43 @@
// 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 {
struct ClientInfo {
int exception_type;
int exception_code;
int exception_subcode;
};
} // namespace google_breakpad
#endif // CLIENT_MAC_CRASH_GENERATION_CLIENT_INFO_H_

View file

@ -0,0 +1,74 @@
// 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/client_info.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
ClientInfo 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,158 @@
// 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: {
ClientInfo &info = (ClientInfo &)*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);
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_, info, 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_, info);
}
break;
}
case kQuitMessage:
return false;
}
} else { // result != KERN_SUCCESS
mach_error("WaitForMessage", result);
return false;
}
return true;
}
} // namespace google_breakpad

View file

@ -0,0 +1,132 @@
// 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 <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
};
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_

View file

@ -221,7 +221,8 @@ 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),
@ -237,6 +238,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);
}
@ -293,7 +296,8 @@ bool ExceptionHandler::WriteMinidump() {
bool ExceptionHandler::WriteMinidump(const string &dump_path,
MinidumpCallback callback,
void *callback_context) {
ExceptionHandler handler(dump_path, NULL, callback, callback_context, false);
ExceptionHandler handler(dump_path, NULL, callback, callback_context, false,
NULL);
return handler.WriteMinidump();
}
@ -312,6 +316,18 @@ bool ExceptionHandler::WriteMinidumpWithException(int exception_type,
if (exception_type && exception_code)
_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;
@ -321,7 +337,7 @@ 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;

View file

@ -40,6 +40,9 @@
#include <string>
#include "client/mac/crash_generation/crash_generation_client.h"
#include "processor/scoped_ptr.h"
namespace google_breakpad {
using std::string;
@ -86,9 +89,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.
// 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.
@ -115,6 +121,11 @@ class ExceptionHandler {
static bool WriteMinidump(const 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();
@ -206,6 +217,9 @@ class ExceptionHandler {
// 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

View file

@ -0,0 +1,217 @@
// 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.
//
// crash_generation_server_test.cc
// Unit tests for CrashGenerationServer
#include <dirent.h>
#include <glob.h>
#include <stdint.h>
#include <sys/wait.h>
#include <unistd.h>
#include <string>
#include "breakpad_googletest_includes.h"
#include "client/mac/crash_generation/client_info.h"
#include "client/mac/crash_generation/crash_generation_client.h"
#include "client/mac/crash_generation/crash_generation_server.h"
#include "client/mac/handler/exception_handler.h"
#include "client/mac/tests/auto_tempdir.h"
namespace {
using std::string;
using google_breakpad::AutoTempDir;
using google_breakpad::ClientInfo;
using google_breakpad::CrashGenerationClient;
using google_breakpad::CrashGenerationServer;
using google_breakpad::ExceptionHandler;
using testing::Test;
class CrashGenerationServerTest : public Test {
public:
// The port name to receive messages on
char mach_port_name[128];
// Filename of the last dump that was generated
string last_dump_name;
// A temp dir
AutoTempDir temp_dir;
// Counter just to ensure that we don't hit the same port again
static int i;
void SetUp() {
sprintf(mach_port_name,
"com.google.breakpad.ServerTest.%d.%d", getpid(),
CrashGenerationServerTest::i++);
}
};
int CrashGenerationServerTest::i = 0;
// Test that starting and stopping a server works
TEST_F(CrashGenerationServerTest, testStartStopServer) {
CrashGenerationServer server(mach_port_name,
NULL, // dump callback
NULL, // dump context
NULL, // exit callback
NULL, // exit context
false, // generate dumps
""); // dump path
ASSERT_TRUE(server.Start());
ASSERT_TRUE(server.Stop());
}
// Test that requesting a dump via CrashGenerationClient works
// Test without actually dumping
TEST_F(CrashGenerationServerTest, testRequestDumpNoDump) {
CrashGenerationServer server(mach_port_name,
NULL, // dump callback
NULL, // dump context
NULL, // exit callback
NULL, // exit context
false, // don't generate dumps
temp_dir.path); // dump path
ASSERT_TRUE(server.Start());
pid_t pid = fork();
ASSERT_NE(-1, pid);
if (pid == 0) {
CrashGenerationClient client(mach_port_name);
bool result = client.RequestDump();
exit(result ? 0 : 1);
}
int ret;
ASSERT_EQ(pid, waitpid(pid, &ret, 0));
EXPECT_TRUE(WIFEXITED(ret));
EXPECT_EQ(0, WEXITSTATUS(ret));
EXPECT_TRUE(server.Stop());
// check that no minidump was written
string pattern = temp_dir.path + "/*";
glob_t dirContents;
ret = glob(pattern.c_str(), GLOB_NOSORT, NULL, &dirContents);
EXPECT_EQ(GLOB_NOMATCH, ret);
if (ret != GLOB_NOMATCH)
globfree(&dirContents);
}
void dumpCallback(void *context, const ClientInfo &client_info,
const std::string &file_path) {
if (context) {
CrashGenerationServerTest* self =
reinterpret_cast<CrashGenerationServerTest*>(context);
if (!file_path.empty())
self->last_dump_name = file_path;
}
}
void *RequestDump(void *context) {
CrashGenerationClient client((const char*)context);
bool result = client.RequestDump();
return (void*)(result ? 0 : 1);
}
// Test that actually writing a minidump works
TEST_F(CrashGenerationServerTest, testRequestDump) {
CrashGenerationServer server(mach_port_name,
dumpCallback, // dump callback
this, // dump context
NULL, // exit callback
NULL, // exit context
true, // generate dumps
temp_dir.path); // dump path
ASSERT_TRUE(server.Start());
pid_t pid = fork();
ASSERT_NE(-1, pid);
if (pid == 0) {
// Have to spawn off a separate thread to request the dump,
// because MinidumpGenerator assumes the handler thread is not
// the only thread
pthread_t thread;
if (pthread_create(&thread, NULL, RequestDump, (void*)mach_port_name) != 0)
exit(1);
void* result;
pthread_join(thread, &result);
exit(reinterpret_cast<intptr_t>(result));
}
int ret;
ASSERT_EQ(pid, waitpid(pid, &ret, 0));
EXPECT_TRUE(WIFEXITED(ret));
EXPECT_EQ(0, WEXITSTATUS(ret));
EXPECT_TRUE(server.Stop());
// check that minidump was written
ASSERT_FALSE(last_dump_name.empty());
struct stat st;
EXPECT_EQ(0, stat(last_dump_name.c_str(), &st));
EXPECT_LT(0, st.st_size);
}
static void Crasher() {
int *a = (int*)0x42;
fprintf(stdout, "Going to crash...\n");
fprintf(stdout, "A = %d", *a);
}
// Test that crashing a child process with an OOP ExceptionHandler installed
// results in a minidump being written by the CrashGenerationServer in
// the parent.
TEST_F(CrashGenerationServerTest, testChildProcessCrash) {
CrashGenerationServer server(mach_port_name,
dumpCallback, // dump callback
this, // dump context
NULL, // exit callback
NULL, // exit context
true, // generate dumps
temp_dir.path); // dump path
ASSERT_TRUE(server.Start());
pid_t pid = fork();
ASSERT_NE(-1, pid);
if (pid == 0) {
// Instantiate an OOP exception handler.
ExceptionHandler eh("", NULL, NULL, NULL, true, mach_port_name);
Crasher();
// not reached
exit(0);
}
int ret;
ASSERT_EQ(pid, waitpid(pid, &ret, 0));
EXPECT_FALSE(WIFEXITED(ret));
EXPECT_TRUE(server.Stop());
// check that minidump was written
ASSERT_FALSE(last_dump_name.empty());
struct stat st;
EXPECT_EQ(0, stat(last_dump_name.c_str(), &st));
EXPECT_LT(0, st.st_size);
}
} // namespace

View file

@ -36,6 +36,7 @@
#include "client/mac/handler/exception_handler.h"
#include "client/mac/tests/auto_tempdir.h"
namespace {
using std::string;
using google_breakpad::AutoTempDir;
using google_breakpad::ExceptionHandler;
@ -76,7 +77,7 @@ TEST(ExceptionHandler, InProcess) {
pid_t pid = fork();
if (pid == 0) {
close(fds[0]);
ExceptionHandler eh(tempDir.path, NULL, MDCallback, &fds[1], true);
ExceptionHandler eh(tempDir.path, NULL, MDCallback, &fds[1], true, NULL);
// crash
SoonToCrash();
// not reached
@ -99,3 +100,5 @@ TEST(ExceptionHandler, InProcess) {
EXPECT_NE(0, WIFEXITED(ret));
EXPECT_EQ(0, WEXITSTATUS(ret));
}
}

View file

@ -255,11 +255,11 @@ class MachSendMessage : public MachMessage {
class ReceivePort {
public:
// Creates a new mach port for receiving messages and registers a name for it
ReceivePort(const char *receive_port_name);
explicit ReceivePort(const char *receive_port_name);
// Given an already existing mach port, use it. We take ownership of the
// port and deallocate it in our destructor.
ReceivePort(mach_port_t receive_port);
explicit ReceivePort(mach_port_t receive_port);
// Create a new mach port for receiving messages
ReceivePort();
@ -285,11 +285,11 @@ class ReceivePort {
class MachPortSender {
public:
// get a port with send rights corresponding to a named registered service
MachPortSender(const char *receive_port_name);
explicit MachPortSender(const char *receive_port_name);
// Given an already existing mach port, use it.
MachPortSender(mach_port_t send_port);
explicit MachPortSender(mach_port_t send_port);
kern_return_t SendMessage(MachSendMessage &message,
mach_msg_timeout_t timeout);

View file

@ -240,8 +240,11 @@ kern_return_t ReceivePort::WaitForMessage(MachReceiveMessage *out_message,
out_message->head.msgh_reserved = 0;
out_message->head.msgh_id = 0;
mach_msg_option_t options = MACH_RCV_MSG;
if (timeout != MACH_MSG_TIMEOUT_NONE)
options |= MACH_RCV_TIMEOUT;
kern_return_t result = mach_msg(&out_message->head,
MACH_RCV_MSG | MACH_RCV_TIMEOUT,
options,
0,
sizeof(MachMessage),
port_,

View file

@ -0,0 +1,56 @@
// 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.
// Inline implementation of ScopedTaskSuspend, which suspends a Mach
// task for the duration of its scope.
#ifndef GOOGLE_BREAKPAD_COMMON_MAC_SCOPED_TASK_SUSPEND_H_
#define GOOGLE_BREAKPAD_COMMON_MAC_SCOPED_TASK_SUSPEND_H_
#include <mach/mach.h>
namespace google_breakpad {
class ScopedTaskSuspend {
public:
explicit ScopedTaskSuspend(mach_port_t target) : target_(target) {
task_suspend(target_);
}
~ScopedTaskSuspend() {
task_resume(target_);
}
private:
mach_port_t target_;
};
} // namespace google_breakpad
#endif // GOOGLE_BREAKPAD_COMMON_MAC_SCOPED_TASK_SUSPEND_H_