mirror of
https://github.com/yuzu-emu/breakpad.git
synced 2025-02-02 20:01:04 +00:00
Issue 181: Add version info for Mac OS X modules. Found by iterating over load commands until I found LC_ID_DYLIB. Also modified crash_report to generate version number. Also added suspend/resume capability to exception handler, necessary because exception handling can behave strangely across fork() calls. Also added fix for filtering out functions with no line number information, and for filtering out some multiple inheritance glue the compiler generates.
git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@291 4c0a9323-5329-0410-9bdc-e9ce6186880e
This commit is contained in:
parent
c5f46b2f4b
commit
32441cc060
|
@ -187,7 +187,7 @@ void* ReadTaskMemory(task_port_t target_task,
|
|||
|
||||
//==============================================================================
|
||||
// Initializes vmaddr_, vmsize_, and slide_
|
||||
void DynamicImage::CalculateMemoryInfo() {
|
||||
void DynamicImage::CalculateMemoryAndVersionInfo() {
|
||||
breakpad_mach_header *header = GetMachHeader();
|
||||
|
||||
// unless we can process the header, ensure that calls to
|
||||
|
@ -195,6 +195,10 @@ void DynamicImage::CalculateMemoryInfo() {
|
|||
vmaddr_ = 0;
|
||||
vmsize_ = 0;
|
||||
slide_ = 0;
|
||||
version_ = 0;
|
||||
|
||||
bool foundTextSection = false;
|
||||
bool foundDylibIDCommand = false;
|
||||
|
||||
#if __LP64__
|
||||
if(header->magic != MH_MAGIC_64) {
|
||||
|
@ -206,15 +210,18 @@ void DynamicImage::CalculateMemoryInfo() {
|
|||
}
|
||||
#endif
|
||||
|
||||
#ifdef __LP64__
|
||||
const uint32_t segmentLoadCommand = LC_SEGMENT_64;
|
||||
#else
|
||||
const uint32_t segmentLoadCommand = LC_SEGMENT;
|
||||
#endif
|
||||
|
||||
const struct load_command *cmd =
|
||||
reinterpret_cast<const struct load_command *>(header + 1);
|
||||
|
||||
for (unsigned int i = 0; cmd && (i < header->ncmds); ++i) {
|
||||
#ifdef __LP64__
|
||||
if (cmd->cmd == LC_SEGMENT_64) {
|
||||
#else
|
||||
if (cmd->cmd == LC_SEGMENT) {
|
||||
#endif
|
||||
if (!foundTextSection) {
|
||||
if (cmd->cmd == segmentLoadCommand) {
|
||||
const breakpad_mach_segment_command *seg =
|
||||
reinterpret_cast<const breakpad_mach_segment_command *>(cmd);
|
||||
|
||||
|
@ -226,9 +233,24 @@ void DynamicImage::CalculateMemoryInfo() {
|
|||
if (seg->fileoff == 0 && seg->filesize != 0) {
|
||||
slide_ = (uintptr_t)GetLoadAddress() - (uintptr_t)seg->vmaddr;
|
||||
}
|
||||
return;
|
||||
foundTextSection = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!foundDylibIDCommand) {
|
||||
if (cmd->cmd == LC_ID_DYLIB) {
|
||||
const struct dylib_command *dc =
|
||||
reinterpret_cast<const struct dylib_command *>(cmd);
|
||||
|
||||
version_ = dc->dylib.current_version;
|
||||
foundDylibIDCommand = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (foundDylibIDCommand && foundTextSection) {
|
||||
return;
|
||||
}
|
||||
|
||||
cmd = reinterpret_cast<const struct load_command *>
|
||||
(reinterpret_cast<const char *>(cmd) + cmd->cmdsize);
|
||||
|
|
|
@ -114,7 +114,7 @@ class DynamicImage {
|
|||
file_mod_date_(image_mod_date),
|
||||
task_(task) {
|
||||
InitializeFilePath(inFilePath);
|
||||
CalculateMemoryInfo();
|
||||
CalculateMemoryAndVersionInfo();
|
||||
}
|
||||
|
||||
~DynamicImage() {
|
||||
|
@ -150,6 +150,7 @@ class DynamicImage {
|
|||
// Task owning this loaded image
|
||||
mach_port_t GetTask() {return task_;}
|
||||
|
||||
uint32_t GetVersion() {return version_;}
|
||||
// For sorting
|
||||
bool operator<(const DynamicImage &inInfo) {
|
||||
return GetLoadAddress() < inInfo.GetLoadAddress();
|
||||
|
@ -176,29 +177,7 @@ class DynamicImage {
|
|||
}
|
||||
|
||||
// Initializes vmaddr_, vmsize_, and slide_
|
||||
void CalculateMemoryInfo();
|
||||
|
||||
#if 0 // currently not needed
|
||||
// Copy constructor: we don't want this to be invoked,
|
||||
// but here's the code in case we need to make it public some day.
|
||||
DynamicImage(DynamicImage &inInfo)
|
||||
: load_address_(inInfo.load_address_),
|
||||
vmaddr_(inInfo.vmaddr_),
|
||||
vmsize_(inInfo.vmsize_),
|
||||
slide_(inInfo.slide_),
|
||||
file_mod_date_(inInfo.file_mod_date_),
|
||||
task_(inInfo.task_) {
|
||||
// copy file path string
|
||||
InitializeFilePath(inInfo.GetFilePath());
|
||||
|
||||
// copy mach_header and load commands
|
||||
void *headerBuffer = malloc(inInfo.header_size_);
|
||||
header_ = reinterpret_cast<breakpad_mach_header*>(headerBuffer);
|
||||
|
||||
memcpy(header_, inInfo.header_, inInfo.header_size_);
|
||||
header_size_ = inInfo.header_size_;
|
||||
}
|
||||
#endif
|
||||
void CalculateMemoryAndVersionInfo();
|
||||
|
||||
breakpad_mach_header *header_; // our local copy of the header
|
||||
int header_size_; // mach_header plus load commands
|
||||
|
@ -206,7 +185,7 @@ class DynamicImage {
|
|||
mach_vm_address_t vmaddr_;
|
||||
mach_vm_size_t vmsize_;
|
||||
ptrdiff_t slide_;
|
||||
|
||||
uint32_t version_; // Dylib version
|
||||
char *file_path_; // path dyld used to load the image
|
||||
uintptr_t file_mod_date_; // time_t of image file
|
||||
|
||||
|
|
|
@ -221,7 +221,7 @@ ExceptionHandler::ExceptionHandler(const string &dump_path,
|
|||
callback_context_(callback_context),
|
||||
directCallback_(NULL),
|
||||
handler_thread_(NULL),
|
||||
handler_port_(0),
|
||||
handler_port_(MACH_PORT_NULL),
|
||||
previous_(NULL),
|
||||
installed_exception_handler_(false),
|
||||
is_in_teardown_(false),
|
||||
|
@ -244,7 +244,7 @@ ExceptionHandler::ExceptionHandler(DirectCallback callback,
|
|||
callback_context_(callback_context),
|
||||
directCallback_(callback),
|
||||
handler_thread_(NULL),
|
||||
handler_port_(0),
|
||||
handler_port_(MACH_PORT_NULL),
|
||||
previous_(NULL),
|
||||
installed_exception_handler_(false),
|
||||
is_in_teardown_(false),
|
||||
|
@ -600,6 +600,36 @@ bool ExceptionHandler::UninstallHandler(bool in_exception) {
|
|||
return result == KERN_SUCCESS;
|
||||
}
|
||||
|
||||
bool ExceptionHandler::SuspendExceptionHandling() {
|
||||
if (!installed_exception_handler_) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return UninstallHandler(false);
|
||||
}
|
||||
|
||||
|
||||
bool ExceptionHandler::ResumeExceptionHandling() {
|
||||
|
||||
if (installed_exception_handler_) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// This conditional means that Setup() has never been
|
||||
// called, but since it's called from the constructor
|
||||
// we should never hit this.
|
||||
assert(handler_port_);
|
||||
if (handler_port_ == MACH_PORT_NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return InstallHandler();
|
||||
}
|
||||
|
||||
bool ExceptionHandler::ExceptionHandlerIsSuspended() {
|
||||
return handler_port_ != MACH_PORT_NULL && !installed_exception_handler_;
|
||||
}
|
||||
|
||||
bool ExceptionHandler::Setup(bool install_handler) {
|
||||
if (pthread_mutex_init(&minidump_write_mutex_, NULL))
|
||||
return false;
|
||||
|
|
|
@ -114,6 +114,21 @@ class ExceptionHandler {
|
|||
static bool WriteMinidump(const string &dump_path, MinidumpCallback callback,
|
||||
void *callback_context);
|
||||
|
||||
// Temporarily stop this class from receiving exceptions
|
||||
// Returns true if exception handling was successfully suspended
|
||||
// It's an error to call this function if exception handling is
|
||||
// not installed(we return false)
|
||||
bool SuspendExceptionHandling();
|
||||
|
||||
// Resume this class from receiving exceptions
|
||||
// Returns true if exception handling was successfully resumed
|
||||
// It's an error to call this function if exception handling is
|
||||
// already installed
|
||||
bool ResumeExceptionHandling();
|
||||
|
||||
// Tell caller whether we're setup to handle exceptions or not
|
||||
bool ExceptionHandlerIsSuspended();
|
||||
|
||||
private:
|
||||
// Install the mach exception handler
|
||||
bool InstallHandler();
|
||||
|
|
|
@ -680,6 +680,26 @@ bool MinidumpGenerator::WriteModuleStream(unsigned int index,
|
|||
module->size_of_image = image->GetVMSize();
|
||||
module->module_name_rva = string_location.rva;
|
||||
|
||||
// We'll skip the executable module, because they don't have
|
||||
// LC_ID_DYLIB load commands, and the crash processing server gets
|
||||
// version information from the Plist file, anyway.
|
||||
if (index != (uint32_t)FindExecutableModule()) {
|
||||
module->version_info.signature = MD_VSFIXEDFILEINFO_SIGNATURE;
|
||||
module->version_info.struct_version |= MD_VSFIXEDFILEINFO_VERSION;
|
||||
// Convert MAC dylib version format, which is a 32 bit number, to the
|
||||
// format used by minidump. The mac format is <16 bits>.<8 bits>.<8 bits>
|
||||
// so it fits nicely into the windows version with some massaging
|
||||
// The mapping is:
|
||||
// 1) upper 16 bits of MAC version go to lower 16 bits of product HI
|
||||
// 2) Next most significant 8 bits go to upper 16 bits of product LO
|
||||
// 3) Least significant 8 bits go to lower 16 bits of product LO
|
||||
uint32_t modVersion = image->GetVersion();
|
||||
module->version_info.file_version_hi = 0;
|
||||
module->version_info.file_version_hi = modVersion >> 16;
|
||||
module->version_info.file_version_lo |= (modVersion & 0xff00) << 8;
|
||||
module->version_info.file_version_lo |= (modVersion & 0xff);
|
||||
}
|
||||
|
||||
if (!WriteCVRecord(module, cpu_type, name)) {
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -502,7 +502,7 @@ void DumpFunctionMap(const dwarf2reader::FunctionMap function_map) {
|
|||
}
|
||||
|
||||
// set line number for beginning of function
|
||||
if (![dict objectForKey:kAddressSourceLineKey])
|
||||
if (iter->second->line && ![dict objectForKey:kAddressSourceLineKey])
|
||||
[dict setObject:[NSNumber numberWithUnsignedInt:iter->second->line]
|
||||
forKey:kAddressSourceLineKey];
|
||||
|
||||
|
@ -534,7 +534,7 @@ void DumpFunctionMap(const dwarf2reader::FunctionMap function_map) {
|
|||
[dict release];
|
||||
}
|
||||
|
||||
if (![dict objectForKey:kAddressSourceLineKey]) {
|
||||
if (iter->second.second && ![dict objectForKey:kAddressSourceLineKey]) {
|
||||
[dict setObject:[NSNumber numberWithUnsignedInt:iter->second.second]
|
||||
forKey:kAddressSourceLineKey];
|
||||
}
|
||||
|
@ -1024,6 +1024,12 @@ static BOOL WriteFormat(int fd, const char *fmt, ...) {
|
|||
if ([symbol hasPrefix:@"GCC_except_table"])
|
||||
continue;
|
||||
|
||||
if ([symbol hasPrefix:@"__tcf"])
|
||||
continue;
|
||||
|
||||
if ([symbol hasPrefix:@"non-virtual thunk"])
|
||||
continue;
|
||||
|
||||
// Find the source file (if any) that contains this address
|
||||
while (sourceCount && (addressVal >= nextSourceFileAddress)) {
|
||||
fileIdx = nextFileIdx;
|
||||
|
|
|
@ -99,6 +99,12 @@ static void PrintStack(const CallStack *stack, const string &cpu) {
|
|||
int maxStr = 20;
|
||||
buffer[maxStr] = 0;
|
||||
printf("%-*s", maxStr, buffer);
|
||||
|
||||
strcpy(buffer, module->version().c_str());
|
||||
buffer[maxStr] = 0;
|
||||
|
||||
printf("%-*s",maxStr, buffer);
|
||||
|
||||
u_int64_t instruction = frame->instruction;
|
||||
|
||||
// PPC only: Adjust the instruction to match that of Crash reporter. The
|
||||
|
|
Loading…
Reference in a new issue