[llvm] r185137 - llvm-symbolizer: add support for Mach-O universal binaries

Alexey Samsonov samsonov at google.com
Fri Jun 28 01:15:41 PDT 2013


Author: samsonov
Date: Fri Jun 28 03:15:40 2013
New Revision: 185137

URL: http://llvm.org/viewvc/llvm-project?rev=185137&view=rev
Log:
llvm-symbolizer: add support for Mach-O universal binaries

Added:
    llvm/trunk/test/DebugInfo/Inputs/macho-universal   (with props)
    llvm/trunk/test/DebugInfo/Inputs/macho-universal.cc
Modified:
    llvm/trunk/docs/CommandGuide/llvm-symbolizer.rst
    llvm/trunk/test/DebugInfo/llvm-symbolizer.test
    llvm/trunk/tools/llvm-symbolizer/LLVMSymbolize.cpp
    llvm/trunk/tools/llvm-symbolizer/LLVMSymbolize.h
    llvm/trunk/tools/llvm-symbolizer/llvm-symbolizer.cpp

Modified: llvm/trunk/docs/CommandGuide/llvm-symbolizer.rst
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/docs/CommandGuide/llvm-symbolizer.rst?rev=185137&r1=185136&r2=185137&view=diff
==============================================================================
--- llvm/trunk/docs/CommandGuide/llvm-symbolizer.rst (original)
+++ llvm/trunk/docs/CommandGuide/llvm-symbolizer.rst Fri Jun 28 03:15:40 2013
@@ -22,6 +22,8 @@ EXAMPLE
   a.out 0x4004f4
   /tmp/b.out 0x400528
   /tmp/c.so 0x710
+  /tmp/mach_universal_binary:i386 0x1f84
+  /tmp/mach_universal_binary:x86_64 0x100000f24
   $ llvm-symbolizer < addr.txt
   main
   /tmp/a.cc:4
@@ -38,6 +40,12 @@ EXAMPLE
   main
   /tmp/source.cc:8
 
+  _main
+  /tmp/source_i386.cc:8
+
+  _main
+  /tmp/source_x86_64.cc:8
+
 OPTIONS
 -------
 
@@ -59,6 +67,14 @@ OPTIONS
  If a source code location is in an inlined function, prints all the
  inlnied frames. Defaults to true.
 
+.. option:: -default-arch
+
+ If a binary contains object files for multiple architectures (e.g. it is a
+ Mach-O universal binary), symbolize the object file for a given architecture.
+ You can also specify architecture by writing ``binary_name:arch_name`` in the
+ input (see example above). If architecture is not specified in either way,
+ address will not be symbolized. Defaults to empty string.
+
 EXIT STATUS
 -----------
 

Added: llvm/trunk/test/DebugInfo/Inputs/macho-universal
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/DebugInfo/Inputs/macho-universal?rev=185137&view=auto
==============================================================================
Binary file - no diff available.

Propchange: llvm/trunk/test/DebugInfo/Inputs/macho-universal
------------------------------------------------------------------------------
    svn:executable = *

Propchange: llvm/trunk/test/DebugInfo/Inputs/macho-universal
------------------------------------------------------------------------------
    svn:mime-type = application/octet-stream

Added: llvm/trunk/test/DebugInfo/Inputs/macho-universal.cc
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/DebugInfo/Inputs/macho-universal.cc?rev=185137&view=auto
==============================================================================
--- llvm/trunk/test/DebugInfo/Inputs/macho-universal.cc (added)
+++ llvm/trunk/test/DebugInfo/Inputs/macho-universal.cc Fri Jun 28 03:15:40 2013
@@ -0,0 +1,10 @@
+// Built with Apple LLVM version 4.2 (clang-425.0.24) (based on LLVM 3.2svn)
+// clang++ -arch x86_64 -arch i386 macho-universal.cc
+
+int inc(int x) {
+  return x + 1;
+}
+
+int main(int argc, char *argv[]) {
+  return inc(argc);
+}

Modified: llvm/trunk/test/DebugInfo/llvm-symbolizer.test
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/DebugInfo/llvm-symbolizer.test?rev=185137&r1=185136&r2=185137&view=diff
==============================================================================
--- llvm/trunk/test/DebugInfo/llvm-symbolizer.test (original)
+++ llvm/trunk/test/DebugInfo/llvm-symbolizer.test Fri Jun 28 03:15:40 2013
@@ -3,9 +3,12 @@ RUN: echo "%p/Inputs/dwarfdump-test.elf-
 RUN: echo "%p/Inputs/dwarfdump-test4.elf-x86-64 0x62c" >> %t.input
 RUN: echo "%p/Inputs/dwarfdump-inl-test.elf-x86-64 0x710" >> %t.input
 RUN: echo "\"%p/Inputs/dwarfdump-test3.elf-x86-64 space\" 0x633" >> %t.input
+RUN: echo "%p/Inputs/macho-universal 0x1f84" >> %t.input
+RUN: echo "%p/Inputs/macho-universal:i386 0x1f67" >> %t.input
+RUN: echo "%p/Inputs/macho-universal:x86_64 0x100000f05" >> %t.input
 
-RUN: llvm-symbolizer --functions --inlining --demangle=false < %t.input \
-RUN:    | FileCheck %s
+RUN: llvm-symbolizer --functions --inlining --demangle=false \
+RUN:    --default-arch=i386 < %t.input | FileCheck %s
 
 REQUIRES: shell
 
@@ -29,5 +32,16 @@ CHECK-NEXT: dwarfdump-inl-test.cc:
 CHECK:       _Z3do1v
 CHECK-NEXT: dwarfdump-test3-decl.h:7
 
+CHECK:      _main
+CHECK:      __Z3inci
+CHECK:      __Z3inci
+
 RUN: echo "unexisting-file 0x1234" > %t.input2
 RUN: llvm-symbolizer < %t.input2
+
+RUN: echo "%p/Inputs/macho-universal 0x1f84" > %t.input3
+RUN: llvm-symbolizer < %t.input3 | FileCheck %s --check-prefix=UNKNOWN-ARCH
+
+UNKNOWN-ARCH-NOT: main
+UNKNOWN-ARCH: ??
+UNKNOWN-ARCH-NOT: main

Modified: llvm/trunk/tools/llvm-symbolizer/LLVMSymbolize.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-symbolizer/LLVMSymbolize.cpp?rev=185137&r1=185136&r2=185137&view=diff
==============================================================================
--- llvm/trunk/tools/llvm-symbolizer/LLVMSymbolize.cpp (original)
+++ llvm/trunk/tools/llvm-symbolizer/LLVMSymbolize.cpp Fri Jun 28 03:15:40 2013
@@ -198,23 +198,10 @@ std::string LLVMSymbolizer::symbolizeDat
 
 void LLVMSymbolizer::flush() {
   DeleteContainerSeconds(Modules);
+  DeleteContainerPointers(ParsedBinariesAndObjects);
 }
 
-// Returns true if the object endianness is known.
-static bool getObjectEndianness(const ObjectFile *Obj, bool &IsLittleEndian) {
-  // FIXME: Implement this when libLLVMObject allows to do it easily.
-  IsLittleEndian = true;
-  return true;
-}
-
-static ObjectFile *getObjectFile(const std::string &Path) {
-  OwningPtr<MemoryBuffer> Buff;
-  if (error(MemoryBuffer::getFile(Path, Buff)))
-    return 0;
-  return ObjectFile::createObjectFile(Buff.take());
-}
-
-static std::string getDarwinDWARFResourceForModule(const std::string &Path) {
+static std::string getDarwinDWARFResourceForPath(const std::string &Path) {
   StringRef Basename = sys::path::filename(Path);
   const std::string &DSymDirectory = Path + ".dSYM";
   SmallString<16> ResourceName = StringRef(DSymDirectory);
@@ -223,39 +210,85 @@ static std::string getDarwinDWARFResourc
   return ResourceName.str();
 }
 
+LLVMSymbolizer::BinaryPair
+LLVMSymbolizer::getOrCreateBinary(const std::string &Path) {
+  BinaryMapTy::iterator I = BinaryForPath.find(Path);
+  if (I != BinaryForPath.end())
+    return I->second;
+  Binary *Bin = 0;
+  Binary *DbgBin = 0;
+  OwningPtr<Binary> ParsedBinary;
+  OwningPtr<Binary> ParsedDbgBinary;
+  if (!error(createBinary(Path, ParsedBinary))) {
+    // Check if it's a universal binary.
+    Bin = ParsedBinary.take();
+    ParsedBinariesAndObjects.push_back(Bin);
+    if (Bin->isMachO() || Bin->isMachOUniversalBinary()) {
+      // On Darwin we may find DWARF in separate object file in
+      // resource directory.
+      const std::string &ResourcePath =
+          getDarwinDWARFResourceForPath(Path);
+      bool ResourceFileExists = false;
+      if (!sys::fs::exists(ResourcePath, ResourceFileExists) &&
+          ResourceFileExists &&
+          !error(createBinary(ResourcePath, ParsedDbgBinary))) {
+        DbgBin = ParsedDbgBinary.take();
+        ParsedBinariesAndObjects.push_back(DbgBin);
+      }
+    }
+  }
+  if (DbgBin == 0)
+    DbgBin = Bin;
+  BinaryPair Res = std::make_pair(Bin, DbgBin);
+  BinaryForPath[Path] = Res;
+  return Res;
+}
+
+ObjectFile *
+LLVMSymbolizer::getObjectFileFromBinary(Binary *Bin, const std::string &ArchName) {
+  if (Bin == 0)
+    return 0;
+  ObjectFile *Res = 0;
+  if (MachOUniversalBinary *UB = dyn_cast<MachOUniversalBinary>(Bin)) {
+    ObjectFileForArchMapTy::iterator I = ObjectFileForArch.find(
+        std::make_pair(UB, ArchName));
+    if (I != ObjectFileForArch.end())
+      return I->second;
+    OwningPtr<ObjectFile> ParsedObj;
+    if (!UB->getObjectForArch(Triple(ArchName).getArch(), ParsedObj)) {
+      Res = ParsedObj.take();
+      ParsedBinariesAndObjects.push_back(Res);
+    }
+    ObjectFileForArch[std::make_pair(UB, ArchName)] = Res;
+  } else if (Bin->isObject()) {
+    Res = cast<ObjectFile>(Bin);
+  }
+  return Res;
+}
+
 ModuleInfo *
 LLVMSymbolizer::getOrCreateModuleInfo(const std::string &ModuleName) {
   ModuleMapTy::iterator I = Modules.find(ModuleName);
   if (I != Modules.end())
     return I->second;
+  std::string BinaryName = ModuleName;
+  std::string ArchName = Opts.DefaultArch;
+  size_t ColonPos = ModuleName.find(':');
+  if (ColonPos != std::string::npos) {
+    BinaryName = ModuleName.substr(0, ColonPos);
+    ArchName = ModuleName.substr(ColonPos + 1);
+  }
+  BinaryPair Binaries = getOrCreateBinary(BinaryName);
+  ObjectFile *Obj = getObjectFileFromBinary(Binaries.first, ArchName);
+  ObjectFile *DbgObj = getObjectFileFromBinary(Binaries.second, ArchName);
 
-  ObjectFile *Obj = getObjectFile(ModuleName);
   if (Obj == 0) {
-    // Module name doesn't point to a valid object file.
+    // Failed to find valid object file.
     Modules.insert(make_pair(ModuleName, (ModuleInfo *)0));
     return 0;
   }
-
-  DIContext *Context = 0;
-  bool IsLittleEndian;
-  if (getObjectEndianness(Obj, IsLittleEndian)) {
-    // On Darwin we may find DWARF in separate object file in
-    // resource directory.
-    ObjectFile *DbgObj = Obj;
-    if (isa<MachOObjectFile>(Obj)) {
-      const std::string &ResourceName =
-          getDarwinDWARFResourceForModule(ModuleName);
-      bool ResourceFileExists = false;
-      if (!sys::fs::exists(ResourceName, ResourceFileExists) &&
-          ResourceFileExists) {
-        if (ObjectFile *ResourceObj = getObjectFile(ResourceName))
-          DbgObj = ResourceObj;
-      }
-    }
-    Context = DIContext::getDWARFContext(DbgObj);
-    assert(Context);
-  }
-
+  DIContext *Context = DIContext::getDWARFContext(DbgObj);
+  assert(Context);
   ModuleInfo *Info = new ModuleInfo(Obj, Context);
   Modules.insert(make_pair(ModuleName, Info));
   return Info;

Modified: llvm/trunk/tools/llvm-symbolizer/LLVMSymbolize.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-symbolizer/LLVMSymbolize.h?rev=185137&r1=185136&r2=185137&view=diff
==============================================================================
--- llvm/trunk/tools/llvm-symbolizer/LLVMSymbolize.h (original)
+++ llvm/trunk/tools/llvm-symbolizer/LLVMSymbolize.h Fri Jun 28 03:15:40 2013
@@ -14,7 +14,9 @@
 #define LLVM_SYMBOLIZE_H
 
 #include "llvm/ADT/OwningPtr.h"
+#include "llvm/ADT/SmallVector.h"
 #include "llvm/DebugInfo/DIContext.h"
+#include "llvm/Object/MachOUniversal.h"
 #include "llvm/Object/ObjectFile.h"
 #include "llvm/Support/MemoryBuffer.h"
 #include <map>
@@ -35,10 +37,13 @@ public:
     bool PrintFunctions : 1;
     bool PrintInlining : 1;
     bool Demangle : 1;
+    std::string DefaultArch;
     Options(bool UseSymbolTable = true, bool PrintFunctions = true,
-            bool PrintInlining = true, bool Demangle = true)
+            bool PrintInlining = true, bool Demangle = true,
+            std::string DefaultArch = "")
         : UseSymbolTable(UseSymbolTable), PrintFunctions(PrintFunctions),
-          PrintInlining(PrintInlining), Demangle(Demangle) {
+          PrintInlining(PrintInlining), Demangle(Demangle),
+          DefaultArch(DefaultArch) {
     }
   };
 
@@ -52,12 +57,29 @@ public:
   symbolizeData(const std::string &ModuleName, uint64_t ModuleOffset);
   void flush();
 private:
+  typedef std::pair<Binary*, Binary*> BinaryPair;
+
   ModuleInfo *getOrCreateModuleInfo(const std::string &ModuleName);
+  /// \brief Returns pair of pointers to binary and debug binary.
+  BinaryPair getOrCreateBinary(const std::string &Path);
+  /// \brief Returns a parsed object file for a given architecture in a
+  /// universal binary (or the binary itself if it is an object file).
+  ObjectFile *getObjectFileFromBinary(Binary *Bin, const std::string &ArchName);
+
   std::string printDILineInfo(DILineInfo LineInfo) const;
   void DemangleName(std::string &Name) const;
 
+  // Owns all the parsed binaries and object files.
+  SmallVector<Binary*, 4> ParsedBinariesAndObjects;
+  // Owns module info objects.
   typedef std::map<std::string, ModuleInfo *> ModuleMapTy;
   ModuleMapTy Modules;
+  typedef std::map<std::string, BinaryPair> BinaryMapTy;
+  BinaryMapTy BinaryForPath;
+  typedef std::map<std::pair<MachOUniversalBinary *, std::string>, ObjectFile *>
+      ObjectFileForArchMapTy;
+  ObjectFileForArchMapTy ObjectFileForArch;
+
   Options Opts;
   static const char kBadString[];
 };
@@ -77,7 +99,7 @@ private:
   bool getNameFromSymbolTable(SymbolRef::Type Type, uint64_t Address,
                               std::string &Name, uint64_t &Addr,
                               uint64_t &Size) const;
-  OwningPtr<ObjectFile> Module;
+  ObjectFile *Module;
   OwningPtr<DIContext> DebugInfoContext;
 
   struct SymbolDesc {

Modified: llvm/trunk/tools/llvm-symbolizer/llvm-symbolizer.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-symbolizer/llvm-symbolizer.cpp?rev=185137&r1=185136&r2=185137&view=diff
==============================================================================
--- llvm/trunk/tools/llvm-symbolizer/llvm-symbolizer.cpp (original)
+++ llvm/trunk/tools/llvm-symbolizer/llvm-symbolizer.cpp Fri Jun 28 03:15:40 2013
@@ -47,6 +47,10 @@ ClPrintInlining("inlining", cl::init(tru
 static cl::opt<bool>
 ClDemangle("demangle", cl::init(true), cl::desc("Demangle function names"));
 
+static cl::opt<std::string> ClDefaultArch("default-arch", cl::init(""),
+                                          cl::desc("Default architecture "
+                                                   "(for multi-arch objects)"));
+
 static bool parseCommand(bool &IsData, std::string &ModuleName,
                          uint64_t &ModuleOffset) {
   const char *kDataCmd = "DATA ";
@@ -102,7 +106,7 @@ int main(int argc, char **argv) {
 
   cl::ParseCommandLineOptions(argc, argv, "llvm symbolizer for compiler-rt\n");
   LLVMSymbolizer::Options Opts(ClUseSymbolTable, ClPrintFunctions,
-                               ClPrintInlining, ClDemangle);
+                               ClPrintInlining, ClDemangle, ClDefaultArch);
   LLVMSymbolizer Symbolizer(Opts);
 
   bool IsData = false;





More information about the llvm-commits mailing list