diff options
author | Alon Zakai <azakai@google.com> | 2020-01-28 09:31:13 -0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-01-28 09:31:13 -0800 |
commit | b00f7f9b97631b214eff177b92639df6307db286 (patch) | |
tree | f94f584c5fc4af7bd44c0f8d23ba03319650bd9c /src/wasm/wasm-debug.cpp | |
parent | bfff812cdfe3caccbceee73cee168326d4b9dc63 (diff) | |
download | binaryen-b00f7f9b97631b214eff177b92639df6307db286.tar.gz binaryen-b00f7f9b97631b214eff177b92639df6307db286.tar.bz2 binaryen-b00f7f9b97631b214eff177b92639df6307db286.zip |
DWARF: Update DW_AT_stmt_list which are offsets into the debug_line section (#2628)
The debug_line section is the only one in which we change
sizes and so must update offsets. It turns out that there are such
offsets, DW_AT_stmt_list, so without updating them we can't
handle multi-unit dwarf files.
Diffstat (limited to 'src/wasm/wasm-debug.cpp')
-rw-r--r-- | src/wasm/wasm-debug.cpp | 72 |
1 files changed, 51 insertions, 21 deletions
diff --git a/src/wasm/wasm-debug.cpp b/src/wasm/wasm-debug.cpp index 73e473f9a..f9929c8bd 100644 --- a/src/wasm/wasm-debug.cpp +++ b/src/wasm/wasm-debug.cpp @@ -46,6 +46,9 @@ bool hasDWARFSections(const Module& wasm) { #ifdef BUILD_LLVM_DWARF +// In wasm32 the address size is 32 bits. +static const size_t AddressSize = 4; + struct BinaryenDWARFInfo { llvm::StringMap<std::unique_ptr<llvm::MemoryBuffer>> sections; std::unique_ptr<llvm::DWARFContext> context; @@ -60,7 +63,7 @@ struct BinaryenDWARFInfo { } } // Parse debug sections. - uint8_t addrSize = 4; + uint8_t addrSize = AddressSize; bool isLittleEndian = true; context = llvm::DWARFContext::create(sections, addrSize, isLittleEndian); } @@ -467,6 +470,9 @@ struct LocationUpdater { AddrExprMap oldExprAddrMap; FuncAddrMap oldFuncAddrMap; + // Map start of line tables in the debug_line section to their new locations. + std::map<BinaryLocation, BinaryLocation> debugLineMap; + // TODO: for memory efficiency, we may want to do this in a streaming manner, // binary to binary, without YAML IR. @@ -600,10 +606,16 @@ struct LocationUpdater { } return 0; } + + BinaryLocation getNewDebugLineLocation(BinaryLocation old) const { + return debugLineMap.at(old); + } }; +// Update debug lines, and update the locationUpdater with debug line offset +// changes so we can update offsets into the debug line section. static void updateDebugLines(llvm::DWARFYAML::Data& data, - const LocationUpdater& locationUpdater) { + LocationUpdater& locationUpdater) { for (auto& table : data.DebugLines) { // Parse the original opcodes and emit new ones. LineState state(table); @@ -684,6 +696,19 @@ static void updateDebugLines(llvm::DWARFYAML::Data& data, table.Opcodes.swap(newOpcodes); } } + // After updating the contents, run the emitter in order to update the + // lengths of each section. We will use that to update offsets into the + // debug_line section. + std::vector<size_t> computedLengths; + llvm::DWARFYAML::ComputeDebugLine(data, computedLengths); + BinaryLocation oldLocation = 0, newLocation = 0; + for (size_t i = 0; i < data.DebugLines.size(); i++) { + auto& table = data.DebugLines[i]; + locationUpdater.debugLineMap[oldLocation] = newLocation; + oldLocation += table.Length.getLength() + AddressSize; + newLocation += computedLengths[i] + AddressSize; + table.Length.setLength(computedLengths[i]); + } } // Iterate in parallel over a DwarfContext representation element and a @@ -705,7 +730,8 @@ static void updateDIE(const llvm::DWARFDebugInfoEntry& DIE, const LocationUpdater& locationUpdater) { auto tag = DIE.getTag(); // Pairs of low/high_pc require some special handling, as the high - // may be an offset relative to the low. First, process the low_pcs. + // may be an offset relative to the low. First, process everything but + // the high pcs, so we see the low pcs first. BinaryLocation oldLowPC = 0, newLowPC = 0; iterContextAndYAML( abbrevDecl->attributes(), @@ -713,25 +739,29 @@ static void updateDIE(const llvm::DWARFDebugInfoEntry& DIE, [&](const llvm::DWARFAbbreviationDeclaration::AttributeSpec& attrSpec, llvm::DWARFYAML::FormValue& yamlValue) { auto attr = attrSpec.Attr; - if (attr != llvm::dwarf::DW_AT_low_pc) { - return; - } - BinaryLocation oldValue = yamlValue.Value, newValue = 0; - if (tag == llvm::dwarf::DW_TAG_GNU_call_site || - tag == llvm::dwarf::DW_TAG_inlined_subroutine || - tag == llvm::dwarf::DW_TAG_lexical_block || - tag == llvm::dwarf::DW_TAG_label) { - newValue = locationUpdater.getNewExprStart(oldValue); - } else if (tag == llvm::dwarf::DW_TAG_compile_unit || - tag == llvm::dwarf::DW_TAG_subprogram) { - newValue = locationUpdater.getNewFuncStart(oldValue); - } else { - Fatal() << "unknown tag with low_pc " - << llvm::dwarf::TagString(tag).str(); + if (attr == llvm::dwarf::DW_AT_low_pc) { + // This is an address. + BinaryLocation oldValue = yamlValue.Value, newValue = 0; + if (tag == llvm::dwarf::DW_TAG_GNU_call_site || + tag == llvm::dwarf::DW_TAG_inlined_subroutine || + tag == llvm::dwarf::DW_TAG_lexical_block || + tag == llvm::dwarf::DW_TAG_label) { + newValue = locationUpdater.getNewExprStart(oldValue); + } else if (tag == llvm::dwarf::DW_TAG_compile_unit || + tag == llvm::dwarf::DW_TAG_subprogram) { + newValue = locationUpdater.getNewFuncStart(oldValue); + } else { + Fatal() << "unknown tag with low_pc " + << llvm::dwarf::TagString(tag).str(); + } + oldLowPC = oldValue; + newLowPC = newValue; + yamlValue.Value = newValue; + } else if (attr == llvm::dwarf::DW_AT_stmt_list) { + // This is an offset into the debug line section. + yamlValue.Value = + locationUpdater.getNewDebugLineLocation(yamlValue.Value); } - oldLowPC = oldValue; - newLowPC = newValue; - yamlValue.Value = newValue; }); // Next, process the high_pcs. // TODO: do this more efficiently, without a second traversal (but that's a |