]>
Commit | Line | Data |
---|---|---|
d696c285 A |
1 | /* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- |
2 | * | |
a645023d | 3 | * Copyright (c) 2005-2010 Apple Inc. All rights reserved. |
c2646906 A |
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 | */ | |
d696c285 | 24 | |
c2646906 A |
25 | #include <sys/types.h> |
26 | #include <sys/stat.h> | |
27 | #include <sys/mman.h> | |
28 | #include <fcntl.h> | |
a645023d A |
29 | #include <mach-o/nlist.h> |
30 | #include <mach-o/stab.h> | |
31 | #include <mach-o/fat.h> | |
32 | #include <mach-o/loader.h> | |
77cc3118 | 33 | |
a645023d A |
34 | #include "MachOFileAbstraction.hpp" |
35 | #include "parsers/macho_relocatable_file.h" | |
36 | #include "parsers/lto_file.h" | |
d696c285 A |
37 | |
38 | static bool sDumpContent= true; | |
39 | static bool sDumpStabs = false; | |
40 | static bool sSort = true; | |
2f2f92e4 | 41 | static bool sNMmode = false; |
a645023d A |
42 | static bool sShowSection = true; |
43 | static bool sShowDefinitionKind = true; | |
44 | static bool sShowCombineKind = true; | |
afe874b1 | 45 | static bool sShowLineInfo = true; |
a645023d | 46 | |
afe874b1 | 47 | static cpu_type_t sPreferredArch = 0xFFFFFFFF; |
c211e7c9 | 48 | static cpu_subtype_t sPreferredSubArch = 0xFFFFFFFF; |
a645023d | 49 | static const char* sMatchName = NULL; |
a61fdf0a A |
50 | static int sPrintRestrict; |
51 | static int sPrintAlign; | |
52 | static int sPrintName; | |
c2646906 | 53 | |
c2646906 A |
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 | ||
2f2f92e4 A |
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 | ||
a645023d | 77 | static void dumpStabs(const std::vector<ld::relocatable::File::Stab>* stabs) |
c2646906 A |
78 | { |
79 | // debug info | |
d696c285 | 80 | printf("stabs: (%lu)\n", stabs->size()); |
a645023d A |
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; | |
c2646906 A |
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; | |
d696c285 A |
121 | case N_OSO: |
122 | code = " OSO"; | |
123 | break; | |
c2646906 A |
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 | } | |
a645023d | 170 | printf(" [atom=%20s] %02X %04X %s %s\n", ((stab.atom != NULL) ? stab.atom->name() : ""), stab.other, stab.desc, code, stab.string); |
c2646906 A |
171 | } |
172 | } | |
173 | ||
a645023d A |
174 | #if 0 |
175 | static void dumpAtomLikeNM(ld::Atom* atom) | |
2f2f92e4 | 176 | { |
a645023d | 177 | uint32_t size = atom->size(); |
2f2f92e4 A |
178 | |
179 | const char* visibility; | |
a645023d A |
180 | switch ( atom->scope() ) { |
181 | case ld::Atom::scopeTranslationUnit: | |
2f2f92e4 A |
182 | visibility = "internal"; |
183 | break; | |
a645023d | 184 | case ld::Atom::scopeLinkageUnit: |
2f2f92e4 A |
185 | visibility = "hidden "; |
186 | break; | |
a645023d | 187 | case ld::Atom::scopeGlobal: |
2f2f92e4 A |
188 | visibility = "global "; |
189 | break; | |
190 | default: | |
191 | visibility = " "; | |
192 | break; | |
193 | } | |
194 | ||
195 | const char* kind; | |
a645023d A |
196 | switch ( atom->definitionKind() ) { |
197 | case ld::Atom::kRegularDefinition: | |
2f2f92e4 A |
198 | kind = "regular "; |
199 | break; | |
a645023d | 200 | case ld::Atom::kTentativeDefinition: |
2f2f92e4 A |
201 | kind = "tentative"; |
202 | break; | |
a645023d | 203 | case ld::Atom::kWeakDefinition: |
2f2f92e4 A |
204 | kind = "weak "; |
205 | break; | |
a645023d | 206 | case ld::Atom::kAbsoluteSymbol: |
2f2f92e4 A |
207 | kind = "absolute "; |
208 | break; | |
209 | default: | |
210 | kind = " "; | |
211 | break; | |
212 | } | |
213 | ||
a645023d | 214 | printf("0x%08X %s %s %s\n", size, visibility, kind, atom->name()); |
2f2f92e4 A |
215 | } |
216 | ||
217 | ||
a645023d | 218 | static void dumpAtom(ld::Atom* atom) |
c2646906 | 219 | { |
a645023d | 220 | if(sMatchName && strcmp(sMatchName, atom->name())) |
a61fdf0a A |
221 | return; |
222 | ||
c2646906 A |
223 | //printf("atom: %p\n", atom); |
224 | ||
225 | // name | |
a61fdf0a | 226 | if(!sPrintRestrict || sPrintName) |
a645023d | 227 | printf("name: %s\n", atom->name()); |
c2646906 A |
228 | |
229 | // scope | |
a61fdf0a | 230 | if(!sPrintRestrict) |
a645023d A |
231 | switch ( atom->scope() ) { |
232 | case ld::Atom::scopeTranslationUnit: | |
c2646906 A |
233 | printf("scope: translation unit\n"); |
234 | break; | |
a645023d | 235 | case ld::Atom::scopeLinkageUnit: |
c2646906 A |
236 | printf("scope: linkage unit\n"); |
237 | break; | |
a645023d | 238 | case ld::Atom::scopeGlobal: |
c2646906 A |
239 | printf("scope: global\n"); |
240 | break; | |
241 | default: | |
242 | printf("scope: unknown\n"); | |
a61fdf0a | 243 | } |
c2646906 | 244 | |
d696c285 | 245 | // kind |
a61fdf0a | 246 | if(!sPrintRestrict) |
a645023d A |
247 | switch ( atom->definitionKind() ) { |
248 | case ld::Atom::kRegularDefinition: | |
d696c285 A |
249 | printf("kind: regular\n"); |
250 | break; | |
a645023d | 251 | case ld::Atom::kWeakDefinition: |
d696c285 A |
252 | printf("kind: weak\n"); |
253 | break; | |
a645023d | 254 | case ld::Atom::kTentativeDefinition: |
d696c285 A |
255 | printf("kind: tentative\n"); |
256 | break; | |
a645023d | 257 | case ld::Atom::kExternalDefinition: |
d696c285 A |
258 | printf("kind: import\n"); |
259 | break; | |
a645023d | 260 | case ld::Atom::kExternalWeakDefinition: |
d696c285 A |
261 | printf("kind: weak import\n"); |
262 | break; | |
a645023d | 263 | case ld::Atom::kAbsoluteSymbol: |
a61fdf0a A |
264 | printf("kind: absolute symbol\n"); |
265 | break; | |
d696c285 | 266 | default: |
a61fdf0a A |
267 | printf("kind: unknown\n"); |
268 | } | |
d696c285 | 269 | |
c2646906 | 270 | // segment and section |
a645023d A |
271 | if(!sPrintRestrict && (atom->section().sectionName() != NULL) ) |
272 | printf("section: %s,%s\n", atom->section().segmentName(), atom->section().sectionName()); | |
c2646906 A |
273 | |
274 | // attributes | |
a61fdf0a A |
275 | if(!sPrintRestrict) { |
276 | printf("attrs: "); | |
277 | if ( atom->dontDeadStrip() ) | |
278 | printf("dont-dead-strip "); | |
2f2f92e4 A |
279 | if ( atom->isThumb() ) |
280 | printf("thumb "); | |
a61fdf0a A |
281 | printf("\n"); |
282 | } | |
c2646906 A |
283 | |
284 | // size | |
a61fdf0a | 285 | if(!sPrintRestrict) |
a645023d | 286 | printf("size: 0x%012llX\n", atom->size()); |
c2646906 A |
287 | |
288 | // alignment | |
a61fdf0a | 289 | if(!sPrintRestrict || sPrintAlign) |
a645023d | 290 | printf("align: %u mod %u\n", atom->alignment().modulus, (1 << atom->alignment().powerOf2) ); |
c2646906 A |
291 | |
292 | // content | |
a61fdf0a | 293 | if (!sPrintRestrict && sDumpContent ) { |
a645023d | 294 | uint64_t size = atom->size(); |
d696c285 A |
295 | if ( size < 4096 ) { |
296 | uint8_t content[size]; | |
297 | atom->copyRawContent(content); | |
298 | printf("content: "); | |
a645023d | 299 | if ( atom->contentType() == ld::Atom::typeCString ) { |
a61fdf0a A |
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("\""); | |
d696c285 A |
308 | } |
309 | else { | |
310 | for (unsigned int i=0; i < size; ++i) | |
311 | printf("%02X ", content[i]); | |
312 | } | |
c2646906 | 313 | } |
d696c285 | 314 | printf("\n"); |
c2646906 | 315 | } |
c2646906 | 316 | |
55e3d2f6 A |
317 | // unwind info |
318 | if(!sPrintRestrict) { | |
319 | if ( atom->beginUnwind() != atom->endUnwind() ) { | |
320 | printf("unwind encodings:\n"); | |
a645023d | 321 | for (ld::Atom::UnwindInfo::iterator it = atom->beginUnwind(); it != atom->endUnwind(); ++it) { |
55e3d2f6 A |
322 | printf("\t 0x%04X 0x%08X\n", it->startOffset, it->unwindInfo); |
323 | } | |
324 | } | |
325 | } | |
a645023d | 326 | #if 0 |
c2646906 | 327 | // references |
a61fdf0a A |
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 | } | |
c2646906 | 336 | } |
a645023d | 337 | #endif |
d696c285 | 338 | // line info |
a61fdf0a | 339 | if(!sPrintRestrict) { |
a645023d A |
340 | if ( atom->beginLineInfo() != atom->endLineInfo() ) { |
341 | printf("line info:\n"); | |
342 | for (ld::Atom::LineInfo::iterator it = atom->beginLineInfo(); it != atom->endLineInfo(); ++it) { | |
a61fdf0a A |
343 | printf(" offset 0x%04X, line %d, file %s\n", it->atomOffset, it->lineNumber, it->fileName); |
344 | } | |
d696c285 A |
345 | } |
346 | } | |
347 | ||
a61fdf0a A |
348 | if(!sPrintRestrict) |
349 | printf("\n"); | |
c2646906 | 350 | } |
a645023d | 351 | #endif |
d696c285 A |
352 | struct AtomSorter |
353 | { | |
a645023d | 354 | bool operator()(const ld::Atom* left, const ld::Atom* right) |
d696c285 | 355 | { |
a61fdf0a A |
356 | if ( left == right ) |
357 | return false; | |
a645023d A |
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()); | |
d696c285 A |
450 | } |
451 | }; | |
452 | ||
c2646906 | 453 | |
a645023d A |
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; | |
a645023d A |
741 | case ld::Fixup::kindStoreX86BranchPCRel8: |
742 | printf(", then store as x86 8-bit pcrel branch"); | |
743 | break; | |
744 | case ld::Fixup::kindStoreX86BranchPCRel32: | |
745 | printf(", then store as x86 32-bit pcrel branch"); | |
746 | break; | |
747 | case ld::Fixup::kindStoreX86PCRel8: | |
748 | printf(", then store as x86 8-bit pcrel"); | |
749 | break; | |
750 | case ld::Fixup::kindStoreX86PCRel16: | |
751 | printf(", then store as x86 16-bit pcrel"); | |
752 | break; | |
753 | case ld::Fixup::kindStoreX86PCRel32: | |
754 | printf(", then store as x86 32-bit pcrel"); | |
755 | break; | |
756 | case ld::Fixup::kindStoreX86PCRel32_1: | |
757 | printf(", then store as x86 32-bit pcrel from +1"); | |
758 | break; | |
759 | case ld::Fixup::kindStoreX86PCRel32_2: | |
760 | printf(", then store as x86 32-bit pcrel from +2"); | |
761 | break; | |
762 | case ld::Fixup::kindStoreX86PCRel32_4: | |
763 | printf(", then store as x86 32-bit pcrel from +4"); | |
764 | break; | |
765 | case ld::Fixup::kindStoreX86PCRel32GOTLoad: | |
766 | printf(", then store as x86 32-bit pcrel GOT load"); | |
767 | break; | |
768 | case ld::Fixup::kindStoreX86PCRel32GOTLoadNowLEA: | |
769 | printf(", then store as x86 32-bit pcrel GOT load -> LEA"); | |
770 | break; | |
771 | case ld::Fixup::kindStoreX86PCRel32GOT: | |
772 | printf(", then store as x86 32-bit pcrel GOT access"); | |
773 | break; | |
774 | case ld::Fixup::kindStoreX86PCRel32TLVLoad: | |
775 | printf(", then store as x86 32-bit pcrel TLV load"); | |
776 | break; | |
777 | case ld::Fixup::kindStoreX86PCRel32TLVLoadNowLEA: | |
778 | printf(", then store as x86 32-bit pcrel TLV load"); | |
779 | break; | |
780 | case ld::Fixup::kindStoreX86Abs32TLVLoad: | |
781 | printf(", then store as x86 32-bit absolute TLV load"); | |
782 | break; | |
783 | case ld::Fixup::kindStoreX86Abs32TLVLoadNowLEA: | |
784 | printf(", then store as x86 32-bit absolute TLV load -> LEA"); | |
785 | break; | |
786 | case ld::Fixup::kindStoreARMBranch24: | |
787 | printf(", then store as ARM 24-bit pcrel branch"); | |
788 | break; | |
789 | case ld::Fixup::kindStoreThumbBranch22: | |
790 | printf(", then store as Thumb 22-bit pcrel branch"); | |
791 | break; | |
792 | case ld::Fixup::kindStoreARMLoad12: | |
793 | printf(", then store as ARM 12-bit pcrel load"); | |
794 | break; | |
795 | case ld::Fixup::kindStoreARMLow16: | |
796 | printf(", then store low-16 in ARM movw"); | |
797 | break; | |
798 | case ld::Fixup::kindStoreARMHigh16: | |
799 | printf(", then store high-16 in ARM movt"); | |
800 | break; | |
801 | case ld::Fixup::kindStoreThumbLow16: | |
802 | printf(", then store low-16 in Thumb movw"); | |
803 | break; | |
804 | case ld::Fixup::kindStoreThumbHigh16: | |
805 | printf(", then store high-16 in Thumb movt"); | |
806 | break; | |
807 | case ld::Fixup::kindDtraceExtra: | |
808 | printf("dtrace static probe extra info"); | |
809 | break; | |
810 | case ld::Fixup::kindStoreX86DtraceCallSiteNop: | |
811 | printf("x86 dtrace static probe site"); | |
812 | break; | |
813 | case ld::Fixup::kindStoreX86DtraceIsEnableSiteClear: | |
814 | printf("x86 dtrace static is-enabled site"); | |
815 | break; | |
a645023d A |
816 | case ld::Fixup::kindStoreARMDtraceCallSiteNop: |
817 | printf("ARM dtrace static probe site"); | |
818 | break; | |
819 | case ld::Fixup::kindStoreARMDtraceIsEnableSiteClear: | |
820 | printf("ARM dtrace static is-enabled site"); | |
821 | break; | |
822 | case ld::Fixup::kindStoreThumbDtraceCallSiteNop: | |
823 | printf("Thumb dtrace static probe site"); | |
824 | break; | |
825 | case ld::Fixup::kindStoreThumbDtraceIsEnableSiteClear: | |
826 | printf("Thumb dtrace static is-enabled site"); | |
827 | break; | |
828 | case ld::Fixup::kindLazyTarget: | |
829 | printf("lazy reference to external symbol %s", referenceTargetAtomName(ref)); | |
830 | break; | |
831 | case ld::Fixup::kindSetLazyOffset: | |
832 | printf("offset of lazy binding info for %s", referenceTargetAtomName(ref)); | |
833 | break; | |
834 | case ld::Fixup::kindStoreTargetAddressLittleEndian32: | |
835 | printf("store 32-bit little endian address of %s", referenceTargetAtomName(ref)); | |
836 | break; | |
837 | case ld::Fixup::kindStoreTargetAddressLittleEndian64: | |
838 | printf("store 64-bit little endian address of %s", referenceTargetAtomName(ref)); | |
839 | break; | |
840 | case ld::Fixup::kindStoreTargetAddressBigEndian32: | |
841 | printf("store 32-bit big endian address of %s", referenceTargetAtomName(ref)); | |
842 | break; | |
843 | case ld::Fixup::kindStoreTargetAddressBigEndian64: | |
844 | printf("store 64-bit big endian address of %s", referenceTargetAtomName(ref)); | |
845 | break; | |
846 | case ld::Fixup::kindStoreTargetAddressX86PCRel32: | |
847 | printf("x86 store 32-bit pc-rel address of %s", referenceTargetAtomName(ref)); | |
848 | break; | |
849 | case ld::Fixup::kindStoreTargetAddressX86BranchPCRel32: | |
850 | printf("x86 store 32-bit pc-rel branch to %s", referenceTargetAtomName(ref)); | |
851 | break; | |
852 | case ld::Fixup::kindStoreTargetAddressX86PCRel32GOTLoad: | |
853 | printf("x86 store 32-bit pc-rel GOT load of %s", referenceTargetAtomName(ref)); | |
854 | break; | |
855 | case ld::Fixup::kindStoreTargetAddressX86PCRel32GOTLoadNowLEA: | |
856 | printf("x86 store 32-bit pc-rel lea of %s", referenceTargetAtomName(ref)); | |
857 | break; | |
858 | case ld::Fixup::kindStoreTargetAddressX86PCRel32TLVLoad: | |
859 | printf("x86 store 32-bit pc-rel TLV load of %s", referenceTargetAtomName(ref)); | |
860 | break; | |
861 | case ld::Fixup::kindStoreTargetAddressX86PCRel32TLVLoadNowLEA: | |
862 | printf("x86 store 32-bit pc-rel TLV lea of %s", referenceTargetAtomName(ref)); | |
863 | break; | |
864 | case ld::Fixup::kindStoreTargetAddressX86Abs32TLVLoad: | |
865 | printf("x86 store 32-bit absolute TLV load of %s", referenceTargetAtomName(ref)); | |
866 | break; | |
867 | case ld::Fixup::kindStoreTargetAddressX86Abs32TLVLoadNowLEA: | |
868 | printf("x86 store 32-bit absolute TLV lea of %s", referenceTargetAtomName(ref)); | |
869 | break; | |
870 | case ld::Fixup::kindStoreTargetAddressARMBranch24: | |
871 | printf("ARM store 24-bit pc-rel branch to %s", referenceTargetAtomName(ref)); | |
872 | break; | |
873 | case ld::Fixup::kindStoreTargetAddressThumbBranch22: | |
874 | printf("Thumb store 22-bit pc-rel branch to %s", referenceTargetAtomName(ref)); | |
875 | break; | |
876 | case ld::Fixup::kindStoreTargetAddressARMLoad12: | |
877 | printf("ARM store 12-bit pc-rel branch to %s", referenceTargetAtomName(ref)); | |
878 | break; | |
a645023d A |
879 | case ld::Fixup::kindSetTargetTLVTemplateOffset: |
880 | case ld::Fixup::kindSetTargetTLVTemplateOffsetLittleEndian32: | |
881 | case ld::Fixup::kindSetTargetTLVTemplateOffsetLittleEndian64: | |
882 | printf("tlv template offset of %s", referenceTargetAtomName(ref)); | |
883 | //default: | |
884 | // printf("unknown fixup"); | |
885 | // break; | |
886 | } | |
887 | } | |
888 | ||
889 | uint64_t dumper::addressOfFirstAtomInSection(const ld::Section& sect) | |
890 | { | |
891 | uint64_t lowestAddr = (uint64_t)(-1); | |
892 | for (std::vector<const ld::Atom*>::iterator it=_atoms.begin(); it != _atoms.end(); ++it) { | |
893 | const ld::Atom* atom = *it; | |
894 | if ( &atom->section() == § ) { | |
895 | if ( atom->objectAddress() < lowestAddr ) | |
896 | lowestAddr = atom->objectAddress(); | |
897 | } | |
898 | } | |
899 | return lowestAddr; | |
900 | } | |
901 | ||
902 | void dumper::doAtom(const ld::Atom& atom) | |
903 | { | |
904 | if ( (sMatchName != NULL) && (strcmp(sMatchName, atom.name()) != 0) ) | |
905 | return; | |
906 | _atoms.push_back(&atom); | |
907 | } | |
908 | ||
909 | void dumper::dump() | |
910 | { | |
911 | if ( sSort ) | |
912 | std::sort(_atoms.begin(), _atoms.end(), AtomSorter()); | |
913 | ||
914 | for (std::vector<const ld::Atom*>::iterator it=_atoms.begin(); it != _atoms.end(); ++it) { | |
915 | this->dumpAtom(**it); | |
916 | } | |
917 | } | |
918 | ||
919 | void dumper::dumpAtom(const ld::Atom& atom) | |
920 | { | |
921 | printf("name: %s\n", makeName(atom)); | |
922 | printf("size: 0x%0llX\n", atom.size()); | |
923 | printf("align: %u mod %u\n", atom.alignment().modulus, (1 << atom.alignment().powerOf2) ); | |
924 | printf("scope: %s\n", scopeString(atom)); | |
925 | if ( sShowDefinitionKind ) | |
926 | printf("def: %s\n", definitionString(atom)); | |
927 | if ( sShowCombineKind ) | |
928 | printf("combine: %s\n", combineString(atom)); | |
929 | printf("symbol: %s\n", inclusionString(atom)); | |
930 | printf("attrs: %s\n", attributeString(atom)); | |
931 | if ( sShowSection ) | |
932 | printf("section: %s,%s\n", atom.section().segmentName(), atom.section().sectionName()); | |
933 | if ( atom.beginUnwind() != atom.endUnwind() ) { | |
afe874b1 A |
934 | uint32_t lastOffset = 0; |
935 | uint32_t lastCUE = 0; | |
936 | bool first = true; | |
937 | const char* label = "unwind:"; | |
938 | for (ld::Atom::UnwindInfo::iterator it=atom.beginUnwind(); it != atom.endUnwind(); ++it) { | |
939 | if ( !first ) { | |
940 | printf("%s 0x%08X -> 0x%08X: 0x%08X\n", label, lastOffset, it->startOffset, lastCUE); | |
941 | label = " "; | |
942 | } | |
943 | lastOffset = it->startOffset; | |
944 | lastCUE = it->unwindInfo; | |
945 | first = false; | |
946 | } | |
947 | printf("%s 0x%08X -> 0x%08X: 0x%08X\n", label, lastOffset, (uint32_t)atom.size(), lastCUE); | |
a645023d A |
948 | } |
949 | if ( atom.contentType() == ld::Atom::typeCString ) { | |
950 | uint8_t buffer[atom.size()+2]; | |
951 | atom.copyRawContent(buffer); | |
952 | buffer[atom.size()] = '\0'; | |
953 | printf("content: \"%s\"\n", buffer); | |
954 | } | |
955 | if ( atom.fixupsBegin() != atom.fixupsEnd() ) { | |
956 | printf("fixups:\n"); | |
957 | for (unsigned int off=0; off < atom.size()+1; ++off) { | |
958 | for (ld::Fixup::iterator it = atom.fixupsBegin(); it != atom.fixupsEnd(); ++it) { | |
959 | if ( it->offsetInAtom == off ) { | |
960 | switch ( it->clusterSize ) { | |
961 | case ld::Fixup::k1of1: | |
962 | printf(" 0x%04X ", it->offsetInAtom); | |
963 | dumpFixup(it); | |
964 | break; | |
965 | case ld::Fixup::k1of2: | |
966 | printf(" 0x%04X ", it->offsetInAtom); | |
967 | dumpFixup(it); | |
968 | ++it; | |
969 | dumpFixup(it); | |
970 | break; | |
971 | case ld::Fixup::k1of3: | |
972 | printf(" 0x%04X ", it->offsetInAtom); | |
973 | dumpFixup(it); | |
974 | ++it; | |
975 | dumpFixup(it); | |
976 | ++it; | |
977 | dumpFixup(it); | |
978 | break; | |
979 | case ld::Fixup::k1of4: | |
980 | printf(" 0x%04X ", it->offsetInAtom); | |
981 | dumpFixup(it); | |
982 | ++it; | |
983 | dumpFixup(it); | |
984 | ++it; | |
985 | dumpFixup(it); | |
986 | ++it; | |
987 | dumpFixup(it); | |
988 | break; | |
989 | case ld::Fixup::k1of5: | |
990 | printf(" 0x%04X ", it->offsetInAtom); | |
991 | dumpFixup(it); | |
992 | ++it; | |
993 | dumpFixup(it); | |
994 | ++it; | |
995 | dumpFixup(it); | |
996 | ++it; | |
997 | dumpFixup(it); | |
998 | ++it; | |
999 | dumpFixup(it); | |
1000 | break; | |
1001 | default: | |
1002 | printf(" BAD CLUSTER SIZE: cluster=%d\n", it->clusterSize); | |
1003 | } | |
1004 | printf("\n"); | |
1005 | } | |
1006 | } | |
1007 | } | |
1008 | } | |
afe874b1 A |
1009 | if ( sShowLineInfo ) { |
1010 | if ( atom.beginLineInfo() != atom.endLineInfo() ) { | |
1011 | printf("line info:\n"); | |
1012 | for (ld::Atom::LineInfo::iterator it = atom.beginLineInfo(); it != atom.endLineInfo(); ++it) { | |
1013 | printf(" offset 0x%04X, line %d, file %s\n", it->atomOffset, it->lineNumber, it->fileName); | |
1014 | } | |
a645023d A |
1015 | } |
1016 | } | |
afe874b1 | 1017 | |
a645023d A |
1018 | printf("\n"); |
1019 | } | |
1020 | ||
1021 | static void dumpFile(ld::relocatable::File* file) | |
c2646906 | 1022 | { |
d696c285 | 1023 | // stabs debug info |
a645023d A |
1024 | if ( sDumpStabs && (file->debugInfo() == ld::relocatable::File::kDebugInfoStabs) ) { |
1025 | const std::vector<ld::relocatable::File::Stab>* stabs = file->stabs(); | |
d696c285 A |
1026 | if ( stabs != NULL ) |
1027 | dumpStabs(stabs); | |
1028 | } | |
a645023d A |
1029 | // dump atoms |
1030 | dumper d; | |
1031 | file->forEachAtom(d); | |
1032 | d.dump(); | |
1033 | ||
1034 | #if 0 | |
d696c285 | 1035 | // get all atoms |
c2646906 | 1036 | std::vector<ObjectFile::Atom*> atoms = reader->getAtoms(); |
d696c285 A |
1037 | |
1038 | // make copy of vector and sort (so output is canonical) | |
1039 | std::vector<ObjectFile::Atom*> sortedAtoms(atoms); | |
1040 | if ( sSort ) | |
1041 | std::sort(sortedAtoms.begin(), sortedAtoms.end(), AtomSorter()); | |
1042 | ||
2f2f92e4 A |
1043 | for(std::vector<ObjectFile::Atom*>::iterator it=sortedAtoms.begin(); it != sortedAtoms.end(); ++it) { |
1044 | if ( sNMmode ) | |
1045 | dumpAtomLikeNM(*it); | |
1046 | else | |
1047 | dumpAtom(*it); | |
1048 | } | |
a645023d | 1049 | #endif |
c2646906 A |
1050 | } |
1051 | ||
1052 | ||
a645023d | 1053 | static ld::relocatable::File* createReader(const char* path) |
c2646906 A |
1054 | { |
1055 | struct stat stat_buf; | |
1056 | ||
1057 | int fd = ::open(path, O_RDONLY, 0); | |
1058 | if ( fd == -1 ) | |
d696c285 | 1059 | throwf("cannot open file: %s", path); |
c2646906 | 1060 | ::fstat(fd, &stat_buf); |
69a49097 | 1061 | uint8_t* p = (uint8_t*)::mmap(NULL, stat_buf.st_size, PROT_READ, MAP_FILE | MAP_PRIVATE, fd, 0); |
c2646906 | 1062 | ::close(fd); |
a645023d A |
1063 | if ( p == (uint8_t*)(-1) ) |
1064 | throwf("cannot mmap file: %s", path); | |
c2646906 | 1065 | const mach_header* mh = (mach_header*)p; |
a645023d A |
1066 | uint64_t fileLen = stat_buf.st_size; |
1067 | bool foundFatSlice = false; | |
c2646906 A |
1068 | if ( mh->magic == OSSwapBigToHostInt32(FAT_MAGIC) ) { |
1069 | const struct fat_header* fh = (struct fat_header*)p; | |
1070 | const struct fat_arch* archs = (struct fat_arch*)(p + sizeof(struct fat_header)); | |
afe874b1 A |
1071 | if ( (uint32_t)sPreferredArch == 0xFFFFFFFF ) { |
1072 | // just dump first slice of fat .o file | |
1073 | if ( OSSwapBigToHostInt32(fh->nfat_arch) > 0 ) { | |
1074 | p = p + OSSwapBigToHostInt32(archs[0].offset); | |
1075 | mh = (struct mach_header*)p; | |
1076 | fileLen = OSSwapBigToHostInt32(archs[0].size); | |
1077 | sPreferredArch = OSSwapBigToHostInt32(archs[0].cputype); | |
1078 | sPreferredSubArch = OSSwapBigToHostInt32(archs[0].cpusubtype); | |
1079 | foundFatSlice = true; | |
1080 | } | |
1081 | } | |
1082 | else { | |
1083 | for (unsigned long i=0; i < OSSwapBigToHostInt32(fh->nfat_arch); ++i) { | |
1084 | if ( OSSwapBigToHostInt32(archs[i].cputype) == (uint32_t)sPreferredArch ) { | |
1085 | if ( ((uint32_t)sPreferredSubArch == 0xFFFFFFFF) || ((uint32_t)sPreferredSubArch == OSSwapBigToHostInt32(archs[i].cpusubtype)) ) { | |
1086 | p = p + OSSwapBigToHostInt32(archs[i].offset); | |
1087 | mh = (struct mach_header*)p; | |
1088 | fileLen = OSSwapBigToHostInt32(archs[i].size); | |
1089 | foundFatSlice = true; | |
1090 | break; | |
1091 | } | |
c211e7c9 | 1092 | } |
c2646906 A |
1093 | } |
1094 | } | |
1095 | } | |
a645023d A |
1096 | |
1097 | mach_o::relocatable::ParserOptions objOpts; | |
1098 | objOpts.architecture = sPreferredArch; | |
1099 | objOpts.objSubtypeMustMatch = false; | |
1100 | objOpts.logAllFiles = false; | |
1101 | objOpts.convertUnwindInfo = true; | |
1102 | objOpts.subType = sPreferredSubArch; | |
1103 | #if 1 | |
1104 | if ( ! foundFatSlice ) { | |
1105 | cpu_type_t archOfObj; | |
1106 | cpu_subtype_t subArchOfObj; | |
1107 | if ( mach_o::relocatable::isObjectFile(p, &archOfObj, &subArchOfObj) ) { | |
1108 | objOpts.architecture = archOfObj; | |
1109 | objOpts.subType = subArchOfObj; | |
1110 | } | |
2f2f92e4 | 1111 | } |
a645023d A |
1112 | |
1113 | ld::relocatable::File* objResult = mach_o::relocatable::parse(p, fileLen, path, stat_buf.st_mtime, 0, objOpts); | |
1114 | if ( objResult != NULL ) | |
1115 | return objResult; | |
1116 | ||
1117 | // see if it is an llvm object file | |
1118 | objResult = lto::parse(p, fileLen, path, stat_buf.st_mtime, 0, sPreferredArch, sPreferredSubArch, false); | |
1119 | if ( objResult != NULL ) | |
1120 | return objResult; | |
1121 | ||
d696c285 | 1122 | throwf("not a mach-o object file: %s", path); |
a645023d A |
1123 | #else |
1124 | // for peformance testing | |
1125 | for (int i=0; i < 500; ++i ) { | |
1126 | ld::relocatable::File* objResult = mach_o::relocatable::parse(p, fileLen, path, stat_buf.st_mtime, 0, objOpts); | |
1127 | delete objResult; | |
1128 | } | |
1129 | exit(0); | |
1130 | #endif | |
c2646906 A |
1131 | } |
1132 | ||
a61fdf0a A |
1133 | static |
1134 | void | |
1135 | usage() | |
1136 | { | |
1137 | fprintf(stderr, "ObjectDump options:\n" | |
1138 | "\t-no_content\tdon't dump contents\n" | |
a645023d A |
1139 | "\t-no_section\tdon't dump section name\n" |
1140 | "\t-no_defintion\tdon't dump definition kind\n" | |
1141 | "\t-no_combine\tdon't dump combine mode\n" | |
a61fdf0a A |
1142 | "\t-stabs\t\tdump stabs\n" |
1143 | "\t-arch aaa\tonly dump info about arch aaa\n" | |
1144 | "\t-only sym\tonly dump info about sym\n" | |
1145 | "\t-align\t\tonly print alignment info\n" | |
1146 | "\t-name\t\tonly print symbol names\n" | |
1147 | ); | |
1148 | } | |
c2646906 A |
1149 | |
1150 | int main(int argc, const char* argv[]) | |
1151 | { | |
a61fdf0a A |
1152 | if(argc<2) { |
1153 | usage(); | |
1154 | return 0; | |
1155 | } | |
1156 | ||
c2646906 | 1157 | try { |
d696c285 A |
1158 | for(int i=1; i < argc; ++i) { |
1159 | const char* arg = argv[i]; | |
1160 | if ( arg[0] == '-' ) { | |
1161 | if ( strcmp(arg, "-no_content") == 0 ) { | |
1162 | sDumpContent = false; | |
1163 | } | |
2f2f92e4 A |
1164 | else if ( strcmp(arg, "-nm") == 0 ) { |
1165 | sNMmode = true; | |
1166 | } | |
d696c285 A |
1167 | else if ( strcmp(arg, "-stabs") == 0 ) { |
1168 | sDumpStabs = true; | |
1169 | } | |
1170 | else if ( strcmp(arg, "-no_sort") == 0 ) { | |
1171 | sSort = false; | |
1172 | } | |
a645023d A |
1173 | else if ( strcmp(arg, "-no_section") == 0 ) { |
1174 | sShowSection = false; | |
1175 | } | |
1176 | else if ( strcmp(arg, "-no_definition") == 0 ) { | |
1177 | sShowDefinitionKind = false; | |
1178 | } | |
1179 | else if ( strcmp(arg, "-no_combine") == 0 ) { | |
1180 | sShowCombineKind = false; | |
1181 | } | |
afe874b1 A |
1182 | else if ( strcmp(arg, "-no_line_info") == 0 ) { |
1183 | sShowLineInfo = false; | |
1184 | } | |
d696c285 | 1185 | else if ( strcmp(arg, "-arch") == 0 ) { |
a61fdf0a | 1186 | const char* arch = ++i<argc? argv[i]: ""; |
b2fa67a8 | 1187 | if ( strcmp(arch, "i386") == 0 ) |
d696c285 | 1188 | sPreferredArch = CPU_TYPE_I386; |
69a49097 A |
1189 | else if ( strcmp(arch, "x86_64") == 0 ) |
1190 | sPreferredArch = CPU_TYPE_X86_64; | |
afe874b1 A |
1191 | else { |
1192 | bool found = false; | |
1193 | for (const ARMSubType* t=ARMSubTypes; t->subTypeName != NULL; ++t) { | |
1194 | if ( strcmp(t->subTypeName,arch) == 0 ) { | |
1195 | sPreferredArch = CPU_TYPE_ARM; | |
1196 | sPreferredSubArch = t->subType; | |
1197 | found = true; | |
1198 | break; | |
1199 | } | |
1200 | } | |
1201 | if ( !found ) | |
1202 | throwf("unknown architecture %s", arch); | |
c211e7c9 | 1203 | } |
d696c285 | 1204 | } |
a61fdf0a A |
1205 | else if ( strcmp(arg, "-only") == 0 ) { |
1206 | sMatchName = ++i<argc? argv[i]: NULL; | |
1207 | } | |
1208 | else if ( strcmp(arg, "-align") == 0 ) { | |
1209 | sPrintRestrict = true; | |
1210 | sPrintAlign = true; | |
1211 | } | |
1212 | else if ( strcmp(arg, "-name") == 0 ) { | |
1213 | sPrintRestrict = true; | |
1214 | sPrintName = true; | |
1215 | } | |
d696c285 | 1216 | else { |
a61fdf0a | 1217 | usage(); |
d696c285 A |
1218 | throwf("unknown option: %s\n", arg); |
1219 | } | |
1220 | } | |
1221 | else { | |
a645023d | 1222 | ld::relocatable::File* reader = createReader(arg); |
d696c285 A |
1223 | dumpFile(reader); |
1224 | } | |
1225 | } | |
c2646906 A |
1226 | } |
1227 | catch (const char* msg) { | |
1228 | fprintf(stderr, "ObjDump failed: %s\n", msg); | |
d696c285 | 1229 | return 1; |
c2646906 A |
1230 | } |
1231 | ||
1232 | return 0; | |
1233 | } |