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::kindStorePPCBranch24
:
742 printf(", then store as PPC branch24");
744 case ld::Fixup::kindStorePPCBranch14
:
745 printf(", then store as PPC branch14");
747 case ld::Fixup::kindStorePPCPicLow14
:
748 printf(", then store as PPC low14 pic");
750 case ld::Fixup::kindStorePPCPicLow16
:
751 printf(", then store as PPC low14 pic");
753 case ld::Fixup::kindStorePPCPicHigh16AddLow
:
754 printf(", then store as PPC high16 pic");
756 case ld::Fixup::kindStorePPCAbsLow14
:
757 printf(", then store as PPC low14 abs");
759 case ld::Fixup::kindStorePPCAbsLow16
:
760 printf(", then store as PPC low14 abs");
762 case ld::Fixup::kindStorePPCAbsHigh16AddLow
:
763 printf(", then store as PPC high16 abs");
765 case ld::Fixup::kindStorePPCAbsHigh16
:
766 printf(", then store as PPC high16 abs, no carry");
768 case ld::Fixup::kindStoreX86BranchPCRel8
:
769 printf(", then store as x86 8-bit pcrel branch");
771 case ld::Fixup::kindStoreX86BranchPCRel32
:
772 printf(", then store as x86 32-bit pcrel branch");
774 case ld::Fixup::kindStoreX86PCRel8
:
775 printf(", then store as x86 8-bit pcrel");
777 case ld::Fixup::kindStoreX86PCRel16
:
778 printf(", then store as x86 16-bit pcrel");
780 case ld::Fixup::kindStoreX86PCRel32
:
781 printf(", then store as x86 32-bit pcrel");
783 case ld::Fixup::kindStoreX86PCRel32_1
:
784 printf(", then store as x86 32-bit pcrel from +1");
786 case ld::Fixup::kindStoreX86PCRel32_2
:
787 printf(", then store as x86 32-bit pcrel from +2");
789 case ld::Fixup::kindStoreX86PCRel32_4
:
790 printf(", then store as x86 32-bit pcrel from +4");
792 case ld::Fixup::kindStoreX86PCRel32GOTLoad
:
793 printf(", then store as x86 32-bit pcrel GOT load");
795 case ld::Fixup::kindStoreX86PCRel32GOTLoadNowLEA
:
796 printf(", then store as x86 32-bit pcrel GOT load -> LEA");
798 case ld::Fixup::kindStoreX86PCRel32GOT
:
799 printf(", then store as x86 32-bit pcrel GOT access");
801 case ld::Fixup::kindStoreX86PCRel32TLVLoad
:
802 printf(", then store as x86 32-bit pcrel TLV load");
804 case ld::Fixup::kindStoreX86PCRel32TLVLoadNowLEA
:
805 printf(", then store as x86 32-bit pcrel TLV load");
807 case ld::Fixup::kindStoreX86Abs32TLVLoad
:
808 printf(", then store as x86 32-bit absolute TLV load");
810 case ld::Fixup::kindStoreX86Abs32TLVLoadNowLEA
:
811 printf(", then store as x86 32-bit absolute TLV load -> LEA");
813 case ld::Fixup::kindStoreARMBranch24
:
814 printf(", then store as ARM 24-bit pcrel branch");
816 case ld::Fixup::kindStoreThumbBranch22
:
817 printf(", then store as Thumb 22-bit pcrel branch");
819 case ld::Fixup::kindStoreARMLoad12
:
820 printf(", then store as ARM 12-bit pcrel load");
822 case ld::Fixup::kindStoreARMLow16
:
823 printf(", then store low-16 in ARM movw");
825 case ld::Fixup::kindStoreARMHigh16
:
826 printf(", then store high-16 in ARM movt");
828 case ld::Fixup::kindStoreThumbLow16
:
829 printf(", then store low-16 in Thumb movw");
831 case ld::Fixup::kindStoreThumbHigh16
:
832 printf(", then store high-16 in Thumb movt");
834 case ld::Fixup::kindDtraceExtra
:
835 printf("dtrace static probe extra info");
837 case ld::Fixup::kindStoreX86DtraceCallSiteNop
:
838 printf("x86 dtrace static probe site");
840 case ld::Fixup::kindStoreX86DtraceIsEnableSiteClear
:
841 printf("x86 dtrace static is-enabled site");
843 case ld::Fixup::kindStorePPCDtraceCallSiteNop
:
844 printf("ppc dtrace static probe site");
846 case ld::Fixup::kindStorePPCDtraceIsEnableSiteClear
:
847 printf("ppc dtrace static is-enabled site");
849 case ld::Fixup::kindStoreARMDtraceCallSiteNop
:
850 printf("ARM dtrace static probe site");
852 case ld::Fixup::kindStoreARMDtraceIsEnableSiteClear
:
853 printf("ARM dtrace static is-enabled site");
855 case ld::Fixup::kindStoreThumbDtraceCallSiteNop
:
856 printf("Thumb dtrace static probe site");
858 case ld::Fixup::kindStoreThumbDtraceIsEnableSiteClear
:
859 printf("Thumb dtrace static is-enabled site");
861 case ld::Fixup::kindLazyTarget
:
862 printf("lazy reference to external symbol %s", referenceTargetAtomName(ref
));
864 case ld::Fixup::kindSetLazyOffset
:
865 printf("offset of lazy binding info for %s", referenceTargetAtomName(ref
));
867 case ld::Fixup::kindStoreTargetAddressLittleEndian32
:
868 printf("store 32-bit little endian address of %s", referenceTargetAtomName(ref
));
870 case ld::Fixup::kindStoreTargetAddressLittleEndian64
:
871 printf("store 64-bit little endian address of %s", referenceTargetAtomName(ref
));
873 case ld::Fixup::kindStoreTargetAddressBigEndian32
:
874 printf("store 32-bit big endian address of %s", referenceTargetAtomName(ref
));
876 case ld::Fixup::kindStoreTargetAddressBigEndian64
:
877 printf("store 64-bit big endian address of %s", referenceTargetAtomName(ref
));
879 case ld::Fixup::kindStoreTargetAddressX86PCRel32
:
880 printf("x86 store 32-bit pc-rel address of %s", referenceTargetAtomName(ref
));
882 case ld::Fixup::kindStoreTargetAddressX86BranchPCRel32
:
883 printf("x86 store 32-bit pc-rel branch to %s", referenceTargetAtomName(ref
));
885 case ld::Fixup::kindStoreTargetAddressX86PCRel32GOTLoad
:
886 printf("x86 store 32-bit pc-rel GOT load of %s", referenceTargetAtomName(ref
));
888 case ld::Fixup::kindStoreTargetAddressX86PCRel32GOTLoadNowLEA
:
889 printf("x86 store 32-bit pc-rel lea of %s", referenceTargetAtomName(ref
));
891 case ld::Fixup::kindStoreTargetAddressX86PCRel32TLVLoad
:
892 printf("x86 store 32-bit pc-rel TLV load of %s", referenceTargetAtomName(ref
));
894 case ld::Fixup::kindStoreTargetAddressX86PCRel32TLVLoadNowLEA
:
895 printf("x86 store 32-bit pc-rel TLV lea of %s", referenceTargetAtomName(ref
));
897 case ld::Fixup::kindStoreTargetAddressX86Abs32TLVLoad
:
898 printf("x86 store 32-bit absolute TLV load of %s", referenceTargetAtomName(ref
));
900 case ld::Fixup::kindStoreTargetAddressX86Abs32TLVLoadNowLEA
:
901 printf("x86 store 32-bit absolute TLV lea of %s", referenceTargetAtomName(ref
));
903 case ld::Fixup::kindStoreTargetAddressARMBranch24
:
904 printf("ARM store 24-bit pc-rel branch to %s", referenceTargetAtomName(ref
));
906 case ld::Fixup::kindStoreTargetAddressThumbBranch22
:
907 printf("Thumb store 22-bit pc-rel branch to %s", referenceTargetAtomName(ref
));
909 case ld::Fixup::kindStoreTargetAddressARMLoad12
:
910 printf("ARM store 12-bit pc-rel branch to %s", referenceTargetAtomName(ref
));
912 case ld::Fixup::kindStoreTargetAddressPPCBranch24
:
913 printf("PowerPC store 24-bit pc-rel load of %s", referenceTargetAtomName(ref
));
915 case ld::Fixup::kindSetTargetTLVTemplateOffset
:
916 case ld::Fixup::kindSetTargetTLVTemplateOffsetLittleEndian32
:
917 case ld::Fixup::kindSetTargetTLVTemplateOffsetLittleEndian64
:
918 printf("tlv template offset of %s", referenceTargetAtomName(ref
));
920 // printf("unknown fixup");
925 uint64_t dumper::addressOfFirstAtomInSection(const ld::Section
& sect
)
927 uint64_t lowestAddr
= (uint64_t)(-1);
928 for (std::vector
<const ld::Atom
*>::iterator it
=_atoms
.begin(); it
!= _atoms
.end(); ++it
) {
929 const ld::Atom
* atom
= *it
;
930 if ( &atom
->section() == §
) {
931 if ( atom
->objectAddress() < lowestAddr
)
932 lowestAddr
= atom
->objectAddress();
938 void dumper::doAtom(const ld::Atom
& atom
)
940 if ( (sMatchName
!= NULL
) && (strcmp(sMatchName
, atom
.name()) != 0) )
942 _atoms
.push_back(&atom
);
948 std::sort(_atoms
.begin(), _atoms
.end(), AtomSorter());
950 for (std::vector
<const ld::Atom
*>::iterator it
=_atoms
.begin(); it
!= _atoms
.end(); ++it
) {
951 this->dumpAtom(**it
);
955 void dumper::dumpAtom(const ld::Atom
& atom
)
957 printf("name: %s\n", makeName(atom
));
958 printf("size: 0x%0llX\n", atom
.size());
959 printf("align: %u mod %u\n", atom
.alignment().modulus
, (1 << atom
.alignment().powerOf2
) );
960 printf("scope: %s\n", scopeString(atom
));
961 if ( sShowDefinitionKind
)
962 printf("def: %s\n", definitionString(atom
));
963 if ( sShowCombineKind
)
964 printf("combine: %s\n", combineString(atom
));
965 printf("symbol: %s\n", inclusionString(atom
));
966 printf("attrs: %s\n", attributeString(atom
));
968 printf("section: %s,%s\n", atom
.section().segmentName(), atom
.section().sectionName());
969 if ( atom
.beginUnwind() != atom
.endUnwind() ) {
970 uint32_t lastOffset
= 0;
971 uint32_t lastCUE
= 0;
973 const char* label
= "unwind:";
974 for (ld::Atom::UnwindInfo::iterator it
=atom
.beginUnwind(); it
!= atom
.endUnwind(); ++it
) {
976 printf("%s 0x%08X -> 0x%08X: 0x%08X\n", label
, lastOffset
, it
->startOffset
, lastCUE
);
979 lastOffset
= it
->startOffset
;
980 lastCUE
= it
->unwindInfo
;
983 printf("%s 0x%08X -> 0x%08X: 0x%08X\n", label
, lastOffset
, (uint32_t)atom
.size(), lastCUE
);
985 if ( atom
.contentType() == ld::Atom::typeCString
) {
986 uint8_t buffer
[atom
.size()+2];
987 atom
.copyRawContent(buffer
);
988 buffer
[atom
.size()] = '\0';
989 printf("content: \"%s\"\n", buffer
);
991 if ( atom
.fixupsBegin() != atom
.fixupsEnd() ) {
993 for (unsigned int off
=0; off
< atom
.size()+1; ++off
) {
994 for (ld::Fixup::iterator it
= atom
.fixupsBegin(); it
!= atom
.fixupsEnd(); ++it
) {
995 if ( it
->offsetInAtom
== off
) {
996 switch ( it
->clusterSize
) {
997 case ld::Fixup::k1of1
:
998 printf(" 0x%04X ", it
->offsetInAtom
);
1001 case ld::Fixup::k1of2
:
1002 printf(" 0x%04X ", it
->offsetInAtom
);
1007 case ld::Fixup::k1of3
:
1008 printf(" 0x%04X ", it
->offsetInAtom
);
1015 case ld::Fixup::k1of4
:
1016 printf(" 0x%04X ", it
->offsetInAtom
);
1025 case ld::Fixup::k1of5
:
1026 printf(" 0x%04X ", it
->offsetInAtom
);
1038 printf(" BAD CLUSTER SIZE: cluster=%d\n", it
->clusterSize
);
1045 if ( sShowLineInfo
) {
1046 if ( atom
.beginLineInfo() != atom
.endLineInfo() ) {
1047 printf("line info:\n");
1048 for (ld::Atom::LineInfo::iterator it
= atom
.beginLineInfo(); it
!= atom
.endLineInfo(); ++it
) {
1049 printf(" offset 0x%04X, line %d, file %s\n", it
->atomOffset
, it
->lineNumber
, it
->fileName
);
1057 static void dumpFile(ld::relocatable::File
* file
)
1060 if ( sDumpStabs
&& (file
->debugInfo() == ld::relocatable::File::kDebugInfoStabs
) ) {
1061 const std::vector
<ld::relocatable::File::Stab
>* stabs
= file
->stabs();
1062 if ( stabs
!= NULL
)
1067 file
->forEachAtom(d
);
1072 std::vector
<ObjectFile::Atom
*> atoms
= reader
->getAtoms();
1074 // make copy of vector and sort (so output is canonical)
1075 std::vector
<ObjectFile::Atom
*> sortedAtoms(atoms
);
1077 std::sort(sortedAtoms
.begin(), sortedAtoms
.end(), AtomSorter());
1079 for(std::vector
<ObjectFile::Atom
*>::iterator it
=sortedAtoms
.begin(); it
!= sortedAtoms
.end(); ++it
) {
1081 dumpAtomLikeNM(*it
);
1089 static ld::relocatable::File
* createReader(const char* path
)
1091 struct stat stat_buf
;
1093 int fd
= ::open(path
, O_RDONLY
, 0);
1095 throwf("cannot open file: %s", path
);
1096 ::fstat(fd
, &stat_buf
);
1097 uint8_t* p
= (uint8_t*)::mmap(NULL
, stat_buf
.st_size
, PROT_READ
, MAP_FILE
| MAP_PRIVATE
, fd
, 0);
1099 if ( p
== (uint8_t*)(-1) )
1100 throwf("cannot mmap file: %s", path
);
1101 const mach_header
* mh
= (mach_header
*)p
;
1102 uint64_t fileLen
= stat_buf
.st_size
;
1103 bool foundFatSlice
= false;
1104 if ( mh
->magic
== OSSwapBigToHostInt32(FAT_MAGIC
) ) {
1105 const struct fat_header
* fh
= (struct fat_header
*)p
;
1106 const struct fat_arch
* archs
= (struct fat_arch
*)(p
+ sizeof(struct fat_header
));
1107 if ( (uint32_t)sPreferredArch
== 0xFFFFFFFF ) {
1108 // just dump first slice of fat .o file
1109 if ( OSSwapBigToHostInt32(fh
->nfat_arch
) > 0 ) {
1110 p
= p
+ OSSwapBigToHostInt32(archs
[0].offset
);
1111 mh
= (struct mach_header
*)p
;
1112 fileLen
= OSSwapBigToHostInt32(archs
[0].size
);
1113 sPreferredArch
= OSSwapBigToHostInt32(archs
[0].cputype
);
1114 sPreferredSubArch
= OSSwapBigToHostInt32(archs
[0].cpusubtype
);
1115 foundFatSlice
= true;
1119 for (unsigned long i
=0; i
< OSSwapBigToHostInt32(fh
->nfat_arch
); ++i
) {
1120 if ( OSSwapBigToHostInt32(archs
[i
].cputype
) == (uint32_t)sPreferredArch
) {
1121 if ( ((uint32_t)sPreferredSubArch
== 0xFFFFFFFF) || ((uint32_t)sPreferredSubArch
== OSSwapBigToHostInt32(archs
[i
].cpusubtype
)) ) {
1122 p
= p
+ OSSwapBigToHostInt32(archs
[i
].offset
);
1123 mh
= (struct mach_header
*)p
;
1124 fileLen
= OSSwapBigToHostInt32(archs
[i
].size
);
1125 foundFatSlice
= true;
1133 mach_o::relocatable::ParserOptions objOpts
;
1134 objOpts
.architecture
= sPreferredArch
;
1135 objOpts
.objSubtypeMustMatch
= false;
1136 objOpts
.logAllFiles
= false;
1137 objOpts
.convertUnwindInfo
= true;
1138 objOpts
.subType
= sPreferredSubArch
;
1140 if ( ! foundFatSlice
) {
1141 cpu_type_t archOfObj
;
1142 cpu_subtype_t subArchOfObj
;
1143 if ( mach_o::relocatable::isObjectFile(p
, &archOfObj
, &subArchOfObj
) ) {
1144 objOpts
.architecture
= archOfObj
;
1145 objOpts
.subType
= subArchOfObj
;
1149 ld::relocatable::File
* objResult
= mach_o::relocatable::parse(p
, fileLen
, path
, stat_buf
.st_mtime
, 0, objOpts
);
1150 if ( objResult
!= NULL
)
1153 // see if it is an llvm object file
1154 objResult
= lto::parse(p
, fileLen
, path
, stat_buf
.st_mtime
, 0, sPreferredArch
, sPreferredSubArch
, false);
1155 if ( objResult
!= NULL
)
1158 throwf("not a mach-o object file: %s", path
);
1160 // for peformance testing
1161 for (int i
=0; i
< 500; ++i
) {
1162 ld::relocatable::File
* objResult
= mach_o::relocatable::parse(p
, fileLen
, path
, stat_buf
.st_mtime
, 0, objOpts
);
1173 fprintf(stderr
, "ObjectDump options:\n"
1174 "\t-no_content\tdon't dump contents\n"
1175 "\t-no_section\tdon't dump section name\n"
1176 "\t-no_defintion\tdon't dump definition kind\n"
1177 "\t-no_combine\tdon't dump combine mode\n"
1178 "\t-stabs\t\tdump stabs\n"
1179 "\t-arch aaa\tonly dump info about arch aaa\n"
1180 "\t-only sym\tonly dump info about sym\n"
1181 "\t-align\t\tonly print alignment info\n"
1182 "\t-name\t\tonly print symbol names\n"
1186 int main(int argc
, const char* argv
[])
1194 for(int i
=1; i
< argc
; ++i
) {
1195 const char* arg
= argv
[i
];
1196 if ( arg
[0] == '-' ) {
1197 if ( strcmp(arg
, "-no_content") == 0 ) {
1198 sDumpContent
= false;
1200 else if ( strcmp(arg
, "-nm") == 0 ) {
1203 else if ( strcmp(arg
, "-stabs") == 0 ) {
1206 else if ( strcmp(arg
, "-no_sort") == 0 ) {
1209 else if ( strcmp(arg
, "-no_section") == 0 ) {
1210 sShowSection
= false;
1212 else if ( strcmp(arg
, "-no_definition") == 0 ) {
1213 sShowDefinitionKind
= false;
1215 else if ( strcmp(arg
, "-no_combine") == 0 ) {
1216 sShowCombineKind
= false;
1218 else if ( strcmp(arg
, "-no_line_info") == 0 ) {
1219 sShowLineInfo
= false;
1221 else if ( strcmp(arg
, "-arch") == 0 ) {
1222 const char* arch
= ++i
<argc
? argv
[i
]: "";
1223 if ( strcmp(arch
, "ppc64") == 0 )
1224 sPreferredArch
= CPU_TYPE_POWERPC64
;
1225 else if ( strcmp(arch
, "ppc") == 0 )
1226 sPreferredArch
= CPU_TYPE_POWERPC
;
1227 else if ( strcmp(arch
, "i386") == 0 )
1228 sPreferredArch
= CPU_TYPE_I386
;
1229 else if ( strcmp(arch
, "x86_64") == 0 )
1230 sPreferredArch
= CPU_TYPE_X86_64
;
1233 for (const ARMSubType
* t
=ARMSubTypes
; t
->subTypeName
!= NULL
; ++t
) {
1234 if ( strcmp(t
->subTypeName
,arch
) == 0 ) {
1235 sPreferredArch
= CPU_TYPE_ARM
;
1236 sPreferredSubArch
= t
->subType
;
1242 throwf("unknown architecture %s", arch
);
1245 else if ( strcmp(arg
, "-only") == 0 ) {
1246 sMatchName
= ++i
<argc
? argv
[i
]: NULL
;
1248 else if ( strcmp(arg
, "-align") == 0 ) {
1249 sPrintRestrict
= true;
1252 else if ( strcmp(arg
, "-name") == 0 ) {
1253 sPrintRestrict
= true;
1258 throwf("unknown option: %s\n", arg
);
1262 ld::relocatable::File
* reader
= createReader(arg
);
1267 catch (const char* msg
) {
1268 fprintf(stderr
, "ObjDump failed: %s\n", msg
);