Chapter Contents

Previous

Next
Using Debugger Commands

Arguments in the Debugger Formats

There are several argument types that are common to many commands. You should become familiar with these arguments in order to effectively use the commands that are described in Command Directory. The following common arguments are explained here:

Arguments that can be used only with one command are explained with that command in Command Directory.


SECTION-NAME and FUNCTION-NAME Arguments

Request breakpoints or actions in specific functions or program sections by using the FUNCTION-NAME or SECTION-NAME arguments.

SECTION-NAME (which must be enclosed in parentheses) is the section name for each source file as specified with the sname compiler option (or default). For example, the following drop command uses a SECTION-NAME argument to drop all requests for the comp23 compilation:
drop (comp23) all

Section names cannot exceed seven characters in length.

Note:    The terms section name and compilation are used interchangeably in this book.  [cautionend]

FUNCTION-NAME is the name of a function. For example, the following break command sets a breakpoint on line 17 of the main function:
break main 17

If extended name support is selected with the auto extname command, function names can be as long as 225 characters; otherwise, function names are limited to 8 characters.

If you omit a function name or section name, the debugger responds differently, depending on where you are in the program and on which argument you use:


HOOK-TYPE Argument

The HOOK-TYPE argument specifies places (or hooks) in a program in whichyou want execution to be interrupted.

What Is a Hook?

A hook is a location in a program where control of execution can be transferred to the debugger. If control is transferred from the executing program to the debugger, it happens before the code that is on that line is executed. Note, however, that certain lines of code, such as IF and FOR statements, have more than one hook.

Hooks are created at each source line in a SAS/C program at compile time (when the program is compiled with the debug option). In addition to these line hooks, the debugger also enables you to gain control at function calls, function entries, and function returns.

No hooks are generated for blank lines or for lines that contain only comments. Certain hooks are generated for code that is included via a #include file.

Rules for hook generation Here are some rules for hook generation:

Function calls Hook generation for function calls differs, depending on whether the function call spans lines. If the entire function call fits on a line, a function call is no different from most simple statements. A hook is produced on the line, as long as there is no other hook on that line (because another statement preceded the function call on the same line).

If a function call spans lines, one hook is always generated on the line in which the parenthesis occurs that closes the function call. On the other lines, hooks are generated only if code is generated. (Because a certain amount of optimization is performed even when the debug option is used, you cannot always determine which statements cause machine code to be generated.)

Specifying Hooks with the HOOK-TYPE Argument

As mentioned in the previous section, you can specify places (hooks) in a program in which you want to interrupt execution. You do this with the HOOK-TYPE argument. Values for the HOOK-TYPE Argument shows values that you use for the HOOK-TYPE argument.

Values for the HOOK-TYPE Argument
Specifier Location (table note 1)
* at every line-hook in every function or section (compiled with debug).
line-num
at a source line number line-num in the current function. (line-num is an integer.)
line-num1:line-num2
at all source lines between line-num1 and line-num2, inclusive in the current function. (line-num1 and line-num2 are integers.)
c{alls} at all calls by function, and at all returns to the functions. The context in both cases is that of the calling function.
e{ntry} at entry to all functions. The context is that of the called function.

Automatic variables of the called function are not yet allocated and, therefore, cannot be examined. The values of formal parameters, however, can be examined.

r{eturn} at all returns from the called functions. The context is that of the returning function.
FUNCTION-NAME/
(SECTION-NAME) *
at every hook in the specified function or section (compiled with the debug option).
FUNCTION-NAME/
(SECTION-NAME) line-num
at a source line number in the specified function or section. (line-num is an integer).
FUNCTION-NAME/
(SECTION-NAME) line-num1:line-num2
at all source lines between line-num1 and line-num2, inclusive in the current function or section. (line-num1 and line-num2 are integers.)
FUNCTION-NAME/
(SECTION-NAME) c{alls}
at calls from the specified function, or at calls from all functions in the specified section. For each call, the debugger breaks twice: when the specified function calls and on return to the specified function. In both cases, the calling function determines the context.
FUNCTION-NAME/
(SECTION-NAME) e{ntry}
at entry to a called function or to all called functions in a section.

Automatic variables of the called function are not yet allocated and, therefore, cannot be examined. The values of formal parameters, however, can be determined.

FUNCTION-NAME/
(SECTION-NAME) r{eturn}
at return from a called function or from all called functions in a section. The context is that of the returning function or functions.

TABLE NOTE 1:   Some source lines, such as lines that contain a FOR statement, may actually contain more than one hook, as described in the previous section. [arrow]


Examples of Specifying Hooks

The following examples of the break command illustrate the use of the HOOK-TYPE argument:

break *
sets breakpoints at all line hooks; that is, at all program lines with executable code.

break 25
sets a breakpoint at line 25 of the function that you are in.

break 18:22
sets breakpoints at lines 18 through 22 of the function that you are in.

break calls
sets breakpoints at calls from all functions.

break entry
sets breakpoints at entry to all functions.

break return
sets breakpoints at return from all functions.

break suba *
sets breakpoints at all line hooks in the function called suba .

break main 15
sets a breakpoint at line 15 of the function named main .

break main 101:135
sets a breakpoint at each line in the function main between line 101 and line 135, inclusive.

break (sub1) *
sets a breakpoint at every line in the compilation called sub1 .

break checkup c
sets breakpoints at calls from the function checkup . The context is that of checkup . For each call, there is a breakpoint at the call from checkup at the return to checkup .


EXPRESSION Argument

The EXPRESSION argument is used with several commands, including assign, copy, dump, monitor, print, transfer, watch, and whatis. In addition, this argument can be used as part of a WHEN clause to express a condition in commands, such as break, trace, and on.

The EXPRESSION argument can be certain valid C and C ++ expressions. An expression is a sequence of operators and operands that

In other words, an expression is a construction consisting of one or more operators and operands, ranging from the simple to the complex. Variable names, function calls, constants, literals, array names and references, and structure references are all considered expressions. The SAS/C Debugger supports expressions such as the following examples:

   i
   i + j
   i * (a + b)
   !strcmp(s, d)
   ((struct xyz *) 0p12345678)->a.b
   arr[i] .xyz->b
   strlen(s) == strlen(d)
   p == &x && q != &y

The expression's order of evaluation follows the operator's rules of precedence and associativity. Operators Supported in Expressions provides a list of the operators that are supported in expressions and operator precedence.

You make an integral constant unsigned by specifying the U suffix. Similarly, use the L suffix to make an integral constant long, using L either alone, or combined with U .

Some restrictions exist on what you can substitute for the EXPRESSION argument with certain debugger commands. For example, what you substitute for EXPRESSION with the dump command must evaluate to a pointer, address, or array. Also, the resulting size for some commands (such as dump) depends on the type of EXPRESSION. For example, with the dump command, if the EXPRESSION is a pointer, then the size of the pointed-to object is dumped; if it is an array, the result is the size of one item of the array, and so on.

Constant pointers in an expression must be typed with leading 0p . A value such as 0p12345678 behaves the same as ((char *)0x12345678) in expressions. 0p12345678 is a short form for ((char *) 0x12345678) .


Operators Supported in Expressions

Operators Supported in Expressions lists the operators that you can use in expressions. They are grouped in order of highest to lowest precedence. The associativity is indicated by R-L (right-to-left) or L-R (left-to-right).

Operators Supported in Expressions
Operators Meaning Associativity
[ ] array element L-R
( ) function call L-R
. structure/union member reference L-R
-> structure/union member pointer L-R
sizeof
size of an object R-L
(type-name) cast (type conversion) R-L
~ bitwise negation R-L
! logical negation R-L
- unary minus R-L
+ unary plus R-L
& address of R-L
* pointer R-L
* multiplication R-L
/ division L-R
% modulus L-R
- subtraction L-R
+ addition L-R
<< left shift L-R
>> right shift L-R
< less than L-R
> greater than L-R
<= less than or equal to L-R
>= greater than or equal to L-R
== equal to L-R
!= not equal to L-R
¬ bitwise exclusive OR L-R
| bitwise OR L-R
&& logical AND L-R
|| logical OR L-R
:: scope resolution L-R

For more information about these C operators, see a C language manual.


Functions That Can Be Used in Expressions

You can use the following functions in expressions:


Casts

A cast is an operator (unary) that converts the value of its operand to a specified type. For commands that take expressions and for the WHEN clause, you can cast an expression or object identifier to a different type by explicitly specifying the type within parentheses. The debugger accepts the following casts:
(TAG *)
( struct TAG *)
( union TAG *)
( enum TAG *)
(basic-arithmetic-data-type *).

Zero or more * can be specified, as long as the result is semantically valid. In many cases, the TAG format for arguments is useful with these commands. Specifying an argument that is an address, such as *(struct tag*) address enables you to refer to storage that starts at any absolute address (ADDRESS) with the mapping of a structure, union, or enumeration of the type named by TAG. For example, the following refers to storage starting at the address in 0p23456789 with the mapping of struct listall :

*(struct listall *) 0p23456789

Note:    The struct , union , or enum keywords can be dropped from the cast if no ambiguity is introduced.  [cautionend]


Structure and Union Members

You can access a member of a structure by specifying the pointer and the structure member name. For example, suppose ptag is declared to be a pointer to a structure named TAG0 that has a member named mem0 . You can access mem0 as follows:

ptag->mem0

You can also access memory, using the mapping of a different structure, by casting the pointer to the appropriate pointer type. For example, ((struct TAG1 *)ptab) is a pointer to structure TAG1 . You can access mem1 as follows:

((struct TAG1 *) ptab)->mem1

If you are working with absolute addresses, you can specify an absolute address with a cast to obtain a pointer to a structure. ((struct TAG2 *)0p00123456) is a pointer to structure TAG2 . A member mem2 of the structure can be accessed as follows:

((struct TAG2 *)0p00123456)->mem2


Macros

Expressions can contain macros that are defined (with a #DEFINE statement) in your program. Macros can be specified in any arithmetic expression. At the time of expression evaluation, the debugger replaces any macros in the expression with their replacement text. The maximum length of the replacement text that is supported by the debugger is 1,536 characters. If the replacement text is another macro, further substitution takes place. The debugger is capable of processing only macros without arguments.

The debugger is sensitive to the case of the macro and distinguishes between upper- and lowercase macro names.

To access macros in your program from the debugger, you must compile your program with the dbgmacro option. See Compiler Options. In addition, except for the debugger whatis command, in order to do macro substitution in an expression, you must set the debugger keyword cmacros. This keyword is set with the auto command. By default, cmacros is not set.

The whatis command is used to display the replacement text of a macro. With whatis, macro replacement is always done, regardless of the setting of the cmacros keyword. If you set the cmacros keyword, however, you also can use the print command to display the replacement text for a macro.


Debugger Variables

Debugger variables are used to represent the value that is contained in one of the 16 general purpose registers, one of the 4 floating-point registers, or the current instruction address. You can use debugger variables in any command that supports expressions; however, they cannot be modified. Debugger Variables lists the debugger variables along with the type that is assumed by the debugger.

Debugger Variables
Variable Name Description Type
$r0 to $r15 General purpose registers 0 through 15 char *
$R0 to $R15 Aliases for $r0 to $r15
$f0, $f2, $f4, $f6 Floating-point registers 0, 2, 4, or 6 double
$F0, $F2, $F4, $F6 Aliases for $f0, $f2, $f4, and $f6
$iad Current instruction address

($iad is not case sensitive.)

char *

If the debugger is stopped at the calls or entry hook of a function call, the debugger variables contain the caller's values. However, if the debugger is stopped at the return hook, they contain the callee's values.

If your program returns an integral or pointer value, $r15 contains the return value. $f0 contains the return value if the program returns a floating-point value. In either case, the return address in the calling function is provided by $r14.


Summary of Types of Expressions

Types of Expressions That Can Be Used in print and Other Commands shows the types of expressions that you can use in the print command and other commands. See also the individual commands in Command Directory for any restrictions that exist in substitutions for the EXPRESSION argument.

Types of Expressions That Can Be Used in print and Other Commands
Type
Description
1 arithmetic For example, a variable (v) is declared:
long v;       unsigned long v;
long long v;  unsigned long long v;
int v;        unsigned int v;
short v;      unsigned short v;
char v;       unsigned char v;
double v;     enum TAG v;
float v;
2 pointer For example, a variable (v) is declared as a pointer to any type (T):
T *v;
3 structure, union or class A variable (v) is declared:
struct {...} v;
union {...} v;
class {...} v;
struct TAG v;
union TAG v;
class TAG v;
4 array A variable (v) is an array of any type (T) declared:
T v[CONSTANT];
(CONSTANT is a decimal integer).
5 address The value (v) is specified to the debugger as an absolute address (any integer constant) or is a variable name preceded by the & operator (&v) (function names are excluded).
6 enum constant The value (v) is an enumeration constant.
7 bitfield A variable (v) is a bitfield, for example:
unsigned v : BITS;
(where BITS is a decimal integer).
8 function If V is a function, then *V is a function pointer.


Output Formats

When you issue the print command with only a single argument (EXPRESSION), the value of the expression that you specify is formatted according to its type (defined in Types of Expressions That Can Be Used in print and Other Commands). The output formats are described in Command Directory.

Note: The format that is natural for the value's type is always used.


SCALAR-TYPE-EXPRESSION Argument

SCALAR-TYPE-EXPRESSION is an expression whose type is arithmetic, pointer, or bitfield. For example, the following assign command assigns the address of int_variable to a pointer name int_ptr .
assign int_ptr = &int_variable

In this example, int_ptr is a SCALAR-TYPE-EXPRESSION argument and int_variable is a VALUE argument. See VALUE Argument for more information.


AGGREGATE-TYPE-EXPRESSION Argument

AGGREGATE-TYPE-EXPRESSION is an expression of type structure or union. (It cannot be an array.) For example, the following assign command assigns values from a value list to a structure named numbers :
assign numbers = {1,2,3}

In this example, numbers is an AGGREGATE-TYPE-EXPRESSION argument, and {1,2,3} is a VALUE-LIST argument.


VALUE Argument

VALUE is an expression whose type is one of the following:

You can assign a value to any scalar expression that is visible at the point at which you issue the assign command. To refer to an identifier in an active function that is different from the function that you are in, precede the identifier by the function name and a colon. As discussed in Specifying Identifiers Outside the Current Function, the general form of this argument is FUNCTION-NAME:IDENTIFIER.


COUNT Argument

With the print command, COUNT is an integer constant that specifies the number of items to be printed. For example, if records is a structure, the following print command prints the first five elements of the structure in the format of the element.

print records 5

You can also use the COUNT argument with the dump command to specify the number of bytes to dump. For example, if ptr is a pointer, the following dump command will dump the first ten bytes of storage beginning at the location pointed to by ptr .

dump ptr 10


PTYPE Argument

A PTYPE argument can be one of the following:

PTYPE can be specified for an EXPRESSION argument that belongs to type 1, 2, or 3 in Types of Expressions That Can Be Used in print and Other Commands. You cannot use a PTYPE argument with the other types.

Native C types include

   char          signed char        unsigned char
   int           signed int         unsigned int
   long          signed long        unsigned long
   long long     signed long long   unsigned long long
   short         signed short       unsigned short
   double
   float

When you specify a PTYPE, the EXPRESSION argument acquires the type indicated by PTYPE and is displayed using the rules for that type. If you do not specify a PTYPE, the default is the type that is associated with the expression in the program. For dereferenced absolute addresses, the default is char .

Note:    One caution is necessary about structure types and typedefs . If you have a structure in your program and a typedef with the same type identifier, then using the identifier by itself (with no struct identifier) refers to the typedef , not the structure. For example, with a structure type of buf and a typedef of buf , the following command prints the storage that is referenced by newvar with the PTYPE of the typedef buf :

print newvar (buf)

  [cautionend]

Use struct to obtain the PTYPE of the structure buf , as in the following example:
print newvar (struct buf)

If you specify only a type identifier, the debugger searches for a typedef first. If the identifier is not found in the list of typedefs , the debugger searches the list of structures, unions, and enumerations next.

To find a description of a type, the debugger follows the normal C-scoping rules that are applicable to the place at which execution is halted. As with expressions and identifiers, you specify a PTYPE as a type that is defined within the scope of a function, FUNCTION-NAME, using the following syntax:

FUNCTION-NAME:TYPE

FUNCTION-NAME is any function in the calling sequence. TYPE is a struct , union , or enum type identifier, or a type that is defined with a typedef . For example, the following command prints the value of x using the type XYZ :
print x (sub1:XYZ)

XYZ is a type within the scope of sub1 .

The following are more examples of the PTYPE argument. Some examples are acceptable; others (marked with a [bull]) are unacceptable. Each example includes a declaration and a list of print commands and results.


Example 1

Declaration:

int arr[5] ; /* assume arr begins at 0p15880 */

Command Result
p arr
arr : 0p00015880
- p arr (int)
LSCD148 Array variable cannot be displayed using a TYPE/cast.
- p arr (XXX)
LSCD148 Array variable cannot be displayed using a TYPE/cast.


Example 2

Declaration:

   struct XXX int a; short b,c; ;
   typedef int INTARR[2]
   int x,y,z;  /* assume x begins at 0p10000 */
       /* assume x=10; y=20; z=30; */

Command Result
p x
x : 10 (0x0000000a)
- p x (INTARR)
LSCD148 Casting to an array type (INTARR) is not allowed.
p x (int *)
x : 0p0000000a
- p x (union XXX)
LSCD148 Invalid TYPE/cast "XXX" specified.


Example 3

Declaration:

   struct XXX {int a,b;} x={1,2};
   struct YYY {int c,d,e,f;} y=3{,4,5,6};

Command Result
p x.a
x.a : 1 (0x00000001)
p x.a
x.b : 2 (0x00000002)
p x (int *)
x : 0p00000001
p y (XXX)
&y : 0p00015880
y.a : 3 (0x00000003)
y.b : 4 (0x00000004)


Example 4

Declaration:

   struct ZZZ  {
               int a;
               double d1;
               };
   struct ZZZ yyy;
   struct ZZZ *xp = &yyy;
   /* assume  xp-->a = 5 and xp-->d1=3.24} */

Command Result
p *xp
&(*xp) : 0p00015880
(*xp) .a : 5 (0x00000005)
(*xp) .d1: 3.24
p xp-->
xp-->a : 5 (0x00 000005)


Example 5

Declaration:

   enum fruit apple, orange, pear, peach;
   enum fruit f1, f2;
   int i = 1, j = 5;
   f1 = apple;
   f2 = pear;

Command Result
p f1
f1:0 (apple)
p f2
f2:2 (pear)
p i (enum fruit)
i:1 (orange)
- p j (enum fruit)
j:5 (constant not in list for enum type fruit) -
p peach
peach:3 (enum constant)


%FMT Argument

The %FMT argument is any of the format specifiers that you can use with the sprintf function. They include the following:
c single character
d decimal signed integer
e or E exponential floating point
f fixed-decimal floating point
g or G f format or e format
ll long long
o octal integer
s character string
u decimal unsigned integer
x hexadecimal integer (lowercase)
X hexadecimal integer (uppercase)

The format specifier must result in the item being formatted in 256 characters or fewer. Also, if the EXPRESSION argument in the print command contains a modulus operator % , you must escape the modulus with a backslash \ ; otherwise, the debugger interprets the modulus as a format specifier. The only exception to this rule is modulus operators that are inside parenthesized expressions.


Chapter Contents

Previous

Next

Top of Page

Copyright © 2001 by SAS Institute Inc., Cary, NC, USA. All rights reserved.