This has probably been asked elsewhere, but was a bit of a tricky one to google.
I am debugging some code like the following in gdb (or cgdb more specifically):
if(something) {
string a = stringMaker();
string b = stringMaker();
}
As I step through using 'n', the cursor will reach the 'string b' line. At this point I can inspect the value of a, but b won't have been populated yet as that line hasn't been executed. Another press of 'n' will execute that line, but will then also move outside the if loop and b will now be out of scope. Is there a way to execute the current line without moving on so that its result can be inspected before it goes out of scope?
Another press of 'n' will execute that line, but will then also move
outside the if loop and b will now be out of scope
The problem is that next executes too much instructions and b variable becomes unavailable. You can substitute this single next with a number of step and finish commands to achieve more granularity in debugging and stop immediately after b was constructed. Here is sample gdb session for test program:
[ks#localhost ~]$ cat ttt.cpp
#include <string>
int main()
{
if (true)
{
std::string a = "aaa";
std::string b = "bbb";
}
return 0;
}
[ks#localhost ~]$ gdb -q a.out
Reading symbols from a.out...done.
(gdb) start
Temporary breakpoint 1 at 0x40081f: file ttt.cpp, line 7.
Starting program: /home/ks/a.out
Temporary breakpoint 1, main () at ttt.cpp:7
7 std::string a = "aaa";
(gdb) n
8 std::string b = "bbb";
(gdb) p b
$1 = ""
(gdb) s
std::allocator<char>::allocator (this=0x7fffffffde8f) at /usr/src/debug/gcc-5.1.1-20150618/obj-x86_64-redhat-linux/x86_64-redhat-linux/libstdc++-v3/include/bits/allocator.h:113
113 allocator() throw() { }
(gdb) fin
Run till exit from #0 std::allocator<char>::allocator (this=0x7fffffffde8f) at /usr/src/debug/gcc-5.1.1-20150618/obj-x86_64-redhat-linux/x86_64-redhat-linux/libstdc++-v3/include/bits/allocator.h:113
0x0000000000400858 in main () at ttt.cpp:8
8 std::string b = "bbb";
(gdb) s
std::basic_string<char, std::char_traits<char>, std::allocator<char> >::basic_string (this=0x7fffffffde70, __s=0x400984 "bbb", __a=...) at /usr/src/debug/gcc-5.1.1-20150618/obj-x86_64-redhat-linux/x86_64-redhat-linux/libstdc++-v3/include/bits/basic_string.tcc:656
656 basic_string<_CharT, _Traits, _Alloc>::
(gdb) fin
Run till exit from #0 std::basic_string<char, std::char_traits<char>, std::allocator<char> >::basic_string (this=0x7fffffffde70, __s=0x400984 "bbb", __a=...) at /usr/src/debug/gcc-5.1.1-20150618/obj-x86_64-redhat-linux/x86_64-redhat-linux/libstdc++-v3/include/bits/basic_string.tcc:656
0x000000000040086d in main () at ttt.cpp:8
8 std::string b = "bbb";
(gdb) p b
$2 = "bbb"
Just add to the code b; the line afterwards. i.e.
if(something) {
string a = stringMaker();
string b = stringMaker();
b; // Break point here
}
Well you can always to a
(gdb) p stringMaker();
regardless of the line you're in given that stringMaker() is accessible. You can execute any kind statements , even involving variables if those variables are in current scope. For more advanced usage, you can use gdb's internal variables($1,$2 etc) to store certain result to use it later when the variables involved in that previous computation went out of scope.
Finally God(whatever that may be) send us gdb Python API. just type py and demolish your code to such extent that you will forget what you were doing at the first place.
Related
According to gdb docs, I can automatically continue after stopping on a breakpoint like this:
break 403
commands
cont
end
I'm trying to conditionally continue after a breakpoint like this:
set confirm off
set pagination off
define test
printf "%d\n", $x
set $x = $x + 1
if $x == 1
cont
end
end
break 403
commands
test
end
This almost works.
gdb indeed stops and checks for the condition ($x == 1). However it does not continue immediately when the condition is true.
Instead it just shows the prompt. If I click ENTER it either continues execution (when $x == 1), or remains in the prompt (if $x != 1).
Currently I just hit ENTER enough times until it does not continue execution any more.
But why does it wait for ENTER?
(This is not a matter of pagination/confirmation as I set them both to off)
Update1
Seems to be related to macro usage?
It does not happen if using commands directly.
Update 2
For clarity, here is a complete session that demonstrates the problem:
$ gdb a.out
GNU gdb (Ubuntu 9.2-0ubuntu1~20.04) 9.2
Copyright (C) 2020 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".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
<http://www.gnu.org/software/gdb/documentation/>.
For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from a.out...
(gdb) set confirm off
(gdb) set pagination off
(gdb) define test
Type commands for definition of "test".
End with a line saying just "end".
>p i
>if i < 3
>cont
>end
>end
(gdb) b 8
Breakpoint 1 at 0x115e: file test.c, line 8.
(gdb) commands
Type commands for breakpoint(s) 1, one per line.
End with a line saying just "end".
>test
>end
(gdb) run
Starting program: /home/amir.gonnen/projects/test/gdb-cont/a.out
Breakpoint 1, main () at test.c:8
8 printf("%d", i);
$1 = 0
Breakpoint 1, main () at test.c:8
8 printf("%d", i);
(gdb) echo Hey gdb why is the prompt?
Hey gdb why is the prompt?$2 = 1
Breakpoint 1, main () at test.c:8
8 printf("%d", i);
(gdb) echo Hey gdb you show the prompt but you still continue!
Hey gdb you show the prompt but you still continue!$3 = 2
Breakpoint 1, main () at test.c:8
8 printf("%d", i);
(gdb) echo again...
again...$4 = 3
(gdb) echo not continuing any more.
not continuing any more.(gdb)
not continuing any more.(gdb)
not continuing any more.(gdb)
This appears to work fine for me using GDB-10.0 on x86_64.
Are you sure it doesn't work? One thing I noticed is that you print $x before incrementing and checking it, which makes it a bit confusing.
Here is my session:
# gdbinit
set confirm off
set pagination off
define test
set $x = $x + 1
printf " x = %d\n", $x
if $x == 1
printf " continuing\n"
cont
end
end
set var $x = -2
gdb -q ./a.out
(gdb) source gdbinit
(gdb) list
1 int main()
2 {
3 int k = 0;
4 for (int j = 1; j < 100; j++) {
5 k += 1;
6 }
7 return k;
8 }
(gdb) b 5
Breakpoint 1 at 0x1139: file t.c, line 5.
(gdb) commands
Type commands for breakpoint(s) 1, one per line.
End with a line saying just "end".
>test
>end
(gdb) run
Starting program: /tmp/a.out
Breakpoint 1, main () at t.c:5
5 k += 1;
x = -1
(gdb) c
Continuing.
Breakpoint 1, main () at t.c:5
5 k += 1;
x = 0
(gdb) c
Continuing.
Breakpoint 1, main () at t.c:5
5 k += 1;
x = 1
continuing <<<=== Note: no 'c' required this time.
Breakpoint 1, main () at t.c:5
5 k += 1;
(gdb)
I'm using gdb with the -x parameter in order to debug without having to interactively continue at each breakpoint.
[root#StackOverflow.com] $ cat gdb_cmds_01
b SomeSourceFile.cpp:123
commands
bt
cont
end
I'm then attaching to a process that uses SomeSourceFile.cpp in it's execution:
[root#StackOverflow.com] $ gdb -p 'pidof SomeRunningProgram' -x gdb_cmds_01
GNU gdb (GDB) Red Hat Enterprise Linux (7.2-92.el6)
...
<GDB outputs a set S of backtraces as instructed by gdb_cmds_01>
Now, Let SomeSourceFile.cpp:123 contain a line like:
if (foo(person, &place, *time) == "Alice") { ... <do stuff > ... }
And then Suppose I want to break on SomeSourceFile:123 only if the return of foo(...) is not equal to "Alice".
Based on:
How to inspect the return value of a function in GDB?, I know that gdb can inspect the return value of a function.
And https://sourceware.org/gdb/onlinedocs/gdb/Break-Commands.html tells me that I can inspect the value of a variable non-interactively:
<...>
For example, here is how you could use breakpoint commands to print the value of x at entry to foo whenever x is positive.
break foo if x>0
commands
silent
printf "x is %d\n",x
cont
end
<...>
I have tried something like:
[root#StackOverflow.com] $ cat gdb_cmds_01
b SomeSourceFile.cpp:123 if foo(person, &place, *time) != "Alice"
commands
bt
cont
end
But GDB spits out:
gdb_cmds_01:1: Error in sourced command file:
No symbol "place" in current context.
Can this be worked around?
In order to break on SomeSourceFile.cpp:123 only when foo(...) != "Alice", can I also inspect the return value of a function non-interactively?
In other words, I want to see only a subset R of the set of backtraces S such that for all backtraces b in R, the return of foo(...) is always unequal to "Alice".
Suppose I want to break on SomeSourceFile:123 only if the return of foo(...) is not equal to "Alice".
This fairly easy to do if you go to the lower (assembly level), and if the code is built without optimization.
It is also trivial to do if you can modify the source like so:
if (foo(...) == "Alice") { ...
} else {
int x = 0; if (x) abort(); // break here
}
Now you can simply set breakpoint on line 125, and you are done.
So how can you do this without modifying the source?
You must understand that the compiler invokes some bool operator==(), compares the return to true or false, and conditionally jumps around the body of if when the condition is false.
The (gdb) info line 123 will give you range of instructions that were produced for this source line.
Disassembling that range of instructions will allow you to locate the call to operator==, and show you the instruction that compares EAX (JE or JNE) with 0 or 1.
You can then set the breakpoint on the conditional jump instruction, and use $EAX (or $RAX for 64-bit code) is the condition on that breakpoint.
I have a file named testing.cpp:
#include <iostream>
#include <string>
struct Foo {
std::string name;
};
int main() {
Foo* foo = new Foo;
foo->name = "hello";
std::cout << foo->name << "\n";
return 0;
}
I compiled it to a.out, and start gdb using gdb a.out.
GNU gdb (Debian 7.10-1.1) 7.10
...
Reading symbols from a.out...done.
(gdb)
I break at line 12 (std::cout << foo->name << "\n";), and run:
(gdb) break 12
Breakpoint 1 at 0x400990: file testing.cpp, line 12.
(gdb) run
Starting program: ...
Breakpoint 1, main () at testing.cpp:12
12 std::cout << foo->name << "\n";
(gdb)
It can print foo->name and foo->name.c_str():
(gdb) print foo->name
$1 = "hello"
(gdb) print foo->name.c_str()
$2 = 0x613c30 "hello"
It can print boolean expression with foo->name.c_str() in the first clause:
(gdb) print foo->name.c_str() && 1
$3 = true
But it can't when I put foo->name.c_str() in second clause:
(gdb) print 1 && foo->name.c_str()
Attempt to take address of value not located in memory.
(gdb)
Is this a bug?
Edit 1:
Use Case
I was trying to use break ... if ... to break at some point if some strings have certain values. E.g.
(gdb) break 14 if foo->name.size() == 5 && $_streq(foo->name.c_str(), "house")
Breakpoint 2 at 0x400aba: file testing.cpp, line 14
(gdb)
When I continue, gdb show the error message and break at line 14 (return 0;) even though foo->name is "hello" but not "house".
(gdb) continue
Continuing.
hello
Error in testing breakpoint condition:
Attempt to take address of value not located in memory.
Breakpoint 2, main () at testing.cpp:14
14 return 0;
(gdb)
Currently a workaround is access data member of std::string directly:
(gdb) break 14 if foo->name.size() == 5 && \
$_streq(foo->name._M_dataplus._M_p, "house")
Some Observations
Is it because my foo is pointer?
Nope. I tried to use Foo foo; instead of Foo* foo = new Foo;. Problem remains.
Does this problem apply for std::string variable created in main(), oppose to as a data member of some object?
Nope. Seems like it only applies for std::string as a data member. Code below works:
(gdb) list 4,8
4 int main() {
5 std::string name("hello");
6 std::cout << name << "\n";
7 return 0;
8 }
(gdb) break 6
Breakpoint 1 at 0x400a93: file testing.cpp, line 6
(gdb) run
Starting program: ...
Breakpoint 1, main() at testing.cpp:6
6 std::cout << name << "\n";
(gdb) print 1 && name.c_str()
$1 = true
Does this problem unique to c_str() only? How about other function?
No, this problem is not unique to c_str(). It is not even unique to std::string. Seems like it happens when we call member function of object inside another object, i.e. foo.bar.func().
What I want is this :
(gdb) define mynext
Redefine command "mynext"? (y or n) y
Type commands for definition of "mynext".
End with a line saying just "end".
>print "------"
>print Location:
>where
>print "-------------"
>print Code:
>list
>print "---------------------"
>print Next:
>next
>end
This is what outputs is:
$1 = "-----"
....
I expect:
-----
....
I used call printf("opopo") also, but It print the return value of "opopo" which is 5. Just like this:$4 = 5
My question is: how can I print something without this format which is :$[num]=[value].
As you found, print puts the printed value into the value history. gdb provides two different ways to avoid this.
One is printf. This works somewhat like the C function, but is a gdb command. Use it like:
(gdb) printf "whatever you like\n"
whatever you like
(gdb)
Another is output. This is a bit like the print command, but does not enter the value into the value history.
(gdb) output 5
5(gdb)
You can see from this that output also doesn't emit a trailing newline. You would have to add that yourself.
In my C++ program I have a nested class defined as follows:
class A {
class B {
// ...
}
// ...
}
When I try casting a pointer in GDB like this: set $b = (A::B*)p
I get "A syntax error in expression"
I'm not familiar with the symbol (or debugging) information stored in the ELF files. I'm wondering what's wrong with my casting here and how to refer to a nested class in GDB.
The answer is to enclose the class name in single quotes:
set $b = ('A::B'*)p
See http://sourceware.org/bugzilla/show_bug.cgi?id=8693
Works for me (using current CVS GDB, as well as 7.3.1):
$ cat t.cc
struct A {
struct B {
int x;
};
int y;
};
int main()
{
A::B ab, *p = &ab;
return 0;
}
$ gcc -g t.cc && gdb -q ./a.out
(gdb) b main
Breakpoint 1 at 0x4005b8: file t.cc, line 10.
(gdb) r
Breakpoint 1, main () at t.cc:10
10 A::B ab, *p = &ab;
(gdb) p (A::B*)0x1
$1 = (A::B *) 0x1
(gdb) set $a = (A::B*)0x1
(gdb) p $a
$2 = (A::B *) 0x1
(gdb) quit