]>
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 | } | |
82b4b32b A |
399 | if ( leftString != rightString ) { |
400 | assert(leftString != NULL); | |
401 | assert(rightString != NULL); | |
402 | diff = strcmp(leftString, rightString); | |
403 | if ( diff != 0 ) | |
404 | return (diff < 0); | |
405 | } | |
a645023d A |
406 | } |
407 | else if ( left->section().type() == ld::Section::typeLiteral4 ) { | |
408 | // if literal sort by content | |
409 | uint32_t leftValue = *(uint32_t*)left->rawContentPointer(); | |
410 | uint32_t rightValue = *(uint32_t*)right->rawContentPointer(); | |
411 | diff = (leftValue - rightValue); | |
412 | if ( diff != 0 ) | |
413 | return (diff < 0); | |
414 | } | |
415 | else if ( left->section().type() == ld::Section::typeCFI ) { | |
416 | // if __he_frame sort by address | |
417 | diff = (left->objectAddress() - right->objectAddress()); | |
418 | if ( diff != 0 ) | |
419 | return (diff < 0); | |
420 | } | |
421 | else if ( left->section().type() == ld::Section::typeNonLazyPointer ) { | |
422 | // if non-lazy-pointer sort by name | |
423 | const char* leftString = NULL; | |
424 | assert(left->fixupsBegin() != left->fixupsEnd()); | |
425 | for (ld::Fixup::iterator fit = left->fixupsBegin(); fit != left->fixupsEnd(); ++fit) { | |
426 | if ( fit->binding == ld::Fixup::bindingByNameUnbound ) { | |
427 | leftString = fit->u.name; | |
428 | } | |
429 | else if ( fit->binding == ld::Fixup::bindingDirectlyBound ) { | |
430 | leftString = fit->u.target->name(); | |
431 | } | |
432 | } | |
433 | const char* rightString = NULL; | |
434 | assert(right->fixupsBegin() != right->fixupsEnd()); | |
435 | for (ld::Fixup::iterator fit = right->fixupsBegin(); fit != right->fixupsEnd(); ++fit) { | |
436 | if ( fit->binding == ld::Fixup::bindingByNameUnbound ) { | |
437 | rightString = fit->u.name; | |
438 | } | |
439 | else if ( fit->binding == ld::Fixup::bindingDirectlyBound ) { | |
440 | rightString = fit->u.target->name(); | |
441 | } | |
442 | } | |
443 | assert(leftString != NULL); | |
444 | assert(rightString != NULL); | |
445 | diff = strcmp(leftString, rightString); | |
446 | if ( diff != 0 ) | |
447 | return (diff < 0); | |
448 | } | |
449 | ||
450 | // else sort by size | |
451 | return (left->size() < right->size()); | |
d696c285 A |
452 | } |
453 | }; | |
454 | ||
c2646906 | 455 | |
a645023d A |
456 | class dumper : public ld::File::AtomHandler |
457 | { | |
458 | public: | |
459 | void dump(); | |
460 | virtual void doAtom(const ld::Atom&); | |
461 | virtual void doFile(const ld::File&) {} | |
462 | private: | |
463 | void dumpAtom(const ld::Atom& atom); | |
464 | const char* scopeString(const ld::Atom&); | |
465 | const char* definitionString(const ld::Atom&); | |
466 | const char* combineString(const ld::Atom&); | |
467 | const char* inclusionString(const ld::Atom&); | |
468 | const char* attributeString(const ld::Atom&); | |
469 | const char* makeName(const ld::Atom& atom); | |
470 | const char* referenceTargetAtomName(const ld::Fixup* ref); | |
471 | void dumpFixup(const ld::Fixup* ref); | |
472 | ||
473 | uint64_t addressOfFirstAtomInSection(const ld::Section&); | |
474 | ||
475 | std::vector<const ld::Atom*> _atoms; | |
476 | }; | |
477 | ||
478 | const char* dumper::scopeString(const ld::Atom& atom) | |
479 | { | |
480 | switch ( (ld::Atom::Scope)atom.scope() ) { | |
481 | case ld::Atom::scopeTranslationUnit: | |
482 | return "translation-unit"; | |
483 | case ld::Atom::scopeLinkageUnit: | |
484 | return "hidden"; | |
485 | case ld::Atom::scopeGlobal: | |
486 | if ( atom.autoHide() ) | |
487 | return "global but automatically hidden"; | |
488 | else | |
489 | return "global"; | |
490 | } | |
491 | return "UNKNOWN"; | |
492 | } | |
493 | ||
494 | const char* dumper::definitionString(const ld::Atom& atom) | |
495 | { | |
496 | switch ( (ld::Atom::Definition)atom.definition() ) { | |
497 | case ld::Atom::definitionRegular: | |
498 | return "regular"; | |
499 | case ld::Atom::definitionTentative: | |
500 | return "tentative"; | |
501 | case ld::Atom::definitionAbsolute: | |
502 | return "absolute"; | |
503 | case ld::Atom::definitionProxy: | |
504 | return "proxy"; | |
505 | } | |
506 | return "UNKNOWN"; | |
507 | } | |
508 | ||
509 | const char* dumper::combineString(const ld::Atom& atom) | |
510 | { | |
511 | switch ( (ld::Atom::Combine)atom.combine() ) { | |
512 | case ld::Atom::combineNever: | |
513 | return "never"; | |
514 | case ld::Atom::combineByName: | |
515 | return "by-name"; | |
516 | case ld::Atom::combineByNameAndContent: | |
517 | return "by-name-and-content"; | |
518 | case ld::Atom::combineByNameAndReferences: | |
519 | return "by-name-and-references"; | |
520 | } | |
521 | return "UNKNOWN"; | |
522 | } | |
523 | ||
524 | const char* dumper::inclusionString(const ld::Atom& atom) | |
525 | { | |
526 | switch ( (ld::Atom::SymbolTableInclusion)atom.symbolTableInclusion() ) { | |
527 | case ld::Atom::symbolTableNotIn: | |
528 | return "not in"; | |
529 | case ld::Atom::symbolTableNotInFinalLinkedImages: | |
530 | return "not in final linked images"; | |
531 | case ld::Atom::symbolTableIn: | |
532 | return "in"; | |
533 | case ld::Atom::symbolTableInAndNeverStrip: | |
534 | return "in and never strip"; | |
535 | case ld::Atom::symbolTableInAsAbsolute: | |
536 | return "in as absolute"; | |
537 | case ld::Atom::symbolTableInWithRandomAutoStripLabel: | |
538 | return "in as random auto-strip label"; | |
539 | } | |
540 | return "UNKNOWN"; | |
541 | } | |
542 | ||
543 | ||
544 | ||
545 | const char* dumper::attributeString(const ld::Atom& atom) | |
546 | { | |
547 | static char buffer[256]; | |
548 | buffer[0] = '\0'; | |
549 | ||
550 | if ( atom.dontDeadStrip() ) | |
551 | strcat(buffer, "dont-dead-strip "); | |
552 | ||
553 | if ( atom.isThumb() ) | |
554 | strcat(buffer, "thumb "); | |
555 | ||
556 | if ( atom.isAlias() ) | |
557 | strcat(buffer, "alias "); | |
558 | ||
559 | if ( atom.contentType() == ld::Atom::typeResolver ) | |
560 | strcat(buffer, "resolver "); | |
561 | ||
562 | return buffer; | |
563 | } | |
564 | ||
565 | const char* dumper::makeName(const ld::Atom& atom) | |
566 | { | |
567 | static char buffer[4096]; | |
568 | strcpy(buffer, "???"); | |
569 | switch ( atom.symbolTableInclusion() ) { | |
570 | case ld::Atom::symbolTableNotIn: | |
571 | if ( atom.contentType() == ld::Atom::typeCString ) { | |
572 | strcpy(buffer, "cstring="); | |
573 | strlcat(buffer, (char*)atom.rawContentPointer(), 4096); | |
574 | } | |
575 | else if ( atom.section().type() == ld::Section::typeLiteral4 ) { | |
576 | char temp[16]; | |
577 | strcpy(buffer, "literal4="); | |
578 | uint32_t value = *(uint32_t*)atom.rawContentPointer(); | |
579 | sprintf(temp, "0x%08X", value); | |
580 | strcat(buffer, temp); | |
581 | } | |
582 | else if ( atom.section().type() == ld::Section::typeLiteral8 ) { | |
583 | char temp[32]; | |
584 | strcpy(buffer, "literal8="); | |
585 | uint32_t value1 = *(uint32_t*)atom.rawContentPointer(); | |
586 | uint32_t value2 = ((uint32_t*)atom.rawContentPointer())[1]; | |
587 | sprintf(temp, "0x%08X%08X", value1, value2); | |
588 | strcat(buffer, temp); | |
589 | } | |
590 | else if ( atom.section().type() == ld::Section::typeLiteral16 ) { | |
591 | char temp[64]; | |
592 | strcpy(buffer, "literal16="); | |
593 | uint32_t value1 = *(uint32_t*)atom.rawContentPointer(); | |
594 | uint32_t value2 = ((uint32_t*)atom.rawContentPointer())[1]; | |
595 | uint32_t value3 = ((uint32_t*)atom.rawContentPointer())[2]; | |
596 | uint32_t value4 = ((uint32_t*)atom.rawContentPointer())[3]; | |
597 | sprintf(temp, "0x%08X%08X%08X%08X", value1, value2, value3, value4); | |
598 | strcat(buffer, temp); | |
599 | } | |
600 | else if ( atom.section().type() == ld::Section::typeCStringPointer ) { | |
601 | assert(atom.fixupsBegin() != atom.fixupsEnd()); | |
602 | for (ld::Fixup::iterator fit = atom.fixupsBegin(); fit != atom.fixupsEnd(); ++fit) { | |
603 | if ( fit->binding == ld::Fixup::bindingByContentBound ) { | |
604 | const ld::Atom* cstringAtom = fit->u.target; | |
605 | if ( (cstringAtom != NULL) && (cstringAtom->contentType() == ld::Atom::typeCString) ) { | |
606 | strlcpy(buffer, atom.name(), 4096); | |
607 | strlcat(buffer, "=", 4096); | |
608 | strlcat(buffer, (char*)cstringAtom->rawContentPointer(), 4096); | |
609 | } | |
610 | } | |
611 | } | |
612 | } | |
613 | else if ( atom.section().type() == ld::Section::typeNonLazyPointer ) { | |
614 | assert(atom.fixupsBegin() != atom.fixupsEnd()); | |
615 | for (ld::Fixup::iterator fit = atom.fixupsBegin(); fit != atom.fixupsEnd(); ++fit) { | |
616 | if ( fit->binding == ld::Fixup::bindingByNameUnbound ) { | |
617 | strcpy(buffer, "non-lazy-pointer-to:"); | |
618 | strlcat(buffer, fit->u.name, 4096); | |
619 | return buffer; | |
620 | } | |
621 | else if ( fit->binding == ld::Fixup::bindingDirectlyBound ) { | |
622 | strcpy(buffer, "non-lazy-pointer-to-local:"); | |
623 | strlcat(buffer, fit->u.target->name(), 4096); | |
624 | return buffer; | |
625 | } | |
626 | } | |
627 | strlcpy(buffer, atom.name(), 4096); | |
628 | } | |
629 | else { | |
630 | uint64_t sectAddr = addressOfFirstAtomInSection(atom.section()); | |
631 | sprintf(buffer, "%s@%s+0x%08llX", atom.name(), atom.section().sectionName(), atom.objectAddress()-sectAddr); | |
632 | } | |
633 | break; | |
634 | case ld::Atom::symbolTableNotInFinalLinkedImages: | |
635 | case ld::Atom::symbolTableIn: | |
636 | case ld::Atom::symbolTableInAndNeverStrip: | |
637 | case ld::Atom::symbolTableInAsAbsolute: | |
638 | case ld::Atom::symbolTableInWithRandomAutoStripLabel: | |
639 | strlcpy(buffer, atom.name(), 4096); | |
640 | break; | |
641 | } | |
642 | return buffer; | |
643 | } | |
644 | ||
645 | const char* dumper::referenceTargetAtomName(const ld::Fixup* ref) | |
646 | { | |
647 | static char buffer[4096]; | |
648 | switch ( ref->binding ) { | |
649 | case ld::Fixup::bindingNone: | |
650 | return "NO BINDING"; | |
651 | case ld::Fixup::bindingByNameUnbound: | |
652 | strcpy(buffer, "by-name("); | |
653 | strlcat(buffer, ref->u.name, 4096); | |
654 | strlcat(buffer, ")", 4096); | |
655 | return buffer; | |
656 | //return ref->u.name; | |
657 | case ld::Fixup::bindingByContentBound: | |
658 | strcpy(buffer, "by-content("); | |
659 | strlcat(buffer, makeName(*ref->u.target), 4096); | |
660 | strlcat(buffer, ")", 4096); | |
661 | return buffer; | |
662 | case ld::Fixup::bindingDirectlyBound: | |
663 | strcpy(buffer, "direct("); | |
664 | strlcat(buffer, makeName(*ref->u.target), 4096); | |
665 | strlcat(buffer, ")", 4096); | |
666 | return buffer; | |
667 | case ld::Fixup::bindingsIndirectlyBound: | |
668 | return "BOUND INDIRECTLY"; | |
669 | } | |
670 | return "BAD BINDING"; | |
671 | } | |
672 | ||
673 | ||
674 | void dumper::dumpFixup(const ld::Fixup* ref) | |
675 | { | |
676 | if ( ref->weakImport ) { | |
677 | printf("weak_import "); | |
678 | } | |
679 | switch ( (ld::Fixup::Kind)(ref->kind) ) { | |
680 | case ld::Fixup::kindNone: | |
681 | printf("none"); | |
682 | break; | |
683 | case ld::Fixup::kindNoneFollowOn: | |
684 | printf("followed by %s", referenceTargetAtomName(ref)); | |
685 | break; | |
686 | case ld::Fixup::kindNoneGroupSubordinate: | |
687 | printf("group subordinate %s", referenceTargetAtomName(ref)); | |
688 | break; | |
689 | case ld::Fixup::kindNoneGroupSubordinateFDE: | |
690 | printf("group subordinate FDE %s", referenceTargetAtomName(ref)); | |
691 | break; | |
692 | case ld::Fixup::kindNoneGroupSubordinateLSDA: | |
693 | printf("group subordinate LSDA %s", referenceTargetAtomName(ref)); | |
694 | break; | |
695 | case ld::Fixup::kindNoneGroupSubordinatePersonality: | |
696 | printf("group subordinate personality %s", referenceTargetAtomName(ref)); | |
697 | break; | |
698 | case ld::Fixup::kindSetTargetAddress: | |
699 | printf("%s", referenceTargetAtomName(ref)); | |
700 | break; | |
701 | case ld::Fixup::kindSubtractTargetAddress: | |
702 | printf(" - %s", referenceTargetAtomName(ref)); | |
703 | break; | |
704 | case ld::Fixup::kindAddAddend: | |
705 | printf(" + 0x%llX", ref->u.addend); | |
706 | break; | |
707 | case ld::Fixup::kindSubtractAddend: | |
708 | printf(" - 0x%llX", ref->u.addend); | |
709 | break; | |
710 | case ld::Fixup::kindSetTargetImageOffset: | |
711 | printf("imageOffset(%s)", referenceTargetAtomName(ref)); | |
712 | break; | |
713 | case ld::Fixup::kindSetTargetSectionOffset: | |
714 | printf("sectionOffset(%s)", referenceTargetAtomName(ref)); | |
715 | break; | |
716 | case ld::Fixup::kindStore8: | |
717 | printf(", then store byte"); | |
718 | break; | |
719 | case ld::Fixup::kindStoreLittleEndian16: | |
720 | printf(", then store 16-bit little endian"); | |
721 | break; | |
722 | case ld::Fixup::kindStoreLittleEndianLow24of32: | |
723 | printf(", then store low 24-bit little endian"); | |
724 | break; | |
725 | case ld::Fixup::kindStoreLittleEndian32: | |
726 | printf(", then store 32-bit little endian"); | |
727 | break; | |
728 | case ld::Fixup::kindStoreLittleEndian64: | |
729 | printf(", then store 64-bit little endian"); | |
730 | break; | |
731 | case ld::Fixup::kindStoreBigEndian16: | |
732 | printf(", then store 16-bit big endian"); | |
733 | break; | |
734 | case ld::Fixup::kindStoreBigEndianLow24of32: | |
735 | printf(", then store low 24-bit big endian"); | |
736 | break; | |
737 | case ld::Fixup::kindStoreBigEndian32: | |
738 | printf(", then store 32-bit big endian"); | |
739 | break; | |
740 | case ld::Fixup::kindStoreBigEndian64: | |
741 | printf(", then store 64-bit big endian"); | |
742 | break; | |
a645023d A |
743 | case ld::Fixup::kindStoreX86BranchPCRel8: |
744 | printf(", then store as x86 8-bit pcrel branch"); | |
745 | break; | |
746 | case ld::Fixup::kindStoreX86BranchPCRel32: | |
747 | printf(", then store as x86 32-bit pcrel branch"); | |
748 | break; | |
749 | case ld::Fixup::kindStoreX86PCRel8: | |
750 | printf(", then store as x86 8-bit pcrel"); | |
751 | break; | |
752 | case ld::Fixup::kindStoreX86PCRel16: | |
753 | printf(", then store as x86 16-bit pcrel"); | |
754 | break; | |
755 | case ld::Fixup::kindStoreX86PCRel32: | |
756 | printf(", then store as x86 32-bit pcrel"); | |
757 | break; | |
758 | case ld::Fixup::kindStoreX86PCRel32_1: | |
759 | printf(", then store as x86 32-bit pcrel from +1"); | |
760 | break; | |
761 | case ld::Fixup::kindStoreX86PCRel32_2: | |
762 | printf(", then store as x86 32-bit pcrel from +2"); | |
763 | break; | |
764 | case ld::Fixup::kindStoreX86PCRel32_4: | |
765 | printf(", then store as x86 32-bit pcrel from +4"); | |
766 | break; | |
767 | case ld::Fixup::kindStoreX86PCRel32GOTLoad: | |
768 | printf(", then store as x86 32-bit pcrel GOT load"); | |
769 | break; | |
770 | case ld::Fixup::kindStoreX86PCRel32GOTLoadNowLEA: | |
771 | printf(", then store as x86 32-bit pcrel GOT load -> LEA"); | |
772 | break; | |
773 | case ld::Fixup::kindStoreX86PCRel32GOT: | |
774 | printf(", then store as x86 32-bit pcrel GOT access"); | |
775 | break; | |
776 | case ld::Fixup::kindStoreX86PCRel32TLVLoad: | |
777 | printf(", then store as x86 32-bit pcrel TLV load"); | |
778 | break; | |
779 | case ld::Fixup::kindStoreX86PCRel32TLVLoadNowLEA: | |
780 | printf(", then store as x86 32-bit pcrel TLV load"); | |
781 | break; | |
782 | case ld::Fixup::kindStoreX86Abs32TLVLoad: | |
783 | printf(", then store as x86 32-bit absolute TLV load"); | |
784 | break; | |
785 | case ld::Fixup::kindStoreX86Abs32TLVLoadNowLEA: | |
786 | printf(", then store as x86 32-bit absolute TLV load -> LEA"); | |
787 | break; | |
788 | case ld::Fixup::kindStoreARMBranch24: | |
789 | printf(", then store as ARM 24-bit pcrel branch"); | |
790 | break; | |
791 | case ld::Fixup::kindStoreThumbBranch22: | |
792 | printf(", then store as Thumb 22-bit pcrel branch"); | |
793 | break; | |
794 | case ld::Fixup::kindStoreARMLoad12: | |
795 | printf(", then store as ARM 12-bit pcrel load"); | |
796 | break; | |
797 | case ld::Fixup::kindStoreARMLow16: | |
798 | printf(", then store low-16 in ARM movw"); | |
799 | break; | |
800 | case ld::Fixup::kindStoreARMHigh16: | |
801 | printf(", then store high-16 in ARM movt"); | |
802 | break; | |
803 | case ld::Fixup::kindStoreThumbLow16: | |
804 | printf(", then store low-16 in Thumb movw"); | |
805 | break; | |
806 | case ld::Fixup::kindStoreThumbHigh16: | |
807 | printf(", then store high-16 in Thumb movt"); | |
808 | break; | |
82b4b32b | 809 | #if SUPPORT_ARCH_arm64 |
f80fe69f A |
810 | case ld::Fixup::kindStoreARM64Branch26: |
811 | printf(", then store as ARM64 26-bit pcrel branch"); | |
812 | break; | |
813 | case ld::Fixup::kindStoreARM64Page21: | |
814 | printf(", then store as ARM64 21-bit pcrel ADRP"); | |
815 | break; | |
816 | case ld::Fixup::kindStoreARM64PageOff12: | |
817 | printf(", then store as ARM64 12-bit offset"); | |
818 | break; | |
819 | case ld::Fixup::kindStoreARM64GOTLoadPage21: | |
820 | printf(", then store as ARM64 21-bit pcrel ADRP of GOT"); | |
821 | break; | |
822 | case ld::Fixup::kindStoreARM64GOTLoadPageOff12: | |
823 | printf(", then store as ARM64 12-bit page offset of GOT"); | |
824 | break; | |
825 | case ld::Fixup::kindStoreARM64GOTLeaPage21: | |
826 | printf(", then store as ARM64 21-bit pcrel ADRP of GOT lea"); | |
827 | break; | |
828 | case ld::Fixup::kindStoreARM64GOTLeaPageOff12: | |
829 | printf(", then store as ARM64 12-bit page offset of GOT lea"); | |
830 | break; | |
831 | case ld::Fixup::kindStoreARM64TLVPLoadPage21: | |
832 | printf(", then store as ARM64 21-bit pcrel ADRP of TLVP"); | |
833 | break; | |
834 | case ld::Fixup::kindStoreARM64TLVPLoadPageOff12: | |
835 | printf(", then store as ARM64 12-bit page offset of TLVP"); | |
836 | break; | |
599556ff A |
837 | case ld::Fixup::kindStoreARM64TLVPLoadNowLeaPage21: |
838 | printf(", then store as ARM64 21-bit pcrel ADRP of lea of TLVP"); | |
839 | break; | |
840 | case ld::Fixup::kindStoreARM64TLVPLoadNowLeaPageOff12: | |
841 | printf(", then store as ARM64 12-bit page offset of lea of TLVP"); | |
842 | break; | |
f80fe69f A |
843 | case ld::Fixup::kindStoreARM64PointerToGOT: |
844 | printf(", then store as 64-bit pointer to GOT entry"); | |
845 | break; | |
846 | case ld::Fixup::kindStoreARM64PCRelToGOT: | |
847 | printf(", then store as 32-bit delta to GOT entry"); | |
848 | break; | |
82b4b32b | 849 | #endif |
a645023d A |
850 | case ld::Fixup::kindDtraceExtra: |
851 | printf("dtrace static probe extra info"); | |
852 | break; | |
853 | case ld::Fixup::kindStoreX86DtraceCallSiteNop: | |
854 | printf("x86 dtrace static probe site"); | |
855 | break; | |
856 | case ld::Fixup::kindStoreX86DtraceIsEnableSiteClear: | |
857 | printf("x86 dtrace static is-enabled site"); | |
858 | break; | |
a645023d A |
859 | case ld::Fixup::kindStoreARMDtraceCallSiteNop: |
860 | printf("ARM dtrace static probe site"); | |
861 | break; | |
862 | case ld::Fixup::kindStoreARMDtraceIsEnableSiteClear: | |
863 | printf("ARM dtrace static is-enabled site"); | |
864 | break; | |
865 | case ld::Fixup::kindStoreThumbDtraceCallSiteNop: | |
866 | printf("Thumb dtrace static probe site"); | |
867 | break; | |
868 | case ld::Fixup::kindStoreThumbDtraceIsEnableSiteClear: | |
869 | printf("Thumb dtrace static is-enabled site"); | |
870 | break; | |
82b4b32b | 871 | #if SUPPORT_ARCH_arm64 |
f80fe69f A |
872 | case ld::Fixup::kindStoreARM64DtraceCallSiteNop: |
873 | printf("ARM64 dtrace static probe site"); | |
874 | break; | |
875 | case ld::Fixup::kindStoreARM64DtraceIsEnableSiteClear: | |
876 | printf("ARM64 dtrace static is-enabled site"); | |
877 | break; | |
82b4b32b | 878 | #endif |
a645023d A |
879 | case ld::Fixup::kindLazyTarget: |
880 | printf("lazy reference to external symbol %s", referenceTargetAtomName(ref)); | |
881 | break; | |
882 | case ld::Fixup::kindSetLazyOffset: | |
883 | printf("offset of lazy binding info for %s", referenceTargetAtomName(ref)); | |
ebf6f434 | 884 | break; |
9543cb2f A |
885 | case ld::Fixup::kindIslandTarget: |
886 | printf("ultimate target of island %s", referenceTargetAtomName(ref)); | |
887 | break; | |
ebf6f434 A |
888 | case ld::Fixup::kindDataInCodeStartData: |
889 | printf("start of data in code"); | |
890 | break; | |
891 | case ld::Fixup::kindDataInCodeStartJT8: | |
892 | printf("start of jump table 8 data in code"); | |
893 | break; | |
894 | case ld::Fixup::kindDataInCodeStartJT16: | |
895 | printf("start of jump table 16 data in code"); | |
896 | break; | |
897 | case ld::Fixup::kindDataInCodeStartJT32: | |
898 | printf("start of jump table 32 data in code"); | |
899 | break; | |
900 | case ld::Fixup::kindDataInCodeStartJTA32: | |
901 | printf("start of jump table absolute 32 data in code"); | |
902 | break; | |
903 | case ld::Fixup::kindDataInCodeEnd: | |
904 | printf("end of data in code"); | |
905 | break; | |
9543cb2f A |
906 | case ld::Fixup::kindLinkerOptimizationHint: |
907 | #if SUPPORT_ARCH_arm64 | |
908 | ld::Fixup::LOH_arm64 extra; | |
909 | extra.addend = ref->u.addend; | |
910 | printf("ARM64 hint: "); | |
911 | switch(extra.info.kind) { | |
912 | case LOH_ARM64_ADRP_ADRP: | |
913 | printf("ADRP-ADRP"); | |
914 | break; | |
915 | case LOH_ARM64_ADRP_LDR: | |
916 | printf("ADRP-LDR"); | |
917 | break; | |
918 | case LOH_ARM64_ADRP_ADD_LDR: | |
919 | printf("ADRP-ADD-LDR"); | |
920 | break; | |
921 | case LOH_ARM64_ADRP_LDR_GOT_LDR: | |
922 | printf("ADRP-LDR-GOT-LDR"); | |
923 | break; | |
924 | case LOH_ARM64_ADRP_ADD_STR: | |
925 | printf("ADRP-ADD-STR"); | |
926 | break; | |
927 | case LOH_ARM64_ADRP_LDR_GOT_STR: | |
928 | printf("ADRP-LDR-GOT-STR"); | |
929 | break; | |
930 | case LOH_ARM64_ADRP_ADD: | |
931 | printf("ADRP-ADD"); | |
932 | break; | |
933 | default: | |
934 | printf("kind=%d", extra.info.kind); | |
935 | break; | |
936 | } | |
937 | printf(", offset1=0x%X", (extra.info.delta1 << 2) + ref->offsetInAtom); | |
938 | if ( extra.info.count > 0 ) | |
939 | printf(", offset2=0x%X", (extra.info.delta2 << 2) + ref->offsetInAtom); | |
940 | if ( extra.info.count > 1 ) | |
941 | printf(", offset3=0x%X", (extra.info.delta3 << 2) + ref->offsetInAtom); | |
942 | if ( extra.info.count > 2 ) | |
943 | printf(", offset4=0x%X", (extra.info.delta4 << 2) + ref->offsetInAtom); | |
944 | #endif | |
945 | break; | |
a645023d A |
946 | case ld::Fixup::kindStoreTargetAddressLittleEndian32: |
947 | printf("store 32-bit little endian address of %s", referenceTargetAtomName(ref)); | |
948 | break; | |
949 | case ld::Fixup::kindStoreTargetAddressLittleEndian64: | |
950 | printf("store 64-bit little endian address of %s", referenceTargetAtomName(ref)); | |
951 | break; | |
952 | case ld::Fixup::kindStoreTargetAddressBigEndian32: | |
953 | printf("store 32-bit big endian address of %s", referenceTargetAtomName(ref)); | |
954 | break; | |
955 | case ld::Fixup::kindStoreTargetAddressBigEndian64: | |
956 | printf("store 64-bit big endian address of %s", referenceTargetAtomName(ref)); | |
957 | break; | |
958 | case ld::Fixup::kindStoreTargetAddressX86PCRel32: | |
959 | printf("x86 store 32-bit pc-rel address of %s", referenceTargetAtomName(ref)); | |
960 | break; | |
961 | case ld::Fixup::kindStoreTargetAddressX86BranchPCRel32: | |
962 | printf("x86 store 32-bit pc-rel branch to %s", referenceTargetAtomName(ref)); | |
963 | break; | |
964 | case ld::Fixup::kindStoreTargetAddressX86PCRel32GOTLoad: | |
965 | printf("x86 store 32-bit pc-rel GOT load of %s", referenceTargetAtomName(ref)); | |
966 | break; | |
967 | case ld::Fixup::kindStoreTargetAddressX86PCRel32GOTLoadNowLEA: | |
968 | printf("x86 store 32-bit pc-rel lea of %s", referenceTargetAtomName(ref)); | |
969 | break; | |
970 | case ld::Fixup::kindStoreTargetAddressX86PCRel32TLVLoad: | |
971 | printf("x86 store 32-bit pc-rel TLV load of %s", referenceTargetAtomName(ref)); | |
972 | break; | |
973 | case ld::Fixup::kindStoreTargetAddressX86PCRel32TLVLoadNowLEA: | |
974 | printf("x86 store 32-bit pc-rel TLV lea of %s", referenceTargetAtomName(ref)); | |
975 | break; | |
976 | case ld::Fixup::kindStoreTargetAddressX86Abs32TLVLoad: | |
977 | printf("x86 store 32-bit absolute TLV load of %s", referenceTargetAtomName(ref)); | |
978 | break; | |
979 | case ld::Fixup::kindStoreTargetAddressX86Abs32TLVLoadNowLEA: | |
980 | printf("x86 store 32-bit absolute TLV lea of %s", referenceTargetAtomName(ref)); | |
981 | break; | |
982 | case ld::Fixup::kindStoreTargetAddressARMBranch24: | |
983 | printf("ARM store 24-bit pc-rel branch to %s", referenceTargetAtomName(ref)); | |
984 | break; | |
985 | case ld::Fixup::kindStoreTargetAddressThumbBranch22: | |
986 | printf("Thumb store 22-bit pc-rel branch to %s", referenceTargetAtomName(ref)); | |
987 | break; | |
988 | case ld::Fixup::kindStoreTargetAddressARMLoad12: | |
989 | printf("ARM store 12-bit pc-rel branch to %s", referenceTargetAtomName(ref)); | |
990 | break; | |
a645023d A |
991 | case ld::Fixup::kindSetTargetTLVTemplateOffset: |
992 | case ld::Fixup::kindSetTargetTLVTemplateOffsetLittleEndian32: | |
993 | case ld::Fixup::kindSetTargetTLVTemplateOffsetLittleEndian64: | |
994 | printf("tlv template offset of %s", referenceTargetAtomName(ref)); | |
f80fe69f | 995 | break; |
82b4b32b | 996 | #if SUPPORT_ARCH_arm64 |
f80fe69f A |
997 | case ld::Fixup::kindStoreTargetAddressARM64Branch26: |
998 | printf("ARM64 store 26-bit pcrel branch to %s", referenceTargetAtomName(ref)); | |
999 | break; | |
1000 | case ld::Fixup::kindStoreTargetAddressARM64Page21: | |
1001 | printf("ARM64 store 21-bit pcrel ADRP to %s", referenceTargetAtomName(ref)); | |
1002 | break; | |
1003 | case ld::Fixup::kindStoreTargetAddressARM64PageOff12: | |
1004 | printf("ARM64 store 12-bit page offset of %s", referenceTargetAtomName(ref)); | |
1005 | break; | |
1006 | case ld::Fixup::kindStoreTargetAddressARM64GOTLoadPage21: | |
1007 | printf("ARM64 store 21-bit pcrel ADRP to GOT for %s", referenceTargetAtomName(ref)); | |
1008 | break; | |
1009 | case ld::Fixup::kindStoreTargetAddressARM64GOTLoadPageOff12: | |
1010 | printf("ARM64 store 12-bit page offset of GOT of %s", referenceTargetAtomName(ref)); | |
1011 | break; | |
1012 | case ld::Fixup::kindStoreTargetAddressARM64GOTLeaPage21: | |
599556ff | 1013 | printf("ARM64 store 21-bit pcrel ADRP to GOT lea for %s", referenceTargetAtomName(ref)); |
f80fe69f A |
1014 | break; |
1015 | case ld::Fixup::kindStoreTargetAddressARM64GOTLeaPageOff12: | |
599556ff A |
1016 | printf("ARM64 store 12-bit page offset of GOT lea of %s", referenceTargetAtomName(ref)); |
1017 | break; | |
1018 | case ld::Fixup::kindStoreTargetAddressARM64TLVPLoadPage21: | |
1019 | printf("ARM64 store 21-bit pcrel ADRP to TLV for %s", referenceTargetAtomName(ref)); | |
1020 | break; | |
1021 | case ld::Fixup::kindStoreTargetAddressARM64TLVPLoadPageOff12: | |
1022 | printf("ARM64 store 12-bit page offset of TLV of %s", referenceTargetAtomName(ref)); | |
1023 | break; | |
1024 | case ld::Fixup::kindStoreTargetAddressARM64TLVPLoadNowLeaPage21: | |
1025 | printf("ARM64 store 21-bit pcrel ADRP to lea for TLV for %s", referenceTargetAtomName(ref)); | |
1026 | break; | |
1027 | case ld::Fixup::kindStoreTargetAddressARM64TLVPLoadNowLeaPageOff12: | |
1028 | printf("ARM64 store 12-bit page offset of lea for TLV of %s", referenceTargetAtomName(ref)); | |
f80fe69f | 1029 | break; |
82b4b32b | 1030 | #endif |
a645023d A |
1031 | //default: |
1032 | // printf("unknown fixup"); | |
1033 | // break; | |
1034 | } | |
1035 | } | |
1036 | ||
1037 | uint64_t dumper::addressOfFirstAtomInSection(const ld::Section& sect) | |
1038 | { | |
1039 | uint64_t lowestAddr = (uint64_t)(-1); | |
1040 | for (std::vector<const ld::Atom*>::iterator it=_atoms.begin(); it != _atoms.end(); ++it) { | |
1041 | const ld::Atom* atom = *it; | |
1042 | if ( &atom->section() == § ) { | |
1043 | if ( atom->objectAddress() < lowestAddr ) | |
1044 | lowestAddr = atom->objectAddress(); | |
1045 | } | |
1046 | } | |
1047 | return lowestAddr; | |
1048 | } | |
1049 | ||
1050 | void dumper::doAtom(const ld::Atom& atom) | |
1051 | { | |
1052 | if ( (sMatchName != NULL) && (strcmp(sMatchName, atom.name()) != 0) ) | |
1053 | return; | |
1054 | _atoms.push_back(&atom); | |
1055 | } | |
1056 | ||
1057 | void dumper::dump() | |
1058 | { | |
1059 | if ( sSort ) | |
1060 | std::sort(_atoms.begin(), _atoms.end(), AtomSorter()); | |
1061 | ||
1062 | for (std::vector<const ld::Atom*>::iterator it=_atoms.begin(); it != _atoms.end(); ++it) { | |
1063 | this->dumpAtom(**it); | |
1064 | } | |
1065 | } | |
1066 | ||
1067 | void dumper::dumpAtom(const ld::Atom& atom) | |
1068 | { | |
1069 | printf("name: %s\n", makeName(atom)); | |
1070 | printf("size: 0x%0llX\n", atom.size()); | |
1071 | printf("align: %u mod %u\n", atom.alignment().modulus, (1 << atom.alignment().powerOf2) ); | |
1072 | printf("scope: %s\n", scopeString(atom)); | |
1073 | if ( sShowDefinitionKind ) | |
1074 | printf("def: %s\n", definitionString(atom)); | |
1075 | if ( sShowCombineKind ) | |
1076 | printf("combine: %s\n", combineString(atom)); | |
1077 | printf("symbol: %s\n", inclusionString(atom)); | |
1078 | printf("attrs: %s\n", attributeString(atom)); | |
1079 | if ( sShowSection ) | |
1080 | printf("section: %s,%s\n", atom.section().segmentName(), atom.section().sectionName()); | |
1081 | if ( atom.beginUnwind() != atom.endUnwind() ) { | |
afe874b1 A |
1082 | uint32_t lastOffset = 0; |
1083 | uint32_t lastCUE = 0; | |
1084 | bool first = true; | |
1085 | const char* label = "unwind:"; | |
1086 | for (ld::Atom::UnwindInfo::iterator it=atom.beginUnwind(); it != atom.endUnwind(); ++it) { | |
1087 | if ( !first ) { | |
1088 | printf("%s 0x%08X -> 0x%08X: 0x%08X\n", label, lastOffset, it->startOffset, lastCUE); | |
1089 | label = " "; | |
1090 | } | |
1091 | lastOffset = it->startOffset; | |
1092 | lastCUE = it->unwindInfo; | |
1093 | first = false; | |
1094 | } | |
1095 | printf("%s 0x%08X -> 0x%08X: 0x%08X\n", label, lastOffset, (uint32_t)atom.size(), lastCUE); | |
a645023d A |
1096 | } |
1097 | if ( atom.contentType() == ld::Atom::typeCString ) { | |
1098 | uint8_t buffer[atom.size()+2]; | |
1099 | atom.copyRawContent(buffer); | |
1100 | buffer[atom.size()] = '\0'; | |
1101 | printf("content: \"%s\"\n", buffer); | |
1102 | } | |
1103 | if ( atom.fixupsBegin() != atom.fixupsEnd() ) { | |
1104 | printf("fixups:\n"); | |
1105 | for (unsigned int off=0; off < atom.size()+1; ++off) { | |
1106 | for (ld::Fixup::iterator it = atom.fixupsBegin(); it != atom.fixupsEnd(); ++it) { | |
1107 | if ( it->offsetInAtom == off ) { | |
1108 | switch ( it->clusterSize ) { | |
1109 | case ld::Fixup::k1of1: | |
1110 | printf(" 0x%04X ", it->offsetInAtom); | |
1111 | dumpFixup(it); | |
1112 | break; | |
1113 | case ld::Fixup::k1of2: | |
1114 | printf(" 0x%04X ", it->offsetInAtom); | |
1115 | dumpFixup(it); | |
1116 | ++it; | |
1117 | dumpFixup(it); | |
1118 | break; | |
1119 | case ld::Fixup::k1of3: | |
1120 | printf(" 0x%04X ", it->offsetInAtom); | |
1121 | dumpFixup(it); | |
1122 | ++it; | |
1123 | dumpFixup(it); | |
1124 | ++it; | |
1125 | dumpFixup(it); | |
1126 | break; | |
1127 | case ld::Fixup::k1of4: | |
1128 | printf(" 0x%04X ", it->offsetInAtom); | |
1129 | dumpFixup(it); | |
1130 | ++it; | |
1131 | dumpFixup(it); | |
1132 | ++it; | |
1133 | dumpFixup(it); | |
1134 | ++it; | |
1135 | dumpFixup(it); | |
1136 | break; | |
1137 | case ld::Fixup::k1of5: | |
1138 | printf(" 0x%04X ", it->offsetInAtom); | |
1139 | dumpFixup(it); | |
1140 | ++it; | |
1141 | dumpFixup(it); | |
1142 | ++it; | |
1143 | dumpFixup(it); | |
1144 | ++it; | |
1145 | dumpFixup(it); | |
1146 | ++it; | |
1147 | dumpFixup(it); | |
1148 | break; | |
1149 | default: | |
1150 | printf(" BAD CLUSTER SIZE: cluster=%d\n", it->clusterSize); | |
1151 | } | |
1152 | printf("\n"); | |
1153 | } | |
1154 | } | |
1155 | } | |
1156 | } | |
afe874b1 A |
1157 | if ( sShowLineInfo ) { |
1158 | if ( atom.beginLineInfo() != atom.endLineInfo() ) { | |
1159 | printf("line info:\n"); | |
1160 | for (ld::Atom::LineInfo::iterator it = atom.beginLineInfo(); it != atom.endLineInfo(); ++it) { | |
1161 | printf(" offset 0x%04X, line %d, file %s\n", it->atomOffset, it->lineNumber, it->fileName); | |
1162 | } | |
a645023d A |
1163 | } |
1164 | } | |
afe874b1 | 1165 | |
a645023d A |
1166 | printf("\n"); |
1167 | } | |
1168 | ||
1169 | static void dumpFile(ld::relocatable::File* file) | |
c2646906 | 1170 | { |
d696c285 | 1171 | // stabs debug info |
a645023d A |
1172 | if ( sDumpStabs && (file->debugInfo() == ld::relocatable::File::kDebugInfoStabs) ) { |
1173 | const std::vector<ld::relocatable::File::Stab>* stabs = file->stabs(); | |
d696c285 A |
1174 | if ( stabs != NULL ) |
1175 | dumpStabs(stabs); | |
1176 | } | |
a645023d A |
1177 | // dump atoms |
1178 | dumper d; | |
1179 | file->forEachAtom(d); | |
1180 | d.dump(); | |
1181 | ||
1182 | #if 0 | |
d696c285 | 1183 | // get all atoms |
c2646906 | 1184 | std::vector<ObjectFile::Atom*> atoms = reader->getAtoms(); |
d696c285 A |
1185 | |
1186 | // make copy of vector and sort (so output is canonical) | |
1187 | std::vector<ObjectFile::Atom*> sortedAtoms(atoms); | |
1188 | if ( sSort ) | |
1189 | std::sort(sortedAtoms.begin(), sortedAtoms.end(), AtomSorter()); | |
1190 | ||
2f2f92e4 A |
1191 | for(std::vector<ObjectFile::Atom*>::iterator it=sortedAtoms.begin(); it != sortedAtoms.end(); ++it) { |
1192 | if ( sNMmode ) | |
1193 | dumpAtomLikeNM(*it); | |
1194 | else | |
1195 | dumpAtom(*it); | |
1196 | } | |
a645023d | 1197 | #endif |
c2646906 A |
1198 | } |
1199 | ||
1200 | ||
a645023d | 1201 | static ld::relocatable::File* createReader(const char* path) |
c2646906 A |
1202 | { |
1203 | struct stat stat_buf; | |
1204 | ||
1205 | int fd = ::open(path, O_RDONLY, 0); | |
1206 | if ( fd == -1 ) | |
d696c285 | 1207 | throwf("cannot open file: %s", path); |
c2646906 | 1208 | ::fstat(fd, &stat_buf); |
69a49097 | 1209 | uint8_t* p = (uint8_t*)::mmap(NULL, stat_buf.st_size, PROT_READ, MAP_FILE | MAP_PRIVATE, fd, 0); |
c2646906 | 1210 | ::close(fd); |
a645023d A |
1211 | if ( p == (uint8_t*)(-1) ) |
1212 | throwf("cannot mmap file: %s", path); | |
c2646906 | 1213 | const mach_header* mh = (mach_header*)p; |
a645023d A |
1214 | uint64_t fileLen = stat_buf.st_size; |
1215 | bool foundFatSlice = false; | |
c2646906 A |
1216 | if ( mh->magic == OSSwapBigToHostInt32(FAT_MAGIC) ) { |
1217 | const struct fat_header* fh = (struct fat_header*)p; | |
1218 | const struct fat_arch* archs = (struct fat_arch*)(p + sizeof(struct fat_header)); | |
afe874b1 A |
1219 | if ( (uint32_t)sPreferredArch == 0xFFFFFFFF ) { |
1220 | // just dump first slice of fat .o file | |
1221 | if ( OSSwapBigToHostInt32(fh->nfat_arch) > 0 ) { | |
1222 | p = p + OSSwapBigToHostInt32(archs[0].offset); | |
1223 | mh = (struct mach_header*)p; | |
1224 | fileLen = OSSwapBigToHostInt32(archs[0].size); | |
1225 | sPreferredArch = OSSwapBigToHostInt32(archs[0].cputype); | |
1226 | sPreferredSubArch = OSSwapBigToHostInt32(archs[0].cpusubtype); | |
1227 | foundFatSlice = true; | |
1228 | } | |
1229 | } | |
1230 | else { | |
1231 | for (unsigned long i=0; i < OSSwapBigToHostInt32(fh->nfat_arch); ++i) { | |
1232 | if ( OSSwapBigToHostInt32(archs[i].cputype) == (uint32_t)sPreferredArch ) { | |
1233 | if ( ((uint32_t)sPreferredSubArch == 0xFFFFFFFF) || ((uint32_t)sPreferredSubArch == OSSwapBigToHostInt32(archs[i].cpusubtype)) ) { | |
1234 | p = p + OSSwapBigToHostInt32(archs[i].offset); | |
1235 | mh = (struct mach_header*)p; | |
1236 | fileLen = OSSwapBigToHostInt32(archs[i].size); | |
1237 | foundFatSlice = true; | |
1238 | break; | |
1239 | } | |
c211e7c9 | 1240 | } |
c2646906 A |
1241 | } |
1242 | } | |
1243 | } | |
a645023d A |
1244 | |
1245 | mach_o::relocatable::ParserOptions objOpts; | |
1246 | objOpts.architecture = sPreferredArch; | |
1247 | objOpts.objSubtypeMustMatch = false; | |
1248 | objOpts.logAllFiles = false; | |
f80fe69f A |
1249 | objOpts.warnUnwindConversionProblems = true; |
1250 | objOpts.keepDwarfUnwind = false; | |
1251 | objOpts.forceDwarfConversion = false; | |
9543cb2f | 1252 | objOpts.verboseOptimizationHints = true; |
ba348e21 | 1253 | objOpts.armUsesZeroCostExceptions = true; |
a645023d | 1254 | objOpts.subType = sPreferredSubArch; |
dd9e569f A |
1255 | objOpts.treateBitcodeAsData = false; |
1256 | objOpts.usingBitcode = true; | |
a645023d A |
1257 | #if 1 |
1258 | if ( ! foundFatSlice ) { | |
1259 | cpu_type_t archOfObj; | |
1260 | cpu_subtype_t subArchOfObj; | |
eaf282aa A |
1261 | Options::Platform platform; |
1262 | if ( mach_o::relocatable::isObjectFile(p, &archOfObj, &subArchOfObj, &platform) ) { | |
a645023d A |
1263 | objOpts.architecture = archOfObj; |
1264 | objOpts.subType = subArchOfObj; | |
1265 | } | |
2f2f92e4 | 1266 | } |
a645023d | 1267 | |
ebf6f434 | 1268 | ld::relocatable::File* objResult = mach_o::relocatable::parse(p, fileLen, path, stat_buf.st_mtime, ld::File::Ordinal::NullOrdinal(), objOpts); |
a645023d A |
1269 | if ( objResult != NULL ) |
1270 | return objResult; | |
1271 | ||
1272 | // see if it is an llvm object file | |
9543cb2f | 1273 | objResult = lto::parse(p, fileLen, path, stat_buf.st_mtime, ld::File::Ordinal::NullOrdinal(), sPreferredArch, sPreferredSubArch, false, true); |
a645023d A |
1274 | if ( objResult != NULL ) |
1275 | return objResult; | |
1276 | ||
d696c285 | 1277 | throwf("not a mach-o object file: %s", path); |
a645023d A |
1278 | #else |
1279 | // for peformance testing | |
1280 | for (int i=0; i < 500; ++i ) { | |
1281 | ld::relocatable::File* objResult = mach_o::relocatable::parse(p, fileLen, path, stat_buf.st_mtime, 0, objOpts); | |
1282 | delete objResult; | |
1283 | } | |
1284 | exit(0); | |
1285 | #endif | |
c2646906 A |
1286 | } |
1287 | ||
a61fdf0a A |
1288 | static |
1289 | void | |
1290 | usage() | |
1291 | { | |
1292 | fprintf(stderr, "ObjectDump options:\n" | |
1293 | "\t-no_content\tdon't dump contents\n" | |
a645023d A |
1294 | "\t-no_section\tdon't dump section name\n" |
1295 | "\t-no_defintion\tdon't dump definition kind\n" | |
1296 | "\t-no_combine\tdon't dump combine mode\n" | |
a61fdf0a A |
1297 | "\t-stabs\t\tdump stabs\n" |
1298 | "\t-arch aaa\tonly dump info about arch aaa\n" | |
1299 | "\t-only sym\tonly dump info about sym\n" | |
1300 | "\t-align\t\tonly print alignment info\n" | |
1301 | "\t-name\t\tonly print symbol names\n" | |
1302 | ); | |
1303 | } | |
c2646906 A |
1304 | |
1305 | int main(int argc, const char* argv[]) | |
1306 | { | |
a61fdf0a A |
1307 | if(argc<2) { |
1308 | usage(); | |
1309 | return 0; | |
1310 | } | |
1311 | ||
c2646906 | 1312 | try { |
d696c285 A |
1313 | for(int i=1; i < argc; ++i) { |
1314 | const char* arg = argv[i]; | |
1315 | if ( arg[0] == '-' ) { | |
1316 | if ( strcmp(arg, "-no_content") == 0 ) { | |
1317 | sDumpContent = false; | |
1318 | } | |
2f2f92e4 A |
1319 | else if ( strcmp(arg, "-nm") == 0 ) { |
1320 | sNMmode = true; | |
1321 | } | |
d696c285 A |
1322 | else if ( strcmp(arg, "-stabs") == 0 ) { |
1323 | sDumpStabs = true; | |
1324 | } | |
1325 | else if ( strcmp(arg, "-no_sort") == 0 ) { | |
1326 | sSort = false; | |
1327 | } | |
a645023d A |
1328 | else if ( strcmp(arg, "-no_section") == 0 ) { |
1329 | sShowSection = false; | |
1330 | } | |
1331 | else if ( strcmp(arg, "-no_definition") == 0 ) { | |
1332 | sShowDefinitionKind = false; | |
1333 | } | |
1334 | else if ( strcmp(arg, "-no_combine") == 0 ) { | |
1335 | sShowCombineKind = false; | |
1336 | } | |
afe874b1 A |
1337 | else if ( strcmp(arg, "-no_line_info") == 0 ) { |
1338 | sShowLineInfo = false; | |
1339 | } | |
d696c285 | 1340 | else if ( strcmp(arg, "-arch") == 0 ) { |
ebf6f434 A |
1341 | const char* archName = argv[++i]; |
1342 | if ( archName == NULL ) | |
1343 | throw "-arch missing architecture name"; | |
1344 | bool found = false; | |
1345 | for (const ArchInfo* t=archInfoArray; t->archName != NULL; ++t) { | |
1346 | if ( strcmp(t->archName,archName) == 0 ) { | |
1347 | sPreferredArch = t->cpuType; | |
1348 | if ( t->isSubType ) | |
1349 | sPreferredSubArch = t->cpuSubType; | |
1350 | found = true; | |
afe874b1 | 1351 | } |
c211e7c9 | 1352 | } |
ebf6f434 A |
1353 | if ( !found ) |
1354 | throwf("unknown architecture %s", archName); | |
d696c285 | 1355 | } |
a61fdf0a A |
1356 | else if ( strcmp(arg, "-only") == 0 ) { |
1357 | sMatchName = ++i<argc? argv[i]: NULL; | |
1358 | } | |
1359 | else if ( strcmp(arg, "-align") == 0 ) { | |
1360 | sPrintRestrict = true; | |
1361 | sPrintAlign = true; | |
1362 | } | |
1363 | else if ( strcmp(arg, "-name") == 0 ) { | |
1364 | sPrintRestrict = true; | |
1365 | sPrintName = true; | |
1366 | } | |
d696c285 | 1367 | else { |
a61fdf0a | 1368 | usage(); |
d696c285 A |
1369 | throwf("unknown option: %s\n", arg); |
1370 | } | |
1371 | } | |
1372 | else { | |
a645023d | 1373 | ld::relocatable::File* reader = createReader(arg); |
d696c285 A |
1374 | dumpFile(reader); |
1375 | } | |
1376 | } | |
c2646906 A |
1377 | } |
1378 | catch (const char* msg) { | |
1379 | fprintf(stderr, "ObjDump failed: %s\n", msg); | |
d696c285 | 1380 | return 1; |
c2646906 A |
1381 | } |
1382 | ||
1383 | return 0; | |
1384 | } |