Skip to content

Commit e2ff01b

Browse files
committed
[DLCov] Origin-Tracking: Add debugify support
1 parent fb65cb7 commit e2ff01b

File tree

2 files changed

+88
-19
lines changed

2 files changed

+88
-19
lines changed

llvm/lib/Transforms/Utils/Debugify.cpp

Lines changed: 73 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,10 @@
1515

1616
#include "llvm/Transforms/Utils/Debugify.h"
1717
#include "llvm/ADT/BitVector.h"
18+
#include "llvm/ADT/DenseMap.h"
19+
#include "llvm/ADT/DenseSet.h"
1820
#include "llvm/ADT/StringExtras.h"
21+
#include "llvm/Config/config.h"
1922
#include "llvm/IR/DIBuilder.h"
2023
#include "llvm/IR/DebugInfo.h"
2124
#include "llvm/IR/InstIterator.h"
@@ -28,6 +31,11 @@
2831
#include "llvm/Support/FileSystem.h"
2932
#include "llvm/Support/JSON.h"
3033
#include <optional>
34+
#if LLVM_ENABLE_DEBUGLOC_TRACKING_ORIGIN
35+
// We need the Signals header to operate on stacktraces if we're using DebugLoc
36+
// origin-tracking.
37+
#include "llvm/Support/Signals.h"
38+
#endif
3139

3240
#define DEBUG_TYPE "debugify"
3341

@@ -59,6 +67,52 @@ cl::opt<Level> DebugifyLevel(
5967

6068
raw_ostream &dbg() { return Quiet ? nulls() : errs(); }
6169

70+
#if LLVM_ENABLE_DEBUGLOC_TRACKING_ORIGIN
71+
// These maps refer to addresses in this instance of LLVM, so we can reuse them
72+
// everywhere - therefore, we store them at file scope.
73+
static DenseMap<void *, SmallVector<std::string, 0>> SymbolizedAddrs;
74+
static DenseSet<void *> UnsymbolizedAddrs;
75+
76+
std::string symbolizeStackTrace(const Instruction *I) {
77+
// We flush the set of unsymbolized addresses at the latest possible moment,
78+
// i.e. now.
79+
if (!UnsymbolizedAddrs.empty()) {
80+
sys::symbolizeAddresses(UnsymbolizedAddrs, SymbolizedAddrs);
81+
UnsymbolizedAddrs.clear();
82+
}
83+
auto OriginStackTraces = I->getDebugLoc().getOriginStackTraces();
84+
std::string Result;
85+
raw_string_ostream OS(Result);
86+
for (size_t TraceIdx = 0; TraceIdx < OriginStackTraces.size(); ++TraceIdx) {
87+
if (TraceIdx != 0)
88+
OS << "========================================\n";
89+
auto &[Depth, StackTrace] = OriginStackTraces[TraceIdx];
90+
unsigned VirtualFrameNo = 0;
91+
for (int Frame = 0; Frame < Depth; ++Frame) {
92+
assert(SymbolizedAddrs.contains(StackTrace[Frame]) &&
93+
"Expected each address to have been symbolized.");
94+
for (std::string &SymbolizedFrame : SymbolizedAddrs[StackTrace[Frame]]) {
95+
OS << right_justify(formatv("#{0}", VirtualFrameNo++).str(), std::log10(Depth) + 2)
96+
<< ' ' << SymbolizedFrame << '\n';
97+
}
98+
}
99+
}
100+
return Result;
101+
}
102+
void collectStackAddresses(Instruction &I) {
103+
auto &OriginStackTraces = I.getDebugLoc().getOriginStackTraces();
104+
for (auto &[Depth, StackTrace] : OriginStackTraces) {
105+
for (int Frame = 0; Frame < Depth; ++Frame) {
106+
void *Addr = StackTrace[Frame];
107+
if (!SymbolizedAddrs.contains(Addr))
108+
UnsymbolizedAddrs.insert(Addr);
109+
}
110+
}
111+
}
112+
#else
113+
void collectStackAddresses(Instruction &I) {}
114+
#endif // LLVM_ENABLE_DEBUGLOC_TRACKING_ORIGIN
115+
62116
uint64_t getAllocSizeInBits(Module &M, Type *Ty) {
63117
return Ty->isSized() ? M.getDataLayout().getTypeAllocSizeInBits(Ty) : 0;
64118
}
@@ -375,6 +429,8 @@ bool llvm::collectDebugInfoMetadata(Module &M,
375429
LLVM_DEBUG(dbgs() << " Collecting info for inst: " << I << '\n');
376430
DebugInfoBeforePass.InstToDelete.insert({&I, &I});
377431

432+
// Track the addresses to symbolize, if the feature is enabled.
433+
collectStackAddresses(I);
378434
DebugInfoBeforePass.DILocations.insert({&I, hasLoc(I)});
379435
}
380436
}
@@ -450,14 +506,23 @@ static bool checkInstructions(const DebugInstMap &DILocsBefore,
450506
auto BBName = BB->hasName() ? BB->getName() : "no-name";
451507
auto InstName = Instruction::getOpcodeName(Instr->getOpcode());
452508

509+
auto CreateJSONBugEntry = [&](const char *Action) {
510+
Bugs.push_back(llvm::json::Object({
511+
{"metadata", "DILocation"},
512+
{"fn-name", FnName.str()},
513+
{"bb-name", BBName.str()},
514+
{"instr", InstName},
515+
{"action", Action},
516+
#if LLVM_ENABLE_DEBUGLOC_TRACKING_ORIGIN
517+
{"origin", symbolizeStackTrace(Instr)},
518+
#endif
519+
}));
520+
};
521+
453522
auto InstrIt = DILocsBefore.find(Instr);
454523
if (InstrIt == DILocsBefore.end()) {
455524
if (ShouldWriteIntoJSON)
456-
Bugs.push_back(llvm::json::Object({{"metadata", "DILocation"},
457-
{"fn-name", FnName.str()},
458-
{"bb-name", BBName.str()},
459-
{"instr", InstName},
460-
{"action", "not-generate"}}));
525+
CreateJSONBugEntry("not-generate");
461526
else
462527
dbg() << "WARNING: " << NameOfWrappedPass
463528
<< " did not generate DILocation for " << *Instr
@@ -470,11 +535,7 @@ static bool checkInstructions(const DebugInstMap &DILocsBefore,
470535
// If the instr had the !dbg attached before the pass, consider it as
471536
// a debug info issue.
472537
if (ShouldWriteIntoJSON)
473-
Bugs.push_back(llvm::json::Object({{"metadata", "DILocation"},
474-
{"fn-name", FnName.str()},
475-
{"bb-name", BBName.str()},
476-
{"instr", InstName},
477-
{"action", "drop"}}));
538+
CreateJSONBugEntry("drop");
478539
else
479540
dbg() << "WARNING: " << NameOfWrappedPass << " dropped DILocation of "
480541
<< *Instr << " (BB: " << BBName << ", Fn: " << FnName
@@ -612,6 +673,8 @@ bool llvm::checkDebugInfoMetadata(Module &M,
612673

613674
LLVM_DEBUG(dbgs() << " Collecting info for inst: " << I << '\n');
614675

676+
// Track the addresses to symbolize, if the feature is enabled.
677+
collectStackAddresses(I);
615678
DebugInfoAfterPass.DILocations.insert({&I, hasLoc(I)});
616679
}
617680
}

llvm/utils/llvm-original-di-preservation.py

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -13,14 +13,15 @@
1313

1414

1515
class DILocBug:
16-
def __init__(self, action, bb_name, fn_name, instr):
16+
def __init__(self, origin, action, bb_name, fn_name, instr):
17+
self.origin = origin
1718
self.action = action
1819
self.bb_name = bb_name
1920
self.fn_name = fn_name
2021
self.instr = instr
2122

2223
def __str__(self):
23-
return self.action + self.bb_name + self.fn_name + self.instr
24+
return self.action + self.bb_name + self.fn_name + self.instr + self.origin
2425

2526

2627
class DISPBug:
@@ -86,6 +87,7 @@ def generate_html_report(
8687
"Function Name",
8788
"Basic Block Name",
8889
"Action",
90+
"Origin",
8991
]
9092

9193
for column in header_di_loc:
@@ -112,6 +114,9 @@ def generate_html_report(
112114
row.append(x.fn_name)
113115
row.append(x.bb_name)
114116
row.append(x.action)
117+
row.append(
118+
f"<details><summary>View Origin StackTrace</summary><pre>{x.origin}</pre></details>"
119+
)
115120
row.append(" </tr>\n")
116121
# Dump the bugs info into the table.
117122
for column in row:
@@ -428,9 +433,9 @@ def Main():
428433
sys.exit(1)
429434

430435
# Use the defaultdict in order to make multidim dicts.
431-
di_location_bugs = defaultdict(lambda: defaultdict(dict))
432-
di_subprogram_bugs = defaultdict(lambda: defaultdict(dict))
433-
di_variable_bugs = defaultdict(lambda: defaultdict(dict))
436+
di_location_bugs = defaultdict(lambda: defaultdict(list))
437+
di_subprogram_bugs = defaultdict(lambda: defaultdict(list))
438+
di_variable_bugs = defaultdict(lambda: defaultdict(list))
434439

435440
# Use the ordered dict to make a summary.
436441
di_location_bugs_summary = OrderedDict()
@@ -470,9 +475,9 @@ def Main():
470475
skipped_lines += 1
471476
continue
472477

473-
di_loc_bugs = []
474-
di_sp_bugs = []
475-
di_var_bugs = []
478+
di_loc_bugs = di_location_bugs[bugs_file][bugs_pass]
479+
di_sp_bugs = di_subprogram_bugs[bugs_file][bugs_pass]
480+
di_var_bugs = di_variable_bugs[bugs_file][bugs_pass]
476481

477482
# Omit duplicated bugs.
478483
di_loc_set = set()
@@ -487,14 +492,15 @@ def Main():
487492

488493
if bugs_metadata == "DILocation":
489494
try:
495+
origin = bug["origin"]
490496
action = bug["action"]
491497
bb_name = bug["bb-name"]
492498
fn_name = bug["fn-name"]
493499
instr = bug["instr"]
494500
except:
495501
skipped_bugs += 1
496502
continue
497-
di_loc_bug = DILocBug(action, bb_name, fn_name, instr)
503+
di_loc_bug = DILocBug(origin, action, bb_name, fn_name, instr)
498504
if not str(di_loc_bug) in di_loc_set:
499505
di_loc_set.add(str(di_loc_bug))
500506
if opts.compress:

0 commit comments

Comments
 (0)