diff options
-rw-r--r-- | src/wasm/wasm-debug.cpp | 120 | ||||
-rw-r--r-- | test/passes/fannkuch3.bin.txt | 44 | ||||
-rw-r--r-- | test/passes/fannkuch3_manyopts.bin.txt | 44 |
3 files changed, 146 insertions, 62 deletions
diff --git a/src/wasm/wasm-debug.cpp b/src/wasm/wasm-debug.cpp index 41654f7de..a244e550d 100644 --- a/src/wasm/wasm-debug.cpp +++ b/src/wasm/wasm-debug.cpp @@ -350,7 +350,7 @@ struct AddrExprMap { } } - Expression* get(uint32_t addr) { + Expression* get(uint32_t addr) const { auto iter = map.find(addr); if (iter != map.end()) { return iter->second; @@ -358,7 +358,7 @@ struct AddrExprMap { return nullptr; } - void dump() { + void dump() const { std::cout << " (size: " << map.size() << ")\n"; for (auto pair : map) { std::cout << " " << pair.first << " => " << pair.second << '\n'; @@ -366,9 +366,13 @@ struct AddrExprMap { } }; -static void updateDebugLines(const Module& wasm, - llvm::DWARFYAML::Data& data, - const BinaryLocationsMap& newLocations) { +struct LocationUpdater { + Module& wasm; + const BinaryLocationsMap& newLocations; + + AddrExprMap oldAddrMap; + AddrExprMap newAddrMap; + // TODO: for memory efficiency, we may want to do this in a streaming manner, // binary to binary, without YAML IR. @@ -376,9 +380,29 @@ static void updateDebugLines(const Module& wasm, // we may need to track their spans too // https://github.com/WebAssembly/debugging/issues/9#issuecomment-567720872 - AddrExprMap oldAddrMap(wasm); - AddrExprMap newAddrMap(newLocations); + LocationUpdater(Module& wasm, const BinaryLocationsMap& newLocations) + : wasm(wasm), newLocations(newLocations), oldAddrMap(wasm), + newAddrMap(newLocations) {} + + // Updates an address. If there was never an instruction at that address, + // or if there was but if that instruction no longer exists, return 0. + // Otherwise, return the new updated location. + uint32_t getNewAddr(uint32_t oldAddr) const { + if (auto* expr = oldAddrMap.get(oldAddr)) { + auto iter = newLocations.find(expr); + if (iter != newLocations.end()) { + uint32_t newAddr = iter->second; + return newAddr; + } + } + return 0; + } + + bool hasOldAddr(uint32_t oldAddr) const { return oldAddrMap.get(oldAddr); } +}; +static void updateDebugLines(llvm::DWARFYAML::Data& data, + const LocationUpdater& locationUpdater) { for (auto& table : data.DebugLines) { // Parse the original opcodes and emit new ones. LineState state(table); @@ -404,16 +428,12 @@ static void updateDebugLines(const Module& wasm, } // An expression may not exist for this line table item, if we optimized // it away. - if (auto* expr = oldAddrMap.get(state.addr)) { - auto iter = newLocations.find(expr); - if (iter != newLocations.end()) { - uint32_t newAddr = iter->second; - newAddrs.push_back(newAddr); - newAddrInfo.emplace(newAddr, state); - auto& updatedState = newAddrInfo.at(newAddr); - // The only difference is the address TODO other stuff? - updatedState.addr = newAddr; - } + if (auto newAddr = locationUpdater.getNewAddr(state.addr)) { + newAddrs.push_back(newAddr); + newAddrInfo.emplace(newAddr, state); + auto& updatedState = newAddrInfo.at(newAddr); + // The only difference is the address TODO other stuff? + updatedState.addr = newAddr; } if (opcode.Opcode == 0 && opcode.SubOpcode == llvm::dwarf::DW_LNE_end_sequence) { @@ -442,6 +462,66 @@ static void updateDebugLines(const Module& wasm, } } +// Iterate in parallel over a DwarfContext representation element and a +// YAML element, which parallel each other. +template<typename T, typename U, typename W> +static void iterContextAndYAML(const T& contextList, U& yamlList, W func) { + auto yamlValue = yamlList.begin(); + for (const auto& contextValue : contextList) { + assert(yamlValue != yamlList.end()); + func(contextValue, *yamlValue); + yamlValue++; + } + assert(yamlValue == yamlList.end()); +} + +static void updateCompileUnits(const BinaryenDWARFInfo& info, + llvm::DWARFYAML::Data& yaml, + const LocationUpdater& locationUpdater) { + // The context has the high-level information we need, and the YAML is where + // we write changes. First, iterate over the compile units. + iterContextAndYAML( + info.context->compile_units(), + yaml.CompileUnits, + [&](const std::unique_ptr<llvm::DWARFUnit>& CU, + llvm::DWARFYAML::Unit& yamlUnit) { + // Process the DIEs in each compile unit. + iterContextAndYAML( + CU->dies(), + yamlUnit.Entries, + [&](const llvm::DWARFDebugInfoEntry& DIE, + llvm::DWARFYAML::Entry& yamlEntry) { + // Process the entries in each relevant DIE, looking for attributes to + // change. + auto abbrevDecl = DIE.getAbbreviationDeclarationPtr(); + if (abbrevDecl) { + iterContextAndYAML( + abbrevDecl->attributes(), + yamlEntry.Values, + [&](const llvm::DWARFAbbreviationDeclaration::AttributeSpec& + attrSpec, + llvm::DWARFYAML::FormValue& yamlValue) { + if (attrSpec.Attr == llvm::dwarf::DW_AT_low_pc) { + // If the old address did not refer to an instruction, then + // this is not something we understand and can update. + if (locationUpdater.hasOldAddr(yamlValue.Value)) { + // The addresses of compile units and functions are not + // instructions. + assert(DIE.getTag() != llvm::dwarf::DW_TAG_compile_unit && + DIE.getTag() != llvm::dwarf::DW_TAG_subprogram); + // Note that the new value may be 0, which is the correct + // way to indicate that this is no longer a valid wasm + // value, the same as wasm-ld would do. + yamlValue.Value = + locationUpdater.getNewAddr(yamlValue.Value); + } + } + }); + } + }); + }); +} + void writeDWARFSections(Module& wasm, const BinaryLocationsMap& newLocations) { BinaryenDWARFInfo info(wasm); @@ -451,7 +531,11 @@ void writeDWARFSections(Module& wasm, const BinaryLocationsMap& newLocations) { Fatal() << "Failed to parse DWARF to YAML"; } - updateDebugLines(wasm, data, newLocations); + LocationUpdater locationUpdater(wasm, newLocations); + + updateDebugLines(data, locationUpdater); + + updateCompileUnits(info, data, locationUpdater); // TODO: Actually update, and remove sections we don't know how to update yet? diff --git a/test/passes/fannkuch3.bin.txt b/test/passes/fannkuch3.bin.txt index 7821d85c5..9ff0e44c3 100644 --- a/test/passes/fannkuch3.bin.txt +++ b/test/passes/fannkuch3.bin.txt @@ -2574,28 +2574,28 @@ Abbrev table for offset: 0x00000000 0x00000174: NULL 0x00000175: DW_TAG_GNU_call_site [20] - DW_AT_low_pc [DW_FORM_addr] (0x000000000000001c) + DW_AT_low_pc [DW_FORM_addr] (0x0000000000000018) 0x0000017a: DW_TAG_GNU_call_site [20] - DW_AT_low_pc [DW_FORM_addr] (0x0000000000000026) + DW_AT_low_pc [DW_FORM_addr] (0x000000000000001e) 0x0000017f: DW_TAG_GNU_call_site [20] - DW_AT_low_pc [DW_FORM_addr] (0x0000000000000030) + DW_AT_low_pc [DW_FORM_addr] (0x0000000000000024) 0x00000184: DW_TAG_GNU_call_site [20] - DW_AT_low_pc [DW_FORM_addr] (0x00000000000000de) + DW_AT_low_pc [DW_FORM_addr] (0x00000000000000ce) 0x00000189: DW_TAG_GNU_call_site [21] DW_AT_abstract_origin [DW_FORM_ref4] (cu + 0x0026 => {0x00000026} "free") - DW_AT_low_pc [DW_FORM_addr] (0x0000000000000387) + DW_AT_low_pc [DW_FORM_addr] (0x000000000000037b) 0x00000192: DW_TAG_GNU_call_site [21] DW_AT_abstract_origin [DW_FORM_ref4] (cu + 0x0026 => {0x00000026} "free") - DW_AT_low_pc [DW_FORM_addr] (0x000000000000038f) + DW_AT_low_pc [DW_FORM_addr] (0x000000000000037f) 0x0000019b: DW_TAG_GNU_call_site [21] DW_AT_abstract_origin [DW_FORM_ref4] (cu + 0x0026 => {0x00000026} "free") - DW_AT_low_pc [DW_FORM_addr] (0x0000000000000397) + DW_AT_low_pc [DW_FORM_addr] (0x0000000000000383) 0x000001a4: NULL @@ -2714,7 +2714,7 @@ Abbrev table for offset: 0x00000000 0x0000026c: DW_TAG_inlined_subroutine [26] * DW_AT_abstract_origin [DW_FORM_ref4] (cu + 0x01a5 => {0x000001a5} "_ZL8fannkuchi") - DW_AT_low_pc [DW_FORM_addr] (0x00000000000003ea) + DW_AT_low_pc [DW_FORM_addr] (0x00000000000003c3) DW_AT_high_pc [DW_FORM_data4] (0x000002cc) DW_AT_call_file [DW_FORM_data1] ("/usr/local/google/home/azakai/Dev/emscripten/fannkuch.cpp") DW_AT_call_line [DW_FORM_data1] (159) @@ -2769,7 +2769,7 @@ Abbrev table for offset: 0x00000000 0x000002be: DW_TAG_label [30] DW_AT_abstract_origin [DW_FORM_ref4] (cu + 0x0223 => {0x00000223} "cleanup") - DW_AT_low_pc [DW_FORM_addr] (0x000000000000065e) + DW_AT_low_pc [DW_FORM_addr] (0x000000000000061e) 0x000002c7: DW_TAG_lexical_block [19] * DW_AT_ranges [DW_FORM_sec_offset] (0x00000028 @@ -2784,46 +2784,46 @@ Abbrev table for offset: 0x00000000 0x000002d2: NULL 0x000002d3: DW_TAG_GNU_call_site [20] - DW_AT_low_pc [DW_FORM_addr] (0x00000000000003cc) + DW_AT_low_pc [DW_FORM_addr] (0x00000000000003ac) 0x000002d8: DW_TAG_GNU_call_site [20] - DW_AT_low_pc [DW_FORM_addr] (0x00000000000003e0) + DW_AT_low_pc [DW_FORM_addr] (0x00000000000003b9) 0x000002dd: DW_TAG_GNU_call_site [20] - DW_AT_low_pc [DW_FORM_addr] (0x000000000000040a) + DW_AT_low_pc [DW_FORM_addr] (0x00000000000003df) 0x000002e2: DW_TAG_GNU_call_site [20] - DW_AT_low_pc [DW_FORM_addr] (0x0000000000000442) + DW_AT_low_pc [DW_FORM_addr] (0x0000000000000413) 0x000002e7: DW_TAG_GNU_call_site [20] - DW_AT_low_pc [DW_FORM_addr] (0x000000000000044c) + DW_AT_low_pc [DW_FORM_addr] (0x0000000000000419) 0x000002ec: DW_TAG_GNU_call_site [20] - DW_AT_low_pc [DW_FORM_addr] (0x00000000000004bb) + DW_AT_low_pc [DW_FORM_addr] (0x0000000000000481) 0x000002f1: DW_TAG_GNU_call_site [20] - DW_AT_low_pc [DW_FORM_addr] (0x00000000000004d1) + DW_AT_low_pc [DW_FORM_addr] (0x0000000000000493) 0x000002f6: DW_TAG_GNU_call_site [20] - DW_AT_low_pc [DW_FORM_addr] (0x000000000000059e) + DW_AT_low_pc [DW_FORM_addr] (0x000000000000055e) 0x000002fb: DW_TAG_GNU_call_site [21] DW_AT_abstract_origin [DW_FORM_ref4] (cu + 0x0026 => {0x00000026} "free") - DW_AT_low_pc [DW_FORM_addr] (0x0000000000000666) + DW_AT_low_pc [DW_FORM_addr] (0x0000000000000622) 0x00000304: DW_TAG_GNU_call_site [21] DW_AT_abstract_origin [DW_FORM_ref4] (cu + 0x0026 => {0x00000026} "free") - DW_AT_low_pc [DW_FORM_addr] (0x000000000000066e) + DW_AT_low_pc [DW_FORM_addr] (0x0000000000000626) 0x0000030d: DW_TAG_GNU_call_site [20] - DW_AT_low_pc [DW_FORM_addr] (0x000000000000068f) + DW_AT_low_pc [DW_FORM_addr] (0x0000000000000643) 0x00000312: DW_TAG_GNU_call_site [21] DW_AT_abstract_origin [DW_FORM_ref4] (cu + 0x0026 => {0x00000026} "free") - DW_AT_low_pc [DW_FORM_addr] (0x00000000000006a0) + DW_AT_low_pc [DW_FORM_addr] (0x0000000000000650) 0x0000031b: DW_TAG_GNU_call_site [20] - DW_AT_low_pc [DW_FORM_addr] (0x00000000000006d2) + DW_AT_low_pc [DW_FORM_addr] (0x000000000000067b) 0x00000320: NULL diff --git a/test/passes/fannkuch3_manyopts.bin.txt b/test/passes/fannkuch3_manyopts.bin.txt index 338594e7b..a9061c853 100644 --- a/test/passes/fannkuch3_manyopts.bin.txt +++ b/test/passes/fannkuch3_manyopts.bin.txt @@ -2574,28 +2574,28 @@ Abbrev table for offset: 0x00000000 0x00000174: NULL 0x00000175: DW_TAG_GNU_call_site [20] - DW_AT_low_pc [DW_FORM_addr] (0x000000000000001c) + DW_AT_low_pc [DW_FORM_addr] (0x0000000000000014) 0x0000017a: DW_TAG_GNU_call_site [20] - DW_AT_low_pc [DW_FORM_addr] (0x0000000000000026) + DW_AT_low_pc [DW_FORM_addr] (0x000000000000001a) 0x0000017f: DW_TAG_GNU_call_site [20] - DW_AT_low_pc [DW_FORM_addr] (0x0000000000000030) + DW_AT_low_pc [DW_FORM_addr] (0x0000000000000020) 0x00000184: DW_TAG_GNU_call_site [20] - DW_AT_low_pc [DW_FORM_addr] (0x00000000000000de) + DW_AT_low_pc [DW_FORM_addr] (0x00000000000000be) 0x00000189: DW_TAG_GNU_call_site [21] DW_AT_abstract_origin [DW_FORM_ref4] (cu + 0x0026 => {0x00000026} "free") - DW_AT_low_pc [DW_FORM_addr] (0x0000000000000387) + DW_AT_low_pc [DW_FORM_addr] (0x0000000000000000) 0x00000192: DW_TAG_GNU_call_site [21] DW_AT_abstract_origin [DW_FORM_ref4] (cu + 0x0026 => {0x00000026} "free") - DW_AT_low_pc [DW_FORM_addr] (0x000000000000038f) + DW_AT_low_pc [DW_FORM_addr] (0x0000000000000000) 0x0000019b: DW_TAG_GNU_call_site [21] DW_AT_abstract_origin [DW_FORM_ref4] (cu + 0x0026 => {0x00000026} "free") - DW_AT_low_pc [DW_FORM_addr] (0x0000000000000397) + DW_AT_low_pc [DW_FORM_addr] (0x0000000000000000) 0x000001a4: NULL @@ -2714,7 +2714,7 @@ Abbrev table for offset: 0x00000000 0x0000026c: DW_TAG_inlined_subroutine [26] * DW_AT_abstract_origin [DW_FORM_ref4] (cu + 0x01a5 => {0x000001a5} "_ZL8fannkuchi") - DW_AT_low_pc [DW_FORM_addr] (0x00000000000003ea) + DW_AT_low_pc [DW_FORM_addr] (0x0000000000000000) DW_AT_high_pc [DW_FORM_data4] (0x000002cc) DW_AT_call_file [DW_FORM_data1] ("/usr/local/google/home/azakai/Dev/emscripten/fannkuch.cpp") DW_AT_call_line [DW_FORM_data1] (159) @@ -2769,7 +2769,7 @@ Abbrev table for offset: 0x00000000 0x000002be: DW_TAG_label [30] DW_AT_abstract_origin [DW_FORM_ref4] (cu + 0x0223 => {0x00000223} "cleanup") - DW_AT_low_pc [DW_FORM_addr] (0x000000000000065e) + DW_AT_low_pc [DW_FORM_addr] (0x0000000000000000) 0x000002c7: DW_TAG_lexical_block [19] * DW_AT_ranges [DW_FORM_sec_offset] (0x00000028 @@ -2784,46 +2784,46 @@ Abbrev table for offset: 0x00000000 0x000002d2: NULL 0x000002d3: DW_TAG_GNU_call_site [20] - DW_AT_low_pc [DW_FORM_addr] (0x00000000000003cc) + DW_AT_low_pc [DW_FORM_addr] (0x0000000000000376) 0x000002d8: DW_TAG_GNU_call_site [20] - DW_AT_low_pc [DW_FORM_addr] (0x00000000000003e0) + DW_AT_low_pc [DW_FORM_addr] (0x0000000000000383) 0x000002dd: DW_TAG_GNU_call_site [20] - DW_AT_low_pc [DW_FORM_addr] (0x000000000000040a) + DW_AT_low_pc [DW_FORM_addr] (0x00000000000003a7) 0x000002e2: DW_TAG_GNU_call_site [20] - DW_AT_low_pc [DW_FORM_addr] (0x0000000000000442) + DW_AT_low_pc [DW_FORM_addr] (0x00000000000003db) 0x000002e7: DW_TAG_GNU_call_site [20] - DW_AT_low_pc [DW_FORM_addr] (0x000000000000044c) + DW_AT_low_pc [DW_FORM_addr] (0x00000000000003e1) 0x000002ec: DW_TAG_GNU_call_site [20] - DW_AT_low_pc [DW_FORM_addr] (0x00000000000004bb) + DW_AT_low_pc [DW_FORM_addr] (0x0000000000000447) 0x000002f1: DW_TAG_GNU_call_site [20] - DW_AT_low_pc [DW_FORM_addr] (0x00000000000004d1) + DW_AT_low_pc [DW_FORM_addr] (0x0000000000000459) 0x000002f6: DW_TAG_GNU_call_site [20] - DW_AT_low_pc [DW_FORM_addr] (0x000000000000059e) + DW_AT_low_pc [DW_FORM_addr] (0x0000000000000518) 0x000002fb: DW_TAG_GNU_call_site [21] DW_AT_abstract_origin [DW_FORM_ref4] (cu + 0x0026 => {0x00000026} "free") - DW_AT_low_pc [DW_FORM_addr] (0x0000000000000666) + DW_AT_low_pc [DW_FORM_addr] (0x0000000000000000) 0x00000304: DW_TAG_GNU_call_site [21] DW_AT_abstract_origin [DW_FORM_ref4] (cu + 0x0026 => {0x00000026} "free") - DW_AT_low_pc [DW_FORM_addr] (0x000000000000066e) + DW_AT_low_pc [DW_FORM_addr] (0x00000000000005d7) 0x0000030d: DW_TAG_GNU_call_site [20] - DW_AT_low_pc [DW_FORM_addr] (0x000000000000068f) + DW_AT_low_pc [DW_FORM_addr] (0x00000000000005ed) 0x00000312: DW_TAG_GNU_call_site [21] DW_AT_abstract_origin [DW_FORM_ref4] (cu + 0x0026 => {0x00000026} "free") - DW_AT_low_pc [DW_FORM_addr] (0x00000000000006a0) + DW_AT_low_pc [DW_FORM_addr] (0x0000000000000000) 0x0000031b: DW_TAG_GNU_call_site [20] - DW_AT_low_pc [DW_FORM_addr] (0x00000000000006d2) + DW_AT_low_pc [DW_FORM_addr] (0x0000000000000623) 0x00000320: NULL |