Chapter 5. Examining and Changing Data
Prev |  | Next

## Chapter 5. Examining and Changing Data

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

- “Using Expressions”

- “Printing Expressions”

- “Using Data Types and Type Coercion (Casts)”

- “Qualifying Names of Program Elements”

- “Displaying and Changing Program Variables”

- “Displaying and Changing Environment Variables Used by a Program”

- “Using the High-Level Debugging Language duel”

- “Determining Variable Scopes and Fully Qualified Names”

- “Displaying Type Declarations”

- “Examining the Stack”

- “Using Interactive Function Calls”

- “Obtaining Basic Blocks Counts”

- “Accessing C++ Member Variables”

## 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” in Chapter 4, 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.

The following list describes the operators provided by `dbx`.

- `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 (`//` also works 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.

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” in Chapter 4, for more information on `dbx` script files. To include the `#` operator in a `dbx` script, use two pound signs (for example, `##27`).

Example 5-1. Using operators

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

The following list shows the C language operators recognized by `dbx`:

- Unary: `! & + - * sizeof()`

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

| Note: C does not allow the use of 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.

The following list describes the Pascal operators recognized by `dbx`:

- Unary: `not ^ + -`

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

The following list describes the FORTRAN 77 and Fortran 90 language operators recognized by `dbx`. Note that `dbx` does not recognize Fortran logical operators (such as `.or.` and `.TRUE.`).

- Unary: `+ -`

- Binary: `+ - * / %`

Fortran array subscripts may be in either square brackets, `[ ]`, or the standard parenthesis, `( )`, and the Fortran 90 member selection operator (`%`) is allowed.

### Constants

You can use both numeric and string constants under `dbx`. 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` $octin variable to a nonzero value. You can set the default input base to hexadecimal by setting $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 and `0x2A` is hexadecimal 2A.

  By default, `dbx` prints the value of numeric expressions in decimal. You can set the default output base to octal by setting the $octints variable to a nonzero value. You can set the default output base to hexadecimal by setting the `dbx` $hexints variable 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-quotation mark (“) or the single-forward quotation mark (') 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

  Enclosing a character string in back quotation marks ( ```) indicates that the whole string is the name of a program element, not a character-string constant. This is useful, for example, when referring to C++ templates, which include in their names the greater-than (`>`) and less-than (`<`) characters. Without back quotation marks, `dbx` would attempt to interpret the characters as operators. For further discussion, see “Qualifying Names of Program Elements”, and “Referring to C++ Functions” in Chapter 6.

## 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” in Chapter 4, 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`.

For displaying information about variables, the `duel` command is a flexible alternative to the `print` command; see “Using the High-Level Debugging Language duel”.

The variable types are as follows:

Table 5-1. Variable Types

Type | Variable Name | Value
--- | --- | ---
Signed char | `sc` | 0xff
Unsigned char | `usc` | 0xff
Signed short | `ssh` | 0xffff
Unsigned short | `ush` | 0xffff

Example 5-2. Printing expressions

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 the `dbx $hexchars` variable 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 char expanded to 32 bits, so `px sc` printed `0xffffffff`.)

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

The following is the syntax of the `printf` command:

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

This command prints 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)` man page.

### Value History for Print and Calls

Values printed by the `print` command as well as values returned by the `ccall` command can be saved so they can be displayed later or used in other expressions.

Use the following command to enable this feature:

    % set $printhistory=0

The value variables are created with names starting with `$`, followed by a number and displayed after each `print` and `ccall` command. These values can be later referred to by using the generated name. The last value can also be referred to simply as `$`.

Example 5-3. Value history

    (dbx) set $valuehistory=1
    (dbx) print foof()
    $1 = 9.9899997711181641
    (dbx) print $1/4567.98987
    $2 = 0.0021869575142289366
    (dbx) print $
    $3 = 0.0021869575142289366

These values are kept until a `givenfile` command is used. They are then discarded.

The `set` command can be used to print the complete list of value history, in addition to the `dbx` variables.

## Using Data Types and Type Coercion (Casts)

You can use data types for type conversion (also known as 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 as shown in the following example:

Example 5-4. Casting value

    (dbx) print (int) 'b'
    98

To convert an integer into a character, use `(char)` to cast the value as shown in the next example:

    (dbx) print (char) 67
    'C'

This is standard C language type casting.

## Qualifying Names of Program Elements

You can use the same name for different program elements, such as variables, functions, statement labels, several times in a program. This is convenient and, during program execution, the potential ambiguity presents no problem. For example, you can use a temporary counter named `i` in many different functions. The scope of each variable is local; space is allocated for it when the function is called and freed when the function returns. However, in `dbx` you sometimes need to distinguish occurrences of identical names.

`dbx` allows unambiguous reference to all program elements by using source file and routine names as qualifying information that makes otherwise indistinguishable names unique. To find the fully qualified name of the active version of a name, use the `which` command. To find the fully qualified names of all versions of a name, use the `whereis` command. Note that if a variable, such as `i`, is used many times, `whereis` can generate many lines of output.

The fully qualified name of a program element allows you not only to refer within a procedure to variables of the same name with different scopes, but to refer unambiguously to program elements outside your current frame or activation stack.

`dbx` qualifies names 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:

    mrx.main.i

In this expression, `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.

For languages without modules, such as C, C++, and Fortran, the base name of the source file, that is the file name up to the first dot in the name, is taken as a module name. For example, if `b` is a Fortran subroutine in `t.f`, then `t.b` names the routine.

To illustrate how names are qualified, 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` variable 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

It is possible to have variable scopes in C and C++ that are in unnamed program blocks. `dbx` provides names for these scopes, starting with `__$$blk1` and followed by `__$$blk2`, `__$$blk3`, etc., which it places in the fully qualified name of the variable as it would an explicit scope name. The `whereis` and `which` commands show the names assigned. `dbx` provides a special name `__aout` for your base executable. So for example, you can use `__aout.main` to refer to a global C function `main` in your executable. You can, of course, also refer to the function using the name of your executable; if your executable is named `myaout`, `myaout.main` also refers to the global C function `main`.

If you wish to refer to a variable that occurs in a DSO, `dbx` uses a naming convention similar to that for variables in your executable. If, for example, `strcpy` is a function from the file `stuff.c` in the library `libc.so.1`, then both `libc.stuff.strcpy` and `libc.strcpy` refer to the function `strcpy`.

In C, `struct`, `union`, and `enum` tags can conflict with other names. From the context, `dbx` usually interprets correctly a reference to one of these tags. However, if `dbx` does not, prefix the tag with the marker `__$T_` to prevent confusion with variables or functions. For example; use `__$T_foo` if you wish to refer to:

    struct foo { /* ... */ }

In ANSI C, statement label names also can conflict with other names. The ambiguity is removed by applying a prefix of `__$L_` to the label name. Thus, for example:

    int myfoo { int x;   x:  goto x; ++x}

If you enter the following, the output is the address of the variable `x`:

    (dbx) print &x

If you enter the following, the output is the address of label `x`. The -32 compiler provides no debugging information on C labels.:

    (dbx) print &__$L_x

To refer to Fortran statement labels you must either use the `__$L_` prefix or use back quotation marks to force `dbx` to recognize a numerical label as a name. For example, if you have the following:

    do 10  i = 1,10
    10 continue

Both of the following commands lists the address of the label:

    (dbx) print &`10`
    (dbx) print &__$L_10

You may have multiple source files with the same name, for example `myfile.c`, that are in different directories. The module name `myfile` may refer to either source file. `dbx` resolves this ambiguity by prefixing the fully qualified file names with a unique, numeric label. The `which` and `whereis` commands show the label used. For example, suppose the main executable has two `myfile.c` source files, then `__aout.myfile` refers to either source file, `__aout._$1_myfile` refers to one of them, and `__aout._$2_myfile` refers to the other.

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`.

## 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.

### 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 by using the `printd`, `printf`, `printo`, and ```printx` commands and the `pd`, `po`, and `px` aliases described in “Printing Expressions”.

Example 5-5. Displaying Variable Values

To print the value of the program variable `total`, enter the following:

    (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
    }

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” in Chapter 7.

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

You can also print parts of arrays and complex structures with `duel`, a high-level debugging language. For more information, see “Using the High-Level Debugging Language duel”.

### 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” in Chapter 7. ``

The following is the syntax of the `assign` command:

    assign variable=expression

This command assigns the value of expression to the program variable.

Example 5-6. `assign` command

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

Example 5-7. Using casts to change variable values

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.

`dbx` keywords include:

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

Example 5-8. Variable name and keyword conflicts

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 `in` is to enter the following command:

    (dbx) print (in)
    34

### Case Sensitivity in Variable Names

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

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 file names.

## Displaying and Changing Environment Variables Used by a Program

You can control the values of environment variables used by a program without affecting the shell. The `dbx` commands `printenv`, `setenv`, and `unsetenv` control the debugging environment much like their `csh` counterparts control the shell environment. However, they only affect your program while it is being debugged. `dbx` passes the values shown by the `printenv` command to the shell as the environment to use while your program is run by the `run` or `rerun` commands.

The following commands control your program's environment variables:

- `printenv`: prints the list of environment variables affecting the program being debugged.

- `setenv`: same as `printenv`.

- `setenv var`: sets the environment variable var to an empty value.

- `setenv var value`: sets the environment variable var to value, where value is not a `dbx` variable.

- `setenv var $var`: sets the environment variable var to $var, where $var is a `dbx` variable.

- `setenv var “charstring”`: sets the environment variable var to "charstring".

- `unsetenv var`: removes the specified environment variable.

If you attempt to change the `PAGER` or `EDITOR` environment variables, the effect on `dbx` is undefined; the new values may, or may not, affect how `dbx` runs.

## Using the High-Level Debugging Language `duel`

The `duel` language is a high-level debugging language that you can invoke from `dbx`. `duel` is an acronym for Debugging U (might) Even Like.

The `duel` language does not control processes; it provides the following commands for printing data such as parts of arrays and complex structures. The following is the syntax of this command:

    duel [alias] [clear]

The `duel` command invokes the debugging language. `alias` shows all current `duel` aliases. `clear` deletes all `duel` aliases.

To invoke `duel` from within `dbx`, type:

    (dbx) duel

Example 5-9. `duel` usage

To print the array elements `x[1]` to `x[10]` that are greater than 5, enter:

    (dbx) duel x[1..10] >? 5
    x[3] = 14
    x[8] = 6

The output includes the values `14` and `6`, as well as their symbolic representation `x[3]` and `x[8]`.

### Using `duel` Quick Start

The `duel` language is implemented by adding the `duel` command to `dbx`. All `dbx` commands work as before. The `duel` command, however, is interpreted by `duel`, and its concepts are not understood by other `dbx` commands.

| Note: This version of `duel` does not allow interactive function calls.

`duel` is based on expressions that return multiple values. The `x..y` operator returns the integers from `x` to `y`; the `x,y` operator returns `x` and then `y`.

Example 5-10. `duel` and multiple values

    (dbx) duel (1,9,12..15,22)

This command prints `1`, `9`, `12`, `13`, `14`, `15`, and `22`.

You can use such expressions wherever a single value is used. For example:

    (dbx) duel x[1,9,12..15,22]

This command prints elements `1`, `9`, `12`, `13`, `14`, `15`, and `22` of the array `x`. `duel` incorporates C operators, and casts C statements as expressions.

The semicolon (`;`) prevents `duel` output. `duel` aliases are defined with `x:=y` and provide an alternative to variable declaration. You can also return `x[i]` instead of using `printf`:

    (dbx) duel if(x[i:=0..99]<0) x[i]
    x[i] = -4

Example 5-11. `duel` and symbolic output

The symbolic output `x[i]` can be fixed by surrounding `i` with `{}`. For example:

    (dbx) duel if(x[i:=0..99]<0) x[{i}]
    x[7] = -4

The braces (`{}`) are like parentheses `()`, but force the symbolic evaluation to use `i`'s value, instead of `i`. You can usually avoid this altogether with direct `duel` operators:

    (dbx) duel x[..100] <? 0
    x[7] = -4

The `..n` operator is a shorthand for `0..n-1`. For example, `..100` is the same as `0..99`. The operators `x<?y, x==?y, x>=?y` compare their left side operand to their right side operand as in C, but return the left side value if the comparison result is true. Otherwise, they look for the next values to compare, without returning anything.

`duel`'s `x.y` and `x->y` allow an expression `y`, evaluated under `x`'s scope:

    (dbx) duel emp[..100].(if(code>400) (code,name))
    emp[46].code = 682
    emp[46].name = “Ela”

The `if()` expression is evaluated under the scope of each element of `emp[]`, an array of structures. In C language terms, we have to write:

    for(i = 0; i < 100; i++ ) {
      if(emp[1].code > 400) {
        printf(“%d %s\n”,emp[i].cond,emp[i].name);

Example 5-12. `duel` and loop alternatives

A useful alternative to loops is the `x=>y` operator. It returns `y` for each value of `x`, setting the underbar (`_`) to reference `x`'s value. For example:

    (dbx) ..100 => if(emp[_].code>400) emp[_].code,emp[_].name

Using `_` instead of `i` also avoids the need for `{i}`. Finally, the `x-->y` operator expands lists and other data structures. If `head` points to a linked list threaded through the next field, then:

    (dbx) duel head-->next->data
    head->data = 12
    head->next->data = 14
    head-->next[[2]]->data = 20
    head-->next[[3]]->data = 26

This produces the data field for each node in the list. `x-->y` returns `x, x->y, x->y->y, x->y->y->y, ...` until a `NULL` is found. The symbolic output `x-->y[[n]]` indicates that `->y` was applied n times. `x[[y]]` is also the selection operator:

    (dbx) duel head-->next[[50..60]]->data

This example returns the 50th through the 60th elements in the list. The `#/x` operator counts the number of values. For example:

    (dbx) duel #/( head-->next->data >? 50 )

This example counts the number of data elements over 50 on the list. Several other operators, including `x@y`, `x#y`, and active call stack access are described in the “duel Operators”.

### `duel` Operator Summary

Most `duel` operators have the same precedence as their C counterparts. Table 5-2, lists `duel` operators in decreasing precedence.

Table 5-2. `duel` Operator Summary

Associativity | Operators | Details
--- | --- | ---
left | `{} () [] -> . f() -->` | `x-->y` expands `x->y x->y->y ...`
| `x[[y]] x#y x@y` | Generate `x`; select, index, or stop at `y`
right | `#/ - * & ! ~ ++ --` (cast) | `#/x` number of `x` values
| `frame`(n) `sizeof`(x) | Reference to call stack activation level n
| `=` | Simple assignment
left | `x/y x*y x%y` | Multiply, divide, and reminder
left | `x-y x+y` | Add and subtract
left | `x<<y x>>y` | Shift left and shift right
none | `x..y ..y x..` | `..y 0..y-1. x..y` Return `x`, `x+1...y`
left | `< > <= >= <? >? <=? >=?` | `x>?y` Return `x` if `x>y`
left | `== != ==? !=?` | `x==?y` Return `x` if `x=y`
left | `x&y` | Bit-`and`
left | `x^y` | Bit-`xor`
left | `x|y` | Bit-`or`
left | `x&&y &&/x` | `&&/x` Are all `x` values nonzero?
left | `x||y ||/x` | `||/x` Is any `x` value nonzero?
right | `x? y:z` | For each `x`, `if(x) y else z`
right | `x:=y` | `x:=y` set `x` as a `duel` alias to `y`
left | `x,y` | Return `x`, then `y`
right | `x=>y` | For each `x`, evaluate `y` with `x` value ``_`'
right | `if() else while() for()` | C statements cast as operators
left | `x;y` | Evaluate and ignore `x`, return `y`
right | `,,` | Fortran multidimensional array separator: `x[7,,5]`. Use square brackets; `x(7,,5)` will not work in `duel`.

### `duel` Examples

Table 5-3, lists and briefly explains `duel` examples.

Table 5-3. `duel` Examples

Example | Explanation
--- | ---
`duel (0xff-0x12)*3` | Compute simple expression
`duel (1..10)*(1..10)` | Display multiplication table
`duel x[10..20,22,24,40..60]` | Display `x[i]` for the selected indexes
`duel x[9..0]` | Display `x[i]` backwards
`duel x[..100] >? 5` | Display `x[i]` that are greater than 5
`duel x[..100] >? 5 <? 10` | Display `x[i]` if `5<x[i]<10`
`duel x[..100] ==? (6..9)` | Same as above
`duel x[0..99]=>if(_>5 && _<10) _` | Same as above
`duel y[x[..100] !=? 0]` | Dsplay `y[x[i]]` for each nonzero `x[i]`
`duel emp[..50].code` | Display `emp[i].code` for i=0 to 49
`duel emp[..50].(code,name)` | Display `emp[i].code` & emp[i].name``
`duel val[..50].(is_dbl? x:y)` | Display `val[i].x` or `val[i].y` depending on `val[i].is_dbl`.
`duel val[..50].if(is_dbl) x else y` | Same as above
`duel (hash[..1024]!=?0)->scope` | `hash[i].scope` for non-null `hash[i]`
`duel x[i:=..100] >? x[i+1]` | Check if `x[i]` is not sorted
`duel x[i:=..100] ==? x[j:=..100]=> if(i<j) x[{i,j}]` | Check if `x` has nonunique elements
`duel if(x[i:=..99] == x[j:=i+1..99]) x[{i,j}]` | Same as above
`duel (x[..100] >? 0)[[0]]` | Return the first (0th element) positive `x[i]`
`duel (x[..100] >? 0)[[2]]` | Return the third positive `x[i]`
`duel (x[..100] >? 0)[[..5]]` | Return the first five positive `x[i]`
`duel (x[0..] >? 6)[[0]]` | Return the first `x[i]>6`, no limit on `i`
`duel argv[0..]@0` | `argv[0] argv[1]..` until first null
`duel x[0..]@20 >? 9` | `x[0..n]>9` where `n` is first `x[n]==20`
`duel emp[0..]@(code==0)` | `emp[0]..emp[n-1]` where `emp[n].code==0`
`duel head-->next->val` | Return `val` of each element in a linked list
`duel head-->next[[20]]` | Return the twenty-first element of a linked list
`duel *head-->next[[20]]` | Display above as a `struct`
`duel #/head-->next` | Count elements on a linked list
`duel x-->y[[#/x-->y - 1]]` | Reutrn last element of a linked list
`duel x-->y[[#/x-->y - 10..1]]` | Return last ten elements of a linked list
`duel head-->next-> if(next) val >? next->val` | Check if the list is sorted by `val`
`duel head-->(next!=?head)` | Expand cyclic linked list (`tail->head`)
`duel head-->(next!=?_)` | Handle termination with `p->next==p`
`duel root-->(left,right)->key` | Expand binary tree, and show keys
`duel root-->(left,right)->( (left!=?0)->key>=?key, (right !=?0 )->key<=?key)` | Check bin tree as sorted by key
`duel (T mytype) x` | Convert `x` to user defined type `mytype`
`duel (struct s*) x` | Convert `x` to `struct s` pointer
`duel if(x) y; else z *ERR*` | ``;`' must be followed by an expression
`duel {x} y *ERR*` | ``}`' requires ``;`' if followed by exp
`fortarray[2..5,, 6,7]` | Print two-dimensional Fortran array elements

### `duel` Semantics

The `duel` semantics are modeled after the Icon programming language. The input consists of expressions that return sequences of values. C statements are cast as expressions, too. Expressions are parsed into abstract syntax trees, which are traversed during evaluation. The evaluation of most nodes (operators) recursively evaluates the next value for each operand, and then applies the operator to produce the next result. Only one value is produced each time, and `duel`'s `eval` function keeps a state record for each node (backtracking, co-routines, consumer-producer or threads are good metaphors for the evaluation mechanism).

For example, in `(5,3)+6..8`, the evaluation of `+` first retrieves the operands `5` and `6`, to compute and return `5+6`. Then `7`, the next right operand is retrieved and `5+7` is returned, followed by `5+8`. Since no other right operand value exists, the next left operand, `3` is fetched. The right operand's computation is restarted returning `6`, and `3+6` is returned. The final return values are `3+7` and `3+8`.

The computation for operators like `x>?y` is similar, but when `x<=y`, the next values are fetched instead of returning a value, forming the basis for an implicit search. Operators like `..` return a sequence of values for each pair of operands.

The `duel` values follow the C semantics. A value is either an `lvalue` (can be used as the left-hand side of assignment), or an `rvalue`. Therefor, objects like arrays can not be directly manipulated. However, operators like `x..y` can accomplish such tasks.

The `duel` types also follow the C semantics, with some important differences. C types are checked statically; `duel` types are checked when operators are applied. For example, `(1,1.0)/2` returns `0` (int) and `0.5` (double); `(x,y).z` returns `x.z` and `y.z` even if `x` and `y` are of different types, as long as they both have a field `z`.

Values and types of symbols are looked up at run-time (using the `dbx` lookup rules).

To avoid this ambiguity, the keyword `T` must precede a user-defined type. For example, if `value` is a `typedef`, C's `(value (*)()) x` is written in `duel` as `(T value (*)()) x`. Types that begin with a reserved keyword don't need `T`. For example, `(struct value*) x` and `(long *[5]) y` are accepted. As special cases, `(type)x` and `(type*)x` are accepted but discouraged (it causes `(printf)(“hi”)`, which is valid in C, to fail). A side effect is that `sizeof x` must be written as `sizeof(x)`.

### `duel` Operators

The `duel` operators are described in the following list:

`x=y x+y x-y x*y x/y x%y x^y x|y x&y x<<y x>>y`

`x>y x<y x>=y x<=y x==y x!=y x[y]`
| These binary operators follow their C semantics. For each value of `x`, they are evaluated for every value of `y`. For example, `(5,2)>(4,1)` evaluates as `5>4, 5>1, 2>4, 2>1` returning `1`, `1`, `0`, `1`. The `y` values are reevaluated for each new value of `x`. For example, `i=4; (4,5)>i++` evaluates as `4>4` and `5>5`. Beware of multiple `y` values in assignment. For example, `x[..3]=(4,6,9)` does not set `x[0]=4`, `x[1]=6`, and `x[2]=9`. It assigns `4`, `6`, and `9` to each element, which has the same effect as `x[..3]=9`. Use `x[i:=..3]=(4,6,9)[[i]]` to achieve the desired effect.
`-x ~x &x *x !x ++x --x x++ x-- sizeof(x) (type)x`
| These unary operators follow their C semantics. They are applied to each value of `x`. The increment and decrement operators require an `lvalue`, so `i:=0 ; i++` produces an error because `i` is a `duel` alias to `0`, an `rvalue`. Parenthesis must be used with `sizeof(x)`. Note that s`izeof x` is not allowed. Cast to user defined type requires generally requires `T`. For example, `(T val(*)())x`, but `(val)x` and `(val*)x` are accepted as special cases.
`x&&y x||y`
| These logical operators also follow their C semantics, but have nonintuitive results for multi-valued `x` and `y`. For example, `(1,0,0) || (1,0)` returns `1,1,0,1,0` - the right hand-side `(1,0)` is returned for each left-hand side `0`. It is best to use these operators only in single value expressions.
`x? y:z if(x)y if(x)y else z`
| These expressions return the values of `y` for each nonzero value returned by `x`, and the values of `z` for each zero value returned by `x`. For example, `if(x[..100]==0) y` returns `y` for every `x[i]==0`, not if all `x[i]` are zero (`if(&&/(x[..100]==0)`); `y` does that). Also, `if(x) y; else z` is illegal. `duel`'s semicolon is an expression separator, not a terminator.
`while(x)y for(w;x;y)z`
| The `while(x)y` expression returns `y` as long as all values of `x` are nonzero. The `for()` expression is similar and both have the expected C semantics. For example, `for(i=0 ; i<100 ; i++) x[i]` is the same as `x[..100]`. Unlike the `if()` expression, `while(x[..100]==0)` continues to execute only if all elements of `x` are zero, that is, the condition is evaluated into a single value using an implicit `&&/x`. At present, assignments are not supported, so the `for` is of limited utility except to assign aliases.
`x,y x..y ..x x..`
| These operators produce multiple values for single value operands. `x,y` returns `x`, then `y. x..y` returns the integers from `x` to `y`. When `x>y`, the sequence is returned in descending order, that is, `5..3` returns `5`, `4`, `3`. The `..x` operator is a shorthand for `0..x-1`. For example, `..3` returns `0`, `1`, `2`. The `x..` operator is a shorthand for `x..maxint`. It returns increasing integer values starting at `x` indefinitely, and should be bounded by `[[n]]` or `@n` operators. A comma (`,`) retains its precedence level in C. The precedence of `..` is above `<` and below arithmetic operators, so `0..n-1` and `x==1..9` work as expected.
`x,,y`
| The `,,` operator is very low precedence, is only usable inside the `[]` array operators, and is used to separate the dimension expressions of Fortran multi-dimensional arrays. Note the deviation from Fortran and `dbx` command-line usage; array operators are square brackets, `[ ]`, not parentheses, `( )`.
`x<?y x>?y x>=?y x<=?y x!=?y x==?y`
| These operators work like their C counterparts but return `x` if the comparison is true. If the comparison is false, the next `(x,y)` value is tried, forming the basis of an implicit search.
`(x) {x} x;y x=>y`
| Both `()` and `{}` act as C parenthesis. The `{}` set the returned symbolic value as the actual value. For example, `if i=5` and `x[5]=3`, then `x[i]` produces the output `x[i] = 3`, `x[{i}]` produces `x[5] = 3`, and `{x[i]}` produces `3`. The semicolon is an operator. `x;y` evaluates `x`, ignoring the results, then evaluates and returns `y`. For example, `(i:=1..3 ; i+5)` sets `i` to `3` and returns `8`. The `x=>y` operator evaluates and returns `y` for each value of `x`. For example, `(i:=1..3 => i+5)` returns `6`, `7`, and `8`. The value returned by `x` is also stored implicitly in `_`, which can be used in `y`. For example, `1..5 => z[_][_]` produces `z[1][1]`, `z[2][2]`, and so forth. The symbolic value for `_` is that of the left side value, hence `{_}` is not needed. Semicolon (`;`) has the lowest precedence, so it must be used inside `()` or `{}` for compound expressions. The precedence of `=>` is just below comma (`,`). Be aware that `if(a) x; else {y;} z` is illegal; a semicolon is not allowed before `}` or `else` and must be inserted before `z`.
`x->y x.y`
| These expressions work as in C for a symbol `y`. If `y` is an expression, it is evaluated under the scope of `x`. For example, `x.(a+b)` is the same as `x.a+x.b`, if `a` and `b` are fields of `x` (if they are not, they are looked up as local or global variables). `x` may return multiple values of different types. For example, `(u,v).a` returns `u.a` and `v.a`, even if `u` and `v` are different structures. Also, the value of `x` is available as `_` inside `y`. For example, `x[..100].(if(a) _)` produces `x[i]` for each `x[i].a!=0`. Nested `x.y` are allowed. For example, `u.(v.(a+b))` looks up `a` and `b` first under `v`, then under `u`.
`x:=y`
| The `duel` aliases store a reference to `y` in `x`. Any reference to `x` is then replaced by `y`. If `y` is a constant or an `rvalue`, its value is replaced for `x`. If `y` is an `lvalue` (e.g., a variable), a reference to same `lvalue` is returned. For example, `x:=emp[5] ; x=9` assigns `9` to `emp[5]`. Aliases retain their values across invocation of the `duel` command. A `duel` alias to a local variable references a stray address when the variable goes out of scope. The special command `duel clear` delete all the `duel` aliases; `duel alias` shows all current `duel` aliases. Symbols are looked up as `duel` aliases first, so a `duel` alias `x` will hide a local `x`. The `duel` aliases are separate from `dbx` aliases. Currently, `duel` aliases are shared across all processes.
`x-->y`
| The expansion operator `x-->y` expands a data structure `x` following the `y` links. It returns `x, x->y, x->y->y`, until a null is found. If `x` is null, no values are produced. If `y` returns multiple values, they are stacked and each is further expanded in a depth-first notion. For example, if `r` is the root of a tree with children `u->childs[..u->nchilds]`, then `u-->(childs[..nchilds])` expands the whole tree. `y` is an arbitrary expression, evaluated exactly like `x->y` (this includes `_`).
`x@y`
| The expression `x@y` produces the values of `x` until `x.y` is nonzero. For example, `for(i=0 ; x[i].code!= -1 && i<100 ; i++) x[i]` can be written as`x[..100]@(code==-1)`. The evaluation of `x` is stopped as soon as `y` evaluates to true. `x->y` (or `x=>y`) is used to evaluate `y` when `x` is not a struct or a union. If `y` is a constant, `(_==y)` is used. For example, `s[0..]@0` produces the characters in string `s` up to but not including the terminating null.
`#/x &&/x ||/x`
| These operators return a single summary value for all the values returned by `x`. The `#/x` returns the number of values returned by `x`. For example, `#/(x[..100]>?0)` counts the number of positive `x[i]`. The `&&/x` returns `1` if all the values produced by `x` are nonzero, and `||/x` returns `1` if any of `x`'s values are nonzero. Like in C, the evaluation stops as soon as possible. For example, `||/(x[..100]==0)` and`&&/(x[..100]==0)` check if one or all of `x[i]` are zero, respectively.
`x#y x[[y]]`
| The operator `x#y` produces the values of `x` and arranges for `y` to be an alias for the index of each value in `x`. It is commonly used with `x-->y` to produce the element's index. For example, `head-->next->val#i=i` assigns each `val` field its element number in the list. The selection operator `x[[y]]` produces the yth result of `x`. If `y` returns multiple value, each select a value of `x`. For example, `(5,7,11,13)[3,0,2]` returns `13`, `5`, and `11` (`13` is the third element, `5` is the 0th element). Do not use side effects in `x`, since its evaluation can be restarted depending on `y`. For example, after `(x[0..i++])[[3,5]]` the value of `i` is unpredictable.
| Note: Within a `duel` command, the `#` operator does not have anything to do with line numbers or `dbx` comments.
`frame(n) frames_no func.x`
| The `frame(n)` for an integer `n` returns a reference to the nth frame, or activation level, on the stack (`0` is the inner most function and `frame(frames_no-1)` is `main()`). Frame values can be compared to function pointers. For example, `frame(3)==myfunc` is true if the fourth frame is a call to `myfunc`, and in scope resolution. For example, `frame(3).x` returns the local variable `x` of the fourth frame. The `frames_no` is the number of active frames on the stack. For example, `(frames(..frames_no) ==? myfunc).x` displays `x` for all active invocations of `myfunc`. As a special case, `(frames(..frames_no)==?f)[[0]].x` can be written as`f.x` (`x` can be an expression).

### Differences from Other Languages

The following list describes the differences between `duel` and the C, and Fortran languages.

- Differences from C: both `{}` and `;` are operators, not statements or expression separators. For example, `if(x) y; else {z;} u` is illegal; use `if(x) y else {z} ; u`. Ambiguities require preceding user-defined types (`typedef`) with the keyword `T`.

  For example, if `value` is a user type, C's `sizeof(value*)` is written `sizeof(T value*)`, except for the casts `(t)x` and `(t*)x`; `sizeof(x)` requires parenthesis for variable `x`.

- Differences from Fortran: because the comma (`,`) is used to separate a sequence of values, the usual `dbx` syntax for multi-dimensional array references of `myarr[3,4]` does not mean the same thing to `duel` as it does to `dbx`.

  In `duel`, refer to the dimensions of a multi-dimensional Fortran array using `,,` as the dimension separator. In other words, if `myarr` is a two-dimensional array, `myarr[3,,4]` refers to the Fortran array element `myarr(3,4)`.

  The base `dbx` syntax for this element remains unchanged. For example, to show that element of `myarr`, use one of the following:

      (dbx) print myarr[3,4]
      (dbx) duel  myarr[3,,4]

## Determining Variable Scopes and Fully Qualified Names

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

Example 5-13. `which` command

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 this example, 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).

The `which` command also determines the fully qualified name of other program elements, such as procedures or type descriptors, that are submitted as arguments for the command. The `whereis` command prints the fully qualified names of all versions of the name of any program element. `dbx` searches (a possibly limited part of) your program for all occurrences of the name and returns the fully qualified names. The range of the search is determined by the `dbx` $whereisdsolimit variable. By default, $whereisdsolimit is 1 and only the main executable is checked by `whereis`. To search all objects, set $whereisdsolimit to 0. To check just the first n objects, set $whereisdsolimit to n.

## Displaying Type Declarations

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

Example 5-14. `whatis` command

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 frame. Activation levels can also consist of blocks that define local variables within procedures.

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.

The stack determines the scope of many `dbx` commands and expressions. For example, unless you qualify a variable, as described in “Qualifying Names of Program Elements”, `dbx` assumes that variables you reference are local to the current activation level. If a variable does not appear in the current activation level, `dbx` successively examines previous activation levels in the stack until it finds the referenced variable. The maximum number of activation levels examined is determined by the `dbx` $stacktracelimit variable, which has a default value of 100.

### Printing Stack Traces

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

Example 5-15. Stack trace

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 a program is highly recursive, stack traces can get quite long. The `dbx` $stacktracelimit variable controls the maximum number of activation levels that appear in a stack trace. In the example above, setting $stacktracelimit = 2 before issuing the `where` command reduces the set of reported frames to just levels 0 and 1.

Example 5-16. Stack trace and `-g` compiler option

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 following examples show register values from code compiled without a `-g` option. MIPS1 or MIPS2 code using the 32-bit ABI (for example, on an Indy workstation):

    (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 system):

    (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 each take num as an argument. `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 Names of Program Elements”, `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]

The following arguments are available:

- `func` (with no arguments): displays the name of the procedure corresponding to the current activation level.

- 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.

When you change your activation level, your scope changes. For example, unless you qualify a variable as described in “Qualifying Names of Program Elements”, `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.

Example 5-17. `func` command

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. The following is the syntax for this command:

    dump [procedure] [.]

The following arguments are available:

- `dump` (with no arguments): prints information about the variables in the current procedure.

- 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.)

- `.` : prints information about the variables in all procedures in all activation levels.

Example 5-18. `dump` command

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 the `ccall` Command

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`. The following is the syntax for this command:

    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.

Example 5-19. Activation levels and stack trace

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 the `clearcalls` Command

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 ====

Example 5-20. Use of `clearcalls`

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.

Example 5-21. 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.

## Obtaining Basic Blocks Counts

`dbx` permits interactive control of a `pixie`-instrumented binary.

`pixie clear` clears the basic block counts for the current execution. `pixie write` writes out the counts file with the current basic block counts. The counts reflect the execution of the program since the `run` command or since the last `pixie clear` command, whichever was more recent.

When you debug a program that has been instrumented by `pixie`, it is often desirable to perform experiments over different code paths and do comparisons of the results. `Y`ou can do this by capturing the `pixie` basic block counts at any point in the program's execution.

Example 5-22. Basic block counts

Suppose you want to determine the basic block counts for the section of code between lines 10 and 15 of a given file. Just set breakpoints at the two lines of interest, zero the counts when the first breakpoint is encountered, and then write out the counts file when the second breakpoint is encountered.

    (dbx) stop at “pix.c”:15
    Process 0: [3] stop at “pix.c”:15
    (dbx) stop at “pix.c”:20
    Process 0: [4] stop at “pix.c”:20
    (dbx) run
    Process 997 (pix.pixie) started
    [3] Process 997 (pix.pixie) stopped at [main:15 ,0x400a48  (pixie
    0x404570)] 15 first = 12;
    (dbx) pixie clear
    (dbx)cont
    [4] Process 997 (pix.pixie) stopped at [main:20 ,0x400aa8 (pixie
    0x404684)] 20 total = multiply(total, 2);
    (dbx) pixie write
    (dbx) sh prof -pixie prog
    --------------------------------------------------------------------------
    Profile listing generated Tue Feb 14 11:08:46 1995
        with:       prof -pixie prog
    --------------------------------------------------------------------------
    Total cycles  Total Time  Instructions  Cycles/inst      Clock   Target
              53    5.3e-07s            27        1.963   100.0MHz    R4000

              10: Total number of Load Instructions executed.
              40: Total number of bytes loaded by the program.
               3: Total number of Store Instructions executed.
              12: Total number of bytes stored by the program.

               2: Total number nops executed in branch delay slot.
               0: Total number conditional branches executed.
               0: Total number conditional branches actually taken.
               0: Total number conditional branch likely executed.
               0: Total number conditional branch likely actually taken.

              18: Total cycles waiting for current instr to finish.
              26: Total cycles lost to satisfy scheduling constraints.
               5: Total cycles lost waiting for operands be available.
    *---------------------------------------------------------------------*
    -p[rocedures] using basic-block counts.                               *
       Sorted in descending order by the number of cycles executed in each  *
       procedure. Unexecuted procedures are not listed.                     *
    *----------------------------------------------------------------------*
              cycles(%)  cum %     secs    instrns      calls procedure(file)

              27(50.94)  50.94     0.00         19      1 main(prog:prog.c)
              18(33.96)  84.91     0.00          4      1 multiply(prog:prog.c)
               8(15.09) 100.00     0.00          4      2 add(prog:prog.c)

The above example uses the `sh` command to invoke `prof` directly from `dbx`.

For more information about the `prof` and `pixie` commands, refer to the `prof(1)` and `pixie(1)` man pages.

## Accessing C++ Member Variables

Debugging a program written in C++ is somewhat different from debugging programs written in other languages. This section describes features that affect how you access variables. See also “Referring to C++ Functions” in Chapter 6.

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

Prev | Table of Contents | Next
Chapter 4. Controlling dbx |  | Chapter 6. Controlling Program Execution