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"
32 #include "LTOReader.hpp"
34 static bool sDumpContent
= true;
35 static bool sDumpStabs
= false;
36 static bool sSort
= true;
37 static bool sNMmode
= false;
38 static cpu_type_t sPreferredArch
= CPU_TYPE_POWERPC64
;
39 static const char* sMatchName
;
40 static int sPrintRestrict
;
41 static int sPrintAlign
;
42 static int sPrintName
;
45 __attribute__((noreturn
))
46 void throwf(const char* format
, ...)
50 va_start(list
, format
);
51 vasprintf(&p
, format
, list
);
58 void warning(const char* format
, ...)
61 fprintf(stderr
, "warning: ");
62 va_start(list
, format
);
63 vfprintf(stderr
, format
, list
);
65 fprintf(stderr
, "\n");
68 static void dumpStabs(std::vector
<ObjectFile::Reader::Stab
>* stabs
)
71 printf("stabs: (%lu)\n", stabs
->size());
72 for (std::vector
<ObjectFile::Reader::Stab
>::iterator it
= stabs
->begin(); it
!= stabs
->end(); ++it
) {
73 ObjectFile::Reader::Stab
& stab
= *it
;
74 const char* code
= "?????";
161 printf(" [atom=%20s] %02X %04X %s %s\n", ((stab
.atom
!= NULL
) ? stab
.atom
->getDisplayName() : ""), stab
.other
, stab
.desc
, code
, stab
.string
);
166 static void dumpAtomLikeNM(ObjectFile::Atom
* atom
)
168 uint32_t size
= atom
->getSize();
170 const char* visibility
;
171 switch ( atom
->getScope() ) {
172 case ObjectFile::Atom::scopeTranslationUnit
:
173 visibility
= "internal";
175 case ObjectFile::Atom::scopeLinkageUnit
:
176 visibility
= "hidden ";
178 case ObjectFile::Atom::scopeGlobal
:
179 visibility
= "global ";
187 switch ( atom
->getDefinitionKind() ) {
188 case ObjectFile::Atom::kRegularDefinition
:
191 case ObjectFile::Atom::kTentativeDefinition
:
194 case ObjectFile::Atom::kWeakDefinition
:
197 case ObjectFile::Atom::kAbsoluteSymbol
:
205 printf("0x%08X %s %s %s\n", size
, visibility
, kind
, atom
->getDisplayName());
209 static void dumpAtom(ObjectFile::Atom
* atom
)
211 if(sMatchName
&& strcmp(sMatchName
, atom
->getDisplayName()))
214 //printf("atom: %p\n", atom);
217 if(!sPrintRestrict
|| sPrintName
)
218 printf("name: %s\n", atom
->getDisplayName());
222 switch ( atom
->getScope() ) {
223 case ObjectFile::Atom::scopeTranslationUnit
:
224 printf("scope: translation unit\n");
226 case ObjectFile::Atom::scopeLinkageUnit
:
227 printf("scope: linkage unit\n");
229 case ObjectFile::Atom::scopeGlobal
:
230 printf("scope: global\n");
233 printf("scope: unknown\n");
238 switch ( atom
->getDefinitionKind() ) {
239 case ObjectFile::Atom::kRegularDefinition
:
240 printf("kind: regular\n");
242 case ObjectFile::Atom::kWeakDefinition
:
243 printf("kind: weak\n");
245 case ObjectFile::Atom::kTentativeDefinition
:
246 printf("kind: tentative\n");
248 case ObjectFile::Atom::kExternalDefinition
:
249 printf("kind: import\n");
251 case ObjectFile::Atom::kExternalWeakDefinition
:
252 printf("kind: weak import\n");
254 case ObjectFile::Atom::kAbsoluteSymbol
:
255 printf("kind: absolute symbol\n");
258 printf("kind: unknown\n");
261 // segment and section
262 if(!sPrintRestrict
&& (atom
->getSectionName() != NULL
) )
263 printf("section: %s,%s\n", atom
->getSegment().getName(), atom
->getSectionName());
266 if(!sPrintRestrict
) {
268 if ( atom
->dontDeadStrip() )
269 printf("dont-dead-strip ");
270 if ( atom
->isZeroFill() )
271 printf("zero-fill ");
272 if ( atom
->isThumb() )
279 printf("size: 0x%012llX\n", atom
->getSize());
282 if(!sPrintRestrict
|| sPrintAlign
)
283 printf("align: %u mod %u\n", atom
->getAlignment().modulus
, (1 << atom
->getAlignment().powerOf2
) );
286 if (!sPrintRestrict
&& sDumpContent
) {
287 uint64_t size
= atom
->getSize();
289 uint8_t content
[size
];
290 atom
->copyRawContent(content
);
292 if ( strcmp(atom
->getSectionName(), "__cstring") == 0 ) {
294 for (unsigned int i
=0; i
< size
; ++i
) {
295 if(content
[i
]<'!' || content
[i
]>=127)
296 printf("\\%o", content
[i
]);
298 printf("%c", content
[i
]);
303 for (unsigned int i
=0; i
< size
; ++i
)
304 printf("%02X ", content
[i
]);
311 if(!sPrintRestrict
) {
312 std::vector
<ObjectFile::Reference
*>& references
= atom
->getReferences();
313 const int refCount
= references
.size();
314 printf("references: (%u)\n", refCount
);
315 for (int i
=0; i
< refCount
; ++i
) {
316 ObjectFile::Reference
* ref
= references
[i
];
317 printf(" %s\n", ref
->getDescription());
322 if(!sPrintRestrict
) {
323 std::vector
<ObjectFile::LineInfo
>* lineInfo
= atom
->getLineInfo();
324 if ( (lineInfo
!= NULL
) && (lineInfo
->size() > 0) ) {
325 printf("line info: (%lu)\n", lineInfo
->size());
326 for (std::vector
<ObjectFile::LineInfo
>::iterator it
= lineInfo
->begin(); it
!= lineInfo
->end(); ++it
) {
327 printf(" offset 0x%04X, line %d, file %s\n", it
->atomOffset
, it
->lineNumber
, it
->fileName
);
338 bool operator()(const ObjectFile::Atom
* left
, const ObjectFile::Atom
* right
)
342 return (strcmp(left
->getDisplayName(), right
->getDisplayName()) < 0);
347 static void dumpFile(ObjectFile::Reader
* reader
)
350 if ( sDumpStabs
&& (reader
->getDebugInfoKind() == ObjectFile::Reader::kDebugInfoStabs
) ) {
351 std::vector
<ObjectFile::Reader::Stab
>* stabs
= reader
->getStabs();
357 std::vector
<ObjectFile::Atom
*> atoms
= reader
->getAtoms();
359 // make copy of vector and sort (so output is canonical)
360 std::vector
<ObjectFile::Atom
*> sortedAtoms(atoms
);
362 std::sort(sortedAtoms
.begin(), sortedAtoms
.end(), AtomSorter());
364 for(std::vector
<ObjectFile::Atom
*>::iterator it
=sortedAtoms
.begin(); it
!= sortedAtoms
.end(); ++it
) {
373 static ObjectFile::Reader
* createReader(const char* path
, const ObjectFile::ReaderOptions
& options
)
375 struct stat stat_buf
;
377 int fd
= ::open(path
, O_RDONLY
, 0);
379 throwf("cannot open file: %s", path
);
380 ::fstat(fd
, &stat_buf
);
381 uint8_t* p
= (uint8_t*)::mmap(NULL
, stat_buf
.st_size
, PROT_READ
, MAP_FILE
| MAP_PRIVATE
, fd
, 0);
383 const mach_header
* mh
= (mach_header
*)p
;
384 if ( mh
->magic
== OSSwapBigToHostInt32(FAT_MAGIC
) ) {
385 const struct fat_header
* fh
= (struct fat_header
*)p
;
386 const struct fat_arch
* archs
= (struct fat_arch
*)(p
+ sizeof(struct fat_header
));
387 for (unsigned long i
=0; i
< OSSwapBigToHostInt32(fh
->nfat_arch
); ++i
) {
388 if ( OSSwapBigToHostInt32(archs
[i
].cputype
) == (uint32_t)sPreferredArch
) {
389 p
= p
+ OSSwapBigToHostInt32(archs
[i
].offset
);
390 mh
= (struct mach_header
*)p
;
394 if ( mach_o::relocatable::Reader
<x86
>::validFile(p
) )
395 return new mach_o::relocatable::Reader
<x86
>::Reader(p
, path
, 0, options
, 0);
396 else if ( mach_o::relocatable::Reader
<ppc
>::validFile(p
) )
397 return new mach_o::relocatable::Reader
<ppc
>::Reader(p
, path
, 0, options
, 0);
398 else if ( mach_o::relocatable::Reader
<ppc64
>::validFile(p
) )
399 return new mach_o::relocatable::Reader
<ppc64
>::Reader(p
, path
, 0, options
, 0);
400 else if ( mach_o::relocatable::Reader
<x86_64
>::validFile(p
) )
401 return new mach_o::relocatable::Reader
<x86_64
>::Reader(p
, path
, 0, options
, 0);
402 else if ( mach_o::relocatable::Reader
<arm
>::validFile(p
) )
403 return new mach_o::relocatable::Reader
<arm
>::Reader(p
, path
, 0, options
, 0);
404 if ( lto::Reader::validFile(p
, stat_buf
.st_size
, 0) ) {
405 return new lto::Reader(p
, stat_buf
.st_size
, path
, 0, options
, 0);
408 throwf("not a mach-o object file: %s", path
);
415 fprintf(stderr
, "ObjectDump options:\n"
416 "\t-no_content\tdon't dump contents\n"
417 "\t-stabs\t\tdump stabs\n"
418 "\t-arch aaa\tonly dump info about arch aaa\n"
419 "\t-only sym\tonly dump info about sym\n"
420 "\t-align\t\tonly print alignment info\n"
421 "\t-name\t\tonly print symbol names\n"
425 int main(int argc
, const char* argv
[])
432 ObjectFile::ReaderOptions options
;
434 for(int i
=1; i
< argc
; ++i
) {
435 const char* arg
= argv
[i
];
436 if ( arg
[0] == '-' ) {
437 if ( strcmp(arg
, "-no_content") == 0 ) {
438 sDumpContent
= false;
440 else if ( strcmp(arg
, "-nm") == 0 ) {
443 else if ( strcmp(arg
, "-stabs") == 0 ) {
446 else if ( strcmp(arg
, "-no_sort") == 0 ) {
449 else if ( strcmp(arg
, "-arch") == 0 ) {
450 const char* arch
= ++i
<argc
? argv
[i
]: "";
451 if ( strcmp(arch
, "ppc64") == 0 )
452 sPreferredArch
= CPU_TYPE_POWERPC64
;
453 else if ( strcmp(arch
, "ppc") == 0 )
454 sPreferredArch
= CPU_TYPE_POWERPC
;
455 else if ( strcmp(arch
, "i386") == 0 )
456 sPreferredArch
= CPU_TYPE_I386
;
457 else if ( strcmp(arch
, "x86_64") == 0 )
458 sPreferredArch
= CPU_TYPE_X86_64
;
460 throwf("unknown architecture %s", arch
);
462 else if ( strcmp(arg
, "-only") == 0 ) {
463 sMatchName
= ++i
<argc
? argv
[i
]: NULL
;
465 else if ( strcmp(arg
, "-align") == 0 ) {
466 sPrintRestrict
= true;
469 else if ( strcmp(arg
, "-name") == 0 ) {
470 sPrintRestrict
= true;
475 throwf("unknown option: %s\n", arg
);
479 ObjectFile::Reader
* reader
= createReader(arg
, options
);
484 catch (const char* msg
) {
485 fprintf(stderr
, "ObjDump failed: %s\n", msg
);