Debugging using GDB

We are going to be using two programs to illustrate how GDB can be used to debug code.

Debugging a program with logical errors

  1. Get a buggy program from /home/gtowell/Public246/Lab1104/fibb.c
  2. Get input data for fibb /home/gtowell/Public246/Lab1104/inpt
  3. This program has several runtime issues. Rather than reading the code to find them use gdb. To do so, first compile and execute the program. Note the -g flag. It is important for using gdb
    UNIX> -g -o fibb fibb.c
    UNIX> ./fibb < inpt
    
  4. The program gets one input hangs. (it does nothing)
  5. Kill the program CTRL-C
  6. Start the debugger
  7. UNIX> gdb fibb
    
    This only starts the debugger; it does not start running the program in the debugger.
  8. Look at the source code and set a breakpoint at line 10
  9. (gdb) b 10
    
    "b" is short for breakpoint.
  10. Now, we start to run the program in the debugger.
  11. (gdb) run < inpt
    Starting program: /home/gtowell/Public246/Lab1104/fibb < inpt
    What number fib number do you want (0 to quit)8
    
    Breakpoint 1, dofibb (n=8) at fibb.c:10
    10              int t = f + s;
    
    Note that the program execution stopped at our first (and only) breakpoint.
  12. It usually helps to see the values of some variables. To do so
    		display i
    		display t
    	
    Display is distinct from its relative print. Display shows the value of a variable after every step. Print shows the value of a variable at the time it is executed.
  13. Now step through the program a couple of times. Try to identify problems by watching variable values rather than looking at the code (The problems are pretty obvious in the code.) To execute the program stepwise use "s" -- short for "Step"
    	(gdb) display i
    	1: i = 0
    	(gdb) display t
    	2: t = 1821770359
    	(gdb) s
    	11              f=s;
    	1: i = 0
    	2: t = 0
    	(gdb) s
    	12              s=t;
    	1: i = 0
    	2: t = 0
    	(gdb) s
    	8           for (int i=0; i<n-2; i)
    	1: i = 0
    	(gdb) s
    
    	Breakpoint 1, dofibb (n=8) at fibb.c:10
    	10              int t = f + s;
    	1: i = 0
    	2: t = 0
    	(gdb) s
    	11              f=s;
    	1: i = 0
    	2: t = 0
    	(gdb) s
    	12              s=t;
    	1: i = 0
    	2: t = 0
    	(gdb) s
    	8           for (int i=0; i<n-2; i)
    	1: i = 0
    
  14. Something is clearly wrong with both i and t as the both remain 0 no matter how many steps you take. So not examine the code and fix it, knowing that there is a problem with both i and t
  15. Quit your gdb session using "q"
  16. After fixing the code recompile it (be sure to use the -g flag) and run as above. You will note it goes into an infinite loop. So kill the loop and start gdb as above.
  17. Set a breakpoint at line 29
  18. start the program within gdb
    			run < inpt
    		
  19. tell gdb to display the value of n
  20. Now go through the program, except this time use "n" -- next. Next is distinct from step in that it will not enter functions. When when you think you know where the problem is, n can be better to use than s.
  21. Note that the value of the variable n always resets to 0 after executing line 32. Fix the problem
  22. Recompile one more. The program should behave
  23. One final thought: Where are we?
  24. If you want to know where you are in the program's execution (and how, to some extent, you got there), you can view the contents of the stack using the backtrace It will show the entire call stack.

Debugging a program that produces a core dump

  1. Get the program /home/gtowell/Public246/Lab1104/segg.c

    This program causes a core dump due to a segmentation fault. We will try to trace the reason for this core dump.

  2. Compile the program using the following command.

    gcc segg.c -g -o segg
    

  3. Run it normally, you should get the following result:

    Segmentation fault (core dumped)

  4. The core dump generates a file called core which can be used for debugging. Since, this program is really short, we will not need to set any breakpoints. Use the following command to start running the debugger.
    	coredumpctl gdb segg
    

    The output of the above command should look like this:

    A whole lot fo stuff ending with 
    
    Core was generated by `segg'.
    Program terminated with signal SIGSEGV, Segmentation fault.
    #0  main () at segg.c:10
    10              temp[3]='F';
    
  5. As we can see from the output above, the core dump was produced as a result of execution of the statement on line 10: temp[3]="F"
  6. Take a closer look at the declaration of temp on line 5 :

    	char *temp = "Paras";
    

    We find that temp is a char* which has been assigned a string literal and so we cannot modify the contents of the literal as on line 10. This is what is causing a core dump

Conditional Breakpoints

  1. Implement the Fisher-Yates shuffle for 10000 items.
    		int a[n]
    		for i from 0 to n a[i]=i
    		for i from 0 to n-2
    			j = random in range i <= j < n
    			exchange a[i] with a[j]
    	
  2. Read about setting a conditional breakpoints using GBD https://sourceware.org/gdb/onlinedocs/gdb/Conditions.html
  3. Set breakpoints at at 1597 and 4181 (the 17th and 19th fibbonacci numbers).
  4. Confirms that your conditional breakpoints work.

Next steps

Go to http://www.cs.yale.edu/homes/aspnes/pinewiki/C(2f)Debugging.html Read through this document. Try out some of the gdb and valgrind commands on some of your programs.

Towers of Hanoi Tournament