1 /* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
3 * Copyright (c) 2008-2011 Apple Inc. All rights reserved.
5 * @APPLE_LICENSE_HEADER_START@
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
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.
22 * @APPLE_LICENSE_HEADER_END@
25 #include <sys/types.h>
36 #include <ext/hash_set>
39 #include "MachOFileAbstraction.hpp"
40 #include "Architectures.hpp"
43 __attribute__((noreturn
))
44 void throwf(const char* format
, ...)
48 va_start(list
, format
);
49 vasprintf(&p
, format
, list
);
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() {}
70 typedef typename
A::P P
;
71 typedef typename
A::P::E E
;
72 typedef typename
A::P::uint_t pint_t
;
77 bool operator()(const char* left
, const char* right
) const { return (strcmp(left
, right
) == 0); }
80 typedef __gnu_cxx::hash_set
<const char*, __gnu_cxx::hash
<const char*>, CStringEquals
> StringSet
;
82 UnwindPrinter(const uint8_t* fileContent
, uint32_t fileLength
,
83 const char* path
, bool showFunctionNames
);
84 bool findUnwindSection();
85 void printUnwindSection(bool showFunctionNames
);
86 void printObjectUnwindSection(bool showFunctionNames
);
87 void getSymbolTableInfo();
88 const char* functionName(pint_t addr
, uint32_t* offset
=NULL
);
89 const char* personalityName(const macho_relocation_info
<typename
A::P
>* reloc
);
90 bool hasExernReloc(uint64_t sectionOffset
, const char** personalityStr
, pint_t
* addr
=NULL
);
92 static const char* archName();
93 static void decode(uint32_t encoding
, const uint8_t* funcStart
, char* str
);
96 const macho_header
<P
>* fHeader
;
98 const macho_section
<P
>* fUnwindSection
;
100 const char* fStringsEnd
;
101 const macho_nlist
<P
>* fSymbols
;
102 uint32_t fSymbolCount
;
103 pint_t fMachHeaderAddress
;
107 template <> const char* UnwindPrinter
<ppc
>::archName() { return "ppc"; }
108 template <> const char* UnwindPrinter
<ppc64
>::archName() { return "ppc64"; }
109 template <> const char* UnwindPrinter
<x86
>::archName() { return "i386"; }
110 template <> const char* UnwindPrinter
<x86_64
>::archName() { return "x86_64"; }
111 template <> const char* UnwindPrinter
<arm
>::archName() { return "arm"; }
115 bool UnwindPrinter
<x86
>::validFile(const uint8_t* fileContent
)
117 const macho_header
<P
>* header
= (const macho_header
<P
>*)fileContent
;
118 if ( header
->magic() != MH_MAGIC
)
120 if ( header
->cputype() != CPU_TYPE_I386
)
122 switch (header
->filetype()) {
134 bool UnwindPrinter
<x86_64
>::validFile(const uint8_t* fileContent
)
136 const macho_header
<P
>* header
= (const macho_header
<P
>*)fileContent
;
137 if ( header
->magic() != MH_MAGIC_64
)
139 if ( header
->cputype() != CPU_TYPE_X86_64
)
141 switch (header
->filetype()) {
153 template <typename A
>
154 UnwindPrinter
<A
>::UnwindPrinter(const uint8_t* fileContent
, uint32_t fileLength
, const char* path
, bool showFunctionNames
)
155 : fHeader(NULL
), fLength(fileLength
), fUnwindSection(NULL
),
156 fStrings(NULL
), fStringsEnd(NULL
), fSymbols(NULL
), fSymbolCount(0), fMachHeaderAddress(0)
159 if ( ! validFile(fileContent
) )
160 throw "not a mach-o file that can be checked";
162 fPath
= strdup(path
);
163 fHeader
= (const macho_header
<P
>*)fileContent
;
165 getSymbolTableInfo();
167 if ( findUnwindSection() ) {
168 if ( fHeader
->filetype() == MH_OBJECT
)
169 printObjectUnwindSection(showFunctionNames
);
171 printUnwindSection(showFunctionNames
);
176 template <typename A
>
177 void UnwindPrinter
<A
>::getSymbolTableInfo()
179 const uint8_t* const endOfFile
= (uint8_t*)fHeader
+ fLength
;
180 const uint8_t* const endOfLoadCommands
= (uint8_t*)fHeader
+ sizeof(macho_header
<P
>) + fHeader
->sizeofcmds();
181 const uint32_t cmd_count
= fHeader
->ncmds();
182 const macho_load_command
<P
>* const cmds
= (macho_load_command
<P
>*)((uint8_t*)fHeader
+ sizeof(macho_header
<P
>));
183 const macho_load_command
<P
>* cmd
= cmds
;
184 for (uint32_t i
= 0; i
< cmd_count
; ++i
) {
185 uint32_t size
= cmd
->cmdsize();
186 const uint8_t* endOfCmd
= ((uint8_t*)cmd
)+cmd
->cmdsize();
187 if ( endOfCmd
> endOfLoadCommands
)
188 throwf("load command #%d extends beyond the end of the load commands", i
);
189 if ( endOfCmd
> endOfFile
)
190 throwf("load command #%d extends beyond the end of the file", i
);
191 if ( cmd
->cmd() == LC_SYMTAB
) {
192 const macho_symtab_command
<P
>* symtab
= (macho_symtab_command
<P
>*)cmd
;
193 fSymbolCount
= symtab
->nsyms();
194 fSymbols
= (const macho_nlist
<P
>*)((char*)fHeader
+ symtab
->symoff());
195 fStrings
= (char*)fHeader
+ symtab
->stroff();
196 fStringsEnd
= fStrings
+ symtab
->strsize();
198 cmd
= (const macho_load_command
<P
>*)endOfCmd
;
202 template <typename A
>
203 const char* UnwindPrinter
<A
>::functionName(pint_t addr
, uint32_t* offset
)
205 const macho_nlist
<P
>* closestSymbol
= NULL
;
206 if ( offset
!= NULL
)
208 for (uint32_t i
=0; i
< fSymbolCount
; ++i
) {
209 uint8_t type
= fSymbols
[i
].n_type();
210 if ( ((type
& N_STAB
) == 0) && ((type
& N_TYPE
) == N_SECT
) ) {
211 if ( fSymbols
[i
].n_value() == addr
) {
212 const char* r
= &fStrings
[fSymbols
[i
].n_strx()];
213 //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);
216 else if ( offset
!= NULL
) {
217 if ( closestSymbol
== NULL
) {
218 if ( fSymbols
[i
].n_value() < addr
)
219 closestSymbol
= &fSymbols
[i
];
222 if ( (fSymbols
[i
].n_value() < addr
) && (fSymbols
[i
].n_value() > closestSymbol
->n_value()) )
223 closestSymbol
= &fSymbols
[i
];
228 if ( closestSymbol
!= NULL
) {
229 *offset
= addr
- closestSymbol
->n_value();
230 return &fStrings
[closestSymbol
->n_strx()];
232 return "--anonymous function--";
237 template <typename A
>
238 bool UnwindPrinter
<A
>::findUnwindSection()
240 const char* unwindSectionName
= "__unwind_info";
241 const char* unwindSegmentName
= "__TEXT";
242 if ( fHeader
->filetype() == MH_OBJECT
) {
243 unwindSectionName
= "__compact_unwind";
244 unwindSegmentName
= "__LD";
246 const uint8_t* const endOfFile
= (uint8_t*)fHeader
+ fLength
;
247 const uint8_t* const endOfLoadCommands
= (uint8_t*)fHeader
+ sizeof(macho_header
<P
>) + fHeader
->sizeofcmds();
248 const uint32_t cmd_count
= fHeader
->ncmds();
249 const macho_load_command
<P
>* const cmds
= (macho_load_command
<P
>*)((uint8_t*)fHeader
+ sizeof(macho_header
<P
>));
250 const macho_load_command
<P
>* cmd
= cmds
;
251 for (uint32_t i
= 0; i
< cmd_count
; ++i
) {
252 uint32_t size
= cmd
->cmdsize();
253 const uint8_t* endOfCmd
= ((uint8_t*)cmd
)+cmd
->cmdsize();
254 if ( endOfCmd
> endOfLoadCommands
)
255 throwf("load command #%d extends beyond the end of the load commands", i
);
256 if ( endOfCmd
> endOfFile
)
257 throwf("load command #%d extends beyond the end of the file", i
);
258 if ( cmd
->cmd() == macho_segment_command
<P
>::CMD
) {
259 const macho_segment_command
<P
>* segCmd
= (const macho_segment_command
<P
>*)cmd
;
260 const macho_section
<P
>* const sectionsStart
= (macho_section
<P
>*)((char*)segCmd
+ sizeof(macho_segment_command
<P
>));
261 const macho_section
<P
>* const sectionsEnd
= §ionsStart
[segCmd
->nsects()];
262 for(const macho_section
<P
>* sect
= sectionsStart
; sect
< sectionsEnd
; ++sect
) {
263 if ( (strncmp(sect
->sectname(), unwindSectionName
, 16) == 0) && (strcmp(sect
->segname(), unwindSegmentName
) == 0) ) {
264 fUnwindSection
= sect
;
265 fMachHeaderAddress
= segCmd
->vmaddr();
266 return fUnwindSection
;
270 cmd
= (const macho_load_command
<P
>*)endOfCmd
;
275 #define EXTRACT_BITS(value, mask) \
276 ( (value >> __builtin_ctz(mask)) & (((1 << __builtin_popcount(mask)))-1) )
280 void UnwindPrinter
<x86_64
>::decode(uint32_t encoding
, const uint8_t* funcStart
, char* str
)
283 switch ( encoding
& UNWIND_X86_64_MODE_MASK
) {
284 case UNWIND_X86_64_MODE_RBP_FRAME
:
286 uint32_t savedRegistersOffset
= EXTRACT_BITS(encoding
, UNWIND_X86_64_RBP_FRAME_OFFSET
);
287 uint32_t savedRegistersLocations
= EXTRACT_BITS(encoding
, UNWIND_X86_64_RBP_FRAME_REGISTERS
);
288 if ( savedRegistersLocations
== 0 ) {
289 strcpy(str
, "rbp frame, no saved registers");
292 sprintf(str
, "rbp frame, at -%d:", savedRegistersOffset
*8);
293 bool needComma
= false;
294 for (int i
=0; i
< 5; ++i
) {
299 switch (savedRegistersLocations
& 0x7) {
300 case UNWIND_X86_64_REG_NONE
:
303 case UNWIND_X86_64_REG_RBX
:
306 case UNWIND_X86_64_REG_R12
:
309 case UNWIND_X86_64_REG_R13
:
312 case UNWIND_X86_64_REG_R14
:
315 case UNWIND_X86_64_REG_R15
:
321 savedRegistersLocations
= (savedRegistersLocations
>> 3);
322 if ( savedRegistersLocations
== 0 )
328 case UNWIND_X86_64_MODE_STACK_IMMD
:
329 case UNWIND_X86_64_MODE_STACK_IND
:
331 uint32_t stackSize
= EXTRACT_BITS(encoding
, UNWIND_X86_64_FRAMELESS_STACK_SIZE
);
332 uint32_t stackAdjust
= EXTRACT_BITS(encoding
, UNWIND_X86_64_FRAMELESS_STACK_ADJUST
);
333 uint32_t regCount
= EXTRACT_BITS(encoding
, UNWIND_X86_64_FRAMELESS_STACK_REG_COUNT
);
334 uint32_t permutation
= EXTRACT_BITS(encoding
, UNWIND_X86_64_FRAMELESS_STACK_REG_PERMUTATION
);
335 if ( (encoding
& UNWIND_X86_64_MODE_MASK
) == UNWIND_X86_64_MODE_STACK_IND
) {
336 // stack size is encoded in subl $xxx,%esp instruction
337 uint32_t subl
= x86_64::P::E::get32(*((uint32_t*)(funcStart
+stackSize
)));
338 sprintf(str
, "stack size=0x%08X, ", subl
+ 8*stackAdjust
);
341 sprintf(str
, "stack size=%d, ", stackSize
*8);
343 if ( regCount
== 0 ) {
344 strcat(str
, "no registers saved");
348 switch ( regCount
) {
350 permunreg
[0] = permutation
/120;
351 permutation
-= (permunreg
[0]*120);
352 permunreg
[1] = permutation
/24;
353 permutation
-= (permunreg
[1]*24);
354 permunreg
[2] = permutation
/6;
355 permutation
-= (permunreg
[2]*6);
356 permunreg
[3] = permutation
/2;
357 permutation
-= (permunreg
[3]*2);
358 permunreg
[4] = permutation
;
362 permunreg
[0] = permutation
/120;
363 permutation
-= (permunreg
[0]*120);
364 permunreg
[1] = permutation
/24;
365 permutation
-= (permunreg
[1]*24);
366 permunreg
[2] = permutation
/6;
367 permutation
-= (permunreg
[2]*6);
368 permunreg
[3] = permutation
/2;
369 permutation
-= (permunreg
[3]*2);
370 permunreg
[4] = permutation
;
373 permunreg
[0] = permutation
/60;
374 permutation
-= (permunreg
[0]*60);
375 permunreg
[1] = permutation
/12;
376 permutation
-= (permunreg
[1]*12);
377 permunreg
[2] = permutation
/3;
378 permutation
-= (permunreg
[2]*3);
379 permunreg
[3] = permutation
;
382 permunreg
[0] = permutation
/20;
383 permutation
-= (permunreg
[0]*20);
384 permunreg
[1] = permutation
/4;
385 permutation
-= (permunreg
[1]*4);
386 permunreg
[2] = permutation
;
389 permunreg
[0] = permutation
/5;
390 permutation
-= (permunreg
[0]*5);
391 permunreg
[1] = permutation
;
394 permunreg
[0] = permutation
;
397 // renumber registers back to standard numbers
399 bool used
[7] = { false, false, false, false, false, false, false };
400 for (int i
=0; i
< regCount
; ++i
) {
402 for (int u
=1; u
< 7; ++u
) {
404 if ( renum
== permunreg
[i
] ) {
413 bool needComma
= false;
414 for (int i
=0; i
< regCount
; ++i
) {
419 switch ( registers
[i
] ) {
420 case UNWIND_X86_64_REG_RBX
:
423 case UNWIND_X86_64_REG_R12
:
426 case UNWIND_X86_64_REG_R13
:
429 case UNWIND_X86_64_REG_R14
:
432 case UNWIND_X86_64_REG_R15
:
435 case UNWIND_X86_64_REG_RBP
:
445 case UNWIND_X86_64_MODE_DWARF
:
446 sprintf(str
, "dwarf offset 0x%08X, ", encoding
& UNWIND_X86_64_DWARF_SECTION_OFFSET
);
450 strcat(str
, "no unwind information");
454 if ( encoding
& UNWIND_HAS_LSDA
) {
455 strcat(str
, " LSDA");
461 void UnwindPrinter
<x86
>::decode(uint32_t encoding
, const uint8_t* funcStart
, char* str
)
464 switch ( encoding
& UNWIND_X86_MODE_MASK
) {
465 case UNWIND_X86_MODE_EBP_FRAME
:
467 uint32_t savedRegistersOffset
= EXTRACT_BITS(encoding
, UNWIND_X86_EBP_FRAME_OFFSET
);
468 uint32_t savedRegistersLocations
= EXTRACT_BITS(encoding
, UNWIND_X86_EBP_FRAME_REGISTERS
);
469 if ( savedRegistersLocations
== 0 ) {
470 strcpy(str
, "ebp frame, no saved registers");
473 sprintf(str
, "ebp frame, at -%d:", savedRegistersOffset
*4);
474 bool needComma
= false;
475 for (int i
=0; i
< 5; ++i
) {
480 switch (savedRegistersLocations
& 0x7) {
481 case UNWIND_X86_REG_NONE
:
484 case UNWIND_X86_REG_EBX
:
487 case UNWIND_X86_REG_ECX
:
490 case UNWIND_X86_REG_EDX
:
493 case UNWIND_X86_REG_EDI
:
496 case UNWIND_X86_REG_ESI
:
502 savedRegistersLocations
= (savedRegistersLocations
>> 3);
503 if ( savedRegistersLocations
== 0 )
509 case UNWIND_X86_MODE_STACK_IMMD
:
510 case UNWIND_X86_MODE_STACK_IND
:
512 uint32_t stackSize
= EXTRACT_BITS(encoding
, UNWIND_X86_FRAMELESS_STACK_SIZE
);
513 uint32_t stackAdjust
= EXTRACT_BITS(encoding
, UNWIND_X86_FRAMELESS_STACK_ADJUST
);
514 uint32_t regCount
= EXTRACT_BITS(encoding
, UNWIND_X86_FRAMELESS_STACK_REG_COUNT
);
515 uint32_t permutation
= EXTRACT_BITS(encoding
, UNWIND_X86_FRAMELESS_STACK_REG_PERMUTATION
);
516 if ( (encoding
& UNWIND_X86_MODE_MASK
) == UNWIND_X86_MODE_STACK_IND
) {
517 // stack size is encoded in subl $xxx,%esp instruction
518 uint32_t subl
= x86::P::E::get32(*((uint32_t*)(funcStart
+stackSize
)));
519 sprintf(str
, "stack size=0x%08X, ", subl
+4*stackAdjust
);
522 sprintf(str
, "stack size=%d, ", stackSize
*4);
524 if ( regCount
== 0 ) {
525 strcat(str
, "no saved regs");
529 switch ( regCount
) {
531 permunreg
[0] = permutation
/120;
532 permutation
-= (permunreg
[0]*120);
533 permunreg
[1] = permutation
/24;
534 permutation
-= (permunreg
[1]*24);
535 permunreg
[2] = permutation
/6;
536 permutation
-= (permunreg
[2]*6);
537 permunreg
[3] = permutation
/2;
538 permutation
-= (permunreg
[3]*2);
539 permunreg
[4] = permutation
;
543 permunreg
[0] = permutation
/120;
544 permutation
-= (permunreg
[0]*120);
545 permunreg
[1] = permutation
/24;
546 permutation
-= (permunreg
[1]*24);
547 permunreg
[2] = permutation
/6;
548 permutation
-= (permunreg
[2]*6);
549 permunreg
[3] = permutation
/2;
550 permutation
-= (permunreg
[3]*2);
551 permunreg
[4] = permutation
;
554 permunreg
[0] = permutation
/60;
555 permutation
-= (permunreg
[0]*60);
556 permunreg
[1] = permutation
/12;
557 permutation
-= (permunreg
[1]*12);
558 permunreg
[2] = permutation
/3;
559 permutation
-= (permunreg
[2]*3);
560 permunreg
[3] = permutation
;
563 permunreg
[0] = permutation
/20;
564 permutation
-= (permunreg
[0]*20);
565 permunreg
[1] = permutation
/4;
566 permutation
-= (permunreg
[1]*4);
567 permunreg
[2] = permutation
;
570 permunreg
[0] = permutation
/5;
571 permutation
-= (permunreg
[0]*5);
572 permunreg
[1] = permutation
;
575 permunreg
[0] = permutation
;
578 // renumber registers back to standard numbers
580 bool used
[7] = { false, false, false, false, false, false, false };
581 for (int i
=0; i
< regCount
; ++i
) {
583 for (int u
=1; u
< 7; ++u
) {
585 if ( renum
== permunreg
[i
] ) {
594 bool needComma
= false;
595 for (int i
=0; i
< regCount
; ++i
) {
600 switch ( registers
[i
] ) {
601 case UNWIND_X86_REG_EBX
:
604 case UNWIND_X86_REG_ECX
:
607 case UNWIND_X86_REG_EDX
:
610 case UNWIND_X86_REG_EDI
:
613 case UNWIND_X86_REG_ESI
:
616 case UNWIND_X86_REG_EBP
:
626 case UNWIND_X86_MODE_DWARF
:
627 sprintf(str
, "dwarf offset 0x%08X, ", encoding
& UNWIND_X86_DWARF_SECTION_OFFSET
);
631 strcat(str
, "no unwind information");
635 if ( encoding
& UNWIND_HAS_LSDA
) {
636 strcat(str
, " LSDA");
644 const char* UnwindPrinter
<x86_64
>::personalityName(const macho_relocation_info
<x86_64::P
>* reloc
)
646 //assert(reloc->r_extern() && "reloc not extern on personality column in __compact_unwind section");
647 //assert((reloc->r_type() == X86_64_RELOC_UNSIGNED) && "wrong reloc type on personality column in __compact_unwind section");
648 const macho_nlist
<P
>& sym
= fSymbols
[reloc
->r_symbolnum()];
649 return &fStrings
[sym
.n_strx()];
653 const char* UnwindPrinter
<x86
>::personalityName(const macho_relocation_info
<x86::P
>* reloc
)
655 //assert(reloc->r_extern() && "reloc not extern on personality column in __compact_unwind section");
656 //assert((reloc->r_type() == GENERIC_RELOC_VANILLA) && "wrong reloc type on personality column in __compact_unwind section");
657 const macho_nlist
<P
>& sym
= fSymbols
[reloc
->r_symbolnum()];
658 return &fStrings
[sym
.n_strx()];
661 template <typename A
>
662 bool UnwindPrinter
<A
>::hasExernReloc(uint64_t sectionOffset
, const char** personalityStr
, pint_t
* addr
)
664 const macho_relocation_info
<P
>* relocs
= (macho_relocation_info
<P
>*)((uint8_t*)fHeader
+ fUnwindSection
->reloff());
665 const macho_relocation_info
<P
>* relocsEnd
= &relocs
[fUnwindSection
->nreloc()];
666 for (const macho_relocation_info
<P
>* reloc
= relocs
; reloc
< relocsEnd
; ++reloc
) {
667 if ( reloc
->r_extern() && (reloc
->r_address() == sectionOffset
) ) {
668 *personalityStr
= this->personalityName(reloc
);
670 *addr
= fSymbols
[reloc
->r_symbolnum()].n_value();
678 template <typename A
>
679 void UnwindPrinter
<A
>::printObjectUnwindSection(bool showFunctionNames
)
681 printf("Arch: %s, Section: __LD,__compact_unwind (size=0x%08llX, => %lld entries)\n",
682 archName(), fUnwindSection
->size(), fUnwindSection
->size() / sizeof(macho_compact_unwind_entry
<P
>));
684 const macho_compact_unwind_entry
<P
>* const entriesStart
= (macho_compact_unwind_entry
<P
>*)((uint8_t*)fHeader
+ fUnwindSection
->offset());
685 const macho_compact_unwind_entry
<P
>* const entriesEnd
= (macho_compact_unwind_entry
<P
>*)((uint8_t*)fHeader
+ fUnwindSection
->offset() + fUnwindSection
->size());
686 for (const macho_compact_unwind_entry
<P
>* entry
=entriesStart
; entry
< entriesEnd
; ++entry
) {
687 uint64_t entryAddress
= ((char*)entry
- (char*)entriesStart
) + fUnwindSection
->addr();
688 printf("0x%08llX:\n", entryAddress
);
689 const char* functionNameStr
;
691 uint32_t offsetInFunction
;
692 if ( hasExernReloc(((char*)entry
-(char*)entriesStart
)+macho_compact_unwind_entry
<P
>::codeStartFieldOffset(), &functionNameStr
, &funcAddress
) ) {
693 offsetInFunction
= entry
->codeStart();
696 functionNameStr
= this->functionName(entry
->codeStart(), &offsetInFunction
);
698 if ( offsetInFunction
== 0 )
699 printf(" start: 0x%08llX %s\n", (uint64_t)funcAddress
, functionNameStr
);
701 printf(" start: 0x%08llX %s+0x%X\n", (uint64_t)funcAddress
+offsetInFunction
, functionNameStr
, offsetInFunction
);
703 printf(" end: 0x%08llX (len=0x%08X)\n", (uint64_t)(funcAddress
+offsetInFunction
+entry
->codeLen()), entry
->codeLen());
705 char encodingString
[200];
706 this->decode(entry
->compactUnwindInfo(), ((const uint8_t*)fHeader
), encodingString
);
707 printf(" unwind info: 0x%08X %s\n", entry
->compactUnwindInfo(), encodingString
);
709 const char* personalityNameStr
;
710 if ( hasExernReloc(((char*)entry
-(char*)entriesStart
)+macho_compact_unwind_entry
<P
>::personalityFieldOffset(), &personalityNameStr
) ) {
711 printf(" personality: %s\n", personalityNameStr
);
714 printf(" personality:\n");
716 if ( entry
->lsda() == 0 ) {
721 const char* lsdaName
= this->functionName(entry
->lsda(), &lsdaOffset
);
722 if ( lsdaOffset
== 0 )
723 printf(" lsda: 0x%08llX %s\n", (uint64_t)entry
->lsda(), lsdaName
);
725 printf(" lsda: 0x%08llX %s+0x%X\n", (uint64_t)entry
->lsda(), lsdaName
, lsdaOffset
);
733 template <typename A
>
734 void UnwindPrinter
<A
>::printUnwindSection(bool showFunctionNames
)
736 const uint8_t* sectionContent
= (uint8_t*)fHeader
+ fUnwindSection
->offset();
737 macho_unwind_info_section_header
<P
>* sectionHeader
= (macho_unwind_info_section_header
<P
>*)(sectionContent
);
739 printf("Arch: %s, Section: __TEXT,__unwind_info (addr=0x%08llX, size=0x%08llX, fileOffset=0x%08X)\n",
740 archName(), fUnwindSection
->addr(), fUnwindSection
->size(), fUnwindSection
->offset());
741 printf("\tversion=0x%08X\n", sectionHeader
->version());
742 printf("\tcommonEncodingsArraySectionOffset=0x%08X\n", sectionHeader
->commonEncodingsArraySectionOffset());
743 printf("\tcommonEncodingsArrayCount=0x%08X\n", sectionHeader
->commonEncodingsArrayCount());
744 printf("\tpersonalityArraySectionOffset=0x%08X\n", sectionHeader
->personalityArraySectionOffset());
745 printf("\tpersonalityArrayCount=0x%08X\n", sectionHeader
->personalityArrayCount());
746 printf("\tindexSectionOffset=0x%08X\n", sectionHeader
->indexSectionOffset());
747 printf("\tindexCount=0x%08X\n", sectionHeader
->indexCount());
748 printf("\tcommon encodings: (count=%u)\n", sectionHeader
->commonEncodingsArrayCount());
749 const uint32_t* commonEncodings
= (uint32_t*)§ionContent
[sectionHeader
->commonEncodingsArraySectionOffset()];
750 for (uint32_t i
=0; i
< sectionHeader
->commonEncodingsArrayCount(); ++i
) {
751 printf("\t\tencoding[%3u]=0x%08X\n", i
, A::P::E::get32(commonEncodings
[i
]));
753 printf("\tpersonalities: (count=%u)\n", sectionHeader
->personalityArrayCount());
754 const uint32_t* personalityArray
= (uint32_t*)§ionContent
[sectionHeader
->personalityArraySectionOffset()];
755 for (uint32_t i
=0; i
< sectionHeader
->personalityArrayCount(); ++i
) {
756 printf("\t\t[%2u]=0x%08X\n", i
+1, A::P::E::get32(personalityArray
[i
]));
758 printf("\tfirst level index: (count=%u)\n", sectionHeader
->indexCount());
759 macho_unwind_info_section_header_index_entry
<P
>* indexes
= (macho_unwind_info_section_header_index_entry
<P
>*)§ionContent
[sectionHeader
->indexSectionOffset()];
760 for (uint32_t i
=0; i
< sectionHeader
->indexCount(); ++i
) {
761 printf("\t\t[%2u] funcOffset=0x%08X, pageOffset=0x%08X, lsdaOffset=0x%08X\n",
762 i
, indexes
[i
].functionOffset(), indexes
[i
].secondLevelPagesSectionOffset(), indexes
[i
].lsdaIndexArraySectionOffset());
764 uint32_t lsdaIndexArraySectionOffset
= indexes
[0].lsdaIndexArraySectionOffset();
765 uint32_t lsdaIndexArrayEndSectionOffset
= indexes
[sectionHeader
->indexCount()-1].lsdaIndexArraySectionOffset();
766 uint32_t lsdaIndexArrayCount
= (lsdaIndexArrayEndSectionOffset
-lsdaIndexArraySectionOffset
)/sizeof(macho_unwind_info_section_header_lsda_index_entry
<P
>);
767 printf("\tLSDA table: (section offset 0x%08X, count=%u)\n", lsdaIndexArraySectionOffset
, lsdaIndexArrayCount
);
768 macho_unwind_info_section_header_lsda_index_entry
<P
>* lindex
= (macho_unwind_info_section_header_lsda_index_entry
<P
>*)§ionContent
[lsdaIndexArraySectionOffset
];
769 for (uint32_t i
=0; i
< lsdaIndexArrayCount
; ++i
) {
770 const char* name
= showFunctionNames
? functionName(lindex
[i
].functionOffset()+fMachHeaderAddress
) : "";
771 printf("\t\t[%3u] funcOffset=0x%08X, lsdaOffset=0x%08X, %s\n", i
, lindex
[i
].functionOffset(), lindex
[i
].lsdaOffset(), name
);
772 if ( *(((uint8_t*)fHeader
) + lindex
[i
].lsdaOffset()) != 0xFF )
773 fprintf(stderr
, "BAD LSDA entry (does not start with 0xFF) for %s\n", functionName(lindex
[i
].functionOffset()+fMachHeaderAddress
));
775 for (uint32_t i
=0; i
< sectionHeader
->indexCount()-1; ++i
) {
776 printf("\tsecond level index[%u] sectionOffset=0x%08X, count=%u, fileOffset=0x%08X\n", i
, indexes
[i
].secondLevelPagesSectionOffset(),
777 sectionHeader
->indexCount(), fUnwindSection
->offset()+indexes
[i
].secondLevelPagesSectionOffset());
778 macho_unwind_info_regular_second_level_page_header
<P
>* page
= (macho_unwind_info_regular_second_level_page_header
<P
>*)§ionContent
[indexes
[i
].secondLevelPagesSectionOffset()];
779 if ( page
->kind() == UNWIND_SECOND_LEVEL_REGULAR
) {
780 printf("\t\tkind=UNWIND_SECOND_LEVEL_REGULAR\n");
781 printf("\t\tentryPageOffset=0x%08X\n", page
->entryPageOffset());
782 printf("\t\tentryCount=0x%08X\n", page
->entryCount());
783 const macho_unwind_info_regular_second_level_entry
<P
>* entry
= (macho_unwind_info_regular_second_level_entry
<P
>*)((char*)page
+page
->entryPageOffset());
784 for (uint32_t j
=0; j
< page
->entryCount(); ++j
) {
785 uint32_t funcOffset
= entry
[j
].functionOffset();
786 if ( entry
[j
].encoding() & UNWIND_HAS_LSDA
) {
787 // verify there is a corresponding entry in lsda table
789 for (uint32_t k
=0; k
< lsdaIndexArrayCount
; ++k
) {
790 if ( lindex
[k
].functionOffset() == funcOffset
) {
796 fprintf(stderr
, "MISSING LSDA entry for %s\n", functionName(funcOffset
+fMachHeaderAddress
));
799 char encodingString
[100];
800 decode(entry
[j
].encoding(), ((const uint8_t*)fHeader
)+funcOffset
, encodingString
);
801 const char* name
= showFunctionNames
? functionName(funcOffset
+fMachHeaderAddress
) : "";
802 printf("\t\t\t[%3u] funcOffset=0x%08X, encoding=0x%08X (%-40s) %s\n",
803 j
, funcOffset
, entry
[j
].encoding(), encodingString
, name
);
806 else if ( page
->kind() == UNWIND_SECOND_LEVEL_COMPRESSED
) {
807 macho_unwind_info_compressed_second_level_page_header
<P
>* cp
= (macho_unwind_info_compressed_second_level_page_header
<P
>*)page
;
808 printf("\t\tkind=UNWIND_SECOND_LEVEL_COMPRESSED\n");
809 printf("\t\tentryPageOffset=0x%08X\n", cp
->entryPageOffset());
810 printf("\t\tentryCount=0x%08X\n", cp
->entryCount());
811 printf("\t\tencodingsPageOffset=0x%08X\n", cp
->encodingsPageOffset());
812 printf("\t\tencodingsCount=0x%08X\n", cp
->encodingsCount());
813 const uint32_t* entries
= (uint32_t*)(((uint8_t*)page
)+cp
->entryPageOffset());
814 const uint32_t* encodings
= (uint32_t*)(((uint8_t*)page
)+cp
->encodingsPageOffset());
815 const uint32_t baseFunctionOffset
= indexes
[i
].functionOffset();
816 for (uint32_t j
=0; j
< cp
->entryCount(); ++j
) {
817 uint8_t encodingIndex
= UNWIND_INFO_COMPRESSED_ENTRY_ENCODING_INDEX(entries
[j
]);
819 if ( encodingIndex
< sectionHeader
->commonEncodingsArrayCount() )
820 encoding
= A::P::E::get32(commonEncodings
[encodingIndex
]);
822 encoding
= A::P::E::get32(encodings
[encodingIndex
-sectionHeader
->commonEncodingsArrayCount()]);
823 char encodingString
[100];
824 uint32_t funcOff
= UNWIND_INFO_COMPRESSED_ENTRY_FUNC_OFFSET(entries
[j
])+baseFunctionOffset
;
825 decode(encoding
, ((const uint8_t*)fHeader
)+funcOff
, encodingString
);
826 const char* name
= showFunctionNames
? functionName(funcOff
+fMachHeaderAddress
) : "";
827 if ( encoding
& UNWIND_HAS_LSDA
) {
828 // verify there is a corresponding entry in lsda table
830 for (uint32_t k
=0; k
< lsdaIndexArrayCount
; ++k
) {
831 if ( lindex
[k
].functionOffset() == funcOff
) {
837 fprintf(stderr
, "MISSING LSDA entry for %s\n", name
);
840 printf("\t\t\t[%3u] funcOffset=0x%08X, encoding[%3u]=0x%08X (%-40s) %s\n",
841 j
, funcOff
, encodingIndex
, encoding
, encodingString
, name
);
845 fprintf(stderr
, "\t\tbad page header\n");
851 static void dump(const char* path
, const std::set
<cpu_type_t
>& onlyArchs
, bool showFunctionNames
)
853 struct stat stat_buf
;
856 int fd
= ::open(path
, O_RDONLY
, 0);
858 throw "cannot open file";
859 if ( ::fstat(fd
, &stat_buf
) != 0 )
860 throwf("fstat(%s) failed, errno=%d\n", path
, errno
);
861 uint32_t length
= stat_buf
.st_size
;
862 uint8_t* p
= (uint8_t*)::mmap(NULL
, stat_buf
.st_size
, PROT_READ
, MAP_FILE
| MAP_PRIVATE
, fd
, 0);
863 if ( p
== ((uint8_t*)(-1)) )
864 throw "cannot map file";
866 const mach_header
* mh
= (mach_header
*)p
;
867 if ( mh
->magic
== OSSwapBigToHostInt32(FAT_MAGIC
) ) {
868 const struct fat_header
* fh
= (struct fat_header
*)p
;
869 const struct fat_arch
* archs
= (struct fat_arch
*)(p
+ sizeof(struct fat_header
));
870 for (unsigned long i
=0; i
< OSSwapBigToHostInt32(fh
->nfat_arch
); ++i
) {
871 size_t offset
= OSSwapBigToHostInt32(archs
[i
].offset
);
872 size_t size
= OSSwapBigToHostInt32(archs
[i
].size
);
873 unsigned int cputype
= OSSwapBigToHostInt32(archs
[i
].cputype
);
874 if ( onlyArchs
.count(cputype
) ) {
877 if ( UnwindPrinter
<x86
>::validFile(p
+ offset
) )
878 UnwindPrinter
<x86
>::make(p
+ offset
, size
, path
, showFunctionNames
);
880 throw "in universal file, i386 slice does not contain i386 mach-o";
882 case CPU_TYPE_X86_64
:
883 if ( UnwindPrinter
<x86_64
>::validFile(p
+ offset
) )
884 UnwindPrinter
<x86_64
>::make(p
+ offset
, size
, path
, showFunctionNames
);
886 throw "in universal file, x86_64 slice does not contain x86_64 mach-o";
889 throwf("in universal file, unknown architecture slice 0x%x\n", cputype
);
894 else if ( UnwindPrinter
<x86
>::validFile(p
) && onlyArchs
.count(CPU_TYPE_I386
) ) {
895 UnwindPrinter
<x86
>::make(p
, length
, path
, showFunctionNames
);
897 else if ( UnwindPrinter
<x86_64
>::validFile(p
) && onlyArchs
.count(CPU_TYPE_X86_64
) ) {
898 UnwindPrinter
<x86_64
>::make(p
, length
, path
, showFunctionNames
);
901 throw "not a known file type";
904 catch (const char* msg
) {
905 throwf("%s in %s", msg
, path
);
910 int main(int argc
, const char* argv
[])
912 std::set
<cpu_type_t
> onlyArchs
;
913 std::vector
<const char*> files
;
914 bool showFunctionNames
= true;
917 for(int i
=1; i
< argc
; ++i
) {
918 const char* arg
= argv
[i
];
919 if ( arg
[0] == '-' ) {
920 if ( strcmp(arg
, "-arch") == 0 ) {
921 const char* arch
= argv
[++i
];
922 if ( strcmp(arch
, "i386") == 0 )
923 onlyArchs
.insert(CPU_TYPE_I386
);
924 else if ( strcmp(arch
, "x86_64") == 0 )
925 onlyArchs
.insert(CPU_TYPE_X86_64
);
927 throwf("unknown architecture %s", arch
);
929 else if ( strcmp(arg
, "-no_symbols") == 0 ) {
930 showFunctionNames
= false;
933 throwf("unknown option: %s\n", arg
);
937 files
.push_back(arg
);
941 // use all architectures if no restrictions specified
942 if ( onlyArchs
.size() == 0 ) {
943 onlyArchs
.insert(CPU_TYPE_I386
);
944 onlyArchs
.insert(CPU_TYPE_X86_64
);
948 for(std::vector
<const char*>::iterator it
=files
.begin(); it
!= files
.end(); ++it
) {
949 dump(*it
, onlyArchs
, showFunctionNames
);
953 catch (const char* msg
) {
954 fprintf(stderr
, "UnwindDump failed: %s\n", msg
);