зеркало из https://github.com/mozilla/pjs.git
bug 423674 - update to breakpad revision 250. rs=sayrer
This commit is contained in:
Родитель
b57e217417
Коммит
dbee1effa5
|
@ -42,12 +42,9 @@
|
|||
#include "common/solaris/guid_creator.h"
|
||||
#include "common/solaris/message_output.h"
|
||||
#include "google_breakpad/common/minidump_format.h"
|
||||
#include "processor/scoped_ptr.h"
|
||||
|
||||
namespace google_breakpad {
|
||||
|
||||
static const int kStackSize = 1024 * 1024;
|
||||
|
||||
// Signals that we are interested.
|
||||
static const int kSigTable[] = {
|
||||
SIGSEGV,
|
||||
|
@ -68,10 +65,9 @@ ExceptionHandler::ExceptionHandler(const string &dump_path,
|
|||
void *callback_context,
|
||||
bool install_handler)
|
||||
: filter_(filter),
|
||||
handler_thread_(0),
|
||||
handler_return_value_(false),
|
||||
callback_(callback),
|
||||
callback_context_(callback_context),
|
||||
dump_path_(),
|
||||
installed_handler_(install_handler) {
|
||||
set_dump_path(dump_path);
|
||||
|
||||
|
@ -79,19 +75,6 @@ ExceptionHandler::ExceptionHandler(const string &dump_path,
|
|||
SetupHandler();
|
||||
}
|
||||
|
||||
sem_init(&handler_start_semaphore_, 0, 0);
|
||||
sem_init(&handler_finish_semaphore_, 0, 0);
|
||||
pthread_attr_t attr;
|
||||
scoped_array<char> thread_stack;
|
||||
|
||||
pthread_attr_init(&attr);
|
||||
thread_stack.reset(new char[kStackSize]);
|
||||
pthread_attr_setstackaddr(&attr, thread_stack.get());
|
||||
pthread_attr_setstacksize(&attr, kStackSize);
|
||||
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
|
||||
pthread_create(&handler_thread_, &attr, ExceptionHandlerThreadMain, this);
|
||||
pthread_attr_destroy(&attr);
|
||||
|
||||
if (install_handler) {
|
||||
pthread_mutex_lock(&handler_stack_mutex_);
|
||||
|
||||
|
@ -125,34 +108,11 @@ ExceptionHandler::~ExceptionHandler() {
|
|||
delete handler_stack_;
|
||||
handler_stack_ = NULL;
|
||||
}
|
||||
pthread_exit((void *)handler_thread_);
|
||||
sem_destroy(&handler_start_semaphore_);
|
||||
sem_destroy(&handler_finish_semaphore_);
|
||||
pthread_mutex_unlock(&handler_stack_mutex_);
|
||||
}
|
||||
|
||||
// static
|
||||
void* ExceptionHandler::ExceptionHandlerThreadMain(void *lpParameter) {
|
||||
ExceptionHandler *self = reinterpret_cast<ExceptionHandler *>(lpParameter);
|
||||
assert(self);
|
||||
|
||||
while (true) {
|
||||
if (!sem_wait(&(self->handler_start_semaphore_))) {
|
||||
// Perform the requested action.
|
||||
self->handler_return_value_ = self->InternalWriteMinidump();
|
||||
|
||||
// Allow the requesting thread to proceed.
|
||||
sem_post(&(self->handler_finish_semaphore_));
|
||||
}
|
||||
}
|
||||
|
||||
// Not reached. This thread will be terminated by ExceptionHandler's
|
||||
// destructor.
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool ExceptionHandler::WriteMinidump() {
|
||||
return WriteMinidumpOnHandlerThread(0);
|
||||
return InternalWriteMinidump(0, 0, NULL);
|
||||
}
|
||||
|
||||
// static
|
||||
|
@ -161,7 +121,7 @@ bool ExceptionHandler::WriteMinidump(const string &dump_path,
|
|||
void *callback_context) {
|
||||
ExceptionHandler handler(dump_path, NULL, callback,
|
||||
callback_context, false);
|
||||
return handler.WriteMinidumpOnHandlerThread(0);
|
||||
return handler.InternalWriteMinidump(0, 0, NULL);
|
||||
}
|
||||
|
||||
void ExceptionHandler::SetupHandler() {
|
||||
|
@ -204,22 +164,22 @@ void ExceptionHandler::TeardownAllHandlers() {
|
|||
}
|
||||
}
|
||||
|
||||
bool ExceptionHandler::WriteMinidumpOnHandlerThread(int signo) {
|
||||
// Set up data to be passed in to the handler thread.
|
||||
signo_ = signo;
|
||||
|
||||
// This causes the handler thread to call InternalWriteMinidump.
|
||||
sem_post(&handler_start_semaphore_);
|
||||
|
||||
// Wait until InternalWriteMinidump is done and collect its return value.
|
||||
sem_wait(&handler_finish_semaphore_);
|
||||
bool status = handler_return_value_;
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
// static
|
||||
void ExceptionHandler::HandleException(int signo) {
|
||||
//void ExceptionHandler::HandleException(int signo, siginfo_t *sip, ucontext_t *sig_ctx) {
|
||||
// The context information about the signal is put on the stack of
|
||||
// the signal handler frame as value parameter. For some reasons, the
|
||||
// prototype of the handler doesn't declare this information as parameter, we
|
||||
// will do it by hand. The stack layout for a signal handler frame is here:
|
||||
// http://src.opensolaris.org/source/xref/onnv/onnv-gate/usr/src/lib/libproc/common/Pstack.c#81
|
||||
//
|
||||
// However, if we are being called by another signal handler passing the
|
||||
// signal up the chain, then we may not have this random extra parameter,
|
||||
// so we may have to walk the stack to find it. We do the actual work
|
||||
// on another thread, where it's a little safer, but we want the ebp
|
||||
// from this frame to find it.
|
||||
uintptr_t current_ebp = (uintptr_t)_getfp();
|
||||
|
||||
pthread_mutex_lock(&handler_stack_mutex_);
|
||||
ExceptionHandler *current_handler =
|
||||
handler_stack_->at(handler_stack_->size() - ++handler_stack_index_);
|
||||
|
@ -227,7 +187,10 @@ void ExceptionHandler::HandleException(int signo) {
|
|||
|
||||
// Restore original handler.
|
||||
current_handler->TeardownHandler(signo);
|
||||
if (current_handler->WriteMinidumpOnHandlerThread(signo)) {
|
||||
|
||||
ucontext_t *sig_ctx = NULL;
|
||||
if (current_handler->InternalWriteMinidump(signo, current_ebp, &sig_ctx)) {
|
||||
// if (current_handler->InternalWriteMinidump(signo, &sig_ctx)) {
|
||||
// Fully handled this exception, safe to exit.
|
||||
exit(EXIT_FAILURE);
|
||||
} else {
|
||||
|
@ -253,7 +216,9 @@ void ExceptionHandler::HandleException(int signo) {
|
|||
pthread_mutex_unlock(&handler_stack_mutex_);
|
||||
}
|
||||
|
||||
bool ExceptionHandler::InternalWriteMinidump() {
|
||||
bool ExceptionHandler::InternalWriteMinidump(int signo,
|
||||
uintptr_t sighandler_ebp,
|
||||
ucontext_t **sig_ctx) {
|
||||
if (filter_ && !filter_(callback_context_))
|
||||
return false;
|
||||
|
||||
|
@ -277,7 +242,8 @@ bool ExceptionHandler::InternalWriteMinidump() {
|
|||
print_message1(2, "HandleException: failed to block signals.\n");
|
||||
}
|
||||
|
||||
success = minidump_generator_.WriteMinidumpToFile(minidump_path, signo_);
|
||||
success = minidump_generator_.WriteMinidumpToFile(
|
||||
minidump_path, signo, sighandler_ebp, sig_ctx);
|
||||
|
||||
// Unblock the signals.
|
||||
if (blocked)
|
||||
|
|
|
@ -32,9 +32,6 @@
|
|||
#ifndef CLIENT_SOLARIS_HANDLER_EXCEPTION_HANDLER_H__
|
||||
#define CLIENT_SOLARIS_HANDLER_EXCEPTION_HANDLER_H__
|
||||
|
||||
#include <pthread.h>
|
||||
#include <semaphore.h>
|
||||
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
@ -119,9 +116,11 @@ class ExceptionHandler {
|
|||
bool install_handler);
|
||||
~ExceptionHandler();
|
||||
|
||||
// Set the minidump path.
|
||||
// Get and Set the minidump path.
|
||||
string dump_path() const { return dump_path_; }
|
||||
void set_dump_path(const string &dump_path) {
|
||||
dump_path_c_ = dump_path.c_str();
|
||||
dump_path_ = dump_path;
|
||||
dump_path_c_ = dump_path_.c_str();
|
||||
}
|
||||
|
||||
// Writes a minidump immediately. This can be used to capture the
|
||||
|
@ -150,36 +149,25 @@ class ExceptionHandler {
|
|||
// Signal handler.
|
||||
static void HandleException(int signo);
|
||||
|
||||
// Trigger the call to InternalWriteMinidump and wait for the return value.
|
||||
bool WriteMinidumpOnHandlerThread(int signo);
|
||||
|
||||
// Write all the information to the dump file.
|
||||
bool InternalWriteMinidump();
|
||||
// If called from a signal handler, sighandler_ebp is the ebp of
|
||||
// that signal handler's frame, and sig_ctx is an out parameter
|
||||
// that will be set to point at the ucontext_t that was placed
|
||||
// on the stack by the kernel. You can pass zero and NULL
|
||||
// for the second and third parameters if you are not calling
|
||||
// this from a signal handler.
|
||||
bool InternalWriteMinidump(int signo, uintptr_t sighandler_ebp,
|
||||
ucontext_t **sig_ctx);
|
||||
|
||||
private:
|
||||
// Signal number when crash happed. Can be 0 if this is a requested dump.
|
||||
int signo_;
|
||||
|
||||
// The exception handler thread.
|
||||
pthread_t handler_thread_;
|
||||
|
||||
// Semaphores used to move exception handling between the exception thread
|
||||
// and the handler thread. handler_start_semaphore_ is signalled by the
|
||||
// exception thread to wake up the handler thread when an exception occurs.
|
||||
// handler_finish_semaphore_ is signalled by the handler thread to wake up
|
||||
// the exception thread when handling is complete.
|
||||
sem_t handler_start_semaphore_;
|
||||
sem_t handler_finish_semaphore_;
|
||||
|
||||
// The return value of the handler, passed from the handler thread back to
|
||||
// the requesting thread.
|
||||
bool handler_return_value_;
|
||||
|
||||
// The callbacks before and after writing the dump file.
|
||||
FilterCallback filter_;
|
||||
MinidumpCallback callback_;
|
||||
void *callback_context_;
|
||||
|
||||
// The directory in which a minidump will be written, set by the dump_path
|
||||
// argument to the constructor, or set_dump_path.
|
||||
string dump_path_;
|
||||
// C style dump path. Keep this when setting dump path, since calling
|
||||
// c_str() of std::string when crashing may not be safe.
|
||||
const char *dump_path_c_;
|
||||
|
|
|
@ -30,12 +30,11 @@
|
|||
// Author: Alfred Peng
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <pthread.h>
|
||||
#include <sys/frame.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/utsname.h>
|
||||
#include <sys/wait.h>
|
||||
#include <ucontext.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <cstdlib>
|
||||
|
@ -45,21 +44,98 @@
|
|||
#include "client/minidump_file_writer-inl.h"
|
||||
#include "common/solaris/file_id.h"
|
||||
|
||||
namespace google_breakpad {
|
||||
namespace {
|
||||
|
||||
MinidumpGenerator::MinidumpGenerator()
|
||||
: requester_pid_(0),
|
||||
signo_(0),
|
||||
lwp_lister_(NULL) {
|
||||
using namespace google_breakpad;
|
||||
|
||||
// Argument for the writer function.
|
||||
struct WriterArgument {
|
||||
MinidumpFileWriter *minidump_writer;
|
||||
|
||||
// Pid of the lwp who called WriteMinidumpToFile
|
||||
int requester_pid;
|
||||
|
||||
// The stack bottom of the lwp which caused the dump.
|
||||
// Mainly used to find the lwp id of the crashed lwp since signal
|
||||
// handler may not be called in the lwp who caused it.
|
||||
uintptr_t crashed_stack_bottom;
|
||||
|
||||
// Id of the crashing lwp.
|
||||
int crashed_lwpid;
|
||||
|
||||
// Signal number when crash happened. Can be 0 if this is a requested dump.
|
||||
int signo;
|
||||
|
||||
// The ebp of the signal handler frame on x86. Can be 0 if this is a
|
||||
// requested dump.
|
||||
uintptr_t sighandler_ebp;
|
||||
|
||||
// User context when crash happens. Can be NULL if this is a requested dump.
|
||||
// This is actually an out parameter, but it will be filled in at the start
|
||||
// of the writer LWP.
|
||||
ucontext_t *sig_ctx;
|
||||
|
||||
// Used to get information about the lwps.
|
||||
SolarisLwp *lwp_lister;
|
||||
};
|
||||
|
||||
// Holding context information for the callback of finding the crashing lwp.
|
||||
struct FindCrashLwpContext {
|
||||
const SolarisLwp *lwp_lister;
|
||||
uintptr_t crashing_stack_bottom;
|
||||
int crashing_lwpid;
|
||||
|
||||
FindCrashLwpContext() :
|
||||
lwp_lister(NULL),
|
||||
crashing_stack_bottom(0UL),
|
||||
crashing_lwpid(-1) {
|
||||
}
|
||||
};
|
||||
|
||||
// Callback for list lwps.
|
||||
// It will compare the stack bottom of the provided lwp with the stack
|
||||
// bottom of the crashed lwp, it they are eqaul, this lwp is the one
|
||||
// who crashed.
|
||||
bool IsLwpCrashedCallback(lwpstatus_t *lsp, void *context) {
|
||||
FindCrashLwpContext *crashing_context =
|
||||
static_cast<FindCrashLwpContext *>(context);
|
||||
const SolarisLwp *lwp_lister = crashing_context->lwp_lister;
|
||||
const prgregset_t *gregs = &(lsp->pr_reg);
|
||||
#if TARGET_CPU_SPARC
|
||||
uintptr_t last_ebp = (*gregs)[R_FP];
|
||||
#elif TARGET_CPU_X86
|
||||
uintptr_t last_ebp = (*gregs)[EBP];
|
||||
#endif
|
||||
uintptr_t stack_bottom = lwp_lister->GetLwpStackBottom(last_ebp);
|
||||
if (stack_bottom > last_ebp &&
|
||||
stack_bottom == crashing_context->crashing_stack_bottom) {
|
||||
// Got it. Stop iteration.
|
||||
crashing_context->crashing_lwpid = lsp->pr_lwpid;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
MinidumpGenerator::~MinidumpGenerator() {
|
||||
// Find the crashing lwpid.
|
||||
// This is done based on stack bottom comparing.
|
||||
int FindCrashingLwp(uintptr_t crashing_stack_bottom,
|
||||
int requester_pid,
|
||||
const SolarisLwp *lwp_lister) {
|
||||
FindCrashLwpContext context;
|
||||
context.lwp_lister = lwp_lister;
|
||||
context.crashing_stack_bottom = crashing_stack_bottom;
|
||||
CallbackParam<LwpCallback> callback_param(IsLwpCrashedCallback,
|
||||
&context);
|
||||
lwp_lister->Lwp_iter_all(lwp_lister->getpid(), &callback_param);
|
||||
return context.crashing_lwpid;
|
||||
}
|
||||
|
||||
bool MinidumpGenerator::WriteLwpStack(uintptr_t last_esp,
|
||||
UntypedMDRVA *memory,
|
||||
MDMemoryDescriptor *loc) {
|
||||
uintptr_t stack_bottom = lwp_lister_->GetLwpStackBottom(last_esp);
|
||||
bool WriteLwpStack(const SolarisLwp *lwp_lister,
|
||||
uintptr_t last_esp,
|
||||
UntypedMDRVA *memory,
|
||||
MDMemoryDescriptor *loc) {
|
||||
uintptr_t stack_bottom = lwp_lister->GetLwpStackBottom(last_esp);
|
||||
if (stack_bottom >= last_esp) {
|
||||
int size = stack_bottom - last_esp;
|
||||
if (size > 0) {
|
||||
|
@ -75,29 +151,52 @@ bool MinidumpGenerator::WriteLwpStack(uintptr_t last_esp,
|
|||
}
|
||||
|
||||
#if TARGET_CPU_SPARC
|
||||
bool MinidumpGenerator::WriteContext(MDRawContextSPARC *context, prgregset_t regs,
|
||||
prfpregset_t *fp_regs) {
|
||||
bool WriteContext(MDRawContextSPARC *context, ucontext_t *sig_ctx) {
|
||||
assert(sig_ctx != NULL);
|
||||
int* regs = sig_ctx->uc_mcontext.gregs;
|
||||
context->context_flags = MD_CONTEXT_SPARC_FULL;
|
||||
|
||||
context->ccr = (unsigned int)(regs[0]);
|
||||
context->pc = (unsigned int)(regs[REG_PC]);
|
||||
context->npc = (unsigned int)(regs[REG_nPC]);
|
||||
context->y = (unsigned int)(regs[REG_Y]);
|
||||
context->asi = (unsigned int)(regs[19]);
|
||||
context->fprs = (unsigned int)(regs[20]);
|
||||
|
||||
for ( int i = 0 ; i < 32; ++i ) {
|
||||
context->g_r[i] = 0;
|
||||
}
|
||||
|
||||
for ( int i = 1 ; i < 16; ++i ) {
|
||||
context->g_r[i] = (uintptr_t)(sig_ctx->uc_mcontext.gregs[i + 3]);
|
||||
}
|
||||
context->g_r[30] = (uintptr_t)(((struct frame *)context->g_r[14])->fr_savfp);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool WriteContext(MDRawContextSPARC *context, prgregset_t regs,
|
||||
prfpregset_t *fp_regs) {
|
||||
if (!context || !regs)
|
||||
return false;
|
||||
|
||||
context->context_flags = MD_CONTEXT_SPARC_FULL;
|
||||
|
||||
context->ccr = (unsigned int)(regs[32]);
|
||||
context->pc = (unsigned int)(regs[R_PC]);
|
||||
context->npc = (unsigned int)(regs[R_nPC]);
|
||||
context->y = (unsigned int)(regs[R_Y]);
|
||||
context->asi = (unsigned int)(regs[36]);
|
||||
context->fprs = (unsigned int)(regs[37]);
|
||||
|
||||
context->ccr = (uintptr_t)(regs[32]);
|
||||
context->pc = (uintptr_t)(regs[R_PC]);
|
||||
context->npc = (uintptr_t)(regs[R_nPC]);
|
||||
context->y = (uintptr_t)(regs[R_Y]);
|
||||
context->asi = (uintptr_t)(regs[36]);
|
||||
context->fprs = (uintptr_t)(regs[37]);
|
||||
for ( int i = 0 ; i < 32 ; ++i ){
|
||||
context->g_r[i] = (unsigned int)(regs[i]);
|
||||
context->g_r[i] = (uintptr_t)(regs[i]);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
#elif TARGET_CPU_X86
|
||||
bool MinidumpGenerator::WriteContext(MDRawContextX86 *context, prgregset_t regs,
|
||||
prfpregset_t *fp_regs) {
|
||||
bool WriteContext(MDRawContextX86 *context, prgregset_t regs,
|
||||
prfpregset_t *fp_regs) {
|
||||
if (!context || !regs)
|
||||
return false;
|
||||
|
||||
|
@ -124,18 +223,67 @@ bool MinidumpGenerator::WriteContext(MDRawContextX86 *context, prgregset_t regs,
|
|||
}
|
||||
#endif /* TARGET_CPU_XXX */
|
||||
|
||||
bool MinidumpGenerator::WriteLwpStream(lwpstatus_t *lsp, MDRawThread *lwp) {
|
||||
prfpregset_t fp_regs = lsp->pr_fpreg;
|
||||
prgregset_t *gregs = &(lsp->pr_reg);
|
||||
UntypedMDRVA memory(&writer_);
|
||||
// Write information about a crashed Lwp.
|
||||
// When a lwp crash, kernel will write something on the stack for processing
|
||||
// signal. This makes the current stack not reliable, and our stack walker
|
||||
// won't figure out the whole call stack for this. So we write the stack at the
|
||||
// time of the crash into the minidump file, not the current stack.
|
||||
bool WriteCrashedLwpStream(MinidumpFileWriter *minidump_writer,
|
||||
const WriterArgument *writer_args,
|
||||
const lwpstatus_t *lsp,
|
||||
MDRawThread *lwp) {
|
||||
assert(writer_args->sig_ctx != NULL);
|
||||
|
||||
lwp->thread_id = lsp->pr_lwpid;
|
||||
|
||||
#if TARGET_CPU_SPARC
|
||||
if (!WriteLwpStack((*gregs)[R_SP],
|
||||
UntypedMDRVA memory(minidump_writer);
|
||||
if (!WriteLwpStack(writer_args->lwp_lister,
|
||||
writer_args->sig_ctx->uc_mcontext.gregs[REG_O6],
|
||||
&memory,
|
||||
&lwp->stack))
|
||||
return false;
|
||||
|
||||
TypedMDRVA<MDRawContextSPARC> context(minidump_writer);
|
||||
if (!context.Allocate())
|
||||
return false;
|
||||
lwp->thread_context = context.location();
|
||||
memset(context.get(), 0, sizeof(MDRawContextSPARC));
|
||||
return WriteContext(context.get(), writer_args->sig_ctx);
|
||||
#elif TARGET_CPU_X86
|
||||
UntypedMDRVA memory(minidump_writer);
|
||||
if (!WriteLwpStack(writer_args->lwp_lister,
|
||||
writer_args->sig_ctx->uc_mcontext.gregs[UESP],
|
||||
&memory,
|
||||
&lwp->stack))
|
||||
return false;
|
||||
|
||||
TypedMDRVA<MDRawContextX86> context(minidump_writer);
|
||||
if (!context.Allocate())
|
||||
return false;
|
||||
lwp->thread_context = context.location();
|
||||
memset(context.get(), 0, sizeof(MDRawContextX86));
|
||||
return WriteContext(context.get(),
|
||||
(int *)&writer_args->sig_ctx->uc_mcontext.gregs,
|
||||
&writer_args->sig_ctx->uc_mcontext.fpregs);
|
||||
#endif
|
||||
}
|
||||
|
||||
bool WriteLwpStream(MinidumpFileWriter *minidump_writer,
|
||||
const SolarisLwp *lwp_lister,
|
||||
const lwpstatus_t *lsp, MDRawThread *lwp) {
|
||||
prfpregset_t fp_regs = lsp->pr_fpreg;
|
||||
const prgregset_t *gregs = &(lsp->pr_reg);
|
||||
UntypedMDRVA memory(minidump_writer);
|
||||
#if TARGET_CPU_SPARC
|
||||
if (!WriteLwpStack(lwp_lister,
|
||||
(*gregs)[R_SP],
|
||||
&memory,
|
||||
&lwp->stack))
|
||||
return false;
|
||||
|
||||
// Write context
|
||||
TypedMDRVA<MDRawContextSPARC> context(&writer_);
|
||||
TypedMDRVA<MDRawContextSPARC> context(minidump_writer);
|
||||
if (!context.Allocate())
|
||||
return false;
|
||||
// should be the thread_id
|
||||
|
@ -143,13 +291,14 @@ bool MinidumpGenerator::WriteLwpStream(lwpstatus_t *lsp, MDRawThread *lwp) {
|
|||
lwp->thread_context = context.location();
|
||||
memset(context.get(), 0, sizeof(MDRawContextSPARC));
|
||||
#elif TARGET_CPU_X86
|
||||
if (!WriteLwpStack((*gregs)[UESP],
|
||||
if (!WriteLwpStack(lwp_lister,
|
||||
(*gregs)[UESP],
|
||||
&memory,
|
||||
&lwp->stack))
|
||||
return false;
|
||||
|
||||
// Write context
|
||||
TypedMDRVA<MDRawContextX86> context(&writer_);
|
||||
TypedMDRVA<MDRawContextX86> context(minidump_writer);
|
||||
if (!context.Allocate())
|
||||
return false;
|
||||
// should be the thread_id
|
||||
|
@ -160,7 +309,7 @@ bool MinidumpGenerator::WriteLwpStream(lwpstatus_t *lsp, MDRawThread *lwp) {
|
|||
return WriteContext(context.get(), (int *)gregs, &fp_regs);
|
||||
}
|
||||
|
||||
bool MinidumpGenerator::WriteCPUInformation(MDRawSystemInfo *sys_info) {
|
||||
bool WriteCPUInformation(MDRawSystemInfo *sys_info) {
|
||||
struct utsname uts;
|
||||
char *major, *minor, *build;
|
||||
|
||||
|
@ -188,7 +337,8 @@ bool MinidumpGenerator::WriteCPUInformation(MDRawSystemInfo *sys_info) {
|
|||
return true;
|
||||
}
|
||||
|
||||
bool MinidumpGenerator::WriteOSInformation(MDRawSystemInfo *sys_info) {
|
||||
bool WriteOSInformation(MinidumpFileWriter *minidump_writer,
|
||||
MDRawSystemInfo *sys_info) {
|
||||
sys_info->platform_id = MD_OS_SOLARIS;
|
||||
|
||||
struct utsname uts;
|
||||
|
@ -220,7 +370,7 @@ bool MinidumpGenerator::WriteOSInformation(MDRawSystemInfo *sys_info) {
|
|||
}
|
||||
|
||||
MDLocationDescriptor location;
|
||||
if (!writer_.WriteString(os_version, 0, &location))
|
||||
if (!minidump_writer->WriteString(os_version, 0, &location))
|
||||
return false;
|
||||
sys_info->csd_version_rva = location.rva;
|
||||
}
|
||||
|
@ -229,21 +379,34 @@ bool MinidumpGenerator::WriteOSInformation(MDRawSystemInfo *sys_info) {
|
|||
|
||||
// Callback context for get writting lwp information.
|
||||
struct LwpInfoCallbackCtx {
|
||||
MinidumpGenerator *generator;
|
||||
MinidumpFileWriter *minidump_writer;
|
||||
const WriterArgument *writer_args;
|
||||
TypedMDRVA<MDRawThreadList> *list;
|
||||
int lwp_index;
|
||||
};
|
||||
|
||||
bool LwpInformationCallback(lwpstatus_t *lsp, void *context) {
|
||||
bool success = true;
|
||||
// The current thread is the one to handle the crash. Ignore it.
|
||||
LwpInfoCallbackCtx *callback_context =
|
||||
static_cast<LwpInfoCallbackCtx *>(context);
|
||||
|
||||
// The current lwp is the one to handle the crash. Ignore it.
|
||||
if (lsp->pr_lwpid != pthread_self()) {
|
||||
LwpInfoCallbackCtx *callback_context =
|
||||
static_cast<LwpInfoCallbackCtx *>(context);
|
||||
MDRawThread lwp;
|
||||
memset(&lwp, 0, sizeof(MDRawThread));
|
||||
|
||||
success = callback_context->generator->WriteLwpStream(lsp, &lwp);
|
||||
if (lsp->pr_lwpid != callback_context->writer_args->crashed_lwpid ||
|
||||
callback_context->writer_args->sig_ctx == NULL) {
|
||||
success = WriteLwpStream(callback_context->minidump_writer,
|
||||
callback_context->writer_args->lwp_lister,
|
||||
lsp, &lwp);
|
||||
} else {
|
||||
success = WriteCrashedLwpStream(callback_context->minidump_writer,
|
||||
callback_context->writer_args,
|
||||
lsp, &lwp);
|
||||
}
|
||||
if (success) {
|
||||
callback_context->list->CopyIndexAfterObject(
|
||||
callback_context->lwp_index++,
|
||||
|
@ -254,12 +417,15 @@ bool LwpInformationCallback(lwpstatus_t *lsp, void *context) {
|
|||
return success;
|
||||
}
|
||||
|
||||
bool MinidumpGenerator::WriteLwpListStream(MDRawDirectory *dir) {
|
||||
bool WriteLwpListStream(MinidumpFileWriter *minidump_writer,
|
||||
const WriterArgument *writer_args,
|
||||
MDRawDirectory *dir) {
|
||||
// Get the lwp information.
|
||||
int lwp_count = lwp_lister_->GetLwpCount();
|
||||
const SolarisLwp *lwp_lister = writer_args->lwp_lister;
|
||||
int lwp_count = lwp_lister->GetLwpCount();
|
||||
if (lwp_count < 0)
|
||||
return false;
|
||||
TypedMDRVA<MDRawThreadList> list(&writer_);
|
||||
TypedMDRVA<MDRawThreadList> list(minidump_writer);
|
||||
if (!list.AllocateObjectAndArray(lwp_count - 1, sizeof(MDRawThread)))
|
||||
return false;
|
||||
dir->stream_type = MD_THREAD_LIST_STREAM;
|
||||
|
@ -267,31 +433,32 @@ bool MinidumpGenerator::WriteLwpListStream(MDRawDirectory *dir) {
|
|||
list.get()->number_of_threads = lwp_count - 1;
|
||||
|
||||
LwpInfoCallbackCtx context;
|
||||
context.generator = this;
|
||||
context.minidump_writer = minidump_writer;
|
||||
context.writer_args = writer_args;
|
||||
context.list = &list;
|
||||
context.lwp_index = 0;
|
||||
CallbackParam<LwpCallback> callback_param(LwpInformationCallback,
|
||||
&context);
|
||||
int written =
|
||||
lwp_lister_->Lwp_iter_all(lwp_lister_->getpid(), &callback_param);
|
||||
lwp_lister->Lwp_iter_all(lwp_lister->getpid(), &callback_param);
|
||||
return written == lwp_count;
|
||||
}
|
||||
|
||||
bool MinidumpGenerator::WriteCVRecord(MDRawModule *module,
|
||||
const char *module_path) {
|
||||
TypedMDRVA<MDCVInfoPDB70> cv(&writer_);
|
||||
bool WriteCVRecord(MinidumpFileWriter *minidump_writer,
|
||||
MDRawModule *module,
|
||||
const char *module_path,
|
||||
char *realname) {
|
||||
TypedMDRVA<MDCVInfoPDB70> cv(minidump_writer);
|
||||
|
||||
char path[PATH_MAX];
|
||||
const char *module_name = module_path ? module_path : "<Unknown>";
|
||||
snprintf(path, sizeof(path), "/proc/self/object/%s", module_name);
|
||||
|
||||
size_t module_name_length = strlen(module_name);
|
||||
size_t module_name_length = strlen(realname);
|
||||
if (!cv.AllocateObjectAndArray(module_name_length + 1, sizeof(u_int8_t)))
|
||||
return false;
|
||||
if (!cv.CopyIndexAfterObject(0, const_cast<char *>(module_name),
|
||||
module_name_length)) {
|
||||
if (!cv.CopyIndexAfterObject(0, realname, module_name_length))
|
||||
return false;
|
||||
}
|
||||
|
||||
module->cv_record = cv.location();
|
||||
MDCVInfoPDB70 *cv_ptr = cv.get();
|
||||
|
@ -322,8 +489,8 @@ bool MinidumpGenerator::WriteCVRecord(MDRawModule *module,
|
|||
}
|
||||
|
||||
struct ModuleInfoCallbackCtx {
|
||||
MinidumpGenerator *generator;
|
||||
MinidumpFileWriter *minidump_writer;
|
||||
const WriterArgument *writer_args;
|
||||
TypedMDRVA<MDRawModuleList> *list;
|
||||
int module_index;
|
||||
};
|
||||
|
@ -338,16 +505,29 @@ bool ModuleInfoCallback(const ModuleInfo &module_info, void *context) {
|
|||
MDRawModule module;
|
||||
memset(&module, 0, sizeof(module));
|
||||
MDLocationDescriptor loc;
|
||||
if (!callback_context->minidump_writer->WriteString(module_info.name,
|
||||
0, &loc)) {
|
||||
char path[PATH_MAX];
|
||||
char buf[PATH_MAX];
|
||||
char *realname;
|
||||
int count;
|
||||
|
||||
snprintf(path, sizeof (path), "/proc/self/path/%s", module_info.name);
|
||||
if ((count = readlink(path, buf, PATH_MAX)) < 0)
|
||||
return false;
|
||||
buf[count] = '\0';
|
||||
|
||||
if ((realname = strrchr(buf, '/')) == NULL)
|
||||
return false;
|
||||
realname++;
|
||||
|
||||
if (!callback_context->minidump_writer->WriteString(realname, 0, &loc))
|
||||
return false;
|
||||
}
|
||||
|
||||
module.base_of_image = (u_int64_t)module_info.start_addr;
|
||||
module.size_of_image = module_info.size;
|
||||
module.module_name_rva = loc.rva;
|
||||
|
||||
if (!callback_context->generator->WriteCVRecord(&module, module_info.name))
|
||||
if (!WriteCVRecord(callback_context->minidump_writer, &module,
|
||||
module_info.name, realname))
|
||||
return false;
|
||||
|
||||
callback_context->list->CopyIndexAfterObject(
|
||||
|
@ -355,9 +535,11 @@ bool ModuleInfoCallback(const ModuleInfo &module_info, void *context) {
|
|||
return true;
|
||||
}
|
||||
|
||||
bool MinidumpGenerator::WriteModuleListStream(MDRawDirectory *dir) {
|
||||
TypedMDRVA<MDRawModuleList> list(&writer_);
|
||||
int module_count = lwp_lister_->GetModuleCount();
|
||||
bool WriteModuleListStream(MinidumpFileWriter *minidump_writer,
|
||||
const WriterArgument *writer_args,
|
||||
MDRawDirectory *dir) {
|
||||
TypedMDRVA<MDRawModuleList> list(minidump_writer);
|
||||
int module_count = writer_args->lwp_lister->GetModuleCount();
|
||||
|
||||
if (module_count <= 0 ||
|
||||
!list.AllocateObjectAndArray(module_count, MD_MODULE_SIZE)) {
|
||||
|
@ -368,16 +550,18 @@ bool MinidumpGenerator::WriteModuleListStream(MDRawDirectory *dir) {
|
|||
dir->location = list.location();
|
||||
list.get()->number_of_modules = module_count;
|
||||
ModuleInfoCallbackCtx context;
|
||||
context.generator = this;
|
||||
context.minidump_writer = &writer_;
|
||||
context.minidump_writer = minidump_writer;
|
||||
context.writer_args = writer_args;
|
||||
context.list = &list;
|
||||
context.module_index = 0;
|
||||
CallbackParam<ModuleCallback> callback(ModuleInfoCallback, &context);
|
||||
return lwp_lister_->ListModules(&callback) == module_count;
|
||||
return writer_args->lwp_lister->ListModules(&callback) == module_count;
|
||||
}
|
||||
|
||||
bool MinidumpGenerator::WriteSystemInfoStream(MDRawDirectory *dir) {
|
||||
TypedMDRVA<MDRawSystemInfo> sys_info(&writer_);
|
||||
bool WriteSystemInfoStream(MinidumpFileWriter *minidump_writer,
|
||||
const WriterArgument *writer_args,
|
||||
MDRawDirectory *dir) {
|
||||
TypedMDRVA<MDRawSystemInfo> sys_info(minidump_writer);
|
||||
|
||||
if (!sys_info.Allocate())
|
||||
return false;
|
||||
|
@ -386,69 +570,65 @@ bool MinidumpGenerator::WriteSystemInfoStream(MDRawDirectory *dir) {
|
|||
dir->location = sys_info.location();
|
||||
|
||||
return WriteCPUInformation(sys_info.get()) &&
|
||||
WriteOSInformation(sys_info.get());
|
||||
WriteOSInformation(minidump_writer, sys_info.get());
|
||||
}
|
||||
|
||||
bool MinidumpGenerator::WriteExceptionStream(MDRawDirectory *dir) {
|
||||
ucontext_t uc;
|
||||
gregset_t *gregs;
|
||||
fpregset_t fp_regs;
|
||||
|
||||
if (getcontext(&uc) != 0)
|
||||
bool WriteExceptionStream(MinidumpFileWriter *minidump_writer,
|
||||
const WriterArgument *writer_args,
|
||||
MDRawDirectory *dir) {
|
||||
// This happenes when this is not a crash, but a requested dump.
|
||||
if (writer_args->sig_ctx == NULL)
|
||||
return false;
|
||||
|
||||
TypedMDRVA<MDRawExceptionStream> exception(&writer_);
|
||||
TypedMDRVA<MDRawExceptionStream> exception(minidump_writer);
|
||||
if (!exception.Allocate())
|
||||
return false;
|
||||
|
||||
dir->stream_type = MD_EXCEPTION_STREAM;
|
||||
dir->location = exception.location();
|
||||
exception.get()->thread_id = requester_pid_;
|
||||
exception.get()->exception_record.exception_code = signo_;
|
||||
exception.get()->thread_id = writer_args->crashed_lwpid;
|
||||
exception.get()->exception_record.exception_code = writer_args->signo;
|
||||
exception.get()->exception_record.exception_flags = 0;
|
||||
|
||||
gregs = &(uc.uc_mcontext.gregs);
|
||||
fp_regs = uc.uc_mcontext.fpregs;
|
||||
#if TARGET_CPU_SPARC
|
||||
exception.get()->exception_record.exception_address = ((unsigned int *)gregs)[1];
|
||||
if (writer_args->sig_ctx != NULL) {
|
||||
exception.get()->exception_record.exception_address =
|
||||
writer_args->sig_ctx->uc_mcontext.gregs[REG_PC];
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Write context of the exception.
|
||||
TypedMDRVA<MDRawContextSPARC> context(&writer_);
|
||||
TypedMDRVA<MDRawContextSPARC> context(minidump_writer);
|
||||
if (!context.Allocate())
|
||||
return false;
|
||||
exception.get()->thread_context = context.location();
|
||||
memset(context.get(), 0, sizeof(MDRawContextSPARC));
|
||||
|
||||
// On Solaris i386, gregset_t = prgregset_t, fpregset_t = prfpregset_t
|
||||
// But on Solaris Sparc are diffrent, see sys/regset.h and sys/procfs_isa.h
|
||||
context.get()->context_flags = MD_CONTEXT_SPARC_FULL;
|
||||
context.get()->ccr = ((unsigned int *)gregs)[0];
|
||||
context.get()->pc = ((unsigned int *)gregs)[1];
|
||||
context.get()->npc = ((unsigned int *)gregs)[2];
|
||||
context.get()->y = ((unsigned int *)gregs)[3];
|
||||
context.get()->asi = ((unsigned int *)gregs)[19];
|
||||
context.get()->fprs = ((unsigned int *)gregs)[20];
|
||||
for (int i = 0; i < 32; ++i) {
|
||||
context.get()->g_r[i] = 0;
|
||||
}
|
||||
for (int i = 1; i < 16; ++i) {
|
||||
context.get()->g_r[i] = ((unsigned int *)gregs)[i + 3];
|
||||
}
|
||||
|
||||
return true;
|
||||
return WriteContext(context.get(), writer_args->sig_ctx);
|
||||
#elif TARGET_CPU_X86
|
||||
exception.get()->exception_record.exception_address = (*gregs)[EIP];
|
||||
if (writer_args->sig_ctx != NULL) {
|
||||
exception.get()->exception_record.exception_address =
|
||||
writer_args->sig_ctx->uc_mcontext.gregs[EIP];
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Write context of the exception.
|
||||
TypedMDRVA<MDRawContextX86> context(&writer_);
|
||||
TypedMDRVA<MDRawContextX86> context(minidump_writer);
|
||||
if (!context.Allocate())
|
||||
return false;
|
||||
exception.get()->thread_context = context.location();
|
||||
memset(context.get(), 0, sizeof(MDRawContextX86));
|
||||
return WriteContext(context.get(), (int *)gregs, &fp_regs);
|
||||
#endif /* TARGET_CPU_XXX */
|
||||
return WriteContext(context.get(),
|
||||
(int *)&writer_args->sig_ctx->uc_mcontext.gregs,
|
||||
NULL);
|
||||
#endif
|
||||
}
|
||||
|
||||
bool MinidumpGenerator::WriteMiscInfoStream(MDRawDirectory *dir) {
|
||||
TypedMDRVA<MDRawMiscInfo> info(&writer_);
|
||||
bool WriteMiscInfoStream(MinidumpFileWriter *minidump_writer,
|
||||
const WriterArgument *writer_args,
|
||||
MDRawDirectory *dir) {
|
||||
TypedMDRVA<MDRawMiscInfo> info(minidump_writer);
|
||||
|
||||
if (!info.Allocate())
|
||||
return false;
|
||||
|
@ -457,13 +637,15 @@ bool MinidumpGenerator::WriteMiscInfoStream(MDRawDirectory *dir) {
|
|||
dir->location = info.location();
|
||||
info.get()->size_of_info = sizeof(MDRawMiscInfo);
|
||||
info.get()->flags1 = MD_MISCINFO_FLAGS1_PROCESS_ID;
|
||||
info.get()->process_id = requester_pid_;
|
||||
info.get()->process_id = writer_args->requester_pid;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool MinidumpGenerator::WriteBreakpadInfoStream(MDRawDirectory *dir) {
|
||||
TypedMDRVA<MDRawBreakpadInfo> info(&writer_);
|
||||
bool WriteBreakpadInfoStream(MinidumpFileWriter *minidump_writer,
|
||||
const WriterArgument *writer_args,
|
||||
MDRawDirectory *dir) {
|
||||
TypedMDRVA<MDRawBreakpadInfo> info(minidump_writer);
|
||||
|
||||
if (!info.Allocate())
|
||||
return false;
|
||||
|
@ -474,7 +656,7 @@ bool MinidumpGenerator::WriteBreakpadInfoStream(MDRawDirectory *dir) {
|
|||
info.get()->validity = MD_BREAKPAD_INFO_VALID_DUMP_THREAD_ID |
|
||||
MD_BREAKPAD_INFO_VALID_REQUESTING_THREAD_ID;
|
||||
info.get()->dump_thread_id = getpid();
|
||||
info.get()->requesting_thread_id = requester_pid_;
|
||||
info.get()->requesting_thread_id = writer_args->requester_pid;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -486,25 +668,53 @@ class AutoLwpResumer {
|
|||
SolarisLwp *lwp_;
|
||||
};
|
||||
|
||||
// Will call each writer function in the writers table.
|
||||
void* MinidumpGenerator::Write() {
|
||||
// Function table to writer a full minidump.
|
||||
const WriteStreamFN writers[] = {
|
||||
&MinidumpGenerator::WriteLwpListStream,
|
||||
&MinidumpGenerator::WriteModuleListStream,
|
||||
&MinidumpGenerator::WriteSystemInfoStream,
|
||||
&MinidumpGenerator::WriteExceptionStream,
|
||||
&MinidumpGenerator::WriteMiscInfoStream,
|
||||
&MinidumpGenerator::WriteBreakpadInfoStream,
|
||||
};
|
||||
// Prototype of writer functions.
|
||||
typedef bool (*WriteStreamFN)(MinidumpFileWriter *,
|
||||
const WriterArgument *,
|
||||
MDRawDirectory *);
|
||||
|
||||
if (!lwp_lister_->ControlAllLwps(true))
|
||||
// Function table to writer a full minidump.
|
||||
const WriteStreamFN writers[] = {
|
||||
WriteLwpListStream,
|
||||
WriteModuleListStream,
|
||||
WriteSystemInfoStream,
|
||||
WriteExceptionStream,
|
||||
WriteMiscInfoStream,
|
||||
WriteBreakpadInfoStream,
|
||||
};
|
||||
|
||||
// Will call each writer function in the writers table.
|
||||
//void* MinidumpGenerator::Write(void *argument) {
|
||||
void* Write(void *argument) {
|
||||
WriterArgument *writer_args = static_cast<WriterArgument *>(argument);
|
||||
|
||||
if (!writer_args->lwp_lister->ControlAllLwps(true))
|
||||
return NULL;
|
||||
|
||||
AutoLwpResumer lwpResumer(lwp_lister_);
|
||||
AutoLwpResumer lwpResumer(writer_args->lwp_lister);
|
||||
|
||||
TypedMDRVA<MDRawHeader> header(&writer_);
|
||||
TypedMDRVA<MDRawDirectory> dir(&writer_);
|
||||
if (writer_args->sighandler_ebp != 0 &&
|
||||
writer_args->lwp_lister->FindSigContext(writer_args->sighandler_ebp,
|
||||
&writer_args->sig_ctx)) {
|
||||
writer_args->crashed_stack_bottom =
|
||||
writer_args->lwp_lister->GetLwpStackBottom(
|
||||
#if TARGET_CPU_SPARC
|
||||
writer_args->sig_ctx->uc_mcontext.gregs[REG_O6]
|
||||
#elif TARGET_CPU_X86
|
||||
writer_args->sig_ctx->uc_mcontext.gregs[UESP]
|
||||
#endif
|
||||
);
|
||||
|
||||
int crashed_lwpid = FindCrashingLwp(writer_args->crashed_stack_bottom,
|
||||
writer_args->requester_pid,
|
||||
writer_args->lwp_lister);
|
||||
if (crashed_lwpid > 0)
|
||||
writer_args->crashed_lwpid = crashed_lwpid;
|
||||
}
|
||||
|
||||
MinidumpFileWriter *minidump_writer = writer_args->minidump_writer;
|
||||
TypedMDRVA<MDRawHeader> header(minidump_writer);
|
||||
TypedMDRVA<MDRawDirectory> dir(minidump_writer);
|
||||
if (!header.Allocate())
|
||||
return 0;
|
||||
|
||||
|
@ -521,29 +731,53 @@ void* MinidumpGenerator::Write() {
|
|||
int dir_index = 0;
|
||||
MDRawDirectory local_dir;
|
||||
for (int i = 0; i < writer_count; ++i) {
|
||||
if ((this->*writers[i])(&local_dir))
|
||||
if ((*writers[i])(minidump_writer, writer_args, &local_dir))
|
||||
dir.CopyIndex(dir_index++, &local_dir);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
namespace google_breakpad {
|
||||
|
||||
MinidumpGenerator::MinidumpGenerator() {
|
||||
}
|
||||
|
||||
MinidumpGenerator::~MinidumpGenerator() {
|
||||
}
|
||||
|
||||
// Write minidump into file.
|
||||
// It runs in a different thread from the crashing thread.
|
||||
bool MinidumpGenerator::WriteMinidumpToFile(const char *file_pathname,
|
||||
int signo) {
|
||||
int signo,
|
||||
uintptr_t sighandler_ebp,
|
||||
ucontext_t **sig_ctx) const {
|
||||
// The exception handler thread.
|
||||
pthread_t handler_thread;
|
||||
|
||||
assert(file_pathname != NULL);
|
||||
|
||||
if (file_pathname == NULL)
|
||||
return false;
|
||||
|
||||
if (writer_.Open(file_pathname)) {
|
||||
MinidumpFileWriter minidump_writer;
|
||||
if (minidump_writer.Open(file_pathname)) {
|
||||
WriterArgument argument;
|
||||
memset(&argument, 0, sizeof(argument));
|
||||
SolarisLwp lwp_lister(getpid());
|
||||
lwp_lister_ = &lwp_lister;
|
||||
requester_pid_ = getpid();
|
||||
signo_ = signo;
|
||||
if (Write())
|
||||
return true;
|
||||
argument.lwp_lister = &lwp_lister;
|
||||
argument.minidump_writer = &minidump_writer;
|
||||
argument.requester_pid = getpid();
|
||||
argument.crashed_lwpid = pthread_self();
|
||||
argument.signo = signo;
|
||||
argument.sighandler_ebp = sighandler_ebp;
|
||||
argument.sig_ctx = NULL;
|
||||
|
||||
pthread_create(&handler_thread, NULL, Write, (void *)&argument);
|
||||
pthread_join(handler_thread, NULL);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
|
|
|
@ -32,13 +32,7 @@
|
|||
#ifndef CLIENT_SOLARIS_HANDLER_MINIDUMP_GENERATOR_H__
|
||||
#define CLIENT_SOLARIS_HANDLER_MINIDUMP_GENERATOR_H__
|
||||
|
||||
#if defined(sparc) || defined(__sparc__)
|
||||
#define TARGET_CPU_SPARC 1
|
||||
#elif defined(i386) || defined(__i386__)
|
||||
#define TARGET_CPU_X86 1
|
||||
#else
|
||||
#error "cannot determine cpu type"
|
||||
#endif
|
||||
#include <ucontext.h>
|
||||
|
||||
#include "client/minidump_file_writer.h"
|
||||
#include "client/solaris/handler/solaris_lwp.h"
|
||||
|
@ -66,59 +60,9 @@ class MinidumpGenerator {
|
|||
|
||||
// Write minidump.
|
||||
bool WriteMinidumpToFile(const char *file_pathname,
|
||||
int signo);
|
||||
|
||||
private:
|
||||
// Helpers
|
||||
bool WriteCVRecord(MDRawModule *module, const char *module_path);
|
||||
|
||||
// Write the lwp stack information to dump file.
|
||||
bool WriteLwpStack(uintptr_t last_esp, UntypedMDRVA *memory,
|
||||
MDMemoryDescriptor *loc);
|
||||
|
||||
// Write CPU context based on provided registers.
|
||||
#if TARGET_CPU_SPARC
|
||||
bool WriteContext(MDRawContextSPARC *context, prgregset_t regs,
|
||||
prfpregset_t *fp_regs);
|
||||
#elif TARGET_CPU_X86
|
||||
bool WriteContext(MDRawContextX86 *context, prgregset_t regs,
|
||||
prfpregset_t *fp_regs);
|
||||
#endif /* TARGET_CPU_XXX */
|
||||
|
||||
// Write information about a lwp.
|
||||
// Only processes lwp running normally at the crash.
|
||||
bool WriteLwpStream(lwpstatus_t *lsp, MDRawThread *lwp);
|
||||
|
||||
// Write the CPU information to the dump file.
|
||||
bool WriteCPUInformation(MDRawSystemInfo *sys_info);
|
||||
|
||||
//Write the OS information to the dump file.
|
||||
bool WriteOSInformation(MDRawSystemInfo *sys_info);
|
||||
|
||||
typedef bool (MinidumpGenerator::*WriteStreamFN)(MDRawDirectory *);
|
||||
|
||||
// Write all the information to the dump file.
|
||||
void *Write();
|
||||
|
||||
// Stream writers
|
||||
bool WriteLwpListStream(MDRawDirectory *dir);
|
||||
bool WriteModuleListStream(MDRawDirectory *dir);
|
||||
bool WriteSystemInfoStream(MDRawDirectory *dir);
|
||||
bool WriteExceptionStream(MDRawDirectory *dir);
|
||||
bool WriteMiscInfoStream(MDRawDirectory *dir);
|
||||
bool WriteBreakpadInfoStream(MDRawDirectory *dir);
|
||||
|
||||
private:
|
||||
MinidumpFileWriter writer_;
|
||||
|
||||
// Pid of the lwp who called WriteMinidumpToFile
|
||||
int requester_pid_;
|
||||
|
||||
// Signal number when crash happed. Can be 0 if this is a requested dump.
|
||||
int signo_;
|
||||
|
||||
// Used to get information about the lwps.
|
||||
SolarisLwp *lwp_lister_;
|
||||
int signo,
|
||||
uintptr_t sighandler_ebp,
|
||||
ucontext_t **sig_ctx) const;
|
||||
};
|
||||
|
||||
} // namespace google_breakpad
|
||||
|
|
|
@ -48,7 +48,7 @@ static void *Reporter(void *) {
|
|||
snprintf(buffer, sizeof(buffer), "./minidump_test.out");
|
||||
fprintf(stdout, "Writing %s\n", buffer);
|
||||
|
||||
md.WriteMinidumpToFile(buffer, 0);
|
||||
md.WriteMinidumpToFile(buffer, 0, 0, NULL);
|
||||
doneWritingReport = true;
|
||||
|
||||
return NULL;
|
||||
|
|
|
@ -30,9 +30,11 @@
|
|||
// Author: Alfred Peng
|
||||
|
||||
#include <dirent.h>
|
||||
#include <elf.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <limits.h>
|
||||
#include <sys/frame.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/wait.h>
|
||||
|
@ -56,6 +58,16 @@ uintptr_t stack_base_address = 0;
|
|||
static const int HEADER_MAX = 2000;
|
||||
static const int MAP_MAX = 1000;
|
||||
|
||||
// Context information for the callbacks when validating address by listing
|
||||
// modules.
|
||||
struct AddressValidatingContext {
|
||||
uintptr_t address;
|
||||
bool is_mapped;
|
||||
|
||||
AddressValidatingContext() : address(0UL), is_mapped(false) {
|
||||
}
|
||||
};
|
||||
|
||||
// Convert from string to int.
|
||||
static bool LocalAtoi(char *s, int *r) {
|
||||
assert(s != NULL);
|
||||
|
@ -69,18 +81,19 @@ static bool LocalAtoi(char *s, int *r) {
|
|||
}
|
||||
|
||||
// Callback invoked for each mapped module.
|
||||
// It use the module's adderss range to validate the address.
|
||||
// It uses the module's adderss range to validate the address.
|
||||
static bool AddressNotInModuleCallback(const ModuleInfo &module_info,
|
||||
void *context) {
|
||||
uintptr_t addr = reinterpret_cast<uintptr_t>(context);
|
||||
if ((module_info.start_addr > 0) &&
|
||||
(addr >= module_info.start_addr) &&
|
||||
(addr <= module_info.start_addr + module_info.size)) {
|
||||
AddressValidatingContext *addr =
|
||||
reinterpret_cast<AddressValidatingContext *>(context);
|
||||
if (addr->is_mapped = ((module_info.start_addr > 0) &&
|
||||
(addr->address >= module_info.start_addr) &&
|
||||
(addr->address <= module_info.start_addr +
|
||||
module_info.size))) {
|
||||
stack_base_address = module_info.start_addr + module_info.size;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
return !addr->is_mapped;
|
||||
}
|
||||
|
||||
static int IterateLwpAll(int pid,
|
||||
|
@ -114,6 +127,28 @@ static int IterateLwpAll(int pid,
|
|||
return count;
|
||||
}
|
||||
|
||||
#if defined(__i386) && !defined(NO_FRAME_POINTER)
|
||||
void *GetNextFrame(void **last_ebp) {
|
||||
void *sp = *last_ebp;
|
||||
if ((unsigned long)sp == (unsigned long)last_ebp)
|
||||
return NULL;
|
||||
if ((unsigned long)sp & (sizeof(void *) - 1))
|
||||
return NULL;
|
||||
if ((unsigned long)sp - (unsigned long)last_ebp > 100000)
|
||||
return NULL;
|
||||
return sp;
|
||||
}
|
||||
#elif defined(__sparc)
|
||||
void *GetNextFrame(void *last_ebp) {
|
||||
return reinterpret_cast<struct frame *>(last_ebp)->fr_savfp;
|
||||
}
|
||||
#else
|
||||
void *GetNextFrame(void **last_ebp) {
|
||||
return reinterpret_cast<void*>(last_ebp);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
class AutoCloser {
|
||||
public:
|
||||
AutoCloser(int fd) : fd_(fd) {}
|
||||
|
@ -250,8 +285,10 @@ int SolarisLwp::Lwp_iter_all(int pid,
|
|||
}
|
||||
|
||||
uintptr_t SolarisLwp::GetLwpStackBottom(uintptr_t current_esp) const {
|
||||
AddressValidatingContext addr;
|
||||
addr.address = current_esp;
|
||||
CallbackParam<ModuleCallback> callback_param(AddressNotInModuleCallback,
|
||||
(void *)current_esp);
|
||||
&addr);
|
||||
ListModules(&callback_param);
|
||||
return stack_base_address;
|
||||
}
|
||||
|
@ -313,7 +350,28 @@ int SolarisLwp::ListModules(
|
|||
memset(&module, 0, sizeof (module));
|
||||
module.start_addr = _maps->pr_vaddr;
|
||||
module.size = _maps->pr_size;
|
||||
if ((strlen(name) > 0) && (strcmp(name, "a.out") != 0)) {
|
||||
if (strlen(name) > 0) {
|
||||
int objectfd = 0;
|
||||
char path[PATH_MAX];
|
||||
char buf[SELFMAG];
|
||||
|
||||
snprintf(path, sizeof (path), "/proc/self/object/%s", name);
|
||||
if ((objectfd = open(path, O_RDONLY)) < 0) {
|
||||
print_message1(2, "can't open module file\n");
|
||||
continue;
|
||||
}
|
||||
|
||||
AutoCloser autocloser(objectfd);
|
||||
|
||||
if (read(objectfd, buf, SELFMAG) != SELFMAG) {
|
||||
print_message1(2, "can't read module file\n");
|
||||
continue;
|
||||
}
|
||||
if (buf[0] != ELFMAG0 || buf[1] != ELFMAG1 ||
|
||||
buf[2] != ELFMAG2 || buf[3] != ELFMAG3) {
|
||||
continue;
|
||||
}
|
||||
|
||||
strncpy(module.name, name, sizeof (module.name) - 1);
|
||||
++module_count;
|
||||
}
|
||||
|
@ -326,4 +384,53 @@ int SolarisLwp::ListModules(
|
|||
return module_count;
|
||||
}
|
||||
|
||||
// Check if the address is a valid virtual address.
|
||||
// If the address is in any of the mapped modules, we take it as valid.
|
||||
// Otherwise it is invalid.
|
||||
bool SolarisLwp::IsAddressMapped(uintptr_t address) const {
|
||||
AddressValidatingContext addr;
|
||||
addr.address = address;
|
||||
CallbackParam<ModuleCallback> callback_param(AddressNotInModuleCallback,
|
||||
&addr);
|
||||
ListModules(&callback_param);
|
||||
return addr.is_mapped;
|
||||
}
|
||||
|
||||
// We're looking for a ucontext_t as the second parameter
|
||||
// to a signal handler function call. Luckily, the ucontext_t
|
||||
// has an ebp(fp on SPARC) member which should match the ebp(fp)
|
||||
// pointed to by the ebp(fp) of the signal handler frame.
|
||||
// The Solaris stack looks like this:
|
||||
// http://src.opensolaris.org/source/xref/onnv/onnv-gate/usr/src/lib/libproc/common/Pstack.c#81
|
||||
bool SolarisLwp::FindSigContext(uintptr_t sighandler_ebp,
|
||||
ucontext_t **sig_ctx) {
|
||||
uintptr_t previous_ebp;
|
||||
uintptr_t sig_ebp;
|
||||
const int MAX_STACK_DEPTH = 50;
|
||||
int depth_counter = 0;
|
||||
|
||||
do {
|
||||
#if TARGET_CPU_SPARC
|
||||
previous_ebp = reinterpret_cast<uintptr_t>(GetNextFrame(
|
||||
reinterpret_cast<void*>(sighandler_ebp)));
|
||||
*sig_ctx = reinterpret_cast<ucontext_t*>(sighandler_ebp + sizeof (struct frame));
|
||||
uintptr_t sig_esp = (*sig_ctx)->uc_mcontext.gregs[REG_O6];
|
||||
if (sig_esp < previous_ebp && sig_esp > sighandler_ebp)
|
||||
sig_ebp = (uintptr_t)(((struct frame *)sig_esp)->fr_savfp);
|
||||
|
||||
#elif TARGET_CPU_X86
|
||||
previous_ebp = reinterpret_cast<uintptr_t>(GetNextFrame(
|
||||
reinterpret_cast<void**>(sighandler_ebp)));
|
||||
*sig_ctx = reinterpret_cast<ucontext_t*>(sighandler_ebp + sizeof (struct frame) +
|
||||
3 * sizeof(uintptr_t));
|
||||
sig_ebp = (*sig_ctx)->uc_mcontext.gregs[EBP];
|
||||
#endif
|
||||
sighandler_ebp = previous_ebp;
|
||||
depth_counter++;
|
||||
} while(previous_ebp != sig_ebp && sighandler_ebp != 0 &&
|
||||
IsAddressMapped(sighandler_ebp) && depth_counter < MAX_STACK_DEPTH);
|
||||
|
||||
return previous_ebp == sig_ebp && previous_ebp != 0;
|
||||
}
|
||||
|
||||
} // namespace google_breakpad
|
||||
|
|
|
@ -32,9 +32,18 @@
|
|||
#ifndef CLIENT_SOLARIS_HANDLER_SOLARIS_LWP_H__
|
||||
#define CLIENT_SOLARIS_HANDLER_SOLARIS_LWP_H__
|
||||
|
||||
#if defined(sparc) || defined(__sparc)
|
||||
#define TARGET_CPU_SPARC 1
|
||||
#elif defined(i386) || defined(__i386)
|
||||
#define TARGET_CPU_X86 1
|
||||
#else
|
||||
#error "cannot determine cpu type"
|
||||
#endif
|
||||
|
||||
#include <signal.h>
|
||||
#include <stdint.h>
|
||||
#include <sys/user.h>
|
||||
#include <ucontext.h>
|
||||
|
||||
#ifndef _KERNEL
|
||||
#define _KERNEL
|
||||
|
@ -134,6 +143,13 @@ class SolarisLwp {
|
|||
// Get the bottom of the stack from esp.
|
||||
uintptr_t GetLwpStackBottom(uintptr_t current_esp) const;
|
||||
|
||||
// Finds a signal context on the stack given the ebp of our signal handler.
|
||||
bool FindSigContext(uintptr_t sighandler_ebp, ucontext_t **sig_ctx);
|
||||
|
||||
private:
|
||||
// Check if the address is a valid virtual address.
|
||||
bool IsAddressMapped(uintptr_t address) const;
|
||||
|
||||
private:
|
||||
// The pid of the process we are listing lwps.
|
||||
int pid_;
|
||||
|
|
|
@ -2,9 +2,14 @@
|
|||
Microsoft Visual Studio Solution File, Format Version 9.00
|
||||
# Visual Studio 2005
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "exception_handler", "handler\exception_handler.vcproj", "{B55CA863-B374-4BAF-95AC-539E4FA4C90C}"
|
||||
ProjectSection(ProjectDependencies) = postProject
|
||||
{A820AF62-6239-4693-8430-4F516C1838F4} = {A820AF62-6239-4693-8430-4F516C1838F4}
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "crash_report_sender", "sender\crash_report_sender.vcproj", "{9946A048-043B-4F8F-9E07-9297B204714C}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "crash_generation", "crash_generation\crash_generation.vcproj", "{A820AF62-6239-4693-8430-4F516C1838F4}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Win32 = Debug|Win32
|
||||
|
@ -29,6 +34,14 @@ Global
|
|||
{9946A048-043B-4F8F-9E07-9297B204714C}.Release|Win32.Build.0 = Release|Win32
|
||||
{9946A048-043B-4F8F-9E07-9297B204714C}.ReleaseStaticCRT|Win32.ActiveCfg = ReleaseStaticCRT|Win32
|
||||
{9946A048-043B-4F8F-9E07-9297B204714C}.ReleaseStaticCRT|Win32.Build.0 = ReleaseStaticCRT|Win32
|
||||
{A820AF62-6239-4693-8430-4F516C1838F4}.Debug|Win32.ActiveCfg = Debug|Win32
|
||||
{A820AF62-6239-4693-8430-4F516C1838F4}.Debug|Win32.Build.0 = Debug|Win32
|
||||
{A820AF62-6239-4693-8430-4F516C1838F4}.DebugStaticCRT|Win32.ActiveCfg = DebugStaticCRT|Win32
|
||||
{A820AF62-6239-4693-8430-4F516C1838F4}.DebugStaticCRT|Win32.Build.0 = DebugStaticCRT|Win32
|
||||
{A820AF62-6239-4693-8430-4F516C1838F4}.Release|Win32.ActiveCfg = Release|Win32
|
||||
{A820AF62-6239-4693-8430-4F516C1838F4}.Release|Win32.Build.0 = Release|Win32
|
||||
{A820AF62-6239-4693-8430-4F516C1838F4}.ReleaseStaticCRT|Win32.ActiveCfg = ReleaseStaticCRT|Win32
|
||||
{A820AF62-6239-4693-8430-4F516C1838F4}.ReleaseStaticCRT|Win32.Build.0 = ReleaseStaticCRT|Win32
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
|
|
|
@ -0,0 +1,63 @@
|
|||
// Copyright (c) 2008, 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.
|
||||
|
||||
#ifndef CLIENT_WINDOWS_COMMON_AUTO_CRITICAL_SECTION_H__
|
||||
#define CLIENT_WINDOWS_COMMON_AUTO_CRITICAL_SECTION_H__
|
||||
|
||||
#include <Windows.h>
|
||||
|
||||
namespace google_breakpad {
|
||||
|
||||
// Automatically enters the critical section in the constructor and leaves
|
||||
// the critical section in the destructor.
|
||||
class AutoCriticalSection {
|
||||
public:
|
||||
// Creates a new instance with the given critical section object
|
||||
// and enters the critical section immediately.
|
||||
explicit AutoCriticalSection(CRITICAL_SECTION* cs) : cs_(cs) {
|
||||
assert(cs_);
|
||||
EnterCriticalSection(cs_);
|
||||
}
|
||||
|
||||
// Destructor: leaves the critical section.
|
||||
~AutoCriticalSection() {
|
||||
LeaveCriticalSection(cs_);
|
||||
}
|
||||
|
||||
private:
|
||||
// Disable copy ctor and operator=.
|
||||
AutoCriticalSection(const AutoCriticalSection&);
|
||||
AutoCriticalSection& operator=(const AutoCriticalSection&);
|
||||
|
||||
CRITICAL_SECTION* cs_;
|
||||
};
|
||||
|
||||
} // namespace google_breakpad
|
||||
|
||||
#endif // CLIENT_WINDOWS_COMMON_AUTO_CRITICAL_SECTION_H__
|
|
@ -0,0 +1,122 @@
|
|||
// Copyright (c) 2008, 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.
|
||||
|
||||
#ifndef CLIENT_WINDOWS_COMMON_IPC_PROTOCOL_H__
|
||||
#define CLIENT_WINDOWS_COMMON_IPC_PROTOCOL_H__
|
||||
|
||||
#include <Windows.h>
|
||||
#include <DbgHelp.h>
|
||||
#include "google_breakpad/common/minidump_format.h"
|
||||
|
||||
namespace google_breakpad {
|
||||
|
||||
// Constants for the protocol between client and the server.
|
||||
|
||||
// Tags sent with each message indicating the purpose of
|
||||
// the message.
|
||||
enum MessageTag {
|
||||
MESSAGE_TAG_NONE = 0,
|
||||
MESSAGE_TAG_REGISTRATION_REQUEST = 1,
|
||||
MESSAGE_TAG_REGISTRATION_RESPONSE = 2,
|
||||
MESSAGE_TAG_REGISTRATION_ACK = 3
|
||||
};
|
||||
|
||||
// Message structure for IPC between crash client and crash server.
|
||||
struct ProtocolMessage {
|
||||
ProtocolMessage()
|
||||
: tag(MESSAGE_TAG_NONE),
|
||||
pid(0),
|
||||
dump_type(MiniDumpNormal),
|
||||
thread_id(0),
|
||||
exception_pointers(NULL),
|
||||
assert_info(NULL),
|
||||
dump_request_handle(NULL),
|
||||
dump_generated_handle(NULL),
|
||||
server_alive_handle(NULL) {
|
||||
}
|
||||
|
||||
// Creates an instance with the given parameters.
|
||||
ProtocolMessage(MessageTag arg_tag,
|
||||
DWORD arg_pid,
|
||||
MINIDUMP_TYPE arg_dump_type,
|
||||
DWORD* arg_thread_id,
|
||||
EXCEPTION_POINTERS** arg_exception_pointers,
|
||||
MDRawAssertionInfo* arg_assert_info,
|
||||
HANDLE arg_dump_request_handle,
|
||||
HANDLE arg_dump_generated_handle,
|
||||
HANDLE arg_server_alive)
|
||||
: tag(arg_tag),
|
||||
pid(arg_pid),
|
||||
dump_type(arg_dump_type),
|
||||
thread_id(arg_thread_id),
|
||||
exception_pointers(arg_exception_pointers),
|
||||
assert_info(arg_assert_info),
|
||||
dump_request_handle(arg_dump_request_handle),
|
||||
dump_generated_handle(arg_dump_generated_handle),
|
||||
server_alive_handle(arg_server_alive) {
|
||||
}
|
||||
|
||||
// Tag in the message.
|
||||
MessageTag tag;
|
||||
|
||||
// Process id.
|
||||
DWORD pid;
|
||||
|
||||
// Dump type requested.
|
||||
MINIDUMP_TYPE dump_type;
|
||||
|
||||
// Client thread id pointer.
|
||||
DWORD* thread_id;
|
||||
|
||||
// Exception information.
|
||||
EXCEPTION_POINTERS** exception_pointers;
|
||||
|
||||
// Assert information in case of an invalid parameter or
|
||||
// pure call failure.
|
||||
MDRawAssertionInfo* assert_info;
|
||||
|
||||
// Handle to signal the crash event.
|
||||
HANDLE dump_request_handle;
|
||||
|
||||
// Handle to check if server is done generating crash.
|
||||
HANDLE dump_generated_handle;
|
||||
|
||||
// Handle to a mutex that becomes signaled (WAIT_ABANDONED)
|
||||
// if server process goes down.
|
||||
HANDLE server_alive_handle;
|
||||
|
||||
private:
|
||||
// Disable copy ctor and operator=.
|
||||
ProtocolMessage(const ProtocolMessage& msg);
|
||||
ProtocolMessage& operator=(const ProtocolMessage& msg);
|
||||
};
|
||||
|
||||
} // namespace google_breakpad
|
||||
|
||||
#endif // CLIENT_WINDOWS_COMMON_IPC_PROTOCOL_H__
|
|
@ -0,0 +1,58 @@
|
|||
=========================================================================
|
||||
State machine transitions for the Crash Generation Server
|
||||
=========================================================================
|
||||
|
||||
=========================================================================
|
||||
|
|
||||
STATE | ACTIONS
|
||||
|
|
||||
=========================================================================
|
||||
ERROR | Clean up resources used to serve clients.
|
||||
| Always remain in ERROR state.
|
||||
-------------------------------------------------------------------------
|
||||
INITIAL | Connect to the pipe asynchronously.
|
||||
| If connection is successfully queued up asynchronously,
|
||||
| go into CONNECTING state.
|
||||
| If connection is done synchronously, go into CONNECTED
|
||||
| state.
|
||||
| For any unexpected problems, go into ERROR state.
|
||||
-------------------------------------------------------------------------
|
||||
CONNECTING | Get the result of async connection request.
|
||||
| If I/O is still incomplete, remain in the CONNECTING
|
||||
| state.
|
||||
| If connection is complete, go into CONNECTED state.
|
||||
| For any unexpected problems, go into DISCONNECTING state.
|
||||
-------------------------------------------------------------------------
|
||||
CONNECTED | Read from the pipe asynchronously.
|
||||
| If read request is successfully queued up asynchronously,
|
||||
| go into READING state.
|
||||
| For any unexpected problems, go into DISCONNECTING state.
|
||||
-------------------------------------------------------------------------
|
||||
READING | Get the result of async read request.
|
||||
| If read is done, go into READ_DONE state.
|
||||
| For any unexpected problems, go into DISCONNECTING state.
|
||||
-------------------------------------------------------------------------
|
||||
READ_DONE | Register the client, prepare the reply and write the
|
||||
| reply to the pipe asynchronously.
|
||||
| If write request is successfully queued up asynchronously,
|
||||
| go into WRITING state.
|
||||
| For any unexpected problems, go into DISCONNECTING state.
|
||||
-------------------------------------------------------------------------
|
||||
WRITING | Get the result of the async write request.
|
||||
| If write is done, go into WRITE_DONE state.
|
||||
| For any unexpected problems, go into DISCONNECTING state.
|
||||
-------------------------------------------------------------------------
|
||||
WRITE_DONE | Read from the pipe asynchronously (for an ACK).
|
||||
| If read request is successfully queued up asynchonously,
|
||||
| go into READING_ACK state.
|
||||
| For any unexpected problems, go into DISCONNECTING state.
|
||||
-------------------------------------------------------------------------
|
||||
READING_ACK | Get the result of the async read request.
|
||||
| If read is done, perform action for successful client
|
||||
| connection.
|
||||
| Go into DISCONNECTING state.
|
||||
-------------------------------------------------------------------------
|
||||
DISCONNECTING | Disconnect from the pipe, reset the event and go into
|
||||
| INITIAL state and signal the event again. If anything
|
||||
| fails, go into ERROR state.
|
||||
=========================================================================
|
|
@ -0,0 +1,147 @@
|
|||
// Copyright (c) 2008, 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.
|
||||
|
||||
#include "client/windows/crash_generation/client_info.h"
|
||||
|
||||
namespace google_breakpad {
|
||||
|
||||
ClientInfo::ClientInfo(CrashGenerationServer* crash_server,
|
||||
DWORD pid,
|
||||
MINIDUMP_TYPE dump_type,
|
||||
DWORD* thread_id,
|
||||
EXCEPTION_POINTERS** ex_info,
|
||||
MDRawAssertionInfo* assert_info)
|
||||
: crash_server_(crash_server),
|
||||
pid_(pid),
|
||||
dump_type_(dump_type),
|
||||
ex_info_(ex_info),
|
||||
assert_info_(assert_info),
|
||||
thread_id_(thread_id),
|
||||
process_handle_(NULL),
|
||||
dump_requested_handle_(NULL),
|
||||
dump_generated_handle_(NULL),
|
||||
dump_request_wait_handle_(NULL),
|
||||
process_exit_wait_handle_(NULL) {
|
||||
}
|
||||
|
||||
bool ClientInfo::Initialize() {
|
||||
process_handle_ = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid_);
|
||||
if (!process_handle_) {
|
||||
return false;
|
||||
}
|
||||
|
||||
dump_requested_handle_ = CreateEvent(NULL, // Security attributes.
|
||||
TRUE, // Manual reset.
|
||||
FALSE, // Initial state.
|
||||
NULL); // Name.
|
||||
if (!dump_requested_handle_) {
|
||||
return false;
|
||||
}
|
||||
|
||||
dump_generated_handle_ = CreateEvent(NULL, // Security attributes.
|
||||
TRUE, // Manual reset.
|
||||
FALSE, // Initial state.
|
||||
NULL); // Name.
|
||||
return dump_generated_handle_ != NULL;
|
||||
}
|
||||
|
||||
ClientInfo::~ClientInfo() {
|
||||
if (process_handle_) {
|
||||
CloseHandle(process_handle_);
|
||||
}
|
||||
|
||||
if (dump_requested_handle_) {
|
||||
CloseHandle(dump_requested_handle_);
|
||||
}
|
||||
|
||||
if (dump_generated_handle_) {
|
||||
CloseHandle(dump_generated_handle_);
|
||||
}
|
||||
|
||||
if (dump_request_wait_handle_) {
|
||||
// Wait for callbacks that might already be running to finish.
|
||||
UnregisterWaitEx(dump_request_wait_handle_, INVALID_HANDLE_VALUE);
|
||||
}
|
||||
|
||||
if (process_exit_wait_handle_) {
|
||||
// Wait for the callback that might already be running to finish.
|
||||
UnregisterWaitEx(process_exit_wait_handle_, INVALID_HANDLE_VALUE);
|
||||
}
|
||||
}
|
||||
|
||||
bool ClientInfo::UnregisterWaits() {
|
||||
bool success = true;
|
||||
|
||||
if (dump_request_wait_handle_) {
|
||||
if (!UnregisterWait(dump_request_wait_handle_)) {
|
||||
success = false;
|
||||
} else {
|
||||
dump_request_wait_handle_ = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (process_exit_wait_handle_) {
|
||||
if (!UnregisterWait(process_exit_wait_handle_)) {
|
||||
success = false;
|
||||
} else {
|
||||
process_exit_wait_handle_ = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
bool ClientInfo::GetClientExceptionInfo(
|
||||
EXCEPTION_POINTERS** ex_info) const {
|
||||
SIZE_T bytes_count = 0;
|
||||
if (!ReadProcessMemory(process_handle_,
|
||||
ex_info_,
|
||||
ex_info,
|
||||
sizeof(*ex_info),
|
||||
&bytes_count)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return bytes_count == sizeof(*ex_info);
|
||||
}
|
||||
|
||||
bool ClientInfo::GetClientThreadId(DWORD* thread_id) const {
|
||||
SIZE_T bytes_count = 0;
|
||||
if (!ReadProcessMemory(process_handle_,
|
||||
thread_id_,
|
||||
thread_id,
|
||||
sizeof(*thread_id),
|
||||
&bytes_count)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return bytes_count == sizeof(*thread_id);
|
||||
}
|
||||
|
||||
} // namespace google_breakpad
|
|
@ -0,0 +1,145 @@
|
|||
// Copyright (c) 2008, 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.
|
||||
|
||||
#ifndef CLIENT_WINDOWS_CRASH_GENERATION_CLIENT_INFO_H__
|
||||
#define CLIENT_WINDOWS_CRASH_GENERATION_CLIENT_INFO_H__
|
||||
|
||||
#include <Windows.h>
|
||||
#include <DbgHelp.h>
|
||||
#include "google_breakpad/common/minidump_format.h"
|
||||
|
||||
namespace google_breakpad {
|
||||
|
||||
class CrashGenerationServer;
|
||||
|
||||
// Abstraction for a crash client process.
|
||||
class ClientInfo {
|
||||
public:
|
||||
// Creates an instance with the given values. Gets the process
|
||||
// handle for the given process id and creates necessary event
|
||||
// objects.
|
||||
ClientInfo(CrashGenerationServer* crash_server,
|
||||
DWORD pid,
|
||||
MINIDUMP_TYPE dump_type,
|
||||
DWORD* thread_id,
|
||||
EXCEPTION_POINTERS** ex_info,
|
||||
MDRawAssertionInfo* assert_info);
|
||||
|
||||
~ClientInfo();
|
||||
|
||||
CrashGenerationServer* crash_server() const { return crash_server_; }
|
||||
DWORD pid() const { return pid_; }
|
||||
MINIDUMP_TYPE dump_type() const { return dump_type_; }
|
||||
EXCEPTION_POINTERS** ex_info() const { return ex_info_; }
|
||||
MDRawAssertionInfo* assert_info() const { return assert_info_; }
|
||||
DWORD* thread_id() const { return thread_id_; }
|
||||
HANDLE process_handle() const { return process_handle_; }
|
||||
HANDLE dump_requested_handle() const { return dump_requested_handle_; }
|
||||
HANDLE dump_generated_handle() const { return dump_generated_handle_; }
|
||||
|
||||
HANDLE dump_request_wait_handle() const {
|
||||
return dump_request_wait_handle_;
|
||||
}
|
||||
|
||||
void set_dump_request_wait_handle(HANDLE value) {
|
||||
dump_request_wait_handle_ = value;
|
||||
}
|
||||
|
||||
HANDLE process_exit_wait_handle() const {
|
||||
return process_exit_wait_handle_;
|
||||
}
|
||||
|
||||
void set_process_exit_wait_handle(HANDLE value) {
|
||||
process_exit_wait_handle_ = value;
|
||||
}
|
||||
|
||||
// Unregister all waits for the client.
|
||||
bool UnregisterWaits();
|
||||
|
||||
bool Initialize();
|
||||
bool GetClientExceptionInfo(EXCEPTION_POINTERS** ex_info) const;
|
||||
bool GetClientThreadId(DWORD* thread_id) const;
|
||||
|
||||
private:
|
||||
// Crash generation server.
|
||||
CrashGenerationServer* crash_server_;
|
||||
|
||||
// Client process ID.
|
||||
DWORD pid_;
|
||||
|
||||
// Dump type requested by the client.
|
||||
MINIDUMP_TYPE dump_type_;
|
||||
|
||||
// Address of an EXCEPTION_POINTERS* variable in the client
|
||||
// process address space that will point to an instance of
|
||||
// EXCEPTION_POINTERS containing information about crash.
|
||||
//
|
||||
// WARNING: Do not dereference these pointers as they are pointers
|
||||
// in the address space of another process.
|
||||
EXCEPTION_POINTERS** ex_info_;
|
||||
|
||||
// Address of an instance of MDRawAssertionInfo in the client
|
||||
// process address space that will contain information about
|
||||
// non-exception related crashes like invalid parameter assertion
|
||||
// failures and pure calls.
|
||||
//
|
||||
// WARNING: Do not dereference these pointers as they are pointers
|
||||
// in the address space of another process.
|
||||
MDRawAssertionInfo* assert_info_;
|
||||
|
||||
// Address of a variable in the client process address space that
|
||||
// will contain the thread id of the crashing client thread.
|
||||
//
|
||||
// WARNING: Do not dereference these pointers as they are pointers
|
||||
// in the address space of another process.
|
||||
DWORD* thread_id_;
|
||||
|
||||
// Client process handle.
|
||||
HANDLE process_handle_;
|
||||
|
||||
// Dump request event handle.
|
||||
HANDLE dump_requested_handle_;
|
||||
|
||||
// Dump generated event handle.
|
||||
HANDLE dump_generated_handle_;
|
||||
|
||||
// Wait handle for dump request event.
|
||||
HANDLE dump_request_wait_handle_;
|
||||
|
||||
// Wait handle for process exit event.
|
||||
HANDLE process_exit_wait_handle_;
|
||||
|
||||
// Disallow copy ctor and operator=.
|
||||
ClientInfo(const ClientInfo& client_info);
|
||||
ClientInfo& operator=(const ClientInfo& client_info);
|
||||
};
|
||||
|
||||
} // namespace google_breakpad
|
||||
|
||||
#endif // CLIENT_WINDOWS_CRASH_GENERATION_CLIENT_INFO_H__
|
|
@ -0,0 +1,343 @@
|
|||
<?xml version="1.0" encoding="Windows-1252"?>
|
||||
<VisualStudioProject
|
||||
ProjectType="Visual C++"
|
||||
Version="8.00"
|
||||
Name="crash_generation"
|
||||
ProjectGUID="{A820AF62-6239-4693-8430-4F516C1838F4}"
|
||||
RootNamespace="CrashGenerationServer"
|
||||
Keyword="Win32Proj"
|
||||
>
|
||||
<Platforms>
|
||||
<Platform
|
||||
Name="Win32"
|
||||
/>
|
||||
</Platforms>
|
||||
<ToolFiles>
|
||||
</ToolFiles>
|
||||
<Configurations>
|
||||
<Configuration
|
||||
Name="Debug|Win32"
|
||||
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
|
||||
IntermediateDirectory="$(ConfigurationName)"
|
||||
ConfigurationType="4"
|
||||
CharacterSet="1"
|
||||
>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
Optimization="0"
|
||||
AdditionalIncludeDirectories="..\..\.."
|
||||
PreprocessorDefinitions="WIN32;_DEBUG;_LIB;WIN32_LEAN_AND_MEAN;_WIN32_WINNT=0x0500"
|
||||
MinimalRebuild="true"
|
||||
BasicRuntimeChecks="3"
|
||||
RuntimeLibrary="3"
|
||||
UsePrecompiledHeader="0"
|
||||
WarningLevel="4"
|
||||
Detect64BitPortabilityProblems="true"
|
||||
DebugInformationFormat="4"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManagedResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCLibrarianTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCALinkTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXDCMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCBscMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCFxCopTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"
|
||||
/>
|
||||
</Configuration>
|
||||
<Configuration
|
||||
Name="Release|Win32"
|
||||
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
|
||||
IntermediateDirectory="$(ConfigurationName)"
|
||||
ConfigurationType="4"
|
||||
CharacterSet="1"
|
||||
WholeProgramOptimization="1"
|
||||
>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
AdditionalIncludeDirectories="..\..\.."
|
||||
PreprocessorDefinitions="WIN32;NDEBUG;_LIB;WIN32_LEAN_AND_MEAN;_WIN32_WINNT=0x0500"
|
||||
RuntimeLibrary="2"
|
||||
UsePrecompiledHeader="0"
|
||||
WarningLevel="4"
|
||||
Detect64BitPortabilityProblems="true"
|
||||
DebugInformationFormat="3"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManagedResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCLibrarianTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCALinkTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXDCMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCBscMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCFxCopTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"
|
||||
/>
|
||||
</Configuration>
|
||||
<Configuration
|
||||
Name="DebugStaticCRT|Win32"
|
||||
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
|
||||
IntermediateDirectory="$(ConfigurationName)"
|
||||
ConfigurationType="4"
|
||||
CharacterSet="1"
|
||||
>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
Optimization="0"
|
||||
AdditionalIncludeDirectories="..\..\.."
|
||||
PreprocessorDefinitions="WIN32;_DEBUG;_LIB;WIN32_LEAN_AND_MEAN;_WIN32_WINNT=0x0500"
|
||||
MinimalRebuild="true"
|
||||
BasicRuntimeChecks="3"
|
||||
RuntimeLibrary="1"
|
||||
UsePrecompiledHeader="0"
|
||||
WarningLevel="4"
|
||||
Detect64BitPortabilityProblems="true"
|
||||
DebugInformationFormat="4"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManagedResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCLibrarianTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCALinkTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXDCMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCBscMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCFxCopTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"
|
||||
/>
|
||||
</Configuration>
|
||||
<Configuration
|
||||
Name="ReleaseStaticCRT|Win32"
|
||||
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
|
||||
IntermediateDirectory="$(ConfigurationName)"
|
||||
ConfigurationType="4"
|
||||
CharacterSet="1"
|
||||
WholeProgramOptimization="1"
|
||||
>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
AdditionalIncludeDirectories="..\..\.."
|
||||
PreprocessorDefinitions="WIN32;NDEBUG;_LIB;WIN32_LEAN_AND_MEAN;_WIN32_WINNT=0x0500"
|
||||
RuntimeLibrary="0"
|
||||
UsePrecompiledHeader="0"
|
||||
WarningLevel="4"
|
||||
Detect64BitPortabilityProblems="true"
|
||||
DebugInformationFormat="3"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManagedResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCLibrarianTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCALinkTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXDCMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCBscMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCFxCopTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"
|
||||
/>
|
||||
</Configuration>
|
||||
</Configurations>
|
||||
<References>
|
||||
</References>
|
||||
<Files>
|
||||
<Filter
|
||||
Name="Source Files"
|
||||
Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
|
||||
UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
|
||||
>
|
||||
<File
|
||||
RelativePath=".\client_info.cc"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\crash_generation_client.cc"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\crash_generation_server.cc"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\..\common\windows\guid_string.cc"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\minidump_generator.cc"
|
||||
>
|
||||
</File>
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="Header Files"
|
||||
Filter="h;hpp;hxx;hm;inl;inc;xsd"
|
||||
UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
|
||||
>
|
||||
<File
|
||||
RelativePath="..\common\auto_critical_section.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\client_info.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\crash_generation_client.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\crash_generation_server.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\common\ipc_protocol.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\..\google_breakpad\common\minidump_format.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\minidump_generator.h"
|
||||
>
|
||||
</File>
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="Resource Files"
|
||||
Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav"
|
||||
UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
|
||||
>
|
||||
</Filter>
|
||||
<File
|
||||
RelativePath=".\ReadMe.txt"
|
||||
>
|
||||
</File>
|
||||
</Files>
|
||||
<Globals>
|
||||
</Globals>
|
||||
</VisualStudioProject>
|
|
@ -0,0 +1,329 @@
|
|||
// Copyright (c) 2008, 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.
|
||||
|
||||
#include "client/windows/crash_generation/crash_generation_client.h"
|
||||
#include <cassert>
|
||||
#include "client/windows/common/ipc_protocol.h"
|
||||
|
||||
namespace google_breakpad {
|
||||
|
||||
const int kPipeBusyWaitTimeoutMs = 2000;
|
||||
|
||||
#ifdef _DEBUG
|
||||
const DWORD kWaitForServerTimeoutMs = INFINITE;
|
||||
#else
|
||||
const DWORD kWaitForServerTimeoutMs = 15000;
|
||||
#endif
|
||||
|
||||
const int kPipeConnectMaxAttempts = 2;
|
||||
|
||||
const DWORD kPipeDesiredAccess = FILE_READ_DATA |
|
||||
FILE_WRITE_DATA |
|
||||
FILE_WRITE_ATTRIBUTES;
|
||||
|
||||
const DWORD kPipeFlagsAndAttributes = SECURITY_IDENTIFICATION |
|
||||
SECURITY_SQOS_PRESENT;
|
||||
|
||||
const DWORD kPipeMode = PIPE_READMODE_MESSAGE;
|
||||
|
||||
const size_t kWaitEventCount = 2;
|
||||
|
||||
// This function is orphan for production code. It can be used
|
||||
// for debugging to help repro some scenarios like the client
|
||||
// is slow in writing to the pipe after connecting, the client
|
||||
// is slow in reading from the pipe after writing, etc. The parameter
|
||||
// overlapped below is not used and it is present to match the signature
|
||||
// of this function to TransactNamedPipe Win32 API. Uncomment if needed
|
||||
// for debugging.
|
||||
/**
|
||||
static bool TransactNamedPipeDebugHelper(HANDLE pipe,
|
||||
const void* in_buffer,
|
||||
DWORD in_size,
|
||||
void* out_buffer,
|
||||
DWORD out_size,
|
||||
DWORD* bytes_count,
|
||||
LPOVERLAPPED) {
|
||||
// Uncomment the next sleep to create a gap before writing
|
||||
// to pipe.
|
||||
// Sleep(5000);
|
||||
|
||||
if (!WriteFile(pipe,
|
||||
in_buffer,
|
||||
in_size,
|
||||
bytes_count,
|
||||
NULL)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Uncomment the next sleep to create a gap between write
|
||||
// and read.
|
||||
// Sleep(5000);
|
||||
|
||||
return ReadFile(pipe, out_buffer, out_size, bytes_count, NULL) != FALSE;
|
||||
}
|
||||
**/
|
||||
|
||||
CrashGenerationClient::CrashGenerationClient(const wchar_t* pipe_name,
|
||||
MINIDUMP_TYPE dump_type)
|
||||
: pipe_name_(pipe_name),
|
||||
dump_type_(dump_type),
|
||||
thread_id_(0),
|
||||
server_process_id_(0),
|
||||
crash_event_(NULL),
|
||||
crash_generated_(NULL),
|
||||
server_alive_(NULL),
|
||||
exception_pointers_(NULL) {
|
||||
memset(&assert_info_, 0, sizeof(assert_info_));
|
||||
}
|
||||
|
||||
CrashGenerationClient::~CrashGenerationClient() {
|
||||
if (crash_event_) {
|
||||
CloseHandle(crash_event_);
|
||||
}
|
||||
|
||||
if (crash_generated_) {
|
||||
CloseHandle(crash_generated_);
|
||||
}
|
||||
|
||||
if (server_alive_) {
|
||||
CloseHandle(server_alive_);
|
||||
}
|
||||
}
|
||||
|
||||
// Performs the registration step with the server process.
|
||||
// The registration step involves communicating with the server
|
||||
// via a named pipe. The client sends the following pieces of
|
||||
// data to the server:
|
||||
//
|
||||
// * Message tag indicating the client is requesting registration.
|
||||
// * Process id of the client process.
|
||||
// * Address of a DWORD variable in the client address space
|
||||
// that will contain the thread id of the client thread that
|
||||
// caused the crash.
|
||||
// * Address of a EXCEPTION_POINTERS* variable in the client
|
||||
// address space that will point to an instance of EXCEPTION_POINTERS
|
||||
// when the crash happens.
|
||||
// * Address of an instance of MDRawAssertionInfo that will contain
|
||||
// relevant information in case of non-exception crashes like assertion
|
||||
// failures and pure calls.
|
||||
//
|
||||
// In return the client expects the following information from the server:
|
||||
//
|
||||
// * Message tag indicating successful registration.
|
||||
// * Server process id.
|
||||
// * Handle to an object that client can signal to request dump
|
||||
// generation from the server.
|
||||
// * Handle to an object that client can wait on after requesting
|
||||
// dump generation for the server to finish dump generation.
|
||||
// * Handle to a mutex object that client can wait on to make sure
|
||||
// server is still alive.
|
||||
//
|
||||
// If any step of the expected behavior mentioned above fails, the
|
||||
// registration step is not considered successful and hence out-of-process
|
||||
// dump generation service is not available.
|
||||
//
|
||||
// Returns true if the registration is successful; false otherwise.
|
||||
bool CrashGenerationClient::Register() {
|
||||
HANDLE pipe = ConnectToServer();
|
||||
if (!pipe) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool success = RegisterClient(pipe);
|
||||
CloseHandle(pipe);
|
||||
return success;
|
||||
}
|
||||
|
||||
HANDLE CrashGenerationClient::ConnectToServer() {
|
||||
HANDLE pipe = ConnectToPipe(pipe_name_.c_str(),
|
||||
kPipeDesiredAccess,
|
||||
kPipeFlagsAndAttributes);
|
||||
if (!pipe) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
DWORD mode = kPipeMode;
|
||||
if (!SetNamedPipeHandleState(pipe, &mode, NULL, NULL)) {
|
||||
CloseHandle(pipe);
|
||||
pipe = NULL;
|
||||
}
|
||||
|
||||
return pipe;
|
||||
}
|
||||
|
||||
bool CrashGenerationClient::RegisterClient(HANDLE pipe) {
|
||||
ProtocolMessage msg(MESSAGE_TAG_REGISTRATION_REQUEST,
|
||||
GetCurrentProcessId(),
|
||||
dump_type_,
|
||||
&thread_id_,
|
||||
&exception_pointers_,
|
||||
&assert_info_,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL);
|
||||
ProtocolMessage reply;
|
||||
DWORD bytes_count = 0;
|
||||
// The call to TransactNamedPipe below can be changed to a call
|
||||
// to TransactNamedPipeDebugHelper to help repro some scenarios.
|
||||
// For details see comments for TransactNamedPipeDebugHelper.
|
||||
if (!TransactNamedPipe(pipe,
|
||||
&msg,
|
||||
sizeof(msg),
|
||||
&reply,
|
||||
sizeof(ProtocolMessage),
|
||||
&bytes_count,
|
||||
NULL)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!ValidateResponse(reply)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ProtocolMessage ack_msg;
|
||||
ack_msg.tag = MESSAGE_TAG_REGISTRATION_ACK;
|
||||
|
||||
if (!WriteFile(pipe, &ack_msg, sizeof(ack_msg), &bytes_count, NULL)) {
|
||||
return false;
|
||||
}
|
||||
crash_event_ = reply.dump_request_handle;
|
||||
crash_generated_ = reply.dump_generated_handle;
|
||||
server_alive_ = reply.server_alive_handle;
|
||||
server_process_id_ = reply.pid;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
HANDLE CrashGenerationClient::ConnectToPipe(const wchar_t* pipe_name,
|
||||
DWORD pipe_access,
|
||||
DWORD flags_attrs) {
|
||||
for (int i = 0; i < kPipeConnectMaxAttempts; ++i) {
|
||||
HANDLE pipe = CreateFile(pipe_name,
|
||||
pipe_access,
|
||||
0,
|
||||
NULL,
|
||||
OPEN_EXISTING,
|
||||
flags_attrs,
|
||||
NULL);
|
||||
if (pipe != INVALID_HANDLE_VALUE) {
|
||||
return pipe;
|
||||
}
|
||||
|
||||
// Cannot continue retrying if error is something other than
|
||||
// ERROR_PIPE_BUSY.
|
||||
if (GetLastError() != ERROR_PIPE_BUSY) {
|
||||
break;
|
||||
}
|
||||
|
||||
// Cannot continue retrying if wait on pipe fails.
|
||||
if (!WaitNamedPipe(pipe_name, kPipeBusyWaitTimeoutMs)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bool CrashGenerationClient::ValidateResponse(
|
||||
const ProtocolMessage& msg) const {
|
||||
return (msg.tag == MESSAGE_TAG_REGISTRATION_RESPONSE) &&
|
||||
(msg.pid != 0) &&
|
||||
(msg.dump_request_handle != NULL) &&
|
||||
(msg.dump_generated_handle != NULL) &&
|
||||
(msg.server_alive_handle != NULL);
|
||||
}
|
||||
|
||||
bool CrashGenerationClient::IsRegistered() const {
|
||||
return crash_event_ != NULL;
|
||||
}
|
||||
|
||||
bool CrashGenerationClient::RequestDump(EXCEPTION_POINTERS* ex_info) {
|
||||
if (!IsRegistered()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
exception_pointers_ = ex_info;
|
||||
thread_id_ = GetCurrentThreadId();
|
||||
|
||||
assert_info_.line = 0;
|
||||
assert_info_.type = 0;
|
||||
assert_info_.expression[0] = 0;
|
||||
assert_info_.file[0] = 0;
|
||||
assert_info_.function[0] = 0;
|
||||
|
||||
return SignalCrashEventAndWait();
|
||||
}
|
||||
|
||||
bool CrashGenerationClient::RequestDump(MDRawAssertionInfo* assert_info) {
|
||||
if (!IsRegistered()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
exception_pointers_ = NULL;
|
||||
|
||||
if (assert_info) {
|
||||
memcpy(&assert_info_, assert_info, sizeof(assert_info_));
|
||||
} else {
|
||||
memset(&assert_info_, 0, sizeof(assert_info_));
|
||||
}
|
||||
|
||||
thread_id_ = GetCurrentThreadId();
|
||||
|
||||
return SignalCrashEventAndWait();
|
||||
}
|
||||
|
||||
bool CrashGenerationClient::SignalCrashEventAndWait() {
|
||||
assert(crash_event_);
|
||||
assert(crash_generated_);
|
||||
assert(server_alive_);
|
||||
|
||||
// Reset the dump generated event before signaling the crash
|
||||
// event so that the server can set the dump generated event
|
||||
// once it is done generating the event.
|
||||
if (!ResetEvent(crash_generated_)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!SetEvent(crash_event_)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
HANDLE wait_handles[kWaitEventCount] = {crash_generated_, server_alive_};
|
||||
|
||||
DWORD result = WaitForMultipleObjects(kWaitEventCount,
|
||||
wait_handles,
|
||||
FALSE,
|
||||
kWaitForServerTimeoutMs);
|
||||
|
||||
// Crash dump was successfully generated only if the server
|
||||
// signaled the crash generated event.
|
||||
return result == WAIT_OBJECT_0;
|
||||
}
|
||||
|
||||
} // namespace google_breakpad
|
|
@ -0,0 +1,149 @@
|
|||
// Copyright (c) 2008, 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.
|
||||
|
||||
#ifndef CLIENT_WINDOWS_CRASH_GENERATION_CRASH_GENERATION_CLIENT_H__
|
||||
#define CLIENT_WINDOWS_CRASH_GENERATION_CRASH_GENERATION_CLIENT_H__
|
||||
|
||||
#include <string>
|
||||
#include "client/windows/common/ipc_protocol.h"
|
||||
|
||||
namespace google_breakpad {
|
||||
|
||||
// Abstraction of client-side implementation of out of process
|
||||
// crash generation.
|
||||
//
|
||||
// The process that desires to have out-of-process crash dump
|
||||
// generation service can use this class in the following way:
|
||||
//
|
||||
// * Create an instance.
|
||||
// * Call Register method so that the client tries to register
|
||||
// with the server process and check the return value. If
|
||||
// registration is not successful, out-of-process crash dump
|
||||
// generation will not be available
|
||||
// * Request dump generation by calling either of the two
|
||||
// overloaded RequestDump methods - one in case of exceptions
|
||||
// and the other in case of assertion failures
|
||||
//
|
||||
// Note that it is the responsibility of the client code of
|
||||
// this class to set the unhandled exception filter with the
|
||||
// system by calling the SetUnhandledExceptionFilter function
|
||||
// and the client code should explicitly request dump generation.
|
||||
class CrashGenerationClient {
|
||||
public:
|
||||
CrashGenerationClient(const wchar_t* pipe_name,
|
||||
MINIDUMP_TYPE dump_type);
|
||||
|
||||
~CrashGenerationClient();
|
||||
|
||||
// Registers the client process with the crash server.
|
||||
//
|
||||
// Returns true if the registration is successful; false otherwise.
|
||||
bool Register();
|
||||
|
||||
// Requests the crash server to generate a dump with the given
|
||||
// exception information.
|
||||
//
|
||||
// Returns true if the dump was successful; false otherwise. Note that
|
||||
// if the registration step was not performed or it was not successful,
|
||||
// false will be returned.
|
||||
bool RequestDump(EXCEPTION_POINTERS* ex_info);
|
||||
|
||||
// Requests the crash server to generate a dump with the given
|
||||
// assertion information.
|
||||
//
|
||||
// Returns true if the dump was successful; false otherwise. Note that
|
||||
// if the registration step was not performed or it was not successful,
|
||||
// false will be returned.
|
||||
bool RequestDump(MDRawAssertionInfo* assert_info);
|
||||
|
||||
private:
|
||||
// Connects to the appropriate pipe and sets the pipe handle state.
|
||||
//
|
||||
// Returns the pipe handle if everything goes well; otherwise Returns NULL.
|
||||
HANDLE ConnectToServer();
|
||||
|
||||
// Performs a handshake with the server over the given pipe which should be
|
||||
// already connected to the server.
|
||||
//
|
||||
// Returns true if handshake with the server was successful; false otherwise.
|
||||
bool RegisterClient(HANDLE pipe);
|
||||
|
||||
// Validates the given server response.
|
||||
bool ValidateResponse(const ProtocolMessage& msg) const;
|
||||
|
||||
// Returns true if the registration step succeeded; false otherwise.
|
||||
bool IsRegistered() const;
|
||||
|
||||
// Connects to the given named pipe with given parameters.
|
||||
//
|
||||
// Returns true if the connection is successful; false otherwise.
|
||||
HANDLE ConnectToPipe(const wchar_t* pipe_name,
|
||||
DWORD pipe_access,
|
||||
DWORD flags_attrs);
|
||||
|
||||
// Signals the crash event and wait for the server to generate crash.
|
||||
bool SignalCrashEventAndWait();
|
||||
|
||||
// Pipe name to use to talk to server.
|
||||
std::wstring pipe_name_;
|
||||
|
||||
// Type of dump to generate.
|
||||
MINIDUMP_TYPE dump_type_;
|
||||
|
||||
// Event to signal in case of a crash.
|
||||
HANDLE crash_event_;
|
||||
|
||||
// Handle to wait on after signaling a crash for the server
|
||||
// to finish generating crash dump.
|
||||
HANDLE crash_generated_;
|
||||
|
||||
// Handle to a mutex that will become signaled with WAIT_ABANDONED
|
||||
// if the server process goes down.
|
||||
HANDLE server_alive_;
|
||||
|
||||
// Server process id.
|
||||
DWORD server_process_id_;
|
||||
|
||||
// Id of the thread that caused the crash.
|
||||
DWORD thread_id_;
|
||||
|
||||
// Exception pointers for an exception crash.
|
||||
EXCEPTION_POINTERS* exception_pointers_;
|
||||
|
||||
// Assertion info for an invalid parameter or pure call crash.
|
||||
MDRawAssertionInfo assert_info_;
|
||||
|
||||
// Disable copy ctor and operator=.
|
||||
CrashGenerationClient(const CrashGenerationClient& crash_client);
|
||||
CrashGenerationClient& operator=(const CrashGenerationClient& crash_client);
|
||||
};
|
||||
|
||||
} // namespace google_breakpad
|
||||
|
||||
#endif // CLIENT_WINDOWS_CRASH_GENERATION_CRASH_GENERATION_CLIENT_H__
|
|
@ -0,0 +1,825 @@
|
|||
// Copyright (c) 2008, 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.
|
||||
|
||||
#include "client/windows/crash_generation/crash_generation_server.h"
|
||||
#include <Windows.h>
|
||||
#include <cassert>
|
||||
#include "client/windows/common/auto_critical_section.h"
|
||||
#include "processor/scoped_ptr.h"
|
||||
|
||||
namespace google_breakpad {
|
||||
|
||||
// Output buffer size.
|
||||
const size_t kOutBufferSize = 64;
|
||||
|
||||
// Input buffer size.
|
||||
const size_t kInBufferSize = 64;
|
||||
|
||||
// Access flags for the client on the dump request event.
|
||||
const DWORD kDumpRequestEventAccess = EVENT_MODIFY_STATE;
|
||||
|
||||
// Access flags for the client on the dump generated event.
|
||||
const DWORD kDumpGeneratedEventAccess = EVENT_MODIFY_STATE |
|
||||
SYNCHRONIZE;
|
||||
|
||||
// Access flags for the client on the mutex.
|
||||
const DWORD kMutexAccess = SYNCHRONIZE;
|
||||
|
||||
// Attribute flags for the pipe.
|
||||
const DWORD kPipeAttr = FILE_FLAG_FIRST_PIPE_INSTANCE |
|
||||
PIPE_ACCESS_DUPLEX |
|
||||
FILE_FLAG_OVERLAPPED;
|
||||
|
||||
// Mode for the pipe.
|
||||
const DWORD kPipeMode = PIPE_TYPE_MESSAGE |
|
||||
PIPE_READMODE_MESSAGE |
|
||||
PIPE_WAIT;
|
||||
|
||||
// For pipe I/O, execute the callback in the wait thread itself,
|
||||
// since the callback does very little work. The callback executes
|
||||
// the code for one of the states of the server state machine and
|
||||
// the code for all of the states perform async I/O and hence
|
||||
// finish very quickly.
|
||||
const ULONG kPipeIOThreadFlags = WT_EXECUTEINWAITTHREAD;
|
||||
|
||||
// Dump request threads will, most likely, generate dumps. That may
|
||||
// take some time to finish, so specify WT_EXECUTELONGFUNCTION flag.
|
||||
const ULONG kDumpRequestThreadFlags = WT_EXECUTEINWAITTHREAD |
|
||||
WT_EXECUTELONGFUNCTION;
|
||||
|
||||
// Maximum delay during server shutdown if some work items
|
||||
// are still executing.
|
||||
const int kShutdownDelayMs = 10000;
|
||||
|
||||
// Interval for each sleep during server shutdown.
|
||||
const int kShutdownSleepIntervalMs = 5;
|
||||
|
||||
static bool ValidateClientRequest(const ProtocolMessage& msg) {
|
||||
return msg.tag == MESSAGE_TAG_REGISTRATION_REQUEST &&
|
||||
msg.pid != 0 &&
|
||||
msg.thread_id != NULL &&
|
||||
msg.exception_pointers != NULL &&
|
||||
msg.assert_info != NULL;
|
||||
}
|
||||
|
||||
CrashGenerationServer::CrashGenerationServer(
|
||||
const wchar_t* pipe_name,
|
||||
OnClientConnectedCallback connect_callback,
|
||||
void* connect_context,
|
||||
OnClientDumpRequestCallback dump_callback,
|
||||
void* dump_context,
|
||||
OnClientExitedCallback exit_callback,
|
||||
void* exit_context,
|
||||
bool generate_dumps,
|
||||
const std::wstring* dump_path)
|
||||
: pipe_name_(pipe_name),
|
||||
pipe_(NULL),
|
||||
pipe_wait_handle_(NULL),
|
||||
server_alive_handle_(NULL),
|
||||
connect_callback_(connect_callback),
|
||||
connect_context_(connect_context),
|
||||
dump_callback_(dump_callback),
|
||||
dump_context_(dump_context),
|
||||
exit_callback_(exit_callback),
|
||||
exit_context_(exit_context),
|
||||
generate_dumps_(generate_dumps),
|
||||
dump_generator_(NULL),
|
||||
server_state_(IPC_SERVER_STATE_INITIAL),
|
||||
shutting_down_(false),
|
||||
overlapped_(),
|
||||
client_info_(NULL),
|
||||
cleanup_item_count_(0) {
|
||||
InitializeCriticalSection(&clients_sync_);
|
||||
|
||||
if (dump_path) {
|
||||
dump_generator_.reset(new MinidumpGenerator(*dump_path));
|
||||
}
|
||||
}
|
||||
|
||||
CrashGenerationServer::~CrashGenerationServer() {
|
||||
// Indicate to existing threads that server is shutting down.
|
||||
shutting_down_ = true;
|
||||
|
||||
// Unregister wait on the pipe.
|
||||
if (pipe_wait_handle_) {
|
||||
// Wait for already executing callbacks to finish.
|
||||
UnregisterWaitEx(pipe_wait_handle_, INVALID_HANDLE_VALUE);
|
||||
}
|
||||
|
||||
// Close the pipe to avoid further client connections.
|
||||
if (pipe_) {
|
||||
CloseHandle(pipe_);
|
||||
}
|
||||
|
||||
// Request all ClientInfo objects to unregister all waits.
|
||||
// New scope to hold the lock for the shortest time.
|
||||
{
|
||||
AutoCriticalSection lock(&clients_sync_);
|
||||
|
||||
std::list<ClientInfo*>::iterator iter;
|
||||
for (iter = clients_.begin(); iter != clients_.end(); ++iter) {
|
||||
ClientInfo* client_info = *iter;
|
||||
client_info->UnregisterWaits();
|
||||
}
|
||||
}
|
||||
|
||||
// Now that all waits have been unregistered, wait for some time
|
||||
// for all pending work items to finish.
|
||||
int total_wait = 0;
|
||||
while (cleanup_item_count_ > 0) {
|
||||
Sleep(kShutdownSleepIntervalMs);
|
||||
|
||||
total_wait += kShutdownSleepIntervalMs;
|
||||
|
||||
if (total_wait >= kShutdownDelayMs) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Clean up all the ClientInfo objects.
|
||||
// New scope to hold the lock for the shortest time.
|
||||
{
|
||||
AutoCriticalSection lock(&clients_sync_);
|
||||
|
||||
std::list<ClientInfo*>::iterator iter;
|
||||
for (iter = clients_.begin(); iter != clients_.end(); ++iter) {
|
||||
ClientInfo* client_info = *iter;
|
||||
delete client_info;
|
||||
}
|
||||
}
|
||||
|
||||
if (server_alive_handle_) {
|
||||
// Release the mutex before closing the handle so that clients requesting
|
||||
// dumps wait for a long time for the server to generate a dump.
|
||||
ReleaseMutex(server_alive_handle_);
|
||||
CloseHandle(server_alive_handle_);
|
||||
}
|
||||
|
||||
DeleteCriticalSection(&clients_sync_);
|
||||
}
|
||||
|
||||
bool CrashGenerationServer::Start() {
|
||||
server_state_ = IPC_SERVER_STATE_INITIAL;
|
||||
|
||||
server_alive_handle_ = CreateMutex(NULL, TRUE, NULL);
|
||||
if (!server_alive_handle_) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Event to signal the client connection and pipe reads and writes.
|
||||
overlapped_.hEvent = CreateEvent(NULL, // Security descriptor.
|
||||
TRUE, // Manual reset.
|
||||
FALSE, // Initially signaled.
|
||||
NULL); // Name.
|
||||
if (!overlapped_.hEvent) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Register a callback with the thread pool for the client connection.
|
||||
RegisterWaitForSingleObject(&pipe_wait_handle_,
|
||||
overlapped_.hEvent,
|
||||
OnPipeConnected,
|
||||
this,
|
||||
INFINITE,
|
||||
kPipeIOThreadFlags);
|
||||
|
||||
pipe_ = CreateNamedPipe(pipe_name_.c_str(),
|
||||
kPipeAttr,
|
||||
kPipeMode,
|
||||
1,
|
||||
kOutBufferSize,
|
||||
kInBufferSize,
|
||||
0,
|
||||
NULL);
|
||||
if (!pipe_) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Signal the event to start a separate thread to handle
|
||||
// client connections.
|
||||
return SetEvent(overlapped_.hEvent) != FALSE;
|
||||
}
|
||||
|
||||
// If the server thread serving clients ever gets into the
|
||||
// ERROR state, reset the event, close the pipe and remain
|
||||
// in the error state forever. Error state means something
|
||||
// that we didn't account for has happened, and it's dangerous
|
||||
// to do anything unknowingly.
|
||||
void CrashGenerationServer::HandleErrorState() {
|
||||
assert(server_state_ == IPC_SERVER_STATE_ERROR);
|
||||
|
||||
// If the server is shutting down anyway, don't clean up
|
||||
// here since shut down process will clean up.
|
||||
if (shutting_down_) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (pipe_wait_handle_) {
|
||||
UnregisterWait(pipe_wait_handle_);
|
||||
pipe_wait_handle_ = NULL;
|
||||
}
|
||||
|
||||
if (pipe_) {
|
||||
CloseHandle(pipe_);
|
||||
pipe_ = NULL;
|
||||
}
|
||||
|
||||
if (overlapped_.hEvent) {
|
||||
CloseHandle(overlapped_.hEvent);
|
||||
overlapped_.hEvent = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
// When the server thread serving clients is in the INITIAL state,
|
||||
// try to connect to the pipe asynchronously. If the connection
|
||||
// finishes synchronously, directly go into the CONNECTED state;
|
||||
// otherwise go into the CONNECTING state. For any problems, go
|
||||
// into the ERROR state.
|
||||
void CrashGenerationServer::HandleInitialState() {
|
||||
assert(server_state_ == IPC_SERVER_STATE_INITIAL);
|
||||
|
||||
if (!ResetEvent(overlapped_.hEvent)) {
|
||||
server_state_ = IPC_SERVER_STATE_ERROR;
|
||||
return;
|
||||
}
|
||||
|
||||
bool success;
|
||||
success = ConnectNamedPipe(pipe_, &overlapped_) != FALSE;
|
||||
|
||||
// From MSDN, it is not clear that when ConnectNamedPipe is used
|
||||
// in an overlapped mode, will it ever return non-zero value, and
|
||||
// if so, in what cases.
|
||||
assert(!success);
|
||||
|
||||
DWORD error_code = GetLastError();
|
||||
switch (error_code) {
|
||||
case ERROR_IO_PENDING:
|
||||
server_state_ = IPC_SERVER_STATE_CONNECTING;
|
||||
break;
|
||||
|
||||
case ERROR_PIPE_CONNECTED:
|
||||
if (SetEvent(overlapped_.hEvent)) {
|
||||
server_state_ = IPC_SERVER_STATE_CONNECTED;
|
||||
} else {
|
||||
server_state_ = IPC_SERVER_STATE_ERROR;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
server_state_ = IPC_SERVER_STATE_ERROR;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// When the server thread serving the clients is in the CONNECTING state,
|
||||
// try to get the result of the asynchronous connection request using
|
||||
// the OVERLAPPED object. If the result indicates the connection is done,
|
||||
// go into the CONNECTED state. If the result indicates I/O is still
|
||||
// INCOMPLETE, remain in the CONNECTING state. For any problems,
|
||||
// go into the DISCONNECTING state.
|
||||
void CrashGenerationServer::HandleConnectingState() {
|
||||
assert(server_state_ == IPC_SERVER_STATE_CONNECTING);
|
||||
|
||||
DWORD bytes_count = 0;
|
||||
bool success = GetOverlappedResult(pipe_,
|
||||
&overlapped_,
|
||||
&bytes_count,
|
||||
FALSE) != FALSE;
|
||||
|
||||
if (success) {
|
||||
server_state_ = IPC_SERVER_STATE_CONNECTED;
|
||||
return;
|
||||
}
|
||||
|
||||
if (GetLastError() != ERROR_IO_INCOMPLETE) {
|
||||
server_state_ = IPC_SERVER_STATE_DISCONNECTING;
|
||||
}
|
||||
}
|
||||
|
||||
// When the server thread serving the clients is in the CONNECTED state,
|
||||
// try to issue an asynchronous read from the pipe. If read completes
|
||||
// synchronously or if I/O is pending then go into the READING state.
|
||||
// For any problems, go into the DISCONNECTING state.
|
||||
void CrashGenerationServer::HandleConnectedState() {
|
||||
assert(server_state_ == IPC_SERVER_STATE_CONNECTED);
|
||||
|
||||
DWORD bytes_count = 0;
|
||||
memset(&msg_, 0, sizeof(msg_));
|
||||
bool success = ReadFile(pipe_,
|
||||
&msg_,
|
||||
sizeof(msg_),
|
||||
&bytes_count,
|
||||
&overlapped_) != FALSE;
|
||||
|
||||
// Note that the asynchronous read issued above can finish before the
|
||||
// code below executes. But, it is okay to change state after issuing
|
||||
// the asynchronous read. This is because even if the asynchronous read
|
||||
// is done, the callback for it would not be executed until the current
|
||||
// thread finishes its execution.
|
||||
if (success || GetLastError() == ERROR_IO_PENDING) {
|
||||
server_state_ = IPC_SERVER_STATE_READING;
|
||||
} else {
|
||||
server_state_ = IPC_SERVER_STATE_DISCONNECTING;
|
||||
}
|
||||
}
|
||||
|
||||
// When the server thread serving the clients is in the READING state,
|
||||
// try to get the result of the async read. If async read is done,
|
||||
// go into the READ_DONE state. For any problems, go into the
|
||||
// DISCONNECTING state.
|
||||
void CrashGenerationServer::HandleReadingState() {
|
||||
assert(server_state_ == IPC_SERVER_STATE_READING);
|
||||
|
||||
DWORD bytes_count = 0;
|
||||
bool success = GetOverlappedResult(pipe_,
|
||||
&overlapped_,
|
||||
&bytes_count,
|
||||
FALSE) != FALSE;
|
||||
|
||||
if (success && bytes_count == sizeof(ProtocolMessage)){
|
||||
server_state_ = IPC_SERVER_STATE_READ_DONE;
|
||||
return;
|
||||
}
|
||||
|
||||
DWORD error_code;
|
||||
error_code = GetLastError();
|
||||
|
||||
// We should never get an I/O incomplete since we should not execute this
|
||||
// unless the Read has finished and the overlapped event is signaled. If
|
||||
// we do get INCOMPLETE, we have a bug in our code.
|
||||
assert(error_code != ERROR_IO_INCOMPLETE);
|
||||
|
||||
server_state_ = IPC_SERVER_STATE_DISCONNECTING;
|
||||
}
|
||||
|
||||
// When the server thread serving the client is in the READ_DONE state,
|
||||
// validate the client's request message, register the client by
|
||||
// creating appropriate objects and prepare the response. Then try to
|
||||
// write the response to the pipe asynchronously. If that succeeds,
|
||||
// go into the WRITING state. For any problems, go into the DISCONNECTING
|
||||
// state.
|
||||
void CrashGenerationServer::HandleReadDoneState() {
|
||||
assert(server_state_ == IPC_SERVER_STATE_READ_DONE);
|
||||
|
||||
if (!ValidateClientRequest(msg_)) {
|
||||
server_state_ = IPC_SERVER_STATE_DISCONNECTING;
|
||||
return;
|
||||
}
|
||||
|
||||
scoped_ptr<ClientInfo> client_info(
|
||||
new ClientInfo(this,
|
||||
msg_.pid,
|
||||
msg_.dump_type,
|
||||
msg_.thread_id,
|
||||
msg_.exception_pointers,
|
||||
msg_.assert_info));
|
||||
|
||||
if (!client_info->Initialize()) {
|
||||
server_state_ = IPC_SERVER_STATE_DISCONNECTING;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!RespondToClient(client_info.get())) {
|
||||
server_state_ = IPC_SERVER_STATE_DISCONNECTING;
|
||||
return;
|
||||
}
|
||||
|
||||
// Note that the asynchronous write issued by RespondToClient function
|
||||
// can finish before the code below executes. But it is okay to change
|
||||
// state after issuing the asynchronous write. This is because even if
|
||||
// the asynchronous write is done, the callback for it would not be
|
||||
// executed until the current thread finishes its execution.
|
||||
server_state_ = IPC_SERVER_STATE_WRITING;
|
||||
client_info_ = client_info.release();
|
||||
}
|
||||
|
||||
// When the server thread serving the clients is in the WRITING state,
|
||||
// try to get the result of the async write. If the async write is done,
|
||||
// go into the WRITE_DONE state. For any problems, go into the
|
||||
// DISONNECTING state.
|
||||
void CrashGenerationServer::HandleWritingState() {
|
||||
assert(server_state_ == IPC_SERVER_STATE_WRITING);
|
||||
|
||||
DWORD bytes_count = 0;
|
||||
bool success = GetOverlappedResult(pipe_,
|
||||
&overlapped_,
|
||||
&bytes_count,
|
||||
FALSE) != FALSE;
|
||||
|
||||
if (success) {
|
||||
server_state_ = IPC_SERVER_STATE_WRITE_DONE;
|
||||
return;
|
||||
}
|
||||
|
||||
DWORD error_code;
|
||||
error_code = GetLastError();
|
||||
|
||||
// We should never get an I/O incomplete since we should not execute this
|
||||
// unless the Write has finished and the overlapped event is signaled. If
|
||||
// we do get INCOMPLETE, we have a bug in our code.
|
||||
assert(error_code != ERROR_IO_INCOMPLETE);
|
||||
|
||||
server_state_ = IPC_SERVER_STATE_DISCONNECTING;
|
||||
}
|
||||
|
||||
// When the server thread serving the clients is in the WRITE_DONE state,
|
||||
// try to issue an async read on the pipe. If the read completes synchronously
|
||||
// or if I/O is still pending then go into the READING_ACK state. For any
|
||||
// issues, go into the DISCONNECTING state.
|
||||
void CrashGenerationServer::HandleWriteDoneState() {
|
||||
assert(server_state_ == IPC_SERVER_STATE_WRITE_DONE);
|
||||
|
||||
server_state_ = IPC_SERVER_STATE_READING_ACK;
|
||||
|
||||
DWORD bytes_count = 0;
|
||||
bool success = ReadFile(pipe_,
|
||||
&msg_,
|
||||
sizeof(msg_),
|
||||
&bytes_count,
|
||||
&overlapped_) != FALSE;
|
||||
|
||||
if (success) {
|
||||
return;
|
||||
}
|
||||
|
||||
DWORD error_code = GetLastError();
|
||||
|
||||
if (error_code != ERROR_IO_PENDING) {
|
||||
server_state_ = IPC_SERVER_STATE_DISCONNECTING;
|
||||
}
|
||||
}
|
||||
|
||||
// When the server thread serving the clients is in the READING_ACK state,
|
||||
// try to get result of async read. Go into the DISCONNECTING state.
|
||||
void CrashGenerationServer::HandleReadingAckState() {
|
||||
assert(server_state_ == IPC_SERVER_STATE_READING_ACK);
|
||||
|
||||
DWORD bytes_count = 0;
|
||||
bool success = GetOverlappedResult(pipe_,
|
||||
&overlapped_,
|
||||
&bytes_count,
|
||||
FALSE) != FALSE;
|
||||
|
||||
if (success) {
|
||||
// The connection handshake with the client is now complete; perform
|
||||
// the callback.
|
||||
if (connect_callback_) {
|
||||
connect_callback_(connect_context_, client_info_);
|
||||
}
|
||||
} else {
|
||||
DWORD error_code;
|
||||
error_code = GetLastError();
|
||||
|
||||
// We should never get an I/O incomplete since we should not execute this
|
||||
// unless the Read has finished and the overlapped event is signaled. If
|
||||
// we do get INCOMPLETE, we have a bug in our code.
|
||||
assert(error_code != ERROR_IO_INCOMPLETE);
|
||||
}
|
||||
|
||||
server_state_ = IPC_SERVER_STATE_DISCONNECTING;
|
||||
}
|
||||
|
||||
// When the server thread serving the client is in the DISCONNECTING state,
|
||||
// disconnect from the pipe and reset the event. If anything fails, go into
|
||||
// the ERROR state. If it goes well, go into the INITIAL state and set the
|
||||
// event to start all over again.
|
||||
void CrashGenerationServer::HandleDisconnectingState() {
|
||||
assert(server_state_ == IPC_SERVER_STATE_DISCONNECTING);
|
||||
|
||||
// Done serving the client.
|
||||
client_info_ = NULL;
|
||||
|
||||
overlapped_.Internal = NULL;
|
||||
overlapped_.InternalHigh = NULL;
|
||||
overlapped_.Offset = 0;
|
||||
overlapped_.OffsetHigh = 0;
|
||||
overlapped_.Pointer = NULL;
|
||||
|
||||
if (!ResetEvent(overlapped_.hEvent)) {
|
||||
server_state_ = IPC_SERVER_STATE_ERROR;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!DisconnectNamedPipe(pipe_)) {
|
||||
server_state_ = IPC_SERVER_STATE_ERROR;
|
||||
return;
|
||||
}
|
||||
|
||||
// If the server is shutting down do not connect to the
|
||||
// next client.
|
||||
if (shutting_down_) {
|
||||
return;
|
||||
}
|
||||
|
||||
server_state_ = IPC_SERVER_STATE_INITIAL;
|
||||
if (!SetEvent(overlapped_.hEvent)) {
|
||||
server_state_ = IPC_SERVER_STATE_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
bool CrashGenerationServer::PrepareReply(const ClientInfo& client_info,
|
||||
ProtocolMessage* reply) const {
|
||||
reply->tag = MESSAGE_TAG_REGISTRATION_RESPONSE;
|
||||
reply->pid = GetCurrentProcessId();
|
||||
|
||||
if (CreateClientHandles(client_info, reply)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (reply->dump_request_handle) {
|
||||
CloseHandle(reply->dump_request_handle);
|
||||
}
|
||||
|
||||
if (reply->dump_generated_handle) {
|
||||
CloseHandle(reply->dump_generated_handle);
|
||||
}
|
||||
|
||||
if (reply->server_alive_handle) {
|
||||
CloseHandle(reply->server_alive_handle);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CrashGenerationServer::CreateClientHandles(const ClientInfo& client_info,
|
||||
ProtocolMessage* reply) const {
|
||||
HANDLE current_process = GetCurrentProcess();
|
||||
if (!DuplicateHandle(current_process,
|
||||
client_info.dump_requested_handle(),
|
||||
client_info.process_handle(),
|
||||
&reply->dump_request_handle,
|
||||
kDumpRequestEventAccess,
|
||||
FALSE,
|
||||
0)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!DuplicateHandle(current_process,
|
||||
client_info.dump_generated_handle(),
|
||||
client_info.process_handle(),
|
||||
&reply->dump_generated_handle,
|
||||
kDumpGeneratedEventAccess,
|
||||
FALSE,
|
||||
0)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!DuplicateHandle(current_process,
|
||||
server_alive_handle_,
|
||||
client_info.process_handle(),
|
||||
&reply->server_alive_handle,
|
||||
kMutexAccess,
|
||||
FALSE,
|
||||
0)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CrashGenerationServer::RespondToClient(ClientInfo* client_info) {
|
||||
ProtocolMessage reply;
|
||||
if (!PrepareReply(*client_info, &reply)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!AddClient(client_info)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
DWORD bytes_count = 0;
|
||||
bool success = WriteFile(pipe_,
|
||||
&reply,
|
||||
sizeof(reply),
|
||||
&bytes_count,
|
||||
&overlapped_) != FALSE;
|
||||
|
||||
return success || GetLastError() == ERROR_IO_PENDING;
|
||||
}
|
||||
|
||||
// The server thread servicing the clients runs this method. The method
|
||||
// implements the state machine described in ReadMe.txt along with the
|
||||
// helper methods HandleXXXState.
|
||||
void CrashGenerationServer::HandleConnectionRequest() {
|
||||
switch (server_state_) {
|
||||
case IPC_SERVER_STATE_ERROR:
|
||||
HandleErrorState();
|
||||
break;
|
||||
|
||||
case IPC_SERVER_STATE_INITIAL:
|
||||
HandleInitialState();
|
||||
break;
|
||||
|
||||
case IPC_SERVER_STATE_CONNECTING:
|
||||
HandleConnectingState();
|
||||
break;
|
||||
|
||||
case IPC_SERVER_STATE_CONNECTED:
|
||||
HandleConnectedState();
|
||||
break;
|
||||
|
||||
case IPC_SERVER_STATE_READING:
|
||||
HandleReadingState();
|
||||
break;
|
||||
|
||||
case IPC_SERVER_STATE_READ_DONE:
|
||||
HandleReadDoneState();
|
||||
break;
|
||||
|
||||
case IPC_SERVER_STATE_WRITING:
|
||||
HandleWritingState();
|
||||
break;
|
||||
|
||||
case IPC_SERVER_STATE_WRITE_DONE:
|
||||
HandleWriteDoneState();
|
||||
break;
|
||||
|
||||
case IPC_SERVER_STATE_READING_ACK:
|
||||
HandleReadingAckState();
|
||||
break;
|
||||
|
||||
case IPC_SERVER_STATE_DISCONNECTING:
|
||||
HandleDisconnectingState();
|
||||
break;
|
||||
|
||||
default:
|
||||
assert(false);
|
||||
// This indicates that we added one more state without
|
||||
// adding handling code.
|
||||
server_state_ = IPC_SERVER_STATE_ERROR;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
bool CrashGenerationServer::AddClient(ClientInfo* client_info) {
|
||||
HANDLE request_wait_handle = NULL;
|
||||
if (!RegisterWaitForSingleObject(&request_wait_handle,
|
||||
client_info->dump_requested_handle(),
|
||||
OnDumpRequest,
|
||||
client_info,
|
||||
INFINITE,
|
||||
kDumpRequestThreadFlags)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
client_info->set_dump_request_wait_handle(request_wait_handle);
|
||||
|
||||
// OnClientEnd will be called when the client process terminates.
|
||||
HANDLE process_wait_handle = NULL;
|
||||
if (!RegisterWaitForSingleObject(&process_wait_handle,
|
||||
client_info->process_handle(),
|
||||
OnClientEnd,
|
||||
client_info,
|
||||
INFINITE,
|
||||
WT_EXECUTEONLYONCE)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
client_info->set_process_exit_wait_handle(process_wait_handle);
|
||||
|
||||
// New scope to hold the lock for the shortest time.
|
||||
{
|
||||
AutoCriticalSection lock(&clients_sync_);
|
||||
clients_.push_back(client_info);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// static
|
||||
void CALLBACK CrashGenerationServer::OnPipeConnected(void* context, BOOLEAN) {
|
||||
assert (context);
|
||||
|
||||
CrashGenerationServer* obj =
|
||||
reinterpret_cast<CrashGenerationServer*>(context);
|
||||
obj->HandleConnectionRequest();
|
||||
}
|
||||
|
||||
// static
|
||||
void CALLBACK CrashGenerationServer::OnDumpRequest(void* context, BOOLEAN) {
|
||||
assert(context);
|
||||
ClientInfo* client_info = reinterpret_cast<ClientInfo*>(context);
|
||||
|
||||
CrashGenerationServer* crash_server = client_info->crash_server();
|
||||
assert(crash_server);
|
||||
crash_server->HandleDumpRequest(*client_info);
|
||||
|
||||
ResetEvent(client_info->dump_requested_handle());
|
||||
}
|
||||
|
||||
// static
|
||||
void CALLBACK CrashGenerationServer::OnClientEnd(void* context, BOOLEAN) {
|
||||
assert(context);
|
||||
ClientInfo* client_info = reinterpret_cast<ClientInfo*>(context);
|
||||
|
||||
CrashGenerationServer* crash_server = client_info->crash_server();
|
||||
assert(crash_server);
|
||||
|
||||
InterlockedIncrement(&crash_server->cleanup_item_count_);
|
||||
|
||||
if (!QueueUserWorkItem(CleanupClient, context, WT_EXECUTEDEFAULT))
|
||||
{
|
||||
InterlockedDecrement(&crash_server->cleanup_item_count_);
|
||||
}
|
||||
}
|
||||
|
||||
// static
|
||||
DWORD WINAPI CrashGenerationServer::CleanupClient(void* context) {
|
||||
assert(context);
|
||||
ClientInfo* client_info = reinterpret_cast<ClientInfo*>(context);
|
||||
|
||||
CrashGenerationServer* crash_server = client_info->crash_server();
|
||||
assert(crash_server);
|
||||
|
||||
if (crash_server->exit_callback_) {
|
||||
crash_server->exit_callback_(crash_server->exit_context_, client_info);
|
||||
}
|
||||
|
||||
crash_server->DoCleanup(client_info);
|
||||
|
||||
InterlockedDecrement(&crash_server->cleanup_item_count_);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void CrashGenerationServer::DoCleanup(ClientInfo* client_info) {
|
||||
assert(client_info);
|
||||
|
||||
// Start a new scope to release lock automatically.
|
||||
{
|
||||
AutoCriticalSection lock(&clients_sync_);
|
||||
clients_.remove(client_info);
|
||||
}
|
||||
|
||||
delete client_info;
|
||||
}
|
||||
|
||||
void CrashGenerationServer::HandleDumpRequest(const ClientInfo& client_info) {
|
||||
// Generate the dump only if it's explicitly requested by the
|
||||
// server application; otherwise the server might want to generate
|
||||
// dump in the callback.
|
||||
if (generate_dumps_) {
|
||||
if (!GenerateDump(client_info)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (dump_callback_) {
|
||||
dump_callback_(dump_context_, &client_info);
|
||||
}
|
||||
|
||||
SetEvent(client_info.dump_generated_handle());
|
||||
}
|
||||
|
||||
bool CrashGenerationServer::GenerateDump(const ClientInfo& client) {
|
||||
assert(client.pid() != 0);
|
||||
assert(client.process_handle());
|
||||
|
||||
// We have to get the address of EXCEPTION_INFORMATION from
|
||||
// the client process address space.
|
||||
EXCEPTION_POINTERS* client_ex_info = NULL;
|
||||
if (!client.GetClientExceptionInfo(&client_ex_info)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
DWORD client_thread_id = 0;
|
||||
if (!client.GetClientThreadId(&client_thread_id)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return dump_generator_->WriteMinidump(client.process_handle(),
|
||||
client.pid(),
|
||||
client_thread_id,
|
||||
GetCurrentThreadId(),
|
||||
client_ex_info,
|
||||
client.assert_info(),
|
||||
client.dump_type(),
|
||||
true);
|
||||
}
|
||||
|
||||
} // namespace google_breakpad
|
|
@ -0,0 +1,255 @@
|
|||
// Copyright (c) 2008, 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.
|
||||
|
||||
#ifndef CLIENT_WINDOWS_CRASH_GENERATION_CRASH_GENERATION_SERVER_H__
|
||||
#define CLIENT_WINDOWS_CRASH_GENERATION_CRASH_GENERATION_SERVER_H__
|
||||
|
||||
#include <list>
|
||||
#include <string>
|
||||
#include "client/windows/common/ipc_protocol.h"
|
||||
#include "client/windows/crash_generation/client_info.h"
|
||||
#include "client/windows/crash_generation/minidump_generator.h"
|
||||
#include "processor/scoped_ptr.h"
|
||||
|
||||
namespace google_breakpad {
|
||||
|
||||
// Abstraction for server side implementation of out-of-process crash
|
||||
// generation protocol. It generates minidumps (Windows platform) for
|
||||
// client processes that request dump generation.
|
||||
class CrashGenerationServer {
|
||||
public:
|
||||
typedef void (*OnClientConnectedCallback)(void* context,
|
||||
const ClientInfo* client_info);
|
||||
|
||||
typedef void (*OnClientDumpRequestCallback)(void* context,
|
||||
const ClientInfo* client_info);
|
||||
|
||||
typedef void (*OnClientExitedCallback)(void* context,
|
||||
const ClientInfo* client_info);
|
||||
|
||||
// Creates an instance with the given parameters.
|
||||
//
|
||||
// Parameter pipe_name: Name of the pipe
|
||||
// Parameter connect_callback: Callback for a new client connection.
|
||||
// Parameter connect_context: Context for client connection callback.
|
||||
// Parameter crash_callback: Callback for a client crash dump request.
|
||||
// Parameter crash_context: Context for client crash dump request callback.
|
||||
// Parameter exit_callback: Callback for client process exit.
|
||||
// Parameter exit_context: Context for client exit callback.
|
||||
// Parameter generate_dumps: Whether to automatically generate dumps or not.
|
||||
// Client code of this class might want to generate dumps explicitly in the
|
||||
// crash dump request callback. In that case, false can be passed for this
|
||||
// parameter.
|
||||
// Parameter dump_path: Path for generating dumps; required only if true is
|
||||
// passed for generateDumps parameter; NULL can be passed otherwise.
|
||||
CrashGenerationServer(const wchar_t* pipe_name,
|
||||
OnClientConnectedCallback connect_callback,
|
||||
void* connect_context,
|
||||
OnClientDumpRequestCallback dump_callback,
|
||||
void* dump_context,
|
||||
OnClientExitedCallback exit_callback,
|
||||
void* exit_context,
|
||||
bool generate_dumps,
|
||||
const std::wstring* dump_path);
|
||||
|
||||
~CrashGenerationServer();
|
||||
|
||||
// Performs initialization steps needed to start listening to clients.
|
||||
//
|
||||
// Returns true if initialization is successful; false otherwise.
|
||||
bool Start();
|
||||
|
||||
private:
|
||||
// Various states the client can be in during the handshake with
|
||||
// the server.
|
||||
enum IPCServerState {
|
||||
// Server is in error state and it cannot serve any clients.
|
||||
IPC_SERVER_STATE_ERROR,
|
||||
|
||||
// Server starts in this state.
|
||||
IPC_SERVER_STATE_INITIAL,
|
||||
|
||||
// Server has issued an async connect to the pipe and it is waiting
|
||||
// for the connection to be established.
|
||||
IPC_SERVER_STATE_CONNECTING,
|
||||
|
||||
// Server is connected successfully.
|
||||
IPC_SERVER_STATE_CONNECTED,
|
||||
|
||||
// Server has issued an async read from the pipe and it is waiting for
|
||||
// the read to finish.
|
||||
IPC_SERVER_STATE_READING,
|
||||
|
||||
// Server is done reading from the pipe.
|
||||
IPC_SERVER_STATE_READ_DONE,
|
||||
|
||||
// Server has issued an async write to the pipe and it is waiting for
|
||||
// the write to finish.
|
||||
IPC_SERVER_STATE_WRITING,
|
||||
|
||||
// Server is done writing to the pipe.
|
||||
IPC_SERVER_STATE_WRITE_DONE,
|
||||
|
||||
// Server has issued an async read from the pipe for an ack and it
|
||||
// is waiting for the read to finish.
|
||||
IPC_SERVER_STATE_READING_ACK,
|
||||
|
||||
// Server is done writing to the pipe and it is now ready to disconnect
|
||||
// and reconnect.
|
||||
IPC_SERVER_STATE_DISCONNECTING
|
||||
};
|
||||
|
||||
//
|
||||
// Helper methods to handle various server IPC states.
|
||||
//
|
||||
void HandleErrorState();
|
||||
void HandleInitialState();
|
||||
void HandleConnectingState();
|
||||
void HandleConnectedState();
|
||||
void HandleReadingState();
|
||||
void HandleReadDoneState();
|
||||
void HandleWritingState();
|
||||
void HandleWriteDoneState();
|
||||
void HandleReadingAckState();
|
||||
void HandleDisconnectingState();
|
||||
|
||||
// Prepares reply for a client from the given parameters.
|
||||
bool PrepareReply(const ClientInfo& client_info,
|
||||
ProtocolMessage* reply) const;
|
||||
|
||||
// Duplicates various handles in the ClientInfo object for the client
|
||||
// process and stores them in the given ProtocolMessage instance. If
|
||||
// creating any handle fails, ProtocolMessage will contain the handles
|
||||
// already created successfully, which should be closed by the caller.
|
||||
bool CreateClientHandles(const ClientInfo& client_info,
|
||||
ProtocolMessage* reply) const;
|
||||
|
||||
// Response to the given client. Return true if all steps of
|
||||
// responding to the client succeed, false otherwise.
|
||||
bool RespondToClient(ClientInfo* client_info);
|
||||
|
||||
// Handles a connection request from the client.
|
||||
void HandleConnectionRequest();
|
||||
|
||||
// Handles a dump request from the client.
|
||||
void HandleDumpRequest(const ClientInfo& client_info);
|
||||
|
||||
// Callback for pipe connected event.
|
||||
static void CALLBACK OnPipeConnected(void* context, BOOLEAN timer_or_wait);
|
||||
|
||||
// Callback for a dump request.
|
||||
static void CALLBACK OnDumpRequest(void* context, BOOLEAN timer_or_wait);
|
||||
|
||||
// Callback for client process exit event.
|
||||
static void CALLBACK OnClientEnd(void* context, BOOLEAN timer_or_wait);
|
||||
|
||||
// Releases resources for a client.
|
||||
static DWORD WINAPI CleanupClient(void* context);
|
||||
|
||||
// Cleans up for the given client.
|
||||
void DoCleanup(ClientInfo* client_info);
|
||||
|
||||
// Adds the given client to the list of registered clients.
|
||||
bool AddClient(ClientInfo* client_info);
|
||||
|
||||
// Generates dump for the given client.
|
||||
bool GenerateDump(const ClientInfo& client);
|
||||
|
||||
// Sync object for thread-safe access to the shared list of clients.
|
||||
CRITICAL_SECTION clients_sync_;
|
||||
|
||||
// List of clients.
|
||||
std::list<ClientInfo*> clients_;
|
||||
|
||||
// Pipe name.
|
||||
std::wstring pipe_name_;
|
||||
|
||||
// Handle to the pipe used for handshake with clients.
|
||||
HANDLE pipe_;
|
||||
|
||||
// Pipe wait handle.
|
||||
HANDLE pipe_wait_handle_;
|
||||
|
||||
// Handle to server-alive mutex.
|
||||
HANDLE server_alive_handle_;
|
||||
|
||||
// Callback for a successful client connection.
|
||||
OnClientConnectedCallback connect_callback_;
|
||||
|
||||
// Context for client connected callback.
|
||||
void* connect_context_;
|
||||
|
||||
// Callback for a client dump request.
|
||||
OnClientDumpRequestCallback dump_callback_;
|
||||
|
||||
// Context for client dump request callback.
|
||||
void* dump_context_;
|
||||
|
||||
// Callback for client process exit.
|
||||
OnClientExitedCallback exit_callback_;
|
||||
|
||||
// Context for client process exit callback.
|
||||
void* exit_context_;
|
||||
|
||||
// Whether to generate dumps or not.
|
||||
bool generate_dumps_;
|
||||
|
||||
// Instance of a mini dump generator.
|
||||
scoped_ptr<MinidumpGenerator> dump_generator_;
|
||||
|
||||
// State of the server in performing the IPC with the client.
|
||||
// Note that since we restrict the pipe to one instance, we
|
||||
// only need to keep one state of the server. Otherwise, server
|
||||
// would have one state per client it is talking to.
|
||||
IPCServerState server_state_;
|
||||
|
||||
// Whether the server is shutting down.
|
||||
volatile bool shutting_down_;
|
||||
|
||||
// Overlapped instance for async I/O on the pipe.
|
||||
OVERLAPPED overlapped_;
|
||||
|
||||
// Message object used in IPC with the client.
|
||||
ProtocolMessage msg_;
|
||||
|
||||
// Client Info for the client that's connecting to the server.
|
||||
ClientInfo* client_info_;
|
||||
|
||||
// Count of clean-up work items that are currently running or are
|
||||
// already queued to run.
|
||||
volatile LONG cleanup_item_count_;
|
||||
|
||||
// Disable copy ctor and operator=.
|
||||
CrashGenerationServer(const CrashGenerationServer& crash_server);
|
||||
CrashGenerationServer& operator=(const CrashGenerationServer& crash_server);
|
||||
};
|
||||
|
||||
} // namespace google_breakpad
|
||||
|
||||
#endif // CLIENT_WINDOWS_CRASH_GENERATION_CRASH_GENERATION_SERVER_H__
|
|
@ -0,0 +1,228 @@
|
|||
// Copyright (c) 2008, 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.
|
||||
|
||||
#include "client/windows/crash_generation/minidump_generator.h"
|
||||
#include <cassert>
|
||||
#include "client/windows/common/auto_critical_section.h"
|
||||
#include "common/windows/guid_string.h"
|
||||
|
||||
using std::wstring;
|
||||
|
||||
namespace google_breakpad {
|
||||
|
||||
MinidumpGenerator::MinidumpGenerator(const wstring& dump_path)
|
||||
: dbghelp_module_(NULL),
|
||||
rpcrt4_module_(NULL),
|
||||
dump_path_(dump_path),
|
||||
write_dump_(NULL),
|
||||
create_uuid_(NULL) {
|
||||
InitializeCriticalSection(&module_load_sync_);
|
||||
InitializeCriticalSection(&get_proc_address_sync_);
|
||||
}
|
||||
|
||||
MinidumpGenerator::~MinidumpGenerator() {
|
||||
if (dbghelp_module_) {
|
||||
FreeLibrary(dbghelp_module_);
|
||||
}
|
||||
|
||||
if (rpcrt4_module_) {
|
||||
FreeLibrary(rpcrt4_module_);
|
||||
}
|
||||
|
||||
DeleteCriticalSection(&get_proc_address_sync_);
|
||||
DeleteCriticalSection(&module_load_sync_);
|
||||
}
|
||||
|
||||
bool MinidumpGenerator::WriteMinidump(HANDLE process_handle,
|
||||
DWORD process_id,
|
||||
DWORD thread_id,
|
||||
DWORD requesting_thread_id,
|
||||
EXCEPTION_POINTERS* exception_pointers,
|
||||
MDRawAssertionInfo* assert_info,
|
||||
MINIDUMP_TYPE dump_type,
|
||||
bool is_client_pointers) {
|
||||
MiniDumpWriteDumpType write_dump = GetWriteDump();
|
||||
if (!write_dump) {
|
||||
return false;
|
||||
}
|
||||
|
||||
wstring dump_file_path;
|
||||
if (!GenerateDumpFilePath(&dump_file_path)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
HANDLE dump_file = CreateFile(dump_file_path.c_str(),
|
||||
GENERIC_WRITE,
|
||||
0,
|
||||
NULL,
|
||||
CREATE_NEW,
|
||||
FILE_ATTRIBUTE_NORMAL,
|
||||
NULL);
|
||||
|
||||
if (dump_file == INVALID_HANDLE_VALUE) {
|
||||
return false;
|
||||
}
|
||||
|
||||
MINIDUMP_EXCEPTION_INFORMATION* dump_exception_pointers = NULL;
|
||||
MINIDUMP_EXCEPTION_INFORMATION dump_exception_info;
|
||||
|
||||
// Setup the exception information object only if it's a dump
|
||||
// due to an exception.
|
||||
if (exception_pointers) {
|
||||
dump_exception_pointers = &dump_exception_info;
|
||||
dump_exception_info.ThreadId = thread_id;
|
||||
dump_exception_info.ExceptionPointers = exception_pointers;
|
||||
dump_exception_info.ClientPointers = is_client_pointers;
|
||||
}
|
||||
|
||||
// Add an MDRawBreakpadInfo stream to the minidump, to provide additional
|
||||
// information about the exception handler to the Breakpad processor.
|
||||
// The information will help the processor determine which threads are
|
||||
// relevant. The Breakpad processor does not require this information but
|
||||
// can function better with Breakpad-generated dumps when it is present.
|
||||
// The native debugger is not harmed by the presence of this information.
|
||||
MDRawBreakpadInfo breakpad_info;
|
||||
breakpad_info.validity = MD_BREAKPAD_INFO_VALID_DUMP_THREAD_ID |
|
||||
MD_BREAKPAD_INFO_VALID_REQUESTING_THREAD_ID;
|
||||
breakpad_info.dump_thread_id = thread_id;
|
||||
breakpad_info.requesting_thread_id = requesting_thread_id;
|
||||
|
||||
// Leave room in user_stream_array for a possible assertion info stream.
|
||||
MINIDUMP_USER_STREAM user_stream_array[2];
|
||||
user_stream_array[0].Type = MD_BREAKPAD_INFO_STREAM;
|
||||
user_stream_array[0].BufferSize = sizeof(breakpad_info);
|
||||
user_stream_array[0].Buffer = &breakpad_info;
|
||||
|
||||
MINIDUMP_USER_STREAM_INFORMATION user_streams;
|
||||
user_streams.UserStreamCount = 1;
|
||||
user_streams.UserStreamArray = user_stream_array;
|
||||
|
||||
MDRawAssertionInfo* actual_assert_info = assert_info;
|
||||
MDRawAssertionInfo client_assert_info = {0};
|
||||
|
||||
if (assert_info) {
|
||||
// If the assertion info object lives in the client process,
|
||||
// read the memory of the client process.
|
||||
if (is_client_pointers) {
|
||||
SIZE_T bytes_read = 0;
|
||||
if (!ReadProcessMemory(process_handle,
|
||||
assert_info,
|
||||
&client_assert_info,
|
||||
sizeof(client_assert_info),
|
||||
&bytes_read)) {
|
||||
CloseHandle(dump_file);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (bytes_read != sizeof(client_assert_info)) {
|
||||
CloseHandle(dump_file);
|
||||
return false;
|
||||
}
|
||||
|
||||
actual_assert_info = &client_assert_info;
|
||||
}
|
||||
|
||||
user_stream_array[1].Type = MD_ASSERTION_INFO_STREAM;
|
||||
user_stream_array[1].BufferSize = sizeof(MDRawAssertionInfo);
|
||||
user_stream_array[1].Buffer = actual_assert_info;
|
||||
++user_streams.UserStreamCount;
|
||||
}
|
||||
|
||||
bool result = write_dump(process_handle,
|
||||
process_id,
|
||||
dump_file,
|
||||
dump_type,
|
||||
exception_pointers ? &dump_exception_info : NULL,
|
||||
&user_streams,
|
||||
NULL) != FALSE;
|
||||
|
||||
CloseHandle(dump_file);
|
||||
return result;
|
||||
}
|
||||
|
||||
HMODULE MinidumpGenerator::GetDbghelpModule() {
|
||||
AutoCriticalSection lock(&module_load_sync_);
|
||||
if (!dbghelp_module_) {
|
||||
dbghelp_module_ = LoadLibrary(TEXT("dbghelp.dll"));
|
||||
}
|
||||
|
||||
return dbghelp_module_;
|
||||
}
|
||||
|
||||
MinidumpGenerator::MiniDumpWriteDumpType MinidumpGenerator::GetWriteDump() {
|
||||
AutoCriticalSection lock(&get_proc_address_sync_);
|
||||
if (!write_dump_) {
|
||||
HMODULE module = GetDbghelpModule();
|
||||
if (module) {
|
||||
FARPROC proc = GetProcAddress(module, "MiniDumpWriteDump");
|
||||
write_dump_ = reinterpret_cast<MiniDumpWriteDumpType>(proc);
|
||||
}
|
||||
}
|
||||
|
||||
return write_dump_;
|
||||
}
|
||||
|
||||
HMODULE MinidumpGenerator::GetRpcrt4Module() {
|
||||
AutoCriticalSection lock(&module_load_sync_);
|
||||
if (!rpcrt4_module_) {
|
||||
rpcrt4_module_ = LoadLibrary(TEXT("rpcrt4.dll"));
|
||||
}
|
||||
|
||||
return rpcrt4_module_;
|
||||
}
|
||||
|
||||
MinidumpGenerator::UuidCreateType MinidumpGenerator::GetCreateUuid() {
|
||||
AutoCriticalSection lock(&module_load_sync_);
|
||||
if (!create_uuid_) {
|
||||
HMODULE module = GetRpcrt4Module();
|
||||
if (module) {
|
||||
FARPROC proc = GetProcAddress(module, "UuidCreate");
|
||||
create_uuid_ = reinterpret_cast<UuidCreateType>(proc);
|
||||
}
|
||||
}
|
||||
|
||||
return create_uuid_;
|
||||
}
|
||||
|
||||
bool MinidumpGenerator::GenerateDumpFilePath(wstring* file_path) {
|
||||
UUID id = {0};
|
||||
|
||||
UuidCreateType create_uuid = GetCreateUuid();
|
||||
if(!create_uuid) {
|
||||
return false;
|
||||
}
|
||||
|
||||
create_uuid(&id);
|
||||
wstring id_str = GUIDString::GUIDToWString(&id);
|
||||
|
||||
*file_path = dump_path_ + TEXT("\\") + id_str + TEXT(".dmp");
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace google_breakpad
|
|
@ -0,0 +1,118 @@
|
|||
// Copyright (c) 2008, 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.
|
||||
|
||||
#ifndef CLIENT_WINDOWS_CRASH_GENERATION_MINIDUMP_GENERATION_H__
|
||||
#define CLIENT_WINDOWS_CRASH_GENERATION_MINIDUMP_GENERATION_H__
|
||||
|
||||
#include <Windows.h>
|
||||
#include <DbgHelp.h>
|
||||
#include <list>
|
||||
#include "google_breakpad/common/minidump_format.h"
|
||||
|
||||
namespace google_breakpad {
|
||||
|
||||
// Abstraction for various objects and operations needed to generate
|
||||
// minidump on Windows. This abstraction is useful to hide all the gory
|
||||
// details for minidump generation and provide a clean interface to
|
||||
// the clients to generate minidumps.
|
||||
class MinidumpGenerator {
|
||||
public:
|
||||
// Creates an instance with the given dump path.
|
||||
explicit MinidumpGenerator(const std::wstring& dump_path);
|
||||
|
||||
~MinidumpGenerator();
|
||||
|
||||
// Writes the minidump with the given parameters.
|
||||
bool WriteMinidump(HANDLE process_handle,
|
||||
DWORD process_id,
|
||||
DWORD thread_id,
|
||||
DWORD requesting_thread_id,
|
||||
EXCEPTION_POINTERS* exception_pointers,
|
||||
MDRawAssertionInfo* assert_info,
|
||||
MINIDUMP_TYPE dump_type,
|
||||
bool is_client_pointers);
|
||||
|
||||
private:
|
||||
// Function pointer type for MiniDumpWriteDump, which is looked up
|
||||
// dynamically.
|
||||
typedef BOOL (WINAPI* MiniDumpWriteDumpType)(
|
||||
HANDLE hProcess,
|
||||
DWORD ProcessId,
|
||||
HANDLE hFile,
|
||||
MINIDUMP_TYPE DumpType,
|
||||
CONST PMINIDUMP_EXCEPTION_INFORMATION ExceptionParam,
|
||||
CONST PMINIDUMP_USER_STREAM_INFORMATION UserStreamParam,
|
||||
CONST PMINIDUMP_CALLBACK_INFORMATION CallbackParam);
|
||||
|
||||
// Function pointer type for UuidCreate, which is looked up dynamically.
|
||||
typedef RPC_STATUS (RPC_ENTRY* UuidCreateType)(UUID* Uuid);
|
||||
|
||||
// Loads the appropriate DLL lazily in a thread safe way.
|
||||
HMODULE GetDbghelpModule();
|
||||
|
||||
// Loads the appropriate DLL and gets a pointer to the MiniDumpWriteDump
|
||||
// function lazily and in a thread-safe manner.
|
||||
MiniDumpWriteDumpType GetWriteDump();
|
||||
|
||||
// Loads the appropriate DLL lazily in a thread safe way.
|
||||
HMODULE GetRpcrt4Module();
|
||||
|
||||
// Loads the appropriate DLL and gets a pointer to the UuidCreate
|
||||
// function lazily and in a thread-safe manner.
|
||||
UuidCreateType GetCreateUuid();
|
||||
|
||||
// Returns the path for the file to write dump to.
|
||||
bool GenerateDumpFilePath(std::wstring* file_path);
|
||||
|
||||
// Handle to dynamically loaded DbgHelp.dll.
|
||||
HMODULE dbghelp_module_;
|
||||
|
||||
// Pointer to the MiniDumpWriteDump function.
|
||||
MiniDumpWriteDumpType write_dump_;
|
||||
|
||||
// Handle to dynamically loaded rpcrt4.dll.
|
||||
HMODULE rpcrt4_module_;
|
||||
|
||||
// Pointer to the UuidCreate function.
|
||||
UuidCreateType create_uuid_;
|
||||
|
||||
// Folder path to store dump files.
|
||||
std::wstring dump_path_;
|
||||
|
||||
// Critical section to sychronize action of loading modules dynamically.
|
||||
CRITICAL_SECTION module_load_sync_;
|
||||
|
||||
// Critical section to synchronize action of dynamically getting function
|
||||
// addresses from modules.
|
||||
CRITICAL_SECTION get_proc_address_sync_;
|
||||
};
|
||||
|
||||
} // namespace google_breakpad
|
||||
|
||||
#endif // CLIENT_WINDOWS_CRASH_GENERATION_MINIDUMP_GENERATION_H__
|
|
@ -0,0 +1,53 @@
|
|||
// Copyright (c) 2008, 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.
|
||||
|
||||
#include "precompile.h"
|
||||
|
||||
namespace google_breakpad {
|
||||
|
||||
Base::Base(Derived* derived)
|
||||
: derived_(derived) {
|
||||
}
|
||||
|
||||
Base::~Base() {
|
||||
derived_->DoSomething();
|
||||
}
|
||||
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable:4355)
|
||||
// Disable warning C4355: 'this' : used in base member initializer list.
|
||||
Derived::Derived()
|
||||
: Base(this) { // C4355
|
||||
}
|
||||
#pragma warning(pop)
|
||||
|
||||
void Derived::DoSomething() {
|
||||
}
|
||||
|
||||
} // namespace google_breakpad
|
|
@ -0,0 +1,57 @@
|
|||
// Copyright (c) 2008, 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.
|
||||
|
||||
#ifndef CLIENT_WINDOWS_TESTS_CRASH_GENERATION_APP_ABSTRACT_CLASS_H__
|
||||
#define CLIENT_WINDOWS_TESTS_CRASH_GENERATION_APP_ABSTRACT_CLASS_H__
|
||||
|
||||
namespace google_breakpad {
|
||||
|
||||
// Dummy classes to help generate a pure call violation.
|
||||
|
||||
class Derived;
|
||||
|
||||
class Base {
|
||||
public:
|
||||
Base(Derived* derived);
|
||||
virtual ~Base();
|
||||
virtual void DoSomething() = 0;
|
||||
|
||||
private:
|
||||
Derived* derived_;
|
||||
};
|
||||
|
||||
class Derived : public Base {
|
||||
public:
|
||||
Derived();
|
||||
virtual void DoSomething();
|
||||
};
|
||||
|
||||
} // namespace google_breakpad
|
||||
|
||||
#endif // CLIENT_WINDOWS_TESTS_CRASH_GENERATION_APP_CRASH_GENERATION_APP_H__
|
|
@ -0,0 +1,467 @@
|
|||
// Copyright (c) 2008, 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.
|
||||
|
||||
// crash_generation_app.cpp : Defines the entry point for the application.
|
||||
//
|
||||
|
||||
#include "precompile.h"
|
||||
|
||||
namespace google_breakpad {
|
||||
|
||||
const int kMaxLoadString = 100;
|
||||
const wchar_t kPipeName[] = L"\\\\.\\pipe\\GoogleCrashServices";
|
||||
|
||||
const DWORD kEditBoxStyles = WS_CHILD |
|
||||
WS_VISIBLE |
|
||||
WS_VSCROLL |
|
||||
ES_LEFT |
|
||||
ES_MULTILINE |
|
||||
ES_AUTOVSCROLL |
|
||||
ES_READONLY;
|
||||
|
||||
// Maximum length of a line in the edit box.
|
||||
const size_t kMaximumLineLength = 256;
|
||||
|
||||
// CS to access edit control in a thread safe way.
|
||||
static CRITICAL_SECTION* cs_edit = NULL;
|
||||
|
||||
// Edit control.
|
||||
static HWND client_status_edit_box;
|
||||
|
||||
HINSTANCE current_instance; // Current instance.
|
||||
TCHAR title[kMaxLoadString]; // Title bar text.
|
||||
TCHAR window_class[kMaxLoadString]; // Main window class name.
|
||||
|
||||
ATOM MyRegisterClass(HINSTANCE instance);
|
||||
BOOL InitInstance(HINSTANCE, int);
|
||||
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
|
||||
INT_PTR CALLBACK About(HWND, UINT, WPARAM, LPARAM);
|
||||
|
||||
static ExceptionHandler* handler = NULL;
|
||||
static CrashGenerationServer* crash_server = NULL;
|
||||
|
||||
// Registers the window class.
|
||||
//
|
||||
// This function and its usage are only necessary if you want this code
|
||||
// to be compatible with Win32 systems prior to the 'RegisterClassEx'
|
||||
// function that was added to Windows 95. It is important to call this
|
||||
// function so that the application will get 'well formed' small icons
|
||||
// associated with it.
|
||||
ATOM MyRegisterClass(HINSTANCE instance) {
|
||||
WNDCLASSEX wcex;
|
||||
wcex.cbSize = sizeof(WNDCLASSEX);
|
||||
wcex.style = CS_HREDRAW | CS_VREDRAW;
|
||||
wcex.lpfnWndProc = WndProc;
|
||||
wcex.cbClsExtra = 0;
|
||||
wcex.cbWndExtra = 0;
|
||||
wcex.hInstance = instance;
|
||||
wcex.hIcon = LoadIcon(instance,
|
||||
MAKEINTRESOURCE(IDI_CRASHGENERATIONAPP));
|
||||
wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
|
||||
wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
|
||||
wcex.lpszMenuName = MAKEINTRESOURCE(IDC_CRASHGENERATIONAPP);
|
||||
wcex.lpszClassName = window_class;
|
||||
wcex.hIconSm = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));
|
||||
|
||||
return RegisterClassEx(&wcex);
|
||||
}
|
||||
|
||||
// Saves instance handle and creates main window
|
||||
//
|
||||
// In this function, we save the instance handle in a global variable and
|
||||
// create and display the main program window.
|
||||
BOOL InitInstance(HINSTANCE instance, int command_show) {
|
||||
current_instance = instance;
|
||||
HWND wnd = CreateWindow(window_class,
|
||||
title,
|
||||
WS_OVERLAPPEDWINDOW,
|
||||
CW_USEDEFAULT,
|
||||
0,
|
||||
CW_USEDEFAULT,
|
||||
0,
|
||||
NULL,
|
||||
NULL,
|
||||
instance,
|
||||
NULL);
|
||||
|
||||
if (!wnd) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
ShowWindow(wnd, command_show);
|
||||
UpdateWindow(wnd);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void AppendTextToEditBox(TCHAR* text) {
|
||||
EnterCriticalSection(cs_edit);
|
||||
SYSTEMTIME current_time;
|
||||
GetLocalTime(¤t_time);
|
||||
TCHAR line[kMaximumLineLength];
|
||||
int result = swprintf_s(line,
|
||||
kMaximumLineLength,
|
||||
L"[%.2d-%.2d-%.4d %.2d:%.2d:%.2d] %s",
|
||||
current_time.wMonth,
|
||||
current_time.wDay,
|
||||
current_time.wYear,
|
||||
current_time.wHour,
|
||||
current_time.wMinute,
|
||||
current_time.wSecond,
|
||||
text);
|
||||
|
||||
if (result == -1) {
|
||||
return;
|
||||
}
|
||||
|
||||
int length = GetWindowTextLength(client_status_edit_box);
|
||||
SendMessage(client_status_edit_box,
|
||||
EM_SETSEL,
|
||||
(WPARAM)length,
|
||||
(LPARAM)length);
|
||||
SendMessage(client_status_edit_box,
|
||||
EM_REPLACESEL,
|
||||
(WPARAM)FALSE,
|
||||
(LPARAM)line);
|
||||
LeaveCriticalSection(cs_edit);
|
||||
}
|
||||
|
||||
static DWORD WINAPI AppendTextWorker(void* context) {
|
||||
TCHAR* text = reinterpret_cast<TCHAR*>(context);
|
||||
|
||||
AppendTextToEditBox(text);
|
||||
delete[] text;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool ShowDumpResults(const wchar_t* dump_path,
|
||||
const wchar_t* minidump_id,
|
||||
void* context,
|
||||
EXCEPTION_POINTERS* exinfo,
|
||||
MDRawAssertionInfo* assertion,
|
||||
bool succeeded) {
|
||||
TCHAR* text = new TCHAR[kMaximumLineLength];
|
||||
int result = swprintf_s(text,
|
||||
kMaximumLineLength,
|
||||
TEXT("Dump generation request %s\r\n"),
|
||||
succeeded ? TEXT("succeeded") : TEXT("failed"));
|
||||
if (result == -1) {
|
||||
delete [] text;
|
||||
}
|
||||
|
||||
AppendTextWorker(text);
|
||||
return succeeded;
|
||||
}
|
||||
|
||||
static void _cdecl ShowClientConnected(void* context,
|
||||
const ClientInfo* client_info) {
|
||||
TCHAR* line = new TCHAR[kMaximumLineLength];
|
||||
int result = swprintf_s(line,
|
||||
kMaximumLineLength,
|
||||
L"Client connected:\t\t%d\r\n",
|
||||
client_info->pid());
|
||||
|
||||
if (result == -1) {
|
||||
delete[] line;
|
||||
return;
|
||||
}
|
||||
|
||||
QueueUserWorkItem(AppendTextWorker, line, WT_EXECUTEDEFAULT);
|
||||
}
|
||||
|
||||
static void _cdecl ShowClientCrashed(void* context,
|
||||
const ClientInfo* client_info) {
|
||||
TCHAR* line = new TCHAR[kMaximumLineLength];
|
||||
int result = swprintf_s(line,
|
||||
kMaximumLineLength,
|
||||
TEXT("Client requested dump:\t%d\r\n"),
|
||||
client_info->pid());
|
||||
|
||||
if (result == -1) {
|
||||
delete[] line;
|
||||
return;
|
||||
}
|
||||
|
||||
QueueUserWorkItem(AppendTextWorker, line, WT_EXECUTEDEFAULT);
|
||||
}
|
||||
|
||||
static void _cdecl ShowClientExited(void* context,
|
||||
const ClientInfo* client_info) {
|
||||
TCHAR* line = new TCHAR[kMaximumLineLength];
|
||||
int result = swprintf_s(line,
|
||||
kMaximumLineLength,
|
||||
TEXT("Client exited:\t\t%d\r\n"),
|
||||
client_info->pid());
|
||||
|
||||
if (result == -1) {
|
||||
delete[] line;
|
||||
return;
|
||||
}
|
||||
|
||||
QueueUserWorkItem(AppendTextWorker, line, WT_EXECUTEDEFAULT);
|
||||
}
|
||||
|
||||
void CrashServerStart() {
|
||||
// Do not create another instance of the server.
|
||||
if (crash_server) {
|
||||
return;
|
||||
}
|
||||
|
||||
std::wstring dump_path = L"C:\\Dumps\\";
|
||||
crash_server = new CrashGenerationServer(kPipeName,
|
||||
ShowClientConnected,
|
||||
NULL,
|
||||
ShowClientCrashed,
|
||||
NULL,
|
||||
ShowClientExited,
|
||||
NULL,
|
||||
true,
|
||||
&dump_path);
|
||||
|
||||
if (!crash_server->Start()) {
|
||||
MessageBoxW(NULL, L"Unable to start server", L"Dumper", MB_OK);
|
||||
delete crash_server;
|
||||
crash_server = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void CrashServerStop() {
|
||||
delete crash_server;
|
||||
crash_server = NULL;
|
||||
}
|
||||
|
||||
void DerefZeroCrash() {
|
||||
int* x = 0;
|
||||
*x = 1;
|
||||
}
|
||||
|
||||
void InvalidParamCrash() {
|
||||
printf(NULL);
|
||||
}
|
||||
|
||||
void PureCallCrash() {
|
||||
Derived derived;
|
||||
}
|
||||
|
||||
void RequestDump() {
|
||||
if (!handler->WriteMinidump()) {
|
||||
MessageBoxW(NULL, L"Dump request failed", L"Dumper", MB_OK);
|
||||
}
|
||||
}
|
||||
|
||||
void CleanUp() {
|
||||
if (cs_edit) {
|
||||
DeleteCriticalSection(cs_edit);
|
||||
delete cs_edit;
|
||||
}
|
||||
|
||||
if (handler) {
|
||||
delete handler;
|
||||
}
|
||||
|
||||
if (crash_server) {
|
||||
delete crash_server;
|
||||
}
|
||||
}
|
||||
|
||||
// Processes messages for the main window.
|
||||
//
|
||||
// WM_COMMAND - process the application menu.
|
||||
// WM_PAINT - Paint the main window.
|
||||
// WM_DESTROY - post a quit message and return.
|
||||
LRESULT CALLBACK WndProc(HWND wnd,
|
||||
UINT message,
|
||||
WPARAM w_param,
|
||||
LPARAM l_param) {
|
||||
int message_id;
|
||||
int message_event;
|
||||
PAINTSTRUCT ps;
|
||||
HDC hdc;
|
||||
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable:4312)
|
||||
// Disable warning C4312: 'type cast' : conversion from 'LONG' to
|
||||
// 'HINSTANCE' of greater size.
|
||||
// The value returned by GetwindowLong in the case below returns unsigned.
|
||||
HINSTANCE instance = (HINSTANCE)GetWindowLong(wnd, GWL_HINSTANCE);
|
||||
#pragma warning(pop)
|
||||
|
||||
switch (message) {
|
||||
case WM_COMMAND:
|
||||
// Parse the menu selections.
|
||||
message_id = LOWORD(w_param);
|
||||
message_event = HIWORD(w_param);
|
||||
switch (message_id) {
|
||||
case IDM_ABOUT:
|
||||
DialogBox(current_instance,
|
||||
MAKEINTRESOURCE(IDD_ABOUTBOX),
|
||||
wnd,
|
||||
About);
|
||||
break;
|
||||
case IDM_EXIT:
|
||||
DestroyWindow(wnd);
|
||||
break;
|
||||
case ID_SERVER_START:
|
||||
CrashServerStart();
|
||||
break;
|
||||
case ID_SERVER_STOP:
|
||||
CrashServerStop();
|
||||
break;
|
||||
case ID_CLIENT_DEREFZERO:
|
||||
DerefZeroCrash();
|
||||
break;
|
||||
case ID_CLIENT_INVALIDPARAM:
|
||||
InvalidParamCrash();
|
||||
break;
|
||||
case ID_CLIENT_PURECALL:
|
||||
PureCallCrash();
|
||||
break;
|
||||
case ID_CLIENT_REQUESTEXPLICITDUMP:
|
||||
RequestDump();
|
||||
break;
|
||||
default:
|
||||
return DefWindowProc(wnd, message, w_param, l_param);
|
||||
}
|
||||
break;
|
||||
case WM_CREATE:
|
||||
client_status_edit_box = CreateWindow(TEXT("EDIT"),
|
||||
NULL,
|
||||
kEditBoxStyles,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
wnd,
|
||||
NULL,
|
||||
instance,
|
||||
NULL);
|
||||
break;
|
||||
case WM_SIZE:
|
||||
// Make the edit control the size of the window's client area.
|
||||
MoveWindow(client_status_edit_box,
|
||||
0,
|
||||
0,
|
||||
LOWORD(l_param), // width of client area.
|
||||
HIWORD(l_param), // height of client area.
|
||||
TRUE); // repaint window.
|
||||
break;
|
||||
case WM_SETFOCUS:
|
||||
SetFocus(client_status_edit_box);
|
||||
break;
|
||||
case WM_PAINT:
|
||||
hdc = BeginPaint(wnd, &ps);
|
||||
EndPaint(wnd, &ps);
|
||||
break;
|
||||
case WM_DESTROY:
|
||||
CleanUp();
|
||||
PostQuitMessage(0);
|
||||
break;
|
||||
default:
|
||||
return DefWindowProc(wnd, message, w_param, l_param);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Message handler for about box.
|
||||
INT_PTR CALLBACK About(HWND dlg,
|
||||
UINT message,
|
||||
WPARAM w_param,
|
||||
LPARAM l_param) {
|
||||
UNREFERENCED_PARAMETER(l_param);
|
||||
switch (message) {
|
||||
case WM_INITDIALOG:
|
||||
return (INT_PTR)TRUE;
|
||||
|
||||
case WM_COMMAND:
|
||||
if (LOWORD(w_param) == IDOK || LOWORD(w_param) == IDCANCEL) {
|
||||
EndDialog(dlg, LOWORD(w_param));
|
||||
return (INT_PTR)TRUE;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return (INT_PTR)FALSE;
|
||||
}
|
||||
|
||||
} // namespace google_breakpad
|
||||
|
||||
int APIENTRY _tWinMain(HINSTANCE instance,
|
||||
HINSTANCE previous_instance,
|
||||
LPTSTR command_line,
|
||||
int command_show) {
|
||||
using namespace google_breakpad;
|
||||
|
||||
UNREFERENCED_PARAMETER(previous_instance);
|
||||
UNREFERENCED_PARAMETER(command_line);
|
||||
|
||||
cs_edit = new CRITICAL_SECTION();
|
||||
InitializeCriticalSection(cs_edit);
|
||||
|
||||
// This is needed for CRT to not show dialog for invalid param
|
||||
// failures and instead let the code handle it.
|
||||
_CrtSetReportMode(_CRT_ASSERT, 0);
|
||||
handler = new ExceptionHandler(L"C:\\dumps\\",
|
||||
NULL,
|
||||
google_breakpad::ShowDumpResults,
|
||||
NULL,
|
||||
ExceptionHandler::HANDLER_ALL,
|
||||
MiniDumpNormal,
|
||||
kPipeName);
|
||||
|
||||
// Initialize global strings.
|
||||
LoadString(instance, IDS_APP_TITLE, title, kMaxLoadString);
|
||||
LoadString(instance,
|
||||
IDC_CRASHGENERATIONAPP,
|
||||
window_class,
|
||||
kMaxLoadString);
|
||||
MyRegisterClass(instance);
|
||||
|
||||
// Perform application initialization.
|
||||
if (!InitInstance (instance, command_show)) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
HACCEL accel_table = LoadAccelerators(
|
||||
instance,
|
||||
MAKEINTRESOURCE(IDC_CRASHGENERATIONAPP));
|
||||
|
||||
// Main message loop.
|
||||
MSG msg;
|
||||
while (GetMessage(&msg, NULL, 0, 0)) {
|
||||
if (!TranslateAccelerator(msg.hwnd, accel_table, &msg)) {
|
||||
TranslateMessage(&msg);
|
||||
DispatchMessage(&msg);
|
||||
}
|
||||
}
|
||||
|
||||
return (int)msg.wParam;
|
||||
}
|
||||
|
|
@ -0,0 +1,35 @@
|
|||
// Copyright (c) 2008, 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.
|
||||
|
||||
#ifndef CLIENT_WINDOWS_TESTS_CRASH_GENERATION_APP_CRASH_GENERATION_APP_H__
|
||||
#define CLIENT_WINDOWS_TESTS_CRASH_GENERATION_APP_CRASH_GENERATION_APP_H__
|
||||
|
||||
#include "resource.h"
|
||||
|
||||
#endif // CLIENT_WINDOWS_TESTS_CRASH_GENERATION_APP_CRASH_GENERATION_APP_H__
|
|
@ -0,0 +1,144 @@
|
|||
// Microsoft Visual C++ generated resource script.
|
||||
//
|
||||
#include "resource.h"
|
||||
|
||||
#define APSTUDIO_READONLY_SYMBOLS
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Generated from the TEXTINCLUDE 2 resource.
|
||||
//
|
||||
#define APSTUDIO_HIDDEN_SYMBOLS
|
||||
#include "windows.h"
|
||||
#undef APSTUDIO_HIDDEN_SYMBOLS
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
#undef APSTUDIO_READONLY_SYMBOLS
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// English (U.S.) resources
|
||||
|
||||
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
|
||||
#ifdef _WIN32
|
||||
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
|
||||
#pragma code_page(1252)
|
||||
#endif //_WIN32
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Icon
|
||||
//
|
||||
|
||||
// Icon with lowest ID value placed first to ensure application icon
|
||||
// remains consistent on all systems.
|
||||
IDI_CRASHGENERATIONAPP ICON "crash_generation_app.ico"
|
||||
IDI_SMALL ICON "small.ico"
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Menu
|
||||
//
|
||||
|
||||
IDC_CRASHGENERATIONAPP MENU
|
||||
BEGIN
|
||||
POPUP "&File"
|
||||
BEGIN
|
||||
MENUITEM "E&xit", IDM_EXIT
|
||||
END
|
||||
POPUP "&Server"
|
||||
BEGIN
|
||||
MENUITEM "&Start", ID_SERVER_START
|
||||
MENUITEM "S&top", ID_SERVER_STOP
|
||||
END
|
||||
POPUP "&Client"
|
||||
BEGIN
|
||||
MENUITEM "&Deref Zero", ID_CLIENT_DEREFZERO
|
||||
MENUITEM "&Invalid Param", ID_CLIENT_INVALIDPARAM
|
||||
MENUITEM "&Pure Call", ID_CLIENT_PURECALL
|
||||
MENUITEM "&Request Dump", ID_CLIENT_REQUESTEXPLICITDUMP
|
||||
END
|
||||
END
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Accelerator
|
||||
//
|
||||
|
||||
IDC_CRASHGENERATIONAPP ACCELERATORS
|
||||
BEGIN
|
||||
"?", IDM_ABOUT, ASCII, ALT
|
||||
"/", IDM_ABOUT, ASCII, ALT
|
||||
END
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Dialog
|
||||
//
|
||||
|
||||
IDD_ABOUTBOX DIALOG 22, 17, 230, 75
|
||||
STYLE DS_SETFONT | DS_MODALFRAME | WS_CAPTION | WS_SYSMENU
|
||||
CAPTION "About"
|
||||
FONT 8, "System"
|
||||
BEGIN
|
||||
ICON IDI_CRASHGENERATIONAPP,IDC_MYICON,14,9,16,16
|
||||
LTEXT "CrashGenerationApp Version 1.0",IDC_STATIC,49,10,119,8,SS_NOPREFIX
|
||||
LTEXT "Copyright (C) 2008",IDC_STATIC,49,20,119,8
|
||||
DEFPUSHBUTTON "OK",IDOK,195,6,30,11,WS_GROUP
|
||||
END
|
||||
|
||||
|
||||
#ifdef APSTUDIO_INVOKED
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// TEXTINCLUDE
|
||||
//
|
||||
|
||||
1 TEXTINCLUDE
|
||||
BEGIN
|
||||
"resource.h\0"
|
||||
END
|
||||
|
||||
2 TEXTINCLUDE
|
||||
BEGIN
|
||||
"#define APSTUDIO_HIDDEN_SYMBOLS\r\n"
|
||||
"#include ""windows.h""\r\n"
|
||||
"#undef APSTUDIO_HIDDEN_SYMBOLS\r\n"
|
||||
"\0"
|
||||
END
|
||||
|
||||
3 TEXTINCLUDE
|
||||
BEGIN
|
||||
"\r\n"
|
||||
"\0"
|
||||
END
|
||||
|
||||
#endif // APSTUDIO_INVOKED
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// String Table
|
||||
//
|
||||
|
||||
STRINGTABLE
|
||||
BEGIN
|
||||
IDS_APP_TITLE "CrashGenerationApp"
|
||||
IDC_CRASHGENERATIONAPP "CRASHGENERATIONAPP"
|
||||
END
|
||||
|
||||
#endif // English (U.S.) resources
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
|
||||
#ifndef APSTUDIO_INVOKED
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Generated from the TEXTINCLUDE 3 resource.
|
||||
//
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
#endif // not APSTUDIO_INVOKED
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
|
||||
Microsoft Visual Studio Solution File, Format Version 9.00
|
||||
# Visual Studio 2005
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "crash_generation_app", "crash_generation_app.vcproj", "{A15674ED-713D-4B37-B1D2-0C29C7E533C8}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Win32 = Debug|Win32
|
||||
DebugStaticCRT|Win32 = DebugStaticCRT|Win32
|
||||
Release|Win32 = Release|Win32
|
||||
ReleaseStaticCRT|Win32 = ReleaseStaticCRT|Win32
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{A15674ED-713D-4B37-B1D2-0C29C7E533C8}.Debug|Win32.ActiveCfg = Debug|Win32
|
||||
{A15674ED-713D-4B37-B1D2-0C29C7E533C8}.Debug|Win32.Build.0 = Debug|Win32
|
||||
{A15674ED-713D-4B37-B1D2-0C29C7E533C8}.DebugStaticCRT|Win32.ActiveCfg = DebugStaticCRT|Win32
|
||||
{A15674ED-713D-4B37-B1D2-0C29C7E533C8}.DebugStaticCRT|Win32.Build.0 = DebugStaticCRT|Win32
|
||||
{A15674ED-713D-4B37-B1D2-0C29C7E533C8}.Release|Win32.ActiveCfg = Release|Win32
|
||||
{A15674ED-713D-4B37-B1D2-0C29C7E533C8}.Release|Win32.Build.0 = Release|Win32
|
||||
{A15674ED-713D-4B37-B1D2-0C29C7E533C8}.ReleaseStaticCRT|Win32.ActiveCfg = ReleaseStaticCRT|Win32
|
||||
{A15674ED-713D-4B37-B1D2-0C29C7E533C8}.ReleaseStaticCRT|Win32.Build.0 = ReleaseStaticCRT|Win32
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
EndGlobal
|
|
@ -0,0 +1,431 @@
|
|||
<?xml version="1.0" encoding="Windows-1252"?>
|
||||
<VisualStudioProject
|
||||
ProjectType="Visual C++"
|
||||
Version="8.00"
|
||||
Name="crash_generation_app"
|
||||
ProjectGUID="{A15674ED-713D-4B37-B1D2-0C29C7E533C8}"
|
||||
RootNamespace="CrashGenerationServerApp"
|
||||
Keyword="Win32Proj"
|
||||
>
|
||||
<Platforms>
|
||||
<Platform
|
||||
Name="Win32"
|
||||
/>
|
||||
</Platforms>
|
||||
<ToolFiles>
|
||||
</ToolFiles>
|
||||
<Configurations>
|
||||
<Configuration
|
||||
Name="Debug|Win32"
|
||||
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
|
||||
IntermediateDirectory="$(ConfigurationName)"
|
||||
ConfigurationType="1"
|
||||
CharacterSet="1"
|
||||
>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
Optimization="0"
|
||||
AdditionalIncludeDirectories="..\..\..\..\"
|
||||
PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS"
|
||||
MinimalRebuild="true"
|
||||
BasicRuntimeChecks="3"
|
||||
RuntimeLibrary="3"
|
||||
UsePrecompiledHeader="2"
|
||||
PrecompiledHeaderThrough="PreCompile.h"
|
||||
WarningLevel="3"
|
||||
Detect64BitPortabilityProblems="true"
|
||||
DebugInformationFormat="4"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManagedResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
AdditionalDependencies="exception_handler.lib"
|
||||
LinkIncremental="2"
|
||||
AdditionalLibraryDirectories="..\..\$(ConfigurationName)"
|
||||
GenerateDebugInformation="true"
|
||||
SubSystem="2"
|
||||
TargetMachine="1"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCALinkTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManifestTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXDCMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCBscMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCFxCopTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCAppVerifierTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebDeploymentTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"
|
||||
/>
|
||||
</Configuration>
|
||||
<Configuration
|
||||
Name="Release|Win32"
|
||||
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
|
||||
IntermediateDirectory="$(ConfigurationName)"
|
||||
ConfigurationType="1"
|
||||
CharacterSet="1"
|
||||
WholeProgramOptimization="1"
|
||||
>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
AdditionalIncludeDirectories="..\..\..\..\"
|
||||
PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS"
|
||||
RuntimeLibrary="2"
|
||||
UsePrecompiledHeader="2"
|
||||
PrecompiledHeaderThrough="precompile.h"
|
||||
WarningLevel="3"
|
||||
Detect64BitPortabilityProblems="true"
|
||||
DebugInformationFormat="3"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManagedResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
AdditionalDependencies="exception_handler.lib"
|
||||
LinkIncremental="1"
|
||||
AdditionalLibraryDirectories="..\..\$(ConfigurationName)"
|
||||
GenerateDebugInformation="true"
|
||||
SubSystem="2"
|
||||
OptimizeReferences="2"
|
||||
EnableCOMDATFolding="2"
|
||||
TargetMachine="1"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCALinkTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManifestTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXDCMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCBscMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCFxCopTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCAppVerifierTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebDeploymentTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"
|
||||
/>
|
||||
</Configuration>
|
||||
<Configuration
|
||||
Name="DebugStaticCRT|Win32"
|
||||
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
|
||||
IntermediateDirectory="$(ConfigurationName)"
|
||||
ConfigurationType="1"
|
||||
CharacterSet="1"
|
||||
>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
Optimization="0"
|
||||
AdditionalIncludeDirectories="..\..\..\..\"
|
||||
PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS"
|
||||
MinimalRebuild="true"
|
||||
BasicRuntimeChecks="3"
|
||||
RuntimeLibrary="1"
|
||||
UsePrecompiledHeader="2"
|
||||
PrecompiledHeaderThrough="PreCompile.h"
|
||||
WarningLevel="3"
|
||||
Detect64BitPortabilityProblems="true"
|
||||
DebugInformationFormat="4"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManagedResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
AdditionalDependencies="exception_handler.lib"
|
||||
LinkIncremental="2"
|
||||
AdditionalLibraryDirectories="..\..\$(ConfigurationName)"
|
||||
GenerateDebugInformation="true"
|
||||
SubSystem="2"
|
||||
TargetMachine="1"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCALinkTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManifestTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXDCMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCBscMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCFxCopTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCAppVerifierTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebDeploymentTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"
|
||||
/>
|
||||
</Configuration>
|
||||
<Configuration
|
||||
Name="ReleaseStaticCRT|Win32"
|
||||
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
|
||||
IntermediateDirectory="$(ConfigurationName)"
|
||||
ConfigurationType="1"
|
||||
CharacterSet="1"
|
||||
WholeProgramOptimization="1"
|
||||
>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
AdditionalIncludeDirectories="..\..\..\..\"
|
||||
PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS"
|
||||
RuntimeLibrary="0"
|
||||
UsePrecompiledHeader="2"
|
||||
PrecompiledHeaderThrough="precompile.h"
|
||||
WarningLevel="3"
|
||||
Detect64BitPortabilityProblems="true"
|
||||
DebugInformationFormat="3"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManagedResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
AdditionalDependencies="exception_handler.lib"
|
||||
LinkIncremental="1"
|
||||
AdditionalLibraryDirectories="..\..\$(ConfigurationName)"
|
||||
GenerateDebugInformation="true"
|
||||
SubSystem="2"
|
||||
OptimizeReferences="2"
|
||||
EnableCOMDATFolding="2"
|
||||
TargetMachine="1"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCALinkTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManifestTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXDCMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCBscMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCFxCopTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCAppVerifierTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebDeploymentTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"
|
||||
/>
|
||||
</Configuration>
|
||||
</Configurations>
|
||||
<References>
|
||||
</References>
|
||||
<Files>
|
||||
<Filter
|
||||
Name="Source Files"
|
||||
Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
|
||||
UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
|
||||
>
|
||||
<File
|
||||
RelativePath=".\abstract_class.cc"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\crash_generation_app.cc"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\precompile.cc"
|
||||
>
|
||||
<FileConfiguration
|
||||
Name="Debug|Win32"
|
||||
>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
UsePrecompiledHeader="1"
|
||||
/>
|
||||
</FileConfiguration>
|
||||
<FileConfiguration
|
||||
Name="Release|Win32"
|
||||
>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
UsePrecompiledHeader="1"
|
||||
/>
|
||||
</FileConfiguration>
|
||||
<FileConfiguration
|
||||
Name="DebugStaticCRT|Win32"
|
||||
>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
UsePrecompiledHeader="1"
|
||||
/>
|
||||
</FileConfiguration>
|
||||
<FileConfiguration
|
||||
Name="ReleaseStaticCRT|Win32"
|
||||
>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
UsePrecompiledHeader="1"
|
||||
/>
|
||||
</FileConfiguration>
|
||||
</File>
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="Header Files"
|
||||
Filter="h;hpp;hxx;hm;inl;inc;xsd"
|
||||
UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
|
||||
>
|
||||
<File
|
||||
RelativePath=".\abstract_class.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\crash_generation_app.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\precompile.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\Resource.h"
|
||||
>
|
||||
</File>
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="Resource Files"
|
||||
Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav"
|
||||
UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
|
||||
>
|
||||
<File
|
||||
RelativePath=".\crash_generation_app.ico"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\crash_generation_app.rc"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\small.ico"
|
||||
>
|
||||
</File>
|
||||
</Filter>
|
||||
</Files>
|
||||
<Globals>
|
||||
</Globals>
|
||||
</VisualStudioProject>
|
|
@ -0,0 +1,37 @@
|
|||
// Copyright (c) 2008, 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.
|
||||
|
||||
// precompile.cpp : source file that includes just the standard includes
|
||||
// CrashGenerationApp.pch will be the pre-compiled header
|
||||
// precompile.obj will contain the pre-compiled type information
|
||||
|
||||
#include "precompile.h"
|
||||
|
||||
// Reference any additional headers you need in PRECOMPILE.H
|
||||
// and not in this file.
|
|
@ -0,0 +1,89 @@
|
|||
// Copyright (c) 2008, 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.
|
||||
|
||||
// PreCompile.h : include file for standard system include files,
|
||||
// or project specific include files that are used frequently, but
|
||||
// are changed infrequently
|
||||
//
|
||||
|
||||
#ifndef CLIENT_WINDOWS_TESTS_CRASH_GENERATION_APP_PRECOMPILE_H__
|
||||
#define CLIENT_WINDOWS_TESTS_CRASH_GENERATION_APP_PRECOMPILE_H__
|
||||
|
||||
// Modify the following defines if you have to target a platform prior to
|
||||
// the ones specified below. Refer to MSDN for the latest info on
|
||||
// corresponding values for different platforms.
|
||||
|
||||
// Allow use of features specific to Windows XP or later.
|
||||
#ifndef WINVER
|
||||
// Change this to the appropriate value to target other versions of Windows.
|
||||
#define WINVER 0x0501
|
||||
#endif
|
||||
|
||||
// Allow use of features specific to Windows XP or later.
|
||||
#ifndef _WIN32_WINNT
|
||||
// Change this to the appropriate value to target other versions of Windows.
|
||||
#define _WIN32_WINNT 0x0501
|
||||
#endif
|
||||
|
||||
// Allow use of features specific to Windows 98 or later.
|
||||
#ifndef _WIN32_WINDOWS
|
||||
// Change this to the appropriate value to target Windows Me or later.
|
||||
#define _WIN32_WINDOWS 0x0410
|
||||
#endif
|
||||
|
||||
// Allow use of features specific to IE 6.0 or later.
|
||||
#ifndef _WIN32_IE
|
||||
// Change this to the appropriate value to target other versions of IE.
|
||||
#define _WIN32_IE 0x0600
|
||||
#endif
|
||||
|
||||
// Exclude rarely-used stuff from Windows headers
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
|
||||
#include <windows.h>
|
||||
#include <DbgHelp.h>
|
||||
#include <malloc.h>
|
||||
#include <memory.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <tchar.h>
|
||||
|
||||
#include <cassert>
|
||||
#include <list>
|
||||
|
||||
#include "client/windows/crash_generation/client_info.h"
|
||||
#include "client/windows/crash_generation/crash_generation_client.h"
|
||||
#include "client/windows/crash_generation/crash_generation_server.h"
|
||||
#include "client/windows/crash_generation/minidump_generator.h"
|
||||
#include "client/windows/handler/exception_handler.h"
|
||||
#include "client/windows/tests/crash_generation_app/abstract_class.h"
|
||||
#include "client/windows/tests/crash_generation_app/crash_generation_app.h"
|
||||
#include "google_breakpad/common/minidump_format.h"
|
||||
|
||||
#endif // CLIENT_WINDOWS_TESTS_CRASH_GENERATION_APP_PRECOMPILE_H__
|
|
@ -0,0 +1,73 @@
|
|||
// Copyright (c) 2008, 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.
|
||||
|
||||
// PreCompile.h : include file for standard system include files,
|
||||
// or project specific include files that are used frequently, but
|
||||
// are changed infrequently
|
||||
//
|
||||
|
||||
#ifndef CLIENT_WINDOWS_TESTS_CRASH_GENERATION_APP_RESOURCE_H__
|
||||
#define CLIENT_WINDOWS_TESTS_CRASH_GENERATION_APP_RESOURCE_H__
|
||||
|
||||
//{{NO_DEPENDENCIES}}
|
||||
// Microsoft Visual C++ generated include file.
|
||||
// Used by crash_generation_app.rc
|
||||
//
|
||||
#define IDC_MYICON 2
|
||||
#define IDD_CRASHGENERATIONAPP_DIALOG 102
|
||||
#define IDS_APP_TITLE 103
|
||||
#define IDD_ABOUTBOX 103
|
||||
#define IDM_ABOUT 104
|
||||
#define IDM_EXIT 105
|
||||
#define IDI_CRASHGENERATIONAPP 107
|
||||
#define IDI_SMALL 108
|
||||
#define IDC_CRASHGENERATIONAPP 109
|
||||
#define IDR_MAINFRAME 128
|
||||
#define ID_SERVER_START 32771
|
||||
#define ID_SERVER_STOP 32772
|
||||
#define ID_CLIENT_INVALIDPARAM 32773
|
||||
#define ID_CLIENT_ASSERTFAILURE 32774
|
||||
#define ID_CLIENT_DEREFZERO 32775
|
||||
#define ID_CLIENT_PURECALL 32777
|
||||
#define ID_CLIENT_REQUESTEXPLICITDUMP 32778
|
||||
#define IDC_STATIC -1
|
||||
|
||||
// Next default values for new objects
|
||||
//
|
||||
#ifdef APSTUDIO_INVOKED
|
||||
#ifndef APSTUDIO_READONLY_SYMBOLS
|
||||
#define _APS_NO_MFC 1
|
||||
#define _APS_NEXT_RESOURCE_VALUE 129
|
||||
#define _APS_NEXT_COMMAND_VALUE 32780
|
||||
#define _APS_NEXT_CONTROL_VALUE 1000
|
||||
#define _APS_NEXT_SYMED_VALUE 110
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#endif // CLIENT_WINDOWS_TESTS_CRASH_GENERATION_APP_RESOURCE_H__
|
|
@ -40,6 +40,7 @@
|
|||
#include <unistd.h>
|
||||
|
||||
#include <functional>
|
||||
#include <map>
|
||||
#include <vector>
|
||||
|
||||
#include "common/solaris/dump_symbols.h"
|
||||
|
@ -50,7 +51,15 @@
|
|||
// This namespace contains helper functions.
|
||||
namespace {
|
||||
|
||||
// Symbol table entry for stabs. Sun CC specific.
|
||||
using std::make_pair;
|
||||
|
||||
#if defined(_LP64)
|
||||
typedef Elf64_Sym Elf_Sym;
|
||||
#else
|
||||
typedef Elf32_Sym Elf_Sym;
|
||||
#endif
|
||||
|
||||
// Symbol table entry from stabs. Sun CC specific.
|
||||
struct slist {
|
||||
// String table index.
|
||||
unsigned int n_strx;
|
||||
|
@ -61,6 +70,14 @@ struct slist {
|
|||
unsigned long n_value;
|
||||
};
|
||||
|
||||
// Symbol table entry
|
||||
struct SymbolEntry {
|
||||
// Offset from the start of the file.
|
||||
GElf_Addr offset;
|
||||
// Function size.
|
||||
GElf_Word size;
|
||||
};
|
||||
|
||||
// Infomation of a line.
|
||||
struct LineInfo {
|
||||
// Offset from start of the function.
|
||||
|
@ -107,10 +124,20 @@ struct SourceFileInfo {
|
|||
std::vector<struct FuncInfo> func_info;
|
||||
};
|
||||
|
||||
struct CompareString {
|
||||
bool operator()(const char *s1, const char *s2) const {
|
||||
return strcmp(s1, s2) < 0;
|
||||
}
|
||||
};
|
||||
|
||||
typedef std::map<const char *, struct SymbolEntry *, CompareString> SymbolMap;
|
||||
|
||||
// Information of a symbol table.
|
||||
// This is the root of all types of symbol.
|
||||
struct SymbolInfo {
|
||||
std::vector<struct SourceFileInfo> source_file_info;
|
||||
// Symbols information.
|
||||
SymbolMap symbol_entries;
|
||||
};
|
||||
|
||||
// Stab section name.
|
||||
|
@ -119,8 +146,32 @@ const char *kStabName = ".stab";
|
|||
// Stab str section name.
|
||||
const char *kStabStrName = ".stabstr";
|
||||
|
||||
// Symtab section name.
|
||||
const char *kSymtabName = ".symtab";
|
||||
|
||||
// Strtab section name.
|
||||
const char *kStrtabName = ".strtab";
|
||||
|
||||
// Default buffer lenght for demangle.
|
||||
const int demangleLen = 2000;
|
||||
const int demangleLen = 20000;
|
||||
|
||||
// Offset to the string table.
|
||||
u_int64_t stringOffset = 0;
|
||||
|
||||
// Update the offset to the start of the string index of the next
|
||||
// object module for every N_ENDM stabs.
|
||||
inline void RecalculateOffset(struct slist* cur_list, char *stabstr) {
|
||||
while ((--cur_list)->n_strx == 0) ;
|
||||
stringOffset += cur_list->n_strx;
|
||||
|
||||
char *temp = stabstr + stringOffset;
|
||||
while (*temp != '\0') {
|
||||
++stringOffset;
|
||||
++temp;
|
||||
}
|
||||
// Skip the extra '\0'
|
||||
++stringOffset;
|
||||
}
|
||||
|
||||
// Demangle using demangle library on Solaris.
|
||||
std::string Demangle(const char *mangled) {
|
||||
|
@ -145,18 +196,6 @@ out:
|
|||
return std::string(mangled);
|
||||
}
|
||||
|
||||
// Find the prefered loading address of the binary.
|
||||
GElf_Addr GetLoadingAddress(const GElf_Phdr *program_headers, int nheader) {
|
||||
for (int i = 0; i < nheader; ++i) {
|
||||
const GElf_Phdr &header = program_headers[i];
|
||||
// For executable, it is the PT_LOAD segment with offset to zero.
|
||||
if (header.p_type == PT_LOAD && header.p_offset == 0)
|
||||
return header.p_vaddr;
|
||||
}
|
||||
// For other types of ELF, return 0.
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool WriteFormat(int fd, const char *fmt, ...) {
|
||||
va_list list;
|
||||
char buffer[4096];
|
||||
|
@ -226,9 +265,11 @@ int LoadLineInfo(struct slist *list,
|
|||
do {
|
||||
// Skip non line information.
|
||||
while (cur_list < list_end && cur_list->n_type != N_SLINE) {
|
||||
// Only exit when got another function, or source file.
|
||||
if (cur_list->n_type == N_FUN || cur_list->n_type == N_SO)
|
||||
// Only exit when got another function, or source file, or end stab.
|
||||
if (cur_list->n_type == N_FUN || cur_list->n_type == N_SO ||
|
||||
cur_list->n_type == N_ENDM) {
|
||||
return cur_list - list;
|
||||
}
|
||||
++cur_list;
|
||||
}
|
||||
struct LineInfo line;
|
||||
|
@ -248,7 +289,7 @@ int LoadLineInfo(struct slist *list,
|
|||
|
||||
int LoadFuncSymbols(struct slist *list,
|
||||
struct slist *list_end,
|
||||
const GElf_Shdr *stabstr_section,
|
||||
char *stabstr,
|
||||
GElf_Word base,
|
||||
struct SourceFileInfo *source_file_info) {
|
||||
struct slist *cur_list = list;
|
||||
|
@ -263,18 +304,20 @@ int LoadFuncSymbols(struct slist *list,
|
|||
return cur_list - list;
|
||||
}
|
||||
++cur_list;
|
||||
if (cur_list->n_type == N_ENDM)
|
||||
RecalculateOffset(cur_list, stabstr);
|
||||
continue;
|
||||
}
|
||||
while (cur_list->n_type == N_FUN) {
|
||||
struct FuncInfo func_info;
|
||||
memset(&func_info, 0, sizeof(func_info));
|
||||
func_info.name =
|
||||
reinterpret_cast<char *>(cur_list->n_strx +
|
||||
stabstr_section->sh_offset + base);
|
||||
func_info.name = stabstr + cur_list->n_strx + stringOffset;
|
||||
// The n_value field is always 0 from stab generated by Sun CC.
|
||||
// TODO(Alfred): Find the correct value.
|
||||
func_info.addr = cur_list->n_value;
|
||||
++cur_list;
|
||||
if (cur_list->n_type == N_ENDM)
|
||||
RecalculateOffset(cur_list, stabstr);
|
||||
if (cur_list->n_type != N_ESYM && cur_list->n_type != N_ISYM &&
|
||||
cur_list->n_type != N_FUN) {
|
||||
// Stack parameter size.
|
||||
|
@ -282,6 +325,8 @@ int LoadFuncSymbols(struct slist *list,
|
|||
// Line info.
|
||||
cur_list += LoadLineInfo(cur_list, list_end, &func_info);
|
||||
}
|
||||
if (cur_list < list_end && cur_list->n_type == N_ENDM)
|
||||
RecalculateOffset(cur_list, stabstr);
|
||||
// Functions in this module should have address bigger than the module
|
||||
// starting address.
|
||||
//
|
||||
|
@ -296,48 +341,70 @@ int LoadFuncSymbols(struct slist *list,
|
|||
}
|
||||
|
||||
// Compute size and rva information based on symbols loaded from stab section.
|
||||
bool ComputeSizeAndRVA(GElf_Addr loading_addr, struct SymbolInfo *symbols) {
|
||||
bool ComputeSizeAndRVA(struct SymbolInfo *symbols) {
|
||||
std::vector<struct SourceFileInfo> *sorted_files =
|
||||
&(symbols->source_file_info);
|
||||
SymbolMap *symbol_entries = &(symbols->symbol_entries);
|
||||
for (size_t i = 0; i < sorted_files->size(); ++i) {
|
||||
struct SourceFileInfo &source_file = (*sorted_files)[i];
|
||||
std::vector<struct FuncInfo> *sorted_functions = &(source_file.func_info);
|
||||
for (size_t j = 0; j < sorted_functions->size(); ++j) {
|
||||
int func_size = sorted_functions->size();
|
||||
|
||||
for (size_t j = 0; j < func_size; ++j) {
|
||||
struct FuncInfo &func_info = (*sorted_functions)[j];
|
||||
assert(func_info.addr >= loading_addr);
|
||||
func_info.rva_to_base = func_info.addr - loading_addr;
|
||||
int line_count = func_info.line_info.size();
|
||||
func_info.size =
|
||||
(line_count == 0) ? 0 :
|
||||
func_info.line_info[line_count - 1].rva_to_func;
|
||||
|
||||
// Discard the ending part of the name.
|
||||
std::string func_name(func_info.name);
|
||||
std::string::size_type last_colon = func_name.find_first_of(':');
|
||||
if (last_colon != std::string::npos)
|
||||
func_name = func_name.substr(0, last_colon);
|
||||
|
||||
// Fine the symbol offset from the loading address and size by name.
|
||||
SymbolMap::const_iterator it = symbol_entries->find(func_name.c_str());
|
||||
if (it->second) {
|
||||
func_info.rva_to_base = it->second->offset;
|
||||
func_info.size = (line_count == 0) ? 0 : it->second->size;
|
||||
} else {
|
||||
func_info.rva_to_base = 0;
|
||||
func_info.size = 0;
|
||||
}
|
||||
|
||||
// Compute function and line size.
|
||||
for (size_t k = 0; k < line_count; ++k) {
|
||||
struct LineInfo &line_info = func_info.line_info[k];
|
||||
if (k == 0) {
|
||||
line_info.size = line_info.rva_to_func;
|
||||
} else {
|
||||
line_info.size =
|
||||
line_info.rva_to_func - func_info.line_info[k - 1].rva_to_func;
|
||||
}
|
||||
|
||||
line_info.rva_to_base = line_info.rva_to_func + func_info.rva_to_base;
|
||||
if (k == line_count - 1) {
|
||||
line_info.size = func_info.size - line_info.rva_to_func;
|
||||
} else {
|
||||
struct LineInfo &next_line = func_info.line_info[k + 1];
|
||||
line_info.size = next_line.rva_to_func - line_info.rva_to_func;
|
||||
}
|
||||
} // for each line.
|
||||
} // for each function.
|
||||
} // for each source file.
|
||||
for (SymbolMap::iterator it = symbol_entries->begin();
|
||||
it != symbol_entries->end(); ++it) {
|
||||
free(it->second);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool LoadAllSymbols(const GElf_Shdr *stab_section,
|
||||
const GElf_Shdr *stabstr_section,
|
||||
GElf_Addr loading_addr,
|
||||
GElf_Word base,
|
||||
struct SymbolInfo *symbols) {
|
||||
if (stab_section == NULL || stabstr_section == NULL)
|
||||
return false;
|
||||
|
||||
char *stabstr =
|
||||
reinterpret_cast<char *>(stabstr_section->sh_offset + base);
|
||||
struct slist *lists =
|
||||
reinterpret_cast<struct slist *>(stab_section->sh_offset + base);
|
||||
int nstab = stab_section->sh_size / sizeof(struct slist);
|
||||
int source_id = 0;
|
||||
|
||||
// First pass, load all symbols from the object file.
|
||||
for (int i = 0; i < nstab; ) {
|
||||
int step = 1;
|
||||
|
@ -345,9 +412,7 @@ bool LoadAllSymbols(const GElf_Shdr *stab_section,
|
|||
if (cur_list->n_type == N_SO) {
|
||||
// FUNC <address> <size> <param_stack_size> <function>
|
||||
struct SourceFileInfo source_file_info;
|
||||
source_file_info.name =
|
||||
reinterpret_cast<char *>(cur_list->n_strx +
|
||||
stabstr_section->sh_offset + base);
|
||||
source_file_info.name = stabstr + cur_list->n_strx + stringOffset;
|
||||
// The n_value field is always 0 from stab generated by Sun CC.
|
||||
// TODO(Alfred): Find the correct value.
|
||||
source_file_info.addr = cur_list->n_value;
|
||||
|
@ -355,22 +420,19 @@ bool LoadAllSymbols(const GElf_Shdr *stab_section,
|
|||
source_file_info.source_id = source_id++;
|
||||
else
|
||||
source_file_info.source_id = -1;
|
||||
step = LoadFuncSymbols(cur_list, lists + nstab - 1,
|
||||
stabstr_section, base, &source_file_info);
|
||||
step = LoadFuncSymbols(cur_list, lists + nstab - 1, stabstr,
|
||||
base, &source_file_info);
|
||||
symbols->source_file_info.push_back(source_file_info);
|
||||
}
|
||||
i += step;
|
||||
}
|
||||
// Second pass, compute the size of functions and lines.
|
||||
return ComputeSizeAndRVA(loading_addr, symbols);
|
||||
return ComputeSizeAndRVA(symbols);
|
||||
}
|
||||
|
||||
bool LoadSymbols(Elf *elf, GElf_Ehdr *elf_header, struct SymbolInfo *symbols,
|
||||
void *obj_base) {
|
||||
GElf_Word base = reinterpret_cast<GElf_Word>(obj_base);
|
||||
GElf_Addr loading_addr = GetLoadingAddress(
|
||||
reinterpret_cast<GElf_Phdr *>(elf_header->e_phoff + base),
|
||||
elf_header->e_phnum);
|
||||
|
||||
const GElf_Shdr *sections =
|
||||
reinterpret_cast<GElf_Shdr *>(elf_header->e_shoff + base);
|
||||
|
@ -386,9 +448,34 @@ bool LoadSymbols(Elf *elf, GElf_Ehdr *elf_header, struct SymbolInfo *symbols,
|
|||
fprintf(stderr, "Stabstr section not found.\n");
|
||||
return false;
|
||||
}
|
||||
GElf_Shdr symtab_section;
|
||||
if (!FindSectionByName(elf, kSymtabName, elf_header->e_shstrndx,
|
||||
&symtab_section)) {
|
||||
fprintf(stderr, "Symtab section not found.\n");
|
||||
return false;
|
||||
}
|
||||
GElf_Shdr strtab_section;
|
||||
if (!FindSectionByName(elf, kStrtabName, elf_header->e_shstrndx,
|
||||
&strtab_section)) {
|
||||
fprintf(stderr, "Strtab section not found.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
Elf_Sym *symbol = (Elf_Sym *)((char *)base + symtab_section.sh_offset);
|
||||
for (int i = 0; i < symtab_section.sh_size/symtab_section.sh_entsize; ++i) {
|
||||
struct SymbolEntry *symbol_entry =
|
||||
(struct SymbolEntry *)malloc(sizeof(struct SymbolEntry));
|
||||
const char *name = reinterpret_cast<char *>(
|
||||
strtab_section.sh_offset + (GElf_Word)base + symbol->st_name);
|
||||
symbol_entry->offset = symbol->st_value;
|
||||
symbol_entry->size = symbol->st_size;
|
||||
symbols->symbol_entries.insert(make_pair(name, symbol_entry));
|
||||
++symbol;
|
||||
}
|
||||
|
||||
|
||||
// Load symbols.
|
||||
return LoadAllSymbols(&stab_section, &stabstr_section, loading_addr, base, symbols);
|
||||
return LoadAllSymbols(&stab_section, &stabstr_section, base, symbols);
|
||||
}
|
||||
|
||||
bool WriteModuleInfo(int fd, GElf_Half arch, const std::string &obj_file) {
|
||||
|
@ -397,8 +484,12 @@ bool WriteModuleInfo(int fd, GElf_Half arch, const std::string &obj_file) {
|
|||
arch_name = "x86";
|
||||
else if (arch == EM_X86_64)
|
||||
arch_name = "x86_64";
|
||||
else
|
||||
else if (arch == EM_SPARC32PLUS)
|
||||
arch_name = "SPARC_32+";
|
||||
else {
|
||||
printf("Please add more ARCH support\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
unsigned char identifier[16];
|
||||
google_breakpad::FileID file_id(obj_file.c_str());
|
||||
|
@ -437,18 +528,20 @@ bool WriteOneFunction(int fd, int source_id,
|
|||
func_name = func_name.substr(0, last_colon);
|
||||
func_name = Demangle(func_name.c_str());
|
||||
|
||||
if (func_info.size < 0)
|
||||
if (func_info.size <= 0)
|
||||
return true;
|
||||
|
||||
// rva_to_base could be unsigned long(32 bit) or unsigned long long(64 bit).
|
||||
if (WriteFormat(fd, "FUNC %llx %d %d %s\n",
|
||||
if (WriteFormat(fd, "FUNC %llx %x %d %s\n",
|
||||
(long long)func_info.rva_to_base,
|
||||
func_info.size,
|
||||
func_info.stack_param_size,
|
||||
func_name.c_str())) {
|
||||
for (size_t i = 0; i < func_info.line_info.size(); ++i) {
|
||||
const struct LineInfo &line_info = func_info.line_info[i];
|
||||
if (!WriteFormat(fd, "%llx %d %d %d\n",
|
||||
if (line_info.line_num == 0)
|
||||
return true;
|
||||
if (!WriteFormat(fd, "%llx %x %d %d\n",
|
||||
(long long)line_info.rva_to_base,
|
||||
line_info.size,
|
||||
line_info.line_num,
|
||||
|
|
|
@ -43,6 +43,10 @@
|
|||
#ifndef _WIN32
|
||||
|
||||
#include <sys/types.h>
|
||||
#ifndef __STDC_FORMAT_MACROS
|
||||
#define __STDC_FORMAT_MACROS
|
||||
#endif /* __STDC_FORMAT_MACROS */
|
||||
#include <inttypes.h>
|
||||
|
||||
#if defined(__SUNPRO_CC) || (defined(__GNUC__) && defined(__sun__))
|
||||
typedef uint8_t u_int8_t;
|
||||
|
@ -69,4 +73,11 @@ typedef struct {
|
|||
|
||||
typedef u_int64_t breakpad_time_t;
|
||||
|
||||
/* Try to get PRIx64 from inttypes.h, but if it's not defined, fall back to
|
||||
* llx, which is the format string for "long long" - this is a 64-bit
|
||||
* integral type on many systems. */
|
||||
#ifndef PRIx64
|
||||
#define PRIx64 "llx"
|
||||
#endif /* !PRIx64 */
|
||||
|
||||
#endif /* GOOGLE_BREAKPAD_COMMON_BREAKPAD_TYPES_H__ */
|
||||
|
|
|
@ -0,0 +1,231 @@
|
|||
/* Copyright (c) 2006, 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. */
|
||||
|
||||
/* minidump_format.h: A cross-platform reimplementation of minidump-related
|
||||
* portions of DbgHelp.h from the Windows Platform SDK.
|
||||
*
|
||||
* (This is C99 source, please don't corrupt it with C++.)
|
||||
*
|
||||
* This file contains the necessary definitions to read minidump files
|
||||
* produced on amd64. These files may be read on any platform provided
|
||||
* that the alignments of these structures on the processing system are
|
||||
* identical to the alignments of these structures on the producing system.
|
||||
* For this reason, precise-sized types are used. The structures defined
|
||||
* by this file have been laid out to minimize alignment problems by ensuring
|
||||
* ensuring that all members are aligned on their natural boundaries. In
|
||||
* In some cases, tail-padding may be significant when different ABIs specify
|
||||
* different tail-padding behaviors. To avoid problems when reading or
|
||||
* writing affected structures, MD_*_SIZE macros are provided where needed,
|
||||
* containing the useful size of the structures without padding.
|
||||
*
|
||||
* Structures that are defined by Microsoft to contain a zero-length array
|
||||
* are instead defined here to contain an array with one element, as
|
||||
* zero-length arrays are forbidden by standard C and C++. In these cases,
|
||||
* *_minsize constants are provided to be used in place of sizeof. For a
|
||||
* cleaner interface to these sizes when using C++, see minidump_size.h.
|
||||
*
|
||||
* These structures are also sufficient to populate minidump files.
|
||||
*
|
||||
* These definitions may be extended to support handling minidump files
|
||||
* for other CPUs and other operating systems.
|
||||
*
|
||||
* Because precise data type sizes are crucial for this implementation to
|
||||
* function properly and portably in terms of interoperability with minidumps
|
||||
* produced by DbgHelp on Windows, a set of primitive types with known sizes
|
||||
* are used as the basis of each structure defined by this file. DbgHelp
|
||||
* on Windows is assumed to be the reference implementation; this file
|
||||
* seeks to provide a cross-platform compatible implementation. To avoid
|
||||
* collisions with the types and values defined and used by DbgHelp in the
|
||||
* event that this implementation is used on Windows, each type and value
|
||||
* defined here is given a new name, beginning with "MD". Names of the
|
||||
* equivalent types and values in the Windows Platform SDK are given in
|
||||
* comments.
|
||||
*
|
||||
* Author: Mark Mentovai
|
||||
* Change to split into its own file: Neal Sidhwaney */
|
||||
|
||||
#ifndef GOOGLE_BREAKPAD_COMMON_MINIDUMP_CPU_AMD64_H__
|
||||
#define GOOGLE_BREAKPAD_COMMON_MINIDUMP_CPU_AMD64_H__
|
||||
|
||||
|
||||
/*
|
||||
* AMD64 support, see WINNT.H
|
||||
*/
|
||||
|
||||
typedef struct {
|
||||
u_int16_t control_word;
|
||||
u_int16_t status_word;
|
||||
u_int8_t tag_word;
|
||||
u_int8_t reserved1;
|
||||
u_int16_t error_opcode;
|
||||
u_int32_t error_offset;
|
||||
u_int16_t error_selector;
|
||||
u_int16_t reserved2;
|
||||
u_int32_t data_offset;
|
||||
u_int16_t data_selector;
|
||||
u_int16_t reserved3;
|
||||
u_int32_t mx_csr;
|
||||
u_int32_t mx_csr_mask;
|
||||
u_int128_t float_registers[8];
|
||||
u_int128_t xmm_registers[16];
|
||||
u_int8_t reserved4[96];
|
||||
} MDXmmSaveArea32AMD64; /* XMM_SAVE_AREA32 */
|
||||
|
||||
#define MD_CONTEXT_AMD64_VR_COUNT 26
|
||||
|
||||
typedef struct {
|
||||
/*
|
||||
* Register parameter home addresses.
|
||||
*/
|
||||
u_int64_t p1_home;
|
||||
u_int64_t p2_home;
|
||||
u_int64_t p3_home;
|
||||
u_int64_t p4_home;
|
||||
u_int64_t p5_home;
|
||||
u_int64_t p6_home;
|
||||
|
||||
/* The next field determines the layout of the structure, and which parts
|
||||
* of it are populated */
|
||||
u_int32_t context_flags;
|
||||
u_int32_t mx_csr;
|
||||
|
||||
/* The next register is included with MD_CONTEXT_AMD64_CONTROL */
|
||||
u_int16_t cs;
|
||||
|
||||
/* The next 4 registers are included with MD_CONTEXT_AMD64_SEGMENTS */
|
||||
u_int16_t ds;
|
||||
u_int16_t es;
|
||||
u_int16_t fs;
|
||||
u_int16_t gs;
|
||||
|
||||
/* The next 2 registers are included with MD_CONTEXT_AMD64_CONTROL */
|
||||
u_int16_t ss;
|
||||
u_int32_t eflags;
|
||||
|
||||
/* The next 6 registers are included with MD_CONTEXT_AMD64_DEBUG_REGISTERS */
|
||||
u_int64_t dr0;
|
||||
u_int64_t dr1;
|
||||
u_int64_t dr2;
|
||||
u_int64_t dr3;
|
||||
u_int64_t dr6;
|
||||
u_int64_t dr7;
|
||||
|
||||
/* The next 4 registers are included with MD_CONTEXT_AMD64_INTEGER */
|
||||
u_int64_t rax;
|
||||
u_int64_t rcx;
|
||||
u_int64_t rdx;
|
||||
u_int64_t rbx;
|
||||
|
||||
/* The next register is included with MD_CONTEXT_AMD64_CONTROL */
|
||||
u_int64_t rsp;
|
||||
|
||||
/* The next 11 registers are included with MD_CONTEXT_AMD64_INTEGER */
|
||||
u_int64_t rbp;
|
||||
u_int64_t rsi;
|
||||
u_int64_t rdi;
|
||||
u_int64_t r8;
|
||||
u_int64_t r9;
|
||||
u_int64_t r10;
|
||||
u_int64_t r11;
|
||||
u_int64_t r12;
|
||||
u_int64_t r13;
|
||||
u_int64_t r14;
|
||||
u_int64_t r15;
|
||||
|
||||
/* The next register is included with MD_CONTEXT_AMD64_CONTROL */
|
||||
u_int64_t rip;
|
||||
|
||||
/* The next set of registers are included with
|
||||
* MD_CONTEXT_AMD64_FLOATING_POINT
|
||||
*/
|
||||
union {
|
||||
MDXmmSaveArea32AMD64 flt_save;
|
||||
struct {
|
||||
u_int128_t header[2];
|
||||
u_int128_t legacy[8];
|
||||
u_int128_t xmm0;
|
||||
u_int128_t xmm1;
|
||||
u_int128_t xmm2;
|
||||
u_int128_t xmm3;
|
||||
u_int128_t xmm4;
|
||||
u_int128_t xmm5;
|
||||
u_int128_t xmm6;
|
||||
u_int128_t xmm7;
|
||||
u_int128_t xmm8;
|
||||
u_int128_t xmm9;
|
||||
u_int128_t xmm10;
|
||||
u_int128_t xmm11;
|
||||
u_int128_t xmm12;
|
||||
u_int128_t xmm13;
|
||||
u_int128_t xmm14;
|
||||
u_int128_t xmm15;
|
||||
} sse_registers;
|
||||
};
|
||||
|
||||
u_int128_t vector_register[MD_CONTEXT_AMD64_VR_COUNT];
|
||||
u_int64_t vector_control;
|
||||
|
||||
/* The next 5 registers are included with MD_CONTEXT_AMD64_DEBUG_REGISTERS */
|
||||
u_int64_t debug_control;
|
||||
u_int64_t last_branch_to_rip;
|
||||
u_int64_t last_branch_from_rip;
|
||||
u_int64_t last_exception_to_rip;
|
||||
u_int64_t last_exception_from_rip;
|
||||
|
||||
} MDRawContextAMD64; /* CONTEXT */
|
||||
|
||||
/* For (MDRawContextAMD64).context_flags. These values indicate the type of
|
||||
* context stored in the structure. The high 26 bits identify the CPU, the
|
||||
* low 6 bits identify the type of context saved. */
|
||||
#define MD_CONTEXT_AMD64_CONTROL (MD_CONTEXT_AMD64 | 0x00000001)
|
||||
/* CONTEXT_CONTROL */
|
||||
#define MD_CONTEXT_AMD64_INTEGER (MD_CONTEXT_AMD64 | 0x00000002)
|
||||
/* CONTEXT_INTEGER */
|
||||
#define MD_CONTEXT_AMD64_SEGMENTS (MD_CONTEXT_AMD64 | 0x00000004)
|
||||
/* CONTEXT_SEGMENTS */
|
||||
#define MD_CONTEXT_AMD64_FLOATING_POINT (MD_CONTEXT_AMD64 | 0x00000008)
|
||||
/* CONTEXT_FLOATING_POINT */
|
||||
#define MD_CONTEXT_AMD64_DEBUG_REGISTERS (MD_CONTEXT_AMD64 | 0x00000010)
|
||||
/* CONTEXT_DEBUG_REGISTERS */
|
||||
/* WinNT.h refers to CONTEXT_MMX_REGISTERS but doesn't appear to define it
|
||||
* I think it really means CONTEXT_FLOATING_POINT.
|
||||
*/
|
||||
|
||||
#define MD_CONTEXT_AMD64_FULL (MD_CONTEXT_AMD64_CONTROL | \
|
||||
MD_CONTEXT_AMD64_INTEGER | \
|
||||
MD_CONTEXT_AMD64_FLOATING_POINT)
|
||||
/* CONTEXT_FULL */
|
||||
|
||||
#define MD_CONTEXT_AMD64_ALL (MD_CONTEXT_AMD64_FULL | \
|
||||
MD_CONTEXT_AMD64_SEGMENTS | \
|
||||
MD_CONTEXT_X86_DEBUG_REGISTERS)
|
||||
/* CONTEXT_ALL */
|
||||
|
||||
|
||||
#endif /* GOOGLE_BREAKPAD_COMMON_MINIDUMP_CPU_AMD64_H__ */
|
|
@ -0,0 +1,148 @@
|
|||
/* Copyright (c) 2006, 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. */
|
||||
|
||||
/* minidump_format.h: A cross-platform reimplementation of minidump-related
|
||||
* portions of DbgHelp.h from the Windows Platform SDK.
|
||||
*
|
||||
* (This is C99 source, please don't corrupt it with C++.)
|
||||
*
|
||||
* This file contains the necessary definitions to read minidump files
|
||||
* produced on ppc. These files may be read on any platform provided
|
||||
* that the alignments of these structures on the processing system are
|
||||
* identical to the alignments of these structures on the producing system.
|
||||
* For this reason, precise-sized types are used. The structures defined
|
||||
* by this file have been laid out to minimize alignment problems by ensuring
|
||||
* ensuring that all members are aligned on their natural boundaries. In
|
||||
* In some cases, tail-padding may be significant when different ABIs specify
|
||||
* different tail-padding behaviors. To avoid problems when reading or
|
||||
* writing affected structures, MD_*_SIZE macros are provided where needed,
|
||||
* containing the useful size of the structures without padding.
|
||||
*
|
||||
* Structures that are defined by Microsoft to contain a zero-length array
|
||||
* are instead defined here to contain an array with one element, as
|
||||
* zero-length arrays are forbidden by standard C and C++. In these cases,
|
||||
* *_minsize constants are provided to be used in place of sizeof. For a
|
||||
* cleaner interface to these sizes when using C++, see minidump_size.h.
|
||||
*
|
||||
* These structures are also sufficient to populate minidump files.
|
||||
*
|
||||
* These definitions may be extended to support handling minidump files
|
||||
* for other CPUs and other operating systems.
|
||||
*
|
||||
* Because precise data type sizes are crucial for this implementation to
|
||||
* function properly and portably in terms of interoperability with minidumps
|
||||
* produced by DbgHelp on Windows, a set of primitive types with known sizes
|
||||
* are used as the basis of each structure defined by this file. DbgHelp
|
||||
* on Windows is assumed to be the reference implementation; this file
|
||||
* seeks to provide a cross-platform compatible implementation. To avoid
|
||||
* collisions with the types and values defined and used by DbgHelp in the
|
||||
* event that this implementation is used on Windows, each type and value
|
||||
* defined here is given a new name, beginning with "MD". Names of the
|
||||
* equivalent types and values in the Windows Platform SDK are given in
|
||||
* comments.
|
||||
*
|
||||
* Author: Mark Mentovai
|
||||
* Change to split into its own file: Neal Sidhwaney */
|
||||
|
||||
/*
|
||||
* Breakpad minidump extension for PowerPC support. Based on Darwin/Mac OS X'
|
||||
* mach/ppc/_types.h
|
||||
*/
|
||||
|
||||
#ifndef GOOGLE_BREAKPAD_COMMON_MINIDUMP_CPU_PPC_H__
|
||||
#define GOOGLE_BREAKPAD_COMMON_MINIDUMP_CPU_PPC_H__
|
||||
|
||||
#define MD_FLOATINGSAVEAREA_PPC_FPR_COUNT 32
|
||||
|
||||
typedef struct {
|
||||
/* fpregs is a double[32] in mach/ppc/_types.h, but a u_int64_t is used
|
||||
* here for precise sizing. */
|
||||
u_int64_t fpregs[MD_FLOATINGSAVEAREA_PPC_FPR_COUNT];
|
||||
u_int32_t fpscr_pad;
|
||||
u_int32_t fpscr; /* Status/control */
|
||||
} MDFloatingSaveAreaPPC; /* Based on ppc_float_state */
|
||||
|
||||
|
||||
#define MD_VECTORSAVEAREA_PPC_VR_COUNT 32
|
||||
|
||||
typedef struct {
|
||||
/* Vector registers (including vscr) are 128 bits, but mach/ppc/_types.h
|
||||
* exposes them as four 32-bit quantities. */
|
||||
u_int128_t save_vr[MD_VECTORSAVEAREA_PPC_VR_COUNT];
|
||||
u_int128_t save_vscr; /* Status/control */
|
||||
u_int32_t save_pad5[4];
|
||||
u_int32_t save_vrvalid; /* Identifies which vector registers are saved */
|
||||
u_int32_t save_pad6[7];
|
||||
} MDVectorSaveAreaPPC; /* ppc_vector_state */
|
||||
|
||||
|
||||
#define MD_CONTEXT_PPC_GPR_COUNT 32
|
||||
|
||||
typedef struct {
|
||||
/* context_flags is not present in ppc_thread_state, but it aids
|
||||
* identification of MDRawContextPPC among other raw context types,
|
||||
* and it guarantees alignment when we get to float_save. */
|
||||
u_int32_t context_flags;
|
||||
|
||||
u_int32_t srr0; /* Machine status save/restore: stores pc
|
||||
* (instruction) */
|
||||
u_int32_t srr1; /* Machine status save/restore: stores msr
|
||||
* (ps, program/machine state) */
|
||||
/* ppc_thread_state contains 32 fields, r0 .. r31. Here, an array is
|
||||
* used for brevity. */
|
||||
u_int32_t gpr[MD_CONTEXT_PPC_GPR_COUNT];
|
||||
u_int32_t cr; /* Condition */
|
||||
u_int32_t xer; /* Integer (fiXed-point) exception */
|
||||
u_int32_t lr; /* Link */
|
||||
u_int32_t ctr; /* Count */
|
||||
u_int32_t mq; /* Multiply/Quotient (PPC 601, POWER only) */
|
||||
u_int32_t vrsave; /* Vector save */
|
||||
|
||||
/* float_save and vector_save aren't present in ppc_thread_state, but
|
||||
* are represented in separate structures that still define a thread's
|
||||
* context. */
|
||||
MDFloatingSaveAreaPPC float_save;
|
||||
MDVectorSaveAreaPPC vector_save;
|
||||
} MDRawContextPPC; /* Based on ppc_thread_state */
|
||||
|
||||
/* For (MDRawContextPPC).context_flags. These values indicate the type of
|
||||
* context stored in the structure. MD_CONTEXT_PPC is Breakpad-defined. Its
|
||||
* value was chosen to avoid likely conflicts with MD_CONTEXT_* for other
|
||||
* CPUs. */
|
||||
#define MD_CONTEXT_PPC 0x20000000
|
||||
#define MD_CONTEXT_PPC_BASE (MD_CONTEXT_PPC | 0x00000001)
|
||||
#define MD_CONTEXT_PPC_FLOATING_POINT (MD_CONTEXT_PPC | 0x00000008)
|
||||
#define MD_CONTEXT_PPC_VECTOR (MD_CONTEXT_PPC | 0x00000020)
|
||||
|
||||
#define MD_CONTEXT_PPC_FULL MD_CONTEXT_PPC_BASE
|
||||
#define MD_CONTEXT_PPC_ALL (MD_CONTEXT_PPC_FULL | \
|
||||
MD_CONTEXT_PPC_FLOATING_POINT | \
|
||||
MD_CONTEXT_PPC_VECTOR)
|
||||
|
||||
#endif /* GOOGLE_BREAKPAD_COMMON_MINIDUMP_CPU_PPC_H__ */
|
|
@ -0,0 +1,129 @@
|
|||
/* Copyright (c) 2008, 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. */
|
||||
|
||||
/* minidump_format.h: A cross-platform reimplementation of minidump-related
|
||||
* portions of DbgHelp.h from the Windows Platform SDK.
|
||||
*
|
||||
* (This is C99 source, please don't corrupt it with C++.)
|
||||
*
|
||||
* This file contains the necessary definitions to read minidump files
|
||||
* produced on ppc64. These files may be read on any platform provided
|
||||
* that the alignments of these structures on the processing system are
|
||||
* identical to the alignments of these structures on the producing system.
|
||||
* For this reason, precise-sized types are used. The structures defined
|
||||
* by this file have been laid out to minimize alignment problems by ensuring
|
||||
* ensuring that all members are aligned on their natural boundaries. In
|
||||
* In some cases, tail-padding may be significant when different ABIs specify
|
||||
* different tail-padding behaviors. To avoid problems when reading or
|
||||
* writing affected structures, MD_*_SIZE macros are provided where needed,
|
||||
* containing the useful size of the structures without padding.
|
||||
*
|
||||
* Structures that are defined by Microsoft to contain a zero-length array
|
||||
* are instead defined here to contain an array with one element, as
|
||||
* zero-length arrays are forbidden by standard C and C++. In these cases,
|
||||
* *_minsize constants are provided to be used in place of sizeof. For a
|
||||
* cleaner interface to these sizes when using C++, see minidump_size.h.
|
||||
*
|
||||
* These structures are also sufficient to populate minidump files.
|
||||
*
|
||||
* These definitions may be extended to support handling minidump files
|
||||
* for other CPUs and other operating systems.
|
||||
*
|
||||
* Because precise data type sizes are crucial for this implementation to
|
||||
* function properly and portably in terms of interoperability with minidumps
|
||||
* produced by DbgHelp on Windows, a set of primitive types with known sizes
|
||||
* are used as the basis of each structure defined by this file. DbgHelp
|
||||
* on Windows is assumed to be the reference implementation; this file
|
||||
* seeks to provide a cross-platform compatible implementation. To avoid
|
||||
* collisions with the types and values defined and used by DbgHelp in the
|
||||
* event that this implementation is used on Windows, each type and value
|
||||
* defined here is given a new name, beginning with "MD". Names of the
|
||||
* equivalent types and values in the Windows Platform SDK are given in
|
||||
* comments.
|
||||
*
|
||||
* Author: Neal Sidhwaney */
|
||||
|
||||
|
||||
/*
|
||||
* Breakpad minidump extension for PPC64 support. Based on Darwin/Mac OS X'
|
||||
* mach/ppc/_types.h
|
||||
*/
|
||||
|
||||
#ifndef GOOGLE_BREAKPAD_COMMON_MINIDUMP_CPU_PPC64_H__
|
||||
#define GOOGLE_BREAKPAD_COMMON_MINIDUMP_CPU_PPC64_H__
|
||||
|
||||
#include "minidump_cpu_ppc.h"
|
||||
|
||||
// these types are the same in ppc64 & ppc
|
||||
typedef MDFloatingSaveAreaPPC MDFloatingSaveAreaPPC64;
|
||||
typedef MDVectorSaveAreaPPC MDVectorSaveAreaPPC64;
|
||||
|
||||
#define MD_CONTEXT_PPC64_GPR_COUNT MD_CONTEXT_PPC_GPR_COUNT
|
||||
|
||||
typedef struct {
|
||||
/* context_flags is not present in ppc_thread_state, but it aids
|
||||
* identification of MDRawContextPPC among other raw context types,
|
||||
* and it guarantees alignment when we get to float_save. */
|
||||
u_int64_t context_flags;
|
||||
|
||||
u_int64_t srr0; /* Machine status save/restore: stores pc
|
||||
* (instruction) */
|
||||
u_int64_t srr1; /* Machine status save/restore: stores msr
|
||||
* (ps, program/machine state) */
|
||||
/* ppc_thread_state contains 32 fields, r0 .. r31. Here, an array is
|
||||
* used for brevity. */
|
||||
u_int64_t gpr[MD_CONTEXT_PPC64_GPR_COUNT];
|
||||
u_int64_t cr; /* Condition */
|
||||
u_int64_t xer; /* Integer (fiXed-point) exception */
|
||||
u_int64_t lr; /* Link */
|
||||
u_int64_t ctr; /* Count */
|
||||
u_int64_t vrsave; /* Vector save */
|
||||
|
||||
/* float_save and vector_save aren't present in ppc_thread_state, but
|
||||
* are represented in separate structures that still define a thread's
|
||||
* context. */
|
||||
MDFloatingSaveAreaPPC float_save;
|
||||
MDVectorSaveAreaPPC vector_save;
|
||||
} MDRawContextPPC64; /* Based on ppc_thread_state */
|
||||
|
||||
/* For (MDRawContextPPC).context_flags. These values indicate the type of
|
||||
* context stored in the structure. MD_CONTEXT_PPC is Breakpad-defined. Its
|
||||
* value was chosen to avoid likely conflicts with MD_CONTEXT_* for other
|
||||
* CPUs. */
|
||||
#define MD_CONTEXT_PPC 0x20000000
|
||||
#define MD_CONTEXT_PPC_BASE (MD_CONTEXT_PPC | 0x00000001)
|
||||
#define MD_CONTEXT_PPC_FLOATING_POINT (MD_CONTEXT_PPC | 0x00000008)
|
||||
#define MD_CONTEXT_PPC_VECTOR (MD_CONTEXT_PPC | 0x00000020)
|
||||
|
||||
#define MD_CONTEXT_PPC_FULL MD_CONTEXT_PPC_BASE
|
||||
#define MD_CONTEXT_PPC_ALL (MD_CONTEXT_PPC_FULL | \
|
||||
MD_CONTEXT_PPC_FLOATING_POINT | \
|
||||
MD_CONTEXT_PPC_VECTOR)
|
||||
|
||||
#endif /* GOOGLE_BREAKPAD_COMMON_MINIDUMP_CPU_PPC64_H__ */
|
|
@ -0,0 +1,158 @@
|
|||
/* Copyright (c) 2006, 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. */
|
||||
|
||||
/* minidump_format.h: A cross-platform reimplementation of minidump-related
|
||||
* portions of DbgHelp.h from the Windows Platform SDK.
|
||||
*
|
||||
* (This is C99 source, please don't corrupt it with C++.)
|
||||
*
|
||||
* This file contains the necessary definitions to read minidump files
|
||||
* produced on sparc. These files may be read on any platform provided
|
||||
* that the alignments of these structures on the processing system are
|
||||
* identical to the alignments of these structures on the producing system.
|
||||
* For this reason, precise-sized types are used. The structures defined
|
||||
* by this file have been laid out to minimize alignment problems by ensuring
|
||||
* ensuring that all members are aligned on their natural boundaries. In
|
||||
* In some cases, tail-padding may be significant when different ABIs specify
|
||||
* different tail-padding behaviors. To avoid problems when reading or
|
||||
* writing affected structures, MD_*_SIZE macros are provided where needed,
|
||||
* containing the useful size of the structures without padding.
|
||||
*
|
||||
* Structures that are defined by Microsoft to contain a zero-length array
|
||||
* are instead defined here to contain an array with one element, as
|
||||
* zero-length arrays are forbidden by standard C and C++. In these cases,
|
||||
* *_minsize constants are provided to be used in place of sizeof. For a
|
||||
* cleaner interface to these sizes when using C++, see minidump_size.h.
|
||||
*
|
||||
* These structures are also sufficient to populate minidump files.
|
||||
*
|
||||
* These definitions may be extended to support handling minidump files
|
||||
* for other CPUs and other operating systems.
|
||||
*
|
||||
* Because precise data type sizes are crucial for this implementation to
|
||||
* function properly and portably in terms of interoperability with minidumps
|
||||
* produced by DbgHelp on Windows, a set of primitive types with known sizes
|
||||
* are used as the basis of each structure defined by this file. DbgHelp
|
||||
* on Windows is assumed to be the reference implementation; this file
|
||||
* seeks to provide a cross-platform compatible implementation. To avoid
|
||||
* collisions with the types and values defined and used by DbgHelp in the
|
||||
* event that this implementation is used on Windows, each type and value
|
||||
* defined here is given a new name, beginning with "MD". Names of the
|
||||
* equivalent types and values in the Windows Platform SDK are given in
|
||||
* comments.
|
||||
*
|
||||
* Author: Mark Mentovai
|
||||
* Change to split into its own file: Neal Sidhwaney */
|
||||
|
||||
/*
|
||||
* SPARC support, see (solaris)sys/procfs_isa.h also
|
||||
*/
|
||||
|
||||
#ifndef GOOGLE_BREAKPAD_COMMON_MINIDUMP_CPU_SPARC_H__
|
||||
#define GOOGLE_BREAKPAD_COMMON_MINIDUMP_CPU_SPARC_H__
|
||||
|
||||
#define MD_FLOATINGSAVEAREA_SPARC_FPR_COUNT 32
|
||||
|
||||
typedef struct {
|
||||
|
||||
/* FPU floating point regs */
|
||||
u_int64_t regs[MD_FLOATINGSAVEAREA_SPARC_FPR_COUNT];
|
||||
|
||||
u_int64_t filler;
|
||||
u_int64_t fsr; /* FPU status register */
|
||||
} MDFloatingSaveAreaSPARC; /* FLOATING_SAVE_AREA */
|
||||
|
||||
#define MD_CONTEXT_SPARC_GPR_COUNT 32
|
||||
|
||||
typedef struct {
|
||||
/* The next field determines the layout of the structure, and which parts
|
||||
* of it are populated
|
||||
*/
|
||||
u_int32_t context_flags;
|
||||
u_int32_t flag_pad;
|
||||
/*
|
||||
* General register access (SPARC).
|
||||
* Don't confuse definitions here with definitions in <sys/regset.h>.
|
||||
* Registers are 32 bits for ILP32, 64 bits for LP64.
|
||||
* SPARC V7/V8 is for 32bit, SPARC V9 is for 64bit
|
||||
*/
|
||||
|
||||
/* 32 Integer working registers */
|
||||
|
||||
/* g_r[0-7] global registers(g0-g7)
|
||||
* g_r[8-15] out registers(o0-o7)
|
||||
* g_r[16-23] local registers(l0-l7)
|
||||
* g_r[24-31] in registers(i0-i7)
|
||||
*/
|
||||
u_int64_t g_r[MD_CONTEXT_SPARC_GPR_COUNT];
|
||||
|
||||
/* several control registers */
|
||||
|
||||
/* Processor State register(PSR) for SPARC V7/V8
|
||||
* Condition Code register (CCR) for SPARC V9
|
||||
*/
|
||||
u_int64_t ccr;
|
||||
|
||||
u_int64_t pc; /* Program Counter register (PC) */
|
||||
u_int64_t npc; /* Next Program Counter register (nPC) */
|
||||
u_int64_t y; /* Y register (Y) */
|
||||
|
||||
/* Address Space Identifier register (ASI) for SPARC V9
|
||||
* WIM for SPARC V7/V8
|
||||
*/
|
||||
u_int64_t asi;
|
||||
|
||||
/* Floating-Point Registers State register (FPRS) for SPARC V9
|
||||
* TBR for for SPARC V7/V8
|
||||
*/
|
||||
u_int64_t fprs;
|
||||
|
||||
/* The next field is included with MD_CONTEXT_SPARC_FLOATING_POINT */
|
||||
MDFloatingSaveAreaSPARC float_save;
|
||||
|
||||
} MDRawContextSPARC; /* CONTEXT_SPARC */
|
||||
|
||||
/* For (MDRawContextSPARC).context_flags. These values indicate the type of
|
||||
* context stored in the structure. MD_CONTEXT_SPARC is Breakpad-defined. Its
|
||||
* value was chosen to avoid likely conflicts with MD_CONTEXT_* for other
|
||||
* CPUs. */
|
||||
#define MD_CONTEXT_SPARC 0x10000000
|
||||
#define MD_CONTEXT_SPARC_CONTROL (MD_CONTEXT_SPARC | 0x00000001)
|
||||
#define MD_CONTEXT_SPARC_INTEGER (MD_CONTEXT_SPARC | 0x00000002)
|
||||
#define MD_CONTEXT_SAPARC_FLOATING_POINT (MD_CONTEXT_SPARC | 0x00000004)
|
||||
#define MD_CONTEXT_SAPARC_EXTRA (MD_CONTEXT_SPARC | 0x00000008)
|
||||
|
||||
#define MD_CONTEXT_SPARC_FULL (MD_CONTEXT_SPARC_CONTROL | \
|
||||
MD_CONTEXT_SPARC_INTEGER)
|
||||
|
||||
#define MD_CONTEXT_SPARC_ALL (MD_CONTEXT_SPARC_FULL | \
|
||||
MD_CONTEXT_SAPARC_FLOATING_POINT | \
|
||||
MD_CONTEXT_SAPARC_EXTRA)
|
||||
|
||||
#endif /* GOOGLE_BREAKPAD_COMMON_MINIDUMP_CPU_SPARC_H__ */
|
|
@ -0,0 +1,172 @@
|
|||
/* Copyright (c) 2006, 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. */
|
||||
|
||||
/* minidump_format.h: A cross-platform reimplementation of minidump-related
|
||||
* portions of DbgHelp.h from the Windows Platform SDK.
|
||||
*
|
||||
* (This is C99 source, please don't corrupt it with C++.)
|
||||
*
|
||||
* This file contains the necessary definitions to read minidump files
|
||||
* produced on x86. These files may be read on any platform provided
|
||||
* that the alignments of these structures on the processing system are
|
||||
* identical to the alignments of these structures on the producing system.
|
||||
* For this reason, precise-sized types are used. The structures defined
|
||||
* by this file have been laid out to minimize alignment problems by ensuring
|
||||
* ensuring that all members are aligned on their natural boundaries. In
|
||||
* In some cases, tail-padding may be significant when different ABIs specify
|
||||
* different tail-padding behaviors. To avoid problems when reading or
|
||||
* writing affected structures, MD_*_SIZE macros are provided where needed,
|
||||
* containing the useful size of the structures without padding.
|
||||
*
|
||||
* Structures that are defined by Microsoft to contain a zero-length array
|
||||
* are instead defined here to contain an array with one element, as
|
||||
* zero-length arrays are forbidden by standard C and C++. In these cases,
|
||||
* *_minsize constants are provided to be used in place of sizeof. For a
|
||||
* cleaner interface to these sizes when using C++, see minidump_size.h.
|
||||
*
|
||||
* These structures are also sufficient to populate minidump files.
|
||||
*
|
||||
* These definitions may be extended to support handling minidump files
|
||||
* for other CPUs and other operating systems.
|
||||
*
|
||||
* Because precise data type sizes are crucial for this implementation to
|
||||
* function properly and portably in terms of interoperability with minidumps
|
||||
* produced by DbgHelp on Windows, a set of primitive types with known sizes
|
||||
* are used as the basis of each structure defined by this file. DbgHelp
|
||||
* on Windows is assumed to be the reference implementation; this file
|
||||
* seeks to provide a cross-platform compatible implementation. To avoid
|
||||
* collisions with the types and values defined and used by DbgHelp in the
|
||||
* event that this implementation is used on Windows, each type and value
|
||||
* defined here is given a new name, beginning with "MD". Names of the
|
||||
* equivalent types and values in the Windows Platform SDK are given in
|
||||
* comments.
|
||||
*
|
||||
* Author: Mark Mentovai */
|
||||
|
||||
#ifndef GOOGLE_BREAKPAD_COMMON_MINIDUMP_CPU_X86_H__
|
||||
#define GOOGLE_BREAKPAD_COMMON_MINIDUMP_CPU_X86_H__
|
||||
|
||||
#define MD_FLOATINGSAVEAREA_X86_REGISTERAREA_SIZE 80
|
||||
/* SIZE_OF_80387_REGISTERS */
|
||||
|
||||
typedef struct {
|
||||
u_int32_t control_word;
|
||||
u_int32_t status_word;
|
||||
u_int32_t tag_word;
|
||||
u_int32_t error_offset;
|
||||
u_int32_t error_selector;
|
||||
u_int32_t data_offset;
|
||||
u_int32_t data_selector;
|
||||
|
||||
/* register_area contains eight 80-bit (x87 "long double") quantities for
|
||||
* floating-point registers %st0 (%mm0) through %st7 (%mm7). */
|
||||
u_int8_t register_area[MD_FLOATINGSAVEAREA_X86_REGISTERAREA_SIZE];
|
||||
u_int32_t cr0_npx_state;
|
||||
} MDFloatingSaveAreaX86; /* FLOATING_SAVE_AREA */
|
||||
|
||||
|
||||
#define MD_CONTEXT_X86_EXTENDED_REGISTERS_SIZE 512
|
||||
/* MAXIMUM_SUPPORTED_EXTENSION */
|
||||
|
||||
typedef struct {
|
||||
/* The next field determines the layout of the structure, and which parts
|
||||
* of it are populated */
|
||||
u_int32_t context_flags;
|
||||
|
||||
/* The next 6 registers are included with MD_CONTEXT_X86_DEBUG_REGISTERS */
|
||||
u_int32_t dr0;
|
||||
u_int32_t dr1;
|
||||
u_int32_t dr2;
|
||||
u_int32_t dr3;
|
||||
u_int32_t dr6;
|
||||
u_int32_t dr7;
|
||||
|
||||
/* The next field is included with MD_CONTEXT_X86_FLOATING_POINT */
|
||||
MDFloatingSaveAreaX86 float_save;
|
||||
|
||||
/* The next 4 registers are included with MD_CONTEXT_X86_SEGMENTS */
|
||||
u_int32_t gs;
|
||||
u_int32_t fs;
|
||||
u_int32_t es;
|
||||
u_int32_t ds;
|
||||
/* The next 6 registers are included with MD_CONTEXT_X86_INTEGER */
|
||||
u_int32_t edi;
|
||||
u_int32_t esi;
|
||||
u_int32_t ebx;
|
||||
u_int32_t edx;
|
||||
u_int32_t ecx;
|
||||
u_int32_t eax;
|
||||
|
||||
/* The next 6 registers are included with MD_CONTEXT_X86_CONTROL */
|
||||
u_int32_t ebp;
|
||||
u_int32_t eip;
|
||||
u_int32_t cs; /* WinNT.h says "must be sanitized" */
|
||||
u_int32_t eflags; /* WinNT.h says "must be sanitized" */
|
||||
u_int32_t esp;
|
||||
u_int32_t ss;
|
||||
|
||||
/* The next field is included with MD_CONTEXT_X86_EXTENDED_REGISTERS.
|
||||
* It contains vector (MMX/SSE) registers. It it laid out in the
|
||||
* format used by the fxsave and fsrstor instructions, so it includes
|
||||
* a copy of the x87 floating-point registers as well. See FXSAVE in
|
||||
* "Intel Architecture Software Developer's Manual, Volume 2." */
|
||||
u_int8_t extended_registers[
|
||||
MD_CONTEXT_X86_EXTENDED_REGISTERS_SIZE];
|
||||
} MDRawContextX86; /* CONTEXT */
|
||||
|
||||
/* For (MDRawContextX86).context_flags. These values indicate the type of
|
||||
* context stored in the structure. The high 26 bits identify the CPU, the
|
||||
* low 6 bits identify the type of context saved. */
|
||||
#define MD_CONTEXT_X86 0x00010000
|
||||
/* CONTEXT_i386, CONTEXT_i486: identifies CPU */
|
||||
#define MD_CONTEXT_X86_CONTROL (MD_CONTEXT_X86 | 0x00000001)
|
||||
/* CONTEXT_CONTROL */
|
||||
#define MD_CONTEXT_X86_INTEGER (MD_CONTEXT_X86 | 0x00000002)
|
||||
/* CONTEXT_INTEGER */
|
||||
#define MD_CONTEXT_X86_SEGMENTS (MD_CONTEXT_X86 | 0x00000004)
|
||||
/* CONTEXT_SEGMENTS */
|
||||
#define MD_CONTEXT_X86_FLOATING_POINT (MD_CONTEXT_X86 | 0x00000008)
|
||||
/* CONTEXT_FLOATING_POINT */
|
||||
#define MD_CONTEXT_X86_DEBUG_REGISTERS (MD_CONTEXT_X86 | 0x00000010)
|
||||
/* CONTEXT_DEBUG_REGISTERS */
|
||||
#define MD_CONTEXT_X86_EXTENDED_REGISTERS (MD_CONTEXT_X86 | 0x00000020)
|
||||
/* CONTEXT_EXTENDED_REGISTERS */
|
||||
|
||||
#define MD_CONTEXT_X86_FULL (MD_CONTEXT_X86_CONTROL | \
|
||||
MD_CONTEXT_X86_INTEGER | \
|
||||
MD_CONTEXT_X86_SEGMENTS)
|
||||
/* CONTEXT_FULL */
|
||||
|
||||
#define MD_CONTEXT_X86_ALL (MD_CONTEXT_X86_FULL | \
|
||||
MD_CONTEXT_X86_FLOATING_POINT | \
|
||||
MD_CONTEXT_X86_DEBUG_REGISTERS | \
|
||||
MD_CONTEXT_X86_EXTENDED_REGISTERS)
|
||||
/* CONTEXT_ALL */
|
||||
|
||||
#endif /* GOOGLE_BREAKPAD_COMMON_MINIDUMP_CPU_X86_H__ */
|
|
@ -0,0 +1,85 @@
|
|||
/* Copyright (c) 2006, 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. */
|
||||
|
||||
/* minidump_exception_linux.h: A definition of exception codes for
|
||||
* Linux
|
||||
*
|
||||
* (This is C99 source, please don't corrupt it with C++.)
|
||||
*
|
||||
* Author: Mark Mentovai
|
||||
* Split into its own file: Neal Sidhwaney */
|
||||
|
||||
|
||||
#ifndef GOOGLE_BREAKPAD_COMMON_MINIDUMP_EXCEPTION_LINUX_H__
|
||||
#define GOOGLE_BREAKPAD_COMMON_MINIDUMP_EXCEPTION_LINUX_H__
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#include "google_breakpad/common/breakpad_types.h"
|
||||
|
||||
|
||||
/* For (MDException).exception_code. These values come from bits/signum.h.
|
||||
*/
|
||||
typedef enum {
|
||||
MD_EXCEPTION_CODE_LIN_SIGHUP = 1, /* Hangup (POSIX) */
|
||||
MD_EXCEPTION_CODE_LIN_SIGINT = 2, /* Interrupt (ANSI) */
|
||||
MD_EXCEPTION_CODE_LIN_SIGQUIT = 3, /* Quit (POSIX) */
|
||||
MD_EXCEPTION_CODE_LIN_SIGILL = 4, /* Illegal instruction (ANSI) */
|
||||
MD_EXCEPTION_CODE_LIN_SIGTRAP = 5, /* Trace trap (POSIX) */
|
||||
MD_EXCEPTION_CODE_LIN_SIGABRT = 6, /* Abort (ANSI) */
|
||||
MD_EXCEPTION_CODE_LIN_SIGBUS = 7, /* BUS error (4.2 BSD) */
|
||||
MD_EXCEPTION_CODE_LIN_SIGFPE = 8, /* Floating-point exception (ANSI) */
|
||||
MD_EXCEPTION_CODE_LIN_SIGKILL = 9, /* Kill, unblockable (POSIX) */
|
||||
MD_EXCEPTION_CODE_LIN_SIGUSR1 = 10, /* User-defined signal 1 (POSIX). */
|
||||
MD_EXCEPTION_CODE_LIN_SIGSEGV = 11, /* Segmentation violation (ANSI) */
|
||||
MD_EXCEPTION_CODE_LIN_SIGUSR2 = 12, /* User-defined signal 2 (POSIX) */
|
||||
MD_EXCEPTION_CODE_LIN_SIGPIPE = 13, /* Broken pipe (POSIX) */
|
||||
MD_EXCEPTION_CODE_LIN_SIGALRM = 14, /* Alarm clock (POSIX) */
|
||||
MD_EXCEPTION_CODE_LIN_SIGTERM = 15, /* Termination (ANSI) */
|
||||
MD_EXCEPTION_CODE_LIN_SIGSTKFLT = 16, /* Stack faultd */
|
||||
MD_EXCEPTION_CODE_LIN_SIGCHLD = 17, /* Child status has changed (POSIX) */
|
||||
MD_EXCEPTION_CODE_LIN_SIGCONT = 18, /* Continue (POSIX) */
|
||||
MD_EXCEPTION_CODE_LIN_SIGSTOP = 19, /* Stop, unblockable (POSIX) */
|
||||
MD_EXCEPTION_CODE_LIN_SIGTSTP = 20, /* Keyboard stop (POSIX) */
|
||||
MD_EXCEPTION_CODE_LIN_SIGTTIN = 21, /* Background read from tty (POSIX) */
|
||||
MD_EXCEPTION_CODE_LIN_SIGTTOU = 22, /* Background write to tty (POSIX) */
|
||||
MD_EXCEPTION_CODE_LIN_SIGURG = 23,
|
||||
/* Urgent condition on socket (4.2 BSD) */
|
||||
MD_EXCEPTION_CODE_LIN_SIGXCPU = 24, /* CPU limit exceeded (4.2 BSD) */
|
||||
MD_EXCEPTION_CODE_LIN_SIGXFSZ = 25,
|
||||
/* File size limit exceeded (4.2 BSD) */
|
||||
MD_EXCEPTION_CODE_LIN_SIGVTALRM = 26, /* Virtual alarm clock (4.2 BSD) */
|
||||
MD_EXCEPTION_CODE_LIN_SIGPROF = 27, /* Profiling alarm clock (4.2 BSD) */
|
||||
MD_EXCEPTION_CODE_LIN_SIGWINCH = 28, /* Window size change (4.3 BSD, Sun) */
|
||||
MD_EXCEPTION_CODE_LIN_SIGIO = 29, /* I/O now possible (4.2 BSD) */
|
||||
MD_EXCEPTION_CODE_LIN_SIGPWR = 30, /* Power failure restart (System V) */
|
||||
MD_EXCEPTION_CODE_LIN_SIGSYS = 31 /* Bad system call */
|
||||
} MDExceptionCodeLinux;
|
||||
|
||||
#endif /* GOOGLE_BREAKPAD_COMMON_MINIDUMP_EXCEPTION_LINUX_H__ */
|
|
@ -0,0 +1,193 @@
|
|||
/* Copyright (c) 2006, 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. */
|
||||
|
||||
/* minidump_exception_mac.h: A definition of exception codes for Mac
|
||||
* OS X
|
||||
*
|
||||
* (This is C99 source, please don't corrupt it with C++.)
|
||||
*
|
||||
* Author: Mark Mentovai
|
||||
* Split into its own file: Neal Sidhwaney */
|
||||
|
||||
|
||||
#ifndef GOOGLE_BREAKPAD_COMMON_MINIDUMP_EXCEPTION_MAC_H__
|
||||
#define GOOGLE_BREAKPAD_COMMON_MINIDUMP_EXCEPTION_MAC_H__
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#include "google_breakpad/common/breakpad_types.h"
|
||||
|
||||
/* For (MDException).exception_code. Breakpad minidump extension for Mac OS X
|
||||
* support. Based on Darwin/Mac OS X' mach/exception_types.h. This is
|
||||
* what Mac OS X calls an "exception", not a "code". */
|
||||
typedef enum {
|
||||
/* Exception code. The high 16 bits of exception_code contains one of
|
||||
* these values. */
|
||||
MD_EXCEPTION_MAC_BAD_ACCESS = 1, /* code can be a kern_return_t */
|
||||
/* EXC_BAD_ACCESS */
|
||||
MD_EXCEPTION_MAC_BAD_INSTRUCTION = 2, /* code is CPU-specific */
|
||||
/* EXC_BAD_INSTRUCTION */
|
||||
MD_EXCEPTION_MAC_ARITHMETIC = 3, /* code is CPU-specific */
|
||||
/* EXC_ARITHMETIC */
|
||||
MD_EXCEPTION_MAC_EMULATION = 4, /* code is CPU-specific */
|
||||
/* EXC_EMULATION */
|
||||
MD_EXCEPTION_MAC_SOFTWARE = 5,
|
||||
/* EXC_SOFTWARE */
|
||||
MD_EXCEPTION_MAC_BREAKPOINT = 6, /* code is CPU-specific */
|
||||
/* EXC_BREAKPOINT */
|
||||
MD_EXCEPTION_MAC_SYSCALL = 7,
|
||||
/* EXC_SYSCALL */
|
||||
MD_EXCEPTION_MAC_MACH_SYSCALL = 8,
|
||||
/* EXC_MACH_SYSCALL */
|
||||
MD_EXCEPTION_MAC_RPC_ALERT = 9
|
||||
/* EXC_RPC_ALERT */
|
||||
} MDExceptionMac;
|
||||
|
||||
/* For (MDException).exception_flags. Breakpad minidump extension for Mac OS X
|
||||
* support. Based on Darwin/Mac OS X' mach/ppc/exception.h and
|
||||
* mach/i386/exception.h. This is what Mac OS X calls a "code". */
|
||||
typedef enum {
|
||||
/* With MD_EXCEPTION_BAD_ACCESS. These are relevant kern_return_t values
|
||||
* from mach/kern_return.h. */
|
||||
MD_EXCEPTION_CODE_MAC_INVALID_ADDRESS = 1,
|
||||
/* KERN_INVALID_ADDRESS */
|
||||
MD_EXCEPTION_CODE_MAC_PROTECTION_FAILURE = 2,
|
||||
/* KERN_PROTECTION_FAILURE */
|
||||
MD_EXCEPTION_CODE_MAC_NO_ACCESS = 8,
|
||||
/* KERN_NO_ACCESS */
|
||||
MD_EXCEPTION_CODE_MAC_MEMORY_FAILURE = 9,
|
||||
/* KERN_MEMORY_FAILURE */
|
||||
MD_EXCEPTION_CODE_MAC_MEMORY_ERROR = 10,
|
||||
/* KERN_MEMORY_ERROR */
|
||||
|
||||
/* With MD_EXCEPTION_SOFTWARE */
|
||||
MD_EXCEPTION_CODE_MAC_BAD_SYSCALL = 0x00010000, /* Mach SIGSYS */
|
||||
MD_EXCEPTION_CODE_MAC_BAD_PIPE = 0x00010001, /* Mach SIGPIPE */
|
||||
MD_EXCEPTION_CODE_MAC_ABORT = 0x00010002, /* Mach SIGABRT */
|
||||
|
||||
/* With MD_EXCEPTION_MAC_BAD_ACCESS on ppc */
|
||||
MD_EXCEPTION_CODE_MAC_PPC_VM_PROT_READ = 0x0101,
|
||||
/* EXC_PPC_VM_PROT_READ */
|
||||
MD_EXCEPTION_CODE_MAC_PPC_BADSPACE = 0x0102,
|
||||
/* EXC_PPC_BADSPACE */
|
||||
MD_EXCEPTION_CODE_MAC_PPC_UNALIGNED = 0x0103,
|
||||
/* EXC_PPC_UNALIGNED */
|
||||
|
||||
/* With MD_EXCEPTION_MAC_BAD_INSTRUCTION on ppc */
|
||||
MD_EXCEPTION_CODE_MAC_PPC_INVALID_SYSCALL = 1,
|
||||
/* EXC_PPC_INVALID_SYSCALL */
|
||||
MD_EXCEPTION_CODE_MAC_PPC_UNIMPLEMENTED_INSTRUCTION = 2,
|
||||
/* EXC_PPC_UNIPL_INST */
|
||||
MD_EXCEPTION_CODE_MAC_PPC_PRIVILEGED_INSTRUCTION = 3,
|
||||
/* EXC_PPC_PRIVINST */
|
||||
MD_EXCEPTION_CODE_MAC_PPC_PRIVILEGED_REGISTER = 4,
|
||||
/* EXC_PPC_PRIVREG */
|
||||
MD_EXCEPTION_CODE_MAC_PPC_TRACE = 5,
|
||||
/* EXC_PPC_TRACE */
|
||||
MD_EXCEPTION_CODE_MAC_PPC_PERFORMANCE_MONITOR = 6,
|
||||
/* EXC_PPC_PERFMON */
|
||||
|
||||
/* With MD_EXCEPTION_MAC_ARITHMETIC on ppc */
|
||||
MD_EXCEPTION_CODE_MAC_PPC_OVERFLOW = 1,
|
||||
/* EXC_PPC_OVERFLOW */
|
||||
MD_EXCEPTION_CODE_MAC_PPC_ZERO_DIVIDE = 2,
|
||||
/* EXC_PPC_ZERO_DIVIDE */
|
||||
MD_EXCEPTION_CODE_MAC_PPC_FLOAT_INEXACT = 3,
|
||||
/* EXC_FLT_INEXACT */
|
||||
MD_EXCEPTION_CODE_MAC_PPC_FLOAT_ZERO_DIVIDE = 4,
|
||||
/* EXC_PPC_FLT_ZERO_DIVIDE */
|
||||
MD_EXCEPTION_CODE_MAC_PPC_FLOAT_UNDERFLOW = 5,
|
||||
/* EXC_PPC_FLT_UNDERFLOW */
|
||||
MD_EXCEPTION_CODE_MAC_PPC_FLOAT_OVERFLOW = 6,
|
||||
/* EXC_PPC_FLT_OVERFLOW */
|
||||
MD_EXCEPTION_CODE_MAC_PPC_FLOAT_NOT_A_NUMBER = 7,
|
||||
/* EXC_PPC_FLT_NOT_A_NUMBER */
|
||||
|
||||
/* With MD_EXCEPTION_MAC_EMULATION on ppc */
|
||||
MD_EXCEPTION_CODE_MAC_PPC_NO_EMULATION = 8,
|
||||
/* EXC_PPC_NOEMULATION */
|
||||
MD_EXCEPTION_CODE_MAC_PPC_ALTIVEC_ASSIST = 9,
|
||||
/* EXC_PPC_ALTIVECASSIST */
|
||||
|
||||
/* With MD_EXCEPTION_MAC_SOFTWARE on ppc */
|
||||
MD_EXCEPTION_CODE_MAC_PPC_TRAP = 0x00000001, /* EXC_PPC_TRAP */
|
||||
MD_EXCEPTION_CODE_MAC_PPC_MIGRATE = 0x00010100, /* EXC_PPC_MIGRATE */
|
||||
|
||||
/* With MD_EXCEPTION_MAC_BREAKPOINT on ppc */
|
||||
MD_EXCEPTION_CODE_MAC_PPC_BREAKPOINT = 1, /* EXC_PPC_BREAKPOINT */
|
||||
|
||||
/* With MD_EXCEPTION_MAC_BAD_INSTRUCTION on x86, see also x86 interrupt
|
||||
* values below. */
|
||||
MD_EXCEPTION_CODE_MAC_X86_INVALID_OPERATION = 1, /* EXC_I386_INVOP */
|
||||
|
||||
/* With MD_EXCEPTION_MAC_ARITHMETIC on x86 */
|
||||
MD_EXCEPTION_CODE_MAC_X86_DIV = 1, /* EXC_I386_DIV */
|
||||
MD_EXCEPTION_CODE_MAC_X86_INTO = 2, /* EXC_I386_INTO */
|
||||
MD_EXCEPTION_CODE_MAC_X86_NOEXT = 3, /* EXC_I386_NOEXT */
|
||||
MD_EXCEPTION_CODE_MAC_X86_EXTOVR = 4, /* EXC_I386_EXTOVR */
|
||||
MD_EXCEPTION_CODE_MAC_X86_EXTERR = 5, /* EXC_I386_EXTERR */
|
||||
MD_EXCEPTION_CODE_MAC_X86_EMERR = 6, /* EXC_I386_EMERR */
|
||||
MD_EXCEPTION_CODE_MAC_X86_BOUND = 7, /* EXC_I386_BOUND */
|
||||
MD_EXCEPTION_CODE_MAC_X86_SSEEXTERR = 8, /* EXC_I386_SSEEXTERR */
|
||||
|
||||
/* With MD_EXCEPTION_MAC_BREAKPOINT on x86 */
|
||||
MD_EXCEPTION_CODE_MAC_X86_SGL = 1, /* EXC_I386_SGL */
|
||||
MD_EXCEPTION_CODE_MAC_X86_BPT = 2, /* EXC_I386_BPT */
|
||||
|
||||
/* With MD_EXCEPTION_MAC_BAD_INSTRUCTION on x86. These are the raw
|
||||
* x86 interrupt codes. Most of these are mapped to other Mach
|
||||
* exceptions and codes, are handled, or should not occur in user space.
|
||||
* A few of these will do occur with MD_EXCEPTION_MAC_BAD_INSTRUCTION. */
|
||||
/* EXC_I386_DIVERR = 0: mapped to EXC_ARITHMETIC/EXC_I386_DIV */
|
||||
/* EXC_I386_SGLSTP = 1: mapped to EXC_BREAKPOINT/EXC_I386_SGL */
|
||||
/* EXC_I386_NMIFLT = 2: should not occur in user space */
|
||||
/* EXC_I386_BPTFLT = 3: mapped to EXC_BREAKPOINT/EXC_I386_BPT */
|
||||
/* EXC_I386_INTOFLT = 4: mapped to EXC_ARITHMETIC/EXC_I386_INTO */
|
||||
/* EXC_I386_BOUNDFLT = 5: mapped to EXC_ARITHMETIC/EXC_I386_BOUND */
|
||||
/* EXC_I386_INVOPFLT = 6: mapped to EXC_BAD_INSTRUCTION/EXC_I386_INVOP */
|
||||
/* EXC_I386_NOEXTFLT = 7: should be handled by the kernel */
|
||||
/* EXC_I386_DBLFLT = 8: should be handled (if possible) by the kernel */
|
||||
/* EXC_I386_EXTOVRFLT = 9: mapped to EXC_BAD_ACCESS/(PROT_READ|PROT_EXEC) */
|
||||
MD_EXCEPTION_CODE_MAC_X86_INVALID_TASK_STATE_SEGMENT = 10,
|
||||
/* EXC_INVTSSFLT */
|
||||
MD_EXCEPTION_CODE_MAC_X86_SEGMENT_NOT_PRESENT = 11,
|
||||
/* EXC_SEGNPFLT */
|
||||
MD_EXCEPTION_CODE_MAC_X86_STACK_FAULT = 12,
|
||||
/* EXC_STKFLT */
|
||||
MD_EXCEPTION_CODE_MAC_X86_GENERAL_PROTECTION_FAULT = 13,
|
||||
/* EXC_GPFLT */
|
||||
/* EXC_I386_PGFLT = 14: should not occur in user space */
|
||||
/* EXC_I386_EXTERRFLT = 16: mapped to EXC_ARITHMETIC/EXC_I386_EXTERR */
|
||||
MD_EXCEPTION_CODE_MAC_X86_ALIGNMENT_FAULT = 17
|
||||
/* EXC_ALIGNFLT (for vector operations) */
|
||||
/* EXC_I386_ENOEXTFLT = 32: should be handled by the kernel */
|
||||
/* EXC_I386_ENDPERR = 33: should not occur */
|
||||
} MDExceptionCodeMac;
|
||||
|
||||
#endif /* GOOGLE_BREAKPAD_COMMON_MINIDUMP_EXCEPTION_MAC_OSX_H__ */
|
|
@ -0,0 +1,94 @@
|
|||
/* Copyright (c) 2006, 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. */
|
||||
|
||||
/* minidump_exception_solaris.h: A definition of exception codes for
|
||||
* Solaris
|
||||
*
|
||||
* (This is C99 source, please don't corrupt it with C++.)
|
||||
*
|
||||
* Author: Mark Mentovai
|
||||
* Split into its own file: Neal Sidhwaney */
|
||||
|
||||
|
||||
#ifndef GOOGLE_BREAKPAD_COMMON_MINIDUMP_EXCEPTION_SOLARIS_H__
|
||||
#define GOOGLE_BREAKPAD_COMMON_MINIDUMP_EXCEPTION_SOLARIS_H__
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#include "google_breakpad/common/breakpad_types.h"
|
||||
|
||||
/* For (MDException).exception_code. These values come from sys/iso/signal_iso.h
|
||||
*/
|
||||
typedef enum {
|
||||
MD_EXCEPTION_CODE_SOL_SIGHUP = 1, /* Hangup */
|
||||
MD_EXCEPTION_CODE_SOL_SIGINT = 2, /* interrupt (rubout) */
|
||||
MD_EXCEPTION_CODE_SOL_SIGQUIT = 3, /* quit (ASCII FS) */
|
||||
MD_EXCEPTION_CODE_SOL_SIGILL = 4, /* illegal instruction (not reset when caught) */
|
||||
MD_EXCEPTION_CODE_SOL_SIGTRAP = 5, /* trace trap (not reset when caught) */
|
||||
MD_EXCEPTION_CODE_SOL_SIGIOT = 6, /* IOT instruction */
|
||||
MD_EXCEPTION_CODE_SOL_SIGABRT = 6, /* used by abort, replace SIGIOT in the future */
|
||||
MD_EXCEPTION_CODE_SOL_SIGEMT = 7, /* EMT instruction */
|
||||
MD_EXCEPTION_CODE_SOL_SIGFPE = 8, /* floating point exception */
|
||||
MD_EXCEPTION_CODE_SOL_SIGKILL = 9, /* kill (cannot be caught or ignored) */
|
||||
MD_EXCEPTION_CODE_SOL_SIGBUS = 10, /* bus error */
|
||||
MD_EXCEPTION_CODE_SOL_SIGSEGV = 11, /* segmentation violation */
|
||||
MD_EXCEPTION_CODE_SOL_SIGSYS = 12, /* bad argument to system call */
|
||||
MD_EXCEPTION_CODE_SOL_SIGPIPE = 13, /* write on a pipe with no one to read it */
|
||||
MD_EXCEPTION_CODE_SOL_SIGALRM = 14, /* alarm clock */
|
||||
MD_EXCEPTION_CODE_SOL_SIGTERM = 15, /* software termination signal from kill */
|
||||
MD_EXCEPTION_CODE_SOL_SIGUSR1 = 16, /* user defined signal 1 */
|
||||
MD_EXCEPTION_CODE_SOL_SIGUSR2 = 17, /* user defined signal 2 */
|
||||
MD_EXCEPTION_CODE_SOL_SIGCLD = 18, /* child status change */
|
||||
MD_EXCEPTION_CODE_SOL_SIGCHLD = 18, /* child status change alias (POSIX) */
|
||||
MD_EXCEPTION_CODE_SOL_SIGPWR = 19, /* power-fail restart */
|
||||
MD_EXCEPTION_CODE_SOL_SIGWINCH = 20, /* window size change */
|
||||
MD_EXCEPTION_CODE_SOL_SIGURG = 21, /* urgent socket condition */
|
||||
MD_EXCEPTION_CODE_SOL_SIGPOLL = 22, /* pollable event occured */
|
||||
MD_EXCEPTION_CODE_SOL_SIGIO = 22, /* socket I/O possible (SIGPOLL alias) */
|
||||
MD_EXCEPTION_CODE_SOL_SIGSTOP = 23, /* stop (cannot be caught or ignored) */
|
||||
MD_EXCEPTION_CODE_SOL_SIGTSTP = 24, /* user stop requested from tty */
|
||||
MD_EXCEPTION_CODE_SOL_SIGCONT = 25, /* stopped process has been continued */
|
||||
MD_EXCEPTION_CODE_SOL_SIGTTIN = 26, /* background tty read attempted */
|
||||
MD_EXCEPTION_CODE_SOL_SIGTTOU = 27, /* background tty write attempted */
|
||||
MD_EXCEPTION_CODE_SOL_SIGVTALRM = 28, /* virtual timer expired */
|
||||
MD_EXCEPTION_CODE_SOL_SIGPROF = 29, /* profiling timer expired */
|
||||
MD_EXCEPTION_CODE_SOL_SIGXCPU = 30, /* exceeded cpu limit */
|
||||
MD_EXCEPTION_CODE_SOL_SIGXFSZ = 31, /* exceeded file size limit */
|
||||
MD_EXCEPTION_CODE_SOL_SIGWAITING = 32, /* reserved signal no longer used by threading code */
|
||||
MD_EXCEPTION_CODE_SOL_SIGLWP = 33, /* reserved signal no longer used by threading code */
|
||||
MD_EXCEPTION_CODE_SOL_SIGFREEZE = 34, /* special signal used by CPR */
|
||||
MD_EXCEPTION_CODE_SOL_SIGTHAW = 35, /* special signal used by CPR */
|
||||
MD_EXCEPTION_CODE_SOL_SIGCANCEL = 36, /* reserved signal for thread cancellation */
|
||||
MD_EXCEPTION_CODE_SOL_SIGLOST = 37, /* resource lost (eg, record-lock lost) */
|
||||
MD_EXCEPTION_CODE_SOL_SIGXRES = 38, /* resource control exceeded */
|
||||
MD_EXCEPTION_CODE_SOL_SIGJVM1 = 39, /* reserved signal for Java Virtual Machine */
|
||||
MD_EXCEPTION_CODE_SOL_SIGJVM2 = 40 /* reserved signal for Java Virtual Machine */
|
||||
} MDExceptionCodeSolaris;
|
||||
|
||||
#endif /* GOOGLE_BREAKPAD_COMMON_MINIDUMP_EXCEPTION_SOLARIS_H__ */
|
|
@ -0,0 +1,102 @@
|
|||
/* Copyright (c) 2006, 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. */
|
||||
|
||||
/* minidump_exception_win32.h: Definitions of exception codes for
|
||||
* Win32 platform
|
||||
*
|
||||
* (This is C99 source, please don't corrupt it with C++.)
|
||||
*
|
||||
* Author: Mark Mentovai
|
||||
* Split into its own file: Neal Sidhwaney */
|
||||
|
||||
|
||||
#ifndef GOOGLE_BREAKPAD_COMMON_MINIDUMP_EXCEPTION_WIN32_H__
|
||||
#define GOOGLE_BREAKPAD_COMMON_MINIDUMP_EXCEPTION_WIN32_H__
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#include "google_breakpad/common/breakpad_types.h"
|
||||
|
||||
|
||||
/* For (MDException).exception_code. These values come from WinBase.h
|
||||
* and WinNT.h (names beginning with EXCEPTION_ are in WinBase.h,
|
||||
* they are STATUS_ in WinNT.h). */
|
||||
typedef enum {
|
||||
MD_EXCEPTION_CODE_WIN_CONTROL_C = 0x40010005,
|
||||
/* DBG_CONTROL_C */
|
||||
MD_EXCEPTION_CODE_WIN_GUARD_PAGE_VIOLATION = 0x80000001,
|
||||
/* EXCEPTION_GUARD_PAGE */
|
||||
MD_EXCEPTION_CODE_WIN_DATATYPE_MISALIGNMENT = 0x80000002,
|
||||
/* EXCEPTION_DATATYPE_MISALIGNMENT */
|
||||
MD_EXCEPTION_CODE_WIN_BREAKPOINT = 0x80000003,
|
||||
/* EXCEPTION_BREAKPOINT */
|
||||
MD_EXCEPTION_CODE_WIN_SINGLE_STEP = 0x80000004,
|
||||
/* EXCEPTION_SINGLE_STEP */
|
||||
MD_EXCEPTION_CODE_WIN_ACCESS_VIOLATION = 0xc0000005,
|
||||
/* EXCEPTION_ACCESS_VIOLATION */
|
||||
MD_EXCEPTION_CODE_WIN_IN_PAGE_ERROR = 0xc0000006,
|
||||
/* EXCEPTION_IN_PAGE_ERROR */
|
||||
MD_EXCEPTION_CODE_WIN_INVALID_HANDLE = 0xc0000008,
|
||||
/* EXCEPTION_INVALID_HANDLE */
|
||||
MD_EXCEPTION_CODE_WIN_ILLEGAL_INSTRUCTION = 0xc000001d,
|
||||
/* EXCEPTION_ILLEGAL_INSTRUCTION */
|
||||
MD_EXCEPTION_CODE_WIN_NONCONTINUABLE_EXCEPTION = 0xc0000025,
|
||||
/* EXCEPTION_NONCONTINUABLE_EXCEPTION */
|
||||
MD_EXCEPTION_CODE_WIN_INVALID_DISPOSITION = 0xc0000026,
|
||||
/* EXCEPTION_INVALID_DISPOSITION */
|
||||
MD_EXCEPTION_CODE_WIN_ARRAY_BOUNDS_EXCEEDED = 0xc000008c,
|
||||
/* EXCEPTION_BOUNDS_EXCEEDED */
|
||||
MD_EXCEPTION_CODE_WIN_FLOAT_DENORMAL_OPERAND = 0xc000008d,
|
||||
/* EXCEPTION_FLT_DENORMAL_OPERAND */
|
||||
MD_EXCEPTION_CODE_WIN_FLOAT_DIVIDE_BY_ZERO = 0xc000008e,
|
||||
/* EXCEPTION_FLT_DIVIDE_BY_ZERO */
|
||||
MD_EXCEPTION_CODE_WIN_FLOAT_INEXACT_RESULT = 0xc000008f,
|
||||
/* EXCEPTION_FLT_INEXACT_RESULT */
|
||||
MD_EXCEPTION_CODE_WIN_FLOAT_INVALID_OPERATION = 0xc0000090,
|
||||
/* EXCEPTION_FLT_INVALID_OPERATION */
|
||||
MD_EXCEPTION_CODE_WIN_FLOAT_OVERFLOW = 0xc0000091,
|
||||
/* EXCEPTION_FLT_OVERFLOW */
|
||||
MD_EXCEPTION_CODE_WIN_FLOAT_STACK_CHECK = 0xc0000092,
|
||||
/* EXCEPTION_FLT_STACK_CHECK */
|
||||
MD_EXCEPTION_CODE_WIN_FLOAT_UNDERFLOW = 0xc0000093,
|
||||
/* EXCEPTION_FLT_UNDERFLOW */
|
||||
MD_EXCEPTION_CODE_WIN_INTEGER_DIVIDE_BY_ZERO = 0xc0000094,
|
||||
/* EXCEPTION_INT_DIVIDE_BY_ZERO */
|
||||
MD_EXCEPTION_CODE_WIN_INTEGER_OVERFLOW = 0xc0000095,
|
||||
/* EXCEPTION_INT_OVERFLOW */
|
||||
MD_EXCEPTION_CODE_WIN_PRIVILEGED_INSTRUCTION = 0xc0000096,
|
||||
/* EXCEPTION_PRIV_INSTRUCTION */
|
||||
MD_EXCEPTION_CODE_WIN_STACK_OVERFLOW = 0xc00000fd,
|
||||
/* EXCEPTION_STACK_OVERFLOW */
|
||||
MD_EXCEPTION_CODE_WIN_POSSIBLE_DEADLOCK = 0xc0000194
|
||||
/* EXCEPTION_POSSIBLE_DEADLOCK */
|
||||
} MDExceptionCodeWin;
|
||||
|
||||
|
||||
#endif /* GOOGLE_BREAKPAD_COMMON_MINIDUMP_EXCEPTION_WIN32_H__ */
|
|
@ -32,18 +32,6 @@
|
|||
*
|
||||
* (This is C99 source, please don't corrupt it with C++.)
|
||||
*
|
||||
* This file contains the necessary definitions to read minidump files
|
||||
* produced on win32/x86. These files may be read on any platform provided
|
||||
* that the alignments of these structures on the processing system are
|
||||
* identical to the alignments of these structures on the producing system.
|
||||
* For this reason, precise-sized types are used. The structures defined
|
||||
* by this file have been laid out to minimize alignment problems by ensuring
|
||||
* ensuring that all members are aligned on their natural boundaries. In
|
||||
* In some cases, tail-padding may be significant when different ABIs specify
|
||||
* different tail-padding behaviors. To avoid problems when reading or
|
||||
* writing affected structures, MD_*_SIZE macros are provided where needed,
|
||||
* containing the useful size of the structures without padding.
|
||||
*
|
||||
* Structures that are defined by Microsoft to contain a zero-length array
|
||||
* are instead defined here to contain an array with one element, as
|
||||
* zero-length arrays are forbidden by standard C and C++. In these cases,
|
||||
|
@ -68,7 +56,7 @@
|
|||
* comments.
|
||||
*
|
||||
* Author: Mark Mentovai */
|
||||
|
||||
|
||||
|
||||
#ifndef GOOGLE_BREAKPAD_COMMON_MINIDUMP_FORMAT_H__
|
||||
#define GOOGLE_BREAKPAD_COMMON_MINIDUMP_FORMAT_H__
|
||||
|
@ -90,7 +78,6 @@
|
|||
* guiddef.h
|
||||
*/
|
||||
|
||||
|
||||
typedef struct {
|
||||
u_int32_t data1;
|
||||
u_int16_t data2;
|
||||
|
@ -103,104 +90,6 @@ typedef struct {
|
|||
* WinNT.h
|
||||
*/
|
||||
|
||||
|
||||
#define MD_FLOATINGSAVEAREA_X86_REGISTERAREA_SIZE 80
|
||||
/* SIZE_OF_80387_REGISTERS */
|
||||
|
||||
typedef struct {
|
||||
u_int32_t control_word;
|
||||
u_int32_t status_word;
|
||||
u_int32_t tag_word;
|
||||
u_int32_t error_offset;
|
||||
u_int32_t error_selector;
|
||||
u_int32_t data_offset;
|
||||
u_int32_t data_selector;
|
||||
|
||||
/* register_area contains eight 80-bit (x87 "long double") quantities for
|
||||
* floating-point registers %st0 (%mm0) through %st7 (%mm7). */
|
||||
u_int8_t register_area[MD_FLOATINGSAVEAREA_X86_REGISTERAREA_SIZE];
|
||||
u_int32_t cr0_npx_state;
|
||||
} MDFloatingSaveAreaX86; /* FLOATING_SAVE_AREA */
|
||||
|
||||
|
||||
#define MD_CONTEXT_X86_EXTENDED_REGISTERS_SIZE 512
|
||||
/* MAXIMUM_SUPPORTED_EXTENSION */
|
||||
|
||||
typedef struct {
|
||||
/* The next field determines the layout of the structure, and which parts
|
||||
* of it are populated */
|
||||
u_int32_t context_flags;
|
||||
|
||||
/* The next 6 registers are included with MD_CONTEXT_X86_DEBUG_REGISTERS */
|
||||
u_int32_t dr0;
|
||||
u_int32_t dr1;
|
||||
u_int32_t dr2;
|
||||
u_int32_t dr3;
|
||||
u_int32_t dr6;
|
||||
u_int32_t dr7;
|
||||
|
||||
/* The next field is included with MD_CONTEXT_X86_FLOATING_POINT */
|
||||
MDFloatingSaveAreaX86 float_save;
|
||||
|
||||
/* The next 4 registers are included with MD_CONTEXT_X86_SEGMENTS */
|
||||
u_int32_t gs;
|
||||
u_int32_t fs;
|
||||
u_int32_t es;
|
||||
u_int32_t ds;
|
||||
/* The next 6 registers are included with MD_CONTEXT_X86_INTEGER */
|
||||
u_int32_t edi;
|
||||
u_int32_t esi;
|
||||
u_int32_t ebx;
|
||||
u_int32_t edx;
|
||||
u_int32_t ecx;
|
||||
u_int32_t eax;
|
||||
|
||||
/* The next 6 registers are included with MD_CONTEXT_X86_CONTROL */
|
||||
u_int32_t ebp;
|
||||
u_int32_t eip;
|
||||
u_int32_t cs; /* WinNT.h says "must be sanitized" */
|
||||
u_int32_t eflags; /* WinNT.h says "must be sanitized" */
|
||||
u_int32_t esp;
|
||||
u_int32_t ss;
|
||||
|
||||
/* The next field is included with MD_CONTEXT_X86_EXTENDED_REGISTERS.
|
||||
* It contains vector (MMX/SSE) registers. It it laid out in the
|
||||
* format used by the fxsave and fsrstor instructions, so it includes
|
||||
* a copy of the x87 floating-point registers as well. See FXSAVE in
|
||||
* "Intel Architecture Software Developer's Manual, Volume 2." */
|
||||
u_int8_t extended_registers[
|
||||
MD_CONTEXT_X86_EXTENDED_REGISTERS_SIZE];
|
||||
} MDRawContextX86; /* CONTEXT */
|
||||
|
||||
/* For (MDRawContextX86).context_flags. These values indicate the type of
|
||||
* context stored in the structure. The high 26 bits identify the CPU, the
|
||||
* low 6 bits identify the type of context saved. */
|
||||
#define MD_CONTEXT_X86 0x00010000
|
||||
/* CONTEXT_i386, CONTEXT_i486: identifies CPU */
|
||||
#define MD_CONTEXT_X86_CONTROL (MD_CONTEXT_X86 | 0x00000001)
|
||||
/* CONTEXT_CONTROL */
|
||||
#define MD_CONTEXT_X86_INTEGER (MD_CONTEXT_X86 | 0x00000002)
|
||||
/* CONTEXT_INTEGER */
|
||||
#define MD_CONTEXT_X86_SEGMENTS (MD_CONTEXT_X86 | 0x00000004)
|
||||
/* CONTEXT_SEGMENTS */
|
||||
#define MD_CONTEXT_X86_FLOATING_POINT (MD_CONTEXT_X86 | 0x00000008)
|
||||
/* CONTEXT_FLOATING_POINT */
|
||||
#define MD_CONTEXT_X86_DEBUG_REGISTERS (MD_CONTEXT_X86 | 0x00000010)
|
||||
/* CONTEXT_DEBUG_REGISTERS */
|
||||
#define MD_CONTEXT_X86_EXTENDED_REGISTERS (MD_CONTEXT_X86 | 0x00000020)
|
||||
/* CONTEXT_EXTENDED_REGISTERS */
|
||||
|
||||
#define MD_CONTEXT_X86_FULL (MD_CONTEXT_X86_CONTROL | \
|
||||
MD_CONTEXT_X86_INTEGER | \
|
||||
MD_CONTEXT_X86_SEGMENTS)
|
||||
/* CONTEXT_FULL */
|
||||
|
||||
#define MD_CONTEXT_X86_ALL (MD_CONTEXT_X86_FULL | \
|
||||
MD_CONTEXT_X86_FLOATING_POINT | \
|
||||
MD_CONTEXT_X86_DEBUG_REGISTERS | \
|
||||
MD_CONTEXT_X86_EXTENDED_REGISTERS)
|
||||
/* CONTEXT_ALL */
|
||||
|
||||
/* Non-x86 CPU identifiers found in the high 26 bits of
|
||||
* (MDRawContext*).context_flags. These aren't used by Breakpad, but are
|
||||
* defined here for reference, to avoid assigning values that conflict
|
||||
|
@ -215,247 +104,6 @@ typedef struct {
|
|||
|
||||
#define MD_CONTEXT_CPU_MASK 0xffffffc0
|
||||
|
||||
/*
|
||||
* AMD64 support, see WINNT.H
|
||||
*/
|
||||
|
||||
typedef struct {
|
||||
u_int16_t control_word;
|
||||
u_int16_t status_word;
|
||||
u_int8_t tag_word;
|
||||
u_int8_t reserved1;
|
||||
u_int16_t error_opcode;
|
||||
u_int32_t error_offset;
|
||||
u_int16_t error_selector;
|
||||
u_int16_t reserved2;
|
||||
u_int32_t data_offset;
|
||||
u_int16_t data_selector;
|
||||
u_int16_t reserved3;
|
||||
u_int32_t mx_csr;
|
||||
u_int32_t mx_csr_mask;
|
||||
u_int128_t float_registers[8];
|
||||
u_int128_t xmm_registers[16];
|
||||
u_int8_t reserved4[96];
|
||||
} MDXmmSaveArea32AMD64; /* XMM_SAVE_AREA32 */
|
||||
|
||||
#define MD_CONTEXT_AMD64_VR_COUNT 26
|
||||
|
||||
typedef struct {
|
||||
/*
|
||||
* Register parameter home addresses.
|
||||
*/
|
||||
u_int64_t p1_home;
|
||||
u_int64_t p2_home;
|
||||
u_int64_t p3_home;
|
||||
u_int64_t p4_home;
|
||||
u_int64_t p5_home;
|
||||
u_int64_t p6_home;
|
||||
|
||||
/* The next field determines the layout of the structure, and which parts
|
||||
* of it are populated */
|
||||
u_int32_t context_flags;
|
||||
u_int32_t mx_csr;
|
||||
|
||||
/* The next register is included with MD_CONTEXT_AMD64_CONTROL */
|
||||
u_int16_t cs;
|
||||
|
||||
/* The next 4 registers are included with MD_CONTEXT_AMD64_SEGMENTS */
|
||||
u_int16_t ds;
|
||||
u_int16_t es;
|
||||
u_int16_t fs;
|
||||
u_int16_t gs;
|
||||
|
||||
/* The next 2 registers are included with MD_CONTEXT_AMD64_CONTROL */
|
||||
u_int16_t ss;
|
||||
u_int32_t eflags;
|
||||
|
||||
/* The next 6 registers are included with MD_CONTEXT_AMD64_DEBUG_REGISTERS */
|
||||
u_int64_t dr0;
|
||||
u_int64_t dr1;
|
||||
u_int64_t dr2;
|
||||
u_int64_t dr3;
|
||||
u_int64_t dr6;
|
||||
u_int64_t dr7;
|
||||
|
||||
/* The next 4 registers are included with MD_CONTEXT_AMD64_INTEGER */
|
||||
u_int64_t rax;
|
||||
u_int64_t rcx;
|
||||
u_int64_t rdx;
|
||||
u_int64_t rbx;
|
||||
|
||||
/* The next register is included with MD_CONTEXT_AMD64_CONTROL */
|
||||
u_int64_t rsp;
|
||||
|
||||
/* The next 11 registers are included with MD_CONTEXT_AMD64_INTEGER */
|
||||
u_int64_t rbp;
|
||||
u_int64_t rsi;
|
||||
u_int64_t rdi;
|
||||
u_int64_t r8;
|
||||
u_int64_t r9;
|
||||
u_int64_t r10;
|
||||
u_int64_t r11;
|
||||
u_int64_t r12;
|
||||
u_int64_t r13;
|
||||
u_int64_t r14;
|
||||
u_int64_t r15;
|
||||
|
||||
/* The next register is included with MD_CONTEXT_AMD64_CONTROL */
|
||||
u_int64_t rip;
|
||||
|
||||
/* The next set of registers are included with
|
||||
* MD_CONTEXT_AMD64_FLOATING_POINT
|
||||
*/
|
||||
union {
|
||||
MDXmmSaveArea32AMD64 flt_save;
|
||||
struct {
|
||||
u_int128_t header[2];
|
||||
u_int128_t legacy[8];
|
||||
u_int128_t xmm0;
|
||||
u_int128_t xmm1;
|
||||
u_int128_t xmm2;
|
||||
u_int128_t xmm3;
|
||||
u_int128_t xmm4;
|
||||
u_int128_t xmm5;
|
||||
u_int128_t xmm6;
|
||||
u_int128_t xmm7;
|
||||
u_int128_t xmm8;
|
||||
u_int128_t xmm9;
|
||||
u_int128_t xmm10;
|
||||
u_int128_t xmm11;
|
||||
u_int128_t xmm12;
|
||||
u_int128_t xmm13;
|
||||
u_int128_t xmm14;
|
||||
u_int128_t xmm15;
|
||||
} sse_registers;
|
||||
};
|
||||
|
||||
u_int128_t vector_register[MD_CONTEXT_AMD64_VR_COUNT];
|
||||
u_int64_t vector_control;
|
||||
|
||||
/* The next 5 registers are included with MD_CONTEXT_AMD64_DEBUG_REGISTERS */
|
||||
u_int64_t debug_control;
|
||||
u_int64_t last_branch_to_rip;
|
||||
u_int64_t last_branch_from_rip;
|
||||
u_int64_t last_exception_to_rip;
|
||||
u_int64_t last_exception_from_rip;
|
||||
|
||||
} MDRawContextAMD64; /* CONTEXT */
|
||||
|
||||
/* For (MDRawContextAMD64).context_flags. These values indicate the type of
|
||||
* context stored in the structure. The high 26 bits identify the CPU, the
|
||||
* low 6 bits identify the type of context saved. */
|
||||
#define MD_CONTEXT_AMD64_CONTROL (MD_CONTEXT_AMD64 | 0x00000001)
|
||||
/* CONTEXT_CONTROL */
|
||||
#define MD_CONTEXT_AMD64_INTEGER (MD_CONTEXT_AMD64 | 0x00000002)
|
||||
/* CONTEXT_INTEGER */
|
||||
#define MD_CONTEXT_AMD64_SEGMENTS (MD_CONTEXT_AMD64 | 0x00000004)
|
||||
/* CONTEXT_SEGMENTS */
|
||||
#define MD_CONTEXT_AMD64_FLOATING_POINT (MD_CONTEXT_AMD64 | 0x00000008)
|
||||
/* CONTEXT_FLOATING_POINT */
|
||||
#define MD_CONTEXT_AMD64_DEBUG_REGISTERS (MD_CONTEXT_AMD64 | 0x00000010)
|
||||
/* CONTEXT_DEBUG_REGISTERS */
|
||||
/* WinNT.h refers to CONTEXT_MMX_REGISTERS but doesn't appear to define it
|
||||
* I think it really means CONTEXT_FLOATING_POINT.
|
||||
*/
|
||||
|
||||
#define MD_CONTEXT_AMD64_FULL (MD_CONTEXT_AMD64_CONTROL | \
|
||||
MD_CONTEXT_AMD64_INTEGER | \
|
||||
MD_CONTEXT_AMD64_FLOATING_POINT)
|
||||
/* CONTEXT_FULL */
|
||||
|
||||
#define MD_CONTEXT_AMD64_ALL (MD_CONTEXT_AMD64_FULL | \
|
||||
MD_CONTEXT_AMD64_SEGMENTS | \
|
||||
MD_CONTEXT_X86_DEBUG_REGISTERS)
|
||||
/* CONTEXT_ALL */
|
||||
|
||||
|
||||
/*
|
||||
* SPARC support, see (solaris)sys/procfs_isa.h also
|
||||
*/
|
||||
|
||||
#define MD_FLOATINGSAVEAREA_SPARC_FPR_COUNT 32
|
||||
|
||||
typedef struct {
|
||||
|
||||
/* FPU floating point regs */
|
||||
u_int64_t regs[MD_FLOATINGSAVEAREA_SPARC_FPR_COUNT];
|
||||
|
||||
u_int64_t filler;
|
||||
u_int64_t fsr; /* FPU status register */
|
||||
} MDFloatingSaveAreaSPARC; /* FLOATING_SAVE_AREA */
|
||||
|
||||
#define MD_CONTEXT_SPARC_GPR_COUNT 32
|
||||
|
||||
typedef struct {
|
||||
/* The next field determines the layout of the structure, and which parts
|
||||
* of it are populated
|
||||
*/
|
||||
u_int32_t context_flags;
|
||||
u_int32_t flag_pad;
|
||||
/*
|
||||
* General register access (SPARC).
|
||||
* Don't confuse definitions here with definitions in <sys/regset.h>.
|
||||
* Registers are 32 bits for ILP32, 64 bits for LP64.
|
||||
* SPARC V7/V8 is for 32bit, SPARC V9 is for 64bit
|
||||
*/
|
||||
|
||||
/* 32 Integer working registers */
|
||||
|
||||
/* g_r[0-7] global registers(g0-g7)
|
||||
* g_r[8-15] out registers(o0-o7)
|
||||
* g_r[16-23] local registers(l0-l7)
|
||||
* g_r[24-31] in registers(i0-i7)
|
||||
*/
|
||||
u_int64_t g_r[MD_CONTEXT_SPARC_GPR_COUNT];
|
||||
|
||||
/* several control registers */
|
||||
|
||||
/* Processor State register(PSR) for SPARC V7/V8
|
||||
* Condition Code register (CCR) for SPARC V9
|
||||
*/
|
||||
u_int64_t ccr;
|
||||
|
||||
u_int64_t pc; /* Program Counter register (PC) */
|
||||
u_int64_t npc; /* Next Program Counter register (nPC) */
|
||||
u_int64_t y; /* Y register (Y) */
|
||||
|
||||
/* Address Space Identifier register (ASI) for SPARC V9
|
||||
* WIM for SPARC V7/V8
|
||||
*/
|
||||
u_int64_t asi;
|
||||
|
||||
/* Floating-Point Registers State register (FPRS) for SPARC V9
|
||||
* TBR for for SPARC V7/V8
|
||||
*/
|
||||
u_int64_t fprs;
|
||||
|
||||
/* The next field is included with MD_CONTEXT_SPARC_FLOATING_POINT */
|
||||
MDFloatingSaveAreaSPARC float_save;
|
||||
|
||||
} MDRawContextSPARC; /* CONTEXT_SPARC */
|
||||
|
||||
/* For (MDRawContextSPARC).context_flags. These values indicate the type of
|
||||
* context stored in the structure. MD_CONTEXT_SPARC is Breakpad-defined. Its
|
||||
* value was chosen to avoid likely conflicts with MD_CONTEXT_* for other
|
||||
* CPUs. */
|
||||
#define MD_CONTEXT_SPARC 0x10000000
|
||||
#define MD_CONTEXT_SPARC_CONTROL (MD_CONTEXT_SPARC | 0x00000001)
|
||||
#define MD_CONTEXT_SPARC_INTEGER (MD_CONTEXT_SPARC | 0x00000002)
|
||||
#define MD_CONTEXT_SAPARC_FLOATING_POINT (MD_CONTEXT_SPARC | 0x00000004)
|
||||
#define MD_CONTEXT_SAPARC_EXTRA (MD_CONTEXT_SPARC | 0x00000008)
|
||||
|
||||
#define MD_CONTEXT_SPARC_FULL (MD_CONTEXT_SPARC_CONTROL | \
|
||||
MD_CONTEXT_SPARC_INTEGER)
|
||||
|
||||
#define MD_CONTEXT_SPARC_ALL (MD_CONTEXT_SPARC_FULL | \
|
||||
MD_CONTEXT_SAPARC_FLOATING_POINT | \
|
||||
MD_CONTEXT_SAPARC_EXTRA)
|
||||
|
||||
/*
|
||||
* Breakpad minidump extension for PowerPC support. Based on Darwin/Mac OS X'
|
||||
* mach/ppc/_types.h
|
||||
*/
|
||||
|
||||
|
||||
/* This is a base type for MDRawContextX86 and MDRawContextPPC. This
|
||||
* structure should never be allocated directly. The actual structure type
|
||||
|
@ -464,73 +112,11 @@ typedef struct {
|
|||
u_int32_t context_flags;
|
||||
} MDRawContextBase;
|
||||
|
||||
|
||||
#define MD_FLOATINGSAVEAREA_PPC_FPR_COUNT 32
|
||||
|
||||
typedef struct {
|
||||
/* fpregs is a double[32] in mach/ppc/_types.h, but a u_int64_t is used
|
||||
* here for precise sizing. */
|
||||
u_int64_t fpregs[MD_FLOATINGSAVEAREA_PPC_FPR_COUNT];
|
||||
u_int32_t fpscr_pad;
|
||||
u_int32_t fpscr; /* Status/control */
|
||||
} MDFloatingSaveAreaPPC; /* Based on ppc_float_state */
|
||||
|
||||
|
||||
#define MD_VECTORSAVEAREA_PPC_VR_COUNT 32
|
||||
|
||||
typedef struct {
|
||||
/* Vector registers (including vscr) are 128 bits, but mach/ppc/_types.h
|
||||
* exposes them as four 32-bit quantities. */
|
||||
u_int128_t save_vr[MD_VECTORSAVEAREA_PPC_VR_COUNT];
|
||||
u_int128_t save_vscr; /* Status/control */
|
||||
u_int32_t save_pad5[4];
|
||||
u_int32_t save_vrvalid; /* Identifies which vector registers are saved */
|
||||
u_int32_t save_pad6[7];
|
||||
} MDVectorSaveAreaPPC; /* ppc_vector_state */
|
||||
|
||||
|
||||
#define MD_CONTEXT_PPC_GPR_COUNT 32
|
||||
|
||||
typedef struct {
|
||||
/* context_flags is not present in ppc_thread_state, but it aids
|
||||
* identification of MDRawContextPPC among other raw context types,
|
||||
* and it guarantees alignment when we get to float_save. */
|
||||
u_int32_t context_flags;
|
||||
|
||||
u_int32_t srr0; /* Machine status save/restore: stores pc
|
||||
* (instruction) */
|
||||
u_int32_t srr1; /* Machine status save/restore: stores msr
|
||||
* (ps, program/machine state) */
|
||||
/* ppc_thread_state contains 32 fields, r0 .. r31. Here, an array is
|
||||
* used for brevity. */
|
||||
u_int32_t gpr[MD_CONTEXT_PPC_GPR_COUNT];
|
||||
u_int32_t cr; /* Condition */
|
||||
u_int32_t xer; /* Integer (fiXed-point) exception */
|
||||
u_int32_t lr; /* Link */
|
||||
u_int32_t ctr; /* Count */
|
||||
u_int32_t mq; /* Multiply/Quotient (PPC 601, POWER only) */
|
||||
u_int32_t vrsave; /* Vector save */
|
||||
|
||||
/* float_save and vector_save aren't present in ppc_thread_state, but
|
||||
* are represented in separate structures that still define a thread's
|
||||
* context. */
|
||||
MDFloatingSaveAreaPPC float_save;
|
||||
MDVectorSaveAreaPPC vector_save;
|
||||
} MDRawContextPPC; /* Based on ppc_thread_state */
|
||||
|
||||
/* For (MDRawContextPPC).context_flags. These values indicate the type of
|
||||
* context stored in the structure. MD_CONTEXT_PPC is Breakpad-defined. Its
|
||||
* value was chosen to avoid likely conflicts with MD_CONTEXT_* for other
|
||||
* CPUs. */
|
||||
#define MD_CONTEXT_PPC 0x20000000
|
||||
#define MD_CONTEXT_PPC_BASE (MD_CONTEXT_PPC | 0x00000001)
|
||||
#define MD_CONTEXT_PPC_FLOATING_POINT (MD_CONTEXT_PPC | 0x00000008)
|
||||
#define MD_CONTEXT_PPC_VECTOR (MD_CONTEXT_PPC | 0x00000020)
|
||||
|
||||
#define MD_CONTEXT_PPC_FULL MD_CONTEXT_PPC_BASE
|
||||
#define MD_CONTEXT_PPC_ALL (MD_CONTEXT_PPC_FULL | \
|
||||
MD_CONTEXT_PPC_FLOATING_POINT | \
|
||||
MD_CONTEXT_PPC_VECTOR)
|
||||
#include "minidump_cpu_sparc.h"
|
||||
#include "minidump_cpu_x86.h"
|
||||
#include "minidump_cpu_ppc.h"
|
||||
#include "minidump_cpu_ppc64.h"
|
||||
#include "minidump_cpu_amd64.h"
|
||||
|
||||
|
||||
/*
|
||||
|
@ -646,7 +232,6 @@ typedef struct {
|
|||
* MDRawHeader is at offset 0. */
|
||||
typedef u_int32_t MDRVA; /* RVA */
|
||||
|
||||
|
||||
typedef struct {
|
||||
u_int32_t data_size;
|
||||
MDRVA rva;
|
||||
|
@ -925,292 +510,10 @@ typedef struct {
|
|||
u_int64_t exception_information[MD_EXCEPTION_MAXIMUM_PARAMETERS];
|
||||
} MDException; /* MINIDUMP_EXCEPTION */
|
||||
|
||||
/* For (MDException).exception_code. These values come from WinBase.h
|
||||
* and WinNT.h (names beginning with EXCEPTION_ are in WinBase.h,
|
||||
* they are STATUS_ in WinNT.h). */
|
||||
typedef enum {
|
||||
MD_EXCEPTION_CODE_WIN_CONTROL_C = 0x40010005,
|
||||
/* DBG_CONTROL_C */
|
||||
MD_EXCEPTION_CODE_WIN_GUARD_PAGE_VIOLATION = 0x80000001,
|
||||
/* EXCEPTION_GUARD_PAGE */
|
||||
MD_EXCEPTION_CODE_WIN_DATATYPE_MISALIGNMENT = 0x80000002,
|
||||
/* EXCEPTION_DATATYPE_MISALIGNMENT */
|
||||
MD_EXCEPTION_CODE_WIN_BREAKPOINT = 0x80000003,
|
||||
/* EXCEPTION_BREAKPOINT */
|
||||
MD_EXCEPTION_CODE_WIN_SINGLE_STEP = 0x80000004,
|
||||
/* EXCEPTION_SINGLE_STEP */
|
||||
MD_EXCEPTION_CODE_WIN_ACCESS_VIOLATION = 0xc0000005,
|
||||
/* EXCEPTION_ACCESS_VIOLATION */
|
||||
MD_EXCEPTION_CODE_WIN_IN_PAGE_ERROR = 0xc0000006,
|
||||
/* EXCEPTION_IN_PAGE_ERROR */
|
||||
MD_EXCEPTION_CODE_WIN_INVALID_HANDLE = 0xc0000008,
|
||||
/* EXCEPTION_INVALID_HANDLE */
|
||||
MD_EXCEPTION_CODE_WIN_ILLEGAL_INSTRUCTION = 0xc000001d,
|
||||
/* EXCEPTION_ILLEGAL_INSTRUCTION */
|
||||
MD_EXCEPTION_CODE_WIN_NONCONTINUABLE_EXCEPTION = 0xc0000025,
|
||||
/* EXCEPTION_NONCONTINUABLE_EXCEPTION */
|
||||
MD_EXCEPTION_CODE_WIN_INVALID_DISPOSITION = 0xc0000026,
|
||||
/* EXCEPTION_INVALID_DISPOSITION */
|
||||
MD_EXCEPTION_CODE_WIN_ARRAY_BOUNDS_EXCEEDED = 0xc000008c,
|
||||
/* EXCEPTION_BOUNDS_EXCEEDED */
|
||||
MD_EXCEPTION_CODE_WIN_FLOAT_DENORMAL_OPERAND = 0xc000008d,
|
||||
/* EXCEPTION_FLT_DENORMAL_OPERAND */
|
||||
MD_EXCEPTION_CODE_WIN_FLOAT_DIVIDE_BY_ZERO = 0xc000008e,
|
||||
/* EXCEPTION_FLT_DIVIDE_BY_ZERO */
|
||||
MD_EXCEPTION_CODE_WIN_FLOAT_INEXACT_RESULT = 0xc000008f,
|
||||
/* EXCEPTION_FLT_INEXACT_RESULT */
|
||||
MD_EXCEPTION_CODE_WIN_FLOAT_INVALID_OPERATION = 0xc0000090,
|
||||
/* EXCEPTION_FLT_INVALID_OPERATION */
|
||||
MD_EXCEPTION_CODE_WIN_FLOAT_OVERFLOW = 0xc0000091,
|
||||
/* EXCEPTION_FLT_OVERFLOW */
|
||||
MD_EXCEPTION_CODE_WIN_FLOAT_STACK_CHECK = 0xc0000092,
|
||||
/* EXCEPTION_FLT_STACK_CHECK */
|
||||
MD_EXCEPTION_CODE_WIN_FLOAT_UNDERFLOW = 0xc0000093,
|
||||
/* EXCEPTION_FLT_UNDERFLOW */
|
||||
MD_EXCEPTION_CODE_WIN_INTEGER_DIVIDE_BY_ZERO = 0xc0000094,
|
||||
/* EXCEPTION_INT_DIVIDE_BY_ZERO */
|
||||
MD_EXCEPTION_CODE_WIN_INTEGER_OVERFLOW = 0xc0000095,
|
||||
/* EXCEPTION_INT_OVERFLOW */
|
||||
MD_EXCEPTION_CODE_WIN_PRIVILEGED_INSTRUCTION = 0xc0000096,
|
||||
/* EXCEPTION_PRIV_INSTRUCTION */
|
||||
MD_EXCEPTION_CODE_WIN_STACK_OVERFLOW = 0xc00000fd,
|
||||
/* EXCEPTION_STACK_OVERFLOW */
|
||||
MD_EXCEPTION_CODE_WIN_POSSIBLE_DEADLOCK = 0xc0000194
|
||||
/* EXCEPTION_POSSIBLE_DEADLOCK */
|
||||
} MDExceptionCodeWin;
|
||||
|
||||
/* For (MDException).exception_code. Breakpad minidump extension for Mac OS X
|
||||
* support. Based on Darwin/Mac OS X' mach/exception_types.h. This is
|
||||
* what Mac OS X calls an "exception", not a "code". */
|
||||
typedef enum {
|
||||
/* Exception code. The high 16 bits of exception_code contains one of
|
||||
* these values. */
|
||||
MD_EXCEPTION_MAC_BAD_ACCESS = 1, /* code can be a kern_return_t */
|
||||
/* EXC_BAD_ACCESS */
|
||||
MD_EXCEPTION_MAC_BAD_INSTRUCTION = 2, /* code is CPU-specific */
|
||||
/* EXC_BAD_INSTRUCTION */
|
||||
MD_EXCEPTION_MAC_ARITHMETIC = 3, /* code is CPU-specific */
|
||||
/* EXC_ARITHMETIC */
|
||||
MD_EXCEPTION_MAC_EMULATION = 4, /* code is CPU-specific */
|
||||
/* EXC_EMULATION */
|
||||
MD_EXCEPTION_MAC_SOFTWARE = 5,
|
||||
/* EXC_SOFTWARE */
|
||||
MD_EXCEPTION_MAC_BREAKPOINT = 6, /* code is CPU-specific */
|
||||
/* EXC_BREAKPOINT */
|
||||
MD_EXCEPTION_MAC_SYSCALL = 7,
|
||||
/* EXC_SYSCALL */
|
||||
MD_EXCEPTION_MAC_MACH_SYSCALL = 8,
|
||||
/* EXC_MACH_SYSCALL */
|
||||
MD_EXCEPTION_MAC_RPC_ALERT = 9
|
||||
/* EXC_RPC_ALERT */
|
||||
} MDExceptionMac;
|
||||
|
||||
/* For (MDException).exception_flags. Breakpad minidump extension for Mac OS X
|
||||
* support. Based on Darwin/Mac OS X' mach/ppc/exception.h and
|
||||
* mach/i386/exception.h. This is what Mac OS X calls a "code". */
|
||||
typedef enum {
|
||||
/* With MD_EXCEPTION_BAD_ACCESS. These are relevant kern_return_t values
|
||||
* from mach/kern_return.h. */
|
||||
MD_EXCEPTION_CODE_MAC_INVALID_ADDRESS = 1,
|
||||
/* KERN_INVALID_ADDRESS */
|
||||
MD_EXCEPTION_CODE_MAC_PROTECTION_FAILURE = 2,
|
||||
/* KERN_PROTECTION_FAILURE */
|
||||
MD_EXCEPTION_CODE_MAC_NO_ACCESS = 8,
|
||||
/* KERN_NO_ACCESS */
|
||||
MD_EXCEPTION_CODE_MAC_MEMORY_FAILURE = 9,
|
||||
/* KERN_MEMORY_FAILURE */
|
||||
MD_EXCEPTION_CODE_MAC_MEMORY_ERROR = 10,
|
||||
/* KERN_MEMORY_ERROR */
|
||||
|
||||
/* With MD_EXCEPTION_SOFTWARE */
|
||||
MD_EXCEPTION_CODE_MAC_BAD_SYSCALL = 0x00010000, /* Mach SIGSYS */
|
||||
MD_EXCEPTION_CODE_MAC_BAD_PIPE = 0x00010001, /* Mach SIGPIPE */
|
||||
MD_EXCEPTION_CODE_MAC_ABORT = 0x00010002, /* Mach SIGABRT */
|
||||
|
||||
/* With MD_EXCEPTION_MAC_BAD_ACCESS on ppc */
|
||||
MD_EXCEPTION_CODE_MAC_PPC_VM_PROT_READ = 0x0101,
|
||||
/* EXC_PPC_VM_PROT_READ */
|
||||
MD_EXCEPTION_CODE_MAC_PPC_BADSPACE = 0x0102,
|
||||
/* EXC_PPC_BADSPACE */
|
||||
MD_EXCEPTION_CODE_MAC_PPC_UNALIGNED = 0x0103,
|
||||
/* EXC_PPC_UNALIGNED */
|
||||
|
||||
/* With MD_EXCEPTION_MAC_BAD_INSTRUCTION on ppc */
|
||||
MD_EXCEPTION_CODE_MAC_PPC_INVALID_SYSCALL = 1,
|
||||
/* EXC_PPC_INVALID_SYSCALL */
|
||||
MD_EXCEPTION_CODE_MAC_PPC_UNIMPLEMENTED_INSTRUCTION = 2,
|
||||
/* EXC_PPC_UNIPL_INST */
|
||||
MD_EXCEPTION_CODE_MAC_PPC_PRIVILEGED_INSTRUCTION = 3,
|
||||
/* EXC_PPC_PRIVINST */
|
||||
MD_EXCEPTION_CODE_MAC_PPC_PRIVILEGED_REGISTER = 4,
|
||||
/* EXC_PPC_PRIVREG */
|
||||
MD_EXCEPTION_CODE_MAC_PPC_TRACE = 5,
|
||||
/* EXC_PPC_TRACE */
|
||||
MD_EXCEPTION_CODE_MAC_PPC_PERFORMANCE_MONITOR = 6,
|
||||
/* EXC_PPC_PERFMON */
|
||||
|
||||
/* With MD_EXCEPTION_MAC_ARITHMETIC on ppc */
|
||||
MD_EXCEPTION_CODE_MAC_PPC_OVERFLOW = 1,
|
||||
/* EXC_PPC_OVERFLOW */
|
||||
MD_EXCEPTION_CODE_MAC_PPC_ZERO_DIVIDE = 2,
|
||||
/* EXC_PPC_ZERO_DIVIDE */
|
||||
MD_EXCEPTION_CODE_MAC_PPC_FLOAT_INEXACT = 3,
|
||||
/* EXC_FLT_INEXACT */
|
||||
MD_EXCEPTION_CODE_MAC_PPC_FLOAT_ZERO_DIVIDE = 4,
|
||||
/* EXC_PPC_FLT_ZERO_DIVIDE */
|
||||
MD_EXCEPTION_CODE_MAC_PPC_FLOAT_UNDERFLOW = 5,
|
||||
/* EXC_PPC_FLT_UNDERFLOW */
|
||||
MD_EXCEPTION_CODE_MAC_PPC_FLOAT_OVERFLOW = 6,
|
||||
/* EXC_PPC_FLT_OVERFLOW */
|
||||
MD_EXCEPTION_CODE_MAC_PPC_FLOAT_NOT_A_NUMBER = 7,
|
||||
/* EXC_PPC_FLT_NOT_A_NUMBER */
|
||||
|
||||
/* With MD_EXCEPTION_MAC_EMULATION on ppc */
|
||||
MD_EXCEPTION_CODE_MAC_PPC_NO_EMULATION = 8,
|
||||
/* EXC_PPC_NOEMULATION */
|
||||
MD_EXCEPTION_CODE_MAC_PPC_ALTIVEC_ASSIST = 9,
|
||||
/* EXC_PPC_ALTIVECASSIST */
|
||||
|
||||
/* With MD_EXCEPTION_MAC_SOFTWARE on ppc */
|
||||
MD_EXCEPTION_CODE_MAC_PPC_TRAP = 0x00000001, /* EXC_PPC_TRAP */
|
||||
MD_EXCEPTION_CODE_MAC_PPC_MIGRATE = 0x00010100, /* EXC_PPC_MIGRATE */
|
||||
|
||||
/* With MD_EXCEPTION_MAC_BREAKPOINT on ppc */
|
||||
MD_EXCEPTION_CODE_MAC_PPC_BREAKPOINT = 1, /* EXC_PPC_BREAKPOINT */
|
||||
|
||||
/* With MD_EXCEPTION_MAC_BAD_INSTRUCTION on x86, see also x86 interrupt
|
||||
* values below. */
|
||||
MD_EXCEPTION_CODE_MAC_X86_INVALID_OPERATION = 1, /* EXC_I386_INVOP */
|
||||
|
||||
/* With MD_EXCEPTION_MAC_ARITHMETIC on x86 */
|
||||
MD_EXCEPTION_CODE_MAC_X86_DIV = 1, /* EXC_I386_DIV */
|
||||
MD_EXCEPTION_CODE_MAC_X86_INTO = 2, /* EXC_I386_INTO */
|
||||
MD_EXCEPTION_CODE_MAC_X86_NOEXT = 3, /* EXC_I386_NOEXT */
|
||||
MD_EXCEPTION_CODE_MAC_X86_EXTOVR = 4, /* EXC_I386_EXTOVR */
|
||||
MD_EXCEPTION_CODE_MAC_X86_EXTERR = 5, /* EXC_I386_EXTERR */
|
||||
MD_EXCEPTION_CODE_MAC_X86_EMERR = 6, /* EXC_I386_EMERR */
|
||||
MD_EXCEPTION_CODE_MAC_X86_BOUND = 7, /* EXC_I386_BOUND */
|
||||
MD_EXCEPTION_CODE_MAC_X86_SSEEXTERR = 8, /* EXC_I386_SSEEXTERR */
|
||||
|
||||
/* With MD_EXCEPTION_MAC_BREAKPOINT on x86 */
|
||||
MD_EXCEPTION_CODE_MAC_X86_SGL = 1, /* EXC_I386_SGL */
|
||||
MD_EXCEPTION_CODE_MAC_X86_BPT = 2, /* EXC_I386_BPT */
|
||||
|
||||
/* With MD_EXCEPTION_MAC_BAD_INSTRUCTION on x86. These are the raw
|
||||
* x86 interrupt codes. Most of these are mapped to other Mach
|
||||
* exceptions and codes, are handled, or should not occur in user space.
|
||||
* A few of these will do occur with MD_EXCEPTION_MAC_BAD_INSTRUCTION. */
|
||||
/* EXC_I386_DIVERR = 0: mapped to EXC_ARITHMETIC/EXC_I386_DIV */
|
||||
/* EXC_I386_SGLSTP = 1: mapped to EXC_BREAKPOINT/EXC_I386_SGL */
|
||||
/* EXC_I386_NMIFLT = 2: should not occur in user space */
|
||||
/* EXC_I386_BPTFLT = 3: mapped to EXC_BREAKPOINT/EXC_I386_BPT */
|
||||
/* EXC_I386_INTOFLT = 4: mapped to EXC_ARITHMETIC/EXC_I386_INTO */
|
||||
/* EXC_I386_BOUNDFLT = 5: mapped to EXC_ARITHMETIC/EXC_I386_BOUND */
|
||||
/* EXC_I386_INVOPFLT = 6: mapped to EXC_BAD_INSTRUCTION/EXC_I386_INVOP */
|
||||
/* EXC_I386_NOEXTFLT = 7: should be handled by the kernel */
|
||||
/* EXC_I386_DBLFLT = 8: should be handled (if possible) by the kernel */
|
||||
/* EXC_I386_EXTOVRFLT = 9: mapped to EXC_BAD_ACCESS/(PROT_READ|PROT_EXEC) */
|
||||
MD_EXCEPTION_CODE_MAC_X86_INVALID_TASK_STATE_SEGMENT = 10,
|
||||
/* EXC_INVTSSFLT */
|
||||
MD_EXCEPTION_CODE_MAC_X86_SEGMENT_NOT_PRESENT = 11,
|
||||
/* EXC_SEGNPFLT */
|
||||
MD_EXCEPTION_CODE_MAC_X86_STACK_FAULT = 12,
|
||||
/* EXC_STKFLT */
|
||||
MD_EXCEPTION_CODE_MAC_X86_GENERAL_PROTECTION_FAULT = 13,
|
||||
/* EXC_GPFLT */
|
||||
/* EXC_I386_PGFLT = 14: should not occur in user space */
|
||||
/* EXC_I386_EXTERRFLT = 16: mapped to EXC_ARITHMETIC/EXC_I386_EXTERR */
|
||||
MD_EXCEPTION_CODE_MAC_X86_ALIGNMENT_FAULT = 17
|
||||
/* EXC_ALIGNFLT (for vector operations) */
|
||||
/* EXC_I386_ENOEXTFLT = 32: should be handled by the kernel */
|
||||
/* EXC_I386_ENDPERR = 33: should not occur */
|
||||
} MDExceptionCodeMac;
|
||||
|
||||
/* For (MDException).exception_code. These values come from bits/signum.h.
|
||||
*/
|
||||
typedef enum {
|
||||
MD_EXCEPTION_CODE_LIN_SIGHUP = 1, /* Hangup (POSIX) */
|
||||
MD_EXCEPTION_CODE_LIN_SIGINT = 2, /* Interrupt (ANSI) */
|
||||
MD_EXCEPTION_CODE_LIN_SIGQUIT = 3, /* Quit (POSIX) */
|
||||
MD_EXCEPTION_CODE_LIN_SIGILL = 4, /* Illegal instruction (ANSI) */
|
||||
MD_EXCEPTION_CODE_LIN_SIGTRAP = 5, /* Trace trap (POSIX) */
|
||||
MD_EXCEPTION_CODE_LIN_SIGABRT = 6, /* Abort (ANSI) */
|
||||
MD_EXCEPTION_CODE_LIN_SIGBUS = 7, /* BUS error (4.2 BSD) */
|
||||
MD_EXCEPTION_CODE_LIN_SIGFPE = 8, /* Floating-point exception (ANSI) */
|
||||
MD_EXCEPTION_CODE_LIN_SIGKILL = 9, /* Kill, unblockable (POSIX) */
|
||||
MD_EXCEPTION_CODE_LIN_SIGUSR1 = 10, /* User-defined signal 1 (POSIX). */
|
||||
MD_EXCEPTION_CODE_LIN_SIGSEGV = 11, /* Segmentation violation (ANSI) */
|
||||
MD_EXCEPTION_CODE_LIN_SIGUSR2 = 12, /* User-defined signal 2 (POSIX) */
|
||||
MD_EXCEPTION_CODE_LIN_SIGPIPE = 13, /* Broken pipe (POSIX) */
|
||||
MD_EXCEPTION_CODE_LIN_SIGALRM = 14, /* Alarm clock (POSIX) */
|
||||
MD_EXCEPTION_CODE_LIN_SIGTERM = 15, /* Termination (ANSI) */
|
||||
MD_EXCEPTION_CODE_LIN_SIGSTKFLT = 16, /* Stack faultd */
|
||||
MD_EXCEPTION_CODE_LIN_SIGCHLD = 17, /* Child status has changed (POSIX) */
|
||||
MD_EXCEPTION_CODE_LIN_SIGCONT = 18, /* Continue (POSIX) */
|
||||
MD_EXCEPTION_CODE_LIN_SIGSTOP = 19, /* Stop, unblockable (POSIX) */
|
||||
MD_EXCEPTION_CODE_LIN_SIGTSTP = 20, /* Keyboard stop (POSIX) */
|
||||
MD_EXCEPTION_CODE_LIN_SIGTTIN = 21, /* Background read from tty (POSIX) */
|
||||
MD_EXCEPTION_CODE_LIN_SIGTTOU = 22, /* Background write to tty (POSIX) */
|
||||
MD_EXCEPTION_CODE_LIN_SIGURG = 23,
|
||||
/* Urgent condition on socket (4.2 BSD) */
|
||||
MD_EXCEPTION_CODE_LIN_SIGXCPU = 24, /* CPU limit exceeded (4.2 BSD) */
|
||||
MD_EXCEPTION_CODE_LIN_SIGXFSZ = 25,
|
||||
/* File size limit exceeded (4.2 BSD) */
|
||||
MD_EXCEPTION_CODE_LIN_SIGVTALRM = 26, /* Virtual alarm clock (4.2 BSD) */
|
||||
MD_EXCEPTION_CODE_LIN_SIGPROF = 27, /* Profiling alarm clock (4.2 BSD) */
|
||||
MD_EXCEPTION_CODE_LIN_SIGWINCH = 28, /* Window size change (4.3 BSD, Sun) */
|
||||
MD_EXCEPTION_CODE_LIN_SIGIO = 29, /* I/O now possible (4.2 BSD) */
|
||||
MD_EXCEPTION_CODE_LIN_SIGPWR = 30, /* Power failure restart (System V) */
|
||||
MD_EXCEPTION_CODE_LIN_SIGSYS = 31 /* Bad system call */
|
||||
} MDExceptionCodeLinux;
|
||||
|
||||
/* For (MDException).exception_code. These values come from sys/iso/signal_iso.h
|
||||
*/
|
||||
typedef enum {
|
||||
MD_EXCEPTION_CODE_SOL_SIGHUP = 1, /* Hangup */
|
||||
MD_EXCEPTION_CODE_SOL_SIGINT = 2, /* interrupt (rubout) */
|
||||
MD_EXCEPTION_CODE_SOL_SIGQUIT = 3, /* quit (ASCII FS) */
|
||||
MD_EXCEPTION_CODE_SOL_SIGILL = 4, /* illegal instruction (not reset when caught) */
|
||||
MD_EXCEPTION_CODE_SOL_SIGTRAP = 5, /* trace trap (not reset when caught) */
|
||||
MD_EXCEPTION_CODE_SOL_SIGIOT = 6, /* IOT instruction */
|
||||
MD_EXCEPTION_CODE_SOL_SIGABRT = 6, /* used by abort, replace SIGIOT in the future */
|
||||
MD_EXCEPTION_CODE_SOL_SIGEMT = 7, /* EMT instruction */
|
||||
MD_EXCEPTION_CODE_SOL_SIGFPE = 8, /* floating point exception */
|
||||
MD_EXCEPTION_CODE_SOL_SIGKILL = 9, /* kill (cannot be caught or ignored) */
|
||||
MD_EXCEPTION_CODE_SOL_SIGBUS = 10, /* bus error */
|
||||
MD_EXCEPTION_CODE_SOL_SIGSEGV = 11, /* segmentation violation */
|
||||
MD_EXCEPTION_CODE_SOL_SIGSYS = 12, /* bad argument to system call */
|
||||
MD_EXCEPTION_CODE_SOL_SIGPIPE = 13, /* write on a pipe with no one to read it */
|
||||
MD_EXCEPTION_CODE_SOL_SIGALRM = 14, /* alarm clock */
|
||||
MD_EXCEPTION_CODE_SOL_SIGTERM = 15, /* software termination signal from kill */
|
||||
MD_EXCEPTION_CODE_SOL_SIGUSR1 = 16, /* user defined signal 1 */
|
||||
MD_EXCEPTION_CODE_SOL_SIGUSR2 = 17, /* user defined signal 2 */
|
||||
MD_EXCEPTION_CODE_SOL_SIGCLD = 18, /* child status change */
|
||||
MD_EXCEPTION_CODE_SOL_SIGCHLD = 18, /* child status change alias (POSIX) */
|
||||
MD_EXCEPTION_CODE_SOL_SIGPWR = 19, /* power-fail restart */
|
||||
MD_EXCEPTION_CODE_SOL_SIGWINCH = 20, /* window size change */
|
||||
MD_EXCEPTION_CODE_SOL_SIGURG = 21, /* urgent socket condition */
|
||||
MD_EXCEPTION_CODE_SOL_SIGPOLL = 22, /* pollable event occured */
|
||||
MD_EXCEPTION_CODE_SOL_SIGIO = 22, /* socket I/O possible (SIGPOLL alias) */
|
||||
MD_EXCEPTION_CODE_SOL_SIGSTOP = 23, /* stop (cannot be caught or ignored) */
|
||||
MD_EXCEPTION_CODE_SOL_SIGTSTP = 24, /* user stop requested from tty */
|
||||
MD_EXCEPTION_CODE_SOL_SIGCONT = 25, /* stopped process has been continued */
|
||||
MD_EXCEPTION_CODE_SOL_SIGTTIN = 26, /* background tty read attempted */
|
||||
MD_EXCEPTION_CODE_SOL_SIGTTOU = 27, /* background tty write attempted */
|
||||
MD_EXCEPTION_CODE_SOL_SIGVTALRM = 28, /* virtual timer expired */
|
||||
MD_EXCEPTION_CODE_SOL_SIGPROF = 29, /* profiling timer expired */
|
||||
MD_EXCEPTION_CODE_SOL_SIGXCPU = 30, /* exceeded cpu limit */
|
||||
MD_EXCEPTION_CODE_SOL_SIGXFSZ = 31, /* exceeded file size limit */
|
||||
MD_EXCEPTION_CODE_SOL_SIGWAITING = 32, /* reserved signal no longer used by threading code */
|
||||
MD_EXCEPTION_CODE_SOL_SIGLWP = 33, /* reserved signal no longer used by threading code */
|
||||
MD_EXCEPTION_CODE_SOL_SIGFREEZE = 34, /* special signal used by CPR */
|
||||
MD_EXCEPTION_CODE_SOL_SIGTHAW = 35, /* special signal used by CPR */
|
||||
MD_EXCEPTION_CODE_SOL_SIGCANCEL = 36, /* reserved signal for thread cancellation */
|
||||
MD_EXCEPTION_CODE_SOL_SIGLOST = 37, /* resource lost (eg, record-lock lost) */
|
||||
MD_EXCEPTION_CODE_SOL_SIGXRES = 38, /* resource control exceeded */
|
||||
MD_EXCEPTION_CODE_SOL_SIGJVM1 = 39, /* reserved signal for Java Virtual Machine */
|
||||
MD_EXCEPTION_CODE_SOL_SIGJVM2 = 40 /* reserved signal for Java Virtual Machine */
|
||||
} MDExceptionCodeSolaris;
|
||||
#include "minidump_exception_win32.h"
|
||||
#include "minidump_exception_mac.h"
|
||||
#include "minidump_exception_linux.h"
|
||||
#include "minidump_exception_solaris.h"
|
||||
|
||||
typedef struct {
|
||||
u_int32_t thread_id; /* Thread in which the exception
|
||||
|
|
|
@ -79,6 +79,7 @@
|
|||
#ifndef GOOGLE_BREAKPAD_PROCESSOR_MINIDUMP_H__
|
||||
#define GOOGLE_BREAKPAD_PROCESSOR_MINIDUMP_H__
|
||||
|
||||
#include <unistd.h>
|
||||
|
||||
#include <map>
|
||||
#include <string>
|
||||
|
|
|
@ -128,9 +128,9 @@ struct StackFrameSPARC : public StackFrame {
|
|||
// to be confirmed
|
||||
enum ContextValidity {
|
||||
CONTEXT_VALID_NONE = 0,
|
||||
CONTEXT_VALID_PC = 0 << 0,
|
||||
CONTEXT_VALID_SP = 0 << 1,
|
||||
CONTEXT_VALID_FP = 0 << 2,
|
||||
CONTEXT_VALID_PC = 1 << 0,
|
||||
CONTEXT_VALID_SP = 1 << 1,
|
||||
CONTEXT_VALID_FP = 1 << 2,
|
||||
CONTEXT_VALID_ALL = -1
|
||||
};
|
||||
|
||||
|
|
|
@ -80,7 +80,7 @@ std::string HexString(u_int32_t number) {
|
|||
|
||||
std::string HexString(u_int64_t number) {
|
||||
char buffer[19];
|
||||
snprintf(buffer, sizeof(buffer), "0x%llx", number);
|
||||
snprintf(buffer, sizeof(buffer), "0x%" PRIx64, number);
|
||||
return std::string(buffer);
|
||||
}
|
||||
|
||||
|
|
|
@ -850,7 +850,7 @@ void MinidumpContext::Print() {
|
|||
for (unsigned int fpr_index = 0;
|
||||
fpr_index < MD_FLOATINGSAVEAREA_PPC_FPR_COUNT;
|
||||
++fpr_index) {
|
||||
printf(" float_save.fpregs[%2d] = 0x%llx\n",
|
||||
printf(" float_save.fpregs[%2d] = 0x%" PRIx64 "\n",
|
||||
fpr_index, context_ppc->float_save.fpregs[fpr_index]);
|
||||
}
|
||||
printf(" float_save.fpscr = 0x%x\n",
|
||||
|
@ -858,7 +858,7 @@ void MinidumpContext::Print() {
|
|||
// TODO(mmentovai): print the 128-bit quantities in
|
||||
// context_ppc->vector_save. This isn't done yet because printf
|
||||
// doesn't support 128-bit quantities, and printing them using
|
||||
// %llx as two 64-bit quantities requires knowledge of the CPU's
|
||||
// PRIx64 as two 64-bit quantities requires knowledge of the CPU's
|
||||
// byte ordering.
|
||||
printf(" vector_save.save_vrvalid = 0x%x\n",
|
||||
context_ppc->vector_save.save_vrvalid);
|
||||
|
@ -870,17 +870,17 @@ void MinidumpContext::Print() {
|
|||
case MD_CONTEXT_AMD64: {
|
||||
const MDRawContextAMD64* context_amd64 = GetContextAMD64();
|
||||
printf("MDRawContextAMD64\n");
|
||||
printf(" p1_home = 0x%llx\n",
|
||||
printf(" p1_home = 0x%" PRIx64 "\n",
|
||||
context_amd64->p1_home);
|
||||
printf(" p2_home = 0x%llx\n",
|
||||
printf(" p2_home = 0x%" PRIx64 "\n",
|
||||
context_amd64->p2_home);
|
||||
printf(" p3_home = 0x%llx\n",
|
||||
printf(" p3_home = 0x%" PRIx64 "\n",
|
||||
context_amd64->p3_home);
|
||||
printf(" p4_home = 0x%llx\n",
|
||||
printf(" p4_home = 0x%" PRIx64 "\n",
|
||||
context_amd64->p4_home);
|
||||
printf(" p5_home = 0x%llx\n",
|
||||
printf(" p5_home = 0x%" PRIx64 "\n",
|
||||
context_amd64->p5_home);
|
||||
printf(" p6_home = 0x%llx\n",
|
||||
printf(" p6_home = 0x%" PRIx64 "\n",
|
||||
context_amd64->p6_home);
|
||||
printf(" context_flags = 0x%x\n",
|
||||
context_amd64->context_flags);
|
||||
|
@ -893,29 +893,29 @@ void MinidumpContext::Print() {
|
|||
printf(" gs = 0x%x\n", context_amd64->gs);
|
||||
printf(" ss = 0x%x\n", context_amd64->ss);
|
||||
printf(" eflags = 0x%x\n", context_amd64->eflags);
|
||||
printf(" dr0 = 0x%llx\n", context_amd64->dr0);
|
||||
printf(" dr1 = 0x%llx\n", context_amd64->dr1);
|
||||
printf(" dr2 = 0x%llx\n", context_amd64->dr2);
|
||||
printf(" dr3 = 0x%llx\n", context_amd64->dr3);
|
||||
printf(" dr6 = 0x%llx\n", context_amd64->dr6);
|
||||
printf(" dr7 = 0x%llx\n", context_amd64->dr7);
|
||||
printf(" rax = 0x%llx\n", context_amd64->rax);
|
||||
printf(" rcx = 0x%llx\n", context_amd64->rcx);
|
||||
printf(" rdx = 0x%llx\n", context_amd64->rdx);
|
||||
printf(" rbx = 0x%llx\n", context_amd64->rbx);
|
||||
printf(" rsp = 0x%llx\n", context_amd64->rsp);
|
||||
printf(" rbp = 0x%llx\n", context_amd64->rbp);
|
||||
printf(" rsi = 0x%llx\n", context_amd64->rsi);
|
||||
printf(" rdi = 0x%llx\n", context_amd64->rdi);
|
||||
printf(" r8 = 0x%llx\n", context_amd64->r8);
|
||||
printf(" r9 = 0x%llx\n", context_amd64->r9);
|
||||
printf(" r10 = 0x%llx\n", context_amd64->r10);
|
||||
printf(" r11 = 0x%llx\n", context_amd64->r11);
|
||||
printf(" r12 = 0x%llx\n", context_amd64->r12);
|
||||
printf(" r13 = 0x%llx\n", context_amd64->r13);
|
||||
printf(" r14 = 0x%llx\n", context_amd64->r14);
|
||||
printf(" r15 = 0x%llx\n", context_amd64->r15);
|
||||
printf(" rip = 0x%llx\n", context_amd64->rip);
|
||||
printf(" dr0 = 0x%" PRIx64 "\n", context_amd64->dr0);
|
||||
printf(" dr1 = 0x%" PRIx64 "\n", context_amd64->dr1);
|
||||
printf(" dr2 = 0x%" PRIx64 "\n", context_amd64->dr2);
|
||||
printf(" dr3 = 0x%" PRIx64 "\n", context_amd64->dr3);
|
||||
printf(" dr6 = 0x%" PRIx64 "\n", context_amd64->dr6);
|
||||
printf(" dr7 = 0x%" PRIx64 "\n", context_amd64->dr7);
|
||||
printf(" rax = 0x%" PRIx64 "\n", context_amd64->rax);
|
||||
printf(" rcx = 0x%" PRIx64 "\n", context_amd64->rcx);
|
||||
printf(" rdx = 0x%" PRIx64 "\n", context_amd64->rdx);
|
||||
printf(" rbx = 0x%" PRIx64 "\n", context_amd64->rbx);
|
||||
printf(" rsp = 0x%" PRIx64 "\n", context_amd64->rsp);
|
||||
printf(" rbp = 0x%" PRIx64 "\n", context_amd64->rbp);
|
||||
printf(" rsi = 0x%" PRIx64 "\n", context_amd64->rsi);
|
||||
printf(" rdi = 0x%" PRIx64 "\n", context_amd64->rdi);
|
||||
printf(" r8 = 0x%" PRIx64 "\n", context_amd64->r8);
|
||||
printf(" r9 = 0x%" PRIx64 "\n", context_amd64->r9);
|
||||
printf(" r10 = 0x%" PRIx64 "\n", context_amd64->r10);
|
||||
printf(" r11 = 0x%" PRIx64 "\n", context_amd64->r11);
|
||||
printf(" r12 = 0x%" PRIx64 "\n", context_amd64->r12);
|
||||
printf(" r13 = 0x%" PRIx64 "\n", context_amd64->r13);
|
||||
printf(" r14 = 0x%" PRIx64 "\n", context_amd64->r14);
|
||||
printf(" r15 = 0x%" PRIx64 "\n", context_amd64->r15);
|
||||
printf(" rip = 0x%" PRIx64 "\n", context_amd64->rip);
|
||||
//TODO: print xmm, vector, debug registers
|
||||
printf("\n");
|
||||
break;
|
||||
|
@ -929,25 +929,25 @@ void MinidumpContext::Print() {
|
|||
for (unsigned int g_r_index = 0;
|
||||
g_r_index < MD_CONTEXT_SPARC_GPR_COUNT;
|
||||
++g_r_index) {
|
||||
printf(" g_r[%2d] = 0x%llx\n",
|
||||
printf(" g_r[%2d] = 0x%" PRIx64 "\n",
|
||||
g_r_index, context_sparc->g_r[g_r_index]);
|
||||
}
|
||||
printf(" ccr = 0x%llx\n", context_sparc->ccr);
|
||||
printf(" pc = 0x%llx\n", context_sparc->pc);
|
||||
printf(" npc = 0x%llx\n", context_sparc->npc);
|
||||
printf(" y = 0x%llx\n", context_sparc->y);
|
||||
printf(" asi = 0x%llx\n", context_sparc->asi);
|
||||
printf(" fprs = 0x%llx\n", context_sparc->fprs);
|
||||
printf(" ccr = 0x%" PRIx64 "\n", context_sparc->ccr);
|
||||
printf(" pc = 0x%" PRIx64 "\n", context_sparc->pc);
|
||||
printf(" npc = 0x%" PRIx64 "\n", context_sparc->npc);
|
||||
printf(" y = 0x%" PRIx64 "\n", context_sparc->y);
|
||||
printf(" asi = 0x%" PRIx64 "\n", context_sparc->asi);
|
||||
printf(" fprs = 0x%" PRIx64 "\n", context_sparc->fprs);
|
||||
|
||||
for (unsigned int fpr_index = 0;
|
||||
fpr_index < MD_FLOATINGSAVEAREA_SPARC_FPR_COUNT;
|
||||
++fpr_index) {
|
||||
printf(" float_save.regs[%2d] = 0x%llx\n",
|
||||
printf(" float_save.regs[%2d] = 0x%" PRIx64 "\n",
|
||||
fpr_index, context_sparc->float_save.regs[fpr_index]);
|
||||
}
|
||||
printf(" float_save.filler = 0x%llx\n",
|
||||
printf(" float_save.filler = 0x%" PRIx64 "\n",
|
||||
context_sparc->float_save.filler);
|
||||
printf(" float_save.fsr = 0x%llx\n",
|
||||
printf(" float_save.fsr = 0x%" PRIx64 "\n",
|
||||
context_sparc->float_save.fsr);
|
||||
break;
|
||||
}
|
||||
|
@ -1265,8 +1265,8 @@ void MinidumpThread::Print() {
|
|||
printf(" suspend_count = %d\n", thread_.suspend_count);
|
||||
printf(" priority_class = 0x%x\n", thread_.priority_class);
|
||||
printf(" priority = 0x%x\n", thread_.priority);
|
||||
printf(" teb = 0x%llx\n", thread_.teb);
|
||||
printf(" stack.start_of_memory_range = 0x%llx\n",
|
||||
printf(" teb = 0x%" PRIx64 "\n", thread_.teb);
|
||||
printf(" stack.start_of_memory_range = 0x%" PRIx64 "\n",
|
||||
thread_.stack.start_of_memory_range);
|
||||
printf(" stack.memory.data_size = 0x%x\n",
|
||||
thread_.stack.memory.data_size);
|
||||
|
@ -2050,7 +2050,7 @@ void MinidumpModule::Print() {
|
|||
}
|
||||
|
||||
printf("MDRawModule\n");
|
||||
printf(" base_of_image = 0x%llx\n",
|
||||
printf(" base_of_image = 0x%" PRIx64 "\n",
|
||||
module_.base_of_image);
|
||||
printf(" size_of_image = 0x%x\n",
|
||||
module_.size_of_image);
|
||||
|
@ -2602,7 +2602,7 @@ void MinidumpMemoryList::Print() {
|
|||
MDMemoryDescriptor* descriptor = &(*descriptors_)[region_index];
|
||||
printf("region[%d]\n", region_index);
|
||||
printf("MDMemoryDescriptor\n");
|
||||
printf(" start_of_memory_range = 0x%llx\n",
|
||||
printf(" start_of_memory_range = 0x%" PRIx64 "\n",
|
||||
descriptor->start_of_memory_range);
|
||||
printf(" memory.data_size = 0x%x\n", descriptor->memory.data_size);
|
||||
printf(" memory.rva = 0x%x\n", descriptor->memory.rva);
|
||||
|
@ -2732,16 +2732,16 @@ void MinidumpException::Print() {
|
|||
exception_.exception_record.exception_code);
|
||||
printf(" exception_record.exception_flags = 0x%x\n",
|
||||
exception_.exception_record.exception_flags);
|
||||
printf(" exception_record.exception_record = 0x%llx\n",
|
||||
printf(" exception_record.exception_record = 0x%" PRIx64 "\n",
|
||||
exception_.exception_record.exception_record);
|
||||
printf(" exception_record.exception_address = 0x%llx\n",
|
||||
printf(" exception_record.exception_address = 0x%" PRIx64 "\n",
|
||||
exception_.exception_record.exception_address);
|
||||
printf(" exception_record.number_parameters = %d\n",
|
||||
exception_.exception_record.number_parameters);
|
||||
for (unsigned int parameterIndex = 0;
|
||||
parameterIndex < exception_.exception_record.number_parameters;
|
||||
++parameterIndex) {
|
||||
printf(" exception_record.exception_information[%2d] = 0x%llx\n",
|
||||
printf(" exception_record.exception_information[%2d] = 0x%" PRIx64 "\n",
|
||||
parameterIndex,
|
||||
exception_.exception_record.exception_information[parameterIndex]);
|
||||
}
|
||||
|
@ -2885,6 +2885,10 @@ string MinidumpSystemInfo::GetCPU() {
|
|||
cpu = "ppc";
|
||||
break;
|
||||
|
||||
case MD_CPU_ARCHITECTURE_SPARC:
|
||||
cpu = "sparc";
|
||||
break;
|
||||
|
||||
default:
|
||||
BPLOG(ERROR) << "MinidumpSystemInfo unknown CPU for architecture " <<
|
||||
HexString(system_info_.processor_architecture);
|
||||
|
@ -3439,7 +3443,7 @@ void Minidump::Print() {
|
|||
strftime(timestr, 20, "%Y-%m-%d %H:%M:%S", ×truct);
|
||||
printf(" time_date_stamp = 0x%x %s\n", header_.time_date_stamp,
|
||||
timestr);
|
||||
printf(" flags = 0x%llx\n", header_.flags);
|
||||
printf(" flags = 0x%" PRIx64 "\n", header_.flags);
|
||||
printf("\n");
|
||||
|
||||
for (unsigned int stream_index = 0;
|
||||
|
|
|
@ -121,18 +121,19 @@ static void PrintStack(const CallStack *stack, const string &cpu) {
|
|||
printf("!%s", frame->function_name.c_str());
|
||||
if (!frame->source_file_name.empty()) {
|
||||
string source_file = PathnameStripper::File(frame->source_file_name);
|
||||
printf(" [%s : %d + 0x%llx]", source_file.c_str(),
|
||||
frame->source_line,
|
||||
frame->instruction -
|
||||
frame->source_line_base);
|
||||
printf(" [%s : %d + 0x%" PRIx64 "]",
|
||||
source_file.c_str(),
|
||||
frame->source_line,
|
||||
frame->instruction - frame->source_line_base);
|
||||
} else {
|
||||
printf(" + 0x%llx", frame->instruction - frame->function_base);
|
||||
printf(" + 0x%" PRIx64, frame->instruction - frame->function_base);
|
||||
}
|
||||
} else {
|
||||
printf(" + 0x%llx", frame->instruction - frame->module->base_address());
|
||||
printf(" + 0x%" PRIx64,
|
||||
frame->instruction - frame->module->base_address());
|
||||
}
|
||||
} else {
|
||||
printf("0x%llx", frame->instruction);
|
||||
printf("0x%" PRIx64, frame->instruction);
|
||||
}
|
||||
|
||||
int sequence = 0;
|
||||
|
@ -213,35 +214,36 @@ static void PrintStackMachineReadable(int thread_num, const CallStack *stack) {
|
|||
printf("%c%s", kOutputSeparator,
|
||||
StripSeparator(frame->function_name).c_str());
|
||||
if (!frame->source_file_name.empty()) {
|
||||
printf("%c%s%c%d%c0x%llx", kOutputSeparator,
|
||||
StripSeparator(frame->source_file_name)
|
||||
.c_str(),
|
||||
kOutputSeparator,
|
||||
frame->source_line,
|
||||
kOutputSeparator,
|
||||
frame->instruction -
|
||||
frame->source_line_base);
|
||||
printf("%c%s%c%d%c0x%" PRIx64,
|
||||
kOutputSeparator,
|
||||
StripSeparator(frame->source_file_name).c_str(),
|
||||
kOutputSeparator,
|
||||
frame->source_line,
|
||||
kOutputSeparator,
|
||||
frame->instruction - frame->source_line_base);
|
||||
} else {
|
||||
printf("%c%c%c0x%llx", kOutputSeparator, // empty source file
|
||||
kOutputSeparator, // empty source line
|
||||
kOutputSeparator,
|
||||
frame->instruction - frame->function_base);
|
||||
printf("%c%c%c0x%" PRIx64,
|
||||
kOutputSeparator, // empty source file
|
||||
kOutputSeparator, // empty source line
|
||||
kOutputSeparator,
|
||||
frame->instruction - frame->function_base);
|
||||
}
|
||||
} else {
|
||||
printf("%c%c%c%c0x%llx", kOutputSeparator, // empty function name
|
||||
kOutputSeparator, // empty source file
|
||||
kOutputSeparator, // empty source line
|
||||
kOutputSeparator,
|
||||
frame->instruction -
|
||||
frame->module->base_address());
|
||||
printf("%c%c%c%c0x%" PRIx64,
|
||||
kOutputSeparator, // empty function name
|
||||
kOutputSeparator, // empty source file
|
||||
kOutputSeparator, // empty source line
|
||||
kOutputSeparator,
|
||||
frame->instruction - frame->module->base_address());
|
||||
}
|
||||
} else {
|
||||
// the printf before this prints a trailing separator for module name
|
||||
printf("%c%c%c%c0x%llx", kOutputSeparator, // empty function name
|
||||
kOutputSeparator, // empty source file
|
||||
kOutputSeparator, // empty source line
|
||||
kOutputSeparator,
|
||||
frame->instruction);
|
||||
printf("%c%c%c%c0x%" PRIx64,
|
||||
kOutputSeparator, // empty function name
|
||||
kOutputSeparator, // empty source file
|
||||
kOutputSeparator, // empty source line
|
||||
kOutputSeparator,
|
||||
frame->instruction);
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
|
@ -266,7 +268,7 @@ static void PrintModules(const CodeModules *modules) {
|
|||
++module_sequence) {
|
||||
const CodeModule *module = modules->GetModuleAtSequence(module_sequence);
|
||||
u_int64_t base_address = module->base_address();
|
||||
printf("0x%08llx - 0x%08llx %s %s%s\n",
|
||||
printf("0x%08" PRIx64 " - 0x%08" PRIx64 " %s %s%s\n",
|
||||
base_address, base_address + module->size() - 1,
|
||||
PathnameStripper::File(module->code_file()).c_str(),
|
||||
module->version().empty() ? "???" : module->version().c_str(),
|
||||
|
@ -296,7 +298,7 @@ static void PrintModulesMachineReadable(const CodeModules *modules) {
|
|||
++module_sequence) {
|
||||
const CodeModule *module = modules->GetModuleAtSequence(module_sequence);
|
||||
u_int64_t base_address = module->base_address();
|
||||
printf("Module%c%s%c%s%c%s%c%s%c0x%08llx%c0x%08llx%c%d\n",
|
||||
printf("Module%c%s%c%s%c%s%c%s%c0x%08" PRIx64 "%c0x%08" PRIx64 "%c%d\n",
|
||||
kOutputSeparator,
|
||||
StripSeparator(PathnameStripper::File(module->code_file())).c_str(),
|
||||
kOutputSeparator, StripSeparator(module->version()).c_str(),
|
||||
|
@ -331,7 +333,7 @@ static void PrintProcessState(const ProcessState& process_state) {
|
|||
// Print crash information.
|
||||
if (process_state.crashed()) {
|
||||
printf("Crash reason: %s\n", process_state.crash_reason().c_str());
|
||||
printf("Crash address: 0x%llx\n", process_state.crash_address());
|
||||
printf("Crash address: 0x%" PRIx64 "\n", process_state.crash_address());
|
||||
} else {
|
||||
printf("No crash\n");
|
||||
}
|
||||
|
@ -384,7 +386,7 @@ static void PrintProcessStateMachineReadable(const ProcessState& process_state)
|
|||
// Crash|{Crash Reason}|{Crash Address}|{Crashed Thread}
|
||||
printf("Crash%c", kOutputSeparator);
|
||||
if (process_state.crashed()) {
|
||||
printf("%s%c0x%llx%c",
|
||||
printf("%s%c0x%" PRIx64 "%c",
|
||||
StripSeparator(process_state.crash_reason()).c_str(),
|
||||
kOutputSeparator, process_state.crash_address(), kOutputSeparator);
|
||||
} else {
|
||||
|
|
|
@ -345,7 +345,7 @@ static unsigned int CountCallerFrames() {
|
|||
frame_index < stack.frames()->size();
|
||||
++frame_index) {
|
||||
StackFrame *frame = stack.frames()->at(frame_index);
|
||||
printf("frame %-3d instruction = 0x%08llx",
|
||||
printf("frame %-3d instruction = 0x%08" PRIx64,
|
||||
frame_index, frame->instruction);
|
||||
#if defined(__i386__)
|
||||
StackFrameX86 *frame_x86 = reinterpret_cast<StackFrameX86*>(frame);
|
||||
|
|
Загрузка…
Ссылка в новой задаче