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 ( strcmp(atom
->getSectionName(), "__cstring") == 0 ) {
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 std::vector
<ObjectFile::Reference
*>& references
= atom
->getReferences();
318 const int refCount
= references
.size();
319 printf("references: (%u)\n", refCount
);
320 for (int i
=0; i
< refCount
; ++i
) {
321 ObjectFile::Reference
* ref
= references
[i
];
322 printf(" %s\n", ref
->getDescription());
327 if(!sPrintRestrict
) {
328 std::vector
<ObjectFile::LineInfo
>* lineInfo
= atom
->getLineInfo();
329 if ( (lineInfo
!= NULL
) && (lineInfo
->size() > 0) ) {
330 printf("line info: (%lu)\n", lineInfo
->size());
331 for (std::vector
<ObjectFile::LineInfo
>::iterator it
= lineInfo
->begin(); it
!= lineInfo
->end(); ++it
) {
332 printf(" offset 0x%04X, line %d, file %s\n", it
->atomOffset
, it
->lineNumber
, it
->fileName
);
343 bool operator()(const ObjectFile::Atom
* left
, const ObjectFile::Atom
* right
)
347 return (strcmp(left
->getDisplayName(), right
->getDisplayName()) < 0);
352 static void dumpFile(ObjectFile::Reader
* reader
)
355 if ( sDumpStabs
&& (reader
->getDebugInfoKind() == ObjectFile::Reader::kDebugInfoStabs
) ) {
356 std::vector
<ObjectFile::Reader::Stab
>* stabs
= reader
->getStabs();
362 std::vector
<ObjectFile::Atom
*> atoms
= reader
->getAtoms();
364 // make copy of vector and sort (so output is canonical)
365 std::vector
<ObjectFile::Atom
*> sortedAtoms(atoms
);
367 std::sort(sortedAtoms
.begin(), sortedAtoms
.end(), AtomSorter());
369 for(std::vector
<ObjectFile::Atom
*>::iterator it
=sortedAtoms
.begin(); it
!= sortedAtoms
.end(); ++it
) {
378 static ObjectFile::Reader
* createReader(const char* path
, const ObjectFile::ReaderOptions
& options
)
380 struct stat stat_buf
;
382 int fd
= ::open(path
, O_RDONLY
, 0);
384 throwf("cannot open file: %s", path
);
385 ::fstat(fd
, &stat_buf
);
386 uint8_t* p
= (uint8_t*)::mmap(NULL
, stat_buf
.st_size
, PROT_READ
, MAP_FILE
| MAP_PRIVATE
, fd
, 0);
388 const mach_header
* mh
= (mach_header
*)p
;
389 if ( mh
->magic
== OSSwapBigToHostInt32(FAT_MAGIC
) ) {
390 const struct fat_header
* fh
= (struct fat_header
*)p
;
391 const struct fat_arch
* archs
= (struct fat_arch
*)(p
+ sizeof(struct fat_header
));
392 for (unsigned long i
=0; i
< OSSwapBigToHostInt32(fh
->nfat_arch
); ++i
) {
393 if ( OSSwapBigToHostInt32(archs
[i
].cputype
) == (uint32_t)sPreferredArch
) {
394 p
= p
+ OSSwapBigToHostInt32(archs
[i
].offset
);
395 mh
= (struct mach_header
*)p
;
399 if ( mach_o::relocatable::Reader
<x86
>::validFile(p
) )
400 return new mach_o::relocatable::Reader
<x86
>::Reader(p
, path
, 0, options
, 0);
401 else if ( mach_o::relocatable::Reader
<ppc
>::validFile(p
) )
402 return new mach_o::relocatable::Reader
<ppc
>::Reader(p
, path
, 0, options
, 0);
403 else if ( mach_o::relocatable::Reader
<ppc64
>::validFile(p
) )
404 return new mach_o::relocatable::Reader
<ppc64
>::Reader(p
, path
, 0, options
, 0);
405 else if ( mach_o::relocatable::Reader
<x86_64
>::validFile(p
) )
406 return new mach_o::relocatable::Reader
<x86_64
>::Reader(p
, path
, 0, options
, 0);
407 else if ( mach_o::relocatable::Reader
<arm
>::validFile(p
) )
408 return new mach_o::relocatable::Reader
<arm
>::Reader(p
, path
, 0, options
, 0);
410 if ( lto::Reader::validFile(p
, stat_buf
.st_size
, 0) ) {
411 return new lto::Reader(p
, stat_buf
.st_size
, path
, 0, options
, 0);
415 throwf("not a mach-o object file: %s", path
);
422 fprintf(stderr
, "ObjectDump options:\n"
423 "\t-no_content\tdon't dump contents\n"
424 "\t-stabs\t\tdump stabs\n"
425 "\t-arch aaa\tonly dump info about arch aaa\n"
426 "\t-only sym\tonly dump info about sym\n"
427 "\t-align\t\tonly print alignment info\n"
428 "\t-name\t\tonly print symbol names\n"
432 int main(int argc
, const char* argv
[])
439 ObjectFile::ReaderOptions options
;
441 for(int i
=1; i
< argc
; ++i
) {
442 const char* arg
= argv
[i
];
443 if ( arg
[0] == '-' ) {
444 if ( strcmp(arg
, "-no_content") == 0 ) {
445 sDumpContent
= false;
447 else if ( strcmp(arg
, "-nm") == 0 ) {
450 else if ( strcmp(arg
, "-stabs") == 0 ) {
453 else if ( strcmp(arg
, "-no_sort") == 0 ) {
456 else if ( strcmp(arg
, "-arch") == 0 ) {
457 const char* arch
= ++i
<argc
? argv
[i
]: "";
458 if ( strcmp(arch
, "ppc64") == 0 )
459 sPreferredArch
= CPU_TYPE_POWERPC64
;
460 else if ( strcmp(arch
, "ppc") == 0 )
461 sPreferredArch
= CPU_TYPE_POWERPC
;
462 else if ( strcmp(arch
, "i386") == 0 )
463 sPreferredArch
= CPU_TYPE_I386
;
464 else if ( strcmp(arch
, "x86_64") == 0 )
465 sPreferredArch
= CPU_TYPE_X86_64
;
467 throwf("unknown architecture %s", arch
);
469 else if ( strcmp(arg
, "-only") == 0 ) {
470 sMatchName
= ++i
<argc
? argv
[i
]: NULL
;
472 else if ( strcmp(arg
, "-align") == 0 ) {
473 sPrintRestrict
= true;
476 else if ( strcmp(arg
, "-name") == 0 ) {
477 sPrintRestrict
= true;
482 throwf("unknown option: %s\n", arg
);
486 ObjectFile::Reader
* reader
= createReader(arg
, options
);
491 catch (const char* msg
) {
492 fprintf(stderr
, "ObjDump failed: %s\n", msg
);