]> git.saurik.com Git - apple/ld64.git/blob - src/other/ObjectDump.cpp
ld64-96.5.tar.gz
[apple/ld64.git] / src / other / ObjectDump.cpp
1 /* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
2 *
3 * Copyright (c) 2005-2006 Apple Computer, 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 <fcntl.h>
30
31 #include "MachOReaderRelocatable.hpp"
32
33 #define LTO_SUPPORT 1
34
35 #if LTO_SUPPORT
36 #include "LTOReader.hpp"
37 #endif
38
39 static bool sDumpContent= true;
40 static bool sDumpStabs = false;
41 static bool sSort = true;
42 static bool sNMmode = false;
43 static cpu_type_t sPreferredArch = CPU_TYPE_POWERPC64;
44 static const char* sMatchName;
45 static int sPrintRestrict;
46 static int sPrintAlign;
47 static int sPrintName;
48
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
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
73 static void dumpStabs(std::vector<ObjectFile::Reader::Stab>* stabs)
74 {
75 // debug info
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;
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;
117 case N_OSO:
118 code = " OSO";
119 break;
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 }
166 printf(" [atom=%20s] %02X %04X %s %s\n", ((stab.atom != NULL) ? stab.atom->getDisplayName() : ""), stab.other, stab.desc, code, stab.string);
167 }
168 }
169
170
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
214 static void dumpAtom(ObjectFile::Atom* atom)
215 {
216 if(sMatchName && strcmp(sMatchName, atom->getDisplayName()))
217 return;
218
219 //printf("atom: %p\n", atom);
220
221 // name
222 if(!sPrintRestrict || sPrintName)
223 printf("name: %s\n", atom->getDisplayName());
224
225 // scope
226 if(!sPrintRestrict)
227 switch ( atom->getScope() ) {
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");
239 }
240
241 // kind
242 if(!sPrintRestrict)
243 switch ( atom->getDefinitionKind() ) {
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;
259 case ObjectFile::Atom::kAbsoluteSymbol:
260 printf("kind: absolute symbol\n");
261 break;
262 default:
263 printf("kind: unknown\n");
264 }
265
266 // segment and section
267 if(!sPrintRestrict && (atom->getSectionName() != NULL) )
268 printf("section: %s,%s\n", atom->getSegment().getName(), atom->getSectionName());
269
270 // attributes
271 if(!sPrintRestrict) {
272 printf("attrs: ");
273 if ( atom->dontDeadStrip() )
274 printf("dont-dead-strip ");
275 if ( atom->isZeroFill() )
276 printf("zero-fill ");
277 if ( atom->isThumb() )
278 printf("thumb ");
279 printf("\n");
280 }
281
282 // size
283 if(!sPrintRestrict)
284 printf("size: 0x%012llX\n", atom->getSize());
285
286 // alignment
287 if(!sPrintRestrict || sPrintAlign)
288 printf("align: %u mod %u\n", atom->getAlignment().modulus, (1 << atom->getAlignment().powerOf2) );
289
290 // content
291 if (!sPrintRestrict && sDumpContent ) {
292 uint64_t size = atom->getSize();
293 if ( size < 4096 ) {
294 uint8_t content[size];
295 atom->copyRawContent(content);
296 printf("content: ");
297 if ( atom->getContentType() == ObjectFile::Atom::kCStringType ) {
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("\"");
306 }
307 else {
308 for (unsigned int i=0; i < size; ++i)
309 printf("%02X ", content[i]);
310 }
311 }
312 printf("\n");
313 }
314
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
325 // references
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 }
334 }
335
336 // line info
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 }
344 }
345 }
346
347 if(!sPrintRestrict)
348 printf("\n");
349 }
350
351 struct AtomSorter
352 {
353 bool operator()(const ObjectFile::Atom* left, const ObjectFile::Atom* right)
354 {
355 if ( left == right )
356 return false;
357 int name = strcmp(left->getDisplayName(), right->getDisplayName());
358 if ( name == 0 )
359 return (left->getSize() < right->getSize());
360 else
361 return ( name < 0);
362 }
363 };
364
365
366 static void dumpFile(ObjectFile::Reader* reader)
367 {
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
376 std::vector<ObjectFile::Atom*> atoms = reader->getAtoms();
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
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 }
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 )
398 throwf("cannot open file: %s", path);
399 ::fstat(fd, &stat_buf);
400 uint8_t* p = (uint8_t*)::mmap(NULL, stat_buf.st_size, PROT_READ, MAP_FILE | MAP_PRIVATE, fd, 0);
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));
406 for (unsigned long i=0; i < OSSwapBigToHostInt32(fh->nfat_arch); ++i) {
407 if ( OSSwapBigToHostInt32(archs[i].cputype) == (uint32_t)sPreferredArch ) {
408 p = p + OSSwapBigToHostInt32(archs[i].offset);
409 mh = (struct mach_header*)p;
410 }
411 }
412 }
413 if ( mach_o::relocatable::Reader<x86>::validFile(p) )
414 return new mach_o::relocatable::Reader<x86>::Reader(p, path, 0, options, 0);
415 else if ( mach_o::relocatable::Reader<ppc>::validFile(p) )
416 return new mach_o::relocatable::Reader<ppc>::Reader(p, path, 0, options, 0);
417 else if ( mach_o::relocatable::Reader<ppc64>::validFile(p) )
418 return new mach_o::relocatable::Reader<ppc64>::Reader(p, path, 0, options, 0);
419 else if ( mach_o::relocatable::Reader<x86_64>::validFile(p) )
420 return new mach_o::relocatable::Reader<x86_64>::Reader(p, path, 0, options, 0);
421 else if ( mach_o::relocatable::Reader<arm>::validFile(p) )
422 return new mach_o::relocatable::Reader<arm>::Reader(p, path, 0, options, 0);
423 #if LTO_SUPPORT
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 }
427 #endif
428
429 throwf("not a mach-o object file: %s", path);
430 }
431
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 }
445
446 int main(int argc, const char* argv[])
447 {
448 if(argc<2) {
449 usage();
450 return 0;
451 }
452
453 ObjectFile::ReaderOptions options;
454 options.fAddCompactUnwindEncoding = true;
455 try {
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 }
462 else if ( strcmp(arg, "-nm") == 0 ) {
463 sNMmode = true;
464 }
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 ) {
472 const char* arch = ++i<argc? argv[i]: "";
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;
479 else if ( strcmp(arch, "x86_64") == 0 )
480 sPreferredArch = CPU_TYPE_X86_64;
481 else if ( strcmp(arch, "arm") == 0 )
482 sPreferredArch = CPU_TYPE_ARM;
483 else if ( strcmp(arch, "armv6") == 0 )
484 sPreferredArch = CPU_TYPE_ARM;
485 else
486 throwf("unknown architecture %s", arch);
487 }
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 }
499 else {
500 usage();
501 throwf("unknown option: %s\n", arg);
502 }
503 }
504 else {
505 ObjectFile::Reader* reader = createReader(arg, options);
506 dumpFile(reader);
507 }
508 }
509 }
510 catch (const char* msg) {
511 fprintf(stderr, "ObjDump failed: %s\n", msg);
512 return 1;
513 }
514
515 return 0;
516 }