PowerAda APPENDIX F. Debugger Command Reference
Once you invoke the debugger, you can control the debugging session by entering various debugger commands. While the debugger executes, it presents a prompt, reads the line containing your command, and writes the line to the log file if one is open. The debugger then processes the command, and presents the output from the command, if any. All command outputs are line oriented.
All these commands can be entered in the command line input area in the debugger GUI. See Chapter 6, "The PowerAda Debugger: adbg" for more information.
The debugger commands are:
.BREAK .CALLS .DISASSEMBLE .MOVE .READ .REGISTERS .SKIP .STEP .SYMBOL .TRAP .UNBREAK .UNTRAP .WRITE := ? BEGIN BOTTOM BREAK CALLS CLEAR CLOSE CONTINUE DECLARE DEFAULT DETACH DOWN EDIT END EXIT GET_LINE HELP HISTORY IF IMPORT IN INVOKE LOAD LOG LOOP MACRO MODE NULL OPEN PUT_LINE RESIZE RESTORE RETURN RUN SCRIPT SHOW SKIP STEP SOURCE SYSTEM TASKS TRACK TRAP UNBREAK UNDECLARE UNTRACK UNTRAP UP WHERE WHILE
The debugger's command syntax is flexible and fairly straightforward:
- You can enter commands in upper or lowercase.
- You can abbreviate commands, provided the abbreviation is unique. One- or two-letter command name abbreviations are usually sufficient.
Ambiguous abbreviations are permitted if the rest of the command allows resolution. For example, u 2 could only be an UNBREAK command, so the command is valid even though using U by itself is ambiguous. However, s 1 is always ambiguous, since it can be interpreted as STEP 1, SKIP 1, or any command beginning with S that accepts one numeric parameter.
- You can abbreviate Ada identifiers by using command-line completion. Type part of the identifier name, then enter an escape sequence by pressing and releasing first the
Esckey and then another key. Press
Esc-*to list all the visible Ada names that match that pattern, or
Esc-\to have the debugger enter the rest of the name. If more than one name matches the pattern, the debugger enters as many characters as it can; then you can either enter the rest of the name, or enter the next part of the name and press
- You can enter several commands on the same input line by separating them with semicolons. The LOG command is the only exception. If a command fails, the debugger displays the appropriate error message and continues with the next command. If the debugger does not recognize the command, it stops processing the command line.
- Some commands have one or more parameters. Such commands generally perform different functions when parameters are added. The first parameter to a command is separated from the command by a space; one parameter is generally separated from another by a comma. (For information on the syntax of a specific command, refer to the paragraph describing the command.)
- To indicate a comment, enter "--" anywhere on the command line. The debugger ignores the remainder of the command line.
The debugger commands available are described in the sections to follow. They are referenced alphabetically in the index. When presented in examples, the commands are in lowercase but otherwise they are in uppercase for readability. You may enter these commands in either lower- or uppercase when you actually use the debugger. You can specify a command with a unique abbreviation of the command's name.
On-line help is available when in adbg through the HELP command. Context-sensitive hypertext help is available by using the
F1 key if using the Graphical User Interface.
Specifying Locations for the Debugger
Most debugging is done in terms of compilation units and line numbers. With respect to compilation units, here are terms that need to be defined.
A compilation unit is a single, compilable piece of code. There are two classes of compilation units: library units and secondary units. Common library units are subprogram specifications and package specifications. Common secondary units are subprogram and package bodies (library unit bodies) and subunits. Compilation unit names are built from Ada unit names. Since unit names may not uniquely identify compilations units (for instance, package specifications and bodies will have the same unit name), the unit name may be prefixed with either lib/ or sec/ to specify the library unit or secondary unit, respectively. If no prefix is supplied, the debugger assumes the secondary unit is intended. Note that you may establish a particular compilation unit as a default by using the DEFAULT command ( See "Changing the Default Compilation Unit: DEFAULT").
A compilation consists of a series of compilation units submitted to the compiler. If, for example, you include three package specifications and two package bodies in one file, that file would represent one compilation involving five compilation units: three library units and two secondary units. Most often, there is only one compilation unit in a compilation.
A subunit is a particular kind of secondary unit. It is used to achieve separate compilation. Remember that the unit name for subunits is formed by the subunit's ultimate ancestor followed by a "." followed by the name of the subunit. Therefore, a compilation unit name of the form sec/a.b.c is always invalid; sec/a.c is the appropriate notation. Subunit specifications are allowed wherever the debugger calls for a compilation unit.
In addition, the DEFAULT command, described in "Changing the Default Compilation Unit: DEFAULT", enables you to set a compilation unit that the debugger uses for operations where you do not explicitly specify which unit to use.
Line Numbers Used by the Debugger
When you are not debugging generic instantiations, line numbers used by the debugger are line numbers within the compilation that contains the specified compilation unit. For example, the following example shows a compilation that contains the body for package EXAMPLE_ONE, which is 52 lines long, followed by the body of package EXAMPLE_TWO, which is 40 lines long. The numbers to the right of the sample, and the dashes preceding them, are only for illustrating line numbers within the compilation units; they do not actually appear in the source display.
1: package body example_one is -- 1 2: -- 2 3: -- 3 0 0 0 52: end example_one; -- 52 53: package body example_two is -- 1 54: -- 2 55: -- 3 0 0 0 67= if J = I + 1 then -- 15 0 0 0 93: end example_two; -- 40
Line 15 in the compilation unit EXAMPLE_TWO is line 67 in the compilation. To set a breakpoint at the latter line, the command would be:
The BREAK command is described in "Setting and Displaying Breakpoints: BREAK". The command:
results in an error, since line 67 of the compilation is not in the secondary unit EXAMPLE_ONE. If you printed the entire compilation with line numbers, you would obtain the numbers to use to specify source lines. The SOURCE command performs part of this function by displaying sections of the compilation with the appropriate line numbers.
Characters Used in Source Line Display
Each line displayed by the debugger is prefaced by a line number (or an extended line number, if you are debugging generic instantiations) and a special character. These characters are described in the following table.
||A breakpoint has been set at the line.|
||An executable Ada statement begins on this line. You can set a breakpoint here.|
||You cannot set a breakpoint at this line.|
||This line is not part of the current compilation unit.|
To illustrate, in the sample below you can set breakpoints at lines 20 and 22 but not at line 21:
20= A:= 21: B + C; 22= PUT_LINE(A);
If you set breakpoints at lines 20 and 22 in the code above, these breakpoints are shown in the source display by the ">" after those line numbers. For example:
20> A:= 21: B + C; 22> PUT_LINE(A);
You may set breakpoints at the beginning of statements on many, but not all, source lines within the program. Breakpoints behave according to certain conventions. They are described in "Setting and Displaying Breakpoints: BREAK".
Specifying Task Names
The CALLS and TASKS debugger commands display information on a task when given the task name as a parameter. Identifying a particular task is not always simple because of the nature of tasks. The Ada language supports task objects and task types. A task object may or may not be based on a task type. There can be many instances of a task type, and many task objects can have the same Ada name in different scopes.
In order to present information related to all tasks, and still provide an unambiguous mapping between the information and the existing tasks, the debugger expands upon the Ada name of a task to create a debugger task name. The most general description of a debugger task name is:
- is the name of the task type, if the task is based on a type. Otherwise, it is the name of the task object.
- Line, CompilationUnit
- is the source location where the task or task type is defined.
- is the number of tasks born of this task type immediately after this task was created. In this case, an object is the creation of a task.
A task name will rarely be this complicated. The debugger always uses the shortest unambiguous name for a task. The debugger accepts other, longer names as long as they correctly describe the task. The CompilationUnit can be omitted if it refers to the default unit at the time.
The simplest and most common way to specify an Ada task is to enter the Ada name of the task, as follows:
When there is more than one instance of a task type, you can add an instantiation number. For example, if you want to specify the third instance of a task, you would enter:
If multiple tasks exist with the same Ada name, you must enter a line number that specifies the location of the task in the source code. If the compilation unit that contains the task is not the default unit, you must also enter the name of the unit. For example, you may enter the following to specify the task MANY_SCOPES at line number 123 in the unit sec/a_place:
Location and instance information are required to uniquely identify a task when there are multiple instances of multiple tasks that have the same Ada name. To specify the 17th instance of the task COMPLICATED, which is located at line number 456 in the unit
sec/somewhere, you would enter:
For each task, TASKS displays the current status, the source line number, the compilation unit, and the containing subprogram. If source information is not available, the debugger displays the machine address. For a task object of an explicit task type, the task type name appears as the subprogram name. The currently executing task is marked by an asterisk (*).
The following is an example of a TASKS status display. The example displays individual tasks using a task identifier as a parameter to the TASKS command.
Debug 21> tasks producer producer: Blocked 51, sec/newtest (producer) Debug 22> tasks consumer consumer: Blocked 97, sec/newtest (consumer) Debug 23> tasks Status Location -------------- -------------------------------------- * newtest: Active 192, sec/newtest (lex_3) producer: Blocked 51, sec/newtest (producer) consumer: Blocked 97, sec/newtest (consumer)
You can specify a compilation unit in several ways, as described in "Specifying Locations for the Debugger".
- Specifying Locations for the Debugger
- Compilation unit
- Line Numbers Used by the Debugger
- Characters Used in Source Line Display
- Characters Used in Source Line Display
- Specifying Task Names
- Miscellaneous Commands
- Debugging Shortcuts
- Commands to Control Program Execution
- Manipulating Debugger and Program Variables
- Using Expressions
- Getting Information for Debugging
- Commands to Change the View
- Conditional Execution of Debugger Commands
- Debugging Mixed-Language Programs
- Debugging Machine-Level Code
- Using the Debugger Window Commands