CS144 Debugging

The following are some very valuable tools for debugging. Mastering these can severely cut down the time spent on that one annoying segfault. It's definitely valuable to spend some time getting to know them, as they will likely aid in other classes as well.

  1. GDB
  2. Valgrind
  3. Dmalloc

GDB

The GNU Debugger (GDB) is a simple, yet powerful debugger. The most common usage is to print stack traces or setup breakpoints in lines of code. Here is a quick start to gdb. A list of commands can be found here, and a slightly more comprehensive guide there.

  1. Launching -- Start GDB by calling it with the executable as an argument. This will start GDB and its command prompt.
                > gdb program
    ...
    (gdb)
  2. Breakpoints -- Once in the command prompt, breakpoints can be added a number of ways. With a breakpoint, gdb will halt execution of the program at the specified line or function and allow you to print out variables to see if they contain what you deeply hope they do. Here are some ways to set up breakpoints:
                (gdb) break function
    (gdb) break line_number
    (gdb) break filename:line_number
  3. Running -- To run the program, just type run followed by any command line arguments. Anything output to STDOUT or STDERR will be output regularly.
                (gdb) run -flag argument1 argument2
    Starting program: /path/to/my/program
    Hola, Mundo!
    Program exited normally.
    (gdb)
  4. Inspecting -- When gdb encounters a specified breakpoint it will stop and let you do peek at values of things. For example, "print expression" will do just that. "next" will advance one line in the code. "continue" will resume execution. For more nifty things to do, check the quick ref or the guide.
                (gdb) break 10
    Breakpoint 1 at 0x400540: file yourbrains.c, line 10.
    (gdb) run
    Starting program: /path/to/yourbrains
    ...
    OM NOM NOM
    ...
    Breakpoint 1, eatMemory () at yourbrains.c:10
    10 int *eyes = (int *) malloc (10);
    (gdb) print eyes
    $1 = (int *) 0x7f29a0f44c00
    (gdb)
  5. Segfaults -- When disaster strikes, gdb will allow you to recover a bit, for example, by printing the stack trace with "backtrace" or "bt." This way you can see where exactly the code it segfaulted.
                (gdb) run
    Starting program: /path/to/yourbrains
    ...
    OM NOM NOM
    ...
    Program received signal SIGSEGV, Segmentation fault.
    (gdb) bt
    #0 0x000000000040061c in eatMemory () at yourbrains.c:13
    #1 0x000000000040056c in openSkull () at yourbrains.c:37
    #2 0x00000000004005ce in main (argc=1, argv=0x7ffff5d54628) at yourbrains.c:22
    (gdb)

Valgrind

Memory leaks are the signature of pure evil. Enter valgrind. As the name implies, you will truly enter the Valhalla of debugging when using valgrind. It is a very nifty tool, and if you'd like to learn more, knock here. Memcheck, one of its many tools and perhaps the most valuable, lists out when and where memory is leaked or accessed outside the bounds that were allocated. This makes it an especially strong tool to vanquish dreaded segfaults. Here is a simple example:

  1. Start valgrind (installed in the myth and corn clusters) with memcheck like so:
            > valgrind --tool=memcheck --leak-check=yes --show-reachable=yes ./yourbrains
        
  2. The output will be something like this:
            
    ==6716== Memcheck, a memory error detector.
    ==6716== Copyright (C) 2002-2007, and GNU GPL'd, by Julian Seward et al.
    ==6716== Using LibVEX rev 1804, a library for dynamic binary translation.
    ==6716== Copyright (C) 2004-2007, and GNU GPL'd, by OpenWorks LLP.
    ==6716== Using valgrind-3.3.0-Debian, a dynamic binary instrumentation framework.
    ==6716== Copyright (C) 2000-2007, and GNU GPL'd, by Julian Seward et al.
    ==6716== For more details, rerun with: -v
    ==6716==
    ...
    OM NOM NOM
    ...
    ==6716== Invalid write of size 4
    ==6716== at 0x40056C: eatMemory (yourbrains.c:13)
    ==6716== by 0x400549: openSkull (yourbrains.c:37)
    ==6716== by 0x4005CD: main (yourbrains.c:22)
    ==6716== Address 0x1cf01430 is not stack'd, malloc'd or (recently) free'd
    ==6716==
    ==6716== Process terminating with default action of signal 11 (SIGSEGV)
    ==6716== Access not within mapped region at address 0x1CF01430
    ==6716== at 0x40056C: eatMemory (yourbrains.c:13)
    ==6716== by 0x400549: openSkull (yourbrains.c:37)
    ==6716== by 0x4005CD: main (yourbrains.c:22)
    ==6716==
    ==6716== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 8 from 1)
    ==6716== malloc/free: in use at exit: 5 bytes in 1 blocks.
    ==6716== malloc/free: 1 allocs, 0 frees, 5 bytes allocated.
    ==6716== For counts of detected errors, rerun with: -v
    ==6716== searching for pointers to 1 not-freed blocks.
    ==6716== checked 75,696 bytes.
    ==6716==
    ==6716==
    ==6716== 5 bytes in 1 blocks are definitely lost in loss record 1 of 1
    ==6716== at 0x4C22FAB: malloc (vg_replace_malloc.c:207)
    ==6716== by 0x400623: eatMemory (yourbrains.c:13)
    ==6716== by 0x400549: openSkull (yourbrains.c:37)
    ==6716== by 0x4005CD: main (yourbrains.c:22)
    ==6716==
    ==6716== LEAK SUMMARY:
    ==6716== definitely lost: 5 bytes in 1 blocks.
    ==6716== possibly lost: 0 bytes in 0 blocks.
    ==6716== still reachable: 0 bytes in 0 blocks.
    ==6716== suppressed: 0 bytes in 0 blocks.
    Segmentation fault

Dmalloc

Dmalloc is another tool to find and duct tape memory leaks. It simply replaces malloc, realloc, calloc, and free with its own versions that provide powerful debugging features. A comprehensive guide can be found here.


Permission hereby granted for anyone to copy, modify, and redistribute this simple overview. Please report errors/typos to jbenet at cs dot stanford dot edu. Thanks! -Juan Batiz-Benet