How to automatically analyse when a C pointer variable is assigned to NULL [duplicate] - c

I am running an application through gdb and I want to set a breakpoint for any time a specific variable is accessed / changed. Is there a good method for doing this? I would also be interested in other ways to monitor a variable in C/C++ to see if/when it changes.

watch only breaks on write, rwatch let you break on read, and awatch let you break on read/write.
You can set read watchpoints on memory locations:
gdb$ rwatch *0xfeedface
Hardware read watchpoint 2: *0xfeedface
but one limitation applies to the rwatch and awatch commands; you can't use gdb variables
in expressions:
gdb$ rwatch $ebx+0xec1a04f
Expression cannot be implemented with read/access watchpoint.
So you have to expand them yourself:
gdb$ print $ebx
$13 = 0x135700
gdb$ rwatch *0x135700+0xec1a04f
Hardware read watchpoint 3: *0x135700 + 0xec1a04f
gdb$ c
Hardware read watchpoint 3: *0x135700 + 0xec1a04f
Value = 0xec34daf
0x9527d6e7 in objc_msgSend ()
Edit: Oh, and by the way. You need either hardware or software support. Software is obviously much slower. To find out if your OS supports hardware watchpoints you can see the can-use-hw-watchpoints environment setting.
gdb$ show can-use-hw-watchpoints
Debugger's willingness to use watchpoint hardware is 1.

What you're looking for is called a watchpoint.
Usage
(gdb) watch foo: watch the value of variable foo
(gdb) watch *(int*)0x12345678: watch the value pointed by an address, casted to whatever type you want
(gdb) watch a*b + c/d: watch an arbitrarily complex expression, valid in the program's native language
Watchpoints are of three kinds:
watch: gdb will break when a write occurs
rwatch: gdb will break wnen a read occurs
awatch: gdb will break in both cases
You may choose the more appropriate for your needs.
For more information, check this out.

Assuming the first answer is referring to the C-like syntax (char *)(0x135700 +0xec1a04f) then the answer to do rwatch *0x135700+0xec1a04f is incorrect. The correct syntax is rwatch *(0x135700+0xec1a04f).
The lack of ()s there caused me a great deal of pain trying to use watchpoints myself.

I just tried the following:
$ cat gdbtest.c
int abc = 43;
int main()
{
abc = 10;
}
$ gcc -g -o gdbtest gdbtest.c
$ gdb gdbtest
...
(gdb) watch abc
Hardware watchpoint 1: abc
(gdb) r
Starting program: /home/mweerden/gdbtest
...
Old value = 43
New value = 10
main () at gdbtest.c:6
6 }
(gdb) quit
So it seems possible, but you do appear to need some hardware support.

Use watch to see when a variable is written to, rwatch when it is read and awatch when it is read/written from/to, as noted above. However, please note that to use this command, you must break the program, and the variable must be in scope when you've broken the program:
Use the watch command. The argument to the watch command is an
expression that is evaluated. This implies that the variabel you want
to set a watchpoint on must be in the current scope. So, to set a
watchpoint on a non-global variable, you must have set a breakpoint
that will stop your program when the variable is in scope. You set the
watchpoint after the program breaks.

In addition to what has already been answered/commented by asksol and Paolo M
I didn't at first read understand, why do we need to cast the results. Though I read this: https://sourceware.org/gdb/onlinedocs/gdb/Set-Watchpoints.html, yet it wasn't intuitive to me..
So I did an experiment to make the result clearer:
Code: (Let's say that int main() is at Line 3; int i=0 is at Line 5 and other code.. is from Line 10)
int main()
{
int i = 0;
int j;
i = 3840 // binary 1100 0000 0000 to take into account endianness
other code..
}
then i started gdb with the executable file
in my first attempt, i set the breakpoint on the location of variable without casting, following were the results displayed
Thread 1 "testing2" h
Breakpoint 2 at 0x10040109b: file testing2.c, line 10.
(gdb) s
7 i = 3840;
(gdb) p i
$1 = 0
(gdb) p &i
$2 = (int *) 0xffffcbfc
(gdb) watch *0xffffcbfc
Hardware watchpoint 3: *0xffffcbfc
(gdb) s
[New Thread 13168.0xa74]
Thread 1 "testing2" hit Breakpoint 2, main () at testing2.c:10
10 b = a;
(gdb) p i
$3 = 3840
(gdb) p *0xffffcbfc
$4 = 3840
(gdb) p/t *0xffffcbfc
$5 = 111100000000
as we could see breakpoint was hit for line 10 which was set by me. gdb didn't break because although variable i underwent change yet the location being watched didn't change (due to endianness, since it continued to remain all 0's)
in my second attempt, i did the casting on the address of the variable to watch for all the sizeof(int) bytes. this time:
(gdb) p &i
$6 = (int *) 0xffffcbfc
(gdb) p i
$7 = 0
(gdb) watch *(int *) 0xffffcbfc
Hardware watchpoint 6: *(int *) 0xffffcbfc
(gdb) b 10
Breakpoint 7 at 0x10040109b: file testing2.c, line 10.
(gdb) i b
Num Type Disp Enb Address What
6 hw watchpoint keep y *(int *) 0xffffcbfc
7 breakpoint keep y 0x000000010040109b in main at testing2.c:10
(gdb) n
[New Thread 21508.0x3c30]
Thread 1 "testing2" hit Hardware watchpoint 6: *(int *) 0xffffcbfc
Old value = 0
New value = 3840
Thread 1 "testing2" hit Breakpoint 7, main () at testing2.c:10
10 b = a;
gdb break since it detected the value has changed.

Related

For gdb, should an rwatch breakpoint activate the commands written to that breakpoint? Mine don't

After I finished writing this I saw that rwatch actives a signal, SIGTRAP, which seems to be different than a breakpoint. I'm confused now because the command 'info breakpoints' still lists it as a breakpoint.
I don't know if this is expected behavior or if I'm setting up something wrong.
I have a setup running gdb (from ARM toolchain) and openocd with the target being a stm32 discovery board.
I'm trying to run certain gdb commands on a watchpoint using the command
commands [breakpointnumber]
Then I add the commands when prompted, I'm using 'p x' and 'p y' to print the x and y variable, and end it with 'end' like it says I should.
This does work when I set a breakpoint using
b [linenumber]
Here is an example of it running on gdb
(gdb) b 15
Breakpoint 5 at 0x8000134: file main.c, line 15.
(gdb) commands 5
Type commands for breakpoint(s) 5, one per line.
End with a line saying just "end".
>p x
>p y
>end
(gdb) info breakpoints
Num Type Disp Enb Address What
5 breakpoint keep y 0x08000134 in main at main.c:15
p x
p y
(gdb) c
Continuing.
Breakpoint 5, main () at main.c:15
15 y++;
$21 = 46 '.'
$22 = 44 ','
(gdb) c
Continuing.
Breakpoint 5, main () at main.c:15
15 y++;
$23 = 47 '/'
$24 = 46 '.'
(gdb) c
Continuing.
Breakpoint 5, main () at main.c:15
15 y++;
$25 = 48 '0'
$26 = 48 '0'
but if I use the rwatch command such as
rwatch x
and set the commands like before, those commands don't run when the program reaches the rwatch breakpoint.
Here is gdb running using rwatch
(gdb) delete
Delete all breakpoints? (y or n) y
(gdb) rwatch x
Hardware read watchpoint 6: x
(gdb) commands 6
Type commands for breakpoint(s) 6, one per line.
End with a line saying just "end".
>p x
>p y
>end
(gdb) info breakpoints
Num Type Disp Enb Address What
6 read watchpoint keep y x
p x
p y
(gdb) c
Continuing.
Program received signal SIGTRAP, Trace/breakpoint trap.
0x0800012c in main () at main.c:14
14 x++;
(gdb) c
Continuing.
Program received signal SIGTRAP, Trace/breakpoint trap.
0x0800012c in main () at main.c:14
14 x++;
(gdb) c
Continuing.
Program received signal SIGTRAP, Trace/breakpoint trap.
0x0800012c in main () at main.c:14
14 x++;
I have deleted all other breakpoints.
Using 'info breakpoints' shows the commands are associated with the breakpoint
It's just a test program as I learn gdb and openocd so it's really short.
#include "stdint.h"
5 uint8_t checker = 0x50;
4 uint8_t x = 0x21;
3 uint8_t y = 0x14;
2 int main(void)
1 {
12 while(1)
1 {
2 x++;
3 y++;
4 y++;
5 ;
6 if(x == 5000)
7 {
8 x = 0;
9 }
10 if(y == 10000)
11 {
12 y = 0;
13 }
14 }
15 }
I suspect that this is an openocd bug. That the watchpoint is being reported as a SIGTRAP is not the correct behaviour, but most likely reflects what GDB is being told by openocd.
If we look at the behaviour of GDB running on native Linux, I see this behaviour:
$ gdb -q test
Reading symbols from test...
(gdb) start
Temporary breakpoint 1 at 0x401123: file test.c, line 10.
Starting program: /tmp/rwatch/test
Temporary breakpoint 1, main () at test.c:10
10 int var = 0;
(gdb) rwatch var
Hardware read watchpoint 2: var
(gdb) commands
Type commands for breakpoint(s) 2, one per line.
End with a line saying just "end".
>echo hello world\n
>end
(gdb) c
Continuing.
Hardware read watchpoint 2: var
Value = 0
main () at test.c:12
12 func (&var);
hello world
(gdb)
And, if I use gdbserver, then I see the same behaviour:
> gdb -q test
Reading symbols from test...
(gdb) target remote :54321
Remote debugging using :54321
... snip lots of library loading text ...
(gdb) b main
Breakpoint 1 at 0x401123: file test.c, line 10.
(gdb) c
Continuing.
... snip lots more library loading text ...
Breakpoint 1, main () at test.c:10
10 int var = 0;
(gdb) rwatch var
Hardware read watchpoint 2: var
(gdb) command
Type commands for breakpoint(s) 2, one per line.
End with a line saying just "end".
>echo hello world\n
>end
(gdb) c
Continuing.
Hardware read watchpoint 2: var
Value = 0
main () at test.c:12
12 func (&var);
hello world
(gdb)
So we can see that GDB can handle read watchpoints better than just reporting a SIGTRAP, so I suspect the problem here is openocd reporting that the stop is due to a SIGTRAP, rather than being due to a read watchpoint triggering.
You might be able to work around this problem by making use of the Python API, there is a gdb.StopEvent, you could catch these and then try printing out the variables you are interested in maybe? The following Python code, placed into a file and then sourced into GDB should do the job:
def stop_handler (event):
if (type (event) == gdb.SignalEvent
and event.stop_signal == 'SIGTRAP'):
print ("Use gdb.execute to run arbitrary commands here!")
gdb.events.stop.connect (stop_handler)

How to break in gdb based on array contents?

I am trying to place a conditional breakpoint on a function that would check the contents of an array. My idea was to use memcmp() in the condition:
typedef struct {
uint8_t arr[4];
} arg_t;
Then in gdb (declaring an array inline):
b func() if memcmp(arg.arr, (uint8_t[]){1, 2, 3, 4}, sizeof(arg.arr)) == 0
However, this does not work:
(gdb) c
Continuing.
Error in testing breakpoint condition:
Too many array elements
I can do it with if arg.arr[0] == 1 && arg.arr[1] == 2 && ... but in my real case access to the array (containing an IPv6 address) is rather convoluted, so it becomes unwieldy rather quickly.
UPDATE: After Mark's comment, I tried the following test program:
#include <stdio.h>
#include <stdint.h>
#include <string.h>
int main(void) {
uint8_t a[] = { 1, 2, 3, 4 };
printf("memcmp returns %d\n", memcmp(a, (uint8_t[4]){1,2,3,4}, sizeof(a)));
return 0;
}
After compiling it, I placed a conditional break on the return using the explicit array size syntax, and it worked but it does not seem to stop as expected:
(gdb) br hello.c:8 if memcmp(a, (uint8_t[4]){1,2,3,4}, sizeof(a)) == 0
Breakpoint 1 at 0x75c: file hello.c, line 8.
(gdb) run
Starting program: /mnt/c/stuff/src/test/hello
memcmp returns 0
[Inferior 1 (process 153) exited normally]
I was trying to evaluate the return value of the function at the break site manually:
(gdb) br hello.c:8
Note: breakpoint 1 also set at pc 0x800075c.
Breakpoint 2 at 0x800075c: file hello.c, line 8.
(gdb) dele 1
(gdb) run
Starting program: /mnt/c/stuff/src/test/hello
memcmp returns 0
Breakpoint 2, main () at hello.c:8
8 return 0;
(gdb) p memcmp(a, (uint8_t[4]){1,2,3,4}, sizeof(a))
$1 = (int (*)(const void *, const void *, size_t)) 0x7fffff18aba0 <__memcmp_avx2_movbe>
I was surprised to see this, I suspect this may be due to memcmp() being a compiler intrinsic to the avx2 instruction, in which case I might need to cast it somehow?
This may not be what you want, but for complex tests, I get the program to help gdb by adding some check routines.
Method 1:
I create a void checkon (void) { if (expr_to_stop_on) badnews(); }
And then have: void badnews { stopme = 1; }
I then instrument the code with calls to checkon
I then tell gdb to do b badnews.
Method 2:
An alternative may be to create: int checkfail(void) { return expr_to_stop_on; }
Then, tell gdb to watch myarray.
This creates a watchpoint (using H/W assist). The watchpoint is like a breakpoint.
You can then do: cond 1 checkfail()
Method 3:
Similar to method 2, but instead of a watchpoint, use a tracepoint [with the same cond command (Actually, you may need to use actions instead).
This essentially single steps the program and allows a set of commands to be executed at every tracepoint.
This can be slow because every line has to do these things.
I think method 2 is probably the best bet.
(Posting my own answer to be able to close this, but credit goes to #mark-plotnick)
It works with the gdb builtin $_memeq instead of using memcmp - suspecting because of the latter not being a real function in my environment but YMMV:
(gdb) br arrbreak.c:8 if $_memeq(a, (uint8_t[4]){1,2,3,4}, sizeof(a))
Breakpoint 2 at 0x800075c: file arrbreak.c, line 8.
(gdb) run
Starting program: /mnt/c/stuff/src/test/arrbreak
memcmp returns 0
Breakpoint 2, main () at arrbreak.c:8
8 return 0;
(gdb) p $_memeq(a, (uint8_t[4]){1,2,3,4}, sizeof(a))
$1 = 1
(gdb) p $_memeq(a, (uint8_t[4]){1,2,3,5}, sizeof(a))
$2 = 0
(gdb)

gdb watchpoint won't work when variable changes from going off end of array

#include <stdio.h>
typedef struct ThingStruct {
int arr[8];
int after;
} Thing;
void foo(int i) {
Thing thing;
int* ip = &thing.after;
thing.after = 12345;
printf("beforehand\n");
thing.arr[i] = 55;
printf("done\n");
}
int main() {
foo(8);
}
This code changes thing.after by accidentally going off the end of the array. I want to try to find the line where where thing.after is changing by using gdb. So I compile with -g , put a breakpoint on line 12, then put a watchpoint on thing.after, but the watchpoint doesn't trigger, even though putting a breakpoint on line 14 does show that thing.after did change.
I even tried taking the address of thing.after and setting a watchpoint on that, but it still does not trigger.
Watch point needs to be re-added each time the foo function is entered (Note that, as you are watching the local variable, it will not be valid after the stack frame exits and will be automatically deleted after the foo returns). Also, if the watched variable changes on the current line to be executed, then the watch point is not getting triggered (not sure why). For me it works when I add the watch point watch thing.after just after entering foo when on line int* ip = &thing.after;. When I continue, the watch point hits 2 times.
You didn't say which platform, what version of GDB, or what command you used to set the watchpoint.
Using gdb 7.9 on Ubuntu/x86_64, things work as I expect them to work:
(gdb) b foo
Breakpoint 1 at 0x400538: file t.c, line 10.
(gdb) r
Starting program: /tmp/a.out
Breakpoint 1, foo (i=8) at t.c:10
10 int* ip = &thing.after;
(gdb) watch thing.after
Hardware watchpoint 2: thing.after
(gdb) c
Continuing.
Hardware watchpoint 2: thing.after
Old value = 4195712
New value = 12345
foo (i=8) at t.c:12
12 printf("beforehand\n");
(gdb) c
Continuing.
beforehand
Hardware watchpoint 2: thing.after
Old value = 12345
New value = 55
foo (i=8) at t.c:14
14 printf("done\n");
(gdb) q

segmentation fault invalid memory 0x0

I have an issue with my pointer to a structure variable. I just started using GDB to debug the issue. The application stops when it hits on the line of code below due to segmentation fault. ptr_var is a pointer to a structure
ptr_var->page = 0;
I discovered that ptr_var is set to an invalid memory 0x0 after a series of function calls which caused the segmentation fault when assigning the value "0" to struct member "page". The series of function calls does not have a reference to ptr_var. The old address that used to be assigned to ptr_var is still in memory. I can still still print the values of members from the struct ptr_var using the old address. GDB session below shows that I am printing a string member of the struct ptr_var using its address
(gdb) x /s *0x7e11c0
0x7e0810: "Sample String"
I couldn't tell when the variable ptr_var gets assigned an invalid address 0x0. I'm a newbie to GDB and an average C programmer. Your assistance in this matter is greatly appreciated. Thank you.
What you want to do is set a watchpoint, GDB will then stop execution every time a member of a struct is modified.
With the following example code
typedef struct {
int val;
} Foo;
int main(void) {
Foo foo;
foo.val = 5;
foo.val = 10;
}
Drop a breakpoint at the creation of the struct and execute watch -l foo.val Then every time that member is changed you will get a break. The following is my GDB session, with my input
(gdb) break test.c:8
Breakpoint 3 at 0x4006f9: file test.c, line 8.
(gdb) run
Starting program: /usr/home/sean/a.out
Breakpoint 3, main () at test.c:9
9 foo.val = 5;
(gdb) watch -l foo.val
Hardware watchpoint 4: -location foo.val
(gdb) cont
Continuing.
Hardware watchpoint 4: -location foo.val
Old value = 0
New value = 5
main () at test.c:10
(gdb) cont
Continuing.
Hardware watchpoint 4: -location foo.val
Old value = 5
New value = 10
main () at test.c:11
(gdb) cont
If you can rerun, then break at a point where ptr_var is correct you can set a watch point on ptr_var like this: (gdb) watch ptr_var. Now when you continue every time ptr_var is modified gdb should stop.
Here's an example. This does contain undefined behaviour, as I'm trying to reproduce a bug, but hopefully it should be good enough to show you what I'm suggesting:
#include <stdio.h>
#include <stdint.h>
int target1;
int target2;
void
bad_func (int **bar)
{
/* Set contents of bar. */
uintptr_t ptr = (uintptr_t) bar;
printf ("Should clear %p\n", (void *) ptr);
ptr += sizeof (int *);
printf ("Will clear %p\n", (void *) ptr);
/* Bad! We just corrupted foo (maybe). */
*((int **) ptr) = NULL;
}
int
main ()
{
int *foo = &target1;
int *bar = &target2;
printf ("&foo = %p\n", (void *) &foo);
printf ("&boo = %p\n", (void *) &bar);
bad_func (&bar);
return *foo;
}
And here's a gdb session:
(gdb) break bad_func
Breakpoint 1 at 0x400542: file watch.c, line 11.
(gdb) r
&foo = 0x7fffffffdb88
&boo = 0x7fffffffdb80
Breakpoint 1, bad_func (bar=0x7fffffffdb80) at watch.c:11
11 uintptr_t ptr = (uintptr_t) bar;
(gdb) up
#1 0x00000000004005d9 in main () at watch.c:27
27 bad_func (&bar);
(gdb) watch foo
Hardware watchpoint 2: foo
(gdb) c
Continuing.
Should clear 0x7fffffffdb80
Will clear 0x7fffffffdb88
Hardware watchpoint 2: foo
Old value = (int *) 0x60103c <target1>
New value = (int *) 0x0
bad_func (bar=0x7fffffffdb80) at watch.c:18
18 }
(gdb)
For some reason the watchpoint appears to trigger on the line after the change was made, even though I compiled this with -O0, which is a bit of a shame. Still, it's usually close enough to help identify the problem.
For such kind of problems I often use the old electric fence library, it can be used to find bug in "software that overruns the boundaries of a malloc() memory allocation". You will find all the instructions and basic usage at this page:
http://elinux.org/Electric_Fence
(At the very end of the page linked above you will find the download link)

How to modify memory contents using GDB?

I know that we can use several commands to access and read memory: for example, print, p, x...
But how can I change the contents of memory at any specific location (while debugging in GDB)?
The easiest is setting a program variable (see GDB: assignment):
(gdb) l
6 {
7 int i;
8 struct file *f, *ftmp;
9
(gdb) set variable i = 10
(gdb) p i
$1 = 10
Or you can just update arbitrary (writable) location by address:
(gdb) set {int}0x83040 = 4
There's more. Read the manual.
As Nikolai has said you can use the gdb 'set' command to change the value of a variable.
You can also use the 'set' command to change memory locations.
eg. Expanding on Nikolai's example:
(gdb) l
6 {
7 int i;
8 struct file *f, *ftmp;
9
(gdb) set variable i = 10
(gdb) p i
$1 = 10
(gdb) p &i
$2 = (int *) 0xbfbb0000
(gdb) set *((int *) 0xbfbb0000) = 20
(gdb) p i
$3 = 20
This should work for any valid pointer, and can be cast to any appropriate data type.
Expanding on the answers provided here.
You can just do set idx = 1 to set a variable, but that syntax is not recommended because the variable name may clash with a set sub-command. As an example set w=1 would not be valid.
This means that you should prefer the syntax: set variable idx = 1 or set var idx = 1.
Last but not least, you can just use your trusty old print command, since it evaluates an expression. The only difference being that he also prints the result of the expression.
(gdb) p idx = 1
$1 = 1
You can read more about gdb here.
Writing memory:
(gdb) set *0x20001234 = 0xABABABAB
Reading memory:
(gdb) x 0x20001234
0x20001234: 0xabababab
One of the most useful things is to change the value of Registers directly.
0x000000000800088e <+67>: lea rdi,[rip+0x118] # 0x80009ad
To change the value of rdi register:
set $rdi = 0x8201010

Resources