aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorted.mielczarek@gmail.com <ted.mielczarek@gmail.com@4c0a9323-5329-0410-9bdc-e9ce6186880e>2010-12-16 22:52:38 +0000
committerted.mielczarek@gmail.com <ted.mielczarek@gmail.com@4c0a9323-5329-0410-9bdc-e9ce6186880e>2010-12-16 22:52:38 +0000
commitc45b12b4225be716eba98f8305eebe36b2b19dbb (patch)
tree04abc736760349d6d8d4880c3e3d75cfb21197fc
parentAllow out-of-process minidump generation to work on processes of a different ... (diff)
downloadbreakpad-c45b12b4225be716eba98f8305eebe36b2b19dbb.tar.xz
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
-rw-r--r--src/client/mac/Breakpad.xcodeproj/project.pbxproj39
-rw-r--r--src/client/mac/crash_generation/crash_generation_client.cc3
-rw-r--r--src/client/mac/crash_generation/crash_generation_server.h8
-rw-r--r--src/client/mac/handler/minidump_generator.cc7
-rw-r--r--src/client/mac/tests/crash_generation_server_test.cc124
-rw-r--r--src/client/mac/tests/minidump_generator_test.cc94
-rw-r--r--src/client/mac/tests/minidump_generator_test_helper.cc39
-rw-r--r--src/client/mac/tests/spawn_child_process.h149
8 files changed, 346 insertions, 117 deletions
diff --git a/src/client/mac/Breakpad.xcodeproj/project.pbxproj b/src/client/mac/Breakpad.xcodeproj/project.pbxproj
index 7e143406..83a3f3c7 100644
--- a/src/client/mac/Breakpad.xcodeproj/project.pbxproj
+++ b/src/client/mac/Breakpad.xcodeproj/project.pbxproj
@@ -60,6 +60,25 @@
D244536C12426F00009BBCE0 /* pathname_stripper.cc in Sources */ = {isa = PBXBuildFile; fileRef = D244535312426EBB009BBCE0 /* pathname_stripper.cc */; };
D244536D12426F00009BBCE0 /* basic_code_modules.cc in Sources */ = {isa = PBXBuildFile; fileRef = D244534F12426E98009BBCE0 /* basic_code_modules.cc */; };
D244540B12439BA0009BBCE0 /* memory_unittest.cc in Sources */ = {isa = PBXBuildFile; fileRef = D244540A12439BA0009BBCE0 /* memory_unittest.cc */; };
+ D246417012BAA40E005170D0 /* exception_handler.cc in Sources */ = {isa = PBXBuildFile; fileRef = F92C536D0ECCE3FD009BE4BA /* exception_handler.cc */; };
+ D246417112BAA41C005170D0 /* crash_generation_client.cc in Sources */ = {isa = PBXBuildFile; fileRef = D2F9A4C6121336C7002747C1 /* crash_generation_client.cc */; };
+ D246417512BAA438005170D0 /* minidump_generator.cc in Sources */ = {isa = PBXBuildFile; fileRef = F92C536F0ECCE3FD009BE4BA /* minidump_generator.cc */; };
+ D246417612BAA43F005170D0 /* dynamic_images.cc in Sources */ = {isa = PBXBuildFile; fileRef = F92C536B0ECCE3FD009BE4BA /* dynamic_images.cc */; };
+ D246417712BAA444005170D0 /* breakpad_nlist_64.cc in Sources */ = {isa = PBXBuildFile; fileRef = F92C53690ECCE3FD009BE4BA /* breakpad_nlist_64.cc */; };
+ D246418412BAA4BA005170D0 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0867D69BFE84028FC02AAC07 /* Foundation.framework */; };
+ D246418812BAA4E3005170D0 /* string_utilities.cc in Sources */ = {isa = PBXBuildFile; fileRef = F92C53820ECCE635009BE4BA /* string_utilities.cc */; };
+ D246418C12BAA508005170D0 /* minidump_file_writer.cc in Sources */ = {isa = PBXBuildFile; fileRef = F92C538F0ECCE70A009BE4BA /* minidump_file_writer.cc */; };
+ D246419012BAA52A005170D0 /* string_conversion.cc in Sources */ = {isa = PBXBuildFile; fileRef = F92C53850ECCE6AD009BE4BA /* string_conversion.cc */; };
+ D246419112BAA52F005170D0 /* convert_UTF.c in Sources */ = {isa = PBXBuildFile; fileRef = F92C53870ECCE6C0009BE4BA /* convert_UTF.c */; };
+ D246419512BAA54C005170D0 /* file_id.cc in Sources */ = {isa = PBXBuildFile; fileRef = F92C53740ECCE635009BE4BA /* file_id.cc */; };
+ D246419612BAA55A005170D0 /* macho_id.cc in Sources */ = {isa = PBXBuildFile; fileRef = F92C537A0ECCE635009BE4BA /* macho_id.cc */; };
+ D246419C12BAA65F005170D0 /* libcrypto.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 8B4BDAA7120124EA009C7060 /* libcrypto.dylib */; };
+ D24641A012BAA67F005170D0 /* macho_walker.cc in Sources */ = {isa = PBXBuildFile; fileRef = F92C537E0ECCE635009BE4BA /* macho_walker.cc */; };
+ D24641AF12BAA82D005170D0 /* macho_utilities.cc in Sources */ = {isa = PBXBuildFile; fileRef = F92C537C0ECCE635009BE4BA /* macho_utilities.cc */; };
+ D24641EC12BAC6FB005170D0 /* logging.cc in Sources */ = {isa = PBXBuildFile; fileRef = D244535112426EBB009BBCE0 /* logging.cc */; };
+ D24641ED12BAC6FB005170D0 /* minidump.cc in Sources */ = {isa = PBXBuildFile; fileRef = D244535212426EBB009BBCE0 /* minidump.cc */; };
+ D24641EE12BAC6FB005170D0 /* pathname_stripper.cc in Sources */ = {isa = PBXBuildFile; fileRef = D244535312426EBB009BBCE0 /* pathname_stripper.cc */; };
+ D24641EF12BAC6FB005170D0 /* basic_code_modules.cc in Sources */ = {isa = PBXBuildFile; fileRef = D244534F12426E98009BBCE0 /* basic_code_modules.cc */; };
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 */; };
@@ -671,6 +690,8 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
+ D246418412BAA4BA005170D0 /* Foundation.framework in Frameworks */,
+ D246419C12BAA65F005170D0 /* libcrypto.dylib in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -1603,6 +1624,19 @@
files = (
D23F4BB112A868CB00686C8D /* minidump_generator_test_helper.cc in Sources */,
D23F4BB812A868F700686C8D /* MachIPC.mm in Sources */,
+ D246417012BAA40E005170D0 /* exception_handler.cc in Sources */,
+ D246417112BAA41C005170D0 /* crash_generation_client.cc in Sources */,
+ D246417512BAA438005170D0 /* minidump_generator.cc in Sources */,
+ D246417612BAA43F005170D0 /* dynamic_images.cc in Sources */,
+ D246417712BAA444005170D0 /* breakpad_nlist_64.cc in Sources */,
+ D246418812BAA4E3005170D0 /* string_utilities.cc in Sources */,
+ D246418C12BAA508005170D0 /* minidump_file_writer.cc in Sources */,
+ D246419012BAA52A005170D0 /* string_conversion.cc in Sources */,
+ D246419112BAA52F005170D0 /* convert_UTF.c in Sources */,
+ D246419512BAA54C005170D0 /* file_id.cc in Sources */,
+ D246419612BAA55A005170D0 /* macho_id.cc in Sources */,
+ D24641A012BAA67F005170D0 /* macho_walker.cc in Sources */,
+ D24641AF12BAA82D005170D0 /* macho_utilities.cc in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -1636,6 +1670,10 @@
D2F9A53A121383A1002747C1 /* macho_utilities.cc in Sources */,
D2F9A53B121383A1002747C1 /* macho_walker.cc in Sources */,
D2F9A53C121383A1002747C1 /* string_utilities.cc in Sources */,
+ D24641EC12BAC6FB005170D0 /* logging.cc in Sources */,
+ D24641ED12BAC6FB005170D0 /* minidump.cc in Sources */,
+ D24641EE12BAC6FB005170D0 /* pathname_stripper.cc in Sources */,
+ D24641EF12BAC6FB005170D0 /* basic_code_modules.cc in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -2109,6 +2147,7 @@
buildSettings = {
DEBUG_INFORMATION_FORMAT = dwarf;
GCC_INLINES_ARE_PRIVATE_EXTERN = NO;
+ GCC_PREPROCESSOR_DEFINITIONS = "BP_LOGGING_INCLUDE=\\\"client/mac/tests/testlogging.h\\\"";
GCC_SYMBOLS_PRIVATE_EXTERN = NO;
HEADER_SEARCH_PATHS = (
../..,
diff --git a/src/client/mac/crash_generation/crash_generation_client.cc b/src/client/mac/crash_generation/crash_generation_client.cc
index 07428876..ceeb3b32 100644
--- a/src/client/mac/crash_generation/crash_generation_client.cc
+++ b/src/client/mac/crash_generation/crash_generation_client.cc
@@ -54,7 +54,7 @@ bool CrashGenerationClient::RequestDumpForException(
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)
@@ -66,7 +66,6 @@ bool CrashGenerationClient::RequestDumpForException(
MachReceiveMessage acknowledge_message;
result = acknowledge_port.WaitForMessage(&acknowledge_message,
kReceiveTimeoutMs);
-
return result == KERN_SUCCESS;
}
diff --git a/src/client/mac/crash_generation/crash_generation_server.h b/src/client/mac/crash_generation/crash_generation_server.h
index e174f9d0..6e6cb44d 100644
--- a/src/client/mac/crash_generation/crash_generation_server.h
+++ b/src/client/mac/crash_generation/crash_generation_server.h
@@ -30,6 +30,8 @@
#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"
@@ -47,9 +49,9 @@ enum {
// Exception details sent by the client when requesting a dump.
struct ExceptionInfo {
- int exception_type;
- int exception_code;
- int exception_subcode;
+ int32_t exception_type;
+ int32_t exception_code;
+ int32_t exception_subcode;
};
class CrashGenerationServer {
diff --git a/src/client/mac/handler/minidump_generator.cc b/src/client/mac/handler/minidump_generator.cc
index 2e9765ad..8d670429 100644
--- a/src/client/mac/handler/minidump_generator.cc
+++ b/src/client/mac/handler/minidump_generator.cc
@@ -870,13 +870,10 @@ MinidumpGenerator::WriteExceptionStream(MDRawDirectory *exception_stream) {
exception_ptr->exception_record.exception_flags = exception_code_;
breakpad_thread_state_data_t state;
- mach_msg_type_number_t stateCount
+ mach_msg_type_number_t state_count
= static_cast<mach_msg_type_number_t>(sizeof(state));
- if (thread_get_state(exception_thread_,
- BREAKPAD_MACHINE_THREAD_STATE,
- state,
- &stateCount) != KERN_SUCCESS)
+ if (!GetThreadState(exception_thread_, state, &state_count))
return false;
if (!WriteContext(state, &exception_ptr->thread_context))
diff --git a/src/client/mac/tests/crash_generation_server_test.cc b/src/client/mac/tests/crash_generation_server_test.cc
index 1ea5bf16..fdb9cdd1 100644
--- a/src/client/mac/tests/crash_generation_server_test.cc
+++ b/src/client/mac/tests/crash_generation_server_test.cc
@@ -44,6 +44,15 @@
#include "client/mac/crash_generation/crash_generation_server.h"
#include "client/mac/handler/exception_handler.h"
#include "client/mac/tests/auto_tempdir.h"
+#include "client/mac/tests/spawn_child_process.h"
+#include "google_breakpad/processor/minidump.h"
+
+namespace google_breakpad {
+// This acts as the log sink for INFO logging from the processor
+// logging code. The logging output confuses XCode and makes it think
+// there are unit test failures. testlogging.h handles the overriding.
+std::ostringstream info_log;
+}
namespace {
using std::string;
@@ -52,7 +61,16 @@ using google_breakpad::ClientInfo;
using google_breakpad::CrashGenerationClient;
using google_breakpad::CrashGenerationServer;
using google_breakpad::ExceptionHandler;
+using google_breakpad::Minidump;
+using google_breakpad::MinidumpContext;
+using google_breakpad::MinidumpException;
+using google_breakpad::MinidumpModule;
+using google_breakpad::MinidumpModuleList;
+using google_breakpad::MinidumpSystemInfo;
+using google_breakpad::MinidumpThread;
+using google_breakpad::MinidumpThreadList;
using testing::Test;
+using namespace google_breakpad_test;
class CrashGenerationServerTest : public Test {
public:
@@ -217,7 +235,111 @@ TEST_F(CrashGenerationServerTest, testChildProcessCrash) {
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);
+ EXPECT_LT(0, st.st_size);
+
+ // Read the minidump, sanity check some data.
+ Minidump minidump(last_dump_name.c_str());
+ ASSERT_TRUE(minidump.Read());
+
+ MinidumpSystemInfo* system_info = minidump.GetSystemInfo();
+ ASSERT_TRUE(system_info);
+ const MDRawSystemInfo* raw_info = system_info->system_info();
+ ASSERT_TRUE(raw_info);
+ EXPECT_EQ(kNativeArchitecture, raw_info->processor_architecture);
+
+ MinidumpThreadList* thread_list = minidump.GetThreadList();
+ ASSERT_TRUE(thread_list);
+ ASSERT_EQ((unsigned int)1, thread_list->thread_count());
+
+ MinidumpThread* main_thread = thread_list->GetThreadAtIndex(0);
+ ASSERT_TRUE(main_thread);
+ MinidumpContext* context = main_thread->GetContext();
+ ASSERT_TRUE(context);
+ EXPECT_EQ(kNativeContext, context->GetContextCPU());
+
+ MinidumpModuleList* module_list = minidump.GetModuleList();
+ ASSERT_TRUE(module_list);
+ const MinidumpModule* main_module = module_list->GetMainModule();
+ ASSERT_TRUE(main_module);
+ EXPECT_EQ(GetExecutablePath(), main_module->code_file());
+}
+
+#if (MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_6) && \
+ (defined(__x86_64__) || defined(__i386__))
+// Test that crashing a child process of a different architecture
+// produces a valid minidump.
+TEST_F(CrashGenerationServerTest, testChildProcessCrashCrossArchitecture) {
+ 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());
+
+ // Spawn a child process
+ string helper_path = GetHelperPath();
+ const char* argv[] = {
+ helper_path.c_str(),
+ "crash",
+ mach_port_name,
+ NULL
+ };
+ pid_t pid = spawn_child_process(argv);
+ ASSERT_NE(-1, pid);
+
+ 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);
+
+const MDCPUArchitecture kExpectedArchitecture =
+#if defined(__x86_64__)
+ MD_CPU_ARCHITECTURE_X86
+#elif defined(__i386__)
+ MD_CPU_ARCHITECTURE_AMD64
+#endif
+ ;
+const u_int32_t kExpectedContext =
+#if defined(__i386__)
+ MD_CONTEXT_AMD64
+#elif defined(__x86_64__)
+ MD_CONTEXT_X86
+#endif
+ ;
+
+ // Read the minidump, sanity check some data.
+ Minidump minidump(last_dump_name.c_str());
+ ASSERT_TRUE(minidump.Read());
+
+ MinidumpSystemInfo* system_info = minidump.GetSystemInfo();
+ ASSERT_TRUE(system_info);
+ const MDRawSystemInfo* raw_info = system_info->system_info();
+ ASSERT_TRUE(raw_info);
+ EXPECT_EQ(kExpectedArchitecture, raw_info->processor_architecture);
+
+ MinidumpThreadList* thread_list = minidump.GetThreadList();
+ ASSERT_TRUE(thread_list);
+ ASSERT_EQ((unsigned int)1, thread_list->thread_count());
+
+ MinidumpThread* main_thread = thread_list->GetThreadAtIndex(0);
+ ASSERT_TRUE(main_thread);
+ MinidumpContext* context = main_thread->GetContext();
+ ASSERT_TRUE(context);
+ EXPECT_EQ(kExpectedContext, context->GetContextCPU());
+
+ MinidumpModuleList* module_list = minidump.GetModuleList();
+ ASSERT_TRUE(module_list);
+ const MinidumpModule* main_module = module_list->GetMainModule();
+ ASSERT_TRUE(main_module);
+ EXPECT_EQ(helper_path, main_module->code_file());
}
+#endif
} // namespace
diff --git a/src/client/mac/tests/minidump_generator_test.cc b/src/client/mac/tests/minidump_generator_test.cc
index 68bc1de6..f9cf75af 100644
--- a/src/client/mac/tests/minidump_generator_test.cc
+++ b/src/client/mac/tests/minidump_generator_test.cc
@@ -33,11 +33,6 @@
#ifndef MAC_OS_X_VERSION_10_6
#define MAC_OS_X_VERSION_10_6 1060
#endif
-#include <crt_externs.h>
-#include <mach-o/dyld.h>
-#if MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_6
-#include <spawn.h>
-#endif
#include <sys/stat.h>
#include <unistd.h>
@@ -47,6 +42,7 @@
#include "breakpad_googletest_includes.h"
#include "client/mac/handler/minidump_generator.h"
#include "client/mac/tests/auto_tempdir.h"
+#include "client/mac/tests/spawn_child_process.h"
#include "common/mac/MachIPC.h"
#include "google_breakpad/processor/minidump.h"
@@ -75,38 +71,7 @@ using google_breakpad::MinidumpThread;
using google_breakpad::MinidumpThreadList;
using google_breakpad::ReceivePort;
using testing::Test;
-
-const MDCPUArchitecture kNativeArchitecture =
-#if defined(__i386__)
- MD_CPU_ARCHITECTURE_X86
-#elif defined(__x86_64__)
- MD_CPU_ARCHITECTURE_AMD64
-#elif defined(__ppc__) || defined(__ppc64__)
- MD_CPU_ARCHITECTURE_PPC
-#else
-#error "This test has not been ported to this CPU architecture."
-#endif
- ;
-
-const u_int32_t kNativeContext =
-#if defined(__i386__)
- MD_CONTEXT_X86
-#elif defined(__x86_64__)
- MD_CONTEXT_AMD64
-#elif defined(__ppc__) || defined(__ppc64__)
- MD_CONTEXT_PPC
-#else
-#error "This test has not been ported to this CPU architecture."
-#endif
- ;
-
-static string GetExecutablePath() {
- char self_path[PATH_MAX];
- uint32_t size = sizeof(self_path);
- if (_NSGetExecutablePath(self_path, &size) != 0)
- return "";
- return self_path;
-}
+using namespace google_breakpad_test;
class MinidumpGeneratorTest : public Test {
public:
@@ -260,65 +225,10 @@ TEST_F(MinidumpGeneratorTest, OutOfProcess) {
EXPECT_EQ(GetExecutablePath(), main_module->code_file());
}
-static string GetHelperPath() {
- string helper_path(GetExecutablePath());
- size_t pos = helper_path.rfind('/');
- if (pos == string::npos)
- return "";
-
- helper_path.erase(pos + 1);
- helper_path += "minidump_generator_test_helper";
- return helper_path;
-}
-
// This test fails on 10.5, but I don't have easy access to a 10.5 machine,
// so it's simpler to just limit it to 10.6 for now.
#if (MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_6) && \
(defined(__x86_64__) || defined(__i386__))
-static pid_t spawn_child_process(const char** argv) {
- posix_spawnattr_t spawnattr;
- if (posix_spawnattr_init(&spawnattr) != 0)
- return (pid_t)-1;
-
- cpu_type_t pref_cpu_types[2] = {
-#if defined(__x86_64__)
- CPU_TYPE_X86,
-#elif defined(__i386__)
- CPU_TYPE_X86_64,
-#endif
- CPU_TYPE_ANY
- };
-
- // Set spawn attributes.
- size_t attr_count = sizeof(pref_cpu_types) / sizeof(pref_cpu_types[0]);
- size_t attr_ocount = 0;
- if (posix_spawnattr_setbinpref_np(&spawnattr,
- attr_count,
- pref_cpu_types,
- &attr_ocount) != 0 ||
- attr_ocount != attr_count) {
- posix_spawnattr_destroy(&spawnattr);
- return (pid_t)-1;
- }
-
- // Create an argv array.
- vector<char*> argv_v;
- while (*argv) {
- argv_v.push_back(strdup(*argv));
- argv++;
- }
- argv_v.push_back(NULL);
- pid_t new_pid = 0;
- int result = posix_spawnp(&new_pid, argv_v[0], NULL, &spawnattr,
- &argv_v[0], *_NSGetEnviron());
- posix_spawnattr_destroy(&spawnattr);
-
- for (unsigned i = 0; i < argv_v.size(); i++) {
- free(argv_v[i]);
- }
-
- return result == 0 ? new_pid : -1;
-}
TEST_F(MinidumpGeneratorTest, CrossArchitectureDump) {
const int kTimeoutMs = 5000;
diff --git a/src/client/mac/tests/minidump_generator_test_helper.cc b/src/client/mac/tests/minidump_generator_test_helper.cc
index 41ef449d..4e8ce3cf 100644
--- a/src/client/mac/tests/minidump_generator_test_helper.cc
+++ b/src/client/mac/tests/minidump_generator_test_helper.cc
@@ -31,9 +31,11 @@
// minidump_generator_test.cc can launch to test certain things
// that require a separate executable.
-#include "common/mac/MachIPC.h"
#include <unistd.h>
+#include "client/mac/handler/exception_handler.h"
+#include "common/mac/MachIPC.h"
+
using google_breakpad::MachPortSender;
using google_breakpad::MachReceiveMessage;
using google_breakpad::MachSendMessage;
@@ -43,21 +45,30 @@ int main(int argc, char** argv) {
if (argc < 2)
return 1;
- const int kTimeoutMs = 2000;
- // Send parent process the task and thread ports.
- MachSendMessage child_message(0);
- child_message.AddDescriptor(mach_task_self());
- child_message.AddDescriptor(mach_thread_self());
+ if (strcmp(argv[1], "crash") != 0) {
+ const int kTimeoutMs = 2000;
+ // Send parent process the task and thread ports.
+ MachSendMessage child_message(0);
+ child_message.AddDescriptor(mach_task_self());
+ child_message.AddDescriptor(mach_thread_self());
- MachPortSender child_sender(argv[1]);
- if (child_sender.SendMessage(child_message, kTimeoutMs) != KERN_SUCCESS) {
- fprintf(stderr, "Error sending message from child process!\n");
- exit(1);
- }
+ MachPortSender child_sender(argv[1]);
+ if (child_sender.SendMessage(child_message, kTimeoutMs) != KERN_SUCCESS) {
+ fprintf(stderr, "Error sending message from child process!\n");
+ exit(1);
+ }
- // Loop forever.
- while (true) {
- sleep(100);
+ // Loop forever.
+ while (true) {
+ sleep(100);
+ }
+ } else if (argc == 3 && strcmp(argv[1], "crash") == 0) {
+ // Instantiate an OOP exception handler
+ google_breakpad::ExceptionHandler eh("", NULL, NULL, NULL, true, argv[2]);
+ // and crash.
+ int *a = (int*)0x42;
+ *a = 1;
}
+
return 0;
}
diff --git a/src/client/mac/tests/spawn_child_process.h b/src/client/mac/tests/spawn_child_process.h
new file mode 100644
index 00000000..bdd293b1
--- /dev/null
+++ b/src/client/mac/tests/spawn_child_process.h
@@ -0,0 +1,149 @@
+// 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.
+
+// Utility functions for spawning a helper process using a different
+// CPU architecture.
+
+#ifndef GOOGLE_BREAKPAD_CLIENT_MAC_TESTS_SPAWN_CHILD_PROCESS
+#define GOOGLE_BREAKPAD_CLIENT_MAC_TESTS_SPAWN_CHILD_PROCESS
+
+#include <AvailabilityMacros.h>
+#ifndef MAC_OS_X_VERSION_10_6
+#define MAC_OS_X_VERSION_10_6 1060
+#endif
+#include <crt_externs.h>
+#include <mach-o/dyld.h>
+#if MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_6
+#include <spawn.h>
+#endif
+
+#include <string>
+#include <vector>
+
+#include "google_breakpad/common/minidump_format.h"
+
+namespace google_breakpad_test {
+
+using std::string;
+using std::vector;
+
+const MDCPUArchitecture kNativeArchitecture =
+#if defined(__i386__)
+ MD_CPU_ARCHITECTURE_X86
+#elif defined(__x86_64__)
+ MD_CPU_ARCHITECTURE_AMD64
+#elif defined(__ppc__) || defined(__ppc64__)
+ MD_CPU_ARCHITECTURE_PPC
+#else
+#error "This file has not been ported to this CPU architecture."
+#endif
+ ;
+
+const u_int32_t kNativeContext =
+#if defined(__i386__)
+ MD_CONTEXT_X86
+#elif defined(__x86_64__)
+ MD_CONTEXT_AMD64
+#elif defined(__ppc__) || defined(__ppc64__)
+ MD_CONTEXT_PPC
+#else
+#error "This file has not been ported to this CPU architecture."
+#endif
+ ;
+
+string GetExecutablePath() {
+ char self_path[PATH_MAX];
+ uint32_t size = sizeof(self_path);
+ if (_NSGetExecutablePath(self_path, &size) != 0)
+ return "";
+ return self_path;
+}
+
+string GetHelperPath() {
+ string helper_path(GetExecutablePath());
+ size_t pos = helper_path.rfind('/');
+ if (pos == string::npos)
+ return "";
+
+ helper_path.erase(pos + 1);
+ helper_path += "minidump_generator_test_helper";
+ return helper_path;
+}
+
+#if MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_6
+
+pid_t spawn_child_process(const char** argv) {
+ posix_spawnattr_t spawnattr;
+ if (posix_spawnattr_init(&spawnattr) != 0)
+ return (pid_t)-1;
+
+ cpu_type_t pref_cpu_types[2] = {
+#if defined(__x86_64__)
+ CPU_TYPE_X86,
+#elif defined(__i386__)
+ CPU_TYPE_X86_64,
+#endif
+ CPU_TYPE_ANY
+ };
+
+ // Set spawn attributes.
+ size_t attr_count = sizeof(pref_cpu_types) / sizeof(pref_cpu_types[0]);
+ size_t attr_ocount = 0;
+ if (posix_spawnattr_setbinpref_np(&spawnattr,
+ attr_count,
+ pref_cpu_types,
+ &attr_ocount) != 0 ||
+ attr_ocount != attr_count) {
+ posix_spawnattr_destroy(&spawnattr);
+ return (pid_t)-1;
+ }
+
+ // Create an argv array.
+ vector<char*> argv_v;
+ while (*argv) {
+ argv_v.push_back(strdup(*argv));
+ argv++;
+ }
+ argv_v.push_back(NULL);
+ pid_t new_pid = 0;
+ int result = posix_spawnp(&new_pid, argv_v[0], NULL, &spawnattr,
+ &argv_v[0], *_NSGetEnviron());
+ posix_spawnattr_destroy(&spawnattr);
+
+ for (unsigned i = 0; i < argv_v.size(); i++) {
+ free(argv_v[i]);
+ }
+
+ return result == 0 ? new_pid : -1;
+}
+#endif
+
+} // namespace google_breakpad_test
+
+#endif // GOOGLE_BREAKPAD_CLIENT_MAC_TESTS_SPAWN_CHILD_PROCESS