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