blob: 4a06742d921371616ff2face9cb3c3b717f5f9e4 [file] [log] [blame]
// -*- mode: ObjC -*-
// This file is part of class-dump, a utility for examining the Objective-C segment of Mach-O files.
// Copyright (C) 1997-2019 Steve Nygard.
#import "CDLCSymbolTable.h"
#include <mach-o/nlist.h>
#import "CDMachOFile.h"
#import "CDSymbol.h"
#import "CDLCSegment.h"
#import "CDLCDylib.h"
@implementation CDLCSymbolTable
{
struct symtab_command _symtabCommand;
NSArray *_symbols;
NSUInteger _baseAddress;
NSDictionary *_classSymbols;
NSDictionary *_externalClassSymbols;
struct {
unsigned int didFindBaseAddress:1;
unsigned int didWarnAboutUnfoundBaseAddress:1;
unsigned int _unused:30;
} _flags;
}
- (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", [cursor.machOFile dataOffsetForAddress:symtabCommand.stroff]);
#endif
_symbols = nil;
_baseAddress = 0;
_classSymbols = nil;
_flags.didFindBaseAddress = NO;
_flags.didWarnAboutUnfoundBaseAddress = NO;
}
return self;
}
#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 [self.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];
NSMutableDictionary *externalClassSymbols = [[NSMutableDictionary alloc] init];
CDMachOFileDataCursor *cursor = [[CDMachOFileDataCursor alloc] initWithFile:self.machOFile offset:_symtabCommand.symoff];
//NSLog(@"offset= %lu", [cursor offset]);
//NSLog(@"stroff= %lu", symtabCommand.stroff);
//NSLog(@"strsize= %lu", symtabCommand.strsize);
const char *strtab = (char *)[self.machOFile.data bytes] + _symtabCommand.stroff;
void (^addSymbol)(NSString *, CDSymbol *) = ^(NSString *name, CDSymbol *symbol) {
[symbols addObject:symbol];
NSString *className = [CDSymbol classNameFromSymbolName:symbol.name];
if (className != nil) {
if (symbol.value != 0)
classSymbols[className] = symbol;
else
externalClassSymbols[className] = symbol;
}
};
if (![self.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:self.machOFile nlist32:nlist];
addSymbol(str, symbol);
}
//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:self.machOFile nlist64:nlist];
addSymbol(str, symbol);
}
//NSLog(@"Loaded %lu 64-bit symbols", [symbols count]);
}
_symbols = [symbols copy];
_classSymbols = [classSymbols copy];
_externalClassSymbols = [externalClassSymbols copy];
//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;
}
- (CDSymbol *)symbolForClassName:(NSString *)className;
{
return _classSymbols[className];
}
- (CDSymbol *)symbolForExternalClassName:(NSString *)className
{
return _externalClassSymbols[className];
}
@end