Chapter 1. Getting Started with dbx

You can use dbx to trace problems in a program at the source code level, rather than at the machine code level. dbx enables you to control a program's execution, symbolically monitoring program control flow, variables, and memory locations. You can also use dbx to trace the logic and flow of control to acquaint yourself with a program written by someone else.

This chapter introduces some basic dbx commands and discusses some tips about how to approach a debugging session. Specifically, this chapter covers:

Examining Core Dumps to Determine Cause of Failure

Even if your program compiles successfully, it still can crash when you try to run it. When a program crashes, it generates a terminating signal that instructs the system to write out to a core file. The core file is the memory image of the program at the time it crashed.

You can examine the core file with dbx to determine at what point your program crashed. To determine the point of failure, follow these steps:

Procedure 1-1. Examining a core File

  1. If the core file is not in the current directory, specify the pathname of the core file on the dbx command line.

    If the source code for the program is on a different machine or the source was moved, provide dbx with the pathname to search for source code (also see “Specifying Source Directories” in Chapter 3).

  2. Invoke dbx for the failed program as described in “Invoking dbx” in Chapter 2. dbx automatically reads in the local core file.

  3. Perform a stack trace using the where command (described in “Examining the Stack” in Chapter 5) to locate the failure point.

For example, suppose you examine the core file for a program called test. Suppose the stack trace appears as follows:

(dbx) where

>  0 foo2(i = 5) [“/usr/tmp/test.c”:44, 0x1000109c]
   1 foo(i = 4) [“/usr/tmp/test.c”:38, 0x1000105c]
   2 main(argc = 1, argv = 0xffffffad78) [“/usr/tmp/test.c”:55, 0x10001104]
   3 __start() [“/shamu/crt1text.s”:137, 0x10000ee4]

In this case, test crashed at line 44 of the source file test.c. The program crashed while executing the function foo2. foo2 was called from line 38 in the function foo, which was in turn called from line 55 in the function main. You can use the other features of dbx to examine values of program variables and otherwise investigate why test crashed.

If you use dbx to debug code that was not compiled with the -g option, local variables are invisible to dbx, and source lines may appear to jump around as a result of various optimizations. If the code is stripped of its debugging information, dbx displays very little information.

Debugging Your Programs

Debugging a program consists primarily of stopping your program under certain conditions and then examining the state of the program stack and the values stored in program variables.

You stop execution of your program by setting breakpoints in your program. Breakpoints can be unconditional , in which case they always stop your program when encountered, or conditional, in which case they stop your program only if a test condition that you specify is true. (See “Setting Breakpoints” in Chapter 6, for more information.)

To use breakpoints to debug your program, examine your program carefully to determine where problems are likely to occur, and set breakpoints in these problem areas. If your program crashes, first determine which line causes it to crash, then set a breakpoint just before that line.

You can use several dbx commands to trace a variable's value. Here's a simple method for tracing a program variable:

Procedure 1-2. Tracing program variables

  1. Use the stop command (see “Setting Breakpoints” in Chapter 6) to set breakpoints in the program at locations where you want to examine the state of the program stack or the values stored in program variables.

  2. Use the run or rerun command (described in “Running Your Program (run, rerun, and sort)” in Chapter 2) to run your program under dbx. The program stops at the first breakpoint that it encounters during execution.

  3. Examine the program variable as described in “Displaying the Value of a Variable” in Chapter 5. Examine the program stack as described in “Examining the Stack” in Chapter 5.

  4. Use the cont command (see “Continuing Execution after a Breakpoint” in Chapter 6) to continue execution past a breakpoint. However, you cannot continue execution past a line that crashes the program.

Studying a New Program

Use dbx to examine the flow of control in a program. When studying the flow of control within a program, use the dbx commands stop, run/rerun, print, next, step, and cont. Use the following procedure to study a new program.

Procedure 1-3. Studying a new program

  1. Use the stop command to set breakpoints in the program. When you execute the program under dbx, it stops execution at the breakpoints.

    If you want to review every line in the program, set a breakpoint on the first executable line. If you don't want to look at each line, set breakpoints just before the sections you intend to review.

  2. Use the run and rerun commands to run the program under dbx. The program stops at the first breakpoint.

  3. Use the print command to print the value of a program variable at a breakpoint.

  4. Use the step, next, or cont command to continue past a breakpoint and execute the rest of the program.

Another tool that you can use to follow the execution of your program is the trace command (described in “Tracing Program Execution” in Chapter 6). With it you can examine:

  • Values of variables at specific points in your program or whenever variables change value.

  • Parameters passed to and values returned from functions.

  • Line numbers as they are executed.

Avoiding Common Pitfalls

You may encounter some problems when you debug a program. Common problems and their solutions are listed below.

  • If dbx does not display variables, recompile the program with the -g compiler option. Note that in some cases, this may cause the problem to go away, or its symptoms to change.

  • If the debugger's listing seems confused, try separating the lines of source code into logical units. The debugger may get confused if more than one source statement occurs on the same line.

  • If the debugger's executable version of the code doesn't match the source, recompile the source code. The code displayed in the debugger is identical to the executable version of the code.

  • If code appears to be missing, it may be contained in an include file or a macro. The debugger treats macros as single lines. To debug a macro, expand the macro in the source code.