]>
Commit | Line | Data |
---|---|---|
d696c285 A |
1 | /* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- |
2 | * | |
3 | * Copyright (c) 2005-2006 Apple Computer, 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> | |
29 | #include <fcntl.h> | |
c2646906 | 30 | |
d696c285 | 31 | #include "MachOReaderRelocatable.hpp" |
77cc3118 | 32 | |
9d2e0767 | 33 | #define LTO_SUPPORT 1 |
77cc3118 A |
34 | |
35 | #if LTO_SUPPORT | |
36 | #include "LTOReader.hpp" | |
37 | #endif | |
d696c285 A |
38 | |
39 | static bool sDumpContent= true; | |
40 | static bool sDumpStabs = false; | |
41 | static bool sSort = true; | |
2f2f92e4 | 42 | static bool sNMmode = false; |
d696c285 | 43 | static cpu_type_t sPreferredArch = CPU_TYPE_POWERPC64; |
a61fdf0a A |
44 | static const char* sMatchName; |
45 | static int sPrintRestrict; | |
46 | static int sPrintAlign; | |
47 | static int sPrintName; | |
c2646906 | 48 | |
c2646906 A |
49 | |
50 | __attribute__((noreturn)) | |
51 | void throwf(const char* format, ...) | |
52 | { | |
53 | va_list list; | |
54 | char* p; | |
55 | va_start(list, format); | |
56 | vasprintf(&p, format, list); | |
57 | va_end(list); | |
58 | ||
59 | const char* t = p; | |
60 | throw t; | |
61 | } | |
62 | ||
2f2f92e4 A |
63 | void warning(const char* format, ...) |
64 | { | |
65 | va_list list; | |
66 | fprintf(stderr, "warning: "); | |
67 | va_start(list, format); | |
68 | vfprintf(stderr, format, list); | |
69 | va_end(list); | |
70 | fprintf(stderr, "\n"); | |
71 | } | |
72 | ||
d696c285 | 73 | static void dumpStabs(std::vector<ObjectFile::Reader::Stab>* stabs) |
c2646906 A |
74 | { |
75 | // debug info | |
d696c285 A |
76 | printf("stabs: (%lu)\n", stabs->size()); |
77 | for (std::vector<ObjectFile::Reader::Stab>::iterator it = stabs->begin(); it != stabs->end(); ++it ) { | |
78 | ObjectFile::Reader::Stab& stab = *it; | |
c2646906 A |
79 | const char* code = "?????"; |
80 | switch (stab.type) { | |
81 | case N_GSYM: | |
82 | code = " GSYM"; | |
83 | break; | |
84 | case N_FNAME: | |
85 | code = "FNAME"; | |
86 | break; | |
87 | case N_FUN: | |
88 | code = " FUN"; | |
89 | break; | |
90 | case N_STSYM: | |
91 | code = "STSYM"; | |
92 | break; | |
93 | case N_LCSYM: | |
94 | code = "LCSYM"; | |
95 | break; | |
96 | case N_BNSYM: | |
97 | code = "BNSYM"; | |
98 | break; | |
99 | case N_OPT: | |
100 | code = " OPT"; | |
101 | break; | |
102 | case N_RSYM: | |
103 | code = " RSYM"; | |
104 | break; | |
105 | case N_SLINE: | |
106 | code = "SLINE"; | |
107 | break; | |
108 | case N_ENSYM: | |
109 | code = "ENSYM"; | |
110 | break; | |
111 | case N_SSYM: | |
112 | code = " SSYM"; | |
113 | break; | |
114 | case N_SO: | |
115 | code = " SO"; | |
116 | break; | |
d696c285 A |
117 | case N_OSO: |
118 | code = " OSO"; | |
119 | break; | |
c2646906 A |
120 | case N_LSYM: |
121 | code = " LSYM"; | |
122 | break; | |
123 | case N_BINCL: | |
124 | code = "BINCL"; | |
125 | break; | |
126 | case N_SOL: | |
127 | code = " SOL"; | |
128 | break; | |
129 | case N_PARAMS: | |
130 | code = "PARMS"; | |
131 | break; | |
132 | case N_VERSION: | |
133 | code = " VERS"; | |
134 | break; | |
135 | case N_OLEVEL: | |
136 | code = "OLEVL"; | |
137 | break; | |
138 | case N_PSYM: | |
139 | code = " PSYM"; | |
140 | break; | |
141 | case N_EINCL: | |
142 | code = "EINCL"; | |
143 | break; | |
144 | case N_ENTRY: | |
145 | code = "ENTRY"; | |
146 | break; | |
147 | case N_LBRAC: | |
148 | code = "LBRAC"; | |
149 | break; | |
150 | case N_EXCL: | |
151 | code = " EXCL"; | |
152 | break; | |
153 | case N_RBRAC: | |
154 | code = "RBRAC"; | |
155 | break; | |
156 | case N_BCOMM: | |
157 | code = "BCOMM"; | |
158 | break; | |
159 | case N_ECOMM: | |
160 | code = "ECOMM"; | |
161 | break; | |
162 | case N_LENG: | |
163 | code = "LENG"; | |
164 | break; | |
165 | } | |
d696c285 | 166 | printf(" [atom=%20s] %02X %04X %s %s\n", ((stab.atom != NULL) ? stab.atom->getDisplayName() : ""), stab.other, stab.desc, code, stab.string); |
c2646906 A |
167 | } |
168 | } | |
169 | ||
170 | ||
2f2f92e4 A |
171 | static void dumpAtomLikeNM(ObjectFile::Atom* atom) |
172 | { | |
173 | uint32_t size = atom->getSize(); | |
174 | ||
175 | const char* visibility; | |
176 | switch ( atom->getScope() ) { | |
177 | case ObjectFile::Atom::scopeTranslationUnit: | |
178 | visibility = "internal"; | |
179 | break; | |
180 | case ObjectFile::Atom::scopeLinkageUnit: | |
181 | visibility = "hidden "; | |
182 | break; | |
183 | case ObjectFile::Atom::scopeGlobal: | |
184 | visibility = "global "; | |
185 | break; | |
186 | default: | |
187 | visibility = " "; | |
188 | break; | |
189 | } | |
190 | ||
191 | const char* kind; | |
192 | switch ( atom->getDefinitionKind() ) { | |
193 | case ObjectFile::Atom::kRegularDefinition: | |
194 | kind = "regular "; | |
195 | break; | |
196 | case ObjectFile::Atom::kTentativeDefinition: | |
197 | kind = "tentative"; | |
198 | break; | |
199 | case ObjectFile::Atom::kWeakDefinition: | |
200 | kind = "weak "; | |
201 | break; | |
202 | case ObjectFile::Atom::kAbsoluteSymbol: | |
203 | kind = "absolute "; | |
204 | break; | |
205 | default: | |
206 | kind = " "; | |
207 | break; | |
208 | } | |
209 | ||
210 | printf("0x%08X %s %s %s\n", size, visibility, kind, atom->getDisplayName()); | |
211 | } | |
212 | ||
213 | ||
c2646906 A |
214 | static void dumpAtom(ObjectFile::Atom* atom) |
215 | { | |
a61fdf0a A |
216 | if(sMatchName && strcmp(sMatchName, atom->getDisplayName())) |
217 | return; | |
218 | ||
c2646906 A |
219 | //printf("atom: %p\n", atom); |
220 | ||
221 | // name | |
a61fdf0a A |
222 | if(!sPrintRestrict || sPrintName) |
223 | printf("name: %s\n", atom->getDisplayName()); | |
c2646906 A |
224 | |
225 | // scope | |
a61fdf0a A |
226 | if(!sPrintRestrict) |
227 | switch ( atom->getScope() ) { | |
c2646906 A |
228 | case ObjectFile::Atom::scopeTranslationUnit: |
229 | printf("scope: translation unit\n"); | |
230 | break; | |
231 | case ObjectFile::Atom::scopeLinkageUnit: | |
232 | printf("scope: linkage unit\n"); | |
233 | break; | |
234 | case ObjectFile::Atom::scopeGlobal: | |
235 | printf("scope: global\n"); | |
236 | break; | |
237 | default: | |
238 | printf("scope: unknown\n"); | |
a61fdf0a | 239 | } |
c2646906 | 240 | |
d696c285 | 241 | // kind |
a61fdf0a A |
242 | if(!sPrintRestrict) |
243 | switch ( atom->getDefinitionKind() ) { | |
d696c285 A |
244 | case ObjectFile::Atom::kRegularDefinition: |
245 | printf("kind: regular\n"); | |
246 | break; | |
247 | case ObjectFile::Atom::kWeakDefinition: | |
248 | printf("kind: weak\n"); | |
249 | break; | |
250 | case ObjectFile::Atom::kTentativeDefinition: | |
251 | printf("kind: tentative\n"); | |
252 | break; | |
253 | case ObjectFile::Atom::kExternalDefinition: | |
254 | printf("kind: import\n"); | |
255 | break; | |
256 | case ObjectFile::Atom::kExternalWeakDefinition: | |
257 | printf("kind: weak import\n"); | |
258 | break; | |
a61fdf0a A |
259 | case ObjectFile::Atom::kAbsoluteSymbol: |
260 | printf("kind: absolute symbol\n"); | |
261 | break; | |
d696c285 | 262 | default: |
a61fdf0a A |
263 | printf("kind: unknown\n"); |
264 | } | |
d696c285 | 265 | |
c2646906 | 266 | // segment and section |
2f2f92e4 | 267 | if(!sPrintRestrict && (atom->getSectionName() != NULL) ) |
a61fdf0a | 268 | printf("section: %s,%s\n", atom->getSegment().getName(), atom->getSectionName()); |
c2646906 A |
269 | |
270 | // attributes | |
a61fdf0a A |
271 | if(!sPrintRestrict) { |
272 | printf("attrs: "); | |
273 | if ( atom->dontDeadStrip() ) | |
274 | printf("dont-dead-strip "); | |
275 | if ( atom->isZeroFill() ) | |
276 | printf("zero-fill "); | |
2f2f92e4 A |
277 | if ( atom->isThumb() ) |
278 | printf("thumb "); | |
a61fdf0a A |
279 | printf("\n"); |
280 | } | |
c2646906 A |
281 | |
282 | // size | |
a61fdf0a A |
283 | if(!sPrintRestrict) |
284 | printf("size: 0x%012llX\n", atom->getSize()); | |
c2646906 A |
285 | |
286 | // alignment | |
a61fdf0a A |
287 | if(!sPrintRestrict || sPrintAlign) |
288 | printf("align: %u mod %u\n", atom->getAlignment().modulus, (1 << atom->getAlignment().powerOf2) ); | |
c2646906 A |
289 | |
290 | // content | |
a61fdf0a | 291 | if (!sPrintRestrict && sDumpContent ) { |
d696c285 A |
292 | uint64_t size = atom->getSize(); |
293 | if ( size < 4096 ) { | |
294 | uint8_t content[size]; | |
295 | atom->copyRawContent(content); | |
296 | printf("content: "); | |
55e3d2f6 | 297 | if ( atom->getContentType() == ObjectFile::Atom::kCStringType ) { |
a61fdf0a A |
298 | printf("\""); |
299 | for (unsigned int i=0; i < size; ++i) { | |
300 | if(content[i]<'!' || content[i]>=127) | |
301 | printf("\\%o", content[i]); | |
302 | else | |
303 | printf("%c", content[i]); | |
304 | } | |
305 | printf("\""); | |
d696c285 A |
306 | } |
307 | else { | |
308 | for (unsigned int i=0; i < size; ++i) | |
309 | printf("%02X ", content[i]); | |
310 | } | |
c2646906 | 311 | } |
d696c285 | 312 | printf("\n"); |
c2646906 | 313 | } |
c2646906 | 314 | |
55e3d2f6 A |
315 | // unwind info |
316 | if(!sPrintRestrict) { | |
317 | if ( atom->beginUnwind() != atom->endUnwind() ) { | |
318 | printf("unwind encodings:\n"); | |
319 | for (ObjectFile::UnwindInfo::iterator it = atom->beginUnwind(); it != atom->endUnwind(); ++it) { | |
320 | printf("\t 0x%04X 0x%08X\n", it->startOffset, it->unwindInfo); | |
321 | } | |
322 | } | |
323 | } | |
324 | ||
c2646906 | 325 | // references |
a61fdf0a A |
326 | if(!sPrintRestrict) { |
327 | std::vector<ObjectFile::Reference*>& references = atom->getReferences(); | |
328 | const int refCount = references.size(); | |
329 | printf("references: (%u)\n", refCount); | |
330 | for (int i=0; i < refCount; ++i) { | |
331 | ObjectFile::Reference* ref = references[i]; | |
332 | printf(" %s\n", ref->getDescription()); | |
333 | } | |
c2646906 A |
334 | } |
335 | ||
d696c285 | 336 | // line info |
a61fdf0a A |
337 | if(!sPrintRestrict) { |
338 | std::vector<ObjectFile::LineInfo>* lineInfo = atom->getLineInfo(); | |
339 | if ( (lineInfo != NULL) && (lineInfo->size() > 0) ) { | |
340 | printf("line info: (%lu)\n", lineInfo->size()); | |
341 | for (std::vector<ObjectFile::LineInfo>::iterator it = lineInfo->begin(); it != lineInfo->end(); ++it) { | |
342 | printf(" offset 0x%04X, line %d, file %s\n", it->atomOffset, it->lineNumber, it->fileName); | |
343 | } | |
d696c285 A |
344 | } |
345 | } | |
346 | ||
a61fdf0a A |
347 | if(!sPrintRestrict) |
348 | printf("\n"); | |
c2646906 A |
349 | } |
350 | ||
d696c285 A |
351 | struct AtomSorter |
352 | { | |
a61fdf0a | 353 | bool operator()(const ObjectFile::Atom* left, const ObjectFile::Atom* right) |
d696c285 | 354 | { |
a61fdf0a A |
355 | if ( left == right ) |
356 | return false; | |
55e3d2f6 A |
357 | int name = strcmp(left->getDisplayName(), right->getDisplayName()); |
358 | if ( name == 0 ) | |
359 | return (left->getSize() < right->getSize()); | |
360 | else | |
361 | return ( name < 0); | |
d696c285 A |
362 | } |
363 | }; | |
364 | ||
c2646906 A |
365 | |
366 | static void dumpFile(ObjectFile::Reader* reader) | |
367 | { | |
d696c285 A |
368 | // stabs debug info |
369 | if ( sDumpStabs && (reader->getDebugInfoKind() == ObjectFile::Reader::kDebugInfoStabs) ) { | |
370 | std::vector<ObjectFile::Reader::Stab>* stabs = reader->getStabs(); | |
371 | if ( stabs != NULL ) | |
372 | dumpStabs(stabs); | |
373 | } | |
374 | ||
375 | // get all atoms | |
c2646906 | 376 | std::vector<ObjectFile::Atom*> atoms = reader->getAtoms(); |
d696c285 A |
377 | |
378 | // make copy of vector and sort (so output is canonical) | |
379 | std::vector<ObjectFile::Atom*> sortedAtoms(atoms); | |
380 | if ( sSort ) | |
381 | std::sort(sortedAtoms.begin(), sortedAtoms.end(), AtomSorter()); | |
382 | ||
2f2f92e4 A |
383 | for(std::vector<ObjectFile::Atom*>::iterator it=sortedAtoms.begin(); it != sortedAtoms.end(); ++it) { |
384 | if ( sNMmode ) | |
385 | dumpAtomLikeNM(*it); | |
386 | else | |
387 | dumpAtom(*it); | |
388 | } | |
c2646906 A |
389 | } |
390 | ||
391 | ||
392 | static ObjectFile::Reader* createReader(const char* path, const ObjectFile::ReaderOptions& options) | |
393 | { | |
394 | struct stat stat_buf; | |
395 | ||
396 | int fd = ::open(path, O_RDONLY, 0); | |
397 | if ( fd == -1 ) | |
d696c285 | 398 | throwf("cannot open file: %s", path); |
c2646906 | 399 | ::fstat(fd, &stat_buf); |
69a49097 | 400 | uint8_t* p = (uint8_t*)::mmap(NULL, stat_buf.st_size, PROT_READ, MAP_FILE | MAP_PRIVATE, fd, 0); |
c2646906 A |
401 | ::close(fd); |
402 | const mach_header* mh = (mach_header*)p; | |
403 | if ( mh->magic == OSSwapBigToHostInt32(FAT_MAGIC) ) { | |
404 | const struct fat_header* fh = (struct fat_header*)p; | |
405 | const struct fat_arch* archs = (struct fat_arch*)(p + sizeof(struct fat_header)); | |
69a49097 | 406 | for (unsigned long i=0; i < OSSwapBigToHostInt32(fh->nfat_arch); ++i) { |
69a49097 A |
407 | if ( OSSwapBigToHostInt32(archs[i].cputype) == (uint32_t)sPreferredArch ) { |
408 | p = p + OSSwapBigToHostInt32(archs[i].offset); | |
c2646906 A |
409 | mh = (struct mach_header*)p; |
410 | } | |
411 | } | |
412 | } | |
d696c285 | 413 | if ( mach_o::relocatable::Reader<x86>::validFile(p) ) |
a61fdf0a | 414 | return new mach_o::relocatable::Reader<x86>::Reader(p, path, 0, options, 0); |
d696c285 | 415 | else if ( mach_o::relocatable::Reader<ppc>::validFile(p) ) |
a61fdf0a | 416 | return new mach_o::relocatable::Reader<ppc>::Reader(p, path, 0, options, 0); |
d696c285 | 417 | else if ( mach_o::relocatable::Reader<ppc64>::validFile(p) ) |
a61fdf0a | 418 | return new mach_o::relocatable::Reader<ppc64>::Reader(p, path, 0, options, 0); |
69a49097 | 419 | else if ( mach_o::relocatable::Reader<x86_64>::validFile(p) ) |
a61fdf0a | 420 | return new mach_o::relocatable::Reader<x86_64>::Reader(p, path, 0, options, 0); |
2f2f92e4 A |
421 | else if ( mach_o::relocatable::Reader<arm>::validFile(p) ) |
422 | return new mach_o::relocatable::Reader<arm>::Reader(p, path, 0, options, 0); | |
77cc3118 | 423 | #if LTO_SUPPORT |
2f2f92e4 A |
424 | if ( lto::Reader::validFile(p, stat_buf.st_size, 0) ) { |
425 | return new lto::Reader(p, stat_buf.st_size, path, 0, options, 0); | |
426 | } | |
77cc3118 | 427 | #endif |
2f2f92e4 | 428 | |
d696c285 | 429 | throwf("not a mach-o object file: %s", path); |
c2646906 A |
430 | } |
431 | ||
a61fdf0a A |
432 | static |
433 | void | |
434 | usage() | |
435 | { | |
436 | fprintf(stderr, "ObjectDump options:\n" | |
437 | "\t-no_content\tdon't dump contents\n" | |
438 | "\t-stabs\t\tdump stabs\n" | |
439 | "\t-arch aaa\tonly dump info about arch aaa\n" | |
440 | "\t-only sym\tonly dump info about sym\n" | |
441 | "\t-align\t\tonly print alignment info\n" | |
442 | "\t-name\t\tonly print symbol names\n" | |
443 | ); | |
444 | } | |
c2646906 A |
445 | |
446 | int main(int argc, const char* argv[]) | |
447 | { | |
a61fdf0a A |
448 | if(argc<2) { |
449 | usage(); | |
450 | return 0; | |
451 | } | |
452 | ||
c2646906 | 453 | ObjectFile::ReaderOptions options; |
55e3d2f6 | 454 | options.fAddCompactUnwindEncoding = true; |
c2646906 | 455 | try { |
d696c285 A |
456 | for(int i=1; i < argc; ++i) { |
457 | const char* arg = argv[i]; | |
458 | if ( arg[0] == '-' ) { | |
459 | if ( strcmp(arg, "-no_content") == 0 ) { | |
460 | sDumpContent = false; | |
461 | } | |
2f2f92e4 A |
462 | else if ( strcmp(arg, "-nm") == 0 ) { |
463 | sNMmode = true; | |
464 | } | |
d696c285 A |
465 | else if ( strcmp(arg, "-stabs") == 0 ) { |
466 | sDumpStabs = true; | |
467 | } | |
468 | else if ( strcmp(arg, "-no_sort") == 0 ) { | |
469 | sSort = false; | |
470 | } | |
471 | else if ( strcmp(arg, "-arch") == 0 ) { | |
a61fdf0a | 472 | const char* arch = ++i<argc? argv[i]: ""; |
d696c285 A |
473 | if ( strcmp(arch, "ppc64") == 0 ) |
474 | sPreferredArch = CPU_TYPE_POWERPC64; | |
475 | else if ( strcmp(arch, "ppc") == 0 ) | |
476 | sPreferredArch = CPU_TYPE_POWERPC; | |
477 | else if ( strcmp(arch, "i386") == 0 ) | |
478 | sPreferredArch = CPU_TYPE_I386; | |
69a49097 A |
479 | else if ( strcmp(arch, "x86_64") == 0 ) |
480 | sPreferredArch = CPU_TYPE_X86_64; | |
55e3d2f6 A |
481 | else if ( strcmp(arch, "arm") == 0 ) |
482 | sPreferredArch = CPU_TYPE_ARM; | |
483 | else if ( strcmp(arch, "armv6") == 0 ) | |
484 | sPreferredArch = CPU_TYPE_ARM; | |
d696c285 A |
485 | else |
486 | throwf("unknown architecture %s", arch); | |
487 | } | |
a61fdf0a A |
488 | else if ( strcmp(arg, "-only") == 0 ) { |
489 | sMatchName = ++i<argc? argv[i]: NULL; | |
490 | } | |
491 | else if ( strcmp(arg, "-align") == 0 ) { | |
492 | sPrintRestrict = true; | |
493 | sPrintAlign = true; | |
494 | } | |
495 | else if ( strcmp(arg, "-name") == 0 ) { | |
496 | sPrintRestrict = true; | |
497 | sPrintName = true; | |
498 | } | |
d696c285 | 499 | else { |
a61fdf0a | 500 | usage(); |
d696c285 A |
501 | throwf("unknown option: %s\n", arg); |
502 | } | |
503 | } | |
504 | else { | |
505 | ObjectFile::Reader* reader = createReader(arg, options); | |
506 | dumpFile(reader); | |
507 | } | |
508 | } | |
c2646906 A |
509 | } |
510 | catch (const char* msg) { | |
511 | fprintf(stderr, "ObjDump failed: %s\n", msg); | |
d696c285 | 512 | return 1; |
c2646906 A |
513 | } |
514 | ||
515 | return 0; | |
516 | } |