layout asm
or the layout regs
command.
This enters TUI mode: your screen splits into multiple windows so you can
see assembly code, the registers, and the command prompt all on the same
screen. To leave TUI mode, press 'Ctrl-X' then 'a'.
See these links for more details:
http://beej.us/guide/bggdb/ http://davis.lbl.gov/Manuals/GDB/gdb_21.html
One problem with TUI mode is that GDB prints the program's outputs in weird places.
Suppose you're debugging a program using layout asm
, so you have the
assembly code in the top half of the screen and the gdb command prompt in the bottom
half of the screen. Now suppose you come across a call to
printf("Hello!\n")
. You might think this will print "Hello!" in the
gdb command window as it does normally, but for some reason it does not. Instead,
it prints "Hello!" somewhere in the middle of the screen, overwritting the assembly
code. I have no idea how to fix this ... if anyone figures it out, let me know!
phase_1
using the break
command. Then you can step
through phase 1 using the stepi
instruction to try to figure out
what it does. Here's how I would do that:
(gdb) break bomb.c:73 Breakpoint 1 at 0x400db1: file bomb.c, line 73. (gdb) run Starting program: cse351/lab2/bomb Welcome to my fiendish little bomb. You have 6 phases with which to blow yourself up. Have a nice day! password Breakpoint 1, main (argc=Lines that begin with, argv=0x7fffffffe108) at bomb.c:73 73 phase_1(input); /* Run the phase */ Missing separate debuginfos, use: debuginfo-install glibc-2.14.1-6.x86_64 (gdb) list 68 printf("Welcome to my fiendish little bomb. You have 6 phases with\n"); 69 printf("which to blow yourself up. Have a nice day!\n"); 70 71 /* Hmm... Six phases must be more secure than one phase! */ 72 input = read_line(); /* Get input */ 73 phase_1(input); /* Run the phase */ 74 phase_defused(); /* Drat! They figured it out! 75 * Let me know how they did it. */ 76 printf("Phase 1 defused. How about the next one?\n"); 77 (gdb) stepi 0x0000000000400db4 73 phase_1(input); /* Run the phase */ (gdb) stepi 0x0000000000400e70 in phase_1 () (gdb) disas Dump of assembler code for function phase_1: => 0x0000000000400e70 <+0>: sub $0x8,%rsp 0x0000000000400e74 <+4>: mov $0x401af8,%esi 0x0000000000400e79 <+9>: callq 0x40124d 0x0000000000400e7e <+14>: test %eax,%eax 0x0000000000400e80 <+16>: je 0x400e87 0x0000000000400e82 <+18>: callq 0x40164d 0x0000000000400e87 <+23>: add $0x8,%rsp 0x0000000000400e8b <+27>: retq End of assembler dump.
(gdb)
are commands you type in. The line that
says password
is an input you type in (this is the input for the
phase_1
function). All other lines are gdb's output.
rdi
, rsi
, rdx
, rcx
,
r8
, and r9
, in that order. The remaining arguments are
pushed onto the stack in reverse order (right to left). The return value is placed in
rax
.
// C code for function foo int foo(int x1, int x2, int x3, int x4, int x5, int x6, int x7, int x8, int x9) { return 42; }Here's how you call that function:
// Assembly code to call foo // Put the first six arguments in registers movl x1, %rdi movl x2, %rsi movl x3, %rdx movl x4, %rcx movl x5, %r8 movl x6, %r9 // Push the next three arguments on the stack, right-to-left pushl x9 pushl x8 pushl x7 // Call the function! // When this returns, %rax should have the value 42 call foo // Cleanup: pop the arguments x7,x8,x9 off the stack addl $0x18, %rsp
| ....... | +-----------+ <-- old %rsp (before we pushed x7, x8, and x9) + x7 + +-----------+ + x8 + <-- each of these slots is 8 bytes (to hold a 64-bit number) +-----------+ + x9 + +-----------+ + ret addr + +-----------+ <-- new %rsp (just after the call) new %rsp = old %rsp - 4*8 = old %rsp - 32 // In this example, the return address is the address of the "cmp $42, $rax" // instruction. This is the instruction we jump to after foo returns. // Remember that stacks grow downwards. This is why new %rsp < %old rsp.
| ....... | +-----------+ + x7 + +-----------+ + x8 + +-----------+ + x9 + +-----------+ <-- %rsp points here // The "ret" pops the return address of the stack and jumps there. Since // the return address was popped, %rsp now points at the location shown above. // The next thing we do is increment %rsp by 24 to pop x7, x8, and x9 off the // stack. Suppose we forgot to pop these values off the stack, and instead we // execute a "ret" instruction just after "call foo". In this case, the // computer will treat "x9" as the return address and pop there! This is why // we need to clean x7, x8, and x9 off the stack.