diff options
author | ted.mielczarek <ted.mielczarek@4c0a9323-5329-0410-9bdc-e9ce6186880e> | 2008-03-18 16:10:10 +0000 |
---|---|---|
committer | ted.mielczarek <ted.mielczarek@4c0a9323-5329-0410-9bdc-e9ce6186880e> | 2008-03-18 16:10:10 +0000 |
commit | dd2ff4a21c57672170eb14ccc5142efd7d92f3f1 (patch) | |
tree | 0d8ced3d3cd41773a89aae46a9b269ebd29935a1 /src/client/solaris/handler/minidump_generator.cc | |
parent | Issue 245: refactoring minidump_format.h into architecture & platform specifi... (diff) | |
download | breakpad-dd2ff4a21c57672170eb14ccc5142efd7d92f3f1.tar.xz |
issue 223 - Fixes for SOlaris handler during integration with Firefox. patch by Alfred Peng, r=mento,me
git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@250 4c0a9323-5329-0410-9bdc-e9ce6186880e
Diffstat (limited to 'src/client/solaris/handler/minidump_generator.cc')
-rw-r--r-- | src/client/solaris/handler/minidump_generator.cc | 488 |
1 files changed, 361 insertions, 127 deletions
diff --git a/src/client/solaris/handler/minidump_generator.cc b/src/client/solaris/handler/minidump_generator.cc index 25e7982f..ea046cff 100644 --- a/src/client/solaris/handler/minidump_generator.cc +++ b/src/client/solaris/handler/minidump_generator.cc @@ -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 { + +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; -MinidumpGenerator::MinidumpGenerator() - : requester_pid_(0), - signo_(0), - lwp_lister_(NULL) { + 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) { +// 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 + 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; - prgregset_t *gregs = &(lsp->pr_reg); - UntypedMDRVA memory(&writer_); + const prgregset_t *gregs = &(lsp->pr_reg); + UntypedMDRVA memory(minidump_writer); #if TARGET_CPU_SPARC - if (!WriteLwpStack((*gregs)[R_SP], + 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_; }; +// Prototype of writer functions. +typedef bool (*WriteStreamFN)(MinidumpFileWriter *, + const WriterArgument *, + MDRawDirectory *); + +// 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() { - // Function table to writer a full minidump. - const WriteStreamFN writers[] = { - &MinidumpGenerator::WriteLwpListStream, - &MinidumpGenerator::WriteModuleListStream, - &MinidumpGenerator::WriteSystemInfoStream, - &MinidumpGenerator::WriteExceptionStream, - &MinidumpGenerator::WriteMiscInfoStream, - &MinidumpGenerator::WriteBreakpadInfoStream, - }; - - if (!lwp_lister_->ControlAllLwps(true)) +//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); + + 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; + } - TypedMDRVA<MDRawHeader> header(&writer_); - TypedMDRVA<MDRawDirectory> dir(&writer_); + 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; |