Step 2: A simple Debugging session

We will use the debugger to check out the buggy code in buggy.cpp. Follow these steps:

  1. Compile buggy.cpp using the -g option. This option tells the compiler and the loader to store information needed for the debugger:
    
       g++ -g buggy.cpp
    
  2. Run the program by typing ./a.out. It should give you a segmentation fault.
  3. Now let's run this program inside the gdb debugger. At the Unix prompt, type:
    
       gdb a.out
    
    After gdb starts up, type
    
       run
    
    at the gdb prompt. You should get a segmentation fault again.
  4. After the segmentation fault, gdb prints out lots of information. Look at the lines:
    
       Program received signal SIGSEGV, Segmentation fault.
       0x0000000000400888 in main () at buggy.cpp:12
       12            A[i/2] = i*i ;
    

    This says the program crashed while executing main() on line 12 of the file buggy.cpp. It also helpfully prints out line 12 for you.

    Using gdb, you can look at the memory contents of your program just after the segmentation fault. This is convenient if running your program requires several steps involving user I/O. At any time while running gdb, you can type the command where to find out where you are in the program.

    If all you remember about gdb is the "where" command, you still have a very useful tool in debugging pointer errors.

  5. Of course, we don't memorize our programs. The list command shows you the source code. Try these variations of the list command:
    
        list 12
        list main
        list 1,18
    
    If you type list right after another list command, it shows you another 10 lines below the previously listed lines.
  6. The command help list will tell you more about list. In general, "help" followed by a topic or a command will give you documentation on that topic. Typing just help will give you a list of topics.
  7. To see the value of variables and objects in the program, use the print command. Try these different print commands (you can also use p as a shortcut for print):
    
       print i
       print A[i]
       print A
       print &A
       print &i
       print &A[2]
    
    Conclusion: somehow the value of i has grown so large that accessing A[i] causes a segmentation fault.
  8. Now we will re-run the program to see what happened. In gdb we can set breakpoints which stop the program at critical places. Type:
    
       break 12
    
    This stops the execution of the program before the code on line 12 is executed. Type run to start the program running. You should see something like:
    
       Breakpoint 1, main () at buggy.cpp:12
       12            A[i] = i*i ;
    
    Type print A and print i to see that the values of A and i are as expected.

    To execute the code in line 12, type:

    
       step
    
    The step command executes one line of source code and shows you the next line. Print out A and i again to see the effects of line 12.
  9. We can continue to step through the program this way, but it is simpler to issue the continue command (or just c for short).
    
       continue
    
    This runs the program until the next breakpoint.
  10. We can keep typing continue and print commands this way, but all those prints get a bit tedious. Type:
    
       display A
       display i
    
    This tells the compiler to print out A and i whenever it stops at a breakpoint.
  11. Type continue again. Now you see the next iteration of the while loop. To continue again, you just have to hit the return key. Notice that the value of i eventually grows quite large. How did that happen?
  12. If you missed the iteration where the value of i ballooned, type kill to stop running the program and run to restart it. Your breakpoints and display items are still intact.
  13. To make sure you don't blow past the critical iteration of the while loop again, stop at the iteration when i is 20. Then use step. You don't have to type step every time. After the first step, hitting the return key is equivalent to typing step.
  14. Now type p &A[10] and p &i. Notice that these are the same hexadecimal (base 16) values (or should be on GL).
  15. Now you can quit, using quit.
Summary: In general you can have many breakpoints and display items. Sometimes you forget where and what they are. To see a list of your breakpoints and display items, use:

   info breakpoints
   info display
You can remove all breakpoints using delete or individual breakpoints using delete 1, delete 2, ... (Use the breakpoint number from the info list.) Sometimes you just want to temporary disable a breakpoint. You can do that with disable 1, disable 2, ... To enable the breakpoint again, use enable 1, enable 2, ...

To list your display items, info display. Use undisplay to remove a display item. Use disable display 1, disable display 2,... to temporarily disable a display item.