diff --git a/src/DwarfInstructions.hpp b/src/DwarfInstructions.hpp index 96744e5..8955248 100644 --- a/src/DwarfInstructions.hpp +++ b/src/DwarfInstructions.hpp @@ -379,16 +379,8 @@ int DwarfInstructions::stepWithDwarf(A &addressSpace, pint_t pc, #endif // Return address is address after call site instruction, so setting IP to - // that simulates a return. - // - // 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); + // that does simulates a return. + newRegisters.setIP(returnAddress); // Simulate the step by replacing the register set with the new ones. registers = newRegisters; diff --git a/src/DwarfParser.hpp b/src/DwarfParser.hpp index 488043d..7adf96a 100644 --- a/src/DwarfParser.hpp +++ b/src/DwarfParser.hpp @@ -452,14 +452,7 @@ bool CFI_Parser::parseFDEInstructions(A &addressSpace, ")\n", static_cast(instructionsEnd)); - // 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. + // see DWARF Spec, section 6.4.2 for details on unwind opcodes while ((p < instructionsEnd) && (codeOffset < pcoffset)) { uint64_t reg; uint64_t reg2; diff --git a/src/UnwindCursor.hpp b/src/UnwindCursor.hpp index 11fc03f..21c9b3b 100644 --- a/src/UnwindCursor.hpp +++ b/src/UnwindCursor.hpp @@ -2605,6 +2605,14 @@ void UnwindCursor::setInfoBasedOnIPRegister(bool isReturnAddress) { --pc; #endif +#if !(defined(_LIBUNWIND_SUPPORT_SEH_UNWIND) && defined(_WIN32)) + // In case of this is frame of signal handler, 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. + if (_isSignalFrame) + ++pc; +#endif + // Ask address space object to find unwind sections for this pc. UnwindInfoSections sects; if (_addressSpace.findUnwindSections(pc, sects)) { @@ -2760,15 +2768,7 @@ int UnwindCursor::stepThroughSigReturn(Registers_arm64 &) { _registers.setRegister(UNW_AARCH64_X0 + i, value); } _registers.setSP(_addressSpace.get64(sigctx + kOffsetSp)); - - // 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); - + _registers.setIP(_addressSpace.get64(sigctx + kOffsetPc)); _isSignalFrame = true; return UNW_STEP_SUCCESS; }