GDB seems to have been clearly made with source-level debugging in mind, the kind where the source code of the program is available. Sometimes this is not the case, or you just don’t want to bother looking for the source code. Here I’ll put a bunch of useful commands.
layout asm
: enable TUI mode and show assembly instructionslayout regs
: enable TUI mode and show CPU registersset disassembly-flavor intel
: use Intel-like disassembly, which is more familiar to those writing or debugging assembly code on WindowsCtrl+P
,Ctrl+N
: serve as alternatives to “up” and “down” when the active TUI window is not the command windowCtrl+X, O
: switch the active TUI windowCtrl+X, (A or Shift+A or Ctrl+A)
: toggle TUI modex/5i $pc
: check out 5 instructions, starting at the program counterni
(nexti
) andsi
(stepi
): next/step, but on an instruction levelb *0x<addr>
: breakpoint on a specific addressinfo registers
: look at CPU registersinfo frame
: look at current stack frame, potentially useful for finding function arguments and local varsx/8g $sp
: look at (64-bit words) in the stack
x64 Linux C/C++ conventions
This is a set of additional notes written during the process of disassembling a library.
For function calls, the arguments are stored in the following order:
- RDI register
- RSI register
- RDX register
- RCX register
- R8 register
- R9 register
- rest are pushed onto the stack in reverse order
When a function is called, it will typically perform the following operations:
push rbp
mov rbp, rsp
sub rsp, (amount of space used for local variables)
...
add rsp, (same amount)
leave ; or mov rsp,rbp and pop rbp
ret
This means that any reference to memory at [rbp-0x…] is using the function’s local variables.
If a function returns a value, it will be stored in the EAX register.
If it is a C++ function, its name will be “mangled”: its argument types will be
included in the name. The utility c++filt
can convert these mangled names to
their standard forms. If the function is part of an object, it will require the
first parameter to be the object’s address.
Seems like the same is true for constructors and destructors: their first parameter is an address that will point to the object in question.