TJ Seabrooks
TJ Seabrooks

Reputation: 20733

Can I set a breakpoint on 'memory access' in GDB?

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.

Upvotes: 282

Views: 220575

Answers (6)

Singh
Singh

Reputation: 95

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.

Upvotes: 1

Paolo M
Paolo M

Reputation: 12777

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.

Upvotes: 51

higgs241
higgs241

Reputation: 629

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.

Upvotes: 2

Smirnov
Smirnov

Reputation: 284

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.

Upvotes: 25

asksol
asksol

Reputation: 19479

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.

Upvotes: 330

mweerden
mweerden

Reputation: 14051

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.

Upvotes: 9

Related Questions