Another type of breakpoint detection technique that is widely used is the trap flag detection. When you trace over the instructions one by one, checking the changes they make in memory and on the registers' values, your debugger sets the trap flag in the EFLAGS register, which is responsible for stopping on the next instruction and returning control back to the debugger.
This flag is not trivial to catch because EFLAGS is not directly readable. It's only readable through the pushf instruction, which saves this register value in the stack. Since this flag is always set to False after returning to the debugger, it's hard to check the value of this flag and detect a single-step breakpoint; however, there are multiple ways to detect this behavior. Let's go through the most common examples.