Skip to content

Commit

Permalink
* NFC. Refactored DIPrinter for better support of new print styles.
Browse files Browse the repository at this point in the history
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
  • Loading branch information
orlov-alex committed Apr 5, 2021
1 parent 0d0514d commit 5f57793
Show file tree
Hide file tree
Showing 3 changed files with 269 additions and 144 deletions.
101 changes: 80 additions & 21 deletions llvm/include/llvm/DebugInfo/Symbolize/DIPrinter.h
Original file line number Diff line number Diff line change
Expand Up @@ -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:
PlainPrinterBase(raw_ostream &OS, raw_ostream &ES, PrinterConfig &Config)
: DIPrinter(), OS(OS), ES(ES), Config(Config) {}

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:
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) {}

DIPrinter &operator<<(const DILineInfo &Info);
DIPrinter &operator<<(const DIInliningInfo &Info);
DIPrinter &operator<<(const DIGlobal &Global);
DIPrinter &operator<<(const DILocal &Local);
GNUPrinter(raw_ostream &OS, raw_ostream &ES, PrinterConfig &Config)
: PlainPrinterBase(OS, ES, Config) {}
};
}
}
} // namespace symbolize
} // namespace llvm

#endif
191 changes: 124 additions & 67 deletions llvm/lib/DebugInfo/Symbolize/DIPrinter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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 =
Expand All @@ -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);
Expand All @@ -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;
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";
}

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 << " Function start filename: " << Info.StartFileName << '\n';
OS << " Function start line: " << Info.StartLine << '\n';
}
OS << " Line: " << Info.Line << "\n";
OS << " Column: " << Info.Column << "\n";
OS << " Line: " << Info.Line << '\n';
OS << " Column: " << Info.Column << '\n';
if (Info.Discriminator)
OS << " Discriminator: " << Info.Discriminator << "\n";
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 (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
Expand Down
Loading

0 comments on commit 5f57793

Please sign in to comment.