Debugging Programs

A debugger is a program that allows you to step through another program one line at a time. This is very useful when trying to identify incorrect code and analyze how a program "flows". Key concepts include: Breakpoints, Stepping, and Viewing data.

The Debugger

The debugger is a program that can run your program one line at a time. Thus the debugger can show you exactly how the computer sees your code.

You could think of the debugger as "instant replay" (or film review) in sports, allowing you to see "step by step" what happened in a given play. Coaches use this all the time to find the strengths and weaknesses of their team. The debugger does the same thing. It shows you what is happening in your program at any moment in time, and allows you to "step by step" through the program.

Proper use of the debugger is essential to finding semantic (logical) errors in how your program behaves. The debugger should be considered your best friend while programming (that is, unless you can perfectly visualize how your program will run in your head).

Like any tool, using the debugger will take practice, but it is well worth the investment. Using the debugger to find errors can greatly reduce the time it takes to perfect a program.

What the debugger does for you

The "power" of the debugger is that it lets you see the "state" of your program at any point and to advance through your program ("step") one line at a time in the exact same manner that the code is being executed by the computer.

Key things that you can use the debugger to determine are:

  1. The flow of the program (what happens next on a line by line basis)
  2. The creation of variables
  3. The data being stored in each variable
  4. The entering/leaving of functions
  5. The calculations that are made
  6. The entering of IF statements or ELSE statements
  7. The LOOPING of code.
  8. etc.

In order to use the debugger you need to know about the following concepts:

  1. Current Line

    A computer can only do "one thing at a time". Thus the computer, when running your program, always has the notion of the "current line". Usually, control of the program flows from the current line to the next line down the screen, to the next line, etc. This can be changed by function calls, if statements, loops, etc.

    In Matlab, a Green Arrow (in left column) will point to the current line that is about to be executed. .

    In GDB (using the GDB debugger in Emacs to debug C programs), a little white arrow will be shown on the left hand side of the window, pointing at the current line.

    It should be noted that we don't usually want to start with the first line in a program. We usually have an approximate idea about where the program is incorrect. To tell the compute to "run the program" until a given line, we use the concept of "break points".

  2. Breakpoints

    Normally when you run a program, even in the debugger, it will start at the beginning of the program and run until completion (or an error occurs).

    Often you may know that the error occurs in a certain function (or part of your program), but that function is not utilized by your code until long after the start of the program. Breakpoints tell the debugger where to "halt" the execution of your program so that you can see what is going on. This allows you to quickly get to the proper location in your program.

    In Matlab:To "set" a breakpoint, click in the left column on one of the dashes next to the line of code you are interested in. A red dot should appear.

    In Matlab to "remove" a breakpoint, click on the "red dot" that represents the breakpoint (in the left column).

    In GDB:To "set" a breakpoint, put the cursor on the line you want and press Cntl-Spacebar.

    In GDB to "remove" a breakpoint, type "del #", where # is the number of the breakpoint. Type "break" to list all the breakpoints.

    Remember, your program will stop at every breakpoint, so you only want a few directly around the "locus" of interest.

  3. Stepping

    Stepping is the action of "telling the debugger" to advance through your program one line at a time. Remember, a computer program is many small steps combined to form a large goal. It is often the case that one of these small steps is "incorrect". To identify which step is incorrect, we "step" through the program, looking at each line of code as we come to it, and seeing what effect this has on the VARIABLES (really the data in the variables).

    There are several ways you can tell the debugger to move through the code:

    1. Step (or Step In)

      Complete the next line of code. If this line contains a function, go to the first line of the function's code and stop, waiting for the user to now debug the function.

      In Matlab: Step In is represented by the arrow between two pages

      In GDB: To step to the next line, or into a function, use: "step" (or "s"))

      Again, remember, if your arrow is at a function call, you will "enter" the code for the function and stop at the first line of the function.

    2. Step Over

      Stepping over means to move to the next line of code in the current function. Even if the current line is a function call, all the code for that function will be executed (with out you seeing anything but the result), and the new current next line will be the next line of the code that you were looking at.

      In Matlab: Step Over: use the button with an arrow by a single page.

      In GDB: type "next" or "n"))

    3. Step Out

      If the current line of execution in the program is inside the code of a function and you want to "Finish It" (complete all the rest of the code in the function), you can use the step out command. This will complete all the code in the current function and return you to the previous function that "called" this function.

      In Matlab: Step Out is the button with the arrow going up.

      In GDB: type "finish".

  4. Continuing Execution of the Program (giving control back to the computer)

    The continue action tells the computer to "resume" the program (moving forward through the program's code until another breakpoint is encountered or until the program ends).

    In Matlab: the continue command is the button with the straight down arrow.

    In GDB: you will need to type "continue" or "c" for short.

  5. Exiting the Debugger

    Once you have used the debugger to find an error in your code you will want to:

    1. Fix the problem (re-write your code)
    2. Stop the current debugger session
    3. Perhaps put a breakpoint on the line you just (presumably) "fixed"
    4. Start a new debugger session to test your fix.

    In Matlab: Click the downward arrow with red X over it.

    In GDB: you don't need to exit the debugger, just make your changes, recompile the program, and then type "run" to start the program over again from the beginning.

  6. Showing the Value of a Variable

    Looking at the "state" of your program is VERY important for realizing if you are calculating and storing the correct data in your program.

    In Matlab: the "Workspace" window will show you all the variables that are currently "visible" to the function. This is usually limited to the parameters, the return value variable, and any local variables.

    You can also type commands or variable names at the debug prompt (Note, the regular Matlab prompt has been changed to a K followed by >>). This allows you to test equations, or variables to make sure the function is acting appropriately.

    In GDB: you will need to type "print variable" where variable is the name of the variable you are interested in. Note, you can abbreviate print with "p".

    Remember: The state of a program is the values of all the variables in the program. Also, variables "outside" of the functions "workspace" are never available inside a function!

  7. The call "Stack"

    As your program enters more and more "Functions" (when a function calls another function), a "Stack" of functions is created. This represents a "trail" of function calls for your program. You often want to see how "calling" one function affects the "current" function.

    In Matlab: to look at the "call stack", click (in the Debug window) on the STACK pull down menu. By selecting the names of the functions you "move up and down on this list" and thus see how your program "got" to where it currently is!

    In GDB: type "backtrace" to see all the functions that have been called up to the current line (and the order in which they were called). You can also use "up" or "down" to move up and down the "call stack". Each time you type one of these commands, the other Emacs window should change to show you the code contained in that level of the call stack.

  8. Multiple Functions Calls on one line

    Sometimes, there will be "nested" function calls:

                do_my_function( do_your_function(5) );
              

    When you "step in", you will enter the nested function first, so in this case, the do_your_function will be executed first, then the do_my_function.

    If you wish to see the execution of "do_my_function" first "step in" to the "do_your_function", then "step out" (or finish that function), and then "step in" again.

  9. Debugging vs Running

    Remember, you only have access to the power of the debugger when you use the "debugger", which starts up when you hit "breakpoints" in your code. If you simply "run" the program without any breakpoints, you will not be able to "walk" through your code nor access any of the "power" of the debugger.

  10. Your Code Vs. The Library Code

    Matlab (and C) provide many (MANY) functions. It can almost always be assumed that Matlab's (or C's) code is correct. Thus, you do not usually want to "STEP IN" to the Matlab functions, you usually want to "STEP" over them.

    On the other hand, sometimes it is informative to see how the Matlab designers wrote their code. It may be even the case that at some point a Matlab function will "call" your code. In these cases, you may well want to "STEP IN" to the Matlab functions.

    It should be noted, that while you can step into Matlab code and view their internals, you cannot do this in C.

    As a general lesson, you should keep a strong "fire wall" between your code and accessory code (Matlab's or even other Developers). Assume, if an error exists, that the error is in your code. Only when all possibilities have been exhausted, should you consider "debugging" the Matlab core software.

    Two Notes: For this class you can always assume Matlab's code is correct.
    The only exception to this is if you "PASS IN" the wrong information to a Matlab function (give it bad values...). In such a case, the result of the Matlab function may well be "bad".

    Garbage In, Garbage Out (GIGO)!

The Debugging Session

Using a debugger is usually a repetitive process. You write some code, run it, it doesn't work, so you debug it, fix something, run the debugger again, fix something, run the debugger again, etc.

You will often use the following sequence of commands:

  1. Set a breakpoint
  2. Run the program via the debugger
  3. Look at the results of the variables associated with the current function. (Look at the "state" of the program.)
  4. If everything looks good:
    1. Decide that you need to keep going
    2. "Resume" the program
    3. The program will stop at another breakpoint (or the same one).
    4. Repeat from 3 above.
  5. If everything doesn't look good:
    1. Figure out what went wrong (using your brain and the value of the variables)
    2. Change the "offending" line of code
    3. Restart the debugging session from the start. If you fixed the problem, remove the current breakpoint, and continue further into your program.

Back to Topics List