Chapter 5. Examining and Changing Data

This chapter describes how to examine and change data in your program while running it under dbx. Topics covered include:

Using Expressions

Many dbx commands accept one or more expressions as arguments. Expressions can consist of constants, dbx variables, program variables, and operators. This section discusses operators and constants. “Creating and Removing dbx Variables” describes dbx variables, and “Displaying and Changing Program Variables” describes program variables.

Operators

In general, dbx recognizes most expression operators from C, Fortran 77, and Pascal. dbx also provides some of its own operators. Operators follow the C language precedence. You can also use parentheses to explicitly determine the order of evaluation.

Table 5-1 lists the operators provided by dbx.

Table 5-1. dbx Language Independent Operators

Operator

Description

not

Unary operator returning false if the operand is true

or

Binary logical operator returning true if either operand is nonzero

xor

Binary operator returning the exclusive-OR of its operands

/

Binary division operator (you can also use “//” for division)

div

Binary operator that coerces its operands to integers before dividing

mod

Binary operator returning op1 modulo op2. This is equivalent to the C “%” operator

# exp

Unary operator returning the address of source line specified by exp

" file " # exp

Unary operator returning the address of source line specified by exp in the file specified by file

proc # exp

Unary operator returning the address of source line specified by exp in the file containing the procedure proc

The # operator takes the line number specified by the expression that follows it and returns the address of that source line. If you precede the # operator with a filename enclosed in quotation marks, the # operator returns the address of the line number in the file you specify. If you precede the # operator with the name of a procedure, dbx identifies the source file that contains the procedure and returns the address of the line number in that file.

For example, to print the address of line 27 in the current source file, enter:

(dbx) print #27

To print the address of line 27 in the source file foo.c (assuming that foo.c contains source that was used to compile the current object file), enter:

(dbx) print "foo.c" #27

To print the address of line 27 in the source file containing the procedure bar (assuming that bar is a function in the current object file), enter:

(dbx) print bar #27


Note: A pound sign (#) introduces a comment in a dbx script file. 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. See “Executing dbx Scripts” for more information on dbx script files. To include the # operator in a dbx script, use two pound signs (for example, ##27).

Table 5-2 lists the C language operators recognized by dbx.

Table 5-2. C Language Operators Recognized by dbx

Type

Operators

Unary

! & + - * sizeof()

Binary

% << >> == <= >= != < > & && | || + - * / [ ] -> .



Note: C does not allow you to use the sizeof operator on bit fields. However, dbx allows you to enter expressions using the sizeof operator on bit fields; in these cases, dbx returns the number of bytes in the data type of bit fields (such as int or unsigned int). The C language “^” exclusive-OR operator is not supported. Use the dbx “xor” operator instead.

Table 5-3 lists the Pascal operators recognized by dbx.

Table 5-3. Pascal Operators Recognized by dbx

Type

Operators

Unary

not ^ + -

Binary

mod = <= >= <> < > and or + - * / div [ ]

Table 5-4 lists the Fortran 77 language operators recognized by dbx. Note that dbx does not recognize Fortran logical operators (such as .or. and .TRUE.).

Table 5-4. Fortran 77 Operators Recognized by dbx

Type

Operators

Unary

+ -

Binary

+ - * /



Note: Fortran array subscripting must use “[]” not “()”. For example, if x is a two-dimension Fortran array, print x(1,2) won't work; however, print x[1,2] will work. If an array is defined as a Fortran array, refer to it with the standard Fortran subscript ordering.


Constants

You can use both numeric and string constants under dbx.


Note: Expressions cannot contain constants defined by #define declarations to the C preprocessor.


Numeric Constants

In numeric expressions, you can use any valid integer or floating point constants. By default, dbx assumes that numeric constants are in decimal. You can set the default input base to octal by setting the dbx variable $octin to a nonzero value. You can set the default input base to hexadecimal by setting the dbx variable $hexin to a nonzero value. If you set both $octin and $hexin to nonzero values, $hexin takes precedence.

You can override the default input type by prefixing “0x” to indicate a hexadecimal constant, or “0t” to indicate a decimal constant. For example, “0t23” is decimal 23 (which equals hexadecimal 0x17), and “0x2A” is hexadecimal 2A (which equals decimal 42).

By default, dbx prints the value of numeric expressions in decimal. You can set the default output base to octal by setting the dbx variable $octints to a nonzero value. You can set the default output base to hexadecimal by setting the dbx variable $hexints to a nonzero value. If you set both $octints and $hexints to nonzero values, $hexints takes precedence.

String Constants

Most dbx expressions cannot include string constants. The print and printf commands are two of the dbx commands that accept string constants as arguments. You can also use the set command to assign a string value to a dbx variable.

Otherwise, string constants are useful only as arguments to functions that you call interactively. See “Using Interactive Function Calls” for information on interactive function calls.

You can use either the double-quote character (") or the single-quote character (') to quote strings in dbx.

In general, dbx recognizes the following escape sequences in quoted strings (following the standard C language usage):

\\ \n \r \f \b \t \' \" \a

Printing Expressions

dbx provides the following commands for printing values of expressions:

print [exp1 [, exp2, ...] ]  


Prints the value(s) of the specified expression(s).

printd [exp1 [, exp2, ... ] ] 


Prints the value(s) of the specified expression(s) in decimal. (pd is an alias for printd. See “Creating and Removing dbx Variables” for more information about dbx aliases.)

printo [exp1 [, exp2, ... ] ] 


Prints the value(s) of the specified expression(s) in octal. (po is an alias for printo.)

printx [exp1 [, exp2, ... ] ] 


Prints the value(s) of the specified expression(s) in hexadecimal. (px is an alias for printx.)

The variable types are listed in Table 5-5.

Table 5-5. Variable Types

Type

Variable Name

Value

signed char

sc

0xff

unsigned char

usc

0xff

signed short

ssh

0xffff

unsigned short

ush

0xffff

Examples include:

(dbx) pd sc
-1
(dbx) pd ssh 
-1
(dbx) px sc 
0xff 
(dbx) px ssh
0xffff
(dbx) pd usc
255
(dbx) pd ush
65535

dbx always prints the bits in the appropriate type. pd is an exception; it expands signed types with sign extension so the decimal value looks correct.

Another example:

(dbx) print sc, usc
'\377' '\377'

If $hexchars is set, this command displays '0xff' `0xff'. (This is a change from releases previous to IRIX 5.2. Previously, the px, po cases on signed short expanded to 32 bits, so px sc printed 0xffffffff.)

If the printed data type is pointer, dbx uses the format specified in the $addrfmt or $addrfmt64 predefined dbx variable ($addrfmt64 is used on only 64-bit processes).

printf string [, exp1 [, exp2, ... ] ]  


Print the value(s) of the specified expression(s) in the format specified by the string, string. The printf command supports all formats of the IRIX printf command except “%s.” For a list of formats, see the printf(3S) reference page.

Using Data Types and Type Coercion (Casts)

You can use data types for type conversion (casting) by including the name of the data type in parentheses before the expression you want to cast. For example, to convert a character into an integer, use (int) to cast the value:

(dbx) print (int) 'b'
98

To convert an integer into a character, use (char) to cast the value:

(dbx) print (char) 67
'C'

This is standard C language type casting.

Displaying and Changing Program Variables

You can use the value of program variables in dbx expressions. You can also change the value of program variables while running your program under dbx control.

Qualifying Variable Names

You can use the same name for different variables multiple times in the same program. For example, you can use a temporary counter named “i” in many different functions.

During program execution, this potential ambiguity presents no problem. The scope of each variable is local; space is allocated for it when the function is called and freed when the function returns.

Under dbx, however, you need to be able to distinguish between different variables that may have the same name. To do so, you can qualify a reference to a variable to specify its scope.

dbx qualifies variables with the file (also called module), the procedure, a block, or a structure. You can manually specify the full scope of a variable by separating scopes with periods. For example, in the expression:

mrx.main.i

i is the variable name, main is a procedure in which it appears, and mrx is the source file (omitting the file extension) in which the procedure is defined.

To illustrate, consider a C program called test that contains a function compare. In this example, the variable i is declared in both the main procedure and the compare function:

int compare ( int );

main( argc, argv )

int argc;
char **argv;
{
   int i;
...
}

int compare ( arg1, arg2 )
{
   int i;
...
}

To trace the value of the i that appears in the function compare, enter:

(dbx) trace test.compare.i

To print the value of the i that appears in the procedure main, enter:

(dbx) print test.main.i

A leading dot (a period at the beginning of the identifier) tells dbx that the first qualifier is not a module (file).

The leading dot is useful when a file and a procedure have the same name. For instance, suppose mrx.c contains a function called mrx. Further, suppose that mrx.c contains a global variable called mi and a local variable, also called mi. To refer to the global variable, use the qualified form .mrx.mi, and to refer to the local variable, use the qualified form mrx.mrx.mi.

Variable Scope

You can access the value of a variable only while it is in scope. The variable is in scope only if the block or procedure with which it is associated is active.

After you start your program, whenever your program executes a block or procedure that contains variables, your program allocates space for those variables and they “come into scope.” You may access the values of those variables as long as the block or procedure is active. Once the block or procedure ends, the space for those variables is deallocated and you may no longer access their values.

Displaying the Value of a Variable

You can display the value of a program variable using the print, printd, printf, printo, and printx commands and the pd, po, and px aliases described in “Printing Expressions”. For example, to print the value of the program variable total, enter:

(dbx) print total
235

The print command also displays arrays, structures, and other complex data structures. For example, if message is a character array (a string), dbx prints the string:

(dbx) print message
"Press <Return> to continue."

As a more complex example, consider a simple linked list stored as an array of elements, each element consisting of a pointer to the next element and an integer value. If the array is named list, print the entire array by entering:

(dbx) print array

dbx prints the value of each element in the array:

{
    [0] struct list {
        next = (nil)
        value = 1034
    }
    [1] struct list {
        next = 0x10012258
        value = 1031
    }
    [2] struct list {
        next = 0x10012270
        value = 1028
    }
    [3] struct list {
        next = 0x10012288
        value = 1025
    }
    [4] struct list {
        next = 0x100122a0
        value = 1022
    }
    [5] struct list {
        next = 0x100122b8
        value = 1019
    }
...
}

To print an individual element, enter a command such as:

(dbx) print array[5]
struct list {
    next = 0x100122b8
    value = 1019
}

No simple method exists for examining a portion of an array with the print command. However, if your array consists of simple elements such as integers or floating point values, you can directly examine the contents of memory using the / (examine forward) command described in “Examining Memory and Disassembling Code”.

Suppose a single-precision floating point array is named float_vals. To see the six consecutive elements beginning with the fifth element, enter:

(dbx) &float_vals[4] / 6f
10012018:  0.25000000000000000 0.20000000298023224 0.16666699945926666
0.14280000329017639
10012028:  0.12500000000000000 0.11111100018024445

Changing the Value of a Variable

The assign command changes the value of existing program variables. You can also use the assign command to change the value of machine registers, as described in “Changing Register Values”.

The syntax of the assign command is:

assign variable = expression 


Assigns the value of expression to the program variable, variable.

For example:

(dbx) assign x = 27
27
(dbx) assign y = 37.5
37.5

If you receive an incompatible types error when you try to assign a value to a pointer, use casts to make the assignment work. For example if next is a pointer to a structure of type “element,” you can assign next a null pointer by entering:

(dbx) assign *(int *) (&next) = 0
0
(dbx) assign next = 0
(nil)
(dbx) assign next = (struct list*) 0;
(nil)

In this example, nil denotes that the value of the pointer is 0; nil is similar to NULL in the C language.

Conflicts Between Variable Names and Keywords

When naming variables in your program, avoid using any dbx keywords. If you have a variable with the same name as a dbx keyword and you attempt to use that variable in a dbx command, dbx reports a syntax error.

If you do have a program variable with the same name as a dbx command, you can force dbx to treat it as a variable by enclosing the variable in parentheses. For example, if you try to print the value of a variable named in by entering the following command, dbx displays an error.

(dbx) print in

print in
      ^ syntax error
Suggestion: in is a dbx keyword; a revised command is in history.
Type !16 or !! to execute: print (in)

The correct way to display the value of input is to enter:

(dbx) print (in)
34

dbx keywords include:

all    not
and    or
at     pgrp
div    pid
if     sizeof
in     to
mod    xor

By default, dbx treats as keywords the following C type keywords:

signed     struct
unsigned   union
short      enum
long       double
int        float
char

However, if your program is not written in C or C++, you may wish to disable these keywords. The dbx variable $ctypenames determines whether or not C type keywords are treated as dbx keywords. If $ctypenames is set to 1 (the default), then C type keywords are treated as dbx keywords; if $ctypenames is set to 0, they are not.

Case Sensitivity in Variable Names

Whether or not dbx is case sensitive when it evaluates program variable names depends on the value of the dbx variable $casesense.

If $casesense is 2 (the default), then the language in which the variable was defined is taken into account (for example, C and C++ are case sensitive while Pascal and Fortran are not). If $casesense is 1, case is always checked. If $casesense is 0, case is always ignored. Note that file (module) names are always case sensitive since they represent UNIX filenames.

Determining the Scope of Variables

The which command allows you to determine the scope of variables. This command is useful for programs that have multiple variables with the same name occurring in different scopes.

The which command prints the fully qualified name of the active version of a specified variable. For example, to determine the scope of the variable i, enter:

(dbx) which i
.foo.foo2.i

In the example above, the variable i that is currently active is local to the procedure foo2 that appears in the module foo (corresponding to the file foo.c in a C language program).

Displaying Type Declarations

The whatis command displays the type declaration for a specified variable or procedure in your program.

For example, to display the type declaration for the variable i, enter:

(dbx) whatis i
int i;

The following example illustrates the output of whatis for an array of structures:

(dbx) whatis array
struct list {
    struct list* next;
    int value;
} array[12];

When you provide a procedure name to whatis, dbx reports the type of the value returned by the procedure and the types of all arguments to the procedure:

(dbx) whatis foo
int foo(i)
int i;
(dbx) whatis main
int main(argc, argv)
int argc;
char** argv;

Examining the Stack

Each time your program executes a procedure, the information about where in the program the call was made from is saved on a stack. The stack also contains arguments to the procedure and all of the procedure's local variables. Each procedure on the stack defines an activation level. Activation levels can also consist of blocks that define local variables within procedures.

The activation level determines the scope of many dbx commands and expressions. For example, unless you qualify a variable, as described in “Qualifying Variable Names” dbx assumes that variables you reference are local to the current activation level.

The most recently called procedure or block is numbered 0. The next active procedure (the one that called the current procedure) is numbered 1. The last activation level is always the main program block.

Printing Stack Traces

The where command prints stack traces. Stack traces show the current activation levels (procedures) of a program.

For example, consider the following stack trace for a program called test:

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

This program has four activation levels. The most recent, a call of the procedure foo2, is numbered 0. The currently selected activation level is 0, indicated by the “>” character.

The stack trace also reports that foo2 was passed one argument: the value 5 was assigned to the local variable i. The trace indicates that the program was stopped at line 44 of the file test.c, which translates to machine address 0x1000109c.

The stack trace reports similar information for the next two activation levels in this example. You can see that the function foo called foo2 from line 38 in test.c. In turn, foo was called by main at line 55 of the file test.c. Finally, the run-time start-up level was called at line 137 from the file ctrltext.s.

If you compile with g0 or with no g option, limited symbols are reported. In cases such as this, where detailed symbolic information is not available, the four hexadecimal values returned represent dbx's guess that the function has four integer arguments. The following example illustrates such a case:

(dbx) where
>  0 fooexample(0x300000000, 0x4000000ff, 0x5000000ff, 0x0) [“/usr/var/tmp/dbx_examples/test3.c”:10, 0x10000cf8]
   1 main(0x3, 0x4, 0x5, 0x0) [“/usr/var/tmp/dbx_examples/test3.c”:5, 0x10000cbc]
   2 __start() [“/shamu/lib/libc/libc_64/csu/crt1text.s”:137, 0x10000c64]
(dbx) quit
Process 22582 terminated
int fooexample(int,int,int);
int main()
{
       fooexample(3,4,5);
       return 0;
}
int fooexample(int i, int j, int k)
{
       int x = i + j + 3*k;
       return x;
}

The examples below show register values from code compiled without a g option. MIPS1 or MIPS2 code using the 32-bit ABI (for example, on an Indy):

(dbx) where
> 0 subr1(0x3, 0x7fffaf14, 0x7fffaf1c, 0x0) [“t.c”:3, 0x4009ec]
  1 test(0x3, 0x7fffaf14, 0x7fffaf1c, 0x0) [“t.c”:8, 0x400a10]
  2 main(0x1, 0x7fffaf14, 0x7fffaf1c, 0x0) [“t.c”:13, 0x400a48]
  3 __start() [“crt1text.s”:133, 0x40099c]

There are four hexadecimal values displayed in most lines of the code above since the 32-bit MIPS ABI has four integer argument passing registers. No user-useful registers are passed to __start().

MIPS3 or MIPS4 code using the 64-bit ABI (for example, on a Power Challenge):

(dbx) where
> 0 subr1(0x3, 0xffffffaed8, 0xffffffaee8, 0x0, 0x2f, 0x10, 0x0, 0xfbd82a0) [“/usr/people/doc/debug/t.c”:3, 0x10000c9c]
  1 test(0x3, 0xffffffaed8, 0xffffffaee8, 0x0, 0x2f, 0x10, 0x0, 0xfbd82a0) [“/usr/people/doc/debug/t.c”:9, 0x10000ce8]
  2 main(0x1000000ff, 0xffffffaed8, 0xffffffaee8, 0x0, 0x2f, 0x10, 0x0, 0xfbd82a0) [“/usr/people/doc/debug/t.c”:14, 0x10000d2c]
  3 __start() [“/shamu/redwood2/work/irix/lib/libc/libc_64/csu/crt1text.s”:137, 0x10000c70]

There are eight hexadecimal values displayed in most lines of the code above since the 64-bit MIPS ABI has eight integer argument passing registers. No user-useful registers are passed to __start().

The values listed as arguments are the integer argument-passing register values. Typically, only the 0 entry of the stack has those argument values correct. Correctness is not guaranteed because the code generator can overwrite the values, using the registers as temporary variables.

The debugger reports the integer argument-passing registers because this information may be of some value.

For example, for the code samples above, the following code calls subr1():

int test(void)
{
     subr1(3);
}

This code displays 0x3 as the argument register value. The other registers listed for subr1 contain arbitrary data.

Moving Within the Stack

The up and down commands move up and down the activation levels in the stack. These commands are useful when examining a call from one level to another. You can also move up and down the activation stack with the func command described in “Moving to a Specified Procedure”.

The up and down commands have the following syntax:

up [num]  

Moves up the specified number of activation levels in the stack. The default is one level.

down [num]  

Moves down the specified number of activation levels in the stack. The default is one level.

When you change activation levels, your scope changes. For example, unless you qualify a variable, as described in “Qualifying Variable Names”, dbx assumes that variables you reference are local to the current activation level. Also, dbx changes the current source file to the file containing the procedure's source.

Consider examining the stack trace for a program called test4 and moving up in the activation stack:

(dbx) where
>  0 foo2(i = 5) [“/usr/var/tmp/dbx_examples/foo.c”:46, 0x10001214]
   1 foo(i = 4) [“/usr/var/tmp/dbx_examples/foo.c”:40, 0x100011d4]
   2 main(argc = 1, argv = 0xffffffad78) [“/usr/var/tmp/dbx_examples/test4.c”:25, 0x10000fa0]
   3 __start() [“/shamu/lib/libc/libc_64/csu/crt1text.s”:137, 0x10000f34]
(dbx) print i
5
(dbx) up 
foo:  40  r = foo2(i+1);

The current activation level is now the procedure foo. As indicated in the output, the variable i receives the argument passed to foo and is therefore local to foo. The variable i at this activation level is different from the variable i in the foo2 activation level. You can reference the currently active i as “i”; whereas you must qualify the reference to the i in foo2:

(dbx) print i
4
(dbx) print foo2.i
<symbol not found>

Moving up one more activation level brings you to the main procedure:

(dbx) up
main:  25  j = foo(j);
(dbx) file
/usr/var/tmp/dbx_examples/test4.c

In this example, the source for main is in test4.c, whereas the source for foo and foo2 is in foo.c; therefore, dbx changes the current source file when you move up to the main activation level.

dbx resets the source file when you return to the foo2 activation level:

(dbx) down 2
foo2:  46  printf(“foo2 arg is %d\n”,i);
(dbx) file
/usr/var/tmp/dbx_examples/foo.c

Moving to a Specified Procedure

The func command moves you up or down the activation stack. You can specify the new activation level by providing either a procedure name or an activation level number.

The syntax for the func command is:

func {activation_level | procedure}  


Changes the current activation level. If you specify an activation level by number, dbx changes to that activation level. If you specify a procedure, dbx changes to the activation level of that procedure. If you specify a procedure name and that procedure has called itself recursively, dbx changes to the most recently called instance of that procedure.

func  

Displays the name of the procedure corresponding to the current activation level.

When you change your activation level, your scope changes. For example, unless you qualify a variable as described in “Qualifying Variable Names”, dbx assumes that variables you reference are local to the current activation level. Also, dbx changes the current source file to the one containing the procedure's source and the current line to the first line of the procedure.

You can also give the func command the name of a procedure that is not on the activation stack, even when your program is not executing. In this case, dbx has no corresponding activation level to make current. However, dbx still changes the current source file to the one containing the procedure's source and the current line to the first line of the procedure.

For example, consider the following activation stack:

(dbx) where
>  0 foo2(i = 5) [“/usr/var/tmp/dbx_examples/foo.c”:46, 0x10001214]
   1 foo(i = 4) [“/usr/var/tmp/dbx_examples/foo.c”:40, 0x100011d4]
   2 main(argc = 1, argv = 0xffffffad78) [“/usr/var/tmp/dbx_examples/test4.c”:25, 0x10000fa0]
   3 __start() [“/shamu/lib/libc/libc_64/csu/crt1text.s”:137, 0x10000f34]

In this case, you can go to the main activation stack by entering:

(dbx) func main
main:  25  j = foo(j);

This command changes the current activation level to “2” and changes the current source file to test4.c.

If you use the func command to go to a function that is not on the activation stack, dbx changes only the current source file to the one containing the procedure's source and the current line to the first line of the procedure:

(dbx) func bar
   3  {
(dbx) file
/usr/var/tmp/dbx_examples/bar.c

Printing Activation Level Information

The dump command prints information about the variables in an activation level:

dump  

Prints information about the variables in the current procedure.

dump procedure  

Prints information about the variables in the specified procedure. The procedure must be active. Starts searching for procedure at the current activation level as set by the up or down command. (See “Moving Within the Stack” for more information about the up and down commands.)

dump .  

Prints information about the variables in all procedures in all activation levels.

For example, executing dump while in a function called foo2 appears as:

(dbx) dump
foo2(i = 5) [“/usr/var/tmp/dbx_examples/foo.c”:46, 0x10001214]

To examine the information for the procedure main, enter:

(dbx) dump main
main(argc = 1, argv = 0xffffffad78) [“/usr/var/tmp/dbx_examples/test4.c”:25,
0x10000fa0]
j = 4
i = 12
r = <expression or syntax error>
a = 0
total = 0

To perform a complete dump of the program's active variables, enter:

(dbx) dump .
>  0 foo2(i = 5) [“/usr/var/tmp/dbx_examples/foo.c”:46, 0x10001214]
   1 foo(i = 4) [“/usr/var/tmp/dbx_examples/foo.c”:40, 0x100011d4]
r = 0
   2 main(argc = 1, argv = 0xffffffad78) [“/usr/var/tmp/dbx_examples/test4.c”:25, 0x10000fa0]
j = 4
i = 12
r = <bad operand>
a = 0
total = 0

Using Interactive Function Calls

You can interactively call a function in your program from dbx.

If the function returns a value, you can use that function in a normal dbx expression. For example, consider a function prime defined in your program that accepts an integer value as an argument, and returns 1 if the value is prime and 0 if it is not. You can call this function interactively and print the results by entering a command such as:

(dbx) print prime(7)
1

Using ccall

If your function does not return a value, or if you want to execute a function primarily for its side effects, you can execute the function interactively with the dbx command ccall:

ccall func(arg1, arg2, ... , argn)  


This command calls a function with the given arguments. Regardless of the language the function was written in, the call is interpreted as if it were written in C, and normal C calling conventions are used.


Note: Structure and union arguments to a function, and structure and union returns from a function, are not supported.

Functions called interactively honor breakpoints. Thus you can debug a function by setting breakpoints and then calling it interactively.

If you perform a stack trace using the where command while stopped in a routine executed interactively, dbx displays only those activation levels created by your interactive function call. The activation levels for your active program are effectively invisible. For example, a stack trace looks like this during an interactive function call:

(dbx) where
>  0 foo2(i = 9) [“/usr/var/tmp/dbx_examples/foo.c”:46, 0x10001214]
   1 foo(i = 8) [“/usr/var/tmp/dbx_examples/foo.c”:40, 0x100011d4]

===== interactive function call =====

   2 foo2(i = 5) [“/usr/var/tmp/dbx_examples/foo.c”:46, 0x10001214]
   3 foo(i = 4) [“/usr/var/tmp/dbx_examples/foo.c”:40, 0x100011d4]
   4 main(argc = 1, argv = 0xffffffad78) [“/usr/var/tmp/dbx_examples/test4.c”:25, 0x10000fa0]
   5 __start() [“/shamu/lib/libc/libc_64/csu/crt1text.s”:137, 0x10000f34]

If you stop execution of an interactively called function, you are responsible for eventually “unstacking” the call and returning from the function call. To unstack a call, you can complete the call using dbx commands such as cont, resume, next, or step as many times as necessary. If you run or rerun your program, dbx automatically unstacks all interactive function calls.

Using clearcalls

Another way to unstack an interactive function call is to execute the clearcalls command, which clears all stopped interactive calls.

(dbx) clearcalls

When stopped or faulted within one or more nested interactive calls, the clearcalls command removes these calls from the stack and returns the program to its regular callstack. This command is useful when a segmentation fault, infinite loop, or other fatal error is encountered within the interactive call.

When stopped in an interactive call, the call stack displayed by where shows the following line at the end of each stack of interactive call instantiation.

==== interactive function call ====

For example, if the procedure foo() is interactively called from main(), you see the following stack:

>  0 foo2(i = 9) [“/usr/var/tmp/dbx_examples/foo.c”:46, 0x10001214]
   1 foo(i = 8) [“/usr/var/tmp/dbx_examples/foo.c”:40, 0x100011d4]

===== interactive function call =====

   2 foo2(i = 5) [“/usr/var/tmp/dbx_examples/foo.c”:46, 0x10001214]
   3 foo(i = 4) [“/usr/var/tmp/dbx_examples/foo.c”:40, 0x100011d4]
   4 main(argc = 1, argv = 0xffffffad78) [“/usr/var/tmp/dbx_examples/test4.c”:25, 0x10000fa0]
   5 __start() [“/shamu/lib/libc/libc_64/csu/crt1text.s”:137, 0x10000f34]

Nesting Interactive Function Calls

You can also nest interactive function calls. In other words, if you have one or more breakpoints in a function, and you call that function repeatedly, each interactive call is stacked on top of the previous call. Breakpoints in a function affect all nesting levels, so you cannot have different breakpoints at different nesting levels.

The where command shows the entire stack trace from which you can determine the nesting depth. The following example has two nesting levels.

(dbx) where
>  0 foo2(i = 17) [“/usr/var/tmp/dbx_examples/foo.c”:46, 0x10001214]
   1 foo(i = 16) [“/usr/var/tmp/src/dbx_examples/foo.c”:40, 0x100011d4]

===== interactive function call =====

   2 foo2(i = 9) [“/usr/var/tmp/dbx_examples/foo.c”:46, 0x10001214]
   3 foo(i = 8) [“/usr/var/tmp/dbx_examples/foo.c”:40, 0x100011d4]

===== interactive function call =====

   4 foo2(i = 5) [“/usr/var/tmp/dbx_examples/foo.c”:46, 0x10001214]
   5 foo(i = 4) [“/usr/var/tmp/dbx_examples/foo.c”:40, 0x100011d4]
   6 main(argc = 1, argv = 0xffffffad78) [“/usr/var/tmp/src/dbx_examples/test4.c”:25, 0x10000fa0]
   7 __start() [“/shamu/lib/libc/libc_64/csu/crt1text.s”:137, 0x10000f34]

To set a conditional breakpoint, for example, type:

(dbx) stop in foo if j == 7
Process     0: [3] stop in foo if j==7

If j is not within the scope of foo, then you will receive an error message if you attempt to call foo interactively. To prevent this, disable or delete any such breakpoints, conditional commands, or traces before executing the interactive function call.

C++ Considerations

Debugging a program written in C++ is somewhat different from debugging programs written in other languages. This section describes these differences.

Accessing C++ Member Variables

Typically you use standard C++ syntax to access member variables of objects. For example, if the string _name is a member variable of the object myWindow, you can print its value by entering:

(dbx) print myWindow._name
0x1001dc1c = “MenuWindow” 

To display a static member variable for a C++ class, you must specify the variable with the class qualifier. For example, to print the value of the static member variable costPerShare of the class CoOp, enter:

(dbx) print CoOp::costPerShare
25.0

Referring to C++ Functions

For the purpose of dbx debugging, functions in C++ programs fall into three general categories:

Member functions 


Refers to member functions using the syntax classname::functionname. For example, refers to the member function foo in the class Window as Window::foo.

Global C++ functions 


Refers to global functions using the syntax ::functionname. For example, refers to the global function foo as ::foo.

Non-C++ functions 


Refers to non-C++ functions using the syntax functionname. For example, refers to the function printf as printf.

A restriction to keep in mind when using dbx with C++ is that you cannot distinguish between overloaded functions. For example, consider two functions:

print(int);
print(float);

The following command sets a breakpoint in both functions:

(dbx) stop in ::print

The following contrived example illustrates various possibilities:

#include <stdio.h> 
class foo {
   int n; 
   public:
   foo() {n = 0;}
   foo(int x);
   int bar();
   int bar(int); 
};

int foo:: bar() 
{
   return n; 
}

int foo:: bar(int x) 
{
   return n + x; 
}

foo::foo(int x) 
{
   n = x; 
}

int square(int x) 
{
   return x*x; 
}

main() 
{ 
   foo a; 
   foo b = 11; 
   int x = a.bar(); 
   int y = b.bar(x) + square(x);		
   printf("y = %d\n", y); 
} 

If you enter:

(dbx) stop in foo::foo

dbx stops execution in the constructor for the variable b; dbx may stop in the constructor for the variable a (the ability to stop in an inline function may not yet be fully implemented).

If you enter:

(dbx) stop in foo::bar

dbx stops execution both when a.bar is called and when b.bar is called, because dbx is unable to distinguish between the overloaded functions.

To stop in square, enter:

(dbx) stop in ::square

To stop in printf (a C function), enter:

(dbx) stop in printf