1 /* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
3 * Copyright (c) 2008 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 getSymbolTableInfo();
87 const char* functionName(pint_t addr
);
88 static const char* archName();
89 static void decode(uint32_t encoding
, const uint8_t* funcStart
, char* str
);
92 const macho_header
<P
>* fHeader
;
94 const macho_section
<P
>* fUnwindSection
;
96 const char* fStringsEnd
;
97 const macho_nlist
<P
>* fSymbols
;
98 uint32_t fSymbolCount
;
99 pint_t fMachHeaderAddress
;
103 template <> const char* UnwindPrinter
<ppc
>::archName() { return "ppc"; }
104 template <> const char* UnwindPrinter
<ppc64
>::archName() { return "ppc64"; }
105 template <> const char* UnwindPrinter
<x86
>::archName() { return "i386"; }
106 template <> const char* UnwindPrinter
<x86_64
>::archName() { return "x86_64"; }
107 template <> const char* UnwindPrinter
<arm
>::archName() { return "arm"; }
110 bool UnwindPrinter
<ppc
>::validFile(const uint8_t* fileContent
)
112 const macho_header
<P
>* header
= (const macho_header
<P
>*)fileContent
;
113 if ( header
->magic() != MH_MAGIC
)
115 if ( header
->cputype() != CPU_TYPE_POWERPC
)
117 switch (header
->filetype()) {
128 bool UnwindPrinter
<ppc64
>::validFile(const uint8_t* fileContent
)
130 const macho_header
<P
>* header
= (const macho_header
<P
>*)fileContent
;
131 if ( header
->magic() != MH_MAGIC_64
)
133 if ( header
->cputype() != CPU_TYPE_POWERPC64
)
135 switch (header
->filetype()) {
146 bool UnwindPrinter
<x86
>::validFile(const uint8_t* fileContent
)
148 const macho_header
<P
>* header
= (const macho_header
<P
>*)fileContent
;
149 if ( header
->magic() != MH_MAGIC
)
151 if ( header
->cputype() != CPU_TYPE_I386
)
153 switch (header
->filetype()) {
164 bool UnwindPrinter
<x86_64
>::validFile(const uint8_t* fileContent
)
166 const macho_header
<P
>* header
= (const macho_header
<P
>*)fileContent
;
167 if ( header
->magic() != MH_MAGIC_64
)
169 if ( header
->cputype() != CPU_TYPE_X86_64
)
171 switch (header
->filetype()) {
182 bool UnwindPrinter
<arm
>::validFile(const uint8_t* fileContent
)
184 const macho_header
<P
>* header
= (const macho_header
<P
>*)fileContent
;
185 if ( header
->magic() != MH_MAGIC
)
187 if ( header
->cputype() != CPU_TYPE_ARM
)
189 switch (header
->filetype()) {
200 template <typename A
>
201 UnwindPrinter
<A
>::UnwindPrinter(const uint8_t* fileContent
, uint32_t fileLength
, const char* path
, bool showFunctionNames
)
202 : fHeader(NULL
), fLength(fileLength
), fUnwindSection(NULL
),
203 fStrings(NULL
), fStringsEnd(NULL
), fSymbols(NULL
), fSymbolCount(0), fMachHeaderAddress(0)
206 if ( ! validFile(fileContent
) )
207 throw "not a mach-o file that can be checked";
209 fPath
= strdup(path
);
210 fHeader
= (const macho_header
<P
>*)fileContent
;
212 getSymbolTableInfo();
214 if ( findUnwindSection() )
215 printUnwindSection(showFunctionNames
);
219 template <typename A
>
220 void UnwindPrinter
<A
>::getSymbolTableInfo()
222 const uint8_t* const endOfFile
= (uint8_t*)fHeader
+ fLength
;
223 const uint8_t* const endOfLoadCommands
= (uint8_t*)fHeader
+ sizeof(macho_header
<P
>) + fHeader
->sizeofcmds();
224 const uint32_t cmd_count
= fHeader
->ncmds();
225 const macho_load_command
<P
>* const cmds
= (macho_load_command
<P
>*)((uint8_t*)fHeader
+ sizeof(macho_header
<P
>));
226 const macho_load_command
<P
>* cmd
= cmds
;
227 for (uint32_t i
= 0; i
< cmd_count
; ++i
) {
228 uint32_t size
= cmd
->cmdsize();
229 const uint8_t* endOfCmd
= ((uint8_t*)cmd
)+cmd
->cmdsize();
230 if ( endOfCmd
> endOfLoadCommands
)
231 throwf("load command #%d extends beyond the end of the load commands", i
);
232 if ( endOfCmd
> endOfFile
)
233 throwf("load command #%d extends beyond the end of the file", i
);
234 if ( cmd
->cmd() == LC_SYMTAB
) {
235 const macho_symtab_command
<P
>* symtab
= (macho_symtab_command
<P
>*)cmd
;
236 fSymbolCount
= symtab
->nsyms();
237 fSymbols
= (const macho_nlist
<P
>*)((char*)fHeader
+ symtab
->symoff());
238 fStrings
= (char*)fHeader
+ symtab
->stroff();
239 fStringsEnd
= fStrings
+ symtab
->strsize();
241 cmd
= (const macho_load_command
<P
>*)endOfCmd
;
245 template <typename A
>
246 const char* UnwindPrinter
<A
>::functionName(pint_t addr
)
248 for (uint32_t i
=0; i
< fSymbolCount
; ++i
) {
249 uint8_t type
= fSymbols
[i
].n_type();
250 if ( ((type
& N_STAB
) == 0) && ((type
& N_TYPE
) == N_SECT
) ) {
251 if ( fSymbols
[i
].n_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);
258 return "--anonymous function--";
263 template <typename A
>
264 bool UnwindPrinter
<A
>::findUnwindSection()
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
= §ionsStart
[segCmd
->nsects()];
282 for(const macho_section
<P
>* sect
= sectionsStart
; sect
< sectionsEnd
; ++sect
) {
283 if ( (strcmp(sect
->sectname(), "__unwind_info") == 0) && (strcmp(sect
->segname(), "__TEXT") == 0) ) {
284 fUnwindSection
= sect
;
285 fMachHeaderAddress
= segCmd
->vmaddr();
286 return fUnwindSection
;
290 cmd
= (const macho_load_command
<P
>*)endOfCmd
;
295 #define EXTRACT_BITS(value, mask) \
296 ( (value >> __builtin_ctz(mask)) & (((1 << __builtin_popcount(mask)))-1) )
300 void UnwindPrinter
<x86_64
>::decode(uint32_t encoding
, const uint8_t* funcStart
, char* str
)
303 switch ( encoding
& UNWIND_X86_64_MODE_MASK
) {
304 case UNWIND_X86_64_MODE_RBP_FRAME
:
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");
312 sprintf(str
, "rbp frame, at -%d:", savedRegistersOffset
*8);
313 bool needComma
= false;
314 for (int i
=0; i
< 5; ++i
) {
319 switch (savedRegistersLocations
& 0x7) {
320 case UNWIND_X86_64_REG_NONE
:
323 case UNWIND_X86_64_REG_RBX
:
326 case UNWIND_X86_64_REG_R12
:
329 case UNWIND_X86_64_REG_R13
:
332 case UNWIND_X86_64_REG_R14
:
335 case UNWIND_X86_64_REG_R15
:
341 savedRegistersLocations
= (savedRegistersLocations
>> 3);
342 if ( savedRegistersLocations
== 0 )
348 case UNWIND_X86_64_MODE_STACK_IMMD
:
349 case UNWIND_X86_64_MODE_STACK_IND
:
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
);
361 sprintf(str
, "stack size=%d, ", stackSize
*8);
363 if ( regCount
== 0 ) {
364 strcat(str
, "no registers saved");
368 switch ( regCount
) {
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
;
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
;
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
;
402 permunreg
[0] = permutation
/20;
403 permutation
-= (permunreg
[0]*20);
404 permunreg
[1] = permutation
/4;
405 permutation
-= (permunreg
[1]*4);
406 permunreg
[2] = permutation
;
409 permunreg
[0] = permutation
/5;
410 permutation
-= (permunreg
[0]*5);
411 permunreg
[1] = permutation
;
414 permunreg
[0] = permutation
;
417 // renumber registers back to standard numbers
419 bool used
[7] = { false, false, false, false, false, false, false };
420 for (int i
=0; i
< regCount
; ++i
) {
422 for (int u
=1; u
< 7; ++u
) {
424 if ( renum
== permunreg
[i
] ) {
433 bool needComma
= false;
434 for (int i
=0; i
< regCount
; ++i
) {
439 switch ( registers
[i
] ) {
440 case UNWIND_X86_64_REG_RBX
:
443 case UNWIND_X86_64_REG_R12
:
446 case UNWIND_X86_64_REG_R13
:
449 case UNWIND_X86_64_REG_R14
:
452 case UNWIND_X86_64_REG_R15
:
455 case UNWIND_X86_64_REG_RBP
:
465 case UNWIND_X86_64_MODE_DWARF
:
466 sprintf(str
, "dwarf offset 0x%08X, ", encoding
& UNWIND_X86_64_DWARF_SECTION_OFFSET
);
470 strcat(str
, "no unwind information");
474 if ( encoding
& UNWIND_HAS_LSDA
) {
475 strcat(str
, " LSDA");
481 void UnwindPrinter
<x86
>::decode(uint32_t encoding
, const uint8_t* funcStart
, char* str
)
484 switch ( encoding
& UNWIND_X86_MODE_MASK
) {
485 case UNWIND_X86_MODE_EBP_FRAME
:
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");
493 sprintf(str
, "ebp frame, at -%d:", savedRegistersOffset
*4);
494 bool needComma
= false;
495 for (int i
=0; i
< 5; ++i
) {
500 switch (savedRegistersLocations
& 0x7) {
501 case UNWIND_X86_REG_NONE
:
504 case UNWIND_X86_REG_EBX
:
507 case UNWIND_X86_REG_ECX
:
510 case UNWIND_X86_REG_EDX
:
513 case UNWIND_X86_REG_EDI
:
516 case UNWIND_X86_REG_ESI
:
522 savedRegistersLocations
= (savedRegistersLocations
>> 3);
523 if ( savedRegistersLocations
== 0 )
529 case UNWIND_X86_MODE_STACK_IMMD
:
530 case UNWIND_X86_MODE_STACK_IND
:
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
);
542 sprintf(str
, "stack size=%d, ", stackSize
*4);
544 if ( regCount
== 0 ) {
545 strcat(str
, "no saved regs");
549 switch ( regCount
) {
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
;
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
;
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
;
583 permunreg
[0] = permutation
/20;
584 permutation
-= (permunreg
[0]*20);
585 permunreg
[1] = permutation
/4;
586 permutation
-= (permunreg
[1]*4);
587 permunreg
[2] = permutation
;
590 permunreg
[0] = permutation
/5;
591 permutation
-= (permunreg
[0]*5);
592 permunreg
[1] = permutation
;
595 permunreg
[0] = permutation
;
598 // renumber registers back to standard numbers
600 bool used
[7] = { false, false, false, false, false, false, false };
601 for (int i
=0; i
< regCount
; ++i
) {
603 for (int u
=1; u
< 7; ++u
) {
605 if ( renum
== permunreg
[i
] ) {
614 bool needComma
= false;
615 for (int i
=0; i
< regCount
; ++i
) {
620 switch ( registers
[i
] ) {
621 case UNWIND_X86_REG_EBX
:
624 case UNWIND_X86_REG_ECX
:
627 case UNWIND_X86_REG_EDX
:
630 case UNWIND_X86_REG_EDI
:
633 case UNWIND_X86_REG_ESI
:
636 case UNWIND_X86_REG_EBP
:
646 case UNWIND_X86_MODE_DWARF
:
647 sprintf(str
, "dwarf offset 0x%08X, ", encoding
& UNWIND_X86_DWARF_SECTION_OFFSET
);
651 strcat(str
, "no unwind information");
655 if ( encoding
& UNWIND_HAS_LSDA
) {
656 strcat(str
, " LSDA");
662 template <typename A
>
663 void UnwindPrinter
<A
>::decode(uint32_t encoding
, const uint8_t* funcStart
, char* str
)
669 template <typename A
>
670 void UnwindPrinter
<A
>::printUnwindSection(bool showFunctionNames
)
672 const uint8_t* sectionContent
= (uint8_t*)fHeader
+ fUnwindSection
->offset();
673 macho_unwind_info_section_header
<P
>* sectionHeader
= (macho_unwind_info_section_header
<P
>*)(sectionContent
);
675 printf("Arch: %s, Section: __TEXT,__unwind_info (addr=0x%08llX, size=0x%08llX, fileOffset=0x%08X)\n",
676 archName(), fUnwindSection
->addr(), fUnwindSection
->size(), fUnwindSection
->offset());
677 printf("\tversion=0x%08X\n", sectionHeader
->version());
678 printf("\tcommonEncodingsArraySectionOffset=0x%08X\n", sectionHeader
->commonEncodingsArraySectionOffset());
679 printf("\tcommonEncodingsArrayCount=0x%08X\n", sectionHeader
->commonEncodingsArrayCount());
680 printf("\tpersonalityArraySectionOffset=0x%08X\n", sectionHeader
->personalityArraySectionOffset());
681 printf("\tpersonalityArrayCount=0x%08X\n", sectionHeader
->personalityArrayCount());
682 printf("\tindexSectionOffset=0x%08X\n", sectionHeader
->indexSectionOffset());
683 printf("\tindexCount=0x%08X\n", sectionHeader
->indexCount());
684 printf("\tcommon encodings: (count=%u)\n", sectionHeader
->commonEncodingsArrayCount());
685 const uint32_t* commonEncodings
= (uint32_t*)§ionContent
[sectionHeader
->commonEncodingsArraySectionOffset()];
686 for (uint32_t i
=0; i
< sectionHeader
->commonEncodingsArrayCount(); ++i
) {
687 printf("\t\tencoding[%3u]=0x%08X\n", i
, A::P::E::get32(commonEncodings
[i
]));
689 printf("\tpersonalities: (count=%u)\n", sectionHeader
->personalityArrayCount());
690 const uint32_t* personalityArray
= (uint32_t*)§ionContent
[sectionHeader
->personalityArraySectionOffset()];
691 for (uint32_t i
=0; i
< sectionHeader
->personalityArrayCount(); ++i
) {
692 printf("\t\t[%2u]=0x%08X\n", i
+1, A::P::E::get32(personalityArray
[i
]));
694 printf("\tfirst level index: (count=%u)\n", sectionHeader
->indexCount());
695 macho_unwind_info_section_header_index_entry
<P
>* indexes
= (macho_unwind_info_section_header_index_entry
<P
>*)§ionContent
[sectionHeader
->indexSectionOffset()];
696 for (uint32_t i
=0; i
< sectionHeader
->indexCount(); ++i
) {
697 printf("\t\t[%2u] funcOffset=0x%08X, pageOffset=0x%08X, lsdaOffset=0x%08X\n",
698 i
, indexes
[i
].functionOffset(), indexes
[i
].secondLevelPagesSectionOffset(), indexes
[i
].lsdaIndexArraySectionOffset());
700 uint32_t lsdaIndexArraySectionOffset
= indexes
[0].lsdaIndexArraySectionOffset();
701 uint32_t lsdaIndexArrayEndSectionOffset
= indexes
[sectionHeader
->indexCount()-1].lsdaIndexArraySectionOffset();
702 uint32_t lsdaIndexArrayCount
= (lsdaIndexArrayEndSectionOffset
-lsdaIndexArraySectionOffset
)/sizeof(macho_unwind_info_section_header_lsda_index_entry
<P
>);
703 printf("\tLSDA table: (section offset 0x%08X, count=%u)\n", lsdaIndexArraySectionOffset
, lsdaIndexArrayCount
);
704 macho_unwind_info_section_header_lsda_index_entry
<P
>* lindex
= (macho_unwind_info_section_header_lsda_index_entry
<P
>*)§ionContent
[lsdaIndexArraySectionOffset
];
705 for (uint32_t i
=0; i
< lsdaIndexArrayCount
; ++i
) {
706 const char* name
= showFunctionNames
? functionName(lindex
[i
].functionOffset()+fMachHeaderAddress
) : "";
707 printf("\t\t[%3u] funcOffset=0x%08X, lsdaOffset=0x%08X, %s\n", i
, lindex
[i
].functionOffset(), lindex
[i
].lsdaOffset(), name
);
708 if ( *(((uint8_t*)fHeader
) + lindex
[i
].lsdaOffset()) != 0xFF )
709 fprintf(stderr
, "BAD LSDA entry (does not start with 0xFF) for %s\n", functionName(lindex
[i
].functionOffset()+fMachHeaderAddress
));
711 for (uint32_t i
=0; i
< sectionHeader
->indexCount()-1; ++i
) {
712 printf("\tsecond level index[%u] sectionOffset=0x%08X, count=%u, fileOffset=0x%08X\n", i
, indexes
[i
].secondLevelPagesSectionOffset(),
713 sectionHeader
->indexCount(), fUnwindSection
->offset()+indexes
[i
].secondLevelPagesSectionOffset());
714 macho_unwind_info_regular_second_level_page_header
<P
>* page
= (macho_unwind_info_regular_second_level_page_header
<P
>*)§ionContent
[indexes
[i
].secondLevelPagesSectionOffset()];
715 if ( page
->kind() == UNWIND_SECOND_LEVEL_REGULAR
) {
716 printf("\t\tkind=UNWIND_SECOND_LEVEL_REGULAR\n");
717 printf("\t\tentryPageOffset=0x%08X\n", page
->entryPageOffset());
718 printf("\t\tentryCount=0x%08X\n", page
->entryCount());
719 const macho_unwind_info_regular_second_level_entry
<P
>* entry
= (macho_unwind_info_regular_second_level_entry
<P
>*)((char*)page
+page
->entryPageOffset());
720 for (uint32_t j
=0; j
< page
->entryCount(); ++j
) {
721 uint32_t funcOffset
= entry
[j
].functionOffset();
722 if ( entry
[j
].encoding() & UNWIND_HAS_LSDA
) {
723 // verify there is a corresponding entry in lsda table
725 for (uint32_t k
=0; k
< lsdaIndexArrayCount
; ++k
) {
726 if ( lindex
[k
].functionOffset() == funcOffset
) {
732 fprintf(stderr
, "MISSING LSDA entry for %s\n", functionName(funcOffset
+fMachHeaderAddress
));
735 char encodingString
[100];
736 decode(entry
[j
].encoding(), ((const uint8_t*)fHeader
)+funcOffset
, encodingString
);
737 const char* name
= showFunctionNames
? functionName(funcOffset
+fMachHeaderAddress
) : "";
738 printf("\t\t\t[%3u] funcOffset=0x%08X, encoding=0x%08X (%-40s) %s\n",
739 j
, funcOffset
, entry
[j
].encoding(), encodingString
, name
);
742 else if ( page
->kind() == UNWIND_SECOND_LEVEL_COMPRESSED
) {
743 macho_unwind_info_compressed_second_level_page_header
<P
>* cp
= (macho_unwind_info_compressed_second_level_page_header
<P
>*)page
;
744 printf("\t\tkind=UNWIND_SECOND_LEVEL_COMPRESSED\n");
745 printf("\t\tentryPageOffset=0x%08X\n", cp
->entryPageOffset());
746 printf("\t\tentryCount=0x%08X\n", cp
->entryCount());
747 printf("\t\tencodingsPageOffset=0x%08X\n", cp
->encodingsPageOffset());
748 printf("\t\tencodingsCount=0x%08X\n", cp
->encodingsCount());
749 const uint32_t* entries
= (uint32_t*)(((uint8_t*)page
)+cp
->entryPageOffset());
750 const uint32_t* encodings
= (uint32_t*)(((uint8_t*)page
)+cp
->encodingsPageOffset());
751 const uint32_t baseFunctionOffset
= indexes
[i
].functionOffset();
752 for (uint32_t j
=0; j
< cp
->entryCount(); ++j
) {
753 uint8_t encodingIndex
= UNWIND_INFO_COMPRESSED_ENTRY_ENCODING_INDEX(entries
[j
]);
755 if ( encodingIndex
< sectionHeader
->commonEncodingsArrayCount() )
756 encoding
= A::P::E::get32(commonEncodings
[encodingIndex
]);
758 encoding
= A::P::E::get32(encodings
[encodingIndex
-sectionHeader
->commonEncodingsArrayCount()]);
759 char encodingString
[100];
760 uint32_t funcOff
= UNWIND_INFO_COMPRESSED_ENTRY_FUNC_OFFSET(entries
[j
])+baseFunctionOffset
;
761 decode(encoding
, ((const uint8_t*)fHeader
)+funcOff
, encodingString
);
762 const char* name
= showFunctionNames
? functionName(funcOff
+fMachHeaderAddress
) : "";
763 if ( encoding
& UNWIND_HAS_LSDA
) {
764 // verify there is a corresponding entry in lsda table
766 for (uint32_t k
=0; k
< lsdaIndexArrayCount
; ++k
) {
767 if ( lindex
[k
].functionOffset() == funcOff
) {
773 fprintf(stderr
, "MISSING LSDA entry for %s\n", name
);
776 printf("\t\t\t[%3u] funcOffset=0x%08X, encoding[%3u]=0x%08X (%-40s) %s\n",
777 j
, funcOff
, encodingIndex
, encoding
, encodingString
, name
);
781 fprintf(stderr
, "\t\tbad page header\n");
787 static void dump(const char* path
, const std::set
<cpu_type_t
>& onlyArchs
, bool showFunctionNames
)
789 struct stat stat_buf
;
792 int fd
= ::open(path
, O_RDONLY
, 0);
794 throw "cannot open file";
795 if ( ::fstat(fd
, &stat_buf
) != 0 )
796 throwf("fstat(%s) failed, errno=%d\n", path
, errno
);
797 uint32_t length
= stat_buf
.st_size
;
798 uint8_t* p
= (uint8_t*)::mmap(NULL
, stat_buf
.st_size
, PROT_READ
, MAP_FILE
| MAP_PRIVATE
, fd
, 0);
799 if ( p
== ((uint8_t*)(-1)) )
800 throw "cannot map file";
802 const mach_header
* mh
= (mach_header
*)p
;
803 if ( mh
->magic
== OSSwapBigToHostInt32(FAT_MAGIC
) ) {
804 const struct fat_header
* fh
= (struct fat_header
*)p
;
805 const struct fat_arch
* archs
= (struct fat_arch
*)(p
+ sizeof(struct fat_header
));
806 for (unsigned long i
=0; i
< OSSwapBigToHostInt32(fh
->nfat_arch
); ++i
) {
807 size_t offset
= OSSwapBigToHostInt32(archs
[i
].offset
);
808 size_t size
= OSSwapBigToHostInt32(archs
[i
].size
);
809 unsigned int cputype
= OSSwapBigToHostInt32(archs
[i
].cputype
);
810 if ( onlyArchs
.count(cputype
) ) {
812 case CPU_TYPE_POWERPC
:
813 if ( UnwindPrinter
<ppc
>::validFile(p
+ offset
) )
814 UnwindPrinter
<ppc
>::make(p
+ offset
, size
, path
, showFunctionNames
);
816 throw "in universal file, ppc slice does not contain ppc mach-o";
819 if ( UnwindPrinter
<x86
>::validFile(p
+ offset
) )
820 UnwindPrinter
<x86
>::make(p
+ offset
, size
, path
, showFunctionNames
);
822 throw "in universal file, i386 slice does not contain i386 mach-o";
824 case CPU_TYPE_POWERPC64
:
825 if ( UnwindPrinter
<ppc64
>::validFile(p
+ offset
) )
826 UnwindPrinter
<ppc64
>::make(p
+ offset
, size
, path
, showFunctionNames
);
828 throw "in universal file, ppc64 slice does not contain ppc64 mach-o";
830 case CPU_TYPE_X86_64
:
831 if ( UnwindPrinter
<x86_64
>::validFile(p
+ offset
) )
832 UnwindPrinter
<x86_64
>::make(p
+ offset
, size
, path
, showFunctionNames
);
834 throw "in universal file, x86_64 slice does not contain x86_64 mach-o";
837 if ( UnwindPrinter
<arm
>::validFile(p
+ offset
) )
838 UnwindPrinter
<arm
>::make(p
+ offset
, size
, path
, showFunctionNames
);
840 throw "in universal file, arm slice does not contain arm mach-o";
843 throwf("in universal file, unknown architecture slice 0x%x\n", cputype
);
848 else if ( UnwindPrinter
<x86
>::validFile(p
) && onlyArchs
.count(CPU_TYPE_I386
) ) {
849 UnwindPrinter
<x86
>::make(p
, length
, path
, showFunctionNames
);
851 else if ( UnwindPrinter
<ppc
>::validFile(p
) && onlyArchs
.count(CPU_TYPE_POWERPC
) ) {
852 UnwindPrinter
<ppc
>::make(p
, length
, path
, showFunctionNames
);
854 else if ( UnwindPrinter
<ppc64
>::validFile(p
) && onlyArchs
.count(CPU_TYPE_POWERPC64
) ) {
855 UnwindPrinter
<ppc64
>::make(p
, length
, path
, showFunctionNames
);
857 else if ( UnwindPrinter
<x86_64
>::validFile(p
) && onlyArchs
.count(CPU_TYPE_X86_64
) ) {
858 UnwindPrinter
<x86_64
>::make(p
, length
, path
, showFunctionNames
);
860 else if ( UnwindPrinter
<arm
>::validFile(p
) && onlyArchs
.count(CPU_TYPE_ARM
) ) {
861 UnwindPrinter
<arm
>::make(p
, length
, path
, showFunctionNames
);
864 throw "not a known file type";
867 catch (const char* msg
) {
868 throwf("%s in %s", msg
, path
);
873 int main(int argc
, const char* argv
[])
875 std::set
<cpu_type_t
> onlyArchs
;
876 std::vector
<const char*> files
;
877 bool showFunctionNames
= true;
880 for(int i
=1; i
< argc
; ++i
) {
881 const char* arg
= argv
[i
];
882 if ( arg
[0] == '-' ) {
883 if ( strcmp(arg
, "-arch") == 0 ) {
884 const char* arch
= argv
[++i
];
885 if ( strcmp(arch
, "ppc") == 0 )
886 onlyArchs
.insert(CPU_TYPE_POWERPC
);
887 else if ( strcmp(arch
, "ppc64") == 0 )
888 onlyArchs
.insert(CPU_TYPE_POWERPC64
);
889 else if ( strcmp(arch
, "i386") == 0 )
890 onlyArchs
.insert(CPU_TYPE_I386
);
891 else if ( strcmp(arch
, "x86_64") == 0 )
892 onlyArchs
.insert(CPU_TYPE_X86_64
);
893 else if ( strcmp(arch
, "arm") == 0 )
894 onlyArchs
.insert(CPU_TYPE_ARM
);
896 throwf("unknown architecture %s", arch
);
898 else if ( strcmp(arg
, "-no_symbols") == 0 ) {
899 showFunctionNames
= false;
902 throwf("unknown option: %s\n", arg
);
906 files
.push_back(arg
);
910 // use all architectures if no restrictions specified
911 if ( onlyArchs
.size() == 0 ) {
912 onlyArchs
.insert(CPU_TYPE_POWERPC
);
913 onlyArchs
.insert(CPU_TYPE_POWERPC64
);
914 onlyArchs
.insert(CPU_TYPE_I386
);
915 onlyArchs
.insert(CPU_TYPE_X86_64
);
916 onlyArchs
.insert(CPU_TYPE_ARM
);
920 for(std::vector
<const char*>::iterator it
=files
.begin(); it
!= files
.end(); ++it
) {
921 dump(*it
, onlyArchs
, showFunctionNames
);
925 catch (const char* msg
) {
926 fprintf(stderr
, "UnwindDump failed: %s\n", msg
);