Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do debuggers guarantee correctness when using INT 3 (0xCC) software breakpoint even though an instruction was patched?

Tags:

I've read that the INT 3 (0xCC) is used for software breakpoints.

It is set by (for instance) a debugger by overwriting the actual program code in memory.

I've also read that INT 3 is a "trap" not "fault" exception meaning the address pushed on the stack is the address of the instruction following the INT3 instruction.

How does the debugger guarantee correctness if the patched instruction is not re-executed?

like image 711
user452188 Avatar asked Sep 19 '10 23:09

user452188


People also ask

How do debuggers set breakpoints?

To set a breakpoint in source code: Click in the far left margin next to a line of code. You can also select the line and press F9, select Debug > Toggle Breakpoint, or right-click and select Breakpoint > Insert breakpoint. The breakpoint appears as a red dot in the left margin.

How does the processor know if we reached a breakpoint while debugging?

The debugger loads the program into memory and provides you some input prompt. You tell the debugger to add a breakpoint. It may use some information to figure out where in memory your breakpoint actually corresponds to the in-memory representation of the program.

What is a breakpoint in the context of IDE debuggers?

In software development, a breakpoint is an intentional stopping or pausing place in a program, put in place for debugging purposes. It is also sometimes simply referred to as a pause.

What is a breakpoint and why would you use a breakpoint in debugging your code?

A breakpoint helps to speed up the debugging process in a large program by allowing the execution to continue up to a desired point before debugging begins. This is more efficient than stepping through the code on a line-by-line basis.


2 Answers

When you want to continue execution after the breakpoint fires, you have two possibilities: either the breakpoint was only supposed to fire once, or it was supposed to be persistent. If it was only supposed to fire once, you restore the original value you overwrote with your breakpoint instruction, manually adjust the address to that instruction's address (remember, regardless of what instruction was there, what executed was your single-byte breakpoint, so the adjustment is always trivial). Then you continue execution.

If it was supposed to be a persistent breakpoint, there's one added wrinkle: before you continue execution, you set the single-step (aka trap) bit in the flags on the stack. That means only the one instruction where the breakpoint was set will execute, then you'll get a breakpoint interrupt again. You respond to that by restoring the int 3 byte you had just patched to the first byte of the original instruction, and (again) continue execution.

like image 178
Jerry Coffin Avatar answered Oct 15 '22 21:10

Jerry Coffin


It's been a while since I've delved into that sort of stuff, but assuming you are correct that the following address is pushed on the stack, the debugger can pop the return address and use it to figure out where the breakpoint was (the return address minus one, since the INT 3 instruction is one byte long) [edited].

In other words, the debugger doesn't necessarily need to return to the address on the stack. It can restore the original instruction, and then execute it at the original location. If the breakpoint is to remain set, it can use the "trap bit" in the flags to execute only a single instruction - the original one that was overwritten - before another trap will be generated (INT 3 again I think); then the INT 3 instruction can be re-established before continuing execution properly.

Most of the time, though, debuggers are operating under a system where they're not directly handling the trap anyway; they might be delivered a signal, for instance, telling them where the trap occurred. Most likely they still need to figure out the "real" address (i.e. the address of the INT 3 instruction) from the trap address, as the OS has no way to do this.

Things get complicated, too, if there are multiple threads involved; in that case restoring the original instruction "in place" may lead to the breakpoint being missed if it is hit by another thread. One solution might be stopping all the other threads before restoring the instruction (and starting them again afterwards).

like image 23
davmac Avatar answered Oct 15 '22 22:10

davmac