Reputation:
Can GDB be used as if it was a traditional assembly monitor?
As soon as you step into eg. library code it returns:
No function contains program counter for selected frame
GDB the debugger is able to step into unknown code but GDB the UI stops working.
In this related question you can find a pair of proposed solutions but neither quite satisfies me.
What if the binary library doesn't come with a debugging symbols package? What if the program jumps into run-time generated code?
Disassembling the code isn't really a solution either as the UI ignores it, most importantly the values of registers aren't updated until you return to the original known code. info registers
works, but that is hardly interactive.
Any suggestion?
Upvotes: 7
Views: 5948
Reputation: 365247
Use layout asm
instead of source
to show disassembly from the current position, not source lines. Or layout reg
/ layout next
to get to a split registers / disassembly TUI view.
https://sourceware.org/gdb/current/onlinedocs/gdb.html/TUI.html
Example from gdb /bin/ls
(without debug info installed)
┌─Register group: general────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
│rax 0x0 0 rbx 0x0 0 rcx 0x0 0 rdx 0x0 0 │
│rsi 0x0 0 rdi 0x0 0 rbp 0x0 0x0 rsp 0x7fffffffe430 0x7fffffffe430 │
│r8 0x0 0 r9 0x0 0 r10 0x0 0 r11 0x0 0 │
│r12 0x0 0 r13 0x0 0 r14 0x0 0 r15 0x0 0 │
│rip 0x7ffff7fe5520 0x7ffff7fe5520 eflags 0x200 [ IF ] cs 0x33 51 ss 0x2b 43 │
│ds 0x0 0 es 0x0 0 fs 0x0 0 gs 0x0 0 │
│fs_base 0x0 0 gs_base 0x0 0 │
│ │
│ │
│ │
┌────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
│ >0x7ffff7fe5520 mov rdi,rsp │
│ 0x7ffff7fe5523 call 0x7ffff7fe6180 │
│ 0x7ffff7fe5528 mov r12,rax │
│ 0x7ffff7fe552b mov rdx,QWORD PTR [rsp] │
│ 0x7ffff7fe552f mov rsi,rdx │
│ 0x7ffff7fe5532 mov r13,rsp │
│ 0x7ffff7fe5535 and rsp,0xfffffffffffffff0 │
│ 0x7ffff7fe5539 mov rdi,QWORD PTR [rip+0x17ac0] # 0x7ffff7ffd000 <_rtld_global> │
│ 0x7ffff7fe5540 lea rcx,[r13+rdx*8+0x10] │
│ 0x7ffff7fe5545 lea rdx,[r13+0x8] │
└────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
native process 2309234 In: L?? PC: 0x7ffff7fe5520
<https://debuginfod.archlinux.org>
Enable debuginfod for this session? (y or [n])
Debuginfod has been disabled.
To make this setting permanent, add 'set debuginfod enabled off' to .gdbinit.
(No debugging symbols found in /bin/ls)
(gdb) starti
Starting program: /usr/bin/ls
Program stopped.
0x00007ffff7fe5520 in ?? () from /lib64/ld-linux-x86-64.so.2
(gdb) layout next
My .gdbinit
has layout reg
which used to be regs + disassembly but is now regs + source. So I need to type layout next
interactively, because putting layout reg
and layout next
in .gdbinit
doesn't work.
Upvotes: 0
Reputation: 47038
You can do this sort of thing with the display
command.
display/i $pc
will disassemble the current instruction just before the prompt
is printed each time:
(gdb) b main
Breakpoint 1 at 0x80483b5: file hw.c, line 5.
(gdb) display/i $pc
(gdb) r
Starting program: /tmp/hw
Breakpoint 1, main () at hw.c:5
5 puts("Hello world");
1: x/i $pc
0x80483b5 <main+17>: movl $0x8048490,(%esp)
Now step an instruction (then just keep hitting Enter to repeat):
(gdb) si
0x080483bc 5 puts("Hello world");
1: x/i $pc
0x80483bc <main+24>: call 0x80482d4 <puts@plt>
(gdb)
0x080482d4 in puts@plt ()
1: x/i $pc
0x80482d4 <puts@plt>: jmp *0x804959c
Current language: auto; currently asm
(gdb)
0x080482da in puts@plt ()
1: x/i $pc
0x80482da <puts@plt+6>: push $0x10
(gdb)
0x080482df in puts@plt ()
1: x/i $pc
0x80482df <puts@plt+11>: jmp 0x80482a4 <_init+48>
It still works when we get to this point:
(gdb)
0x080482a4 in ?? ()
1: x/i $pc
0x80482a4 <_init+48>: pushl 0x804958c
(gdb)
0x080482aa in ?? ()
1: x/i $pc
0x80482aa <_init+54>: jmp *0x8049590
(gdb)
0xb7f052d0 in _dl_runtime_resolve () from /lib/ld-linux.so.2
1: x/i $pc
0xb7f052d0 <_dl_runtime_resolve>: push %eax
More than one display
expression can be active at once (use undisplay <number>
to remove them). For example, to watch what happens to %eax
:
(gdb) display/x $eax
2: /x $eax = 0xbf90ab34
(gdb) si
0xb7f052d1 in _dl_runtime_resolve () from /lib/ld-linux.so.2
2: /x $eax = 0xbf90ab34
1: x/i $pc
0xb7f052d1 <_dl_runtime_resolve+1>: push %ecx
(gdb)
0xb7f052d2 in _dl_runtime_resolve () from /lib/ld-linux.so.2
2: /x $eax = 0xbf90ab34
1: x/i $pc
0xb7f052d2 <_dl_runtime_resolve+2>: push %edx
(gdb)
0xb7f052d3 in _dl_runtime_resolve () from /lib/ld-linux.so.2
2: /x $eax = 0xbf90ab34
1: x/i $pc
0xb7f052d3 <_dl_runtime_resolve+3>: mov 0x10(%esp),%edx
(gdb)
0xb7f052d7 in _dl_runtime_resolve () from /lib/ld-linux.so.2
2: /x $eax = 0xbf90ab34
1: x/i $pc
0xb7f052d7 <_dl_runtime_resolve+7>: mov 0xc(%esp),%eax
...and here the change in %eax
can be seen:
(gdb)
0xb7f052db in _dl_runtime_resolve () from /lib/ld-linux.so.2
2: /x $eax = 0xb7f0d668
1: x/i $pc
0xb7f052db <_dl_runtime_resolve+11>: call 0xb7eff780 <_dl_fixup>
(gdb)
Upvotes: 10