Chapter Contents

Previous

Next
Using the Debugger

Performing Advanced Debugger Actions


Displaying a Traceback

The where command produces a calling trace or traceback that shows (among other information) the functions that are active at the point in the program from which the where command was issued. One format of the where command is

where

The where command enables you to see the calling sequence for active functions. Use the where command in order to determine the sequence of functions that are active or whether you are executing in the appropriate section.

Because source lines are accessed only for active compilation names and because variables are accessed only for active functions, use the where command to display the list of active functions. This allows you to determine what variables can be accessed. For example, suppose that you want to view lines of code (via the list command) for a function called readin. You could issue the following command:

list readin*

However, the command does not display the readin function in the Source window if readin is not currently in the calling sequence identified by your command scope. You can only access variables in functions and sections that are listed in the traceback (that is, active functions). An external variable is accessed from any function whose context contains a declaration for it. See where for more details on the where command.


Viewing and Searching Source Code


Using the list Command

The list command lists source lines in a program that is executing under the debugger. In a full-screen session, the list command is used to move around in the Source window. For example, to move to a specific line, use the format

list LINENO

Then, to move back to your current position in your source code use the format

list

See list for more details.

Using the window find Subcommand

The window find subcommand is used to search for strings and is supported in the following windows:

The following format is used with the window find subcommand:

 window find WINDOW-NAME 

The WINDOW-NAME argument can be any of the following:

If the <> WINDOW-NAME argument is used, the position of the cursor determines the window to which the command is applied. See Find Window for more details on the window find subcommand.


Changing Scope

The scope command is used to change the command scope. In order to understand the concept of command scope, you must first understand the concept of run scope. Run scope is the term used to describe the location in your program at which the debugger has stopped. Normally, the debugger uses the context of this location to resolve variable references. In other words, the debugger uses the value of a variable as it appears at the location in your code where you stopped.

Command scope identifies a second location in your source code that can be used to resolve variable references. Normally, command scope is the same as run scope; however, it can be changed with the scope command. Certain commands use command scope in order to resolve variable references and to supply default function and section names. As described in Run Scope and Command Scope, both command and run scope are displayed in the Status window. Some formats of the scope command are as follows:

scope FUNCTION-NAME
changes the command scope to the function that is named by the FUNCTION-NAME argument. This argument must name a function in the calling sequence. If multiple instances of the function are identified by FUNCTION-NAME, the command scope is set to the most recent.

scope + INTEGER
changes the command scope to a function that is farther up in the calling sequence. The INTEGER argument specifies the number of functions up in the calling sequence to change the command scope.

scope - INTEGER
changes the command scope to a function that is farther down in the calling sequence. The INTEGER argument specifies the number of functions down in the calling sequence to change the command scope.

scope
sets the command scope back to run scope.

See scope for details on the scope command.


Stopping Execution When a Value Changes

The monitor command causes the debugger to test for changes in the object that is addressed by the expression at each hook. If the value changes, the program is interrupted. This request is called a monitor. When the monitor command is used to test for changes in a value, the debugger is monitoring the object. A change in value is said to trigger the monitor. One format of the command is

monitor EXPRESSION [LENGTH] [print]


Arguments and Option Used with the monitor Command

The arguments and option for this form of the monitor command are as follows:

EXPRESSION
identifies the object (such as a variable) to be monitored.

LENGTH
shows the number of bytes to be monitored. The number of bytes can be larger or smaller than the actual length of the object in bytes.

print
prints the value of the object when the monitor is triggered. (The abbreviation is p.) With the print option, the debugger displays the new value of the object. If the object is no more than 256 bytes in length, the debugger also displays the old value. The values are formatted appropriately for the type of the object. If the object is an aggregate and less than 256 bytes, then only those fields that change are displayed.

Arguments can follow the EXPRESSION in any order. See monitor for more details on the monitor command.


Performing One or More Debugger Commands at Various Locations

The on command enables you to perform one or more debugger commands at a specific location in your program. You can issue a list of commands {CMD-LIST} to be performed at locations that are specified with the HOOK-TYPE argument when a certain condition is met (EXPRESSION). Values for the HOOK-TYPE argument are described in HOOK-TYPE Argument. Use the following format for the on command.

on HOOK-TYPE [when (EXPRESSION)] {CMD-LIST}


The CMD-LIST Argument

The CMD-LIST argument contains one or more debugger commands and command arguments, separated by semicolons, as in the following example:

on stats c {break; print lengthsum, totcnt}

Issuing this command interrupts program execution at calls from stats and at returns to stats, and prints the value of lengthsum and totcnt.

The CMD-LIST is enclosed by braces. The CMD-LIST argument may contain nested on commands, as in this example:

on lookup e when (strcmp(arg, "testid") == 0) {
on lookup * {dump var str; break;}print}

In this example, on entry to lookup, the following occurs: If the argument to lookup is TESTID, the debugger defines an action for each line of lookup and prints the value of arguments to lookup. The action, for each line at lookup, is requested to dump the value of var and interrupt execution. You can use this action in order to track down an error that occurs only on calls to lookup with a particular argument, without having to look at calls with other arguments.

This example also illustrates how you can issue commands that are part of the CMD-LIST argument on different lines. Type an open brace at the end of the first line, followed by the list of commands on subsequent lines, and finally the close brace.

Note:    If you put commands on separate lines, the end of a line can be the command separator. You do not need a semicolon. You can also enter commands with long CMD-LIST arguments in the Log window by using the \ continuation character. You cannot use the continuation character in the Command window.   [cautionend]

How the on Command Works

When you enter text for an on command, the command text goes into the command buffer for only a moment. Then the debugger processes the CMD-LIST argument and stores it as text in an internal debugger data structure. No parsing is done to the on command's CMD-LIST at the time it is entered. When the hook that you specify is reached, the CMD-LIST is reinserted into the command buffer, this time parsed and ready for execution. If, at the time you enter an on command, there is already another debugger command in the buffer, the on CMD-LIST arguments are placed before the other command (or commands). You can think of an implied go command as being placed after the on command.

For example, suppose you want to break at line 15 in your program and dump two variables, p and g. Issue the following on command:

on main 15 {dump &p; dump &g}

The command is put in the command buffer momentarily and then is put (as text only) into some internal data structure. Now you reach line 14 and type the following commands:

go; print z; print w;

The debugger executes the go command and reaches line 15. As this point, the command buffer is

go; print z; print w;
      ↑

Your on command and an implied go command are inserted into the buffer after go, where the arrow is pointing above, and execution continues. The buffer now looks like

go; dump &p; dump &q; implied go; print z; print w;
     ↑

The debugger executes the inserted commands and then executes the added go. This means that the two print commands are not executed at line 15. In fact, they are not executed until the next breakpoint. See on for more details about the on command.


Setting Different Debugger Modes

The auto command lets you set keywords that define several characteristics of output produced by the debugger. The format of the auto command is

 auto KEYWORD KEYWORD . . . 

For example, the cmacro keyword allows substitution of program macros in expressions. In order to use the cmacro keyword command you must compile your program with the dbgmacro option. Suppose you had the following line in your program:

#define MAXLEN 15

Then at the command line you would type:

Cdebug: auto cmacro

And to print the value of MAXLEN you would type:

Cdebug: print MAXLEN

which prints a value of 15 to the Log window.

See auto for a detailed discussion of these keywords and other auto command keywords.


Viewing Memory

The dump command dumps the contents of storage that is pointed to by an EXPRESSION. Formats of the dump command include the following:

dump EXPRESSION 

dump EXPRESSION str 

The EXPRESSION argument is either a pointer, an address, or an array. An absolute address must be specified with a leading 0p, for example, 0p00001234. For the first format of the dump command, the number of bytes dumped is determined as follows:

Dump Command: number of Bytes Dumped
Argument Type Number of Bytes Dumped
Pointer The size of the pointed to object
Address of a scalar or aggregate The size of the scalar or aggregate
Array The size of one item of the array
Absolute address One (treated as a pointer to char)

The second form of the command dumps the contents of storage that is pointed to by the EXPRESSION until the null terminator, \0, is encountered.

For all formats, the output of the dump command shows the contents of the EXPRESSION argument in characters and in hexadecimal format, and shows the address of the argument as a hexadecimal number.

In the following example, because str is specified, the entire string test is dumped:

Cdebug: dump wordstrg str  

wordstrg

0002b1d0	a385a2a3		*test            * 

In the next example, inword is an int, so 4 bytes are dumped (int type has a size of 4 bytes):

Cdebug: dump &inword

&inword

0002b1cc	00000001		*....             * 

See dump for more details on the dump command.


Defining Macros

The define command enables you to use the debugger commands as macros. Once you have defined a macro, you can invoke it by using the macro name, prefixed with #. One format for the define command is

define DMACRO "REPLACEMENT TEXT"

The DMACRO argument is any valid identifier. The REPLACEMENT TEXT argument is the debugger command that is substituted for the macro when you invoke the macro. The REPLACEMENT TEXT argument can contain double quotation marks, but you must escape the quotation marks with a backslash. Drop debugger macro definitions with the undef command when you no longer need them. See undef for a discussion of the undef command.

Do not confuse C macros with debugger macros. C macros are defined in your program via the C preprocessor #define statement. Debugger macros define a shorthand version for commands that you plan to use often in a debugger session. In the following example, the define command defines a macro dmp as dump wordarry str:

Cdebug: define dmp "dump wordarry str"

See define for more details on the define command.


Executing Operating Environment Commands

The system command sends an operating environment command to the operating environment. The system command is equivalent to calling the system function from within your C program by using the TSO: or CMS: prefix. The format of the system command is

system OPERATING-SYSTEM-COMMAND


Under CMS

The system command uses full command resolution as if the command were entered in response to the CMS prompt. See Command Directory, for more information on the system under CMS.

Under TSO

The OPERATING-SYSTEM-COMMAND is either a native TSO command or a CLIST or REXX EXEC that contains TSO commands.


Displaying Storage Analysis

The storage command prints an analysis of the program's use of both heap and stack storage. This analysis can be useful for locating a memory overlay. To display a report of both heap and stack storage, type

Cdebug: storage

The following output is an example of a report:

At     SUB1(PGM1)     entry    ------
  SIZE: FREE/USED  SIZE: FREE/USED  SIZE: FREE/USED  SIZE: FREE/USED
    24:    0/116     32:    0/118     40:    0/18      48:    0/69
    56:    0/10      64:    0/7       72:    0/59      80:    0/10
    88:    0/9       96:    0/4      104:    0/3      120:    0/2
   144:    0/5      152:    0/1      160:    0/1      280:    0/1
   512:    1/0      792:    1/0     1152:    1/0     1472:    1/1
  1792:    0/2     8192:    0/1
No corruptions found in heap.

  SIZE  NUMBER  SIZE  NUMBER  SIZE  NUMBER  SIZE  NUMBER  SIZE  NUMBER

   152:    1     168:    1     208:    1     248:    1     256:    1
   296:    2     672:    1
 Total unused space in stack (bytes): 1768
No corruptions found in stack.


Halting Your Running Program

The attn command generates a SIGINT interrupt signal in programs that execute under the debugger. When the SIGINT signal occurs, it sends a message to the debugger output. The format of the attn command is

attn 

You generate the SIGINT signal under TSO by pressing the attention (PA1) key, and under CMS by using the immediate command IC. However, when you are using the debugger, pressing the attention key under TSO, IC under CMS, or CTRL+C under UNIX System Services gives control back to the debugger. To actually send a SIGINT signal to the executing program under the debugger, you must use the attn command.

Note:    When using the debugger in full-screen mode under CMS, you might not be able to issue an immediate command. Another method of interrupting the debugger under CMS is to press the attention key to give control to the VM control program CP, and then issue the CP command EXTERNAL DB. This sends an external interrupt of the debugger, which interprets it as an attention.  [cautionend]
See attn for more details on the attn command. See the discussion of signal handling in the SAS/C Library Reference, Volume 1 for details on the characteristics of signals.


Chapter Contents

Previous

Next

Top of Page

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