summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/wasm/wasm-debug.cpp70
1 files changed, 43 insertions, 27 deletions
diff --git a/src/wasm/wasm-debug.cpp b/src/wasm/wasm-debug.cpp
index 20c5dfb62..4181b06f2 100644
--- a/src/wasm/wasm-debug.cpp
+++ b/src/wasm/wasm-debug.cpp
@@ -123,11 +123,17 @@ struct LineState {
bool basicBlock = false;
bool prologueEnd = false;
bool epilogueBegin = false;
- bool endSequence = false;
+ // Each instruction is part of a sequence, all of which get the same ID. The
+ // order within a sequence may change if binaryen reorders things, which means
+ // that we can't track the end_sequence location and assume it is at the end -
+ // we must track sequences and then emit an end for each one.
+ // -1 is an invalid marker value (note that this assumes we can fit all ids
+ // into just under 32 bits).
+ uint32_t sequenceId = -1;
LineState(const LineState& other) = default;
- LineState(const llvm::DWARFYAML::LineTable& table)
- : isStmt(table.DefaultIsStmt) {}
+ LineState(const llvm::DWARFYAML::LineTable& table, uint32_t sequenceId)
+ : isStmt(table.DefaultIsStmt), sequenceId(sequenceId) {}
LineState& operator=(const LineState& other) = default;
@@ -143,7 +149,6 @@ struct LineState {
break;
}
case llvm::dwarf::DW_LNE_end_sequence: {
- endSequence = true;
return true;
}
case llvm::dwarf::DW_LNE_set_discriminator: {
@@ -241,17 +246,17 @@ struct LineState {
}
bool needToEmit() {
- // Zero values imply we can ignore this line, unless it has something
- // special we must emit.
+ // Zero values imply we can ignore this line.
// https://github.com/WebAssembly/debugging/issues/9#issuecomment-567720872
- return (line != 0 && addr != 0) || endSequence;
+ return line != 0 && addr != 0;
}
// Given an old state, emit the diff from it to this state into a new line
// table entry (that will be emitted in the updated DWARF debug line section).
void emitDiff(const LineState& old,
std::vector<llvm::DWARFYAML::LineTableOpcode>& newOpcodes,
- const llvm::DWARFYAML::LineTable& table) {
+ const llvm::DWARFYAML::LineTable& table,
+ bool endSequence) const {
bool useSpecial = false;
if (addr != old.addr || line != old.line) {
// Try to use a special opcode TODO
@@ -299,8 +304,7 @@ struct LineState {
assert(basicBlock);
newOpcodes.push_back(makeItem(llvm::dwarf::DW_LNS_set_basic_block));
}
- if (prologueEnd != old.prologueEnd) {
- assert(prologueEnd);
+ if (prologueEnd) {
newOpcodes.push_back(makeItem(llvm::dwarf::DW_LNS_set_prologue_end));
}
if (epilogueBegin != old.epilogueBegin) {
@@ -314,27 +318,25 @@ struct LineState {
if (endSequence) {
// len = 1 (subopcode)
newOpcodes.push_back(makeItem(llvm::dwarf::DW_LNE_end_sequence, 1));
- // Reset the state.
- *this = LineState(table);
} else {
newOpcodes.push_back(makeItem(llvm::dwarf::DW_LNS_copy));
}
}
- resetAfterLine();
}
// Some flags are automatically reset after each debug line.
void resetAfterLine() { prologueEnd = false; }
private:
- llvm::DWARFYAML::LineTableOpcode makeItem(llvm::dwarf::LineNumberOps opcode) {
+ llvm::DWARFYAML::LineTableOpcode
+ makeItem(llvm::dwarf::LineNumberOps opcode) const {
llvm::DWARFYAML::LineTableOpcode item = {};
item.Opcode = opcode;
return item;
}
llvm::DWARFYAML::LineTableOpcode
- makeItem(llvm::dwarf::LineNumberExtendedOps opcode, uint64_t len) {
+ makeItem(llvm::dwarf::LineNumberExtendedOps opcode, uint64_t len) const {
auto item = makeItem(llvm::dwarf::LineNumberOps(0));
// All the length after the len field itself, including the subopcode
// (1 byte).
@@ -626,8 +628,9 @@ struct LocationUpdater {
static void updateDebugLines(llvm::DWARFYAML::Data& data,
LocationUpdater& locationUpdater) {
for (auto& table : data.DebugLines) {
+ uint32_t sequenceId = 0;
// Parse the original opcodes and emit new ones.
- LineState state(table);
+ LineState state(table, sequenceId);
// All the addresses we need to write out.
std::vector<BinaryLocation> newAddrs;
std::unordered_map<BinaryLocation, LineState> newAddrInfo;
@@ -645,7 +648,7 @@ static void updateDebugLines(llvm::DWARFYAML::Data& data,
omittingRange = true;
}
if (omittingRange) {
- state = LineState(table);
+ state = LineState(table, sequenceId);
continue;
}
// An expression may not exist for this line table item, if we optimized
@@ -666,7 +669,7 @@ static void updateDebugLines(llvm::DWARFYAML::Data& data,
} else if (locationUpdater.hasOldDelimiter(oldAddr)) {
newAddr = locationUpdater.getNewDelimiter(oldAddr);
}
- if (newAddr) {
+ if (newAddr && state.needToEmit()) {
// LLVM sometimes emits the same address more than once. We should
// probably investigate that.
if (newAddrInfo.count(newAddr)) {
@@ -682,7 +685,11 @@ static void updateDebugLines(llvm::DWARFYAML::Data& data,
}
if (opcode.Opcode == 0 &&
opcode.SubOpcode == llvm::dwarf::DW_LNE_end_sequence) {
- state = LineState(table);
+ sequenceId++;
+ // We assume the number of sequences can fit in 32 bits, and -1 is
+ // an invalid value.
+ assert(sequenceId != uint32_t(-1));
+ state = LineState(table, sequenceId);
}
}
}
@@ -692,15 +699,24 @@ static void updateDebugLines(llvm::DWARFYAML::Data& data,
// Emit a new line table.
{
std::vector<llvm::DWARFYAML::LineTableOpcode> newOpcodes;
- LineState state(table);
- for (BinaryLocation addr : newAddrs) {
- LineState oldState(state);
- state = newAddrInfo.at(addr);
- if (state.needToEmit()) {
- state.emitDiff(oldState, newOpcodes, table);
- } else {
- state = oldState;
+ for (size_t i = 0; i < newAddrs.size(); i++) {
+ LineState state = newAddrInfo.at(newAddrs[i]);
+ assert(state.needToEmit());
+ LineState lastState(table, -1);
+ if (i != 0) {
+ lastState = newAddrInfo.at(newAddrs[i - 1]);
+ // If the last line is in another sequence, clear the old state, as
+ // there is nothing to diff to.
+ if (lastState.sequenceId != state.sequenceId) {
+ lastState = LineState(table, -1);
+ }
}
+ // This line ends a sequence if there is no next line after it, or if
+ // the next line is in a different sequence.
+ bool endSequence =
+ i + 1 == newAddrs.size() ||
+ newAddrInfo.at(newAddrs[i + 1]).sequenceId != state.sequenceId;
+ state.emitDiff(lastState, newOpcodes, table, endSequence);
}
table.Opcodes.swap(newOpcodes);
}