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:
parent
0344a368de
commit
c45b12b422
@ -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 = (
|
||||
../..,
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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 {
|
||||
|
@ -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))
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
149
src/client/mac/tests/spawn_child_process.h
Normal file
149
src/client/mac/tests/spawn_child_process.h
Normal 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
|
Loading…
Reference in New Issue
Block a user