| Index: obsolete/breakpad/common/mac/dump_syms.mm
|
| diff --git a/obsolete/breakpad/common/mac/dump_syms.mm b/obsolete/breakpad/common/mac/dump_syms.mm
|
| deleted file mode 100644
|
| index cf70b1c62e5c07debb762aff9aaabdf06b8e9f30..0000000000000000000000000000000000000000
|
| --- a/obsolete/breakpad/common/mac/dump_syms.mm
|
| +++ /dev/null
|
| @@ -1,1222 +0,0 @@
|
| -// 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.
|
| -
|
| -// dump_syms.mm: Create a symbol file for use with minidumps
|
| -
|
| -#include <unistd.h>
|
| -#include <signal.h>
|
| -#include <cxxabi.h>
|
| -#include <stdlib.h>
|
| -
|
| -#include <mach/machine.h>
|
| -#include <mach-o/arch.h>
|
| -#include <mach-o/fat.h>
|
| -#include <mach-o/loader.h>
|
| -#include <mach-o/nlist.h>
|
| -#include <mach-o/stab.h>
|
| -#include <fcntl.h>
|
| -
|
| -#import <Foundation/Foundation.h>
|
| -
|
| -#import "dump_syms.h"
|
| -#import "common/mac/file_id.h"
|
| -#import "common/mac/macho_utilities.h"
|
| -#import "common/dwarf/dwarf2reader.h"
|
| -#import "common/dwarf/functioninfo.h"
|
| -#import "common/dwarf/bytereader.h"
|
| -
|
| -using google_breakpad::FileID;
|
| -
|
| -static NSString *kAddressSymbolKey = @"symbol";
|
| -static NSString *kAddressConvertedSymbolKey = @"converted_symbol";
|
| -static NSString *kAddressSourceLineKey = @"line";
|
| -static NSString *kFunctionSizeKey = @"size";
|
| -static NSString *kFunctionFileKey = @"source_file";
|
| -static NSString *kHeaderBaseAddressKey = @"baseAddr";
|
| -static NSString *kHeaderSizeKey = @"size";
|
| -static NSString *kHeaderOffsetKey = @"offset"; // Offset to the header
|
| -static NSString *kHeaderIs64BitKey = @"is64";
|
| -static NSString *kHeaderCPUTypeKey = @"cpuType";
|
| -
|
| -// The section for __TEXT, __text seems to be always 1. This is useful
|
| -// for pruning out extraneous non-function symbols.
|
| -static const int kTextSection = 1;
|
| -
|
| -// Dump FunctionMap to stdout. Print address, function name, file
|
| -// name, line number, lowpc, and highpc if available.
|
| -void DumpFunctionMap(const dwarf2reader::FunctionMap function_map) {
|
| - for (dwarf2reader::FunctionMap::const_iterator iter = function_map.begin();
|
| - iter != function_map.end(); ++iter) {
|
| - if (iter->second->name.empty()) {
|
| - continue;
|
| - }
|
| - printf("%08llx: %s", iter->first,
|
| - iter->second->name.data());
|
| - if (!iter->second->file.empty()) {
|
| - printf(" - %s", iter->second->file.data());
|
| - if (iter->second->line != 0) {
|
| - printf(":%u", iter->second->line);
|
| - }
|
| - }
|
| - if (iter->second->lowpc != 0 && iter->second->highpc != 0) {
|
| - printf(" (%08llx - %08llx)\n",
|
| - iter->second->lowpc,
|
| - iter->second->highpc);
|
| - }
|
| - }
|
| -}
|
| -
|
| -
|
| -@interface DumpSymbols(PrivateMethods)
|
| -- (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;
|
| -- (BOOL)loadSymbolInfo64:(void *)base offset:(uint32_t)offset;
|
| -- (BOOL)loadSymbolInfoForArchitecture;
|
| -- (BOOL)loadDWARFSymbolInfo:(void *)base offset:(uint32_t)offset;
|
| -- (BOOL)loadSTABSSymbolInfo:(void *)base offset:(uint32_t)offset;
|
| -- (void)generateSectionDictionary:(struct mach_header*)header;
|
| -- (BOOL)loadHeader:(void *)base offset:(uint32_t)offset;
|
| -- (BOOL)loadHeader64:(void *)base offset:(uint32_t)offset;
|
| -- (BOOL)loadModuleInfo;
|
| -- (void)processDWARFLineNumberInfo:(dwarf2reader::LineMap*)line_map;
|
| -- (void)processDWARFFunctionInfo:(dwarf2reader::FunctionMap*)address_to_funcinfo;
|
| -- (void)processDWARFSourceFileInfo:(vector<dwarf2reader::SourceFileInfo>*) files;
|
| -- (BOOL)loadSymbolInfo:(void *)base offset:(uint32_t)offset;
|
| -- (dwarf2reader::SectionMap*)getSectionMapForArchitecture:(NSString*)architecture;
|
| -@end
|
| -
|
| -@implementation DumpSymbols
|
| -//=============================================================================
|
| -- (NSString *)convertCPlusPlusSymbol:(NSString *)symbol {
|
| - // __cxa_demangle will realloc this if needed
|
| - char *buffer = (char *)malloc(1024);
|
| - size_t buffer_size = 1024;
|
| - int result;
|
| -
|
| - 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 demangled;
|
| -}
|
| -
|
| -//=============================================================================
|
| -- (void)addFunction:(NSString *)name line:(int)line address:(uint64_t)address section:(int)section {
|
| - NSNumber *addressNum = [NSNumber numberWithUnsignedLongLong:address];
|
| -
|
| - if (!address)
|
| - return;
|
| -
|
| - // If the function starts with "_Z" or "__Z" then demangle it.
|
| - BOOL isCPP = NO;
|
| -
|
| - if ([name hasPrefix:@"__Z"]) {
|
| - // Remove the leading underscore
|
| - name = [name substringFromIndex:1];
|
| - isCPP = YES;
|
| - } else if ([name hasPrefix:@"_Z"]) {
|
| - isCPP = YES;
|
| - }
|
| -
|
| - // Filter out non-functions
|
| - if ([name hasSuffix:@".eh"])
|
| - return;
|
| -
|
| - if ([name hasSuffix:@"__func__"])
|
| - return;
|
| -
|
| - if ([name hasSuffix:@"GCC_except_table"])
|
| - return;
|
| -
|
| - if (isCPP) {
|
| - // OBJCPP_MANGLING_HACK
|
| - // There are cases where ObjC++ mangles up an ObjC name using quasi-C++
|
| - // mangling:
|
| - // @implementation Foozles + (void)barzles {
|
| - // static int Baz = 0;
|
| - // } @end
|
| - // gives you _ZZ18+[Foozles barzles]E3Baz
|
| - // c++filt won't parse this properly, and will crash in certain cases.
|
| - // Logged as radar:
|
| - // 5129938: c++filt does not deal with ObjC++ symbols
|
| - // If 5129938 ever gets fixed, we can remove this, but for now this prevents
|
| - // c++filt from attempting to demangle names it doesn't know how to handle.
|
| - // This is with c++filt 2.16
|
| - NSCharacterSet *objcppCharSet = [NSCharacterSet characterSetWithCharactersInString:@"-+[]: "];
|
| - NSRange emptyRange = { NSNotFound, 0 };
|
| - NSRange objcppRange = [name rangeOfCharacterFromSet:objcppCharSet];
|
| - isCPP = NSEqualRanges(objcppRange, emptyRange);
|
| - } else if ([name characterAtIndex:0] == '_') {
|
| - // Remove the leading underscore
|
| - name = [name substringFromIndex:1];
|
| - }
|
| -
|
| - // If there's already an entry for this address, check and see if we can add
|
| - // either the symbol, or a missing line #
|
| - NSMutableDictionary *dict = [addresses_ objectForKey:addressNum];
|
| -
|
| - if (!dict) {
|
| - dict = [[NSMutableDictionary alloc] init];
|
| - [addresses_ setObject:dict forKey:addressNum];
|
| - [dict release];
|
| - }
|
| -
|
| - if (name && ![dict objectForKey:kAddressSymbolKey]) {
|
| - [dict setObject:name forKey:kAddressSymbolKey];
|
| -
|
| - // 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]
|
| - forKey:kAddressSourceLineKey];
|
| -
|
| -}
|
| -
|
| -//=============================================================================
|
| -- (BOOL)processSymbolItem:(struct nlist_64 *)list stringTable:(char *)table {
|
| - uint32_t n_strx = list->n_un.n_strx;
|
| - BOOL result = NO;
|
| -
|
| - // We don't care about non-section specific information except function length
|
| - if (list->n_sect == 0 && list->n_type != N_FUN )
|
| - return NO;
|
| -
|
| - if (list->n_type == N_FUN) {
|
| - if (list->n_sect != 0) {
|
| - // we get the function address from the first N_FUN
|
| - lastStartAddress_ = list->n_value;
|
| - }
|
| - else {
|
| - // an N_FUN from section 0 may follow the initial N_FUN
|
| - // giving us function length information
|
| - NSMutableDictionary *dict = [addresses_ objectForKey:
|
| - [NSNumber numberWithUnsignedLong:lastStartAddress_]];
|
| -
|
| - assert(dict);
|
| -
|
| - // only set the function size the first time
|
| - // (sometimes multiple section 0 N_FUN entries appear!)
|
| - if (![dict objectForKey:kFunctionSizeKey]) {
|
| - [dict setObject:[NSNumber numberWithUnsignedLongLong:list->n_value]
|
| - forKey:kFunctionSizeKey];
|
| - }
|
| - }
|
| - }
|
| -
|
| - int line = list->n_desc;
|
| -
|
| - // __TEXT __text section
|
| - NSMutableDictionary *archSections = [sectionData_ objectForKey:architecture_];
|
| -
|
| - uint32_t mainSection = [[archSections objectForKey:@"__TEXT__text" ] sectionNumber];
|
| -
|
| - // Extract debugging information:
|
| - // Doc: http://developer.apple.com/documentation/DeveloperTools/gdb/stabs/stabs_toc.html
|
| - // Header: /usr/include/mach-o/stab.h:
|
| - if (list->n_type == N_SO) {
|
| - NSString *src = [NSString stringWithUTF8String:&table[n_strx]];
|
| - NSString *ext = [src pathExtension];
|
| - NSNumber *address = [NSNumber numberWithUnsignedLongLong:list->n_value];
|
| -
|
| - // Leopard puts .c files with no code as an offset of 0, but a
|
| - // crash can't happen here and it throws off our code that matches
|
| - // symbols to line numbers so we ignore them..
|
| - // Return YES because this isn't an error, just something we don't
|
| - // care to handle.
|
| - if ([address unsignedLongValue] == 0) {
|
| - return YES;
|
| - }
|
| - // TODO(waylonis):Ensure that we get the full path for the source file
|
| - // from the first N_SO record
|
| - // If there is an extension, we'll consider it source code
|
| - if ([ext length]) {
|
| - if (!sources_)
|
| - sources_ = [[NSMutableDictionary alloc] init];
|
| - // Save the source associated with an address
|
| - [sources_ setObject:src forKey:address];
|
| - result = YES;
|
| - }
|
| - } else if (list->n_type == N_FUN) {
|
| - NSString *fn = [NSString stringWithUTF8String:&table[n_strx]];
|
| - NSRange range = [fn rangeOfString:@":" options:NSBackwardsSearch];
|
| -
|
| - if (![fn length])
|
| - return NO;
|
| -
|
| - if (range.length > 0) {
|
| - // The function has a ":" followed by some stuff, so strip it off
|
| - fn = [fn substringToIndex:range.location];
|
| - }
|
| -
|
| - [self addFunction:fn line:line address:list->n_value section:list->n_sect ];
|
| -
|
| - result = YES;
|
| - } else if (list->n_type == N_SLINE && list->n_sect == mainSection) {
|
| - [self addFunction:nil line:line address:list->n_value section:list->n_sect ];
|
| - result = YES;
|
| - } else if (((list->n_type & N_TYPE) == N_SECT) && !(list->n_type & N_STAB)) {
|
| - // Regular symbols or ones that are external
|
| - NSString *fn = [NSString stringWithUTF8String:&table[n_strx]];
|
| -
|
| - [self addFunction:fn line:0 address:list->n_value section:list->n_sect ];
|
| - result = YES;
|
| - }
|
| -
|
| - return result;
|
| -}
|
| -
|
| -#define SwapLongLongIfNeeded(a) (swap ? NXSwapLongLong(a) : (a))
|
| -#define SwapLongIfNeeded(a) (swap ? NXSwapLong(a) : (a))
|
| -#define SwapIntIfNeeded(a) (swap ? NXSwapInt(a) : (a))
|
| -#define SwapShortIfNeeded(a) (swap ? NXSwapShort(a) : (a))
|
| -
|
| -//=============================================================================
|
| -- (BOOL)loadSymbolInfo:(void *)base offset:(uint32_t)offset {
|
| - BOOL loadedStabs = [self loadSTABSSymbolInfo:base offset:offset];
|
| -
|
| - NSMutableDictionary *archSections = [sectionData_ objectForKey:architecture_];
|
| - BOOL loadedDWARF = NO;
|
| - if ([archSections objectForKey:@"__DWARF__debug_info"]) {
|
| - // Treat this this as debug information
|
| - loadedDWARF = [self loadDWARFSymbolInfo:base offset:offset];
|
| - }
|
| -
|
| - return loadedDWARF || loadedStabs;
|
| -}
|
| -
|
| -//=============================================================================
|
| -- (BOOL)loadDWARFSymbolInfo:(void *)base offset:(uint32_t)offset {
|
| -
|
| - struct mach_header *header = (struct mach_header *)
|
| - ((uint32_t)base + offset);
|
| - BOOL swap = (header->magic == MH_CIGAM);
|
| -
|
| - NSMutableDictionary *archSections = [sectionData_ objectForKey:architecture_];
|
| - assert (archSections != nil);
|
| - section *dbgInfoSection = [[archSections objectForKey:@"__DWARF__debug_info"] sectionPointer];
|
| - uint32_t debugInfoSize = SwapLongIfNeeded(dbgInfoSection->size);
|
| -
|
| -#if __BIG_ENDIAN__
|
| - dwarf2reader::ByteReader byte_reader(swap ?
|
| - dwarf2reader::ENDIANNESS_LITTLE :
|
| - dwarf2reader::ENDIANNESS_BIG);
|
| -#elif __LITTLE_ENDIAN__
|
| - dwarf2reader::ByteReader byte_reader(swap ?
|
| - dwarf2reader::ENDIANNESS_BIG :
|
| - dwarf2reader::ENDIANNESS_LITTLE);
|
| -#endif
|
| - uint64_t dbgOffset = 0;
|
| -
|
| - dwarf2reader::SectionMap* oneArchitectureSectionMap = [self getSectionMapForArchitecture:architecture_];
|
| -
|
| - while (dbgOffset < debugInfoSize) {
|
| - // Prepare necessary objects.
|
| - dwarf2reader::FunctionMap off_to_funcinfo;
|
| - dwarf2reader::FunctionMap address_to_funcinfo;
|
| - dwarf2reader::LineMap line_map;
|
| - vector<dwarf2reader::SourceFileInfo> files;
|
| - vector<string> dirs;
|
| -
|
| - dwarf2reader::CULineInfoHandler line_info_handler(&files, &dirs,
|
| - &line_map);
|
| -
|
| - dwarf2reader::CUFunctionInfoHandler function_info_handler(&files, &dirs,
|
| - &line_map,
|
| - &off_to_funcinfo,
|
| - &address_to_funcinfo,
|
| - &line_info_handler,
|
| - *oneArchitectureSectionMap,
|
| - &byte_reader);
|
| -
|
| - dwarf2reader::CompilationUnit compilation_unit(*oneArchitectureSectionMap,
|
| - dbgOffset,
|
| - &byte_reader,
|
| - &function_info_handler);
|
| -
|
| - dbgOffset += compilation_unit.Start();
|
| -
|
| - // The next 3 functions take the info that the dwarf reader
|
| - // gives and massages them into the data structures that
|
| - // dump_syms uses
|
| - [self processDWARFSourceFileInfo:&files];
|
| - [self processDWARFFunctionInfo:&address_to_funcinfo];
|
| - [self processDWARFLineNumberInfo:&line_map];
|
| - }
|
| -
|
| - return YES;
|
| -}
|
| -
|
| -- (void)processDWARFSourceFileInfo:(vector<dwarf2reader::SourceFileInfo>*) files {
|
| - if (!sources_)
|
| - sources_ = [[NSMutableDictionary alloc] init];
|
| - // Save the source associated with an address
|
| - vector<dwarf2reader::SourceFileInfo>::const_iterator iter = files->begin();
|
| - for (; iter != files->end(); iter++) {
|
| - NSString *sourceFile = [NSString stringWithUTF8String:(*iter).name.c_str()];
|
| - if ((*iter).lowpc != ULLONG_MAX) {
|
| - NSNumber *address = [NSNumber numberWithUnsignedLongLong:(*iter).lowpc];
|
| - if ([address unsignedLongLongValue] == 0) {
|
| - continue;
|
| - }
|
| - [sources_ setObject:sourceFile forKey:address];
|
| - }
|
| - }
|
| -}
|
| -
|
| -- (void)processDWARFFunctionInfo:(dwarf2reader::FunctionMap*)address_to_funcinfo {
|
| - for (dwarf2reader::FunctionMap::const_iterator iter = address_to_funcinfo->begin();
|
| - iter != address_to_funcinfo->end(); ++iter) {
|
| - if (iter->second->name.empty()) {
|
| - continue;
|
| - }
|
| -
|
| - if (!addresses_)
|
| - addresses_ = [[NSMutableDictionary alloc] init];
|
| -
|
| - NSNumber *addressNum = [NSNumber numberWithUnsignedLongLong:(*iter).second->lowpc];
|
| -
|
| - [functionAddresses_ addObject:addressNum];
|
| -
|
| - NSMutableDictionary *dict = [addresses_ objectForKey:addressNum];
|
| -
|
| - if (!dict) {
|
| - dict = [[NSMutableDictionary alloc] init];
|
| - [addresses_ setObject:dict forKey:addressNum];
|
| - [dict release];
|
| - }
|
| -
|
| - // set name of function if it isn't already set
|
| - if (![dict objectForKey:kAddressSymbolKey]) {
|
| - 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])
|
| - [dict setObject:[NSNumber numberWithUnsignedInt:iter->second->line]
|
| - forKey:kAddressSourceLineKey];
|
| -
|
| - // set function size by subtracting low PC from high PC
|
| - if (![dict objectForKey:kFunctionSizeKey]) {
|
| - [dict setObject:[NSNumber numberWithUnsignedLongLong:iter->second->highpc - iter->second->lowpc]
|
| - forKey:kFunctionSizeKey];
|
| - }
|
| -
|
| - // Set the file that the function is in
|
| - if (![dict objectForKey:kFunctionFileKey]) {
|
| - [dict setObject:[NSString stringWithUTF8String:iter->second->file.c_str()]
|
| - forKey:kFunctionFileKey];
|
| - }
|
| - }
|
| -}
|
| -
|
| -- (void)processDWARFLineNumberInfo:(dwarf2reader::LineMap*)line_map {
|
| - for (dwarf2reader::LineMap::const_iterator iter = line_map->begin();
|
| - iter != line_map->end();
|
| - ++iter) {
|
| -
|
| - NSNumber *addressNum = [NSNumber numberWithUnsignedLongLong:iter->first];
|
| - NSMutableDictionary *dict = [addresses_ objectForKey:addressNum];
|
| -
|
| - if (!dict) {
|
| - dict = [[NSMutableDictionary alloc] init];
|
| - [addresses_ setObject:dict forKey:addressNum];
|
| - [dict release];
|
| - }
|
| -
|
| - if (iter->second.second && ![dict objectForKey:kAddressSourceLineKey]) {
|
| - [dict setObject:[NSNumber numberWithUnsignedInt:iter->second.second]
|
| - forKey:kAddressSourceLineKey];
|
| - }
|
| -
|
| - // Set the file that the function's address is in
|
| - if (![dict objectForKey:kFunctionFileKey]) {
|
| - [dict setObject:[NSString stringWithUTF8String:iter->second.first.c_str()]
|
| - forKey:kFunctionFileKey];
|
| - }
|
| - }
|
| -}
|
| -
|
| -//=============================================================================
|
| -- (BOOL)loadSTABSSymbolInfo:(void *)base offset:(uint32_t)offset {
|
| - struct mach_header *header = (struct mach_header *)((uint32_t)base + offset);
|
| - BOOL swap = (header->magic == MH_CIGAM);
|
| - uint32_t count = SwapLongIfNeeded(header->ncmds);
|
| - struct load_command *cmd =
|
| - (struct load_command *)((uint32_t)header + sizeof(struct mach_header));
|
| - uint32_t symbolTableCommand = SwapLongIfNeeded(LC_SYMTAB);
|
| - BOOL result = NO;
|
| -
|
| - if (!addresses_)
|
| - addresses_ = [[NSMutableDictionary alloc] init];
|
| -
|
| - for (uint32_t i = 0; cmd && (i < count); ++i) {
|
| - if (cmd->cmd == symbolTableCommand) {
|
| - struct symtab_command *symtab = (struct symtab_command *)cmd;
|
| - uint32_t ncmds = SwapLongIfNeeded(symtab->nsyms);
|
| - uint32_t symoff = SwapLongIfNeeded(symtab->symoff);
|
| - uint32_t stroff = SwapLongIfNeeded(symtab->stroff);
|
| - struct nlist *list = (struct nlist *)((uint32_t)base + symoff + offset);
|
| - char *strtab = ((char *)header + stroff);
|
| -
|
| - // Process each command, looking for debugging stuff
|
| - for (uint32_t j = 0; j < ncmds; ++j, ++list) {
|
| - // Fill in an nlist_64 structure and process with that
|
| - struct nlist_64 nlist64;
|
| - nlist64.n_un.n_strx = SwapLongIfNeeded(list->n_un.n_strx);
|
| - nlist64.n_type = list->n_type;
|
| - nlist64.n_sect = list->n_sect;
|
| - nlist64.n_desc = SwapShortIfNeeded(list->n_desc);
|
| - nlist64.n_value = (uint64_t)SwapLongIfNeeded(list->n_value);
|
| -
|
| - // TODO(nealsid): is this broken? we get NO if one symbol fails
|
| - // but then we lose that information if another suceeeds
|
| - if ([self processSymbolItem:&nlist64 stringTable:strtab])
|
| - result = YES;
|
| - }
|
| - }
|
| -
|
| - uint32_t cmdSize = SwapLongIfNeeded(cmd->cmdsize);
|
| - cmd = (struct load_command *)((uint32_t)cmd + cmdSize);
|
| - }
|
| -
|
| - return result;
|
| -}
|
| -
|
| -//=============================================================================
|
| -- (BOOL)loadSymbolInfo64:(void *)base offset:(uint32_t)offset {
|
| - struct mach_header_64 *header = (struct mach_header_64 *)
|
| - ((uint32_t)base + offset);
|
| - BOOL swap = (header->magic == MH_CIGAM_64);
|
| - uint32_t count = SwapLongIfNeeded(header->ncmds);
|
| - struct load_command *cmd =
|
| - (struct load_command *)((uint32_t)header + sizeof(struct mach_header));
|
| - uint32_t symbolTableCommand = SwapLongIfNeeded(LC_SYMTAB);
|
| - BOOL result = NO;
|
| -
|
| - for (uint32_t i = 0; cmd && (i < count); i++) {
|
| - if (cmd->cmd == symbolTableCommand) {
|
| - struct symtab_command *symtab = (struct symtab_command *)cmd;
|
| - uint32_t ncmds = SwapLongIfNeeded(symtab->nsyms);
|
| - uint32_t symoff = SwapLongIfNeeded(symtab->symoff);
|
| - uint32_t stroff = SwapLongIfNeeded(symtab->stroff);
|
| - struct nlist_64 *list = (struct nlist_64 *)((uint32_t)base + symoff);
|
| - char *strtab = ((char *)header + stroff);
|
| -
|
| - // Process each command, looking for debugging stuff
|
| - for (uint32_t j = 0; j < ncmds; ++j, ++list) {
|
| - if (!(list->n_type & (N_STAB | N_TYPE)))
|
| - continue;
|
| -
|
| - // Fill in an nlist_64 structure and process with that
|
| - struct nlist_64 nlist64;
|
| - nlist64.n_un.n_strx = SwapLongIfNeeded(list->n_un.n_strx);
|
| - nlist64.n_type = list->n_type;
|
| - nlist64.n_sect = list->n_sect;
|
| - nlist64.n_desc = SwapShortIfNeeded(list->n_desc);
|
| - nlist64.n_value = SwapLongLongIfNeeded(list->n_value);
|
| -
|
| - if ([self processSymbolItem:&nlist64 stringTable:strtab])
|
| - result = YES;
|
| - }
|
| - }
|
| -
|
| - uint32_t cmdSize = SwapLongIfNeeded(cmd->cmdsize);
|
| - cmd = (struct load_command *)((uint32_t)cmd + cmdSize);
|
| - }
|
| -
|
| - return result;
|
| -}
|
| -
|
| -//=============================================================================
|
| -- (BOOL)loadSymbolInfoForArchitecture {
|
| - NSMutableData *data = [[NSMutableData alloc]
|
| - initWithContentsOfMappedFile:sourcePath_];
|
| -
|
| - NSDictionary *headerInfo = [headers_ objectForKey:architecture_];
|
| - void *base = [data mutableBytes];
|
| - uint32_t offset =
|
| - [[headerInfo objectForKey:kHeaderOffsetKey] unsignedLongValue];
|
| - BOOL is64 = [[headerInfo objectForKey:kHeaderIs64BitKey] boolValue];
|
| - BOOL result = is64 ? [self loadSymbolInfo64:base offset:offset] :
|
| - [self loadSymbolInfo:base offset:offset];
|
| -
|
| - [data release];
|
| - return result;
|
| -}
|
| -
|
| -- (dwarf2reader::SectionMap*)getSectionMapForArchitecture:(NSString*)architecture {
|
| -
|
| - string currentArch([architecture UTF8String]);
|
| - dwarf2reader::SectionMap *oneArchitectureSectionMap;
|
| -
|
| - ArchSectionMap::const_iterator iter = sectionsForArch_->find(currentArch);
|
| -
|
| - if (iter == sectionsForArch_->end()) {
|
| - oneArchitectureSectionMap = new dwarf2reader::SectionMap();
|
| - sectionsForArch_->insert(make_pair(currentArch, oneArchitectureSectionMap));
|
| - } else {
|
| - oneArchitectureSectionMap = iter->second;
|
| - }
|
| -
|
| - return oneArchitectureSectionMap;
|
| -}
|
| -
|
| -//=============================================================================
|
| -// build a dictionary of section numbers keyed off a string
|
| -// which is the concatenation of the segment name and the section name
|
| -- (void)generateSectionDictionary:(struct mach_header*)header {
|
| -
|
| - BOOL swap = (header->magic == MH_CIGAM);
|
| - uint32_t count = SwapLongIfNeeded(header->ncmds);
|
| - struct load_command *cmd =
|
| - (struct load_command *)((uint32_t)header + sizeof(struct mach_header));
|
| - uint32_t segmentCommand = SwapLongIfNeeded(LC_SEGMENT);
|
| - uint32_t sectionNumber = 1; // section numbers are counted from 1
|
| -
|
| - cpu_type_t cpu = SwapIntIfNeeded(header->cputype);
|
| -
|
| - NSString *arch;
|
| -
|
| - if (cpu & CPU_ARCH_ABI64)
|
| - arch = ((cpu & ~CPU_ARCH_ABI64) == CPU_TYPE_X86) ?
|
| - @"x86_64" : @"ppc64";
|
| - else
|
| - arch = (cpu == CPU_TYPE_X86) ? @"x86" : @"ppc";
|
| -
|
| - NSMutableDictionary *archSections;
|
| -
|
| - if (!sectionData_) {
|
| - sectionData_ = [[NSMutableDictionary alloc] init];
|
| - }
|
| -
|
| - if (![sectionData_ objectForKey:architecture_]) {
|
| - [sectionData_ setObject:[[NSMutableDictionary alloc] init] forKey:arch];
|
| - }
|
| -
|
| - archSections = [sectionData_ objectForKey:arch];
|
| -
|
| - dwarf2reader::SectionMap* oneArchitectureSectionMap = [self getSectionMapForArchitecture:arch];
|
| -
|
| - // loop through every segment command, then through every section
|
| - // contained inside each of them
|
| - for (uint32_t i = 0; cmd && (i < count); ++i) {
|
| - if (cmd->cmd == segmentCommand) {
|
| - struct segment_command *seg = (struct segment_command *)cmd;
|
| - section *sect = (section *)((uint32_t)cmd + sizeof(segment_command));
|
| - uint32_t nsects = SwapLongIfNeeded(seg->nsects);
|
| -
|
| - for (uint32_t j = 0; j < nsects; ++j) {
|
| - NSString *segSectName = [NSString stringWithFormat:@"%s%s",
|
| - seg->segname, sect->sectname];
|
| -
|
| - [archSections setObject:[[MachSection alloc] initWithMachSection:sect andNumber:sectionNumber]
|
| - forKey:segSectName];
|
| -
|
| - // filter out sections with size 0, offset 0
|
| - if (sect->offset != 0 && sect->size != 0) {
|
| - // fill sectionmap for dwarf reader
|
| - oneArchitectureSectionMap->insert(make_pair(sect->sectname,make_pair(((const char*)header) + SwapLongIfNeeded(sect->offset), (size_t)SwapLongIfNeeded(sect->size))));
|
| - }
|
| -
|
| - ++sect;
|
| - ++sectionNumber;
|
| - }
|
| - }
|
| -
|
| - uint32_t cmdSize = SwapLongIfNeeded(cmd->cmdsize);
|
| - cmd = (struct load_command *)((uint32_t)cmd + cmdSize);
|
| - }
|
| -}
|
| -
|
| -//=============================================================================
|
| -- (BOOL)loadHeader:(void *)base offset:(uint32_t)offset {
|
| - struct mach_header *header = (struct mach_header *)((uint32_t)base + offset);
|
| - BOOL swap = (header->magic == MH_CIGAM);
|
| - uint32_t count = SwapLongIfNeeded(header->ncmds);
|
| - struct load_command *cmd =
|
| - (struct load_command *)((uint32_t)header + sizeof(struct mach_header));
|
| - uint32_t segmentCommand = SwapLongIfNeeded(LC_SEGMENT);
|
| -
|
| - [self generateSectionDictionary:header];
|
| -
|
| - for (uint32_t i = 0; cmd && (i < count); ++i) {
|
| - if (cmd->cmd == segmentCommand) {
|
| - struct segment_command *seg = (struct segment_command *)cmd;
|
| -
|
| - if (!strcmp(seg->segname, "__TEXT")) {
|
| - uint32_t addr = SwapLongIfNeeded(seg->vmaddr);
|
| - uint32_t size = SwapLongIfNeeded(seg->vmsize);
|
| - cpu_type_t cpu = SwapIntIfNeeded(header->cputype);
|
| - NSString *cpuStr = (cpu == CPU_TYPE_I386) ? @"x86" : @"ppc";
|
| -
|
| - [headers_ setObject:[NSDictionary dictionaryWithObjectsAndKeys:
|
| - [NSNumber numberWithUnsignedLongLong:(uint64_t)addr],
|
| - kHeaderBaseAddressKey,
|
| - [NSNumber numberWithUnsignedLongLong:(uint64_t)size], kHeaderSizeKey,
|
| - [NSNumber numberWithUnsignedLong:offset], kHeaderOffsetKey,
|
| - [NSNumber numberWithBool:NO], kHeaderIs64BitKey,
|
| - [NSNumber numberWithUnsignedLong:cpu], kHeaderCPUTypeKey,
|
| - nil] forKey:cpuStr];
|
| -
|
| - return YES;
|
| - }
|
| - }
|
| -
|
| - uint32_t cmdSize = SwapLongIfNeeded(cmd->cmdsize);
|
| - cmd = (struct load_command *)((uint32_t)cmd + cmdSize);
|
| - }
|
| -
|
| - return NO;
|
| -}
|
| -
|
| -//=============================================================================
|
| -- (BOOL)loadHeader64:(void *)base offset:(uint32_t)offset {
|
| - struct mach_header_64 *header =
|
| - (struct mach_header_64 *)((uint32_t)base + offset);
|
| - BOOL swap = (header->magic == MH_CIGAM_64);
|
| - uint32_t count = SwapLongIfNeeded(header->ncmds);
|
| - struct load_command *cmd =
|
| - (struct load_command *)((uint32_t)header + sizeof(struct mach_header_64));
|
| -
|
| - for (uint32_t i = 0; cmd && (i < count); ++i) {
|
| - uint32_t segmentCommand = SwapLongIfNeeded(LC_SEGMENT_64);
|
| - if (cmd->cmd == segmentCommand) {
|
| - struct segment_command_64 *seg = (struct segment_command_64 *)cmd;
|
| - if (!strcmp(seg->segname, "__TEXT")) {
|
| - uint64_t addr = SwapLongLongIfNeeded(seg->vmaddr);
|
| - uint64_t size = SwapLongLongIfNeeded(seg->vmsize);
|
| - cpu_type_t cpu = SwapIntIfNeeded(header->cputype);
|
| - cpu &= (~CPU_ARCH_ABI64);
|
| - NSString *cpuStr = (cpu == CPU_TYPE_I386) ? @"x86_64" : @"ppc64";
|
| -
|
| - [headers_ setObject:[NSDictionary dictionaryWithObjectsAndKeys:
|
| - [NSNumber numberWithUnsignedLongLong:addr], kHeaderBaseAddressKey,
|
| - [NSNumber numberWithUnsignedLongLong:size], kHeaderSizeKey,
|
| - [NSNumber numberWithUnsignedLong:offset], kHeaderOffsetKey,
|
| - [NSNumber numberWithBool:YES], kHeaderIs64BitKey,
|
| - [NSNumber numberWithUnsignedLong:cpu], kHeaderCPUTypeKey,
|
| - nil] forKey:cpuStr];
|
| - return YES;
|
| - }
|
| - }
|
| -
|
| - uint32_t cmdSize = SwapLongIfNeeded(cmd->cmdsize);
|
| - cmd = (struct load_command *)((uint32_t)cmd + cmdSize);
|
| - }
|
| -
|
| - return NO;
|
| -}
|
| -
|
| -//=============================================================================
|
| -- (BOOL)loadModuleInfo {
|
| - uint64_t result = 0;
|
| - NSMutableData *data = [[NSMutableData alloc]
|
| - initWithContentsOfMappedFile:sourcePath_];
|
| - void *bytes = [data mutableBytes];
|
| - struct fat_header *fat = (struct fat_header *)bytes;
|
| -
|
| - if (!fat) {
|
| - [data release];
|
| - return 0;
|
| - }
|
| -
|
| - // Gather some information based on the header
|
| - BOOL isFat = fat->magic == FAT_MAGIC || fat->magic == FAT_CIGAM;
|
| - BOOL is64 = fat->magic == MH_MAGIC_64 || fat->magic == MH_CIGAM_64;
|
| - BOOL is32 = fat->magic == MH_MAGIC || fat->magic == MH_CIGAM;
|
| - BOOL swap = fat->magic == FAT_CIGAM || fat->magic == MH_CIGAM_64 ||
|
| - fat->magic == MH_CIGAM;
|
| -
|
| - if (!is64 && !is32 && !isFat) {
|
| - [data release];
|
| - return 0;
|
| - }
|
| -
|
| - // Load any available architectures and save the information
|
| - headers_ = [[NSMutableDictionary alloc] init];
|
| -
|
| - if (isFat) {
|
| - struct fat_arch *archs =
|
| - (struct fat_arch *)((uint32_t)fat + sizeof(struct fat_header));
|
| - uint32_t count = SwapLongIfNeeded(fat->nfat_arch);
|
| -
|
| - for (uint32_t i = 0; i < count; ++i) {
|
| - archs[i].cputype = SwapIntIfNeeded(archs[i].cputype);
|
| - archs[i].cpusubtype = SwapIntIfNeeded(archs[i].cpusubtype);
|
| - archs[i].offset = SwapLongIfNeeded(archs[i].offset);
|
| - archs[i].size = SwapLongIfNeeded(archs[i].size);
|
| - archs[i].align = SwapLongIfNeeded(archs[i].align);
|
| -
|
| - if (archs[i].cputype & CPU_ARCH_ABI64)
|
| - result = [self loadHeader64:bytes offset:archs[i].offset];
|
| - else
|
| - result = [self loadHeader:bytes offset:archs[i].offset];
|
| - }
|
| - } else if (is32) {
|
| - result = [self loadHeader:bytes offset:0];
|
| - } else {
|
| - result = [self loadHeader64:bytes offset:0];
|
| - }
|
| -
|
| - [data release];
|
| - return result;
|
| -}
|
| -
|
| -//=============================================================================
|
| -static BOOL WriteFormat(int fd, const char *fmt, ...) {
|
| - va_list list;
|
| - char buffer[4096];
|
| - ssize_t expected, written;
|
| -
|
| - va_start(list, fmt);
|
| - vsnprintf(buffer, sizeof(buffer), fmt, list);
|
| - expected = strlen(buffer);
|
| - written = write(fd, buffer, strlen(buffer));
|
| - va_end(list);
|
| -
|
| - return expected == written;
|
| -}
|
| -
|
| -//=============================================================================
|
| -- (BOOL)outputSymbolFile:(int)fd {
|
| - // Get the baseAddress for this architecture
|
| - NSDictionary *archDict = [headers_ objectForKey:architecture_];
|
| - NSNumber *baseAddressNum = [archDict objectForKey:kHeaderBaseAddressKey];
|
| - uint64_t baseAddress =
|
| - baseAddressNum ? [baseAddressNum unsignedLongLongValue] : 0;
|
| - NSNumber *moduleSizeNum = [archDict objectForKey:kHeaderSizeKey];
|
| - uint64_t moduleSize =
|
| - moduleSizeNum ? [moduleSizeNum unsignedLongLongValue] : 0;
|
| -
|
| - // UUID
|
| - FileID file_id([sourcePath_ fileSystemRepresentation]);
|
| - unsigned char identifier[16];
|
| - char identifierStr[40];
|
| - const char *moduleName = [[sourcePath_ lastPathComponent] UTF8String];
|
| - int cpu_type = [[archDict objectForKey:kHeaderCPUTypeKey] unsignedLongValue];
|
| - if (file_id.MachoIdentifier(cpu_type, identifier)) {
|
| - FileID::ConvertIdentifierToString(identifier, identifierStr,
|
| - sizeof(identifierStr));
|
| - }
|
| - else {
|
| - fprintf(stderr, "Unable to calculate UUID of mach-o binary!\n");
|
| - return NO;
|
| - }
|
| -
|
| - // keep track exclusively of function addresses
|
| - // for sanity checking function lengths
|
| - functionAddresses_ = [[NSMutableSet alloc] init];
|
| -
|
| - // Gather the information
|
| - [self loadSymbolInfoForArchitecture];
|
| -
|
| - NSArray *sortedAddresses = [[addresses_ allKeys]
|
| - sortedArrayUsingSelector:@selector(compare:)];
|
| -
|
| - NSArray *sortedFunctionAddresses = [[functionAddresses_ allObjects]
|
| - sortedArrayUsingSelector:@selector(compare:)];
|
| -
|
| - // position ourselves at the 2nd function
|
| - unsigned int funcIndex = 1;
|
| -
|
| - // Remove the dashes from the string
|
| - NSMutableString *compactedStr =
|
| - [NSMutableString stringWithCString:identifierStr encoding:NSASCIIStringEncoding];
|
| - [compactedStr replaceOccurrencesOfString:@"-" withString:@"" options:0
|
| - range:NSMakeRange(0, [compactedStr length])];
|
| -
|
| - if (!WriteFormat(fd, "MODULE mac %s %s0 %s\n", [architecture_ UTF8String],
|
| - [compactedStr UTF8String], moduleName)) {
|
| - return NO;
|
| - }
|
| -
|
| - // Sources ordered by address
|
| - NSArray *sources = [[sources_ allKeys]
|
| - sortedArrayUsingSelector:@selector(compare:)];
|
| - NSMutableDictionary *fileNameToFileIndex = [[NSMutableDictionary alloc] init];
|
| - unsigned int sourceCount = [sources count];
|
| - for (unsigned int i = 0; i < sourceCount; ++i) {
|
| - NSString *file = [sources_ objectForKey:[sources objectAtIndex:i]];
|
| - if (!WriteFormat(fd, "FILE %d %s\n", i + 1, [file UTF8String]))
|
| - return NO;
|
| -
|
| - [fileNameToFileIndex setObject:[NSNumber numberWithUnsignedInt:i+1]
|
| - forKey:file];
|
| - }
|
| -
|
| - // Symbols
|
| - char terminatingChar = '\n';
|
| - uint32_t fileIdx = 0, nextFileIdx = 0;
|
| - uint64_t nextSourceFileAddress = 0;
|
| - NSNumber *nextAddress;
|
| - uint64_t nextAddressVal;
|
| - unsigned int addressCount = [sortedAddresses count];
|
| -
|
| - bool insideFunction = false;
|
| -
|
| - for (unsigned int i = 0; i < addressCount; ++i) {
|
| - NSNumber *address = [sortedAddresses objectAtIndex:i];
|
| - // skip sources that have a starting address of 0
|
| - if ([address unsignedLongValue] == 0) {
|
| - continue;
|
| - }
|
| -
|
| - uint64_t addressVal = [address unsignedLongLongValue] - baseAddress;
|
| -
|
| - // Get the next address to calculate the length
|
| - if (i + 1 < addressCount) {
|
| - nextAddress = [sortedAddresses objectAtIndex:i + 1];
|
| - nextAddressVal = [nextAddress unsignedLongLongValue] - baseAddress;
|
| - } else {
|
| - nextAddressVal = baseAddress + moduleSize;
|
| - // The symbol reader doesn't want a trailing newline
|
| - terminatingChar = '\0';
|
| - }
|
| -
|
| - NSDictionary *dict = [addresses_ objectForKey:address];
|
| - NSNumber *line = [dict objectForKey:kAddressSourceLineKey];
|
| - NSString *symbol = [dict objectForKey:kAddressConvertedSymbolKey];
|
| -
|
| - if (!symbol)
|
| - symbol = [dict objectForKey:kAddressSymbolKey];
|
| -
|
| - // sanity check the function length by making sure it doesn't
|
| - // run beyond the next function entry
|
| - uint64_t nextFunctionAddress = 0;
|
| - if (symbol && funcIndex < [sortedFunctionAddresses count]) {
|
| - nextFunctionAddress = [[sortedFunctionAddresses objectAtIndex:funcIndex]
|
| - unsignedLongLongValue] - baseAddress;
|
| - ++funcIndex;
|
| - }
|
| -
|
| - // Skip some symbols
|
| - if ([symbol hasPrefix:@"vtable for"])
|
| - continue;
|
| -
|
| - if ([symbol hasPrefix:@"__static_initialization_and_destruction_0"])
|
| - continue;
|
| -
|
| - if ([symbol hasPrefix:@"_GLOBAL__I_"])
|
| - continue;
|
| -
|
| - if ([symbol hasPrefix:@"__func__."])
|
| - continue;
|
| -
|
| - if ([symbol hasPrefix:@"__gnu"])
|
| - continue;
|
| -
|
| - if ([symbol hasPrefix:@"typeinfo "])
|
| - continue;
|
| -
|
| - if ([symbol hasPrefix:@"EH_frame"])
|
| - continue;
|
| -
|
| - 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;
|
| -
|
| - if (nextFileIdx < sourceCount) {
|
| - NSNumber *addr = [sources objectAtIndex:nextFileIdx];
|
| - ++nextFileIdx;
|
| - nextSourceFileAddress = [addr unsignedLongLongValue] - baseAddress;
|
| - } else {
|
| - nextSourceFileAddress = baseAddress + moduleSize;
|
| - break;
|
| - }
|
| - }
|
| -
|
| - NSNumber *functionLength = [dict objectForKey:kFunctionSizeKey];
|
| -
|
| - if (line) {
|
| - if (symbol && functionLength) {
|
| -
|
| - uint64_t functionLengthVal = [functionLength unsignedLongLongValue];
|
| -
|
| - insideFunction = true;
|
| - // sanity check to make sure the length we were told does not exceed
|
| - // the space between this function and the next
|
| - if (nextFunctionAddress != 0) {
|
| - uint64_t functionLengthVal2 = nextFunctionAddress - addressVal;
|
| -
|
| - if(functionLengthVal > functionLengthVal2 ) {
|
| - functionLengthVal = functionLengthVal2;
|
| - }
|
| - }
|
| -
|
| - // Function
|
| - if (!WriteFormat(fd, "FUNC %llx %llx 0 %s\n", addressVal,
|
| - functionLengthVal, [symbol UTF8String]))
|
| - return NO;
|
| - }
|
| -
|
| - // Throw out line number information that doesn't correspond to
|
| - // any function
|
| - if (insideFunction) {
|
| - // Source line
|
| - uint64_t length = nextAddressVal - addressVal;
|
| -
|
| - // if fileNameToFileIndex/dict has an entry for the
|
| - // file/kFunctionFileKey, we're processing DWARF and have stored
|
| - // files for each program counter. If there is no entry, we're
|
| - // processing STABS and can use the old method of mapping
|
| - // addresses to files(which was basically iterating over a set
|
| - // of addresses until we reached one that was greater than the
|
| - // high PC of the current file, then moving on to the next file)
|
| - NSNumber *fileIndex = [fileNameToFileIndex objectForKey:[dict objectForKey:kFunctionFileKey]];
|
| - if (!WriteFormat(fd, "%llx %llx %d %d\n", addressVal, length,
|
| - [line unsignedIntValue], fileIndex ? [fileIndex unsignedIntValue] : fileIdx))
|
| - return NO;
|
| - }
|
| - } else {
|
| - // PUBLIC <address> <stack-size> <name>
|
| - if (!WriteFormat(fd, "PUBLIC %llx 0 %s\n", addressVal,
|
| - [symbol UTF8String]))
|
| - return NO;
|
| - insideFunction = false;
|
| - }
|
| - }
|
| -
|
| - return YES;
|
| -}
|
| -
|
| -//=============================================================================
|
| -- (id)initWithContentsOfFile:(NSString *)path {
|
| - if ((self = [super init])) {
|
| -
|
| - if (![[NSFileManager defaultManager] fileExistsAtPath:path]) {
|
| - [self autorelease];
|
| - return nil;
|
| - }
|
| -
|
| - sourcePath_ = [path copy];
|
| -
|
| - // Test for .DSYM bundle
|
| - NSBundle *dsymBundle = [NSBundle bundleWithPath:sourcePath_];
|
| -
|
| - if (dsymBundle) {
|
| -
|
| - // we need to take the DSYM bundle path and remove it's
|
| - // extension to get the name of the file inside the resources
|
| - // directory of the bundle that actually has the DWARF
|
| - // information
|
| - // But, Xcode supports something called "Wrapper extension"(see
|
| - // build settings), which would make the bundle name
|
| - // /tmp/foo/test.kext.dSYM, but the dwarf binary name would
|
| - // still be "test". so, now we loop through until deleting the
|
| - // extension doesn't change the string
|
| -
|
| - // e.g. suppose sourcepath_ is /tmp/foo/test.dSYM
|
| -
|
| - NSString *dwarfBinName = [sourcePath_ lastPathComponent];
|
| - NSString *dwarfBinPath;
|
| -
|
| - // We use a do/while loop so we can handle files without an extension
|
| - do {
|
| - dwarfBinName = [dwarfBinName stringByDeletingPathExtension];
|
| - // now, dwarfBinName is "test"
|
| - dwarfBinPath = [dsymBundle pathForResource:dwarfBinName ofType:nil inDirectory:@"DWARF"];
|
| - if (dwarfBinPath != nil)
|
| - break;
|
| - } while (![[dwarfBinName stringByDeletingPathExtension] isEqualToString:dwarfBinName]);
|
| -
|
| - if (dwarfBinPath == nil) {
|
| - NSLog(@"The bundle passed on the command line does not appear to be a DWARF dSYM bundle");
|
| - [self autorelease];
|
| - return nil;
|
| - }
|
| -
|
| - // otherwise we're good to go
|
| - [sourcePath_ release];
|
| -
|
| - sourcePath_ = [dwarfBinPath copy];
|
| - NSLog(@"Loading DWARF dSYM file from %@", sourcePath_);
|
| - }
|
| -
|
| - sectionsForArch_ = new ArchSectionMap();
|
| -
|
| - if (![self loadModuleInfo]) {
|
| - [self autorelease];
|
| - return nil;
|
| - }
|
| -
|
| - // If there's more than one, use the native one
|
| - if ([headers_ count] > 1) {
|
| - const NXArchInfo *localArchInfo = NXGetLocalArchInfo();
|
| -
|
| - if (localArchInfo) {
|
| - cpu_type_t cpu = localArchInfo->cputype;
|
| - NSString *arch;
|
| -
|
| - if (cpu & CPU_ARCH_ABI64)
|
| - arch = ((cpu & ~CPU_ARCH_ABI64) == CPU_TYPE_X86) ?
|
| - @"x86_64" : @"ppc64";
|
| - else
|
| - arch = (cpu == CPU_TYPE_X86) ? @"x86" : @"ppc";
|
| -
|
| - [self setArchitecture:arch];
|
| - }
|
| - } else {
|
| - // Specify the default architecture
|
| - [self setArchitecture:[[headers_ allKeys] objectAtIndex:0]];
|
| - }
|
| - }
|
| -
|
| - return self;
|
| -}
|
| -
|
| -//=============================================================================
|
| -- (NSArray *)availableArchitectures {
|
| - return [headers_ allKeys];
|
| -}
|
| -
|
| -//=============================================================================
|
| -- (void)dealloc {
|
| - [sourcePath_ release];
|
| - [architecture_ release];
|
| - [addresses_ release];
|
| - [functionAddresses_ release];
|
| - [sources_ release];
|
| - [headers_ release];
|
| - delete sectionsForArch_;
|
| -
|
| - [super dealloc];
|
| -}
|
| -
|
| -//=============================================================================
|
| -- (BOOL)setArchitecture:(NSString *)architecture {
|
| - NSString *normalized = [architecture lowercaseString];
|
| - BOOL isValid = NO;
|
| -
|
| - if ([normalized isEqualToString:@"ppc"]) {
|
| - isValid = YES;
|
| - }
|
| - else if ([normalized isEqualToString:@"i386"]) {
|
| - normalized = @"x86";
|
| - isValid = YES;
|
| - }
|
| - else if ([normalized isEqualToString:@"x86"]) {
|
| - isValid = YES;
|
| - }
|
| - else if ([normalized isEqualToString:@"ppc64"]) {
|
| - isValid = YES;
|
| - }
|
| - else if ([normalized isEqualToString:@"x86_64"]) {
|
| - isValid = YES;
|
| - }
|
| -
|
| - if (isValid) {
|
| - if (![headers_ objectForKey:normalized])
|
| - return NO;
|
| -
|
| - [architecture_ autorelease];
|
| - architecture_ = [normalized copy];
|
| - }
|
| -
|
| - return isValid;
|
| -}
|
| -
|
| -//=============================================================================
|
| -- (NSString *)architecture {
|
| - return architecture_;
|
| -}
|
| -
|
| -//=============================================================================
|
| -- (BOOL)writeSymbolFile:(NSString *)destinationPath {
|
| - const char *dest = [destinationPath fileSystemRepresentation];
|
| - int fd;
|
| -
|
| - if ([[destinationPath substringToIndex:1] isEqualToString:@"-"])
|
| - fd = STDOUT_FILENO;
|
| - else
|
| - fd = open(dest, O_WRONLY | O_CREAT | O_TRUNC, 0666);
|
| -
|
| - if (fd == -1)
|
| - return NO;
|
| -
|
| - BOOL result = [self outputSymbolFile:fd];
|
| -
|
| - close(fd);
|
| -
|
| - return result;
|
| -}
|
| -
|
| -@end
|
| -
|
| -@implementation MachSection
|
| -
|
| -- (id)initWithMachSection:(section *)sect andNumber:(uint32_t)sectionNumber {
|
| - if ((self = [super init])) {
|
| - sect_ = sect;
|
| - sectionNumber_ = sectionNumber;
|
| - }
|
| -
|
| - return self;
|
| -}
|
| -
|
| -- (section*)sectionPointer {
|
| - return sect_;
|
| -}
|
| -
|
| -- (uint32_t)sectionNumber {
|
| - return sectionNumber_;
|
| -}
|
| -@end
|
|
|