]> git.saurik.com Git - apple/ld64.git/blobdiff - src/other/unwinddump.cpp
ld64-409.12.tar.gz
[apple/ld64.git] / src / other / unwinddump.cpp
index 90605570149ca17895aebb3367b56823a9a73bb0..70d4c9a6b37fe8a7663ab3aae763b232b926f29d 100644 (file)
@@ -33,9 +33,9 @@
 
 #include <vector>
 #include <set>
-#include <ext/hash_set>
-
+#include <unordered_set>
 
+#include "configure.h"
 #include "MachOFileAbstraction.hpp"
 #include "Architectures.hpp"
 
@@ -71,14 +71,6 @@ private:
        typedef typename A::P::E                                E;
        typedef typename A::P::uint_t                   pint_t;
        
-       class CStringEquals
-       {
-       public:
-               bool operator()(const char* left, const char* right) const { return (strcmp(left, right) == 0); }
-       };
-
-       typedef __gnu_cxx::hash_set<const char*, __gnu_cxx::hash<const char*>, CStringEquals>  StringSet;
-
                                                                                                UnwindPrinter(const uint8_t* fileContent, uint32_t fileLength, 
                                                                                                                                const char* path, bool showFunctionNames);
        bool                                                                            findUnwindSection();
@@ -107,7 +99,9 @@ private:
 template <>     const char*    UnwindPrinter<x86>::archName()          { return "i386"; }
 template <>     const char*    UnwindPrinter<x86_64>::archName()       { return "x86_64"; }
 template <>     const char*    UnwindPrinter<arm>::archName()          { return "arm"; }
-
+#if SUPPORT_ARCH_arm64
+template <>     const char*    UnwindPrinter<arm64>::archName()        { return "arm64"; }
+#endif
 
 template <>
 bool UnwindPrinter<x86>::validFile(const uint8_t* fileContent)
@@ -148,6 +142,47 @@ bool UnwindPrinter<x86_64>::validFile(const uint8_t* fileContent)
 }
 
 
+#if SUPPORT_ARCH_arm64
+template <>
+bool UnwindPrinter<arm64>::validFile(const uint8_t* fileContent)
+{      
+       const macho_header<P>* header = (const macho_header<P>*)fileContent;
+       if ( header->magic() != MH_MAGIC_64 )
+               return false;
+       if ( header->cputype() != CPU_TYPE_ARM64 )
+               return false;
+       switch (header->filetype()) {
+               case MH_EXECUTE:
+               case MH_DYLIB:
+               case MH_BUNDLE:
+               case MH_DYLINKER:
+               case MH_OBJECT:
+                       return true;
+       }
+       return false;
+}
+#endif
+
+
+template <>
+bool UnwindPrinter<arm>::validFile(const uint8_t* fileContent)
+{      
+       const macho_header<P>* header = (const macho_header<P>*)fileContent;
+       if ( header->magic() != MH_MAGIC )
+               return false;
+       if ( header->cputype() != CPU_TYPE_ARM )
+               return false;
+       switch (header->filetype()) {
+               case MH_EXECUTE:
+               case MH_DYLIB:
+               case MH_BUNDLE:
+               case MH_DYLINKER:
+               case MH_OBJECT:
+                       return true;
+       }
+       return false;
+}
+
 template <typename A>
 UnwindPrinter<A>::UnwindPrinter(const uint8_t* fileContent, uint32_t fileLength, const char* path, bool showFunctionNames)
  : fHeader(NULL), fLength(fileLength), fUnwindSection(NULL),
@@ -180,7 +215,6 @@ void UnwindPrinter<A>::getSymbolTableInfo()
        const macho_load_command<P>* const cmds = (macho_load_command<P>*)((uint8_t*)fHeader + sizeof(macho_header<P>));
        const macho_load_command<P>* cmd = cmds;
        for (uint32_t i = 0; i < cmd_count; ++i) {
-               uint32_t size = cmd->cmdsize();
                const uint8_t* endOfCmd = ((uint8_t*)cmd)+cmd->cmdsize();
                if ( endOfCmd > endOfLoadCommands )
                        throwf("load command #%d extends beyond the end of the load commands", i);
@@ -206,7 +240,14 @@ const char* UnwindPrinter<A>::functionName(pint_t addr, uint32_t* offset)
        for (uint32_t i=0; i < fSymbolCount; ++i) {
                uint8_t type = fSymbols[i].n_type();
                if ( ((type & N_STAB) == 0) && ((type & N_TYPE) == N_SECT) ) {
-                       if ( fSymbols[i].n_value() == addr ) {
+                       pint_t value = fSymbols[i].n_value();
+                       if ( value == addr ) {
+                               const char* r = &fStrings[fSymbols[i].n_strx()];
+                               return r;
+                       }
+                       if ( fSymbols[i].n_desc() & N_ARM_THUMB_DEF ) 
+                               value |= 1;
+                       if ( value == addr ) {
                                const char* r = &fStrings[fSymbols[i].n_strx()];
                                //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);
                                return r;
@@ -247,7 +288,6 @@ bool UnwindPrinter<A>::findUnwindSection()
        const macho_load_command<P>* const cmds = (macho_load_command<P>*)((uint8_t*)fHeader + sizeof(macho_header<P>));
        const macho_load_command<P>* cmd = cmds;
        for (uint32_t i = 0; i < cmd_count; ++i) {
-               uint32_t size = cmd->cmdsize();
                const uint8_t* endOfCmd = ((uint8_t*)cmd)+cmd->cmdsize();
                if ( endOfCmd > endOfLoadCommands )
                        throwf("load command #%d extends beyond the end of the load commands", i);
@@ -636,6 +676,171 @@ void UnwindPrinter<x86>::decode(uint32_t encoding, const uint8_t* funcStart, cha
 
 }
 
+#if SUPPORT_ARCH_arm64
+template <>
+void UnwindPrinter<arm64>::decode(uint32_t encoding, const uint8_t* funcStart, char* str)
+{
+       uint32_t stackSize;
+       switch ( encoding & UNWIND_ARM64_MODE_MASK ) {
+               case UNWIND_ARM64_MODE_FRAMELESS:
+                       stackSize = EXTRACT_BITS(encoding, UNWIND_ARM64_FRAMELESS_STACK_SIZE_MASK);
+                       if ( stackSize == 0 )
+                               strcpy(str, "no frame, no saved registers ");
+                       else
+                               sprintf(str, "stack size=%d: ", 16 * stackSize);
+                       if ( encoding & UNWIND_ARM64_FRAME_X19_X20_PAIR )
+                               strcat(str, "x19/20 ");
+                       if ( encoding & UNWIND_ARM64_FRAME_X21_X22_PAIR )
+                               strcat(str, "x21/22 ");
+                       if ( encoding & UNWIND_ARM64_FRAME_X23_X24_PAIR )
+                               strcat(str, "x23/24 ");
+                       if ( encoding & UNWIND_ARM64_FRAME_X25_X26_PAIR )
+                               strcat(str, "x25/26 ");
+                       if ( encoding & UNWIND_ARM64_FRAME_X27_X28_PAIR )
+                               strcat(str, "x27/28 ");
+                       if ( encoding & UNWIND_ARM64_FRAME_D8_D9_PAIR )
+                               strcat(str, "d8/9 ");
+                       if ( encoding & UNWIND_ARM64_FRAME_D10_D11_PAIR )
+                               strcat(str, "d10/11 ");
+                       if ( encoding & UNWIND_ARM64_FRAME_D12_D13_PAIR )
+                               strcat(str, "d12/13 ");
+                       if ( encoding & UNWIND_ARM64_FRAME_D14_D15_PAIR )
+                               strcat(str, "d14/15 ");
+                       break;
+                       break;
+               case UNWIND_ARM64_MODE_DWARF:
+                       sprintf(str, "dwarf offset 0x%08X, ", encoding & UNWIND_X86_64_DWARF_SECTION_OFFSET);
+                       break;
+               case UNWIND_ARM64_MODE_FRAME:
+                       strcpy(str, "std frame: ");
+                       if ( encoding & UNWIND_ARM64_FRAME_X19_X20_PAIR )
+                               strcat(str, "x19/20 ");
+                       if ( encoding & UNWIND_ARM64_FRAME_X21_X22_PAIR )
+                               strcat(str, "x21/22 ");
+                       if ( encoding & UNWIND_ARM64_FRAME_X23_X24_PAIR )
+                               strcat(str, "x23/24 ");
+                       if ( encoding & UNWIND_ARM64_FRAME_X25_X26_PAIR )
+                               strcat(str, "x25/26 ");
+                       if ( encoding & UNWIND_ARM64_FRAME_X27_X28_PAIR )
+                               strcat(str, "x27/28 ");
+                       if ( encoding & UNWIND_ARM64_FRAME_D8_D9_PAIR )
+                               strcat(str, "d8/9 ");
+                       if ( encoding & UNWIND_ARM64_FRAME_D10_D11_PAIR )
+                               strcat(str, "d10/11 ");
+                       if ( encoding & UNWIND_ARM64_FRAME_D12_D13_PAIR )
+                               strcat(str, "d12/13 ");
+                       if ( encoding & UNWIND_ARM64_FRAME_D14_D15_PAIR )
+                               strcat(str, "d14/15 ");
+                       break;
+               case UNWIND_ARM64_MODE_FRAME_OLD:
+                       strcpy(str, "old frame: ");
+                       if ( encoding & UNWIND_ARM64_FRAME_X21_X22_PAIR_OLD )
+                               strcat(str, "x21/22 ");
+                       if ( encoding & UNWIND_ARM64_FRAME_X23_X24_PAIR_OLD )
+                               strcat(str, "x23/24 ");
+                       if ( encoding & UNWIND_ARM64_FRAME_X25_X26_PAIR_OLD )
+                               strcat(str, "x25/26 ");
+                       if ( encoding & UNWIND_ARM64_FRAME_X27_X28_PAIR_OLD )
+                               strcat(str, "x27/28 ");
+                       if ( encoding & UNWIND_ARM64_FRAME_D8_D9_PAIR_OLD )
+                               strcat(str, "d8/9 ");
+                       if ( encoding & UNWIND_ARM64_FRAME_D10_D11_PAIR_OLD )
+                               strcat(str, "d10/11 ");
+                       if ( encoding & UNWIND_ARM64_FRAME_D12_D13_PAIR_OLD )
+                               strcat(str, "d12/13 ");
+                       if ( encoding & UNWIND_ARM64_FRAME_D14_D15_PAIR_OLD )
+                               strcat(str, "d14/15 ");
+                       break;
+       }
+}
+#endif
+
+
+template <>
+void UnwindPrinter<arm>::decode(uint32_t encoding, const uint8_t* funcStart, char* str)
+{
+       *str = '\0';
+       switch ( encoding & UNWIND_ARM_MODE_MASK ) {
+               case UNWIND_ARM_MODE_DWARF:
+                       sprintf(str, "dwarf offset 0x%08X, ", encoding & UNWIND_ARM_DWARF_SECTION_OFFSET);
+                       break;
+               case UNWIND_ARM_MODE_FRAME:
+               case UNWIND_ARM_MODE_FRAME_D:
+                       switch ( encoding & UNWIND_ARM_FRAME_STACK_ADJUST_MASK ) {
+                               case 0x00000000:
+                                       strcpy(str, "std frame: ");
+                                       break;
+                               case 0x00400000:
+                                       strcat(str, "std frame(sp adj 4): ");
+                                       break;
+                               case 0x00800000:
+                                       strcat(str, "std frame(sp adj 8): ");
+                                       break;
+                               case 0x00C00000:
+                                       strcat(str, "std frame(sp adj 12): ");
+                                       break;
+                       }
+                       if ( encoding & UNWIND_ARM_FRAME_FIRST_PUSH_R4 )
+                               strcat(str, "r4 ");
+                       if ( encoding & UNWIND_ARM_FRAME_FIRST_PUSH_R5 )
+                               strcat(str, "r5 ");
+                       if ( encoding & UNWIND_ARM_FRAME_FIRST_PUSH_R6 )
+                               strcat(str, "r6 ");
+                               
+                       if ( encoding & 0x000000F8) 
+                               strcat(str, " / ");
+                       if ( encoding & UNWIND_ARM_FRAME_SECOND_PUSH_R8 )
+                               strcat(str, "r8 ");
+                       if ( encoding & UNWIND_ARM_FRAME_SECOND_PUSH_R9 )
+                               strcat(str, "r9 ");
+                       if ( encoding & UNWIND_ARM_FRAME_SECOND_PUSH_R10 )
+                               strcat(str, "r10 ");
+                       if ( encoding & UNWIND_ARM_FRAME_SECOND_PUSH_R11 )
+                               strcat(str, "r11 ");
+                       if ( encoding & UNWIND_ARM_FRAME_SECOND_PUSH_R12 )
+                               strcat(str, "r12 ");
+                       
+                       if ( (encoding & UNWIND_ARM_MODE_MASK) == UNWIND_ARM_MODE_FRAME_D ) {
+                               switch ( encoding & UNWIND_ARM_FRAME_D_REG_COUNT_MASK ) {
+                                       case 0x00000000:
+                                               strcat(str, " / d8 ");
+                                               break;
+                                       case 0x00000100:
+                                               strcat(str, " / d8,d10 ");
+                                               break;
+                                       case 0x00000200:
+                                               strcat(str, " / d8,d10,d12 ");
+                                               break;
+                                       case 0x00000300:
+                                               strcat(str, " / d8,d10,d12,d14 ");
+                                               break;
+                                       case 0x00000400:
+                                               strcat(str, " / d12,d14 / d8,d9,d10 ");
+                                               break;
+                                       case 0x00000500:
+                                               strcat(str, " / d14 / d8,d9,d10,d11,d12");
+                                               break;
+                                       case 0x00000600:
+                                               strcat(str, " / d8,d9,d10,d11,d12,d13,d14 ");
+                                               break;
+                                       case 0x00000700:
+                                               strcat(str, " / d8,d9,d10,d11,d12,d13,d14 ");
+                                               break;
+                                       default:
+                                               strcat(str, " / unknown D register usage ");
+                                               break;
+                               }
+                       }
+                       
+                       break;
+               default:
+                       if ( encoding == 0 )
+                               strcpy(str, "no unwind information");
+                       else
+                               strcpy(str, "unsupported compact unwind");
+                       break;
+       }
+}
 
 
 template <>
@@ -656,6 +861,27 @@ const char* UnwindPrinter<x86>::personalityName(const macho_relocation_info<x86:
        return &fStrings[sym.n_strx()];
 }
 
+#if SUPPORT_ARCH_arm64
+template <>
+const char* UnwindPrinter<arm64>::personalityName(const macho_relocation_info<arm64::P>* reloc)
+{
+       //assert(reloc->r_extern() && "reloc not extern on personality column in __compact_unwind section");
+       //assert((reloc->r_type() == ARM64_RELOC_UNSIGNED) && "wrong reloc type on personality column in __compact_unwind section");
+       const macho_nlist<P>& sym = fSymbols[reloc->r_symbolnum()];
+       return &fStrings[sym.n_strx()];
+}
+#endif
+
+
+template <>
+const char* UnwindPrinter<arm>::personalityName(const macho_relocation_info<arm::P>* reloc)
+{
+       //assert(reloc->r_extern() && "reloc not extern on personality column in __compact_unwind section");
+       //assert((reloc->r_type() == GENERIC_RELOC_VANILLA) && "wrong reloc type on personality column in __compact_unwind section");
+       const macho_nlist<P>& sym = fSymbols[reloc->r_symbolnum()];
+       return &fStrings[sym.n_strx()];
+}
+
 template <typename A>
 bool UnwindPrinter<A>::hasExernReloc(uint64_t sectionOffset, const char** personalityStr, pint_t* addr)
 {
@@ -692,6 +918,7 @@ void UnwindPrinter<A>::printObjectUnwindSection(bool showFunctionNames)
                }
                else {
                        functionNameStr = this->functionName(entry->codeStart(), &offsetInFunction);
+                       funcAddress = entry->codeStart();
                }
                if ( offsetInFunction == 0 )
                        printf("  start:        0x%08llX   %s\n", (uint64_t)funcAddress, functionNameStr);
@@ -723,7 +950,6 @@ void UnwindPrinter<A>::printObjectUnwindSection(bool showFunctionNames)
                                printf("  lsda:         0x%08llX  %s+0x%X\n", (uint64_t)entry->lsda(), lsdaName, lsdaOffset);
                }
        }
-       
 }
 
 
@@ -797,7 +1023,7 @@ void UnwindPrinter<A>::printUnwindSection(bool showFunctionNames)
                                char encodingString[100];
                                decode(entry[j].encoding(), ((const uint8_t*)fHeader)+funcOffset, encodingString);
                                const char* name = showFunctionNames ? functionName(funcOffset+fMachHeaderAddress) : "";
-                               printf("\t\t\t[%3u] funcOffset=0x%08X, encoding=0x%08X (%-40s) %s\n", 
+                               printf("\t\t\t[%3u] funcOffset=0x%08X, encoding=0x%08X (%-56s) %s\n", 
                                        j, funcOffset, entry[j].encoding(), encodingString, name);
                        }
                }
@@ -835,7 +1061,7 @@ void UnwindPrinter<A>::printUnwindSection(bool showFunctionNames)
                                                fprintf(stderr, "MISSING LSDA entry for %s\n", name);
                                        }
                                } 
-                               printf("\t\t\t[%3u] funcOffset=0x%08X, encoding[%3u]=0x%08X (%-40s) %s\n", 
+                               printf("\t\t\t[%3u] funcOffset=0x%08X, encoding[%3u]=0x%08X (%-56s) %s\n", 
                                        j, funcOff, encodingIndex, encoding, encodingString, name);
                        }                                       
                }
@@ -883,6 +1109,20 @@ static void dump(const char* path, const std::set<cpu_type_t>& onlyArchs, bool s
                                                else
                                                        throw "in universal file, x86_64 slice does not contain x86_64 mach-o";
                                                break;
+#if SUPPORT_ARCH_arm64
+                                       case CPU_TYPE_ARM64:
+                                               if ( UnwindPrinter<arm64>::validFile(p + offset) )
+                                                       UnwindPrinter<arm64>::make(p + offset, size, path, showFunctionNames);
+                                               else
+                                                       throw "in universal file, arm64 slice does not contain arm64 mach-o";
+                                               break;
+#endif
+                                       case CPU_TYPE_ARM:
+                                               if ( UnwindPrinter<arm>::validFile(p + offset) )
+                                                       UnwindPrinter<arm>::make(p + offset, size, path, showFunctionNames);
+                                               else
+                                                       throw "in universal file, arm slice does not contain arm mach-o";
+                                               break;
                                        default:
                                                        throwf("in universal file, unknown architecture slice 0x%x\n", cputype);
                                        }
@@ -895,6 +1135,14 @@ static void dump(const char* path, const std::set<cpu_type_t>& onlyArchs, bool s
                else if ( UnwindPrinter<x86_64>::validFile(p) && onlyArchs.count(CPU_TYPE_X86_64) ) {
                        UnwindPrinter<x86_64>::make(p, length, path, showFunctionNames);
                }
+#if SUPPORT_ARCH_arm64
+               else if ( UnwindPrinter<arm64>::validFile(p) && onlyArchs.count(CPU_TYPE_ARM64) ) {
+                       UnwindPrinter<arm64>::make(p, length, path, showFunctionNames);
+               }
+#endif
+               else if ( UnwindPrinter<arm>::validFile(p) && onlyArchs.count(CPU_TYPE_ARM) ) {
+                       UnwindPrinter<arm>::make(p, length, path, showFunctionNames);
+               }
                else {
                        throw "not a known file type";
                }
@@ -921,6 +1169,12 @@ int main(int argc, const char* argv[])
                                                onlyArchs.insert(CPU_TYPE_I386);
                                        else if ( strcmp(arch, "x86_64") == 0 )
                                                onlyArchs.insert(CPU_TYPE_X86_64);
+#if SUPPORT_ARCH_arm64
+                                       else if ( strcmp(arch, "arm64") == 0 )
+                                               onlyArchs.insert(CPU_TYPE_ARM64);
+#endif
+                                       else if ( strcmp(arch, "armv7k") == 0 )
+                                               onlyArchs.insert(CPU_TYPE_ARM);
                                        else 
                                                throwf("unknown architecture %s", arch);
                                }
@@ -940,6 +1194,10 @@ int main(int argc, const char* argv[])
                if ( onlyArchs.size() == 0 ) {
                        onlyArchs.insert(CPU_TYPE_I386);
                        onlyArchs.insert(CPU_TYPE_X86_64);
+#if SUPPORT_ARCH_arm64
+                       onlyArchs.insert(CPU_TYPE_ARM64);
+#endif
+                       onlyArchs.insert(CPU_TYPE_ARM);
                }
                
                // process each file