OLD | NEW |
(Empty) | |
| 1 // -*- mode: ObjC -*- |
| 2 |
| 3 // This file is part of class-dump, a utility for examining the Objective-C seg
ment of Mach-O files. |
| 4 // Copyright (C) 1997-1998, 2000-2001, 2004-2010 Steve Nygard. |
| 5 |
| 6 #import "CDObjectiveC1Processor.h" |
| 7 |
| 8 #include <mach-o/arch.h> |
| 9 |
| 10 #import "CDClassDump.h" |
| 11 #import "CDLCDylib.h" |
| 12 #import "CDMachOFile.h" |
| 13 #import "CDOCCategory.h" |
| 14 #import "CDOCClass.h" |
| 15 #import "CDOCIvar.h" |
| 16 #import "CDOCMethod.h" |
| 17 #import "CDOCModule.h" |
| 18 #import "CDOCProtocol.h" |
| 19 #import "CDOCSymtab.h" |
| 20 #import "CDSection32.h" |
| 21 #import "CDLCSegment32.h" |
| 22 #import "NSArray-Extensions.h" |
| 23 #import "CDVisitor.h" |
| 24 |
| 25 |
| 26 #import "CDSection.h" |
| 27 #import "CDLCSegment.h" |
| 28 |
| 29 // Section: __module_info |
| 30 struct cd_objc_module { |
| 31 uint32_t version; |
| 32 uint32_t size; |
| 33 uint32_t name; |
| 34 uint32_t symtab; |
| 35 }; |
| 36 |
| 37 // Section: __symbols |
| 38 struct cd_objc_symtab |
| 39 { |
| 40 uint32_t sel_ref_cnt; |
| 41 uint32_t refs; // not used until runtime? |
| 42 uint16_t cls_def_count; |
| 43 uint16_t cat_def_count; |
| 44 //long class_pointer; |
| 45 }; |
| 46 |
| 47 // Section: __class |
| 48 struct cd_objc_class |
| 49 { |
| 50 uint32_t isa; |
| 51 uint32_t super_class; |
| 52 uint32_t name; |
| 53 uint32_t version; |
| 54 uint32_t info; |
| 55 uint32_t instance_size; |
| 56 uint32_t ivars; |
| 57 uint32_t methods; |
| 58 uint32_t cache; |
| 59 uint32_t protocols; |
| 60 }; |
| 61 |
| 62 // Section: ?? |
| 63 struct cd_objc_category |
| 64 { |
| 65 uint32_t category_name; |
| 66 uint32_t class_name; |
| 67 uint32_t methods; |
| 68 uint32_t class_methods; |
| 69 uint32_t protocols; |
| 70 }; |
| 71 |
| 72 // Section: __instance_vars |
| 73 struct cd_objc_ivar_list |
| 74 { |
| 75 uint32_t ivar_count; |
| 76 // Followed by ivars |
| 77 }; |
| 78 |
| 79 // Section: __instance_vars |
| 80 struct cd_objc_ivar |
| 81 { |
| 82 uint32_t name; |
| 83 uint32_t type; |
| 84 uint32_t offset; |
| 85 }; |
| 86 |
| 87 // Section: __inst_meth |
| 88 struct cd_objc_method_list |
| 89 { |
| 90 uint32_t _obsolete; |
| 91 uint32_t method_count; |
| 92 // Followed by methods |
| 93 }; |
| 94 |
| 95 // Section: __inst_meth |
| 96 struct cd_objc_method |
| 97 { |
| 98 uint32_t name; |
| 99 uint32_t types; |
| 100 uint32_t imp; |
| 101 }; |
| 102 |
| 103 |
| 104 struct cd_objc_protocol_list |
| 105 { |
| 106 uint32_t next; |
| 107 uint32_t count; |
| 108 //uint32_t list; |
| 109 }; |
| 110 |
| 111 struct cd_objc_protocol |
| 112 { |
| 113 uint32_t isa; |
| 114 uint32_t protocol_name; |
| 115 uint32_t protocol_list; |
| 116 uint32_t instance_methods; |
| 117 uint32_t class_methods; |
| 118 }; |
| 119 |
| 120 struct cd_objc_protocol_method_list |
| 121 { |
| 122 uint32_t method_count; |
| 123 // Followed by methods |
| 124 }; |
| 125 |
| 126 struct cd_objc_protocol_method |
| 127 { |
| 128 uint32_t name; |
| 129 uint32_t types; |
| 130 }; |
| 131 |
| 132 static BOOL debug = NO; |
| 133 |
| 134 @implementation CDObjectiveC1Processor |
| 135 |
| 136 - (id)initWithMachOFile:(CDMachOFile *)aMachOFile; |
| 137 { |
| 138 if ([super initWithMachOFile:aMachOFile] == nil) |
| 139 return nil; |
| 140 |
| 141 modules = [[NSMutableArray alloc] init]; |
| 142 |
| 143 return self; |
| 144 } |
| 145 |
| 146 - (void)dealloc; |
| 147 { |
| 148 [modules release]; |
| 149 |
| 150 [super dealloc]; |
| 151 } |
| 152 |
| 153 - (void)process; |
| 154 { |
| 155 if ([machOFile isEncrypted] == NO && [machOFile canDecryptAllSegments]) { |
| 156 [super process]; |
| 157 |
| 158 [self processModules]; |
| 159 } |
| 160 } |
| 161 |
| 162 // |
| 163 // Formerly private |
| 164 // |
| 165 |
| 166 - (void)processModules; |
| 167 { |
| 168 CDLCSegment *objcSegment; |
| 169 CDSection *moduleSection; |
| 170 NSData *sectionData; |
| 171 CDDataCursor *cursor; |
| 172 |
| 173 objcSegment = [machOFile segmentWithName:@"__OBJC"]; |
| 174 moduleSection = [objcSegment sectionWithName:@"__module_info"]; |
| 175 sectionData = [moduleSection data]; |
| 176 |
| 177 cursor = [[CDDataCursor alloc] initWithData:sectionData]; |
| 178 [cursor setByteOrder:[machOFile byteOrder]]; |
| 179 while ([cursor isAtEnd] == NO) { |
| 180 struct cd_objc_module objcModule; |
| 181 CDOCModule *module; |
| 182 NSString *name; |
| 183 NSArray *array; |
| 184 |
| 185 objcModule.version = [cursor readInt32]; |
| 186 objcModule.size = [cursor readInt32]; |
| 187 objcModule.name = [cursor readInt32]; |
| 188 objcModule.symtab = [cursor readInt32]; |
| 189 |
| 190 //NSLog(@"objcModule.size: %u", objcModule.size); |
| 191 //NSLog(@"sizeof(struct cd_objc_module): %u", sizeof(struct cd_objc_modu
le)); |
| 192 assert(objcModule.size == sizeof(struct cd_objc_module)); // Because thi
s is what we're assuming. |
| 193 |
| 194 name = [machOFile stringAtAddress:objcModule.name]; |
| 195 if (name != nil && [name length] > 0 && debug) |
| 196 NSLog(@"Note: a module name is set: %@", name); |
| 197 |
| 198 //NSLog(@"%08x %08x %08x %08x - '%@'", objcModule.version, objcModule.si
ze, objcModule.name, objcModule.symtab, name); |
| 199 //NSLog(@"\tsect: %@", [[machOFile segmentContainingAddress:objcModule.n
ame] sectionContainingAddress:objcModule.name]); |
| 200 //NSLog(@"symtab: %08x", objcModule.symtab); |
| 201 |
| 202 module = [[CDOCModule alloc] init]; |
| 203 [module setVersion:objcModule.version]; |
| 204 [module setName:[machOFile stringAtAddress:objcModule.name]]; |
| 205 [module setSymtab:[self processSymtabAtAddress:objcModule.symtab]]; |
| 206 [modules addObject:module]; |
| 207 |
| 208 array = [[module symtab] classes]; |
| 209 if (array != nil) |
| 210 [classes addObjectsFromArray:array]; |
| 211 |
| 212 array = [[module symtab] categories]; |
| 213 if (array != nil) |
| 214 [categories addObjectsFromArray:array]; |
| 215 |
| 216 [module release]; |
| 217 } |
| 218 |
| 219 [cursor release]; |
| 220 } |
| 221 |
| 222 - (CDOCSymtab *)processSymtabAtAddress:(uint32_t)address; |
| 223 { |
| 224 CDDataCursor *cursor; |
| 225 struct cd_objc_symtab objcSymtab; |
| 226 CDOCSymtab *aSymtab = nil; |
| 227 unsigned int index; |
| 228 |
| 229 //---------------------------------------- |
| 230 |
| 231 cursor = [[CDDataCursor alloc] initWithData:[machOFile data]]; |
| 232 [cursor setByteOrder:[machOFile byteOrder]]; |
| 233 [cursor setOffset:[machOFile dataOffsetForAddress:address segmentName:@"__OB
JC"]]; |
| 234 //[cursor setOffset:[machOFile dataOffsetForAddress:address]]; |
| 235 //NSLog(@"cursor offset: %08x", [cursor offset]); |
| 236 if ([cursor offset] != 0) { |
| 237 objcSymtab.sel_ref_cnt = [cursor readInt32]; |
| 238 objcSymtab.refs = [cursor readInt32]; |
| 239 objcSymtab.cls_def_count = [cursor readInt16]; |
| 240 objcSymtab.cat_def_count = [cursor readInt16]; |
| 241 //NSLog(@"[@ %08x]: %08x %08x %04x %04x", address, objcSymtab.sel_ref_cn
t, objcSymtab.refs, objcSymtab.cls_def_count, objcSymtab.cat_def_count); |
| 242 |
| 243 aSymtab = [[[CDOCSymtab alloc] init] autorelease]; |
| 244 |
| 245 for (index = 0; index < objcSymtab.cls_def_count; index++) { |
| 246 CDOCClass *aClass; |
| 247 uint32_t val; |
| 248 |
| 249 val = [cursor readInt32]; |
| 250 //NSLog(@"%4d: %08x", index, val); |
| 251 |
| 252 aClass = [self processClassDefinitionAtAddress:val]; |
| 253 if (aClass != nil) |
| 254 [aSymtab addClass:aClass]; |
| 255 } |
| 256 |
| 257 for (index = 0; index < objcSymtab.cat_def_count; index++) { |
| 258 CDOCCategory *aCategory; |
| 259 uint32_t val; |
| 260 |
| 261 val = [cursor readInt32]; |
| 262 //NSLog(@"%4d: %08x", index, val); |
| 263 |
| 264 aCategory = [self processCategoryDefinitionAtAddress:val]; |
| 265 if (aCategory != nil) |
| 266 [aSymtab addCategory:aCategory]; |
| 267 } |
| 268 } |
| 269 |
| 270 [cursor release]; |
| 271 |
| 272 return aSymtab; |
| 273 } |
| 274 |
| 275 - (CDOCClass *)processClassDefinitionAtAddress:(uint32_t)address; |
| 276 { |
| 277 CDDataCursor *cursor; |
| 278 struct cd_objc_class objcClass; |
| 279 CDOCClass *aClass; |
| 280 NSString *name; |
| 281 |
| 282 cursor = [[CDDataCursor alloc] initWithData:[machOFile data]]; |
| 283 [cursor setByteOrder:[machOFile byteOrder]]; |
| 284 [cursor setOffset:[machOFile dataOffsetForAddress:address]]; |
| 285 |
| 286 objcClass.isa = [cursor readInt32]; |
| 287 objcClass.super_class = [cursor readInt32]; |
| 288 objcClass.name = [cursor readInt32]; |
| 289 objcClass.version = [cursor readInt32]; |
| 290 objcClass.info = [cursor readInt32]; |
| 291 objcClass.instance_size = [cursor readInt32]; |
| 292 objcClass.ivars = [cursor readInt32]; |
| 293 objcClass.methods = [cursor readInt32]; |
| 294 objcClass.cache = [cursor readInt32]; |
| 295 objcClass.protocols = [cursor readInt32]; |
| 296 |
| 297 name = [machOFile stringAtAddress:objcClass.name]; |
| 298 //NSLog(@"name: %08x", objcClass.name); |
| 299 //NSLog(@"name = %@", name); |
| 300 if (name == nil) { |
| 301 NSLog(@"Note: objcClass.name was %08x, returning nil.", objcClass.name); |
| 302 [cursor release]; |
| 303 return nil; |
| 304 } |
| 305 |
| 306 aClass = [[[CDOCClass alloc] init] autorelease]; |
| 307 [aClass setName:name]; |
| 308 [aClass setSuperClassName:[machOFile stringAtAddress:objcClass.super_class]]
; |
| 309 //NSLog(@"[aClass superClassName]: %@", [aClass superClassName]); |
| 310 |
| 311 // Process ivars |
| 312 if (objcClass.ivars != 0) { |
| 313 uint32_t count, index; |
| 314 NSMutableArray *ivars; |
| 315 |
| 316 [cursor setOffset:[machOFile dataOffsetForAddress:objcClass.ivars]]; |
| 317 NSParameterAssert([cursor offset] != 0); |
| 318 |
| 319 count = [cursor readInt32]; |
| 320 ivars = [[NSMutableArray alloc] init]; |
| 321 for (index = 0; index < count; index++) { |
| 322 struct cd_objc_ivar objcIvar; |
| 323 NSString *name, *type; |
| 324 |
| 325 objcIvar.name = [cursor readInt32]; |
| 326 objcIvar.type = [cursor readInt32]; |
| 327 objcIvar.offset = [cursor readInt32]; |
| 328 |
| 329 name = [machOFile stringAtAddress:objcIvar.name]; |
| 330 type = [machOFile stringAtAddress:objcIvar.type]; |
| 331 |
| 332 // bitfields don't need names. |
| 333 // NSIconRefBitmapImageRep in AppKit on 10.5 has a single-bit bitfie
ld, plus an unnamed 31-bit field. |
| 334 if (type != nil) { |
| 335 CDOCIvar *anIvar; |
| 336 |
| 337 anIvar = [[CDOCIvar alloc] initWithName:name type:type offset:ob
jcIvar.offset]; |
| 338 [ivars addObject:anIvar]; |
| 339 [anIvar release]; |
| 340 } |
| 341 } |
| 342 |
| 343 [aClass setIvars:[NSArray arrayWithArray:ivars]]; |
| 344 [ivars release]; |
| 345 } |
| 346 |
| 347 // Process instance methods |
| 348 for (CDOCMethod *method in [self processMethodsAtAddress:objcClass.methods]) |
| 349 [aClass addInstanceMethod:method]; |
| 350 |
| 351 // Process meta class |
| 352 { |
| 353 struct cd_objc_class metaClass; |
| 354 |
| 355 NSParameterAssert(objcClass.isa != 0); |
| 356 //NSLog(@"meta class, isa = %08x", objcClass.isa); |
| 357 |
| 358 [cursor setOffset:[machOFile dataOffsetForAddress:objcClass.isa]]; |
| 359 |
| 360 metaClass.isa = [cursor readInt32]; |
| 361 metaClass.super_class = [cursor readInt32]; |
| 362 metaClass.name = [cursor readInt32]; |
| 363 metaClass.version = [cursor readInt32]; |
| 364 metaClass.info = [cursor readInt32]; |
| 365 metaClass.instance_size = [cursor readInt32]; |
| 366 metaClass.ivars = [cursor readInt32]; |
| 367 metaClass.methods = [cursor readInt32]; |
| 368 metaClass.cache = [cursor readInt32]; |
| 369 metaClass.protocols = [cursor readInt32]; |
| 370 |
| 371 #if 0 |
| 372 // TODO (2009-06-23): See if there's anything else interesting here. |
| 373 NSLog(@"metaclass= isa:%08x super:%08x name:%08x ver:%08x info:%08x is
ize:%08x ivar:%08x meth:%08x cache:%08x proto:%08x", |
| 374 metaClass.isa, metaClass.super_class, metaClass.name, metaClass.ve
rsion, metaClass.info, metaClass.instance_size, |
| 375 metaClass.ivars, metaClass.methods, metaClass.cache, metaClass.pro
tocols); |
| 376 #endif |
| 377 // Process class methods |
| 378 for (CDOCMethod *method in [self processMethodsAtAddress:metaClass.metho
ds]) |
| 379 [aClass addClassMethod:method]; |
| 380 } |
| 381 |
| 382 // Process protocols |
| 383 for (CDOCProtocol *protocol in [self uniquedProtocolListAtAddress:objcClass.
protocols]) |
| 384 [aClass addProtocol:protocol]; |
| 385 |
| 386 [cursor release]; |
| 387 |
| 388 return aClass; |
| 389 } |
| 390 |
| 391 // Returns list of uniqued protocols. |
| 392 - (NSArray *)uniquedProtocolListAtAddress:(uint32_t)address; |
| 393 { |
| 394 NSMutableArray *protocols; |
| 395 |
| 396 protocols = [[[NSMutableArray alloc] init] autorelease];; |
| 397 |
| 398 if (address != 0) { |
| 399 CDDataCursor *cursor; |
| 400 struct cd_objc_protocol_list protocolList; |
| 401 uint32_t index; |
| 402 |
| 403 cursor = [[CDDataCursor alloc] initWithData:[machOFile data]]; |
| 404 [cursor setByteOrder:[machOFile byteOrder]]; |
| 405 [cursor setOffset:[machOFile dataOffsetForAddress:address]]; |
| 406 |
| 407 protocolList.next = [cursor readInt32]; |
| 408 protocolList.count = [cursor readInt32]; |
| 409 |
| 410 for (index = 0; index < protocolList.count; index++) { |
| 411 uint32_t val; |
| 412 CDOCProtocol *protocol, *uniqueProtocol; |
| 413 |
| 414 val = [cursor readInt32]; |
| 415 protocol = [protocolsByAddress objectForKey:[NSNumber numberWithUnsi
gnedInt:val]]; |
| 416 //NSLog(@"%3d protocol @ %08x: %@", index, val, [protocol name]); |
| 417 if (protocol != nil) { |
| 418 uniqueProtocol = [protocolsByName objectForKey:[protocol name]]; |
| 419 if (uniqueProtocol != nil) |
| 420 [protocols addObject:uniqueProtocol]; |
| 421 } |
| 422 } |
| 423 |
| 424 [cursor release]; |
| 425 } |
| 426 |
| 427 return protocols; |
| 428 } |
| 429 |
| 430 - (NSArray *)processMethodsAtAddress:(uint32_t)address; |
| 431 { |
| 432 return [self processMethodsAtAddress:address isFromProtocolDefinition:NO]; |
| 433 } |
| 434 |
| 435 - (NSArray *)processMethodsAtAddress:(uint32_t)address isFromProtocolDefinition:
(BOOL)isFromProtocolDefinition; |
| 436 { |
| 437 CDDataCursor *cursor; |
| 438 NSMutableArray *methods; |
| 439 |
| 440 if (address == 0) |
| 441 return [NSArray array]; |
| 442 |
| 443 methods = [NSMutableArray array]; |
| 444 |
| 445 cursor = [[CDDataCursor alloc] initWithData:[machOFile data]]; |
| 446 [cursor setByteOrder:[machOFile byteOrder]]; |
| 447 [cursor setOffset:[machOFile dataOffsetForAddress:address]]; |
| 448 if ([cursor offset] != 0) { |
| 449 struct cd_objc_method_list methodList; |
| 450 uint32_t index; |
| 451 |
| 452 if (isFromProtocolDefinition) |
| 453 methodList._obsolete = 0; |
| 454 else |
| 455 methodList._obsolete = [cursor readInt32]; |
| 456 methodList.method_count = [cursor readInt32]; |
| 457 |
| 458 for (index = 0; index < methodList.method_count; index++) { |
| 459 struct cd_objc_method objcMethod; |
| 460 NSString *name, *type; |
| 461 |
| 462 objcMethod.name = [cursor readInt32]; |
| 463 objcMethod.types = [cursor readInt32]; |
| 464 if (isFromProtocolDefinition) |
| 465 objcMethod.imp = 0; |
| 466 else |
| 467 objcMethod.imp = [cursor readInt32]; |
| 468 |
| 469 name = [machOFile stringAtAddress:objcMethod.name]; |
| 470 type = [machOFile stringAtAddress:objcMethod.types]; |
| 471 if (name != nil && type != nil) { |
| 472 CDOCMethod *method; |
| 473 |
| 474 method = [[CDOCMethod alloc] initWithName:name type:type imp:obj
cMethod.imp]; |
| 475 [methods addObject:method]; |
| 476 [method release]; |
| 477 } else { |
| 478 if (name == nil) NSLog(@"Note: Method name was nil (%08x, %p)",
objcMethod.name, name); |
| 479 if (type == nil) NSLog(@"Note: Method type was nil (%08x, %p)",
objcMethod.types, type); |
| 480 } |
| 481 } |
| 482 } |
| 483 |
| 484 [cursor release]; |
| 485 |
| 486 return [methods reversedArray]; |
| 487 } |
| 488 |
| 489 - (CDOCCategory *)processCategoryDefinitionAtAddress:(uint32_t)address; |
| 490 { |
| 491 CDOCCategory *aCategory = nil; |
| 492 |
| 493 if (address != 0) { |
| 494 CDDataCursor *cursor; |
| 495 struct cd_objc_category objcCategory; |
| 496 NSString *name; |
| 497 |
| 498 cursor = [[CDDataCursor alloc] initWithData:[machOFile data]]; |
| 499 [cursor setByteOrder:[machOFile byteOrder]]; |
| 500 [cursor setOffset:[machOFile dataOffsetForAddress:address]]; |
| 501 |
| 502 objcCategory.category_name = [cursor readInt32]; |
| 503 objcCategory.class_name = [cursor readInt32]; |
| 504 objcCategory.methods = [cursor readInt32]; |
| 505 objcCategory.class_methods = [cursor readInt32]; |
| 506 objcCategory.protocols = [cursor readInt32]; |
| 507 |
| 508 name = [machOFile stringAtAddress:objcCategory.category_name]; |
| 509 if (name == nil) { |
| 510 NSLog(@"Note: objcCategory.category_name was %08x, returning nil.",
objcCategory.category_name); |
| 511 [cursor release]; |
| 512 return nil; |
| 513 } |
| 514 |
| 515 aCategory = [[[CDOCCategory alloc] init] autorelease]; |
| 516 [aCategory setName:name]; |
| 517 [aCategory setClassName:[machOFile stringAtAddress:objcCategory.class_na
me]]; |
| 518 |
| 519 for (CDOCMethod *method in [self processMethodsAtAddress:objcCategory.me
thods]) |
| 520 [aCategory addInstanceMethod:method]; |
| 521 |
| 522 for (CDOCMethod *method in [self processMethodsAtAddress:objcCategory.cl
ass_methods]) |
| 523 [aCategory addClassMethod:method]; |
| 524 |
| 525 for (CDOCProtocol *protocol in [self uniquedProtocolListAtAddress:objcCa
tegory.protocols]) |
| 526 [aCategory addProtocol:protocol]; |
| 527 |
| 528 [cursor release]; |
| 529 } |
| 530 |
| 531 return aCategory; |
| 532 } |
| 533 |
| 534 - (CDOCProtocol *)protocolAtAddress:(uint32_t)address; |
| 535 { |
| 536 NSNumber *key; |
| 537 CDOCProtocol *aProtocol; |
| 538 |
| 539 key = [NSNumber numberWithUnsignedInt:address]; |
| 540 aProtocol = [protocolsByAddress objectForKey:key]; |
| 541 if (aProtocol == nil) { |
| 542 CDDataCursor *cursor; |
| 543 uint32_t v1, v2, v3, v4, v5; |
| 544 NSString *name; |
| 545 |
| 546 //NSLog(@"Creating new protocol from address: 0x%08x", address); |
| 547 aProtocol = [[[CDOCProtocol alloc] init] autorelease]; |
| 548 [protocolsByAddress setObject:aProtocol forKey:key]; |
| 549 |
| 550 cursor = [[CDDataCursor alloc] initWithData:[machOFile data]]; |
| 551 [cursor setByteOrder:[machOFile byteOrder]]; |
| 552 [cursor setOffset:[machOFile dataOffsetForAddress:address]]; |
| 553 |
| 554 v1 = [cursor readInt32]; |
| 555 v2 = [cursor readInt32]; |
| 556 v3 = [cursor readInt32]; |
| 557 v4 = [cursor readInt32]; |
| 558 v5 = [cursor readInt32]; |
| 559 name = [machOFile stringAtAddress:v2]; |
| 560 [aProtocol setName:name]; // Need to set name before adding to another p
rotocol |
| 561 //NSLog(@"data offset for %08x: %08x", v2, [machOFile dataOffsetForAddre
ss:v2]); |
| 562 //NSLog(@"[@ %08x] v1-5: 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x (%@)", addre
ss, v1, v2, v3, v4, v5, name); |
| 563 |
| 564 { |
| 565 uint32_t count, index; |
| 566 |
| 567 // Protocols |
| 568 if (v3 != 0) { |
| 569 uint32_t val; |
| 570 |
| 571 [cursor setOffset:[machOFile dataOffsetForAddress:v3]]; |
| 572 val = [cursor readInt32]; |
| 573 NSParameterAssert(val == 0); // next pointer, let me know if it'
s ever not zero |
| 574 //NSLog(@"val: 0x%08x", val); |
| 575 count = [cursor readInt32]; |
| 576 //NSLog(@"protocol count: %08x", count); |
| 577 for (index = 0; index < count; index++) { |
| 578 CDOCProtocol *anotherProtocol; |
| 579 |
| 580 val = [cursor readInt32]; |
| 581 //NSLog(@"val[%2d]: 0x%08x", index, val); |
| 582 anotherProtocol = [self protocolAtAddress:val]; |
| 583 if (anotherProtocol != nil) { |
| 584 [aProtocol addProtocol:anotherProtocol]; |
| 585 } else { |
| 586 NSLog(@"Note: another protocol was nil."); |
| 587 } |
| 588 } |
| 589 } |
| 590 |
| 591 // Instance methods |
| 592 for (CDOCMethod *method in [self processMethodsAtAddress:v4 isFromPr
otocolDefinition:YES]) |
| 593 [aProtocol addInstanceMethod:method]; |
| 594 |
| 595 // Class methods |
| 596 for (CDOCMethod *method in [self processMethodsAtAddress:v5 isFromPr
otocolDefinition:YES]) |
| 597 [aProtocol addClassMethod:method]; |
| 598 } |
| 599 |
| 600 [cursor release]; |
| 601 } else { |
| 602 //NSLog(@"Found existing protocol at address: 0x%08x", address); |
| 603 } |
| 604 |
| 605 return aProtocol; |
| 606 } |
| 607 |
| 608 // Protocols can reference other protocols, so we can't try to create them |
| 609 // in order. Instead we create them lazily and just make sure we reference |
| 610 // all available protocols. |
| 611 |
| 612 // Many of the protocol structures share the same name, but have differnt method
lists. Create them all, then merge/unique by name after. |
| 613 // Perhaps a bit more work than necessary, but at least I can see exactly what i
s happening. |
| 614 - (void)loadProtocols; |
| 615 { |
| 616 CDLCSegment *objcSegment; |
| 617 CDSection *protocolSection; |
| 618 uint32_t addr; |
| 619 int count, index; |
| 620 |
| 621 objcSegment = [machOFile segmentWithName:@"__OBJC"]; |
| 622 protocolSection = [objcSegment sectionWithName:@"__protocol"]; |
| 623 addr = [protocolSection addr]; |
| 624 |
| 625 count = [protocolSection size] / sizeof(struct cd_objc_protocol); |
| 626 for (index = 0; index < count; index++, addr += sizeof(struct cd_objc_protoc
ol)) |
| 627 [self protocolAtAddress:addr]; // Forces them to be loaded |
| 628 |
| 629 [self createUniquedProtocols]; |
| 630 } |
| 631 |
| 632 - (NSData *)objcImageInfoData; |
| 633 { |
| 634 return [[[machOFile segmentWithName:@"__OBJC"] sectionWithName:@"__image_inf
o"] data]; |
| 635 } |
| 636 |
| 637 @end |
OLD | NEW |