diff options
author | waylonis <waylonis@4c0a9323-5329-0410-9bdc-e9ce6186880e> | 2007-01-23 19:17:03 +0000 |
---|---|---|
committer | waylonis <waylonis@4c0a9323-5329-0410-9bdc-e9ce6186880e> | 2007-01-23 19:17:03 +0000 |
commit | d31c8b02925a1b20c09ee9ab771322353aea6267 (patch) | |
tree | 42696ec49303b9b114b05e8d8352b43e2f0b0a0a /src/common/mac/dump_syms.m | |
parent | Library to handle SymSrv integration (#111). r=bryner (diff) | |
download | breakpad-d31c8b02925a1b20c09ee9ab771322353aea6267.tar.xz |
Changes to support patch #108:
- Calculate unique file id for mach-o files
- Add file id support to dump_syms and symupload tools
- Fix return values of tools to indicate success or failure
- Change dump_syms class to be Objective-C++
git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@109 4c0a9323-5329-0410-9bdc-e9ce6186880e
Diffstat (limited to 'src/common/mac/dump_syms.m')
-rw-r--r-- | src/common/mac/dump_syms.m | 808 |
1 files changed, 0 insertions, 808 deletions
diff --git a/src/common/mac/dump_syms.m b/src/common/mac/dump_syms.m deleted file mode 100644 index d133e120..00000000 --- a/src/common/mac/dump_syms.m +++ /dev/null @@ -1,808 +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.m: Create a symbol file for use with minidumps - -#include <unistd.h> -#include <signal.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> - -#import <Foundation/Foundation.h> - -#import "dump_syms.h" - -static NSString *kAddressSymbolKey = @"symbol"; -static NSString *kAddressConvertedSymbolKey = @"converted_symbol"; -static NSString *kAddressSourceLineKey = @"line"; -static NSString *kFunctionSizeKey = @"size"; -static NSString *kHeaderBaseAddressKey = @"baseAddr"; -static NSString *kHeaderSizeKey = @"size"; -static NSString *kHeaderOffsetKey = @"offset"; // Offset to the header -static NSString *kHeaderIs64BitKey = @"is64"; -static NSString *kUnknownSymbol = @"???"; - -@interface DumpSymbols(PrivateMethods) -- (NSString *)stringFromTask:(NSString *)action args:(NSArray *)args - standardIn:(NSFileHandle *)standardIn; -- (NSArray *)convertCPlusPlusSymbols:(NSArray *)symbols; -- (void)convertSymbols; -- (void)addFunction:(NSString *)name line:(int)line address:(uint64_t)address; -- (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)loadHeader:(void *)base offset:(uint32_t)offset; -- (BOOL)loadHeader64:(void *)base offset:(uint32_t)offset; -- (BOOL)loadModuleInfo; -- (NSMutableString *)generateSymbolFileString; -@end - -@implementation DumpSymbols -//============================================================================= -- (NSString *)stringFromTask:(NSString *)action args:(NSArray *)args - standardIn:(NSFileHandle *)standardIn { - NSTask *task = [[NSTask alloc] init]; - [task setLaunchPath:action]; - NSPipe *pipe = [NSPipe pipe]; - [task setStandardOutput:pipe]; - NSFileHandle *output = [pipe fileHandleForReading]; - - if (standardIn) - [task setStandardInput:standardIn]; - - if (args) - [task setArguments:args]; - - [task launch]; - - // This seems a bit strange, but when using [task waitUntilExit], it hangs - // waiting for data, but there isn't any. So, we'll poll for data, - // take a short nap, and then ask again - BOOL done = NO; - NSMutableData *allData = [NSMutableData data]; - NSData *data = nil; - int exceptionCount = 0; - - while (!done) { - data = nil; - // If there's a communications problem with the task, this might throw - // an exception. We'll catch and keep trying. - @try { - data = [output availableData]; - } - @catch (NSException *e) { - ++exceptionCount; - } - - [allData appendData:data]; - - // Loop over the data until we're no longer returning data. If we're - // still receiving data, sleep for 1/2 second and let the task - // continue. If we keep receiving exceptions, bail out - if (![data length] && data || exceptionCount > 10) - done = YES; - else - usleep(500); - } - - // Gather any remaining data - [task waitUntilExit]; - data = [output availableData]; - [allData appendData:data]; - [task release]; - - return [[[NSString alloc] initWithData:allData - encoding:NSUTF8StringEncoding] autorelease]; -} - -//============================================================================= -- (NSArray *)convertCPlusPlusSymbols:(NSArray *)symbols { - NSString *action = @"/usr/bin/c++filt"; - int count = [symbols count]; - - // It's possible that we have too many symbols on the command line. - // Unfortunately, c++filt doesn't take a file containing names, so we'll - // copy the symbols to a temporary file and use that as stdin. - char buffer[PATH_MAX]; - snprintf(buffer, sizeof(buffer), "/tmp/dump_syms_filtXXXXX"); - int fd = mkstemp(buffer); - char nl = '\n'; - for (unsigned int i = 0; i < count; ++i) { - const char *symbol = [[symbols objectAtIndex:i] UTF8String]; - write(fd, symbol, strlen(symbol)); - write(fd, &nl, 1); - } - - // Reset to the beginning and wrap up with a file handle - lseek(fd, 0, SEEK_SET); - NSArray *args = [NSArray arrayWithObject:@"-n"]; - NSFileHandle *fh = [[NSFileHandle alloc] initWithFileDescriptor:fd - closeOnDealloc:YES]; - NSArray *result = [[self stringFromTask:action args:args standardIn:fh] - componentsSeparatedByString:@"\n"]; - - [fh release]; - - return result; -} - -//============================================================================= -- (void)convertSymbols { - unsigned int count = [cppAddresses_ count]; - NSMutableArray *symbols = [[NSMutableArray alloc] initWithCapacity:count]; - - // Sort addresses for processing - NSArray *addresses = [cppAddresses_ sortedArrayUsingSelector: - @selector(compare:)]; - - for (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]; - } - - NSArray *converted = [self convertCPlusPlusSymbols:symbols]; - [symbols release]; - - for (int i = 0; i < count; ++i) { - NSMutableDictionary *dict = [addresses_ objectForKey: - [addresses objectAtIndex:i]]; - NSString *symbol = [converted objectAtIndex:i]; - - // Only add if this is a non-zero length symbol - if ([symbol length]) - [dict setObject:symbol forKey:kAddressConvertedSymbolKey]; - } -} - -//============================================================================= -- (void)addFunction:(NSString *)name line:(int)line address:(uint64_t)address { - NSNumber *addressNum = [NSNumber numberWithUnsignedLongLong:address]; - - 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 - BOOL isCPP = NO; - if ([name length] > 3) { - unichar buffer[3]; - [name getCharacters:buffer range:NSMakeRange(0, 3)]; - if (buffer[0] == '_') { - if (buffer[1] == '_' && buffer[2] == 'Z') { - // Remove the leading underscore - name = [name substringFromIndex:1]; - isCPP = YES; - } else if (buffer[1] == 'Z') { - isCPP = YES; - } - } - } - - if (isCPP) { - // Check if this is some debug symbol that ends in ".eh" I appears as - // though it's got to do with exception handling, but it's not the - // actual address of the function. So we'll ignore them - if ([[name substringFromIndex:[name length] - 3] isEqualToString:@".eh"]) - return; - - if (!cppAddresses_) - cppAddresses_ = [[NSMutableArray alloc] init]; - [cppAddresses_ addObject:addressNum]; - } 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]; - - if (line && ![dict objectForKey:kAddressSourceLineKey]) - [dict setObject:[NSNumber numberWithUnsignedInt:line] - forKey:kAddressSourceLineKey]; - - // Save the function name so that we can add the end of function address - if ([name length]) - lastFunctionStart_ = addressNum; -} - -//============================================================================= -- (BOOL)processSymbolItem:(struct nlist_64 *)list stringTable:(char *)table { - uint32_t n_strx = list->n_un.n_strx; - BOOL result = NO; - - // 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]; - - // 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] || !range.length) - return NO; - - // The function has a ":" followed by some stuff - fn = [fn substringToIndex:range.location]; - [self addFunction:fn line:list->n_desc address:list->n_value]; - result = YES; - } else if (list->n_type == N_SLINE) { - [self addFunction:nil line:list->n_desc address:list->n_value]; - 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]; - result = YES; - } else if (list->n_type == N_ENSYM) { - // End of symbols for current function - if (lastFunctionStart_) { - unsigned long long start = [lastFunctionStart_ unsignedLongLongValue]; - unsigned long long size = list->n_value - start; - NSMutableDictionary *dict = [addresses_ objectForKey:lastFunctionStart_]; - assert(dict); - [dict setObject:[NSNumber numberWithUnsignedLongLong:size] - forKey:kFunctionSizeKey]; - } - } - - 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 { - struct mach_header *header = (struct mach_header *)(base + offset); - BOOL swap = (header->magic == MH_CIGAM); - uint32_t count = SwapLongIfNeeded(header->ncmds); - struct load_command *cmd = (void *)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 *)(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 = { - .n_un.n_strx = SwapLongIfNeeded(list->n_un.n_strx), - .n_type = list->n_type, - .n_sect = list->n_sect, - .n_desc = SwapIntIfNeeded(list->n_desc), - .n_value = (uint64_t)SwapLongIfNeeded(list->n_value) - }; - - if ([self processSymbolItem:&nlist64 stringTable:strtab]) - result = YES; - } - } - - uint32_t cmdSize = SwapLongIfNeeded(cmd->cmdsize); - cmd = (struct load_command *)((char *)cmd + cmdSize); - } - - return result; -} - -//============================================================================= -- (BOOL)loadSymbolInfo64:(void *)base offset:(uint32_t)offset { - struct mach_header_64 *header = (struct mach_header_64 *)(base + offset); - BOOL swap = (header->magic == MH_CIGAM_64); - uint32_t count = SwapLongIfNeeded(header->ncmds); - struct load_command *cmd = (void *)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 *)(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 = { - .n_un.n_strx = SwapLongIfNeeded(list->n_un.n_strx), - .n_type = list->n_type, - .n_sect = list->n_sect, - .n_desc = SwapIntIfNeeded(list->n_desc), - .n_value = SwapLongLongIfNeeded(list->n_value) - }; - - if ([self processSymbolItem:&nlist64 stringTable:strtab]) - result = YES; - } - } - - uint32_t cmdSize = SwapLongIfNeeded(cmd->cmdsize); - cmd = (struct load_command *)((char *)cmd + cmdSize); - } - - return result; -} - -//============================================================================= -- (BOOL)loadSymbolInfoForArchitecture { - NSMutableData *data = [[NSMutableData alloc] - initWithContentsOfMappedFile:sourcePath_]; - NSDictionary *headerInfo = [headers_ objectForKey:architecture_]; - char *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; -} - -//============================================================================= -- (BOOL)loadHeader:(void *)base offset:(uint32_t)offset { - struct mach_header *header = (struct mach_header *)(base + offset); - BOOL swap = (header->magic == MH_CIGAM); - uint32_t count = SwapLongIfNeeded(header->ncmds); - struct load_command *cmd = (void *)header + sizeof(struct mach_header); - - for (uint32_t i = 0; cmd && (i < count); i++) { - uint32_t segmentCommand = SwapLongIfNeeded(LC_SEGMENT); - 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, - nil] forKey:cpuStr]; - - return YES; - } - } - - uint32_t cmdSize = SwapLongIfNeeded(cmd->cmdsize); - cmd = (struct load_command *)((char *)cmd + cmdSize); - } - - return NO; -} - -//============================================================================= -- (BOOL)loadHeader64:(void *)base offset:(uint32_t)offset { - struct mach_header_64 *header = (struct mach_header_64 *)(base + offset); - BOOL swap = (header->magic == MH_CIGAM_64); - uint32_t count = SwapLongIfNeeded(header->ncmds); - struct load_command *cmd = (void *)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, - nil] forKey:cpuStr]; - return YES; - } - } - - uint32_t cmdSize = SwapLongIfNeeded(cmd->cmdsize); - cmd = (struct load_command *)((char *)cmd + cmdSize); - } - - return NO; -} - -//============================================================================= -- (BOOL)loadModuleInfo { - uint64_t result = 0; - NSMutableData *data = [[NSMutableData alloc] - initWithContentsOfMappedFile:sourcePath_]; - char *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 *)((void *)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; - - lastFunctionStart_ = nil; - - // Gather the information - [self loadSymbolInfoForArchitecture]; - [self convertSymbols]; - - NSArray *sortedAddresses = [[addresses_ allKeys] - sortedArrayUsingSelector:@selector(compare:)]; - - // Module - if (!WriteFormat(fd, "MODULE mac %s %s 1 %s\n", [architecture_ UTF8String], - [uuidStr_ UTF8String], - [[sourcePath_ lastPathComponent] UTF8String])) - return NO; - - // Sources ordered by address - NSArray *sources = [[sources_ allKeys] - sortedArrayUsingSelector:@selector(compare:)]; - int sourceCount = [sources count]; - for (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; - } - - // Symbols - char terminatingChar = '\n'; - uint32_t fileIdx = 0, nextFileIdx = 0; - uint64_t nextSourceFileAddress = 0; - NSNumber *nextAddress; - uint64_t nextAddressVal; - int addressCount = [sortedAddresses count]; - - for (int i = 0; i < addressCount; ++i) { - NSNumber *address = [sortedAddresses objectAtIndex:i]; - 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]; - - // 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; - } - } - - if (!symbol) - symbol = [dict objectForKey:kAddressSymbolKey]; - - if (line) { - if (symbol) { - NSNumber *functionLength = [dict objectForKey:kFunctionSizeKey]; - uint64_t functionLengthVal = [functionLength unsignedLongLongValue]; - - // Function - if (!WriteFormat(fd, "FUNC %llx %llx 0 %s%c", addressVal, - functionLengthVal, [symbol UTF8String], - terminatingChar)) - return NO; - } - - // Source line - uint64_t length = nextAddressVal - addressVal; - if (!WriteFormat(fd, "%llx %llx %d %d%c", addressVal, length, - [line unsignedIntValue], fileIdx, terminatingChar)) - return NO; - } else { - // PUBLIC <address> <stack-size> <name> - if (!WriteFormat(fd, "PUBLIC %llx 0 %s%c", addressVal, - [symbol UTF8String], terminatingChar)) - return NO; - } - } - - return YES; -} - -//============================================================================= -- (id)initWithContentsOfFile:(NSString *)path { - if (self = [super init]) { - - if (![[NSFileManager defaultManager] fileExistsAtPath:path]) { - NSLog(@"Missing source file: %@", path); - [self autorelease]; - return nil; - } - - sourcePath_ = [path copy]; - - if (![self loadModuleInfo]) { - NSLog(@"Not a valid Mach-o file: %@", path); - [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]]; - } - - [self setUUID:nil]; - } - - return self; -} - -//============================================================================= -- (NSArray *)availableArchitectures { - return [headers_ allKeys]; -} - -//============================================================================= -- (void)dealloc { - [sourcePath_ release]; - [architecture_ release]; - [uuidStr_ release]; - [addresses_ release]; - [sources_ release]; - [headers_ release]; - - [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_ = [architecture copy]; - } - - return isValid; -} - -//============================================================================= -- (NSString *)architecture { - return architecture_; -} - -//============================================================================= -- (void)setUUID:(NSString *)uuidStr { - if (!uuidStr) { - CFUUIDRef uuid = CFUUIDCreate(NULL); - uuidStr = [(NSString *)CFUUIDCreateString(NULL, uuid) autorelease]; - } - - [uuidStr_ autorelease]; - uuidStr_ = [uuidStr copy]; -} - -//============================================================================= -- (NSString *)uuid { - return uuidStr_; -} - -//============================================================================= -- (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 |