Add placeholder for types that start with A, for _Atomic() types.
[class-dump.git] / Source / CDSymbol.m
blobcda3870d9a7bc1a28da22ee109583eb604796014
1 // -*- mode: ObjC -*-
3 //  This file is part of class-dump, a utility for examining the Objective-C segment of Mach-O files.
4 //  Copyright (C) 1997-2019 Steve Nygard.
6 #import "CDSymbol.h"
8 #import <mach-o/nlist.h>
9 #import <mach-o/loader.h>
10 #import "CDMachOFile.h"
11 #import "CDLCDylib.h"
12 #import "CDLCSegment.h"
13 #import "CDSection.h"
15 NSString *const ObjCClassSymbolPrefix = @"_OBJC_CLASS_$_";
17 @interface CDSymbol ()
18 @property (weak, readonly) CDMachOFile *machOFile;
19 @end
21 #pragma mark -
23 @implementation CDSymbol
25     struct nlist_64 _nlist;
26     BOOL _is32Bit;
27     NSString *_name;
28     __weak CDMachOFile *_machOFile;
31 - (id)initWithName:(NSString *)name machOFile:(CDMachOFile *)machOFile nlist32:(struct nlist)nlist32;
33     if ((self = [super init])) {
34         _is32Bit = YES;
35         _name = name;
36         _machOFile = machOFile;
37         _nlist.n_un.n_strx = 0; // We don't use it.
38         _nlist.n_type      = nlist32.n_type;
39         _nlist.n_sect      = nlist32.n_sect;
40         _nlist.n_desc      = nlist32.n_desc;
41         _nlist.n_value     = nlist32.n_value;
42     }
44     return self;
47 - (id)initWithName:(NSString *)name machOFile:(CDMachOFile *)machOFile nlist64:(struct nlist_64)nlist64;
49     if ((self = [super init])) {
50         _is32Bit = NO;
51         _name = name;
52         _machOFile = machOFile;
53         _nlist.n_un.n_strx = 0; // We don't use it.
54         _nlist.n_type      = nlist64.n_type;
55         _nlist.n_sect      = nlist64.n_sect;
56         _nlist.n_desc      = nlist64.n_desc;
57         _nlist.n_value     = nlist64.n_value;
58     }
60     return self;
63 #pragma mark - Debugging
65 - (NSString *)description;
67     NSString *valueString;
69     if (self.isDefined) {
70         valueString = [NSString stringWithFormat:(_is32Bit ? @"%08llx" : @"%016llx"), self.value];
71     } else {
72         valueString = [@" " stringByPaddingToLength:(_is32Bit ? 8 : 16) withString:@" " startingAtIndex:0];
73     }
75     return [NSString stringWithFormat:@"%@ %@ %@", valueString, [self shortTypeDescription], self.name];
78 #pragma mark -
80 + (NSString *)classNameFromSymbolName:(NSString *)symbolName;
82     if ([symbolName hasPrefix:ObjCClassSymbolPrefix])
83         return [symbolName substringFromIndex:[ObjCClassSymbolPrefix length]];
84     else
85         return nil;
88 - (uint64_t)value;
90     return _nlist.n_value;
93 - (CDSection *)section;
95     // We might be tempted to do [[self.machOFile segmentContainingAddress:nlist.n_value] sectionContainingAddress:nlist.n_value]
96     // but this does not work for __mh_dylib_header for example (n_value == 0, but it is in the __TEXT,__text section)
97     NSMutableArray *sections = [NSMutableArray array];
98     for (CDLCSegment *segment in self.machOFile.segments) {
99         for (CDSection *section in [segment sections])
100             [sections addObject:section];
101     }
103     // n_sect is 1-indexed (NO_SECT == 0)
104     NSUInteger sectionIndex = _nlist.n_sect - 1;
105     if (sectionIndex < [sections count])
106         return sections[sectionIndex];
107     else
108         return nil;
111 - (CDLCDylib *)dylibLoadCommand;
113     NSUInteger libraryOrdinal = GET_LIBRARY_ORDINAL(_nlist.n_desc);
114     return [self.machOFile dylibLoadCommandForLibraryOrdinal:libraryOrdinal];
117 - (BOOL)isExternal;
119     return (_nlist.n_type & N_EXT) == N_EXT;
122 - (BOOL)isPrivateExternal;
124     return (_nlist.n_type & N_PEXT) == N_PEXT;
127 - (NSUInteger)stab;
129     return _nlist.n_type & N_STAB;
132 - (NSUInteger)type;
134     return _nlist.n_type & N_TYPE;
137 - (BOOL)isDefined;
139     return self.type != N_UNDF;
142 - (BOOL)isAbsolute;
144     return self.type == N_ABS;
147 - (BOOL)isInSection;
149     return self.type == N_SECT;
152 - (BOOL)isPrebound;
154     return self.type == N_PBUD;
157 - (BOOL)isIndirect;
159     return self.type == N_INDR;
162 - (BOOL)isCommon;
164     return !self.isDefined && self.isExternal && _nlist.n_value != 0;
167 - (BOOL)isInTextSection;
169     CDSection *section = self.section;
170     return [section.segmentName isEqualToString:@"__TEXT"] && [section.sectionName isEqualToString:@"__text"];
173 - (BOOL)isInDataSection;
175     CDSection *section = self.section;
176     return [section.segmentName isEqualToString:@"__DATA"] && [section.sectionName isEqualToString:@"__data"];
179 - (BOOL)isInBssSection;
181     CDSection *section = self.section;
182     return [section.segmentName isEqualToString:@"__DATA"] && [section.sectionName isEqualToString:@"__bss"];
185 - (NSUInteger)referenceType;
187     return (_nlist.n_desc & REFERENCE_TYPE);
190 - (NSString *)referenceTypeName
192     switch (self.referenceType) {
193         case REFERENCE_FLAG_UNDEFINED_NON_LAZY:         return @"undefined non lazy";
194         case REFERENCE_FLAG_UNDEFINED_LAZY:             return @"undefined lazy";
195         case REFERENCE_FLAG_DEFINED:                    return @"defined";
196         case REFERENCE_FLAG_PRIVATE_DEFINED:            return @"private defined";
197         case REFERENCE_FLAG_PRIVATE_UNDEFINED_NON_LAZY: return @"private undefined non lazy";
198         case REFERENCE_FLAG_PRIVATE_UNDEFINED_LAZY:     return @"private undefined lazy";
199     }
200     return nil;
203 - (NSComparisonResult)compare:(CDSymbol *)other;
205     if (other.value > self.value) return NSOrderedAscending;
206     if (other.value < self.value) return NSOrderedDescending;
208     return NSOrderedSame;
211 - (NSComparisonResult)compareByName:(CDSymbol *)other;
213     return [self.name compare:other.name];
216 - (NSString *)shortTypeDescription;
218     NSString *c;
220     if (self.stab)                               c = @"-";
221     else if (self.isCommon)                      c = @"c";
222     else if (!self.isDefined || self.isPrebound) c = @"u";
223     else if (self.isAbsolute)                    c = @"a";
224     else if (self.isInSection) {
225         if (self.isInTextSection)                c = @"t";
226         else if (self.isInDataSection)           c = @"d";
227         else if (self.isInBssSection)            c = @"b";
228         else                                     c = @"s";
229     }
230     else if (self.isIndirect)                    c = @"i";
231     else                                         c = @"?";
233     return self.isExternal ? [c uppercaseString] : c;
236 - (NSString *)longTypeDescription;
238     NSString *c;
240     if (self.isCommon)                           c = @"common";
241     else if (!self.isDefined)                    c =  @"undefined";
242     else if (self.isPrebound)                    c =  @"prebound";
243     else if (self.isAbsolute)                    c =  @"absolute";
244     else if (self.isInSection) {
245         CDSection *section = self.section;
246         if (section)                             c = [NSString stringWithFormat:@"%@,%@", section.segmentName, section.sectionName];
247         else                                     c = @"?,?";
248     }
249     else if (self.isIndirect)                    c = @"indirect";
250     else                                         c = @"?";
252     return c;
255 @end