Chapter 6 Debugging Tools

Table of Contents
6.1 Turbo Debugger (TD)
6.2 The Case of the Speckled Bug

What does a debugging program do and how is it useful? These questions are better explained by example, but to give a quick answer, a debugging program allows you to monitor control of a program during program execution. What does that mean? Well, let s give a quick example. Using the debug program (hereafter we will refer to it as the "debugger") you can tell the program to execute until a specific statement is reached; upon reaching this statement the debugger allows you to look at and change values of different variables in the program and also the registers used by the PC (of course the debugger will allow you to do much more than that). The usefulness of this ability to watch your program unfold in great detail will become apparent later on.

Before showing how to use the debugger, a word of encouragement should be offered. In our experience with assembly language and programmers, we have found two types of programmers who use a debugger: first of all, those who just naturally like this kind of programming tool and pick it up easily, and second, those who have done a considerable amount of programming and who have in the process been forced to learn how to use a debugger, and much to their surprise have found it to be extremely useful. We have tried to write the following debugger "tutorial" to create a third category of people who use the debugger--those who have not had much experience programming but have had a good description of how to use a debugger. We hope that you will take the time to learn how to use it, in order to save time debugging your programs later on. And one more word of encouragement: at first, like most people, you may shy away from using the debugger. It may seem too complicated and time-consuming to run part of the program and then to go into memory to try to figure out what state the computer is in (the values of the registers and variables), and whether it is in the state you want it to be in. But trying to fix your program without the debugger is much like trying to fix a car without being able to look under the hood! It will take you a few minutes to learn how the debugger works, but used properly, it will save you hours in the lab. So don t be tentative about "looking inside" the computer while executing your program; it is not so complicated as you might think. If you have never used a debugger before, it will be useful to go through a simple program using the debugger before tackling larger programs. The first machine problem in ECE 291, MP0, will help you learn how to use the debugger.

There are four basic steps in debugging:

  1. Discovering the Bug. Is there one? It is not always obvious that you have a bug. (Why?)

  2. Isolating the Bug. Where is it? Locate the part(s) of the code that is causing the bug.

  3. Finding the Bug. What exactly is wrong with the buggy code fragment?

  4. Fixing the Bug. How should the buggy fragment be rewritten?

The debugger gives you the tools to help in all these steps. E.g., you can run the code in a step-by-step fashion or until some breakpoint you set in the code. In between these execution steps, you can examine memory and CPU state (variables, registers, flags, and stack).

6.1 Turbo Debugger (TD)

Turbo Debugger is a window-oriented mouse-driven debugging tool. To start Turbo Debugger (oftentimes referred to as simply TD), type the following at the DOS prompt:

td [progname[.exe]]

6.1.1 Mechanics of Using TD

6.1.1.1 Overview

The main TD window shows a standard (pull-down) menu bar at the top. The menu bar lists the following menus: File, Edit, View, Run, Breakpoints, Data, Options, Windows, Help. The status bar at the bottom of the TD window contains helpful information about the current context. For instance, you often see a list of all the functions associated with the function keys F1 to F10. For instance, F9 is the "Run" command. That means these functions are available in the current context.

6.1.1.2 Windows

Within the Main TD window we can have a variety of (sub)windows. At any moment, several of these windows may be active. Each active windows is numbered (1,2,3, etc.) and this number is displayed on the upper right hand corner of window. Below, we will go into some of these windows and discuss how to manage them. Among the active windows, one of them is the current top window. The top window has a little green rectangle at its upper left corner. You can close this window by clicking on this little green rectangle. The function key F6 (called "Next") steps through the active windows, allowing each of them to be "top window" in turn.

6.1.1.3 Online Help

We already mentioned the Help (pulldown) menu. But there are more "immediate" or context-sensitive help available:

Status Bar

We noted that status bar usually shows the list of functions associated with the 10 function keys. But if you hold down the Alt key, the status bar will show the functions associated with Alt+Function Keys.

E.g., ALT-F5 is the "User Screen" Function. Try this! This is useful if you need to see any output from your executed code. To get back from the User Screen, press any key.

If you hold down the Ctrl key, you will see the Ctrl+key functions.

E.g., CTRL-I allows you to inspect the variable that the cursor is currently pointed at.

F1 key

This key opens a help window containing information about the current top window, with further subtopics to choose from.

SpeedMenu

This can be invoked with a right mouse click at any time. In most windows, it will display a list of options suitable for that window.

6.1.2 Some Pulldown Menus

View

The types of windows available are listed under the View menu. See Section 6.1.3 for descriptions of the various types of windows available.

Window

The Window menu helps you manage the various windows. This menu is divided into two halves (separated by a horizontal line): the top half contains commands such as Zoom (F5), Next (F6), Next Pane (Tab), etc. The bottom half is a list of the currently active windows.

Run

Windows are for watching. But for action, you need to execute your code. For this, the Run menu provides several modes of execution:

  • Run (F9), i.e., until program terminates (or until the next breakpoint, see Section 6.1.4).

  • Trace Into (F7), i.e., single stepping, one instruction at a time. What constitutes a single step depends on which the current "top window". If the top window is the Module window or if you use F7, then a single line of source code is executed. If the top window is the CPU window or if you use ALT-F7, then a single machine instruction is executed. If the current source line contains a function call, TD traces into the function (assuming it was compiled with debug information). Some machine instructions, however, cause multiple instructions to be executed include: CALL, INT, LOOP, etc.

  • Step Over (F8). This is like "Trace Into" except that when the instruction pointer is at a function call, then the entire function is executed and you are next placed at the statement following the function call.

  • Animate. Similar to run until terminate, except it pauses between machine instructions to allow you to catch what is happening.

  • Restart. Moves the instruction pointer back to the first instruction.

6.1.3 TD Windows

6.1.3.1 The Regs Window

The Regs window displays the contents of all the processor registers as well as the CPU flags. It is possible to view either the 16-bit registers or the 32-bit registers. Various options can be accessed by using the SpeedMenu (see Section 6.1.1.3). As the program is being stepped through, register and flag changes are highlighted in the window.

6.1.3.2 The Dump Window

This is a hex display of an area in memory. The leftmost path of each line shows the starting address of the line (e.g., DS:0000). In the default display format (byte format), you see 8 bytes per line, and to the right of these 8 bytes are their representation in the IBM extended character set (which is an extension of the ASCII set). You can use the Goto command in the SpeedMenu to examine variables (e.g., Goto Input, assuming you have defined the variable "Input").

6.1.3.3 The Module Window

The Module window displays the program source code if debugging information is available. The F8 key steps through each line of code. The F7 key also steps through each line of code, but unlike F8, it also traces into procedure calls. F2 sets a breakpoint in the code at the line where the cursor is at (see Section 6.1.2 for more information on stepping through the program and Section 6.1.4 for more information on breakpoints).

6.1.3.4 The CPU Window

The CPU window combines the Module, Dump, and Regs windows into a single window. It's also less powerful and harder to use than the three separate windows, so it's almost always better to use the specific windows rather than the combined CPU window.

6.1.4 Breakpoints

Breakpoints are a device to cause the computer to take specific actions at specific points in its execution. The user can define a breakpoint by specifying three pieces of information:

  • The location where the breakpoint is set.

  • The condition which allows the breakpoint to activate.

  • The action that takes place when the breakpoint is activated.

The simplest kind of breakpoint is one that (a) is associated with a specific instruction in the program, which (b) is always activated (condition is "always true") and (c) pauses the program execution (action is "break"). These are called simple breakpoints. It is the default assumed by TD, and it should suffice for our purposes. Using this, you run the program at full speed until specific instructions, at which points you can examine the state of the memory and CPU.

How do you set simple breakpoints? Well, you only need to specify an instruction in the program. The simplest is to do this from within the Module window, or from the Code pane in the CPU window:

  • First place the cursor at an executable line of code where a breakpoint is desired. (How do you tell if a line is executable?) You then left the 2 leftmost columns of line. Instead of left, you can also use F2 (see the status line).

    Note: If the line already has a breakpoint, then this action removes that breakpoint. Hence this is also called the toggle action.

  • If you use the Breakpoint->At menu option, you can also place a simple breakpoint at the current cursor position. However, since this has a pop-up Breakpoint option dialog box, you can also specify more complex types of breakpoints.

Breakpoint addresses must be entered when you use the keyboard to enter breakpoints. (You can see this in the Breakpoint option dialog box). These are the kinds of addresses you can specify:

  • #number -- for instance, #68 specifies a breakpoint in line 68 of your source code.

    Note: If you have several program modules, you need to preface the line number with the module name. E.g. #mp0#68 refers to line 68 in the mp0.asm module.

  • Symbolic names--for instance, labels can be specified. If you have have a label called "repeat", you can use that as an address.

How do you see all the current breakpoints? In the Breakpoints window, which can be activated using the View->Breakpoints menu option. This window has two panes: the left pane lists all the current breakpoints, the right pane gives details about the breakpoint that is currently highlighted. The SpeedMenu from the left pane has options to add or delete breakpoints, etc.