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 const ld::VersionSet
ld::File::_platforms
;
40 static bool sDumpContent
= true;
41 static bool sDumpStabs
= false;
42 static bool sSort
= true;
43 static bool sNMmode
= false;
44 static bool sShowSection
= true;
45 static bool sShowDefinitionKind
= true;
46 static bool sShowCombineKind
= true;
47 static bool sShowLineInfo
= true;
49 static cpu_type_t sPreferredArch
= 0xFFFFFFFF;
50 static cpu_subtype_t sPreferredSubArch
= 0xFFFFFFFF;
51 static const char* sMatchName
= NULL
;
52 static int sPrintRestrict
;
53 static int sPrintAlign
;
54 static int sPrintName
;
56 __attribute__((noreturn
))
57 void throwf(const char* format
, ...)
61 va_start(list
, format
);
62 vasprintf(&p
, format
, list
);
69 void warning(const char* format
, ...)
72 fprintf(stderr
, "warning: ");
73 va_start(list
, format
);
74 vfprintf(stderr
, format
, list
);
76 fprintf(stderr
, "\n");
79 static void dumpStabs(const std::vector
<ld::relocatable::File::Stab
>* stabs
)
82 printf("stabs: (%lu)\n", stabs
->size());
83 for (std::vector
<ld::relocatable::File::Stab
>::const_iterator it
= stabs
->begin(); it
!= stabs
->end(); ++it
) {
84 const ld::relocatable::File::Stab
& stab
= *it
;
85 const char* code
= "?????";
172 printf(" [atom=%20s] %02X %04X %s %s\n", ((stab
.atom
!= NULL
) ? stab
.atom
->name() : ""), stab
.other
, stab
.desc
, code
, stab
.string
);
177 static void dumpAtomLikeNM(ld::Atom
* atom
)
179 uint32_t size
= atom
->size();
181 const char* visibility
;
182 switch ( atom
->scope() ) {
183 case ld::Atom::scopeTranslationUnit
:
184 visibility
= "internal";
186 case ld::Atom::scopeLinkageUnit
:
187 visibility
= "hidden ";
189 case ld::Atom::scopeGlobal
:
190 visibility
= "global ";
198 switch ( atom
->definitionKind() ) {
199 case ld::Atom::kRegularDefinition
:
202 case ld::Atom::kTentativeDefinition
:
205 case ld::Atom::kWeakDefinition
:
208 case ld::Atom::kAbsoluteSymbol
:
216 printf("0x%08X %s %s %s\n", size
, visibility
, kind
, atom
->name());
220 static void dumpAtom(ld::Atom
* atom
)
222 if(sMatchName
&& strcmp(sMatchName
, atom
->name()))
225 //printf("atom: %p\n", atom);
228 if(!sPrintRestrict
|| sPrintName
)
229 printf("name: %s\n", atom
->name());
233 switch ( atom
->scope() ) {
234 case ld::Atom::scopeTranslationUnit
:
235 printf("scope: translation unit\n");
237 case ld::Atom::scopeLinkageUnit
:
238 printf("scope: linkage unit\n");
240 case ld::Atom::scopeGlobal
:
241 printf("scope: global\n");
244 printf("scope: unknown\n");
249 switch ( atom
->definitionKind() ) {
250 case ld::Atom::kRegularDefinition
:
251 printf("kind: regular\n");
253 case ld::Atom::kWeakDefinition
:
254 printf("kind: weak\n");
256 case ld::Atom::kTentativeDefinition
:
257 printf("kind: tentative\n");
259 case ld::Atom::kExternalDefinition
:
260 printf("kind: import\n");
262 case ld::Atom::kExternalWeakDefinition
:
263 printf("kind: weak import\n");
265 case ld::Atom::kAbsoluteSymbol
:
266 printf("kind: absolute symbol\n");
269 printf("kind: unknown\n");
272 // segment and section
273 if(!sPrintRestrict
&& (atom
->section().sectionName() != NULL
) )
274 printf("section: %s,%s\n", atom
->section().segmentName(), atom
->section().sectionName());
277 if(!sPrintRestrict
) {
279 if ( atom
->dontDeadStrip() )
280 printf("dont-dead-strip ");
281 if ( atom
->isThumb() )
288 printf("size: 0x%012llX\n", atom
->size());
291 if(!sPrintRestrict
|| sPrintAlign
)
292 printf("align: %u mod %u\n", atom
->alignment().modulus
, (1 << atom
->alignment().powerOf2
) );
295 if (!sPrintRestrict
&& sDumpContent
) {
296 uint64_t size
= atom
->size();
298 uint8_t content
[size
];
299 atom
->copyRawContent(content
);
301 if ( atom
->contentType() == ld::Atom::typeCString
) {
303 for (unsigned int i
=0; i
< size
; ++i
) {
304 if(content
[i
]<'!' || content
[i
]>=127)
305 printf("\\%o", content
[i
]);
307 printf("%c", content
[i
]);
312 for (unsigned int i
=0; i
< size
; ++i
)
313 printf("%02X ", content
[i
]);
320 if(!sPrintRestrict
) {
321 if ( atom
->beginUnwind() != atom
->endUnwind() ) {
322 printf("unwind encodings:\n");
323 for (ld::Atom::UnwindInfo::iterator it
= atom
->beginUnwind(); it
!= atom
->endUnwind(); ++it
) {
324 printf("\t 0x%04X 0x%08X\n", it
->startOffset
, it
->unwindInfo
);
330 if(!sPrintRestrict
) {
331 std::vector
<ObjectFile::Reference
*>& references
= atom
->getReferences();
332 const int refCount
= references
.size();
333 printf("references: (%u)\n", refCount
);
334 for (int i
=0; i
< refCount
; ++i
) {
335 ObjectFile::Reference
* ref
= references
[i
];
336 printf(" %s\n", ref
->getDescription());
341 if(!sPrintRestrict
) {
342 if ( atom
->beginLineInfo() != atom
->endLineInfo() ) {
343 printf("line info:\n");
344 for (ld::Atom::LineInfo::iterator it
= atom
->beginLineInfo(); it
!= atom
->endLineInfo(); ++it
) {
345 printf(" offset 0x%04X, line %d, file %s\n", it
->atomOffset
, it
->lineNumber
, it
->fileName
);
356 bool operator()(const ld::Atom
* left
, const ld::Atom
* right
)
360 // first sort by segment name
361 int diff
= strcmp(left
->section().segmentName(), right
->section().segmentName());
365 // then sort by section name
366 diff
= strcmp(left
->section().sectionName(), right
->section().sectionName());
370 // then sort by atom name
371 diff
= strcmp(left
->name(), right
->name());
375 // if cstring, sort by content
376 if ( left
->contentType() == ld::Atom::typeCString
) {
377 diff
= strcmp((char*)left
->rawContentPointer(), (char*)right
->rawContentPointer());
381 else if ( left
->section().type() == ld::Section::typeCStringPointer
) {
382 // if pointer to c-string sort by name
383 const char* leftString
= NULL
;
384 assert(left
->fixupsBegin() != left
->fixupsEnd());
385 for (ld::Fixup::iterator fit
= left
->fixupsBegin(); fit
!= left
->fixupsEnd(); ++fit
) {
386 if ( fit
->binding
== ld::Fixup::bindingByContentBound
) {
387 const ld::Atom
* cstringAtom
= fit
->u
.target
;
388 assert(cstringAtom
->contentType() == ld::Atom::typeCString
);
389 leftString
= (char*)cstringAtom
->rawContentPointer();
392 const char* rightString
= NULL
;
393 assert(right
->fixupsBegin() != right
->fixupsEnd());
394 for (ld::Fixup::iterator fit
= right
->fixupsBegin(); fit
!= right
->fixupsEnd(); ++fit
) {
395 if ( fit
->binding
== ld::Fixup::bindingByContentBound
) {
396 const ld::Atom
* cstringAtom
= fit
->u
.target
;
397 assert(cstringAtom
->contentType() == ld::Atom::typeCString
);
398 rightString
= (char*)cstringAtom
->rawContentPointer();
401 if ( leftString
!= rightString
) {
402 assert(leftString
!= NULL
);
403 assert(rightString
!= NULL
);
404 diff
= strcmp(leftString
, rightString
);
409 else if ( left
->section().type() == ld::Section::typeLiteral4
) {
410 // if literal sort by content
411 uint32_t leftValue
= *(uint32_t*)left
->rawContentPointer();
412 uint32_t rightValue
= *(uint32_t*)right
->rawContentPointer();
413 diff
= (leftValue
- rightValue
);
417 else if ( left
->section().type() == ld::Section::typeCFI
) {
418 // if __he_frame sort by address
419 diff
= (left
->objectAddress() - right
->objectAddress());
423 else if ( left
->section().type() == ld::Section::typeNonLazyPointer
) {
424 // if non-lazy-pointer sort by name
425 const char* leftString
= NULL
;
426 assert(left
->fixupsBegin() != left
->fixupsEnd());
427 for (ld::Fixup::iterator fit
= left
->fixupsBegin(); fit
!= left
->fixupsEnd(); ++fit
) {
428 if ( fit
->binding
== ld::Fixup::bindingByNameUnbound
) {
429 leftString
= fit
->u
.name
;
431 else if ( fit
->binding
== ld::Fixup::bindingDirectlyBound
) {
432 leftString
= fit
->u
.target
->name();
435 const char* rightString
= NULL
;
436 assert(right
->fixupsBegin() != right
->fixupsEnd());
437 for (ld::Fixup::iterator fit
= right
->fixupsBegin(); fit
!= right
->fixupsEnd(); ++fit
) {
438 if ( fit
->binding
== ld::Fixup::bindingByNameUnbound
) {
439 rightString
= fit
->u
.name
;
441 else if ( fit
->binding
== ld::Fixup::bindingDirectlyBound
) {
442 rightString
= fit
->u
.target
->name();
445 assert(leftString
!= NULL
);
446 assert(rightString
!= NULL
);
447 diff
= strcmp(leftString
, rightString
);
453 return (left
->size() < right
->size());
458 class dumper
: public ld::File::AtomHandler
462 virtual void doAtom(const ld::Atom
&);
463 virtual void doFile(const ld::File
&) {}
465 void dumpAtom(const ld::Atom
& atom
);
466 const char* scopeString(const ld::Atom
&);
467 const char* definitionString(const ld::Atom
&);
468 const char* combineString(const ld::Atom
&);
469 const char* inclusionString(const ld::Atom
&);
470 const char* attributeString(const ld::Atom
&);
471 const char* makeName(const ld::Atom
& atom
);
472 const char* referenceTargetAtomName(const ld::Fixup
* ref
);
473 void dumpFixup(const ld::Fixup
* ref
);
475 uint64_t addressOfFirstAtomInSection(const ld::Section
&);
477 std::vector
<const ld::Atom
*> _atoms
;
480 const char* dumper::scopeString(const ld::Atom
& atom
)
482 switch ( (ld::Atom::Scope
)atom
.scope() ) {
483 case ld::Atom::scopeTranslationUnit
:
484 return "translation-unit";
485 case ld::Atom::scopeLinkageUnit
:
487 case ld::Atom::scopeGlobal
:
488 if ( atom
.autoHide() )
489 return "global but automatically hidden";
496 const char* dumper::definitionString(const ld::Atom
& atom
)
498 switch ( (ld::Atom::Definition
)atom
.definition() ) {
499 case ld::Atom::definitionRegular
:
501 case ld::Atom::definitionTentative
:
503 case ld::Atom::definitionAbsolute
:
505 case ld::Atom::definitionProxy
:
511 const char* dumper::combineString(const ld::Atom
& atom
)
513 switch ( (ld::Atom::Combine
)atom
.combine() ) {
514 case ld::Atom::combineNever
:
516 case ld::Atom::combineByName
:
518 case ld::Atom::combineByNameAndContent
:
519 return "by-name-and-content";
520 case ld::Atom::combineByNameAndReferences
:
521 return "by-name-and-references";
526 const char* dumper::inclusionString(const ld::Atom
& atom
)
528 switch ( (ld::Atom::SymbolTableInclusion
)atom
.symbolTableInclusion() ) {
529 case ld::Atom::symbolTableNotIn
:
531 case ld::Atom::symbolTableNotInFinalLinkedImages
:
532 return "not in final linked images";
533 case ld::Atom::symbolTableIn
:
535 case ld::Atom::symbolTableInAndNeverStrip
:
536 return "in and never strip";
537 case ld::Atom::symbolTableInAsAbsolute
:
538 return "in as absolute";
539 case ld::Atom::symbolTableInWithRandomAutoStripLabel
:
540 return "in as random auto-strip label";
547 const char* dumper::attributeString(const ld::Atom
& atom
)
549 static char buffer
[256];
552 if ( atom
.dontDeadStrip() )
553 strcat(buffer
, "dont-dead-strip ");
555 if ( atom
.isThumb() )
556 strcat(buffer
, "thumb ");
558 if ( atom
.isAlias() )
559 strcat(buffer
, "alias ");
561 if ( atom
.contentType() == ld::Atom::typeResolver
)
562 strcat(buffer
, "resolver ");
567 const char* dumper::makeName(const ld::Atom
& atom
)
569 static char buffer
[4096];
570 strcpy(buffer
, "???");
571 switch ( atom
.symbolTableInclusion() ) {
572 case ld::Atom::symbolTableNotIn
:
573 if ( atom
.contentType() == ld::Atom::typeCString
) {
574 strcpy(buffer
, "cstring=");
575 strlcat(buffer
, (char*)atom
.rawContentPointer(), 4096);
577 else if ( atom
.section().type() == ld::Section::typeLiteral4
) {
579 strcpy(buffer
, "literal4=");
580 uint32_t value
= *(uint32_t*)atom
.rawContentPointer();
581 sprintf(temp
, "0x%08X", value
);
582 strcat(buffer
, temp
);
584 else if ( atom
.section().type() == ld::Section::typeLiteral8
) {
586 strcpy(buffer
, "literal8=");
587 uint32_t value1
= *(uint32_t*)atom
.rawContentPointer();
588 uint32_t value2
= ((uint32_t*)atom
.rawContentPointer())[1];
589 sprintf(temp
, "0x%08X%08X", value1
, value2
);
590 strcat(buffer
, temp
);
592 else if ( atom
.section().type() == ld::Section::typeLiteral16
) {
594 strcpy(buffer
, "literal16=");
595 uint32_t value1
= *(uint32_t*)atom
.rawContentPointer();
596 uint32_t value2
= ((uint32_t*)atom
.rawContentPointer())[1];
597 uint32_t value3
= ((uint32_t*)atom
.rawContentPointer())[2];
598 uint32_t value4
= ((uint32_t*)atom
.rawContentPointer())[3];
599 sprintf(temp
, "0x%08X%08X%08X%08X", value1
, value2
, value3
, value4
);
600 strcat(buffer
, temp
);
602 else if ( atom
.section().type() == ld::Section::typeCStringPointer
) {
603 assert(atom
.fixupsBegin() != atom
.fixupsEnd());
604 for (ld::Fixup::iterator fit
= atom
.fixupsBegin(); fit
!= atom
.fixupsEnd(); ++fit
) {
605 if ( fit
->binding
== ld::Fixup::bindingByContentBound
) {
606 const ld::Atom
* cstringAtom
= fit
->u
.target
;
607 if ( (cstringAtom
!= NULL
) && (cstringAtom
->contentType() == ld::Atom::typeCString
) ) {
608 strlcpy(buffer
, atom
.name(), 4096);
609 strlcat(buffer
, "=", 4096);
610 strlcat(buffer
, (char*)cstringAtom
->rawContentPointer(), 4096);
615 else if ( atom
.section().type() == ld::Section::typeNonLazyPointer
) {
616 assert(atom
.fixupsBegin() != atom
.fixupsEnd());
617 for (ld::Fixup::iterator fit
= atom
.fixupsBegin(); fit
!= atom
.fixupsEnd(); ++fit
) {
618 if ( fit
->binding
== ld::Fixup::bindingByNameUnbound
) {
619 strcpy(buffer
, "non-lazy-pointer-to:");
620 strlcat(buffer
, fit
->u
.name
, 4096);
623 else if ( fit
->binding
== ld::Fixup::bindingDirectlyBound
) {
624 strcpy(buffer
, "non-lazy-pointer-to-local:");
625 strlcat(buffer
, fit
->u
.target
->name(), 4096);
629 strlcpy(buffer
, atom
.name(), 4096);
632 uint64_t sectAddr
= addressOfFirstAtomInSection(atom
.section());
633 sprintf(buffer
, "%s@%s+0x%08llX", atom
.name(), atom
.section().sectionName(), atom
.objectAddress()-sectAddr
);
636 case ld::Atom::symbolTableNotInFinalLinkedImages
:
637 case ld::Atom::symbolTableIn
:
638 case ld::Atom::symbolTableInAndNeverStrip
:
639 case ld::Atom::symbolTableInAsAbsolute
:
640 case ld::Atom::symbolTableInWithRandomAutoStripLabel
:
641 strlcpy(buffer
, atom
.name(), 4096);
647 const char* dumper::referenceTargetAtomName(const ld::Fixup
* ref
)
649 static char buffer
[4096];
650 switch ( ref
->binding
) {
651 case ld::Fixup::bindingNone
:
653 case ld::Fixup::bindingByNameUnbound
:
654 strcpy(buffer
, "by-name(");
655 strlcat(buffer
, ref
->u
.name
, 4096);
656 strlcat(buffer
, ")", 4096);
658 //return ref->u.name;
659 case ld::Fixup::bindingByContentBound
:
660 strcpy(buffer
, "by-content(");
661 strlcat(buffer
, makeName(*ref
->u
.target
), 4096);
662 strlcat(buffer
, ")", 4096);
664 case ld::Fixup::bindingDirectlyBound
:
665 strcpy(buffer
, "direct(");
666 strlcat(buffer
, makeName(*ref
->u
.target
), 4096);
667 strlcat(buffer
, ")", 4096);
669 case ld::Fixup::bindingsIndirectlyBound
:
670 return "BOUND INDIRECTLY";
672 return "BAD BINDING";
676 void dumper::dumpFixup(const ld::Fixup
* ref
)
678 if ( ref
->weakImport
) {
679 printf("weak_import ");
681 switch ( (ld::Fixup::Kind
)(ref
->kind
) ) {
682 case ld::Fixup::kindNone
:
685 case ld::Fixup::kindNoneFollowOn
:
686 printf("followed by %s", referenceTargetAtomName(ref
));
688 case ld::Fixup::kindNoneGroupSubordinate
:
689 printf("group subordinate %s", referenceTargetAtomName(ref
));
691 case ld::Fixup::kindNoneGroupSubordinateFDE
:
692 printf("group subordinate FDE %s", referenceTargetAtomName(ref
));
694 case ld::Fixup::kindNoneGroupSubordinateLSDA
:
695 printf("group subordinate LSDA %s", referenceTargetAtomName(ref
));
697 case ld::Fixup::kindNoneGroupSubordinatePersonality
:
698 printf("group subordinate personality %s", referenceTargetAtomName(ref
));
700 case ld::Fixup::kindSetTargetAddress
:
701 printf("%s", referenceTargetAtomName(ref
));
703 case ld::Fixup::kindSubtractTargetAddress
:
704 printf(" - %s", referenceTargetAtomName(ref
));
706 case ld::Fixup::kindAddAddend
:
707 printf(" + 0x%llX", ref
->u
.addend
);
709 case ld::Fixup::kindSubtractAddend
:
710 printf(" - 0x%llX", ref
->u
.addend
);
712 case ld::Fixup::kindSetTargetImageOffset
:
713 printf("imageOffset(%s)", referenceTargetAtomName(ref
));
715 case ld::Fixup::kindSetTargetSectionOffset
:
716 printf("sectionOffset(%s)", referenceTargetAtomName(ref
));
718 case ld::Fixup::kindStore8
:
719 printf(", then store byte");
721 case ld::Fixup::kindStoreLittleEndian16
:
722 printf(", then store 16-bit little endian");
724 case ld::Fixup::kindStoreLittleEndianLow24of32
:
725 printf(", then store low 24-bit little endian");
727 case ld::Fixup::kindStoreLittleEndian32
:
728 printf(", then store 32-bit little endian");
730 case ld::Fixup::kindStoreLittleEndian64
:
731 printf(", then store 64-bit little endian");
733 case ld::Fixup::kindStoreBigEndian16
:
734 printf(", then store 16-bit big endian");
736 case ld::Fixup::kindStoreBigEndianLow24of32
:
737 printf(", then store low 24-bit big endian");
739 case ld::Fixup::kindStoreBigEndian32
:
740 printf(", then store 32-bit big endian");
742 case ld::Fixup::kindStoreBigEndian64
:
743 printf(", then store 64-bit big endian");
745 case ld::Fixup::kindStoreX86BranchPCRel8
:
746 printf(", then store as x86 8-bit pcrel branch");
748 case ld::Fixup::kindStoreX86BranchPCRel32
:
749 printf(", then store as x86 32-bit pcrel branch");
751 case ld::Fixup::kindStoreX86PCRel8
:
752 printf(", then store as x86 8-bit pcrel");
754 case ld::Fixup::kindStoreX86PCRel16
:
755 printf(", then store as x86 16-bit pcrel");
757 case ld::Fixup::kindStoreX86PCRel32
:
758 printf(", then store as x86 32-bit pcrel");
760 case ld::Fixup::kindStoreX86PCRel32_1
:
761 printf(", then store as x86 32-bit pcrel from +1");
763 case ld::Fixup::kindStoreX86PCRel32_2
:
764 printf(", then store as x86 32-bit pcrel from +2");
766 case ld::Fixup::kindStoreX86PCRel32_4
:
767 printf(", then store as x86 32-bit pcrel from +4");
769 case ld::Fixup::kindStoreX86PCRel32GOTLoad
:
770 printf(", then store as x86 32-bit pcrel GOT load");
772 case ld::Fixup::kindStoreX86PCRel32GOTLoadNowLEA
:
773 printf(", then store as x86 32-bit pcrel GOT load -> LEA");
775 case ld::Fixup::kindStoreX86PCRel32GOT
:
776 printf(", then store as x86 32-bit pcrel GOT access");
778 case ld::Fixup::kindStoreX86PCRel32TLVLoad
:
779 printf(", then store as x86 32-bit pcrel TLV load");
781 case ld::Fixup::kindStoreX86PCRel32TLVLoadNowLEA
:
782 printf(", then store as x86 32-bit pcrel TLV load");
784 case ld::Fixup::kindStoreX86Abs32TLVLoad
:
785 printf(", then store as x86 32-bit absolute TLV load");
787 case ld::Fixup::kindStoreX86Abs32TLVLoadNowLEA
:
788 printf(", then store as x86 32-bit absolute TLV load -> LEA");
790 case ld::Fixup::kindStoreARMBranch24
:
791 printf(", then store as ARM 24-bit pcrel branch");
793 case ld::Fixup::kindStoreThumbBranch22
:
794 printf(", then store as Thumb 22-bit pcrel branch");
796 case ld::Fixup::kindStoreARMLoad12
:
797 printf(", then store as ARM 12-bit pcrel load");
799 case ld::Fixup::kindStoreARMLow16
:
800 printf(", then store low-16 in ARM movw");
802 case ld::Fixup::kindStoreARMHigh16
:
803 printf(", then store high-16 in ARM movt");
805 case ld::Fixup::kindStoreThumbLow16
:
806 printf(", then store low-16 in Thumb movw");
808 case ld::Fixup::kindStoreThumbHigh16
:
809 printf(", then store high-16 in Thumb movt");
811 #if SUPPORT_ARCH_arm64
812 case ld::Fixup::kindStoreARM64Branch26
:
813 printf(", then store as ARM64 26-bit pcrel branch");
815 case ld::Fixup::kindStoreARM64Page21
:
816 printf(", then store as ARM64 21-bit pcrel ADRP");
818 case ld::Fixup::kindStoreARM64PageOff12
:
819 printf(", then store as ARM64 12-bit offset");
821 case ld::Fixup::kindStoreARM64GOTLoadPage21
:
822 printf(", then store as ARM64 21-bit pcrel ADRP of GOT");
824 case ld::Fixup::kindStoreARM64GOTLoadPageOff12
:
825 printf(", then store as ARM64 12-bit page offset of GOT");
827 case ld::Fixup::kindStoreARM64GOTLeaPage21
:
828 printf(", then store as ARM64 21-bit pcrel ADRP of GOT lea");
830 case ld::Fixup::kindStoreARM64GOTLeaPageOff12
:
831 printf(", then store as ARM64 12-bit page offset of GOT lea");
833 case ld::Fixup::kindStoreARM64TLVPLoadPage21
:
834 printf(", then store as ARM64 21-bit pcrel ADRP of TLVP");
836 case ld::Fixup::kindStoreARM64TLVPLoadPageOff12
:
837 printf(", then store as ARM64 12-bit page offset of TLVP");
839 case ld::Fixup::kindStoreARM64TLVPLoadNowLeaPage21
:
840 printf(", then store as ARM64 21-bit pcrel ADRP of lea of TLVP");
842 case ld::Fixup::kindStoreARM64TLVPLoadNowLeaPageOff12
:
843 printf(", then store as ARM64 12-bit page offset of lea of TLVP");
845 case ld::Fixup::kindStoreARM64PointerToGOT
:
846 printf(", then store as 64-bit pointer to GOT entry");
848 case ld::Fixup::kindStoreARM64PCRelToGOT
:
849 printf(", then store as 32-bit delta to GOT entry");
852 case ld::Fixup::kindDtraceExtra
:
853 printf("dtrace static probe extra info");
855 case ld::Fixup::kindStoreX86DtraceCallSiteNop
:
856 printf("x86 dtrace static probe site");
858 case ld::Fixup::kindStoreX86DtraceIsEnableSiteClear
:
859 printf("x86 dtrace static is-enabled site");
861 case ld::Fixup::kindStoreARMDtraceCallSiteNop
:
862 printf("ARM dtrace static probe site");
864 case ld::Fixup::kindStoreARMDtraceIsEnableSiteClear
:
865 printf("ARM dtrace static is-enabled site");
867 case ld::Fixup::kindStoreThumbDtraceCallSiteNop
:
868 printf("Thumb dtrace static probe site");
870 case ld::Fixup::kindStoreThumbDtraceIsEnableSiteClear
:
871 printf("Thumb dtrace static is-enabled site");
873 #if SUPPORT_ARCH_arm64
874 case ld::Fixup::kindStoreARM64DtraceCallSiteNop
:
875 printf("ARM64 dtrace static probe site");
877 case ld::Fixup::kindStoreARM64DtraceIsEnableSiteClear
:
878 printf("ARM64 dtrace static is-enabled site");
881 case ld::Fixup::kindLazyTarget
:
882 printf("lazy reference to external symbol %s", referenceTargetAtomName(ref
));
884 case ld::Fixup::kindSetLazyOffset
:
885 printf("offset of lazy binding info for %s", referenceTargetAtomName(ref
));
887 case ld::Fixup::kindIslandTarget
:
888 printf("ultimate target of island %s", referenceTargetAtomName(ref
));
890 case ld::Fixup::kindDataInCodeStartData
:
891 printf("start of data in code");
893 case ld::Fixup::kindDataInCodeStartJT8
:
894 printf("start of jump table 8 data in code");
896 case ld::Fixup::kindDataInCodeStartJT16
:
897 printf("start of jump table 16 data in code");
899 case ld::Fixup::kindDataInCodeStartJT32
:
900 printf("start of jump table 32 data in code");
902 case ld::Fixup::kindDataInCodeStartJTA32
:
903 printf("start of jump table absolute 32 data in code");
905 case ld::Fixup::kindDataInCodeEnd
:
906 printf("end of data in code");
908 case ld::Fixup::kindLinkerOptimizationHint
:
909 #if SUPPORT_ARCH_arm64
910 ld::Fixup::LOH_arm64 extra
;
911 extra
.addend
= ref
->u
.addend
;
912 printf("ARM64 hint: ");
913 switch(extra
.info
.kind
) {
914 case LOH_ARM64_ADRP_ADRP
:
917 case LOH_ARM64_ADRP_LDR
:
920 case LOH_ARM64_ADRP_ADD_LDR
:
921 printf("ADRP-ADD-LDR");
923 case LOH_ARM64_ADRP_LDR_GOT_LDR
:
924 printf("ADRP-LDR-GOT-LDR");
926 case LOH_ARM64_ADRP_ADD_STR
:
927 printf("ADRP-ADD-STR");
929 case LOH_ARM64_ADRP_LDR_GOT_STR
:
930 printf("ADRP-LDR-GOT-STR");
932 case LOH_ARM64_ADRP_ADD
:
936 printf("kind=%d", extra
.info
.kind
);
939 printf(", offset1=0x%X", (extra
.info
.delta1
<< 2) + ref
->offsetInAtom
);
940 if ( extra
.info
.count
> 0 )
941 printf(", offset2=0x%X", (extra
.info
.delta2
<< 2) + ref
->offsetInAtom
);
942 if ( extra
.info
.count
> 1 )
943 printf(", offset3=0x%X", (extra
.info
.delta3
<< 2) + ref
->offsetInAtom
);
944 if ( extra
.info
.count
> 2 )
945 printf(", offset4=0x%X", (extra
.info
.delta4
<< 2) + ref
->offsetInAtom
);
948 case ld::Fixup::kindStoreTargetAddressLittleEndian32
:
949 printf("store 32-bit little endian address of %s", referenceTargetAtomName(ref
));
951 case ld::Fixup::kindStoreTargetAddressLittleEndian64
:
952 printf("store 64-bit little endian address of %s", referenceTargetAtomName(ref
));
954 case ld::Fixup::kindStoreTargetAddressBigEndian32
:
955 printf("store 32-bit big endian address of %s", referenceTargetAtomName(ref
));
957 case ld::Fixup::kindStoreTargetAddressBigEndian64
:
958 printf("store 64-bit big endian address of %s", referenceTargetAtomName(ref
));
960 case ld::Fixup::kindStoreTargetAddressX86PCRel32
:
961 printf("x86 store 32-bit pc-rel address of %s", referenceTargetAtomName(ref
));
963 case ld::Fixup::kindStoreTargetAddressX86BranchPCRel32
:
964 printf("x86 store 32-bit pc-rel branch to %s", referenceTargetAtomName(ref
));
966 case ld::Fixup::kindStoreTargetAddressX86PCRel32GOTLoad
:
967 printf("x86 store 32-bit pc-rel GOT load of %s", referenceTargetAtomName(ref
));
969 case ld::Fixup::kindStoreTargetAddressX86PCRel32GOTLoadNowLEA
:
970 printf("x86 store 32-bit pc-rel lea of %s", referenceTargetAtomName(ref
));
972 case ld::Fixup::kindStoreTargetAddressX86PCRel32TLVLoad
:
973 printf("x86 store 32-bit pc-rel TLV load of %s", referenceTargetAtomName(ref
));
975 case ld::Fixup::kindStoreTargetAddressX86PCRel32TLVLoadNowLEA
:
976 printf("x86 store 32-bit pc-rel TLV lea of %s", referenceTargetAtomName(ref
));
978 case ld::Fixup::kindStoreTargetAddressX86Abs32TLVLoad
:
979 printf("x86 store 32-bit absolute TLV load of %s", referenceTargetAtomName(ref
));
981 case ld::Fixup::kindStoreTargetAddressX86Abs32TLVLoadNowLEA
:
982 printf("x86 store 32-bit absolute TLV lea of %s", referenceTargetAtomName(ref
));
984 case ld::Fixup::kindStoreTargetAddressARMBranch24
:
985 printf("ARM store 24-bit pc-rel branch to %s", referenceTargetAtomName(ref
));
987 case ld::Fixup::kindStoreTargetAddressThumbBranch22
:
988 printf("Thumb store 22-bit pc-rel branch to %s", referenceTargetAtomName(ref
));
990 case ld::Fixup::kindStoreTargetAddressARMLoad12
:
991 printf("ARM store 12-bit pc-rel branch to %s", referenceTargetAtomName(ref
));
993 case ld::Fixup::kindSetTargetTLVTemplateOffset
:
994 case ld::Fixup::kindSetTargetTLVTemplateOffsetLittleEndian32
:
995 case ld::Fixup::kindSetTargetTLVTemplateOffsetLittleEndian64
:
996 printf("tlv template offset of %s", referenceTargetAtomName(ref
));
998 #if SUPPORT_ARCH_arm64
999 case ld::Fixup::kindStoreTargetAddressARM64Branch26
:
1000 printf("ARM64 store 26-bit pcrel branch to %s", referenceTargetAtomName(ref
));
1002 case ld::Fixup::kindStoreTargetAddressARM64Page21
:
1003 printf("ARM64 store 21-bit pcrel ADRP to %s", referenceTargetAtomName(ref
));
1005 case ld::Fixup::kindStoreTargetAddressARM64PageOff12
:
1006 printf("ARM64 store 12-bit page offset of %s", referenceTargetAtomName(ref
));
1008 case ld::Fixup::kindStoreTargetAddressARM64GOTLoadPage21
:
1009 printf("ARM64 store 21-bit pcrel ADRP to GOT for %s", referenceTargetAtomName(ref
));
1011 case ld::Fixup::kindStoreTargetAddressARM64GOTLoadPageOff12
:
1012 printf("ARM64 store 12-bit page offset of GOT of %s", referenceTargetAtomName(ref
));
1014 case ld::Fixup::kindStoreTargetAddressARM64GOTLeaPage21
:
1015 printf("ARM64 store 21-bit pcrel ADRP to GOT lea for %s", referenceTargetAtomName(ref
));
1017 case ld::Fixup::kindStoreTargetAddressARM64GOTLeaPageOff12
:
1018 printf("ARM64 store 12-bit page offset of GOT lea of %s", referenceTargetAtomName(ref
));
1020 case ld::Fixup::kindStoreTargetAddressARM64TLVPLoadPage21
:
1021 printf("ARM64 store 21-bit pcrel ADRP to TLV for %s", referenceTargetAtomName(ref
));
1023 case ld::Fixup::kindStoreTargetAddressARM64TLVPLoadPageOff12
:
1024 printf("ARM64 store 12-bit page offset of TLV of %s", referenceTargetAtomName(ref
));
1026 case ld::Fixup::kindStoreTargetAddressARM64TLVPLoadNowLeaPage21
:
1027 printf("ARM64 store 21-bit pcrel ADRP to lea for TLV for %s", referenceTargetAtomName(ref
));
1029 case ld::Fixup::kindStoreTargetAddressARM64TLVPLoadNowLeaPageOff12
:
1030 printf("ARM64 store 12-bit page offset of lea for TLV of %s", referenceTargetAtomName(ref
));
1034 // printf("unknown fixup");
1039 uint64_t dumper::addressOfFirstAtomInSection(const ld::Section
& sect
)
1041 uint64_t lowestAddr
= (uint64_t)(-1);
1042 for (std::vector
<const ld::Atom
*>::iterator it
=_atoms
.begin(); it
!= _atoms
.end(); ++it
) {
1043 const ld::Atom
* atom
= *it
;
1044 if ( &atom
->section() == §
) {
1045 if ( atom
->objectAddress() < lowestAddr
)
1046 lowestAddr
= atom
->objectAddress();
1052 void dumper::doAtom(const ld::Atom
& atom
)
1054 if ( (sMatchName
!= NULL
) && (strcmp(sMatchName
, atom
.name()) != 0) )
1056 _atoms
.push_back(&atom
);
1062 std::sort(_atoms
.begin(), _atoms
.end(), AtomSorter());
1064 for (std::vector
<const ld::Atom
*>::iterator it
=_atoms
.begin(); it
!= _atoms
.end(); ++it
) {
1065 this->dumpAtom(**it
);
1069 void dumper::dumpAtom(const ld::Atom
& atom
)
1071 printf("name: %s\n", makeName(atom
));
1072 printf("size: 0x%0llX\n", atom
.size());
1073 printf("align: %u mod %u\n", atom
.alignment().modulus
, (1 << atom
.alignment().powerOf2
) );
1074 printf("scope: %s\n", scopeString(atom
));
1075 if ( sShowDefinitionKind
)
1076 printf("def: %s\n", definitionString(atom
));
1077 if ( sShowCombineKind
)
1078 printf("combine: %s\n", combineString(atom
));
1079 printf("symbol: %s\n", inclusionString(atom
));
1080 printf("attrs: %s\n", attributeString(atom
));
1082 printf("section: %s,%s\n", atom
.section().segmentName(), atom
.section().sectionName());
1083 if ( atom
.beginUnwind() != atom
.endUnwind() ) {
1084 uint32_t lastOffset
= 0;
1085 uint32_t lastCUE
= 0;
1087 const char* label
= "unwind:";
1088 for (ld::Atom::UnwindInfo::iterator it
=atom
.beginUnwind(); it
!= atom
.endUnwind(); ++it
) {
1090 printf("%s 0x%08X -> 0x%08X: 0x%08X\n", label
, lastOffset
, it
->startOffset
, lastCUE
);
1093 lastOffset
= it
->startOffset
;
1094 lastCUE
= it
->unwindInfo
;
1097 printf("%s 0x%08X -> 0x%08X: 0x%08X\n", label
, lastOffset
, (uint32_t)atom
.size(), lastCUE
);
1099 if ( atom
.contentType() == ld::Atom::typeCString
) {
1100 uint8_t buffer
[atom
.size()+2];
1101 atom
.copyRawContent(buffer
);
1102 buffer
[atom
.size()] = '\0';
1103 printf("content: \"%s\"\n", buffer
);
1105 if ( atom
.fixupsBegin() != atom
.fixupsEnd() ) {
1106 printf("fixups:\n");
1107 for (unsigned int off
=0; off
< atom
.size()+1; ++off
) {
1108 for (ld::Fixup::iterator it
= atom
.fixupsBegin(); it
!= atom
.fixupsEnd(); ++it
) {
1109 if ( it
->offsetInAtom
== off
) {
1110 switch ( it
->clusterSize
) {
1111 case ld::Fixup::k1of1
:
1112 printf(" 0x%04X ", it
->offsetInAtom
);
1115 case ld::Fixup::k1of2
:
1116 printf(" 0x%04X ", it
->offsetInAtom
);
1121 case ld::Fixup::k1of3
:
1122 printf(" 0x%04X ", it
->offsetInAtom
);
1129 case ld::Fixup::k1of4
:
1130 printf(" 0x%04X ", it
->offsetInAtom
);
1139 case ld::Fixup::k1of5
:
1140 printf(" 0x%04X ", it
->offsetInAtom
);
1152 printf(" BAD CLUSTER SIZE: cluster=%d\n", it
->clusterSize
);
1159 if ( sShowLineInfo
) {
1160 if ( atom
.beginLineInfo() != atom
.endLineInfo() ) {
1161 printf("line info:\n");
1162 for (ld::Atom::LineInfo::iterator it
= atom
.beginLineInfo(); it
!= atom
.endLineInfo(); ++it
) {
1163 printf(" offset 0x%04X, line %d, file %s\n", it
->atomOffset
, it
->lineNumber
, it
->fileName
);
1171 static void dumpFile(ld::relocatable::File
* file
)
1174 if ( sDumpStabs
&& (file
->debugInfo() == ld::relocatable::File::kDebugInfoStabs
) ) {
1175 const std::vector
<ld::relocatable::File::Stab
>* stabs
= file
->stabs();
1176 if ( stabs
!= NULL
)
1181 file
->forEachAtom(d
);
1186 std::vector
<ObjectFile::Atom
*> atoms
= reader
->getAtoms();
1188 // make copy of vector and sort (so output is canonical)
1189 std::vector
<ObjectFile::Atom
*> sortedAtoms(atoms
);
1191 std::sort(sortedAtoms
.begin(), sortedAtoms
.end(), AtomSorter());
1193 for(std::vector
<ObjectFile::Atom
*>::iterator it
=sortedAtoms
.begin(); it
!= sortedAtoms
.end(); ++it
) {
1195 dumpAtomLikeNM(*it
);
1203 static ld::relocatable::File
* createReader(const char* path
)
1205 struct stat stat_buf
;
1207 int fd
= ::open(path
, O_RDONLY
, 0);
1209 throwf("cannot open file: %s", path
);
1210 ::fstat(fd
, &stat_buf
);
1211 uint8_t* p
= (uint8_t*)::mmap(NULL
, stat_buf
.st_size
, PROT_READ
, MAP_FILE
| MAP_PRIVATE
, fd
, 0);
1213 if ( p
== (uint8_t*)(-1) )
1214 throwf("cannot mmap file: %s", path
);
1215 const mach_header
* mh
= (mach_header
*)p
;
1216 uint64_t fileLen
= stat_buf
.st_size
;
1217 bool foundFatSlice
= false;
1218 if ( mh
->magic
== OSSwapBigToHostInt32(FAT_MAGIC
) ) {
1219 const struct fat_header
* fh
= (struct fat_header
*)p
;
1220 const struct fat_arch
* archs
= (struct fat_arch
*)(p
+ sizeof(struct fat_header
));
1221 if ( (uint32_t)sPreferredArch
== 0xFFFFFFFF ) {
1222 // just dump first slice of fat .o file
1223 if ( OSSwapBigToHostInt32(fh
->nfat_arch
) > 0 ) {
1224 p
= p
+ OSSwapBigToHostInt32(archs
[0].offset
);
1225 mh
= (struct mach_header
*)p
;
1226 fileLen
= OSSwapBigToHostInt32(archs
[0].size
);
1227 sPreferredArch
= OSSwapBigToHostInt32(archs
[0].cputype
);
1228 sPreferredSubArch
= OSSwapBigToHostInt32(archs
[0].cpusubtype
);
1229 foundFatSlice
= true;
1233 for (unsigned long i
=0; i
< OSSwapBigToHostInt32(fh
->nfat_arch
); ++i
) {
1234 if ( OSSwapBigToHostInt32(archs
[i
].cputype
) == (uint32_t)sPreferredArch
) {
1235 if ( ((uint32_t)sPreferredSubArch
== 0xFFFFFFFF) || ((uint32_t)sPreferredSubArch
== OSSwapBigToHostInt32(archs
[i
].cpusubtype
)) ) {
1236 p
= p
+ OSSwapBigToHostInt32(archs
[i
].offset
);
1237 mh
= (struct mach_header
*)p
;
1238 fileLen
= OSSwapBigToHostInt32(archs
[i
].size
);
1239 foundFatSlice
= true;
1247 mach_o::relocatable::ParserOptions objOpts
;
1248 objOpts
.architecture
= sPreferredArch
;
1249 objOpts
.objSubtypeMustMatch
= false;
1250 objOpts
.logAllFiles
= false;
1251 objOpts
.warnUnwindConversionProblems
= true;
1252 objOpts
.keepDwarfUnwind
= false;
1253 objOpts
.forceDwarfConversion
= false;
1254 objOpts
.verboseOptimizationHints
= true;
1255 objOpts
.armUsesZeroCostExceptions
= true;
1256 objOpts
.subType
= sPreferredSubArch
;
1257 objOpts
.treateBitcodeAsData
= false;
1258 objOpts
.usingBitcode
= true;
1260 if ( ! foundFatSlice
) {
1261 cpu_type_t archOfObj
;
1262 cpu_subtype_t subArchOfObj
;
1263 ld::Platform platform
;
1265 if ( mach_o::relocatable::isObjectFile(p
, &archOfObj
, &subArchOfObj
, &platform
, &minOS
) ) {
1266 objOpts
.architecture
= archOfObj
;
1267 objOpts
.subType
= subArchOfObj
;
1271 ld::relocatable::File
* objResult
= mach_o::relocatable::parse(p
, fileLen
, path
, stat_buf
.st_mtime
, ld::File::Ordinal::NullOrdinal(), objOpts
);
1272 if ( objResult
!= NULL
)
1275 // see if it is an llvm object file
1276 objResult
= lto::parse(p
, fileLen
, path
, stat_buf
.st_mtime
, ld::File::Ordinal::NullOrdinal(), sPreferredArch
, sPreferredSubArch
, false, true);
1277 if ( objResult
!= NULL
)
1280 throwf("not a mach-o object file: %s", path
);
1282 // for peformance testing
1283 for (int i
=0; i
< 500; ++i
) {
1284 ld::relocatable::File
* objResult
= mach_o::relocatable::parse(p
, fileLen
, path
, stat_buf
.st_mtime
, 0, objOpts
);
1295 fprintf(stderr
, "ObjectDump options:\n"
1296 "\t-no_content\tdon't dump contents\n"
1297 "\t-no_section\tdon't dump section name\n"
1298 "\t-no_defintion\tdon't dump definition kind\n"
1299 "\t-no_combine\tdon't dump combine mode\n"
1300 "\t-stabs\t\tdump stabs\n"
1301 "\t-arch aaa\tonly dump info about arch aaa\n"
1302 "\t-only sym\tonly dump info about sym\n"
1303 "\t-align\t\tonly print alignment info\n"
1304 "\t-name\t\tonly print symbol names\n"
1308 int main(int argc
, const char* argv
[])
1316 for(int i
=1; i
< argc
; ++i
) {
1317 const char* arg
= argv
[i
];
1318 if ( arg
[0] == '-' ) {
1319 if ( strcmp(arg
, "-no_content") == 0 ) {
1320 sDumpContent
= false;
1322 else if ( strcmp(arg
, "-nm") == 0 ) {
1325 else if ( strcmp(arg
, "-stabs") == 0 ) {
1328 else if ( strcmp(arg
, "-no_sort") == 0 ) {
1331 else if ( strcmp(arg
, "-no_section") == 0 ) {
1332 sShowSection
= false;
1334 else if ( strcmp(arg
, "-no_definition") == 0 ) {
1335 sShowDefinitionKind
= false;
1337 else if ( strcmp(arg
, "-no_combine") == 0 ) {
1338 sShowCombineKind
= false;
1340 else if ( strcmp(arg
, "-no_line_info") == 0 ) {
1341 sShowLineInfo
= false;
1343 else if ( strcmp(arg
, "-arch") == 0 ) {
1344 const char* archName
= argv
[++i
];
1345 if ( archName
== NULL
)
1346 throw "-arch missing architecture name";
1348 for (const ArchInfo
* t
=archInfoArray
; t
->archName
!= NULL
; ++t
) {
1349 if ( strcmp(t
->archName
,archName
) == 0 ) {
1350 sPreferredArch
= t
->cpuType
;
1352 sPreferredSubArch
= t
->cpuSubType
;
1357 throwf("unknown architecture %s", archName
);
1359 else if ( strcmp(arg
, "-only") == 0 ) {
1360 sMatchName
= ++i
<argc
? argv
[i
]: NULL
;
1362 else if ( strcmp(arg
, "-align") == 0 ) {
1363 sPrintRestrict
= true;
1366 else if ( strcmp(arg
, "-name") == 0 ) {
1367 sPrintRestrict
= true;
1372 throwf("unknown option: %s\n", arg
);
1376 ld::relocatable::File
* reader
= createReader(arg
);
1381 catch (const char* msg
) {
1382 fprintf(stderr
, "ObjDump failed: %s\n", msg
);