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;
45 static bool sShowLineInfo
= true;
47 static cpu_type_t sPreferredArch
= 0xFFFFFFFF;
48 static cpu_subtype_t sPreferredSubArch
= 0xFFFFFFFF;
49 static const char* sMatchName
= NULL
;
50 static int sPrintRestrict
;
51 static int sPrintAlign
;
52 static int sPrintName
;
54 __attribute__((noreturn
))
55 void throwf(const char* format
, ...)
59 va_start(list
, format
);
60 vasprintf(&p
, format
, list
);
67 void warning(const char* format
, ...)
70 fprintf(stderr
, "warning: ");
71 va_start(list
, format
);
72 vfprintf(stderr
, format
, list
);
74 fprintf(stderr
, "\n");
77 static void dumpStabs(const std::vector
<ld::relocatable::File::Stab
>* stabs
)
80 printf("stabs: (%lu)\n", stabs
->size());
81 for (std::vector
<ld::relocatable::File::Stab
>::const_iterator it
= stabs
->begin(); it
!= stabs
->end(); ++it
) {
82 const ld::relocatable::File::Stab
& stab
= *it
;
83 const char* code
= "?????";
170 printf(" [atom=%20s] %02X %04X %s %s\n", ((stab
.atom
!= NULL
) ? stab
.atom
->name() : ""), stab
.other
, stab
.desc
, code
, stab
.string
);
175 static void dumpAtomLikeNM(ld::Atom
* atom
)
177 uint32_t size
= atom
->size();
179 const char* visibility
;
180 switch ( atom
->scope() ) {
181 case ld::Atom::scopeTranslationUnit
:
182 visibility
= "internal";
184 case ld::Atom::scopeLinkageUnit
:
185 visibility
= "hidden ";
187 case ld::Atom::scopeGlobal
:
188 visibility
= "global ";
196 switch ( atom
->definitionKind() ) {
197 case ld::Atom::kRegularDefinition
:
200 case ld::Atom::kTentativeDefinition
:
203 case ld::Atom::kWeakDefinition
:
206 case ld::Atom::kAbsoluteSymbol
:
214 printf("0x%08X %s %s %s\n", size
, visibility
, kind
, atom
->name());
218 static void dumpAtom(ld::Atom
* atom
)
220 if(sMatchName
&& strcmp(sMatchName
, atom
->name()))
223 //printf("atom: %p\n", atom);
226 if(!sPrintRestrict
|| sPrintName
)
227 printf("name: %s\n", atom
->name());
231 switch ( atom
->scope() ) {
232 case ld::Atom::scopeTranslationUnit
:
233 printf("scope: translation unit\n");
235 case ld::Atom::scopeLinkageUnit
:
236 printf("scope: linkage unit\n");
238 case ld::Atom::scopeGlobal
:
239 printf("scope: global\n");
242 printf("scope: unknown\n");
247 switch ( atom
->definitionKind() ) {
248 case ld::Atom::kRegularDefinition
:
249 printf("kind: regular\n");
251 case ld::Atom::kWeakDefinition
:
252 printf("kind: weak\n");
254 case ld::Atom::kTentativeDefinition
:
255 printf("kind: tentative\n");
257 case ld::Atom::kExternalDefinition
:
258 printf("kind: import\n");
260 case ld::Atom::kExternalWeakDefinition
:
261 printf("kind: weak import\n");
263 case ld::Atom::kAbsoluteSymbol
:
264 printf("kind: absolute symbol\n");
267 printf("kind: unknown\n");
270 // segment and section
271 if(!sPrintRestrict
&& (atom
->section().sectionName() != NULL
) )
272 printf("section: %s,%s\n", atom
->section().segmentName(), atom
->section().sectionName());
275 if(!sPrintRestrict
) {
277 if ( atom
->dontDeadStrip() )
278 printf("dont-dead-strip ");
279 if ( atom
->isThumb() )
286 printf("size: 0x%012llX\n", atom
->size());
289 if(!sPrintRestrict
|| sPrintAlign
)
290 printf("align: %u mod %u\n", atom
->alignment().modulus
, (1 << atom
->alignment().powerOf2
) );
293 if (!sPrintRestrict
&& sDumpContent
) {
294 uint64_t size
= atom
->size();
296 uint8_t content
[size
];
297 atom
->copyRawContent(content
);
299 if ( atom
->contentType() == ld::Atom::typeCString
) {
301 for (unsigned int i
=0; i
< size
; ++i
) {
302 if(content
[i
]<'!' || content
[i
]>=127)
303 printf("\\%o", content
[i
]);
305 printf("%c", content
[i
]);
310 for (unsigned int i
=0; i
< size
; ++i
)
311 printf("%02X ", content
[i
]);
318 if(!sPrintRestrict
) {
319 if ( atom
->beginUnwind() != atom
->endUnwind() ) {
320 printf("unwind encodings:\n");
321 for (ld::Atom::UnwindInfo::iterator it
= atom
->beginUnwind(); it
!= atom
->endUnwind(); ++it
) {
322 printf("\t 0x%04X 0x%08X\n", it
->startOffset
, it
->unwindInfo
);
328 if(!sPrintRestrict
) {
329 std::vector
<ObjectFile::Reference
*>& references
= atom
->getReferences();
330 const int refCount
= references
.size();
331 printf("references: (%u)\n", refCount
);
332 for (int i
=0; i
< refCount
; ++i
) {
333 ObjectFile::Reference
* ref
= references
[i
];
334 printf(" %s\n", ref
->getDescription());
339 if(!sPrintRestrict
) {
340 if ( atom
->beginLineInfo() != atom
->endLineInfo() ) {
341 printf("line info:\n");
342 for (ld::Atom::LineInfo::iterator it
= atom
->beginLineInfo(); it
!= atom
->endLineInfo(); ++it
) {
343 printf(" offset 0x%04X, line %d, file %s\n", it
->atomOffset
, it
->lineNumber
, it
->fileName
);
354 bool operator()(const ld::Atom
* left
, const ld::Atom
* right
)
358 // first sort by segment name
359 int diff
= strcmp(left
->section().segmentName(), right
->section().segmentName());
363 // then sort by section name
364 diff
= strcmp(left
->section().sectionName(), right
->section().sectionName());
368 // then sort by atom name
369 diff
= strcmp(left
->name(), right
->name());
373 // if cstring, sort by content
374 if ( left
->contentType() == ld::Atom::typeCString
) {
375 diff
= strcmp((char*)left
->rawContentPointer(), (char*)right
->rawContentPointer());
379 else if ( left
->section().type() == ld::Section::typeCStringPointer
) {
380 // if pointer to c-string sort by name
381 const char* leftString
= NULL
;
382 assert(left
->fixupsBegin() != left
->fixupsEnd());
383 for (ld::Fixup::iterator fit
= left
->fixupsBegin(); fit
!= left
->fixupsEnd(); ++fit
) {
384 if ( fit
->binding
== ld::Fixup::bindingByContentBound
) {
385 const ld::Atom
* cstringAtom
= fit
->u
.target
;
386 assert(cstringAtom
->contentType() == ld::Atom::typeCString
);
387 leftString
= (char*)cstringAtom
->rawContentPointer();
390 const char* rightString
= NULL
;
391 assert(right
->fixupsBegin() != right
->fixupsEnd());
392 for (ld::Fixup::iterator fit
= right
->fixupsBegin(); fit
!= right
->fixupsEnd(); ++fit
) {
393 if ( fit
->binding
== ld::Fixup::bindingByContentBound
) {
394 const ld::Atom
* cstringAtom
= fit
->u
.target
;
395 assert(cstringAtom
->contentType() == ld::Atom::typeCString
);
396 rightString
= (char*)cstringAtom
->rawContentPointer();
399 assert(leftString
!= NULL
);
400 assert(rightString
!= NULL
);
401 diff
= strcmp(leftString
, rightString
);
405 else if ( left
->section().type() == ld::Section::typeLiteral4
) {
406 // if literal sort by content
407 uint32_t leftValue
= *(uint32_t*)left
->rawContentPointer();
408 uint32_t rightValue
= *(uint32_t*)right
->rawContentPointer();
409 diff
= (leftValue
- rightValue
);
413 else if ( left
->section().type() == ld::Section::typeCFI
) {
414 // if __he_frame sort by address
415 diff
= (left
->objectAddress() - right
->objectAddress());
419 else if ( left
->section().type() == ld::Section::typeNonLazyPointer
) {
420 // if non-lazy-pointer sort by name
421 const char* leftString
= NULL
;
422 assert(left
->fixupsBegin() != left
->fixupsEnd());
423 for (ld::Fixup::iterator fit
= left
->fixupsBegin(); fit
!= left
->fixupsEnd(); ++fit
) {
424 if ( fit
->binding
== ld::Fixup::bindingByNameUnbound
) {
425 leftString
= fit
->u
.name
;
427 else if ( fit
->binding
== ld::Fixup::bindingDirectlyBound
) {
428 leftString
= fit
->u
.target
->name();
431 const char* rightString
= NULL
;
432 assert(right
->fixupsBegin() != right
->fixupsEnd());
433 for (ld::Fixup::iterator fit
= right
->fixupsBegin(); fit
!= right
->fixupsEnd(); ++fit
) {
434 if ( fit
->binding
== ld::Fixup::bindingByNameUnbound
) {
435 rightString
= fit
->u
.name
;
437 else if ( fit
->binding
== ld::Fixup::bindingDirectlyBound
) {
438 rightString
= fit
->u
.target
->name();
441 assert(leftString
!= NULL
);
442 assert(rightString
!= NULL
);
443 diff
= strcmp(leftString
, rightString
);
449 return (left
->size() < right
->size());
454 class dumper
: public ld::File::AtomHandler
458 virtual void doAtom(const ld::Atom
&);
459 virtual void doFile(const ld::File
&) {}
461 void dumpAtom(const ld::Atom
& atom
);
462 const char* scopeString(const ld::Atom
&);
463 const char* definitionString(const ld::Atom
&);
464 const char* combineString(const ld::Atom
&);
465 const char* inclusionString(const ld::Atom
&);
466 const char* attributeString(const ld::Atom
&);
467 const char* makeName(const ld::Atom
& atom
);
468 const char* referenceTargetAtomName(const ld::Fixup
* ref
);
469 void dumpFixup(const ld::Fixup
* ref
);
471 uint64_t addressOfFirstAtomInSection(const ld::Section
&);
473 std::vector
<const ld::Atom
*> _atoms
;
476 const char* dumper::scopeString(const ld::Atom
& atom
)
478 switch ( (ld::Atom::Scope
)atom
.scope() ) {
479 case ld::Atom::scopeTranslationUnit
:
480 return "translation-unit";
481 case ld::Atom::scopeLinkageUnit
:
483 case ld::Atom::scopeGlobal
:
484 if ( atom
.autoHide() )
485 return "global but automatically hidden";
492 const char* dumper::definitionString(const ld::Atom
& atom
)
494 switch ( (ld::Atom::Definition
)atom
.definition() ) {
495 case ld::Atom::definitionRegular
:
497 case ld::Atom::definitionTentative
:
499 case ld::Atom::definitionAbsolute
:
501 case ld::Atom::definitionProxy
:
507 const char* dumper::combineString(const ld::Atom
& atom
)
509 switch ( (ld::Atom::Combine
)atom
.combine() ) {
510 case ld::Atom::combineNever
:
512 case ld::Atom::combineByName
:
514 case ld::Atom::combineByNameAndContent
:
515 return "by-name-and-content";
516 case ld::Atom::combineByNameAndReferences
:
517 return "by-name-and-references";
522 const char* dumper::inclusionString(const ld::Atom
& atom
)
524 switch ( (ld::Atom::SymbolTableInclusion
)atom
.symbolTableInclusion() ) {
525 case ld::Atom::symbolTableNotIn
:
527 case ld::Atom::symbolTableNotInFinalLinkedImages
:
528 return "not in final linked images";
529 case ld::Atom::symbolTableIn
:
531 case ld::Atom::symbolTableInAndNeverStrip
:
532 return "in and never strip";
533 case ld::Atom::symbolTableInAsAbsolute
:
534 return "in as absolute";
535 case ld::Atom::symbolTableInWithRandomAutoStripLabel
:
536 return "in as random auto-strip label";
543 const char* dumper::attributeString(const ld::Atom
& atom
)
545 static char buffer
[256];
548 if ( atom
.dontDeadStrip() )
549 strcat(buffer
, "dont-dead-strip ");
551 if ( atom
.isThumb() )
552 strcat(buffer
, "thumb ");
554 if ( atom
.isAlias() )
555 strcat(buffer
, "alias ");
557 if ( atom
.contentType() == ld::Atom::typeResolver
)
558 strcat(buffer
, "resolver ");
563 const char* dumper::makeName(const ld::Atom
& atom
)
565 static char buffer
[4096];
566 strcpy(buffer
, "???");
567 switch ( atom
.symbolTableInclusion() ) {
568 case ld::Atom::symbolTableNotIn
:
569 if ( atom
.contentType() == ld::Atom::typeCString
) {
570 strcpy(buffer
, "cstring=");
571 strlcat(buffer
, (char*)atom
.rawContentPointer(), 4096);
573 else if ( atom
.section().type() == ld::Section::typeLiteral4
) {
575 strcpy(buffer
, "literal4=");
576 uint32_t value
= *(uint32_t*)atom
.rawContentPointer();
577 sprintf(temp
, "0x%08X", value
);
578 strcat(buffer
, temp
);
580 else if ( atom
.section().type() == ld::Section::typeLiteral8
) {
582 strcpy(buffer
, "literal8=");
583 uint32_t value1
= *(uint32_t*)atom
.rawContentPointer();
584 uint32_t value2
= ((uint32_t*)atom
.rawContentPointer())[1];
585 sprintf(temp
, "0x%08X%08X", value1
, value2
);
586 strcat(buffer
, temp
);
588 else if ( atom
.section().type() == ld::Section::typeLiteral16
) {
590 strcpy(buffer
, "literal16=");
591 uint32_t value1
= *(uint32_t*)atom
.rawContentPointer();
592 uint32_t value2
= ((uint32_t*)atom
.rawContentPointer())[1];
593 uint32_t value3
= ((uint32_t*)atom
.rawContentPointer())[2];
594 uint32_t value4
= ((uint32_t*)atom
.rawContentPointer())[3];
595 sprintf(temp
, "0x%08X%08X%08X%08X", value1
, value2
, value3
, value4
);
596 strcat(buffer
, temp
);
598 else if ( atom
.section().type() == ld::Section::typeCStringPointer
) {
599 assert(atom
.fixupsBegin() != atom
.fixupsEnd());
600 for (ld::Fixup::iterator fit
= atom
.fixupsBegin(); fit
!= atom
.fixupsEnd(); ++fit
) {
601 if ( fit
->binding
== ld::Fixup::bindingByContentBound
) {
602 const ld::Atom
* cstringAtom
= fit
->u
.target
;
603 if ( (cstringAtom
!= NULL
) && (cstringAtom
->contentType() == ld::Atom::typeCString
) ) {
604 strlcpy(buffer
, atom
.name(), 4096);
605 strlcat(buffer
, "=", 4096);
606 strlcat(buffer
, (char*)cstringAtom
->rawContentPointer(), 4096);
611 else if ( atom
.section().type() == ld::Section::typeNonLazyPointer
) {
612 assert(atom
.fixupsBegin() != atom
.fixupsEnd());
613 for (ld::Fixup::iterator fit
= atom
.fixupsBegin(); fit
!= atom
.fixupsEnd(); ++fit
) {
614 if ( fit
->binding
== ld::Fixup::bindingByNameUnbound
) {
615 strcpy(buffer
, "non-lazy-pointer-to:");
616 strlcat(buffer
, fit
->u
.name
, 4096);
619 else if ( fit
->binding
== ld::Fixup::bindingDirectlyBound
) {
620 strcpy(buffer
, "non-lazy-pointer-to-local:");
621 strlcat(buffer
, fit
->u
.target
->name(), 4096);
625 strlcpy(buffer
, atom
.name(), 4096);
628 uint64_t sectAddr
= addressOfFirstAtomInSection(atom
.section());
629 sprintf(buffer
, "%s@%s+0x%08llX", atom
.name(), atom
.section().sectionName(), atom
.objectAddress()-sectAddr
);
632 case ld::Atom::symbolTableNotInFinalLinkedImages
:
633 case ld::Atom::symbolTableIn
:
634 case ld::Atom::symbolTableInAndNeverStrip
:
635 case ld::Atom::symbolTableInAsAbsolute
:
636 case ld::Atom::symbolTableInWithRandomAutoStripLabel
:
637 strlcpy(buffer
, atom
.name(), 4096);
643 const char* dumper::referenceTargetAtomName(const ld::Fixup
* ref
)
645 static char buffer
[4096];
646 switch ( ref
->binding
) {
647 case ld::Fixup::bindingNone
:
649 case ld::Fixup::bindingByNameUnbound
:
650 strcpy(buffer
, "by-name(");
651 strlcat(buffer
, ref
->u
.name
, 4096);
652 strlcat(buffer
, ")", 4096);
654 //return ref->u.name;
655 case ld::Fixup::bindingByContentBound
:
656 strcpy(buffer
, "by-content(");
657 strlcat(buffer
, makeName(*ref
->u
.target
), 4096);
658 strlcat(buffer
, ")", 4096);
660 case ld::Fixup::bindingDirectlyBound
:
661 strcpy(buffer
, "direct(");
662 strlcat(buffer
, makeName(*ref
->u
.target
), 4096);
663 strlcat(buffer
, ")", 4096);
665 case ld::Fixup::bindingsIndirectlyBound
:
666 return "BOUND INDIRECTLY";
668 return "BAD BINDING";
672 void dumper::dumpFixup(const ld::Fixup
* ref
)
674 if ( ref
->weakImport
) {
675 printf("weak_import ");
677 switch ( (ld::Fixup::Kind
)(ref
->kind
) ) {
678 case ld::Fixup::kindNone
:
681 case ld::Fixup::kindNoneFollowOn
:
682 printf("followed by %s", referenceTargetAtomName(ref
));
684 case ld::Fixup::kindNoneGroupSubordinate
:
685 printf("group subordinate %s", referenceTargetAtomName(ref
));
687 case ld::Fixup::kindNoneGroupSubordinateFDE
:
688 printf("group subordinate FDE %s", referenceTargetAtomName(ref
));
690 case ld::Fixup::kindNoneGroupSubordinateLSDA
:
691 printf("group subordinate LSDA %s", referenceTargetAtomName(ref
));
693 case ld::Fixup::kindNoneGroupSubordinatePersonality
:
694 printf("group subordinate personality %s", referenceTargetAtomName(ref
));
696 case ld::Fixup::kindSetTargetAddress
:
697 printf("%s", referenceTargetAtomName(ref
));
699 case ld::Fixup::kindSubtractTargetAddress
:
700 printf(" - %s", referenceTargetAtomName(ref
));
702 case ld::Fixup::kindAddAddend
:
703 printf(" + 0x%llX", ref
->u
.addend
);
705 case ld::Fixup::kindSubtractAddend
:
706 printf(" - 0x%llX", ref
->u
.addend
);
708 case ld::Fixup::kindSetTargetImageOffset
:
709 printf("imageOffset(%s)", referenceTargetAtomName(ref
));
711 case ld::Fixup::kindSetTargetSectionOffset
:
712 printf("sectionOffset(%s)", referenceTargetAtomName(ref
));
714 case ld::Fixup::kindStore8
:
715 printf(", then store byte");
717 case ld::Fixup::kindStoreLittleEndian16
:
718 printf(", then store 16-bit little endian");
720 case ld::Fixup::kindStoreLittleEndianLow24of32
:
721 printf(", then store low 24-bit little endian");
723 case ld::Fixup::kindStoreLittleEndian32
:
724 printf(", then store 32-bit little endian");
726 case ld::Fixup::kindStoreLittleEndian64
:
727 printf(", then store 64-bit little endian");
729 case ld::Fixup::kindStoreBigEndian16
:
730 printf(", then store 16-bit big endian");
732 case ld::Fixup::kindStoreBigEndianLow24of32
:
733 printf(", then store low 24-bit big endian");
735 case ld::Fixup::kindStoreBigEndian32
:
736 printf(", then store 32-bit big endian");
738 case ld::Fixup::kindStoreBigEndian64
:
739 printf(", then store 64-bit big endian");
741 case ld::Fixup::kindStoreX86BranchPCRel8
:
742 printf(", then store as x86 8-bit pcrel branch");
744 case ld::Fixup::kindStoreX86BranchPCRel32
:
745 printf(", then store as x86 32-bit pcrel branch");
747 case ld::Fixup::kindStoreX86PCRel8
:
748 printf(", then store as x86 8-bit pcrel");
750 case ld::Fixup::kindStoreX86PCRel16
:
751 printf(", then store as x86 16-bit pcrel");
753 case ld::Fixup::kindStoreX86PCRel32
:
754 printf(", then store as x86 32-bit pcrel");
756 case ld::Fixup::kindStoreX86PCRel32_1
:
757 printf(", then store as x86 32-bit pcrel from +1");
759 case ld::Fixup::kindStoreX86PCRel32_2
:
760 printf(", then store as x86 32-bit pcrel from +2");
762 case ld::Fixup::kindStoreX86PCRel32_4
:
763 printf(", then store as x86 32-bit pcrel from +4");
765 case ld::Fixup::kindStoreX86PCRel32GOTLoad
:
766 printf(", then store as x86 32-bit pcrel GOT load");
768 case ld::Fixup::kindStoreX86PCRel32GOTLoadNowLEA
:
769 printf(", then store as x86 32-bit pcrel GOT load -> LEA");
771 case ld::Fixup::kindStoreX86PCRel32GOT
:
772 printf(", then store as x86 32-bit pcrel GOT access");
774 case ld::Fixup::kindStoreX86PCRel32TLVLoad
:
775 printf(", then store as x86 32-bit pcrel TLV load");
777 case ld::Fixup::kindStoreX86PCRel32TLVLoadNowLEA
:
778 printf(", then store as x86 32-bit pcrel TLV load");
780 case ld::Fixup::kindStoreX86Abs32TLVLoad
:
781 printf(", then store as x86 32-bit absolute TLV load");
783 case ld::Fixup::kindStoreX86Abs32TLVLoadNowLEA
:
784 printf(", then store as x86 32-bit absolute TLV load -> LEA");
786 case ld::Fixup::kindStoreARMBranch24
:
787 printf(", then store as ARM 24-bit pcrel branch");
789 case ld::Fixup::kindStoreThumbBranch22
:
790 printf(", then store as Thumb 22-bit pcrel branch");
792 case ld::Fixup::kindStoreARMLoad12
:
793 printf(", then store as ARM 12-bit pcrel load");
795 case ld::Fixup::kindStoreARMLow16
:
796 printf(", then store low-16 in ARM movw");
798 case ld::Fixup::kindStoreARMHigh16
:
799 printf(", then store high-16 in ARM movt");
801 case ld::Fixup::kindStoreThumbLow16
:
802 printf(", then store low-16 in Thumb movw");
804 case ld::Fixup::kindStoreThumbHigh16
:
805 printf(", then store high-16 in Thumb movt");
807 case ld::Fixup::kindStoreARM64Branch26
:
808 printf(", then store as ARM64 26-bit pcrel branch");
810 case ld::Fixup::kindStoreARM64Page21
:
811 printf(", then store as ARM64 21-bit pcrel ADRP");
813 case ld::Fixup::kindStoreARM64PageOff12
:
814 printf(", then store as ARM64 12-bit offset");
816 case ld::Fixup::kindStoreARM64GOTLoadPage21
:
817 printf(", then store as ARM64 21-bit pcrel ADRP of GOT");
819 case ld::Fixup::kindStoreARM64GOTLoadPageOff12
:
820 printf(", then store as ARM64 12-bit page offset of GOT");
822 case ld::Fixup::kindStoreARM64GOTLeaPage21
:
823 printf(", then store as ARM64 21-bit pcrel ADRP of GOT lea");
825 case ld::Fixup::kindStoreARM64GOTLeaPageOff12
:
826 printf(", then store as ARM64 12-bit page offset of GOT lea");
828 case ld::Fixup::kindStoreARM64TLVPLoadPage21
:
829 printf(", then store as ARM64 21-bit pcrel ADRP of TLVP");
831 case ld::Fixup::kindStoreARM64TLVPLoadPageOff12
:
832 printf(", then store as ARM64 12-bit page offset of TLVP");
834 case ld::Fixup::kindStoreARM64TLVPLoadNowLeaPage21
:
835 printf(", then store as ARM64 21-bit pcrel ADRP of lea of TLVP");
837 case ld::Fixup::kindStoreARM64TLVPLoadNowLeaPageOff12
:
838 printf(", then store as ARM64 12-bit page offset of lea of TLVP");
840 case ld::Fixup::kindStoreARM64PointerToGOT
:
841 printf(", then store as 64-bit pointer to GOT entry");
843 case ld::Fixup::kindStoreARM64PCRelToGOT
:
844 printf(", then store as 32-bit delta to GOT entry");
846 case ld::Fixup::kindDtraceExtra
:
847 printf("dtrace static probe extra info");
849 case ld::Fixup::kindStoreX86DtraceCallSiteNop
:
850 printf("x86 dtrace static probe site");
852 case ld::Fixup::kindStoreX86DtraceIsEnableSiteClear
:
853 printf("x86 dtrace static is-enabled site");
855 case ld::Fixup::kindStoreARMDtraceCallSiteNop
:
856 printf("ARM dtrace static probe site");
858 case ld::Fixup::kindStoreARMDtraceIsEnableSiteClear
:
859 printf("ARM dtrace static is-enabled site");
861 case ld::Fixup::kindStoreThumbDtraceCallSiteNop
:
862 printf("Thumb dtrace static probe site");
864 case ld::Fixup::kindStoreThumbDtraceIsEnableSiteClear
:
865 printf("Thumb dtrace static is-enabled site");
867 case ld::Fixup::kindStoreARM64DtraceCallSiteNop
:
868 printf("ARM64 dtrace static probe site");
870 case ld::Fixup::kindStoreARM64DtraceIsEnableSiteClear
:
871 printf("ARM64 dtrace static is-enabled site");
873 case ld::Fixup::kindLazyTarget
:
874 printf("lazy reference to external symbol %s", referenceTargetAtomName(ref
));
876 case ld::Fixup::kindSetLazyOffset
:
877 printf("offset of lazy binding info for %s", referenceTargetAtomName(ref
));
879 case ld::Fixup::kindIslandTarget
:
880 printf("ultimate target of island %s", referenceTargetAtomName(ref
));
882 case ld::Fixup::kindDataInCodeStartData
:
883 printf("start of data in code");
885 case ld::Fixup::kindDataInCodeStartJT8
:
886 printf("start of jump table 8 data in code");
888 case ld::Fixup::kindDataInCodeStartJT16
:
889 printf("start of jump table 16 data in code");
891 case ld::Fixup::kindDataInCodeStartJT32
:
892 printf("start of jump table 32 data in code");
894 case ld::Fixup::kindDataInCodeStartJTA32
:
895 printf("start of jump table absolute 32 data in code");
897 case ld::Fixup::kindDataInCodeEnd
:
898 printf("end of data in code");
900 case ld::Fixup::kindLinkerOptimizationHint
:
901 #if SUPPORT_ARCH_arm64
902 ld::Fixup::LOH_arm64 extra
;
903 extra
.addend
= ref
->u
.addend
;
904 printf("ARM64 hint: ");
905 switch(extra
.info
.kind
) {
906 case LOH_ARM64_ADRP_ADRP
:
909 case LOH_ARM64_ADRP_LDR
:
912 case LOH_ARM64_ADRP_ADD_LDR
:
913 printf("ADRP-ADD-LDR");
915 case LOH_ARM64_ADRP_LDR_GOT_LDR
:
916 printf("ADRP-LDR-GOT-LDR");
918 case LOH_ARM64_ADRP_ADD_STR
:
919 printf("ADRP-ADD-STR");
921 case LOH_ARM64_ADRP_LDR_GOT_STR
:
922 printf("ADRP-LDR-GOT-STR");
924 case LOH_ARM64_ADRP_ADD
:
928 printf("kind=%d", extra
.info
.kind
);
931 printf(", offset1=0x%X", (extra
.info
.delta1
<< 2) + ref
->offsetInAtom
);
932 if ( extra
.info
.count
> 0 )
933 printf(", offset2=0x%X", (extra
.info
.delta2
<< 2) + ref
->offsetInAtom
);
934 if ( extra
.info
.count
> 1 )
935 printf(", offset3=0x%X", (extra
.info
.delta3
<< 2) + ref
->offsetInAtom
);
936 if ( extra
.info
.count
> 2 )
937 printf(", offset4=0x%X", (extra
.info
.delta4
<< 2) + ref
->offsetInAtom
);
940 case ld::Fixup::kindStoreTargetAddressLittleEndian32
:
941 printf("store 32-bit little endian address of %s", referenceTargetAtomName(ref
));
943 case ld::Fixup::kindStoreTargetAddressLittleEndian64
:
944 printf("store 64-bit little endian address of %s", referenceTargetAtomName(ref
));
946 case ld::Fixup::kindStoreTargetAddressBigEndian32
:
947 printf("store 32-bit big endian address of %s", referenceTargetAtomName(ref
));
949 case ld::Fixup::kindStoreTargetAddressBigEndian64
:
950 printf("store 64-bit big endian address of %s", referenceTargetAtomName(ref
));
952 case ld::Fixup::kindStoreTargetAddressX86PCRel32
:
953 printf("x86 store 32-bit pc-rel address of %s", referenceTargetAtomName(ref
));
955 case ld::Fixup::kindStoreTargetAddressX86BranchPCRel32
:
956 printf("x86 store 32-bit pc-rel branch to %s", referenceTargetAtomName(ref
));
958 case ld::Fixup::kindStoreTargetAddressX86PCRel32GOTLoad
:
959 printf("x86 store 32-bit pc-rel GOT load of %s", referenceTargetAtomName(ref
));
961 case ld::Fixup::kindStoreTargetAddressX86PCRel32GOTLoadNowLEA
:
962 printf("x86 store 32-bit pc-rel lea of %s", referenceTargetAtomName(ref
));
964 case ld::Fixup::kindStoreTargetAddressX86PCRel32TLVLoad
:
965 printf("x86 store 32-bit pc-rel TLV load of %s", referenceTargetAtomName(ref
));
967 case ld::Fixup::kindStoreTargetAddressX86PCRel32TLVLoadNowLEA
:
968 printf("x86 store 32-bit pc-rel TLV lea of %s", referenceTargetAtomName(ref
));
970 case ld::Fixup::kindStoreTargetAddressX86Abs32TLVLoad
:
971 printf("x86 store 32-bit absolute TLV load of %s", referenceTargetAtomName(ref
));
973 case ld::Fixup::kindStoreTargetAddressX86Abs32TLVLoadNowLEA
:
974 printf("x86 store 32-bit absolute TLV lea of %s", referenceTargetAtomName(ref
));
976 case ld::Fixup::kindStoreTargetAddressARMBranch24
:
977 printf("ARM store 24-bit pc-rel branch to %s", referenceTargetAtomName(ref
));
979 case ld::Fixup::kindStoreTargetAddressThumbBranch22
:
980 printf("Thumb store 22-bit pc-rel branch to %s", referenceTargetAtomName(ref
));
982 case ld::Fixup::kindStoreTargetAddressARMLoad12
:
983 printf("ARM store 12-bit pc-rel branch to %s", referenceTargetAtomName(ref
));
985 case ld::Fixup::kindSetTargetTLVTemplateOffset
:
986 case ld::Fixup::kindSetTargetTLVTemplateOffsetLittleEndian32
:
987 case ld::Fixup::kindSetTargetTLVTemplateOffsetLittleEndian64
:
988 printf("tlv template offset of %s", referenceTargetAtomName(ref
));
990 case ld::Fixup::kindStoreTargetAddressARM64Branch26
:
991 printf("ARM64 store 26-bit pcrel branch to %s", referenceTargetAtomName(ref
));
993 case ld::Fixup::kindStoreTargetAddressARM64Page21
:
994 printf("ARM64 store 21-bit pcrel ADRP to %s", referenceTargetAtomName(ref
));
996 case ld::Fixup::kindStoreTargetAddressARM64PageOff12
:
997 printf("ARM64 store 12-bit page offset of %s", referenceTargetAtomName(ref
));
999 case ld::Fixup::kindStoreTargetAddressARM64GOTLoadPage21
:
1000 printf("ARM64 store 21-bit pcrel ADRP to GOT for %s", referenceTargetAtomName(ref
));
1002 case ld::Fixup::kindStoreTargetAddressARM64GOTLoadPageOff12
:
1003 printf("ARM64 store 12-bit page offset of GOT of %s", referenceTargetAtomName(ref
));
1005 case ld::Fixup::kindStoreTargetAddressARM64GOTLeaPage21
:
1006 printf("ARM64 store 21-bit pcrel ADRP to GOT lea for %s", referenceTargetAtomName(ref
));
1008 case ld::Fixup::kindStoreTargetAddressARM64GOTLeaPageOff12
:
1009 printf("ARM64 store 12-bit page offset of GOT lea of %s", referenceTargetAtomName(ref
));
1011 case ld::Fixup::kindStoreTargetAddressARM64TLVPLoadPage21
:
1012 printf("ARM64 store 21-bit pcrel ADRP to TLV for %s", referenceTargetAtomName(ref
));
1014 case ld::Fixup::kindStoreTargetAddressARM64TLVPLoadPageOff12
:
1015 printf("ARM64 store 12-bit page offset of TLV of %s", referenceTargetAtomName(ref
));
1017 case ld::Fixup::kindStoreTargetAddressARM64TLVPLoadNowLeaPage21
:
1018 printf("ARM64 store 21-bit pcrel ADRP to lea for TLV for %s", referenceTargetAtomName(ref
));
1020 case ld::Fixup::kindStoreTargetAddressARM64TLVPLoadNowLeaPageOff12
:
1021 printf("ARM64 store 12-bit page offset of lea for TLV of %s", referenceTargetAtomName(ref
));
1024 // printf("unknown fixup");
1029 uint64_t dumper::addressOfFirstAtomInSection(const ld::Section
& sect
)
1031 uint64_t lowestAddr
= (uint64_t)(-1);
1032 for (std::vector
<const ld::Atom
*>::iterator it
=_atoms
.begin(); it
!= _atoms
.end(); ++it
) {
1033 const ld::Atom
* atom
= *it
;
1034 if ( &atom
->section() == §
) {
1035 if ( atom
->objectAddress() < lowestAddr
)
1036 lowestAddr
= atom
->objectAddress();
1042 void dumper::doAtom(const ld::Atom
& atom
)
1044 if ( (sMatchName
!= NULL
) && (strcmp(sMatchName
, atom
.name()) != 0) )
1046 _atoms
.push_back(&atom
);
1052 std::sort(_atoms
.begin(), _atoms
.end(), AtomSorter());
1054 for (std::vector
<const ld::Atom
*>::iterator it
=_atoms
.begin(); it
!= _atoms
.end(); ++it
) {
1055 this->dumpAtom(**it
);
1059 void dumper::dumpAtom(const ld::Atom
& atom
)
1061 printf("name: %s\n", makeName(atom
));
1062 printf("size: 0x%0llX\n", atom
.size());
1063 printf("align: %u mod %u\n", atom
.alignment().modulus
, (1 << atom
.alignment().powerOf2
) );
1064 printf("scope: %s\n", scopeString(atom
));
1065 if ( sShowDefinitionKind
)
1066 printf("def: %s\n", definitionString(atom
));
1067 if ( sShowCombineKind
)
1068 printf("combine: %s\n", combineString(atom
));
1069 printf("symbol: %s\n", inclusionString(atom
));
1070 printf("attrs: %s\n", attributeString(atom
));
1072 printf("section: %s,%s\n", atom
.section().segmentName(), atom
.section().sectionName());
1073 if ( atom
.beginUnwind() != atom
.endUnwind() ) {
1074 uint32_t lastOffset
= 0;
1075 uint32_t lastCUE
= 0;
1077 const char* label
= "unwind:";
1078 for (ld::Atom::UnwindInfo::iterator it
=atom
.beginUnwind(); it
!= atom
.endUnwind(); ++it
) {
1080 printf("%s 0x%08X -> 0x%08X: 0x%08X\n", label
, lastOffset
, it
->startOffset
, lastCUE
);
1083 lastOffset
= it
->startOffset
;
1084 lastCUE
= it
->unwindInfo
;
1087 printf("%s 0x%08X -> 0x%08X: 0x%08X\n", label
, lastOffset
, (uint32_t)atom
.size(), lastCUE
);
1089 if ( atom
.contentType() == ld::Atom::typeCString
) {
1090 uint8_t buffer
[atom
.size()+2];
1091 atom
.copyRawContent(buffer
);
1092 buffer
[atom
.size()] = '\0';
1093 printf("content: \"%s\"\n", buffer
);
1095 if ( atom
.fixupsBegin() != atom
.fixupsEnd() ) {
1096 printf("fixups:\n");
1097 for (unsigned int off
=0; off
< atom
.size()+1; ++off
) {
1098 for (ld::Fixup::iterator it
= atom
.fixupsBegin(); it
!= atom
.fixupsEnd(); ++it
) {
1099 if ( it
->offsetInAtom
== off
) {
1100 switch ( it
->clusterSize
) {
1101 case ld::Fixup::k1of1
:
1102 printf(" 0x%04X ", it
->offsetInAtom
);
1105 case ld::Fixup::k1of2
:
1106 printf(" 0x%04X ", it
->offsetInAtom
);
1111 case ld::Fixup::k1of3
:
1112 printf(" 0x%04X ", it
->offsetInAtom
);
1119 case ld::Fixup::k1of4
:
1120 printf(" 0x%04X ", it
->offsetInAtom
);
1129 case ld::Fixup::k1of5
:
1130 printf(" 0x%04X ", it
->offsetInAtom
);
1142 printf(" BAD CLUSTER SIZE: cluster=%d\n", it
->clusterSize
);
1149 if ( sShowLineInfo
) {
1150 if ( atom
.beginLineInfo() != atom
.endLineInfo() ) {
1151 printf("line info:\n");
1152 for (ld::Atom::LineInfo::iterator it
= atom
.beginLineInfo(); it
!= atom
.endLineInfo(); ++it
) {
1153 printf(" offset 0x%04X, line %d, file %s\n", it
->atomOffset
, it
->lineNumber
, it
->fileName
);
1161 static void dumpFile(ld::relocatable::File
* file
)
1164 if ( sDumpStabs
&& (file
->debugInfo() == ld::relocatable::File::kDebugInfoStabs
) ) {
1165 const std::vector
<ld::relocatable::File::Stab
>* stabs
= file
->stabs();
1166 if ( stabs
!= NULL
)
1171 file
->forEachAtom(d
);
1176 std::vector
<ObjectFile::Atom
*> atoms
= reader
->getAtoms();
1178 // make copy of vector and sort (so output is canonical)
1179 std::vector
<ObjectFile::Atom
*> sortedAtoms(atoms
);
1181 std::sort(sortedAtoms
.begin(), sortedAtoms
.end(), AtomSorter());
1183 for(std::vector
<ObjectFile::Atom
*>::iterator it
=sortedAtoms
.begin(); it
!= sortedAtoms
.end(); ++it
) {
1185 dumpAtomLikeNM(*it
);
1193 static ld::relocatable::File
* createReader(const char* path
)
1195 struct stat stat_buf
;
1197 int fd
= ::open(path
, O_RDONLY
, 0);
1199 throwf("cannot open file: %s", path
);
1200 ::fstat(fd
, &stat_buf
);
1201 uint8_t* p
= (uint8_t*)::mmap(NULL
, stat_buf
.st_size
, PROT_READ
, MAP_FILE
| MAP_PRIVATE
, fd
, 0);
1203 if ( p
== (uint8_t*)(-1) )
1204 throwf("cannot mmap file: %s", path
);
1205 const mach_header
* mh
= (mach_header
*)p
;
1206 uint64_t fileLen
= stat_buf
.st_size
;
1207 bool foundFatSlice
= false;
1208 if ( mh
->magic
== OSSwapBigToHostInt32(FAT_MAGIC
) ) {
1209 const struct fat_header
* fh
= (struct fat_header
*)p
;
1210 const struct fat_arch
* archs
= (struct fat_arch
*)(p
+ sizeof(struct fat_header
));
1211 if ( (uint32_t)sPreferredArch
== 0xFFFFFFFF ) {
1212 // just dump first slice of fat .o file
1213 if ( OSSwapBigToHostInt32(fh
->nfat_arch
) > 0 ) {
1214 p
= p
+ OSSwapBigToHostInt32(archs
[0].offset
);
1215 mh
= (struct mach_header
*)p
;
1216 fileLen
= OSSwapBigToHostInt32(archs
[0].size
);
1217 sPreferredArch
= OSSwapBigToHostInt32(archs
[0].cputype
);
1218 sPreferredSubArch
= OSSwapBigToHostInt32(archs
[0].cpusubtype
);
1219 foundFatSlice
= true;
1223 for (unsigned long i
=0; i
< OSSwapBigToHostInt32(fh
->nfat_arch
); ++i
) {
1224 if ( OSSwapBigToHostInt32(archs
[i
].cputype
) == (uint32_t)sPreferredArch
) {
1225 if ( ((uint32_t)sPreferredSubArch
== 0xFFFFFFFF) || ((uint32_t)sPreferredSubArch
== OSSwapBigToHostInt32(archs
[i
].cpusubtype
)) ) {
1226 p
= p
+ OSSwapBigToHostInt32(archs
[i
].offset
);
1227 mh
= (struct mach_header
*)p
;
1228 fileLen
= OSSwapBigToHostInt32(archs
[i
].size
);
1229 foundFatSlice
= true;
1237 mach_o::relocatable::ParserOptions objOpts
;
1238 objOpts
.architecture
= sPreferredArch
;
1239 objOpts
.objSubtypeMustMatch
= false;
1240 objOpts
.logAllFiles
= false;
1241 objOpts
.warnUnwindConversionProblems
= true;
1242 objOpts
.keepDwarfUnwind
= false;
1243 objOpts
.forceDwarfConversion
= false;
1244 objOpts
.verboseOptimizationHints
= true;
1245 objOpts
.armUsesZeroCostExceptions
= true;
1246 objOpts
.subType
= sPreferredSubArch
;
1247 objOpts
.treateBitcodeAsData
= false;
1248 objOpts
.usingBitcode
= true;
1250 if ( ! foundFatSlice
) {
1251 cpu_type_t archOfObj
;
1252 cpu_subtype_t subArchOfObj
;
1253 Options::Platform platform
;
1254 if ( mach_o::relocatable::isObjectFile(p
, &archOfObj
, &subArchOfObj
, &platform
) ) {
1255 objOpts
.architecture
= archOfObj
;
1256 objOpts
.subType
= subArchOfObj
;
1260 ld::relocatable::File
* objResult
= mach_o::relocatable::parse(p
, fileLen
, path
, stat_buf
.st_mtime
, ld::File::Ordinal::NullOrdinal(), objOpts
);
1261 if ( objResult
!= NULL
)
1264 // see if it is an llvm object file
1265 objResult
= lto::parse(p
, fileLen
, path
, stat_buf
.st_mtime
, ld::File::Ordinal::NullOrdinal(), sPreferredArch
, sPreferredSubArch
, false, true);
1266 if ( objResult
!= NULL
)
1269 throwf("not a mach-o object file: %s", path
);
1271 // for peformance testing
1272 for (int i
=0; i
< 500; ++i
) {
1273 ld::relocatable::File
* objResult
= mach_o::relocatable::parse(p
, fileLen
, path
, stat_buf
.st_mtime
, 0, objOpts
);
1284 fprintf(stderr
, "ObjectDump options:\n"
1285 "\t-no_content\tdon't dump contents\n"
1286 "\t-no_section\tdon't dump section name\n"
1287 "\t-no_defintion\tdon't dump definition kind\n"
1288 "\t-no_combine\tdon't dump combine mode\n"
1289 "\t-stabs\t\tdump stabs\n"
1290 "\t-arch aaa\tonly dump info about arch aaa\n"
1291 "\t-only sym\tonly dump info about sym\n"
1292 "\t-align\t\tonly print alignment info\n"
1293 "\t-name\t\tonly print symbol names\n"
1297 int main(int argc
, const char* argv
[])
1305 for(int i
=1; i
< argc
; ++i
) {
1306 const char* arg
= argv
[i
];
1307 if ( arg
[0] == '-' ) {
1308 if ( strcmp(arg
, "-no_content") == 0 ) {
1309 sDumpContent
= false;
1311 else if ( strcmp(arg
, "-nm") == 0 ) {
1314 else if ( strcmp(arg
, "-stabs") == 0 ) {
1317 else if ( strcmp(arg
, "-no_sort") == 0 ) {
1320 else if ( strcmp(arg
, "-no_section") == 0 ) {
1321 sShowSection
= false;
1323 else if ( strcmp(arg
, "-no_definition") == 0 ) {
1324 sShowDefinitionKind
= false;
1326 else if ( strcmp(arg
, "-no_combine") == 0 ) {
1327 sShowCombineKind
= false;
1329 else if ( strcmp(arg
, "-no_line_info") == 0 ) {
1330 sShowLineInfo
= false;
1332 else if ( strcmp(arg
, "-arch") == 0 ) {
1333 const char* archName
= argv
[++i
];
1334 if ( archName
== NULL
)
1335 throw "-arch missing architecture name";
1337 for (const ArchInfo
* t
=archInfoArray
; t
->archName
!= NULL
; ++t
) {
1338 if ( strcmp(t
->archName
,archName
) == 0 ) {
1339 sPreferredArch
= t
->cpuType
;
1341 sPreferredSubArch
= t
->cpuSubType
;
1346 throwf("unknown architecture %s", archName
);
1348 else if ( strcmp(arg
, "-only") == 0 ) {
1349 sMatchName
= ++i
<argc
? argv
[i
]: NULL
;
1351 else if ( strcmp(arg
, "-align") == 0 ) {
1352 sPrintRestrict
= true;
1355 else if ( strcmp(arg
, "-name") == 0 ) {
1356 sPrintRestrict
= true;
1361 throwf("unknown option: %s\n", arg
);
1365 ld::relocatable::File
* reader
= createReader(arg
);
1370 catch (const char* msg
) {
1371 fprintf(stderr
, "ObjDump failed: %s\n", msg
);