]>
Commit | Line | Data |
---|---|---|
1 | /* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- | |
2 | * | |
3 | * Copyright (c) 2005-2010 Apple Inc. All rights reserved. | |
4 | * | |
5 | * @APPLE_LICENSE_HEADER_START@ | |
6 | * | |
7 | * This file contains Original Code and/or Modifications of Original Code | |
8 | * as defined in and that are subject to the Apple Public Source License | |
9 | * Version 2.0 (the 'License'). You may not use this file except in | |
10 | * compliance with the License. Please obtain a copy of the License at | |
11 | * http://www.opensource.apple.com/apsl/ and read it before using this | |
12 | * file. | |
13 | * | |
14 | * The Original Code and all software distributed under the License are | |
15 | * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER | |
16 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, | |
17 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, | |
18 | * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. | |
19 | * Please see the License for the specific language governing rights and | |
20 | * limitations under the License. | |
21 | * | |
22 | * @APPLE_LICENSE_HEADER_END@ | |
23 | */ | |
24 | ||
25 | #include <sys/types.h> | |
26 | #include <sys/stat.h> | |
27 | #include <sys/mman.h> | |
28 | #include <fcntl.h> | |
29 | #include <mach-o/nlist.h> | |
30 | #include <mach-o/stab.h> | |
31 | #include <mach-o/fat.h> | |
32 | #include <mach-o/loader.h> | |
33 | ||
34 | #include "MachOFileAbstraction.hpp" | |
35 | #include "parsers/macho_relocatable_file.h" | |
36 | #include "parsers/lto_file.h" | |
37 | ||
38 | const ld::VersionSet ld::File::_platforms; | |
39 | ||
40 | static bool sDumpContent= true; | |
41 | static bool sDumpStabs = false; | |
42 | static bool sSort = true; | |
43 | static bool sNMmode = false; | |
44 | static bool sShowSection = true; | |
45 | static bool sShowDefinitionKind = true; | |
46 | static bool sShowCombineKind = true; | |
47 | static bool sShowLineInfo = true; | |
48 | ||
49 | static cpu_type_t sPreferredArch = 0xFFFFFFFF; | |
50 | static cpu_subtype_t sPreferredSubArch = 0xFFFFFFFF; | |
51 | static const char* sMatchName = NULL; | |
52 | static int sPrintRestrict; | |
53 | static int sPrintAlign; | |
54 | static int sPrintName; | |
55 | ||
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 | ||
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 | ||
79 | static void dumpStabs(const std::vector<ld::relocatable::File::Stab>* stabs) | |
80 | { | |
81 | // debug info | |
82 | printf("stabs: (%lu)\n", stabs->size()); | |
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; | |
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; | |
123 | case N_OSO: | |
124 | code = " OSO"; | |
125 | break; | |
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 | } | |
172 | printf(" [atom=%20s] %02X %04X %s %s\n", ((stab.atom != NULL) ? stab.atom->name() : ""), stab.other, stab.desc, code, stab.string); | |
173 | } | |
174 | } | |
175 | ||
176 | #if 0 | |
177 | static void dumpAtomLikeNM(ld::Atom* atom) | |
178 | { | |
179 | uint32_t size = atom->size(); | |
180 | ||
181 | const char* visibility; | |
182 | switch ( atom->scope() ) { | |
183 | case ld::Atom::scopeTranslationUnit: | |
184 | visibility = "internal"; | |
185 | break; | |
186 | case ld::Atom::scopeLinkageUnit: | |
187 | visibility = "hidden "; | |
188 | break; | |
189 | case ld::Atom::scopeGlobal: | |
190 | visibility = "global "; | |
191 | break; | |
192 | default: | |
193 | visibility = " "; | |
194 | break; | |
195 | } | |
196 | ||
197 | const char* kind; | |
198 | switch ( atom->definitionKind() ) { | |
199 | case ld::Atom::kRegularDefinition: | |
200 | kind = "regular "; | |
201 | break; | |
202 | case ld::Atom::kTentativeDefinition: | |
203 | kind = "tentative"; | |
204 | break; | |
205 | case ld::Atom::kWeakDefinition: | |
206 | kind = "weak "; | |
207 | break; | |
208 | case ld::Atom::kAbsoluteSymbol: | |
209 | kind = "absolute "; | |
210 | break; | |
211 | default: | |
212 | kind = " "; | |
213 | break; | |
214 | } | |
215 | ||
216 | printf("0x%08X %s %s %s\n", size, visibility, kind, atom->name()); | |
217 | } | |
218 | ||
219 | ||
220 | static void dumpAtom(ld::Atom* atom) | |
221 | { | |
222 | if(sMatchName && strcmp(sMatchName, atom->name())) | |
223 | return; | |
224 | ||
225 | //printf("atom: %p\n", atom); | |
226 | ||
227 | // name | |
228 | if(!sPrintRestrict || sPrintName) | |
229 | printf("name: %s\n", atom->name()); | |
230 | ||
231 | // scope | |
232 | if(!sPrintRestrict) | |
233 | switch ( atom->scope() ) { | |
234 | case ld::Atom::scopeTranslationUnit: | |
235 | printf("scope: translation unit\n"); | |
236 | break; | |
237 | case ld::Atom::scopeLinkageUnit: | |
238 | printf("scope: linkage unit\n"); | |
239 | break; | |
240 | case ld::Atom::scopeGlobal: | |
241 | printf("scope: global\n"); | |
242 | break; | |
243 | default: | |
244 | printf("scope: unknown\n"); | |
245 | } | |
246 | ||
247 | // kind | |
248 | if(!sPrintRestrict) | |
249 | switch ( atom->definitionKind() ) { | |
250 | case ld::Atom::kRegularDefinition: | |
251 | printf("kind: regular\n"); | |
252 | break; | |
253 | case ld::Atom::kWeakDefinition: | |
254 | printf("kind: weak\n"); | |
255 | break; | |
256 | case ld::Atom::kTentativeDefinition: | |
257 | printf("kind: tentative\n"); | |
258 | break; | |
259 | case ld::Atom::kExternalDefinition: | |
260 | printf("kind: import\n"); | |
261 | break; | |
262 | case ld::Atom::kExternalWeakDefinition: | |
263 | printf("kind: weak import\n"); | |
264 | break; | |
265 | case ld::Atom::kAbsoluteSymbol: | |
266 | printf("kind: absolute symbol\n"); | |
267 | break; | |
268 | default: | |
269 | printf("kind: unknown\n"); | |
270 | } | |
271 | ||
272 | // segment and section | |
273 | if(!sPrintRestrict && (atom->section().sectionName() != NULL) ) | |
274 | printf("section: %s,%s\n", atom->section().segmentName(), atom->section().sectionName()); | |
275 | ||
276 | // attributes | |
277 | if(!sPrintRestrict) { | |
278 | printf("attrs: "); | |
279 | if ( atom->dontDeadStrip() ) | |
280 | printf("dont-dead-strip "); | |
281 | if ( atom->isThumb() ) | |
282 | printf("thumb "); | |
283 | printf("\n"); | |
284 | } | |
285 | ||
286 | // size | |
287 | if(!sPrintRestrict) | |
288 | printf("size: 0x%012llX\n", atom->size()); | |
289 | ||
290 | // alignment | |
291 | if(!sPrintRestrict || sPrintAlign) | |
292 | printf("align: %u mod %u\n", atom->alignment().modulus, (1 << atom->alignment().powerOf2) ); | |
293 | ||
294 | // content | |
295 | if (!sPrintRestrict && sDumpContent ) { | |
296 | uint64_t size = atom->size(); | |
297 | if ( size < 4096 ) { | |
298 | uint8_t content[size]; | |
299 | atom->copyRawContent(content); | |
300 | printf("content: "); | |
301 | if ( atom->contentType() == ld::Atom::typeCString ) { | |
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("\""); | |
310 | } | |
311 | else { | |
312 | for (unsigned int i=0; i < size; ++i) | |
313 | printf("%02X ", content[i]); | |
314 | } | |
315 | } | |
316 | printf("\n"); | |
317 | } | |
318 | ||
319 | // unwind info | |
320 | if(!sPrintRestrict) { | |
321 | if ( atom->beginUnwind() != atom->endUnwind() ) { | |
322 | printf("unwind encodings:\n"); | |
323 | for (ld::Atom::UnwindInfo::iterator it = atom->beginUnwind(); it != atom->endUnwind(); ++it) { | |
324 | printf("\t 0x%04X 0x%08X\n", it->startOffset, it->unwindInfo); | |
325 | } | |
326 | } | |
327 | } | |
328 | #if 0 | |
329 | // references | |
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 | } | |
338 | } | |
339 | #endif | |
340 | // line info | |
341 | if(!sPrintRestrict) { | |
342 | if ( atom->beginLineInfo() != atom->endLineInfo() ) { | |
343 | printf("line info:\n"); | |
344 | for (ld::Atom::LineInfo::iterator it = atom->beginLineInfo(); it != atom->endLineInfo(); ++it) { | |
345 | printf(" offset 0x%04X, line %d, file %s\n", it->atomOffset, it->lineNumber, it->fileName); | |
346 | } | |
347 | } | |
348 | } | |
349 | ||
350 | if(!sPrintRestrict) | |
351 | printf("\n"); | |
352 | } | |
353 | #endif | |
354 | struct AtomSorter | |
355 | { | |
356 | bool operator()(const ld::Atom* left, const ld::Atom* right) | |
357 | { | |
358 | if ( left == right ) | |
359 | return false; | |
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 | } | |
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 | } | |
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()); | |
454 | } | |
455 | }; | |
456 | ||
457 | ||
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; | |
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; | |
811 | #if SUPPORT_ARCH_arm64 | |
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; | |
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; | |
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; | |
851 | #endif | |
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; | |
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; | |
873 | #if SUPPORT_ARCH_arm64 | |
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; | |
880 | #endif | |
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)); | |
886 | break; | |
887 | case ld::Fixup::kindIslandTarget: | |
888 | printf("ultimate target of island %s", referenceTargetAtomName(ref)); | |
889 | break; | |
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; | |
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; | |
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; | |
993 | case ld::Fixup::kindSetTargetTLVTemplateOffset: | |
994 | case ld::Fixup::kindSetTargetTLVTemplateOffsetLittleEndian32: | |
995 | case ld::Fixup::kindSetTargetTLVTemplateOffsetLittleEndian64: | |
996 | printf("tlv template offset of %s", referenceTargetAtomName(ref)); | |
997 | break; | |
998 | #if SUPPORT_ARCH_arm64 | |
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: | |
1015 | printf("ARM64 store 21-bit pcrel ADRP to GOT lea for %s", referenceTargetAtomName(ref)); | |
1016 | break; | |
1017 | case ld::Fixup::kindStoreTargetAddressARM64GOTLeaPageOff12: | |
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)); | |
1031 | break; | |
1032 | #endif | |
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() ) { | |
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); | |
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 | } | |
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 | } | |
1165 | } | |
1166 | } | |
1167 | ||
1168 | printf("\n"); | |
1169 | } | |
1170 | ||
1171 | static void dumpFile(ld::relocatable::File* file) | |
1172 | { | |
1173 | // stabs debug info | |
1174 | if ( sDumpStabs && (file->debugInfo() == ld::relocatable::File::kDebugInfoStabs) ) { | |
1175 | const std::vector<ld::relocatable::File::Stab>* stabs = file->stabs(); | |
1176 | if ( stabs != NULL ) | |
1177 | dumpStabs(stabs); | |
1178 | } | |
1179 | // dump atoms | |
1180 | dumper d; | |
1181 | file->forEachAtom(d); | |
1182 | d.dump(); | |
1183 | ||
1184 | #if 0 | |
1185 | // get all atoms | |
1186 | std::vector<ObjectFile::Atom*> atoms = reader->getAtoms(); | |
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 | ||
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 | } | |
1199 | #endif | |
1200 | } | |
1201 | ||
1202 | ||
1203 | static ld::relocatable::File* createReader(const char* path) | |
1204 | { | |
1205 | struct stat stat_buf; | |
1206 | ||
1207 | int fd = ::open(path, O_RDONLY, 0); | |
1208 | if ( fd == -1 ) | |
1209 | throwf("cannot open file: %s", path); | |
1210 | ::fstat(fd, &stat_buf); | |
1211 | uint8_t* p = (uint8_t*)::mmap(NULL, stat_buf.st_size, PROT_READ, MAP_FILE | MAP_PRIVATE, fd, 0); | |
1212 | ::close(fd); | |
1213 | if ( p == (uint8_t*)(-1) ) | |
1214 | throwf("cannot mmap file: %s", path); | |
1215 | const mach_header* mh = (mach_header*)p; | |
1216 | uint64_t fileLen = stat_buf.st_size; | |
1217 | bool foundFatSlice = false; | |
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)); | |
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 | } | |
1242 | } | |
1243 | } | |
1244 | } | |
1245 | } | |
1246 | ||
1247 | mach_o::relocatable::ParserOptions objOpts; | |
1248 | objOpts.architecture = sPreferredArch; | |
1249 | objOpts.objSubtypeMustMatch = false; | |
1250 | objOpts.logAllFiles = false; | |
1251 | objOpts.warnUnwindConversionProblems = true; | |
1252 | objOpts.keepDwarfUnwind = false; | |
1253 | objOpts.forceDwarfConversion = false; | |
1254 | objOpts.verboseOptimizationHints = true; | |
1255 | objOpts.armUsesZeroCostExceptions = true; | |
1256 | objOpts.subType = sPreferredSubArch; | |
1257 | objOpts.treateBitcodeAsData = false; | |
1258 | objOpts.usingBitcode = true; | |
1259 | #if 1 | |
1260 | if ( ! foundFatSlice ) { | |
1261 | cpu_type_t archOfObj; | |
1262 | cpu_subtype_t subArchOfObj; | |
1263 | ld::Platform platform; | |
1264 | uint32_t minOS; | |
1265 | if ( mach_o::relocatable::isObjectFile(p, &archOfObj, &subArchOfObj, &platform, &minOS) ) { | |
1266 | objOpts.architecture = archOfObj; | |
1267 | objOpts.subType = subArchOfObj; | |
1268 | } | |
1269 | } | |
1270 | ||
1271 | ld::relocatable::File* objResult = mach_o::relocatable::parse(p, fileLen, path, stat_buf.st_mtime, ld::File::Ordinal::NullOrdinal(), objOpts); | |
1272 | if ( objResult != NULL ) | |
1273 | return objResult; | |
1274 | ||
1275 | // see if it is an llvm object file | |
1276 | objResult = lto::parse(p, fileLen, path, stat_buf.st_mtime, ld::File::Ordinal::NullOrdinal(), sPreferredArch, sPreferredSubArch, false, true); | |
1277 | if ( objResult != NULL ) | |
1278 | return objResult; | |
1279 | ||
1280 | throwf("not a mach-o object file: %s", path); | |
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 | |
1289 | } | |
1290 | ||
1291 | static | |
1292 | void | |
1293 | usage() | |
1294 | { | |
1295 | fprintf(stderr, "ObjectDump options:\n" | |
1296 | "\t-no_content\tdon't dump contents\n" | |
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" | |
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 | } | |
1307 | ||
1308 | int main(int argc, const char* argv[]) | |
1309 | { | |
1310 | if(argc<2) { | |
1311 | usage(); | |
1312 | return 0; | |
1313 | } | |
1314 | ||
1315 | try { | |
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 | } | |
1322 | else if ( strcmp(arg, "-nm") == 0 ) { | |
1323 | sNMmode = true; | |
1324 | } | |
1325 | else if ( strcmp(arg, "-stabs") == 0 ) { | |
1326 | sDumpStabs = true; | |
1327 | } | |
1328 | else if ( strcmp(arg, "-no_sort") == 0 ) { | |
1329 | sSort = false; | |
1330 | } | |
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 | } | |
1340 | else if ( strcmp(arg, "-no_line_info") == 0 ) { | |
1341 | sShowLineInfo = false; | |
1342 | } | |
1343 | else if ( strcmp(arg, "-arch") == 0 ) { | |
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; | |
1354 | } | |
1355 | } | |
1356 | if ( !found ) | |
1357 | throwf("unknown architecture %s", archName); | |
1358 | } | |
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 | } | |
1370 | else { | |
1371 | usage(); | |
1372 | throwf("unknown option: %s\n", arg); | |
1373 | } | |
1374 | } | |
1375 | else { | |
1376 | ld::relocatable::File* reader = createReader(arg); | |
1377 | dumpFile(reader); | |
1378 | } | |
1379 | } | |
1380 | } | |
1381 | catch (const char* msg) { | |
1382 | fprintf(stderr, "ObjDump failed: %s\n", msg); | |
1383 | return 1; | |
1384 | } | |
1385 | ||
1386 | return 0; | |
1387 | } |