How are GDB Hardware Watchpoints working? - gdb

I am interested in how a hardware watchpoint is realized. If I watch for a uint8_t variable by watch varName (watch -> write watch) so in case any data is changed on any bit within the range of the memory location it will be detected?
And how is the memory location/range handled by GDB?

I am interested in how a hardware watchpoint is realized.
On platforms which support hardware watchpoints, GDB uses the processor features which enable them (duh!).
For example, on x86, there are special debug registers, which can be programmed to have the processor halt execution when the address bus matches the given address and the access is a write (used for watchpoints), a read (used to implement access watchpoints), etc.
If I watch for a uint8_t variable ... any data is changed on any bit within the range of the memory location it will be detected?
The x86 processors do not write single bits into memory. The least you can write is a byte. The processor will stop after writing the byte (if the debug registers are so configured). GDB can then compare the new value with the old one, and if they differ, stop execution (otherwise GDB will swallow the watchpoint and continue as of nothing happened).
Yes, this can work on single-bit changes -- all it requires is for GDB to remember the old value (which it does when you set up the breakpoint).
Note: there are some gaps in this -- if the value is changed by the kernel (e.g. as a result of read system call), GDB watchpoint will not stop when that happens.

Related

How does OS detect a crash of a process

How does OS know that EIP is no longer a valid/legal instruction and that application has crashed? How does it know when to generate the crash dump data?
On an x86-compatible processor, when EIP points to a page which does not have read permission, a page that is not mapped, an invalid instruction, or when a valid instruction tries to access a memory page without permission, or a page that is not mapped, or a divide instruction sees that the denominator is zero, or an INT instruction is executed, or a bunch of other things, it raises an exception. In the case of an exception occuring in protected mode when the current privilege level (CPL) is > 0, the following things occur:
Loads the values for SS and ESP from a memory section called the task state segment.
Pushes the values of SS, ESP, EFLAGS, CS and EIP onto the stack. The SS and ESP values are the previous ones, not the new ones from the TSS.
Some exceptions also push an error code onto the stack.
Gets the values for CS and EIP from the interrupt descriptor table and puts these values in CS and EIP.
Note that the kernel has set up these tables and segments in advance.
Then:
The kernel decides what to do with the exception. This depends on the specific kernel. Usually, it decides to kill your program. On Linux, you can override this default using signal handling and on Windows you can override it using Structured Exception Handling.
(This is not an exhaustive reference to x86 exception handling. This is a brief overview of the most common case.)
The detailed answer https://stackoverflow.com/a/59075911/15304 from #user253751 is there for you to know all that you may want to know.
A word of context might help though: processor usually proceeds to the next instruction after each instruction is over, but there are cases where it will suddenly start a completely unrelated instruction. This is called an interrupt, and is widely used to support device operations or get some code called at periodic intervals.
In an interrupt handler, we have to save the full processor state so that the interrupted code can be safely resumed after we're done with device-specific code.
The hardware exception mechanism used to know that a process is trying to do something that is impossible/invalid given the current configuration extensively borrows interrupts mechanisms, but it also has to take care of a context switch between (presumably) user-level code for the "faulty" process and kernel-level code that will handle the fault. That context switch is the reason why we see stack pointers re-loaded and task state segment involved in the description of hardware exceptions that have much simpler definitions (e.g. exectue instruction at address 0xfffff000) on other architectures.
Note that having a hardware exception doesn't necessarily means that the process crashed. The exception handler in the kernel will usually have to compare some information (what address we tried to access, what object is mapped at this address, etc.) and either does useful job (bring one more page of a mapped file into memory) and resume the process, or calls it an invalid access.

How do GDB rwatch and awatch commands work?

I see it is possible in GDB to set a breakpoint which will fire when a specific memory address will be read or written.
I am wondering how it works. Does GDB have a sort of copy of the process memory and check what has changed between each instruction ? Or is it a syscall or kernel feature for that ?
(Intel x86 32 and 64 bits architecture)
I am wondering how it works.
There are two ways: software watchpoints and hardware watchpoints (only available on some architectures).
Software watchpoints work by single-stepping the application, and checking whether the value has changed after every instruction. These are painfully slow (1000x slower), and in practice aren't usable for anything other than a toy program. They also can't detect access, only change of the value in watched location.
Hardware watchpoints require processor support. Intel x86 chips have debug registers, which could be programmed to watch for access (awatch, rwatch) or change (watch) of a given memory location. When the processor detects that the location of interest has been accessed, it raises debug exception, which the OS translates into a signal, and (as usual) a signal is given to the debugger before the target sees it.
HW watchpoints execute at native speed, but (on x86) you can have only up to 4 distinct addresses (in practice, I've never needed more than 2).
Does execution of current instruction fire a watch read at eip address?
It should. You could trivially answer this yourself. Just try it.
Does push on stack fire a write on stack memory address?
Likewise.

Breakpoints not working when booting from Flash

In the past, I have been debugging executables loaded in the internal SRAM of my Cortex M3 (STM32F2) without problems. I have recently been loading my executable to Flash (because of size issues).
Ever since, debugging with GDB has not been working. As I understand, when the executable is in Flash, only hardware breakpoint can be used (as opposed to software breakpoints), and I have six hardware breakpoints. However, when setting just one hardware breakpoint GDB yields an error message:
(gdb) break main
Breakpoint 1 at 0x800019a: file src/main.c, line 88.
(gdb) c
Continuing.
Note: automatically using hardware breakpoints for read-only addresses.
(gdb) Warning:
Cannot insert hardware breakpoint 1.
Could not insert hardware breakpoints:
You may have requested too many hardware breakpoints/watchpoints.
What could be going wrong? Have my hardware breakpoints be taken in the background?
Note: I used OpenOCD to load the executable through JTAG.
So, there's basically two ways (plus one really bad way) that breakpoints can be implemented on any given debugger/platform combination:
Use some hardware capabilities ("hardware breakpoints") to cause the processor to trap when it hits a particular address. This is typically restricted to just a couple of breakpoints, if it's available at all.
For each breakpoint that's being set, replace the instruction at the breakpoint with a "trap" instruction of some variety (i.e, an instruction that will break into the debugger). When one of the breakpoints is hit, swap the original instruction back in and single-step once to make it run.
Single-step through the whole program. This one doesn't really count, because it's horrifically slow.
It sounds as though your debugger is only using method #2 ("software breakpoints"). The gotcha with this method is that it requires the program to be writable -- and flash memory isn't writable one instruction at a time, so this technique won't work.

How can gdb be used to watch for any changes in an entire region of memory?

For example, can I break on any change to memory in an address range from <startaddress> to <endaddress>?
How about reads and/or writes?
On Linux/x86, GDB uses the processor debug registers to implement hardware watchpoints. Such watchpoints are fast -- the program runs at full speed, until the processor stops and signals the application when the access or write watchpoint is triggered.
But such watchpoints can only work on 1-word sized data.
Recent Valgrind versions (SVN, but no released versions) implement GDB remote protocol stub, and allow you to set read or write watchpoints over arbitrary memory via special monitor commands.
So if you are on a platform that has Valgrind, and if your application runs acceptably fast under Valgrind, then yes: you can set watchpoints on arbitrary memory regions.

How do breakpoints work in C++ code?

How do breakpoints work in C++ code? Are they special instructions inserted in between some assembler instructions when the code is compiled? Or is there something else in place? Also, how are stepping-through-the-code implemented? The same way as breakpoints...?
This is heavly depend on the CPU and debugger.
For example, one of the possible solution on x86 CPU:
Insert one-byte INT3 instruction on the required place
Wait until breakpoint exception hits
Compare exception address to the list of breakpoint to determine which one
Do breakpoint actions
Replace INT3 with original byte and switch the debugged process into trace mode (step-by-step execution of CPU instructions)
Continue debugged process
Immediately you catch trace exception - the instruction was executed
Put INT3 back
Watchpoints can be implemented in the similar way, but instead of INT3 you put the memory page where watched variable is into read only, or into no access mode, and wait for segmentation exception.
Stepping through assembly can also be done by using trace mode. Stepping through source lines can also be done by placing breakpoints onto next instructions, based on debug data.
Also some CPU has hardware breakpoint support, when you just load address into some register.
According to this blog entry on technochakra.com you are correct:
Software breakpoints work by inserting a special instruction in the program being debugged. This special instruction on the Intel platform is “int 3″. When executed it calls the debugger’s exception handler.
I'm not sure how stepping into or over the next instruction is implemented though. However, the article goes on to add:
For practical reasons, it is unwise to ask for a recompilation whenever a breakpoint is added or deleted. Debuggers change the loaded image of the executable in memory and insert the “int 3″ instruction at runtime.
However, this would only be used for the "run to current line option".
Single stepping is implemented at (assembler) code level not at C++ level. The debugger knows how to map the C++ code lines to code addresses.
There are different implementations. There are CPUs that support debugging with breakpoint registers. When the execution reaches the address in the breakpoint register, the CPU executes a breakpoint exception.
A different approach is to patch the code for the time of execution with a special instruction, at best a one-byte instruction. At x86 systems that usually int 3.
The first approach allows breakpoints in ROM, the second allows more breakpoints at the same time.
AFAIK all debuggers (for whatever compiled language) that allow an unlimited number of breakpoints use a variant of replacing the instruction to be breakpointed with a special value (as described above) and keeping a list of places where these values have been placed.
When the processor tries to execute one of these special values, an exception is raised, the debugger catches it and checks if the address of the exception is on its list of breakpoints.
If it is, the debugger is invoked and the user is given an opportunity to interact.
If it is NOT, then the exception is due to something that was in the program from the outset and the debugger lets the exception 'pass' to whatever error handler might be there.
Note also, that debugging self-modifying code can fail precisely because the debugger momentarily modifies the code itself. (Of course, nobody would ever write self-modifying, now would they? >;-)
For these reasons, it is important that the debugger be given the opportunity to remove all the breakpoints it sets before terminating the debugging session.