Watching variable i in a for loop with lldb - c++

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

Related

Setting watchpoints for large data structures in lldb

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

Local Variables in Dtrace

How do I access variables local to a function using dtrace?
For example, in the following snippet I would like to know the value of variable x using dtrace.
void foo(int a){
int x=some_fun(a);
}
Tracing local variables is impossible for kernel code because there is no mechanism to instrument arbitrary kernel instructions. Even in user-land, tracing local variables is somewhat convoluted and so, for the specific example you give, it would make a lot more sense to trace the return value of some_fun() instead.
If you must trace an arbitrary local variable then you will need to determine its location (typically a register or a location in memory) at the specific point of interest. For simple cases you may be able to do this by disassembling the function and inspecting the output. For more complex cases it may be helpful to build the object with DWARF and then find the DW_AT_location attribute of the local variable's DIE.
One you find the variable's location you'll need to express it in D; note that registers are exposed through the uregs[] array. Furthermore, you'll need to describe your probe using the offset within the function since dtrace(1) has no way of understanding line numbers. See the section on "User Process Tracing" in the Oracle Solaris Dynamic
Tracing Guide for more.
As an example, I wrote a trivial program containing
int
foo(int i)
{
int x;
...
for (x = 0; x < 10; x++)
i += 2;
and built it, as an amd64 executable, with DWARF...
cc -m64 -g -o demo demo.c
...before looking for foo() and its definition of x in the output
of dwarfdump demo:
< 1><0x000000e4> DW_TAG_subprogram
DW_AT_name "foo"
...
DW_AT_frame_base DW_OP_reg6
< 2><0x00000121> DW_TAG_variable
DW_AT_name "x"
...
DW_AT_location DW_OP_fbreg -24
x is described as DW_OP_fbreg -24 but DW_OP_fbreg itself must be
substituted by the result of the parent function's DW_AT_frame_base
attribute, i.e. DW_OP_reg6. DWARF uses its own architecture-agnostic
numbering for registers and the mapping to individual registers is up to
the appropriate standards body. In this case, the AMD64 ABI tells
us that DWARF register 6 corresponds to %rbp. Thus x is stored at
%rbp - 0x18. (For more about DWARF itself I recommend Michael Eager's
Introduction to the DWARF Debugging Format.)
Thus, if you had found that the line of source in which you're
interested is at offset 0x32 (perhaps by inspecting the DWARF
line table) then you might write a probe like:
pid$target:a.out:foo:32
{
self->up = (uintptr_t)(uregs[R_RBP] - 0x18);
self->kp = (int *)copyin(self->up, sizeof (int));
printf("x = %d\n", *self->kp);
self->up = 0;
self->kp = 0;
}
This is what I see when I run the demo program:
# dtrace -q -s test.d -c /tmp/demo
x = 1
x = 2
x = 3
x = 4
x = 5
x = 6
x = 7
x = 8
x = 9
x = 10
#

Stop lldb if difference between 2 variables is greater than x

I'm using lldb to debug a C++ program which has the following code
// Brute force to inner points
for (int i = 0; i < y_strip.size(); i++) {
for (int j = i + 1; j < y_strip.size(); j++) {
// If the vertical distance between the points is greater
// than delta, break the loop
if (abs(y_strip[i].y - y_strip[j].y) > delta) {
break;
} else {
mid_min_distance = minimal_distance(y_strip[i], y_strip[j]);
mid_min = min(mid_min_distance, mid_min);
}
}
}
and I want to come up with a way of stopping the program if the difference between j and i is greater than 10. How can I do this?
Compiling the program with clang++ -Wall -g closest.cpp -o closest
(lldb) break set -p "If the vertical distance between" -c "abs(i - j) > 10"
will do the trick. The -c option here is the breakpoint condition; if that expression evaluates to true, the program will stop at the breakpoint, otherwise the program will keep running. Note that you are still stopping to check the condition every time round the two loops, and this condition runs a function, so if the code you are checking is going to get run a lot, evaluating the condition might get slow. In that case it might be worth rewriting the condition to something like:
i - j > 10 || j - i > 10
since a simple expression with no function calls can be emulated in the debugger w/o having to call code in the debugee to check the condition.
And if this is code that you can modify, and it is going to get called a whole lot so that stopping each time around the loop to check the condition would be a big performance hit, then you can just put the check in your code:
if (abs(i - j) > 10)
printf ("Set a breakpoint here.\n");
rebuild it, and then just do:
(lldb) break set -p "Set a breakpoint here"
Note, the -p breakpoint option sets a breakpoint on the line whose source matches the pattern given in the option argument. You can also use file & line breakpoints:
(lldb) break set -f closest.cpp -l <whatever>
I like the pattern one because it moves with the intended location as the code is edited and it means I don't have to count lines.

How to make a GDB breakpoint only break after the point is reached a given number times?

I have a function that is called some large number of times, and eventually segfaults.
However, I don't want to set a breakpoint at this function and stop after every time it's called, because I will be here for years.
I've heard that I can set a counter in GDB for a breakpoint, and each time the breakpoint is hit, the counter is decremented, and only gets triggered when the counter = 0.
Is this accurate, and if so how do I do it? Please give the gdb code for setting such a breakpoint.
Read section 5.1.6 of the GDB manual. What you have to do is first set a breakpoint, then set an 'ignore count' for that breakpoint number, e.g. ignore 23 1000.
If you don't know how many times to ignore the breakpoint, and don't want to count manually, the following may help:
ignore 23 1000000 # set ignore count very high.
run # the program will SIGSEGV before reaching the ignore count.
# Once it stops with SIGSEGV:
info break 23 # tells you how many times the breakpoint has been hit,
# which is exactly the count you want
continue <n>
This is a convenient method that skips the last hit breakpoint n - 1 times (and therefore stops at the n-th hit):
main.c
#include <stdio.h>
int main(void) {
int i = 0;
while (1) {
i++; /* Line 6 */
printf("%d\n", i);
}
}
Usage:
gdb -n -q main.out
GDB session:
Reading symbols from main.out...done.
(gdb) start
Temporary breakpoint 1 at 0x6a8: file main.c, line 4.
Starting program: /home/ciro/bak/git/cpp-cheat/gdb/main.out
Temporary breakpoint 1, main () at main.c:4
4 int i = 0;
(gdb) b 6
Breakpoint 2 at 0x5555555546af: file main.c, line 6.
(gdb) c
Continuing.
Breakpoint 2, main () at main.c:6
6 i++; /* Line 6 */
(gdb) c 5
Will ignore next 4 crossings of breakpoint 2. Continuing.
1
2
3
4
5
Breakpoint 2, main () at main.c:6
6 i++; /* Line 6 */
(gdb) p i
$1 = 5
(gdb)
(gdb) help c
Continue program being debugged, after signal or breakpoint.
Usage: continue [N]
If proceeding from breakpoint, a number N may be used as an argument,
which means to set the ignore count of that breakpoint to N - 1 (so that
the breakpoint won't break until the Nth time it is reached).

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.