]> git.saurik.com Git - apple/ld64.git/blob - src/other/ObjectDump.cpp
25352b1b3b9cf066f8c184082bc6fbf0d22cf65a
[apple/ld64.git] / src / other / ObjectDump.cpp
1 /* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
2 *
3 * Copyright (c) 2005-2006 Apple Computer, Inc. All rights reserved.
4 *
5 * @APPLE_LICENSE_HEADER_START@
6 *
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
12 * file.
13 *
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.
21 *
22 * @APPLE_LICENSE_HEADER_END@
23 */
24
25 #include <sys/types.h>
26 #include <sys/stat.h>
27 #include <sys/mman.h>
28 #include <fcntl.h>
29 #include <fcntl.h>
30
31 #include "MachOReaderRelocatable.hpp"
32
33 #define LTO_SUPPORT 1
34
35 #if LTO_SUPPORT
36 #include "LTOReader.hpp"
37 #endif
38
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;
49
50
51 __attribute__((noreturn))
52 void throwf(const char* format, ...)
53 {
54 va_list list;
55 char* p;
56 va_start(list, format);
57 vasprintf(&p, format, list);
58 va_end(list);
59
60 const char* t = p;
61 throw t;
62 }
63
64 void warning(const char* format, ...)
65 {
66 va_list list;
67 fprintf(stderr, "warning: ");
68 va_start(list, format);
69 vfprintf(stderr, format, list);
70 va_end(list);
71 fprintf(stderr, "\n");
72 }
73
74 static void dumpStabs(std::vector<ObjectFile::Reader::Stab>* stabs)
75 {
76 // debug info
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 = "?????";
81 switch (stab.type) {
82 case N_GSYM:
83 code = " GSYM";
84 break;
85 case N_FNAME:
86 code = "FNAME";
87 break;
88 case N_FUN:
89 code = " FUN";
90 break;
91 case N_STSYM:
92 code = "STSYM";
93 break;
94 case N_LCSYM:
95 code = "LCSYM";
96 break;
97 case N_BNSYM:
98 code = "BNSYM";
99 break;
100 case N_OPT:
101 code = " OPT";
102 break;
103 case N_RSYM:
104 code = " RSYM";
105 break;
106 case N_SLINE:
107 code = "SLINE";
108 break;
109 case N_ENSYM:
110 code = "ENSYM";
111 break;
112 case N_SSYM:
113 code = " SSYM";
114 break;
115 case N_SO:
116 code = " SO";
117 break;
118 case N_OSO:
119 code = " OSO";
120 break;
121 case N_LSYM:
122 code = " LSYM";
123 break;
124 case N_BINCL:
125 code = "BINCL";
126 break;
127 case N_SOL:
128 code = " SOL";
129 break;
130 case N_PARAMS:
131 code = "PARMS";
132 break;
133 case N_VERSION:
134 code = " VERS";
135 break;
136 case N_OLEVEL:
137 code = "OLEVL";
138 break;
139 case N_PSYM:
140 code = " PSYM";
141 break;
142 case N_EINCL:
143 code = "EINCL";
144 break;
145 case N_ENTRY:
146 code = "ENTRY";
147 break;
148 case N_LBRAC:
149 code = "LBRAC";
150 break;
151 case N_EXCL:
152 code = " EXCL";
153 break;
154 case N_RBRAC:
155 code = "RBRAC";
156 break;
157 case N_BCOMM:
158 code = "BCOMM";
159 break;
160 case N_ECOMM:
161 code = "ECOMM";
162 break;
163 case N_LENG:
164 code = "LENG";
165 break;
166 }
167 printf(" [atom=%20s] %02X %04X %s %s\n", ((stab.atom != NULL) ? stab.atom->getDisplayName() : ""), stab.other, stab.desc, code, stab.string);
168 }
169 }
170
171
172 static void dumpAtomLikeNM(ObjectFile::Atom* atom)
173 {
174 uint32_t size = atom->getSize();
175
176 const char* visibility;
177 switch ( atom->getScope() ) {
178 case ObjectFile::Atom::scopeTranslationUnit:
179 visibility = "internal";
180 break;
181 case ObjectFile::Atom::scopeLinkageUnit:
182 visibility = "hidden ";
183 break;
184 case ObjectFile::Atom::scopeGlobal:
185 visibility = "global ";
186 break;
187 default:
188 visibility = " ";
189 break;
190 }
191
192 const char* kind;
193 switch ( atom->getDefinitionKind() ) {
194 case ObjectFile::Atom::kRegularDefinition:
195 kind = "regular ";
196 break;
197 case ObjectFile::Atom::kTentativeDefinition:
198 kind = "tentative";
199 break;
200 case ObjectFile::Atom::kWeakDefinition:
201 kind = "weak ";
202 break;
203 case ObjectFile::Atom::kAbsoluteSymbol:
204 kind = "absolute ";
205 break;
206 default:
207 kind = " ";
208 break;
209 }
210
211 printf("0x%08X %s %s %s\n", size, visibility, kind, atom->getDisplayName());
212 }
213
214
215 static void dumpAtom(ObjectFile::Atom* atom)
216 {
217 if(sMatchName && strcmp(sMatchName, atom->getDisplayName()))
218 return;
219
220 //printf("atom: %p\n", atom);
221
222 // name
223 if(!sPrintRestrict || sPrintName)
224 printf("name: %s\n", atom->getDisplayName());
225
226 // scope
227 if(!sPrintRestrict)
228 switch ( atom->getScope() ) {
229 case ObjectFile::Atom::scopeTranslationUnit:
230 printf("scope: translation unit\n");
231 break;
232 case ObjectFile::Atom::scopeLinkageUnit:
233 printf("scope: linkage unit\n");
234 break;
235 case ObjectFile::Atom::scopeGlobal:
236 printf("scope: global\n");
237 break;
238 default:
239 printf("scope: unknown\n");
240 }
241
242 // kind
243 if(!sPrintRestrict)
244 switch ( atom->getDefinitionKind() ) {
245 case ObjectFile::Atom::kRegularDefinition:
246 printf("kind: regular\n");
247 break;
248 case ObjectFile::Atom::kWeakDefinition:
249 printf("kind: weak\n");
250 break;
251 case ObjectFile::Atom::kTentativeDefinition:
252 printf("kind: tentative\n");
253 break;
254 case ObjectFile::Atom::kExternalDefinition:
255 printf("kind: import\n");
256 break;
257 case ObjectFile::Atom::kExternalWeakDefinition:
258 printf("kind: weak import\n");
259 break;
260 case ObjectFile::Atom::kAbsoluteSymbol:
261 printf("kind: absolute symbol\n");
262 break;
263 default:
264 printf("kind: unknown\n");
265 }
266
267 // segment and section
268 if(!sPrintRestrict && (atom->getSectionName() != NULL) )
269 printf("section: %s,%s\n", atom->getSegment().getName(), atom->getSectionName());
270
271 // attributes
272 if(!sPrintRestrict) {
273 printf("attrs: ");
274 if ( atom->dontDeadStrip() )
275 printf("dont-dead-strip ");
276 if ( atom->isZeroFill() )
277 printf("zero-fill ");
278 if ( atom->isThumb() )
279 printf("thumb ");
280 printf("\n");
281 }
282
283 // size
284 if(!sPrintRestrict)
285 printf("size: 0x%012llX\n", atom->getSize());
286
287 // alignment
288 if(!sPrintRestrict || sPrintAlign)
289 printf("align: %u mod %u\n", atom->getAlignment().modulus, (1 << atom->getAlignment().powerOf2) );
290
291 // content
292 if (!sPrintRestrict && sDumpContent ) {
293 uint64_t size = atom->getSize();
294 if ( size < 4096 ) {
295 uint8_t content[size];
296 atom->copyRawContent(content);
297 printf("content: ");
298 if ( atom->getContentType() == ObjectFile::Atom::kCStringType ) {
299 printf("\"");
300 for (unsigned int i=0; i < size; ++i) {
301 if(content[i]<'!' || content[i]>=127)
302 printf("\\%o", content[i]);
303 else
304 printf("%c", content[i]);
305 }
306 printf("\"");
307 }
308 else {
309 for (unsigned int i=0; i < size; ++i)
310 printf("%02X ", content[i]);
311 }
312 }
313 printf("\n");
314 }
315
316 // unwind info
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);
322 }
323 }
324 }
325
326 // references
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());
334 }
335 }
336
337 // line info
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);
344 }
345 }
346 }
347
348 if(!sPrintRestrict)
349 printf("\n");
350 }
351
352 struct AtomSorter
353 {
354 bool operator()(const ObjectFile::Atom* left, const ObjectFile::Atom* right)
355 {
356 if ( left == right )
357 return false;
358 int name = strcmp(left->getDisplayName(), right->getDisplayName());
359 if ( name == 0 )
360 return (left->getSize() < right->getSize());
361 else
362 return ( name < 0);
363 }
364 };
365
366
367 static void dumpFile(ObjectFile::Reader* reader)
368 {
369 // stabs debug info
370 if ( sDumpStabs && (reader->getDebugInfoKind() == ObjectFile::Reader::kDebugInfoStabs) ) {
371 std::vector<ObjectFile::Reader::Stab>* stabs = reader->getStabs();
372 if ( stabs != NULL )
373 dumpStabs(stabs);
374 }
375
376 // get all atoms
377 std::vector<ObjectFile::Atom*> atoms = reader->getAtoms();
378
379 // make copy of vector and sort (so output is canonical)
380 std::vector<ObjectFile::Atom*> sortedAtoms(atoms);
381 if ( sSort )
382 std::sort(sortedAtoms.begin(), sortedAtoms.end(), AtomSorter());
383
384 for(std::vector<ObjectFile::Atom*>::iterator it=sortedAtoms.begin(); it != sortedAtoms.end(); ++it) {
385 if ( sNMmode )
386 dumpAtomLikeNM(*it);
387 else
388 dumpAtom(*it);
389 }
390 }
391
392
393 static ObjectFile::Reader* createReader(const char* path, const ObjectFile::ReaderOptions& options)
394 {
395 struct stat stat_buf;
396
397 int fd = ::open(path, O_RDONLY, 0);
398 if ( fd == -1 )
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);
402 ::close(fd);
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;
412 break;
413 }
414 }
415 }
416 }
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);
427 #if LTO_SUPPORT
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);
430 }
431 #endif
432
433 throwf("not a mach-o object file: %s", path);
434 }
435
436 static
437 void
438 usage()
439 {
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"
447 );
448 }
449
450 int main(int argc, const char* argv[])
451 {
452 if(argc<2) {
453 usage();
454 return 0;
455 }
456
457 ObjectFile::ReaderOptions options;
458 options.fAddCompactUnwindEncoding = true;
459 try {
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;
465 }
466 else if ( strcmp(arg, "-nm") == 0 ) {
467 sNMmode = true;
468 }
469 else if ( strcmp(arg, "-stabs") == 0 ) {
470 sDumpStabs = true;
471 }
472 else if ( strcmp(arg, "-no_sort") == 0 ) {
473 sSort = false;
474 }
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;
490 }
491 else if ( strcmp(arch, "armv5") == 0 ) {
492 sPreferredArch = CPU_TYPE_ARM;
493 sPreferredSubArch = CPU_SUBTYPE_ARM_V5TEJ;
494 }
495 else if ( strcmp(arch, "armv6") == 0 ) {
496 sPreferredArch = CPU_TYPE_ARM;
497 sPreferredSubArch = CPU_SUBTYPE_ARM_V6;
498 }
499 else if ( strcmp(arch, "armv7") == 0 ) {
500 sPreferredArch = CPU_TYPE_ARM;
501 sPreferredSubArch = CPU_SUBTYPE_ARM_V7;
502 }
503 else
504 throwf("unknown architecture %s", arch);
505 }
506 else if ( strcmp(arg, "-only") == 0 ) {
507 sMatchName = ++i<argc? argv[i]: NULL;
508 }
509 else if ( strcmp(arg, "-align") == 0 ) {
510 sPrintRestrict = true;
511 sPrintAlign = true;
512 }
513 else if ( strcmp(arg, "-name") == 0 ) {
514 sPrintRestrict = true;
515 sPrintName = true;
516 }
517 else {
518 usage();
519 throwf("unknown option: %s\n", arg);
520 }
521 }
522 else {
523 ObjectFile::Reader* reader = createReader(arg, options);
524 dumpFile(reader);
525 }
526 }
527 }
528 catch (const char* msg) {
529 fprintf(stderr, "ObjDump failed: %s\n", msg);
530 return 1;
531 }
532
533 return 0;
534 }