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
);