[LLVMSymbolize] Factor out the logic for printing structs from DIContext. NFC.

Introduce DIPrinter which takes care of rendering DILineInfo and
friends. This allows LLVMSymbolizer class to return a structured data
instead of plain std::strings.

llvm-svn: 251989
This commit is contained in:
Alexey Samsonov 2015-11-03 22:20:52 +00:00
parent 61362ce876
commit d6aa820262
6 changed files with 135 additions and 80 deletions

View File

@ -0,0 +1,43 @@
//===- llvm/DebugInfo/Symbolize/DIPrinter.h ---------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file declares the DIPrinter class, which is responsible for printing
// structures defined in DebugInfo/DIContext.h
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_DEBUGINFO_SYMBOLIZE_DIPRINTER_H
#define LLVM_DEBUGINFO_SYMBOLIZE_DIPRINTER_H
#include "llvm/Support/raw_ostream.h"
namespace llvm {
struct DILineInfo;
class DIInliningInfo;
struct DIGlobal;
namespace symbolize {
class DIPrinter {
raw_ostream &OS;
bool PrintFunctionNames;
public:
DIPrinter(raw_ostream &OS, bool PrintFunctionNames = true)
: OS(OS), PrintFunctionNames(PrintFunctionNames) {}
DIPrinter &operator<<(const DILineInfo &Info);
DIPrinter &operator<<(const DIInliningInfo &Info);
DIPrinter &operator<<(const DIGlobal &Global);
};
}
}
#endif

View File

@ -51,14 +51,11 @@ public:
flush();
}
// Returns the result of symbolization for module name/offset as
// a string (possibly containing newlines).
std::string
symbolizeCode(const std::string &ModuleName, uint64_t ModuleOffset);
std::string symbolizeInlinedCode(const std::string &ModuleName,
uint64_t ModuleOffset);
std::string
symbolizeData(const std::string &ModuleName, uint64_t ModuleOffset);
DILineInfo symbolizeCode(const std::string &ModuleName,
uint64_t ModuleOffset);
DIInliningInfo symbolizeInlinedCode(const std::string &ModuleName,
uint64_t ModuleOffset);
DIGlobal symbolizeData(const std::string &ModuleName, uint64_t ModuleOffset);
void flush();
static std::string DemangleName(const std::string &Name,
const SymbolizableModule *ModInfo);
@ -78,10 +75,6 @@ private:
/// 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;
std::string printDIInliningInfo(DIInliningInfo InlinedContext) const;
std::string printDIGlobal(DIGlobal Global) const;
// Owns all the parsed binaries and object files.
SmallVector<std::unique_ptr<Binary>, 4> ParsedBinariesAndObjects;
SmallVector<std::unique_ptr<MemoryBuffer>, 4> MemoryBuffers;
@ -100,7 +93,6 @@ private:
ObjectPairForPathArch;
Options Opts;
static const char kBadString[];
};
} // namespace symbolize

View File

@ -1,4 +1,5 @@
add_llvm_library(LLVMSymbolize
DIPrinter.cpp
SymbolizableObjectFile.cpp
Symbolize.cpp

View File

@ -0,0 +1,61 @@
//===- lib/DebugInfo/Symbolize/DIPrinter.cpp ------------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file defines the DIPrinter class, which is responsible for printing
// structures defined in DebugInfo/DIContext.h
//
//===----------------------------------------------------------------------===//
#include "llvm/DebugInfo/Symbolize/DIPrinter.h"
#include "llvm/DebugInfo/DIContext.h"
namespace llvm {
namespace symbolize {
// By default, DILineInfo contains "<invalid>" for function/filename it
// cannot fetch. We replace it to "??" to make our output closer to addr2line.
static const char kDILineInfoBadString[] = "<invalid>";
static const char kBadString[] = "??";
DIPrinter &DIPrinter::operator<<(const DILineInfo &Info) {
if (PrintFunctionNames) {
std::string FunctionName = Info.FunctionName;
if (FunctionName == kDILineInfoBadString)
FunctionName = kBadString;
OS << FunctionName << "\n";
}
std::string Filename = Info.FileName;
if (Filename == kDILineInfoBadString)
Filename = kBadString;
OS << Filename << ":" << Info.Line << ":" << Info.Column << "\n";
return *this;
}
DIPrinter &DIPrinter::operator<<(const DIInliningInfo &Info) {
uint32_t FramesNum = Info.getNumberOfFrames();
if (FramesNum == 0)
return (*this << DILineInfo());
for (uint32_t i = 0; i < FramesNum; i++) {
*this << Info.getFrame(i);
}
return *this;
}
DIPrinter &DIPrinter::operator<<(const DIGlobal &Global) {
std::string Name = Global.Name;
if (Name == kDILineInfoBadString)
Name = kBadString;
OS << Name << "\n";
OS << Global.Start << " " << Global.Size << "\n";
return *this;
}
}
}

View File

@ -30,7 +30,6 @@
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/Path.h"
#include <sstream>
#include <stdlib.h>
#if defined(_MSC_VER)
@ -55,18 +54,11 @@ static bool error(std::error_code ec) {
return true;
}
// By default, DILineInfo contains "<invalid>" for function/filename it
// cannot fetch. We replace it to "??" to make our output closer to addr2line.
static const char kDILineInfoBadString[] = "<invalid>";
const char LLVMSymbolizer::kBadString[] = "??";
std::string LLVMSymbolizer::symbolizeCode(const std::string &ModuleName,
uint64_t ModuleOffset) {
DILineInfo LLVMSymbolizer::symbolizeCode(const std::string &ModuleName,
uint64_t ModuleOffset) {
SymbolizableModule *Info = getOrCreateModuleInfo(ModuleName);
if (!Info)
return printDILineInfo(DILineInfo());
return DILineInfo();
// If the user is giving us relative addresses, add the preferred base of the
// object to the offset before we do the query. It's what DIContext expects.
@ -77,14 +69,15 @@ std::string LLVMSymbolizer::symbolizeCode(const std::string &ModuleName,
Opts.UseSymbolTable);
if (Opts.Demangle)
LineInfo.FunctionName = DemangleName(LineInfo.FunctionName, Info);
return printDILineInfo(LineInfo);
return LineInfo;
}
std::string LLVMSymbolizer::symbolizeInlinedCode(const std::string &ModuleName,
uint64_t ModuleOffset) {
DIInliningInfo
LLVMSymbolizer::symbolizeInlinedCode(const std::string &ModuleName,
uint64_t ModuleOffset) {
SymbolizableModule *Info = getOrCreateModuleInfo(ModuleName);
if (!Info)
return printDIInliningInfo(DIInliningInfo());
return DIInliningInfo();
// If the user is giving us relative addresses, add the preferred base of the
// object to the offset before we do the query. It's what DIContext expects.
@ -99,16 +92,16 @@ std::string LLVMSymbolizer::symbolizeInlinedCode(const std::string &ModuleName,
Frame->FunctionName = DemangleName(Frame->FunctionName, Info);
}
}
return printDIInliningInfo(InlinedContext);
return InlinedContext;
}
std::string LLVMSymbolizer::symbolizeData(const std::string &ModuleName,
uint64_t ModuleOffset) {
DIGlobal LLVMSymbolizer::symbolizeData(const std::string &ModuleName,
uint64_t ModuleOffset) {
if (!Opts.UseSymbolTable)
return printDIGlobal(DIGlobal());
return DIGlobal();
SymbolizableModule *Info = getOrCreateModuleInfo(ModuleName);
if (!Info)
return printDIGlobal(DIGlobal());
return DIGlobal();
// If the user is giving us relative addresses, add the preferred base of
// the object to the offset before we do the query. It's what DIContext
@ -119,7 +112,7 @@ std::string LLVMSymbolizer::symbolizeData(const std::string &ModuleName,
DIGlobal Global = Info->symbolizeData(ModuleOffset);
if (Opts.Demangle)
Global.Name = DemangleName(Global.Name, Info);
return printDIGlobal(Global);
return Global;
}
void LLVMSymbolizer::flush() {
@ -371,46 +364,6 @@ LLVMSymbolizer::getOrCreateModuleInfo(const std::string &ModuleName) {
return Res;
}
std::string
LLVMSymbolizer::printDILineInfo(DILineInfo LineInfo) const {
std::stringstream Result;
if (Opts.PrintFunctions != FunctionNameKind::None) {
std::string FunctionName = LineInfo.FunctionName;
if (FunctionName == kDILineInfoBadString)
FunctionName = kBadString;
Result << FunctionName << "\n";
}
std::string Filename = LineInfo.FileName;
if (Filename == kDILineInfoBadString)
Filename = kBadString;
Result << Filename << ":" << LineInfo.Line << ":" << LineInfo.Column << "\n";
return Result.str();
}
std::string
LLVMSymbolizer::printDIInliningInfo(DIInliningInfo InlinedContext) const {
uint32_t FramesNum = InlinedContext.getNumberOfFrames();
if (FramesNum == 0)
return printDILineInfo(DILineInfo());
std::string Result;
for (uint32_t i = 0; i < FramesNum; i++) {
DILineInfo LineInfo = InlinedContext.getFrame(i);
Result += printDILineInfo(LineInfo);
}
return Result;
}
std::string
LLVMSymbolizer::printDIGlobal(DIGlobal Global) const {
std::stringstream Result;
std::string Name = Global.Name;
if (Name == kDILineInfoBadString)
Name = kBadString;
Result << Name << "\n";
Result << Global.Start << " " << Global.Size << "\n";
return Result.str();
}
// Undo these various manglings for Win32 extern "C" functions:
// cdecl - _foo
// stdcall - _foo@12

View File

@ -16,6 +16,7 @@
//===----------------------------------------------------------------------===//
#include "llvm/ADT/StringRef.h"
#include "llvm/DebugInfo/Symbolize/DIPrinter.h"
#include "llvm/DebugInfo/Symbolize/Symbolize.h"
#include "llvm/Support/COM.h"
#include "llvm/Support/CommandLine.h"
@ -148,18 +149,22 @@ int main(int argc, char **argv) {
bool IsData = false;
std::string ModuleName;
uint64_t ModuleOffset;
DIPrinter Printer(outs(), ClPrintFunctions != FunctionNameKind::None);
while (parseCommand(IsData, ModuleName, ModuleOffset)) {
std::string Result =
IsData ? Symbolizer.symbolizeData(ModuleName, ModuleOffset)
: ClPrintInlining
? Symbolizer.symbolizeInlinedCode(ModuleName, ModuleOffset)
: Symbolizer.symbolizeCode(ModuleName, ModuleOffset);
if (ClPrintAddress) {
outs() << "0x";
outs().write_hex(ModuleOffset);
outs() << "\n";
}
outs() << Result << "\n";
if (IsData) {
Printer << Symbolizer.symbolizeData(ModuleName, ModuleOffset);
} else if (ClPrintInlining) {
Printer << Symbolizer.symbolizeInlinedCode(ModuleName, ModuleOffset);
} else {
Printer << Symbolizer.symbolizeCode(ModuleName, ModuleOffset);
}
outs() << "\n";
outs().flush();
}