Need an Overview of Debugging Process from the Hardware Layer

Need an overview of debugging process from the hardware layer

The x86 ISA includes a single-byte int3 encoding that's intended for software breakpoints. GDB uses this (via ptrace) by default for breakpoints.

(Why Single Stepping Instruction on X86?)

x86 also has a Trap Flag (TF) in EFLAGS for single-step mode. (https://en.wikipedia.org/wiki/Trap_flag). See also Difference between trap flag (TF) and monitor trap flag?

There are even "debug registers" for setting hardware breakpoints, without modifying the machine code to be run. And also hardware support for watch points, to break on write to a certain address. This makes GDB watch points efficient, not requiring it to single-step and manually decode the instruction to see where it writes.

https://wiki.osdev.org/CPU_Registers_x86#Debug_Registers

Implementing hardware breakpoints using x86 debug register osdev forum thread might be relevant.


Some other ISAs exist without nearly as much HW support for debugging. e.g. without a single-step flag, a debugger might have to always decode the current instruction (pointed to by program counter) to find the next one to be executed, and set a software breakpoint there.

ARM Linux used to do that to implement ptrace single-step, but that disassembler code was removed from the kernel and now just returns -EIO. https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=425fc47adb5bb69f76285be77a09a3341a30799e is the commit that removed it.

Why Single Stepping Instruction on X86?

int 3 is a special 1-byte interrupt. Invoking it will break into the debugger if one is present, otherwise the application will typically crash.

When the debugger sets the trap flag, this causes the processor to automatically execute an int 1 interrupt after every instruction. This allows the debugger to single-step by instructions, without having to insert an int 3 instruction. You do not have to invoke this interrupt explicitly.

Can virtual memory be used to support Data Breakpoint feature in i386?

Linear addresses are virtual, in x86 terminology. x86 memory addressing goes:

  • addressing mode like [ebp + eax*4] to "effective address" (the offset part of a seg:off). (And every addressing mode implies a segment, if you don't manually override with [fs: rdi] for example. Normally DS, unless the base register is R/E/BP or R/ESP in which case SS. Or for implicit addressing modes as part of e.g. push rax or stosb, it depends on the instruction.)
  • seg:off -> linear by adding the segment base to the offset.
  • translation of that linear address to physical. (And if virtualizing, from guest-physical to true physical.)

All steps are done by the CPU hardware, first using the segment base, then using the page-table pointed to by CR3. Or the TLB which caches the translations from that page table.

The hardware debug registers for hardware breakpoints / watchpoints use virtual addresses. https://en.wikipedia.org/wiki/X86_debug_register explains it as follows:

The addresses in these registers are linear addresses. If paging is enabled, the linear addresses are translated into physical addresses by the processor's paging mechanism. If paging is not enabled, these linear addresses are the same as physical addresses.

That implies that a watchpoint can trigger when you access the same physical address from a different virtual address than the one you put in the debug register. (If that description on Wikipedia is accurate; I'd test it and/or check Intel or AMD's manuals if that matters.)

I don't actually know the details; know x86 has a TF flag and debug registers, and a general idea of things they can do, but I've never written code to use them.



I only know that the debugger uses INT 3 to pause the program

"hardware breakpoint" means the CPU will stop without software having to rewrite the executing code to 0xCC int3. The debug registers can do this, and also detect access to certain memory locations by any instruction.

So you can set a watchpoint to break when anything your program reads or writes a certain global variable in memory, letting you find code that modifies it through a pointer or something. And since it's HW supported, you can run at full speed instead of having to single-step and have software check every access.

See also

  • Need an overview of debugging process from the hardware layer

  • How does GDB restore instruction after breakpoint

  • How does gdb set software breakpoints in shared library functions?

  • Why Single Stepping Instruction on X86?

  • Intel's manuals.

Debug session freezes when trying to watch an array


I have to mention that watching variables works well.

When you set the watchpoint on a variable, GDB probably says Hardware watchpoint N (but your IDE may be hiding that message).

When you set a watchpoint on anything larger than 8 bytes on x86 processor, GDB can not set a hardware watchpoint (because x86 hardware doesn't support such watchpoints). GDB sets a software watchpoint instead. Software watchpoints are implemented as follows:

  1. single-step the program
  2. did values change? No -> go to step 1. Yes: stop.

Software watchpoints are really slow. If you watch your system with top, you'll likely discover that GDB is consuming 100% CPU.

If you really need to watch an entire array, this answer shows how that can be done with valgrind.

Debugging with Android Studio stuck at Waiting For Debugger forever

Both of my dev machines have JDK 8 installed, the debugging function is restored once JDK 7.0.71 was installed and JAVA_HOME environmental variable was set to point to the new JDK.

Guess there's some compatibility issue between Android Studio + ADB + JDK8 (Eclipse + ADB + JDK8 works fine).



Related Topics



Leave a reply



Submit