gdb: break when a particular object is altered - c++

I have an object defined in c++ with a pointer to it used in various functions and files throughout the project. I am having an issue with the data being updated, so I want to debug it to see what is happening. Ideally, I want to break every time the object is accessed. however, watch requires a specific memory address. So, for example, if I have:
class data{
public:
int a;
int b;
};
then gdb will only break when a is altered, since the pointer to data is pointed at a, but not when b is altered.
Is there a way to break whenever the entire range of memory covered by the data class is altered?

Is there a way to break whenever the entire range of memory covered by the data class is altered?
Perhaps.
GDB hardware watchpoints use special debug registers in hardware, and there is usually a limit on how such registers work. On x86, you can set up to 4 word-sized hardware watch points, so for example you gave you can set watchpoints on &data->a and &data->b, and that will "cover" entire memory of the data.
I am guessing that your actual data has many more members though, and so 4 word-sized watch points will not suffice.
If you are on platform which has Valgrind support, and if your program can execute under Valgrind, then you can use Valgrind's built-in gdbserver to set watchpoints on arbitrary regions of memory.
Update:
I looked through the page you linked to and couldn't find what I was looking for
I am not sure what you were looking for. Here is a sample session showing how it works:
#include <stdlib.h>
void foo(char *p)
{
*p = 'a';
}
typedef struct {
char buf[1024];
} data;
int main()
{
data *d = calloc(1, sizeof(data));
foo(d->buf + 999);
}
gcc -g main.c
valgrind --vgdb-error=0 ./a.out
...
==10345== TO DEBUG THIS PROCESS USING GDB: start GDB like this
==10345== /path/to/gdb ./a.out
==10345== and then give GDB the following command
==10345== target remote | vgdb --pid=10345
... Valgrind now waits for debugger to attach.
In another window:
gdb ./a.out
GNU gdb (GDB) 7.4
...
(gdb) target remote | vgdb --pid=10345
relaying data between gdb and process 10345
[Switching to Thread 10345]
0x0000000004000af0 in _start () from /lib64/ld-linux-x86-64.so.2
(gdb) b main
Breakpoint 1 at 0x40053d: file main.c, line 14.
(gdb) c
Breakpoint 1, main () at main.c:14
14 data *d = calloc(1, sizeof(data));
(gdb) n
15 foo(d->buf + 999);
(gdb) watch *d
Hardware watchpoint 2: *d
Note that a "hardware" watchpoint has been set on entire *d.
It's a hardware watchpoint only in the sense that Valgrind is the hardware.
(gdb) p d.buf[999]
$1 = 0 '\000'
(gdb) c
Hardware watchpoint 2: *d
Old value = {buf = '\000' <repeats 1023 times>}
New value = {buf = '\000' <repeats 999 times>, "a", '\000' <repeats 23 times>}
foo (p=0x51b6457 "a") at main.c:6
6 }
(gdb) q
Voila: the debugger stopped when 999th element was modified, proving that the watchpoint "covered" the entire structure.

Related

Continue debugging after SegFault in GDB?

I am debugging a huge program using GDB and there is a SegFault in my program.
Instead of re-running the program, is it possible to switch to a previous stack frame and continue execution from there?
On Unix and Linux systems, at least, you can use gdb's handle command to tell gdb to stop the program when a signal is received (with the stop keyword) and not to pass the signal to the program (with the nopass keyword). When the program stops, you can use the return command to return a value from the current frame, then continue the program.
$ gdb -q segvtest
Reading symbols from segvtest...done.
(gdb) list 1,99999
1 #include <stdio.h>
2
3 int a()
4 {
5 int *p = 0;
6 return *p;
7 }
8
9 int main()
10 {
11 int i = a();
12 printf("a() returned %d\n", i);
13 }
(gdb) handle SIGSEGV stop nopass
Signal Stop Print Pass to program Description
SIGSEGV Yes Yes No Segmentation fault
(gdb) run
Starting program: /home/mp/segvtest
Program received signal SIGSEGV, Segmentation fault.
0x00000000080006c0 in a () at segvtest.c:6
6 return *p;
(gdb) return 12345
Make a return now? (y or n) y
#0 0x00000000080006d6 in main () at segvtest.c:11
11 int i = a();
(gdb) c
Continuing.
a() returned 12345
[Inferior 1 (process 74) exited normally]
(gdb)
is it possible to switch to a previous stack frame and continue
execution from there?
Yes, you can do it with reverse debugging.
When you get segfault, run reverse-finish to go out of the current frame in reverse direction. You will stop in the previous frame where you are about to call the function that caused a segfault.

Access old stack frames

If I'm understanding this right, each time you call a C++ function, SP (and possibly BP) get moved to allocate some temporary space on the stack — a stack frame. And when the function returns, the pointers get moved back, deallocating the stack frame again.
But it appears to me that the data on the old stack frame is still there, it's just not referenced any more. Is there some way to make GDB show me these deleted stack frames? (Obviously once you enter a new stack frame it will at least partially overwrite any previous ones... but until then it seems like it should be possible.)
But it appears to me that the data on the old stack frame is still there, it's just not referenced any more.
Correct.
Is there some way to make GDB show me these deleted stack frames?
You can trivially look at the unused stack with GDB examine command. For example:
void fn()
{
int x[100];
for (int j = 0; j < 100; j++) x[j] = (0x1234 << 12) + j;
}
int main()
{
fn();
return 0;
}
Build and debug with:
gcc -g t.c
gdb -q ./a.out
(gdb) start
Temporary breakpoint 1 at 0x115f: file t.c, line 10.
Starting program: /tmp/a.out
Temporary breakpoint 1, main () at t.c:10
10 fn();
(gdb) n
11 return 0;
(gdb) x/40x $rsp-0x40
0x7fffffffdc60: 0x0123405c 0x0123405d 0x0123405e 0x0123405f
0x7fffffffdc70: 0x01234060 0x01234061 0x01234062 0x01234063
0x7fffffffdc80: 0x55555170 0x00005555 0x55555040 0x00000064
0x7fffffffdc90: 0xffffdca0 0x00007fff 0x55555169 0x00005555
0x7fffffffdca0: 0x55555170 0x00005555 0xf7a3a52b 0x00007fff
0x7fffffffdcb0: 0x00000000 0x00000000 0xffffdd88 0x00007fff
0x7fffffffdcc0: 0x00080000 0x00000001 0x5555515b 0x00005555
0x7fffffffdcd0: 0x00000000 0x00000000 0xa91c6994 0xc8f4292d
0x7fffffffdce0: 0x55555040 0x00005555 0xffffdd80 0x00007fff
0x7fffffffdcf0: 0x00000000 0x00000000 0x00000000 0x00000000
Here you can clearly see x still on stack: 0x7fffffffdc60 is where x[92] used to be, 0x7fffffffdc70 is where x[96] used to be, etc.
There is no easy way to make GDB interpret that data as locals of fn though.
Stackframes do not contain any information about its size or boundaries, rather this knowledge is hardcoded into functions' code. There is a (stack) frame pointer register, using which makes it possible to walk the stack up, but not down. In the current function you know the boundaries of the current frame, but there is no information of what could possibly be below it.

Find the variable change in GDB

I am working in a project where there are more than 100 files of source code. I am debugging it for find an error.
What I need to find is the time when a particular object assigned to a value. ie. This object is NULL at first, but some other file changes its value, which I don't know.
Are there any method to find when this variable changes its value ?
What I tried upto now is to put a breakpoint on the function where the variable is initilized. I also added a watchpoint. But it does not show any point where the value is changing.
But it does not show any point where the value is changing.
There are two possible explanations:
You've set the watchpoint incorrectly, or
The value changes while the process is in kernel mode (GDB watchpoints are not effective for detecting such change).
Example:
#include <unistd.h>
int global_a;
int global_b;
int foo()
{
global_a = 42;
read(0, &global_b, 1);
return global_a + global_b;
}
int main()
{
return foo();
}
gcc -g -Wall t.c
gdb -q ./a.out
(gdb) start
Temporary breakpoint 1 at 0x400563: file t.c, line 16.
Starting program: /tmp/a.out
Temporary breakpoint 1, main () at t.c:16
16 return foo();
(gdb) watch global_a
Hardware watchpoint 2: global_a
(gdb) watch global_b
Hardware watchpoint 3: global_b
(gdb) c
Continuing.
Hardware watchpoint 2: global_a
Old value = 0
New value = 42
This is a modification of global_a in user-space (via direct assignment), and it triggers watchpoint 2 as expected
foo () at t.c:9
9 read(0, &global_b, 1);
(gdb) c
Continuing.
# Press Enter here
This read 0xA == 10 into global_b.
[Inferior 1 (process 126196) exited with code 064]
Note that the exit code is 064 == 52 == 42+10, but the watchpoint 3 did not fire.
any method to find when this variable changes its value
If you are sure that your "normal" watchpoints are working (e.g. by running above test yourself) and suspect that the variable is being changed via a system call, you can:
Print the address of the variable and
Run your program under strace and look for system calls that could change the value at variable's address.
Using the same example:
(gdb) p &global_b
$1 = (int *) 0x601044 <global_b>
strace -e raw=all ./a.out < /dev/zero
execve(0x7ffe1853e530, 0x7ffe1853f920, 0x7ffe1853f930) = 0
brk(0) = 0x2253000
access(0x7fa66eee48c3, 0) = -1 (errno 2)
mmap(0, 0x2000, 0x3, 0x22, 0xffffffff, 0) = 0x7fa66f0e8000
...
munmap(0x7f57ece26000, 0x203a2) = 0
read(0, 0x601044, 0x1) = 0x1 ### &global_b is "covered" by the buffer being read into
exit_group(42) = ?
+++ exited with 42 +++

Where to put HW BP to catch the global variable address corruption?

Program in C/C++ runs on embedded PowerPC under debugger with HW break points capabilities.
There is global variable 'char Name[256]' known in 2 files and 2 tasks correspondingly. One task reads Name, another fills it with a text, '1234567...', for example.
At some moment, global variable Name gets corrupted. When asked for the variable address gdb shows (and application prints by debug printouts) address equal to 0x31323334.
How to catch this bug with HW breakpoints? I mean at what address to put HWBP.
When I look into assembler, I see:
lis 9,Name#ha
lwz 9,Namel#l(9)
So, how memory corruption can change the code without influencing the application flow - it should crash immediately, no?
Thanks a lot ahead
0x31323334 is "1234" sans null terminator. Further, "Global variable address corruption" does not make much sense "global variables" (whose addresses do not change), nor really for an array of size 256 (unless you're using a pointer somewhere and it's the pointer which is being corrupted). So I suspect you might be unfamiliar with GDB.
When using GNU gdb (Ubuntu 7.7.1-0ubuntu5~14.04.2) 7.7.1 on x86 (admittedly, not ppc, but basically the same software) with the following test file:
// g++ test.cpp -g
#include <iostream>
char Name[256] = "123456789";
int main() {
Name[0] = 'a';
std::cout << Name << std::endl;
}
I can get the following output from GDB:
(gdb) break main
Breakpoint 2 at 0x40086a: file test.cpp, line 6.
(gdb) r
Starting program: /home/keithb/dev/mytest/a.out
Breakpoint 2, main () at test.cpp:6
6 Name[0] = 'a';
(gdb) whatis Name
type = char [256]
(gdb) print Name
$1 = "123456789", '\000' <repeats 246 times>
(gdb) print &Name
$2 = (char (*)[256]) 0x6010c0 <Name>
In any case, if you really do want to set a "hardware breakpoint" (GDB calls those "watchpoints"), then you can do get the address of Name prior to corruption. Then just set the watchpoint and wait for your program to write to the address.
(gdb) c
Continuing.
a23456789
[Inferior 1 (process 21878) exited normally]
(gdb) delete 2
(gdb) watch *0x6010c0
Hardware watchpoint 3: *0x6010c0
(gdb) r
Starting program: /home/keithb/dev/mytest/a.out
Hardware watchpoint 3: *0x6010c0
Old value = 875770417
New value = 875770465
main () at test.cpp:7
7 std::cout << Name << std::endl;
(gdb)

sizeof reference to array in gdb

int main()
{
typedef unsigned char a4[4];
a4 p1;
a4& p2 = p1;
p2[1]=1;
cout<<sizeof(p2);
return p2[1];
}
Compile, start gdb and put breakpoint on return. If you type p sizeof(p2), gdb will print 8 instead of 4 which will be printed if you start the program. If you write in gdb p sizeof(*p2), the output is 4 (the size of array). I think this is because gdb treats p2 as pointer(reference is implemented behind the scene as pointer).
Tested with compilers GCC 4.8.2 and Clang 4.3 on GDB 7.7 linux arch., ubuntu 13.10,
Is this correct or a bug in gdb?
Here's a modified version of your program. I've changed the array size from 4 to 17 to ensure that its size is distinguishable from anything else. I've also changed the type and variable names to make the code easier to follow, and added #include <iostream> so it actually compiles. I've also removed some unnecessary stuff.
#include <iostream>
int main()
{
typedef unsigned char char17[17];
char17 arr17;
char17& arr17_ref = arr17;
std::cout << "sizeof(arr17) = "
<< sizeof arr17
<< ", sizeof(arr17_ref) = "
<< sizeof(arr17_ref)
<< "\n";
return 0;
}
When I compile and run it on my system, the output is 17.
When I run it under gdb, I get 8 (the size of a pointer on my system):
$ gdb ./c
GNU gdb (GDB) 7.5-ubuntu
[snip]
Reading symbols from /home/kst/c...done.
(gdb) b 12
Breakpoint 1 at 0x40097e: file c.cpp, line 12.
(gdb) r
Starting program: /home/kst/c
sizeof(arr17) = 17, sizeof(arr17_ref) = 17
Breakpoint 1, main () at c.cpp:12
12 return 0;
(gdb) p sizeof(arr17)
$1 = 17
(gdb) p sizeof(arr17_ref)
$2 = 8
(gdb) c
Continuing.
[Inferior 1 (process 23420) exited normally]
(gdb) q
$
Yes, this is a bug in gdb. gdb is supposed to evaluate expressions as they'd be evaluated in a running program; in this case, it fails to do so.
(I'm using gcc 4.7.2 and gdb 7.5 on Linux Mint 14.)
UPDATE :
The OP submitted a bug report: https://sourceware.org/bugzilla/show_bug.cgi?id=16675
and it's been fixed. The patch was approved and committed 2014-04-14. I still see the bug in gdb 7.7.1, but it's fixed in 7.11.1.