diff options
author | Alon Zakai <azakai@google.com> | 2020-01-14 10:18:43 -0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-01-14 10:18:43 -0800 |
commit | a43b533b0778a1daf47178a3d3d9e559f3d390ed (patch) | |
tree | 201e7f128b95c58dd2c7719f06ac9f65d1b7c1da /src | |
parent | a7be271b6371c5968b77b4227bd3159db558951f (diff) | |
download | binaryen-a43b533b0778a1daf47178a3d3d9e559f3d390ed.tar.gz binaryen-a43b533b0778a1daf47178a3d3d9e559f3d390ed.tar.bz2 binaryen-a43b533b0778a1daf47178a3d3d9e559f3d390ed.zip |
DWARF updating: update DW_AT_low_pc attributes (#2584)
Mostly straightforward: go over the dwarf entries, find the
low_pc ones, and update their positions. A slight oddity is
that we must traverse both the dwarf context - which has
the rich APIs for analsis - and the YAML data structure -
which is minimal but is used for writing out.
Diffstat (limited to 'src')
-rw-r--r-- | src/wasm/wasm-debug.cpp | 120 |
1 files changed, 102 insertions, 18 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? |