Skip to content
161 changes: 80 additions & 81 deletions src/wasm/wasm-debug.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -290,36 +290,36 @@ struct LineState {
// FIXME: look at AddrSize on the Unit.
auto item = makeItem(llvm::dwarf::DW_LNE_set_address, 5);
item.Data = addr;
newOpcodes.push_back(item);
newOpcodes.push_back(std::move(item));
}
if (line != old.line && !useSpecial) {
auto item = makeItem(llvm::dwarf::DW_LNS_advance_line);
// In wasm32 we have 32-bit addresses, and the delta here might be
// negative (note that SData is 64-bit, as LLVM supports 64-bit
// addresses too).
item.SData = int32_t(line - old.line);
newOpcodes.push_back(item);
newOpcodes.push_back(std::move(item));
}
if (col != old.col) {
auto item = makeItem(llvm::dwarf::DW_LNS_set_column);
item.Data = col;
newOpcodes.push_back(item);
newOpcodes.push_back(std::move(item));
}
if (file != old.file) {
auto item = makeItem(llvm::dwarf::DW_LNS_set_file);
item.Data = file;
newOpcodes.push_back(item);
newOpcodes.push_back(std::move(item));
}
if (isa != old.isa) {
auto item = makeItem(llvm::dwarf::DW_LNS_set_isa);
item.Data = isa;
newOpcodes.push_back(item);
newOpcodes.push_back(std::move(item));
}
if (discriminator != old.discriminator) {
// len = 1 (subopcode) + 4 (wasm32 address)
auto item = makeItem(llvm::dwarf::DW_LNE_set_discriminator, 5);
item.Data = discriminator;
newOpcodes.push_back(item);
newOpcodes.push_back(std::move(item));
}
if (isStmt != old.isStmt) {
newOpcodes.push_back(makeItem(llvm::dwarf::DW_LNS_negate_stmt));
Expand Down Expand Up @@ -391,6 +391,19 @@ struct AddrExprMap {

// Construct the map from the binaryLocations loaded from the wasm.
AddrExprMap(const Module& wasm) {
size_t numExprs = 0, numDelims = 0;
for (const auto& func : wasm.functions) {
numExprs += func->expressionLocations.size();

for (const auto& [_, delim] : func->delimiterLocations) {
// May be a little large if 0-delimiters exist.
numDelims += delim.size();
}
}
startMap.reserve(numExprs);
endMap.reserve(numExprs);
delimiterMap.reserve(numDelims);

for (auto& func : wasm.functions) {
for (auto& [expr, span] : func->expressionLocations) {
add(expr, span);
Expand Down Expand Up @@ -427,18 +440,23 @@ struct AddrExprMap {

private:
void add(Expression* expr, const BinaryLocations::Span span) {
assert(startMap.count(span.start) == 0);
startMap[span.start] = expr;
assert(endMap.count(span.end) == 0);
endMap[span.end] = expr;
{
[[maybe_unused]] auto [_, inserted] = startMap.emplace(span.start, expr);
assert(inserted);
}
{
[[maybe_unused]] auto [_, inserted] = endMap.emplace(span.end, expr);
assert(inserted);
}
}

void add(Expression* expr,
const BinaryLocations::DelimiterLocations& delimiter) {
for (Index i = 0; i < delimiter.size(); i++) {
if (delimiter[i] != 0) {
assert(delimiterMap.count(delimiter[i]) == 0);
delimiterMap[delimiter[i]] = DelimiterInfo{expr, i};
[[maybe_unused]] auto [_, inserted] =
delimiterMap.emplace(delimiter[i], DelimiterInfo{expr, i});
assert(inserted);
}
}
}
Expand Down Expand Up @@ -530,10 +548,6 @@ struct LocationUpdater {
return 0;
}

bool hasOldExprStart(BinaryLocation oldAddr) const {
return oldExprAddrMap.getStart(oldAddr);
}

BinaryLocation getNewExprEnd(BinaryLocation oldAddr) const {
if (auto* expr = oldExprAddrMap.getEnd(oldAddr)) {
auto iter = newLocations.expressions.find(expr);
Expand All @@ -544,10 +558,6 @@ struct LocationUpdater {
return 0;
}

bool hasOldExprEnd(BinaryLocation oldAddr) const {
return oldExprAddrMap.getEnd(oldAddr);
}

BinaryLocation getNewFuncStart(BinaryLocation oldAddr) const {
if (auto* func = oldFuncAddrMap.getStart(oldAddr)) {
// The function might have been optimized away, check.
Expand All @@ -567,10 +577,6 @@ struct LocationUpdater {
return 0;
}

bool hasOldFuncStart(BinaryLocation oldAddr) const {
return oldFuncAddrMap.getStart(oldAddr);
}

BinaryLocation getNewFuncEnd(BinaryLocation oldAddr) const {
if (auto* func = oldFuncAddrMap.getEnd(oldAddr)) {
// The function might have been optimized away, check.
Expand All @@ -590,19 +596,6 @@ struct LocationUpdater {
return 0;
}

// Check for either the end opcode, or one past the end.
bool hasOldFuncEnd(BinaryLocation oldAddr) const {
return oldFuncAddrMap.getEnd(oldAddr);
}

// Check specifically for the end opcode.
bool hasOldFuncEndOpcode(BinaryLocation oldAddr) const {
if (auto* func = oldFuncAddrMap.getEnd(oldAddr)) {
return oldAddr == func->funcLocation.end - 1;
}
return false;
}

BinaryLocation getNewDelimiter(BinaryLocation oldAddr) const {
auto info = oldExprAddrMap.getDelimiter(oldAddr);
if (info.expr) {
Expand All @@ -614,31 +607,31 @@ struct LocationUpdater {
return 0;
}

bool hasOldDelimiter(BinaryLocation oldAddr) const {
return oldExprAddrMap.getDelimiter(oldAddr).expr;
}

// getNewStart|EndAddr utilities.
// TODO: should we track the start and end of delimiters, even though they
// are just one byte?
BinaryLocation getNewStart(BinaryLocation oldStart) const {
if (hasOldExprStart(oldStart)) {
return getNewExprStart(oldStart);
} else if (hasOldFuncStart(oldStart)) {
return getNewFuncStart(oldStart);
} else if (hasOldDelimiter(oldStart)) {
return getNewDelimiter(oldStart);
if (auto loc = getNewExprStart(oldStart)) {
return loc;
}
if (auto loc = getNewFuncStart(oldStart)) {
return loc;
}
if (auto loc = getNewDelimiter(oldStart)) {
return loc;
}
return 0;
}

BinaryLocation getNewEnd(BinaryLocation oldEnd) const {
if (hasOldExprEnd(oldEnd)) {
return getNewExprEnd(oldEnd);
} else if (hasOldFuncEnd(oldEnd)) {
return getNewFuncEnd(oldEnd);
} else if (hasOldDelimiter(oldEnd)) {
return getNewDelimiter(oldEnd);
if (auto loc = getNewExprEnd(oldEnd)) {
return loc;
}
if (auto loc = getNewFuncEnd(oldEnd)) {
return loc;
}
if (auto loc = getNewDelimiter(oldEnd)) {
return loc;
}
return 0;
}
Expand Down Expand Up @@ -706,21 +699,21 @@ static void updateDebugLines(llvm::DWARFYAML::Data& data,
// it away.
BinaryLocation oldAddr = state.addr;
BinaryLocation newAddr = 0;
if (locationUpdater.hasOldExprStart(oldAddr)) {
newAddr = locationUpdater.getNewExprStart(oldAddr);
if (auto loc = locationUpdater.getNewExprStart(oldAddr)) {
newAddr = loc;
}
// Test for a function's end address first, as LLVM output appears to
// use 1-past-the-end-of-the-function as a location in that function,
// and not the next (but the first byte of the next function, which is
// ambiguously identical to that value, is used at least in low_pc).
else if (locationUpdater.hasOldFuncEnd(oldAddr)) {
newAddr = locationUpdater.getNewFuncEnd(oldAddr);
} else if (locationUpdater.hasOldFuncStart(oldAddr)) {
newAddr = locationUpdater.getNewFuncStart(oldAddr);
} else if (locationUpdater.hasOldDelimiter(oldAddr)) {
newAddr = locationUpdater.getNewDelimiter(oldAddr);
} else if (locationUpdater.hasOldExprEnd(oldAddr)) {
newAddr = locationUpdater.getNewExprEnd(oldAddr);
else if ((loc = locationUpdater.getNewFuncEnd(oldAddr))) {
newAddr = loc;
} else if ((loc = locationUpdater.getNewFuncStart(oldAddr))) {
newAddr = loc;
} else if ((loc = locationUpdater.getNewDelimiter(oldAddr))) {
newAddr = loc;
} else if ((loc = locationUpdater.getNewExprEnd(oldAddr))) {
newAddr = loc;
}
if (newAddr && state.needToEmit()) {
// LLVM sometimes emits the same address more than once. We should
Expand Down Expand Up @@ -1075,36 +1068,42 @@ static void updateLoc(llvm::DWARFYAML::Data& yaml,
}

void writeDWARFSections(Module& wasm, const BinaryLocations& newLocations) {
BinaryenDWARFInfo info(wasm);

// Convert to Data representation, which YAML can use to write.
llvm::DWARFYAML::Data data;
if (dwarf2yaml(*info.context, data)) {
Fatal() << "Failed to parse DWARF to YAML";
}
llvm::StringMap<std::unique_ptr<llvm::MemoryBuffer>> newSections;
{
BinaryenDWARFInfo info(wasm);

// Convert to Data representation, which YAML can use to write.
llvm::DWARFYAML::Data data;
if (dwarf2yaml(*info.context, data)) {
Fatal() << "Failed to parse DWARF to YAML";
}

LocationUpdater locationUpdater(wasm, newLocations);
{
LocationUpdater locationUpdater(wasm, newLocations);

updateDebugLines(data, locationUpdater);
updateDebugLines(data, locationUpdater);

bool is64 = wasm.memories.size() > 0 ? wasm.memories[0]->is64() : false;
updateCompileUnits(info, data, locationUpdater, is64);
bool is64 = wasm.memories.size() > 0 ? wasm.memories[0]->is64() : false;
updateCompileUnits(info, data, locationUpdater, is64);

updateRanges(data, locationUpdater);
updateRanges(data, locationUpdater);

updateLoc(data, locationUpdater);
updateLoc(data, locationUpdater);
}

// Convert to binary sections.
auto newSections =
EmitDebugSections(data, false /* EmitFixups for debug_info */);
// Convert to binary sections.
newSections =
EmitDebugSections(data, false /* EmitFixups for debug_info */);
}

// Update the custom sections in the wasm.
// TODO: efficiency
for (auto& section : wasm.customSections) {
if (Name(section.name).startsWith(".debug_")) {
auto llvmName = section.name.substr(1);
if (newSections.count(llvmName)) {
auto llvmData = newSections[llvmName]->getBuffer();
auto it = newSections.find(llvmName);
if (it != newSections.end()) {
auto llvmData = it->second->getBuffer();
section.data.resize(llvmData.size());
std::copy(llvmData.begin(), llvmData.end(), section.data.data());
}
Expand Down
5 changes: 3 additions & 2 deletions third_party/llvm-project/dwarf2yaml.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -139,17 +139,18 @@ void dumpDebugLoc(DWARFContext &DCtx, DWARFYAML::Data &Y) { // XXX BINARYEN
DWARFYAML::Loc loc;
loc.Start = entry.Begin;
loc.End = entry.End;
loc.Location.reserve(entry.Loc.size());
for (auto x : entry.Loc) {
loc.Location.push_back(x);
}
loc.CompileUnitOffset = locListOffset; // XXX BINARYEN
Y.Locs.push_back(loc);
Y.Locs.push_back(std::move(loc));
}
DWARFYAML::Loc loc;
loc.Start = 0;
loc.End = 0;
loc.CompileUnitOffset = locListOffset; // XXX BINARYEN
Y.Locs.push_back(loc);
Y.Locs.push_back(std::move(loc));
}
}

Expand Down
Loading