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