]> git.saurik.com Git - apple/ld64.git/blame - src/other/unwinddump.cpp
ld64-95.8.4.tar.gz
[apple/ld64.git] / src / other / unwinddump.cpp
CommitLineData
55e3d2f6
A
1/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
2 *
3 * Copyright (c) 2008 Apple 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 <stdarg.h>
29#include <stdio.h>
30#include <fcntl.h>
31#include <unistd.h>
32#include <errno.h>
33
34#include <vector>
35#include <set>
36#include <ext/hash_set>
37
38
39#include "MachOFileAbstraction.hpp"
40#include "Architectures.hpp"
41
42
43 __attribute__((noreturn))
44void throwf(const char* format, ...)
45{
46 va_list list;
47 char* p;
48 va_start(list, format);
49 vasprintf(&p, format, list);
50 va_end(list);
51
52 const char* t = p;
53 throw t;
54}
55
56
57template <typename A>
58class UnwindPrinter
59{
60public:
61 static bool validFile(const uint8_t* fileContent);
62 static UnwindPrinter<A>* make(const uint8_t* fileContent, uint32_t fileLength, const char* path)
63 { return new UnwindPrinter<A>(fileContent, fileLength, path); }
64 virtual ~UnwindPrinter() {}
65
66
67private:
68 typedef typename A::P P;
69 typedef typename A::P::E E;
70 typedef typename A::P::uint_t pint_t;
71
72 class CStringEquals
73 {
74 public:
75 bool operator()(const char* left, const char* right) const { return (strcmp(left, right) == 0); }
76 };
77
78 typedef __gnu_cxx::hash_set<const char*, __gnu_cxx::hash<const char*>, CStringEquals> StringSet;
79
80 UnwindPrinter(const uint8_t* fileContent, uint32_t fileLength, const char* path);
81 bool findUnwindSection();
82 void printUnwindSection();
83 void getSymbolTableInfo();
84 const char* functionName(pint_t addr);
85 static const char* archName();
55e3d2f6
A
86
87 const char* fPath;
88 const macho_header<P>* fHeader;
89 uint64_t fLength;
90 const macho_section<P>* fUnwindSection;
91 const char* fStrings;
92 const char* fStringsEnd;
93 const macho_nlist<P>* fSymbols;
94 uint32_t fSymbolCount;
95 pint_t fMachHeaderAddress;
96};
97
98
99template <> const char* UnwindPrinter<ppc>::archName() { return "ppc"; }
100template <> const char* UnwindPrinter<ppc64>::archName() { return "ppc64"; }
101template <> const char* UnwindPrinter<x86>::archName() { return "i386"; }
102template <> const char* UnwindPrinter<x86_64>::archName() { return "x86_64"; }
103template <> const char* UnwindPrinter<arm>::archName() { return "arm"; }
104
105template <>
106bool UnwindPrinter<ppc>::validFile(const uint8_t* fileContent)
107{
108 const macho_header<P>* header = (const macho_header<P>*)fileContent;
109 if ( header->magic() != MH_MAGIC )
110 return false;
111 if ( header->cputype() != CPU_TYPE_POWERPC )
112 return false;
113 switch (header->filetype()) {
114 case MH_EXECUTE:
115 case MH_DYLIB:
116 case MH_BUNDLE:
117 case MH_DYLINKER:
118 return true;
119 }
120 return false;
121}
122
123template <>
124bool UnwindPrinter<ppc64>::validFile(const uint8_t* fileContent)
125{
126 const macho_header<P>* header = (const macho_header<P>*)fileContent;
127 if ( header->magic() != MH_MAGIC_64 )
128 return false;
129 if ( header->cputype() != CPU_TYPE_POWERPC64 )
130 return false;
131 switch (header->filetype()) {
132 case MH_EXECUTE:
133 case MH_DYLIB:
134 case MH_BUNDLE:
135 case MH_DYLINKER:
136 return true;
137 }
138 return false;
139}
140
141template <>
142bool UnwindPrinter<x86>::validFile(const uint8_t* fileContent)
143{
144 const macho_header<P>* header = (const macho_header<P>*)fileContent;
145 if ( header->magic() != MH_MAGIC )
146 return false;
147 if ( header->cputype() != CPU_TYPE_I386 )
148 return false;
149 switch (header->filetype()) {
150 case MH_EXECUTE:
151 case MH_DYLIB:
152 case MH_BUNDLE:
153 case MH_DYLINKER:
154 return true;
155 }
156 return false;
157}
158
159template <>
160bool UnwindPrinter<x86_64>::validFile(const uint8_t* fileContent)
161{
162 const macho_header<P>* header = (const macho_header<P>*)fileContent;
163 if ( header->magic() != MH_MAGIC_64 )
164 return false;
165 if ( header->cputype() != CPU_TYPE_X86_64 )
166 return false;
167 switch (header->filetype()) {
168 case MH_EXECUTE:
169 case MH_DYLIB:
170 case MH_BUNDLE:
171 case MH_DYLINKER:
172 return true;
173 }
174 return false;
175}
176
177template <>
178bool UnwindPrinter<arm>::validFile(const uint8_t* fileContent)
179{
180 const macho_header<P>* header = (const macho_header<P>*)fileContent;
181 if ( header->magic() != MH_MAGIC )
182 return false;
183 if ( header->cputype() != CPU_TYPE_ARM )
184 return false;
185 switch (header->filetype()) {
186 case MH_EXECUTE:
187 case MH_DYLIB:
188 case MH_BUNDLE:
189 case MH_DYLINKER:
190 return true;
191 }
192 return false;
193}
194
195
196template <typename A>
197UnwindPrinter<A>::UnwindPrinter(const uint8_t* fileContent, uint32_t fileLength, const char* path)
198 : fHeader(NULL), fLength(fileLength), fUnwindSection(NULL),
199 fStrings(NULL), fStringsEnd(NULL), fSymbols(NULL), fSymbolCount(0), fMachHeaderAddress(0)
200{
201 // sanity check
202 if ( ! validFile(fileContent) )
203 throw "not a mach-o file that can be checked";
204
205 fPath = strdup(path);
206 fHeader = (const macho_header<P>*)fileContent;
207
208 getSymbolTableInfo();
209
210 if ( findUnwindSection() )
211 printUnwindSection();
212}
213
214
215template <typename A>
216void UnwindPrinter<A>::getSymbolTableInfo()
217{
218 const uint8_t* const endOfFile = (uint8_t*)fHeader + fLength;
219 const uint8_t* const endOfLoadCommands = (uint8_t*)fHeader + sizeof(macho_header<P>) + fHeader->sizeofcmds();
220 const uint32_t cmd_count = fHeader->ncmds();
221 const macho_load_command<P>* const cmds = (macho_load_command<P>*)((uint8_t*)fHeader + sizeof(macho_header<P>));
222 const macho_load_command<P>* cmd = cmds;
223 for (uint32_t i = 0; i < cmd_count; ++i) {
224 uint32_t size = cmd->cmdsize();
225 const uint8_t* endOfCmd = ((uint8_t*)cmd)+cmd->cmdsize();
226 if ( endOfCmd > endOfLoadCommands )
227 throwf("load command #%d extends beyond the end of the load commands", i);
228 if ( endOfCmd > endOfFile )
229 throwf("load command #%d extends beyond the end of the file", i);
230 if ( cmd->cmd() == LC_SYMTAB) {
231 const macho_symtab_command<P>* symtab = (macho_symtab_command<P>*)cmd;
232 fSymbolCount = symtab->nsyms();
233 fSymbols = (const macho_nlist<P>*)((char*)fHeader + symtab->symoff());
234 fStrings = (char*)fHeader + symtab->stroff();
235 fStringsEnd = fStrings + symtab->strsize();
236 }
237 cmd = (const macho_load_command<P>*)endOfCmd;
238 }
239}
240
241template <typename A>
242const char* UnwindPrinter<A>::functionName(pint_t addr)
243{
244 for (uint32_t i=0; i < fSymbolCount; ++i) {
245 uint8_t type = fSymbols[i].n_type();
246 if ( ((type & N_STAB) == 0) && ((type & N_TYPE) == N_SECT) ) {
247 if ( fSymbols[i].n_value() == addr ) {
248 const char* r = &fStrings[fSymbols[i].n_strx()];
249 //fprintf(stderr, "addr=0x%08llX, i=%u, n_type=0x%0X, r=%s\n", (long long)(fSymbols[i].n_value()), i, fSymbols[i].n_type(), r);
250 return r;
251 }
252 }
253 }
4be885f6 254 return "??";
55e3d2f6
A
255}
256
257
258
259template <typename A>
260bool UnwindPrinter<A>::findUnwindSection()
261{
262 const uint8_t* const endOfFile = (uint8_t*)fHeader + fLength;
263 const uint8_t* const endOfLoadCommands = (uint8_t*)fHeader + sizeof(macho_header<P>) + fHeader->sizeofcmds();
264 const uint32_t cmd_count = fHeader->ncmds();
265 const macho_load_command<P>* const cmds = (macho_load_command<P>*)((uint8_t*)fHeader + sizeof(macho_header<P>));
266 const macho_load_command<P>* cmd = cmds;
267 for (uint32_t i = 0; i < cmd_count; ++i) {
268 uint32_t size = cmd->cmdsize();
269 const uint8_t* endOfCmd = ((uint8_t*)cmd)+cmd->cmdsize();
270 if ( endOfCmd > endOfLoadCommands )
271 throwf("load command #%d extends beyond the end of the load commands", i);
272 if ( endOfCmd > endOfFile )
273 throwf("load command #%d extends beyond the end of the file", i);
274 if ( cmd->cmd() == macho_segment_command<P>::CMD ) {
275 const macho_segment_command<P>* segCmd = (const macho_segment_command<P>*)cmd;
276 const macho_section<P>* const sectionsStart = (macho_section<P>*)((char*)segCmd + sizeof(macho_segment_command<P>));
277 const macho_section<P>* const sectionsEnd = &sectionsStart[segCmd->nsects()];
278 for(const macho_section<P>* sect = sectionsStart; sect < sectionsEnd; ++sect) {
279 if ( (strcmp(sect->sectname(), "__unwind_info") == 0) && (strcmp(sect->segname(), "__TEXT") == 0) ) {
280 fUnwindSection = sect;
281 fMachHeaderAddress = segCmd->vmaddr();
282 return fUnwindSection;
283 }
284 }
285 }
286 cmd = (const macho_load_command<P>*)endOfCmd;
287 }
288 return false;
289}
290
55e3d2f6
A
291
292
55e3d2f6
A
293
294template <typename A>
295void UnwindPrinter<A>::printUnwindSection()
296{
297 const uint8_t* sectionContent = (uint8_t*)fHeader + fUnwindSection->offset();
298 macho_unwind_info_section_header<P>* sectionHeader = (macho_unwind_info_section_header<P>*)(sectionContent);
299
300 printf("Arch: %s, Section: __TEXT,__unwind_info (addr=0x%08llX, size=0x%08llX, fileOffset=0x%08X)\n",
301 archName(), fUnwindSection->addr(), fUnwindSection->size(), fUnwindSection->offset());
302 printf("\tversion=0x%08X\n", sectionHeader->version());
303 printf("\tcommonEncodingsArraySectionOffset=0x%08X\n", sectionHeader->commonEncodingsArraySectionOffset());
304 printf("\tcommonEncodingsArrayCount=0x%08X\n", sectionHeader->commonEncodingsArrayCount());
305 printf("\tpersonalityArraySectionOffset=0x%08X\n", sectionHeader->personalityArraySectionOffset());
306 printf("\tpersonalityArrayCount=0x%08X\n", sectionHeader->personalityArrayCount());
307 printf("\tindexSectionOffset=0x%08X\n", sectionHeader->indexSectionOffset());
308 printf("\tindexCount=0x%08X\n", sectionHeader->indexCount());
309 printf("\tcommon encodings: (count=%u)\n", sectionHeader->commonEncodingsArrayCount());
310 const uint32_t* commonEncodings = (uint32_t*)&sectionContent[sectionHeader->commonEncodingsArraySectionOffset()];
311 for (uint32_t i=0; i < sectionHeader->commonEncodingsArrayCount(); ++i) {
4be885f6 312 printf("\t\tencoding[%2u]=0x%08X\n", i, A::P::E::get32(commonEncodings[i]));
55e3d2f6
A
313 }
314 printf("\tpersonalities: (count=%u)\n", sectionHeader->personalityArrayCount());
315 const uint32_t* personalityArray = (uint32_t*)&sectionContent[sectionHeader->personalityArraySectionOffset()];
316 for (uint32_t i=0; i < sectionHeader->personalityArrayCount(); ++i) {
317 printf("\t\t[%2u]=0x%08X\n", i+1, A::P::E::get32(personalityArray[i]));
318 }
319 printf("\tfirst level index: (count=%u)\n", sectionHeader->indexCount());
320 macho_unwind_info_section_header_index_entry<P>* indexes = (macho_unwind_info_section_header_index_entry<P>*)&sectionContent[sectionHeader->indexSectionOffset()];
321 for (uint32_t i=0; i < sectionHeader->indexCount(); ++i) {
322 printf("\t\t[%2u] funcOffset=0x%08X, pageOffset=0x%08X, lsdaOffset=0x%08X\n",
323 i, indexes[i].functionOffset(), indexes[i].secondLevelPagesSectionOffset(), indexes[i].lsdaIndexArraySectionOffset());
324 }
325 uint32_t lsdaIndexArraySectionOffset = indexes[0].lsdaIndexArraySectionOffset();
326 uint32_t lsdaIndexArrayEndSectionOffset = indexes[sectionHeader->indexCount()-1].lsdaIndexArraySectionOffset();
327 uint32_t lsdaIndexArrayCount = (lsdaIndexArrayEndSectionOffset-lsdaIndexArraySectionOffset)/sizeof(macho_unwind_info_section_header_lsda_index_entry<P>);
328 printf("\tLSDA table: (section offset 0x%08X, count=%u)\n", lsdaIndexArraySectionOffset, lsdaIndexArrayCount);
329 macho_unwind_info_section_header_lsda_index_entry<P>* lindex = (macho_unwind_info_section_header_lsda_index_entry<P>*)&sectionContent[lsdaIndexArraySectionOffset];
330 for (uint32_t i=0; i < lsdaIndexArrayCount; ++i) {
331 printf("\t\t[%3u] funcOffset=0x%08X, lsdaOffset=0x%08X, %s\n",
332 i, lindex[i].functionOffset(), lindex[i].lsdaOffset(), functionName(lindex[i].functionOffset()+fMachHeaderAddress));
333 if ( *(((uint8_t*)fHeader) + lindex[i].lsdaOffset()) != 0xFF )
334 fprintf(stderr, "BAD LSDA entry (does not start with 0xFF) for %s\n", functionName(lindex[i].functionOffset()+fMachHeaderAddress));
335 }
336 for (uint32_t i=0; i < sectionHeader->indexCount()-1; ++i) {
337 printf("\tsecond level index[%u] sectionOffset=0x%08X, count=%u, fileOffset=0x%08X\n", i, indexes[i].secondLevelPagesSectionOffset(),
338 sectionHeader->indexCount(), fUnwindSection->offset()+indexes[i].secondLevelPagesSectionOffset());
339 macho_unwind_info_regular_second_level_page_header<P>* page = (macho_unwind_info_regular_second_level_page_header<P>*)&sectionContent[indexes[i].secondLevelPagesSectionOffset()];
340 if ( page->kind() == UNWIND_SECOND_LEVEL_REGULAR ) {
341 printf("\t\tkind=UNWIND_SECOND_LEVEL_REGULAR\n");
342 printf("\t\tentryPageOffset=0x%08X\n", page->entryPageOffset());
343 printf("\t\tentryCount=0x%08X\n", page->entryCount());
344 const macho_unwind_info_regular_second_level_entry<P>* entry = (macho_unwind_info_regular_second_level_entry<P>*)((char*)page+page->entryPageOffset());
345 for (uint32_t j=0; j < page->entryCount(); ++j) {
55e3d2f6
A
346 if ( entry[j].encoding() & UNWIND_HAS_LSDA ) {
347 // verify there is a corresponding entry in lsda table
348 bool found = false;
4be885f6 349 uint32_t funcOffset = entry[j].functionOffset();
55e3d2f6
A
350 for (uint32_t k=0; k < lsdaIndexArrayCount; ++k) {
351 if ( lindex[k].functionOffset() == funcOffset ) {
352 found = true;
353 break;
354 }
355 }
356 if ( !found ) {
357 fprintf(stderr, "MISSING LSDA entry for %s\n", functionName(funcOffset+fMachHeaderAddress));
358 }
359 }
4be885f6
A
360 printf("\t\t\t[%3u] funcOffset=0x%08X, encoding=0x%08X %s\n",
361 j, entry[j].functionOffset(), entry[j].encoding(), functionName(entry[j].functionOffset()+fMachHeaderAddress));
55e3d2f6
A
362 }
363 }
364 else if ( page->kind() == UNWIND_SECOND_LEVEL_COMPRESSED ) {
365 macho_unwind_info_compressed_second_level_page_header<P>* cp = (macho_unwind_info_compressed_second_level_page_header<P>*)page;
366 printf("\t\tkind=UNWIND_SECOND_LEVEL_COMPRESSED\n");
367 printf("\t\tentryPageOffset=0x%08X\n", cp->entryPageOffset());
368 printf("\t\tentryCount=0x%08X\n", cp->entryCount());
369 printf("\t\tencodingsPageOffset=0x%08X\n", cp->encodingsPageOffset());
370 printf("\t\tencodingsCount=0x%08X\n", cp->encodingsCount());
371 const uint32_t* entries = (uint32_t*)(((uint8_t*)page)+cp->entryPageOffset());
372 const uint32_t* encodings = (uint32_t*)(((uint8_t*)page)+cp->encodingsPageOffset());
373 const uint32_t baseFunctionOffset = indexes[i].functionOffset();
374 for (uint32_t j=0; j < cp->entryCount(); ++j) {
375 uint8_t encodingIndex = UNWIND_INFO_COMPRESSED_ENTRY_ENCODING_INDEX(entries[j]);
376 uint32_t encoding;
377 if ( encodingIndex < sectionHeader->commonEncodingsArrayCount() )
378 encoding = A::P::E::get32(commonEncodings[encodingIndex]);
379 else
380 encoding = A::P::E::get32(encodings[encodingIndex-sectionHeader->commonEncodingsArrayCount()]);
55e3d2f6 381 uint32_t funcOff = UNWIND_INFO_COMPRESSED_ENTRY_FUNC_OFFSET(entries[j])+baseFunctionOffset;
55e3d2f6
A
382 const char* name = functionName(funcOff+fMachHeaderAddress);
383 if ( encoding & UNWIND_HAS_LSDA ) {
384 // verify there is a corresponding entry in lsda table
385 bool found = false;
386 for (uint32_t k=0; k < lsdaIndexArrayCount; ++k) {
387 if ( lindex[k].functionOffset() == funcOff ) {
388 found = true;
389 break;
390 }
391 }
392 if ( !found ) {
393 fprintf(stderr, "MISSING LSDA entry for %s\n", name);
394 }
395 }
4be885f6
A
396 printf("\t\t\t[%3u] funcOffset=0x%08X, encoding[%2u]=0x%08X %s\n",
397 j, funcOff, encodingIndex, encoding, name);
55e3d2f6
A
398 }
399 }
400 else {
401 fprintf(stderr, "\t\tbad page header\n");
402 }
403 }
404
405}
406
407static void dump(const char* path, const std::set<cpu_type_t>& onlyArchs)
408{
409 struct stat stat_buf;
410
411 try {
412 int fd = ::open(path, O_RDONLY, 0);
413 if ( fd == -1 )
414 throw "cannot open file";
415 if ( ::fstat(fd, &stat_buf) != 0 )
416 throwf("fstat(%s) failed, errno=%d\n", path, errno);
417 uint32_t length = stat_buf.st_size;
418 uint8_t* p = (uint8_t*)::mmap(NULL, stat_buf.st_size, PROT_READ, MAP_FILE | MAP_PRIVATE, fd, 0);
419 if ( p == ((uint8_t*)(-1)) )
420 throw "cannot map file";
421 ::close(fd);
422 const mach_header* mh = (mach_header*)p;
423 if ( mh->magic == OSSwapBigToHostInt32(FAT_MAGIC) ) {
424 const struct fat_header* fh = (struct fat_header*)p;
425 const struct fat_arch* archs = (struct fat_arch*)(p + sizeof(struct fat_header));
426 for (unsigned long i=0; i < OSSwapBigToHostInt32(fh->nfat_arch); ++i) {
427 size_t offset = OSSwapBigToHostInt32(archs[i].offset);
428 size_t size = OSSwapBigToHostInt32(archs[i].size);
429 unsigned int cputype = OSSwapBigToHostInt32(archs[i].cputype);
430 if ( onlyArchs.count(cputype) ) {
431 switch(cputype) {
432 case CPU_TYPE_POWERPC:
433 if ( UnwindPrinter<ppc>::validFile(p + offset) )
434 UnwindPrinter<ppc>::make(p + offset, size, path);
435 else
436 throw "in universal file, ppc slice does not contain ppc mach-o";
437 break;
438 case CPU_TYPE_I386:
439 if ( UnwindPrinter<x86>::validFile(p + offset) )
440 UnwindPrinter<x86>::make(p + offset, size, path);
441 else
442 throw "in universal file, i386 slice does not contain i386 mach-o";
443 break;
444 case CPU_TYPE_POWERPC64:
445 if ( UnwindPrinter<ppc64>::validFile(p + offset) )
446 UnwindPrinter<ppc64>::make(p + offset, size, path);
447 else
448 throw "in universal file, ppc64 slice does not contain ppc64 mach-o";
449 break;
450 case CPU_TYPE_X86_64:
451 if ( UnwindPrinter<x86_64>::validFile(p + offset) )
452 UnwindPrinter<x86_64>::make(p + offset, size, path);
453 else
454 throw "in universal file, x86_64 slice does not contain x86_64 mach-o";
455 break;
456 case CPU_TYPE_ARM:
457 if ( UnwindPrinter<arm>::validFile(p + offset) )
458 UnwindPrinter<arm>::make(p + offset, size, path);
459 else
460 throw "in universal file, arm slice does not contain arm mach-o";
461 break;
462 default:
463 throwf("in universal file, unknown architecture slice 0x%x\n", cputype);
464 }
465 }
466 }
467 }
468 else if ( UnwindPrinter<x86>::validFile(p) && onlyArchs.count(CPU_TYPE_I386) ) {
469 UnwindPrinter<x86>::make(p, length, path);
470 }
471 else if ( UnwindPrinter<ppc>::validFile(p) && onlyArchs.count(CPU_TYPE_POWERPC) ) {
472 UnwindPrinter<ppc>::make(p, length, path);
473 }
474 else if ( UnwindPrinter<ppc64>::validFile(p) && onlyArchs.count(CPU_TYPE_POWERPC64) ) {
475 UnwindPrinter<ppc64>::make(p, length, path);
476 }
477 else if ( UnwindPrinter<x86_64>::validFile(p) && onlyArchs.count(CPU_TYPE_X86_64) ) {
478 UnwindPrinter<x86_64>::make(p, length, path);
479 }
480 else if ( UnwindPrinter<arm>::validFile(p) && onlyArchs.count(CPU_TYPE_ARM) ) {
481 UnwindPrinter<arm>::make(p, length, path);
482 }
483 else {
484 throw "not a known file type";
485 }
486 }
487 catch (const char* msg) {
488 throwf("%s in %s", msg, path);
489 }
490}
491
492
493int main(int argc, const char* argv[])
494{
495 std::set<cpu_type_t> onlyArchs;
496 std::vector<const char*> files;
497
498 try {
499 for(int i=1; i < argc; ++i) {
500 const char* arg = argv[i];
501 if ( arg[0] == '-' ) {
502 if ( strcmp(arg, "-arch") == 0 ) {
503 const char* arch = argv[++i];
504 if ( strcmp(arch, "ppc") == 0 )
505 onlyArchs.insert(CPU_TYPE_POWERPC);
506 else if ( strcmp(arch, "ppc64") == 0 )
507 onlyArchs.insert(CPU_TYPE_POWERPC64);
508 else if ( strcmp(arch, "i386") == 0 )
509 onlyArchs.insert(CPU_TYPE_I386);
510 else if ( strcmp(arch, "x86_64") == 0 )
511 onlyArchs.insert(CPU_TYPE_X86_64);
512 else if ( strcmp(arch, "arm") == 0 )
513 onlyArchs.insert(CPU_TYPE_ARM);
514 else
515 throwf("unknown architecture %s", arch);
516 }
517 else {
518 throwf("unknown option: %s\n", arg);
519 }
520 }
521 else {
522 files.push_back(arg);
523 }
524 }
525
526 // use all architectures if no restrictions specified
527 if ( onlyArchs.size() == 0 ) {
528 onlyArchs.insert(CPU_TYPE_POWERPC);
529 onlyArchs.insert(CPU_TYPE_POWERPC64);
530 onlyArchs.insert(CPU_TYPE_I386);
531 onlyArchs.insert(CPU_TYPE_X86_64);
532 onlyArchs.insert(CPU_TYPE_ARM);
533 }
534
535 // process each file
536 for(std::vector<const char*>::iterator it=files.begin(); it != files.end(); ++it) {
537 dump(*it, onlyArchs);
538 }
539
540 }
541 catch (const char* msg) {
542 fprintf(stderr, "UnwindDump failed: %s\n", msg);
543 return 1;
544 }
545
546 return 0;
547}
548
549
550