1/*
2 * Copyright © 2009 Apple Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions are met:
8 *
9 * 1.  Redistributions of source code must retain the above copyright notice,
10 * this list of conditions and the following disclaimer.
11 * 2.  Redistributions in binary form must reproduce the above copyright notice,
12 * this list of conditions and the following disclaimer in the documentation
13 * and/or other materials provided with the distribution.
14 * 3.  Neither the name of Apple Inc. ("Apple") nor the names of its
15 * contributors may be used to endorse or promote products derived from this
16 * software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
19 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
22 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
24 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
25 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 *
29 * @APPLE_LICENSE_HEADER_END@
30 */
31#include "stdio.h"
32#include "string.h"
33#include "mach-o/loader.h"
34#include "objc/objc-runtime.h"
35#include "stuff/allocate.h"
36#include "stuff/bytesex.h"
37#include "stuff/symbol.h"
38#include "ofile_print.h"
39
40/*
41 * Here we need structures that have the same memory layout and size as the
42 * 32-bit Objective-C 1 meta data structures.
43 *
44 * The real structure definitions come from the header file objc/objc-runtime.h
45 * and those it includes like objc/objc-class.h, etc.  But since this program
46 * must also run on 64-bit hosts that can't be used.
47 */
48
49struct objc_module_t {
50    uint32_t version;
51    uint32_t size;
52    uint32_t name;	/* char * (32-bit pointer) */
53    uint32_t symtab;	/* struct objc_symtab * (32-bit pointer) */
54};
55
56struct objc_symtab_t {
57    uint32_t sel_ref_cnt;
58    uint32_t refs;		/* SEL * (32-bit pointer) */
59    uint16_t cls_def_cnt;
60    uint16_t cat_def_cnt;
61    uint32_t defs[1];		/* void * (32-bit pointer) variable size */
62};
63
64struct objc_class_t {
65    uint32_t isa;	  /* struct objc_class * (32-bit pointer) */
66    uint32_t super_class; /* struct objc_class * (32-bit pointer) */
67    uint32_t name; 	  /* const char * (32-bit pointer) */
68    int32_t version;
69    int32_t info;
70    int32_t instance_size;
71    uint32_t ivars; 	  /* struct objc_ivar_list * (32-bit pointer) */
72    uint32_t methodLists; /* struct objc_method_list ** (32-bit pointer) */
73    uint32_t cache; 	  /* struct objc_cache * (32-bit pointer) */
74    uint32_t protocols;   /* struct objc_protocol_list * (32-bit pointer) */
75};
76
77struct objc_category_t {
78    uint32_t category_name;	/* char * (32-bit pointer) */
79    uint32_t class_name;	/* char * (32-bit pointer) */
80    uint32_t instance_methods;	/* struct objc_method_list * (32-bit pointer) */
81    uint32_t class_methods;	/* struct objc_method_list * (32-bit pointer) */
82    uint32_t protocols;		/* struct objc_protocol_list * (32-bit ptr) */
83};
84
85struct objc_ivar_t {
86    uint32_t ivar_name;		/* char * (32-bit pointer) */
87    uint32_t ivar_type;		/* char * (32-bit pointer) */
88    int32_t ivar_offset;
89};
90
91struct objc_ivar_list_t {
92    int32_t ivar_count;
93    struct objc_ivar_t ivar_list[1];          /* variable length structure */
94};
95
96struct objc_method_t {
97    uint32_t method_name; /* SEL, aka struct objc_selector * (32-bit pointer) */
98    uint32_t method_types; /* char * (32-bit pointer) */
99    uint32_t method_imp; /* IMP, aka function pointer, (*IMP)(id, SEL, ...)
100			    (32-bit pointer) */
101};
102
103struct objc_method_list_t {
104    uint32_t obsolete;		/* struct objc_method_list * (32-bit pointer) */
105    int32_t method_count;
106    struct objc_method_t method_list[1];      /* variable length structure */
107};
108
109struct objc_protocol_t {
110    uint32_t isa;		/* struct objc_class * (32-bit pointer) */
111    uint32_t protocol_name;	/* char * (32-bit pointer) */
112    uint32_t protocol_list;	/* struct objc_protocol_list *
113				   (32-bit pointer) */
114    uint32_t instance_methods;	/* struct objc_method_description_list *
115				   (32-bit pointer) */
116    uint32_t class_methods;	/* struct objc_method_description_list *
117				   (32-bit pointer) */
118};
119
120struct objc_protocol_list_t {
121    uint32_t next;	/* struct objc_protocol_list * (32-bit pointer) */
122    int32_t count;
123    uint32_t list[1];	/* Protocol *, aka struct objc_protocol_t * (
124			   (32-bit pointer) */
125};
126
127struct objc_method_description_t {
128    uint32_t name;	/* SEL, aka struct objc_selector * (32-bit pointer) */
129    uint32_t types;	/* char * (32-bit pointer) */
130};
131
132struct objc_method_description_list_t {
133    int32_t count;
134    struct objc_method_description_t list[1];
135};
136
137
138/*
139 * The header file "objc/NXString.h" has gone away and there is no real public
140 * header file to get this definition from anymore.
141 */
142struct objc_string_object_t {
143    uint32_t isa;		/* struct objc_class * (32-bit pointer) */
144    uint32_t characters;	/* char * (32-bit pointer) */
145    uint32_t _length;
146};
147typedef struct objc_string_object_t NXConstantString;
148
149#define SIZEHASHTABLE 821
150struct _hashEntry_t {
151    uint32_t next;	/* struct _hashEntry * (32-bit pointer) */
152    uint32_t sel;	/* char * (32-bit pointer) */
153};
154
155struct imageInfo_t {
156    uint32_t version;
157    uint32_t flags;
158};
159
160static
161void
162swap_imageInfo_t(
163struct imageInfo_t *o,
164enum byte_sex target_byte_sex)
165{
166	o->version = SWAP_INT(o->version);
167	o->flags = SWAP_INT(o->flags);
168}
169
170void
171swap_objc_module_t(
172struct objc_module_t *module,
173enum byte_sex target_byte_sex)
174{
175	module->version = SWAP_INT(module->version);
176	module->size = SWAP_INT(module->size);
177	module->name = SWAP_INT(module->name);
178	module->symtab = SWAP_INT(module->symtab);
179}
180
181void
182swap_objc_symtab_t(
183struct objc_symtab_t *symtab,
184enum byte_sex target_byte_sex)
185{
186	symtab->sel_ref_cnt = SWAP_INT(symtab->sel_ref_cnt);
187	symtab->refs = SWAP_INT(symtab->refs);
188	symtab->cls_def_cnt = SWAP_SHORT(symtab->cls_def_cnt);
189	symtab->cat_def_cnt = SWAP_SHORT(symtab->cat_def_cnt);
190}
191
192void
193swap_objc_class_t(
194struct objc_class_t *objc_class,
195enum byte_sex target_byte_sex)
196{
197	objc_class->isa = SWAP_INT(objc_class->isa);
198	objc_class->super_class = SWAP_INT(objc_class->super_class);
199	objc_class->name = SWAP_INT(objc_class->name);
200	objc_class->version = SWAP_INT(objc_class->version);
201	objc_class->info = SWAP_INT(objc_class->info);
202	objc_class->instance_size = SWAP_INT(objc_class->instance_size);
203	objc_class->ivars = SWAP_INT(objc_class->ivars);
204	objc_class->methodLists = SWAP_INT(objc_class->methodLists);
205	objc_class->cache = SWAP_INT(objc_class->cache);
206	objc_class->protocols = SWAP_INT(objc_class->protocols);
207}
208
209void
210swap_objc_category_t(
211struct objc_category_t *objc_category,
212enum byte_sex target_byte_sex)
213{
214	objc_category->category_name = SWAP_INT(objc_category->category_name);
215	objc_category->class_name = SWAP_INT(objc_category->class_name);
216	objc_category->instance_methods =
217		SWAP_INT(objc_category->instance_methods);
218	objc_category->class_methods =
219		SWAP_INT(objc_category->class_methods);
220	objc_category->protocols =
221		SWAP_INT(objc_category->protocols);
222}
223
224void
225swap_objc_ivar_list_t(
226struct objc_ivar_list_t *objc_ivar_list,
227enum byte_sex target_byte_sex)
228{
229	objc_ivar_list->ivar_count = SWAP_INT(objc_ivar_list->ivar_count);
230}
231
232void
233swap_objc_ivar_t(
234struct objc_ivar_t *objc_ivar,
235enum byte_sex target_byte_sex)
236{
237	objc_ivar->ivar_name = SWAP_INT(objc_ivar->ivar_name);
238	objc_ivar->ivar_type = SWAP_INT(objc_ivar->ivar_type);
239	objc_ivar->ivar_offset = SWAP_INT(objc_ivar->ivar_offset);
240}
241
242void
243swap_objc_method_list_t(
244struct objc_method_list_t *method_list,
245enum byte_sex target_byte_sex)
246{
247	method_list->obsolete = SWAP_INT(method_list->obsolete);
248	method_list->method_count = SWAP_INT(method_list->method_count);
249}
250
251void
252swap_objc_method_t(
253struct objc_method_t *method,
254enum byte_sex target_byte_sex)
255{
256	method->method_name = SWAP_INT(method->method_name);
257	method->method_types = SWAP_INT(method->method_types);
258	method->method_imp = SWAP_INT(method->method_imp);
259}
260
261void
262swap_objc_protocol_list_t(
263struct objc_protocol_list_t *protocol_list,
264enum byte_sex target_byte_sex)
265{
266	protocol_list->next = SWAP_INT(protocol_list->next);
267	protocol_list->count = SWAP_INT(protocol_list->count);
268}
269
270void
271swap_objc_protocol_t(
272struct objc_protocol_t *protocol,
273enum byte_sex target_byte_sex)
274{
275	protocol->isa = SWAP_INT(protocol->isa);
276	protocol->protocol_name = SWAP_INT(protocol->protocol_name);
277	protocol->protocol_list = SWAP_INT(protocol->protocol_list);
278	protocol->instance_methods = SWAP_INT(protocol->instance_methods);
279	protocol->class_methods = SWAP_INT(protocol->class_methods);
280}
281
282void
283swap_objc_method_description_list_t(
284struct objc_method_description_list_t *mdl,
285enum byte_sex target_byte_sex)
286{
287	mdl->count = SWAP_INT(mdl->count);
288}
289
290void
291swap_objc_method_description_t(
292struct objc_method_description_t *md,
293enum byte_sex target_byte_sex)
294{
295	md->name = SWAP_INT(md->name);
296	md->types = SWAP_INT(md->types);
297}
298
299void
300swap_string_object_t(
301struct objc_string_object_t *string_object,
302enum byte_sex target_byte_sex)
303{
304	string_object->isa = SWAP_INT(string_object->isa);
305	string_object->characters = SWAP_INT(string_object->characters);
306	string_object->_length = SWAP_INT(string_object->_length);
307}
308
309void
310swap_hashEntry_t(
311struct _hashEntry_t *_hashEntry,
312enum byte_sex target_byte_sex)
313{
314	_hashEntry->next = SWAP_INT(_hashEntry->next);
315	_hashEntry->sel = SWAP_INT(_hashEntry->sel);
316}
317
318struct section_info {
319    char *contents;
320    uint32_t addr;
321    uint32_t size;
322    uint32_t offset;
323    enum bool protected;
324    enum bool zerofill;
325};
326
327static void get_objc_sections(
328    struct load_command *load_commands,
329    uint32_t ncmds,
330    uint32_t sizeofcmds,
331    enum byte_sex object_byte_sex,
332    char *object_addr,
333    uint32_t object_size,
334    struct section_info **objc_sections,
335    uint32_t *nobjc_sections,
336    char *sectname,
337    char **sect,
338    uint32_t *sect_addr,
339    uint32_t *sect_size);
340
341static void get_cstring_section(
342    struct load_command *load_commands,
343    uint32_t ncmds,
344    uint32_t sizeofcmds,
345    enum byte_sex object_byte_sex,
346    char *object_addr,
347    uint32_t object_size,
348    struct section_info *cstring_section_ptr);
349
350static enum bool print_method_list(
351    uint32_t addr,
352    struct section_info *objc_sections,
353    uint32_t nobjc_sections,
354    struct section_info *cstring_section_ptr,
355    enum byte_sex host_byte_sex,
356    enum bool swapped,
357    struct symbol *sorted_symbols,
358    uint32_t nsorted_symbols,
359    enum bool verbose);
360
361static enum bool print_protocol_list(
362    uint32_t indent,
363    uint32_t addr,
364    struct section_info *objc_sections,
365    uint32_t nobjc_sections,
366    struct section_info *cstring_section_ptr,
367    enum byte_sex host_byte_sex,
368    enum bool swapped,
369    enum bool verbose);
370
371static void print_protocol(
372    uint32_t indent,
373    struct objc_protocol_t *protocol,
374    struct section_info *objc_sections,
375    uint32_t nobjc_sections,
376    struct section_info *cstring_section_ptr,
377    enum byte_sex host_byte_sex,
378    enum bool swapped,
379    enum bool verbose);
380
381static enum bool print_method_description_list(
382    uint32_t indent,
383    uint32_t addr,
384    struct section_info *objc_sections,
385    uint32_t nobjc_sections,
386    struct section_info *cstring_section_ptr,
387    enum byte_sex host_byte_sex,
388    enum bool swapped,
389    enum bool verbose);
390
391static enum bool print_PHASH(
392    uint32_t indent,
393    uint32_t addr,
394    struct section_info *objc_sections,
395    uint32_t nobjc_sections,
396    struct section_info *cstring_section_ptr,
397    enum byte_sex host_byte_sex,
398    enum bool swapped,
399    enum bool verbose);
400
401static void print_indent(
402    uint32_t indent);
403
404static void *get_pointer(
405    uint32_t addr,
406    uint32_t *left,
407    struct section_info *objc_sections,
408    uint32_t nobjc_sections,
409    struct section_info *cstring_section_ptr);
410
411static enum bool get_symtab(
412    uint32_t addr,
413    struct objc_symtab_t *symtab,
414    uint32_t **defs,
415    uint32_t *left,
416    enum bool *trunc,
417    struct section_info *objc_sections,
418    uint32_t nobjc_sections,
419    enum byte_sex host_byte_sex,
420    enum bool swapped);
421
422static enum bool get_objc_class(
423    uint32_t addr,
424    struct objc_class_t *objc_class,
425    enum bool *trunc,
426    struct section_info *objc_sections,
427    uint32_t nobjc_sections,
428    enum byte_sex host_byte_sex,
429    enum bool swapped);
430
431static enum bool get_objc_category(
432    uint32_t addr,
433    struct objc_category_t *objc_category,
434    enum bool *trunc,
435    struct section_info *objc_sections,
436    uint32_t nobjc_sections,
437    enum byte_sex host_byte_sex,
438    enum bool swapped);
439
440static enum bool get_ivar_list(
441    uint32_t addr,
442    struct objc_ivar_list_t *objc_ivar_list,
443    struct objc_ivar_t **ivar_list,
444    uint32_t *left,
445    enum bool *trunc,
446    struct section_info *objc_sections,
447    uint32_t nobjc_sections,
448    enum byte_sex host_byte_sex,
449    enum bool swapped);
450
451static enum bool get_method_list(
452    uint32_t addr,
453    struct objc_method_list_t *method_list,
454    struct objc_method_t **methods,
455    uint32_t *left,
456    enum bool *trunc,
457    struct section_info *objc_sections,
458    uint32_t nobjc_sections,
459    enum byte_sex host_byte_sex,
460    enum bool swapped);
461
462static enum bool get_protocol_list(
463    uint32_t addr,
464    struct objc_protocol_list_t *protocol_list,
465    uint32_t **list,
466    uint32_t *left,
467    enum bool *trunc,
468    struct section_info *objc_sections,
469    uint32_t nobjc_sections,
470    enum byte_sex host_byte_sex,
471    enum bool swapped);
472
473static enum bool get_protocol(
474    uint32_t addr,
475    struct objc_protocol_t *protocol,
476    enum bool *trunc,
477    struct section_info *objc_sections,
478    uint32_t nobjc_sections,
479    enum byte_sex host_byte_sex,
480    enum bool swapped);
481
482static enum bool get_method_description_list(
483    uint32_t addr,
484    struct objc_method_description_list_t *mdl,
485    struct objc_method_description_t **list,
486    uint32_t *left,
487    enum bool *trunc,
488    struct section_info *objc_sections,
489    uint32_t nobjc_sections,
490    enum byte_sex host_byte_sex,
491    enum bool swapped);
492
493static enum bool get_hashEntry(
494    uint32_t addr,
495    struct _hashEntry_t *_hashEntry,
496    enum bool *trunc,
497    struct section_info *objc_sections,
498    uint32_t nobjc_sections,
499    enum byte_sex host_byte_sex,
500    enum bool swapped);
501
502/*
503 * Print the objc segment.
504 */
505enum bool
506print_objc_segment(
507cpu_type_t mh_cputype,
508struct load_command *load_commands,
509uint32_t ncmds,
510uint32_t sizeofcmds,
511enum byte_sex object_byte_sex,
512char *object_addr,
513uint32_t object_size,
514struct symbol *sorted_symbols,
515uint32_t nsorted_symbols,
516enum bool verbose)
517{
518    enum byte_sex host_byte_sex;
519    enum bool swapped, trunc;
520    uint32_t i, j, left, size, defs_left, def, ivar_list_left;
521    char *p;
522    struct section_info *objc_sections;
523    uint32_t nobjc_sections;
524    struct section_info cstring_section;
525
526    struct objc_module_t *modules, *m, module;
527    uint32_t modules_addr, modules_size;
528    struct objc_symtab_t symtab;
529    uint32_t *defs;
530    struct objc_class_t objc_class;
531    struct objc_ivar_list_t objc_ivar_list;
532    struct objc_ivar_t *ivar_list, ivar;
533    struct objc_category_t objc_category;
534
535    struct imageInfo_t *imageInfo, info;
536    uint32_t imageInfo_addr, imageInfo_size;
537
538	printf("Objective-C segment\n");
539	get_objc_sections(load_commands, ncmds, sizeofcmds, object_byte_sex,
540			  object_addr, object_size, &objc_sections,
541			  &nobjc_sections, SECT_OBJC_MODULES, (char **)&modules,
542			  &modules_addr, &modules_size);
543
544	if(modules == NULL){
545	    if(mh_cputype == CPU_TYPE_I386)
546		return(FALSE);
547	    printf("can't print objective-C information no (" SEG_OBJC ","
548		   SECT_OBJC_MODULES ") section\n");
549	    return(TRUE);
550	}
551
552    if (verbose)
553        get_cstring_section(load_commands, ncmds, sizeofcmds, object_byte_sex,
554                            object_addr, object_size, &cstring_section);
555
556    host_byte_sex = get_host_byte_sex();
557	swapped = host_byte_sex != object_byte_sex;
558
559	memset(&module, '\0', sizeof(struct objc_module_t));
560
561	for(m = modules;
562	    (char *)m < (char *)modules + modules_size;
563	    m = (struct objc_module_t *)((char *)m + module.size) ){
564
565	    memset(&module, '\0', sizeof(struct objc_module_t));
566	    left = modules_size - (m - modules);
567	    size = left < sizeof(struct objc_module_t) ?
568		   left : sizeof(struct objc_module_t);
569	    memcpy(&module, m, size);
570	    if(swapped)
571		swap_objc_module_t(&module, host_byte_sex);
572
573	    if((char *)m + module.size > (char *)m + modules_size)
574		printf("module extends past end of " SECT_OBJC_MODULES
575		       " section\n");
576	    printf("Module 0x%x\n", (unsigned int)
577		   (modules_addr + (char *)m - (char *)modules));
578
579	    printf("    version %u\n", module.version);
580	    printf("       size %u\n", module.size);
581	    if(verbose){
582		p = get_pointer(module.name, &left,
583		    objc_sections, nobjc_sections, &cstring_section);
584		if(p != NULL)
585		    printf("       name %.*s\n", (int)left, p);
586		else
587		    printf("       name 0x%08x (not in an " SEG_OBJC
588			   " section)\n", (unsigned int)module.name);
589	    }
590	    else
591		printf("       name 0x%08x\n", (unsigned int)(module.name));
592
593	    if(get_symtab(module.symtab, &symtab, &defs, &defs_left, &trunc,
594		    objc_sections, nobjc_sections,
595		    host_byte_sex, swapped) == FALSE){
596		printf("     symtab 0x%08x (not in an " SEG_OBJC
597		       " section)\n", (unsigned int)module.symtab);
598		continue;
599	    }
600	    printf("     symtab 0x%08x\n", (unsigned int)module.symtab);
601	    if(trunc == TRUE)
602		printf("\tsymtab extends past end of an " SEG_OBJC
603		       " section\n");
604	    printf("\tsel_ref_cnt %u\n", symtab.sel_ref_cnt);
605	    p = get_pointer(symtab.refs, &left,
606                     objc_sections, nobjc_sections, &cstring_section);
607	    if(p != NULL)
608		printf("\trefs 0x%08x", symtab.refs);
609	    else
610		printf("\trefs 0x%08x (not in an " SEG_OBJC " section)\n",
611		       symtab.refs);
612
613	    printf("\tcls_def_cnt %d\n", symtab.cls_def_cnt);
614	    printf("\tcat_def_cnt %d\n", symtab.cat_def_cnt);
615	    if(symtab.cls_def_cnt > 0)
616		printf("\tClass Definitions\n");
617	    for(i = 0; i < symtab.cls_def_cnt; i++){
618		if((i + 1) * sizeof(uint32_t) > defs_left){
619		    printf("\t(remaining class defs entries entends past "
620			   "the end of the section)\n");
621		    break;
622		}
623
624		memcpy(&def, defs + i, sizeof(uint32_t));
625		if(swapped)
626		    def = SWAP_INT(def);
627
628		if(get_objc_class(def, &objc_class, &trunc, objc_sections,
629			  nobjc_sections, host_byte_sex, swapped) == TRUE){
630		    printf("\tdefs[%u] 0x%08x", i, def);
631print_objc_class:
632		    if(trunc == TRUE)
633			printf(" (entends past the end of the section)\n");
634		    else
635			printf("\n");
636		    printf("\t\t      isa 0x%08x", objc_class.isa);
637
638		    if(verbose && CLS_GETINFO(&objc_class, CLS_META)){
639			p = get_pointer(objc_class.isa, &left, objc_sections,
640					nobjc_sections, &cstring_section);
641			if(p != NULL)
642			    printf(" %.*s\n", (int)left, p);
643			else
644			    printf(" (not in an " SEG_OBJC " section)\n");
645		    }
646		    else
647			printf("\n");
648
649		    printf("\t      super_class 0x%08x",objc_class.super_class);
650		    if(verbose){
651			p = get_pointer(objc_class.super_class, &left,
652					objc_sections, nobjc_sections, &cstring_section);
653			if(p != NULL)
654			    printf(" %.*s\n", (int)left, p);
655			else
656			    printf(" (not in an " SEG_OBJC " section)\n");
657		    }
658		    else
659			printf("\n");
660
661		    printf("\t\t     name 0x%08x", objc_class.name);
662		    if(verbose){
663			p = get_pointer(objc_class.name, &left,
664					objc_sections, nobjc_sections, &cstring_section);
665			if(p != NULL)
666			    printf(" %.*s\n", (int)left, p);
667			else
668			    printf(" (not in an " SEG_OBJC " section)\n");
669		    }
670		    else
671			printf("\n");
672		    printf("\t\t  version 0x%08x\n",
673			   (unsigned int)objc_class.version);
674		    printf("\t\t     info 0x%08x",
675			   (unsigned int)objc_class.info);
676		    if(verbose){
677			if(CLS_GETINFO(&objc_class, CLS_CLASS))
678			    printf(" CLS_CLASS\n");
679			else if(CLS_GETINFO(&objc_class, CLS_META))
680			    printf(" CLS_META\n");
681			else
682			    printf("\n");
683		    }
684		    else
685			printf("\n");
686		    printf("\t    instance_size 0x%08x\n",
687			   (unsigned int)objc_class.instance_size);
688
689		    if(get_ivar_list(objc_class.ivars, &objc_ivar_list,
690			    &ivar_list, &ivar_list_left, &trunc,
691			    objc_sections, nobjc_sections, host_byte_sex,
692			    swapped) == TRUE){
693			printf("\t\t    ivars 0x%08x\n",
694			       (unsigned int)objc_class.ivars);
695			if(trunc == TRUE)
696			    printf("\t\t objc_ivar_list extends past end "
697				   "of " SECT_OBJC_SYMBOLS " section\n");
698			printf("\t\t       ivar_count %d\n",
699				    objc_ivar_list.ivar_count);
700			for(j = 0;
701			    j < (uint32_t)objc_ivar_list.ivar_count;
702			    j++){
703			    if((j + 1) * sizeof(struct objc_ivar_t) >
704			       ivar_list_left){
705				printf("\t\t remaining ivar's extend past "
706				       "the of the section\n");
707				break;
708			    }
709			    memcpy(&ivar, ivar_list + j,
710				   sizeof(struct objc_ivar_t));
711			    if(swapped)
712				swap_objc_ivar_t(&ivar, host_byte_sex);
713
714			    printf("\t\t\tivar_name 0x%08x",
715				   (unsigned int)ivar.ivar_name);
716			    if(verbose){
717				p = get_pointer(ivar.ivar_name, &left,
718					    objc_sections, nobjc_sections, &cstring_section);
719				if(p != NULL)
720				    printf(" %.*s\n", (int)left, p);
721				else
722				    printf(" (not in an " SEG_OBJC
723					   " section)\n");
724			    }
725			    else
726				printf("\n");
727			    printf("\t\t\tivar_type 0x%08x",
728				   (unsigned int)ivar.ivar_type);
729			    if(verbose){
730				p = get_pointer(ivar.ivar_type, &left,
731					    objc_sections, nobjc_sections, &cstring_section);
732				if(p != NULL)
733				    printf(" %.*s\n", (int)left, p);
734				else
735				    printf(" (not in an " SEG_OBJC
736					   " section)\n");
737			    }
738			    else
739				printf("\n");
740			    printf("\t\t      ivar_offset 0x%08x\n",
741				   (unsigned int)ivar.ivar_offset);
742			}
743		    }
744		    else{
745			printf("\t\t    ivars 0x%08x (not in an " SEG_OBJC
746			       " section)\n",
747			       (unsigned int)objc_class.ivars);
748		    }
749
750		    printf("\t\t  methods 0x%08x",
751			   (unsigned int)objc_class.methodLists);
752		    if(print_method_list(objc_class.methodLists,
753					 objc_sections, nobjc_sections,
754					 &cstring_section,
755					 host_byte_sex, swapped, sorted_symbols,
756					 nsorted_symbols, verbose) == FALSE)
757			printf(" (not in an " SEG_OBJC " section)\n");
758
759		    printf("\t\t    cache 0x%08x\n",
760			   (unsigned int)objc_class.cache);
761
762		    printf("\t\tprotocols 0x%08x",
763			   (unsigned int)objc_class.protocols);
764		    if(print_protocol_list(16, objc_class.protocols,
765			objc_sections, nobjc_sections, &cstring_section,
766			host_byte_sex, swapped, verbose) == FALSE)
767			printf(" (not in an " SEG_OBJC " section)\n");
768
769		    if(CLS_GETINFO((&objc_class), CLS_CLASS)){
770			printf("\tMeta Class");
771			if(get_objc_class((uint32_t)objc_class.isa,
772			     &objc_class, &trunc, objc_sections, nobjc_sections,
773			     host_byte_sex, swapped) == TRUE){
774			    goto print_objc_class;
775			}
776			else
777			    printf(" (not in " SECT_OBJC_SYMBOLS
778				   " section)\n");
779		    }
780		}
781		else
782		    printf("\tdefs[%u] 0x%08x (not in an " SEG_OBJC
783			   " section)\n", i, (unsigned int)def);
784	    }
785	    if(symtab.cat_def_cnt > 0)
786		printf("\tCategory Definitions\n");
787	    for(i = 0; i < symtab.cat_def_cnt; i++){
788		if((i + symtab.cls_def_cnt + 1) * sizeof(uint32_t) >
789							      defs_left){
790		    printf("\t(remaining category defs entries entends "
791			   "past the end of the section)\n");
792		    break;
793		}
794
795		memcpy(&def, defs + i + symtab.cls_def_cnt, sizeof(uint32_t));
796		if(swapped)
797		    def = SWAP_INT(def);
798
799		if(get_objc_category(def, &objc_category, &trunc,
800			  objc_sections, nobjc_sections,
801              host_byte_sex, swapped) == TRUE){
802		    printf("\tdefs[%u] 0x%08x", i + symtab.cls_def_cnt,
803			   (unsigned int)def);
804		    if(trunc == TRUE)
805			printf(" (entends past the end of the section)\n");
806		    else
807			printf("\n");
808		    printf("\t       category name 0x%08x",
809			   objc_category.category_name);
810		    if(verbose){
811			p = get_pointer(objc_category.category_name, &left,
812					objc_sections, nobjc_sections,
813					&cstring_section);
814			if(p != NULL)
815			    printf(" %.*s\n", (int)left, p);
816			else
817			    printf(" (not in an " SEG_OBJC " section)\n");
818		    }
819		    else
820			printf("\n");
821
822		    printf("\t\t  class name 0x%08x", objc_category.class_name);
823		    if(verbose){
824			p = get_pointer(objc_category.class_name, &left,
825					objc_sections, nobjc_sections,
826					&cstring_section);
827			if(p != NULL)
828			    printf(" %.*s\n", (int)left, p);
829			else
830			    printf(" (not in an " SEG_OBJC " section)\n");
831		    }
832		    else
833			printf("\n");
834
835		    printf("\t    instance methods 0x%08x",
836			   objc_category.instance_methods);
837		    if(print_method_list(objc_category.instance_methods,
838					 objc_sections, nobjc_sections,
839					 &cstring_section,
840					 host_byte_sex, swapped,
841					 sorted_symbols, nsorted_symbols,
842					 verbose) == FALSE)
843			printf(" (not in an " SEG_OBJC " section)\n");
844
845		    printf("\t       class methods 0x%08x",
846			   objc_category.class_methods);
847		    if(print_method_list(objc_category.class_methods,
848			objc_sections, nobjc_sections, &cstring_section,
849			host_byte_sex, swapped, sorted_symbols, nsorted_symbols,
850			verbose) == FALSE)
851			printf(" (not in an " SEG_OBJC " section)\n");
852		}
853		else
854		    printf("\tdefs[%u] 0x%08x (not in an " SEG_OBJC
855			   " section)\n", i + symtab.cls_def_cnt,
856			   (unsigned int)def);
857	    }
858	}
859
860	printf("Contents of (%s,%s) section\n", SEG_OBJC, "__image_info");
861	get_objc_sections(load_commands, ncmds, sizeofcmds, object_byte_sex,
862			  object_addr, object_size, &objc_sections,
863			  &nobjc_sections, "__image_info", (char **)&imageInfo,
864			  &imageInfo_addr, &imageInfo_size);
865	memset(&info, '\0', sizeof(struct imageInfo_t));
866	if(imageInfo_size < sizeof(struct imageInfo_t)){
867	    memcpy(&info, imageInfo, imageInfo_size);
868	    printf(" (imageInfo entends past the end of the section)\n");
869	}
870	else
871	    memcpy(&info, imageInfo, sizeof(struct imageInfo_t));
872	if(swapped)
873	    swap_imageInfo_t(&info, host_byte_sex);
874	printf("  version %u\n", info.version);
875	printf("    flags 0x%x", info.flags);
876	if(info.flags & 0x1)
877	    printf("  F&C");
878	if(info.flags & 0x2)
879	    printf(" GC");
880	if(info.flags & 0x4)
881	    printf(" GC-only");
882	else
883	    printf(" RR");
884	printf("\n");
885	return(TRUE);
886}
887
888void
889print_objc_protocol_section(
890struct load_command *load_commands,
891uint32_t ncmds,
892uint32_t sizeofcmds,
893enum byte_sex object_byte_sex,
894char *object_addr,
895uint32_t object_size,
896enum bool verbose)
897{
898    enum byte_sex host_byte_sex;
899    enum bool swapped;
900    struct section_info *objc_sections, cstring_section;
901    uint32_t nobjc_sections;
902    struct objc_protocol_t *protocols, *p, protocol;
903    uint32_t protocols_addr, protocols_size;
904    uint32_t size, left;
905
906	printf("Contents of (" SEG_OBJC ",__protocol) section\n");
907	get_objc_sections(load_commands, ncmds, sizeofcmds, object_byte_sex,
908			  object_addr, object_size, &objc_sections,
909			  &nobjc_sections, "__protocol", (char **)&protocols,
910			  &protocols_addr, &protocols_size);
911
912    if (verbose)
913        get_cstring_section(load_commands, ncmds, sizeofcmds, object_byte_sex,
914                            object_addr, object_size, &cstring_section);
915
916    host_byte_sex = get_host_byte_sex();
917	swapped = host_byte_sex != object_byte_sex;
918
919	for(p = protocols; (char *)p < (char *)protocols + protocols_size; p++){
920
921	    memset(&protocol, '\0', sizeof(struct objc_protocol_t));
922	    left = protocols_size - (p - protocols);
923	    size = left < sizeof(struct objc_protocol_t) ?
924		   left : sizeof(struct objc_protocol_t);
925	    memcpy(&protocol, p, size);
926
927	    if((char *)p + sizeof(struct objc_protocol_t) >
928	       (char *)p + protocols_size)
929		printf("Protocol extends past end of __protocol section\n");
930	    printf("Protocol 0x%x\n", (unsigned int)
931		   (protocols_addr + (char *)p - (char *)protocols));
932
933	    print_protocol(0, &protocol,
934			      objc_sections, nobjc_sections, &cstring_section,
935			      host_byte_sex, swapped, verbose);
936	}
937}
938
939void
940print_objc_string_object_section(
941char *sectname,
942struct load_command *load_commands,
943uint32_t ncmds,
944uint32_t sizeofcmds,
945enum byte_sex object_byte_sex,
946char *object_addr,
947uint32_t object_size,
948enum bool verbose)
949{
950    enum byte_sex host_byte_sex;
951    enum bool swapped;
952    struct section_info *objc_sections;
953    uint32_t nobjc_sections;
954    struct section_info cstring_section;
955    struct objc_string_object_t *string_objects, *s, string_object;
956    uint32_t string_objects_addr, string_objects_size;
957    uint32_t size, left;
958    char *p;
959
960	printf("Contents of (" SEG_OBJC ",%s) section\n", sectname);
961	get_objc_sections(load_commands, ncmds, sizeofcmds, object_byte_sex,
962			  object_addr, object_size, &objc_sections,
963			  &nobjc_sections, sectname, (char **)&string_objects,
964			  &string_objects_addr, &string_objects_size);
965
966	get_cstring_section(load_commands, ncmds, sizeofcmds, object_byte_sex,
967			    object_addr, object_size, &cstring_section);
968
969	host_byte_sex = get_host_byte_sex();
970	swapped = host_byte_sex != object_byte_sex;
971
972	for(s = string_objects;
973	    (char *)s < (char *)string_objects + string_objects_size;
974	    s++){
975
976	    memset(&string_object, '\0', sizeof(struct objc_string_object_t));
977	    left = string_objects_size - (s - string_objects);
978	    size = left < sizeof(struct objc_string_object_t) ?
979		   left : sizeof(struct objc_string_object_t);
980	    memcpy(&string_object, s, size);
981
982	    if((char *)s + sizeof(struct objc_string_object_t) >
983	       (char *)s + string_objects_size)
984		printf("String Object extends past end of %s section\n",
985		       sectname);
986	    printf("String Object 0x%x\n", (unsigned int)
987		   (string_objects_addr + (char *)s - (char *)string_objects));
988
989	    if(swapped)
990		swap_string_object_t(&string_object, host_byte_sex);
991	    printf("           isa 0x%x\n", string_object.isa);
992	    printf("    characters 0x%x",
993		   (unsigned int)string_object.characters);
994	    if(verbose){
995		p = get_pointer(string_object.characters, &left,
996			        &cstring_section, 1, &cstring_section);
997		if(p != NULL)
998		    printf(" %.*s\n", (int)left, p);
999		else
1000		    printf(" (not in the (" SEG_TEXT ",__cstring) section)\n");
1001	    }
1002	    else
1003		printf("\n");
1004	    printf("       _length %u\n", string_object._length);
1005	}
1006}
1007
1008/*
1009 * PHASH[SIZEHASHTABLE];
1010 * HASH[?]; variable sized (computed from size of section).
1011 */
1012void
1013print_objc_runtime_setup_section(
1014struct load_command *load_commands,
1015uint32_t ncmds,
1016uint32_t sizeofcmds,
1017enum byte_sex object_byte_sex,
1018char *object_addr,
1019uint32_t object_size,
1020enum bool verbose)
1021{
1022
1023    enum byte_sex host_byte_sex;
1024    enum bool swapped;
1025    struct section_info *objc_sections, cstring_section;
1026    uint32_t i, nobjc_sections, left;
1027    struct _hashEntry_t **PHASH, *HASH, _hashEntry;
1028    char *sect, *p;
1029    uint32_t sect_addr, sect_size, phash;
1030
1031	printf("Contents of (" SEG_OBJC ",__runtime_setup) section\n");
1032	get_objc_sections(load_commands, ncmds, sizeofcmds, object_byte_sex,
1033			  object_addr, object_size, &objc_sections,
1034			  &nobjc_sections, "__runtime_setup", &sect, &sect_addr,
1035			  &sect_size);
1036
1037    if (verbose)
1038        get_cstring_section(load_commands, ncmds, sizeofcmds, object_byte_sex,
1039                            object_addr, object_size, &cstring_section);
1040
1041    host_byte_sex = get_host_byte_sex();
1042	swapped = host_byte_sex != object_byte_sex;
1043
1044	PHASH = (struct _hashEntry_t **)sect;
1045	for(i = 0;
1046	    i < SIZEHASHTABLE && (i + 1) * sizeof(uint32_t) < sect_size;
1047	    i++){
1048
1049	    memcpy(&phash, PHASH + i, sizeof(uint32_t));
1050	    if(swapped)
1051		phash = SWAP_INT(phash);
1052
1053	    if(phash == 0)
1054		continue;
1055
1056	    printf("PHASH[%3u] 0x%x", i, (unsigned int)phash);
1057	    if(print_PHASH(4, phash,
1058			   objc_sections, nobjc_sections, &cstring_section,
1059			   host_byte_sex, swapped, verbose) == FALSE)
1060		printf(" (not in an " SEG_OBJC " section)\n");
1061	}
1062
1063	HASH = (struct _hashEntry_t *)(PHASH + SIZEHASHTABLE);
1064	for(i = 0; (char *)(HASH + i) < sect + sect_size; i++){
1065	    memcpy((char *)&_hashEntry, HASH + i, sizeof(struct _hashEntry_t));
1066	    if(swapped)
1067		swap_hashEntry_t(&_hashEntry, host_byte_sex);
1068
1069	    printf("HASH at 0x%08x\n",
1070		   (unsigned int)(sect_addr + (char *)(HASH + i) - sect));
1071	    printf("     sel 0x%08x", (unsigned int)_hashEntry.sel);
1072	    if(verbose){
1073		p = get_pointer(_hashEntry.sel, &left, objc_sections,
1074				nobjc_sections, &cstring_section);
1075		if(p != NULL)
1076		    printf(" %.*s\n", (int)left, p);
1077		else
1078		    printf(" (not in an " SEG_OBJC " section)\n");
1079	    }
1080	    else
1081		printf("\n");
1082
1083	    printf("    next 0x%08x", (unsigned int)_hashEntry.next);
1084	    if(_hashEntry.next == 0){
1085		printf("\n");
1086	    }
1087	    else{
1088		if((uint32_t)_hashEntry.next < sect_addr ||
1089		   (uint32_t)_hashEntry.next >= sect_addr + sect_size)
1090		    printf(" (not in the ("SEG_OBJC ",__runtime_setup "
1091			   "section)\n");
1092		else
1093		    printf("\n");
1094	    }
1095	}
1096}
1097
1098static
1099void
1100get_objc_sections(
1101struct load_command *load_commands,
1102uint32_t ncmds,
1103uint32_t sizeofcmds,
1104enum byte_sex object_byte_sex,
1105char *object_addr,
1106uint32_t object_size,
1107struct section_info **objc_sections,
1108uint32_t *nobjc_sections,
1109char *sectname,
1110char **sect,
1111uint32_t *sect_addr,
1112uint32_t *sect_size)
1113{
1114    enum byte_sex host_byte_sex;
1115    enum bool swapped, encrypt_found, encrypt64_found;
1116
1117    uint32_t i, j, left, size;
1118    struct load_command lcmd, *lc;
1119    char *p;
1120    struct segment_command sg;
1121    struct section s;
1122    struct encryption_info_command encrypt;
1123    struct encryption_info_command_64 encrypt64;
1124
1125	host_byte_sex = get_host_byte_sex();
1126	swapped = host_byte_sex != object_byte_sex;
1127
1128	*objc_sections = NULL;
1129	*nobjc_sections = 0;
1130	*sect = NULL;
1131	*sect_addr = 0;
1132	*sect_size = 0;
1133	encrypt_found = FALSE;
1134	encrypt64_found = FALSE;
1135
1136	lc = load_commands;
1137	for(i = 0 ; i < ncmds; i++){
1138	    memcpy((char *)&lcmd, (char *)lc, sizeof(struct load_command));
1139	    if(swapped)
1140		swap_load_command(&lcmd, host_byte_sex);
1141	    if(lcmd.cmdsize % sizeof(int32_t) != 0)
1142		printf("load command %u size not a multiple of "
1143		       "sizeof(int32_t)\n", i);
1144	    if((char *)lc + lcmd.cmdsize >
1145	       (char *)load_commands + sizeofcmds)
1146		printf("load command %u extends past end of load "
1147		       "commands\n", i);
1148	    left = sizeofcmds - ((char *)lc - (char *)load_commands);
1149
1150	    switch(lcmd.cmd){
1151	    case LC_SEGMENT:
1152		memset((char *)&sg, '\0', sizeof(struct segment_command));
1153		size = left < sizeof(struct segment_command) ?
1154		       left : sizeof(struct segment_command);
1155		memcpy((char *)&sg, (char *)lc, size);
1156		if(swapped)
1157		    swap_segment_command(&sg, host_byte_sex);
1158
1159		p = (char *)lc + sizeof(struct segment_command);
1160		for(j = 0 ; j < sg.nsects ; j++){
1161		    if(p + sizeof(struct section) >
1162		       (char *)load_commands + sizeofcmds){
1163			printf("section structure command extends past "
1164			       "end of load commands\n");
1165		    }
1166		    left = sizeofcmds - (p - (char *)load_commands);
1167		    memset((char *)&s, '\0', sizeof(struct section));
1168		    size = left < sizeof(struct section) ?
1169			   left : sizeof(struct section);
1170		    memcpy((char *)&s, p, size);
1171		    if(swapped)
1172			swap_section(&s, 1, host_byte_sex);
1173
1174		    if(strcmp(s.segname, SEG_OBJC) == 0){
1175			*objc_sections = reallocate(*objc_sections,
1176			   sizeof(struct section_info) * (*nobjc_sections + 1));
1177			(*objc_sections)[*nobjc_sections].addr = s.addr;
1178			(*objc_sections)[*nobjc_sections].contents =
1179							 object_addr + s.offset;
1180			(*objc_sections)[*nobjc_sections].offset = s.offset;
1181		        (*objc_sections)[*nobjc_sections].zerofill =
1182			  (s.flags & SECTION_TYPE) == S_ZEROFILL ? TRUE : FALSE;
1183			if(s.offset > object_size){
1184			    printf("section contents of: (%.16s,%.16s) is past "
1185				   "end of file\n", s.segname, s.sectname);
1186			    (*objc_sections)[*nobjc_sections].size =  0;
1187			}
1188			else if(s.offset + s.size > object_size){
1189			    printf("part of section contents of: (%.16s,%.16s) "
1190				   "is past end of file\n",
1191				   s.segname, s.sectname);
1192			    (*objc_sections)[*nobjc_sections].size =
1193				object_size - s.offset;
1194			}
1195			else
1196			    (*objc_sections)[*nobjc_sections].size = s.size;
1197
1198			if(strncmp(s.sectname, sectname, 16) == 0){
1199			    if(*sect != NULL)
1200				printf("more than one (" SEG_OBJC ",%s) "
1201				       "section\n", sectname);
1202			    else{
1203				*sect = (object_addr + s.offset);
1204				*sect_size = s.size;
1205				*sect_addr = s.addr;
1206			    }
1207			}
1208			if(sg.flags & SG_PROTECTED_VERSION_1)
1209			    (*objc_sections)[*nobjc_sections].protected = TRUE;
1210			else
1211			    (*objc_sections)[*nobjc_sections].protected = FALSE;
1212			(*nobjc_sections)++;
1213		    }
1214
1215		    if(p + sizeof(struct section) >
1216		       (char *)load_commands + sizeofcmds)
1217			break;
1218		    p += size;
1219		}
1220		break;
1221	    case LC_ENCRYPTION_INFO:
1222		memset((char *)&encrypt, '\0',
1223		       sizeof(struct encryption_info_command));
1224		size = left < sizeof(struct encryption_info_command) ?
1225		       left : sizeof(struct encryption_info_command);
1226		memcpy((char *)&encrypt, (char *)lc, size);
1227		if(swapped)
1228		    swap_encryption_command(&encrypt, host_byte_sex);
1229		encrypt_found = TRUE;
1230		break;
1231	    case LC_ENCRYPTION_INFO_64:
1232		memset((char *)&encrypt64, '\0',
1233		       sizeof(struct encryption_info_command_64));
1234		size = left < sizeof(struct encryption_info_command_64) ?
1235		       left : sizeof(struct encryption_info_command_64);
1236		memcpy((char *)&encrypt64, (char *)lc, size);
1237		if(swapped)
1238		    swap_encryption_command_64(&encrypt64, host_byte_sex);
1239		encrypt64_found = TRUE;
1240		break;
1241	    }
1242	    if(lcmd.cmdsize == 0){
1243		printf("load command %u size zero (can't advance to other "
1244		       "load commands)\n", i);
1245		break;
1246	    }
1247	    lc = (struct load_command *)((char *)lc + lcmd.cmdsize);
1248	    if((char *)lc > (char *)load_commands + sizeofcmds)
1249		break;
1250	}
1251
1252	if(encrypt_found == TRUE && encrypt.cryptid != 0){
1253	    for(i = 0; i < *nobjc_sections; i++){
1254		if((*objc_sections)[i].size > 0 &&
1255		   (*objc_sections)[i].zerofill == FALSE){
1256		    if((*objc_sections)[i].offset >
1257		       encrypt.cryptoff + encrypt.cryptsize){
1258			/* section starts past encryption area */ ;
1259		    }
1260		    else if((*objc_sections)[i].offset +
1261			    (*objc_sections)[i].size < encrypt.cryptoff){
1262			/* section ends before encryption area */ ;
1263		    }
1264		    else{
1265			/* section has part in the encrypted area */
1266			(*objc_sections)[i].protected = TRUE;
1267		    }
1268		}
1269	    }
1270	}
1271	if(encrypt64_found == TRUE && encrypt64.cryptid != 0){
1272	    for(i = 0; i < *nobjc_sections; i++){
1273		if((*objc_sections)[i].size > 0 &&
1274		   (*objc_sections)[i].zerofill == FALSE){
1275		    if((*objc_sections)[i].offset >
1276		       encrypt64.cryptoff + encrypt64.cryptsize){
1277			/* section starts past encryption area */ ;
1278		    }
1279		    else if((*objc_sections)[i].offset +
1280			    (*objc_sections)[i].size < encrypt64.cryptoff){
1281			/* section ends before encryption area */ ;
1282		    }
1283		    else{
1284			/* section has part in the encrypted area */
1285			(*objc_sections)[i].protected = TRUE;
1286		    }
1287		}
1288	    }
1289	}
1290}
1291
1292static
1293void
1294get_cstring_section(
1295struct load_command *load_commands,
1296uint32_t ncmds,
1297uint32_t sizeofcmds,
1298enum byte_sex object_byte_sex,
1299char *object_addr,
1300uint32_t object_size,
1301struct section_info *cstring_section)
1302{
1303    enum byte_sex host_byte_sex;
1304    enum bool swapped;
1305
1306    uint32_t i, j, left, size;
1307    struct load_command lcmd, *lc;
1308    char *p;
1309    struct segment_command sg;
1310    struct section s;
1311
1312	host_byte_sex = get_host_byte_sex();
1313	swapped = host_byte_sex != object_byte_sex;
1314
1315	memset(cstring_section, '\0', sizeof(struct section_info));
1316
1317	lc = load_commands;
1318	for(i = 0 ; i < ncmds; i++){
1319	    memcpy((char *)&lcmd, (char *)lc, sizeof(struct load_command));
1320	    if(swapped)
1321		swap_load_command(&lcmd, host_byte_sex);
1322	    if(lcmd.cmdsize % sizeof(int32_t) != 0)
1323		printf("load command %u size not a multiple of "
1324		       "sizeof(int32_t)\n", i);
1325	    if((char *)lc + lcmd.cmdsize >
1326	       (char *)load_commands + sizeofcmds)
1327		printf("load command %u extends past end of load "
1328		       "commands\n", i);
1329	    left = sizeofcmds - ((char *)lc - (char *)load_commands);
1330
1331	    switch(lcmd.cmd){
1332	    case LC_SEGMENT:
1333		memset((char *)&sg, '\0', sizeof(struct segment_command));
1334		size = left < sizeof(struct segment_command) ?
1335		       left : sizeof(struct segment_command);
1336		memcpy((char *)&sg, (char *)lc, size);
1337		if(swapped)
1338		    swap_segment_command(&sg, host_byte_sex);
1339
1340		p = (char *)lc + sizeof(struct segment_command);
1341		for(j = 0 ; j < sg.nsects ; j++){
1342		    if(p + sizeof(struct section) >
1343		       (char *)load_commands + sizeofcmds){
1344			printf("section structure command extends past "
1345			       "end of load commands\n");
1346		    }
1347		    left = sizeofcmds - (p - (char *)load_commands);
1348		    memset((char *)&s, '\0', sizeof(struct section));
1349		    size = left < sizeof(struct section) ?
1350			   left : sizeof(struct section);
1351		    memcpy((char *)&s, p, size);
1352		    if(swapped)
1353			swap_section(&s, 1, host_byte_sex);
1354
1355		    if(strcmp(s.segname, SEG_TEXT) == 0 &&
1356		       strcmp(s.sectname, "__cstring") == 0){
1357			cstring_section->addr = s.addr;
1358			cstring_section->contents = object_addr + s.offset;
1359			if(s.offset > object_size){
1360			    printf("section contents of: (%.16s,%.16s) is past "
1361				   "end of file\n", s.segname, s.sectname);
1362			    cstring_section->size = 0;
1363			}
1364			else if(s.offset + s.size > object_size){
1365			    printf("part of section contents of: (%.16s,%.16s) "
1366				   "is past end of file\n",
1367				   s.segname, s.sectname);
1368			    cstring_section->size = object_size - s.offset;
1369			}
1370			else
1371			    cstring_section->size = s.size;
1372			if(sg.flags & SG_PROTECTED_VERSION_1)
1373			    cstring_section->protected = TRUE;
1374			else
1375			    cstring_section->protected = FALSE;
1376			return;
1377		    }
1378
1379		    if(p + sizeof(struct section) >
1380		       (char *)load_commands + sizeofcmds)
1381			break;
1382		    p += size;
1383		}
1384		break;
1385	    }
1386	    if(lcmd.cmdsize == 0){
1387		printf("load command %u size zero (can't advance to other "
1388		       "load commands)\n", i);
1389		break;
1390	    }
1391	    lc = (struct load_command *)((char *)lc + lcmd.cmdsize);
1392	    if((char *)lc > (char *)load_commands + sizeofcmds)
1393		break;
1394	}
1395}
1396
1397static
1398enum bool
1399print_method_list(
1400uint32_t addr,
1401struct section_info *objc_sections,
1402uint32_t nobjc_sections,
1403struct section_info *cstring_section_ptr,
1404enum byte_sex host_byte_sex,
1405enum bool swapped,
1406struct symbol *sorted_symbols,
1407uint32_t nsorted_symbols,
1408enum bool verbose)
1409{
1410    struct objc_method_t *methods, method;
1411    struct objc_method_list_t method_list;
1412    enum bool trunc;
1413    uint32_t i, methods_left, left;
1414    char *p;
1415
1416	if(get_method_list(addr, &method_list, &methods, &methods_left, &trunc,
1417			   objc_sections, nobjc_sections,
1418			   host_byte_sex, swapped) == FALSE)
1419	    return(FALSE);
1420
1421	printf("\n");
1422	if(trunc == TRUE)
1423	    printf("\t\t objc_method_list extends past end of the section\n");
1424
1425	printf("\t\t         obsolete 0x%08x\n",
1426	       (unsigned int)method_list.obsolete);
1427	printf("\t\t     method_count %d\n",
1428	       method_list.method_count);
1429
1430	for(i = 0; i < (uint32_t)method_list.method_count; i++){
1431	    if((i + 1) * sizeof(struct objc_method_t) > methods_left){
1432		printf("\t\t remaining method's extend past the of the "
1433		       "section\n");
1434		break;
1435	    }
1436	    memcpy(&method, methods + i, sizeof(struct objc_method_t));
1437	    if(swapped)
1438		swap_objc_method_t(&method, host_byte_sex);
1439
1440	    printf("\t\t      method_name 0x%08x", method.method_name);
1441	    if(verbose){
1442		p = get_pointer(method.method_name, &left, objc_sections,
1443				nobjc_sections, cstring_section_ptr);
1444		if(p != NULL)
1445		    printf(" %.*s\n", (int)left, p);
1446		else
1447		    printf(" (not in an " SEG_OBJC " section)\n");
1448	    }
1449	    else
1450		printf("\n");
1451
1452	    printf("\t\t     method_types 0x%08x", method.method_types);
1453	    if(verbose){
1454		p = get_pointer(method.method_types, &left, objc_sections,
1455				nobjc_sections, cstring_section_ptr);
1456		if(p != NULL)
1457		    printf(" %.*s\n", (int)left, p);
1458		else
1459		    printf(" (not in an " SEG_OBJC " section)\n");
1460	    }
1461	    else
1462		printf("\n");
1463	    printf("\t\t       method_imp 0x%08x ", method.method_imp);
1464	    if(verbose)
1465		print_label(method.method_imp, FALSE, sorted_symbols,
1466			    nsorted_symbols);
1467	    printf("\n");
1468	}
1469	return(TRUE);
1470}
1471
1472static
1473enum bool
1474print_protocol_list(
1475uint32_t indent,
1476uint32_t addr,
1477struct section_info *objc_sections,
1478uint32_t nobjc_sections,
1479struct section_info *cstring_section_ptr,
1480enum byte_sex host_byte_sex,
1481enum bool swapped,
1482enum bool verbose)
1483{
1484    uint32_t *list;
1485    struct objc_protocol_t protocol;
1486    struct objc_protocol_list_t protocol_list;
1487    enum bool trunc;
1488    uint32_t l, i, list_left;
1489
1490	if(get_protocol_list(addr, &protocol_list, &list, &list_left, &trunc,
1491			     objc_sections, nobjc_sections,
1492			     host_byte_sex, swapped) == FALSE)
1493	    return(FALSE);
1494
1495	printf("\n");
1496	if(trunc == TRUE){
1497	    print_indent(indent);
1498	    printf(" objc_protocol_list extends past end of the section\n");
1499	}
1500
1501	print_indent(indent);
1502	printf("         next 0x%08x\n",
1503	       (unsigned int)protocol_list.next);
1504	print_indent(indent);
1505	printf("        count %u\n", protocol_list.count);
1506
1507	for(i = 0; i < protocol_list.count; i++){
1508	    if((i + 1) * sizeof(uint32_t) > list_left){
1509		print_indent(indent);
1510		printf(" remaining list entries extend past the of the "
1511		       "section\n");
1512		break;
1513	    }
1514	    memcpy(&l, list + i, sizeof(uint32_t));
1515	    if(swapped)
1516		l = SWAP_INT(l);
1517
1518	    print_indent(indent);
1519	    printf("      list[%u] 0x%08x", i, l);
1520	    if(get_protocol(l, &protocol, &trunc, objc_sections, nobjc_sections,
1521			host_byte_sex, swapped) == FALSE){
1522		printf(" (not in an " SEG_OBJC " section)\n");
1523		continue;
1524	    }
1525	    printf("\n");
1526	    if(trunc == TRUE){
1527		print_indent(indent);
1528		printf("            Protocol extends past end of the "
1529			"section\n");
1530	    }
1531	    print_protocol(indent, &protocol,
1532		    objc_sections, nobjc_sections, cstring_section_ptr,
1533		    host_byte_sex, swapped, verbose);
1534	}
1535	return(TRUE);
1536}
1537
1538static
1539void
1540print_protocol(
1541uint32_t indent,
1542struct objc_protocol_t *protocol,
1543struct section_info *objc_sections,
1544uint32_t nobjc_sections,
1545struct section_info *cstring_section_ptr,
1546enum byte_sex host_byte_sex,
1547enum bool swapped,
1548enum bool verbose)
1549{
1550    uint32_t left;
1551    char *p;
1552
1553	print_indent(indent);
1554	printf("              isa 0x%08x\n",
1555		(unsigned int)protocol->isa);
1556	print_indent(indent);
1557	printf("    protocol_name 0x%08x",
1558		(unsigned int)protocol->protocol_name);
1559	if(verbose){
1560	    p = get_pointer(protocol->protocol_name, &left,
1561		    objc_sections, nobjc_sections, cstring_section_ptr);
1562	    if(p != NULL)
1563		printf(" %.*s\n", (int)left, p);
1564	    else
1565		printf(" (not in an " SEG_OBJC " section)\n");
1566	}
1567	else
1568	    printf("\n");
1569	print_indent(indent);
1570	printf("    protocol_list 0x%08x",
1571		(unsigned int)protocol->protocol_list);
1572	if(print_protocol_list(indent + 4, protocol->protocol_list,
1573		    objc_sections, nobjc_sections, cstring_section_ptr,
1574		    host_byte_sex, swapped, verbose) == FALSE)
1575	    printf(" (not in an " SEG_OBJC " section)\n");
1576
1577	print_indent(indent);
1578	printf(" instance_methods 0x%08x",
1579		(unsigned int)protocol->instance_methods);
1580	if(print_method_description_list(indent, protocol->instance_methods,
1581		    objc_sections, nobjc_sections, cstring_section_ptr,
1582		    host_byte_sex, swapped, verbose) == FALSE)
1583	    printf(" (not in an " SEG_OBJC " section)\n");
1584
1585	print_indent(indent);
1586	printf("    class_methods 0x%08x",
1587		(unsigned int)protocol->class_methods);
1588	if(print_method_description_list(indent, protocol->class_methods,
1589		    objc_sections, nobjc_sections, cstring_section_ptr,
1590		    host_byte_sex, swapped, verbose) == FALSE)
1591	    printf(" (not in an " SEG_OBJC " section)\n");
1592}
1593
1594static
1595enum bool
1596print_method_description_list(
1597	uint32_t indent,
1598	uint32_t addr,
1599	struct section_info *objc_sections,
1600	uint32_t nobjc_sections,
1601	struct section_info *cstring_section_ptr,
1602	enum byte_sex host_byte_sex,
1603	enum bool swapped,
1604	enum bool verbose)
1605{
1606    struct objc_method_description_list_t mdl;
1607    struct objc_method_description_t *list, md;
1608    enum bool trunc;
1609    uint32_t i, list_left, left;
1610    char *p;
1611
1612    if(get_method_description_list(addr, &mdl, &list, &list_left,
1613		&trunc, objc_sections, nobjc_sections,
1614		host_byte_sex, swapped) == FALSE)
1615	return(FALSE);
1616
1617    printf("\n");
1618    if(trunc == TRUE){
1619	print_indent(indent);
1620	printf(" objc_method_description_list extends past end of the "
1621		"section\n");
1622    }
1623
1624    print_indent(indent);
1625    printf("        count %d\n", mdl.count);
1626
1627    for(i = 0; i < (uint32_t)mdl.count; i++){
1628	if((i + 1) * sizeof(struct objc_method_description_t) > list_left){
1629		print_indent(indent);
1630		printf(" remaining list entries extend past the of the "
1631		       "section\n");
1632		break;
1633	    }
1634	    print_indent(indent);
1635	    printf("        list[%u]\n", i);
1636	    memcpy(&md, list + i, sizeof(struct objc_method_description_t));
1637	    if(swapped)
1638		swap_objc_method_description_t(&md, host_byte_sex);
1639
1640	    print_indent(indent);
1641	    printf("             name 0x%08x", (unsigned int)md.name);
1642	    if(verbose){
1643		p = get_pointer(md.name, &left,
1644		    objc_sections, nobjc_sections, cstring_section_ptr);
1645		if(p != NULL)
1646		    printf(" %.*s\n", (int)left, p);
1647		else
1648		    printf(" (not in an " SEG_OBJC " section)\n");
1649	    }
1650	    else
1651		printf("\n");
1652
1653	    print_indent(indent);
1654	    printf("            types 0x%08x", (unsigned int)md.types);
1655	    if(verbose){
1656		p = get_pointer(md.types, &left,
1657		    objc_sections, nobjc_sections, cstring_section_ptr);
1658		if(p != NULL)
1659		    printf(" %.*s\n", (int)left, p);
1660		else
1661		    printf(" (not in an " SEG_OBJC " section)\n");
1662	    }
1663	    else
1664		printf("\n");
1665	}
1666	return(TRUE);
1667}
1668
1669static enum bool
1670print_PHASH(
1671uint32_t indent,
1672uint32_t addr,
1673struct section_info *objc_sections,
1674uint32_t nobjc_sections,
1675struct section_info *cstring_section_ptr,
1676enum byte_sex host_byte_sex,
1677enum bool swapped,
1678enum bool verbose)
1679{
1680    struct _hashEntry_t _hashEntry;
1681    enum bool trunc;
1682    uint32_t left;
1683    char *p;
1684
1685	if(get_hashEntry(addr, &_hashEntry, &trunc, objc_sections,
1686	    nobjc_sections, host_byte_sex, swapped) == FALSE)
1687	    return(FALSE);
1688
1689	printf("\n");
1690	if(trunc == TRUE){
1691	    print_indent(indent);
1692	    printf("_hashEntry extends past end of the section\n");
1693	}
1694
1695	print_indent(indent);
1696	printf(" sel 0x%08x", (unsigned int)_hashEntry.sel);
1697	if(verbose){
1698	    p = get_pointer(_hashEntry.sel, &left,
1699    	    objc_sections, nobjc_sections, cstring_section_ptr);
1700	    if(p != NULL)
1701		printf(" %.*s\n", (int)left, p);
1702	    else
1703		printf(" (not in an " SEG_OBJC " section)\n");
1704	}
1705	else
1706	    printf("\n");
1707
1708	print_indent(indent);
1709	printf("next 0x%08x", (unsigned int)_hashEntry.next);
1710	if(_hashEntry.next == 0){
1711	    printf("\n");
1712	    return(TRUE);
1713	}
1714	if(print_PHASH(indent+4, _hashEntry.next,
1715	    objc_sections, nobjc_sections, cstring_section_ptr,
1716	    host_byte_sex, swapped, verbose) == FALSE)
1717	    printf(" (not in an " SEG_OBJC " section)\n");
1718	return(TRUE);
1719}
1720
1721static
1722void
1723print_indent(
1724uint32_t indent)
1725{
1726     uint32_t i;
1727
1728	for(i = 0; i < indent; ){
1729	    if(indent - i >= 8){
1730		printf("\t");
1731		i += 8;
1732	    }
1733	    else{
1734		printf("%.*s", (int)(indent - i), "        ");
1735		return;
1736	    }
1737	}
1738}
1739
1740static
1741void *
1742get_pointer(
1743uint32_t addr,
1744uint32_t *left,
1745struct section_info *objc_sections,
1746uint32_t nobjc_sections,
1747struct section_info *cstring_section_ptr)
1748{
1749    void* returnValue = NULL;
1750    uint32_t i;
1751
1752	if(addr >= cstring_section_ptr->addr &&
1753	   addr < cstring_section_ptr->addr + cstring_section_ptr->size){
1754	    *left = cstring_section_ptr->size -
1755	    (addr - cstring_section_ptr->addr);
1756	    if(cstring_section_ptr->protected == TRUE)
1757		returnValue = "some string from a protected section";
1758	    else
1759		returnValue = (cstring_section_ptr->contents +
1760			       (addr - cstring_section_ptr->addr));
1761	}
1762	for(i = 0; returnValue != NULL && i < nobjc_sections; i++){
1763	    if(addr >= objc_sections[i].addr &&
1764	       addr < objc_sections[i].addr + objc_sections[i].size){
1765		*left = objc_sections[i].size -
1766		        (addr - objc_sections[i].addr);
1767		returnValue = (objc_sections[i].contents +
1768		       (addr - objc_sections[i].addr));
1769	    }
1770	}
1771	return(returnValue);
1772}
1773
1774static
1775enum bool
1776get_symtab(
1777uint32_t addr,
1778struct objc_symtab_t *symtab,
1779uint32_t **defs,
1780uint32_t *left,
1781enum bool *trunc,
1782struct section_info *objc_sections,
1783uint32_t nobjc_sections,
1784enum byte_sex host_byte_sex,
1785enum bool swapped)
1786{
1787    uint32_t i;
1788
1789	memset(symtab, '\0', sizeof(struct objc_symtab_t));
1790	if(addr == 0)
1791	    return(0);
1792	for(i = 0; i < nobjc_sections; i++){
1793	    if(addr >= objc_sections[i].addr &&
1794	       addr < objc_sections[i].addr + objc_sections[i].size){
1795
1796		*left = objc_sections[i].size -
1797		        (addr - objc_sections[i].addr);
1798		if(*left >= sizeof(struct objc_symtab_t) - sizeof(uint32_t)){
1799		    memcpy(symtab,
1800			   objc_sections[i].contents +
1801			       (addr - objc_sections[i].addr),
1802			   sizeof(struct objc_symtab_t) - sizeof(uint32_t));
1803		    *left -= sizeof(struct objc_symtab_t) - sizeof(uint32_t);
1804		    *defs = (uint32_t *)(objc_sections[i].contents +
1805				     (addr - objc_sections[i].addr) +
1806			   	     sizeof(struct objc_symtab_t) -
1807				     sizeof(uint32_t));
1808		    *trunc = FALSE;
1809		}
1810		else{
1811		    memcpy(symtab,
1812			   objc_sections[i].contents +
1813			        (addr - objc_sections[i].addr),
1814			   *left);
1815		    *left = 0;
1816		    *defs = NULL;
1817		    *trunc = TRUE;
1818		}
1819		if(swapped)
1820		    swap_objc_symtab_t(symtab, host_byte_sex);
1821		return(TRUE);
1822	    }
1823	}
1824	return(FALSE);
1825}
1826
1827static
1828enum bool
1829get_objc_class(
1830uint32_t addr,
1831struct objc_class_t *objc_class,
1832enum bool *trunc,
1833struct section_info *objc_sections,
1834uint32_t nobjc_sections,
1835enum byte_sex host_byte_sex,
1836enum bool swapped)
1837{
1838    uint32_t left, i;
1839
1840	memset(objc_class, '\0', sizeof(struct objc_class_t));
1841	if(addr == 0)
1842	    return(FALSE);
1843	for(i = 0; i < nobjc_sections; i++){
1844	    if(addr >= objc_sections[i].addr &&
1845	       addr < objc_sections[i].addr + objc_sections[i].size){
1846
1847		left = objc_sections[i].size -
1848		        (addr - objc_sections[i].addr);
1849		if(left >= sizeof(struct objc_class_t)){
1850		    memcpy(objc_class,
1851			   objc_sections[i].contents +
1852			       (addr - objc_sections[i].addr),
1853			   sizeof(struct objc_class_t));
1854		    *trunc = FALSE;
1855		}
1856		else{
1857		    memcpy(objc_class,
1858			   objc_sections[i].contents +
1859			        (addr - objc_sections[i].addr),
1860			   left);
1861		    *trunc = TRUE;
1862		}
1863		if(swapped)
1864		    swap_objc_class_t(objc_class, host_byte_sex);
1865		return(TRUE);
1866	    }
1867	}
1868	return(FALSE);
1869}
1870
1871static
1872enum bool
1873get_objc_category(
1874uint32_t addr,
1875struct objc_category_t *objc_category,
1876enum bool *trunc,
1877struct section_info *objc_sections,
1878uint32_t nobjc_sections,
1879enum byte_sex host_byte_sex,
1880enum bool swapped)
1881{
1882    uint32_t left, i;
1883
1884	memset(objc_category, '\0', sizeof(struct objc_category_t));
1885	if(addr == 0)
1886	    return(FALSE);
1887	for(i = 0; i < nobjc_sections; i++){
1888	    if(addr >= objc_sections[i].addr &&
1889	       addr < objc_sections[i].addr + objc_sections[i].size){
1890
1891		left = objc_sections[i].size -
1892		        (addr - objc_sections[i].addr);
1893		if(left >= sizeof(struct objc_category_t)){
1894		    memcpy(objc_category,
1895			   objc_sections[i].contents +
1896			       (addr - objc_sections[i].addr),
1897			   sizeof(struct objc_category_t));
1898		    *trunc = FALSE;
1899		}
1900		else{
1901		    memcpy(objc_category,
1902			   objc_sections[i].contents +
1903			        (addr - objc_sections[i].addr),
1904			   left);
1905		    *trunc = TRUE;
1906		}
1907		if(swapped)
1908		    swap_objc_category_t(objc_category, host_byte_sex);
1909		return(TRUE);
1910	    }
1911	}
1912	return(FALSE);
1913}
1914
1915static
1916enum bool
1917get_ivar_list(
1918uint32_t addr,
1919struct objc_ivar_list_t *objc_ivar_list,
1920struct objc_ivar_t **ivar_list,
1921uint32_t *left,
1922enum bool *trunc,
1923struct section_info *objc_sections,
1924uint32_t nobjc_sections,
1925enum byte_sex host_byte_sex,
1926enum bool swapped)
1927{
1928    uint32_t i;
1929
1930	memset(objc_ivar_list, '\0', sizeof(struct objc_ivar_list_t));
1931	if(addr == 0)
1932	    return(FALSE);
1933	for(i = 0; i < nobjc_sections; i++){
1934	    if(addr >= objc_sections[i].addr &&
1935	       addr < objc_sections[i].addr + objc_sections[i].size){
1936
1937		*left = objc_sections[i].size -
1938		        (addr - objc_sections[i].addr);
1939		if(*left >= sizeof(struct objc_ivar_list_t) -
1940			    sizeof(struct objc_ivar_t)){
1941		    memcpy(objc_ivar_list,
1942			   objc_sections[i].contents +
1943				(addr - objc_sections[i].addr),
1944			   sizeof(struct objc_ivar_list_t) -
1945				sizeof(struct objc_ivar_t));
1946		    *left -= sizeof(struct objc_ivar_list_t) -
1947			     sizeof(struct objc_ivar_t);
1948		    *ivar_list = (struct objc_ivar_t *)
1949				 (objc_sections[i].contents +
1950				     (addr - objc_sections[i].addr) +
1951				  sizeof(struct objc_ivar_list_t) -
1952				      sizeof(struct objc_ivar_t));
1953		    *trunc = FALSE;
1954		}
1955		else{
1956		    memcpy(objc_ivar_list,
1957			   objc_sections[i].contents +
1958			        (addr - objc_sections[i].addr),
1959			   *left);
1960		    *left = 0;
1961		    *ivar_list = NULL;
1962		    *trunc = TRUE;
1963		}
1964		if(swapped)
1965		    swap_objc_ivar_list_t(objc_ivar_list, host_byte_sex);
1966		return(TRUE);
1967	    }
1968	}
1969	return(FALSE);
1970}
1971
1972static
1973enum bool
1974get_method_list(
1975uint32_t addr,
1976struct objc_method_list_t *method_list,
1977struct objc_method_t **methods,
1978uint32_t *left,
1979enum bool *trunc,
1980struct section_info *objc_sections,
1981uint32_t nobjc_sections,
1982enum byte_sex host_byte_sex,
1983enum bool swapped)
1984{
1985    uint32_t i;
1986
1987	memset(method_list, '\0', sizeof(struct objc_method_list_t));
1988	if(addr == 0)
1989	    return(FALSE);
1990	for(i = 0; i < nobjc_sections; i++){
1991	    if(addr >= objc_sections[i].addr &&
1992	       addr < objc_sections[i].addr + objc_sections[i].size){
1993
1994		*left = objc_sections[i].size -
1995		        (addr - objc_sections[i].addr);
1996		if(*left >= sizeof(struct objc_method_list_t) -
1997			    sizeof(struct objc_method_t)){
1998		    memcpy(method_list,
1999			   objc_sections[i].contents +
2000				(addr - objc_sections[i].addr),
2001			   sizeof(struct objc_method_list_t) -
2002				sizeof(struct objc_method_t));
2003		    *left -= sizeof(struct objc_method_list_t) -
2004			     sizeof(struct objc_method_t);
2005		    *methods = (struct objc_method_t *)
2006				 (objc_sections[i].contents +
2007				     (addr - objc_sections[i].addr) +
2008				  sizeof(struct objc_method_list_t) -
2009				      sizeof(struct objc_method_t));
2010		    *trunc = FALSE;
2011		}
2012		else{
2013		    memcpy(method_list,
2014			   objc_sections[i].contents +
2015			        (addr - objc_sections[i].addr),
2016			   *left);
2017		    *left = 0;
2018		    *methods = NULL;
2019		    *trunc = TRUE;
2020		}
2021		if(swapped)
2022		    swap_objc_method_list_t(method_list, host_byte_sex);
2023		return(TRUE);
2024	    }
2025	}
2026	return(FALSE);
2027}
2028
2029static
2030enum bool
2031get_protocol_list(
2032uint32_t addr,
2033struct objc_protocol_list_t *protocol_list,
2034uint32_t **list,
2035uint32_t *left,
2036enum bool *trunc,
2037struct section_info *objc_sections,
2038uint32_t nobjc_sections,
2039enum byte_sex host_byte_sex,
2040enum bool swapped)
2041{
2042    uint32_t i;
2043
2044	memset(protocol_list, '\0', sizeof(struct objc_protocol_list_t));
2045	if(addr == 0)
2046	    return(FALSE);
2047	for(i = 0; i < nobjc_sections; i++){
2048	    if(addr >= objc_sections[i].addr &&
2049	       addr < objc_sections[i].addr + objc_sections[i].size){
2050
2051		*left = objc_sections[i].size -
2052		        (addr - objc_sections[i].addr);
2053		if(*left >= sizeof(struct objc_protocol_list_t) -
2054			    sizeof(uint32_t)){
2055		    memcpy(protocol_list,
2056			   objc_sections[i].contents +
2057				(addr - objc_sections[i].addr),
2058			   sizeof(struct objc_protocol_list_t) -
2059				sizeof(uint32_t));
2060		    *left -= sizeof(struct objc_protocol_list_t) -
2061			     sizeof(uint32_t);
2062		    *list = (uint32_t *)
2063				 (objc_sections[i].contents +
2064				     (addr - objc_sections[i].addr) +
2065				  sizeof(struct objc_protocol_list_t) -
2066				      sizeof(uint32_t));
2067		    *trunc = FALSE;
2068		}
2069		else{
2070		    memcpy(protocol_list,
2071			   objc_sections[i].contents +
2072			        (addr - objc_sections[i].addr),
2073			   *left);
2074		    *left = 0;
2075		    *list = NULL;
2076		    *trunc = TRUE;
2077		}
2078		if(swapped)
2079		    swap_objc_protocol_list_t(protocol_list, host_byte_sex);
2080		return(TRUE);
2081	    }
2082	}
2083	return(FALSE);
2084}
2085
2086static
2087enum bool
2088get_protocol(
2089uint32_t addr,
2090struct objc_protocol_t *protocol,
2091enum bool *trunc,
2092struct section_info *objc_sections,
2093uint32_t nobjc_sections,
2094enum byte_sex host_byte_sex,
2095enum bool swapped)
2096{
2097    uint32_t left, i;
2098
2099	memset(protocol, '\0', sizeof(struct objc_protocol_t));
2100	if(addr == 0)
2101	    return(FALSE);
2102	for(i = 0; i < nobjc_sections; i++){
2103	    if(addr >= objc_sections[i].addr &&
2104	       addr < objc_sections[i].addr + objc_sections[i].size){
2105
2106		left = objc_sections[i].size -
2107		        (addr - objc_sections[i].addr);
2108		if(left >= sizeof(struct objc_protocol_t)){
2109		    memcpy(protocol,
2110			   objc_sections[i].contents +
2111			       (addr - objc_sections[i].addr),
2112			   sizeof(struct objc_protocol_t));
2113		    *trunc = FALSE;
2114		}
2115		else{
2116		    memcpy(protocol,
2117			   objc_sections[i].contents +
2118			        (addr - objc_sections[i].addr),
2119			   left);
2120		    *trunc = TRUE;
2121		}
2122		if(swapped)
2123		    swap_objc_protocol_t(protocol, host_byte_sex);
2124		return(TRUE);
2125	    }
2126	}
2127	return(FALSE);
2128}
2129
2130static
2131enum bool
2132get_method_description_list(
2133uint32_t addr,
2134struct objc_method_description_list_t *mdl,
2135struct objc_method_description_t **list,
2136uint32_t *left,
2137enum bool *trunc,
2138struct section_info *objc_sections,
2139uint32_t nobjc_sections,
2140enum byte_sex host_byte_sex,
2141enum bool swapped)
2142{
2143    uint32_t i;
2144
2145	memset(mdl, '\0', sizeof(struct objc_method_description_list_t));
2146	if(addr == 0)
2147	    return(FALSE);
2148	for(i = 0; i < nobjc_sections; i++){
2149	    if(addr >= objc_sections[i].addr &&
2150	       addr < objc_sections[i].addr + objc_sections[i].size){
2151
2152		*left = objc_sections[i].size -
2153		        (addr - objc_sections[i].addr);
2154		if(*left >= sizeof(struct objc_method_description_list_t) -
2155			    sizeof(struct objc_method_description_t)){
2156		    memcpy(mdl,
2157			   objc_sections[i].contents +
2158				(addr - objc_sections[i].addr),
2159			   sizeof(struct objc_method_description_list_t) -
2160				sizeof(struct objc_method_description_t));
2161		    *left -= sizeof(struct objc_method_description_list_t) -
2162			     sizeof(struct objc_method_description_t);
2163		    *list = (struct objc_method_description_t *)
2164				 (objc_sections[i].contents +
2165				     (addr - objc_sections[i].addr) +
2166				 sizeof(struct objc_method_description_list_t) -
2167				      sizeof(struct objc_method_description_t));
2168		    *trunc = FALSE;
2169		}
2170		else{
2171		    memcpy(mdl,
2172			   objc_sections[i].contents +
2173			        (addr - objc_sections[i].addr),
2174			   *left);
2175		    *left = 0;
2176		    *list = NULL;
2177		    *trunc = TRUE;
2178		}
2179		if(swapped)
2180		    swap_objc_method_description_list_t(mdl, host_byte_sex);
2181		return(TRUE);
2182	    }
2183	}
2184	return(FALSE);
2185}
2186
2187static
2188enum bool
2189get_hashEntry(
2190uint32_t addr,
2191struct _hashEntry_t *_hashEntry,
2192enum bool *trunc,
2193struct section_info *objc_sections,
2194uint32_t nobjc_sections,
2195enum byte_sex host_byte_sex,
2196enum bool swapped)
2197{
2198    uint32_t left, i;
2199
2200	memset(_hashEntry, '\0', sizeof(struct _hashEntry_t));
2201	if(addr == 0)
2202	    return(FALSE);
2203	for(i = 0; i < nobjc_sections; i++){
2204	    if(addr >= objc_sections[i].addr &&
2205	       addr < objc_sections[i].addr + objc_sections[i].size){
2206
2207		left = objc_sections[i].size -
2208		        (addr - objc_sections[i].addr);
2209		if(left >= sizeof(struct _hashEntry_t)){
2210		    memcpy(_hashEntry,
2211			   objc_sections[i].contents +
2212			       (addr - objc_sections[i].addr),
2213			   sizeof(struct _hashEntry_t));
2214		    *trunc = FALSE;
2215		}
2216		else{
2217		    memcpy(_hashEntry,
2218			   objc_sections[i].contents +
2219			        (addr - objc_sections[i].addr),
2220			   left);
2221		    *trunc = TRUE;
2222		}
2223		if(swapped)
2224		    swap_hashEntry_t(_hashEntry, host_byte_sex);
2225		return(TRUE);
2226	    }
2227	}
2228	return(FALSE);
2229}
2230