1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-05-31 04:38:11 +00:00

LibDebug: Make sure to not single step the program twice

After hitting a breakpoint, we single step the program to execute the
instruction we breaked on and re-enable the breakpoint.
We also single step the program when the user of LibDebug returned a
DebugDecision::SingleStep.

Previously, if we hit a breakpoint and then were asked to to a
DebugDecision::SingleStep, we would single step twice.

This bug can actually crash programs, because it might cause us to
skip over a patched INT3 instruction in the second single-step.

Interestingely enough, this bug manifested as functrace crashing
certain programs: after hitting a breakpoint on a CALL instruction,
functrace single steps the program to see where the CALL jumps to
(yes, this can be optimized :D). functrace crashed when a CALL
instruction jumps to another CALL, because it inserts breakpoints on CALL
instructions, and so the INT3 in the 2nd CALL was skipped over, and we
executed garbage :).

This commit fixes this by making sure not to single-step twice.
This commit is contained in:
Itamar 2020-05-23 17:11:11 +03:00 committed by Andreas Kling
parent 2686957836
commit f9d62fd5e5
2 changed files with 22 additions and 2 deletions

View file

@ -225,6 +225,12 @@ int DebugSession::continue_debugee_and_wait(ContinueType type)
void* DebugSession::single_step()
{
// Single stepping works by setting the x86 TRAP flag bit in the eflags register.
// This flag causes the cpu to enter single-stepping mode, which causes
// Interupt 1 (debug interrupt) to be emitted after every instruction.
// To single step the program, we set the TRAP flag and continue the debugee.
// After the debugee has stopped, we clear the TRAP flag.
auto regs = get_registers();
constexpr u32 TRAP_FLAG = 0x100;
regs.eflags |= TRAP_FLAG;