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
This commit is contained in:
ted.mielczarek@gmail.com 2010-12-16 22:52:38 +00:00
parent 0344a368de
commit c45b12b422
8 changed files with 346 additions and 117 deletions

View File

@ -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 = (
../..,

View File

@ -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;
}

View File

@ -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 {

View File

@ -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))

View File

@ -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

View File

@ -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;

View File

@ -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);
}
} 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;
}
// Loop forever.
while (true) {
sleep(100);
}
return 0;
}

View File

@ -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