diff --git a/src/DwarfInstructions.hpp b/src/DwarfInstructions.hpp index 042c860..96744e5 100644 --- a/src/DwarfInstructions.hpp +++ b/src/DwarfInstructions.hpp @@ -381,10 +381,13 @@ int DwarfInstructions::stepWithDwarf(A &addressSpace, pint_t pc, // Return address is address after call site instruction, so setting IP to // that simulates a return. // - // In case of this is frame of signal handler, the IP should be - // incremented, because the IP saved in the signal handler points to - // first non-executed instruction, while FDE/CIE expects IP to be after - // the first non-executed instruction. + // The +-1 situation is subtle. + // Return address points to the next instruction after the `call` + // instruction, but logically we're "inside" the call instruction, and + // FDEs are constructed accordingly. + // So our FDE parsing implicitly subtracts 1 from the address. + // But for signal return, there's no `call` instruction, and + // subtracting 1 would be incorrect. So we add 1 here to compensate. newRegisters.setIP(returnAddress + cieInfo.isSignalFrame); // Simulate the step by replacing the register set with the new ones. diff --git a/src/DwarfParser.hpp b/src/DwarfParser.hpp index 7adf96a..488043d 100644 --- a/src/DwarfParser.hpp +++ b/src/DwarfParser.hpp @@ -452,7 +452,14 @@ bool CFI_Parser::parseFDEInstructions(A &addressSpace, ")\n", static_cast(instructionsEnd)); - // see DWARF Spec, section 6.4.2 for details on unwind opcodes + // see DWARF Spec, section 6.4.2 for details on unwind opcodes; + // + // Note that we're looking for the PrologInfo for address `codeOffset - 1`, + // hence '<' instead of '<=" in `codeOffset < pcoffset` + // (compare to DWARF Spec section 6.4.3 "Call Frame Instruction Usage"). + // The -1 accounts for the fact that function return address points to the + // next instruction *after* the `call` instruction, while control is + // logically "inside" the `call` instruction. while ((p < instructionsEnd) && (codeOffset < pcoffset)) { uint64_t reg; uint64_t reg2; diff --git a/src/UnwindCursor.hpp b/src/UnwindCursor.hpp index 093e88a..11fc03f 100644 --- a/src/UnwindCursor.hpp +++ b/src/UnwindCursor.hpp @@ -2760,7 +2760,15 @@ int UnwindCursor::stepThroughSigReturn(Registers_arm64 &) { _registers.setRegister(UNW_AARCH64_X0 + i, value); } _registers.setSP(_addressSpace.get64(sigctx + kOffsetSp)); - _registers.setIP(_addressSpace.get64(sigctx + kOffsetPc)); + + // The +1 story is the same as in DwarfInstructions::stepWithDwarf() + // (search for "returnAddress + cieInfo.isSignalFrame" or "Return address points to the next instruction"). + // This is probably not the right place for this because this function is not necessarily used + // with DWARF. Need to research whether the other unwind methods have the same +-1 situation or + // are off by one. + pint_t returnAddress = _addressSpace.get64(sigctx + kOffsetPc); + _registers.setIP(returnAddress + 1); + _isSignalFrame = true; return UNW_STEP_SUCCESS; }