home *** CD-ROM | disk | FTP | other *** search
/ Big Green CD 8 / BGCD_8_Dev.iso / OPENSTEP / UNIX / Programming / class-dump-2.1.1-MIS / src / class-dump.m < prev    next >
Encoding:
Text File  |  1997-12-08  |  26.5 KB  |  976 lines

  1. //
  2. // $Id: class-dump.m,v 1.9 1997/12/08 08:03:00 nygard Exp $
  3. //
  4.  
  5. //
  6. //  This file is a part of class-dump v2, a utility for examining the
  7. //  Objective-C segment of Mach-O files.
  8. //  Copyright (C) 1997  Steve Nygard
  9. //
  10. //  This program is free software; you can redistribute it and/or modify
  11. //  it under the terms of the GNU General Public License as published by
  12. //  the Free Software Foundation; either version 2 of the License, or
  13. //  (at your option) any later version.
  14. //
  15. //  This program is distributed in the hope that it will be useful,
  16. //  but WITHOUT ANY WARRANTY; without even the implied warranty of
  17. //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  18. //  GNU General Public License for more details.
  19. //
  20. //  You should have received a copy of the GNU General Public License
  21. //  along with this program; if not, write to the Free Software
  22. //  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  23. //
  24. //  You may contact the author by:
  25. //     e-mail:  nygard@telusplanet.net
  26. //
  27.  
  28. #include <stdio.h>
  29. #include <libc.h>
  30. #include <ctype.h>
  31.  
  32. #include <sys/types.h>
  33. #include <sys/stat.h>
  34.  
  35. #include <mach/mach.h>
  36. #include <mach/mach_error.h>
  37.  
  38. #include <mach-o/loader.h>
  39. #include <mach-o/fat.h>
  40.  
  41. #if NS_TARGET_MAJOR >= 4
  42. #import <Foundation/Foundation.h>
  43. #else
  44. #import <foundation/NSString.h>
  45. #import <foundation/NSArray.h>
  46. #import <foundation/NSDictionary.h>
  47. #import <foundation/NSAutoreleasePool.h>
  48. #import <foundation/NSUtilities.h>
  49. #endif
  50.  
  51. #include "datatypes.h"
  52. #include "class-dump.h"
  53.  
  54. #include "my_regex.h"
  55.  
  56. #import "ObjcThing.h"
  57. #import "ObjcClass.h"
  58. #import "ObjcCategory.h"
  59. #import "ObjcProtocol.h"
  60. #import "ObjcIvar.h"
  61. #import "ObjcMethod.h"
  62. #import "MappedFile.h"
  63.  
  64. #ifndef LC_PREBOUND_DYLIB
  65. #define LC_PREBOUND_DYLIB 0x10
  66. #endif
  67.  
  68. #ifndef LC_LOAD_DYLIB
  69. #define LC_LOAD_DYLIB 0x0c
  70.  
  71. struct dylib {
  72.     union lc_str  name;
  73.     unsigned long timestamp;
  74.     unsigned long current_version;
  75.     unsigned long compatibility_version;
  76. };
  77.  
  78. struct dylib_command {
  79.     unsigned long    cmd;
  80.     unsigned long    cmdsize;
  81.     struct dylib    dylib;
  82. };
  83. #endif
  84.  
  85. //----------------------------------------------------------------------
  86.  
  87. #define CLASS_DUMP_VERSION "2.1.1"
  88.  
  89. int expand_structures_flag = 0;
  90. int char_star_flag = 0;
  91.  
  92. BOOL show_ivar_offsets_flag = NO;
  93. BOOL show_method_addresses_flag = NO;
  94. BOOL expand_protocols_flag = NO;
  95. BOOL match_flag = NO;
  96. BOOL expand_frameworks_flag = NO;
  97. BOOL sort_flag = NO;
  98.  
  99. int swap_fat = 0;
  100. int swap_macho = 0;
  101.  
  102. #define MAX_SECTIONS 2048
  103.  
  104. NSMutableArray *mappedFiles;
  105.  
  106. char *current_filename = NULL;
  107.  
  108. struct section_info
  109. {
  110.     char *filename;
  111.     char name[17];
  112.     struct section *section;
  113.     void *start;
  114.     long vmaddr;
  115.     long size;
  116. } objc_sections[MAX_SECTIONS];
  117.  
  118. int section_count = 0;
  119.  
  120. //----------------------------------------------------------------------
  121.  
  122. #define SEC_CLASS          "__class"
  123. #define SEC_SYMBOLS        "__symbols"
  124. #define SEC_PROTOCOL       "__protocol"
  125. #define SEC_CATEGORY       "__category"
  126. #define SEC_CLS_METH       "__cls_meth"
  127. #define SEC_INST_METH      "__inst_meth"
  128. #define SEC_META_CLASS     "__meta_class"
  129. #define SEC_CLASS_NAMES    "__class_names"
  130. #define SEC_MODULE_INFO    "__module_info"
  131. #define SEC_CAT_CLS_METH   "__cat_cls_meth"
  132. #define SEC_INSTANCE_VARS  "__instance_vars"
  133. #define SEC_CAT_INST_METH  "__cat_inst_meth"
  134. #define SEC_METH_VAR_TYPES "__meth_var_types"
  135. #define SEC_METH_VAR_NAMES "__meth_var_names"
  136.  
  137. //======================================================================
  138.  
  139. char *file_type_names[] =
  140. {
  141.     "MH_<unknown>",
  142.     "MH_OBJECT",
  143.     "MH_EXECUTE",
  144.     "MH_FVMLIB",
  145.     "MH_CORE",
  146.     "MH_PRELOAD",
  147.     "MH_DYLIB",
  148.     "MH_DYLINKER",
  149.     "MH_BUNDLE",
  150. };
  151.  
  152. char *load_command_names[] =
  153. {
  154.     "LC_<unknown>",
  155.     "LC_SEGMENT",
  156.     "LC_SYMTAB",
  157.     "LC_SYMSEG",
  158.     "LC_THREAD",
  159.     "LC_UNIXTHREAD",
  160.     "LC_LOADFVMLIB",
  161.     "LC_IDFVMLIB",
  162.     "LC_IDENT",
  163.     "LC_FVMFILE",
  164.     "LC_PREPAGE",
  165.     "LC_DYSYMTAB",
  166.     "LC_LOAD_DYLIB",
  167.     "LC_ID_DYLIB",
  168.     "LC_LOAD_DYLINKER",
  169.     "LC_ID_DYLINKER",
  170.     "LC_PREBOUND_DYLIB",
  171. };
  172.  
  173. NSMutableDictionary *protocols;
  174.  
  175. //======================================================================
  176.  
  177. void process_file (void *ptr, char *filename);
  178.  
  179. int process_macho (void *ptr, char *filename);
  180. unsigned long process_load_command (void *start, void *ptr, char *filename);
  181. void process_dylib_command (void *start, void *ptr);
  182. void process_fvmlib_command (void *start, void *ptr);
  183. void process_segment_command (void *start, void *ptr, char *filename);
  184. void process_objc_segment (void *start, void *ptr, char *filename);
  185.  
  186. struct section_info *find_objc_section (char *name, char *filename);
  187. void *translate_address_to_pointer (long addr, char *section);
  188. char *string_at (long addr, char *section);
  189. NSString *nsstring_at (long addr, char *section);
  190.  
  191. struct section_info *section_of_address (long addr);
  192. NSArray *handle_objc_symtab (struct my_objc_symtab *symtab);
  193. ObjcClass *handle_objc_class (struct my_objc_class *ocl);
  194. ObjcCategory *handle_objc_category (struct my_objc_category *ocat);
  195. NSArray *handle_objc_protocols (struct my_objc_protocol_list *plist, BOOL expandProtocols);
  196. NSArray *handle_objc_meta_class (struct my_objc_class *ocl);
  197. NSArray *handle_objc_ivars (struct my_objc_ivars *ivars);
  198. NSArray *handle_objc_methods (struct my_objc_methods *methods, char ch);
  199.  
  200. void show_single_module (struct section_info *module_info);
  201. void show_all_modules (void);
  202. void build_up_objc_segments (char *filename);
  203.  
  204. //======================================================================
  205.  
  206. void process_file (void *ptr, char *filename)
  207. {
  208.     struct mach_header *mh = (struct mach_header *)ptr;
  209.     struct fat_header *fh = (struct fat_header *)ptr;
  210.     struct fat_arch *fa = (struct fat_arch *)(fh + 1);
  211.     int l;
  212.     int result = 1;
  213.  
  214.     if (mh->magic == FAT_CIGAM)
  215.     {
  216.         // Fat file... Other endian.
  217.  
  218.         swap_fat = 1;
  219.         for (l = 0; l < NXSwapLong (fh->nfat_arch); l++)
  220.         {
  221. #ifdef VERBOSE
  222.             printf ("archs: %ld\n", NXSwapLong (fh->nfat_arch));
  223.             printf ("offset: %lx\n", NXSwapLong (fa->offset));
  224.             printf ("arch: %08lx\n", NXSwapLong (fa->cputype));
  225. #endif
  226.             result = process_macho (ptr + NXSwapLong (fa->offset), filename);
  227.             if (result == 0) 
  228.                 break;
  229.             fa++;
  230.         }
  231.     }
  232.     else if (mh->magic == FAT_MAGIC)
  233.     {
  234.         // Fat file... This endian.
  235.  
  236.         for (l = 0; l < fh->nfat_arch; l++)
  237.         {
  238. #ifdef VERBOSE
  239.             printf ("archs: %ld\n", fh->nfat_arch);
  240.             printf ("offset: %lx\n", fa->offset);
  241.             printf ("arch: %08lx\n", fa->cputype);
  242. #endif
  243.             result = process_macho (ptr + fa->offset, filename);
  244.             if (result == 0) 
  245.                 break;
  246.             fa++;
  247.         }
  248.     }
  249.     else
  250.     {
  251.         result = process_macho (ptr, filename);
  252.     }
  253.  
  254.     switch (result)
  255.     {
  256.       case 0:
  257.           break;
  258.           
  259.       case 1:
  260.           printf ("Error: File did not contain an executable with our endian.\n");
  261.           break;
  262.  
  263.       default:
  264.           printf ("Error: processing Mach-O file.\n");
  265.     }
  266. }
  267.  
  268. //----------------------------------------------------------------------
  269.  
  270. // Returns 0 if this was our endian, 1 if it was not, 2 otherwise.
  271.  
  272. int process_macho (void *ptr, char *filename)
  273. {
  274.     struct mach_header *mh = (struct mach_header *)ptr;
  275.     int l;
  276.     void *start = ptr;
  277.  
  278.     if (mh->magic == MH_CIGAM)
  279.     {
  280.         swap_macho = 1;
  281.         return 1;
  282.     }
  283.     else if (mh->magic != MH_MAGIC)
  284.     {
  285.         printf ("This is not a Mach-O file.\n");
  286.         return 2;
  287.     }
  288.  
  289.     ptr += sizeof (struct mach_header);
  290.  
  291.     for (l = 0; l < mh->ncmds; l++)
  292.     {
  293.         ptr += process_load_command (start, ptr, filename);
  294.     }
  295.  
  296.     return 0;
  297. }
  298.  
  299. //----------------------------------------------------------------------
  300.  
  301. unsigned long process_load_command (void *start, void *ptr, char *filename)
  302. {
  303.     struct load_command *lc = (struct load_command *)ptr;
  304.  
  305. #ifdef VERBOSE
  306.     if (lc->cmd >= 0 && lc->cmd <= LC_PREBOUND_DYLIB)
  307.     {
  308.         printf ("%s\n", load_command_names[ lc->cmd ]);
  309.     }
  310.     else
  311.     {
  312.         printf ("%08lx\n", lc->cmd);
  313.     }
  314. #endif
  315.  
  316.     if (lc->cmd == LC_SEGMENT)
  317.     {
  318.         process_segment_command (start, ptr, filename);
  319.     }
  320.     else if (lc->cmd == LC_LOAD_DYLIB)
  321.     {
  322.         process_dylib_command (start, ptr);
  323.     }
  324.     else if (lc->cmd == LC_LOADFVMLIB)
  325.     {
  326.         process_fvmlib_command (start, ptr);
  327.     }
  328.  
  329.     return lc->cmdsize;
  330. }
  331.  
  332. //----------------------------------------------------------------------
  333.  
  334. void process_dylib_command (void *start, void *ptr)
  335. {
  336.     struct dylib_command *dc = (struct dylib_command *)ptr;
  337.  
  338.     build_up_objc_segments (ptr + dc->dylib.name.offset);
  339. }
  340.  
  341. //----------------------------------------------------------------------
  342.  
  343. void process_fvmlib_command (void *start, void *ptr)
  344. {
  345.     struct fvmlib_command *fc = (struct fvmlib_command *)ptr;
  346.  
  347.     build_up_objc_segments (ptr + fc->fvmlib.name.offset);
  348. }
  349.  
  350. //----------------------------------------------------------------------
  351.  
  352. void process_segment_command (void *start, void *ptr, char *filename)
  353. {
  354.     struct segment_command *sc = (struct segment_command *)ptr;
  355.     char name[17];
  356.   
  357.     strncpy (name, sc->segname, 16);
  358.     name[16] = 0;
  359.  
  360.     if (!strcmp (name, SEG_OBJC))
  361.     {
  362.         process_objc_segment (start, ptr, filename);
  363.     }
  364. }
  365.  
  366. //----------------------------------------------------------------------
  367.  
  368. void process_objc_segment (void *start, void *ptr, char *filename)
  369. {
  370.     struct segment_command *sc = (struct segment_command *)ptr;
  371.     struct section *section = (struct section *)(sc + 1);
  372.     int l;
  373.  
  374.     for (l = 0; l < sc->nsects; l++)
  375.     {
  376.         if (section_count >= MAX_SECTIONS)
  377.         {
  378.             printf ("Error: Maximum number of sections reached.\n");
  379.             return;
  380.         }
  381.  
  382.         objc_sections[section_count].filename = filename;
  383.         strncpy (objc_sections[section_count].name, section->sectname, 16);
  384.         objc_sections[section_count].name[16] = 0;
  385.         objc_sections[section_count].section = section;
  386.         objc_sections[section_count].start = start + section->offset;
  387.         objc_sections[section_count].vmaddr = section->addr;
  388.         objc_sections[section_count].size = section->size;
  389.         section++;
  390.         section_count++;
  391.     }
  392. }
  393.  
  394. //----------------------------------------------------------------------
  395.  
  396. // Find the Objective-C segment for the given filename noted in our
  397. // list.
  398.  
  399. struct section_info *find_objc_section (char *name, char *filename)
  400. {
  401.     int l;
  402.  
  403.     for (l = 0; l < section_count; l++)
  404.     {
  405.         if (!strcmp (name, objc_sections[l].name) && !strcmp (filename, objc_sections[l].filename))
  406.         {
  407.             return &objc_sections[l];
  408.         }
  409.     }
  410.  
  411.     return NULL;
  412. }
  413.  
  414. //----------------------------------------------------------------------
  415.  
  416. void debug_section_overlap (void)
  417. {
  418.     int l;
  419.  
  420.     for (l = 0; l < section_count; l++)
  421.     {
  422.         printf ("%10ld to %10ld [size 0x%08ld] %-16s of %s\n",
  423.                 objc_sections[l].vmaddr, objc_sections[l].vmaddr + objc_sections[l].size, objc_sections[l].size,
  424.                 objc_sections[l].name, objc_sections[l].filename);
  425.     }
  426. }
  427.  
  428. //----------------------------------------------------------------------
  429.  
  430. //
  431. // Take a long from the Mach-O file (which is really a pointer when
  432. // the section is loaded at the proper location) and translate it into
  433. // a pointer to where we have the file mapped.
  434. //
  435.  
  436. void *translate_address_to_pointer (long addr, char *section)
  437. {
  438.     int l;
  439.     int count = 0;
  440.  
  441.     for (l = 0; l < section_count; l++)
  442.     {
  443.         if (addr >= objc_sections[l].vmaddr && addr < objc_sections[l].vmaddr + objc_sections[l].size
  444.             && !strcmp (objc_sections[l].name, section))
  445.         {
  446.             count++;
  447.         }
  448.     }
  449.  
  450.     if (count > 1)
  451.     {
  452.         // If there are still duplicates, we choose the one for the current file.
  453.         for (l = 0; l < section_count; l++)
  454.         {
  455.             if (addr >= objc_sections[l].vmaddr && addr < objc_sections[l].vmaddr + objc_sections[l].size
  456.                 && !strcmp (objc_sections[l].name, section)
  457.                 && !strcmp (objc_sections[l].filename, current_filename))
  458.             {
  459.                 return objc_sections[l].start + addr - objc_sections[l].vmaddr;
  460.             }
  461.         }
  462.     }
  463.     else
  464.     {
  465.         for (l = 0; l < section_count; l++)
  466.         {
  467.             if (addr >= objc_sections[l].vmaddr && addr < objc_sections[l].vmaddr + objc_sections[l].size
  468.                 && !strcmp (objc_sections[l].name, section))
  469.             {
  470.                 return objc_sections[l].start + addr - objc_sections[l].vmaddr;
  471.             }
  472.         }
  473.     }
  474.  
  475.     if (addr != 0)
  476.         printf ("address (0x%08lx) not in OBJC segment!\n", addr);
  477.  
  478.     return NULL;
  479. }
  480.  
  481. //----------------------------------------------------------------------
  482.  
  483. char *string_at (long addr, char *section)
  484. {
  485.     return (char *)translate_address_to_pointer (addr, section);
  486. }
  487.  
  488. //----------------------------------------------------------------------
  489.  
  490. NSString *nsstring_at (long addr, char *section)
  491. {
  492.     char *str = string_at (addr, section);
  493.     return (str == NULL) ? (NSString *)@"" : [NSString stringWithCString:str];
  494. }
  495.  
  496. //----------------------------------------------------------------------
  497.  
  498. struct section_info *section_of_address (long addr)
  499. {
  500.     int l;
  501.  
  502.     for (l = 0; l < section_count; l++)
  503.     {
  504.         if (addr >= objc_sections[l].vmaddr && addr < objc_sections[l].vmaddr + objc_sections[l].size)
  505.         {
  506.             return &objc_sections[l];
  507.         }
  508.     }
  509.  
  510.     return NULL;
  511. }
  512.  
  513. //======================================================================
  514.  
  515. NSArray *handle_objc_symtab (struct my_objc_symtab *symtab)
  516. {
  517.     NSMutableArray *classList = [NSMutableArray array];
  518.     ObjcThing *objcThing;
  519.     long *class_pointer;
  520.     int l;
  521.   
  522.     if (symtab == NULL)
  523.     {
  524.         printf ("NULL symtab...\n");
  525.         return nil;
  526.     }
  527.  
  528.     class_pointer = &symtab->class_pointer;
  529.  
  530.     for (l = 0; l < symtab->cls_def_count; l++)
  531.     {
  532.         objcThing = handle_objc_class (translate_address_to_pointer (*class_pointer, SEC_CLASS));
  533.         if (objcThing != nil)
  534.             [classList addObject:objcThing];
  535.  
  536.         class_pointer++;
  537.     }
  538.  
  539.     for (l = 0; l < symtab->cat_def_count; l++)
  540.     {
  541.         objcThing = handle_objc_category (translate_address_to_pointer (*class_pointer, SEC_CATEGORY));
  542.         if (objcThing != nil)
  543.             [classList addObject:objcThing];
  544.  
  545.         class_pointer++;
  546.     }
  547.  
  548.     return classList;
  549. }
  550.  
  551. //----------------------------------------------------------------------
  552.  
  553. ObjcClass *handle_objc_class (struct my_objc_class *ocl)
  554. {
  555.     ObjcClass *objcClass;
  556.     NSArray *tmp;
  557.     
  558.     if (ocl == NULL)
  559.         return nil;
  560.  
  561.     tmp = handle_objc_protocols ((struct my_objc_protocol_list *)translate_address_to_pointer (ocl->protocols, SEC_CAT_CLS_METH), YES);
  562.  
  563.     if (string_at (ocl->super_class, SEC_CLASS_NAMES) == NULL)
  564.     {
  565.         objcClass = [[[ObjcClass alloc] initWithClassName:nsstring_at (ocl->name, SEC_CLASS_NAMES) superClassName:nil] autorelease];
  566.     }
  567.     else
  568.     {
  569.         objcClass = [[[ObjcClass alloc] initWithClassName:nsstring_at (ocl->name, SEC_CLASS_NAMES)
  570.                                         superClassName:nsstring_at (ocl->super_class, SEC_CLASS_NAMES)] autorelease];
  571.     }
  572.  
  573.     [objcClass addProtocolNames:tmp];
  574.  
  575.     tmp = handle_objc_ivars ((struct my_objc_ivars *)translate_address_to_pointer (ocl->ivars, SEC_INSTANCE_VARS));
  576.     [objcClass addIvars:tmp];
  577.  
  578.     tmp = handle_objc_meta_class ((struct my_objc_class *)translate_address_to_pointer (ocl->isa, SEC_META_CLASS));
  579.     [objcClass addClassMethods:tmp];
  580.  
  581.     tmp = handle_objc_methods ((struct my_objc_methods *)translate_address_to_pointer (ocl->methods, SEC_INST_METH), '-');
  582.     [objcClass addInstanceMethods:tmp];
  583.  
  584.     return objcClass;
  585. }
  586.  
  587. //----------------------------------------------------------------------
  588.  
  589. ObjcCategory *handle_objc_category (struct my_objc_category *ocat)
  590. {
  591.     ObjcCategory *objcCategory;
  592.     NSArray *tmp;
  593.     
  594.     if (ocat == NULL)
  595.         return nil;
  596.   
  597.     objcCategory = [[[ObjcCategory alloc] initWithClassName:nsstring_at (ocat->class_name, SEC_CLASS_NAMES)
  598.                                           categoryName:nsstring_at (ocat->category_name, SEC_CLASS_NAMES)] autorelease];
  599.  
  600.     tmp = handle_objc_methods ((struct my_objc_methods *)translate_address_to_pointer (ocat->class_methods, SEC_CAT_CLS_METH), '+');
  601.     [objcCategory addClassMethods:tmp];
  602.  
  603.     tmp = handle_objc_methods ((struct my_objc_methods *)translate_address_to_pointer (ocat->methods, SEC_CAT_INST_METH), '-');
  604.     [objcCategory addInstanceMethods:tmp];
  605.  
  606.     return objcCategory;
  607. }
  608.  
  609. //----------------------------------------------------------------------
  610.  
  611. // Return list of protocol names.
  612. NSArray *handle_objc_protocols (struct my_objc_protocol_list *plist, BOOL expandProtocols)
  613. {
  614.     NSMutableArray *protocolArray = [NSMutableArray array];
  615.     ObjcProtocol *objcProtocol;
  616.     struct my_objc_protocol *prot;
  617.     struct my_objc_prot_inst_meth_list *mlist;
  618.     struct my_objc_prot_inst_meth *meth;
  619.     int l, p;
  620.     long *ptr;
  621.     NSArray *parentProtocols;
  622.  
  623.     if (plist == NULL)
  624.         return nil;
  625.   
  626.     ptr = &plist->list;
  627.  
  628.     for (p = 0; p < plist->count; p++)
  629.     {
  630.         prot = translate_address_to_pointer (*ptr, SEC_PROTOCOL);
  631.  
  632.         objcProtocol = [[[ObjcProtocol alloc] initWithProtocolName:nsstring_at (prot->protocol_name, SEC_CLASS_NAMES)] autorelease];
  633.         [protocolArray addObject:[objcProtocol protocolName]];
  634.  
  635.         parentProtocols = handle_objc_protocols (translate_address_to_pointer (prot->protocol_list, SEC_CAT_CLS_METH),
  636.                                                  expand_protocols_flag);
  637.         [objcProtocol addProtocolNames:parentProtocols];
  638.  
  639.         mlist = translate_address_to_pointer (prot->instance_methods, SEC_CAT_INST_METH);
  640.         if (mlist != NULL)
  641.         {
  642.             meth = (struct my_objc_prot_inst_meth *)&mlist->methods;
  643.  
  644.             for (l = 0; l < mlist->count; l++)
  645.             {
  646.                 [objcProtocol addProtocolMethod:[[[ObjcMethod alloc] initWithMethodName:nsstring_at (meth->name, SEC_METH_VAR_NAMES)
  647.                                                                      type:nsstring_at (meth->types, SEC_METH_VAR_TYPES)] autorelease]];
  648.                 meth++;
  649.             }
  650.         }
  651.  
  652.         if (expandProtocols == YES && [protocols objectForKey:[objcProtocol protocolName]] == nil)
  653.         {
  654.             [protocols setObject:objcProtocol forKey:[objcProtocol protocolName]];
  655.             objcProtocol = nil;
  656.         }
  657.  
  658.         ptr++;
  659.     }
  660.  
  661.     return protocolArray;
  662. }
  663.  
  664. //----------------------------------------------------------------------
  665.  
  666. NSArray *handle_objc_meta_class (struct my_objc_class *ocl)
  667. {
  668.     if (ocl == NULL)
  669.         return nil;
  670.  
  671.     return handle_objc_methods ((struct my_objc_methods *)translate_address_to_pointer (ocl->methods, SEC_CLS_METH), '+');
  672. }  
  673.  
  674. //----------------------------------------------------------------------
  675.  
  676. NSArray *handle_objc_ivars (struct my_objc_ivars *ivars)
  677. {
  678.     struct my_objc_ivar *ivar = (struct my_objc_ivar *)(ivars + 1);
  679.     NSMutableArray *ivarArray = [NSMutableArray array];
  680.     ObjcIvar *objcIvar;
  681.     int l;
  682.  
  683.     if (ivars == NULL)
  684.         return nil;
  685.  
  686.     for (l = 0; l < ivars->ivar_count; l++)
  687.     {
  688.         objcIvar = [[[ObjcIvar alloc] initWithName:nsstring_at (ivar->name, SEC_METH_VAR_NAMES)
  689.                                       type:nsstring_at (ivar->type, SEC_METH_VAR_TYPES)
  690.                                       offset:ivar->offset] autorelease];
  691.         [ivarArray addObject:objcIvar];
  692.  
  693.         ivar++;
  694.     }
  695.  
  696.     return ivarArray;
  697. }
  698.  
  699. //----------------------------------------------------------------------
  700.  
  701. NSArray *handle_objc_methods (struct my_objc_methods *methods, char ch)
  702. {
  703.     struct my_objc_method *method = (struct my_objc_method *)(methods + 1);
  704.     NSMutableArray *methodArray = [NSMutableArray array];
  705.     ObjcMethod *objcMethod;
  706.     int l;
  707.  
  708.     if (methods == NULL)
  709.         return nil;
  710.  
  711.     for (l = 0; l < methods->method_count; l++)
  712.     {
  713.         if (method->imp != 0)
  714.         {
  715.             objcMethod = [[[ObjcMethod alloc] initWithMethodName:nsstring_at (method->name, SEC_METH_VAR_NAMES)
  716.                                               type:nsstring_at (method->types, SEC_METH_VAR_TYPES)
  717.                                               address:method->imp] autorelease];
  718.             [methodArray addObject:objcMethod];
  719.         }
  720.         method++;
  721.     }
  722.  
  723.     return methodArray;
  724. }
  725.  
  726. //======================================================================
  727.  
  728. void show_single_module (struct section_info *module_info)
  729. {
  730.     struct my_objc_module *m;
  731.     int module_count;
  732.     int l;
  733.     char *tmp;
  734.     id en, thing, key;
  735.     NSMutableArray *classList = [NSMutableArray array];
  736.     NSArray *newClasses;
  737.     int flags = 0;
  738.  
  739.     if (module_info == NULL)
  740.     {
  741.         return;
  742.     }
  743.  
  744.     if (sort_flag == YES)
  745.         flags |= F_SORT_METHODS;
  746.  
  747.     if (show_ivar_offsets_flag == YES)
  748.         flags |= F_SHOW_IVAR_OFFSET;
  749.  
  750.     if (show_method_addresses_flag == YES)
  751.         flags |= F_SHOW_METHOD_ADDRESS;
  752.  
  753.     tmp = current_filename;
  754.     m = module_info->start;
  755.     module_count = module_info->size / sizeof (struct my_objc_module);
  756.  
  757.     printf ("\n/*\n * File: %s\n */\n\n", module_info->filename);
  758.     current_filename = module_info->filename;
  759.  
  760.     for (l = 0; l < module_count; l++)
  761.     {
  762.         newClasses = handle_objc_symtab ((struct my_objc_symtab *)translate_address_to_pointer (m->symtab, SEC_SYMBOLS));
  763.         [classList addObjectsFromArray:newClasses];
  764.         m++;
  765.     }
  766.  
  767.  
  768.     if (sort_flag == YES)
  769.         en = [[[protocols allKeys] sortedArrayUsingSelector:@selector (compare:)] objectEnumerator];
  770.     else
  771.         en = [[protocols allKeys] objectEnumerator];
  772.  
  773.     while (key = [en nextObject])
  774.     {
  775.         thing = [protocols objectForKey:key];
  776.         if (match_flag == NO || RE_EXEC ([[thing sortableName] cString]) == 1)
  777.             [thing showDefinition:flags];
  778.     }
  779.  
  780.     if (sort_flag == YES)
  781.         en = [[classList sortedArrayUsingSelector:@selector (orderByName:)] objectEnumerator];
  782.     else
  783.         en = [classList objectEnumerator]; 
  784.  
  785.     while (thing = [en nextObject])
  786.     {
  787.         if (match_flag == NO || RE_EXEC ([[thing sortableName] cString]) == 1)
  788.             [thing showDefinition:flags];
  789.     }
  790.  
  791.     [protocols removeAllObjects];
  792.  
  793.     current_filename = tmp;
  794. }
  795.  
  796. //----------------------------------------------------------------------
  797.  
  798. void show_all_modules (void)
  799. {
  800.     int l;
  801.  
  802.     for (l = section_count - 1; l >= 0; l--)
  803.     {
  804.         if (!strcmp (objc_sections[l].name, SEC_MODULE_INFO))
  805.         {
  806.             show_single_module ((struct section_info *)&objc_sections[l]);
  807.         }
  808.     }
  809. }
  810.  
  811. //----------------------------------------------------------------------
  812.  
  813. void build_up_objc_segments (char *filename)
  814. {    
  815.     MappedFile *mappedFile;
  816.     NSEnumerator *mfEnumerator;
  817.  
  818.     // Only process each file once.
  819.  
  820.     mfEnumerator = [mappedFiles objectEnumerator];
  821.     while (mappedFile = [mfEnumerator nextObject])
  822.     {
  823.         if (!strcmp (filename, [[mappedFile filename] cString]))
  824.             return;
  825.     }
  826.  
  827.     mappedFile = [[[MappedFile alloc] initWithFilename:[NSString stringWithCString:filename]] autorelease];
  828.     //NSCAssert (mappedFile != nil, @"Could not map file...");
  829.     if (mappedFile != nil)
  830.     {
  831.         [mappedFiles addObject:mappedFile];
  832.  
  833.         process_file ((void *)[mappedFile data], filename);
  834.     }
  835. }
  836.  
  837. //----------------------------------------------------------------------
  838.  
  839. void print_usage (void)
  840. {
  841.     fprintf (stderr,
  842.              "class-dump %s\n"
  843.              "Usage: class-dump [-a] [-A] [-e] [-R] [-C regex] [-r] [-s] [-S] executable-file\n"
  844.              "        -a  show instance variable offsets\n"
  845.              "        -A  show implementation addresses\n"
  846.              "        -e  expand structure (and union) definition whenever possible\n"
  847.              "        -R  recursively expand @protocol <>\n"
  848.              "        -C  only display classes matching regular expression\n"
  849.              "        -r  recursively expand frameworks and fixed VM shared libraries\n"
  850.              "        -s  convert STR to char *\n"
  851.              "        -S  sort protocols, classes, and methods\n",
  852.              CLASS_DUMP_VERSION
  853.        );
  854. }
  855.  
  856. //----------------------------------------------------------------------
  857.  
  858. void print_header (void)
  859. {
  860.     printf (
  861.         "/*\n"
  862.         " *     Generated by class-dump (version %s).\n"
  863.         " *\n"
  864.         " *     class-dump is Copyright (C) 1997 by Steve Nygard.\n"
  865.         " */\n", CLASS_DUMP_VERSION
  866.        );
  867. }
  868.  
  869. //======================================================================
  870.  
  871. int main (int argc, char *argv[])
  872. {
  873.     NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
  874.     int c;
  875.     extern int optind;
  876.     extern char *optarg;
  877.     int error_flag = 0;
  878.     const char *tmp;
  879.   
  880.     if (argc == 1)
  881.     {
  882.         print_usage();
  883.         exit (2);
  884.     }
  885.  
  886.     while ( (c = getopt (argc, argv, "aAeRC:rsS")) != EOF)
  887.     {
  888.         switch (c)
  889.         {
  890.           case 'a':
  891.               show_ivar_offsets_flag = YES;
  892.               break;
  893.         
  894.           case 'A':
  895.               show_method_addresses_flag = YES;
  896.               break;
  897.         
  898.           case 'e':
  899.               expand_structures_flag = 1;
  900.               break;
  901.         
  902.           case 'R':
  903.               expand_protocols_flag = YES;
  904.               break;
  905.         
  906.           case 'C':
  907.               if (match_flag == YES)
  908.               {
  909.                   printf ("Error: sorry, only one -C allowed\n");
  910.                   error_flag++;
  911.               }
  912.               else
  913.               {
  914.                   match_flag = YES;
  915.  
  916.                   tmp = RE_COMP (optarg);
  917.                   if (tmp != NULL)
  918.                   {
  919.                       printf ("Error: %s\n", tmp);
  920.                       exit (1);
  921.                   }
  922.               }
  923.               break;
  924.         
  925.           case 'r':
  926.               expand_frameworks_flag = YES;
  927.               break;
  928.         
  929.           case 's':
  930.               char_star_flag = 1;
  931.               break;
  932.         
  933.           case 'S':
  934.               sort_flag = YES;
  935.               break;
  936.  
  937.           case '?':
  938.           default:
  939.               error_flag++;
  940.               break;
  941.         }
  942.     }
  943.  
  944.     if (error_flag > 0)
  945.     {
  946.         print_usage ();
  947.         exit (2);
  948.     }
  949.  
  950.     mappedFiles = [NSMutableArray array];
  951.     protocols = [NSMutableDictionary dictionary];
  952.  
  953.     if (optind < argc)
  954.     {
  955.         build_up_objc_segments (argv[optind]);
  956.  
  957.         print_header ();
  958.  
  959.         //debug_section_overlap ();
  960.  
  961.         if (section_count > 0)
  962.         {
  963.             if (expand_frameworks_flag == NO)
  964.                 show_single_module ((struct section_info *)find_objc_section (SEC_MODULE_INFO, argv[optind]));
  965.             else
  966.                 show_all_modules ();
  967.         }
  968.     }
  969.  
  970.     [mappedFiles removeAllObjects];
  971.  
  972.     [pool release];
  973.  
  974.     return 0;
  975. }
  976.