Skip to content

Commit fe9494b

Browse files
committed
[DLCov] Origin-Tracking: Add debugify support
1 parent 3d83059 commit fe9494b

File tree

2 files changed

+80
-19
lines changed

2 files changed

+80
-19
lines changed

llvm/lib/Transforms/Utils/Debugify.cpp

Lines changed: 67 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_ORIGIN_TRACKING
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,49 @@ cl::opt<Level> DebugifyLevel(
5967

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

70+
#if LLVM_ENABLE_DEBUGLOC_ORIGIN_TRACKING
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 *, std::string> 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+
for (int Frame = 0; Frame < Depth; ++Frame) {
91+
assert(SymbolizedAddrs.contains(StackTrace[Frame]) &&
92+
"Expected each address to have been symbolized.");
93+
OS << right_justify(formatv("#{0}", Frame).str(), std::log10(Depth) + 2)
94+
<< ' ' << SymbolizedAddrs[StackTrace[Frame]];
95+
}
96+
}
97+
return Result;
98+
}
99+
void collectStackAddresses(Instruction &I) {
100+
auto &OriginStackTraces = I.getDebugLoc().getOriginStackTraces();
101+
for (auto &[Depth, StackTrace] : OriginStackTraces) {
102+
for (int Frame = 0; Frame < Depth; ++Frame) {
103+
void *Addr = StackTrace[Frame];
104+
if (!SymbolizedAddrs.contains(Addr))
105+
UnsymbolizedAddrs.insert(Addr);
106+
}
107+
}
108+
}
109+
#else
110+
void collectStackAddresses(Instruction &I) {}
111+
#endif // LLVM_ENABLE_DEBUGLOC_ORIGIN_TRACKING
112+
62113
uint64_t getAllocSizeInBits(Module &M, Type *Ty) {
63114
return Ty->isSized() ? M.getDataLayout().getTypeAllocSizeInBits(Ty) : 0;
64115
}
@@ -379,6 +430,8 @@ bool llvm::collectDebugInfoMetadata(Module &M,
379430
LLVM_DEBUG(dbgs() << " Collecting info for inst: " << I << '\n');
380431
DebugInfoBeforePass.InstToDelete.insert({&I, &I});
381432

433+
// Track the addresses to symbolize, if the feature is enabled.
434+
collectStackAddresses(I);
382435
DebugInfoBeforePass.DILocations.insert({&I, hasLoc(I)});
383436
}
384437
}
@@ -454,14 +507,20 @@ static bool checkInstructions(const DebugInstMap &DILocsBefore,
454507
auto BBName = BB->hasName() ? BB->getName() : "no-name";
455508
auto InstName = Instruction::getOpcodeName(Instr->getOpcode());
456509

510+
auto CreateJSONBugEntry = [&](const char *Action) {
511+
Bugs.push_back(llvm::json::Object({
512+
{"metadata", "DILocation"}, {"fn-name", FnName.str()},
513+
{"bb-name", BBName.str()}, {"instr", InstName}, {"action", Action},
514+
#if LLVM_ENABLE_DEBUGLOC_ORIGIN_TRACKING
515+
{"origin", symbolizeStackTrace(Instr)},
516+
#endif
517+
}));
518+
};
519+
457520
auto InstrIt = DILocsBefore.find(Instr);
458521
if (InstrIt == DILocsBefore.end()) {
459522
if (ShouldWriteIntoJSON)
460-
Bugs.push_back(llvm::json::Object({{"metadata", "DILocation"},
461-
{"fn-name", FnName.str()},
462-
{"bb-name", BBName.str()},
463-
{"instr", InstName},
464-
{"action", "not-generate"}}));
523+
CreateJSONBugEntry("not-generate");
465524
else
466525
dbg() << "WARNING: " << NameOfWrappedPass
467526
<< " did not generate DILocation for " << *Instr
@@ -474,11 +533,7 @@ static bool checkInstructions(const DebugInstMap &DILocsBefore,
474533
// If the instr had the !dbg attached before the pass, consider it as
475534
// a debug info issue.
476535
if (ShouldWriteIntoJSON)
477-
Bugs.push_back(llvm::json::Object({{"metadata", "DILocation"},
478-
{"fn-name", FnName.str()},
479-
{"bb-name", BBName.str()},
480-
{"instr", InstName},
481-
{"action", "drop"}}));
536+
CreateJSONBugEntry("drop");
482537
else
483538
dbg() << "WARNING: " << NameOfWrappedPass << " dropped DILocation of "
484539
<< *Instr << " (BB: " << BBName << ", Fn: " << FnName
@@ -622,6 +677,8 @@ bool llvm::checkDebugInfoMetadata(Module &M,
622677

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

680+
// Track the addresses to symbolize, if the feature is enabled.
681+
collectStackAddresses(I);
625682
DebugInfoAfterPass.DILocations.insert({&I, hasLoc(I)});
626683
}
627684
}

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

Lines changed: 13 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,7 @@ def generate_html_report(
112114
row.append(x.fn_name)
113115
row.append(x.bb_name)
114116
row.append(x.action)
117+
row.append(f"<details><summary>View Origin StackTrace</summary><pre>{x.origin}</pre></details>")
115118
row.append(" </tr>\n")
116119
# Dump the bugs info into the table.
117120
for column in row:
@@ -428,9 +431,9 @@ def Main():
428431
sys.exit(1)
429432

430433
# 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))
434+
di_location_bugs = defaultdict(lambda: defaultdict(list))
435+
di_subprogram_bugs = defaultdict(lambda: defaultdict(list))
436+
di_variable_bugs = defaultdict(lambda: defaultdict(list))
434437

435438
# Use the ordered dict to make a summary.
436439
di_location_bugs_summary = OrderedDict()
@@ -470,9 +473,9 @@ def Main():
470473
skipped_lines += 1
471474
continue
472475

473-
di_loc_bugs = []
474-
di_sp_bugs = []
475-
di_var_bugs = []
476+
di_loc_bugs = di_location_bugs[bugs_file][bugs_pass]
477+
di_sp_bugs = di_subprogram_bugs[bugs_file][bugs_pass]
478+
di_var_bugs = di_variable_bugs[bugs_file][bugs_pass]
476479

477480
# Omit duplicated bugs.
478481
di_loc_set = set()
@@ -487,14 +490,15 @@ def Main():
487490

488491
if bugs_metadata == "DILocation":
489492
try:
493+
origin = bug["origin"]
490494
action = bug["action"]
491495
bb_name = bug["bb-name"]
492496
fn_name = bug["fn-name"]
493497
instr = bug["instr"]
494498
except:
495499
skipped_bugs += 1
496500
continue
497-
di_loc_bug = DILocBug(action, bb_name, fn_name, instr)
501+
di_loc_bug = DILocBug(origin, action, bb_name, fn_name, instr)
498502
if not str(di_loc_bug) in di_loc_set:
499503
di_loc_set.add(str(di_loc_bug))
500504
if opts.compress:

0 commit comments

Comments
 (0)