diff options
-rw-r--r-- | src/wasm/wasm-debug.cpp | 72 | ||||
-rw-r--r-- | third_party/llvm-project/DWARFEmitter.cpp | 24 | ||||
-rw-r--r-- | third_party/llvm-project/include/llvm/ObjectYAML/DWARFEmitter.h | 4 |
3 files changed, 77 insertions, 23 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 diff --git a/third_party/llvm-project/DWARFEmitter.cpp b/third_party/llvm-project/DWARFEmitter.cpp index b155fb807..92efcdfa0 100644 --- a/third_party/llvm-project/DWARFEmitter.cpp +++ b/third_party/llvm-project/DWARFEmitter.cpp @@ -256,8 +256,12 @@ static void EmitFileEntry(raw_ostream &OS, const DWARFYAML::File &File) { encodeULEB128(File.Length, OS); } -void DWARFYAML::EmitDebugLine(raw_ostream &RealOS, const DWARFYAML::Data &DI) { - for (const auto &LineTable : DI.DebugLines) { +// XXX BINARYEN: Refactor to an *Internal method that allows us to optionally +// compute the new lengths. +static void EmitDebugLineInternal(raw_ostream &RealOS, + const DWARFYAML::Data &DI, + std::vector<size_t>* computedLengths) { + for (auto &LineTable : DI.DebugLines) { // XXX BINARYEN We need to update each line table's length. Write to a // temp stream first, then get the size from that. std::string Buffer; @@ -348,11 +352,27 @@ void DWARFYAML::EmitDebugLine(raw_ostream &RealOS, const DWARFYAML::Data &DI) { if (Size >= UINT32_MAX) { llvm_unreachable("Table is too big"); } + if (computedLengths) { + computedLengths->push_back(Size); + } writeInteger((uint32_t)Size, RealOS, DI.IsLittleEndian); RealOS << OS.str(); } } +void DWARFYAML::EmitDebugLine(raw_ostream &RealOS, const DWARFYAML::Data &DI) { + EmitDebugLineInternal(RealOS, DI, nullptr); +} + +void DWARFYAML::ComputeDebugLine(Data &DI, + std::vector<size_t>& computedLengths) { + // TODO: Avoid writing out the data, or at least cache it so we don't need to + // do it again later. + std::string buffer; + llvm::raw_string_ostream tempStream(buffer); + EmitDebugLineInternal(tempStream, DI, &computedLengths); +} + using EmitFuncType = void (*)(raw_ostream &, const DWARFYAML::Data &); static void diff --git a/third_party/llvm-project/include/llvm/ObjectYAML/DWARFEmitter.h b/third_party/llvm-project/include/llvm/ObjectYAML/DWARFEmitter.h index b4d62f44d..2be618677 100644 --- a/third_party/llvm-project/include/llvm/ObjectYAML/DWARFEmitter.h +++ b/third_party/llvm-project/include/llvm/ObjectYAML/DWARFEmitter.h @@ -38,6 +38,10 @@ void EmitPubSection(raw_ostream &OS, const PubSection &Sect, bool IsLittleEndian); void EmitDebugInfo(raw_ostream &OS, const Data &DI); void EmitDebugLine(raw_ostream &OS, const Data &DI); +// XXX BINARYEN: Same as EmitDebugLine but also update the Length field in +// the YAML as we write. We use that information to update +// offsets into the debug line section. +void ComputeDebugLine(Data &DI, std::vector<size_t>& computedLengths); Expected<StringMap<std::unique_ptr<MemoryBuffer>>> EmitDebugSections(StringRef YAMLString, bool ApplyFixups = false, |