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