1
0
mirror of https://github.com/RPCS3/llvm-mirror.git synced 2024-11-22 18:54:02 +01:00

* NFC. Refactored DIPrinter for better support of new print styles.

This patch introduces a DIPrinter interface to implement by different output style printer implementations. DIPrinterGNU and DIPrinterLLVM implement the GNU and LLVM output style printing respectively. No functional changes.

This refactoring clarifies and simplifies the code, and makes a new output style addition easier.

Reviewed By: jhenderson, dblaikie

Differential Revision: https://reviews.llvm.org/D98994
This commit is contained in:
Alex Orlov 2021-04-05 15:40:41 +04:00
parent 9ae8059434
commit dac2590aaa
3 changed files with 269 additions and 144 deletions

View File

@ -14,46 +14,105 @@
#ifndef LLVM_DEBUGINFO_SYMBOLIZE_DIPRINTER_H
#define LLVM_DEBUGINFO_SYMBOLIZE_DIPRINTER_H
#include "llvm/ADT/StringRef.h"
#include <string>
#include <vector>
namespace llvm {
struct DILineInfo;
class DIInliningInfo;
struct DIGlobal;
struct DILocal;
class ErrorInfoBase;
class raw_ostream;
namespace symbolize {
struct Request {
StringRef ModuleName;
uint64_t Address = 0;
};
class DIPrinter {
public:
enum class OutputStyle { LLVM, GNU };
DIPrinter(){};
virtual ~DIPrinter(){};
private:
raw_ostream &OS;
bool PrintFunctionNames;
bool PrintPretty;
int PrintSourceContext;
virtual void print(const Request &Request, const DILineInfo &Info) = 0;
virtual void print(const Request &Request, const DIInliningInfo &Info) = 0;
virtual void print(const Request &Request, const DIGlobal &Global) = 0;
virtual void print(const Request &Request,
const std::vector<DILocal> &Locals) = 0;
virtual void printInvalidCommand(const Request &Request,
const ErrorInfoBase &ErrorInfo) = 0;
virtual bool printError(const Request &Request,
const ErrorInfoBase &ErrorInfo,
StringRef ErrorBanner) = 0;
};
struct PrinterConfig {
bool PrintAddress;
bool PrintFunctions;
bool Pretty;
bool Verbose;
OutputStyle Style;
int SourceContextLines;
};
class PlainPrinterBase : public DIPrinter {
protected:
raw_ostream &OS;
raw_ostream &ES;
PrinterConfig Config;
void print(const DILineInfo &Info, bool Inlined);
void printContext(const std::string &FileName, int64_t Line);
void printFunctionName(StringRef FunctionName, bool Inlined);
virtual void printSimpleLocation(StringRef Filename,
const DILineInfo &Info) = 0;
void printContext(StringRef FileName, int64_t Line);
void printVerbose(StringRef Filename, const DILineInfo &Info);
virtual void printFooter() {}
private:
void printHeader(uint64_t Address);
public:
DIPrinter(raw_ostream &OS, bool PrintFunctionNames = true,
bool PrintPretty = false, int PrintSourceContext = 0,
bool Verbose = false, OutputStyle Style = OutputStyle::LLVM)
: OS(OS), PrintFunctionNames(PrintFunctionNames),
PrintPretty(PrintPretty), PrintSourceContext(PrintSourceContext),
Verbose(Verbose), Style(Style) {}
PlainPrinterBase(raw_ostream &OS, raw_ostream &ES, PrinterConfig &Config)
: DIPrinter(), OS(OS), ES(ES), Config(Config) {}
DIPrinter &operator<<(const DILineInfo &Info);
DIPrinter &operator<<(const DIInliningInfo &Info);
DIPrinter &operator<<(const DIGlobal &Global);
DIPrinter &operator<<(const DILocal &Local);
void print(const Request &Request, const DILineInfo &Info) override;
void print(const Request &Request, const DIInliningInfo &Info) override;
void print(const Request &Request, const DIGlobal &Global) override;
void print(const Request &Request,
const std::vector<DILocal> &Locals) override;
void printInvalidCommand(const Request &Request,
const ErrorInfoBase &ErrorInfo) override;
bool printError(const Request &Request, const ErrorInfoBase &ErrorInfo,
StringRef ErrorBanner) override;
};
}
}
class LLVMPrinter : public PlainPrinterBase {
private:
void printSimpleLocation(StringRef Filename, const DILineInfo &Info) override;
void printFooter() override;
public:
LLVMPrinter(raw_ostream &OS, raw_ostream &ES, PrinterConfig &Config)
: PlainPrinterBase(OS, ES, Config) {}
};
class GNUPrinter : public PlainPrinterBase {
private:
void printSimpleLocation(StringRef Filename, const DILineInfo &Info) override;
public:
GNUPrinter(raw_ostream &OS, raw_ostream &ES, PrinterConfig &Config)
: PlainPrinterBase(OS, ES, Config) {}
};
} // namespace symbolize
} // namespace llvm
#endif

View File

@ -30,9 +30,18 @@
namespace llvm {
namespace symbolize {
void PlainPrinterBase::printHeader(uint64_t Address) {
if (Config.PrintAddress) {
OS << "0x";
OS.write_hex(Address);
StringRef Delimiter = Config.Pretty ? ": " : "\n";
OS << Delimiter;
}
}
// Prints source code around in the FileName the Line.
void DIPrinter::printContext(const std::string &FileName, int64_t Line) {
if (PrintSourceContext <= 0)
void PlainPrinterBase::printContext(StringRef FileName, int64_t Line) {
if (Config.SourceContextLines <= 0)
return;
ErrorOr<std::unique_ptr<MemoryBuffer>> BufOrErr =
@ -42,8 +51,8 @@ void DIPrinter::printContext(const std::string &FileName, int64_t Line) {
std::unique_ptr<MemoryBuffer> Buf = std::move(BufOrErr.get());
int64_t FirstLine =
std::max(static_cast<int64_t>(1), Line - PrintSourceContext / 2);
int64_t LastLine = FirstLine + PrintSourceContext;
std::max(static_cast<int64_t>(1), Line - Config.SourceContextLines / 2);
int64_t LastLine = FirstLine + Config.SourceContextLines;
size_t MaxLineNumberWidth = std::ceil(std::log10(LastLine));
for (line_iterator I = line_iterator(*Buf, false);
@ -60,97 +69,145 @@ void DIPrinter::printContext(const std::string &FileName, int64_t Line) {
}
}
void DIPrinter::print(const DILineInfo &Info, bool Inlined) {
if (PrintFunctionNames) {
std::string FunctionName = Info.FunctionName;
void PlainPrinterBase::printFunctionName(StringRef FunctionName, bool Inlined) {
if (Config.PrintFunctions) {
if (FunctionName == DILineInfo::BadString)
FunctionName = DILineInfo::Addr2LineBadString;
StringRef Delimiter = PrintPretty ? " at " : "\n";
StringRef Prefix = (PrintPretty && Inlined) ? " (inlined by) " : "";
StringRef Delimiter = Config.Pretty ? " at " : "\n";
StringRef Prefix = (Config.Pretty && Inlined) ? " (inlined by) " : "";
OS << Prefix << FunctionName << Delimiter;
}
std::string Filename = Info.FileName;
}
void LLVMPrinter::printSimpleLocation(StringRef Filename,
const DILineInfo &Info) {
OS << Filename << ':' << Info.Line << ':' << Info.Column << '\n';
printContext(Filename, Info.Line);
}
void GNUPrinter::printSimpleLocation(StringRef Filename,
const DILineInfo &Info) {
OS << Filename << ':' << Info.Line;
if (Info.Discriminator)
OS << " (discriminator " << Info.Discriminator << ')';
OS << '\n';
printContext(Filename, Info.Line);
}
void PlainPrinterBase::printVerbose(StringRef Filename,
const DILineInfo &Info) {
OS << " Filename: " << Filename << '\n';
if (Info.StartLine) {
OS << " Function start filename: " << Info.StartFileName << '\n';
OS << " Function start line: " << Info.StartLine << '\n';
}
OS << " Line: " << Info.Line << '\n';
OS << " Column: " << Info.Column << '\n';
if (Info.Discriminator)
OS << " Discriminator: " << Info.Discriminator << '\n';
}
void LLVMPrinter::printFooter() { OS << '\n'; }
void PlainPrinterBase::print(const DILineInfo &Info, bool Inlined) {
printFunctionName(Info.FunctionName, Inlined);
StringRef Filename = Info.FileName;
if (Filename == DILineInfo::BadString)
Filename = DILineInfo::Addr2LineBadString;
if (!Verbose) {
OS << Filename << ":" << Info.Line;
if (Style == OutputStyle::LLVM)
OS << ":" << Info.Column;
else if (Style == OutputStyle::GNU && Info.Discriminator != 0)
OS << " (discriminator " << Info.Discriminator << ")";
OS << "\n";
printContext(Filename, Info.Line);
return;
}
OS << " Filename: " << Filename << "\n";
if (Info.StartLine) {
OS << " Function start filename: " << Info.StartFileName << "\n";
OS << " Function start line: " << Info.StartLine << "\n";
}
OS << " Line: " << Info.Line << "\n";
OS << " Column: " << Info.Column << "\n";
if (Info.Discriminator)
OS << " Discriminator: " << Info.Discriminator << "\n";
if (Config.Verbose)
printVerbose(Filename, Info);
else
printSimpleLocation(Filename, Info);
}
DIPrinter &DIPrinter::operator<<(const DILineInfo &Info) {
void PlainPrinterBase::print(const Request &Request, const DILineInfo &Info) {
printHeader(Request.Address);
print(Info, false);
return *this;
printFooter();
}
DIPrinter &DIPrinter::operator<<(const DIInliningInfo &Info) {
void PlainPrinterBase::print(const Request &Request,
const DIInliningInfo &Info) {
printHeader(Request.Address);
uint32_t FramesNum = Info.getNumberOfFrames();
if (FramesNum == 0) {
if (FramesNum == 0)
print(DILineInfo(), false);
return *this;
}
for (uint32_t i = 0; i < FramesNum; i++)
print(Info.getFrame(i), i > 0);
return *this;
else
for (uint32_t I = 0; I < FramesNum; ++I)
print(Info.getFrame(I), I > 0);
printFooter();
}
DIPrinter &DIPrinter::operator<<(const DIGlobal &Global) {
std::string Name = Global.Name;
void PlainPrinterBase::print(const Request &Request, const DIGlobal &Global) {
printHeader(Request.Address);
StringRef Name = Global.Name;
if (Name == DILineInfo::BadString)
Name = DILineInfo::Addr2LineBadString;
OS << Name << "\n";
OS << Global.Start << " " << Global.Size << "\n";
return *this;
printFooter();
}
DIPrinter &DIPrinter::operator<<(const DILocal &Local) {
if (Local.FunctionName.empty())
OS << "??\n";
void PlainPrinterBase::print(const Request &Request,
const std::vector<DILocal> &Locals) {
printHeader(Request.Address);
if (Locals.empty())
OS << DILineInfo::Addr2LineBadString << '\n';
else
OS << Local.FunctionName << '\n';
for (const DILocal &L : Locals) {
if (L.FunctionName.empty())
OS << DILineInfo::Addr2LineBadString;
else
OS << L.FunctionName;
OS << '\n';
if (Local.Name.empty())
OS << "??\n";
else
OS << Local.Name << '\n';
if (L.Name.empty())
OS << DILineInfo::Addr2LineBadString;
else
OS << L.Name;
OS << '\n';
if (Local.DeclFile.empty())
OS << "??";
else
OS << Local.DeclFile;
OS << ':' << Local.DeclLine << '\n';
if (L.DeclFile.empty())
OS << DILineInfo::Addr2LineBadString;
else
OS << L.DeclFile;
if (Local.FrameOffset)
OS << *Local.FrameOffset << ' ';
else
OS << "?? ";
OS << ':' << L.DeclLine << '\n';
if (Local.Size)
OS << *Local.Size << ' ';
else
OS << "?? ";
if (L.FrameOffset)
OS << *L.FrameOffset;
else
OS << DILineInfo::Addr2LineBadString;
OS << ' ';
if (Local.TagOffset)
OS << *Local.TagOffset << '\n';
else
OS << "??\n";
return *this;
if (L.Size)
OS << *L.Size;
else
OS << DILineInfo::Addr2LineBadString;
OS << ' ';
if (L.TagOffset)
OS << *L.TagOffset;
else
OS << DILineInfo::Addr2LineBadString;
OS << '\n';
}
printFooter();
}
void PlainPrinterBase::printInvalidCommand(const Request &Request,
const ErrorInfoBase &ErrorInfo) {
OS << ErrorInfo.message() << '\n';
}
bool PlainPrinterBase::printError(const Request &Request,
const ErrorInfoBase &ErrorInfo,
StringRef ErrorBanner) {
ES << ErrorBanner;
ErrorInfo.log(ES);
ES << '\n';
// Print an empty struct too.
return true;
}
} // end namespace symbolize

View File

@ -74,15 +74,29 @@ static cl::list<std::string> ClInputAddresses(cl::Positional,
cl::desc("<input addresses>..."),
cl::ZeroOrMore);
template<typename T>
static bool error(Expected<T> &ResOrErr) {
if (ResOrErr)
return false;
logAllUnhandledErrors(ResOrErr.takeError(), errs(),
"LLVMSymbolizer: error reading file: ");
return true;
template <typename T>
static void print(const Request &Request, Expected<T> &ResOrErr,
DIPrinter &Printer) {
if (ResOrErr) {
// No error, print the result.
Printer.print(Request, *ResOrErr);
return;
}
// Handle the error.
bool PrintEmpty = true;
handleAllErrors(std::move(ResOrErr.takeError()),
[&](const ErrorInfoBase &EI) {
PrintEmpty = Printer.printError(
Request, EI, "LLVMSymbolizer: error reading file: ");
});
if (PrintEmpty)
Printer.print(Request, T());
}
enum class OutputStyle { LLVM, GNU };
enum class Command {
Code,
Data,
@ -136,7 +150,7 @@ static bool parseCommand(StringRef BinaryName, bool IsAddr2Line,
}
static void symbolizeInput(const opt::InputArgList &Args, uint64_t AdjustVMA,
bool IsAddr2Line, DIPrinter::OutputStyle OutputStyle,
bool IsAddr2Line, OutputStyle OutputStyle,
StringRef InputString, LLVMSymbolizer &Symbolizer,
DIPrinter &Printer) {
Command Cmd;
@ -144,56 +158,46 @@ static void symbolizeInput(const opt::InputArgList &Args, uint64_t AdjustVMA,
uint64_t Offset = 0;
if (!parseCommand(Args.getLastArgValue(OPT_obj_EQ), IsAddr2Line,
StringRef(InputString), Cmd, ModuleName, Offset)) {
outs() << InputString << "\n";
Printer.printInvalidCommand(
{ModuleName, Offset},
StringError(InputString,
std::make_error_code(std::errc::invalid_argument)));
return;
}
if (Args.hasArg(OPT_addresses)) {
outs() << "0x";
outs().write_hex(Offset);
StringRef Delimiter = Args.hasArg(OPT_pretty_print) ? ": " : "\n";
outs() << Delimiter;
}
Offset -= AdjustVMA;
uint64_t AdjustedOffset = Offset - AdjustVMA;
if (Cmd == Command::Data) {
auto ResOrErr = Symbolizer.symbolizeData(
ModuleName, {Offset, object::SectionedAddress::UndefSection});
Printer << (error(ResOrErr) ? DIGlobal() : ResOrErr.get());
Expected<DIGlobal> ResOrErr = Symbolizer.symbolizeData(
ModuleName, {AdjustedOffset, object::SectionedAddress::UndefSection});
print({ModuleName, Offset}, ResOrErr, Printer);
} else if (Cmd == Command::Frame) {
auto ResOrErr = Symbolizer.symbolizeFrame(
ModuleName, {Offset, object::SectionedAddress::UndefSection});
if (!error(ResOrErr)) {
for (DILocal Local : *ResOrErr)
Printer << Local;
if (ResOrErr->empty())
outs() << "??\n";
}
Expected<std::vector<DILocal>> ResOrErr = Symbolizer.symbolizeFrame(
ModuleName, {AdjustedOffset, object::SectionedAddress::UndefSection});
print({ModuleName, Offset}, ResOrErr, Printer);
} else if (Args.hasFlag(OPT_inlines, OPT_no_inlines, !IsAddr2Line)) {
auto ResOrErr = Symbolizer.symbolizeInlinedCode(
ModuleName, {Offset, object::SectionedAddress::UndefSection});
Printer << (error(ResOrErr) ? DIInliningInfo() : ResOrErr.get());
} else if (OutputStyle == DIPrinter::OutputStyle::GNU) {
Expected<DIInliningInfo> ResOrErr = Symbolizer.symbolizeInlinedCode(
ModuleName, {AdjustedOffset, object::SectionedAddress::UndefSection});
print({ModuleName, Offset}, ResOrErr, Printer);
} else if (OutputStyle == OutputStyle::GNU) {
// With PrintFunctions == FunctionNameKind::LinkageName (default)
// and UseSymbolTable == true (also default), Symbolizer.symbolizeCode()
// may override the name of an inlined function with the name of the topmost
// caller function in the inlining chain. This contradicts the existing
// behavior of addr2line. Symbolizer.symbolizeInlinedCode() overrides only
// the topmost function, which suits our needs better.
auto ResOrErr = Symbolizer.symbolizeInlinedCode(
ModuleName, {Offset, object::SectionedAddress::UndefSection});
if (!ResOrErr || ResOrErr->getNumberOfFrames() == 0) {
error(ResOrErr);
Printer << DILineInfo();
} else {
Printer << ResOrErr->getFrame(0);
}
Expected<DIInliningInfo> ResOrErr = Symbolizer.symbolizeInlinedCode(
ModuleName, {AdjustedOffset, object::SectionedAddress::UndefSection});
Expected<DILineInfo> Res0OrErr =
!ResOrErr
? Expected<DILineInfo>(ResOrErr.takeError())
: ((ResOrErr->getNumberOfFrames() == 0) ? DILineInfo()
: ResOrErr->getFrame(0));
print({ModuleName, Offset}, Res0OrErr, Printer);
} else {
auto ResOrErr = Symbolizer.symbolizeCode(
ModuleName, {Offset, object::SectionedAddress::UndefSection});
Printer << (error(ResOrErr) ? DILineInfo() : ResOrErr.get());
Expected<DILineInfo> ResOrErr = Symbolizer.symbolizeCode(
ModuleName, {AdjustedOffset, object::SectionedAddress::UndefSection});
print({ModuleName, Offset}, ResOrErr, Printer);
}
if (OutputStyle == DIPrinter::OutputStyle::LLVM)
outs() << "\n";
}
static void printHelp(StringRef ToolName, const SymbolizerOptTable &Tbl,
@ -273,7 +277,7 @@ int main(int argc, char **argv) {
LLVMSymbolizer::Options Opts;
uint64_t AdjustVMA;
unsigned SourceContextLines;
PrinterConfig Config;
parseIntArg(Args, OPT_adjust_vma_EQ, AdjustVMA);
if (const opt::Arg *A = Args.getLastArg(OPT_basenames, OPT_relativenames)) {
Opts.PathStyle =
@ -290,7 +294,8 @@ int main(int argc, char **argv) {
Opts.FallbackDebugPath =
Args.getLastArgValue(OPT_fallback_debug_path_EQ).str();
Opts.PrintFunctions = decideHowToPrintFunctions(Args, IsAddr2Line);
parseIntArg(Args, OPT_print_source_context_lines_EQ, SourceContextLines);
parseIntArg(Args, OPT_print_source_context_lines_EQ,
Config.SourceContextLines);
Opts.RelativeAddresses = Args.hasArg(OPT_relative_address);
Opts.UntagAddresses =
Args.hasFlag(OPT_untag_addresses, OPT_no_untag_addresses, !IsAddr2Line);
@ -302,6 +307,10 @@ int main(int argc, char **argv) {
}
#endif
Opts.UseSymbolTable = true;
Config.PrintAddress = Args.hasArg(OPT_addresses);
Config.PrintFunctions = Opts.PrintFunctions != FunctionNameKind::None;
Config.Pretty = Args.hasArg(OPT_pretty_print);
Config.Verbose = Args.hasArg(OPT_verbose);
for (const opt::Arg *A : Args.filtered(OPT_dsym_hint_EQ)) {
StringRef Hint(A->getValue());
@ -313,18 +322,18 @@ int main(int argc, char **argv) {
}
}
auto OutputStyle =
IsAddr2Line ? DIPrinter::OutputStyle::GNU : DIPrinter::OutputStyle::LLVM;
auto OutputStyle = IsAddr2Line ? OutputStyle::GNU : OutputStyle::LLVM;
if (const opt::Arg *A = Args.getLastArg(OPT_output_style_EQ)) {
OutputStyle = strcmp(A->getValue(), "GNU") == 0
? DIPrinter::OutputStyle::GNU
: DIPrinter::OutputStyle::LLVM;
OutputStyle = strcmp(A->getValue(), "GNU") == 0 ? OutputStyle::GNU
: OutputStyle::LLVM;
}
LLVMSymbolizer Symbolizer(Opts);
DIPrinter Printer(outs(), Opts.PrintFunctions != FunctionNameKind::None,
Args.hasArg(OPT_pretty_print), SourceContextLines,
Args.hasArg(OPT_verbose), OutputStyle);
std::unique_ptr<DIPrinter> Printer;
if (OutputStyle == OutputStyle::GNU)
Printer = std::make_unique<GNUPrinter>(outs(), errs(), Config);
else
Printer = std::make_unique<LLVMPrinter>(outs(), errs(), Config);
std::vector<std::string> InputAddresses = Args.getAllArgValues(OPT_INPUT);
if (InputAddresses.empty()) {
@ -337,13 +346,13 @@ int main(int argc, char **argv) {
llvm::erase_if(StrippedInputString,
[](char c) { return c == '\r' || c == '\n'; });
symbolizeInput(Args, AdjustVMA, IsAddr2Line, OutputStyle,
StrippedInputString, Symbolizer, Printer);
StrippedInputString, Symbolizer, *Printer);
outs().flush();
}
} else {
for (StringRef Address : InputAddresses)
symbolizeInput(Args, AdjustVMA, IsAddr2Line, OutputStyle, Address,
Symbolizer, Printer);
Symbolizer, *Printer);
}
return 0;