| // -*- mode: ObjC -*- |
| |
| // This file is part of class-dump, a utility for examining the Objective-C segment of Mach-O files. |
| // Copyright (C) 1997-1998, 2000-2001, 2004-2011 Steve Nygard. |
| |
| #import "CDLCSymbolTable.h" |
| |
| #include <mach-o/nlist.h> |
| #import "CDMachOFile.h" |
| #import "CDSymbol.h" |
| #import "CDLCSegment.h" |
| |
| @implementation CDLCSymbolTable |
| |
| - (id)initWithDataCursor:(CDMachOFileDataCursor *)cursor; |
| { |
| if ((self = [super initWithDataCursor:cursor])) { |
| symtabCommand.cmd = [cursor readInt32]; |
| symtabCommand.cmdsize = [cursor readInt32]; |
| |
| symtabCommand.symoff = [cursor readInt32]; |
| symtabCommand.nsyms = [cursor readInt32]; |
| symtabCommand.stroff = [cursor readInt32]; |
| symtabCommand.strsize = [cursor readInt32]; |
| |
| // symoff is at the start of the first section (__pointers) of the __IMPORT segment |
| // stroff falls within the __LINKEDIT segment |
| #if 0 |
| NSLog(@"symtab: %08x %08x %08x %08x %08x %08x", |
| symtabCommand.cmd, symtabCommand.cmdsize, |
| symtabCommand.symoff, symtabCommand.nsyms, symtabCommand.stroff, symtabCommand.strsize); |
| NSLog(@"data offset for stroff: %lu", [aMachOFile dataOffsetForAddress:symtabCommand.stroff]); |
| #endif |
| |
| symbols = nil; |
| baseAddress = 0; |
| |
| classSymbols = nil; |
| |
| flags.didFindBaseAddress = NO; |
| flags.didWarnAboutUnfoundBaseAddress = NO; |
| } |
| |
| return self; |
| } |
| |
| - (void)dealloc; |
| { |
| [symbols release]; |
| [classSymbols release]; |
| |
| [super dealloc]; |
| } |
| |
| #pragma mark - Debugging |
| |
| - (NSString *)extraDescription; |
| { |
| return [NSString stringWithFormat:@"symoff: 0x%08x (%u), nsyms: 0x%08x (%u), stroff: 0x%08x (%u), strsize: 0x%08x (%u)", |
| symtabCommand.symoff, symtabCommand.symoff, symtabCommand.nsyms, symtabCommand.nsyms, |
| symtabCommand.stroff, symtabCommand.stroff, symtabCommand.strsize, symtabCommand.strsize]; |
| } |
| |
| #pragma mark - |
| |
| - (uint32_t)cmd; |
| { |
| return symtabCommand.cmd; |
| } |
| |
| - (uint32_t)cmdsize; |
| { |
| return symtabCommand.cmdsize; |
| } |
| |
| #define CD_VM_PROT_RW (VM_PROT_READ|VM_PROT_WRITE) |
| |
| - (void)loadSymbols; |
| { |
| for (CDLoadCommand *loadCommand in [nonretained_machOFile loadCommands]) { |
| if ([loadCommand isKindOfClass:[CDLCSegment class]]) { |
| CDLCSegment *segment = (CDLCSegment *)loadCommand; |
| |
| if (([segment initprot] & CD_VM_PROT_RW) == CD_VM_PROT_RW) { |
| //NSLog(@"segment... initprot = %08x, addr= %016lx *** r/w", [segment initprot], [segment vmaddr]); |
| baseAddress = [segment vmaddr]; |
| flags.didFindBaseAddress = YES; |
| break; |
| } |
| } |
| } |
| |
| NSMutableArray *_symbols = [[NSMutableArray alloc] init]; |
| NSMutableDictionary *_classSymbols = [[NSMutableDictionary alloc] init]; |
| |
| CDMachOFileDataCursor *cursor = [[CDMachOFileDataCursor alloc] initWithFile:nonretained_machOFile offset:symtabCommand.symoff]; |
| //NSLog(@"offset= %lu", [cursor offset]); |
| //NSLog(@"stroff= %lu", symtabCommand.stroff); |
| //NSLog(@"strsize= %lu", symtabCommand.strsize); |
| |
| const char *strtab = [[nonretained_machOFile machOData] bytes] + symtabCommand.stroff; |
| |
| if (![nonretained_machOFile uses64BitABI]) { |
| //NSLog(@"32 bit..."); |
| //NSLog(@" str table index type sect desc value"); |
| //NSLog(@" --------------- ---- ---- ---- --------"); |
| for (uint32_t index = 0; index < symtabCommand.nsyms; index++) { |
| struct nlist nlist; |
| |
| nlist.n_un.n_strx = [cursor readInt32]; |
| nlist.n_type = [cursor readByte]; |
| nlist.n_sect = [cursor readByte]; |
| nlist.n_desc = [cursor readInt16]; |
| nlist.n_value = [cursor readInt32]; |
| #if 0 |
| NSLog(@"%5u: %08x %02x %02x %04x %08x - %s", |
| index, nlist.n_un.n_strx, nlist.n_type, nlist.n_sect, nlist.n_desc, nlist.n_value, strtab + nlist.n_un.n_strx); |
| #endif |
| |
| const char *ptr = strtab + nlist.n_un.n_strx; |
| NSString *str = [[NSString alloc] initWithBytes:ptr length:strlen(ptr) encoding:NSASCIIStringEncoding]; |
| |
| CDSymbol *symbol = [[CDSymbol alloc] initWithName:str machOFile:nonretained_machOFile nlist32:nlist]; |
| [_symbols addObject:symbol]; |
| [symbol release]; |
| |
| [str release]; |
| } |
| |
| //NSLog(@"Loaded %lu 32-bit symbols", [symbols count]); |
| } else { |
| //NSLog(@" str table index type sect desc value"); |
| //NSLog(@" --------------- ---- ---- ---- ----------------"); |
| for (uint32_t index = 0; index < symtabCommand.nsyms; index++) { |
| struct nlist_64 nlist; |
| |
| nlist.n_un.n_strx = [cursor readInt32]; |
| nlist.n_type = [cursor readByte]; |
| nlist.n_sect = [cursor readByte]; |
| nlist.n_desc = [cursor readInt16]; |
| nlist.n_value = [cursor readInt64]; |
| #if 0 |
| NSLog(@"%5u: %08x %02x %02x %04x %016x - %s", |
| index, nlist.n_un.n_strx, nlist.n_type, nlist.n_sect, nlist.n_desc, nlist.n_value, strtab + nlist.n_un.n_strx); |
| #endif |
| const char *ptr = strtab + nlist.n_un.n_strx; |
| NSString *str = [[NSString alloc] initWithBytes:ptr length:strlen(ptr) encoding:NSASCIIStringEncoding]; |
| |
| CDSymbol *symbol = [[CDSymbol alloc] initWithName:str machOFile:nonretained_machOFile nlist64:nlist]; |
| [_symbols addObject:symbol]; |
| |
| if ([str hasPrefix:ObjCClassSymbolPrefix] && [symbol value] != 0) { |
| NSString *className = [str substringFromIndex:[ObjCClassSymbolPrefix length]]; |
| [_classSymbols setObject:symbol forKey:className]; |
| } |
| |
| [symbol release]; |
| |
| [str release]; |
| } |
| |
| //NSLog(@"Loaded %lu 64-bit symbols", [symbols count]); |
| } |
| |
| [cursor release]; |
| |
| symbols = [_symbols copy]; [_symbols release]; |
| classSymbols = [_classSymbols copy]; [_classSymbols release]; |
| |
| //NSLog(@"symbols: %@", symbols); |
| } |
| |
| - (uint32_t)symoff; |
| { |
| return symtabCommand.symoff; |
| } |
| |
| - (uint32_t)nsyms; |
| { |
| return symtabCommand.nsyms; |
| } |
| |
| - (uint32_t)stroff; |
| { |
| return symtabCommand.stroff; |
| } |
| |
| - (uint32_t)strsize; |
| { |
| return symtabCommand.strsize; |
| } |
| |
| - (NSUInteger)baseAddress; |
| { |
| if (flags.didFindBaseAddress == NO && flags.didWarnAboutUnfoundBaseAddress == NO) { |
| fprintf(stderr, "Warning: Couldn't find first read/write segment for base address of relocation entries.\n"); |
| flags.didWarnAboutUnfoundBaseAddress = YES; |
| } |
| |
| return baseAddress; |
| } |
| |
| - (NSArray *)symbols; |
| { |
| return symbols; |
| } |
| |
| - (CDSymbol *)symbolForClass:(NSString *)className; |
| { |
| return [classSymbols objectForKey:className]; |
| } |
| |
| @end |