[ Bottom of Page | Previous Page | Next Page | Contents | Index | Library Home | Legal | Search ]

General Programming Concepts:
Writing and Debugging Programs

Displaying and Manipulating the Source File with the dbx debug Program

You can use the dbx debug program to search through and display portions of the source files for a program.

You do not need a current source listing for the search. The dbx debug program keeps track of the current file, current procedure, and current line. If a core file exists, the current line and current file are set initially to the line and file containing the source statement where the process ended. This is only true if the process stopped in a location compiled for debugging.

Changing the Source Directory Path

By default, the dbx debug program searches for the source file of the program being debugged in the following directories:

You can change the list of directories to be searched by using the -I option on the dbx invocation line or issuing the use subcommand within the dbx program. For example, if you moved the source file to a new location since compilation time, you might want to use one of these commands to specify the old location, the new location, and some temporary location.

Displaying the Current File

The list subcommand allows you to list source lines.

The $ (dollar sign) and @ (at sign) symbols represent SourceLineExpression and are useful with the list, stop, and trace subcommands. The $ symbol represents the next line to be run. The @ symbol represents the next line to be listed.

The move subcommand changes the next line number to be listed.

Changing the Current File or Procedure

Use the func and file subcommands to change the current file, current procedure, and current line within the dbx program without having to run any part of your program.

Search through the current file for text that matches regular expressions. If a match is found, the current line is set to the line containing the matching text. The syntax of the search subcommand is:

/ RegularExpression [/] Searches forward in the current source file for the given expression.
? RegularExpression [?] Searches backward in the current source file for the given expression.

If you repeat the search without arguments, the dbx command searches again for the previous regular expression. The search wraps around the end or beginning of the file.

You can also invoke an external text editor for your source file using the edit subcommand. You can override the default editor (vi) by setting the EDITOR environment variable to your desired editor before starting the dbx program.

The dbx program resumes control of the process when the editing session is completed.

 

Debugging Programs Involving Multiple Threads

Programs involving multiple user threads call the subroutine pthread_create. When a process calls this subroutine, the operating system creates a new thread of execution within the process. When debugging a multi-threaded program, it is necessary to work with individual threads instead of with processes. The dbx program only works with user threads: in the dbx documentation, the word thread is usually used alone to mean user thread. The dbx program assigns a unique thread number to each thread in the process being debugged, and also supports the concept of a running and current thread:

Running thread The user thread that was responsible for stopping the program by hitting a breakpoint. Subcommands that single-step the program work with the running thread.
Current thread The user thread that you are examining. Subcommands that display information work in the context of the current thread.

By default, the running thread and current thread are the same. You can select a different current thread by using the thread subcommand. When the thread subcommand displays threads, the current thread line is preceded by a >. If the running thread is not the same as the current thread, its line is preceded by a *.

Identifying Thread-Related Objects

Threads use mutexes and condition variables to synchronize access to resources. Threads, mutexes, and condition variables are created with attribute objects that define how they behave. The dbx program automatically creates several variables that identify these various thread-related objects. For each object class, dbx maintains a numbered list and creates an associated variable for each object in the list. These variable names begin with a $ (dollar sign), followed by a letter indicating the object class (a, c, m, or t), followed by a number indicating the object's position in the class list. The letters and their associated object classes are as follows:

For example, $t2 corresponds to the second thread in the dbx thread list. In this case, 2 is the object's thread number, which is unrelated to the kernel thread identifier (tid). You can list the objects in each class using the following dbx subcommands: attribute, condition, mutex, and thread. For example, you can simply use the thread subcommand to list all threads.

The dbx program automatically defines and maintains the variable $running_thread, which identifies the thread that was running when a breakpoint was hit.

Breakpoints and Threads

If your program has multiple user threads, simply setting a breakpoint on a source line will not guarantee that a particular thread will hit the breakpoint, because several threads can execute the same code. If any thread hits the breakpoint, all the threads of the process will stop.

If you want to specify which thread is to hit the breakpoint, you can use the stop or stopi subcommands to set a conditional breakpoint. The following aliases set the necessary conditions automatically:

These aliases stop the thread at the specified function or source line number, respectively. ThreadNumber is the number part of the symbolic thread name as reported by the thread subcommand (for example, 2 is the ThreadNumber for the thread name $t2).

For example, the following subcommand stops thread $t1 at function func1:

(dbx) bfth (func1, 1)

and the following subcommand stops thread $t2 at source line 103:

(dbx) blth (103, 2)

If no particular thread was specified with the breakpoint, any thread that executes the code where the breakpoint is set could become the running thread.

Thread-Related subcommands

The dbx debug program has the following subcommands that enable you to work with individual attribute objects, condition variables, mutexes, and threads:

attribute Displays information about all attribute objects, or attribute objects specified by attribute number.
condition Displays information about all condition variables, condition variables that have waiting threads, condition variables that have no waiting threads, or condition variables specified by condition number.
mutex Displays information about all mutexes, locked or unlocked mutexes, or mutexes specified by mutex number.
thread Displays information about threads, selects the current thread, and holds and releases threads.

A number of subcommands that do not deal with threads directly are also affected when used to debug a multi-threaded program:

print If passed a symbolic object name reported by the thread, mutex, condition, or attribute subcommands, displays status information about the object. For example, to display the third mutex and the first thread:

(dbx) print $m3, $t1

stop, stopi If a single thread hits a breakpoint, all other threads are stopped as well, and the process timer is halted. This means that the breakpoint does not affect the global behavior of the process. These normal breakpoints are global, meaning that they can stop any thread.

If you want to specify which thread will hit the breakpoint, you must use a condition as shown in the following example, which ensures that only thread $t5 can hit the breakpoint set on function f1:

(dbx) stopi at &f1 if ($running_thread == 5)

This syntax also works with the stop subcommand. Another way to specify these conditions is to use the bfth and blth aliases, as explained in the section "Breakpoints and Threads" (Breakpoints and Threads).

step, next, nexti All threads resume execution during the step, next, and nexti subcommands. If you want to step the running thread only, set the $hold_next dbx debug program variable; this holds all threads except the running thread during these subcommands.
stepi The stepi subcommand executes the specified number of machine instructions in the running thread only. Other threads in the process being debugged will not run during the stepi subcommand.
trace, tracei A specific user thread can be traced by specifying a condition with the trace and tracei subcommands as shown in the following example, which traces changes made to var1 by thread $t1:

(dbx) trace var1 if ($running_thread == 1)

If a multi-threaded program does not protect its variables with mutexes, the dbx debug program behavior may be affected by the resulting race conditions. For example, suppose that your program contains the following lines:

59 var = 5;

60 printf("var=%d\n", var);

If you want to verify that the variable is being initialized correctly, you could type:

stop at 60 if var==5

The dbx debug program puts a breakpoint at line 60, but if access to the variable is not controlled by a mutex, another thread could update the variable before the breakpoint is hit. This means that the dbx debug program would not see the value of five and would continue execution.

Debugging Programs Involving Multiple Processes

Programs involving multiple processes call the fork and exec subroutines. When a program forks, the operating system creates another process that has the same image as the original. The original process is called the parent process, the created process is called the child process.

When a process performs an exec subroutine, a new program takes over the original process. Under normal circumstances, the debug program debugs only the parent process. However, the dbx program can follow the execution and debug the new processes when you issue the multproc subcommand. The multproc subcommand enables multiprocess debugging.

When multiprocess debugging is enabled and a fork occurs, the parent and child processes are halted. A separate virtual terminal Xwindow is opened for a new version of the dbx program to control running of the child process:

(dbx) multproc on
(dbx) multproc
multi-process debugging is enabled
(dbx) run

When the fork occurs, execution is stopped in the parent, and the dbx program displays the state of the program:

application forked, child pid = 422, process stopped, awaiting input
stopped due to fork with multiprocessing enabled in fork at 0x1000025a (fork+0xe)
(dbx)

Another virtual terminal Xwindow is then opened to debug the child process:

debugging child, pid=422, process stopped, awaiting input
stopped due to fork with multiprocessing enabled in fork at 0x10000250
10000250 (fork+0x4) )80010010    1       r0,0x10(r1)
(dbx)

At this point, two distinct debugging sessions are running. The debugging session for the child process retains all the breakpoints from the parent process, but only the parent process can be rerun.

When a program performs an exec subroutine in multiprocess debugging mode, the program overwrites itself, and the original symbol information becomes obsolete. All breakpoints are deleted when the exec subroutine runs; the new program is stopped and identified for the debugging to be meaningful. The dbx program attaches itself to the new program image, makes a subroutine to determine the name of the new program, reports the name, and then prompts for input. The prompt is similar to the following:

(dbx) multproc
Multi-process debugging is enabled
(dbx) run
Attaching to program from exec . . . 
Determining program name . . . 
Successfully attached to /home/user/execprog . . . 
Reading symbolic information . . . 
(dbx)

If a multi-threaded program forks, the new child process will have only one thread. The process should call the exec subroutine. Otherwise, the original symbol information is retained, and thread-related subcommands (such as thread) display the objects of the parent process, which are obsolete. If an exec subroutine is called, the original symbol information is reinitialized, and the thread-related subcommands display the objects in the new child process.

It is possible to follow the child process of a fork without a new Xwindow being opened by using the child flag of the multproc subcommand. When a forked process is created, dbx follows the child process. The parent flag of the multproc subcommand causes dbx to stop when a program forks, but then follows the parent. Both the child and parent flags follow an execed process. These flags are very useful for debugging programs when Xwindows is not running.

[ Top of Page | Previous Page | Next Page | Contents | Index | Library Home | Legal | Search ]