GDB cheat sheets

http://users.ece.utexas.edu/~adnan/gdb-refcard.pdf
http://darkdust.net/files/GDB%20Cheat%20Sheet.pdf
http://www.yolinux.com/TUTORIALS/GDB-Commands.html

How do I use the nice GUI layout you showed us in class?

Use the 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!

Those lists of commands are overwhelming: how do I get started?

The first thing I would do is set a breakpoint at the call to 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=, 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.
Lines that begin with (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.

What calling convention does the bomb use?

The bomb uses the standard linux 64-bit calling convention. The first six arguments go in registers 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.

Great! Could you show me an example of how to call a function?

Here's a function with 9 arguments:
    // 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

When the call instruction executes, it pushes a return address on the stack and jumps to the first instruction in foo:
    |  .......  |
    +-----------+  <-- 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.

Right after foo returns, the stack looks like this:
    |  .......  |
    +-----------+
    +     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.