How to use GDB inside giant loops - c

I have the following loop and my code breaks but I don't know at which iteration it breaks exactly.
int n=1000;
for (i=0; i<n; i++) {
slot = random() % max_allocs;
doAlloc = random() % 4;
doWrite = writeData;
if (!doAlloc || ptr[slot] != NULL) {
if (ptr[slot] == NULL)
;//assert(Mem_Free(ptr[slot]) == -1);
else
{
printf("I got here \n");
printf("mem free ptr slot is %d \n",Mem_Free(ptr[slot]));
}
free(shadow[slot]);
ptr[slot] = NULL;
shadow[slot] = NULL;
}
if (doAlloc) {
size[slot] = min_alloc_size +
(random() % (max_alloc_size - min_alloc_size + 1));
printf("size[slot] :%d\n", size[slot]);
ptr[slot] = Mem_Alloc(size[slot], BESTFIT);
printf("ptr slot is %p \n",ptr[slot]);
assert(ptr[slot] != NULL);
if (doWrite) {
shadow[slot] = malloc(size[slot]);
int j;
for (j=0; j<size[slot]; j++) {
char data = random();
*((char*)(ptr[slot] + j)) = data;
*((char*)(shadow[slot] + j)) = data;
}
}
}
}
How can I find at which iteration of n the code breaks and how can I put a breakpoint at that iteration?
P.S.: Is there any other better debugger for this purpose in Linux? (If I don't want to use Eclipse!)
Here's the error I am receiving in gdb:
mymain: mymain.c:104: main: Assertion `ptr[slot] != ((void *)0)' failed.
Program received signal SIGABRT, Aborted.
0x000000368da328e5 in raise (sig=6) at ../nptl/sysdeps/unix/sysv/linux/raise.c:64
64 return INLINE_SYSCALL (tgkill, 3, pid, selftid, sig);
(gdb) backtrace
#0 0x000000368da328e5 in raise (sig=6) at ../nptl/sysdeps/unix/sysv/linux/raise.c:64
#1 0x000000368da340c5 in abort () at abort.c:92
#2 0x000000368da2ba0e in __assert_fail_base (fmt=<value optimized out>, assertion=0x40114b "ptr[slot] != ((void *)0)", file=0x401142 "mymain.c", line=<value optimized out>, function=<value optimized out>)
at assert.c:96
#3 0x000000368da2bad0 in __assert_fail (assertion=0x40114b "ptr[slot] != ((void *)0)", file=0x401142 "mymain.c", line=104, function=0x401199 "main") at assert.c:105
#4 0x0000000000400e2a in main (argc=4, argv=0x7fffffffdb68) at mymain.c:104
(gdb) frame 1
#1 0x000000368da340c5 in abort () at abort.c:92
92 raise (SIGABRT);
(gdb) frame 3
#3 0x000000368da2bad0 in __assert_fail (assertion=0x40114b "ptr[slot] != ((void *)0)", file=0x401142 "mymain.c", line=104, function=0x401199 "main") at assert.c:105
105 __assert_fail_base (_("%s%s%s:%u: %s%sAssertion `%s' failed.\n%n"),

How do you know the code is "breaking" in the first place? Usually it's because some variable suddenly takes on a value you don't expect. In this case, you can set a watchpoint rather than a breakpoint, and it'll break when and only when that variable goes outside of expectations.
For instance, with this program:
#include <stdio.h>
int main(void) {
int b = 0;
for ( int i = 0; i < 20; ++i ) {
b += 5;
}
return 0;
}
we can get gdb to stop when b hits or exceeds a certain value, and find out on exactly which iteration of the loop it occurred:
paul#local:~/src/c/scratch$ gdb testwatch
GNU gdb (GDB) 7.4.1-debian
Copyright (C) 2012 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law. Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-linux-gnu".
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>...
Reading symbols from /home/paul/src/c/scratch/testwatch...done.
(gdb) list
1 #include <stdio.h>
2
3 int main(void) {
4 int b = 0;
5 for ( int i = 0; i < 20; ++i ) {
6 b += 5;
7 }
8 return 0;
9 }
(gdb) break 5
Breakpoint 1 at 0x400567: file testwatch.c, line 5.
(gdb) run
Starting program: /home/paul/src/c/scratch/testwatch
Breakpoint 1, main () at testwatch.c:5
5 for ( int i = 0; i < 20; ++i ) {
(gdb) watch b > 20
Hardware watchpoint 2: b > 20
(gdb) continue
Continuing.
Hardware watchpoint 2: b > 20
Old value = 0
New value = 1
main () at testwatch.c:5
5 for ( int i = 0; i < 20; ++i ) {
(gdb) print b
$1 = 25
(gdb) print i
$2 = 4
(gdb)
Here we can tell that b went above 20 when i was 4, i.e. on the fifth iteration of the loop. You can watch for whole expressions, such as watch b > 20 && i > 10, to look for combinations of values that you don't expect to be simultaneously true. gdb is pretty powerful when you get into it.
You can watch for a variable becoming a particular value, or a pointer becoming NULL, or a range counter going past the last element of your array, or whatever other condition is resulting in your code being broken. Once it stops, you'll know exactly the point at which your error occurs, and you can poke around looking at other variables to figure out what's going wrong.
In general, a debugger wouldn't be all that useful if you had to know where and when an error was occurring before you could use it.
EDIT: Since updating your post, in your particular case, you can just use backtrace and get right to the iteration, e.g.
paul#local:~/src/c/scratch$ gdb segfault
GNU gdb (GDB) 7.4.1-debian
Copyright (C) 2012 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law. Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-linux-gnu".
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>...
Reading symbols from /home/paul/src/c/scratch/segfault...done.
(gdb) list 1,16
1 #include <stdlib.h>
2
3 void segfault(int * p) {
4 int n = *p;
5 }
6
7 int main(void) {
8 int n = 0;
9 int * parray[] = {&n, &n, &n, &n, NULL};
10
11 for ( int i = 0; i < 10; ++i ) {
12 segfault(parray[i]);
13 }
14
15 return 0;
16 }
(gdb) run
Starting program: /home/paul/src/c/scratch/segfault
Program received signal SIGSEGV, Segmentation fault.
0x0000000000400568 in segfault (p=0x0) at segfault.c:4
4 int n = *p;
(gdb) backtrace
#0 0x0000000000400568 in segfault (p=0x0) at segfault.c:4
#1 0x00000000004005c1 in main () at segfault.c:12
(gdb) frame 1
#1 0x00000000004005c1 in main () at segfault.c:12
12 segfault(parray[i]);
(gdb) print i
$1 = 4
(gdb)
In your case, you'd go to whatever frame corresponds to the function your loop is in, and just do print i to get the loop index.

take a look at this: GDB Tutorial.
You can use break (to set a breakpoint) and continue / next to do what you want:
Don't forget to compile with -g option: gcc -g source.c
gdb ./a.out
break linenumber
continue or next (to proceed to the next breakpoint)
print variable (to print the value of variable)
Hope it helps.

From gdb's documentation 5.1.7 "Breakpoint Command Lists":
You can give any breakpoint (or watchpoint or catchpoint) a series of commands to execute when your program stops due to that breakpoint. For example, you might want to print the values of certain expressions, or enable other breakpoints.
So you can set a breakpoint in the loop that displays the iteration value, i, each time it is hit. That way when you crash you can see the last value printed:
break <line number just after start of the loop>
commands
silent
printf "i == %d\n", i
continue
end
Of course there are other (probably more efficient) ways of debugging this problem, but the technique of using a breakpoint to display information or perform other scripted actions then continue running is a valuable thing to have in your debugging toolbox.

If I want to set a breakpoint at line 94 when I am in the 500th iteration I should do it like this:
b 94 if i=500
generally you would say:
break line_number if condition

You seem to be hung up on finding the iteration on which it breaks, but the answer from nos, above, clearly states how to do this.
Run your program in GDB, wait for the code to crash (at which point GDB will grab it), and then work out which iteration it's crashed in by printing the value of the index variable using print i at the GDB prompt.
Edit: Ok, I think I understand. When you say the code "breaks", you mean it's breaking in such a way that allows it to continue to be executed: it's not crashing, and GDB isn't automatically catching it.
In this case, there's no way to determine where to set the breakpoint you want. You simply don't know when the problem is occurring. How are you determining that the program is breaking? Are there any variables you could print the value of to show when the breakage occurs? If so, you could have GDB print the values during each iteration (rather than writing debug directly into the code).
You can do this using the commands option. There's an example of how to do this in this thread.
On each iteration print the value of i and also the value of whichever variable you're using to track the breakage. This should then give you the iteration on which the breakage occurs, and you can go back and set a breakpoint in the right place.

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)

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

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.

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)

GDB: break if variable equal value

I like to make GDB set a break point when a variable equal some value I set, I tried this example:
#include <stdio.h>
main()
{
int i = 0;
for(i=0;i<7;++i)
printf("%d\n", i);
return 0;
}
Output from GDB:
(gdb) break if ((int)i == 5)
No default breakpoint address now.
(gdb) run
Starting program: /home/SIFE/run
0
1
2
3
4
5
6
Program exited normally.
(gdb)
Like you see, GDB didn't make any break point, is this possible with GDB?
in addition to a watchpoint nested inside a breakpoint
you can also set a single breakpoint on the 'filename:line_number' and use a condition.
I find it sometimes easier.
(gdb) break iter.c:6 if i == 5
Breakpoint 2 at 0x4004dc: file iter.c, line 6.
(gdb) c
Continuing.
0
1
2
3
4
Breakpoint 2, main () at iter.c:6
6 printf("%d\n", i);
If like me you get tired of line numbers changing, you can add a label
then set the breakpoint on the label like so:
#include <stdio.h>
main()
{
int i = 0;
for(i=0;i<7;++i) {
looping:
printf("%d\n", i);
}
return 0;
}
(gdb) break main:looping if i == 5
You can use a watchpoint for this (A breakpoint on data instead of code).
You can start by using watch i.
Then set a condition for it using condition <breakpoint num> i == 5
You can get the breakpoint number by using info watch
First, you need to compile your code with appropriate flags, enabling debug into code.
$ gcc -Wall -g -ggdb -o ex1 ex1.c
then just run you code with your favourite debugger
$ gdb ./ex1
show me the code.
(gdb) list
1 #include <stdio.h>
2 int main(void)
3 {
4 int i = 0;
5 for(i=0;i<7;++i)
6 printf("%d\n", i);
7
8 return 0;
9 }
break on lines 5 and looks if i == 5.
(gdb) b 5
Breakpoint 1 at 0x4004fb: file ex1.c, line 5.
(gdb) rwatch i if i==5
Hardware read watchpoint 5: i
checking breakpoints
(gdb) info b
Num Type Disp Enb Address What
1 breakpoint keep y 0x00000000004004fb in main at ex1.c:5
breakpoint already hit 1 time
5 read watchpoint keep y i
stop only if i==5
running the program
(gdb) c
Continuing.
0
1
2
3
4
Hardware read watchpoint 5: i
Value = 5
0x0000000000400523 in main () at ex1.c:5
5 for(i=0;i<7;++i)
There are hardware and software watchpoints. They are for reading and for writing a variable. You need to consult a tutorial:
http://www.unknownroad.com/rtfm/gdbtut/gdbwatch.html
To set a watchpoint, first you need to break the code into a place where the varianle i is present in the environment, and set the watchpoint.
watch command is used to set a watchpoit for writing, while rwatch for reading, and awatch for reading/writing.

Resources