Skip to content
139 changes: 83 additions & 56 deletions src/wasm/wasm-debug.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -69,9 +69,9 @@ struct BinaryenDWARFInfo {
BinaryenDWARFInfo(const Module& wasm) {
// Get debug sections from the wasm.
for (auto& section : wasm.customSections) {
if (Name(section.name).startsWith(".debug_") && section.data.data()) {
if (llvm::StringRef(section.name).startswith(".debug_") && section.data.data()) {
// TODO: efficiency
sections[section.name.substr(1)] = llvm::MemoryBuffer::getMemBufferCopy(
sections[llvm::StringRef(section.name).substr(1)] = llvm::MemoryBuffer::getMemBufferCopy(
llvm::StringRef(section.data.data(), section.data.size()));
}
}
Expand Down 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 (auto& func : wasm.functions) {
numExprs += func->expressionLocations.size();

for (auto& [expr, 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,22 @@ 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]] bool inserted = startMap.emplace(span.start, expr).second;
assert(inserted);
}
{
[[maybe_unused]] bool inserted = endMap.emplace(span.end, expr).second;
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]] bool inserted = delimiterMap.emplace(delimiter[i], DelimiterInfo{expr, i}).second;
assert(inserted);
}
}
}
Expand Down Expand Up @@ -622,23 +639,27 @@ struct LocationUpdater {
// 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 +727,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 +1096,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();
if (llvm::StringRef(section.name).startswith(".debug_")) {
auto llvmName = llvm::StringRef(section.name).substr(1);
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
37 changes: 25 additions & 12 deletions third_party/llvm-project/dwarf2yaml.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,14 +26,21 @@ void dumpInitialLength(DataExtractor &Data, uint64_t &Offset,
void dumpDebugAbbrev(DWARFContext &DCtx, DWARFYAML::Data &Y) {
auto AbbrevSetPtr = DCtx.getDebugAbbrev();
if (AbbrevSetPtr) {
for (auto AbbrvDeclSet : *AbbrevSetPtr) {
size_t ReserveAttrs = 0;
for (const auto &AbbrvDeclSet : *AbbrevSetPtr) {
ReserveAttrs += AbbrvDeclSet.second.end() - AbbrvDeclSet.second.begin() + 1;
}
Y.AbbrevDecls.reserve(Y.AbbrevDecls.size() + ReserveAttrs);

for (const auto &AbbrvDeclSet : *AbbrevSetPtr) {
auto ListOffset = AbbrvDeclSet.second.getOffset();
for (auto AbbrvDecl : AbbrvDeclSet.second) {
for (const auto &AbbrvDecl : AbbrvDeclSet.second) {
DWARFYAML::Abbrev Abbrv;
Abbrv.Code = AbbrvDecl.getCode();
Abbrv.Tag = AbbrvDecl.getTag();
Abbrv.Children = AbbrvDecl.hasChildren() ? dwarf::DW_CHILDREN_yes
: dwarf::DW_CHILDREN_no;
Abbrv.Attributes.reserve(AbbrvDecl.getNumAttributes());
for (auto Attribute : AbbrvDecl.attributes()) {
DWARFYAML::AttributeAbbrev AttAbrv;
AttAbrv.Attribute = Attribute.Attr;
Expand All @@ -43,7 +50,7 @@ void dumpDebugAbbrev(DWARFContext &DCtx, DWARFYAML::Data &Y) {
Abbrv.Attributes.push_back(AttAbrv);
}
Abbrv.ListOffset = ListOffset;
Y.AbbrevDecls.push_back(Abbrv);
Y.AbbrevDecls.push_back(std::move(Abbrv));
}
// XXX BINARYEN: null-terminate the DeclSet. This is needed to separate
// DeclSets from each other, and to null-terminate the entire list
Expand All @@ -52,7 +59,7 @@ void dumpDebugAbbrev(DWARFContext &DCtx, DWARFYAML::Data &Y) {
DWARFYAML::Abbrev Abbrv;
Abbrv.Code = 0;
Abbrv.Tag = dwarf::Tag(0);
Y.AbbrevDecls.push_back(Abbrv);
Y.AbbrevDecls.push_back(std::move(Abbrv));
}
}
}
Expand All @@ -79,13 +86,15 @@ void dumpDebugARanges(DWARFContext &DCtx, DWARFYAML::Data &Y) {
Range.CuOffset = Set.getHeader().CuOffset;
Range.AddrSize = Set.getHeader().AddrSize;
Range.SegSize = Set.getHeader().SegSize;

Range.Descriptors.reserve(Set.descriptors().end() - Set.descriptors().begin());
for (auto Descriptor : Set.descriptors()) {
DWARFYAML::ARangeDescriptor Desc;
Desc.Address = Descriptor.Address;
Desc.Length = Descriptor.Length;
Range.Descriptors.push_back(Desc);
}
Y.ARanges.push_back(Range);
Y.ARanges.push_back(std::move(Range));
}
}

Expand Down Expand Up @@ -139,17 +148,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 Expand Up @@ -188,6 +198,7 @@ void dumpDebugPubSections(DWARFContext &DCtx, DWARFYAML::Data &Y) {
}

void dumpDebugInfo(DWARFContext &DCtx, DWARFYAML::Data &Y) {
Y.CompileUnits.reserve(DCtx.getNumCompileUnits());
for (const auto &CU : DCtx.compile_units()) {
DWARFYAML::Unit NewUnit;
NewUnit.Length.setLength(CU->getLength());
Expand All @@ -198,6 +209,7 @@ void dumpDebugInfo(DWARFContext &DCtx, DWARFYAML::Data &Y) {
NewUnit.AbbrOffset = Abbreviations->getOffset();
}
NewUnit.AddrSize = CU->getAddressByteSize();
NewUnit.Entries.reserve(CU->getNumDIEs());
for (auto DIE : CU->dies()) {
DWARFYAML::Entry NewEntry;
DataExtractor EntryData = CU->getDebugInfoExtractor();
Expand All @@ -211,6 +223,7 @@ void dumpDebugInfo(DWARFContext &DCtx, DWARFYAML::Data &Y) {

auto AbbrevDecl = DIE.getAbbreviationDeclarationPtr();
if (AbbrevDecl) {
NewEntry.Values.reserve(AbbrevDecl->getNumAttributes());
for (const auto &AttrSpec : AbbrevDecl->attributes()) {
DWARFYAML::FormValue NewValue;
NewValue.Value = 0xDEADBEEFDEADBEEF;
Expand Down Expand Up @@ -297,13 +310,13 @@ void dumpDebugInfo(DWARFContext &DCtx, DWARFYAML::Data &Y) {
break;
}
} while (indirect);
NewEntry.Values.push_back(NewValue);
NewEntry.Values.push_back(std::move(NewValue));
}
}

NewUnit.Entries.push_back(NewEntry);
NewUnit.Entries.push_back(std::move(NewEntry));
}
Y.CompileUnits.push_back(NewUnit);
Y.CompileUnits.push_back(std::move(NewUnit));
}
}

Expand Down Expand Up @@ -422,9 +435,9 @@ void dumpDebugLines(DWARFContext &DCtx, DWARFYAML::Data &Y) {
NewOp.StandardOpcodeData.push_back(LineData.getULEB128(&Offset));
}
}
DebugLines.Opcodes.push_back(NewOp);
DebugLines.Opcodes.push_back(std::move(NewOp));
}
Y.DebugLines.push_back(DebugLines);
Y.DebugLines.push_back(std::move(DebugLines));
}
}
}
Expand Down