Skip to content

Commit e46273b

Browse files
committed
[DLCov] Origin-Tracking: Add debugify support
1 parent 5e56291 commit e46273b

File tree

2 files changed

+85
-19
lines changed

2 files changed

+85
-19
lines changed

llvm/lib/Transforms/Utils/Debugify.cpp

Lines changed: 70 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,23 @@ 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"},
513+
{"fn-name", FnName.str()},
514+
{"bb-name", BBName.str()},
515+
{"instr", InstName},
516+
{"action", Action},
517+
#if LLVM_ENABLE_DEBUGLOC_ORIGIN_TRACKING
518+
{"origin", symbolizeStackTrace(Instr)},
519+
#endif
520+
}));
521+
};
522+
457523
auto InstrIt = DILocsBefore.find(Instr);
458524
if (InstrIt == DILocsBefore.end()) {
459525
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"}}));
526+
CreateJSONBugEntry("not-generate");
465527
else
466528
dbg() << "WARNING: " << NameOfWrappedPass
467529
<< " did not generate DILocation for " << *Instr
@@ -474,11 +536,7 @@ static bool checkInstructions(const DebugInstMap &DILocsBefore,
474536
// If the instr had the !dbg attached before the pass, consider it as
475537
// a debug info issue.
476538
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"}}));
539+
CreateJSONBugEntry("drop");
482540
else
483541
dbg() << "WARNING: " << NameOfWrappedPass << " dropped DILocation of "
484542
<< *Instr << " (BB: " << BBName << ", Fn: " << FnName
@@ -622,6 +680,8 @@ bool llvm::checkDebugInfoMetadata(Module &M,
622680

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

683+
// Track the addresses to symbolize, if the feature is enabled.
684+
collectStackAddresses(I);
625685
DebugInfoAfterPass.DILocations.insert({&I, hasLoc(I)});
626686
}
627687
}

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)