diff options
Diffstat (limited to 'toolkit/crashreporter/google-breakpad/src/tools/mac/crash_report/on_demand_symbol_supplier.mm')
-rw-r--r-- | toolkit/crashreporter/google-breakpad/src/tools/mac/crash_report/on_demand_symbol_supplier.mm | 314 |
1 files changed, 314 insertions, 0 deletions
diff --git a/toolkit/crashreporter/google-breakpad/src/tools/mac/crash_report/on_demand_symbol_supplier.mm b/toolkit/crashreporter/google-breakpad/src/tools/mac/crash_report/on_demand_symbol_supplier.mm new file mode 100644 index 0000000000..1955d2667b --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/tools/mac/crash_report/on_demand_symbol_supplier.mm @@ -0,0 +1,314 @@ +// 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. + +#import <Foundation/Foundation.h> +#include <sys/stat.h> +#include <map> +#include <string> +#include <iostream> +#include <fstream> +#include <utility> + +#include "google_breakpad/processor/basic_source_line_resolver.h" +#include "google_breakpad/processor/minidump.h" +#include "google_breakpad/processor/system_info.h" +#include "processor/pathname_stripper.h" + +#include "on_demand_symbol_supplier.h" +#include "common/mac/dump_syms.h" + +using std::map; +using std::string; + +using google_breakpad::OnDemandSymbolSupplier; +using google_breakpad::PathnameStripper; +using google_breakpad::SymbolSupplier; +using google_breakpad::SystemInfo; + +OnDemandSymbolSupplier::OnDemandSymbolSupplier(const string &search_dir, + const string &symbol_search_dir) + : search_dir_(search_dir) { + NSFileManager *mgr = [NSFileManager defaultManager]; + size_t length = symbol_search_dir.length(); + if (length) { + // Load all sym files in symbol_search_dir into our module_file_map + // A symbol file always starts with a line like this: + // MODULE mac x86 BBF0A8F9BEADDD2048E6464001CA193F0 GoogleDesktopDaemon + // or + // MODULE mac ppc BBF0A8F9BEADDD2048E6464001CA193F0 GoogleDesktopDaemon + const char *symbolSearchStr = symbol_search_dir.c_str(); + NSString *symbolSearchPath = + [mgr stringWithFileSystemRepresentation:symbolSearchStr + length:strlen(symbolSearchStr)]; + NSDirectoryEnumerator *dirEnum = [mgr enumeratorAtPath:symbolSearchPath]; + NSString *fileName; + NSCharacterSet *hexSet = + [NSCharacterSet characterSetWithCharactersInString:@"0123456789ABCDEF"]; + NSCharacterSet *newlineSet = + [NSCharacterSet characterSetWithCharactersInString:@"\r\n"]; + while ((fileName = [dirEnum nextObject])) { + // Check to see what type of file we have + NSDictionary *attrib = [dirEnum fileAttributes]; + NSString *fileType = [attrib objectForKey:NSFileType]; + if ([fileType isEqualToString:NSFileTypeDirectory]) { + // Skip subdirectories + [dirEnum skipDescendents]; + } else { + NSString *filePath = [symbolSearchPath stringByAppendingPathComponent:fileName]; + NSString *dataStr = [NSString stringWithContentsOfFile:filePath encoding:NSUTF8StringEncoding error:NULL]; + if (dataStr) { + // Check file to see if it is of appropriate type, and grab module + // name. + NSScanner *scanner = [NSScanner scannerWithString:dataStr]; + BOOL goodScan = [scanner scanString:@"MODULE mac " intoString:nil]; + if (goodScan) { + goodScan = ([scanner scanString:@"x86 " intoString:nil] || + [scanner scanString:@"x86_64 " intoString:nil] || + [scanner scanString:@"ppc " intoString:nil]); + if (goodScan) { + NSString *moduleID; + goodScan = [scanner scanCharactersFromSet:hexSet + intoString:&moduleID]; + if (goodScan) { + // Module IDs are always 33 chars long + goodScan = [moduleID length] == 33; + if (goodScan) { + NSString *moduleName; + goodScan = [scanner scanUpToCharactersFromSet:newlineSet + intoString:&moduleName]; + if (goodScan) { + goodScan = [moduleName length] > 0; + if (goodScan) { + const char *moduleNameStr = [moduleName UTF8String]; + const char *filePathStr = [filePath fileSystemRepresentation]; + // Map our file + module_file_map_[moduleNameStr] = filePathStr; + } + } + } + } + } + } + } + } + } + } +} + +SymbolSupplier::SymbolResult +OnDemandSymbolSupplier::GetSymbolFile(const CodeModule *module, + const SystemInfo *system_info, + string *symbol_file) { + string path(GetModuleSymbolFile(module)); + + if (path.empty()) { + if (!GenerateSymbolFile(module, system_info)) + return NOT_FOUND; + + path = GetModuleSymbolFile(module); + } + + if (path.empty()) + return NOT_FOUND; + + *symbol_file = path; + return FOUND; +} + +SymbolSupplier::SymbolResult +OnDemandSymbolSupplier::GetSymbolFile(const CodeModule *module, + const SystemInfo *system_info, + string *symbol_file, + string *symbol_data) { + SymbolSupplier::SymbolResult s = GetSymbolFile(module, + system_info, + symbol_file); + + + if (s == FOUND) { + std::ifstream in(symbol_file->c_str()); + getline(in, *symbol_data, std::string::traits_type::to_char_type( + std::string::traits_type::eof())); + in.close(); + } + + return s; +} + +SymbolSupplier::SymbolResult +OnDemandSymbolSupplier::GetCStringSymbolData(const CodeModule *module, + const SystemInfo *system_info, + string *symbol_file, + char **symbol_data, + size_t *symbol_data_size) { + std::string symbol_data_string; + SymbolSupplier::SymbolResult result = GetSymbolFile(module, + system_info, + symbol_file, + &symbol_data_string); + if (result == FOUND) { + *symbol_data_size = symbol_data_string.size() + 1; + *symbol_data = new char[*symbol_data_size]; + if (*symbol_data == NULL) { + // Should return INTERRUPT on memory allocation failure. + return INTERRUPT; + } + memcpy(*symbol_data, symbol_data_string.c_str(), symbol_data_string.size()); + (*symbol_data)[symbol_data_string.size()] = '\0'; + memory_buffers_.insert(make_pair(module->code_file(), *symbol_data)); + } + return result; +} + +void OnDemandSymbolSupplier::FreeSymbolData(const CodeModule *module) { + map<string, char *>::iterator it = memory_buffers_.find(module->code_file()); + if (it != memory_buffers_.end()) { + delete [] it->second; + memory_buffers_.erase(it); + } +} + +string OnDemandSymbolSupplier::GetLocalModulePath(const CodeModule *module) { + NSFileManager *mgr = [NSFileManager defaultManager]; + const char *moduleStr = module->code_file().c_str(); + NSString *modulePath = + [mgr stringWithFileSystemRepresentation:moduleStr length:strlen(moduleStr)]; + const char *searchStr = search_dir_.c_str(); + NSString *searchDir = + [mgr stringWithFileSystemRepresentation:searchStr length:strlen(searchStr)]; + + if ([mgr fileExistsAtPath:modulePath]) + return module->code_file(); + + // If the module is not found, try to start appending the components to the + // search string and stop if a file (not dir) is found or all components + // have been appended + NSArray *pathComponents = [modulePath componentsSeparatedByString:@"/"]; + size_t count = [pathComponents count]; + NSMutableString *path = [NSMutableString string]; + + for (size_t i = 0; i < count; ++i) { + [path setString:searchDir]; + + for (size_t j = 0; j < i + 1; ++j) { + size_t idx = count - 1 - i + j; + [path appendFormat:@"/%@", [pathComponents objectAtIndex:idx]]; + } + + BOOL isDir; + if ([mgr fileExistsAtPath:path isDirectory:&isDir] && (!isDir)) { + return [path fileSystemRepresentation]; + } + } + + return ""; +} + +string OnDemandSymbolSupplier::GetModulePath(const CodeModule *module) { + return module->code_file(); +} + +string OnDemandSymbolSupplier::GetNameForModule(const CodeModule *module) { + return PathnameStripper::File(module->code_file()); +} + +string OnDemandSymbolSupplier::GetModuleSymbolFile(const CodeModule *module) { + string name(GetNameForModule(module)); + map<string, string>::iterator result = module_file_map_.find(name); + + return (result == module_file_map_.end()) ? "" : (*result).second; +} + +static float GetFileModificationTime(const char *path) { + float result = 0; + struct stat file_stat; + if (stat(path, &file_stat) == 0) + result = (float)file_stat.st_mtimespec.tv_sec + + (float)file_stat.st_mtimespec.tv_nsec / 1.0e9f; + + return result; +} + +bool OnDemandSymbolSupplier::GenerateSymbolFile(const CodeModule *module, + const SystemInfo *system_info) { + bool result = true; + string name = GetNameForModule(module); + string module_path = GetLocalModulePath(module); + NSString *symbol_path = [NSString stringWithFormat:@"/tmp/%s.%s.sym", + name.c_str(), system_info->cpu.c_str()]; + + if (module_path.empty()) + return false; + + // Check if there's already a symbol file cached. Ensure that the file is + // newer than the module. Otherwise, generate a new one. + BOOL generate_file = YES; + if ([[NSFileManager defaultManager] fileExistsAtPath:symbol_path]) { + // Check if the module file is newer than the saved symbols + float cache_time = + GetFileModificationTime([symbol_path fileSystemRepresentation]); + float module_time = + GetFileModificationTime(module_path.c_str()); + + if (cache_time > module_time) + generate_file = NO; + } + + if (generate_file) { + DumpSymbols dump(ALL_SYMBOL_DATA, false); + if (dump.Read(module_path)) { + // What Breakpad calls "x86" should be given to the system as "i386". + std::string architecture; + if (system_info->cpu.compare("x86") == 0) { + architecture = "i386"; + } else { + architecture = system_info->cpu; + } + + if (dump.SetArchitecture(architecture)) { + std::fstream file([symbol_path fileSystemRepresentation], + std::ios_base::out | std::ios_base::trunc); + dump.WriteSymbolFile(file); + } else { + printf("Architecture %s not available for %s\n", + system_info->cpu.c_str(), name.c_str()); + result = false; + } + } else { + printf("Unable to open %s\n", module_path.c_str()); + result = false; + } + } + + // Add the mapping + if (result) + module_file_map_[name] = [symbol_path fileSystemRepresentation]; + + return result; +} |