1 /* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
3 * Copyright (c) 2005-2010 Apple Inc. All rights reserved.
5 * @APPLE_LICENSE_HEADER_START@
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
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.
22 * @APPLE_LICENSE_HEADER_END@
25 #include <sys/types.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>
34 #include "MachOFileAbstraction.hpp"
35 #include "parsers/macho_relocatable_file.h"
36 #include "parsers/lto_file.h"
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;
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
;
53 __attribute__((noreturn
))
54 void throwf(const char* format
, ...)
58 va_start(list
, format
);
59 vasprintf(&p
, format
, list
);
66 void warning(const char* format
, ...)
69 fprintf(stderr
, "warning: ");
70 va_start(list
, format
);
71 vfprintf(stderr
, format
, list
);
73 fprintf(stderr
, "\n");
76 static void dumpStabs(const std::vector
<ld::relocatable::File::Stab
>* stabs
)
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
= "?????";
169 printf(" [atom=%20s] %02X %04X %s %s\n", ((stab
.atom
!= NULL
) ? stab
.atom
->name() : ""), stab
.other
, stab
.desc
, code
, stab
.string
);
174 static void dumpAtomLikeNM(ld::Atom
* atom
)
176 uint32_t size
= atom
->size();
178 const char* visibility
;
179 switch ( atom
->scope() ) {
180 case ld::Atom::scopeTranslationUnit
:
181 visibility
= "internal";
183 case ld::Atom::scopeLinkageUnit
:
184 visibility
= "hidden ";
186 case ld::Atom::scopeGlobal
:
187 visibility
= "global ";
195 switch ( atom
->definitionKind() ) {
196 case ld::Atom::kRegularDefinition
:
199 case ld::Atom::kTentativeDefinition
:
202 case ld::Atom::kWeakDefinition
:
205 case ld::Atom::kAbsoluteSymbol
:
213 printf("0x%08X %s %s %s\n", size
, visibility
, kind
, atom
->name());
217 static void dumpAtom(ld::Atom
* atom
)
219 if(sMatchName
&& strcmp(sMatchName
, atom
->name()))
222 //printf("atom: %p\n", atom);
225 if(!sPrintRestrict
|| sPrintName
)
226 printf("name: %s\n", atom
->name());
230 switch ( atom
->scope() ) {
231 case ld::Atom::scopeTranslationUnit
:
232 printf("scope: translation unit\n");
234 case ld::Atom::scopeLinkageUnit
:
235 printf("scope: linkage unit\n");
237 case ld::Atom::scopeGlobal
:
238 printf("scope: global\n");
241 printf("scope: unknown\n");
246 switch ( atom
->definitionKind() ) {
247 case ld::Atom::kRegularDefinition
:
248 printf("kind: regular\n");
250 case ld::Atom::kWeakDefinition
:
251 printf("kind: weak\n");
253 case ld::Atom::kTentativeDefinition
:
254 printf("kind: tentative\n");
256 case ld::Atom::kExternalDefinition
:
257 printf("kind: import\n");
259 case ld::Atom::kExternalWeakDefinition
:
260 printf("kind: weak import\n");
262 case ld::Atom::kAbsoluteSymbol
:
263 printf("kind: absolute symbol\n");
266 printf("kind: unknown\n");
269 // segment and section
270 if(!sPrintRestrict
&& (atom
->section().sectionName() != NULL
) )
271 printf("section: %s,%s\n", atom
->section().segmentName(), atom
->section().sectionName());
274 if(!sPrintRestrict
) {
276 if ( atom
->dontDeadStrip() )
277 printf("dont-dead-strip ");
278 if ( atom
->isThumb() )
285 printf("size: 0x%012llX\n", atom
->size());
288 if(!sPrintRestrict
|| sPrintAlign
)
289 printf("align: %u mod %u\n", atom
->alignment().modulus
, (1 << atom
->alignment().powerOf2
) );
292 if (!sPrintRestrict
&& sDumpContent
) {
293 uint64_t size
= atom
->size();
295 uint8_t content
[size
];
296 atom
->copyRawContent(content
);
298 if ( atom
->contentType() == ld::Atom::typeCString
) {
300 for (unsigned int i
=0; i
< size
; ++i
) {
301 if(content
[i
]<'!' || content
[i
]>=127)
302 printf("\\%o", content
[i
]);
304 printf("%c", content
[i
]);
309 for (unsigned int i
=0; i
< size
; ++i
)
310 printf("%02X ", content
[i
]);
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
);
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());
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
);
353 bool operator()(const ld::Atom
* left
, const ld::Atom
* right
)
357 // first sort by segment name
358 int diff
= strcmp(left
->section().segmentName(), right
->section().segmentName());
362 // then sort by section name
363 diff
= strcmp(left
->section().sectionName(), right
->section().sectionName());
367 // then sort by atom name
368 diff
= strcmp(left
->name(), right
->name());
372 // if cstring, sort by content
373 if ( left
->contentType() == ld::Atom::typeCString
) {
374 diff
= strcmp((char*)left
->rawContentPointer(), (char*)right
->rawContentPointer());
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();
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();
398 assert(leftString
!= NULL
);
399 assert(rightString
!= NULL
);
400 diff
= strcmp(leftString
, rightString
);
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
);
412 else if ( left
->section().type() == ld::Section::typeCFI
) {
413 // if __he_frame sort by address
414 diff
= (left
->objectAddress() - right
->objectAddress());
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
;
426 else if ( fit
->binding
== ld::Fixup::bindingDirectlyBound
) {
427 leftString
= fit
->u
.target
->name();
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
;
436 else if ( fit
->binding
== ld::Fixup::bindingDirectlyBound
) {
437 rightString
= fit
->u
.target
->name();
440 assert(leftString
!= NULL
);
441 assert(rightString
!= NULL
);
442 diff
= strcmp(leftString
, rightString
);
448 return (left
->size() < right
->size());
453 class dumper
: public ld::File::AtomHandler
457 virtual void doAtom(const ld::Atom
&);
458 virtual void doFile(const ld::File
&) {}
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
);
470 uint64_t addressOfFirstAtomInSection(const ld::Section
&);
472 std::vector
<const ld::Atom
*> _atoms
;
475 const char* dumper::scopeString(const ld::Atom
& atom
)
477 switch ( (ld::Atom::Scope
)atom
.scope() ) {
478 case ld::Atom::scopeTranslationUnit
:
479 return "translation-unit";
480 case ld::Atom::scopeLinkageUnit
:
482 case ld::Atom::scopeGlobal
:
483 if ( atom
.autoHide() )
484 return "global but automatically hidden";
491 const char* dumper::definitionString(const ld::Atom
& atom
)
493 switch ( (ld::Atom::Definition
)atom
.definition() ) {
494 case ld::Atom::definitionRegular
:
496 case ld::Atom::definitionTentative
:
498 case ld::Atom::definitionAbsolute
:
500 case ld::Atom::definitionProxy
:
506 const char* dumper::combineString(const ld::Atom
& atom
)
508 switch ( (ld::Atom::Combine
)atom
.combine() ) {
509 case ld::Atom::combineNever
:
511 case ld::Atom::combineByName
:
513 case ld::Atom::combineByNameAndContent
:
514 return "by-name-and-content";
515 case ld::Atom::combineByNameAndReferences
:
516 return "by-name-and-references";
521 const char* dumper::inclusionString(const ld::Atom
& atom
)
523 switch ( (ld::Atom::SymbolTableInclusion
)atom
.symbolTableInclusion() ) {
524 case ld::Atom::symbolTableNotIn
:
526 case ld::Atom::symbolTableNotInFinalLinkedImages
:
527 return "not in final linked images";
528 case ld::Atom::symbolTableIn
:
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";
542 const char* dumper::attributeString(const ld::Atom
& atom
)
544 static char buffer
[256];
547 if ( atom
.dontDeadStrip() )
548 strcat(buffer
, "dont-dead-strip ");
550 if ( atom
.isThumb() )
551 strcat(buffer
, "thumb ");
553 if ( atom
.isAlias() )
554 strcat(buffer
, "alias ");
556 if ( atom
.contentType() == ld::Atom::typeResolver
)
557 strcat(buffer
, "resolver ");
562 const char* dumper::makeName(const ld::Atom
& atom
)
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);
572 else if ( atom
.section().type() == ld::Section::typeLiteral4
) {
574 strcpy(buffer
, "literal4=");
575 uint32_t value
= *(uint32_t*)atom
.rawContentPointer();
576 sprintf(temp
, "0x%08X", value
);
577 strcat(buffer
, temp
);
579 else if ( atom
.section().type() == ld::Section::typeLiteral8
) {
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
);
587 else if ( atom
.section().type() == ld::Section::typeLiteral16
) {
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
);
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);
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);
618 else if ( fit
->binding
== ld::Fixup::bindingDirectlyBound
) {
619 strcpy(buffer
, "non-lazy-pointer-to-local:");
620 strlcat(buffer
, fit
->u
.target
->name(), 4096);
624 strlcpy(buffer
, atom
.name(), 4096);
627 uint64_t sectAddr
= addressOfFirstAtomInSection(atom
.section());
628 sprintf(buffer
, "%s@%s+0x%08llX", atom
.name(), atom
.section().sectionName(), atom
.objectAddress()-sectAddr
);
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);
642 const char* dumper::referenceTargetAtomName(const ld::Fixup
* ref
)
644 static char buffer
[4096];
645 switch ( ref
->binding
) {
646 case ld::Fixup::bindingNone
:
648 case ld::Fixup::bindingByNameUnbound
:
649 strcpy(buffer
, "by-name(");
650 strlcat(buffer
, ref
->u
.name
, 4096);
651 strlcat(buffer
, ")", 4096);
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);
659 case ld::Fixup::bindingDirectlyBound
:
660 strcpy(buffer
, "direct(");
661 strlcat(buffer
, makeName(*ref
->u
.target
), 4096);
662 strlcat(buffer
, ")", 4096);
664 case ld::Fixup::bindingsIndirectlyBound
:
665 return "BOUND INDIRECTLY";
667 return "BAD BINDING";
671 void dumper::dumpFixup(const ld::Fixup
* ref
)
673 if ( ref
->weakImport
) {
674 printf("weak_import ");
676 switch ( (ld::Fixup::Kind
)(ref
->kind
) ) {
677 case ld::Fixup::kindNone
:
680 case ld::Fixup::kindNoneFollowOn
:
681 printf("followed by %s", referenceTargetAtomName(ref
));
683 case ld::Fixup::kindNoneGroupSubordinate
:
684 printf("group subordinate %s", referenceTargetAtomName(ref
));
686 case ld::Fixup::kindNoneGroupSubordinateFDE
:
687 printf("group subordinate FDE %s", referenceTargetAtomName(ref
));
689 case ld::Fixup::kindNoneGroupSubordinateLSDA
:
690 printf("group subordinate LSDA %s", referenceTargetAtomName(ref
));
692 case ld::Fixup::kindNoneGroupSubordinatePersonality
:
693 printf("group subordinate personality %s", referenceTargetAtomName(ref
));
695 case ld::Fixup::kindSetTargetAddress
:
696 printf("%s", referenceTargetAtomName(ref
));
698 case ld::Fixup::kindSubtractTargetAddress
:
699 printf(" - %s", referenceTargetAtomName(ref
));
701 case ld::Fixup::kindAddAddend
:
702 printf(" + 0x%llX", ref
->u
.addend
);
704 case ld::Fixup::kindSubtractAddend
:
705 printf(" - 0x%llX", ref
->u
.addend
);
707 case ld::Fixup::kindSetTargetImageOffset
:
708 printf("imageOffset(%s)", referenceTargetAtomName(ref
));
710 case ld::Fixup::kindSetTargetSectionOffset
:
711 printf("sectionOffset(%s)", referenceTargetAtomName(ref
));
713 case ld::Fixup::kindStore8
:
714 printf(", then store byte");
716 case ld::Fixup::kindStoreLittleEndian16
:
717 printf(", then store 16-bit little endian");
719 case ld::Fixup::kindStoreLittleEndianLow24of32
:
720 printf(", then store low 24-bit little endian");
722 case ld::Fixup::kindStoreLittleEndian32
:
723 printf(", then store 32-bit little endian");
725 case ld::Fixup::kindStoreLittleEndian64
:
726 printf(", then store 64-bit little endian");
728 case ld::Fixup::kindStoreBigEndian16
:
729 printf(", then store 16-bit big endian");
731 case ld::Fixup::kindStoreBigEndianLow24of32
:
732 printf(", then store low 24-bit big endian");
734 case ld::Fixup::kindStoreBigEndian32
:
735 printf(", then store 32-bit big endian");
737 case ld::Fixup::kindStoreBigEndian64
:
738 printf(", then store 64-bit big endian");
740 case ld::Fixup::kindStorePPCBranch24
:
741 printf(", then store as PPC branch24");
743 case ld::Fixup::kindStorePPCBranch14
:
744 printf(", then store as PPC branch14");
746 case ld::Fixup::kindStorePPCPicLow14
:
747 printf(", then store as PPC low14 pic");
749 case ld::Fixup::kindStorePPCPicLow16
:
750 printf(", then store as PPC low14 pic");
752 case ld::Fixup::kindStorePPCPicHigh16AddLow
:
753 printf(", then store as PPC high16 pic");
755 case ld::Fixup::kindStorePPCAbsLow14
:
756 printf(", then store as PPC low14 abs");
758 case ld::Fixup::kindStorePPCAbsLow16
:
759 printf(", then store as PPC low14 abs");
761 case ld::Fixup::kindStorePPCAbsHigh16AddLow
:
762 printf(", then store as PPC high16 abs");
764 case ld::Fixup::kindStorePPCAbsHigh16
:
765 printf(", then store as PPC high16 abs, no carry");
767 case ld::Fixup::kindStoreX86BranchPCRel8
:
768 printf(", then store as x86 8-bit pcrel branch");
770 case ld::Fixup::kindStoreX86BranchPCRel32
:
771 printf(", then store as x86 32-bit pcrel branch");
773 case ld::Fixup::kindStoreX86PCRel8
:
774 printf(", then store as x86 8-bit pcrel");
776 case ld::Fixup::kindStoreX86PCRel16
:
777 printf(", then store as x86 16-bit pcrel");
779 case ld::Fixup::kindStoreX86PCRel32
:
780 printf(", then store as x86 32-bit pcrel");
782 case ld::Fixup::kindStoreX86PCRel32_1
:
783 printf(", then store as x86 32-bit pcrel from +1");
785 case ld::Fixup::kindStoreX86PCRel32_2
:
786 printf(", then store as x86 32-bit pcrel from +2");
788 case ld::Fixup::kindStoreX86PCRel32_4
:
789 printf(", then store as x86 32-bit pcrel from +4");
791 case ld::Fixup::kindStoreX86PCRel32GOTLoad
:
792 printf(", then store as x86 32-bit pcrel GOT load");
794 case ld::Fixup::kindStoreX86PCRel32GOTLoadNowLEA
:
795 printf(", then store as x86 32-bit pcrel GOT load -> LEA");
797 case ld::Fixup::kindStoreX86PCRel32GOT
:
798 printf(", then store as x86 32-bit pcrel GOT access");
800 case ld::Fixup::kindStoreX86PCRel32TLVLoad
:
801 printf(", then store as x86 32-bit pcrel TLV load");
803 case ld::Fixup::kindStoreX86PCRel32TLVLoadNowLEA
:
804 printf(", then store as x86 32-bit pcrel TLV load");
806 case ld::Fixup::kindStoreX86Abs32TLVLoad
:
807 printf(", then store as x86 32-bit absolute TLV load");
809 case ld::Fixup::kindStoreX86Abs32TLVLoadNowLEA
:
810 printf(", then store as x86 32-bit absolute TLV load -> LEA");
812 case ld::Fixup::kindStoreARMBranch24
:
813 printf(", then store as ARM 24-bit pcrel branch");
815 case ld::Fixup::kindStoreThumbBranch22
:
816 printf(", then store as Thumb 22-bit pcrel branch");
818 case ld::Fixup::kindStoreARMLoad12
:
819 printf(", then store as ARM 12-bit pcrel load");
821 case ld::Fixup::kindStoreARMLow16
:
822 printf(", then store low-16 in ARM movw");
824 case ld::Fixup::kindStoreARMHigh16
:
825 printf(", then store high-16 in ARM movt");
827 case ld::Fixup::kindStoreThumbLow16
:
828 printf(", then store low-16 in Thumb movw");
830 case ld::Fixup::kindStoreThumbHigh16
:
831 printf(", then store high-16 in Thumb movt");
833 case ld::Fixup::kindDtraceExtra
:
834 printf("dtrace static probe extra info");
836 case ld::Fixup::kindStoreX86DtraceCallSiteNop
:
837 printf("x86 dtrace static probe site");
839 case ld::Fixup::kindStoreX86DtraceIsEnableSiteClear
:
840 printf("x86 dtrace static is-enabled site");
842 case ld::Fixup::kindStorePPCDtraceCallSiteNop
:
843 printf("ppc dtrace static probe site");
845 case ld::Fixup::kindStorePPCDtraceIsEnableSiteClear
:
846 printf("ppc dtrace static is-enabled site");
848 case ld::Fixup::kindStoreARMDtraceCallSiteNop
:
849 printf("ARM dtrace static probe site");
851 case ld::Fixup::kindStoreARMDtraceIsEnableSiteClear
:
852 printf("ARM dtrace static is-enabled site");
854 case ld::Fixup::kindStoreThumbDtraceCallSiteNop
:
855 printf("Thumb dtrace static probe site");
857 case ld::Fixup::kindStoreThumbDtraceIsEnableSiteClear
:
858 printf("Thumb dtrace static is-enabled site");
860 case ld::Fixup::kindLazyTarget
:
861 printf("lazy reference to external symbol %s", referenceTargetAtomName(ref
));
863 case ld::Fixup::kindSetLazyOffset
:
864 printf("offset of lazy binding info for %s", referenceTargetAtomName(ref
));
866 case ld::Fixup::kindStoreTargetAddressLittleEndian32
:
867 printf("store 32-bit little endian address of %s", referenceTargetAtomName(ref
));
869 case ld::Fixup::kindStoreTargetAddressLittleEndian64
:
870 printf("store 64-bit little endian address of %s", referenceTargetAtomName(ref
));
872 case ld::Fixup::kindStoreTargetAddressBigEndian32
:
873 printf("store 32-bit big endian address of %s", referenceTargetAtomName(ref
));
875 case ld::Fixup::kindStoreTargetAddressBigEndian64
:
876 printf("store 64-bit big endian address of %s", referenceTargetAtomName(ref
));
878 case ld::Fixup::kindStoreTargetAddressX86PCRel32
:
879 printf("x86 store 32-bit pc-rel address of %s", referenceTargetAtomName(ref
));
881 case ld::Fixup::kindStoreTargetAddressX86BranchPCRel32
:
882 printf("x86 store 32-bit pc-rel branch to %s", referenceTargetAtomName(ref
));
884 case ld::Fixup::kindStoreTargetAddressX86PCRel32GOTLoad
:
885 printf("x86 store 32-bit pc-rel GOT load of %s", referenceTargetAtomName(ref
));
887 case ld::Fixup::kindStoreTargetAddressX86PCRel32GOTLoadNowLEA
:
888 printf("x86 store 32-bit pc-rel lea of %s", referenceTargetAtomName(ref
));
890 case ld::Fixup::kindStoreTargetAddressX86PCRel32TLVLoad
:
891 printf("x86 store 32-bit pc-rel TLV load of %s", referenceTargetAtomName(ref
));
893 case ld::Fixup::kindStoreTargetAddressX86PCRel32TLVLoadNowLEA
:
894 printf("x86 store 32-bit pc-rel TLV lea of %s", referenceTargetAtomName(ref
));
896 case ld::Fixup::kindStoreTargetAddressX86Abs32TLVLoad
:
897 printf("x86 store 32-bit absolute TLV load of %s", referenceTargetAtomName(ref
));
899 case ld::Fixup::kindStoreTargetAddressX86Abs32TLVLoadNowLEA
:
900 printf("x86 store 32-bit absolute TLV lea of %s", referenceTargetAtomName(ref
));
902 case ld::Fixup::kindStoreTargetAddressARMBranch24
:
903 printf("ARM store 24-bit pc-rel branch to %s", referenceTargetAtomName(ref
));
905 case ld::Fixup::kindStoreTargetAddressThumbBranch22
:
906 printf("Thumb store 22-bit pc-rel branch to %s", referenceTargetAtomName(ref
));
908 case ld::Fixup::kindStoreTargetAddressARMLoad12
:
909 printf("ARM store 12-bit pc-rel branch to %s", referenceTargetAtomName(ref
));
911 case ld::Fixup::kindStoreTargetAddressPPCBranch24
:
912 printf("PowerPC store 24-bit pc-rel load of %s", referenceTargetAtomName(ref
));
914 case ld::Fixup::kindSetTargetTLVTemplateOffset
:
915 case ld::Fixup::kindSetTargetTLVTemplateOffsetLittleEndian32
:
916 case ld::Fixup::kindSetTargetTLVTemplateOffsetLittleEndian64
:
917 printf("tlv template offset of %s", referenceTargetAtomName(ref
));
919 // printf("unknown fixup");
924 uint64_t dumper::addressOfFirstAtomInSection(const ld::Section
& sect
)
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() == §
) {
930 if ( atom
->objectAddress() < lowestAddr
)
931 lowestAddr
= atom
->objectAddress();
937 void dumper::doAtom(const ld::Atom
& atom
)
939 if ( (sMatchName
!= NULL
) && (strcmp(sMatchName
, atom
.name()) != 0) )
941 _atoms
.push_back(&atom
);
947 std::sort(_atoms
.begin(), _atoms
.end(), AtomSorter());
949 for (std::vector
<const ld::Atom
*>::iterator it
=_atoms
.begin(); it
!= _atoms
.end(); ++it
) {
950 this->dumpAtom(**it
);
954 void dumper::dumpAtom(const ld::Atom
& atom
)
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
));
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
);
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
);
977 if ( atom
.fixupsBegin() != atom
.fixupsEnd() ) {
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
);
987 case ld::Fixup::k1of2
:
988 printf(" 0x%04X ", it
->offsetInAtom
);
993 case ld::Fixup::k1of3
:
994 printf(" 0x%04X ", it
->offsetInAtom
);
1001 case ld::Fixup::k1of4
:
1002 printf(" 0x%04X ", it
->offsetInAtom
);
1011 case ld::Fixup::k1of5
:
1012 printf(" 0x%04X ", it
->offsetInAtom
);
1024 printf(" BAD CLUSTER SIZE: cluster=%d\n", it
->clusterSize
);
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
);
1041 static void dumpFile(ld::relocatable::File
* file
)
1044 if ( sDumpStabs
&& (file
->debugInfo() == ld::relocatable::File::kDebugInfoStabs
) ) {
1045 const std::vector
<ld::relocatable::File::Stab
>* stabs
= file
->stabs();
1046 if ( stabs
!= NULL
)
1051 file
->forEachAtom(d
);
1056 std::vector
<ObjectFile::Atom
*> atoms
= reader
->getAtoms();
1058 // make copy of vector and sort (so output is canonical)
1059 std::vector
<ObjectFile::Atom
*> sortedAtoms(atoms
);
1061 std::sort(sortedAtoms
.begin(), sortedAtoms
.end(), AtomSorter());
1063 for(std::vector
<ObjectFile::Atom
*>::iterator it
=sortedAtoms
.begin(); it
!= sortedAtoms
.end(); ++it
) {
1065 dumpAtomLikeNM(*it
);
1073 static ld::relocatable::File
* createReader(const char* path
)
1075 struct stat stat_buf
;
1077 int fd
= ::open(path
, O_RDONLY
, 0);
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);
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;
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
;
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
;
1120 ld::relocatable::File
* objResult
= mach_o::relocatable::parse(p
, fileLen
, path
, stat_buf
.st_mtime
, 0, objOpts
);
1121 if ( objResult
!= NULL
)
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
)
1129 throwf("not a mach-o object file: %s", path
);
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
);
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"
1157 int main(int argc
, const char* argv
[])
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;
1171 else if ( strcmp(arg
, "-nm") == 0 ) {
1174 else if ( strcmp(arg
, "-stabs") == 0 ) {
1177 else if ( strcmp(arg
, "-no_sort") == 0 ) {
1180 else if ( strcmp(arg
, "-no_section") == 0 ) {
1181 sShowSection
= false;
1183 else if ( strcmp(arg
, "-no_definition") == 0 ) {
1184 sShowDefinitionKind
= false;
1186 else if ( strcmp(arg
, "-no_combine") == 0 ) {
1187 sShowCombineKind
= false;
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
;
1205 else if ( strcmp(arch
, "armv5") == 0 ) {
1206 sPreferredArch
= CPU_TYPE_ARM
;
1207 sPreferredSubArch
= CPU_SUBTYPE_ARM_V5TEJ
;
1209 else if ( strcmp(arch
, "armv6") == 0 ) {
1210 sPreferredArch
= CPU_TYPE_ARM
;
1211 sPreferredSubArch
= CPU_SUBTYPE_ARM_V6
;
1213 else if ( strcmp(arch
, "armv7") == 0 ) {
1214 sPreferredArch
= CPU_TYPE_ARM
;
1215 sPreferredSubArch
= CPU_SUBTYPE_ARM_V7
;
1218 throwf("unknown architecture %s", arch
);
1220 else if ( strcmp(arg
, "-only") == 0 ) {
1221 sMatchName
= ++i
<argc
? argv
[i
]: NULL
;
1223 else if ( strcmp(arg
, "-align") == 0 ) {
1224 sPrintRestrict
= true;
1227 else if ( strcmp(arg
, "-name") == 0 ) {
1228 sPrintRestrict
= true;
1233 throwf("unknown option: %s\n", arg
);
1237 ld::relocatable::File
* reader
= createReader(arg
);
1242 catch (const char* msg
) {
1243 fprintf(stderr
, "ObjDump failed: %s\n", msg
);