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 <unordered_set> 
  38 #include "configure.h" 
  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
; 
  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
); 
  84         static const char*                                                      archName(); 
  85         static void                                                                     decode(uint32_t encoding
, const uint8_t* funcStart
, char* str
); 
  88         const macho_header
<P
>*                                          fHeader
; 
  90         const macho_section
<P
>*                                         fUnwindSection
; 
  92         const char*                                                                     fStringsEnd
; 
  93         const macho_nlist
<P
>*                                           fSymbols
; 
  94         uint32_t                                                                        fSymbolCount
; 
  95         pint_t                                                                          fMachHeaderAddress
; 
  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"; } 
 107 bool UnwindPrinter
<x86
>::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_I386 
) 
 114         switch (header
->filetype()) { 
 126 bool UnwindPrinter
<x86_64
>::validFile(const uint8_t* fileContent
) 
 128         const macho_header
<P
>* header 
= (const macho_header
<P
>*)fileContent
; 
 129         if ( header
->magic() != MH_MAGIC_64 
) 
 131         if ( header
->cputype() != CPU_TYPE_X86_64 
) 
 133         switch (header
->filetype()) { 
 145 #if SUPPORT_ARCH_arm64 
 147 bool UnwindPrinter
<arm64
>::validFile(const uint8_t* fileContent
) 
 149         const macho_header
<P
>* header 
= (const macho_header
<P
>*)fileContent
; 
 150         if ( header
->magic() != MH_MAGIC_64 
) 
 152         if ( header
->cputype() != CPU_TYPE_ARM64 
) 
 154         switch (header
->filetype()) { 
 168 bool UnwindPrinter
<arm
>::validFile(const uint8_t* fileContent
) 
 170         const macho_header
<P
>* header 
= (const macho_header
<P
>*)fileContent
; 
 171         if ( header
->magic() != MH_MAGIC 
) 
 173         if ( header
->cputype() != CPU_TYPE_ARM 
) 
 175         switch (header
->filetype()) { 
 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) 
 192         if ( ! validFile(fileContent
) ) 
 193                 throw "not a mach-o file that can be checked"; 
 195         fPath 
= strdup(path
); 
 196         fHeader 
= (const macho_header
<P
>*)fileContent
; 
 198         getSymbolTableInfo(); 
 200         if ( findUnwindSection() ) { 
 201                 if ( fHeader
->filetype() == MH_OBJECT 
)  
 202                         printObjectUnwindSection(showFunctionNames
); 
 204                         printUnwindSection(showFunctionNames
); 
 209 template <typename A
> 
 210 void UnwindPrinter
<A
>::getSymbolTableInfo() 
 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(); 
 231                 cmd 
= (const macho_load_command
<P
>*)endOfCmd
; 
 235 template <typename A
> 
 236 const char* UnwindPrinter
<A
>::functionName(pint_t addr
, uint32_t* offset
) 
 238         const macho_nlist
<P
>* closestSymbol 
= NULL
; 
 239         if ( offset 
!= NULL 
) 
 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()]; 
 249                         if ( fSymbols
[i
].n_desc() & N_ARM_THUMB_DEF 
)  
 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); 
 256                         else if ( offset 
!= NULL 
) { 
 257                                 if ( closestSymbol 
== NULL 
) { 
 258                                         if ( fSymbols
[i
].n_value() < addr 
) 
 259                                                 closestSymbol 
= &fSymbols
[i
]; 
 262                                         if ( (fSymbols
[i
].n_value() < addr
) && (fSymbols
[i
].n_value() > closestSymbol
->n_value()) ) 
 263                                                 closestSymbol 
= &fSymbols
[i
]; 
 268         if ( closestSymbol 
!= NULL 
) { 
 269                 *offset 
= addr 
- closestSymbol
->n_value(); 
 270                 return &fStrings
[closestSymbol
->n_strx()]; 
 272         return "--anonymous function--"; 
 277 template <typename A
> 
 278 bool UnwindPrinter
<A
>::findUnwindSection() 
 280         const char* unwindSectionName 
= "__unwind_info"; 
 281         const char* unwindSegmentName 
= "__TEXT"; 
 282         if ( fHeader
->filetype() == MH_OBJECT 
) { 
 283                 unwindSectionName 
= "__compact_unwind"; 
 284                 unwindSegmentName 
= "__LD"; 
 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 
= §ionsStart
[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
; 
 310                 cmd 
= (const macho_load_command
<P
>*)endOfCmd
; 
 315 #define EXTRACT_BITS(value, mask) \ 
 316         ( (value >> __builtin_ctz(mask)) & (((1 << __builtin_popcount(mask)))-1) ) 
 320 void UnwindPrinter
<x86_64
>::decode(uint32_t encoding
, const uint8_t* funcStart
, char* str
) 
 323         switch ( encoding 
& UNWIND_X86_64_MODE_MASK 
) { 
 324                 case UNWIND_X86_64_MODE_RBP_FRAME
: 
 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"); 
 332                                 sprintf(str
, "rbp frame, at -%d:", savedRegistersOffset
*8); 
 333                                 bool needComma 
= false; 
 334                                 for (int i
=0; i 
< 5; ++i
) { 
 339                                         switch (savedRegistersLocations 
& 0x7) { 
 340                                                 case UNWIND_X86_64_REG_NONE
: 
 343                                                 case UNWIND_X86_64_REG_RBX
: 
 346                                                 case UNWIND_X86_64_REG_R12
: 
 349                                                 case UNWIND_X86_64_REG_R13
: 
 352                                                 case UNWIND_X86_64_REG_R14
: 
 355                                                 case UNWIND_X86_64_REG_R15
: 
 361                                         savedRegistersLocations 
= (savedRegistersLocations 
>> 3); 
 362                                         if ( savedRegistersLocations 
== 0 ) 
 368                 case UNWIND_X86_64_MODE_STACK_IMMD
: 
 369                 case UNWIND_X86_64_MODE_STACK_IND
: 
 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
); 
 381                                 sprintf(str
, "stack size=%d, ", stackSize
*8); 
 383                         if ( regCount 
== 0 ) { 
 384                                 strcat(str
, "no registers saved"); 
 388                                 switch ( regCount 
) { 
 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
; 
 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
; 
 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
; 
 422                                                 permunreg
[0] = permutation
/20; 
 423                                                 permutation 
-= (permunreg
[0]*20); 
 424                                                 permunreg
[1] = permutation
/4; 
 425                                                 permutation 
-= (permunreg
[1]*4); 
 426                                                 permunreg
[2] = permutation
; 
 429                                                 permunreg
[0] = permutation
/5; 
 430                                                 permutation 
-= (permunreg
[0]*5); 
 431                                                 permunreg
[1] = permutation
; 
 434                                                 permunreg
[0] = permutation
; 
 437                                 // renumber registers back to standard numbers 
 439                                 bool used
[7] = { false, false, false, false, false, false, false }; 
 440                                 for (int i
=0; i 
< regCount
; ++i
) { 
 442                                         for (int u
=1; u 
< 7; ++u
) { 
 444                                                         if ( renum 
== permunreg
[i
] ) { 
 453                                 bool needComma 
= false; 
 454                                 for (int i
=0; i 
< regCount
; ++i
) { 
 459                                         switch ( registers
[i
] ) { 
 460                                                 case UNWIND_X86_64_REG_RBX
: 
 463                                                 case UNWIND_X86_64_REG_R12
: 
 466                                                 case UNWIND_X86_64_REG_R13
: 
 469                                                 case UNWIND_X86_64_REG_R14
: 
 472                                                 case UNWIND_X86_64_REG_R15
: 
 475                                                 case UNWIND_X86_64_REG_RBP
: 
 485                 case UNWIND_X86_64_MODE_DWARF
: 
 486                         sprintf(str
, "dwarf offset 0x%08X, ", encoding 
& UNWIND_X86_64_DWARF_SECTION_OFFSET
); 
 490                                 strcat(str
, "no unwind information"); 
 494         if ( encoding 
& UNWIND_HAS_LSDA 
) { 
 495                 strcat(str
, " LSDA"); 
 501 void UnwindPrinter
<x86
>::decode(uint32_t encoding
, const uint8_t* funcStart
, char* str
) 
 504         switch ( encoding 
& UNWIND_X86_MODE_MASK 
) { 
 505                 case UNWIND_X86_MODE_EBP_FRAME
: 
 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"); 
 513                                 sprintf(str
, "ebp frame, at -%d:", savedRegistersOffset
*4); 
 514                                 bool needComma 
= false; 
 515                                 for (int i
=0; i 
< 5; ++i
) { 
 520                                         switch (savedRegistersLocations 
& 0x7) { 
 521                                                 case UNWIND_X86_REG_NONE
: 
 524                                                 case UNWIND_X86_REG_EBX
: 
 527                                                 case UNWIND_X86_REG_ECX
: 
 530                                                 case UNWIND_X86_REG_EDX
: 
 533                                                 case UNWIND_X86_REG_EDI
: 
 536                                                 case UNWIND_X86_REG_ESI
: 
 542                                         savedRegistersLocations 
= (savedRegistersLocations 
>> 3); 
 543                                         if ( savedRegistersLocations 
== 0 ) 
 549                 case UNWIND_X86_MODE_STACK_IMMD
: 
 550                 case UNWIND_X86_MODE_STACK_IND
: 
 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
); 
 562                                 sprintf(str
, "stack size=%d, ", stackSize
*4); 
 564                         if ( regCount 
== 0 ) { 
 565                                 strcat(str
, "no saved regs"); 
 569                                 switch ( regCount 
) { 
 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
; 
 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
; 
 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
; 
 603                                                 permunreg
[0] = permutation
/20; 
 604                                                 permutation 
-= (permunreg
[0]*20); 
 605                                                 permunreg
[1] = permutation
/4; 
 606                                                 permutation 
-= (permunreg
[1]*4); 
 607                                                 permunreg
[2] = permutation
; 
 610                                                 permunreg
[0] = permutation
/5; 
 611                                                 permutation 
-= (permunreg
[0]*5); 
 612                                                 permunreg
[1] = permutation
; 
 615                                                 permunreg
[0] = permutation
; 
 618                                 // renumber registers back to standard numbers 
 620                                 bool used
[7] = { false, false, false, false, false, false, false }; 
 621                                 for (int i
=0; i 
< regCount
; ++i
) { 
 623                                         for (int u
=1; u 
< 7; ++u
) { 
 625                                                         if ( renum 
== permunreg
[i
] ) { 
 634                                 bool needComma 
= false; 
 635                                 for (int i
=0; i 
< regCount
; ++i
) { 
 640                                         switch ( registers
[i
] ) { 
 641                                                 case UNWIND_X86_REG_EBX
: 
 644                                                 case UNWIND_X86_REG_ECX
: 
 647                                                 case UNWIND_X86_REG_EDX
: 
 650                                                 case UNWIND_X86_REG_EDI
: 
 653                                                 case UNWIND_X86_REG_ESI
: 
 656                                                 case UNWIND_X86_REG_EBP
: 
 666                 case UNWIND_X86_MODE_DWARF
: 
 667                         sprintf(str
, "dwarf offset 0x%08X, ", encoding 
& UNWIND_X86_DWARF_SECTION_OFFSET
); 
 671                                 strcat(str
, "no unwind information"); 
 675         if ( encoding 
& UNWIND_HAS_LSDA 
) { 
 676                 strcat(str
, " LSDA"); 
 681 #if SUPPORT_ARCH_arm64 
 683 void UnwindPrinter
<arm64
>::decode(uint32_t encoding
, const uint8_t* funcStart
, char* str
) 
 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 "); 
 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 "); 
 713                 case UNWIND_ARM64_MODE_DWARF
: 
 714                         sprintf(str
, "dwarf offset 0x%08X, ", encoding 
& UNWIND_X86_64_DWARF_SECTION_OFFSET
); 
 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 "); 
 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 "); 
 762 void UnwindPrinter
<arm
>::decode(uint32_t encoding
, const uint8_t* funcStart
, char* str
) 
 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
); 
 769                 case UNWIND_ARM_MODE_FRAME
: 
 770                 case UNWIND_ARM_MODE_FRAME_D
: 
 771                         switch ( encoding 
& UNWIND_ARM_FRAME_STACK_ADJUST_MASK 
) { 
 773                                         strcpy(str
, "std frame: "); 
 776                                         strcat(str
, "std frame(sp adj 4): "); 
 779                                         strcat(str
, "std frame(sp adj 8): "); 
 782                                         strcat(str
, "std frame(sp adj 12): "); 
 785                         if ( encoding 
& UNWIND_ARM_FRAME_FIRST_PUSH_R4 
) 
 787                         if ( encoding 
& UNWIND_ARM_FRAME_FIRST_PUSH_R5 
) 
 789                         if ( encoding 
& UNWIND_ARM_FRAME_FIRST_PUSH_R6 
) 
 792                         if ( encoding 
& 0x000000F8)  
 794                         if ( encoding 
& UNWIND_ARM_FRAME_SECOND_PUSH_R8 
) 
 796                         if ( encoding 
& UNWIND_ARM_FRAME_SECOND_PUSH_R9 
) 
 798                         if ( encoding 
& UNWIND_ARM_FRAME_SECOND_PUSH_R10 
) 
 800                         if ( encoding 
& UNWIND_ARM_FRAME_SECOND_PUSH_R11 
) 
 802                         if ( encoding 
& UNWIND_ARM_FRAME_SECOND_PUSH_R12 
) 
 805                         if ( (encoding 
& UNWIND_ARM_MODE_MASK
) == UNWIND_ARM_MODE_FRAME_D 
) { 
 806                                 switch ( encoding 
& UNWIND_ARM_FRAME_D_REG_COUNT_MASK 
) { 
 808                                                 strcat(str
, " / d8 "); 
 811                                                 strcat(str
, " / d8,d10 "); 
 814                                                 strcat(str
, " / d8,d10,d12 "); 
 817                                                 strcat(str
, " / d8,d10,d12,d14 "); 
 820                                                 strcat(str
, " / d12,d14 / d8,d9,d10 "); 
 823                                                 strcat(str
, " / d14 / d8,d9,d10,d11,d12"); 
 826                                                 strcat(str
, " / d8,d9,d10,d11,d12,d13,d14 "); 
 829                                                 strcat(str
, " / d8,d9,d10,d11,d12,d13,d14 "); 
 832                                                 strcat(str
, " / unknown D register usage "); 
 840                                 strcpy(str
, "no unwind information"); 
 842                                 strcpy(str
, "unsupported compact unwind"); 
 849 const char* UnwindPrinter
<x86_64
>::personalityName(const macho_relocation_info
<x86_64::P
>* reloc
) 
 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()]; 
 858 const char* UnwindPrinter
<x86
>::personalityName(const macho_relocation_info
<x86::P
>* reloc
) 
 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()]; 
 866 #if SUPPORT_ARCH_arm64 
 868 const char* UnwindPrinter
<arm64
>::personalityName(const macho_relocation_info
<arm64::P
>* reloc
) 
 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()]; 
 879 const char* UnwindPrinter
<arm
>::personalityName(const macho_relocation_info
<arm::P
>* reloc
) 
 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()]; 
 887 template <typename A
> 
 888 bool UnwindPrinter
<A
>::hasExernReloc(uint64_t sectionOffset
, const char** personalityStr
, pint_t
* addr
) 
 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
); 
 896                                 *addr 
= fSymbols
[reloc
->r_symbolnum()].n_value(); 
 904 template <typename A
> 
 905 void UnwindPrinter
<A
>::printObjectUnwindSection(bool showFunctionNames
) 
 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
>)); 
 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
; 
 917                 uint32_t offsetInFunction
; 
 918                 if ( hasExernReloc(((char*)entry
-(char*)entriesStart
)+macho_compact_unwind_entry
<P
>::codeStartFieldOffset(), &functionNameStr
, &funcAddress
) ) { 
 919                         offsetInFunction 
= entry
->codeStart(); 
 922                         functionNameStr 
= this->functionName(entry
->codeStart(), &offsetInFunction
); 
 923                         funcAddress 
= entry
->codeStart(); 
 925                 if ( offsetInFunction 
== 0 ) 
 926                         printf("  start:        0x%08llX   %s\n", (uint64_t)funcAddress
, functionNameStr
); 
 928                         printf("  start:        0x%08llX   %s+0x%X\n", (uint64_t)funcAddress
+offsetInFunction
, functionNameStr
, offsetInFunction
); 
 930                 printf("  end:          0x%08llX   (len=0x%08X)\n", (uint64_t)(funcAddress
+offsetInFunction
+entry
->codeLen()), entry
->codeLen()); 
 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
); 
 936                 const char* personalityNameStr
; 
 937                 if ( hasExernReloc(((char*)entry
-(char*)entriesStart
)+macho_compact_unwind_entry
<P
>::personalityFieldOffset(), &personalityNameStr
) ) { 
 938                         printf("  personality:              %s\n", personalityNameStr
); 
 941                         printf("  personality:\n"); 
 943                 if ( entry
->lsda() == 0 ) { 
 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
); 
 952                                 printf("  lsda:         0x%08llX  %s+0x%X\n", (uint64_t)entry
->lsda(), lsdaName
, lsdaOffset
); 
 959 template <typename A
> 
 960 void UnwindPrinter
<A
>::printUnwindSection(bool showFunctionNames
) 
 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
); 
 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*)§ionContent
[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
])); 
 979         printf("\tpersonalities: (count=%u)\n", sectionHeader
->personalityArrayCount()); 
 980         const uint32_t* personalityArray 
= (uint32_t*)§ionContent
[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
])); 
 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
>*)§ionContent
[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()); 
 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
>*)§ionContent
[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
)); 
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
>*)§ionContent
[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 
1015                                         for (uint32_t k
=0; k 
< lsdaIndexArrayCount
; ++k
) { 
1016                                                 if ( lindex
[k
].functionOffset() == funcOffset 
) { 
1022                                                 fprintf(stderr
, "MISSING LSDA entry for %s\n", functionName(funcOffset
+fMachHeaderAddress
)); 
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
); 
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
]); 
1045                                 if ( encodingIndex 
< sectionHeader
->commonEncodingsArrayCount() ) 
1046                                         encoding 
=  A::P::E::get32(commonEncodings
[encodingIndex
]); 
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 
1056                                         for (uint32_t k
=0; k 
< lsdaIndexArrayCount
; ++k
) { 
1057                                                 if ( lindex
[k
].functionOffset() == funcOff 
) { 
1063                                                 fprintf(stderr
, "MISSING LSDA entry for %s\n", name
); 
1066                                 printf("\t\t\t[%3u] funcOffset=0x%08X, encoding[%3u]=0x%08X (%-56s) %s\n",  
1067                                         j
, funcOff
, encodingIndex
, encoding
, encodingString
, name
); 
1071                         fprintf(stderr
, "\t\tbad page header\n"); 
1077 static void dump(const char* path
, const std::set
<cpu_type_t
>& onlyArchs
, bool showFunctionNames
) 
1079         struct stat stat_buf
; 
1082                 int fd 
= ::open(path
, O_RDONLY
, 0); 
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"; 
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
) ) { 
1103                                                 if ( UnwindPrinter
<x86
>::validFile(p 
+ offset
) ) 
1104                                                         UnwindPrinter
<x86
>::make(p 
+ offset
, size
, path
, showFunctionNames
); 
1106                                                         throw "in universal file, i386 slice does not contain i386 mach-o"; 
1108                                         case CPU_TYPE_X86_64
: 
1109                                                 if ( UnwindPrinter
<x86_64
>::validFile(p 
+ offset
) ) 
1110                                                         UnwindPrinter
<x86_64
>::make(p 
+ offset
, size
, path
, showFunctionNames
); 
1112                                                         throw "in universal file, x86_64 slice does not contain x86_64 mach-o"; 
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
); 
1119                                                         throw "in universal file, arm64 slice does not contain arm64 mach-o"; 
1123                                                 if ( UnwindPrinter
<arm
>::validFile(p 
+ offset
) ) 
1124                                                         UnwindPrinter
<arm
>::make(p 
+ offset
, size
, path
, showFunctionNames
); 
1126                                                         throw "in universal file, arm slice does not contain arm mach-o"; 
1129                                                         throwf("in universal file, unknown architecture slice 0x%x\n", cputype
); 
1134                 else if ( UnwindPrinter
<x86
>::validFile(p
) && onlyArchs
.count(CPU_TYPE_I386
) ) { 
1135                         UnwindPrinter
<x86
>::make(p
, length
, path
, showFunctionNames
); 
1137                 else if ( UnwindPrinter
<x86_64
>::validFile(p
) && onlyArchs
.count(CPU_TYPE_X86_64
) ) { 
1138                         UnwindPrinter
<x86_64
>::make(p
, length
, path
, showFunctionNames
); 
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
); 
1145                 else if ( UnwindPrinter
<arm
>::validFile(p
) && onlyArchs
.count(CPU_TYPE_ARM
) ) { 
1146                         UnwindPrinter
<arm
>::make(p
, length
, path
, showFunctionNames
); 
1149                         throw "not a known file type"; 
1152         catch (const char* msg
) { 
1153                 throwf("%s in %s", msg
, path
); 
1158 int main(int argc
, const char* argv
[]) 
1160         std::set
<cpu_type_t
> onlyArchs
; 
1161         std::vector
<const char*> files
; 
1162         bool showFunctionNames 
= true; 
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
); 
1178                                         else if ( strcmp(arch
, "armv7k") == 0 ) 
1179                                                 onlyArchs
.insert(CPU_TYPE_ARM
); 
1181                                                 throwf("unknown architecture %s", arch
); 
1183                                 else if ( strcmp(arg
, "-no_symbols") == 0 ) { 
1184                                         showFunctionNames 
= false; 
1187                                         throwf("unknown option: %s\n", arg
); 
1191                                 files
.push_back(arg
); 
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
); 
1202                         onlyArchs
.insert(CPU_TYPE_ARM
); 
1205                 // process each file 
1206                 for(std::vector
<const char*>::iterator it
=files
.begin(); it 
!= files
.end(); ++it
) { 
1207                         dump(*it
, onlyArchs
, showFunctionNames
); 
1211         catch (const char* msg
) { 
1212                 fprintf(stderr
, "UnwindDump failed: %s\n", msg
);