diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/client/mac/Breakpad.xcodeproj/project.pbxproj | 39 | ||||
-rw-r--r-- | src/client/mac/crash_generation/crash_generation_client.cc | 3 | ||||
-rw-r--r-- | src/client/mac/crash_generation/crash_generation_server.h | 8 | ||||
-rw-r--r-- | src/client/mac/handler/minidump_generator.cc | 7 | ||||
-rw-r--r-- | src/client/mac/tests/crash_generation_server_test.cc | 124 | ||||
-rw-r--r-- | src/client/mac/tests/minidump_generator_test.cc | 94 | ||||
-rw-r--r-- | src/client/mac/tests/minidump_generator_test_helper.cc | 39 | ||||
-rw-r--r-- | src/client/mac/tests/spawn_child_process.h | 149 |
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 |