Search code examples
gdblldb

How can I inspect stack frame in lldb or gdb?


I would like to view a complete function stack frame in either lldb or gdb, which includes:

  • function arguments
  • old ebp
  • return address
  • local variables

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.


Solution

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