Skip to content

Commit a4ef5c6

Browse files
committed
[DLCov] Origin-Tracking: Add debugify support
1 parent 51a62f4 commit a4ef5c6

File tree

3 files changed

+88
-23
lines changed

3 files changed

+88
-23
lines changed

llvm/include/llvm/Support/Signals.h

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -26,10 +26,8 @@
2626
namespace llvm {
2727
// Typedefs that are convenient but only used by the stack-trace-collection code
2828
// added if DebugLoc origin-tracking is enabled.
29-
using AddressSet = DenseSet<void *, DenseMapInfo<void *, void>>;
30-
using SymbolizedAddressMap =
31-
DenseMap<void *, SmallVector<std::string, 0>, DenseMapInfo<void *, void>,
32-
detail::DenseMapPair<void *, SmallVector<std::string, 0>>>;
29+
using AddressSet = DenseSet<void *>;
30+
using SymbolizedAddressMap = DenseMap<void *, SmallVector<std::string, 0>>;
3331
} // namespace llvm
3432
#endif
3533

llvm/lib/Transforms/Utils/Debugify.cpp

Lines changed: 71 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
#include "llvm/Transforms/Utils/Debugify.h"
1717
#include "llvm/ADT/BitVector.h"
1818
#include "llvm/ADT/StringExtras.h"
19+
#include "llvm/Config/llvm-config.h"
1920
#include "llvm/IR/DIBuilder.h"
2021
#include "llvm/IR/DebugInfo.h"
2122
#include "llvm/IR/InstIterator.h"
@@ -28,6 +29,11 @@
2829
#include "llvm/Support/FileSystem.h"
2930
#include "llvm/Support/JSON.h"
3031
#include <optional>
32+
#if LLVM_ENABLE_DEBUGLOC_TRACKING_ORIGIN
33+
// We need the Signals header to operate on stacktraces if we're using DebugLoc
34+
// origin-tracking.
35+
#include "llvm/Support/Signals.h"
36+
#endif
3137

3238
#define DEBUG_TYPE "debugify"
3339

@@ -59,6 +65,52 @@ cl::opt<Level> DebugifyLevel(
5965

6066
raw_ostream &dbg() { return Quiet ? nulls() : errs(); }
6167

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

430+
// Track the addresses to symbolize, if the feature is enabled.
431+
collectStackAddresses(I);
378432
DebugInfoBeforePass.DILocations.insert({&I, hasLoc(I)});
379433
}
380434
}
@@ -450,14 +504,23 @@ static bool checkInstructions(const DebugInstMap &DILocsBefore,
450504
auto BBName = BB->hasName() ? BB->getName() : "no-name";
451505
auto InstName = Instruction::getOpcodeName(Instr->getOpcode());
452506

507+
auto CreateJSONBugEntry = [&](const char *Action) {
508+
Bugs.push_back(llvm::json::Object({
509+
{"metadata", "DILocation"},
510+
{"fn-name", FnName.str()},
511+
{"bb-name", BBName.str()},
512+
{"instr", InstName},
513+
{"action", Action},
514+
#if LLVM_ENABLE_DEBUGLOC_TRACKING_ORIGIN
515+
{"origin", symbolizeStackTrace(Instr)},
516+
#endif
517+
}));
518+
};
519+
453520
auto InstrIt = DILocsBefore.find(Instr);
454521
if (InstrIt == DILocsBefore.end()) {
455522
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"}}));
523+
CreateJSONBugEntry("not-generate");
461524
else
462525
dbg() << "WARNING: " << NameOfWrappedPass
463526
<< " did not generate DILocation for " << *Instr
@@ -470,11 +533,7 @@ static bool checkInstructions(const DebugInstMap &DILocsBefore,
470533
// If the instr had the !dbg attached before the pass, consider it as
471534
// a debug info issue.
472535
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"}}));
536+
CreateJSONBugEntry("drop");
478537
else
479538
dbg() << "WARNING: " << NameOfWrappedPass << " dropped DILocation of "
480539
<< *Instr << " (BB: " << BBName << ", Fn: " << FnName
@@ -612,6 +671,8 @@ bool llvm::checkDebugInfoMetadata(Module &M,
612671

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

674+
// Track the addresses to symbolize, if the feature is enabled.
675+
collectStackAddresses(I);
615676
DebugInfoAfterPass.DILocations.insert({&I, hasLoc(I)});
616677
}
617678
}

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.get("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)