mirror of
https://git.suyu.dev/suyu/breakpad.git
synced 2026-01-08 23:48:22 +01:00
Mac: Add support for in-process crash reporting to Breakpad.
Add new option BREAKPAD_IN_PROCESS. If YES, Breakpad will write the dump file in-process and then launch the reporter executable as a child process. Originally reviewed at https://codereview.chromium.org/571523004/ BUG=chromium:414239 R=mark@chromium.org Review URL: https://breakpad.appspot.com/1714002 git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@1375 4c0a9323-5329-0410-9bdc-e9ce6186880e
This commit is contained in:
parent
c75e316359
commit
def0b7a7b0
8 changed files with 196 additions and 49 deletions
|
|
@ -62,6 +62,7 @@
|
|||
#define BREAKPAD_EMAIL "BreakpadEmail"
|
||||
#define BREAKPAD_SERVER_TYPE "BreakpadServerType"
|
||||
#define BREAKPAD_SERVER_PARAMETER_DICT "BreakpadServerParameters"
|
||||
#define BREAKPAD_IN_PROCESS "BreakpadInProcess"
|
||||
|
||||
// The keys below are NOT user supplied, and are used internally.
|
||||
#define BREAKPAD_PROCESS_START_TIME "BreakpadProcStartTime"
|
||||
|
|
|
|||
|
|
@ -158,6 +158,11 @@ typedef bool (*BreakpadFilterCallback)(int exception_type,
|
|||
// but pass as URL parameters when
|
||||
// uploading theminidump to the crash
|
||||
// server.
|
||||
//
|
||||
// BREAKPAD_IN_PROCESS A boolean NSNumber value. If YES, Breakpad
|
||||
// will write the dump file in-process and then
|
||||
// launch the reporter executable as a child
|
||||
// process.
|
||||
//=============================================================================
|
||||
// The BREAKPAD_PRODUCT, BREAKPAD_VERSION and BREAKPAD_URL are
|
||||
// required to have non-NULL values. By default, the BREAKPAD_PRODUCT
|
||||
|
|
|
|||
|
|
@ -44,6 +44,7 @@
|
|||
#import "client/mac/Framework/Breakpad.h"
|
||||
#import "client/mac/Framework/OnDemandServer.h"
|
||||
#import "client/mac/handler/protected_memory_allocator.h"
|
||||
#include "common/mac/launch_reporter.h"
|
||||
#import "common/mac/MachIPC.h"
|
||||
#import "common/simple_string_dictionary.h"
|
||||
|
||||
|
|
@ -173,6 +174,8 @@ class Breakpad {
|
|||
}
|
||||
|
||||
bool Initialize(NSDictionary *parameters);
|
||||
bool InitializeInProcess(NSDictionary *parameters);
|
||||
bool InitializeOutOfProcess(NSDictionary *parameters);
|
||||
|
||||
bool ExtractParameters(NSDictionary *parameters);
|
||||
|
||||
|
|
@ -188,6 +191,17 @@ class Breakpad {
|
|||
int exception_subcode,
|
||||
mach_port_t crashing_thread);
|
||||
|
||||
// Dispatches to HandleMinidump().
|
||||
// This gets called instead of ExceptionHandlerDirectCallback when running
|
||||
// with the BREAKPAD_IN_PROCESS option.
|
||||
static bool HandleMinidumpCallback(const char *dump_dir,
|
||||
const char *minidump_id,
|
||||
void *context,
|
||||
bool succeeded);
|
||||
|
||||
// This is only used when BREAKPAD_IN_PROCESS is YES.
|
||||
bool HandleMinidump(const char *dump_dir, const char *minidump_id);
|
||||
|
||||
// Since ExceptionHandler (w/o namespace) is defined as typedef in OSX's
|
||||
// MachineExceptions.h, we have to explicitly name the handler.
|
||||
google_breakpad::ExceptionHandler *handler_; // The actual handler (STRONG)
|
||||
|
|
@ -265,6 +279,21 @@ bool Breakpad::ExceptionHandlerDirectCallback(void *context,
|
|||
crashing_thread);
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
bool Breakpad::HandleMinidumpCallback(const char *dump_dir,
|
||||
const char *minidump_id,
|
||||
void *context,
|
||||
bool succeeded) {
|
||||
Breakpad *breakpad = (Breakpad *)context;
|
||||
|
||||
// If our context is damaged or something, just return false to indicate that
|
||||
// the handler should continue without us.
|
||||
if (!breakpad || !succeeded)
|
||||
return false;
|
||||
|
||||
return breakpad->HandleMinidump(dump_dir, minidump_id);
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
#pragma mark -
|
||||
|
||||
|
|
@ -326,6 +355,25 @@ bool Breakpad::Initialize(NSDictionary *parameters) {
|
|||
return false;
|
||||
}
|
||||
|
||||
if ([[parameters objectForKey:@BREAKPAD_IN_PROCESS] boolValue])
|
||||
return InitializeInProcess(parameters);
|
||||
else
|
||||
return InitializeOutOfProcess(parameters);
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
bool Breakpad::InitializeInProcess(NSDictionary* parameters) {
|
||||
handler_ =
|
||||
new (gBreakpadAllocator->Allocate(
|
||||
sizeof(google_breakpad::ExceptionHandler)))
|
||||
google_breakpad::ExceptionHandler(
|
||||
config_params_->GetValueForKey(BREAKPAD_DUMP_DIRECTORY),
|
||||
0, &HandleMinidumpCallback, this, true, 0);
|
||||
return true;
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
bool Breakpad::InitializeOutOfProcess(NSDictionary* parameters) {
|
||||
// Get path to Inspector executable.
|
||||
NSString *inspectorPathString = KeyValue(@BREAKPAD_INSPECTOR_LOCATION);
|
||||
|
||||
|
|
@ -710,6 +758,16 @@ bool Breakpad::HandleException(int exception_type,
|
|||
return false;
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
bool Breakpad::HandleMinidump(const char *dump_dir, const char *minidump_id) {
|
||||
google_breakpad::ConfigFile config_file;
|
||||
config_file.WriteFile(dump_dir, config_params_, dump_dir, minidump_id);
|
||||
google_breakpad::LaunchReporter(
|
||||
config_params_->GetValueForKey(BREAKPAD_REPORTER_EXE_LOCATION),
|
||||
config_file.GetFilePath());
|
||||
return true;
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
//=============================================================================
|
||||
|
||||
|
|
|
|||
|
|
@ -36,7 +36,7 @@
|
|||
#include <sys/time.h>
|
||||
|
||||
#import "client/apple/Framework/BreakpadDefines.h"
|
||||
#import "GTMDefines.h"
|
||||
#import "common/mac/GTMDefines.h"
|
||||
|
||||
|
||||
namespace google_breakpad {
|
||||
|
|
|
|||
|
|
@ -138,7 +138,6 @@ class Inspector {
|
|||
|
||||
bool InspectTask();
|
||||
kern_return_t SendAcknowledgement();
|
||||
void LaunchReporter(const char *inConfigFilePath);
|
||||
|
||||
// The bootstrap port in which the inspector is registered and into which it
|
||||
// must check in.
|
||||
|
|
|
|||
|
|
@ -43,6 +43,7 @@
|
|||
|
||||
#import "common/mac/MachIPC.h"
|
||||
#include "common/mac/bootstrap_compat.h"
|
||||
#include "common/mac/launch_reporter.h"
|
||||
|
||||
#import "GTMDefines.h"
|
||||
|
||||
|
|
@ -76,7 +77,9 @@ void Inspector::Inspect(const char *receive_port_name) {
|
|||
if (wrote_minidump) {
|
||||
// Ask the user if he wants to upload the crash report to a server,
|
||||
// and do so if he agrees.
|
||||
LaunchReporter(config_file_.GetFilePath());
|
||||
LaunchReporter(
|
||||
config_params_.GetValueForKey(BREAKPAD_REPORTER_EXE_LOCATION),
|
||||
config_file_.GetFilePath());
|
||||
} else {
|
||||
fprintf(stderr, "Inspection of crashed process failed\n");
|
||||
}
|
||||
|
|
@ -355,51 +358,5 @@ kern_return_t Inspector::SendAcknowledgement() {
|
|||
return KERN_INVALID_NAME;
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
void Inspector::LaunchReporter(const char *inConfigFilePath) {
|
||||
// Extract the path to the reporter executable.
|
||||
const char *reporterExecutablePath =
|
||||
config_params_.GetValueForKey(BREAKPAD_REPORTER_EXE_LOCATION);
|
||||
|
||||
// Setup and launch the crash dump sender.
|
||||
const char *argv[3];
|
||||
argv[0] = reporterExecutablePath;
|
||||
argv[1] = inConfigFilePath;
|
||||
argv[2] = NULL;
|
||||
|
||||
// Launch the reporter
|
||||
pid_t pid = fork();
|
||||
|
||||
// If we're in the child, load in our new executable and run.
|
||||
// The parent will not wait for the child to complete.
|
||||
if (pid == 0) {
|
||||
execv(argv[0], (char * const *)argv);
|
||||
config_file_.Unlink(); // launch failed - get rid of config file
|
||||
_exit(1);
|
||||
}
|
||||
|
||||
// Wait until the Reporter child process exits.
|
||||
//
|
||||
|
||||
// We'll use a timeout of one minute.
|
||||
int timeoutCount = 60; // 60 seconds
|
||||
|
||||
while (timeoutCount-- > 0) {
|
||||
int status;
|
||||
pid_t result = waitpid(pid, &status, WNOHANG);
|
||||
|
||||
if (result == 0) {
|
||||
// The child has not yet finished.
|
||||
sleep(1);
|
||||
} else if (result == -1) {
|
||||
// error occurred.
|
||||
break;
|
||||
} else {
|
||||
// child has finished
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace google_breakpad
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue