Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
131 changes: 79 additions & 52 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 (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();
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
41 changes: 29 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,11 @@ void dumpDebugInfo(DWARFContext &DCtx, DWARFYAML::Data &Y) {

auto AbbrevDecl = DIE.getAbbreviationDeclarationPtr();
if (AbbrevDecl) {
// This reserve doesn't account for DW_FORM_indirect values, which would
// result in more entries in NewEntry.Values than getNumAttributes()
// implies. Not all binaries have these, and it'll reduce the number of
// allocations in any case.
NewEntry.Values.reserve(AbbrevDecl->getNumAttributes());
for (const auto &AttrSpec : AbbrevDecl->attributes()) {
DWARFYAML::FormValue NewValue;
NewValue.Value = 0xDEADBEEFDEADBEEF;
Expand Down Expand Up @@ -297,13 +314,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 +439,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