Setting GDB hardware watchpoint/how to set software watchpoint - c++

An earlier question explained that on x86 the size of objects being watched is limited by debug registers. As expected, I can "watch" a double variable. But I can't watch a double datamember, for example,
watch pObject->dPrice
produces
Hardware watchpoint 1: pObject->dPrice
But when you try to continue execution, it says
Could not insert hardware breakpoints:
You may have requested too many hardware breakpoints/watchpoints.
even though this is the only breakpoint/watchpoint.
I'm curious why this is so, but more importantly is there a way around it? According to GDB documentation it may use software watchpoints if it can't use hardware. In this case it makes no attempt to use a software watchpoint -- is there a way to force it to do so?

Yes, you can:
set can-use-hw-watchpoints 0
From 5.1.2 Setting Watchpoints:
You can force GDB to use only software watchpoints with the set can-use-hw-watchpoints 0 command. With this variable set to zero, GDB will never try to use hardware watchpoints, even if the underlying system supports them. (Note that hardware-assisted watchpoints that were set before setting can-use-hw-watchpoints to zero will still use the hardware mechanism of watching expression values.)
set can-use-hw-watchpoints
Set whether or not to use hardware watchpoints.
show can-use-hw-watchpoints
Show the current mode of using hardware watchpoints.

Short answer: Use watch -location pObject->dPrice, or the short form watch -l.
Long answer: Quoting the GDB manual:
Watching complex expressions that reference many variables can also exhaust the resources available for hardware-assisted watchpoints. That's because GDB needs to watch every variable in the expression with separately allocated resources.
GDB quite literally watches the expression itself, not whatever address it points to. In this case, it means that the breakpoint will hit if pObject itself is changed to point to a new dPrice; there's not just a watchpoint for pObject->dPrice, but also one for pObject itself. This may be more than what's available.
A more comprehensive example:
// Set a watchpoint on '*p' before running
#include <stdio.h>
int a = 0;
int b = 0;
int c = 0;
int* p = &a;
int main()
{
puts("Hi"); // Dummy lines to make the results clearer, watchpoints stop at the line after the change
*p = 1; // Breaks: *p was changed from 0 to 1
puts("Hi");
a = 2; // Breaks: a is *p, which changed from 1 to 2
puts("Hi");
p = &b; // Breaks: p is now b, changing *p from 2 to 0
puts("Hi");
p = &c; // Doesn't break: while p changed, *p is still 0
puts("Hi");
p = NULL; // Breaks: *p is now unreadable
puts("Hi");
return 0;
}
In theory, this is a useful feature; you can watch a complex expression, breaking as soon as it's false, somewhat like a constantly-tested assertion. For example, you can watch a==b in the above program.
In practice, it's unexpected, often triggers this issue, and usually isn't what you want.
To watch only the target address, use watch -location pObject->dPrice. (This is available as of GDB 7.3, released in July 2011; if you're using anything older, use print &pObject->dPrice and watch *(double*)0x12345678, or whichever address it prints.)

I'm not 100% sure, but my understanding is that when you watch pObject->dPrice, GDB tries to watch anything that can change the watched value.
Using software watchpoints, after each step GDB checks if the expression has changed. Using hardware watchpoints, GDB has to set a watchpoint for dprice, as you expect, but also for pObject.
Now, you tagged the question 'x86'. On x86 you can set breakpoints for up to four bytes. A double is eight bytes. If you want to watch a double, I would guess that GDB would need two hardware watchpoints. You need an additional watchpoint for pObject as well. I'm guessing that GDB tries to watch all of pObject, which goes back to the problem in the question you linked in the question.
When I want to do something similar, if I'm certain that the pointer pObject will not change, I usually do:
p &pObject->dprice
Let's say GDB says the address is (double *) 0xabcdef10, now I do:
watch (double *) *0xabcdef10
and watch only what I want to.
Note: I don't have GDB open in front of me, so I may have the exact syntax for the watch command wrong (regarding the placement of the *), so check it out first.

Related

Find out the source file (line number) where a global variable was initialized?

I have pretty large C++ code base of a shared library which is messed up with complicated conditional macro spaghetti so IDE has troubles with that. I examined it with GDB to find the initial value of a global variable as follows:
$ gdb libcomplex.so
(gdb) p some_global_var
$1 = 1024
So I figured out the value the variable was initialized with.
QUESTION: Is it possible to find out which source file (and maybe line number) it was initialized at with GDB?
I tried list some_global_var, but it simply prints nothing:
(gdb) list some_global_var
(gdb)
So on x86 you can put a limited number of hardware watchpoints on that variable being changed:
If you are lucky, on a global you can get away with
watch some_global_var
But the debugger may still decide that is not a fixed address, and do a software watchpoint.
So you need to get the address, and watch exactly that:
p &some_global_var
(int*)0x000123456789ABC
watch (int*)0x000123456789ABC
Now, when you restart, the debugger should pop out when the value is first initialised, perhaps to zero, and/or when it is initialised to the unexpected value. If you are lucky, listing the associated source code will tell you how it came to be initialised. As others have stated you may then need to deduce why that line of code generated that value, which can be a pain with complex macros.
If that doesn't help you, or it stops many times unexpectedly during startup, then you should initially disable the watchpoint, then starti to restart you program and stop as soon as possible. Then p your global, and if it does not yet have the magic value, enable the watchpoint and continue. Hopefully this will skip the irrelevant startup and zoom in on the problem value.
You could use rr (https://rr-project.org/) to record a trace of the program, then you could reverse-execute to find the location. E.g.:
rr replay
(gdb) continue
...
(gdb) watch -l some_global_var
(gdb) reverse-continue

Set Read-Write watchpoint with GDB?

I'm trying to trackdown the source of incorrect runtime cpu feature reporting. I'm fairly certain its due to C++ "As-If-Broken" rule, where the language allows the compiler to take a correct program and turn it into an incorrect program.
According to 5.1.2 Setting Watchpoints:
Set a watchpoint for an expression. gdb will break when the expression expr is written into by the program and its value changes. The simplest (and the most popular) use of this command is to watch the value of a single variable:
(gdb) watch foo
Notice the watchpoints are for write access, but not read-write access.
I'd like to set a watchpoint for read-write access on a variable which is set once at startup in a function with __attribute__(constructor), and then read multiple times after the features have been determined. I want to do it to confirm the optimizer is removing the calls, and maybe determine how many of the calls are being removed.
How do I set a read-write watchpoint with GDB?
How do I set a read-write watchpoint with GDB?
(gdb) help awatch
From the manual:
awatch [-l|-location] expr [thread thread-id] [mask maskvalue]
Set a watchpoint that will break when expr is either read from
or written into by the program.

Is Hardware Breakpoint able to write memory?

I have this ASM Code which i would like to do a Hardware breakpoint on it, however I'm wonder if I could use Hardware Breakpoint to write the memory. Can anyone advice?
[ASM]
41A8BA - 68 12345678 [PUSH 78563412]
Is there anyway I can write it on Hardware Breakpoint that makes it to "68 00000000" for example on C++?
[C++ Code]
LONG WINAPI ExceptionFilter(PEXCEPTION_POINTERS ExceptionInfo)
{
if(ExceptionInfo->ExceptionRecord->ExceptionCode == EXCEPTION_SINGLE_STEP)
{
if((DWORD)ExceptionInfo->ExceptionRecord->ExceptionAddress == 0x41A8BA)
{
//What do i write here?
return EXCEPTION_CONTINUE_EXECUTION;
}
}
return EXCEPTION_CONTINUE_SEARCH;
}
I'm very familiar with how x86's implementation of hardware breakpoints work (from "what it does to the processor" - not how it's actually designed internally), and have read the descriptions for several others.
Hardware breakpoints do not DO anything to the code in question - it is a set of special registers, that can be given a pattern ("Address X, trigger on write", "Address Y, trigger on execute"), which are checked against during the execution of the code, and if there is a match (e.g. "Address X is being written to" or "Address Y is being executed"), then the processor will stop executing and enter an exception handler - at which point the software in the exception handler takes over, typically by handing over to the debugger to say "Your code did a write to address X, here's where you are at" or "Your code executed address Y, here's where we stopped".
The hardware brekapoints can't directly be used to read, write or execute anything - it's just a "match + exception" mechanism. Technically, one could make the exception handler do something like writing to the address being executed, but that would not be "the hardware breakpoint", and it would still be treated just like any other code executing on the processor, meaning the memory has to be mapped in a way that it can be written (code, typically, isn't writeable in modern OS's such as Windows and Linux).
You can of course, in the exception handler for the debug break, map the memory as writeable (if needed), and write a different value to the part of code you care about (if it's in another process, you need to use OpenProcess and WriteProcessMemory) - again, this is nothing directly to do with hardware breakpoints, but about the code executed as a consequence, and will still follow the usual rules of the OS with regards to what memory you can read and write.
I'm wondering what this has to do with hardware breakpoints.
Is far as I understand you want to modify a Windows program when it is stopped?
To do this you should use the "WriteProcessMemory()" API function.

gdb stops with too many watchpoints when there is only one

Do you know any other reasons why a watchpoint could not be inserted other than too many hardware breakpoints/watchpoints?
I have the following debug session:
GNU gdb (GDB) 7.1
...
(gdb) watch itrap_t_beg[1][222]
Hardware watchpoint 1: itrap_t_beg[1][222]
(gdb) cont
Continuing.
...
Hardware watchpoint 1: itrap_t_beg[1][222]
...
(gdb) cont
Continuing.
Warning:
Could not insert hardware watchpoint 1.
Could not insert hardware breakpoints:
You may have requested too many hardware breakpoints/watchpoints.
(gdb) info break
Num Type Disp Enb Address What
1 hw watchpoint keep y itrap_t_beg[1][222]
breakpoint already hit 1 time
As you can see, there's only one watchpoint yet it can't insert the breakpoint.
Do you know how can I fix this?
As far as I know commodity x86 CPUs have four debug registers available for supporting hardware breaks/watches. This limits the object size that you can watch. Object alignment also plays here.
Try limiting the watch scope to a smaller object like pair of first and last members of the structure.
Can force software breakpoints (which do not have limit on size) by running
set can-use-hw-watchpoints 0
Shot answer: Use watch -location itrap_t_beg[1][222], or the short form watch -l.
Long answer: Quoting the GDB manual:
Watching complex expressions that reference many variables can also exhaust the resources available for hardware-assisted watchpoints. That's because gdb needs to watch every variable in the expression with separately allocated resources.
gdb quite literally watches the expression itself, not whatever address it points to. In this case, it means that the breakpoint will hit if itrap_t_beg itself is changed such that itrap_t_beg[1][222] does; there's not just a watchpoint for itrap_t_beg[1][222], but also one for itrap_t_beg itself. This may be more than what's available.
In your case, itrap_t_beg is 7 ints, 28 bytes. A x86_64 watchpoint is up to eight bytes, so GDB needs four watchpoints for the entire structure - plus a fifth for itrap_t_beg itself. The x86 family only supports four simultaneous watchpoints.
A more comprehensive example on how watchpoints work:
//set a watchpoint on '*p' before running
#include <stdio.h>
int a = 0;
int b = 0;
int c = 0;
int* p = &a;
int main()
{
puts("Hi"); // Dummy lines to make the results clearer, watchpoints stop at the line after the change
*p = 1; // Breaks: *p was changed from 0 to 1
puts("Hi");
a = 2; // Breaks: a is *p, which changed from 1 to 2
puts("Hi");
p = &b; // Breaks: p is now b, changing *p from 2 to 0
puts("Hi");
p = &c; // Doesn't break: while p changed, *p is still 0
puts("Hi");
p = NULL; // Breaks: *p is now unreadable
puts("Hi");
return 0;
}
In theory, this is a useful feature; you can watch a complex expression, breaking as soon as it's false, somewhat like a constantly-tested assertion. For example, you can watch a==b in the above program.
In practice, it's unexpected, often triggers this issue, and usually isn't what you want.
To watch only the target address, use watch -location itrap_t_beg[1][222]. (This is available as of GDB 7.3, released in July 2011; if you're still on 7.1, use print &itrap_t_beg[1][222] and watch *(itrap_t)0x12345678, or whichever address it prints.)

Could I ever want to access the address zero?

The constant 0 is used as the null pointer in C and C++. But as in the question "Pointer to a specific fixed address" there seems to be some possible use of assigning fixed addresses. Is there ever any conceivable need, in any system, for whatever low level task, for accessing the address 0?
If there is, how is that solved with 0 being the null pointer and all?
If not, what makes it certain that there is not such a need?
Neither in C nor in C++ null-pointer value is in any way tied to physical address 0. The fact that you use constant 0 in the source code to set a pointer to null-pointer value is nothing more than just a piece of syntactic sugar. The compiler is required to translate it into the actual physical address used as null-pointer value on the specific platform.
In other words, 0 in the source code has no physical importance whatsoever. It could have been 42 or 13, for example. I.e. the language authors, if they so pleased, could have made it so that you'd have to do p = 42 in order to set the pointer p to null-pointer value. Again, this does not mean that the physical address 42 would have to be reserved for null pointers. The compiler would be required to translate source code p = 42 into machine code that would stuff the actual physical null-pointer value (0x0000 or 0xBAAD) into the pointer p. That's exactly how it is now with constant 0.
Also note, that neither C nor C++ provides a strictly defined feature that would allow you to assign a specific physical address to a pointer. So your question about "how one would assign 0 address to a pointer" formally has no answer. You simply can't assign a specific address to a pointer in C/C++. However, in the realm of implementation-defined features, the explicit integer-to-pointer conversion is intended to have that effect. So, you'd do it as follows
uintptr_t address = 0;
void *p = (void *) address;
Note, that this is not the same as doing
void *p = 0;
The latter always produces the null-pointer value, while the former in general case does not. The former will normally produce a pointer to physical address 0, which might or might not be the null-pointer value on the given platform.
On a tangential note: you might be interested to know that with Microsoft's C++ compiler, a NULL pointer to member will be represented as the bit pattern 0xFFFFFFFF on a 32-bit machine. That is:
struct foo
{
int field;
};
int foo::*pmember = 0; // 'null' member pointer
pmember will have the bit pattern 'all ones'. This is because you need this value to distinguish it from
int foo::*pmember = &foo::field;
where the bit pattern will indeed by 'all zeroes' -- since we want offset 0 into the structure foo.
Other C++ compilers may choose a different bit pattern for a null pointer to member, but the key observation is that it won't be the all-zeroes bit pattern you might have been expecting.
You're starting from a mistaken premise. When you assign an integer constant with the value 0 to a pointer, that becomes a null pointer constant. This does not, however, mean that a null pointer necessarily refers to address 0. Quite the contrary, the C and C++ standards are both very clear that a null pointer may refer to some address other than zero.
What it comes down to is this: you do have to set aside an address that a null pointer would refer to -- but it can be essentially any address you choose. When you convert zero to a pointer, it has to refer to that chosen address -- but that's all that's really required. Just for example, if you decided that converting an integer to a point would mean adding 0x8000 to the integer, then the null pointer to would actually refer to address 0x8000 instead of address 0.
It's also worth noting that dereferencing a null pointer results in undefined behavior. That means you can't do it in portable code, but it does not mean you can't do it at all. When you're writing code for small microcontrollers and such, it's fairly common to include some bits and pieces of code that aren't portable at all. Reading from one address may give you the value from some sensor, while writing to the same address could activate a stepper motor (just for example). The next device (even using exactly the same processor) might be connected up so both of those addresses referred to normal RAM instead.
Even if a null pointer does refer to address 0, that doesn't prevent you from using it to read and/or write whatever happens to be at that address -- it just prevents you from doing so portably -- but that doesn't really matter a whole lot. The only reason address zero would normally be important would be if it was decoded to connect to something other than normal storage, so you probably can't use it entirely portably anyway.
The compiler takes care of this for you (comp.lang.c FAQ):
If a machine uses a nonzero bit pattern for null pointers, it is the compiler's responsibility to generate it when the programmer requests, by writing "0" or "NULL," a null pointer. Therefore, #defining NULL as 0 on a machine for which internal null pointers are nonzero is as valid as on any other, because the compiler must (and can) still generate the machine's correct null pointers in response to unadorned 0's seen in pointer contexts.
You can get to address zero by referencing zero from a non-pointer context.
In practice, C compilers will happily let your program attempt to write to address 0. Checking every pointer operation at run time for a NULL pointer would be a tad expensive. On computers, the program will crash because the operating system forbids it. On embedded systems without memory protection, the program will indeed write to address 0 which will often crash the whole system.
The address 0 might be useful on an embedded systems (a general term for a CPU that's not in a computer; they run everything from your stereo to your digital camera). Usually, the systems are designed so that you wouldn't need to write to address 0. In every case I know of, it's some kind of special address. Even if the programmer needs to write to it (e.g., to set up an interrupt table), they would only need to write to it during the initial boot sequence (usually a short bit of assembly language to set up the environment for C).
Memory address 0 is also called the Zero Page. This is populated by the BIOS, and contains information about the hardware running on your system. All modern kernels protect this region of memory. You should never need to access this memory, but if you want to you need to do it from within kernel land, a kernel module will do the trick.
On the x86, address 0 (or rather, 0000:0000) and its vicinity in real mode is the location of the interrupt vector. In the bad old days, you would typically write values to the interrupt vector to install interrupt handers (or if you were more disciplined, used the MS-DOS service 0x25). C compilers for MS-DOS defined a far pointer type which when assigned NULL or 0 would recieve the bit pattern 0000 in its segment part and 0000 in its offset part.
Of course, a misbehaving program that accidentally wrote to a far pointer whose value was 0000:0000 would cause very bad things to happen on the machine, typically locking it up and forcing a reboot.
In the question from the link, people are discussing setting to fixed addresses in a microcontroller. When you program a microcontroller everything is at a much lower level there.
You even don't have an OS in terms of desktop/server PC, and you don't have virtual memory and that stuff. So there is it OK and even necessary to access memory at a specific address. On a modern desktop/server PC it is useless and even dangerous.
I compiled some code using gcc for the Motorola HC11, which has no MMU and 0 is a perfectly good address, and was disappointed to find out that to write to address 0, you just write to it. There's no difference between NULL and address 0.
And I can see why. I mean, it's not really possible to define a unique NULL on an architecture where every memory location is potentially valid, so I guess the gcc authors just said 0 was good enough for NULL whether it's a valid address or not.
char *null = 0;
; Clears 8-bit AR and BR and stores it as a 16-bit pointer on the stack.
; The stack pointer, ironically, is stored at address 0.
1b: 4f clra
1c: 5f clrb
1d: de 00 ldx *0 <main>
1f: ed 05 std 5,x
When I compare it with another pointer, the compiler generates a regular comparison. Meaning that it in no way considers char *null = 0 to be a special NULL pointer, and in fact a pointer to address 0 and a "NULL" pointer will be equal.
; addr is a pointer stored at 7,x (offset of 7 from the address in XR) and
; the "NULL" pointer is at 5,y (offset of 5 from the address in YR). It doesn't
; treat the so-called NULL pointer as a special pointer, which is not standards
; compliant as far as I know.
37: de 00 ldx *0 <main>
39: ec 07 ldd 7,x
3b: 18 de 00 ldy *0 <main>
3e: cd a3 05 cpd 5,y
41: 26 10 bne 53 <.LM7>
So to address the original question, I guess my answer is to check your compiler implementation and find out whether they even bothered to implement a unique-value NULL. If not, you don't have to worry about it. ;)
(Of course this answer is not standard compliant.)
It all depends on whether the machine has virtual memory. Systems with it will typically put an unwritable page there, which is probably the behaviour that you are used to. However in systems without it (typically microcontrollers these days, but they used to be far more common) then there's often very interesting things in that area such as an interrupt table. I remember hacking around with those things back in the days of 8-bit systems; fun, and not too big a pain when you had to hard-reset the system and start over. :-)
Yes, you might want to access memory address 0x0h. Why you would want to do this is platform-dependent. A processor might use this for a reset vector, such that writing to it causes the CPU to reset. It could also be used for an interrupt vector, as a memory-mapped interface to some hardware resource (program counter, system clock, etc), or it could even be valid as a plain old memory address. There is nothing necessarily magical about memory address zero, it is just one that was historically used for special purposes (reset vectors and the like). C-like languages follow this tradition by using zero as the address for a NULL pointer, but in reality the underlying hardware may or may not see address zero as special.
The need to access address zero usually arises only in low-level details like bootloaders or drivers. In these cases, the compiler can provide options/pragmas to compile a section of code without optimizations (to prevent the zero pointer from being extracted away as a NULL pointer) or inline assembly can be used to access the true address zero.
C/C++ don't allows you to write to any address. It is the OS that can raise a signal when a user access some forbidden address. C and C++ ensure you that any memory obtained from the heap, will be different of 0.
I have at times used loads from address zero (on a known platform where that would be guaranteed to segfault) to deliberately crash at an informatively named symbol in library code if the user violates some necessary condition and there isn't any good way to throw an exception available to me. "Segfault at someFunction$xWasnt16ByteAligned" is a pretty effective error message to alert someone to what they did wrong and how to fix it. That said, I wouldn't recommend making a habit of that sort of thing.
Writing to address zero can be done, but it depends upon several factors such as your OS, target architecture and MMU configuration. In fact, it can be a useful debugging tool (but not always).
For example, a few years ago while working on an embedded system (with few debugging tools available), we had a problem which was resulting in a warm reboot. To help locate the problem, we were debugging using sprintf(NULL, ...); and a 9600 baud serial cable. As I said--few debugging tools available. With our setup, we knew that a warm reboot would not corrupt the first 256 bytes of memory. Thus after the warm reboot we could pause the loader and dump the memory contents to find out what happened prior to reboot.
Remember that in all normal cases, you don't actually see specific addresses.
When you allocate memory, the OS supplies you with the address of that chunk of memory.
When you take the reference of a variable, the the variable has already been allocated at an address determined by the system.
So accessing address zero is not really a problem, because when you follow a pointer, you don't care what address it points to, only that it is valid:
int* i = new int(); // suppose this returns a pointer to address zero
*i = 42; // now we're accessing address zero, writing the value 42 to it
So if you need to access address zero, it'll generally work just fine.
The 0 == null thing only really becomes an issue if for some reason you're accessing physical memory directly. Perhaps you're writing an OS kernel or something like that yourself. In that case, you're going to be writing to specific memory addresses (especially those mapped to hardware registers), and so you might conceivably need to write to address zero. But then you're really bypassing C++ and relying on the specifics of your compiler and hardware platform.
Of course, if you need to write to address zero, that is possible. Only the constant 0 represents a null pointer. The non-constant integer value zero will not, if assigned to a pointer, yield a null pointer.
So you could simply do something like this:
int i = 0;
int* zeroaddr = (int*)i;
now zeroaddr will point to address zero(*), but it will not, strictly speaking, be a null pointer, because the zero value was not constant.
(*): that's not entirely true. The C++ standard only guarantees an "implementation-defined mapping" between integers and addresses. It could convert the 0 to address 0x1633de20` or any other address it likes. But the mapping is usually the intuitive and obvious one, where the integer 0 is mapped to the address zero)
It may surprise many people, but in the core C language there is no such thing as a special null pointer. You are totally free to read and write to address 0 if it's physically possible.
The code below does not even compile, as NULL is not defined:
int main(int argc, char *argv[])
{
void *p = NULL;
return 0;
}
OTOH, the code below compiles, and you can read and write address 0, if the hardware/OS allows:
int main(int argc, char *argv[])
{
int *p = 0;
*p = 42;
int x = *p; /* let's assume C99 */
}
Please note, I did not include anything in the above examples.
If we start including stuff from the standard C library, NULL becomes magically defined. As far as I remember it comes from string.h.
NULL is still not a core C feature, it's a CONVENTION of many C library functions to indicate the invalidity of pointers. The C library on the given platform will define NULL to a memory location which is not accessible anyway. Let's try it on a Linux PC:
#include <stdio.h>
int main(int argc, char *argv[])
{
int *p = NULL;
printf("NULL is address %p\n", p);
printf("Contents of address NULL is %d\n", *p);
return 0;
}
The result is:
NULL is address 0x0
Segmentation fault (core dumped)
So our C library defines NULL to address zero, which it turns out is inaccessible.
But it was not the C compiler, of not even the C-library function printf() that handled the zero address specially. They all happily tried to work with it normally. It was the OS that detected a segmentation fault, when printf tried to read from address zero.
If I remember correctly, in an AVR microcontroller the register file is mapped into an address space of RAM and register R0 is at the address 0x00. It was clearly done in purpose and apparently Atmel thinks there are situations, when it's convenient to access address 0x00 instead of writing R0 explicitly.
In the program memory, at the address 0x0000 there is a reset interrupt vector and again this address is clearly intended to be accessed when programming the chip.