I would like to view a complete function stack frame in either lldb or gdb, which includes:
What should I do? Can anyone give me an example?
I‘ve tried using finish
command, frame info
... but I am confused about the meaning of the outputs.
Using GDB, you can view the stack using the backtrace
command, or bt
for short, this will give output like:
(gdb) bt
#0 func_c (str=0x402010 "this is a string", num=3) at test.cc:11
#1 0x000000000040113d in func_b (arg=..., num=129, str=0x402010 "this is a string") at test.cc:16
#2 0x000000000040116f in func_a (arg=..., str=0x402010 "this is a string") at test.cc:23
#3 0x0000000000401199 in main () at test.cc:30
The number on the left is the frame number, initially, frame #0, the most recent frame will be selected. You can select another frame using the up
and down
commands, or by just using frame NUM
, e.g. frame 2
:
(gdb) frame 2
#2 0x000000000040116f in func_a (arg=..., str=0x402010 "this is a string") at test.cc:23
23 func_b (arg, var + 6, str);
If you loose track of which frame you have selected, just use the frame
command without any arguments and GDB will remind you.
With a frame selected we can view the arguments with info args
:
(gdb) info args
arg = {
a = 1,
b = 2
}
str = 0x402010 "this is a string"
Notice how with info args
the argument called arg
is now presented as its full value, while in backtrace
, or frame
command output GDB only printed ...
. This is because arg
is not a scalar, GDB is trying to reduce the size of the frame line. You can adjust this behaviour with set print frame-args all
, and restore the default behaviour with set print frame-args scalar
.
On x86-64 you can view the stack frame address in the info frame
output:
(gdb) info frame
Stack level 2, frame at 0x7fffffffad80:
rip = 0x40116f in func_a (test.cc:23); saved rip = 0x401199
called by frame at 0x7fffffffada0, caller of frame at 0x7fffffffad50
source language c++.
Arglist at 0x7fffffffad70, args: arg=..., str=0x402010 "this is a string"
Locals at 0x7fffffffad70, Previous frame's sp is 0x7fffffffad80
Saved registers:
rbp at 0x7fffffffad70, rip at 0x7fffffffad78
The first line Stack level 2, frame at 0x7fffffffad80:
contains the address you want. But you can always confirm this, the frame address in one frame will be the stack-pointer address in the previous frame, so:
(gdb) up
#3 0x0000000000401199 in main () at test.cc:30
30 func_a (f, "this is a string");
(gdb) p $rsp
$2 = (void *) 0x7fffffffad80
Which seems to line up. The info frame
output also told us the return address with this line rip = 0x40116f in func_a (test.cc:23); saved rip = 0x401199
, the saved rip = 0x401199
is the address you want. Again we can confirm this in the previous frame:
(gdb) frame
#3 0x0000000000401199 in main () at test.cc:30
30 func_a (f, "this is a string");
(gdb) disassemble
Dump of assembler code for function main():
0x0000000000401172 <+0>: push %rbp
0x0000000000401173 <+1>: mov %rsp,%rbp
0x0000000000401176 <+4>: sub $0x10,%rsp
0x000000000040117a <+8>: movl $0x1,-0x8(%rbp)
0x0000000000401181 <+15>: movl $0x2,-0x4(%rbp)
0x0000000000401188 <+22>: mov -0x8(%rbp),%rax
0x000000000040118c <+26>: mov $0x402010,%esi
0x0000000000401191 <+31>: mov %rax,%rdi
0x0000000000401194 <+34>: call 0x401140 <_Z6func_a5foo_tPKc>
=> 0x0000000000401199 <+39>: mov $0x0,%eax
0x000000000040119e <+44>: leave
0x000000000040119f <+45>: ret
End of assembler dump.
Notice the =>
marker, which indicates where GDB thinks we will next execute in that particular frame, i.e. the return address within that frame.
And finally, for local variables, we can use info locals
:
(gdb) frame
#3 0x0000000000401199 in main () at test.cc:30
30 func_a (f, "this is a string");
(gdb) info locals
f = {
a = 1,
b = 2
}
(gdb) down
#2 0x000000000040116f in func_a (arg=..., str=0x402010 "this is a string") at test.cc:23
23 func_b (arg, var + 6, str);
(gdb) info locals
var = 123
The output here is very like info args
, but GDB is just printing the stack locals.
You can always print particular locals, arguments, or globals like print var
-- assuming of course, that you are in a frame where that variable is valid.
To learn more, GDB has a built-in help system, so you can do help COMMAND
to get more info, e.g. help info locals
. There is also a basic search feature, apropos KEYWORD
, though this is pretty crude, if the command name, or help text doesn't contain KEYWORD, you'll not find a match. But it can sometimes be useful.
Finally, the GDB documentation is pretty extensive, and is online here.