]> git.saurik.com Git - apple/ld64.git/blob - src/other/ObjectDump.cpp
ld64-123.2.tar.gz
[apple/ld64.git] / src / other / ObjectDump.cpp
1 /* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
2 *
3 * Copyright (c) 2005-2010 Apple Inc. All rights reserved.
4 *
5 * @APPLE_LICENSE_HEADER_START@
6 *
7 * This file contains Original Code and/or Modifications of Original Code
8 * as defined in and that are subject to the Apple Public Source License
9 * Version 2.0 (the 'License'). You may not use this file except in
10 * compliance with the License. Please obtain a copy of the License at
11 * http://www.opensource.apple.com/apsl/ and read it before using this
12 * file.
13 *
14 * The Original Code and all software distributed under the License are
15 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
16 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
19 * Please see the License for the specific language governing rights and
20 * limitations under the License.
21 *
22 * @APPLE_LICENSE_HEADER_END@
23 */
24
25 #include <sys/types.h>
26 #include <sys/stat.h>
27 #include <sys/mman.h>
28 #include <fcntl.h>
29 #include <mach-o/nlist.h>
30 #include <mach-o/stab.h>
31 #include <mach-o/fat.h>
32 #include <mach-o/loader.h>
33
34 #include "MachOFileAbstraction.hpp"
35 #include "parsers/macho_relocatable_file.h"
36 #include "parsers/lto_file.h"
37
38 static bool sDumpContent= true;
39 static bool sDumpStabs = false;
40 static bool sSort = true;
41 static bool sNMmode = false;
42 static bool sShowSection = true;
43 static bool sShowDefinitionKind = true;
44 static bool sShowCombineKind = true;
45
46 static cpu_type_t sPreferredArch = CPU_TYPE_I386;
47 static cpu_subtype_t sPreferredSubArch = 0xFFFFFFFF;
48 static const char* sMatchName = NULL;
49 static int sPrintRestrict;
50 static int sPrintAlign;
51 static int sPrintName;
52
53 __attribute__((noreturn))
54 void throwf(const char* format, ...)
55 {
56 va_list list;
57 char* p;
58 va_start(list, format);
59 vasprintf(&p, format, list);
60 va_end(list);
61
62 const char* t = p;
63 throw t;
64 }
65
66 void warning(const char* format, ...)
67 {
68 va_list list;
69 fprintf(stderr, "warning: ");
70 va_start(list, format);
71 vfprintf(stderr, format, list);
72 va_end(list);
73 fprintf(stderr, "\n");
74 }
75
76 static void dumpStabs(const std::vector<ld::relocatable::File::Stab>* stabs)
77 {
78 // debug info
79 printf("stabs: (%lu)\n", stabs->size());
80 for (std::vector<ld::relocatable::File::Stab>::const_iterator it = stabs->begin(); it != stabs->end(); ++it ) {
81 const ld::relocatable::File::Stab& stab = *it;
82 const char* code = "?????";
83 switch (stab.type) {
84 case N_GSYM:
85 code = " GSYM";
86 break;
87 case N_FNAME:
88 code = "FNAME";
89 break;
90 case N_FUN:
91 code = " FUN";
92 break;
93 case N_STSYM:
94 code = "STSYM";
95 break;
96 case N_LCSYM:
97 code = "LCSYM";
98 break;
99 case N_BNSYM:
100 code = "BNSYM";
101 break;
102 case N_OPT:
103 code = " OPT";
104 break;
105 case N_RSYM:
106 code = " RSYM";
107 break;
108 case N_SLINE:
109 code = "SLINE";
110 break;
111 case N_ENSYM:
112 code = "ENSYM";
113 break;
114 case N_SSYM:
115 code = " SSYM";
116 break;
117 case N_SO:
118 code = " SO";
119 break;
120 case N_OSO:
121 code = " OSO";
122 break;
123 case N_LSYM:
124 code = " LSYM";
125 break;
126 case N_BINCL:
127 code = "BINCL";
128 break;
129 case N_SOL:
130 code = " SOL";
131 break;
132 case N_PARAMS:
133 code = "PARMS";
134 break;
135 case N_VERSION:
136 code = " VERS";
137 break;
138 case N_OLEVEL:
139 code = "OLEVL";
140 break;
141 case N_PSYM:
142 code = " PSYM";
143 break;
144 case N_EINCL:
145 code = "EINCL";
146 break;
147 case N_ENTRY:
148 code = "ENTRY";
149 break;
150 case N_LBRAC:
151 code = "LBRAC";
152 break;
153 case N_EXCL:
154 code = " EXCL";
155 break;
156 case N_RBRAC:
157 code = "RBRAC";
158 break;
159 case N_BCOMM:
160 code = "BCOMM";
161 break;
162 case N_ECOMM:
163 code = "ECOMM";
164 break;
165 case N_LENG:
166 code = "LENG";
167 break;
168 }
169 printf(" [atom=%20s] %02X %04X %s %s\n", ((stab.atom != NULL) ? stab.atom->name() : ""), stab.other, stab.desc, code, stab.string);
170 }
171 }
172
173 #if 0
174 static void dumpAtomLikeNM(ld::Atom* atom)
175 {
176 uint32_t size = atom->size();
177
178 const char* visibility;
179 switch ( atom->scope() ) {
180 case ld::Atom::scopeTranslationUnit:
181 visibility = "internal";
182 break;
183 case ld::Atom::scopeLinkageUnit:
184 visibility = "hidden ";
185 break;
186 case ld::Atom::scopeGlobal:
187 visibility = "global ";
188 break;
189 default:
190 visibility = " ";
191 break;
192 }
193
194 const char* kind;
195 switch ( atom->definitionKind() ) {
196 case ld::Atom::kRegularDefinition:
197 kind = "regular ";
198 break;
199 case ld::Atom::kTentativeDefinition:
200 kind = "tentative";
201 break;
202 case ld::Atom::kWeakDefinition:
203 kind = "weak ";
204 break;
205 case ld::Atom::kAbsoluteSymbol:
206 kind = "absolute ";
207 break;
208 default:
209 kind = " ";
210 break;
211 }
212
213 printf("0x%08X %s %s %s\n", size, visibility, kind, atom->name());
214 }
215
216
217 static void dumpAtom(ld::Atom* atom)
218 {
219 if(sMatchName && strcmp(sMatchName, atom->name()))
220 return;
221
222 //printf("atom: %p\n", atom);
223
224 // name
225 if(!sPrintRestrict || sPrintName)
226 printf("name: %s\n", atom->name());
227
228 // scope
229 if(!sPrintRestrict)
230 switch ( atom->scope() ) {
231 case ld::Atom::scopeTranslationUnit:
232 printf("scope: translation unit\n");
233 break;
234 case ld::Atom::scopeLinkageUnit:
235 printf("scope: linkage unit\n");
236 break;
237 case ld::Atom::scopeGlobal:
238 printf("scope: global\n");
239 break;
240 default:
241 printf("scope: unknown\n");
242 }
243
244 // kind
245 if(!sPrintRestrict)
246 switch ( atom->definitionKind() ) {
247 case ld::Atom::kRegularDefinition:
248 printf("kind: regular\n");
249 break;
250 case ld::Atom::kWeakDefinition:
251 printf("kind: weak\n");
252 break;
253 case ld::Atom::kTentativeDefinition:
254 printf("kind: tentative\n");
255 break;
256 case ld::Atom::kExternalDefinition:
257 printf("kind: import\n");
258 break;
259 case ld::Atom::kExternalWeakDefinition:
260 printf("kind: weak import\n");
261 break;
262 case ld::Atom::kAbsoluteSymbol:
263 printf("kind: absolute symbol\n");
264 break;
265 default:
266 printf("kind: unknown\n");
267 }
268
269 // segment and section
270 if(!sPrintRestrict && (atom->section().sectionName() != NULL) )
271 printf("section: %s,%s\n", atom->section().segmentName(), atom->section().sectionName());
272
273 // attributes
274 if(!sPrintRestrict) {
275 printf("attrs: ");
276 if ( atom->dontDeadStrip() )
277 printf("dont-dead-strip ");
278 if ( atom->isThumb() )
279 printf("thumb ");
280 printf("\n");
281 }
282
283 // size
284 if(!sPrintRestrict)
285 printf("size: 0x%012llX\n", atom->size());
286
287 // alignment
288 if(!sPrintRestrict || sPrintAlign)
289 printf("align: %u mod %u\n", atom->alignment().modulus, (1 << atom->alignment().powerOf2) );
290
291 // content
292 if (!sPrintRestrict && sDumpContent ) {
293 uint64_t size = atom->size();
294 if ( size < 4096 ) {
295 uint8_t content[size];
296 atom->copyRawContent(content);
297 printf("content: ");
298 if ( atom->contentType() == ld::Atom::typeCString ) {
299 printf("\"");
300 for (unsigned int i=0; i < size; ++i) {
301 if(content[i]<'!' || content[i]>=127)
302 printf("\\%o", content[i]);
303 else
304 printf("%c", content[i]);
305 }
306 printf("\"");
307 }
308 else {
309 for (unsigned int i=0; i < size; ++i)
310 printf("%02X ", content[i]);
311 }
312 }
313 printf("\n");
314 }
315
316 // unwind info
317 if(!sPrintRestrict) {
318 if ( atom->beginUnwind() != atom->endUnwind() ) {
319 printf("unwind encodings:\n");
320 for (ld::Atom::UnwindInfo::iterator it = atom->beginUnwind(); it != atom->endUnwind(); ++it) {
321 printf("\t 0x%04X 0x%08X\n", it->startOffset, it->unwindInfo);
322 }
323 }
324 }
325 #if 0
326 // references
327 if(!sPrintRestrict) {
328 std::vector<ObjectFile::Reference*>& references = atom->getReferences();
329 const int refCount = references.size();
330 printf("references: (%u)\n", refCount);
331 for (int i=0; i < refCount; ++i) {
332 ObjectFile::Reference* ref = references[i];
333 printf(" %s\n", ref->getDescription());
334 }
335 }
336 #endif
337 // line info
338 if(!sPrintRestrict) {
339 if ( atom->beginLineInfo() != atom->endLineInfo() ) {
340 printf("line info:\n");
341 for (ld::Atom::LineInfo::iterator it = atom->beginLineInfo(); it != atom->endLineInfo(); ++it) {
342 printf(" offset 0x%04X, line %d, file %s\n", it->atomOffset, it->lineNumber, it->fileName);
343 }
344 }
345 }
346
347 if(!sPrintRestrict)
348 printf("\n");
349 }
350 #endif
351 struct AtomSorter
352 {
353 bool operator()(const ld::Atom* left, const ld::Atom* right)
354 {
355 if ( left == right )
356 return false;
357 // first sort by segment name
358 int diff = strcmp(left->section().segmentName(), right->section().segmentName());
359 if ( diff != 0 )
360 return (diff > 0);
361
362 // then sort by section name
363 diff = strcmp(left->section().sectionName(), right->section().sectionName());
364 if ( diff != 0 )
365 return (diff < 0);
366
367 // then sort by atom name
368 diff = strcmp(left->name(), right->name());
369 if ( diff != 0 )
370 return (diff < 0);
371
372 // if cstring, sort by content
373 if ( left->contentType() == ld::Atom::typeCString ) {
374 diff = strcmp((char*)left->rawContentPointer(), (char*)right->rawContentPointer());
375 if ( diff != 0 )
376 return (diff < 0);
377 }
378 else if ( left->section().type() == ld::Section::typeCStringPointer ) {
379 // if pointer to c-string sort by name
380 const char* leftString = NULL;
381 assert(left->fixupsBegin() != left->fixupsEnd());
382 for (ld::Fixup::iterator fit = left->fixupsBegin(); fit != left->fixupsEnd(); ++fit) {
383 if ( fit->binding == ld::Fixup::bindingByContentBound ) {
384 const ld::Atom* cstringAtom = fit->u.target;
385 assert(cstringAtom->contentType() == ld::Atom::typeCString);
386 leftString = (char*)cstringAtom->rawContentPointer();
387 }
388 }
389 const char* rightString = NULL;
390 assert(right->fixupsBegin() != right->fixupsEnd());
391 for (ld::Fixup::iterator fit = right->fixupsBegin(); fit != right->fixupsEnd(); ++fit) {
392 if ( fit->binding == ld::Fixup::bindingByContentBound ) {
393 const ld::Atom* cstringAtom = fit->u.target;
394 assert(cstringAtom->contentType() == ld::Atom::typeCString);
395 rightString = (char*)cstringAtom->rawContentPointer();
396 }
397 }
398 assert(leftString != NULL);
399 assert(rightString != NULL);
400 diff = strcmp(leftString, rightString);
401 if ( diff != 0 )
402 return (diff < 0);
403 }
404 else if ( left->section().type() == ld::Section::typeLiteral4 ) {
405 // if literal sort by content
406 uint32_t leftValue = *(uint32_t*)left->rawContentPointer();
407 uint32_t rightValue = *(uint32_t*)right->rawContentPointer();
408 diff = (leftValue - rightValue);
409 if ( diff != 0 )
410 return (diff < 0);
411 }
412 else if ( left->section().type() == ld::Section::typeCFI ) {
413 // if __he_frame sort by address
414 diff = (left->objectAddress() - right->objectAddress());
415 if ( diff != 0 )
416 return (diff < 0);
417 }
418 else if ( left->section().type() == ld::Section::typeNonLazyPointer ) {
419 // if non-lazy-pointer sort by name
420 const char* leftString = NULL;
421 assert(left->fixupsBegin() != left->fixupsEnd());
422 for (ld::Fixup::iterator fit = left->fixupsBegin(); fit != left->fixupsEnd(); ++fit) {
423 if ( fit->binding == ld::Fixup::bindingByNameUnbound ) {
424 leftString = fit->u.name;
425 }
426 else if ( fit->binding == ld::Fixup::bindingDirectlyBound ) {
427 leftString = fit->u.target->name();
428 }
429 }
430 const char* rightString = NULL;
431 assert(right->fixupsBegin() != right->fixupsEnd());
432 for (ld::Fixup::iterator fit = right->fixupsBegin(); fit != right->fixupsEnd(); ++fit) {
433 if ( fit->binding == ld::Fixup::bindingByNameUnbound ) {
434 rightString = fit->u.name;
435 }
436 else if ( fit->binding == ld::Fixup::bindingDirectlyBound ) {
437 rightString = fit->u.target->name();
438 }
439 }
440 assert(leftString != NULL);
441 assert(rightString != NULL);
442 diff = strcmp(leftString, rightString);
443 if ( diff != 0 )
444 return (diff < 0);
445 }
446
447 // else sort by size
448 return (left->size() < right->size());
449 }
450 };
451
452
453 class dumper : public ld::File::AtomHandler
454 {
455 public:
456 void dump();
457 virtual void doAtom(const ld::Atom&);
458 virtual void doFile(const ld::File&) {}
459 private:
460 void dumpAtom(const ld::Atom& atom);
461 const char* scopeString(const ld::Atom&);
462 const char* definitionString(const ld::Atom&);
463 const char* combineString(const ld::Atom&);
464 const char* inclusionString(const ld::Atom&);
465 const char* attributeString(const ld::Atom&);
466 const char* makeName(const ld::Atom& atom);
467 const char* referenceTargetAtomName(const ld::Fixup* ref);
468 void dumpFixup(const ld::Fixup* ref);
469
470 uint64_t addressOfFirstAtomInSection(const ld::Section&);
471
472 std::vector<const ld::Atom*> _atoms;
473 };
474
475 const char* dumper::scopeString(const ld::Atom& atom)
476 {
477 switch ( (ld::Atom::Scope)atom.scope() ) {
478 case ld::Atom::scopeTranslationUnit:
479 return "translation-unit";
480 case ld::Atom::scopeLinkageUnit:
481 return "hidden";
482 case ld::Atom::scopeGlobal:
483 if ( atom.autoHide() )
484 return "global but automatically hidden";
485 else
486 return "global";
487 }
488 return "UNKNOWN";
489 }
490
491 const char* dumper::definitionString(const ld::Atom& atom)
492 {
493 switch ( (ld::Atom::Definition)atom.definition() ) {
494 case ld::Atom::definitionRegular:
495 return "regular";
496 case ld::Atom::definitionTentative:
497 return "tentative";
498 case ld::Atom::definitionAbsolute:
499 return "absolute";
500 case ld::Atom::definitionProxy:
501 return "proxy";
502 }
503 return "UNKNOWN";
504 }
505
506 const char* dumper::combineString(const ld::Atom& atom)
507 {
508 switch ( (ld::Atom::Combine)atom.combine() ) {
509 case ld::Atom::combineNever:
510 return "never";
511 case ld::Atom::combineByName:
512 return "by-name";
513 case ld::Atom::combineByNameAndContent:
514 return "by-name-and-content";
515 case ld::Atom::combineByNameAndReferences:
516 return "by-name-and-references";
517 }
518 return "UNKNOWN";
519 }
520
521 const char* dumper::inclusionString(const ld::Atom& atom)
522 {
523 switch ( (ld::Atom::SymbolTableInclusion)atom.symbolTableInclusion() ) {
524 case ld::Atom::symbolTableNotIn:
525 return "not in";
526 case ld::Atom::symbolTableNotInFinalLinkedImages:
527 return "not in final linked images";
528 case ld::Atom::symbolTableIn:
529 return "in";
530 case ld::Atom::symbolTableInAndNeverStrip:
531 return "in and never strip";
532 case ld::Atom::symbolTableInAsAbsolute:
533 return "in as absolute";
534 case ld::Atom::symbolTableInWithRandomAutoStripLabel:
535 return "in as random auto-strip label";
536 }
537 return "UNKNOWN";
538 }
539
540
541
542 const char* dumper::attributeString(const ld::Atom& atom)
543 {
544 static char buffer[256];
545 buffer[0] = '\0';
546
547 if ( atom.dontDeadStrip() )
548 strcat(buffer, "dont-dead-strip ");
549
550 if ( atom.isThumb() )
551 strcat(buffer, "thumb ");
552
553 if ( atom.isAlias() )
554 strcat(buffer, "alias ");
555
556 if ( atom.contentType() == ld::Atom::typeResolver )
557 strcat(buffer, "resolver ");
558
559 return buffer;
560 }
561
562 const char* dumper::makeName(const ld::Atom& atom)
563 {
564 static char buffer[4096];
565 strcpy(buffer, "???");
566 switch ( atom.symbolTableInclusion() ) {
567 case ld::Atom::symbolTableNotIn:
568 if ( atom.contentType() == ld::Atom::typeCString ) {
569 strcpy(buffer, "cstring=");
570 strlcat(buffer, (char*)atom.rawContentPointer(), 4096);
571 }
572 else if ( atom.section().type() == ld::Section::typeLiteral4 ) {
573 char temp[16];
574 strcpy(buffer, "literal4=");
575 uint32_t value = *(uint32_t*)atom.rawContentPointer();
576 sprintf(temp, "0x%08X", value);
577 strcat(buffer, temp);
578 }
579 else if ( atom.section().type() == ld::Section::typeLiteral8 ) {
580 char temp[32];
581 strcpy(buffer, "literal8=");
582 uint32_t value1 = *(uint32_t*)atom.rawContentPointer();
583 uint32_t value2 = ((uint32_t*)atom.rawContentPointer())[1];
584 sprintf(temp, "0x%08X%08X", value1, value2);
585 strcat(buffer, temp);
586 }
587 else if ( atom.section().type() == ld::Section::typeLiteral16 ) {
588 char temp[64];
589 strcpy(buffer, "literal16=");
590 uint32_t value1 = *(uint32_t*)atom.rawContentPointer();
591 uint32_t value2 = ((uint32_t*)atom.rawContentPointer())[1];
592 uint32_t value3 = ((uint32_t*)atom.rawContentPointer())[2];
593 uint32_t value4 = ((uint32_t*)atom.rawContentPointer())[3];
594 sprintf(temp, "0x%08X%08X%08X%08X", value1, value2, value3, value4);
595 strcat(buffer, temp);
596 }
597 else if ( atom.section().type() == ld::Section::typeCStringPointer ) {
598 assert(atom.fixupsBegin() != atom.fixupsEnd());
599 for (ld::Fixup::iterator fit = atom.fixupsBegin(); fit != atom.fixupsEnd(); ++fit) {
600 if ( fit->binding == ld::Fixup::bindingByContentBound ) {
601 const ld::Atom* cstringAtom = fit->u.target;
602 if ( (cstringAtom != NULL) && (cstringAtom->contentType() == ld::Atom::typeCString) ) {
603 strlcpy(buffer, atom.name(), 4096);
604 strlcat(buffer, "=", 4096);
605 strlcat(buffer, (char*)cstringAtom->rawContentPointer(), 4096);
606 }
607 }
608 }
609 }
610 else if ( atom.section().type() == ld::Section::typeNonLazyPointer ) {
611 assert(atom.fixupsBegin() != atom.fixupsEnd());
612 for (ld::Fixup::iterator fit = atom.fixupsBegin(); fit != atom.fixupsEnd(); ++fit) {
613 if ( fit->binding == ld::Fixup::bindingByNameUnbound ) {
614 strcpy(buffer, "non-lazy-pointer-to:");
615 strlcat(buffer, fit->u.name, 4096);
616 return buffer;
617 }
618 else if ( fit->binding == ld::Fixup::bindingDirectlyBound ) {
619 strcpy(buffer, "non-lazy-pointer-to-local:");
620 strlcat(buffer, fit->u.target->name(), 4096);
621 return buffer;
622 }
623 }
624 strlcpy(buffer, atom.name(), 4096);
625 }
626 else {
627 uint64_t sectAddr = addressOfFirstAtomInSection(atom.section());
628 sprintf(buffer, "%s@%s+0x%08llX", atom.name(), atom.section().sectionName(), atom.objectAddress()-sectAddr);
629 }
630 break;
631 case ld::Atom::symbolTableNotInFinalLinkedImages:
632 case ld::Atom::symbolTableIn:
633 case ld::Atom::symbolTableInAndNeverStrip:
634 case ld::Atom::symbolTableInAsAbsolute:
635 case ld::Atom::symbolTableInWithRandomAutoStripLabel:
636 strlcpy(buffer, atom.name(), 4096);
637 break;
638 }
639 return buffer;
640 }
641
642 const char* dumper::referenceTargetAtomName(const ld::Fixup* ref)
643 {
644 static char buffer[4096];
645 switch ( ref->binding ) {
646 case ld::Fixup::bindingNone:
647 return "NO BINDING";
648 case ld::Fixup::bindingByNameUnbound:
649 strcpy(buffer, "by-name(");
650 strlcat(buffer, ref->u.name, 4096);
651 strlcat(buffer, ")", 4096);
652 return buffer;
653 //return ref->u.name;
654 case ld::Fixup::bindingByContentBound:
655 strcpy(buffer, "by-content(");
656 strlcat(buffer, makeName(*ref->u.target), 4096);
657 strlcat(buffer, ")", 4096);
658 return buffer;
659 case ld::Fixup::bindingDirectlyBound:
660 strcpy(buffer, "direct(");
661 strlcat(buffer, makeName(*ref->u.target), 4096);
662 strlcat(buffer, ")", 4096);
663 return buffer;
664 case ld::Fixup::bindingsIndirectlyBound:
665 return "BOUND INDIRECTLY";
666 }
667 return "BAD BINDING";
668 }
669
670
671 void dumper::dumpFixup(const ld::Fixup* ref)
672 {
673 if ( ref->weakImport ) {
674 printf("weak_import ");
675 }
676 switch ( (ld::Fixup::Kind)(ref->kind) ) {
677 case ld::Fixup::kindNone:
678 printf("none");
679 break;
680 case ld::Fixup::kindNoneFollowOn:
681 printf("followed by %s", referenceTargetAtomName(ref));
682 break;
683 case ld::Fixup::kindNoneGroupSubordinate:
684 printf("group subordinate %s", referenceTargetAtomName(ref));
685 break;
686 case ld::Fixup::kindNoneGroupSubordinateFDE:
687 printf("group subordinate FDE %s", referenceTargetAtomName(ref));
688 break;
689 case ld::Fixup::kindNoneGroupSubordinateLSDA:
690 printf("group subordinate LSDA %s", referenceTargetAtomName(ref));
691 break;
692 case ld::Fixup::kindNoneGroupSubordinatePersonality:
693 printf("group subordinate personality %s", referenceTargetAtomName(ref));
694 break;
695 case ld::Fixup::kindSetTargetAddress:
696 printf("%s", referenceTargetAtomName(ref));
697 break;
698 case ld::Fixup::kindSubtractTargetAddress:
699 printf(" - %s", referenceTargetAtomName(ref));
700 break;
701 case ld::Fixup::kindAddAddend:
702 printf(" + 0x%llX", ref->u.addend);
703 break;
704 case ld::Fixup::kindSubtractAddend:
705 printf(" - 0x%llX", ref->u.addend);
706 break;
707 case ld::Fixup::kindSetTargetImageOffset:
708 printf("imageOffset(%s)", referenceTargetAtomName(ref));
709 break;
710 case ld::Fixup::kindSetTargetSectionOffset:
711 printf("sectionOffset(%s)", referenceTargetAtomName(ref));
712 break;
713 case ld::Fixup::kindStore8:
714 printf(", then store byte");
715 break;
716 case ld::Fixup::kindStoreLittleEndian16:
717 printf(", then store 16-bit little endian");
718 break;
719 case ld::Fixup::kindStoreLittleEndianLow24of32:
720 printf(", then store low 24-bit little endian");
721 break;
722 case ld::Fixup::kindStoreLittleEndian32:
723 printf(", then store 32-bit little endian");
724 break;
725 case ld::Fixup::kindStoreLittleEndian64:
726 printf(", then store 64-bit little endian");
727 break;
728 case ld::Fixup::kindStoreBigEndian16:
729 printf(", then store 16-bit big endian");
730 break;
731 case ld::Fixup::kindStoreBigEndianLow24of32:
732 printf(", then store low 24-bit big endian");
733 break;
734 case ld::Fixup::kindStoreBigEndian32:
735 printf(", then store 32-bit big endian");
736 break;
737 case ld::Fixup::kindStoreBigEndian64:
738 printf(", then store 64-bit big endian");
739 break;
740 case ld::Fixup::kindStorePPCBranch24:
741 printf(", then store as PPC branch24");
742 break;
743 case ld::Fixup::kindStorePPCBranch14:
744 printf(", then store as PPC branch14");
745 break;
746 case ld::Fixup::kindStorePPCPicLow14:
747 printf(", then store as PPC low14 pic");
748 break;
749 case ld::Fixup::kindStorePPCPicLow16:
750 printf(", then store as PPC low14 pic");
751 break;
752 case ld::Fixup::kindStorePPCPicHigh16AddLow:
753 printf(", then store as PPC high16 pic");
754 break;
755 case ld::Fixup::kindStorePPCAbsLow14:
756 printf(", then store as PPC low14 abs");
757 break;
758 case ld::Fixup::kindStorePPCAbsLow16:
759 printf(", then store as PPC low14 abs");
760 break;
761 case ld::Fixup::kindStorePPCAbsHigh16AddLow:
762 printf(", then store as PPC high16 abs");
763 break;
764 case ld::Fixup::kindStorePPCAbsHigh16:
765 printf(", then store as PPC high16 abs, no carry");
766 break;
767 case ld::Fixup::kindStoreX86BranchPCRel8:
768 printf(", then store as x86 8-bit pcrel branch");
769 break;
770 case ld::Fixup::kindStoreX86BranchPCRel32:
771 printf(", then store as x86 32-bit pcrel branch");
772 break;
773 case ld::Fixup::kindStoreX86PCRel8:
774 printf(", then store as x86 8-bit pcrel");
775 break;
776 case ld::Fixup::kindStoreX86PCRel16:
777 printf(", then store as x86 16-bit pcrel");
778 break;
779 case ld::Fixup::kindStoreX86PCRel32:
780 printf(", then store as x86 32-bit pcrel");
781 break;
782 case ld::Fixup::kindStoreX86PCRel32_1:
783 printf(", then store as x86 32-bit pcrel from +1");
784 break;
785 case ld::Fixup::kindStoreX86PCRel32_2:
786 printf(", then store as x86 32-bit pcrel from +2");
787 break;
788 case ld::Fixup::kindStoreX86PCRel32_4:
789 printf(", then store as x86 32-bit pcrel from +4");
790 break;
791 case ld::Fixup::kindStoreX86PCRel32GOTLoad:
792 printf(", then store as x86 32-bit pcrel GOT load");
793 break;
794 case ld::Fixup::kindStoreX86PCRel32GOTLoadNowLEA:
795 printf(", then store as x86 32-bit pcrel GOT load -> LEA");
796 break;
797 case ld::Fixup::kindStoreX86PCRel32GOT:
798 printf(", then store as x86 32-bit pcrel GOT access");
799 break;
800 case ld::Fixup::kindStoreX86PCRel32TLVLoad:
801 printf(", then store as x86 32-bit pcrel TLV load");
802 break;
803 case ld::Fixup::kindStoreX86PCRel32TLVLoadNowLEA:
804 printf(", then store as x86 32-bit pcrel TLV load");
805 break;
806 case ld::Fixup::kindStoreX86Abs32TLVLoad:
807 printf(", then store as x86 32-bit absolute TLV load");
808 break;
809 case ld::Fixup::kindStoreX86Abs32TLVLoadNowLEA:
810 printf(", then store as x86 32-bit absolute TLV load -> LEA");
811 break;
812 case ld::Fixup::kindStoreARMBranch24:
813 printf(", then store as ARM 24-bit pcrel branch");
814 break;
815 case ld::Fixup::kindStoreThumbBranch22:
816 printf(", then store as Thumb 22-bit pcrel branch");
817 break;
818 case ld::Fixup::kindStoreARMLoad12:
819 printf(", then store as ARM 12-bit pcrel load");
820 break;
821 case ld::Fixup::kindStoreARMLow16:
822 printf(", then store low-16 in ARM movw");
823 break;
824 case ld::Fixup::kindStoreARMHigh16:
825 printf(", then store high-16 in ARM movt");
826 break;
827 case ld::Fixup::kindStoreThumbLow16:
828 printf(", then store low-16 in Thumb movw");
829 break;
830 case ld::Fixup::kindStoreThumbHigh16:
831 printf(", then store high-16 in Thumb movt");
832 break;
833 case ld::Fixup::kindDtraceExtra:
834 printf("dtrace static probe extra info");
835 break;
836 case ld::Fixup::kindStoreX86DtraceCallSiteNop:
837 printf("x86 dtrace static probe site");
838 break;
839 case ld::Fixup::kindStoreX86DtraceIsEnableSiteClear:
840 printf("x86 dtrace static is-enabled site");
841 break;
842 case ld::Fixup::kindStorePPCDtraceCallSiteNop:
843 printf("ppc dtrace static probe site");
844 break;
845 case ld::Fixup::kindStorePPCDtraceIsEnableSiteClear:
846 printf("ppc dtrace static is-enabled site");
847 break;
848 case ld::Fixup::kindStoreARMDtraceCallSiteNop:
849 printf("ARM dtrace static probe site");
850 break;
851 case ld::Fixup::kindStoreARMDtraceIsEnableSiteClear:
852 printf("ARM dtrace static is-enabled site");
853 break;
854 case ld::Fixup::kindStoreThumbDtraceCallSiteNop:
855 printf("Thumb dtrace static probe site");
856 break;
857 case ld::Fixup::kindStoreThumbDtraceIsEnableSiteClear:
858 printf("Thumb dtrace static is-enabled site");
859 break;
860 case ld::Fixup::kindLazyTarget:
861 printf("lazy reference to external symbol %s", referenceTargetAtomName(ref));
862 break;
863 case ld::Fixup::kindSetLazyOffset:
864 printf("offset of lazy binding info for %s", referenceTargetAtomName(ref));
865 break;
866 case ld::Fixup::kindStoreTargetAddressLittleEndian32:
867 printf("store 32-bit little endian address of %s", referenceTargetAtomName(ref));
868 break;
869 case ld::Fixup::kindStoreTargetAddressLittleEndian64:
870 printf("store 64-bit little endian address of %s", referenceTargetAtomName(ref));
871 break;
872 case ld::Fixup::kindStoreTargetAddressBigEndian32:
873 printf("store 32-bit big endian address of %s", referenceTargetAtomName(ref));
874 break;
875 case ld::Fixup::kindStoreTargetAddressBigEndian64:
876 printf("store 64-bit big endian address of %s", referenceTargetAtomName(ref));
877 break;
878 case ld::Fixup::kindStoreTargetAddressX86PCRel32:
879 printf("x86 store 32-bit pc-rel address of %s", referenceTargetAtomName(ref));
880 break;
881 case ld::Fixup::kindStoreTargetAddressX86BranchPCRel32:
882 printf("x86 store 32-bit pc-rel branch to %s", referenceTargetAtomName(ref));
883 break;
884 case ld::Fixup::kindStoreTargetAddressX86PCRel32GOTLoad:
885 printf("x86 store 32-bit pc-rel GOT load of %s", referenceTargetAtomName(ref));
886 break;
887 case ld::Fixup::kindStoreTargetAddressX86PCRel32GOTLoadNowLEA:
888 printf("x86 store 32-bit pc-rel lea of %s", referenceTargetAtomName(ref));
889 break;
890 case ld::Fixup::kindStoreTargetAddressX86PCRel32TLVLoad:
891 printf("x86 store 32-bit pc-rel TLV load of %s", referenceTargetAtomName(ref));
892 break;
893 case ld::Fixup::kindStoreTargetAddressX86PCRel32TLVLoadNowLEA:
894 printf("x86 store 32-bit pc-rel TLV lea of %s", referenceTargetAtomName(ref));
895 break;
896 case ld::Fixup::kindStoreTargetAddressX86Abs32TLVLoad:
897 printf("x86 store 32-bit absolute TLV load of %s", referenceTargetAtomName(ref));
898 break;
899 case ld::Fixup::kindStoreTargetAddressX86Abs32TLVLoadNowLEA:
900 printf("x86 store 32-bit absolute TLV lea of %s", referenceTargetAtomName(ref));
901 break;
902 case ld::Fixup::kindStoreTargetAddressARMBranch24:
903 printf("ARM store 24-bit pc-rel branch to %s", referenceTargetAtomName(ref));
904 break;
905 case ld::Fixup::kindStoreTargetAddressThumbBranch22:
906 printf("Thumb store 22-bit pc-rel branch to %s", referenceTargetAtomName(ref));
907 break;
908 case ld::Fixup::kindStoreTargetAddressARMLoad12:
909 printf("ARM store 12-bit pc-rel branch to %s", referenceTargetAtomName(ref));
910 break;
911 case ld::Fixup::kindStoreTargetAddressPPCBranch24:
912 printf("PowerPC store 24-bit pc-rel load of %s", referenceTargetAtomName(ref));
913 break;
914 case ld::Fixup::kindSetTargetTLVTemplateOffset:
915 case ld::Fixup::kindSetTargetTLVTemplateOffsetLittleEndian32:
916 case ld::Fixup::kindSetTargetTLVTemplateOffsetLittleEndian64:
917 printf("tlv template offset of %s", referenceTargetAtomName(ref));
918 //default:
919 // printf("unknown fixup");
920 // break;
921 }
922 }
923
924 uint64_t dumper::addressOfFirstAtomInSection(const ld::Section& sect)
925 {
926 uint64_t lowestAddr = (uint64_t)(-1);
927 for (std::vector<const ld::Atom*>::iterator it=_atoms.begin(); it != _atoms.end(); ++it) {
928 const ld::Atom* atom = *it;
929 if ( &atom->section() == &sect ) {
930 if ( atom->objectAddress() < lowestAddr )
931 lowestAddr = atom->objectAddress();
932 }
933 }
934 return lowestAddr;
935 }
936
937 void dumper::doAtom(const ld::Atom& atom)
938 {
939 if ( (sMatchName != NULL) && (strcmp(sMatchName, atom.name()) != 0) )
940 return;
941 _atoms.push_back(&atom);
942 }
943
944 void dumper::dump()
945 {
946 if ( sSort )
947 std::sort(_atoms.begin(), _atoms.end(), AtomSorter());
948
949 for (std::vector<const ld::Atom*>::iterator it=_atoms.begin(); it != _atoms.end(); ++it) {
950 this->dumpAtom(**it);
951 }
952 }
953
954 void dumper::dumpAtom(const ld::Atom& atom)
955 {
956 printf("name: %s\n", makeName(atom));
957 printf("size: 0x%0llX\n", atom.size());
958 printf("align: %u mod %u\n", atom.alignment().modulus, (1 << atom.alignment().powerOf2) );
959 printf("scope: %s\n", scopeString(atom));
960 if ( sShowDefinitionKind )
961 printf("def: %s\n", definitionString(atom));
962 if ( sShowCombineKind )
963 printf("combine: %s\n", combineString(atom));
964 printf("symbol: %s\n", inclusionString(atom));
965 printf("attrs: %s\n", attributeString(atom));
966 if ( sShowSection )
967 printf("section: %s,%s\n", atom.section().segmentName(), atom.section().sectionName());
968 if ( atom.beginUnwind() != atom.endUnwind() ) {
969 printf("unwind: 0x%08X\n", atom.beginUnwind()->unwindInfo);
970 }
971 if ( atom.contentType() == ld::Atom::typeCString ) {
972 uint8_t buffer[atom.size()+2];
973 atom.copyRawContent(buffer);
974 buffer[atom.size()] = '\0';
975 printf("content: \"%s\"\n", buffer);
976 }
977 if ( atom.fixupsBegin() != atom.fixupsEnd() ) {
978 printf("fixups:\n");
979 for (unsigned int off=0; off < atom.size()+1; ++off) {
980 for (ld::Fixup::iterator it = atom.fixupsBegin(); it != atom.fixupsEnd(); ++it) {
981 if ( it->offsetInAtom == off ) {
982 switch ( it->clusterSize ) {
983 case ld::Fixup::k1of1:
984 printf(" 0x%04X ", it->offsetInAtom);
985 dumpFixup(it);
986 break;
987 case ld::Fixup::k1of2:
988 printf(" 0x%04X ", it->offsetInAtom);
989 dumpFixup(it);
990 ++it;
991 dumpFixup(it);
992 break;
993 case ld::Fixup::k1of3:
994 printf(" 0x%04X ", it->offsetInAtom);
995 dumpFixup(it);
996 ++it;
997 dumpFixup(it);
998 ++it;
999 dumpFixup(it);
1000 break;
1001 case ld::Fixup::k1of4:
1002 printf(" 0x%04X ", it->offsetInAtom);
1003 dumpFixup(it);
1004 ++it;
1005 dumpFixup(it);
1006 ++it;
1007 dumpFixup(it);
1008 ++it;
1009 dumpFixup(it);
1010 break;
1011 case ld::Fixup::k1of5:
1012 printf(" 0x%04X ", it->offsetInAtom);
1013 dumpFixup(it);
1014 ++it;
1015 dumpFixup(it);
1016 ++it;
1017 dumpFixup(it);
1018 ++it;
1019 dumpFixup(it);
1020 ++it;
1021 dumpFixup(it);
1022 break;
1023 default:
1024 printf(" BAD CLUSTER SIZE: cluster=%d\n", it->clusterSize);
1025 }
1026 printf("\n");
1027 }
1028 }
1029 }
1030 }
1031 if ( atom.beginLineInfo() != atom.endLineInfo() ) {
1032 printf("line info:\n");
1033 for (ld::Atom::LineInfo::iterator it = atom.beginLineInfo(); it != atom.endLineInfo(); ++it) {
1034 printf(" offset 0x%04X, line %d, file %s\n", it->atomOffset, it->lineNumber, it->fileName);
1035 }
1036 }
1037
1038 printf("\n");
1039 }
1040
1041 static void dumpFile(ld::relocatable::File* file)
1042 {
1043 // stabs debug info
1044 if ( sDumpStabs && (file->debugInfo() == ld::relocatable::File::kDebugInfoStabs) ) {
1045 const std::vector<ld::relocatable::File::Stab>* stabs = file->stabs();
1046 if ( stabs != NULL )
1047 dumpStabs(stabs);
1048 }
1049 // dump atoms
1050 dumper d;
1051 file->forEachAtom(d);
1052 d.dump();
1053
1054 #if 0
1055 // get all atoms
1056 std::vector<ObjectFile::Atom*> atoms = reader->getAtoms();
1057
1058 // make copy of vector and sort (so output is canonical)
1059 std::vector<ObjectFile::Atom*> sortedAtoms(atoms);
1060 if ( sSort )
1061 std::sort(sortedAtoms.begin(), sortedAtoms.end(), AtomSorter());
1062
1063 for(std::vector<ObjectFile::Atom*>::iterator it=sortedAtoms.begin(); it != sortedAtoms.end(); ++it) {
1064 if ( sNMmode )
1065 dumpAtomLikeNM(*it);
1066 else
1067 dumpAtom(*it);
1068 }
1069 #endif
1070 }
1071
1072
1073 static ld::relocatable::File* createReader(const char* path)
1074 {
1075 struct stat stat_buf;
1076
1077 int fd = ::open(path, O_RDONLY, 0);
1078 if ( fd == -1 )
1079 throwf("cannot open file: %s", path);
1080 ::fstat(fd, &stat_buf);
1081 uint8_t* p = (uint8_t*)::mmap(NULL, stat_buf.st_size, PROT_READ, MAP_FILE | MAP_PRIVATE, fd, 0);
1082 ::close(fd);
1083 if ( p == (uint8_t*)(-1) )
1084 throwf("cannot mmap file: %s", path);
1085 const mach_header* mh = (mach_header*)p;
1086 uint64_t fileLen = stat_buf.st_size;
1087 bool foundFatSlice = false;
1088 if ( mh->magic == OSSwapBigToHostInt32(FAT_MAGIC) ) {
1089 const struct fat_header* fh = (struct fat_header*)p;
1090 const struct fat_arch* archs = (struct fat_arch*)(p + sizeof(struct fat_header));
1091 for (unsigned long i=0; i < OSSwapBigToHostInt32(fh->nfat_arch); ++i) {
1092 if ( OSSwapBigToHostInt32(archs[i].cputype) == (uint32_t)sPreferredArch ) {
1093 if ( ((uint32_t)sPreferredSubArch == 0xFFFFFFFF) || ((uint32_t)sPreferredSubArch == OSSwapBigToHostInt32(archs[i].cpusubtype)) ) {
1094 p = p + OSSwapBigToHostInt32(archs[i].offset);
1095 mh = (struct mach_header*)p;
1096 fileLen = OSSwapBigToHostInt32(archs[i].size);
1097 foundFatSlice = true;
1098 break;
1099 }
1100 }
1101 }
1102 }
1103
1104 mach_o::relocatable::ParserOptions objOpts;
1105 objOpts.architecture = sPreferredArch;
1106 objOpts.objSubtypeMustMatch = false;
1107 objOpts.logAllFiles = false;
1108 objOpts.convertUnwindInfo = true;
1109 objOpts.subType = sPreferredSubArch;
1110 #if 1
1111 if ( ! foundFatSlice ) {
1112 cpu_type_t archOfObj;
1113 cpu_subtype_t subArchOfObj;
1114 if ( mach_o::relocatable::isObjectFile(p, &archOfObj, &subArchOfObj) ) {
1115 objOpts.architecture = archOfObj;
1116 objOpts.subType = subArchOfObj;
1117 }
1118 }
1119
1120 ld::relocatable::File* objResult = mach_o::relocatable::parse(p, fileLen, path, stat_buf.st_mtime, 0, objOpts);
1121 if ( objResult != NULL )
1122 return objResult;
1123
1124 // see if it is an llvm object file
1125 objResult = lto::parse(p, fileLen, path, stat_buf.st_mtime, 0, sPreferredArch, sPreferredSubArch, false);
1126 if ( objResult != NULL )
1127 return objResult;
1128
1129 throwf("not a mach-o object file: %s", path);
1130 #else
1131 // for peformance testing
1132 for (int i=0; i < 500; ++i ) {
1133 ld::relocatable::File* objResult = mach_o::relocatable::parse(p, fileLen, path, stat_buf.st_mtime, 0, objOpts);
1134 delete objResult;
1135 }
1136 exit(0);
1137 #endif
1138 }
1139
1140 static
1141 void
1142 usage()
1143 {
1144 fprintf(stderr, "ObjectDump options:\n"
1145 "\t-no_content\tdon't dump contents\n"
1146 "\t-no_section\tdon't dump section name\n"
1147 "\t-no_defintion\tdon't dump definition kind\n"
1148 "\t-no_combine\tdon't dump combine mode\n"
1149 "\t-stabs\t\tdump stabs\n"
1150 "\t-arch aaa\tonly dump info about arch aaa\n"
1151 "\t-only sym\tonly dump info about sym\n"
1152 "\t-align\t\tonly print alignment info\n"
1153 "\t-name\t\tonly print symbol names\n"
1154 );
1155 }
1156
1157 int main(int argc, const char* argv[])
1158 {
1159 if(argc<2) {
1160 usage();
1161 return 0;
1162 }
1163
1164 try {
1165 for(int i=1; i < argc; ++i) {
1166 const char* arg = argv[i];
1167 if ( arg[0] == '-' ) {
1168 if ( strcmp(arg, "-no_content") == 0 ) {
1169 sDumpContent = false;
1170 }
1171 else if ( strcmp(arg, "-nm") == 0 ) {
1172 sNMmode = true;
1173 }
1174 else if ( strcmp(arg, "-stabs") == 0 ) {
1175 sDumpStabs = true;
1176 }
1177 else if ( strcmp(arg, "-no_sort") == 0 ) {
1178 sSort = false;
1179 }
1180 else if ( strcmp(arg, "-no_section") == 0 ) {
1181 sShowSection = false;
1182 }
1183 else if ( strcmp(arg, "-no_definition") == 0 ) {
1184 sShowDefinitionKind = false;
1185 }
1186 else if ( strcmp(arg, "-no_combine") == 0 ) {
1187 sShowCombineKind = false;
1188 }
1189 else if ( strcmp(arg, "-arch") == 0 ) {
1190 const char* arch = ++i<argc? argv[i]: "";
1191 if ( strcmp(arch, "ppc64") == 0 )
1192 sPreferredArch = CPU_TYPE_POWERPC64;
1193 else if ( strcmp(arch, "ppc") == 0 )
1194 sPreferredArch = CPU_TYPE_POWERPC;
1195 else if ( strcmp(arch, "i386") == 0 )
1196 sPreferredArch = CPU_TYPE_I386;
1197 else if ( strcmp(arch, "x86_64") == 0 )
1198 sPreferredArch = CPU_TYPE_X86_64;
1199 else if ( strcmp(arch, "arm") == 0 )
1200 sPreferredArch = CPU_TYPE_ARM;
1201 else if ( strcmp(arch, "armv4t") == 0 ) {
1202 sPreferredArch = CPU_TYPE_ARM;
1203 sPreferredSubArch = CPU_SUBTYPE_ARM_V4T;
1204 }
1205 else if ( strcmp(arch, "armv5") == 0 ) {
1206 sPreferredArch = CPU_TYPE_ARM;
1207 sPreferredSubArch = CPU_SUBTYPE_ARM_V5TEJ;
1208 }
1209 else if ( strcmp(arch, "armv6") == 0 ) {
1210 sPreferredArch = CPU_TYPE_ARM;
1211 sPreferredSubArch = CPU_SUBTYPE_ARM_V6;
1212 }
1213 else if ( strcmp(arch, "armv7") == 0 ) {
1214 sPreferredArch = CPU_TYPE_ARM;
1215 sPreferredSubArch = CPU_SUBTYPE_ARM_V7;
1216 }
1217 else
1218 throwf("unknown architecture %s", arch);
1219 }
1220 else if ( strcmp(arg, "-only") == 0 ) {
1221 sMatchName = ++i<argc? argv[i]: NULL;
1222 }
1223 else if ( strcmp(arg, "-align") == 0 ) {
1224 sPrintRestrict = true;
1225 sPrintAlign = true;
1226 }
1227 else if ( strcmp(arg, "-name") == 0 ) {
1228 sPrintRestrict = true;
1229 sPrintName = true;
1230 }
1231 else {
1232 usage();
1233 throwf("unknown option: %s\n", arg);
1234 }
1235 }
1236 else {
1237 ld::relocatable::File* reader = createReader(arg);
1238 dumpFile(reader);
1239 }
1240 }
1241 }
1242 catch (const char* msg) {
1243 fprintf(stderr, "ObjDump failed: %s\n", msg);
1244 return 1;
1245 }
1246
1247 return 0;
1248 }