How to break in gdb based on array contents? - c

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)

Related

How to use actions command in GDB tool?

Below is the code which i had used to understand actions command in gdb.
#include <stdio.h>
int Use_Action(int CatchedInt, char * CatchedStr)
{
printf("CatchedInt = %d, CatchedStr = %s\n", CatchedInt, CatchedStr);
return 0;
}
int main(void)
{
int PassingInt = 20;
char PassingStr[10] = "Hello";
Use_Action(PassingInt, PassingStr);
}
In GDB Tool I have done the following things with the help of https://sourceware.org/gdb/current/onlinedocs/gdb/Tracepoint-Actions.html
(gdb) trace Use_Action
Tracepoint 1 at 0x1169: file action.c, line 5.
(gdb) info tracepoints
Num Type Disp Enb Address What
1 tracepoint keep y 0x0000000000001169 in Use_Action at action.c:5
not installed on target
(gdb) actions
Enter actions for tracepoint 1, one per line.
End with a line saying just "end".
>collect CatchedInt
>end
(gdb) info tracepoints
Num Type Disp Enb Address What
1 tracepoint keep y 0x0000000000001169 in Use_Action at action.c:5
collect CatchedInt
not installed on target
If i had collect the value of "Catchedint" by command collect Catchedint, then how to display the value. Is there something I missed? or i understand this actions command in wrong way!!?
Is there something I missed?
Yes: you need to actually run the program while collecting the trace, using tstart, run and tstop commands.
If you tried that, you would likely get this error:
(gdb) tstart
You can't do that when your target is `exec'
That's because only some targets support tracepoints, and local execution doesn't. You'll need to use gdbserver instead.

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.

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

How to use GDB inside giant loops

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.

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