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
, const char* path
)
63 { return new UnwindPrinter
<A
>(fileContent
, fileLength
, path
); }
64 virtual ~UnwindPrinter() {}
68 typedef typename
A::P P
;
69 typedef typename
A::P::E E
;
70 typedef typename
A::P::uint_t pint_t
;
75 bool operator()(const char* left
, const char* right
) const { return (strcmp(left
, right
) == 0); }
78 typedef __gnu_cxx::hash_set
<const char*, __gnu_cxx::hash
<const char*>, CStringEquals
> StringSet
;
80 UnwindPrinter(const uint8_t* fileContent
, uint32_t fileLength
, const char* path
);
81 bool findUnwindSection();
82 void printUnwindSection();
83 void getSymbolTableInfo();
84 const char* functionName(pint_t addr
);
85 static const char* archName();
86 static void decode(uint32_t encoding
, const uint8_t* funcStart
, char* str
);
89 const macho_header
<P
>* fHeader
;
91 const macho_section
<P
>* fUnwindSection
;
93 const char* fStringsEnd
;
94 const macho_nlist
<P
>* fSymbols
;
95 uint32_t fSymbolCount
;
96 pint_t fMachHeaderAddress
;
100 template <> const char* UnwindPrinter
<ppc
>::archName() { return "ppc"; }
101 template <> const char* UnwindPrinter
<ppc64
>::archName() { return "ppc64"; }
102 template <> const char* UnwindPrinter
<x86
>::archName() { return "i386"; }
103 template <> const char* UnwindPrinter
<x86_64
>::archName() { return "x86_64"; }
104 template <> const char* UnwindPrinter
<arm
>::archName() { return "arm"; }
107 bool UnwindPrinter
<ppc
>::validFile(const uint8_t* fileContent
)
109 const macho_header
<P
>* header
= (const macho_header
<P
>*)fileContent
;
110 if ( header
->magic() != MH_MAGIC
)
112 if ( header
->cputype() != CPU_TYPE_POWERPC
)
114 switch (header
->filetype()) {
125 bool UnwindPrinter
<ppc64
>::validFile(const uint8_t* fileContent
)
127 const macho_header
<P
>* header
= (const macho_header
<P
>*)fileContent
;
128 if ( header
->magic() != MH_MAGIC_64
)
130 if ( header
->cputype() != CPU_TYPE_POWERPC64
)
132 switch (header
->filetype()) {
143 bool UnwindPrinter
<x86
>::validFile(const uint8_t* fileContent
)
145 const macho_header
<P
>* header
= (const macho_header
<P
>*)fileContent
;
146 if ( header
->magic() != MH_MAGIC
)
148 if ( header
->cputype() != CPU_TYPE_I386
)
150 switch (header
->filetype()) {
161 bool UnwindPrinter
<x86_64
>::validFile(const uint8_t* fileContent
)
163 const macho_header
<P
>* header
= (const macho_header
<P
>*)fileContent
;
164 if ( header
->magic() != MH_MAGIC_64
)
166 if ( header
->cputype() != CPU_TYPE_X86_64
)
168 switch (header
->filetype()) {
179 bool UnwindPrinter
<arm
>::validFile(const uint8_t* fileContent
)
181 const macho_header
<P
>* header
= (const macho_header
<P
>*)fileContent
;
182 if ( header
->magic() != MH_MAGIC
)
184 if ( header
->cputype() != CPU_TYPE_ARM
)
186 switch (header
->filetype()) {
197 template <typename A
>
198 UnwindPrinter
<A
>::UnwindPrinter(const uint8_t* fileContent
, uint32_t fileLength
, const char* path
)
199 : fHeader(NULL
), fLength(fileLength
), fUnwindSection(NULL
),
200 fStrings(NULL
), fStringsEnd(NULL
), fSymbols(NULL
), fSymbolCount(0), fMachHeaderAddress(0)
203 if ( ! validFile(fileContent
) )
204 throw "not a mach-o file that can be checked";
206 fPath
= strdup(path
);
207 fHeader
= (const macho_header
<P
>*)fileContent
;
209 getSymbolTableInfo();
211 if ( findUnwindSection() )
212 printUnwindSection();
216 template <typename A
>
217 void UnwindPrinter
<A
>::getSymbolTableInfo()
219 const uint8_t* const endOfFile
= (uint8_t*)fHeader
+ fLength
;
220 const uint8_t* const endOfLoadCommands
= (uint8_t*)fHeader
+ sizeof(macho_header
<P
>) + fHeader
->sizeofcmds();
221 const uint32_t cmd_count
= fHeader
->ncmds();
222 const macho_load_command
<P
>* const cmds
= (macho_load_command
<P
>*)((uint8_t*)fHeader
+ sizeof(macho_header
<P
>));
223 const macho_load_command
<P
>* cmd
= cmds
;
224 for (uint32_t i
= 0; i
< cmd_count
; ++i
) {
225 uint32_t size
= cmd
->cmdsize();
226 const uint8_t* endOfCmd
= ((uint8_t*)cmd
)+cmd
->cmdsize();
227 if ( endOfCmd
> endOfLoadCommands
)
228 throwf("load command #%d extends beyond the end of the load commands", i
);
229 if ( endOfCmd
> endOfFile
)
230 throwf("load command #%d extends beyond the end of the file", i
);
231 if ( cmd
->cmd() == LC_SYMTAB
) {
232 const macho_symtab_command
<P
>* symtab
= (macho_symtab_command
<P
>*)cmd
;
233 fSymbolCount
= symtab
->nsyms();
234 fSymbols
= (const macho_nlist
<P
>*)((char*)fHeader
+ symtab
->symoff());
235 fStrings
= (char*)fHeader
+ symtab
->stroff();
236 fStringsEnd
= fStrings
+ symtab
->strsize();
238 cmd
= (const macho_load_command
<P
>*)endOfCmd
;
242 template <typename A
>
243 const char* UnwindPrinter
<A
>::functionName(pint_t addr
)
245 for (uint32_t i
=0; i
< fSymbolCount
; ++i
) {
246 uint8_t type
= fSymbols
[i
].n_type();
247 if ( ((type
& N_STAB
) == 0) && ((type
& N_TYPE
) == N_SECT
) ) {
248 if ( fSymbols
[i
].n_value() == addr
) {
249 const char* r
= &fStrings
[fSymbols
[i
].n_strx()];
250 //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);
255 return "--anonymous function--";
260 template <typename A
>
261 bool UnwindPrinter
<A
>::findUnwindSection()
263 const uint8_t* const endOfFile
= (uint8_t*)fHeader
+ fLength
;
264 const uint8_t* const endOfLoadCommands
= (uint8_t*)fHeader
+ sizeof(macho_header
<P
>) + fHeader
->sizeofcmds();
265 const uint32_t cmd_count
= fHeader
->ncmds();
266 const macho_load_command
<P
>* const cmds
= (macho_load_command
<P
>*)((uint8_t*)fHeader
+ sizeof(macho_header
<P
>));
267 const macho_load_command
<P
>* cmd
= cmds
;
268 for (uint32_t i
= 0; i
< cmd_count
; ++i
) {
269 uint32_t size
= cmd
->cmdsize();
270 const uint8_t* endOfCmd
= ((uint8_t*)cmd
)+cmd
->cmdsize();
271 if ( endOfCmd
> endOfLoadCommands
)
272 throwf("load command #%d extends beyond the end of the load commands", i
);
273 if ( endOfCmd
> endOfFile
)
274 throwf("load command #%d extends beyond the end of the file", i
);
275 if ( cmd
->cmd() == macho_segment_command
<P
>::CMD
) {
276 const macho_segment_command
<P
>* segCmd
= (const macho_segment_command
<P
>*)cmd
;
277 const macho_section
<P
>* const sectionsStart
= (macho_section
<P
>*)((char*)segCmd
+ sizeof(macho_segment_command
<P
>));
278 const macho_section
<P
>* const sectionsEnd
= §ionsStart
[segCmd
->nsects()];
279 for(const macho_section
<P
>* sect
= sectionsStart
; sect
< sectionsEnd
; ++sect
) {
280 if ( (strcmp(sect
->sectname(), "__unwind_info") == 0) && (strcmp(sect
->segname(), "__TEXT") == 0) ) {
281 fUnwindSection
= sect
;
282 fMachHeaderAddress
= segCmd
->vmaddr();
283 return fUnwindSection
;
287 cmd
= (const macho_load_command
<P
>*)endOfCmd
;
292 #define EXTRACT_BITS(value, mask) \
293 ( (value >> __builtin_ctz(mask)) & (((1 << __builtin_popcount(mask)))-1) )
297 void UnwindPrinter
<x86_64
>::decode(uint32_t encoding
, const uint8_t* funcStart
, char* str
)
300 switch ( encoding
& UNWIND_X86_64_MODE_MASK
) {
301 case UNWIND_X86_64_MODE_RBP_FRAME
:
303 uint32_t savedRegistersOffset
= EXTRACT_BITS(encoding
, UNWIND_X86_64_RBP_FRAME_OFFSET
);
304 uint32_t savedRegistersLocations
= EXTRACT_BITS(encoding
, UNWIND_X86_64_RBP_FRAME_REGISTERS
);
305 if ( savedRegistersLocations
== 0 ) {
306 strcpy(str
, "rbp frame, no saved registers");
309 sprintf(str
, "rbp frame, at -%d:", savedRegistersOffset
*8);
310 bool needComma
= false;
311 for (int i
=0; i
< 5; ++i
) {
316 switch (savedRegistersLocations
& 0x7) {
317 case UNWIND_X86_64_REG_NONE
:
320 case UNWIND_X86_64_REG_RBX
:
323 case UNWIND_X86_64_REG_R12
:
326 case UNWIND_X86_64_REG_R13
:
329 case UNWIND_X86_64_REG_R14
:
332 case UNWIND_X86_64_REG_R15
:
338 savedRegistersLocations
= (savedRegistersLocations
>> 3);
339 if ( savedRegistersLocations
== 0 )
345 case UNWIND_X86_64_MODE_STACK_IMMD
:
346 case UNWIND_X86_64_MODE_STACK_IND
:
348 uint32_t stackSize
= EXTRACT_BITS(encoding
, UNWIND_X86_64_FRAMELESS_STACK_SIZE
);
349 uint32_t stackAdjust
= EXTRACT_BITS(encoding
, UNWIND_X86_64_FRAMELESS_STACK_ADJUST
);
350 uint32_t regCount
= EXTRACT_BITS(encoding
, UNWIND_X86_64_FRAMELESS_STACK_REG_COUNT
);
351 uint32_t permutation
= EXTRACT_BITS(encoding
, UNWIND_X86_64_FRAMELESS_STACK_REG_PERMUTATION
);
352 if ( (encoding
& UNWIND_X86_64_MODE_MASK
) == UNWIND_X86_64_MODE_STACK_IND
) {
353 // stack size is encoded in subl $xxx,%esp instruction
354 uint32_t subl
= x86_64::P::E::get32(*((uint32_t*)(funcStart
+stackSize
)));
355 sprintf(str
, "stack size=0x%08X, ", subl
+ 8*stackAdjust
);
358 sprintf(str
, "stack size=%d, ", stackSize
*8);
360 if ( regCount
== 0 ) {
361 strcat(str
, "no registers saved");
365 switch ( regCount
) {
367 permunreg
[0] = permutation
/120;
368 permutation
-= (permunreg
[0]*120);
369 permunreg
[1] = permutation
/24;
370 permutation
-= (permunreg
[1]*24);
371 permunreg
[2] = permutation
/6;
372 permutation
-= (permunreg
[2]*6);
373 permunreg
[3] = permutation
/2;
374 permutation
-= (permunreg
[3]*2);
375 permunreg
[4] = permutation
;
379 permunreg
[0] = permutation
/120;
380 permutation
-= (permunreg
[0]*120);
381 permunreg
[1] = permutation
/24;
382 permutation
-= (permunreg
[1]*24);
383 permunreg
[2] = permutation
/6;
384 permutation
-= (permunreg
[2]*6);
385 permunreg
[3] = permutation
/2;
386 permutation
-= (permunreg
[3]*2);
387 permunreg
[4] = permutation
;
390 permunreg
[0] = permutation
/60;
391 permutation
-= (permunreg
[0]*60);
392 permunreg
[1] = permutation
/12;
393 permutation
-= (permunreg
[1]*12);
394 permunreg
[2] = permutation
/3;
395 permutation
-= (permunreg
[2]*3);
396 permunreg
[3] = permutation
;
399 permunreg
[0] = permutation
/20;
400 permutation
-= (permunreg
[0]*20);
401 permunreg
[1] = permutation
/4;
402 permutation
-= (permunreg
[1]*4);
403 permunreg
[2] = permutation
;
406 permunreg
[0] = permutation
/5;
407 permutation
-= (permunreg
[0]*5);
408 permunreg
[1] = permutation
;
411 permunreg
[0] = permutation
;
414 // renumber registers back to standard numbers
416 bool used
[7] = { false, false, false, false, false, false, false };
417 for (int i
=0; i
< regCount
; ++i
) {
419 for (int u
=1; u
< 7; ++u
) {
421 if ( renum
== permunreg
[i
] ) {
430 bool needComma
= false;
431 for (int i
=0; i
< regCount
; ++i
) {
436 switch ( registers
[i
] ) {
437 case UNWIND_X86_64_REG_RBX
:
440 case UNWIND_X86_64_REG_R12
:
443 case UNWIND_X86_64_REG_R13
:
446 case UNWIND_X86_64_REG_R14
:
449 case UNWIND_X86_64_REG_R15
:
452 case UNWIND_X86_64_REG_RBP
:
462 case UNWIND_X86_64_MODE_DWARF
:
463 sprintf(str
, "dwarf offset 0x%08X, ", encoding
& UNWIND_X86_64_DWARF_SECTION_OFFSET
);
467 strcat(str
, "no unwind information");
471 if ( encoding
& UNWIND_HAS_LSDA
) {
472 strcat(str
, " LSDA");
478 void UnwindPrinter
<x86
>::decode(uint32_t encoding
, const uint8_t* funcStart
, char* str
)
481 switch ( encoding
& UNWIND_X86_MODE_MASK
) {
482 case UNWIND_X86_MODE_EBP_FRAME
:
484 uint32_t savedRegistersOffset
= EXTRACT_BITS(encoding
, UNWIND_X86_EBP_FRAME_OFFSET
);
485 uint32_t savedRegistersLocations
= EXTRACT_BITS(encoding
, UNWIND_X86_EBP_FRAME_REGISTERS
);
486 if ( savedRegistersLocations
== 0 ) {
487 strcpy(str
, "ebp frame, no saved registers");
490 sprintf(str
, "ebp frame, at -%d:", savedRegistersOffset
*4);
491 bool needComma
= false;
492 for (int i
=0; i
< 5; ++i
) {
497 switch (savedRegistersLocations
& 0x7) {
498 case UNWIND_X86_REG_NONE
:
501 case UNWIND_X86_REG_EBX
:
504 case UNWIND_X86_REG_ECX
:
507 case UNWIND_X86_REG_EDX
:
510 case UNWIND_X86_REG_EDI
:
513 case UNWIND_X86_REG_ESI
:
519 savedRegistersLocations
= (savedRegistersLocations
>> 3);
520 if ( savedRegistersLocations
== 0 )
526 case UNWIND_X86_MODE_STACK_IMMD
:
527 case UNWIND_X86_MODE_STACK_IND
:
529 uint32_t stackSize
= EXTRACT_BITS(encoding
, UNWIND_X86_FRAMELESS_STACK_SIZE
);
530 uint32_t stackAdjust
= EXTRACT_BITS(encoding
, UNWIND_X86_FRAMELESS_STACK_ADJUST
);
531 uint32_t regCount
= EXTRACT_BITS(encoding
, UNWIND_X86_FRAMELESS_STACK_REG_COUNT
);
532 uint32_t permutation
= EXTRACT_BITS(encoding
, UNWIND_X86_FRAMELESS_STACK_REG_PERMUTATION
);
533 if ( (encoding
& UNWIND_X86_MODE_MASK
) == UNWIND_X86_MODE_STACK_IND
) {
534 // stack size is encoded in subl $xxx,%esp instruction
535 uint32_t subl
= x86::P::E::get32(*((uint32_t*)(funcStart
+stackSize
)));
536 sprintf(str
, "stack size=0x%08X, ", subl
+4*stackAdjust
);
539 sprintf(str
, "stack size=%d, ", stackSize
*4);
541 if ( regCount
== 0 ) {
542 strcat(str
, "no saved regs");
546 switch ( regCount
) {
548 permunreg
[0] = permutation
/120;
549 permutation
-= (permunreg
[0]*120);
550 permunreg
[1] = permutation
/24;
551 permutation
-= (permunreg
[1]*24);
552 permunreg
[2] = permutation
/6;
553 permutation
-= (permunreg
[2]*6);
554 permunreg
[3] = permutation
/2;
555 permutation
-= (permunreg
[3]*2);
556 permunreg
[4] = permutation
;
560 permunreg
[0] = permutation
/120;
561 permutation
-= (permunreg
[0]*120);
562 permunreg
[1] = permutation
/24;
563 permutation
-= (permunreg
[1]*24);
564 permunreg
[2] = permutation
/6;
565 permutation
-= (permunreg
[2]*6);
566 permunreg
[3] = permutation
/2;
567 permutation
-= (permunreg
[3]*2);
568 permunreg
[4] = permutation
;
571 permunreg
[0] = permutation
/60;
572 permutation
-= (permunreg
[0]*60);
573 permunreg
[1] = permutation
/12;
574 permutation
-= (permunreg
[1]*12);
575 permunreg
[2] = permutation
/3;
576 permutation
-= (permunreg
[2]*3);
577 permunreg
[3] = permutation
;
580 permunreg
[0] = permutation
/20;
581 permutation
-= (permunreg
[0]*20);
582 permunreg
[1] = permutation
/4;
583 permutation
-= (permunreg
[1]*4);
584 permunreg
[2] = permutation
;
587 permunreg
[0] = permutation
/5;
588 permutation
-= (permunreg
[0]*5);
589 permunreg
[1] = permutation
;
592 permunreg
[0] = permutation
;
595 // renumber registers back to standard numbers
597 bool used
[7] = { false, false, false, false, false, false, false };
598 for (int i
=0; i
< regCount
; ++i
) {
600 for (int u
=1; u
< 7; ++u
) {
602 if ( renum
== permunreg
[i
] ) {
611 bool needComma
= false;
612 for (int i
=0; i
< regCount
; ++i
) {
617 switch ( registers
[i
] ) {
618 case UNWIND_X86_REG_EBX
:
621 case UNWIND_X86_REG_ECX
:
624 case UNWIND_X86_REG_EDX
:
627 case UNWIND_X86_REG_EDI
:
630 case UNWIND_X86_REG_ESI
:
633 case UNWIND_X86_REG_EBP
:
643 case UNWIND_X86_MODE_DWARF
:
644 sprintf(str
, "dwarf offset 0x%08X, ", encoding
& UNWIND_X86_DWARF_SECTION_OFFSET
);
648 strcat(str
, "no unwind information");
652 if ( encoding
& UNWIND_HAS_LSDA
) {
653 strcat(str
, " LSDA");
659 template <typename A
>
660 void UnwindPrinter
<A
>::decode(uint32_t encoding
, const uint8_t* funcStart
, char* str
)
666 template <typename A
>
667 void UnwindPrinter
<A
>::printUnwindSection()
669 const uint8_t* sectionContent
= (uint8_t*)fHeader
+ fUnwindSection
->offset();
670 macho_unwind_info_section_header
<P
>* sectionHeader
= (macho_unwind_info_section_header
<P
>*)(sectionContent
);
672 printf("Arch: %s, Section: __TEXT,__unwind_info (addr=0x%08llX, size=0x%08llX, fileOffset=0x%08X)\n",
673 archName(), fUnwindSection
->addr(), fUnwindSection
->size(), fUnwindSection
->offset());
674 printf("\tversion=0x%08X\n", sectionHeader
->version());
675 printf("\tcommonEncodingsArraySectionOffset=0x%08X\n", sectionHeader
->commonEncodingsArraySectionOffset());
676 printf("\tcommonEncodingsArrayCount=0x%08X\n", sectionHeader
->commonEncodingsArrayCount());
677 printf("\tpersonalityArraySectionOffset=0x%08X\n", sectionHeader
->personalityArraySectionOffset());
678 printf("\tpersonalityArrayCount=0x%08X\n", sectionHeader
->personalityArrayCount());
679 printf("\tindexSectionOffset=0x%08X\n", sectionHeader
->indexSectionOffset());
680 printf("\tindexCount=0x%08X\n", sectionHeader
->indexCount());
681 printf("\tcommon encodings: (count=%u)\n", sectionHeader
->commonEncodingsArrayCount());
682 const uint32_t* commonEncodings
= (uint32_t*)§ionContent
[sectionHeader
->commonEncodingsArraySectionOffset()];
683 for (uint32_t i
=0; i
< sectionHeader
->commonEncodingsArrayCount(); ++i
) {
684 printf("\t\tencoding[%3u]=0x%08X\n", i
, A::P::E::get32(commonEncodings
[i
]));
686 printf("\tpersonalities: (count=%u)\n", sectionHeader
->personalityArrayCount());
687 const uint32_t* personalityArray
= (uint32_t*)§ionContent
[sectionHeader
->personalityArraySectionOffset()];
688 for (uint32_t i
=0; i
< sectionHeader
->personalityArrayCount(); ++i
) {
689 printf("\t\t[%2u]=0x%08X\n", i
+1, A::P::E::get32(personalityArray
[i
]));
691 printf("\tfirst level index: (count=%u)\n", sectionHeader
->indexCount());
692 macho_unwind_info_section_header_index_entry
<P
>* indexes
= (macho_unwind_info_section_header_index_entry
<P
>*)§ionContent
[sectionHeader
->indexSectionOffset()];
693 for (uint32_t i
=0; i
< sectionHeader
->indexCount(); ++i
) {
694 printf("\t\t[%2u] funcOffset=0x%08X, pageOffset=0x%08X, lsdaOffset=0x%08X\n",
695 i
, indexes
[i
].functionOffset(), indexes
[i
].secondLevelPagesSectionOffset(), indexes
[i
].lsdaIndexArraySectionOffset());
697 uint32_t lsdaIndexArraySectionOffset
= indexes
[0].lsdaIndexArraySectionOffset();
698 uint32_t lsdaIndexArrayEndSectionOffset
= indexes
[sectionHeader
->indexCount()-1].lsdaIndexArraySectionOffset();
699 uint32_t lsdaIndexArrayCount
= (lsdaIndexArrayEndSectionOffset
-lsdaIndexArraySectionOffset
)/sizeof(macho_unwind_info_section_header_lsda_index_entry
<P
>);
700 printf("\tLSDA table: (section offset 0x%08X, count=%u)\n", lsdaIndexArraySectionOffset
, lsdaIndexArrayCount
);
701 macho_unwind_info_section_header_lsda_index_entry
<P
>* lindex
= (macho_unwind_info_section_header_lsda_index_entry
<P
>*)§ionContent
[lsdaIndexArraySectionOffset
];
702 for (uint32_t i
=0; i
< lsdaIndexArrayCount
; ++i
) {
703 printf("\t\t[%3u] funcOffset=0x%08X, lsdaOffset=0x%08X, %s\n",
704 i
, lindex
[i
].functionOffset(), lindex
[i
].lsdaOffset(), functionName(lindex
[i
].functionOffset()+fMachHeaderAddress
));
705 if ( *(((uint8_t*)fHeader
) + lindex
[i
].lsdaOffset()) != 0xFF )
706 fprintf(stderr
, "BAD LSDA entry (does not start with 0xFF) for %s\n", functionName(lindex
[i
].functionOffset()+fMachHeaderAddress
));
708 for (uint32_t i
=0; i
< sectionHeader
->indexCount()-1; ++i
) {
709 printf("\tsecond level index[%u] sectionOffset=0x%08X, count=%u, fileOffset=0x%08X\n", i
, indexes
[i
].secondLevelPagesSectionOffset(),
710 sectionHeader
->indexCount(), fUnwindSection
->offset()+indexes
[i
].secondLevelPagesSectionOffset());
711 macho_unwind_info_regular_second_level_page_header
<P
>* page
= (macho_unwind_info_regular_second_level_page_header
<P
>*)§ionContent
[indexes
[i
].secondLevelPagesSectionOffset()];
712 if ( page
->kind() == UNWIND_SECOND_LEVEL_REGULAR
) {
713 printf("\t\tkind=UNWIND_SECOND_LEVEL_REGULAR\n");
714 printf("\t\tentryPageOffset=0x%08X\n", page
->entryPageOffset());
715 printf("\t\tentryCount=0x%08X\n", page
->entryCount());
716 const macho_unwind_info_regular_second_level_entry
<P
>* entry
= (macho_unwind_info_regular_second_level_entry
<P
>*)((char*)page
+page
->entryPageOffset());
717 for (uint32_t j
=0; j
< page
->entryCount(); ++j
) {
718 uint32_t funcOffset
= entry
[j
].functionOffset();
719 if ( entry
[j
].encoding() & UNWIND_HAS_LSDA
) {
720 // verify there is a corresponding entry in lsda table
722 for (uint32_t k
=0; k
< lsdaIndexArrayCount
; ++k
) {
723 if ( lindex
[k
].functionOffset() == funcOffset
) {
729 fprintf(stderr
, "MISSING LSDA entry for %s\n", functionName(funcOffset
+fMachHeaderAddress
));
732 char encodingString
[100];
733 decode(entry
[j
].encoding(), ((const uint8_t*)fHeader
)+funcOffset
, encodingString
);
734 printf("\t\t\t[%3u] funcOffset=0x%08X, encoding=0x%08X (%-40s) %s\n",
735 j
, funcOffset
, entry
[j
].encoding(), encodingString
, functionName(funcOffset
+fMachHeaderAddress
));
738 else if ( page
->kind() == UNWIND_SECOND_LEVEL_COMPRESSED
) {
739 macho_unwind_info_compressed_second_level_page_header
<P
>* cp
= (macho_unwind_info_compressed_second_level_page_header
<P
>*)page
;
740 printf("\t\tkind=UNWIND_SECOND_LEVEL_COMPRESSED\n");
741 printf("\t\tentryPageOffset=0x%08X\n", cp
->entryPageOffset());
742 printf("\t\tentryCount=0x%08X\n", cp
->entryCount());
743 printf("\t\tencodingsPageOffset=0x%08X\n", cp
->encodingsPageOffset());
744 printf("\t\tencodingsCount=0x%08X\n", cp
->encodingsCount());
745 const uint32_t* entries
= (uint32_t*)(((uint8_t*)page
)+cp
->entryPageOffset());
746 const uint32_t* encodings
= (uint32_t*)(((uint8_t*)page
)+cp
->encodingsPageOffset());
747 const uint32_t baseFunctionOffset
= indexes
[i
].functionOffset();
748 for (uint32_t j
=0; j
< cp
->entryCount(); ++j
) {
749 uint8_t encodingIndex
= UNWIND_INFO_COMPRESSED_ENTRY_ENCODING_INDEX(entries
[j
]);
751 if ( encodingIndex
< sectionHeader
->commonEncodingsArrayCount() )
752 encoding
= A::P::E::get32(commonEncodings
[encodingIndex
]);
754 encoding
= A::P::E::get32(encodings
[encodingIndex
-sectionHeader
->commonEncodingsArrayCount()]);
755 char encodingString
[100];
756 uint32_t funcOff
= UNWIND_INFO_COMPRESSED_ENTRY_FUNC_OFFSET(entries
[j
])+baseFunctionOffset
;
757 decode(encoding
, ((const uint8_t*)fHeader
)+funcOff
, encodingString
);
758 const char* name
= functionName(funcOff
+fMachHeaderAddress
);
759 if ( encoding
& UNWIND_HAS_LSDA
) {
760 // verify there is a corresponding entry in lsda table
762 for (uint32_t k
=0; k
< lsdaIndexArrayCount
; ++k
) {
763 if ( lindex
[k
].functionOffset() == funcOff
) {
769 fprintf(stderr
, "MISSING LSDA entry for %s\n", name
);
772 printf("\t\t\t[%3u] funcOffset=0x%08X, encoding[%3u]=0x%08X (%-40s) %s\n",
773 j
, funcOff
, encodingIndex
, encoding
, encodingString
, name
);
777 fprintf(stderr
, "\t\tbad page header\n");
783 static void dump(const char* path
, const std::set
<cpu_type_t
>& onlyArchs
)
785 struct stat stat_buf
;
788 int fd
= ::open(path
, O_RDONLY
, 0);
790 throw "cannot open file";
791 if ( ::fstat(fd
, &stat_buf
) != 0 )
792 throwf("fstat(%s) failed, errno=%d\n", path
, errno
);
793 uint32_t length
= stat_buf
.st_size
;
794 uint8_t* p
= (uint8_t*)::mmap(NULL
, stat_buf
.st_size
, PROT_READ
, MAP_FILE
| MAP_PRIVATE
, fd
, 0);
795 if ( p
== ((uint8_t*)(-1)) )
796 throw "cannot map file";
798 const mach_header
* mh
= (mach_header
*)p
;
799 if ( mh
->magic
== OSSwapBigToHostInt32(FAT_MAGIC
) ) {
800 const struct fat_header
* fh
= (struct fat_header
*)p
;
801 const struct fat_arch
* archs
= (struct fat_arch
*)(p
+ sizeof(struct fat_header
));
802 for (unsigned long i
=0; i
< OSSwapBigToHostInt32(fh
->nfat_arch
); ++i
) {
803 size_t offset
= OSSwapBigToHostInt32(archs
[i
].offset
);
804 size_t size
= OSSwapBigToHostInt32(archs
[i
].size
);
805 unsigned int cputype
= OSSwapBigToHostInt32(archs
[i
].cputype
);
806 if ( onlyArchs
.count(cputype
) ) {
808 case CPU_TYPE_POWERPC
:
809 if ( UnwindPrinter
<ppc
>::validFile(p
+ offset
) )
810 UnwindPrinter
<ppc
>::make(p
+ offset
, size
, path
);
812 throw "in universal file, ppc slice does not contain ppc mach-o";
815 if ( UnwindPrinter
<x86
>::validFile(p
+ offset
) )
816 UnwindPrinter
<x86
>::make(p
+ offset
, size
, path
);
818 throw "in universal file, i386 slice does not contain i386 mach-o";
820 case CPU_TYPE_POWERPC64
:
821 if ( UnwindPrinter
<ppc64
>::validFile(p
+ offset
) )
822 UnwindPrinter
<ppc64
>::make(p
+ offset
, size
, path
);
824 throw "in universal file, ppc64 slice does not contain ppc64 mach-o";
826 case CPU_TYPE_X86_64
:
827 if ( UnwindPrinter
<x86_64
>::validFile(p
+ offset
) )
828 UnwindPrinter
<x86_64
>::make(p
+ offset
, size
, path
);
830 throw "in universal file, x86_64 slice does not contain x86_64 mach-o";
833 if ( UnwindPrinter
<arm
>::validFile(p
+ offset
) )
834 UnwindPrinter
<arm
>::make(p
+ offset
, size
, path
);
836 throw "in universal file, arm slice does not contain arm mach-o";
839 throwf("in universal file, unknown architecture slice 0x%x\n", cputype
);
844 else if ( UnwindPrinter
<x86
>::validFile(p
) && onlyArchs
.count(CPU_TYPE_I386
) ) {
845 UnwindPrinter
<x86
>::make(p
, length
, path
);
847 else if ( UnwindPrinter
<ppc
>::validFile(p
) && onlyArchs
.count(CPU_TYPE_POWERPC
) ) {
848 UnwindPrinter
<ppc
>::make(p
, length
, path
);
850 else if ( UnwindPrinter
<ppc64
>::validFile(p
) && onlyArchs
.count(CPU_TYPE_POWERPC64
) ) {
851 UnwindPrinter
<ppc64
>::make(p
, length
, path
);
853 else if ( UnwindPrinter
<x86_64
>::validFile(p
) && onlyArchs
.count(CPU_TYPE_X86_64
) ) {
854 UnwindPrinter
<x86_64
>::make(p
, length
, path
);
856 else if ( UnwindPrinter
<arm
>::validFile(p
) && onlyArchs
.count(CPU_TYPE_ARM
) ) {
857 UnwindPrinter
<arm
>::make(p
, length
, path
);
860 throw "not a known file type";
863 catch (const char* msg
) {
864 throwf("%s in %s", msg
, path
);
869 int main(int argc
, const char* argv
[])
871 std::set
<cpu_type_t
> onlyArchs
;
872 std::vector
<const char*> files
;
875 for(int i
=1; i
< argc
; ++i
) {
876 const char* arg
= argv
[i
];
877 if ( arg
[0] == '-' ) {
878 if ( strcmp(arg
, "-arch") == 0 ) {
879 const char* arch
= argv
[++i
];
880 if ( strcmp(arch
, "ppc") == 0 )
881 onlyArchs
.insert(CPU_TYPE_POWERPC
);
882 else if ( strcmp(arch
, "ppc64") == 0 )
883 onlyArchs
.insert(CPU_TYPE_POWERPC64
);
884 else if ( strcmp(arch
, "i386") == 0 )
885 onlyArchs
.insert(CPU_TYPE_I386
);
886 else if ( strcmp(arch
, "x86_64") == 0 )
887 onlyArchs
.insert(CPU_TYPE_X86_64
);
888 else if ( strcmp(arch
, "arm") == 0 )
889 onlyArchs
.insert(CPU_TYPE_ARM
);
891 throwf("unknown architecture %s", arch
);
894 throwf("unknown option: %s\n", arg
);
898 files
.push_back(arg
);
902 // use all architectures if no restrictions specified
903 if ( onlyArchs
.size() == 0 ) {
904 onlyArchs
.insert(CPU_TYPE_POWERPC
);
905 onlyArchs
.insert(CPU_TYPE_POWERPC64
);
906 onlyArchs
.insert(CPU_TYPE_I386
);
907 onlyArchs
.insert(CPU_TYPE_X86_64
);
908 onlyArchs
.insert(CPU_TYPE_ARM
);
912 for(std::vector
<const char*>::iterator it
=files
.begin(); it
!= files
.end(); ++it
) {
913 dump(*it
, onlyArchs
);
917 catch (const char* msg
) {
918 fprintf(stderr
, "UnwindDump failed: %s\n", msg
);