[llvm-symbolizer] rewrite r183213 in a more clear way
[oota-llvm.git] / tools / llvm-symbolizer / LLVMSymbolize.cpp
index fe32178f02dbbb582737ee950fa67e0f320d9c91..7fccedf1c4e004d6a47daf1b1c7e4877d1d3d976 100644 (file)
 //===----------------------------------------------------------------------===//
 
 #include "LLVMSymbolize.h"
+#include "llvm/ADT/STLExtras.h"
 #include "llvm/Object/MachO.h"
 #include "llvm/Support/Casting.h"
+#include "llvm/Support/FileSystem.h"
 #include "llvm/Support/Path.h"
 
 #include <sstream>
@@ -22,13 +24,14 @@ namespace llvm {
 namespace symbolize {
 
 static bool error(error_code ec) {
-  if (!ec) return false;
+  if (!ec)
+    return false;
   errs() << "LLVMSymbolizer: error reading file: " << ec.message() << ".\n";
   return true;
 }
 
-static uint32_t getDILineInfoSpecifierFlags(
-    const LLVMSymbolizer::Options &Opts) {
+static uint32_t
+getDILineInfoSpecifierFlags(const LLVMSymbolizer::Options &Opts) {
   uint32_t Flags = llvm::DILineInfoSpecifier::FileLineInfo |
                    llvm::DILineInfoSpecifier::AbsoluteFilePath;
   if (Opts.PrintFunctions)
@@ -44,36 +47,37 @@ static void patchFunctionNameInDILineInfo(const std::string &NewFunctionName,
 }
 
 ModuleInfo::ModuleInfo(ObjectFile *Obj, DIContext *DICtx)
-    : Module(Obj)
-    , DebugInfoContext(DICtx) {
+    : Module(Obj), DebugInfoContext(DICtx) {
   error_code ec;
-  for (symbol_iterator si = Module->begin_symbols(),
-                       se = Module->end_symbols();
-                       si != se; si.increment(ec)) {
+  for (symbol_iterator si = Module->begin_symbols(), se = Module->end_symbols();
+       si != se; si.increment(ec)) {
     if (error(ec))
       return;
     SymbolRef::Type SymbolType;
     if (error(si->getType(SymbolType)))
       continue;
-    if (SymbolType != SymbolRef::ST_Function
-        && SymbolType != SymbolRef::ST_Data)
+    if (SymbolType != SymbolRef::ST_Function &&
+        SymbolType != SymbolRef::ST_Data)
       continue;
     uint64_t SymbolAddress;
-    if (error(si->getAddress(SymbolAddress))
-        || SymbolAddress == UnknownAddressOrSize)
+    if (error(si->getAddress(SymbolAddress)) ||
+        SymbolAddress == UnknownAddressOrSize)
       continue;
     uint64_t SymbolSize;
-    if (error(si->getSize(SymbolSize))
-        || SymbolSize == UnknownAddressOrSize)
+    // Getting symbol size is linear for Mach-O files, so assume that symbol
+    // occupies the memory range up to the following symbol.
+    if (isa<MachOObjectFile>(Obj))
+      SymbolSize = 0;
+    else if (error(si->getSize(SymbolSize)) ||
+             SymbolSize == UnknownAddressOrSize)
       continue;
     StringRef SymbolName;
     if (error(si->getName(SymbolName)))
       continue;
     // FIXME: If a function has alias, there are two entries in symbol table
     // with same address size. Make sure we choose the correct one.
-    SymbolMapTy &M = SymbolType == SymbolRef::ST_Function ?
-        Functions : Objects;
-    SymbolDesc SD = {SymbolAddress, SymbolAddress + SymbolSize};
+    SymbolMapTy &M = SymbolType == SymbolRef::ST_Function ? Functions : Objects;
+    SymbolDesc SD = { SymbolAddress, SymbolSize };
     M.insert(std::make_pair(SD, SymbolName));
   }
 }
@@ -81,22 +85,24 @@ ModuleInfo::ModuleInfo(ObjectFile *Obj, DIContext *DICtx)
 bool ModuleInfo::getNameFromSymbolTable(SymbolRef::Type Type, uint64_t Address,
                                         std::string &Name, uint64_t &Addr,
                                         uint64_t &Size) const {
-  const SymbolMapTy& M = Type == SymbolRef::ST_Function ?
-      Functions : Objects;
-  SymbolDesc SD = {Address, Address + 1};
-  SymbolMapTy::const_iterator it = M.find(SD);
-  if (it == M.end())
+  const SymbolMapTy &M = Type == SymbolRef::ST_Function ? Functions : Objects;
+  if (M.empty())
+    return false;
+  SymbolDesc SD = { Address, Address };
+  SymbolMapTy::const_iterator it = M.upper_bound(SD);
+  if (it == M.begin())
     return false;
-  if (Address < it->first.Addr || Address >= it->first.AddrEnd)
+  --it;
+  if (it->first.Size != 0 && it->first.Addr + it->first.Size <= Address)
     return false;
   Name = it->second.str();
   Addr = it->first.Addr;
-  Size = it->first.AddrEnd - it->first.Addr;
+  Size = it->first.Size;
   return true;
 }
 
-DILineInfo ModuleInfo::symbolizeCode(uint64_t ModuleOffset,
-    const LLVMSymbolizer::Options& Opts) const {
+DILineInfo ModuleInfo::symbolizeCode(
+    uint64_t ModuleOffset, const LLVMSymbolizer::Options &Opts) const {
   DILineInfo LineInfo;
   if (DebugInfoContext) {
     LineInfo = DebugInfoContext->getLineInfoForAddress(
@@ -106,16 +112,16 @@ DILineInfo ModuleInfo::symbolizeCode(uint64_t ModuleOffset,
   if (Opts.PrintFunctions && Opts.UseSymbolTable) {
     std::string FunctionName;
     uint64_t Start, Size;
-    if (getNameFromSymbolTable(SymbolRef::ST_Function,
-                               ModuleOffset, FunctionName, Start, Size)) {
+    if (getNameFromSymbolTable(SymbolRef::ST_Function, ModuleOffset,
+                               FunctionName, Start, Size)) {
       patchFunctionNameInDILineInfo(FunctionName, LineInfo);
     }
   }
   return LineInfo;
 }
 
-DIInliningInfo ModuleInfo::symbolizeInlinedCode(uint64_t ModuleOffset,
-    const LLVMSymbolizer::Options& Opts) const {
+DIInliningInfo ModuleInfo::symbolizeInlinedCode(
+    uint64_t ModuleOffset, const LLVMSymbolizer::Options &Opts) const {
   DIInliningInfo InlinedContext;
   if (DebugInfoContext) {
     InlinedContext = DebugInfoContext->getInliningInfoForAddress(
@@ -128,14 +134,13 @@ DIInliningInfo ModuleInfo::symbolizeInlinedCode(uint64_t ModuleOffset,
   // Override the function name in lower frame with name from symbol table.
   if (Opts.PrintFunctions && Opts.UseSymbolTable) {
     DIInliningInfo PatchedInlinedContext;
-    for (uint32_t i = 0, n = InlinedContext.getNumberOfFrames();
-         i < n; i++) {
+    for (uint32_t i = 0, n = InlinedContext.getNumberOfFrames(); i < n; i++) {
       DILineInfo LineInfo = InlinedContext.getFrame(i);
       if (i == n - 1) {
         std::string FunctionName;
         uint64_t Start, Size;
-        if (getNameFromSymbolTable(SymbolRef::ST_Function,
-                                   ModuleOffset, FunctionName, Start, Size)) {
+        if (getNameFromSymbolTable(SymbolRef::ST_Function, ModuleOffset,
+                                   FunctionName, Start, Size)) {
           patchFunctionNameInDILineInfo(FunctionName, LineInfo);
         }
       }
@@ -148,8 +153,8 @@ DIInliningInfo ModuleInfo::symbolizeInlinedCode(uint64_t ModuleOffset,
 
 bool ModuleInfo::symbolizeData(uint64_t ModuleOffset, std::string &Name,
                                uint64_t &Start, uint64_t &Size) const {
-  return getNameFromSymbolTable(SymbolRef::ST_Data,
-                                ModuleOffset, Name, Start, Size);
+  return getNameFromSymbolTable(SymbolRef::ST_Data, ModuleOffset, Name, Start,
+                                Size);
 }
 
 const char LLVMSymbolizer::kBadString[] = "??";
@@ -160,8 +165,8 @@ std::string LLVMSymbolizer::symbolizeCode(const std::string &ModuleName,
   if (Info == 0)
     return printDILineInfo(DILineInfo());
   if (Opts.PrintInlining) {
-    DIInliningInfo InlinedContext = Info->symbolizeInlinedCode(
-        ModuleOffset, Opts);
+    DIInliningInfo InlinedContext =
+        Info->symbolizeInlinedCode(ModuleOffset, Opts);
     uint32_t FramesNum = InlinedContext.getNumberOfFrames();
     assert(FramesNum > 0);
     std::string Result;
@@ -191,9 +196,12 @@ std::string LLVMSymbolizer::symbolizeData(const std::string &ModuleName,
   return ss.str();
 }
 
+void LLVMSymbolizer::flush() {
+  DeleteContainerSeconds(Modules);
+}
+
 // Returns true if the object endianness is known.
-static bool getObjectEndianness(const ObjectFile *Obj,
-                                bool &IsLittleEndian) {
+static bool getObjectEndianness(const ObjectFile *Obj, bool &IsLittleEndian) {
   // FIXME: Implement this when libLLVMObject allows to do it easily.
   IsLittleEndian = true;
   return true;
@@ -201,8 +209,8 @@ static bool getObjectEndianness(const ObjectFile *Obj,
 
 static ObjectFile *getObjectFile(const std::string &Path) {
   OwningPtr<MemoryBuffer> Buff;
-  if (error_code ec = MemoryBuffer::getFile(Path, Buff))
-    error(ec);
+  if (error(MemoryBuffer::getFile(Path, Buff)))
+    return 0;
   return ObjectFile::createObjectFile(Buff.take());
 }
 
@@ -215,8 +223,8 @@ static std::string getDarwinDWARFResourceForModule(const std::string &Path) {
   return ResourceName.str();
 }
 
-ModuleInfo *LLVMSymbolizer::getOrCreateModuleInfo(
-    const std::string &ModuleName) {
+ModuleInfo *
+LLVMSymbolizer::getOrCreateModuleInfo(const std::string &ModuleName) {
   ModuleMapTy::iterator I = Modules.find(ModuleName);
   if (I != Modules.end())
     return I->second;
@@ -224,7 +232,7 @@ ModuleInfo *LLVMSymbolizer::getOrCreateModuleInfo(
   ObjectFile *Obj = getObjectFile(ModuleName);
   if (Obj == 0) {
     // Module name doesn't point to a valid object file.
-    Modules.insert(make_pair(ModuleName, (ModuleInfo*)0));
+    Modules.insert(make_pair(ModuleName, (ModuleInfo *)0));
     return 0;
   }
 
@@ -235,11 +243,14 @@ ModuleInfo *LLVMSymbolizer::getOrCreateModuleInfo(
     // resource directory.
     ObjectFile *DbgObj = Obj;
     if (isa<MachOObjectFile>(Obj)) {
-      const std::string &ResourceName = getDarwinDWARFResourceForModule(
-          ModuleName);
-      ObjectFile *ResourceObj = getObjectFile(ResourceName);
-      if (ResourceObj != 0)
-        DbgObj = ResourceObj;
+      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);
@@ -265,8 +276,8 @@ std::string LLVMSymbolizer::printDILineInfo(DILineInfo LineInfo) const {
   std::string Filename = LineInfo.getFileName();
   if (Filename == kDILineInfoBadString)
     Filename = kBadString;
-  Result << Filename << ":" << LineInfo.getLine()
-                     << ":" << LineInfo.getColumn() << "\n";
+  Result << Filename << ":" << LineInfo.getLine() << ":" << LineInfo.getColumn()
+         << "\n";
   return Result.str();
 }
 
@@ -289,5 +300,5 @@ void LLVMSymbolizer::DemangleName(std::string &Name) const {
 #endif
 }
 
-}  // namespace symbolize
-}  // namespace llvm
+} // namespace symbolize
+} // namespace llvm