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