diff options
Diffstat (limited to 'src/wasm/wasm-debug.cpp')
-rw-r--r-- | src/wasm/wasm-debug.cpp | 164 |
1 files changed, 117 insertions, 47 deletions
diff --git a/src/wasm/wasm-debug.cpp b/src/wasm/wasm-debug.cpp index ac1314ad6..c4d403e64 100644 --- a/src/wasm/wasm-debug.cpp +++ b/src/wasm/wasm-debug.cpp @@ -346,15 +346,15 @@ struct AddrExprMap { std::unordered_map<BinaryLocation, Expression*> startMap; std::unordered_map<BinaryLocation, Expression*> endMap; - // Some instructions have extra binary locations, like the else and end in + // Some instructions have delimiter binary locations, like the else and end in // and if. Track those separately, including their expression and their id // ("else", "end", etc.), as they are rare, and we don't want to // bloat the common case which is represented in the earlier maps. - struct ExtraInfo { + struct DelimiterInfo { Expression* expr; BinaryLocations::DelimiterId id; }; - std::unordered_map<BinaryLocation, ExtraInfo> extraMap; + std::unordered_map<BinaryLocation, DelimiterInfo> delimiterMap; // Construct the map from the binaryLocations loaded from the wasm. AddrExprMap(const Module& wasm) { @@ -384,12 +384,12 @@ struct AddrExprMap { return nullptr; } - ExtraInfo getExtra(BinaryLocation addr) const { - auto iter = extraMap.find(addr); - if (iter != extraMap.end()) { + DelimiterInfo getDelimiter(BinaryLocation addr) const { + auto iter = delimiterMap.find(addr); + if (iter != delimiterMap.end()) { return iter->second; } - return ExtraInfo{nullptr, BinaryLocations::Invalid}; + return DelimiterInfo{nullptr, BinaryLocations::Invalid}; } private: @@ -400,11 +400,13 @@ private: endMap[span.end] = expr; } - void add(Expression* expr, const BinaryLocations::DelimiterLocations& extra) { - for (Index i = 0; i < extra.size(); i++) { - if (extra[i] != 0) { - assert(extraMap.count(extra[i]) == 0); - extraMap[extra[i]] = ExtraInfo{expr, BinaryLocations::DelimiterId(i)}; + 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, BinaryLocations::DelimiterId(i)}; } } } @@ -472,7 +474,7 @@ struct LocationUpdater { // Updates an expression's 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. - BinaryLocation getNewExprAddr(BinaryLocation oldAddr) const { + BinaryLocation getNewExprStart(BinaryLocation oldAddr) const { if (auto* expr = oldExprAddrMap.getStart(oldAddr)) { auto iter = newLocations.expressions.find(expr); if (iter != newLocations.expressions.end()) { @@ -483,11 +485,11 @@ struct LocationUpdater { return 0; } - bool hasOldExprAddr(BinaryLocation oldAddr) const { + bool hasOldExprStart(BinaryLocation oldAddr) const { return oldExprAddrMap.getStart(oldAddr); } - BinaryLocation getNewExprEndAddr(BinaryLocation oldAddr) const { + BinaryLocation getNewExprEnd(BinaryLocation oldAddr) const { if (auto* expr = oldExprAddrMap.getEnd(oldAddr)) { auto iter = newLocations.expressions.find(expr); if (iter != newLocations.expressions.end()) { @@ -497,11 +499,11 @@ struct LocationUpdater { return 0; } - bool hasOldExprEndAddr(BinaryLocation oldAddr) const { + bool hasOldExprEnd(BinaryLocation oldAddr) const { return oldExprAddrMap.getEnd(oldAddr); } - BinaryLocation getNewFuncStartAddr(BinaryLocation oldAddr) const { + BinaryLocation getNewFuncStart(BinaryLocation oldAddr) const { if (auto* func = oldFuncAddrMap.getStart(oldAddr)) { // The function might have been optimized away, check. auto iter = newLocations.functions.find(func); @@ -520,11 +522,11 @@ struct LocationUpdater { return 0; } - bool hasOldFuncStartAddr(BinaryLocation oldAddr) const { + bool hasOldFuncStart(BinaryLocation oldAddr) const { return oldFuncAddrMap.getStart(oldAddr); } - BinaryLocation getNewFuncEndAddr(BinaryLocation oldAddr) const { + BinaryLocation getNewFuncEnd(BinaryLocation oldAddr) const { if (auto* func = oldFuncAddrMap.getEnd(oldAddr)) { // The function might have been optimized away, check. auto iter = newLocations.functions.find(func); @@ -544,20 +546,20 @@ struct LocationUpdater { } // Check for either the end opcode, or one past the end. - bool hasOldFuncEndAddr(BinaryLocation oldAddr) const { + bool hasOldFuncEnd(BinaryLocation oldAddr) const { return oldFuncAddrMap.getEnd(oldAddr); } // Check specifically for the end opcode. - bool hasOldFuncEndOpcodeAddr(BinaryLocation oldAddr) const { + bool hasOldFuncEndOpcode(BinaryLocation oldAddr) const { if (auto* func = oldFuncAddrMap.getEnd(oldAddr)) { return oldAddr == func->funcLocation.end - 1; } return false; } - BinaryLocation getNewExtraAddr(BinaryLocation oldAddr) const { - auto info = oldExprAddrMap.getExtra(oldAddr); + BinaryLocation getNewDelimiter(BinaryLocation oldAddr) const { + auto info = oldExprAddrMap.getDelimiter(oldAddr); if (info.expr) { auto iter = newLocations.delimiters.find(info.expr); if (iter != newLocations.delimiters.end()) { @@ -567,8 +569,33 @@ struct LocationUpdater { return 0; } - bool hasOldExtraAddr(BinaryLocation oldAddr) const { - return oldExprAddrMap.getExtra(oldAddr).expr; + bool hasOldDelimiter(BinaryLocation oldAddr) const { + return oldExprAddrMap.getDelimiter(oldAddr).expr; + } + + // getNewStart|EndAddr utilities. + // 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); + } + 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); + } + return 0; } }; @@ -601,19 +628,19 @@ static void updateDebugLines(llvm::DWARFYAML::Data& data, // it away. BinaryLocation oldAddr = state.addr; BinaryLocation newAddr = 0; - if (locationUpdater.hasOldExprAddr(oldAddr)) { - newAddr = locationUpdater.getNewExprAddr(oldAddr); + if (locationUpdater.hasOldExprStart(oldAddr)) { + newAddr = locationUpdater.getNewExprStart(oldAddr); } // 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.hasOldFuncEndAddr(oldAddr)) { - newAddr = locationUpdater.getNewFuncEndAddr(oldAddr); - } else if (locationUpdater.hasOldFuncStartAddr(oldAddr)) { - newAddr = locationUpdater.getNewFuncStartAddr(oldAddr); - } else if (locationUpdater.hasOldExtraAddr(oldAddr)) { - newAddr = locationUpdater.getNewExtraAddr(oldAddr); + 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); } if (newAddr) { // LLVM sometimes emits the same address more than once. We should @@ -691,10 +718,10 @@ static void updateDIE(const llvm::DWARFDebugInfoEntry& DIE, tag == llvm::dwarf::DW_TAG_inlined_subroutine || tag == llvm::dwarf::DW_TAG_lexical_block || tag == llvm::dwarf::DW_TAG_label) { - newValue = locationUpdater.getNewExprAddr(oldValue); + newValue = locationUpdater.getNewExprStart(oldValue); } else if (tag == llvm::dwarf::DW_TAG_compile_unit || tag == llvm::dwarf::DW_TAG_subprogram) { - newValue = locationUpdater.getNewFuncStartAddr(oldValue); + newValue = locationUpdater.getNewFuncStart(oldValue); } else { Fatal() << "unknown tag with low_pc " << llvm::dwarf::TagString(tag).str(); @@ -724,10 +751,10 @@ static void updateDIE(const llvm::DWARFDebugInfoEntry& DIE, tag == llvm::dwarf::DW_TAG_inlined_subroutine || tag == llvm::dwarf::DW_TAG_lexical_block || tag == llvm::dwarf::DW_TAG_label) { - newValue = locationUpdater.getNewExprEndAddr(oldValue); + newValue = locationUpdater.getNewExprEnd(oldValue); } else if (tag == llvm::dwarf::DW_TAG_compile_unit || tag == llvm::dwarf::DW_TAG_subprogram) { - newValue = locationUpdater.getNewFuncEndAddr(oldValue); + newValue = locationUpdater.getNewFuncEnd(oldValue); } else { Fatal() << "unknown tag with low_pc " << llvm::dwarf::TagString(tag).str(); @@ -777,16 +804,8 @@ static void updateRanges(llvm::DWARFYAML::Data& yaml, newEnd = 0; // If this was not an end marker, try to find what it should be updated to. if (oldStart != 0 && oldEnd != 0) { - if (locationUpdater.hasOldExprAddr(oldStart)) { - newStart = locationUpdater.getNewExprAddr(oldStart); - } else if (locationUpdater.hasOldFuncStartAddr(oldStart)) { - newStart = locationUpdater.getNewFuncStartAddr(oldStart); - } - if (locationUpdater.hasOldExprEndAddr(oldEnd)) { - newEnd = locationUpdater.getNewExprEndAddr(oldEnd); - } else if (locationUpdater.hasOldFuncEndAddr(oldEnd)) { - newEnd = locationUpdater.getNewFuncEndAddr(oldEnd); - } + newStart = locationUpdater.getNewStart(oldStart); + newEnd = locationUpdater.getNewEnd(oldEnd); if (newStart == 0 || newEnd == 0) { // This part of the range no longer has a mapping, so we must skip it. skip++; @@ -815,6 +834,55 @@ static void updateRanges(llvm::DWARFYAML::Data& yaml, } } +// A location that is ignoreable, i.e., not a special value like 0 or -1 (which +// would indicate an end or a base in .debug_loc). +static const BinaryLocation IGNOREABLE_LOCATION = 1; + +// Update the .debug_loc section. +static void updateLoc(llvm::DWARFYAML::Data& yaml, + const LocationUpdater& locationUpdater) { + // Similar to ranges, try to update the start and end. Note that here we + // can't skip since the location description is a variable number of bytes, + // so we mark no longer valid addresses as empty. + // Locations have an optional base. + BinaryLocation base = 0; + for (size_t i = 0; i < yaml.Locs.size(); i++) { + auto& loc = yaml.Locs[i]; + BinaryLocation newStart = loc.Start, newEnd = loc.End; + if (newStart == BinaryLocation(-1)) { + // This is a new base. + // Note that the base is not the address of an instruction, necessarily - + // it's just a number (seems like it could always be an instruction, but + // that's not what LLVM emits). + base = newEnd; + } else if (newStart == 0 && newEnd == 0) { + // This is an end marker, this list is done. + base = 0; + } else { + // This is a normal entry, try to find what it should be updated to. First + // de-relativize it to the base to get the absolute address, then look for + // a new address for it. + newStart = locationUpdater.getNewStart(loc.Start + base); + newEnd = locationUpdater.getNewEnd(loc.End + base); + if (newStart == 0 || newEnd == 0) { + // This part of the loc no longer has a mapping, so we must ignore it. + newStart = newEnd = IGNOREABLE_LOCATION; + } else { + // Finally, relativize it against the base. + newStart -= base; + newEnd -= base; + } + // The loc start and end markers have been preserved. However, TODO + // instructions in the middle may have moved around, making the loc no + // longer contiguous, we should check that, and possibly split/merge + // the loc. Or, we may need to have tracking in the IR for this. + } + loc.Start = newStart; + loc.End = newEnd; + // Note how the ".Location" field is unchanged. + } +} + void writeDWARFSections(Module& wasm, const BinaryLocations& newLocations) { BinaryenDWARFInfo info(wasm); @@ -832,6 +900,8 @@ void writeDWARFSections(Module& wasm, const BinaryLocations& newLocations) { updateRanges(data, locationUpdater); + updateLoc(data, locationUpdater); + // Convert to binary sections. auto newSections = EmitDebugSections(data, false /* EmitFixups for debug_info */); |