Update llvm-objdump’s Mach-O symbolizer code to demangle C++ names.
[oota-llvm.git] / tools / llvm-objdump / MachODump.cpp
index bf0108ce05dd725fffc7ca7ab4c1d53f057532ea..7d7eb80569ca52d294101d181222eb253c8fca24 100644 (file)
@@ -16,6 +16,7 @@
 #include "llvm/ADT/STLExtras.h"
 #include "llvm/ADT/StringExtras.h"
 #include "llvm/ADT/Triple.h"
+#include "llvm/Config/config.h"
 #include "llvm/DebugInfo/DIContext.h"
 #include "llvm/MC/MCAsmInfo.h"
 #include "llvm/MC/MCContext.h"
 #include <algorithm>
 #include <cstring>
 #include <system_error>
+
+#if HAVE_CXXABI_H
+#include <cxxabi.h>
+#endif
+
 using namespace llvm;
 using namespace object;
 
@@ -249,7 +255,8 @@ struct DisassembleInfo {
   const char *class_name;
   const char *selector_name;
   char *method;
-  BindTable *BindTable;
+  char *demangled_name;
+  BindTable *bindtable;
 };
 
 // SymbolizerGetOpInfo() is the operand information call back function.
@@ -821,7 +828,7 @@ const char *get_objc2_64bit_class_name(uint64_t pointer_value,
     const char *symbol_name = get_symbol_64(offset, S, info, n_value);
     if (symbol_name == nullptr)
       return nullptr;
-    const char *class_name = rindex(symbol_name, '$');
+    const char *class_name = strrchr(symbol_name, '$');
     if (class_name != nullptr && class_name[1] == '_' && class_name[2] != '\0')
       return class_name + 2;
     else
@@ -978,7 +985,7 @@ const char *GuessLiteralPointer(uint64_t ReferenceValue, uint64_t ReferencePC,
     const char *name = get_dyld_bind_info_symbolname(ReferenceValue, info);
     if (name != nullptr) {
       *ReferenceType = LLVMDisassembler_ReferenceType_Out_Objc_Class_Ref;
-      const char *class_name = rindex(name, '$');
+      const char *class_name = strrchr(name, '$');
       if (class_name != nullptr && class_name[1] == '_' &&
           class_name[2] != '\0') {
         info->class_name = class_name + 2;
@@ -1045,9 +1052,11 @@ const char *GuessLiteralPointer(uint64_t ReferenceValue, uint64_t ReferencePC,
 // Out type and the ReferenceName will also be set which is added as a comment
 // to the disassembled instruction.
 //
-// TODO: If the symbol name is a C++ mangled name then the demangled name is
+#if HAVE_CXXABI_H
+// If the symbol name is a C++ mangled name then the demangled name is
 // returned through ReferenceName and ReferenceType is set to
 // LLVMDisassembler_ReferenceType_DeMangled_Name .
+#endif
 //
 // When this is called to get a symbol name for a branch target then the
 // ReferenceType will be LLVMDisassembler_ReferenceType_In_Branch and then
@@ -1074,8 +1083,8 @@ const char *SymbolizerSymbolLookUp(void *DisInfo, uint64_t ReferenceValue,
   }
 
   const char *SymbolName = nullptr;
-  if (ReferenceValue != 0xffffffffffffffffLLU &&
-      ReferenceValue != 0xfffffffffffffffeLLU) {
+  if (ReferenceValue != 0xffffffffffffffffULL &&
+      ReferenceValue != 0xfffffffffffffffeULL) {
     StringRef name = info->AddrMap->lookup(ReferenceValue);
     if (!name.empty())
       SymbolName = name.data();
@@ -1083,13 +1092,25 @@ const char *SymbolizerSymbolLookUp(void *DisInfo, uint64_t ReferenceValue,
 
   if (*ReferenceType == LLVMDisassembler_ReferenceType_In_Branch) {
     *ReferenceName = GuessIndirectSymbol(ReferenceValue, info);
-    if (*ReferenceName) {
+    if (*ReferenceName != nullptr) {
       method_reference(info, ReferenceType, ReferenceName);
       if (*ReferenceType != LLVMDisassembler_ReferenceType_Out_Objc_Message)
         *ReferenceType = LLVMDisassembler_ReferenceType_Out_SymbolStub;
     } else
-      // TODO: if SymbolName is not nullptr see if it is a C++ name
-      // and demangle it.
+#if HAVE_CXXABI_H
+    if (SymbolName != nullptr && strncmp(SymbolName, "__Z", 3) == 0) {
+      if (info->demangled_name != nullptr)
+        free(info->demangled_name);
+      int status;
+      info->demangled_name = abi::__cxa_demangle(SymbolName + 1, nullptr,
+                                                 nullptr, &status);
+      if (info->demangled_name != nullptr) {
+        *ReferenceName = info->demangled_name;
+        *ReferenceType = LLVMDisassembler_ReferenceType_DeMangled_Name;
+      } else
+        *ReferenceType = LLVMDisassembler_ReferenceType_InOut_None;
+    } else
+#endif
       *ReferenceType = LLVMDisassembler_ReferenceType_InOut_None;
   } else if (*ReferenceType == LLVMDisassembler_ReferenceType_In_PCrel_Load) {
     *ReferenceName =
@@ -1099,8 +1120,19 @@ const char *SymbolizerSymbolLookUp(void *DisInfo, uint64_t ReferenceValue,
     else
       *ReferenceType = LLVMDisassembler_ReferenceType_InOut_None;
   }
-  // TODO: if SymbolName is not nullptr see if it is a C++ name
-  // and demangle it.
+#if HAVE_CXXABI_H
+  else if (SymbolName != nullptr && strncmp(SymbolName, "__Z", 3) == 0) {
+    if (info->demangled_name != nullptr)
+      free(info->demangled_name);
+    int status;
+    info->demangled_name = abi::__cxa_demangle(SymbolName + 1, nullptr, nullptr,
+                                               &status);
+    if (info->demangled_name != nullptr) {
+      *ReferenceName = info->demangled_name;
+      *ReferenceType = LLVMDisassembler_ReferenceType_DeMangled_Name;
+    }
+  }
+#endif
   else {
     *ReferenceName = nullptr;
     *ReferenceType = LLVMDisassembler_ReferenceType_InOut_None;
@@ -1392,7 +1424,8 @@ static void DisassembleInputMachO2(StringRef Filename,
     SymbolizerInfo.class_name = nullptr;
     SymbolizerInfo.selector_name = nullptr;
     SymbolizerInfo.method = nullptr;
-    SymbolizerInfo.BindTable = nullptr;
+    SymbolizerInfo.demangled_name = nullptr;
+    SymbolizerInfo.bindtable = nullptr;
 
     // Disassemble symbol by symbol.
     for (unsigned SymIdx = 0; SymIdx != Symbols.size(); SymIdx++) {
@@ -1569,8 +1602,10 @@ static void DisassembleInputMachO2(StringRef Filename,
     }
     if (SymbolizerInfo.method != nullptr)
       free(SymbolizerInfo.method);
-    if (SymbolizerInfo.BindTable != nullptr)
-      delete SymbolizerInfo.BindTable;
+    if (SymbolizerInfo.demangled_name != nullptr)
+      free(SymbolizerInfo.demangled_name);
+    if (SymbolizerInfo.bindtable != nullptr)
+      delete SymbolizerInfo.bindtable;
   }
 }
 
@@ -3412,8 +3447,8 @@ void llvm::printMachOWeakBindTable(const object::MachOObjectFile *Obj) {
 // name is returned.  If not nullptr is returned.
 static const char *get_dyld_bind_info_symbolname(uint64_t ReferenceValue,
                                                  struct DisassembleInfo *info) {
-  if (info->BindTable == nullptr) {
-    info->BindTable = new (BindTable);
+  if (info->bindtable == nullptr) {
+    info->bindtable = new (BindTable);
     SegInfo sectionTable(info->O);
     for (const llvm::object::MachOBindEntry &Entry : info->O->bindTable()) {
       uint32_t SegIndex = Entry.segmentIndex();
@@ -3423,11 +3458,11 @@ static const char *get_dyld_bind_info_symbolname(uint64_t ReferenceValue,
       StringRef name = Entry.symbolName();
       if (!name.empty())
         SymbolName = name.data();
-      info->BindTable->push_back(std::make_pair(Address, SymbolName));
+      info->bindtable->push_back(std::make_pair(Address, SymbolName));
     }
   }
-  for (bind_table_iterator BI = info->BindTable->begin(),
-                           BE = info->BindTable->end();
+  for (bind_table_iterator BI = info->bindtable->begin(),
+                           BE = info->bindtable->end();
        BI != BE; ++BI) {
     uint64_t Address = BI->first;
     if (ReferenceValue == Address) {