]> git.saurik.com Git - apple/ld64.git/blob - src/ObjectDump.cpp
a06c7a2e5f007a76c88fecdceeea1b0d685614c6
[apple/ld64.git] / src / 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 0
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 ( strcmp(atom->getSectionName(), "__cstring") == 0 ) {
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 // references
316 if(!sPrintRestrict) {
317 std::vector<ObjectFile::Reference*>& references = atom->getReferences();
318 const int refCount = references.size();
319 printf("references: (%u)\n", refCount);
320 for (int i=0; i < refCount; ++i) {
321 ObjectFile::Reference* ref = references[i];
322 printf(" %s\n", ref->getDescription());
323 }
324 }
325
326 // line info
327 if(!sPrintRestrict) {
328 std::vector<ObjectFile::LineInfo>* lineInfo = atom->getLineInfo();
329 if ( (lineInfo != NULL) && (lineInfo->size() > 0) ) {
330 printf("line info: (%lu)\n", lineInfo->size());
331 for (std::vector<ObjectFile::LineInfo>::iterator it = lineInfo->begin(); it != lineInfo->end(); ++it) {
332 printf(" offset 0x%04X, line %d, file %s\n", it->atomOffset, it->lineNumber, it->fileName);
333 }
334 }
335 }
336
337 if(!sPrintRestrict)
338 printf("\n");
339 }
340
341 struct AtomSorter
342 {
343 bool operator()(const ObjectFile::Atom* left, const ObjectFile::Atom* right)
344 {
345 if ( left == right )
346 return false;
347 return (strcmp(left->getDisplayName(), right->getDisplayName()) < 0);
348 }
349 };
350
351
352 static void dumpFile(ObjectFile::Reader* reader)
353 {
354 // stabs debug info
355 if ( sDumpStabs && (reader->getDebugInfoKind() == ObjectFile::Reader::kDebugInfoStabs) ) {
356 std::vector<ObjectFile::Reader::Stab>* stabs = reader->getStabs();
357 if ( stabs != NULL )
358 dumpStabs(stabs);
359 }
360
361 // get all atoms
362 std::vector<ObjectFile::Atom*> atoms = reader->getAtoms();
363
364 // make copy of vector and sort (so output is canonical)
365 std::vector<ObjectFile::Atom*> sortedAtoms(atoms);
366 if ( sSort )
367 std::sort(sortedAtoms.begin(), sortedAtoms.end(), AtomSorter());
368
369 for(std::vector<ObjectFile::Atom*>::iterator it=sortedAtoms.begin(); it != sortedAtoms.end(); ++it) {
370 if ( sNMmode )
371 dumpAtomLikeNM(*it);
372 else
373 dumpAtom(*it);
374 }
375 }
376
377
378 static ObjectFile::Reader* createReader(const char* path, const ObjectFile::ReaderOptions& options)
379 {
380 struct stat stat_buf;
381
382 int fd = ::open(path, O_RDONLY, 0);
383 if ( fd == -1 )
384 throwf("cannot open file: %s", path);
385 ::fstat(fd, &stat_buf);
386 uint8_t* p = (uint8_t*)::mmap(NULL, stat_buf.st_size, PROT_READ, MAP_FILE | MAP_PRIVATE, fd, 0);
387 ::close(fd);
388 const mach_header* mh = (mach_header*)p;
389 if ( mh->magic == OSSwapBigToHostInt32(FAT_MAGIC) ) {
390 const struct fat_header* fh = (struct fat_header*)p;
391 const struct fat_arch* archs = (struct fat_arch*)(p + sizeof(struct fat_header));
392 for (unsigned long i=0; i < OSSwapBigToHostInt32(fh->nfat_arch); ++i) {
393 if ( OSSwapBigToHostInt32(archs[i].cputype) == (uint32_t)sPreferredArch ) {
394 p = p + OSSwapBigToHostInt32(archs[i].offset);
395 mh = (struct mach_header*)p;
396 }
397 }
398 }
399 if ( mach_o::relocatable::Reader<x86>::validFile(p) )
400 return new mach_o::relocatable::Reader<x86>::Reader(p, path, 0, options, 0);
401 else if ( mach_o::relocatable::Reader<ppc>::validFile(p) )
402 return new mach_o::relocatable::Reader<ppc>::Reader(p, path, 0, options, 0);
403 else if ( mach_o::relocatable::Reader<ppc64>::validFile(p) )
404 return new mach_o::relocatable::Reader<ppc64>::Reader(p, path, 0, options, 0);
405 else if ( mach_o::relocatable::Reader<x86_64>::validFile(p) )
406 return new mach_o::relocatable::Reader<x86_64>::Reader(p, path, 0, options, 0);
407 else if ( mach_o::relocatable::Reader<arm>::validFile(p) )
408 return new mach_o::relocatable::Reader<arm>::Reader(p, path, 0, options, 0);
409 #if LTO_SUPPORT
410 if ( lto::Reader::validFile(p, stat_buf.st_size, 0) ) {
411 return new lto::Reader(p, stat_buf.st_size, path, 0, options, 0);
412 }
413 #endif
414
415 throwf("not a mach-o object file: %s", path);
416 }
417
418 static
419 void
420 usage()
421 {
422 fprintf(stderr, "ObjectDump options:\n"
423 "\t-no_content\tdon't dump contents\n"
424 "\t-stabs\t\tdump stabs\n"
425 "\t-arch aaa\tonly dump info about arch aaa\n"
426 "\t-only sym\tonly dump info about sym\n"
427 "\t-align\t\tonly print alignment info\n"
428 "\t-name\t\tonly print symbol names\n"
429 );
430 }
431
432 int main(int argc, const char* argv[])
433 {
434 if(argc<2) {
435 usage();
436 return 0;
437 }
438
439 ObjectFile::ReaderOptions options;
440 try {
441 for(int i=1; i < argc; ++i) {
442 const char* arg = argv[i];
443 if ( arg[0] == '-' ) {
444 if ( strcmp(arg, "-no_content") == 0 ) {
445 sDumpContent = false;
446 }
447 else if ( strcmp(arg, "-nm") == 0 ) {
448 sNMmode = true;
449 }
450 else if ( strcmp(arg, "-stabs") == 0 ) {
451 sDumpStabs = true;
452 }
453 else if ( strcmp(arg, "-no_sort") == 0 ) {
454 sSort = false;
455 }
456 else if ( strcmp(arg, "-arch") == 0 ) {
457 const char* arch = ++i<argc? argv[i]: "";
458 if ( strcmp(arch, "ppc64") == 0 )
459 sPreferredArch = CPU_TYPE_POWERPC64;
460 else if ( strcmp(arch, "ppc") == 0 )
461 sPreferredArch = CPU_TYPE_POWERPC;
462 else if ( strcmp(arch, "i386") == 0 )
463 sPreferredArch = CPU_TYPE_I386;
464 else if ( strcmp(arch, "x86_64") == 0 )
465 sPreferredArch = CPU_TYPE_X86_64;
466 else
467 throwf("unknown architecture %s", arch);
468 }
469 else if ( strcmp(arg, "-only") == 0 ) {
470 sMatchName = ++i<argc? argv[i]: NULL;
471 }
472 else if ( strcmp(arg, "-align") == 0 ) {
473 sPrintRestrict = true;
474 sPrintAlign = true;
475 }
476 else if ( strcmp(arg, "-name") == 0 ) {
477 sPrintRestrict = true;
478 sPrintName = true;
479 }
480 else {
481 usage();
482 throwf("unknown option: %s\n", arg);
483 }
484 }
485 else {
486 ObjectFile::Reader* reader = createReader(arg, options);
487 dumpFile(reader);
488 }
489 }
490 }
491 catch (const char* msg) {
492 fprintf(stderr, "ObjDump failed: %s\n", msg);
493 return 1;
494 }
495
496 return 0;
497 }