Chapter 4. Controlling dbx

This chapter describes features of dbx that affect its operation while debugging a program. Specifically, this chapter covers:

Creating and Removing dbx Variables

dbx allows you to define variables that you can use within dbx to store values. These variables exist entirely in dbx; they are not part of your program. You can use dbx variables for a variety of purposes while debugging. For example, you can use dbx variables as temporary storage, counters, or pointers that you use to step through arrays.

dbx also provides many predefined variables that control how various dbx commands function. Appendix C, "Predefined dbx Variables" provides a complete list of predefined dbx variables and their purposes.

A dbx variable does not have a fixed type. You can assign a dbx variable any type of value, even if it already has a value of a different type. However, a variable predefined by dbx does have a fixed predefined type.

You can use almost any name for dbx variables. A good practice to follow is to use a dollar sign ($) as the first character of all dbx variables to prevent conflicts with most program variable names. All of dbx's predefined variables begin with a dollar sign.

The commands described in this section apply only to the manipulations of dbx variables, not program variables. "Displaying and Changing Program Variables" describes how to manipulate program variables.

Setting dbx Variables

The set command sets a dbx variable to a given value, defining the variable if it does not exist:

set var = exp 

Define (or redefine) the specified dbx variable, setting its value to that of the expression you provide.

You can display the value of a variable with the print command. For example:

(dbx) set $k = 1
(dbx) print $k
1
(dbx) set $k = $k +23
(dbx) print $k
24
(dbx) print $k / 11
2

In the above example, dbx performs an integer division because both the variable $k and the constant 11 are integers. If you assign a floating point value to $k and evaluate the expression again, dbx performs a floating point division:

(dbx) set $k = 24.0
(dbx) print $k
24.0
(dbx) print $k / 11
2.1818181818181817


Note: We recommend that you begin a dbx variable with a $ to avoid confusion with a program variable. A dbx variable without a leading $ hides any program variable that has the same name. The only way to see the program variable is to remove the dbx variable with an unset command.


Listing dbx Variables

If you enter the set command without providing any arguments, dbx displays (in alphabetical order) a list of all currently defined dbx variables, including predefined variables. Partial output looks like this:

(dbx) set
$addrfmt        "0x%x"
$addrfmt64      "0x%llx"
$assignverify   1
$casesense      2
$ctypenames     1
$curevent       3
$curline        44
$curpc          268439708
...
$stacktracelimit        1024
$stdc           0
$stepintoall    0
$tagfile        "tags"

Removing Variables

The unset command removes a dbx variable. For example, to delete the variable $k, enter:

(dbx) unset $k

Using the History Feature and the History Editor

The dbx history feature is similar to the C shell's history feature in that it allows you to repeat commands that you have entered previously. However, unlike the C shell's history feature, dbx does not allow you to execute a history command anywhere except the beginning of a line. Also, dbx does not support history substitution of command arguments such as the C shell !$ argument.

Examining the History List

dbx stores all commands that you enter in the history list. The value of the dbx variable $lines determines how many commands are stored in the history list. The default value is 100.

Display the history list with the history command. For example, after setting a breakpoint, running a program, and examining some variables, your history list might look something like this:

(dbx) history
  1     set $prompt = "(dbx)"
  2     set $page=0
  3     set $pimode=1
  4     stop in main
  5     history

Repeating Commands

You can execute any of the commands contained in the history list. Each history command begins with an exclamation point (!):

!! 

Repeats the previous command. If the value of the dbx variable $repeatmode is set to 1, then entering a carriage return at an empty line is equivalent to executing !!. By default, $repeatmode is set to 0.

!string 

Repeats the most recent command that starts with the specified string.

!integer 

Repeats the command associated with the specified integer in the history list.

!-integer 

Repeats the command that occurred integer times before the most recent command. Entering !-1 executes the previous command, !-2 the command before that, and so forth.

You can use the !! command to facilitate single-stepping through your program. (Single-stepping is described in "Stepping Through Your Program".) The following illustrates using the next command to execute 5 lines of source code and then using the !! command to repeat the next command.

For example:

(dbx) next 5
Process 22545 (test) stopped at [main:60 ,0x10001150]
  60  total += j;
(dbx) !!
(!! = next 5)
Process 22545 (test) stopped at [main:65 ,0x100011a0]
  65  printf("i = %d, j = %d, total = %d\n",i,j,total);

Another convenient way to repeat a commonly used command is with !string. For example, suppose that you occasionally print the values of certain variables using the printf command while running your program under dbx. (The printf command is described in "Printing Expressions".) In this case, as long as you do not enter any command beginning with "pr" after you enter the printf command, you can repeat the printf command by entering !pr. For example:

(dbx) printf "i = %d, j = %d, total = %d\n", i, j, total
i = 4, j = 25, total = 1
  ...
(dbx) !pr
i = 12, j = 272, total = 529

Using !integer, you can repeat any command in the history list. If you want to repeat the printf command, but you have entered a subsequent print command, examine the history list and then explicitly repeat the printf command using its reference number. For example:

(dbx) history
  1     set $prompt = "(dbx)"
  2     set $page=0
  ...
  45    printf "i = %d, j = %d, total = %d\n", i, j, total
  46    next
  ...
  49    print j
  ...
  53    history
(dbx) !45
(!45 = printf "i = %d, j = %d, total = %d\n", i, j, total)
i = 9, j = 43, total = 1084

The History Editor

The history editor, hed, lets you use your favorite editor on any or all of the commands in the current dbx history list. When you enter the hed command, dbx copies all or part of the history list into a temporary file that you can edit. When you quit the editor, any commands left in this temporary file are automatically executed by dbx.

If you have set the dbx variable $editor to the name of an editor, the hed command invokes that editor. If you have not set the dbx variable $editor, dbx checks whether you have set the environment variable EDITOR and, if so, invokes that editor. If you have not set either the dbx variable or the environment variable, dbx invokes the vi editor.

The syntax for the hed commands is:

hed 

Edits only the last line of the history list (the last command executed).

hed num1 

Edits line num1 in the history list.

hed num1,num2 


Edits the lines in the history list from num1 through num2.

hed all 

Edits the entire history list.

By default, dbx doesn't display the commands that it executes as a result of the hed command (the dbx variable $pimode is set to 0). If $pimode is set to 1, dbx displays the commands as it executes them. See $pimode in Appendix C, "Predefined dbx Variables" for more information.

Creating and Removing dbx Aliases

You can create dbx aliases for debugger commands. Use these aliases as you would any other dbx command. When dbx encounters an alias, it expands the alias using the definition you provided.

dbx has a group of predefined aliases that you can modify or delete. These aliases are listed and described in Appendix B, "Predefined Aliases."

If you find that you often create the same aliases in your debugging sessions, you can include their definitions in your .dbxinit file so that they are automatically defined for you. See "Automatically Executing Commands on Startup" for more information on the .dbxinit file.

Listing Aliases

You can display the definition of aliases using the alias command:

alias 

Lists all existing aliases.

alias name 

Lists the alias definition for name.

For example, to display the definitions of the predefined aliases "l" and "bp," enter:

(dbx) alias l
"list"
(dbx) alias bp
"stop in"

Creating Command Aliases

You can use the alias command to define new aliases:

alias name command 


Defines name as an alias for command.

alias name "string" 


Defines name as an alias for string. With this form of the alias command, you can provide command arguments in the alias definition.

alias name(arg1 [, ... argN]) "string" 


Defines name as an alias for string. arg1 through argN are arguments to the alias, appearing in the string definition. When you use the alias, you must provide values for the arguments, which dbx then substitutes in string.

The simplest form of an alias is to redefine a dbx command with a short alias. Many of the predefined dbx aliases fall into this category: "a" is an alias for the assign command, "s" is an alias for the step command. When you use one of these aliases, dbx simply replaces it with the command for which it is an alias. Any arguments that you include on the command line are passed to the command.

For example, if you to create "gf" as an alias for the givenfile command, enter:

(dbx) alias gf givenfile
(dbx) alias gf
"givenfile"
(dbx) gf
Current givenfile is test
(dbx) gf test2
Process 22545 (test) terminated
Executable /usr/var/tmp/dbx_examples/test2
(dbx) gf
Current givenfile is test2

More complex alias definitions require more than the name of a command. In these cases, you must enclose the entire alias definition string in double quotation marks. For example, you can define a brief alias to print the value of a variable that you commonly examine. Note that you must use the escape character (\) to include the double quotation marks as part of the alias definition. For example:

(dbx) alias pa "print \"a =\", a"
(dbx) alias pa
"print "a =", a"
(dbx) pa
a = 3

You can also define an alias so that you can pass arguments to it, much in the same way that you can provide arguments in a C language macro definition. When you use the alias, you must include the arguments. dbx then substitutes the values that you provide in the alias definition.

To illustrate this, consider the following alias definition:

(dbx) alias p(arg1, arg2, arg3, arg4) "print '|arg1|arg2|arg3|arg4|'"
(dbx) alias p
(arg1, arg2, arg3, arg4)"print '|arg1|arg2|arg3|arg4|'"

The "p" alias takes four arguments and prints them surrounded by vertical bars (|). For example:

(dbx) p(1,2,3,4)
|1|2|3|4|
(dbx) p( first, second, 3rd,4)
| first| second| 3rd|4|

In the previous example, dbx retains any spaces that you enter when calling an alias.

You can also omit arguments when calling an alias as long as you include the commas as argument separators in the alias call:

(dbx) p(a,,b,c)
|a||b|c|
(dbx) p(,first missing, preceding space,)
||first missing| preceding space||
(dbx) delete
delete

Removing Command Aliases

The unalias command removes the alias you provide as an argument. For example, to remove the "pa" alias defined in the previous section, enter:

(dbx) unalias pa

You can remove any of the predefined dbx aliases; however, these aliases are restored the next time you start dbx.

Alias Example

One way to follow linked lists is to use aliases and casts, another is to use the duel command (See "Using the High-Level Debugging Language duel" in Chapter 5). This example shows how to construct an alias that follows a simple linked list with members defined by the following structure:

struct list { struct list *next; int value; };

In this example, a dbx variable called $p is used as a pointer to a member of the linked list. You can define an alias called "foll" to print the contents of the list member to which $p currently points and then advance to the next list member. Because the command is too long to fit onto one line, this example uses the backslash character (\) to continue the command on a second line:

(dbx) alias foll "print *(struct list *)$p ; \
set $p = (long)((struct list *)($p))->next"

Casting $p to an integer type when following the link (the second assignment in the alias) is essential. If omitted, dbx may leave the $p reference symbolic and if so, goes into an infinite loop. (Type Ctrl-c to interrupt dbx if it gets into the infinite loop.)

Before using this alias, you must set $p to point at the first list member. In this example, assume that the program variable top points to the first list member. Then you can use the "foll" alias to follow the linked list, printing the contents of each member as you proceed:

(dbx) set $p = top
(dbx) foll
struct list {
    next = 0x7fffc71c
    value = 57
} 
(dbx) foll
struct list {
    next = 0x7fffc724
    value = 3
} 
(dbx) foll
struct list {
    next = 0x7fffc72c
    value = 12
}

Recording and Playing Back dbx Input and Output

dbx allows you to play back your input and record dbx's output. dbx saves the information that you capture in files, which allows you to create command scripts that you can use in subsequent dbx sessions.

Recording Input

Use the record input command to start an input recording session. Once you start an input recording session, all commands to dbx are copied to the specified file. If the specified file already exists, dbx appends the input to the existing file. You can start and run as many simultaneous dbx input recording sessions as you need.

Each recording session is assigned a number when you begin it. Use this number to reference the recording session with the unrecord command described in "Ending a Recording Session".

After you end the input recording session, use the command file with the playbackinput or pi commands to execute again all the commands saved to the file. See "Playing Back Input".

For example, to save the recorded input in a file called script, enter:

(dbx) record input script
[4] record input script (0 lines)

If you do not specify a file to record input, dbx creates a temporary dbx file in the /tmp directory. The name of the temporary file is stored in the dbx variable $defaultin. You can display the temporary filename using the print command:

(dbx) print $defaultin

Because the dbx temporary files are deleted at the end of the dbx session, use the temporary file to repeat previously executed dbx commands in the current debugging session only. If you need a command file for use in subsequent dbx sessions, you must specify the filename when you invoke record input. If the specified file exists, the new input is appended to the file.

Ending a Recording Session

To end input or output recording sessions, use the unrecord command.

unrecord session1 [, session2 ...] 


Turns off the specified recording session(s) and closes the file(s) involved.

unrecord all 

Turns off all recording sessions and closes all files involved.

For example, to stop recording session 4, enter the dbx command:

(dbx) unrecord 4

To stop all recording sessions, enter:

(dbx) unrecord all

The dbxstatus command does not report on recording sessions. To see whether or not any active recording sessions exist, use the record command described in "Examining the Record State".

Playing Back Input

Use playback input to execute commands that you recorded with the record input command. Two aliases exist for playback input: pi and source.) If you don't specify a filename, dbx uses the current temporary file that it created for the record input command. If you set the dbx variable $pimode to nonzero, the commands are printed out as they are played back. By default, $pimode is set to zero.

Recording Output

Use the record output command to start output recording sessions within dbx. During an output recording session, dbx copies its screen output to a file. If the specified file already exists, dbx appends to the existing file. You can start and run as many simultaneous dbx output recording sessions as you need.

By default, the commands you enter are not copied to the output file; however, if you set the dbx variable $rimode to a nonzero value, dbx also copies the commands you enter.

Each recording session is assigned a number when you begin it. Use this number to reference the recording session with the unrecord command described in "Ending a Recording Session".

The record output command is very useful when the screen output is too large for a single screen (for example, printing a large structure). Within dbx, you can use the playback output command (described in "Playing Back Output") to look at the recorded information. After quitting dbx, you can review the output file using any IRIX system text viewing command (such as vi(1)).

For example, to record the dbx output in a file called gaffa, enter:

(dbx) record output gaffa

To record both the commands and the output, enter:

(dbx) set $rimode=1
(dbx) record output gaffa

If you omit the filename, dbx saves the recorded output in a temporary file in /tmp. The temporary file is deleted at the end of the dbx session. To save output for use after the dbx session, you must specify the filename when giving the record output command. The name of the temporary file is stored in the dbx variable $defaultout.

To display the temporary filename, type:

(dbx) print $defaultout

Playing Back Output

The playback output command displays output saved with the record output command. This command works the same as the cat(1) command. If you don't specify a filename, dbx uses the current temporary file created for the record output command.

For example, to display the output stored in the file script, enter:

(dbx) playback output script

Examining the Record State

The record command displays all record input and record output sessions currently active. For example:

(dbx) record
[4] record input /usr/demo/script (12 lines)
[5] record output /tmp/dbxoXa17992 (5 lines)

Executing dbx Scripts

You can create dbx command scripts using an external editor and then execute these scripts using the pi or playback input command. This is a convenient method for creating and executing automated test scripts.

You can include comments in your command scripts by using a single pound sign (#) to introduce a comment. To include a # operator (described in "Operators") in a dbx script, use two pound signs (for example, ##27). When dbx sees a pound sign in a script file, it interprets all characters between the pound sign and the end of the current line as a comment.