]> git.saurik.com Git - apple/ld64.git/blob - src/ObjectDump.cpp
4150fdae309e09a964c43d54d94e2974f5c89ec0
[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 #include <mach-o/loader.h>
31 #include <mach-o/fat.h>
32 #include <mach-o/stab.h>
33
34 #include "MachOReaderRelocatable.hpp"
35
36 static bool sDumpContent= true;
37 static bool sDumpStabs = false;
38 static bool sSort = true;
39 static cpu_type_t sPreferredArch = CPU_TYPE_POWERPC64;
40
41
42 __attribute__((noreturn))
43 void throwf(const char* format, ...)
44 {
45 va_list list;
46 char* p;
47 va_start(list, format);
48 vasprintf(&p, format, list);
49 va_end(list);
50
51 const char* t = p;
52 throw t;
53 }
54
55 static void dumpStabs(std::vector<ObjectFile::Reader::Stab>* stabs)
56 {
57 // debug info
58 printf("stabs: (%lu)\n", stabs->size());
59 for (std::vector<ObjectFile::Reader::Stab>::iterator it = stabs->begin(); it != stabs->end(); ++it ) {
60 ObjectFile::Reader::Stab& stab = *it;
61 const char* code = "?????";
62 switch (stab.type) {
63 case N_GSYM:
64 code = " GSYM";
65 break;
66 case N_FNAME:
67 code = "FNAME";
68 break;
69 case N_FUN:
70 code = " FUN";
71 break;
72 case N_STSYM:
73 code = "STSYM";
74 break;
75 case N_LCSYM:
76 code = "LCSYM";
77 break;
78 case N_BNSYM:
79 code = "BNSYM";
80 break;
81 case N_OPT:
82 code = " OPT";
83 break;
84 case N_RSYM:
85 code = " RSYM";
86 break;
87 case N_SLINE:
88 code = "SLINE";
89 break;
90 case N_ENSYM:
91 code = "ENSYM";
92 break;
93 case N_SSYM:
94 code = " SSYM";
95 break;
96 case N_SO:
97 code = " SO";
98 break;
99 case N_OSO:
100 code = " OSO";
101 break;
102 case N_LSYM:
103 code = " LSYM";
104 break;
105 case N_BINCL:
106 code = "BINCL";
107 break;
108 case N_SOL:
109 code = " SOL";
110 break;
111 case N_PARAMS:
112 code = "PARMS";
113 break;
114 case N_VERSION:
115 code = " VERS";
116 break;
117 case N_OLEVEL:
118 code = "OLEVL";
119 break;
120 case N_PSYM:
121 code = " PSYM";
122 break;
123 case N_EINCL:
124 code = "EINCL";
125 break;
126 case N_ENTRY:
127 code = "ENTRY";
128 break;
129 case N_LBRAC:
130 code = "LBRAC";
131 break;
132 case N_EXCL:
133 code = " EXCL";
134 break;
135 case N_RBRAC:
136 code = "RBRAC";
137 break;
138 case N_BCOMM:
139 code = "BCOMM";
140 break;
141 case N_ECOMM:
142 code = "ECOMM";
143 break;
144 case N_LENG:
145 code = "LENG";
146 break;
147 }
148 printf(" [atom=%20s] %02X %04X %s %s\n", ((stab.atom != NULL) ? stab.atom->getDisplayName() : ""), stab.other, stab.desc, code, stab.string);
149 }
150 }
151
152
153 static void dumpAtom(ObjectFile::Atom* atom)
154 {
155 //printf("atom: %p\n", atom);
156
157 // name
158 printf("name: %s\n", atom->getDisplayName());
159
160 // scope
161 switch ( atom->getScope() ) {
162 case ObjectFile::Atom::scopeTranslationUnit:
163 printf("scope: translation unit\n");
164 break;
165 case ObjectFile::Atom::scopeLinkageUnit:
166 printf("scope: linkage unit\n");
167 break;
168 case ObjectFile::Atom::scopeGlobal:
169 printf("scope: global\n");
170 break;
171 default:
172 printf("scope: unknown\n");
173 }
174
175 // kind
176 switch ( atom->getDefinitionKind() ) {
177 case ObjectFile::Atom::kRegularDefinition:
178 printf("kind: regular\n");
179 break;
180 case ObjectFile::Atom::kWeakDefinition:
181 printf("kind: weak\n");
182 break;
183 case ObjectFile::Atom::kTentativeDefinition:
184 printf("kind: tentative\n");
185 break;
186 case ObjectFile::Atom::kExternalDefinition:
187 printf("kind: import\n");
188 break;
189 case ObjectFile::Atom::kExternalWeakDefinition:
190 printf("kind: weak import\n");
191 break;
192 default:
193 printf("scope: unknown\n");
194 }
195
196 // segment and section
197 printf("section: %s,%s\n", atom->getSegment().getName(), atom->getSectionName());
198
199 // attributes
200 printf("attrs: ");
201 if ( atom->dontDeadStrip() )
202 printf("dont-dead-strip ");
203 if ( atom->isZeroFill() )
204 printf("zero-fill ");
205 printf("\n");
206
207 // size
208 printf("size: 0x%012llX\n", atom->getSize());
209
210 // alignment
211 printf("align: %d\n", atom->getAlignment());
212
213 // content
214 if ( sDumpContent ) {
215 uint64_t size = atom->getSize();
216 if ( size < 4096 ) {
217 uint8_t content[size];
218 atom->copyRawContent(content);
219 printf("content: ");
220 if ( strcmp(atom->getSectionName(), "__cstring") == 0 ) {
221 printf("\"%s\"", content);
222 }
223 else {
224 for (unsigned int i=0; i < size; ++i)
225 printf("%02X ", content[i]);
226 }
227 }
228 printf("\n");
229 }
230
231 // references
232 std::vector<ObjectFile::Reference*>& references = atom->getReferences();
233 const int refCount = references.size();
234 printf("references: (%u)\n", refCount);
235 for (int i=0; i < refCount; ++i) {
236 ObjectFile::Reference* ref = references[i];
237 printf(" %s\n", ref->getDescription());
238 }
239
240 // line info
241 std::vector<ObjectFile::LineInfo>* lineInfo = atom->getLineInfo();
242 if ( (lineInfo != NULL) && (lineInfo->size() > 0) ) {
243 printf("line info: (%lu)\n", lineInfo->size());
244 for (std::vector<ObjectFile::LineInfo>::iterator it = lineInfo->begin(); it != lineInfo->end(); ++it) {
245 printf(" offset 0x%04X, line %d, file %s\n", it->atomOffset, it->lineNumber, it->fileName);
246 }
247 }
248
249 }
250
251 struct AtomSorter
252 {
253 bool operator()(ObjectFile::Atom* left, ObjectFile::Atom* right)
254 {
255 return (strcmp(left->getDisplayName(), right->getDisplayName()) < 0);
256 }
257 };
258
259
260 static void dumpFile(ObjectFile::Reader* reader)
261 {
262 // stabs debug info
263 if ( sDumpStabs && (reader->getDebugInfoKind() == ObjectFile::Reader::kDebugInfoStabs) ) {
264 std::vector<ObjectFile::Reader::Stab>* stabs = reader->getStabs();
265 if ( stabs != NULL )
266 dumpStabs(stabs);
267 }
268
269 // get all atoms
270 std::vector<ObjectFile::Atom*> atoms = reader->getAtoms();
271
272 // make copy of vector and sort (so output is canonical)
273 std::vector<ObjectFile::Atom*> sortedAtoms(atoms);
274 if ( sSort )
275 std::sort(sortedAtoms.begin(), sortedAtoms.end(), AtomSorter());
276
277 for(std::vector<ObjectFile::Atom*>::iterator it=sortedAtoms.begin(); it != sortedAtoms.end(); ++it) {
278 dumpAtom(*it);
279 printf("\n");
280 }
281 }
282
283
284 static ObjectFile::Reader* createReader(const char* path, const ObjectFile::ReaderOptions& options)
285 {
286 struct stat stat_buf;
287
288 int fd = ::open(path, O_RDONLY, 0);
289 if ( fd == -1 )
290 throwf("cannot open file: %s", path);
291 ::fstat(fd, &stat_buf);
292 uint8_t* p = (uint8_t*)::mmap(NULL, stat_buf.st_size, PROT_READ, MAP_FILE | MAP_PRIVATE, fd, 0);
293 ::close(fd);
294 const mach_header* mh = (mach_header*)p;
295 if ( mh->magic == OSSwapBigToHostInt32(FAT_MAGIC) ) {
296 const struct fat_header* fh = (struct fat_header*)p;
297 const struct fat_arch* archs = (struct fat_arch*)(p + sizeof(struct fat_header));
298 for (unsigned long i=0; i < OSSwapBigToHostInt32(fh->nfat_arch); ++i) {
299 fprintf(stderr, "archs[i].cputype = %X\n", archs[i].cputype);
300 if ( OSSwapBigToHostInt32(archs[i].cputype) == (uint32_t)sPreferredArch ) {
301 p = p + OSSwapBigToHostInt32(archs[i].offset);
302 mh = (struct mach_header*)p;
303 }
304 }
305 }
306 if ( mach_o::relocatable::Reader<x86>::validFile(p) )
307 return mach_o::relocatable::Reader<x86>::make(p, path, 0, options);
308 else if ( mach_o::relocatable::Reader<ppc>::validFile(p) )
309 return mach_o::relocatable::Reader<ppc>::make(p, path, 0, options);
310 else if ( mach_o::relocatable::Reader<ppc64>::validFile(p) )
311 return mach_o::relocatable::Reader<ppc64>::make(p, path, 0, options);
312 else if ( mach_o::relocatable::Reader<x86_64>::validFile(p) )
313 return mach_o::relocatable::Reader<x86_64>::make(p, path, 0, options);
314 throwf("not a mach-o object file: %s", path);
315 }
316
317
318 int main(int argc, const char* argv[])
319 {
320 ObjectFile::ReaderOptions options;
321 try {
322 for(int i=1; i < argc; ++i) {
323 const char* arg = argv[i];
324 if ( arg[0] == '-' ) {
325 if ( strcmp(arg, "-no_content") == 0 ) {
326 sDumpContent = false;
327 }
328 else if ( strcmp(arg, "-stabs") == 0 ) {
329 sDumpStabs = true;
330 }
331 else if ( strcmp(arg, "-no_sort") == 0 ) {
332 sSort = false;
333 }
334 else if ( strcmp(arg, "-arch") == 0 ) {
335 const char* arch = argv[++i];
336 if ( strcmp(arch, "ppc64") == 0 )
337 sPreferredArch = CPU_TYPE_POWERPC64;
338 else if ( strcmp(arch, "ppc") == 0 )
339 sPreferredArch = CPU_TYPE_POWERPC;
340 else if ( strcmp(arch, "i386") == 0 )
341 sPreferredArch = CPU_TYPE_I386;
342 else if ( strcmp(arch, "x86_64") == 0 )
343 sPreferredArch = CPU_TYPE_X86_64;
344 else
345 throwf("unknown architecture %s", arch);
346 }
347 else {
348 throwf("unknown option: %s\n", arg);
349 }
350 }
351 else {
352 ObjectFile::Reader* reader = createReader(arg, options);
353 dumpFile(reader);
354 }
355 }
356 }
357 catch (const char* msg) {
358 fprintf(stderr, "ObjDump failed: %s\n", msg);
359 return 1;
360 }
361
362 return 0;
363 }
364
365
366