1 /* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
3 * Copyright (c) 2005-2006 Apple Computer, 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>
31 #include "MachOReaderRelocatable.hpp"
36 #include "LTOReader.hpp"
39 static bool sDumpContent
= true;
40 static bool sDumpStabs
= false;
41 static bool sSort
= true;
42 static bool sNMmode
= false;
43 static cpu_type_t sPreferredArch
= CPU_TYPE_I386
;
44 static cpu_subtype_t sPreferredSubArch
= 0xFFFFFFFF;
45 static const char* sMatchName
;
46 static int sPrintRestrict
;
47 static int sPrintAlign
;
48 static int sPrintName
;
51 __attribute__((noreturn
))
52 void throwf(const char* format
, ...)
56 va_start(list
, format
);
57 vasprintf(&p
, format
, list
);
64 void warning(const char* format
, ...)
67 fprintf(stderr
, "warning: ");
68 va_start(list
, format
);
69 vfprintf(stderr
, format
, list
);
71 fprintf(stderr
, "\n");
74 static void dumpStabs(std::vector
<ObjectFile::Reader::Stab
>* stabs
)
77 printf("stabs: (%lu)\n", stabs
->size());
78 for (std::vector
<ObjectFile::Reader::Stab
>::iterator it
= stabs
->begin(); it
!= stabs
->end(); ++it
) {
79 ObjectFile::Reader::Stab
& stab
= *it
;
80 const char* code
= "?????";
167 printf(" [atom=%20s] %02X %04X %s %s\n", ((stab
.atom
!= NULL
) ? stab
.atom
->getDisplayName() : ""), stab
.other
, stab
.desc
, code
, stab
.string
);
172 static void dumpAtomLikeNM(ObjectFile::Atom
* atom
)
174 uint32_t size
= atom
->getSize();
176 const char* visibility
;
177 switch ( atom
->getScope() ) {
178 case ObjectFile::Atom::scopeTranslationUnit
:
179 visibility
= "internal";
181 case ObjectFile::Atom::scopeLinkageUnit
:
182 visibility
= "hidden ";
184 case ObjectFile::Atom::scopeGlobal
:
185 visibility
= "global ";
193 switch ( atom
->getDefinitionKind() ) {
194 case ObjectFile::Atom::kRegularDefinition
:
197 case ObjectFile::Atom::kTentativeDefinition
:
200 case ObjectFile::Atom::kWeakDefinition
:
203 case ObjectFile::Atom::kAbsoluteSymbol
:
211 printf("0x%08X %s %s %s\n", size
, visibility
, kind
, atom
->getDisplayName());
215 static void dumpAtom(ObjectFile::Atom
* atom
)
217 if(sMatchName
&& strcmp(sMatchName
, atom
->getDisplayName()))
220 //printf("atom: %p\n", atom);
223 if(!sPrintRestrict
|| sPrintName
)
224 printf("name: %s\n", atom
->getDisplayName());
228 switch ( atom
->getScope() ) {
229 case ObjectFile::Atom::scopeTranslationUnit
:
230 printf("scope: translation unit\n");
232 case ObjectFile::Atom::scopeLinkageUnit
:
233 printf("scope: linkage unit\n");
235 case ObjectFile::Atom::scopeGlobal
:
236 printf("scope: global\n");
239 printf("scope: unknown\n");
244 switch ( atom
->getDefinitionKind() ) {
245 case ObjectFile::Atom::kRegularDefinition
:
246 printf("kind: regular\n");
248 case ObjectFile::Atom::kWeakDefinition
:
249 printf("kind: weak\n");
251 case ObjectFile::Atom::kTentativeDefinition
:
252 printf("kind: tentative\n");
254 case ObjectFile::Atom::kExternalDefinition
:
255 printf("kind: import\n");
257 case ObjectFile::Atom::kExternalWeakDefinition
:
258 printf("kind: weak import\n");
260 case ObjectFile::Atom::kAbsoluteSymbol
:
261 printf("kind: absolute symbol\n");
264 printf("kind: unknown\n");
267 // segment and section
268 if(!sPrintRestrict
&& (atom
->getSectionName() != NULL
) )
269 printf("section: %s,%s\n", atom
->getSegment().getName(), atom
->getSectionName());
272 if(!sPrintRestrict
) {
274 if ( atom
->dontDeadStrip() )
275 printf("dont-dead-strip ");
276 if ( atom
->isZeroFill() )
277 printf("zero-fill ");
278 if ( atom
->isThumb() )
285 printf("size: 0x%012llX\n", atom
->getSize());
288 if(!sPrintRestrict
|| sPrintAlign
)
289 printf("align: %u mod %u\n", atom
->getAlignment().modulus
, (1 << atom
->getAlignment().powerOf2
) );
292 if (!sPrintRestrict
&& sDumpContent
) {
293 uint64_t size
= atom
->getSize();
295 uint8_t content
[size
];
296 atom
->copyRawContent(content
);
298 if ( atom
->getContentType() == ObjectFile::Atom::kCStringType
) {
300 for (unsigned int i
=0; i
< size
; ++i
) {
301 if(content
[i
]<'!' || content
[i
]>=127)
302 printf("\\%o", content
[i
]);
304 printf("%c", content
[i
]);
309 for (unsigned int i
=0; i
< size
; ++i
)
310 printf("%02X ", content
[i
]);
317 if(!sPrintRestrict
) {
318 if ( atom
->beginUnwind() != atom
->endUnwind() ) {
319 printf("unwind encodings:\n");
320 for (ObjectFile::UnwindInfo::iterator it
= atom
->beginUnwind(); it
!= atom
->endUnwind(); ++it
) {
321 printf("\t 0x%04X 0x%08X\n", it
->startOffset
, it
->unwindInfo
);
327 if(!sPrintRestrict
) {
328 std::vector
<ObjectFile::Reference
*>& references
= atom
->getReferences();
329 const int refCount
= references
.size();
330 printf("references: (%u)\n", refCount
);
331 for (int i
=0; i
< refCount
; ++i
) {
332 ObjectFile::Reference
* ref
= references
[i
];
333 printf(" %s\n", ref
->getDescription());
338 if(!sPrintRestrict
) {
339 std::vector
<ObjectFile::LineInfo
>* lineInfo
= atom
->getLineInfo();
340 if ( (lineInfo
!= NULL
) && (lineInfo
->size() > 0) ) {
341 printf("line info: (%lu)\n", lineInfo
->size());
342 for (std::vector
<ObjectFile::LineInfo
>::iterator it
= lineInfo
->begin(); it
!= lineInfo
->end(); ++it
) {
343 printf(" offset 0x%04X, line %d, file %s\n", it
->atomOffset
, it
->lineNumber
, it
->fileName
);
354 bool operator()(const ObjectFile::Atom
* left
, const ObjectFile::Atom
* right
)
358 int name
= strcmp(left
->getDisplayName(), right
->getDisplayName());
360 return (left
->getSize() < right
->getSize());
367 static void dumpFile(ObjectFile::Reader
* reader
)
370 if ( sDumpStabs
&& (reader
->getDebugInfoKind() == ObjectFile::Reader::kDebugInfoStabs
) ) {
371 std::vector
<ObjectFile::Reader::Stab
>* stabs
= reader
->getStabs();
377 std::vector
<ObjectFile::Atom
*> atoms
= reader
->getAtoms();
379 // make copy of vector and sort (so output is canonical)
380 std::vector
<ObjectFile::Atom
*> sortedAtoms(atoms
);
382 std::sort(sortedAtoms
.begin(), sortedAtoms
.end(), AtomSorter());
384 for(std::vector
<ObjectFile::Atom
*>::iterator it
=sortedAtoms
.begin(); it
!= sortedAtoms
.end(); ++it
) {
393 static ObjectFile::Reader
* createReader(const char* path
, const ObjectFile::ReaderOptions
& options
)
395 struct stat stat_buf
;
397 int fd
= ::open(path
, O_RDONLY
, 0);
399 throwf("cannot open file: %s", path
);
400 ::fstat(fd
, &stat_buf
);
401 uint8_t* p
= (uint8_t*)::mmap(NULL
, stat_buf
.st_size
, PROT_READ
, MAP_FILE
| MAP_PRIVATE
, fd
, 0);
403 const mach_header
* mh
= (mach_header
*)p
;
404 if ( mh
->magic
== OSSwapBigToHostInt32(FAT_MAGIC
) ) {
405 const struct fat_header
* fh
= (struct fat_header
*)p
;
406 const struct fat_arch
* archs
= (struct fat_arch
*)(p
+ sizeof(struct fat_header
));
407 for (unsigned long i
=0; i
< OSSwapBigToHostInt32(fh
->nfat_arch
); ++i
) {
408 if ( OSSwapBigToHostInt32(archs
[i
].cputype
) == (uint32_t)sPreferredArch
) {
409 if ( ((uint32_t)sPreferredSubArch
== 0xFFFFFFFF) || ((uint32_t)sPreferredSubArch
== OSSwapBigToHostInt32(archs
[i
].cpusubtype
)) ) {
410 p
= p
+ OSSwapBigToHostInt32(archs
[i
].offset
);
411 mh
= (struct mach_header
*)p
;
417 if ( mach_o::relocatable::Reader
<x86
>::validFile(p
) )
418 return new mach_o::relocatable::Reader
<x86
>::Reader(p
, path
, 0, options
, 0);
419 else if ( mach_o::relocatable::Reader
<ppc
>::validFile(p
) )
420 return new mach_o::relocatable::Reader
<ppc
>::Reader(p
, path
, 0, options
, 0);
421 else if ( mach_o::relocatable::Reader
<ppc64
>::validFile(p
) )
422 return new mach_o::relocatable::Reader
<ppc64
>::Reader(p
, path
, 0, options
, 0);
423 else if ( mach_o::relocatable::Reader
<x86_64
>::validFile(p
) )
424 return new mach_o::relocatable::Reader
<x86_64
>::Reader(p
, path
, 0, options
, 0);
425 else if ( mach_o::relocatable::Reader
<arm
>::validFile(p
) )
426 return new mach_o::relocatable::Reader
<arm
>::Reader(p
, path
, 0, options
, 0);
428 if ( lto::Reader::validFile(p
, stat_buf
.st_size
, 0) ) {
429 return new lto::Reader(p
, stat_buf
.st_size
, path
, 0, options
, 0);
433 throwf("not a mach-o object file: %s", path
);
440 fprintf(stderr
, "ObjectDump options:\n"
441 "\t-no_content\tdon't dump contents\n"
442 "\t-stabs\t\tdump stabs\n"
443 "\t-arch aaa\tonly dump info about arch aaa\n"
444 "\t-only sym\tonly dump info about sym\n"
445 "\t-align\t\tonly print alignment info\n"
446 "\t-name\t\tonly print symbol names\n"
450 int main(int argc
, const char* argv
[])
457 ObjectFile::ReaderOptions options
;
458 options
.fAddCompactUnwindEncoding
= true;
460 for(int i
=1; i
< argc
; ++i
) {
461 const char* arg
= argv
[i
];
462 if ( arg
[0] == '-' ) {
463 if ( strcmp(arg
, "-no_content") == 0 ) {
464 sDumpContent
= false;
466 else if ( strcmp(arg
, "-nm") == 0 ) {
469 else if ( strcmp(arg
, "-stabs") == 0 ) {
472 else if ( strcmp(arg
, "-no_sort") == 0 ) {
475 else if ( strcmp(arg
, "-arch") == 0 ) {
476 const char* arch
= ++i
<argc
? argv
[i
]: "";
477 if ( strcmp(arch
, "ppc64") == 0 )
478 sPreferredArch
= CPU_TYPE_POWERPC64
;
479 else if ( strcmp(arch
, "ppc") == 0 )
480 sPreferredArch
= CPU_TYPE_POWERPC
;
481 else if ( strcmp(arch
, "i386") == 0 )
482 sPreferredArch
= CPU_TYPE_I386
;
483 else if ( strcmp(arch
, "x86_64") == 0 )
484 sPreferredArch
= CPU_TYPE_X86_64
;
485 else if ( strcmp(arch
, "arm") == 0 )
486 sPreferredArch
= CPU_TYPE_ARM
;
487 else if ( strcmp(arch
, "armv4t") == 0 ) {
488 sPreferredArch
= CPU_TYPE_ARM
;
489 sPreferredSubArch
= CPU_SUBTYPE_ARM_V4T
;
491 else if ( strcmp(arch
, "armv5") == 0 ) {
492 sPreferredArch
= CPU_TYPE_ARM
;
493 sPreferredSubArch
= CPU_SUBTYPE_ARM_V5TEJ
;
495 else if ( strcmp(arch
, "armv6") == 0 ) {
496 sPreferredArch
= CPU_TYPE_ARM
;
497 sPreferredSubArch
= CPU_SUBTYPE_ARM_V6
;
499 else if ( strcmp(arch
, "armv7") == 0 ) {
500 sPreferredArch
= CPU_TYPE_ARM
;
501 sPreferredSubArch
= CPU_SUBTYPE_ARM_V7
;
504 throwf("unknown architecture %s", arch
);
506 else if ( strcmp(arg
, "-only") == 0 ) {
507 sMatchName
= ++i
<argc
? argv
[i
]: NULL
;
509 else if ( strcmp(arg
, "-align") == 0 ) {
510 sPrintRestrict
= true;
513 else if ( strcmp(arg
, "-name") == 0 ) {
514 sPrintRestrict
= true;
519 throwf("unknown option: %s\n", arg
);
523 ObjectFile::Reader
* reader
= createReader(arg
, options
);
528 catch (const char* msg
) {
529 fprintf(stderr
, "ObjDump failed: %s\n", msg
);