]> git.saurik.com Git - apple/ld64.git/blob - src/other/ObjectDump.cpp
3d7ac5eaa5c737f4714eaf697652a82484d97d82
[apple/ld64.git] / src / other / ObjectDump.cpp
1 /* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
2 *
3 * Copyright (c) 2005-2010 Apple 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 <mach-o/nlist.h>
30 #include <mach-o/stab.h>
31 #include <mach-o/fat.h>
32 #include <mach-o/loader.h>
33
34 #include "MachOFileAbstraction.hpp"
35 #include "parsers/macho_relocatable_file.h"
36 #include "parsers/lto_file.h"
37
38 static bool sDumpContent= true;
39 static bool sDumpStabs = false;
40 static bool sSort = true;
41 static bool sNMmode = false;
42 static bool sShowSection = true;
43 static bool sShowDefinitionKind = true;
44 static bool sShowCombineKind = true;
45 static bool sShowLineInfo = true;
46
47 static cpu_type_t sPreferredArch = 0xFFFFFFFF;
48 static cpu_subtype_t sPreferredSubArch = 0xFFFFFFFF;
49 static const char* sMatchName = NULL;
50 static int sPrintRestrict;
51 static int sPrintAlign;
52 static int sPrintName;
53
54 __attribute__((noreturn))
55 void throwf(const char* format, ...)
56 {
57 va_list list;
58 char* p;
59 va_start(list, format);
60 vasprintf(&p, format, list);
61 va_end(list);
62
63 const char* t = p;
64 throw t;
65 }
66
67 void warning(const char* format, ...)
68 {
69 va_list list;
70 fprintf(stderr, "warning: ");
71 va_start(list, format);
72 vfprintf(stderr, format, list);
73 va_end(list);
74 fprintf(stderr, "\n");
75 }
76
77 static void dumpStabs(const std::vector<ld::relocatable::File::Stab>* stabs)
78 {
79 // debug info
80 printf("stabs: (%lu)\n", stabs->size());
81 for (std::vector<ld::relocatable::File::Stab>::const_iterator it = stabs->begin(); it != stabs->end(); ++it ) {
82 const ld::relocatable::File::Stab& stab = *it;
83 const char* code = "?????";
84 switch (stab.type) {
85 case N_GSYM:
86 code = " GSYM";
87 break;
88 case N_FNAME:
89 code = "FNAME";
90 break;
91 case N_FUN:
92 code = " FUN";
93 break;
94 case N_STSYM:
95 code = "STSYM";
96 break;
97 case N_LCSYM:
98 code = "LCSYM";
99 break;
100 case N_BNSYM:
101 code = "BNSYM";
102 break;
103 case N_OPT:
104 code = " OPT";
105 break;
106 case N_RSYM:
107 code = " RSYM";
108 break;
109 case N_SLINE:
110 code = "SLINE";
111 break;
112 case N_ENSYM:
113 code = "ENSYM";
114 break;
115 case N_SSYM:
116 code = " SSYM";
117 break;
118 case N_SO:
119 code = " SO";
120 break;
121 case N_OSO:
122 code = " OSO";
123 break;
124 case N_LSYM:
125 code = " LSYM";
126 break;
127 case N_BINCL:
128 code = "BINCL";
129 break;
130 case N_SOL:
131 code = " SOL";
132 break;
133 case N_PARAMS:
134 code = "PARMS";
135 break;
136 case N_VERSION:
137 code = " VERS";
138 break;
139 case N_OLEVEL:
140 code = "OLEVL";
141 break;
142 case N_PSYM:
143 code = " PSYM";
144 break;
145 case N_EINCL:
146 code = "EINCL";
147 break;
148 case N_ENTRY:
149 code = "ENTRY";
150 break;
151 case N_LBRAC:
152 code = "LBRAC";
153 break;
154 case N_EXCL:
155 code = " EXCL";
156 break;
157 case N_RBRAC:
158 code = "RBRAC";
159 break;
160 case N_BCOMM:
161 code = "BCOMM";
162 break;
163 case N_ECOMM:
164 code = "ECOMM";
165 break;
166 case N_LENG:
167 code = "LENG";
168 break;
169 }
170 printf(" [atom=%20s] %02X %04X %s %s\n", ((stab.atom != NULL) ? stab.atom->name() : ""), stab.other, stab.desc, code, stab.string);
171 }
172 }
173
174 #if 0
175 static void dumpAtomLikeNM(ld::Atom* atom)
176 {
177 uint32_t size = atom->size();
178
179 const char* visibility;
180 switch ( atom->scope() ) {
181 case ld::Atom::scopeTranslationUnit:
182 visibility = "internal";
183 break;
184 case ld::Atom::scopeLinkageUnit:
185 visibility = "hidden ";
186 break;
187 case ld::Atom::scopeGlobal:
188 visibility = "global ";
189 break;
190 default:
191 visibility = " ";
192 break;
193 }
194
195 const char* kind;
196 switch ( atom->definitionKind() ) {
197 case ld::Atom::kRegularDefinition:
198 kind = "regular ";
199 break;
200 case ld::Atom::kTentativeDefinition:
201 kind = "tentative";
202 break;
203 case ld::Atom::kWeakDefinition:
204 kind = "weak ";
205 break;
206 case ld::Atom::kAbsoluteSymbol:
207 kind = "absolute ";
208 break;
209 default:
210 kind = " ";
211 break;
212 }
213
214 printf("0x%08X %s %s %s\n", size, visibility, kind, atom->name());
215 }
216
217
218 static void dumpAtom(ld::Atom* atom)
219 {
220 if(sMatchName && strcmp(sMatchName, atom->name()))
221 return;
222
223 //printf("atom: %p\n", atom);
224
225 // name
226 if(!sPrintRestrict || sPrintName)
227 printf("name: %s\n", atom->name());
228
229 // scope
230 if(!sPrintRestrict)
231 switch ( atom->scope() ) {
232 case ld::Atom::scopeTranslationUnit:
233 printf("scope: translation unit\n");
234 break;
235 case ld::Atom::scopeLinkageUnit:
236 printf("scope: linkage unit\n");
237 break;
238 case ld::Atom::scopeGlobal:
239 printf("scope: global\n");
240 break;
241 default:
242 printf("scope: unknown\n");
243 }
244
245 // kind
246 if(!sPrintRestrict)
247 switch ( atom->definitionKind() ) {
248 case ld::Atom::kRegularDefinition:
249 printf("kind: regular\n");
250 break;
251 case ld::Atom::kWeakDefinition:
252 printf("kind: weak\n");
253 break;
254 case ld::Atom::kTentativeDefinition:
255 printf("kind: tentative\n");
256 break;
257 case ld::Atom::kExternalDefinition:
258 printf("kind: import\n");
259 break;
260 case ld::Atom::kExternalWeakDefinition:
261 printf("kind: weak import\n");
262 break;
263 case ld::Atom::kAbsoluteSymbol:
264 printf("kind: absolute symbol\n");
265 break;
266 default:
267 printf("kind: unknown\n");
268 }
269
270 // segment and section
271 if(!sPrintRestrict && (atom->section().sectionName() != NULL) )
272 printf("section: %s,%s\n", atom->section().segmentName(), atom->section().sectionName());
273
274 // attributes
275 if(!sPrintRestrict) {
276 printf("attrs: ");
277 if ( atom->dontDeadStrip() )
278 printf("dont-dead-strip ");
279 if ( atom->isThumb() )
280 printf("thumb ");
281 printf("\n");
282 }
283
284 // size
285 if(!sPrintRestrict)
286 printf("size: 0x%012llX\n", atom->size());
287
288 // alignment
289 if(!sPrintRestrict || sPrintAlign)
290 printf("align: %u mod %u\n", atom->alignment().modulus, (1 << atom->alignment().powerOf2) );
291
292 // content
293 if (!sPrintRestrict && sDumpContent ) {
294 uint64_t size = atom->size();
295 if ( size < 4096 ) {
296 uint8_t content[size];
297 atom->copyRawContent(content);
298 printf("content: ");
299 if ( atom->contentType() == ld::Atom::typeCString ) {
300 printf("\"");
301 for (unsigned int i=0; i < size; ++i) {
302 if(content[i]<'!' || content[i]>=127)
303 printf("\\%o", content[i]);
304 else
305 printf("%c", content[i]);
306 }
307 printf("\"");
308 }
309 else {
310 for (unsigned int i=0; i < size; ++i)
311 printf("%02X ", content[i]);
312 }
313 }
314 printf("\n");
315 }
316
317 // unwind info
318 if(!sPrintRestrict) {
319 if ( atom->beginUnwind() != atom->endUnwind() ) {
320 printf("unwind encodings:\n");
321 for (ld::Atom::UnwindInfo::iterator it = atom->beginUnwind(); it != atom->endUnwind(); ++it) {
322 printf("\t 0x%04X 0x%08X\n", it->startOffset, it->unwindInfo);
323 }
324 }
325 }
326 #if 0
327 // references
328 if(!sPrintRestrict) {
329 std::vector<ObjectFile::Reference*>& references = atom->getReferences();
330 const int refCount = references.size();
331 printf("references: (%u)\n", refCount);
332 for (int i=0; i < refCount; ++i) {
333 ObjectFile::Reference* ref = references[i];
334 printf(" %s\n", ref->getDescription());
335 }
336 }
337 #endif
338 // line info
339 if(!sPrintRestrict) {
340 if ( atom->beginLineInfo() != atom->endLineInfo() ) {
341 printf("line info:\n");
342 for (ld::Atom::LineInfo::iterator it = atom->beginLineInfo(); it != atom->endLineInfo(); ++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 #endif
352 struct AtomSorter
353 {
354 bool operator()(const ld::Atom* left, const ld::Atom* right)
355 {
356 if ( left == right )
357 return false;
358 // first sort by segment name
359 int diff = strcmp(left->section().segmentName(), right->section().segmentName());
360 if ( diff != 0 )
361 return (diff > 0);
362
363 // then sort by section name
364 diff = strcmp(left->section().sectionName(), right->section().sectionName());
365 if ( diff != 0 )
366 return (diff < 0);
367
368 // then sort by atom name
369 diff = strcmp(left->name(), right->name());
370 if ( diff != 0 )
371 return (diff < 0);
372
373 // if cstring, sort by content
374 if ( left->contentType() == ld::Atom::typeCString ) {
375 diff = strcmp((char*)left->rawContentPointer(), (char*)right->rawContentPointer());
376 if ( diff != 0 )
377 return (diff < 0);
378 }
379 else if ( left->section().type() == ld::Section::typeCStringPointer ) {
380 // if pointer to c-string sort by name
381 const char* leftString = NULL;
382 assert(left->fixupsBegin() != left->fixupsEnd());
383 for (ld::Fixup::iterator fit = left->fixupsBegin(); fit != left->fixupsEnd(); ++fit) {
384 if ( fit->binding == ld::Fixup::bindingByContentBound ) {
385 const ld::Atom* cstringAtom = fit->u.target;
386 assert(cstringAtom->contentType() == ld::Atom::typeCString);
387 leftString = (char*)cstringAtom->rawContentPointer();
388 }
389 }
390 const char* rightString = NULL;
391 assert(right->fixupsBegin() != right->fixupsEnd());
392 for (ld::Fixup::iterator fit = right->fixupsBegin(); fit != right->fixupsEnd(); ++fit) {
393 if ( fit->binding == ld::Fixup::bindingByContentBound ) {
394 const ld::Atom* cstringAtom = fit->u.target;
395 assert(cstringAtom->contentType() == ld::Atom::typeCString);
396 rightString = (char*)cstringAtom->rawContentPointer();
397 }
398 }
399 assert(leftString != NULL);
400 assert(rightString != NULL);
401 diff = strcmp(leftString, rightString);
402 if ( diff != 0 )
403 return (diff < 0);
404 }
405 else if ( left->section().type() == ld::Section::typeLiteral4 ) {
406 // if literal sort by content
407 uint32_t leftValue = *(uint32_t*)left->rawContentPointer();
408 uint32_t rightValue = *(uint32_t*)right->rawContentPointer();
409 diff = (leftValue - rightValue);
410 if ( diff != 0 )
411 return (diff < 0);
412 }
413 else if ( left->section().type() == ld::Section::typeCFI ) {
414 // if __he_frame sort by address
415 diff = (left->objectAddress() - right->objectAddress());
416 if ( diff != 0 )
417 return (diff < 0);
418 }
419 else if ( left->section().type() == ld::Section::typeNonLazyPointer ) {
420 // if non-lazy-pointer sort by name
421 const char* leftString = NULL;
422 assert(left->fixupsBegin() != left->fixupsEnd());
423 for (ld::Fixup::iterator fit = left->fixupsBegin(); fit != left->fixupsEnd(); ++fit) {
424 if ( fit->binding == ld::Fixup::bindingByNameUnbound ) {
425 leftString = fit->u.name;
426 }
427 else if ( fit->binding == ld::Fixup::bindingDirectlyBound ) {
428 leftString = fit->u.target->name();
429 }
430 }
431 const char* rightString = NULL;
432 assert(right->fixupsBegin() != right->fixupsEnd());
433 for (ld::Fixup::iterator fit = right->fixupsBegin(); fit != right->fixupsEnd(); ++fit) {
434 if ( fit->binding == ld::Fixup::bindingByNameUnbound ) {
435 rightString = fit->u.name;
436 }
437 else if ( fit->binding == ld::Fixup::bindingDirectlyBound ) {
438 rightString = fit->u.target->name();
439 }
440 }
441 assert(leftString != NULL);
442 assert(rightString != NULL);
443 diff = strcmp(leftString, rightString);
444 if ( diff != 0 )
445 return (diff < 0);
446 }
447
448 // else sort by size
449 return (left->size() < right->size());
450 }
451 };
452
453
454 class dumper : public ld::File::AtomHandler
455 {
456 public:
457 void dump();
458 virtual void doAtom(const ld::Atom&);
459 virtual void doFile(const ld::File&) {}
460 private:
461 void dumpAtom(const ld::Atom& atom);
462 const char* scopeString(const ld::Atom&);
463 const char* definitionString(const ld::Atom&);
464 const char* combineString(const ld::Atom&);
465 const char* inclusionString(const ld::Atom&);
466 const char* attributeString(const ld::Atom&);
467 const char* makeName(const ld::Atom& atom);
468 const char* referenceTargetAtomName(const ld::Fixup* ref);
469 void dumpFixup(const ld::Fixup* ref);
470
471 uint64_t addressOfFirstAtomInSection(const ld::Section&);
472
473 std::vector<const ld::Atom*> _atoms;
474 };
475
476 const char* dumper::scopeString(const ld::Atom& atom)
477 {
478 switch ( (ld::Atom::Scope)atom.scope() ) {
479 case ld::Atom::scopeTranslationUnit:
480 return "translation-unit";
481 case ld::Atom::scopeLinkageUnit:
482 return "hidden";
483 case ld::Atom::scopeGlobal:
484 if ( atom.autoHide() )
485 return "global but automatically hidden";
486 else
487 return "global";
488 }
489 return "UNKNOWN";
490 }
491
492 const char* dumper::definitionString(const ld::Atom& atom)
493 {
494 switch ( (ld::Atom::Definition)atom.definition() ) {
495 case ld::Atom::definitionRegular:
496 return "regular";
497 case ld::Atom::definitionTentative:
498 return "tentative";
499 case ld::Atom::definitionAbsolute:
500 return "absolute";
501 case ld::Atom::definitionProxy:
502 return "proxy";
503 }
504 return "UNKNOWN";
505 }
506
507 const char* dumper::combineString(const ld::Atom& atom)
508 {
509 switch ( (ld::Atom::Combine)atom.combine() ) {
510 case ld::Atom::combineNever:
511 return "never";
512 case ld::Atom::combineByName:
513 return "by-name";
514 case ld::Atom::combineByNameAndContent:
515 return "by-name-and-content";
516 case ld::Atom::combineByNameAndReferences:
517 return "by-name-and-references";
518 }
519 return "UNKNOWN";
520 }
521
522 const char* dumper::inclusionString(const ld::Atom& atom)
523 {
524 switch ( (ld::Atom::SymbolTableInclusion)atom.symbolTableInclusion() ) {
525 case ld::Atom::symbolTableNotIn:
526 return "not in";
527 case ld::Atom::symbolTableNotInFinalLinkedImages:
528 return "not in final linked images";
529 case ld::Atom::symbolTableIn:
530 return "in";
531 case ld::Atom::symbolTableInAndNeverStrip:
532 return "in and never strip";
533 case ld::Atom::symbolTableInAsAbsolute:
534 return "in as absolute";
535 case ld::Atom::symbolTableInWithRandomAutoStripLabel:
536 return "in as random auto-strip label";
537 }
538 return "UNKNOWN";
539 }
540
541
542
543 const char* dumper::attributeString(const ld::Atom& atom)
544 {
545 static char buffer[256];
546 buffer[0] = '\0';
547
548 if ( atom.dontDeadStrip() )
549 strcat(buffer, "dont-dead-strip ");
550
551 if ( atom.isThumb() )
552 strcat(buffer, "thumb ");
553
554 if ( atom.isAlias() )
555 strcat(buffer, "alias ");
556
557 if ( atom.contentType() == ld::Atom::typeResolver )
558 strcat(buffer, "resolver ");
559
560 return buffer;
561 }
562
563 const char* dumper::makeName(const ld::Atom& atom)
564 {
565 static char buffer[4096];
566 strcpy(buffer, "???");
567 switch ( atom.symbolTableInclusion() ) {
568 case ld::Atom::symbolTableNotIn:
569 if ( atom.contentType() == ld::Atom::typeCString ) {
570 strcpy(buffer, "cstring=");
571 strlcat(buffer, (char*)atom.rawContentPointer(), 4096);
572 }
573 else if ( atom.section().type() == ld::Section::typeLiteral4 ) {
574 char temp[16];
575 strcpy(buffer, "literal4=");
576 uint32_t value = *(uint32_t*)atom.rawContentPointer();
577 sprintf(temp, "0x%08X", value);
578 strcat(buffer, temp);
579 }
580 else if ( atom.section().type() == ld::Section::typeLiteral8 ) {
581 char temp[32];
582 strcpy(buffer, "literal8=");
583 uint32_t value1 = *(uint32_t*)atom.rawContentPointer();
584 uint32_t value2 = ((uint32_t*)atom.rawContentPointer())[1];
585 sprintf(temp, "0x%08X%08X", value1, value2);
586 strcat(buffer, temp);
587 }
588 else if ( atom.section().type() == ld::Section::typeLiteral16 ) {
589 char temp[64];
590 strcpy(buffer, "literal16=");
591 uint32_t value1 = *(uint32_t*)atom.rawContentPointer();
592 uint32_t value2 = ((uint32_t*)atom.rawContentPointer())[1];
593 uint32_t value3 = ((uint32_t*)atom.rawContentPointer())[2];
594 uint32_t value4 = ((uint32_t*)atom.rawContentPointer())[3];
595 sprintf(temp, "0x%08X%08X%08X%08X", value1, value2, value3, value4);
596 strcat(buffer, temp);
597 }
598 else if ( atom.section().type() == ld::Section::typeCStringPointer ) {
599 assert(atom.fixupsBegin() != atom.fixupsEnd());
600 for (ld::Fixup::iterator fit = atom.fixupsBegin(); fit != atom.fixupsEnd(); ++fit) {
601 if ( fit->binding == ld::Fixup::bindingByContentBound ) {
602 const ld::Atom* cstringAtom = fit->u.target;
603 if ( (cstringAtom != NULL) && (cstringAtom->contentType() == ld::Atom::typeCString) ) {
604 strlcpy(buffer, atom.name(), 4096);
605 strlcat(buffer, "=", 4096);
606 strlcat(buffer, (char*)cstringAtom->rawContentPointer(), 4096);
607 }
608 }
609 }
610 }
611 else if ( atom.section().type() == ld::Section::typeNonLazyPointer ) {
612 assert(atom.fixupsBegin() != atom.fixupsEnd());
613 for (ld::Fixup::iterator fit = atom.fixupsBegin(); fit != atom.fixupsEnd(); ++fit) {
614 if ( fit->binding == ld::Fixup::bindingByNameUnbound ) {
615 strcpy(buffer, "non-lazy-pointer-to:");
616 strlcat(buffer, fit->u.name, 4096);
617 return buffer;
618 }
619 else if ( fit->binding == ld::Fixup::bindingDirectlyBound ) {
620 strcpy(buffer, "non-lazy-pointer-to-local:");
621 strlcat(buffer, fit->u.target->name(), 4096);
622 return buffer;
623 }
624 }
625 strlcpy(buffer, atom.name(), 4096);
626 }
627 else {
628 uint64_t sectAddr = addressOfFirstAtomInSection(atom.section());
629 sprintf(buffer, "%s@%s+0x%08llX", atom.name(), atom.section().sectionName(), atom.objectAddress()-sectAddr);
630 }
631 break;
632 case ld::Atom::symbolTableNotInFinalLinkedImages:
633 case ld::Atom::symbolTableIn:
634 case ld::Atom::symbolTableInAndNeverStrip:
635 case ld::Atom::symbolTableInAsAbsolute:
636 case ld::Atom::symbolTableInWithRandomAutoStripLabel:
637 strlcpy(buffer, atom.name(), 4096);
638 break;
639 }
640 return buffer;
641 }
642
643 const char* dumper::referenceTargetAtomName(const ld::Fixup* ref)
644 {
645 static char buffer[4096];
646 switch ( ref->binding ) {
647 case ld::Fixup::bindingNone:
648 return "NO BINDING";
649 case ld::Fixup::bindingByNameUnbound:
650 strcpy(buffer, "by-name(");
651 strlcat(buffer, ref->u.name, 4096);
652 strlcat(buffer, ")", 4096);
653 return buffer;
654 //return ref->u.name;
655 case ld::Fixup::bindingByContentBound:
656 strcpy(buffer, "by-content(");
657 strlcat(buffer, makeName(*ref->u.target), 4096);
658 strlcat(buffer, ")", 4096);
659 return buffer;
660 case ld::Fixup::bindingDirectlyBound:
661 strcpy(buffer, "direct(");
662 strlcat(buffer, makeName(*ref->u.target), 4096);
663 strlcat(buffer, ")", 4096);
664 return buffer;
665 case ld::Fixup::bindingsIndirectlyBound:
666 return "BOUND INDIRECTLY";
667 }
668 return "BAD BINDING";
669 }
670
671
672 void dumper::dumpFixup(const ld::Fixup* ref)
673 {
674 if ( ref->weakImport ) {
675 printf("weak_import ");
676 }
677 switch ( (ld::Fixup::Kind)(ref->kind) ) {
678 case ld::Fixup::kindNone:
679 printf("none");
680 break;
681 case ld::Fixup::kindNoneFollowOn:
682 printf("followed by %s", referenceTargetAtomName(ref));
683 break;
684 case ld::Fixup::kindNoneGroupSubordinate:
685 printf("group subordinate %s", referenceTargetAtomName(ref));
686 break;
687 case ld::Fixup::kindNoneGroupSubordinateFDE:
688 printf("group subordinate FDE %s", referenceTargetAtomName(ref));
689 break;
690 case ld::Fixup::kindNoneGroupSubordinateLSDA:
691 printf("group subordinate LSDA %s", referenceTargetAtomName(ref));
692 break;
693 case ld::Fixup::kindNoneGroupSubordinatePersonality:
694 printf("group subordinate personality %s", referenceTargetAtomName(ref));
695 break;
696 case ld::Fixup::kindSetTargetAddress:
697 printf("%s", referenceTargetAtomName(ref));
698 break;
699 case ld::Fixup::kindSubtractTargetAddress:
700 printf(" - %s", referenceTargetAtomName(ref));
701 break;
702 case ld::Fixup::kindAddAddend:
703 printf(" + 0x%llX", ref->u.addend);
704 break;
705 case ld::Fixup::kindSubtractAddend:
706 printf(" - 0x%llX", ref->u.addend);
707 break;
708 case ld::Fixup::kindSetTargetImageOffset:
709 printf("imageOffset(%s)", referenceTargetAtomName(ref));
710 break;
711 case ld::Fixup::kindSetTargetSectionOffset:
712 printf("sectionOffset(%s)", referenceTargetAtomName(ref));
713 break;
714 case ld::Fixup::kindStore8:
715 printf(", then store byte");
716 break;
717 case ld::Fixup::kindStoreLittleEndian16:
718 printf(", then store 16-bit little endian");
719 break;
720 case ld::Fixup::kindStoreLittleEndianLow24of32:
721 printf(", then store low 24-bit little endian");
722 break;
723 case ld::Fixup::kindStoreLittleEndian32:
724 printf(", then store 32-bit little endian");
725 break;
726 case ld::Fixup::kindStoreLittleEndian64:
727 printf(", then store 64-bit little endian");
728 break;
729 case ld::Fixup::kindStoreBigEndian16:
730 printf(", then store 16-bit big endian");
731 break;
732 case ld::Fixup::kindStoreBigEndianLow24of32:
733 printf(", then store low 24-bit big endian");
734 break;
735 case ld::Fixup::kindStoreBigEndian32:
736 printf(", then store 32-bit big endian");
737 break;
738 case ld::Fixup::kindStoreBigEndian64:
739 printf(", then store 64-bit big endian");
740 break;
741 case ld::Fixup::kindStorePPCBranch24:
742 printf(", then store as PPC branch24");
743 break;
744 case ld::Fixup::kindStorePPCBranch14:
745 printf(", then store as PPC branch14");
746 break;
747 case ld::Fixup::kindStorePPCPicLow14:
748 printf(", then store as PPC low14 pic");
749 break;
750 case ld::Fixup::kindStorePPCPicLow16:
751 printf(", then store as PPC low14 pic");
752 break;
753 case ld::Fixup::kindStorePPCPicHigh16AddLow:
754 printf(", then store as PPC high16 pic");
755 break;
756 case ld::Fixup::kindStorePPCAbsLow14:
757 printf(", then store as PPC low14 abs");
758 break;
759 case ld::Fixup::kindStorePPCAbsLow16:
760 printf(", then store as PPC low14 abs");
761 break;
762 case ld::Fixup::kindStorePPCAbsHigh16AddLow:
763 printf(", then store as PPC high16 abs");
764 break;
765 case ld::Fixup::kindStorePPCAbsHigh16:
766 printf(", then store as PPC high16 abs, no carry");
767 break;
768 case ld::Fixup::kindStoreX86BranchPCRel8:
769 printf(", then store as x86 8-bit pcrel branch");
770 break;
771 case ld::Fixup::kindStoreX86BranchPCRel32:
772 printf(", then store as x86 32-bit pcrel branch");
773 break;
774 case ld::Fixup::kindStoreX86PCRel8:
775 printf(", then store as x86 8-bit pcrel");
776 break;
777 case ld::Fixup::kindStoreX86PCRel16:
778 printf(", then store as x86 16-bit pcrel");
779 break;
780 case ld::Fixup::kindStoreX86PCRel32:
781 printf(", then store as x86 32-bit pcrel");
782 break;
783 case ld::Fixup::kindStoreX86PCRel32_1:
784 printf(", then store as x86 32-bit pcrel from +1");
785 break;
786 case ld::Fixup::kindStoreX86PCRel32_2:
787 printf(", then store as x86 32-bit pcrel from +2");
788 break;
789 case ld::Fixup::kindStoreX86PCRel32_4:
790 printf(", then store as x86 32-bit pcrel from +4");
791 break;
792 case ld::Fixup::kindStoreX86PCRel32GOTLoad:
793 printf(", then store as x86 32-bit pcrel GOT load");
794 break;
795 case ld::Fixup::kindStoreX86PCRel32GOTLoadNowLEA:
796 printf(", then store as x86 32-bit pcrel GOT load -> LEA");
797 break;
798 case ld::Fixup::kindStoreX86PCRel32GOT:
799 printf(", then store as x86 32-bit pcrel GOT access");
800 break;
801 case ld::Fixup::kindStoreX86PCRel32TLVLoad:
802 printf(", then store as x86 32-bit pcrel TLV load");
803 break;
804 case ld::Fixup::kindStoreX86PCRel32TLVLoadNowLEA:
805 printf(", then store as x86 32-bit pcrel TLV load");
806 break;
807 case ld::Fixup::kindStoreX86Abs32TLVLoad:
808 printf(", then store as x86 32-bit absolute TLV load");
809 break;
810 case ld::Fixup::kindStoreX86Abs32TLVLoadNowLEA:
811 printf(", then store as x86 32-bit absolute TLV load -> LEA");
812 break;
813 case ld::Fixup::kindStoreARMBranch24:
814 printf(", then store as ARM 24-bit pcrel branch");
815 break;
816 case ld::Fixup::kindStoreThumbBranch22:
817 printf(", then store as Thumb 22-bit pcrel branch");
818 break;
819 case ld::Fixup::kindStoreARMLoad12:
820 printf(", then store as ARM 12-bit pcrel load");
821 break;
822 case ld::Fixup::kindStoreARMLow16:
823 printf(", then store low-16 in ARM movw");
824 break;
825 case ld::Fixup::kindStoreARMHigh16:
826 printf(", then store high-16 in ARM movt");
827 break;
828 case ld::Fixup::kindStoreThumbLow16:
829 printf(", then store low-16 in Thumb movw");
830 break;
831 case ld::Fixup::kindStoreThumbHigh16:
832 printf(", then store high-16 in Thumb movt");
833 break;
834 case ld::Fixup::kindDtraceExtra:
835 printf("dtrace static probe extra info");
836 break;
837 case ld::Fixup::kindStoreX86DtraceCallSiteNop:
838 printf("x86 dtrace static probe site");
839 break;
840 case ld::Fixup::kindStoreX86DtraceIsEnableSiteClear:
841 printf("x86 dtrace static is-enabled site");
842 break;
843 case ld::Fixup::kindStorePPCDtraceCallSiteNop:
844 printf("ppc dtrace static probe site");
845 break;
846 case ld::Fixup::kindStorePPCDtraceIsEnableSiteClear:
847 printf("ppc dtrace static is-enabled site");
848 break;
849 case ld::Fixup::kindStoreARMDtraceCallSiteNop:
850 printf("ARM dtrace static probe site");
851 break;
852 case ld::Fixup::kindStoreARMDtraceIsEnableSiteClear:
853 printf("ARM dtrace static is-enabled site");
854 break;
855 case ld::Fixup::kindStoreThumbDtraceCallSiteNop:
856 printf("Thumb dtrace static probe site");
857 break;
858 case ld::Fixup::kindStoreThumbDtraceIsEnableSiteClear:
859 printf("Thumb dtrace static is-enabled site");
860 break;
861 case ld::Fixup::kindLazyTarget:
862 printf("lazy reference to external symbol %s", referenceTargetAtomName(ref));
863 break;
864 case ld::Fixup::kindSetLazyOffset:
865 printf("offset of lazy binding info for %s", referenceTargetAtomName(ref));
866 break;
867 case ld::Fixup::kindStoreTargetAddressLittleEndian32:
868 printf("store 32-bit little endian address of %s", referenceTargetAtomName(ref));
869 break;
870 case ld::Fixup::kindStoreTargetAddressLittleEndian64:
871 printf("store 64-bit little endian address of %s", referenceTargetAtomName(ref));
872 break;
873 case ld::Fixup::kindStoreTargetAddressBigEndian32:
874 printf("store 32-bit big endian address of %s", referenceTargetAtomName(ref));
875 break;
876 case ld::Fixup::kindStoreTargetAddressBigEndian64:
877 printf("store 64-bit big endian address of %s", referenceTargetAtomName(ref));
878 break;
879 case ld::Fixup::kindStoreTargetAddressX86PCRel32:
880 printf("x86 store 32-bit pc-rel address of %s", referenceTargetAtomName(ref));
881 break;
882 case ld::Fixup::kindStoreTargetAddressX86BranchPCRel32:
883 printf("x86 store 32-bit pc-rel branch to %s", referenceTargetAtomName(ref));
884 break;
885 case ld::Fixup::kindStoreTargetAddressX86PCRel32GOTLoad:
886 printf("x86 store 32-bit pc-rel GOT load of %s", referenceTargetAtomName(ref));
887 break;
888 case ld::Fixup::kindStoreTargetAddressX86PCRel32GOTLoadNowLEA:
889 printf("x86 store 32-bit pc-rel lea of %s", referenceTargetAtomName(ref));
890 break;
891 case ld::Fixup::kindStoreTargetAddressX86PCRel32TLVLoad:
892 printf("x86 store 32-bit pc-rel TLV load of %s", referenceTargetAtomName(ref));
893 break;
894 case ld::Fixup::kindStoreTargetAddressX86PCRel32TLVLoadNowLEA:
895 printf("x86 store 32-bit pc-rel TLV lea of %s", referenceTargetAtomName(ref));
896 break;
897 case ld::Fixup::kindStoreTargetAddressX86Abs32TLVLoad:
898 printf("x86 store 32-bit absolute TLV load of %s", referenceTargetAtomName(ref));
899 break;
900 case ld::Fixup::kindStoreTargetAddressX86Abs32TLVLoadNowLEA:
901 printf("x86 store 32-bit absolute TLV lea of %s", referenceTargetAtomName(ref));
902 break;
903 case ld::Fixup::kindStoreTargetAddressARMBranch24:
904 printf("ARM store 24-bit pc-rel branch to %s", referenceTargetAtomName(ref));
905 break;
906 case ld::Fixup::kindStoreTargetAddressThumbBranch22:
907 printf("Thumb store 22-bit pc-rel branch to %s", referenceTargetAtomName(ref));
908 break;
909 case ld::Fixup::kindStoreTargetAddressARMLoad12:
910 printf("ARM store 12-bit pc-rel branch to %s", referenceTargetAtomName(ref));
911 break;
912 case ld::Fixup::kindStoreTargetAddressPPCBranch24:
913 printf("PowerPC store 24-bit pc-rel load of %s", referenceTargetAtomName(ref));
914 break;
915 case ld::Fixup::kindSetTargetTLVTemplateOffset:
916 case ld::Fixup::kindSetTargetTLVTemplateOffsetLittleEndian32:
917 case ld::Fixup::kindSetTargetTLVTemplateOffsetLittleEndian64:
918 printf("tlv template offset of %s", referenceTargetAtomName(ref));
919 //default:
920 // printf("unknown fixup");
921 // break;
922 }
923 }
924
925 uint64_t dumper::addressOfFirstAtomInSection(const ld::Section& sect)
926 {
927 uint64_t lowestAddr = (uint64_t)(-1);
928 for (std::vector<const ld::Atom*>::iterator it=_atoms.begin(); it != _atoms.end(); ++it) {
929 const ld::Atom* atom = *it;
930 if ( &atom->section() == &sect ) {
931 if ( atom->objectAddress() < lowestAddr )
932 lowestAddr = atom->objectAddress();
933 }
934 }
935 return lowestAddr;
936 }
937
938 void dumper::doAtom(const ld::Atom& atom)
939 {
940 if ( (sMatchName != NULL) && (strcmp(sMatchName, atom.name()) != 0) )
941 return;
942 _atoms.push_back(&atom);
943 }
944
945 void dumper::dump()
946 {
947 if ( sSort )
948 std::sort(_atoms.begin(), _atoms.end(), AtomSorter());
949
950 for (std::vector<const ld::Atom*>::iterator it=_atoms.begin(); it != _atoms.end(); ++it) {
951 this->dumpAtom(**it);
952 }
953 }
954
955 void dumper::dumpAtom(const ld::Atom& atom)
956 {
957 printf("name: %s\n", makeName(atom));
958 printf("size: 0x%0llX\n", atom.size());
959 printf("align: %u mod %u\n", atom.alignment().modulus, (1 << atom.alignment().powerOf2) );
960 printf("scope: %s\n", scopeString(atom));
961 if ( sShowDefinitionKind )
962 printf("def: %s\n", definitionString(atom));
963 if ( sShowCombineKind )
964 printf("combine: %s\n", combineString(atom));
965 printf("symbol: %s\n", inclusionString(atom));
966 printf("attrs: %s\n", attributeString(atom));
967 if ( sShowSection )
968 printf("section: %s,%s\n", atom.section().segmentName(), atom.section().sectionName());
969 if ( atom.beginUnwind() != atom.endUnwind() ) {
970 uint32_t lastOffset = 0;
971 uint32_t lastCUE = 0;
972 bool first = true;
973 const char* label = "unwind:";
974 for (ld::Atom::UnwindInfo::iterator it=atom.beginUnwind(); it != atom.endUnwind(); ++it) {
975 if ( !first ) {
976 printf("%s 0x%08X -> 0x%08X: 0x%08X\n", label, lastOffset, it->startOffset, lastCUE);
977 label = " ";
978 }
979 lastOffset = it->startOffset;
980 lastCUE = it->unwindInfo;
981 first = false;
982 }
983 printf("%s 0x%08X -> 0x%08X: 0x%08X\n", label, lastOffset, (uint32_t)atom.size(), lastCUE);
984 }
985 if ( atom.contentType() == ld::Atom::typeCString ) {
986 uint8_t buffer[atom.size()+2];
987 atom.copyRawContent(buffer);
988 buffer[atom.size()] = '\0';
989 printf("content: \"%s\"\n", buffer);
990 }
991 if ( atom.fixupsBegin() != atom.fixupsEnd() ) {
992 printf("fixups:\n");
993 for (unsigned int off=0; off < atom.size()+1; ++off) {
994 for (ld::Fixup::iterator it = atom.fixupsBegin(); it != atom.fixupsEnd(); ++it) {
995 if ( it->offsetInAtom == off ) {
996 switch ( it->clusterSize ) {
997 case ld::Fixup::k1of1:
998 printf(" 0x%04X ", it->offsetInAtom);
999 dumpFixup(it);
1000 break;
1001 case ld::Fixup::k1of2:
1002 printf(" 0x%04X ", it->offsetInAtom);
1003 dumpFixup(it);
1004 ++it;
1005 dumpFixup(it);
1006 break;
1007 case ld::Fixup::k1of3:
1008 printf(" 0x%04X ", it->offsetInAtom);
1009 dumpFixup(it);
1010 ++it;
1011 dumpFixup(it);
1012 ++it;
1013 dumpFixup(it);
1014 break;
1015 case ld::Fixup::k1of4:
1016 printf(" 0x%04X ", it->offsetInAtom);
1017 dumpFixup(it);
1018 ++it;
1019 dumpFixup(it);
1020 ++it;
1021 dumpFixup(it);
1022 ++it;
1023 dumpFixup(it);
1024 break;
1025 case ld::Fixup::k1of5:
1026 printf(" 0x%04X ", it->offsetInAtom);
1027 dumpFixup(it);
1028 ++it;
1029 dumpFixup(it);
1030 ++it;
1031 dumpFixup(it);
1032 ++it;
1033 dumpFixup(it);
1034 ++it;
1035 dumpFixup(it);
1036 break;
1037 default:
1038 printf(" BAD CLUSTER SIZE: cluster=%d\n", it->clusterSize);
1039 }
1040 printf("\n");
1041 }
1042 }
1043 }
1044 }
1045 if ( sShowLineInfo ) {
1046 if ( atom.beginLineInfo() != atom.endLineInfo() ) {
1047 printf("line info:\n");
1048 for (ld::Atom::LineInfo::iterator it = atom.beginLineInfo(); it != atom.endLineInfo(); ++it) {
1049 printf(" offset 0x%04X, line %d, file %s\n", it->atomOffset, it->lineNumber, it->fileName);
1050 }
1051 }
1052 }
1053
1054 printf("\n");
1055 }
1056
1057 static void dumpFile(ld::relocatable::File* file)
1058 {
1059 // stabs debug info
1060 if ( sDumpStabs && (file->debugInfo() == ld::relocatable::File::kDebugInfoStabs) ) {
1061 const std::vector<ld::relocatable::File::Stab>* stabs = file->stabs();
1062 if ( stabs != NULL )
1063 dumpStabs(stabs);
1064 }
1065 // dump atoms
1066 dumper d;
1067 file->forEachAtom(d);
1068 d.dump();
1069
1070 #if 0
1071 // get all atoms
1072 std::vector<ObjectFile::Atom*> atoms = reader->getAtoms();
1073
1074 // make copy of vector and sort (so output is canonical)
1075 std::vector<ObjectFile::Atom*> sortedAtoms(atoms);
1076 if ( sSort )
1077 std::sort(sortedAtoms.begin(), sortedAtoms.end(), AtomSorter());
1078
1079 for(std::vector<ObjectFile::Atom*>::iterator it=sortedAtoms.begin(); it != sortedAtoms.end(); ++it) {
1080 if ( sNMmode )
1081 dumpAtomLikeNM(*it);
1082 else
1083 dumpAtom(*it);
1084 }
1085 #endif
1086 }
1087
1088
1089 static ld::relocatable::File* createReader(const char* path)
1090 {
1091 struct stat stat_buf;
1092
1093 int fd = ::open(path, O_RDONLY, 0);
1094 if ( fd == -1 )
1095 throwf("cannot open file: %s", path);
1096 ::fstat(fd, &stat_buf);
1097 uint8_t* p = (uint8_t*)::mmap(NULL, stat_buf.st_size, PROT_READ, MAP_FILE | MAP_PRIVATE, fd, 0);
1098 ::close(fd);
1099 if ( p == (uint8_t*)(-1) )
1100 throwf("cannot mmap file: %s", path);
1101 const mach_header* mh = (mach_header*)p;
1102 uint64_t fileLen = stat_buf.st_size;
1103 bool foundFatSlice = false;
1104 if ( mh->magic == OSSwapBigToHostInt32(FAT_MAGIC) ) {
1105 const struct fat_header* fh = (struct fat_header*)p;
1106 const struct fat_arch* archs = (struct fat_arch*)(p + sizeof(struct fat_header));
1107 if ( (uint32_t)sPreferredArch == 0xFFFFFFFF ) {
1108 // just dump first slice of fat .o file
1109 if ( OSSwapBigToHostInt32(fh->nfat_arch) > 0 ) {
1110 p = p + OSSwapBigToHostInt32(archs[0].offset);
1111 mh = (struct mach_header*)p;
1112 fileLen = OSSwapBigToHostInt32(archs[0].size);
1113 sPreferredArch = OSSwapBigToHostInt32(archs[0].cputype);
1114 sPreferredSubArch = OSSwapBigToHostInt32(archs[0].cpusubtype);
1115 foundFatSlice = true;
1116 }
1117 }
1118 else {
1119 for (unsigned long i=0; i < OSSwapBigToHostInt32(fh->nfat_arch); ++i) {
1120 if ( OSSwapBigToHostInt32(archs[i].cputype) == (uint32_t)sPreferredArch ) {
1121 if ( ((uint32_t)sPreferredSubArch == 0xFFFFFFFF) || ((uint32_t)sPreferredSubArch == OSSwapBigToHostInt32(archs[i].cpusubtype)) ) {
1122 p = p + OSSwapBigToHostInt32(archs[i].offset);
1123 mh = (struct mach_header*)p;
1124 fileLen = OSSwapBigToHostInt32(archs[i].size);
1125 foundFatSlice = true;
1126 break;
1127 }
1128 }
1129 }
1130 }
1131 }
1132
1133 mach_o::relocatable::ParserOptions objOpts;
1134 objOpts.architecture = sPreferredArch;
1135 objOpts.objSubtypeMustMatch = false;
1136 objOpts.logAllFiles = false;
1137 objOpts.convertUnwindInfo = true;
1138 objOpts.subType = sPreferredSubArch;
1139 #if 1
1140 if ( ! foundFatSlice ) {
1141 cpu_type_t archOfObj;
1142 cpu_subtype_t subArchOfObj;
1143 if ( mach_o::relocatable::isObjectFile(p, &archOfObj, &subArchOfObj) ) {
1144 objOpts.architecture = archOfObj;
1145 objOpts.subType = subArchOfObj;
1146 }
1147 }
1148
1149 ld::relocatable::File* objResult = mach_o::relocatable::parse(p, fileLen, path, stat_buf.st_mtime, 0, objOpts);
1150 if ( objResult != NULL )
1151 return objResult;
1152
1153 // see if it is an llvm object file
1154 objResult = lto::parse(p, fileLen, path, stat_buf.st_mtime, 0, sPreferredArch, sPreferredSubArch, false);
1155 if ( objResult != NULL )
1156 return objResult;
1157
1158 throwf("not a mach-o object file: %s", path);
1159 #else
1160 // for peformance testing
1161 for (int i=0; i < 500; ++i ) {
1162 ld::relocatable::File* objResult = mach_o::relocatable::parse(p, fileLen, path, stat_buf.st_mtime, 0, objOpts);
1163 delete objResult;
1164 }
1165 exit(0);
1166 #endif
1167 }
1168
1169 static
1170 void
1171 usage()
1172 {
1173 fprintf(stderr, "ObjectDump options:\n"
1174 "\t-no_content\tdon't dump contents\n"
1175 "\t-no_section\tdon't dump section name\n"
1176 "\t-no_defintion\tdon't dump definition kind\n"
1177 "\t-no_combine\tdon't dump combine mode\n"
1178 "\t-stabs\t\tdump stabs\n"
1179 "\t-arch aaa\tonly dump info about arch aaa\n"
1180 "\t-only sym\tonly dump info about sym\n"
1181 "\t-align\t\tonly print alignment info\n"
1182 "\t-name\t\tonly print symbol names\n"
1183 );
1184 }
1185
1186 int main(int argc, const char* argv[])
1187 {
1188 if(argc<2) {
1189 usage();
1190 return 0;
1191 }
1192
1193 try {
1194 for(int i=1; i < argc; ++i) {
1195 const char* arg = argv[i];
1196 if ( arg[0] == '-' ) {
1197 if ( strcmp(arg, "-no_content") == 0 ) {
1198 sDumpContent = false;
1199 }
1200 else if ( strcmp(arg, "-nm") == 0 ) {
1201 sNMmode = true;
1202 }
1203 else if ( strcmp(arg, "-stabs") == 0 ) {
1204 sDumpStabs = true;
1205 }
1206 else if ( strcmp(arg, "-no_sort") == 0 ) {
1207 sSort = false;
1208 }
1209 else if ( strcmp(arg, "-no_section") == 0 ) {
1210 sShowSection = false;
1211 }
1212 else if ( strcmp(arg, "-no_definition") == 0 ) {
1213 sShowDefinitionKind = false;
1214 }
1215 else if ( strcmp(arg, "-no_combine") == 0 ) {
1216 sShowCombineKind = false;
1217 }
1218 else if ( strcmp(arg, "-no_line_info") == 0 ) {
1219 sShowLineInfo = false;
1220 }
1221 else if ( strcmp(arg, "-arch") == 0 ) {
1222 const char* arch = ++i<argc? argv[i]: "";
1223 if ( strcmp(arch, "ppc64") == 0 )
1224 sPreferredArch = CPU_TYPE_POWERPC64;
1225 else if ( strcmp(arch, "ppc") == 0 )
1226 sPreferredArch = CPU_TYPE_POWERPC;
1227 else if ( strcmp(arch, "i386") == 0 )
1228 sPreferredArch = CPU_TYPE_I386;
1229 else if ( strcmp(arch, "x86_64") == 0 )
1230 sPreferredArch = CPU_TYPE_X86_64;
1231 else {
1232 bool found = false;
1233 for (const ARMSubType* t=ARMSubTypes; t->subTypeName != NULL; ++t) {
1234 if ( strcmp(t->subTypeName,arch) == 0 ) {
1235 sPreferredArch = CPU_TYPE_ARM;
1236 sPreferredSubArch = t->subType;
1237 found = true;
1238 break;
1239 }
1240 }
1241 if ( !found )
1242 throwf("unknown architecture %s", arch);
1243 }
1244 }
1245 else if ( strcmp(arg, "-only") == 0 ) {
1246 sMatchName = ++i<argc? argv[i]: NULL;
1247 }
1248 else if ( strcmp(arg, "-align") == 0 ) {
1249 sPrintRestrict = true;
1250 sPrintAlign = true;
1251 }
1252 else if ( strcmp(arg, "-name") == 0 ) {
1253 sPrintRestrict = true;
1254 sPrintName = true;
1255 }
1256 else {
1257 usage();
1258 throwf("unknown option: %s\n", arg);
1259 }
1260 }
1261 else {
1262 ld::relocatable::File* reader = createReader(arg);
1263 dumpFile(reader);
1264 }
1265 }
1266 }
1267 catch (const char* msg) {
1268 fprintf(stderr, "ObjDump failed: %s\n", msg);
1269 return 1;
1270 }
1271
1272 return 0;
1273 }