diff --git a/toolkit/crashreporter/google-breakpad/src/client/windows/handler/exception_handler.cc b/toolkit/crashreporter/google-breakpad/src/client/windows/handler/exception_handler.cc index 8594d1bfcf0..7217e19d403 100644 --- a/toolkit/crashreporter/google-breakpad/src/client/windows/handler/exception_handler.cc +++ b/toolkit/crashreporter/google-breakpad/src/client/windows/handler/exception_handler.cc @@ -140,15 +140,22 @@ void ExceptionHandler::Initialize(const wstring& dump_path, // context outside of an exception. InitializeCriticalSection(&handler_critical_section_); handler_start_semaphore_ = CreateSemaphore(NULL, 0, 1, NULL); - handler_finish_semaphore_ = CreateSemaphore(NULL, 0, 1, NULL); + assert(handler_start_semaphore_ != NULL); - DWORD thread_id; - handler_thread_ = CreateThread(NULL, // lpThreadAttributes - kExceptionHandlerThreadInitialStackSize, - ExceptionHandlerThreadMain, - this, // lpParameter - 0, // dwCreationFlags - &thread_id); + handler_finish_semaphore_ = CreateSemaphore(NULL, 0, 1, NULL); + assert(handler_finish_semaphore_ != NULL); + + // Don't attempt to create the thread if we could not create the semaphores. + if (handler_finish_semaphore_ != NULL && handler_start_semaphore_ != NULL) { + DWORD thread_id; + handler_thread_ = CreateThread(NULL, // lpThreadAttributes + kExceptionHandlerThreadInitialStackSize, + ExceptionHandlerThreadMain, + this, // lpParameter + 0, // dwCreationFlags + &thread_id); + assert(handler_thread_ != NULL); + } dbghelp_module_ = LoadLibrary(L"dbghelp.dll"); if (dbghelp_module_) { @@ -264,6 +271,8 @@ ExceptionHandler::~ExceptionHandler() { DWORD ExceptionHandler::ExceptionHandlerThreadMain(void* lpParameter) { ExceptionHandler* self = reinterpret_cast(lpParameter); assert(self); + assert(self->handler_start_semaphore_ != NULL); + assert(self->handler_finish_semaphore_ != NULL); while (true) { if (WaitForSingleObject(self->handler_start_semaphore_, INFINITE) == @@ -519,6 +528,17 @@ bool ExceptionHandler::WriteMinidumpOnHandlerThread( EXCEPTION_POINTERS* exinfo, MDRawAssertionInfo* assertion) { EnterCriticalSection(&handler_critical_section_); + // There isn't much we can do if the handler thread + // was not successfully created. + if (handler_thread_ == NULL) { + LeaveCriticalSection(&handler_critical_section_); + return false; + } + + // The handler thread should only be created when the semaphores are valid. + assert(handler_start_semaphore_ != NULL); + assert(handler_finish_semaphore_ != NULL); + // Set up data to be passed in to the handler thread. requesting_thread_id_ = GetCurrentThreadId(); exception_info_ = exinfo; diff --git a/toolkit/crashreporter/google-breakpad/src/common/mac/dump_syms.h b/toolkit/crashreporter/google-breakpad/src/common/mac/dump_syms.h index e234a6a6c54..12d8f7d6e75 100644 --- a/toolkit/crashreporter/google-breakpad/src/common/mac/dump_syms.h +++ b/toolkit/crashreporter/google-breakpad/src/common/mac/dump_syms.h @@ -46,7 +46,6 @@ typedef hash_map ArchSectionMap; NSMutableDictionary *addresses_; // Addresses and symbols (STRONG) NSMutableSet *functionAddresses_; // Function addresses (STRONG) NSMutableDictionary *sources_; // Address and Source file paths (STRONG) - NSMutableArray *cppAddresses_; // Addresses of C++ symbols (STRONG) NSMutableDictionary *headers_; // Mach-o header information (STRONG) NSMutableDictionary *sectionData_; // Keyed by seg/sect name (STRONG) uint32_t lastStartAddress_; diff --git a/toolkit/crashreporter/google-breakpad/src/common/mac/dump_syms.mm b/toolkit/crashreporter/google-breakpad/src/common/mac/dump_syms.mm index b4f779dfc85..88f1f4f15da 100644 --- a/toolkit/crashreporter/google-breakpad/src/common/mac/dump_syms.mm +++ b/toolkit/crashreporter/google-breakpad/src/common/mac/dump_syms.mm @@ -63,7 +63,6 @@ static NSString *kHeaderSizeKey = @"size"; static NSString *kHeaderOffsetKey = @"offset"; // Offset to the header static NSString *kHeaderIs64BitKey = @"is64"; static NSString *kHeaderCPUTypeKey = @"cpuType"; -static NSString *kUnknownSymbol = @"???"; // The section for __TEXT, __text seems to be always 1. This is useful // for pruning out extraneous non-function symbols. @@ -104,8 +103,7 @@ void DumpFunctionMap(const dwarf2reader::FunctionMap function_map) { @interface DumpSymbols(PrivateMethods) -- (NSArray *)convertCPlusPlusSymbols:(NSArray *)symbols; -- (void)convertSymbols; +- (NSString *)convertCPlusPlusSymbol:(NSString *)symbol; - (void)addFunction:(NSString *)name line:(int)line address:(uint64_t)address section:(int)section; - (BOOL)processSymbolItem:(struct nlist_64 *)list stringTable:(char *)table; - (BOOL)loadSymbolInfo:(void *)base offset:(uint32_t)offset; @@ -126,86 +124,20 @@ void DumpFunctionMap(const dwarf2reader::FunctionMap function_map) { @implementation DumpSymbols //============================================================================= -- (NSArray *)convertCPlusPlusSymbols:(NSArray *)symbols { - NSMutableArray *symbols_demangled = [[NSMutableArray alloc] - initWithCapacity:[symbols count]]; +- (NSString *)convertCPlusPlusSymbol:(NSString *)symbol { // __cxa_demangle will realloc this if needed char *buffer = (char *)malloc(1024); size_t buffer_size = 1024; int result; - NSEnumerator *enumerator = [symbols objectEnumerator]; - id symbolObject; - while ((symbolObject = [enumerator nextObject])) { - const char *symbol = [symbolObject UTF8String]; - buffer = abi::__cxa_demangle(symbol, buffer, &buffer_size, &result); - if (result == 0) { - [symbols_demangled addObject:[NSString stringWithUTF8String:buffer]]; - } else { - // unable to demangle - use mangled name instead - [symbols_demangled addObject:symbolObject]; - } + const char *sym = [symbol UTF8String]; + NSString *demangled = nil; + buffer = abi::__cxa_demangle(sym, buffer, &buffer_size, &result); + if (result == 0) { + demangled = [NSString stringWithUTF8String:buffer]; } free(buffer); - - return symbols_demangled; -} - -//============================================================================= -- (void)convertSymbols { - unsigned int count = [cppAddresses_ count]; - NSMutableArray *symbols = [[NSMutableArray alloc] initWithCapacity:count]; - - // Sort addresses for processing - NSArray *addresses = [cppAddresses_ sortedArrayUsingSelector: - @selector(compare:)]; - - for (unsigned int i = 0; i < count; ++i) { - NSMutableDictionary *dict = [addresses_ objectForKey: - [addresses objectAtIndex:i]]; - NSString *symbol = [dict objectForKey:kAddressSymbolKey]; - - // Make sure that the symbol is valid - if ([symbol length] < 1) - symbol = kUnknownSymbol; - - [symbols addObject:symbol]; - } - - // In order to deal with crashing problems in c++filt, we setup - // a while loop to handle the case where convertCPlusPlusSymbols - // only returns partial results. - // We then attempt to continue from the point where c++filt failed - // and add the partial results to the total results until we're - // completely done. - - unsigned int totalIndex = 0; - unsigned int totalCount = count; - - while (totalIndex < totalCount) { - NSRange range = NSMakeRange(totalIndex, totalCount - totalIndex); - NSArray *subarray = [symbols subarrayWithRange:range]; - NSArray *converted = [self convertCPlusPlusSymbols:subarray]; - unsigned int convertedCount = [converted count]; - - if (convertedCount == 0) { - break; // we give up at this point - } - - for (unsigned int convertedIndex = 0; - convertedIndex < convertedCount && totalIndex < totalCount; - ++totalIndex, ++convertedIndex) { - NSMutableDictionary *dict = [addresses_ objectForKey: - [addresses objectAtIndex:totalIndex]]; - NSString *symbol = [converted objectAtIndex:convertedIndex]; - - // Only add if this is a non-zero length symbol - if ([symbol length]) - [dict setObject:symbol forKey:kAddressConvertedSymbolKey]; - } - } - - [symbols release]; + return demangled; } //============================================================================= @@ -215,8 +147,7 @@ void DumpFunctionMap(const dwarf2reader::FunctionMap function_map) { if (!address) return; - // If the function starts with "_Z" or "__Z" then add it to the list of - // addresses to run through the c++filt + // If the function starts with "_Z" or "__Z" then demangle it. BOOL isCPP = NO; if ([name hasPrefix:@"__Z"]) { @@ -255,12 +186,6 @@ void DumpFunctionMap(const dwarf2reader::FunctionMap function_map) { NSRange emptyRange = { NSNotFound, 0 }; NSRange objcppRange = [name rangeOfCharacterFromSet:objcppCharSet]; isCPP = NSEqualRanges(objcppRange, emptyRange); - } - - if (isCPP) { - if (!cppAddresses_) - cppAddresses_ = [[NSMutableArray alloc] init]; - [cppAddresses_ addObject:addressNum]; } else if ([name characterAtIndex:0] == '_') { // Remove the leading underscore name = [name substringFromIndex:1]; @@ -282,6 +207,13 @@ void DumpFunctionMap(const dwarf2reader::FunctionMap function_map) { // only functions, not line number addresses [functionAddresses_ addObject:addressNum]; } + + if (isCPP) { + // try demangling + NSString *demangled = [self convertCPlusPlusSymbol:name]; + if (demangled != nil) + [dict setObject:demangled forKey:kAddressConvertedSymbolKey]; + } if (line && ![dict objectForKey:kAddressSourceLineKey]) [dict setObject:[NSNumber numberWithUnsignedInt:line] @@ -500,6 +432,15 @@ void DumpFunctionMap(const dwarf2reader::FunctionMap function_map) { NSString *symbolName = [NSString stringWithUTF8String:iter->second->name.c_str()]; [dict setObject:symbolName forKey:kAddressSymbolKey]; } + + // try demangling function name if we have a mangled name + if (![dict objectForKey:kAddressConvertedSymbolKey] && + !iter->second->mangled_name.empty()) { + NSString *mangled = [NSString stringWithUTF8String:iter->second->mangled_name.c_str()]; + NSString *demangled = [self convertCPlusPlusSymbol:mangled]; + if (demangled != nil) + [dict setObject:demangled forKey:kAddressConvertedSymbolKey]; + } // set line number for beginning of function if (iter->second->line && ![dict objectForKey:kAddressSourceLineKey]) @@ -920,7 +861,6 @@ static BOOL WriteFormat(int fd, const char *fmt, ...) { // Gather the information [self loadSymbolInfoForArchitecture]; - [self convertSymbols]; NSArray *sortedAddresses = [[addresses_ allKeys] sortedArrayUsingSelector:@selector(compare:)]; diff --git a/toolkit/crashreporter/google-breakpad/src/common/mac/dwarf/functioninfo.cc b/toolkit/crashreporter/google-breakpad/src/common/mac/dwarf/functioninfo.cc index e9d33b836cc..b6d3f0fe197 100644 --- a/toolkit/crashreporter/google-breakpad/src/common/mac/dwarf/functioninfo.cc +++ b/toolkit/crashreporter/google-breakpad/src/common/mac/dwarf/functioninfo.cc @@ -51,6 +51,25 @@ namespace __gnu_cxx namespace dwarf2reader { +// Given an offset value, its form, and the base offset of the +// compilation unit containing this value, return an absolute offset +// within the .debug_info section. +uint64 GetAbsoluteOffset(uint64 offset, + enum DwarfForm form, + uint64 compilation_unit_base) { + switch (form) { + case DW_FORM_ref1: + case DW_FORM_ref2: + case DW_FORM_ref4: + case DW_FORM_ref8: + case DW_FORM_ref_udata: + return offset + compilation_unit_base; + case DW_FORM_ref_addr: + default: + return offset; + } +} + CULineInfoHandler::CULineInfoHandler(vector* files, vector* dirs, LineMap* linemap):linemap_(linemap), @@ -117,6 +136,7 @@ bool CUFunctionInfoHandler::StartCompilationUnit(uint64 offset, uint8 offset_size, uint64 cu_length, uint8 dwarf_version) { + current_compilation_unit_offset_ = offset; return true; } @@ -152,8 +172,12 @@ void CUFunctionInfoHandler::ProcessAttributeString(uint64 offset, enum DwarfAttribute attr, enum DwarfForm form, const string &data) { - if (attr == DW_AT_name && current_function_info_) - current_function_info_->name = data; + if (current_function_info_) { + if (attr == DW_AT_name) + current_function_info_->name = data; + else if(attr == DW_AT_MIPS_linkage_name) + current_function_info_->mangled_name = data; + } } void CUFunctionInfoHandler::ProcessAttributeUnsigned(uint64 offset, @@ -183,6 +207,24 @@ void CUFunctionInfoHandler::ProcessAttributeUnsigned(uint64 offset, case DW_AT_decl_file: current_function_info_->file = files_->at(data).name; break; + case DW_AT_specification: { + // Some functions have a "specification" attribute + // which means they were defined elsewhere. The name + // attribute is not repeated, and must be taken from + // the specification DIE. Here we'll assume that + // any DIE referenced in this manner will already have + // been seen, but that's not really required by the spec. + uint64 abs_offset = GetAbsoluteOffset(data, form, current_compilation_unit_offset_); + FunctionMap::iterator iter = offset_to_funcinfo_->find(abs_offset); + if (iter != offset_to_funcinfo_->end()) { + current_function_info_->name = iter->second->name; + current_function_info_->mangled_name = iter->second->mangled_name; + } else { + // If you hit this, this code probably needs to be rewritten. + fprintf(stderr, "Error: DW_AT_specification was seen before the referenced DIE! (Looking for DIE at offset %08llx, in DIE at offset %08llx)\n", abs_offset, offset); + } + break; + } default: break; } diff --git a/toolkit/crashreporter/google-breakpad/src/common/mac/dwarf/functioninfo.h b/toolkit/crashreporter/google-breakpad/src/common/mac/dwarf/functioninfo.h index f529f0928ec..130f182e0f3 100644 --- a/toolkit/crashreporter/google-breakpad/src/common/mac/dwarf/functioninfo.h +++ b/toolkit/crashreporter/google-breakpad/src/common/mac/dwarf/functioninfo.h @@ -47,6 +47,8 @@ namespace dwarf2reader { struct FunctionInfo { // Name of the function string name; + // Mangled name of the function + string mangled_name; // File containing this function string file; // Line number for start of function. @@ -169,6 +171,7 @@ class CUFunctionInfoHandler: public Dwarf2Handler { const SectionMap& sections_; ByteReader* reader_; FunctionInfo* current_function_info_; + uint64 current_compilation_unit_offset_; }; } // namespace dwarf2reader