Setting watchpoints for large data structures in lldb - c++

I am learning lldb and I am curious how you go about setting watchpoints for larger data structures for example a vector. I know that I can use print and that works but I get a message saying that watch points of size "x" are not supported. Is there a way around this? Thanks for the help!
(lldb) s
Process 36110 stopped
* thread #1, queue = 'com.apple.main-thread', stop reason = step in
frame #0: 0x0000000100001600 a.out`main at test.cpp:10
7 vector<int> arr;
8 arr.push_back(1);
9 arr.push_back(2);
-> 10 arr.push_back(3);
11 arr.push_back(4);
12 arr.push_back(5);
13
Target 0: (a.out) stopped.
(lldb) print arr
(std::__1::vector<int, std::__1::allocator<int> >) $2 = size=2 {
[0] = 1
[1] = 2
}
(lldb) w s v arr
error: Watchpoint creation failed (addr=0x7ffeefbff458, size=24, variable expression='arr').
error: watch size of 24 is not supported

If you are on a Mac, the x86_64 architecture allows 4 separate watched regions of at most 8 bytes each. At present, lldb will only use one region per watch request. It could gang multiple watch regions together to handle larger requests which would work for this structure. Feel free to file an enhancement request for this feature with http://bugs.llvm.org. But watchpoints are really limited resources, so you generally have to be very targeted about what you are trying to watch - which is probably why nobody's gotten around to supporting > 8 bytes.
If you want to stop when elements get added to or removed from the vector, it's good enough to watch the end pointer in the vector (i.e. __end_). You can see the actual guts of the vector with the --raw argument to "frame var":
(lldb) fr v --raw arr
(std::__1::vector<int, std::__1::allocator<int> >) arr = {
std::__1::__vector_base<int, std::__1::allocator<int> > = {
__begin_ = 0x0000000100400000
__end_ = 0x000000010040001c
__end_cap_ = {
std::__1::__compressed_pair_elem<int *, 0, false> = {
__value_ = 0x0000000100400038
}
}
}
}
Whenever the vector grows or shrinks, the end marker will get adjusted, so a watchpoint set with:
(lldb) watch set v arr.__end_
Watchpoint created: Watchpoint 1: addr = 0x7ffeefbff1c8 size = 8 state = enabled type = w
declare # '/tmp/vectors.cpp:6'
watchpoint spec = 'arr.__end_'
new value: 0x000000010030020c
will catch push_back, erase, etc.
If you want to stop when the vector values change, you're going to have to watch individual values; given only 32 bytes to play with you're not going to watch all the data in a vector of meaningful size. And of course when the vector resizes, your watchpoint on the old data will now be pointing to freed memory...

Related

Watching variable i in a for loop with lldb

Having just switched to lldb, I'm trying to do the equivalent of gdb's watch i being I'm inside a for loop in my code.
(lldb) f
frame #0: 0x0000000100000664 a.out`MaxPairwiseProduct(numbers=size=5) + 4 at max_pairwise_product.cpp:19 [opt]
16 // Find max value in vector
17
18 for (int i=1; i<numbers.size(); i++) {
-> 19 if (numbers[i] > numbers[i-1]) {
20 second_max = max;
21 max = numbers[i];
22 if (numbers[i] < max && numbers[i] > second_max)
(lldb)
As you can see above, int i has already been declared.
Checking which watchpoints I have yields
(lldb) watchpoint list -b
Number of supported hardware watchpoints: 4
No watchpoints currently set.
(lldb)
Now trying to set a watchpoint to i (according to the lldb reference) I get
(lldb) wa s v i
error: Watchpoint creation failed (addr=0xffffffffffffffff, size=0, variable expression='i').
error: cannot set a watchpoint with watch_size of 0
(lldb)
I don't understand why this is, being the variable has been declared. Googling the error didn't help much as most issues seem to be related with hitting the max number of watchpoints, which is not my case as can be seen above. Any help would be much appreciated!
I changed the way I was compiling the program to clang++ -Wall -g -o max_pairwise max_pairwise.cpp and it started showing me the right information, including tracking the value of i

Using gdb to decode hex data to struct

I have a hex stream of hex data that is printed like
0x3a45 0x1234 0x0352 (in real far longer)
I know that it is content in a struct. Is there a way in gdb to map this on the struct? Gdb seems only to accept single values for doing this.
Like:
(gdb) print (myStruct) 0x3a45 0x1234 0x0352
$1 = { a = 3a, b = 45, f = 0x1234, c = 03, e = 52}
In this case it's very simple but there is complex struct and the hex string is far larger.
I think there are a couple viable ways to do this in gdb.
The simplest way is to write the data into the inferior's memory somehow. It might look something like:
(gdb) set $mem = malloc(50) # number of bytes
(gdb) set $mem[0] = 0x72
(gdb) set $mem[1] = 0xff
# etc - you can find faster ways to do this
(gdb) print *(struct whatever *) $mem
Filling the memory is a pain, but this can be scripted. For example you can write a little shell script to convert the raw bytes into a sequence of set commands and then source it. Or you can just write a new gdb command in Python that automates it all.
gdb also has an extension to let one create an array on the command line, and do a kind of "reinterpret cast" on it. I found this method a bit less handy, because I could only make the array feature create arrays of int, not char. But anyhow, consider this little program:
struct x {
int a;
long b;
};
int main() {
struct x x = { 23, 97 };
return 0;
}
I start gdb and stop on the return, then examine the memory:
(gdb) p sizeof(int)
$1 = 4
(gdb) p sizeof(x)
$2 = 16
(gdb) x/4xw &x
0x7fffffffe240: 0x00000017 0x00007fff 0x00000061 0x00000000
(That second word is garbage because it is in the struct padding...)
Now we can recreate x by hand from the raw data:
(gdb) print {struct x}{0x17, 0x7fff, 0x61, 0}
$3 = {
a = 23,
b = 97
}
This expression uses two extensions to C expressions that gdb provides. First, {0x17, 0x7fff...} is a way to write an array. Second, {struct x} is a kind of "reinterpret cast" - it reinterprets the raw bytes of the value as named type.

Array of pointer not giving proper output as it suppose?

Hi i have array of two pointers int *p[2] and i am trying to store 3 address of integer lets take &i,&j,&k as below code At *p[0]
i am getting garbage why here garbage ?it should be at p[2]? At *p[1] i am getting value it is ok but At *p[2] i am getting value here i should get garbage?
#include<stdio.h>
int main()
{
int i=10,j=20,k=30;
int *p[2]; // here p is array of 2 pointers
p[0]=&i; // but here i am storing
p[1]=&j; // 3 address of variable i,j,k
p[2]=&k;
printf("p[0]=%d\n",*p[0]); // why garbage here ?
printf("p[1]=%d\n",*p[1]); // here 20
printf("p[2]=%d\n",*p[2]); // here 30 why here ?
}
printf("p[2]=%d\n",*p[2]); // here 30 why here ?
Because p has two elements, not three. You can access elements 0 and 1, but accessing 2 is undefined behavior. Any number can be printed, or your program could crash when you invoke undefined behavior.
I am getting value here i should get garbage?
30 is as good a garbage value as any other number.
**EDIT (in response to an edit of the question) When you assign p[2] = &k you write to a location that is not allocated to your program. However, if the write operation completes without a crash, the new value would stay in memory.
Since the memory to which you wrote an address of k does not belong to your program, the system may write a new value into it. However, it wouldn't do it with 100% certainty: it may not write a new value into that memory at all. This is precisely what appears to be happening in your case: the value of &k written into p[2] illegally "survives" past two invocations of printf, producing 30 as the result.
u are using int *p[2], which is an array of size 2. only p[0] and p[1] are valid. remember the index of an array in c++ starts with 0 not 1. using p[2] would end up with something strange.
you are having array of two pointers int *p[2]. But you are trying to print the next element using pointer-
printf("p[2]=%d\n",*p[2]);
It results in undefined behavior. Anything can happen. But you are getting 30 some times you may get garbage values.
For your program i am getting-
root#ubuntu:~/c/array/string# ./a.out
p[0]=10
p[1]=20
p[2]=-13543595 // note this value. Undefined Behaviour
root#ubuntu:~/c/array/string#
first of all you need
int *p[3].
secondly since you used
int *p[2]
p[2] wasn't kept aside for this array. so what was there at p[2]? in my case it was variable k.
mine was 64 bit system with 64 bit pointers.
my output
p[0]=10
p[1]=20
p[2]=32767
and look at the gdb dump especially the addresses of k and p[2]
(gdb) p p[0]
$7 = (int *) 0x7fffffffe02c
(gdb) p p[1]
$8 = (int *) 0x7fffffffe028
(gdb) p p[2]
$9 = (int *) 0x7fffffffe024
(gdb) p &i
$10 = (int *) 0x7fffffffe02c
(gdb) p &j
$11 = (int *) 0x7fffffffe028
(gdb) p &k
$12 = (int *) 0x7fffffffe024
(gdb) p &p
$14 = (int *(*)[2]) 0x7fffffffe010
(gdb) x/32 0x7fffffffe010
0x7fffffffe010: -8148 32767 -8152 32767
0x7fffffffe020: -8156 32767 20 10
in your case it must have been the address of i.

gdb - get variable name of register

In GDB, info registers or info all-registers will show you all of the register symbol names and their values.
Question:
How do I get the variable name (i.e. from the source code) that is stored in that register? (or a line number in source code, or anything)
For example:
int my_reg = /* something */;
float another_reg = /* something else */;
...
Then perhaps, info all-registers will return:
R0 0x0 0
R1 0xfffbf0 16776176
R2 0x0 0
R3 0x0 0
R4 0x6 6
How do I determine which register (R0? R2? R4?) is "associated" with my_reg?
If you have access to the debug symbols (and understand how to read them - that is, you have some code that parses the debug symbols), it is possible to trace exactly which register corresponds to which register. However, this is quite possibly changing from one line to the next, as the compiler decides to move things around for one reason or another (e.g. some calculation starts with R1, and ends up with the result in R2, because that's better than trying to retain the value in R1 [or we need the original value in R1 too - think array[x++] - now we have the new value of x, hopefully in a register, and the value of the old x that we need to use for indexing, also needed to be in a register to add to the base-address of array.
Not all variables end up in registers (depending on processor, and "what registers are available").
The debugger WILL know where each variable is at any given time - but sometimes it can be a big confused, e.g:
int array[10000];
...
for(int i = 0; i < 10000; i++)
{
array[i] = rand();
}
may translate to something like this during optimization:
int array[10000];
int *ptr = array;
int *ptr2 = &array[10000];
while(ptr < ptr2)
{
*ptr++ = rand();
}
Now try printing i... ;)
There might be one register, multiple registers, or even no registers associated with any given C variable at any given point in time. You'll have to inspect the disassembly to see what's going on.
Why not just print my_reg to see the value?
l *$pc will list the source code around the current instruction being executed.

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.
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.