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_POWERPC64
;
44 static const char* sMatchName
;
45 static int sPrintRestrict
;
46 static int sPrintAlign
;
47 static int sPrintName
;
50 __attribute__((noreturn
))
51 void throwf(const char* format
, ...)
55 va_start(list
, format
);
56 vasprintf(&p
, format
, list
);
63 void warning(const char* format
, ...)
66 fprintf(stderr
, "warning: ");
67 va_start(list
, format
);
68 vfprintf(stderr
, format
, list
);
70 fprintf(stderr
, "\n");
73 static void dumpStabs(std::vector
<ObjectFile::Reader::Stab
>* stabs
)
76 printf("stabs: (%lu)\n", stabs
->size());
77 for (std::vector
<ObjectFile::Reader::Stab
>::iterator it
= stabs
->begin(); it
!= stabs
->end(); ++it
) {
78 ObjectFile::Reader::Stab
& stab
= *it
;
79 const char* code
= "?????";
166 printf(" [atom=%20s] %02X %04X %s %s\n", ((stab
.atom
!= NULL
) ? stab
.atom
->getDisplayName() : ""), stab
.other
, stab
.desc
, code
, stab
.string
);
171 static void dumpAtomLikeNM(ObjectFile::Atom
* atom
)
173 uint32_t size
= atom
->getSize();
175 const char* visibility
;
176 switch ( atom
->getScope() ) {
177 case ObjectFile::Atom::scopeTranslationUnit
:
178 visibility
= "internal";
180 case ObjectFile::Atom::scopeLinkageUnit
:
181 visibility
= "hidden ";
183 case ObjectFile::Atom::scopeGlobal
:
184 visibility
= "global ";
192 switch ( atom
->getDefinitionKind() ) {
193 case ObjectFile::Atom::kRegularDefinition
:
196 case ObjectFile::Atom::kTentativeDefinition
:
199 case ObjectFile::Atom::kWeakDefinition
:
202 case ObjectFile::Atom::kAbsoluteSymbol
:
210 printf("0x%08X %s %s %s\n", size
, visibility
, kind
, atom
->getDisplayName());
214 static void dumpAtom(ObjectFile::Atom
* atom
)
216 if(sMatchName
&& strcmp(sMatchName
, atom
->getDisplayName()))
219 //printf("atom: %p\n", atom);
222 if(!sPrintRestrict
|| sPrintName
)
223 printf("name: %s\n", atom
->getDisplayName());
227 switch ( atom
->getScope() ) {
228 case ObjectFile::Atom::scopeTranslationUnit
:
229 printf("scope: translation unit\n");
231 case ObjectFile::Atom::scopeLinkageUnit
:
232 printf("scope: linkage unit\n");
234 case ObjectFile::Atom::scopeGlobal
:
235 printf("scope: global\n");
238 printf("scope: unknown\n");
243 switch ( atom
->getDefinitionKind() ) {
244 case ObjectFile::Atom::kRegularDefinition
:
245 printf("kind: regular\n");
247 case ObjectFile::Atom::kWeakDefinition
:
248 printf("kind: weak\n");
250 case ObjectFile::Atom::kTentativeDefinition
:
251 printf("kind: tentative\n");
253 case ObjectFile::Atom::kExternalDefinition
:
254 printf("kind: import\n");
256 case ObjectFile::Atom::kExternalWeakDefinition
:
257 printf("kind: weak import\n");
259 case ObjectFile::Atom::kAbsoluteSymbol
:
260 printf("kind: absolute symbol\n");
263 printf("kind: unknown\n");
266 // segment and section
267 if(!sPrintRestrict
&& (atom
->getSectionName() != NULL
) )
268 printf("section: %s,%s\n", atom
->getSegment().getName(), atom
->getSectionName());
271 if(!sPrintRestrict
) {
273 if ( atom
->dontDeadStrip() )
274 printf("dont-dead-strip ");
275 if ( atom
->isZeroFill() )
276 printf("zero-fill ");
277 if ( atom
->isThumb() )
284 printf("size: 0x%012llX\n", atom
->getSize());
287 if(!sPrintRestrict
|| sPrintAlign
)
288 printf("align: %u mod %u\n", atom
->getAlignment().modulus
, (1 << atom
->getAlignment().powerOf2
) );
291 if (!sPrintRestrict
&& sDumpContent
) {
292 uint64_t size
= atom
->getSize();
294 uint8_t content
[size
];
295 atom
->copyRawContent(content
);
297 if ( atom
->getContentType() == ObjectFile::Atom::kCStringType
) {
299 for (unsigned int i
=0; i
< size
; ++i
) {
300 if(content
[i
]<'!' || content
[i
]>=127)
301 printf("\\%o", content
[i
]);
303 printf("%c", content
[i
]);
308 for (unsigned int i
=0; i
< size
; ++i
)
309 printf("%02X ", content
[i
]);
316 if(!sPrintRestrict
) {
317 if ( atom
->beginUnwind() != atom
->endUnwind() ) {
318 printf("unwind encodings:\n");
319 for (ObjectFile::UnwindInfo::iterator it
= atom
->beginUnwind(); it
!= atom
->endUnwind(); ++it
) {
320 printf("\t 0x%04X 0x%08X\n", it
->startOffset
, it
->unwindInfo
);
326 if(!sPrintRestrict
) {
327 std::vector
<ObjectFile::Reference
*>& references
= atom
->getReferences();
328 const int refCount
= references
.size();
329 printf("references: (%u)\n", refCount
);
330 for (int i
=0; i
< refCount
; ++i
) {
331 ObjectFile::Reference
* ref
= references
[i
];
332 printf(" %s\n", ref
->getDescription());
337 if(!sPrintRestrict
) {
338 std::vector
<ObjectFile::LineInfo
>* lineInfo
= atom
->getLineInfo();
339 if ( (lineInfo
!= NULL
) && (lineInfo
->size() > 0) ) {
340 printf("line info: (%lu)\n", lineInfo
->size());
341 for (std::vector
<ObjectFile::LineInfo
>::iterator it
= lineInfo
->begin(); it
!= lineInfo
->end(); ++it
) {
342 printf(" offset 0x%04X, line %d, file %s\n", it
->atomOffset
, it
->lineNumber
, it
->fileName
);
353 bool operator()(const ObjectFile::Atom
* left
, const ObjectFile::Atom
* right
)
357 int name
= strcmp(left
->getDisplayName(), right
->getDisplayName());
359 return (left
->getSize() < right
->getSize());
366 static void dumpFile(ObjectFile::Reader
* reader
)
369 if ( sDumpStabs
&& (reader
->getDebugInfoKind() == ObjectFile::Reader::kDebugInfoStabs
) ) {
370 std::vector
<ObjectFile::Reader::Stab
>* stabs
= reader
->getStabs();
376 std::vector
<ObjectFile::Atom
*> atoms
= reader
->getAtoms();
378 // make copy of vector and sort (so output is canonical)
379 std::vector
<ObjectFile::Atom
*> sortedAtoms(atoms
);
381 std::sort(sortedAtoms
.begin(), sortedAtoms
.end(), AtomSorter());
383 for(std::vector
<ObjectFile::Atom
*>::iterator it
=sortedAtoms
.begin(); it
!= sortedAtoms
.end(); ++it
) {
392 static ObjectFile::Reader
* createReader(const char* path
, const ObjectFile::ReaderOptions
& options
)
394 struct stat stat_buf
;
396 int fd
= ::open(path
, O_RDONLY
, 0);
398 throwf("cannot open file: %s", path
);
399 ::fstat(fd
, &stat_buf
);
400 uint8_t* p
= (uint8_t*)::mmap(NULL
, stat_buf
.st_size
, PROT_READ
, MAP_FILE
| MAP_PRIVATE
, fd
, 0);
402 const mach_header
* mh
= (mach_header
*)p
;
403 if ( mh
->magic
== OSSwapBigToHostInt32(FAT_MAGIC
) ) {
404 const struct fat_header
* fh
= (struct fat_header
*)p
;
405 const struct fat_arch
* archs
= (struct fat_arch
*)(p
+ sizeof(struct fat_header
));
406 for (unsigned long i
=0; i
< OSSwapBigToHostInt32(fh
->nfat_arch
); ++i
) {
407 if ( OSSwapBigToHostInt32(archs
[i
].cputype
) == (uint32_t)sPreferredArch
) {
408 p
= p
+ OSSwapBigToHostInt32(archs
[i
].offset
);
409 mh
= (struct mach_header
*)p
;
413 if ( mach_o::relocatable::Reader
<x86
>::validFile(p
) )
414 return new mach_o::relocatable::Reader
<x86
>::Reader(p
, path
, 0, options
, 0);
415 else if ( mach_o::relocatable::Reader
<ppc
>::validFile(p
) )
416 return new mach_o::relocatable::Reader
<ppc
>::Reader(p
, path
, 0, options
, 0);
417 else if ( mach_o::relocatable::Reader
<ppc64
>::validFile(p
) )
418 return new mach_o::relocatable::Reader
<ppc64
>::Reader(p
, path
, 0, options
, 0);
419 else if ( mach_o::relocatable::Reader
<x86_64
>::validFile(p
) )
420 return new mach_o::relocatable::Reader
<x86_64
>::Reader(p
, path
, 0, options
, 0);
421 else if ( mach_o::relocatable::Reader
<arm
>::validFile(p
) )
422 return new mach_o::relocatable::Reader
<arm
>::Reader(p
, path
, 0, options
, 0);
424 if ( lto::Reader::validFile(p
, stat_buf
.st_size
, 0) ) {
425 return new lto::Reader(p
, stat_buf
.st_size
, path
, 0, options
, 0);
429 throwf("not a mach-o object file: %s", path
);
436 fprintf(stderr
, "ObjectDump options:\n"
437 "\t-no_content\tdon't dump contents\n"
438 "\t-stabs\t\tdump stabs\n"
439 "\t-arch aaa\tonly dump info about arch aaa\n"
440 "\t-only sym\tonly dump info about sym\n"
441 "\t-align\t\tonly print alignment info\n"
442 "\t-name\t\tonly print symbol names\n"
446 int main(int argc
, const char* argv
[])
453 ObjectFile::ReaderOptions options
;
454 options
.fAddCompactUnwindEncoding
= true;
456 for(int i
=1; i
< argc
; ++i
) {
457 const char* arg
= argv
[i
];
458 if ( arg
[0] == '-' ) {
459 if ( strcmp(arg
, "-no_content") == 0 ) {
460 sDumpContent
= false;
462 else if ( strcmp(arg
, "-nm") == 0 ) {
465 else if ( strcmp(arg
, "-stabs") == 0 ) {
468 else if ( strcmp(arg
, "-no_sort") == 0 ) {
471 else if ( strcmp(arg
, "-arch") == 0 ) {
472 const char* arch
= ++i
<argc
? argv
[i
]: "";
473 if ( strcmp(arch
, "ppc64") == 0 )
474 sPreferredArch
= CPU_TYPE_POWERPC64
;
475 else if ( strcmp(arch
, "ppc") == 0 )
476 sPreferredArch
= CPU_TYPE_POWERPC
;
477 else if ( strcmp(arch
, "i386") == 0 )
478 sPreferredArch
= CPU_TYPE_I386
;
479 else if ( strcmp(arch
, "x86_64") == 0 )
480 sPreferredArch
= CPU_TYPE_X86_64
;
481 else if ( strcmp(arch
, "arm") == 0 )
482 sPreferredArch
= CPU_TYPE_ARM
;
483 else if ( strcmp(arch
, "armv6") == 0 )
484 sPreferredArch
= CPU_TYPE_ARM
;
486 throwf("unknown architecture %s", arch
);
488 else if ( strcmp(arg
, "-only") == 0 ) {
489 sMatchName
= ++i
<argc
? argv
[i
]: NULL
;
491 else if ( strcmp(arg
, "-align") == 0 ) {
492 sPrintRestrict
= true;
495 else if ( strcmp(arg
, "-name") == 0 ) {
496 sPrintRestrict
= true;
501 throwf("unknown option: %s\n", arg
);
505 ObjectFile::Reader
* reader
= createReader(arg
, options
);
510 catch (const char* msg
) {
511 fprintf(stderr
, "ObjDump failed: %s\n", msg
);