]> git.saurik.com Git - apple/ld64.git/blame - src/other/unwinddump.cpp
ld64-241.9.tar.gz
[apple/ld64.git] / src / other / unwinddump.cpp
CommitLineData
55e3d2f6
A
1/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
2 *
afe874b1 3 * Copyright (c) 2008-2011 Apple Inc. All rights reserved.
55e3d2f6
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 */
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>
d425e388 36#include <unordered_set>
55e3d2f6 37
f80fe69f 38#include "configure.h"
55e3d2f6
A
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);
a645023d
A
62 static UnwindPrinter<A>* make(const uint8_t* fileContent, uint32_t fileLength,
63 const char* path, bool showFunctionNames)
64 { return new UnwindPrinter<A>(fileContent, fileLength,
65 path, showFunctionNames); }
55e3d2f6
A
66 virtual ~UnwindPrinter() {}
67
68
69private:
70 typedef typename A::P P;
71 typedef typename A::P::E E;
72 typedef typename A::P::uint_t pint_t;
73
a645023d
A
74 UnwindPrinter(const uint8_t* fileContent, uint32_t fileLength,
75 const char* path, bool showFunctionNames);
55e3d2f6 76 bool findUnwindSection();
a645023d 77 void printUnwindSection(bool showFunctionNames);
afe874b1 78 void printObjectUnwindSection(bool showFunctionNames);
55e3d2f6 79 void getSymbolTableInfo();
afe874b1
A
80 const char* functionName(pint_t addr, uint32_t* offset=NULL);
81 const char* personalityName(const macho_relocation_info<typename A::P>* reloc);
82 bool hasExernReloc(uint64_t sectionOffset, const char** personalityStr, pint_t* addr=NULL);
83
55e3d2f6 84 static const char* archName();
fb24a050 85 static void decode(uint32_t encoding, const uint8_t* funcStart, char* str);
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
55e3d2f6
A
99template <> const char* UnwindPrinter<x86>::archName() { return "i386"; }
100template <> const char* UnwindPrinter<x86_64>::archName() { return "x86_64"; }
101template <> const char* UnwindPrinter<arm>::archName() { return "arm"; }
f80fe69f
A
102#if SUPPORT_ARCH_arm64
103template <> const char* UnwindPrinter<arm64>::archName() { return "arm64"; }
104#endif
55e3d2f6
A
105
106template <>
107bool UnwindPrinter<x86>::validFile(const uint8_t* fileContent)
108{
109 const macho_header<P>* header = (const macho_header<P>*)fileContent;
110 if ( header->magic() != MH_MAGIC )
111 return false;
112 if ( header->cputype() != CPU_TYPE_I386 )
113 return false;
114 switch (header->filetype()) {
115 case MH_EXECUTE:
116 case MH_DYLIB:
117 case MH_BUNDLE:
118 case MH_DYLINKER:
afe874b1 119 case MH_OBJECT:
55e3d2f6
A
120 return true;
121 }
122 return false;
123}
124
125template <>
126bool UnwindPrinter<x86_64>::validFile(const uint8_t* fileContent)
127{
128 const macho_header<P>* header = (const macho_header<P>*)fileContent;
129 if ( header->magic() != MH_MAGIC_64 )
130 return false;
131 if ( header->cputype() != CPU_TYPE_X86_64 )
132 return false;
133 switch (header->filetype()) {
134 case MH_EXECUTE:
135 case MH_DYLIB:
136 case MH_BUNDLE:
137 case MH_DYLINKER:
afe874b1 138 case MH_OBJECT:
55e3d2f6
A
139 return true;
140 }
141 return false;
142}
143
144
f80fe69f
A
145#if SUPPORT_ARCH_arm64
146template <>
147bool UnwindPrinter<arm64>::validFile(const uint8_t* fileContent)
148{
149 const macho_header<P>* header = (const macho_header<P>*)fileContent;
150 if ( header->magic() != MH_MAGIC_64 )
151 return false;
152 if ( header->cputype() != CPU_TYPE_ARM64 )
153 return false;
154 switch (header->filetype()) {
155 case MH_EXECUTE:
156 case MH_DYLIB:
157 case MH_BUNDLE:
158 case MH_DYLINKER:
159 case MH_OBJECT:
160 return true;
161 }
162 return false;
163}
164#endif
165
55e3d2f6 166template <typename A>
a645023d 167UnwindPrinter<A>::UnwindPrinter(const uint8_t* fileContent, uint32_t fileLength, const char* path, bool showFunctionNames)
55e3d2f6
A
168 : fHeader(NULL), fLength(fileLength), fUnwindSection(NULL),
169 fStrings(NULL), fStringsEnd(NULL), fSymbols(NULL), fSymbolCount(0), fMachHeaderAddress(0)
170{
171 // sanity check
172 if ( ! validFile(fileContent) )
173 throw "not a mach-o file that can be checked";
174
175 fPath = strdup(path);
176 fHeader = (const macho_header<P>*)fileContent;
177
178 getSymbolTableInfo();
179
afe874b1
A
180 if ( findUnwindSection() ) {
181 if ( fHeader->filetype() == MH_OBJECT )
182 printObjectUnwindSection(showFunctionNames);
183 else
184 printUnwindSection(showFunctionNames);
185 }
55e3d2f6
A
186}
187
188
189template <typename A>
190void UnwindPrinter<A>::getSymbolTableInfo()
191{
192 const uint8_t* const endOfFile = (uint8_t*)fHeader + fLength;
193 const uint8_t* const endOfLoadCommands = (uint8_t*)fHeader + sizeof(macho_header<P>) + fHeader->sizeofcmds();
194 const uint32_t cmd_count = fHeader->ncmds();
195 const macho_load_command<P>* const cmds = (macho_load_command<P>*)((uint8_t*)fHeader + sizeof(macho_header<P>));
196 const macho_load_command<P>* cmd = cmds;
197 for (uint32_t i = 0; i < cmd_count; ++i) {
198 uint32_t size = cmd->cmdsize();
199 const uint8_t* endOfCmd = ((uint8_t*)cmd)+cmd->cmdsize();
200 if ( endOfCmd > endOfLoadCommands )
201 throwf("load command #%d extends beyond the end of the load commands", i);
202 if ( endOfCmd > endOfFile )
203 throwf("load command #%d extends beyond the end of the file", i);
204 if ( cmd->cmd() == LC_SYMTAB) {
205 const macho_symtab_command<P>* symtab = (macho_symtab_command<P>*)cmd;
206 fSymbolCount = symtab->nsyms();
207 fSymbols = (const macho_nlist<P>*)((char*)fHeader + symtab->symoff());
208 fStrings = (char*)fHeader + symtab->stroff();
209 fStringsEnd = fStrings + symtab->strsize();
210 }
211 cmd = (const macho_load_command<P>*)endOfCmd;
212 }
213}
214
215template <typename A>
afe874b1 216const char* UnwindPrinter<A>::functionName(pint_t addr, uint32_t* offset)
55e3d2f6 217{
afe874b1
A
218 const macho_nlist<P>* closestSymbol = NULL;
219 if ( offset != NULL )
220 *offset = 0;
55e3d2f6
A
221 for (uint32_t i=0; i < fSymbolCount; ++i) {
222 uint8_t type = fSymbols[i].n_type();
223 if ( ((type & N_STAB) == 0) && ((type & N_TYPE) == N_SECT) ) {
599556ff
A
224 uint32_t value = fSymbols[i].n_value();
225 if ( value == addr ) {
226 const char* r = &fStrings[fSymbols[i].n_strx()];
227 return r;
228 }
229 if ( fSymbols[i].n_desc() & N_ARM_THUMB_DEF )
230 value |= 1;
231 if ( value == addr ) {
55e3d2f6
A
232 const char* r = &fStrings[fSymbols[i].n_strx()];
233 //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);
234 return r;
235 }
afe874b1
A
236 else if ( offset != NULL ) {
237 if ( closestSymbol == NULL ) {
238 if ( fSymbols[i].n_value() < addr )
239 closestSymbol = &fSymbols[i];
240 }
241 else {
242 if ( (fSymbols[i].n_value() < addr) && (fSymbols[i].n_value() > closestSymbol->n_value()) )
243 closestSymbol = &fSymbols[i];
244 }
245 }
55e3d2f6
A
246 }
247 }
afe874b1
A
248 if ( closestSymbol != NULL ) {
249 *offset = addr - closestSymbol->n_value();
250 return &fStrings[closestSymbol->n_strx()];
251 }
fb24a050 252 return "--anonymous function--";
55e3d2f6
A
253}
254
255
256
257template <typename A>
258bool UnwindPrinter<A>::findUnwindSection()
259{
afe874b1
A
260 const char* unwindSectionName = "__unwind_info";
261 const char* unwindSegmentName = "__TEXT";
262 if ( fHeader->filetype() == MH_OBJECT ) {
263 unwindSectionName = "__compact_unwind";
264 unwindSegmentName = "__LD";
265 }
55e3d2f6
A
266 const uint8_t* const endOfFile = (uint8_t*)fHeader + fLength;
267 const uint8_t* const endOfLoadCommands = (uint8_t*)fHeader + sizeof(macho_header<P>) + fHeader->sizeofcmds();
268 const uint32_t cmd_count = fHeader->ncmds();
269 const macho_load_command<P>* const cmds = (macho_load_command<P>*)((uint8_t*)fHeader + sizeof(macho_header<P>));
270 const macho_load_command<P>* cmd = cmds;
271 for (uint32_t i = 0; i < cmd_count; ++i) {
272 uint32_t size = cmd->cmdsize();
273 const uint8_t* endOfCmd = ((uint8_t*)cmd)+cmd->cmdsize();
274 if ( endOfCmd > endOfLoadCommands )
275 throwf("load command #%d extends beyond the end of the load commands", i);
276 if ( endOfCmd > endOfFile )
277 throwf("load command #%d extends beyond the end of the file", i);
278 if ( cmd->cmd() == macho_segment_command<P>::CMD ) {
279 const macho_segment_command<P>* segCmd = (const macho_segment_command<P>*)cmd;
280 const macho_section<P>* const sectionsStart = (macho_section<P>*)((char*)segCmd + sizeof(macho_segment_command<P>));
281 const macho_section<P>* const sectionsEnd = &sectionsStart[segCmd->nsects()];
282 for(const macho_section<P>* sect = sectionsStart; sect < sectionsEnd; ++sect) {
afe874b1 283 if ( (strncmp(sect->sectname(), unwindSectionName, 16) == 0) && (strcmp(sect->segname(), unwindSegmentName) == 0) ) {
55e3d2f6
A
284 fUnwindSection = sect;
285 fMachHeaderAddress = segCmd->vmaddr();
286 return fUnwindSection;
287 }
288 }
289 }
290 cmd = (const macho_load_command<P>*)endOfCmd;
291 }
292 return false;
293}
294
fb24a050
A
295#define EXTRACT_BITS(value, mask) \
296 ( (value >> __builtin_ctz(mask)) & (((1 << __builtin_popcount(mask)))-1) )
55e3d2f6
A
297
298
fb24a050
A
299template <>
300void UnwindPrinter<x86_64>::decode(uint32_t encoding, const uint8_t* funcStart, char* str)
301{
302 *str = '\0';
303 switch ( encoding & UNWIND_X86_64_MODE_MASK ) {
304 case UNWIND_X86_64_MODE_RBP_FRAME:
305 {
306 uint32_t savedRegistersOffset = EXTRACT_BITS(encoding, UNWIND_X86_64_RBP_FRAME_OFFSET);
307 uint32_t savedRegistersLocations = EXTRACT_BITS(encoding, UNWIND_X86_64_RBP_FRAME_REGISTERS);
308 if ( savedRegistersLocations == 0 ) {
309 strcpy(str, "rbp frame, no saved registers");
310 }
311 else {
312 sprintf(str, "rbp frame, at -%d:", savedRegistersOffset*8);
313 bool needComma = false;
314 for (int i=0; i < 5; ++i) {
315 if ( needComma )
316 strcat(str, ",");
317 else
318 needComma = true;
319 switch (savedRegistersLocations & 0x7) {
320 case UNWIND_X86_64_REG_NONE:
321 strcat(str, "-");
322 break;
323 case UNWIND_X86_64_REG_RBX:
324 strcat(str, "rbx");
325 break;
326 case UNWIND_X86_64_REG_R12:
327 strcat(str, "r12");
328 break;
329 case UNWIND_X86_64_REG_R13:
330 strcat(str, "r13");
331 break;
332 case UNWIND_X86_64_REG_R14:
333 strcat(str, "r14");
334 break;
335 case UNWIND_X86_64_REG_R15:
336 strcat(str, "r15");
337 break;
338 default:
339 strcat(str, "r?");
340 }
341 savedRegistersLocations = (savedRegistersLocations >> 3);
342 if ( savedRegistersLocations == 0 )
343 break;
344 }
345 }
346 }
347 break;
348 case UNWIND_X86_64_MODE_STACK_IMMD:
349 case UNWIND_X86_64_MODE_STACK_IND:
350 {
351 uint32_t stackSize = EXTRACT_BITS(encoding, UNWIND_X86_64_FRAMELESS_STACK_SIZE);
352 uint32_t stackAdjust = EXTRACT_BITS(encoding, UNWIND_X86_64_FRAMELESS_STACK_ADJUST);
353 uint32_t regCount = EXTRACT_BITS(encoding, UNWIND_X86_64_FRAMELESS_STACK_REG_COUNT);
354 uint32_t permutation = EXTRACT_BITS(encoding, UNWIND_X86_64_FRAMELESS_STACK_REG_PERMUTATION);
355 if ( (encoding & UNWIND_X86_64_MODE_MASK) == UNWIND_X86_64_MODE_STACK_IND ) {
356 // stack size is encoded in subl $xxx,%esp instruction
357 uint32_t subl = x86_64::P::E::get32(*((uint32_t*)(funcStart+stackSize)));
358 sprintf(str, "stack size=0x%08X, ", subl + 8*stackAdjust);
359 }
360 else {
361 sprintf(str, "stack size=%d, ", stackSize*8);
362 }
363 if ( regCount == 0 ) {
364 strcat(str, "no registers saved");
365 }
366 else {
367 int permunreg[6];
368 switch ( regCount ) {
369 case 6:
370 permunreg[0] = permutation/120;
371 permutation -= (permunreg[0]*120);
372 permunreg[1] = permutation/24;
373 permutation -= (permunreg[1]*24);
374 permunreg[2] = permutation/6;
375 permutation -= (permunreg[2]*6);
376 permunreg[3] = permutation/2;
377 permutation -= (permunreg[3]*2);
378 permunreg[4] = permutation;
379 permunreg[5] = 0;
380 break;
381 case 5:
382 permunreg[0] = permutation/120;
383 permutation -= (permunreg[0]*120);
384 permunreg[1] = permutation/24;
385 permutation -= (permunreg[1]*24);
386 permunreg[2] = permutation/6;
387 permutation -= (permunreg[2]*6);
388 permunreg[3] = permutation/2;
389 permutation -= (permunreg[3]*2);
390 permunreg[4] = permutation;
391 break;
392 case 4:
393 permunreg[0] = permutation/60;
394 permutation -= (permunreg[0]*60);
395 permunreg[1] = permutation/12;
396 permutation -= (permunreg[1]*12);
397 permunreg[2] = permutation/3;
398 permutation -= (permunreg[2]*3);
399 permunreg[3] = permutation;
400 break;
401 case 3:
402 permunreg[0] = permutation/20;
403 permutation -= (permunreg[0]*20);
404 permunreg[1] = permutation/4;
405 permutation -= (permunreg[1]*4);
406 permunreg[2] = permutation;
407 break;
408 case 2:
409 permunreg[0] = permutation/5;
410 permutation -= (permunreg[0]*5);
411 permunreg[1] = permutation;
412 break;
413 case 1:
414 permunreg[0] = permutation;
415 break;
416 }
417 // renumber registers back to standard numbers
418 int registers[6];
419 bool used[7] = { false, false, false, false, false, false, false };
420 for (int i=0; i < regCount; ++i) {
421 int renum = 0;
422 for (int u=1; u < 7; ++u) {
423 if ( !used[u] ) {
424 if ( renum == permunreg[i] ) {
425 registers[i] = u;
426 used[u] = true;
427 break;
428 }
429 ++renum;
430 }
431 }
432 }
433 bool needComma = false;
434 for (int i=0; i < regCount; ++i) {
435 if ( needComma )
436 strcat(str, ",");
437 else
438 needComma = true;
439 switch ( registers[i] ) {
440 case UNWIND_X86_64_REG_RBX:
441 strcat(str, "rbx");
442 break;
443 case UNWIND_X86_64_REG_R12:
444 strcat(str, "r12");
445 break;
446 case UNWIND_X86_64_REG_R13:
447 strcat(str, "r13");
448 break;
449 case UNWIND_X86_64_REG_R14:
450 strcat(str, "r14");
451 break;
452 case UNWIND_X86_64_REG_R15:
453 strcat(str, "r15");
454 break;
455 case UNWIND_X86_64_REG_RBP:
456 strcat(str, "rbp");
457 break;
458 default:
459 strcat(str, "r??");
460 }
461 }
462 }
463 }
464 break;
465 case UNWIND_X86_64_MODE_DWARF:
466 sprintf(str, "dwarf offset 0x%08X, ", encoding & UNWIND_X86_64_DWARF_SECTION_OFFSET);
467 break;
468 default:
469 if ( encoding == 0 )
470 strcat(str, "no unwind information");
471 else
472 strcat(str, "tbd ");
473 }
474 if ( encoding & UNWIND_HAS_LSDA ) {
475 strcat(str, " LSDA");
476 }
477
478}
479
480template <>
481void UnwindPrinter<x86>::decode(uint32_t encoding, const uint8_t* funcStart, char* str)
482{
483 *str = '\0';
484 switch ( encoding & UNWIND_X86_MODE_MASK ) {
485 case UNWIND_X86_MODE_EBP_FRAME:
486 {
487 uint32_t savedRegistersOffset = EXTRACT_BITS(encoding, UNWIND_X86_EBP_FRAME_OFFSET);
488 uint32_t savedRegistersLocations = EXTRACT_BITS(encoding, UNWIND_X86_EBP_FRAME_REGISTERS);
489 if ( savedRegistersLocations == 0 ) {
490 strcpy(str, "ebp frame, no saved registers");
491 }
492 else {
493 sprintf(str, "ebp frame, at -%d:", savedRegistersOffset*4);
494 bool needComma = false;
495 for (int i=0; i < 5; ++i) {
496 if ( needComma )
497 strcat(str, ",");
498 else
499 needComma = true;
500 switch (savedRegistersLocations & 0x7) {
501 case UNWIND_X86_REG_NONE:
502 strcat(str, "-");
503 break;
504 case UNWIND_X86_REG_EBX:
505 strcat(str, "ebx");
506 break;
507 case UNWIND_X86_REG_ECX:
508 strcat(str, "ecx");
509 break;
510 case UNWIND_X86_REG_EDX:
511 strcat(str, "edx");
512 break;
513 case UNWIND_X86_REG_EDI:
514 strcat(str, "edi");
515 break;
516 case UNWIND_X86_REG_ESI:
517 strcat(str, "esi");
518 break;
519 default:
520 strcat(str, "e??");
521 }
522 savedRegistersLocations = (savedRegistersLocations >> 3);
523 if ( savedRegistersLocations == 0 )
524 break;
525 }
526 }
527 }
528 break;
529 case UNWIND_X86_MODE_STACK_IMMD:
530 case UNWIND_X86_MODE_STACK_IND:
531 {
532 uint32_t stackSize = EXTRACT_BITS(encoding, UNWIND_X86_FRAMELESS_STACK_SIZE);
533 uint32_t stackAdjust = EXTRACT_BITS(encoding, UNWIND_X86_FRAMELESS_STACK_ADJUST);
534 uint32_t regCount = EXTRACT_BITS(encoding, UNWIND_X86_FRAMELESS_STACK_REG_COUNT);
535 uint32_t permutation = EXTRACT_BITS(encoding, UNWIND_X86_FRAMELESS_STACK_REG_PERMUTATION);
536 if ( (encoding & UNWIND_X86_MODE_MASK) == UNWIND_X86_MODE_STACK_IND ) {
537 // stack size is encoded in subl $xxx,%esp instruction
538 uint32_t subl = x86::P::E::get32(*((uint32_t*)(funcStart+stackSize)));
539 sprintf(str, "stack size=0x%08X, ", subl+4*stackAdjust);
540 }
541 else {
542 sprintf(str, "stack size=%d, ", stackSize*4);
543 }
544 if ( regCount == 0 ) {
545 strcat(str, "no saved regs");
546 }
547 else {
548 int permunreg[6];
549 switch ( regCount ) {
550 case 6:
551 permunreg[0] = permutation/120;
552 permutation -= (permunreg[0]*120);
553 permunreg[1] = permutation/24;
554 permutation -= (permunreg[1]*24);
555 permunreg[2] = permutation/6;
556 permutation -= (permunreg[2]*6);
557 permunreg[3] = permutation/2;
558 permutation -= (permunreg[3]*2);
559 permunreg[4] = permutation;
560 permunreg[5] = 0;
561 break;
562 case 5:
563 permunreg[0] = permutation/120;
564 permutation -= (permunreg[0]*120);
565 permunreg[1] = permutation/24;
566 permutation -= (permunreg[1]*24);
567 permunreg[2] = permutation/6;
568 permutation -= (permunreg[2]*6);
569 permunreg[3] = permutation/2;
570 permutation -= (permunreg[3]*2);
571 permunreg[4] = permutation;
572 break;
573 case 4:
574 permunreg[0] = permutation/60;
575 permutation -= (permunreg[0]*60);
576 permunreg[1] = permutation/12;
577 permutation -= (permunreg[1]*12);
578 permunreg[2] = permutation/3;
579 permutation -= (permunreg[2]*3);
580 permunreg[3] = permutation;
581 break;
582 case 3:
583 permunreg[0] = permutation/20;
584 permutation -= (permunreg[0]*20);
585 permunreg[1] = permutation/4;
586 permutation -= (permunreg[1]*4);
587 permunreg[2] = permutation;
588 break;
589 case 2:
590 permunreg[0] = permutation/5;
591 permutation -= (permunreg[0]*5);
592 permunreg[1] = permutation;
593 break;
594 case 1:
595 permunreg[0] = permutation;
596 break;
597 }
598 // renumber registers back to standard numbers
599 int registers[6];
600 bool used[7] = { false, false, false, false, false, false, false };
601 for (int i=0; i < regCount; ++i) {
602 int renum = 0;
603 for (int u=1; u < 7; ++u) {
604 if ( !used[u] ) {
605 if ( renum == permunreg[i] ) {
606 registers[i] = u;
607 used[u] = true;
608 break;
609 }
610 ++renum;
611 }
612 }
613 }
614 bool needComma = false;
615 for (int i=0; i < regCount; ++i) {
616 if ( needComma )
617 strcat(str, ",");
618 else
619 needComma = true;
620 switch ( registers[i] ) {
621 case UNWIND_X86_REG_EBX:
622 strcat(str, "ebx");
623 break;
624 case UNWIND_X86_REG_ECX:
625 strcat(str, "ecx");
626 break;
627 case UNWIND_X86_REG_EDX:
628 strcat(str, "edx");
629 break;
630 case UNWIND_X86_REG_EDI:
631 strcat(str, "edi");
632 break;
633 case UNWIND_X86_REG_ESI:
634 strcat(str, "esi");
635 break;
636 case UNWIND_X86_REG_EBP:
637 strcat(str, "ebp");
638 break;
639 default:
640 strcat(str, "e??");
641 }
642 }
643 }
644 }
645 break;
646 case UNWIND_X86_MODE_DWARF:
647 sprintf(str, "dwarf offset 0x%08X, ", encoding & UNWIND_X86_DWARF_SECTION_OFFSET);
648 break;
649 default:
650 if ( encoding == 0 )
651 strcat(str, "no unwind information");
652 else
653 strcat(str, "tbd ");
654 }
655 if ( encoding & UNWIND_HAS_LSDA ) {
656 strcat(str, " LSDA");
657 }
658
659}
660
f80fe69f
A
661#if SUPPORT_ARCH_arm64
662template <>
663void UnwindPrinter<arm64>::decode(uint32_t encoding, const uint8_t* funcStart, char* str)
664{
665 uint32_t stackSize;
666 switch ( encoding & UNWIND_ARM64_MODE_MASK ) {
667 case UNWIND_ARM64_MODE_FRAMELESS:
668 stackSize = EXTRACT_BITS(encoding, UNWIND_ARM64_FRAMELESS_STACK_SIZE_MASK);
669 if ( stackSize == 0 )
670 strcpy(str, "no frame, no saved registers ");
671 else
672 sprintf(str, "stack size=%d: ", 16 * stackSize);
673 if ( encoding & UNWIND_ARM64_FRAME_X19_X20_PAIR )
674 strcat(str, "x19/20 ");
675 if ( encoding & UNWIND_ARM64_FRAME_X21_X22_PAIR )
676 strcat(str, "x21/22 ");
677 if ( encoding & UNWIND_ARM64_FRAME_X23_X24_PAIR )
678 strcat(str, "x23/24 ");
679 if ( encoding & UNWIND_ARM64_FRAME_X25_X26_PAIR )
680 strcat(str, "x25/26 ");
681 if ( encoding & UNWIND_ARM64_FRAME_X27_X28_PAIR )
682 strcat(str, "x27/28 ");
683 if ( encoding & UNWIND_ARM64_FRAME_D8_D9_PAIR )
684 strcat(str, "d8/9 ");
685 if ( encoding & UNWIND_ARM64_FRAME_D10_D11_PAIR )
686 strcat(str, "d10/11 ");
687 if ( encoding & UNWIND_ARM64_FRAME_D12_D13_PAIR )
688 strcat(str, "d12/13 ");
689 if ( encoding & UNWIND_ARM64_FRAME_D14_D15_PAIR )
690 strcat(str, "d14/15 ");
691 break;
692 break;
693 case UNWIND_ARM64_MODE_DWARF:
694 sprintf(str, "dwarf offset 0x%08X, ", encoding & UNWIND_X86_64_DWARF_SECTION_OFFSET);
695 break;
696 case UNWIND_ARM64_MODE_FRAME:
697 strcpy(str, "std frame: ");
698 if ( encoding & UNWIND_ARM64_FRAME_X19_X20_PAIR )
699 strcat(str, "x19/20 ");
700 if ( encoding & UNWIND_ARM64_FRAME_X21_X22_PAIR )
701 strcat(str, "x21/22 ");
702 if ( encoding & UNWIND_ARM64_FRAME_X23_X24_PAIR )
703 strcat(str, "x23/24 ");
704 if ( encoding & UNWIND_ARM64_FRAME_X25_X26_PAIR )
705 strcat(str, "x25/26 ");
706 if ( encoding & UNWIND_ARM64_FRAME_X27_X28_PAIR )
707 strcat(str, "x27/28 ");
708 if ( encoding & UNWIND_ARM64_FRAME_D8_D9_PAIR )
709 strcat(str, "d8/9 ");
710 if ( encoding & UNWIND_ARM64_FRAME_D10_D11_PAIR )
711 strcat(str, "d10/11 ");
712 if ( encoding & UNWIND_ARM64_FRAME_D12_D13_PAIR )
713 strcat(str, "d12/13 ");
714 if ( encoding & UNWIND_ARM64_FRAME_D14_D15_PAIR )
715 strcat(str, "d14/15 ");
716 break;
717 case UNWIND_ARM64_MODE_FRAME_OLD:
718 strcpy(str, "old frame: ");
719 if ( encoding & UNWIND_ARM64_FRAME_X21_X22_PAIR_OLD )
720 strcat(str, "x21/22 ");
721 if ( encoding & UNWIND_ARM64_FRAME_X23_X24_PAIR_OLD )
722 strcat(str, "x23/24 ");
723 if ( encoding & UNWIND_ARM64_FRAME_X25_X26_PAIR_OLD )
724 strcat(str, "x25/26 ");
725 if ( encoding & UNWIND_ARM64_FRAME_X27_X28_PAIR_OLD )
726 strcat(str, "x27/28 ");
727 if ( encoding & UNWIND_ARM64_FRAME_D8_D9_PAIR_OLD )
728 strcat(str, "d8/9 ");
729 if ( encoding & UNWIND_ARM64_FRAME_D10_D11_PAIR_OLD )
730 strcat(str, "d10/11 ");
731 if ( encoding & UNWIND_ARM64_FRAME_D12_D13_PAIR_OLD )
732 strcat(str, "d12/13 ");
733 if ( encoding & UNWIND_ARM64_FRAME_D14_D15_PAIR_OLD )
734 strcat(str, "d14/15 ");
735 break;
736 }
737}
738#endif
afe874b1 739
599556ff
A
740
741
afe874b1
A
742template <>
743const char* UnwindPrinter<x86_64>::personalityName(const macho_relocation_info<x86_64::P>* reloc)
744{
745 //assert(reloc->r_extern() && "reloc not extern on personality column in __compact_unwind section");
746 //assert((reloc->r_type() == X86_64_RELOC_UNSIGNED) && "wrong reloc type on personality column in __compact_unwind section");
747 const macho_nlist<P>& sym = fSymbols[reloc->r_symbolnum()];
748 return &fStrings[sym.n_strx()];
749}
750
751template <>
752const char* UnwindPrinter<x86>::personalityName(const macho_relocation_info<x86::P>* reloc)
753{
754 //assert(reloc->r_extern() && "reloc not extern on personality column in __compact_unwind section");
755 //assert((reloc->r_type() == GENERIC_RELOC_VANILLA) && "wrong reloc type on personality column in __compact_unwind section");
756 const macho_nlist<P>& sym = fSymbols[reloc->r_symbolnum()];
757 return &fStrings[sym.n_strx()];
758}
759
f80fe69f
A
760#if SUPPORT_ARCH_arm64
761template <>
762const char* UnwindPrinter<arm64>::personalityName(const macho_relocation_info<arm64::P>* reloc)
763{
764 //assert(reloc->r_extern() && "reloc not extern on personality column in __compact_unwind section");
765 //assert((reloc->r_type() == ARM64_RELOC_UNSIGNED) && "wrong reloc type on personality column in __compact_unwind section");
766 const macho_nlist<P>& sym = fSymbols[reloc->r_symbolnum()];
767 return &fStrings[sym.n_strx()];
768}
769#endif
770
599556ff 771
fb24a050 772template <typename A>
afe874b1 773bool UnwindPrinter<A>::hasExernReloc(uint64_t sectionOffset, const char** personalityStr, pint_t* addr)
fb24a050 774{
afe874b1
A
775 const macho_relocation_info<P>* relocs = (macho_relocation_info<P>*)((uint8_t*)fHeader + fUnwindSection->reloff());
776 const macho_relocation_info<P>* relocsEnd = &relocs[fUnwindSection->nreloc()];
777 for (const macho_relocation_info<P>* reloc = relocs; reloc < relocsEnd; ++reloc) {
778 if ( reloc->r_extern() && (reloc->r_address() == sectionOffset) ) {
779 *personalityStr = this->personalityName(reloc);
780 if ( addr != NULL )
781 *addr = fSymbols[reloc->r_symbolnum()].n_value();
782 return true;
783 }
784 }
785 return false;
786}
787
fb24a050 788
afe874b1
A
789template <typename A>
790void UnwindPrinter<A>::printObjectUnwindSection(bool showFunctionNames)
791{
792 printf("Arch: %s, Section: __LD,__compact_unwind (size=0x%08llX, => %lld entries)\n",
793 archName(), fUnwindSection->size(), fUnwindSection->size() / sizeof(macho_compact_unwind_entry<P>));
794
795 const macho_compact_unwind_entry<P>* const entriesStart = (macho_compact_unwind_entry<P>*)((uint8_t*)fHeader + fUnwindSection->offset());
796 const macho_compact_unwind_entry<P>* const entriesEnd = (macho_compact_unwind_entry<P>*)((uint8_t*)fHeader + fUnwindSection->offset() + fUnwindSection->size());
797 for (const macho_compact_unwind_entry<P>* entry=entriesStart; entry < entriesEnd; ++entry) {
798 uint64_t entryAddress = ((char*)entry - (char*)entriesStart) + fUnwindSection->addr();
799 printf("0x%08llX:\n", entryAddress);
800 const char* functionNameStr;
801 pint_t funcAddress;
802 uint32_t offsetInFunction;
803 if ( hasExernReloc(((char*)entry-(char*)entriesStart)+macho_compact_unwind_entry<P>::codeStartFieldOffset(), &functionNameStr, &funcAddress) ) {
804 offsetInFunction = entry->codeStart();
805 }
806 else {
807 functionNameStr = this->functionName(entry->codeStart(), &offsetInFunction);
599556ff 808 funcAddress = entry->codeStart();
afe874b1
A
809 }
810 if ( offsetInFunction == 0 )
811 printf(" start: 0x%08llX %s\n", (uint64_t)funcAddress, functionNameStr);
812 else
813 printf(" start: 0x%08llX %s+0x%X\n", (uint64_t)funcAddress+offsetInFunction, functionNameStr, offsetInFunction);
814
815 printf(" end: 0x%08llX (len=0x%08X)\n", (uint64_t)(funcAddress+offsetInFunction+entry->codeLen()), entry->codeLen());
816
817 char encodingString[200];
818 this->decode(entry->compactUnwindInfo(), ((const uint8_t*)fHeader), encodingString);
819 printf(" unwind info: 0x%08X %s\n", entry->compactUnwindInfo(), encodingString);
820
821 const char* personalityNameStr;
822 if ( hasExernReloc(((char*)entry-(char*)entriesStart)+macho_compact_unwind_entry<P>::personalityFieldOffset(), &personalityNameStr) ) {
823 printf(" personality: %s\n", personalityNameStr);
824 }
825 else {
826 printf(" personality:\n");
827 }
828 if ( entry->lsda() == 0 ) {
829 printf(" lsda:\n");
830 }
831 else {
832 uint32_t lsdaOffset;
833 const char* lsdaName = this->functionName(entry->lsda(), &lsdaOffset);
834 if ( lsdaOffset == 0 )
835 printf(" lsda: 0x%08llX %s\n", (uint64_t)entry->lsda(), lsdaName);
836 else
837 printf(" lsda: 0x%08llX %s+0x%X\n", (uint64_t)entry->lsda(), lsdaName, lsdaOffset);
838 }
839 }
fb24a050 840}
55e3d2f6 841
afe874b1
A
842
843
55e3d2f6 844template <typename A>
a645023d 845void UnwindPrinter<A>::printUnwindSection(bool showFunctionNames)
55e3d2f6
A
846{
847 const uint8_t* sectionContent = (uint8_t*)fHeader + fUnwindSection->offset();
848 macho_unwind_info_section_header<P>* sectionHeader = (macho_unwind_info_section_header<P>*)(sectionContent);
849
850 printf("Arch: %s, Section: __TEXT,__unwind_info (addr=0x%08llX, size=0x%08llX, fileOffset=0x%08X)\n",
851 archName(), fUnwindSection->addr(), fUnwindSection->size(), fUnwindSection->offset());
852 printf("\tversion=0x%08X\n", sectionHeader->version());
853 printf("\tcommonEncodingsArraySectionOffset=0x%08X\n", sectionHeader->commonEncodingsArraySectionOffset());
854 printf("\tcommonEncodingsArrayCount=0x%08X\n", sectionHeader->commonEncodingsArrayCount());
855 printf("\tpersonalityArraySectionOffset=0x%08X\n", sectionHeader->personalityArraySectionOffset());
856 printf("\tpersonalityArrayCount=0x%08X\n", sectionHeader->personalityArrayCount());
857 printf("\tindexSectionOffset=0x%08X\n", sectionHeader->indexSectionOffset());
858 printf("\tindexCount=0x%08X\n", sectionHeader->indexCount());
859 printf("\tcommon encodings: (count=%u)\n", sectionHeader->commonEncodingsArrayCount());
860 const uint32_t* commonEncodings = (uint32_t*)&sectionContent[sectionHeader->commonEncodingsArraySectionOffset()];
861 for (uint32_t i=0; i < sectionHeader->commonEncodingsArrayCount(); ++i) {
fb24a050 862 printf("\t\tencoding[%3u]=0x%08X\n", i, A::P::E::get32(commonEncodings[i]));
55e3d2f6
A
863 }
864 printf("\tpersonalities: (count=%u)\n", sectionHeader->personalityArrayCount());
865 const uint32_t* personalityArray = (uint32_t*)&sectionContent[sectionHeader->personalityArraySectionOffset()];
866 for (uint32_t i=0; i < sectionHeader->personalityArrayCount(); ++i) {
867 printf("\t\t[%2u]=0x%08X\n", i+1, A::P::E::get32(personalityArray[i]));
868 }
869 printf("\tfirst level index: (count=%u)\n", sectionHeader->indexCount());
870 macho_unwind_info_section_header_index_entry<P>* indexes = (macho_unwind_info_section_header_index_entry<P>*)&sectionContent[sectionHeader->indexSectionOffset()];
871 for (uint32_t i=0; i < sectionHeader->indexCount(); ++i) {
872 printf("\t\t[%2u] funcOffset=0x%08X, pageOffset=0x%08X, lsdaOffset=0x%08X\n",
873 i, indexes[i].functionOffset(), indexes[i].secondLevelPagesSectionOffset(), indexes[i].lsdaIndexArraySectionOffset());
874 }
875 uint32_t lsdaIndexArraySectionOffset = indexes[0].lsdaIndexArraySectionOffset();
876 uint32_t lsdaIndexArrayEndSectionOffset = indexes[sectionHeader->indexCount()-1].lsdaIndexArraySectionOffset();
877 uint32_t lsdaIndexArrayCount = (lsdaIndexArrayEndSectionOffset-lsdaIndexArraySectionOffset)/sizeof(macho_unwind_info_section_header_lsda_index_entry<P>);
878 printf("\tLSDA table: (section offset 0x%08X, count=%u)\n", lsdaIndexArraySectionOffset, lsdaIndexArrayCount);
879 macho_unwind_info_section_header_lsda_index_entry<P>* lindex = (macho_unwind_info_section_header_lsda_index_entry<P>*)&sectionContent[lsdaIndexArraySectionOffset];
880 for (uint32_t i=0; i < lsdaIndexArrayCount; ++i) {
a645023d
A
881 const char* name = showFunctionNames ? functionName(lindex[i].functionOffset()+fMachHeaderAddress) : "";
882 printf("\t\t[%3u] funcOffset=0x%08X, lsdaOffset=0x%08X, %s\n", i, lindex[i].functionOffset(), lindex[i].lsdaOffset(), name);
55e3d2f6
A
883 if ( *(((uint8_t*)fHeader) + lindex[i].lsdaOffset()) != 0xFF )
884 fprintf(stderr, "BAD LSDA entry (does not start with 0xFF) for %s\n", functionName(lindex[i].functionOffset()+fMachHeaderAddress));
885 }
886 for (uint32_t i=0; i < sectionHeader->indexCount()-1; ++i) {
887 printf("\tsecond level index[%u] sectionOffset=0x%08X, count=%u, fileOffset=0x%08X\n", i, indexes[i].secondLevelPagesSectionOffset(),
888 sectionHeader->indexCount(), fUnwindSection->offset()+indexes[i].secondLevelPagesSectionOffset());
889 macho_unwind_info_regular_second_level_page_header<P>* page = (macho_unwind_info_regular_second_level_page_header<P>*)&sectionContent[indexes[i].secondLevelPagesSectionOffset()];
890 if ( page->kind() == UNWIND_SECOND_LEVEL_REGULAR ) {
891 printf("\t\tkind=UNWIND_SECOND_LEVEL_REGULAR\n");
892 printf("\t\tentryPageOffset=0x%08X\n", page->entryPageOffset());
893 printf("\t\tentryCount=0x%08X\n", page->entryCount());
894 const macho_unwind_info_regular_second_level_entry<P>* entry = (macho_unwind_info_regular_second_level_entry<P>*)((char*)page+page->entryPageOffset());
895 for (uint32_t j=0; j < page->entryCount(); ++j) {
fb24a050 896 uint32_t funcOffset = entry[j].functionOffset();
55e3d2f6
A
897 if ( entry[j].encoding() & UNWIND_HAS_LSDA ) {
898 // verify there is a corresponding entry in lsda table
899 bool found = false;
900 for (uint32_t k=0; k < lsdaIndexArrayCount; ++k) {
901 if ( lindex[k].functionOffset() == funcOffset ) {
902 found = true;
903 break;
904 }
905 }
906 if ( !found ) {
907 fprintf(stderr, "MISSING LSDA entry for %s\n", functionName(funcOffset+fMachHeaderAddress));
908 }
909 }
fb24a050
A
910 char encodingString[100];
911 decode(entry[j].encoding(), ((const uint8_t*)fHeader)+funcOffset, encodingString);
a645023d 912 const char* name = showFunctionNames ? functionName(funcOffset+fMachHeaderAddress) : "";
f80fe69f 913 printf("\t\t\t[%3u] funcOffset=0x%08X, encoding=0x%08X (%-56s) %s\n",
a645023d 914 j, funcOffset, entry[j].encoding(), encodingString, name);
55e3d2f6
A
915 }
916 }
917 else if ( page->kind() == UNWIND_SECOND_LEVEL_COMPRESSED ) {
918 macho_unwind_info_compressed_second_level_page_header<P>* cp = (macho_unwind_info_compressed_second_level_page_header<P>*)page;
919 printf("\t\tkind=UNWIND_SECOND_LEVEL_COMPRESSED\n");
920 printf("\t\tentryPageOffset=0x%08X\n", cp->entryPageOffset());
921 printf("\t\tentryCount=0x%08X\n", cp->entryCount());
922 printf("\t\tencodingsPageOffset=0x%08X\n", cp->encodingsPageOffset());
923 printf("\t\tencodingsCount=0x%08X\n", cp->encodingsCount());
924 const uint32_t* entries = (uint32_t*)(((uint8_t*)page)+cp->entryPageOffset());
925 const uint32_t* encodings = (uint32_t*)(((uint8_t*)page)+cp->encodingsPageOffset());
926 const uint32_t baseFunctionOffset = indexes[i].functionOffset();
927 for (uint32_t j=0; j < cp->entryCount(); ++j) {
928 uint8_t encodingIndex = UNWIND_INFO_COMPRESSED_ENTRY_ENCODING_INDEX(entries[j]);
929 uint32_t encoding;
930 if ( encodingIndex < sectionHeader->commonEncodingsArrayCount() )
931 encoding = A::P::E::get32(commonEncodings[encodingIndex]);
932 else
933 encoding = A::P::E::get32(encodings[encodingIndex-sectionHeader->commonEncodingsArrayCount()]);
fb24a050 934 char encodingString[100];
55e3d2f6 935 uint32_t funcOff = UNWIND_INFO_COMPRESSED_ENTRY_FUNC_OFFSET(entries[j])+baseFunctionOffset;
fb24a050 936 decode(encoding, ((const uint8_t*)fHeader)+funcOff, encodingString);
a645023d 937 const char* name = showFunctionNames ? functionName(funcOff+fMachHeaderAddress) : "";
55e3d2f6
A
938 if ( encoding & UNWIND_HAS_LSDA ) {
939 // verify there is a corresponding entry in lsda table
940 bool found = false;
941 for (uint32_t k=0; k < lsdaIndexArrayCount; ++k) {
942 if ( lindex[k].functionOffset() == funcOff ) {
943 found = true;
944 break;
945 }
946 }
947 if ( !found ) {
948 fprintf(stderr, "MISSING LSDA entry for %s\n", name);
949 }
950 }
f80fe69f 951 printf("\t\t\t[%3u] funcOffset=0x%08X, encoding[%3u]=0x%08X (%-56s) %s\n",
fb24a050 952 j, funcOff, encodingIndex, encoding, encodingString, name);
55e3d2f6
A
953 }
954 }
955 else {
956 fprintf(stderr, "\t\tbad page header\n");
957 }
958 }
959
960}
961
a645023d 962static void dump(const char* path, const std::set<cpu_type_t>& onlyArchs, bool showFunctionNames)
55e3d2f6
A
963{
964 struct stat stat_buf;
965
966 try {
967 int fd = ::open(path, O_RDONLY, 0);
968 if ( fd == -1 )
969 throw "cannot open file";
970 if ( ::fstat(fd, &stat_buf) != 0 )
971 throwf("fstat(%s) failed, errno=%d\n", path, errno);
972 uint32_t length = stat_buf.st_size;
973 uint8_t* p = (uint8_t*)::mmap(NULL, stat_buf.st_size, PROT_READ, MAP_FILE | MAP_PRIVATE, fd, 0);
974 if ( p == ((uint8_t*)(-1)) )
975 throw "cannot map file";
976 ::close(fd);
977 const mach_header* mh = (mach_header*)p;
978 if ( mh->magic == OSSwapBigToHostInt32(FAT_MAGIC) ) {
979 const struct fat_header* fh = (struct fat_header*)p;
980 const struct fat_arch* archs = (struct fat_arch*)(p + sizeof(struct fat_header));
981 for (unsigned long i=0; i < OSSwapBigToHostInt32(fh->nfat_arch); ++i) {
982 size_t offset = OSSwapBigToHostInt32(archs[i].offset);
983 size_t size = OSSwapBigToHostInt32(archs[i].size);
984 unsigned int cputype = OSSwapBigToHostInt32(archs[i].cputype);
985 if ( onlyArchs.count(cputype) ) {
986 switch(cputype) {
55e3d2f6
A
987 case CPU_TYPE_I386:
988 if ( UnwindPrinter<x86>::validFile(p + offset) )
a645023d 989 UnwindPrinter<x86>::make(p + offset, size, path, showFunctionNames);
55e3d2f6
A
990 else
991 throw "in universal file, i386 slice does not contain i386 mach-o";
992 break;
55e3d2f6
A
993 case CPU_TYPE_X86_64:
994 if ( UnwindPrinter<x86_64>::validFile(p + offset) )
a645023d 995 UnwindPrinter<x86_64>::make(p + offset, size, path, showFunctionNames);
55e3d2f6
A
996 else
997 throw "in universal file, x86_64 slice does not contain x86_64 mach-o";
998 break;
f80fe69f
A
999#if SUPPORT_ARCH_arm64
1000 case CPU_TYPE_ARM64:
1001 if ( UnwindPrinter<arm64>::validFile(p + offset) )
1002 UnwindPrinter<arm64>::make(p + offset, size, path, showFunctionNames);
1003 else
599556ff 1004 throw "in universal file, arm64 slice does not contain arm64 mach-o";
f80fe69f
A
1005 break;
1006#endif
55e3d2f6
A
1007 default:
1008 throwf("in universal file, unknown architecture slice 0x%x\n", cputype);
1009 }
1010 }
1011 }
1012 }
1013 else if ( UnwindPrinter<x86>::validFile(p) && onlyArchs.count(CPU_TYPE_I386) ) {
a645023d 1014 UnwindPrinter<x86>::make(p, length, path, showFunctionNames);
55e3d2f6 1015 }
55e3d2f6 1016 else if ( UnwindPrinter<x86_64>::validFile(p) && onlyArchs.count(CPU_TYPE_X86_64) ) {
a645023d 1017 UnwindPrinter<x86_64>::make(p, length, path, showFunctionNames);
55e3d2f6 1018 }
f80fe69f
A
1019#if SUPPORT_ARCH_arm64
1020 else if ( UnwindPrinter<arm64>::validFile(p) && onlyArchs.count(CPU_TYPE_ARM64) ) {
1021 UnwindPrinter<arm64>::make(p, length, path, showFunctionNames);
1022 }
1023#endif
55e3d2f6
A
1024 else {
1025 throw "not a known file type";
1026 }
1027 }
1028 catch (const char* msg) {
1029 throwf("%s in %s", msg, path);
1030 }
1031}
1032
1033
1034int main(int argc, const char* argv[])
1035{
1036 std::set<cpu_type_t> onlyArchs;
1037 std::vector<const char*> files;
a645023d 1038 bool showFunctionNames = true;
55e3d2f6
A
1039
1040 try {
1041 for(int i=1; i < argc; ++i) {
1042 const char* arg = argv[i];
1043 if ( arg[0] == '-' ) {
1044 if ( strcmp(arg, "-arch") == 0 ) {
1045 const char* arch = argv[++i];
afe874b1 1046 if ( strcmp(arch, "i386") == 0 )
55e3d2f6
A
1047 onlyArchs.insert(CPU_TYPE_I386);
1048 else if ( strcmp(arch, "x86_64") == 0 )
1049 onlyArchs.insert(CPU_TYPE_X86_64);
f80fe69f
A
1050#if SUPPORT_ARCH_arm64
1051 else if ( strcmp(arch, "arm64") == 0 )
1052 onlyArchs.insert(CPU_TYPE_ARM64);
1053#endif
55e3d2f6
A
1054 else
1055 throwf("unknown architecture %s", arch);
1056 }
a645023d
A
1057 else if ( strcmp(arg, "-no_symbols") == 0 ) {
1058 showFunctionNames = false;
1059 }
55e3d2f6
A
1060 else {
1061 throwf("unknown option: %s\n", arg);
1062 }
1063 }
1064 else {
1065 files.push_back(arg);
1066 }
1067 }
1068
1069 // use all architectures if no restrictions specified
1070 if ( onlyArchs.size() == 0 ) {
55e3d2f6
A
1071 onlyArchs.insert(CPU_TYPE_I386);
1072 onlyArchs.insert(CPU_TYPE_X86_64);
f80fe69f
A
1073#if SUPPORT_ARCH_arm64
1074 onlyArchs.insert(CPU_TYPE_ARM64);
1075#endif
599556ff 1076 onlyArchs.insert(CPU_TYPE_ARM);
55e3d2f6
A
1077 }
1078
1079 // process each file
1080 for(std::vector<const char*>::iterator it=files.begin(); it != files.end(); ++it) {
a645023d 1081 dump(*it, onlyArchs, showFunctionNames);
55e3d2f6
A
1082 }
1083
1084 }
1085 catch (const char* msg) {
1086 fprintf(stderr, "UnwindDump failed: %s\n", msg);
1087 return 1;
1088 }
1089
1090 return 0;
1091}
1092
1093
1094