-
Notifications
You must be signed in to change notification settings - Fork 15.1k
Added --report=debugger option to llvm-debuginfo-analyzer #159853
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from 11 commits
a85243d
25793b4
76efd65
8b0d172
0752ef8
6a0edef
bf7848e
5d0f679
ceee148
dbc8d36
431ec62
936e9f6
6ad0daa
dbc62cd
0f5a6a9
9f2beca
cf5c3ef
efc481e
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -394,6 +394,8 @@ to make the output easier to understand. | |
| =list: Elements are displayed in a tabular format. | ||
| =parents: Elements and parents are displayed in a tree format. | ||
| =view: Elements, parents and children are displayed in a tree format. | ||
| =debugger: Lines, and optionally variables and instructions are | ||
| displayed in a way to simulate stepping through a debugger. | ||
|
|
||
| The **list** layout presents the logical elements in a tabular form | ||
| without any parent-child relationship. This may be the preferred way to | ||
|
|
@@ -417,6 +419,10 @@ The combined **view** layout includes the elements that match any given | |
| criteria (:option:`--select`) or (:option:`--compare`), its parents | ||
| and children. | ||
|
|
||
| The combined **debugger** layout prints each statement line in order and | ||
| variables live at each line (if `--print=symbols` given), as well as | ||
| instructions (if `--print=instructions` given). | ||
|
|
||
|
||
| **Notes**: | ||
|
|
||
| 1. When a selection criteria (:option:`--select`) is specified with no | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -167,7 +167,8 @@ enum class LVReportKind { | |
| Children, // --report=children | ||
| List, // --report=list | ||
| Parents, // --report=parents | ||
| View // --report=view | ||
| View, // --report=view | ||
| Debugger // --report=debugger | ||
adam-yang marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| }; | ||
| using LVReportKindSet = std::set<LVReportKind>; | ||
|
|
||
|
|
@@ -408,6 +409,7 @@ class LVOptions { | |
| REPORT_OPTION(Children); | ||
| REPORT_OPTION(List); | ||
| REPORT_OPTION(Parents); | ||
| REPORT_OPTION(Debugger); | ||
|
||
| REPORT_OPTION(View); | ||
| BOOL_FUNCTION(Report, AnyView); | ||
| BOOL_FUNCTION(Report, Execute); | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -648,6 +648,19 @@ void LVLocation::print(LVLocations *Locations, raw_ostream &OS, bool Full) { | |
| Location->print(OS, Full); | ||
| } | ||
|
|
||
| void LVLocationSymbol::printLocations(raw_ostream &OS) const { | ||
| if (Entries) { | ||
| bool CodeViewLocation = getParentSymbol()->getHasCodeViewLocation(); | ||
| std::string Leading; | ||
| for (LVOperation *Operation : *Entries) { | ||
| OS << Leading | ||
| << (CodeViewLocation ? Operation->getOperandsCodeViewInfo() | ||
| : Operation->getOperandsDWARFInfo()); | ||
| Leading = ", "; | ||
| } | ||
|
Comment on lines
+654
to
+660
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Nit: I see that this code was moved from this original location, but perhaps we could take the chance to adopt |
||
| } | ||
| } | ||
|
|
||
| void LVLocationSymbol::printExtra(raw_ostream &OS, bool Full) const { | ||
| OS << "{Location}"; | ||
| if (getIsCallSite()) | ||
|
|
@@ -657,15 +670,9 @@ void LVLocationSymbol::printExtra(raw_ostream &OS, bool Full) const { | |
|
|
||
| // Print location entries. | ||
| if (Full && Entries) { | ||
| bool CodeViewLocation = getParentSymbol()->getHasCodeViewLocation(); | ||
| std::stringstream Stream; | ||
| std::string Leading; | ||
| for (LVOperation *Operation : *Entries) { | ||
| Stream << Leading | ||
| << (CodeViewLocation ? Operation->getOperandsCodeViewInfo() | ||
| : Operation->getOperandsDWARFInfo()); | ||
| Leading = ", "; | ||
| } | ||
| std::string Str; | ||
| raw_string_ostream Stream(Str); | ||
| printLocations(Stream); | ||
| printAttributes(OS, Full, "{Entry} ", const_cast<LVLocationSymbol *>(this), | ||
| StringRef(Stream.str()), | ||
| /*UseQuotes=*/false, | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -132,6 +132,14 @@ void LVOptions::resolveDependencies() { | |
| setPrintWarnings(); | ||
| } | ||
|
|
||
| if (getReportDebugger()) { | ||
| // Must include at least the lines, otherwise there's nothing to print | ||
| setPrintLines(); | ||
| // Printing symbols in debugger report requires the symbol ranges | ||
| if (getPrintSymbols()) | ||
| setAttributeRange(); | ||
| } | ||
|
|
||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Just a very minor points. Missing full stops in the comments. |
||
| // '--warning=all' settings. | ||
| if (getWarningAll()) { | ||
| setWarningCoverages(); | ||
|
|
@@ -189,6 +197,7 @@ void LVOptions::resolveDependencies() { | |
| setReportList(); | ||
| setReportParents(); | ||
| setReportView(); | ||
| setReportDebugger(); | ||
adam-yang marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| } | ||
|
|
||
| // '--report=view' is a shortcut for '--report=parents,children'. | ||
|
|
@@ -202,7 +211,7 @@ void LVOptions::resolveDependencies() { | |
| setReportAnyView(); | ||
|
|
||
| // The report will include: List or Parents or Children. | ||
| if (getReportList() || getReportAnyView()) | ||
| if (getReportList() || getReportAnyView() || getReportDebugger()) | ||
| setReportExecute(); | ||
|
|
||
| // If a view or element comparison has been requested, the following options | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -11,6 +11,7 @@ | |
| //===----------------------------------------------------------------------===// | ||
|
|
||
| #include "llvm/DebugInfo/LogicalView/Core/LVReader.h" | ||
| #include "llvm/ADT/SetVector.h" | ||
| #include "llvm/DebugInfo/LogicalView/Core/LVScope.h" | ||
| #include "llvm/Support/FileSystem.h" | ||
| #include "llvm/Support/FormatAdapters.h" | ||
|
|
@@ -516,13 +517,181 @@ Error LVReader::doPrint() { | |
| if (options().getReportParents() || options().getReportView()) | ||
| if (Error Err = printScopes()) | ||
| return Err; | ||
|
|
||
| // Requested debugger report | ||
adam-yang marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| if (options().getReportDebugger()) | ||
| if (Error Err = printDebugger()) | ||
| return Err; | ||
| return Error::success(); | ||
| } | ||
|
|
||
| return printScopes(); | ||
| } | ||
|
|
||
| namespace { | ||
|
|
||
| struct DebuggerViewPrinter { | ||
| std::vector<const LVLine *> Lines; | ||
| std::unordered_map<LVAddress, std::vector<const LVLocation *>> LifetimeBegins; | ||
| std::unordered_map<LVAddress, std::vector<const LVLocation *>> | ||
| LifetimeEndsExclusive; | ||
| raw_ostream &OS; | ||
|
|
||
| const bool IncludeRanges = false; | ||
|
|
||
| void Walk(raw_ostream &OS, const LVScope *Scope) { | ||
adam-yang marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| if (Scope->scopeCount()) { | ||
| for (const LVScope *ChildScope : *Scope->getScopes()) | ||
| Walk(OS, ChildScope); | ||
| } | ||
| if (Scope->lineCount()) { | ||
| for (const LVLine *Line : *Scope->getLines()) { | ||
| Lines.push_back(Line); | ||
| } | ||
| } | ||
| if (Scope->symbolCount()) { | ||
| for (const LVSymbol *Symbol : *Scope->getSymbols()) { | ||
| LVLocations SymbolLocations; | ||
| Symbol->getLocations(SymbolLocations); | ||
| if (SymbolLocations.empty()) | ||
| continue; | ||
|
|
||
| if (IncludeRanges) | ||
| OS << "{Range}: " << Symbol->getName() << " (line " | ||
| << Symbol->getLineNumber() << ")" << ": "; | ||
|
|
||
| for (const LVLocation *Loc : SymbolLocations) { | ||
| if (Loc->getIsGapEntry()) | ||
|
||
| continue; | ||
|
|
||
| LVAddress Begin = Loc->getLowerAddress(); | ||
| LVAddress End = Loc->getUpperAddress(); | ||
| LifetimeBegins[Begin].push_back(Loc); | ||
| LifetimeEndsExclusive[End].push_back(Loc); | ||
|
|
||
| if (IncludeRanges) | ||
| OS << "[" << hexValue(Begin) << ":" << hexValue(End) << "] "; | ||
| } | ||
|
|
||
| if (IncludeRanges) | ||
| OS << "\n"; | ||
| } | ||
| } | ||
| } | ||
|
|
||
| DebuggerViewPrinter(raw_ostream &OS, const LVScopeFunction *Fn) : OS(OS) { | ||
| Walk(OS, Fn); | ||
| std::sort(Lines.begin(), Lines.end(), | ||
| [](const LVLine *a, const LVLine *b) -> bool { | ||
| if (a->getAddress() != b->getAddress()) | ||
| return a->getAddress() < b->getAddress(); | ||
| if (a->getIsLineDebug() != b->getIsLineDebug()) | ||
| return a->getIsLineDebug(); | ||
| return a->getID() < b->getID(); | ||
| }); | ||
| } | ||
|
|
||
| static void PrintIndent(raw_ostream &OS, int Indent) { | ||
| for (int i = 0; i < Indent; i++) | ||
| OS << " "; | ||
| } | ||
|
|
||
| static void PrintCallstack(raw_ostream &OS, const LVScope *Scope) { | ||
| const LVScope *PrevScope = nullptr; | ||
| while (Scope) { | ||
| if (Scope->getIsFunction() || Scope->getIsInlinedFunction()) { | ||
| OS << "[" << Scope->getName(); | ||
| if (PrevScope && PrevScope->getIsInlinedFunction()) { | ||
| OS << ":" | ||
| << cast<LVScopeFunctionInlined>(PrevScope)->getCallLineNumber(); | ||
| } | ||
| OS << "]"; | ||
| PrevScope = Scope; | ||
| } | ||
| Scope = Scope->getParentScope(); | ||
| } | ||
| } | ||
|
|
||
| static bool IsChildScopeOf(const LVScope *A, const LVScope *B) { | ||
| while (A) { | ||
| A = A->getParentScope(); | ||
| if (A == B) | ||
| return true; | ||
| } | ||
| return false; | ||
| } | ||
|
|
||
| void Print() { | ||
| const bool IncludeVars = options().getPrintSymbols(); | ||
| const bool IncludeCode = options().getPrintInstructions(); | ||
| SetVector<const LVLocation *> | ||
| LiveSymbols; // This needs to be ordered since we're iterating over it. | ||
| for (const LVLine *Line : Lines) { | ||
| const LVScope *Scope = Line->getParentScope(); | ||
| // Update live list: Add lives | ||
| for (auto Loc : LifetimeBegins[Line->getAddress()]) | ||
| LiveSymbols.insert(Loc); | ||
| // Update live list: remove dead | ||
| for (auto Loc : LifetimeEndsExclusive[Line->getAddress()]) | ||
| LiveSymbols.remove(Loc); | ||
|
|
||
| if (Line->getIsNewStatement() && Line->getIsLineDebug() && | ||
| Line->getLineNumber() != 0) { | ||
| auto LineDebug = cast<LVLineDebug>(Line); | ||
|
|
||
| PrintIndent(OS, 1); | ||
| OS << "{Line}: " << " [" << hexValue(LineDebug->getAddress()) << "] " | ||
| << LineDebug->getPathname() << ":" << LineDebug->getLineNumber() | ||
| << " "; | ||
| PrintCallstack(OS, Scope); | ||
| OS << "\n"; | ||
| if (IncludeVars) { | ||
| for (auto SymLoc : LiveSymbols) { | ||
| const LVSymbol *Sym = SymLoc->getParentSymbol(); | ||
| auto SymScope = Sym->getParentScope(); | ||
| auto LineScope = LineDebug->getParentScope(); | ||
| if (SymScope != LineScope && !IsChildScopeOf(LineScope, SymScope)) | ||
| continue; | ||
| PrintIndent(OS, 2); | ||
| OS << "{Variable}: " << Sym->getName() << ": " | ||
| << Sym->getType()->getName() << " : "; | ||
| SymLoc->printLocations(OS); | ||
| OS << " (line " << Sym->getLineNumber() << ")"; | ||
| OS << "\n"; | ||
| } | ||
| } | ||
|
|
||
| } else if (IncludeCode && Line->getIsLineAssembler()) { | ||
| OS << " {Code}: " << " [" << hexValue(Line->getAddress()) << "] " | ||
| << Line->getName() << "\n"; | ||
| } | ||
| } | ||
| } | ||
| }; | ||
|
|
||
| } // namespace | ||
|
|
||
adam-yang marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| Error LVReader::printDebugger() { | ||
| auto *CU = getCompileUnit(); | ||
|
||
| if (!CU) | ||
| return createStringError(std::make_error_code(std::errc::invalid_argument), | ||
| "Error: No compute unit found."); | ||
|
||
|
|
||
| for (const LVScope *ChildScope : *CU->getScopes()) { | ||
| auto *Fn = dyn_cast<LVScopeFunction>(ChildScope); | ||
| if (Fn) { | ||
| const LVLines *Lines = Fn->getLines(); | ||
| // If there's no lines, this function has no body. | ||
| if (!Lines) | ||
| continue; | ||
| outs() << "{Function}: " << ChildScope->getName() << "\n"; | ||
|
|
||
| DebuggerViewPrinter P(OS, Fn); | ||
| P.Print(); | ||
| } | ||
| } | ||
| return Error::success(); | ||
| } | ||
|
|
||
| Error LVReader::printScopes() { | ||
| if (bool DoPrint = | ||
| (options().getPrintExecute() || options().getComparePrint())) { | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.