8 Examining Program Information

This chapter describes the methods for examining information in your program with the Ladebug debugger command interface.

8.1 Listing Source Code: the list Command

The list command displays source-code lines starting with one of the following:

When the list command is entered without an argument, the number of lines listed is determined by the value of the $listwindow debugger environment variable. The default value of the $listwindow variable is 20. Entering list (or pressing Return) lists the next 20 lines of code. Repeated list commands display your program's source code in 20-line segments.

To display a range of lines, enter a list command with the following syntax:

list  begin_line_number, end_line_number

The begin_line_number argument specifies the number associated with the starting source-code line. The end_line_ number argument specifies the number associated with the last line of source code you want listed.

Example 8-1 uses the list command to display the lines of a COBOL program source file numbered 43 through 50.

Example 8-1 Listing Source Code in a Number Range

(ladebug) list 43,50
     43     PERFORM LOOK-BACK  VARYING SUB-1 FROM 20 BY -1
     44         UNTIL TEMP-CHAR (SUB-1) NOT = SPACE.
     45     MOVE SUB-1 TO CHARCT.
     46     PERFORM MOVE-IT    VARYING SUB-2 FROM 1 BY 1   UNTIL SUB-1 = 0.
     47     MOVE HOLD-WORD TO TEMP-WORD.
     48 MOVE-IT.
     49     MOVE TEMP-CHAR (SUB-1) TO HOLD-CHAR (SUB-2).
     50     SUBTRACT 1 FROM SUB-1.
(ladebug)

To display a specific number of lines, beginning with a particular line, enter the list command with the following syntax:

list  begin_line_number:count

The count argument specifies the number of lines to list.

Example 8-2 uses the list command to display the first 25 lines of an Ada program.

Example 8-2 Listing Source Code By Counting from a Starting Line

(ladebug) list 1:25
     1  with TEXT_IO; use TEXT_IO;
     2  with INTEGER_TEXT_IO; use INTEGER_TEXT_IO;
     3  with FLOAT_TEXT_IO; use FLOAT_TEXT_IO;
     4  procedure TEST is

     5
     6     procedure P (I : INTEGER);
     7     procedure P (F : FLOAT);

     8
     9     procedure P (I : INTEGER) is
    10        TWO : constant := 2;
    11     begin
    12        PUT (I * TWO);
    13        NEW_LINE;
    14     end;

    15
    16     procedure P (F : FLOAT) is
    17     begin
    18        PUT(F);
    19        NEW_LINE;
    20     end;

    21
    22  begin
    23     P(5);
    24     P(6.0);
    25  end;
(ladebug)

To display the source code for a particular function, enter the name of the function as an argument to the list command. The syntax is as follows:

list  function

The debugger prints an error message if it cannot find the source file corresponding to the current function.

If the source file is not in the current directory, you can enter a use command to add directories to the list of directories the debugger will search. The syntax is as follows:

use  [directory]

You can enter multiple use commands to ensure that the debugger finds all source files associated with your program.

The unuse command sets the search list to any of the following:

Include the name of a directory to remove it from the search list or an asterisk (*) to remove all directories from the search list. The syntax is as follows:

unuse  [directory]

unuse *

You can also specify search directories as command-line arguments to the ladebug command with the -I option. (See the ladebug(1) reference page for more information about the options to the ladebug command.)

8.2 Displaying a Stack Trace: the where Command

As explained in Chapter 7, the stack trace lists the active functions in the program you are debugging. Figure 8-1 shows the elements of a stack trace that the debugger displays when you enter a where command.

Figure 8-1 Sample Stack Trace

The stack trace provides the following information for each activation level:
Stack level  The number used to refer to an activation level on the stack. The function entered most recently is on activation level 0. 
Function name  The name of the function active at this activation level of the stack. The values of any variables passed to this function are also listed. 
Function parameters  The list of parameter names and values from previous function calls. 
Memory address  The address of the next instruction to be executed in the named function. 
File name  The name of the file containing the source code for the function. 
Line number  The number of the last executed source line in the function. 

Example 8-3 uses the where command to display the stack trace of a COBOL program.

Example 8-3 Displaying the Stack Trace in a COBOL Program

(ladebug) where
>0  0x3ff81808744 in cob_acc_display() cob_accdis.c:349
#1  0x120001fbc in testa() testa.cob:20
#2  0x3ff8181f054 in main() cob_main.c:253

8.3 The Current Context

The debugger recognizes the scoping rules of the symbols in the target program by maintaining a current context and accessing program symbols based on this context. The context is determined by:

And, if applicable, by:

The context is automatically set to the current point of execution when the debugger is given control (for example, when the debugger stops at a breakpoint).

The debugger extends symbol accessibility beyond that allowed by the language rules when you change the current context or qualify a symbol name with full scope information.

If you do not qualify the symbol name with full scope information, the debugger looks for the symbol in the current context (including process context or thread context, if applicable). The current context is determined by the point at which execution is paused or by the context set when you change the function, file, or class scope.

If the symbol is not found, the debugger searches the calling function, and then its caller, and so on. Within each context, the debugger uses the visibility rules of the language to locate a symbol. If the symbol is still not found, the debugger searches the global symbol table.

8.3.1 The Current Function Scope: the func, up, and down Commands

When the debugger encounters a breakpoint and suspends program execution, the current function is at activation level 0. The stack trace marks the current function scope with an angle bracket ( > ). All other levels on the stack are marked with a pound sign (#). If you want to examine a function other than the current function, use the func, up, or down command to change the current function scope.

Changing the current function scope does not change the current point of program execution. When you continue program execution, the program begins where it left off, regardless of the current function scope.

Change the function scope to examine the value of program symbols or data structures that are not visible in the current scope.

The func command lets you specify a new current function scope by function name. In Example 8-4 the current function scope is changed to function main so that a variable in main() can be displayed.

Example 8-4 Using the func Command

(ladebug) stop at 13
[#1: stop at "sample.c":13 ]

(ladebug) run
[1] stopped at [factorial:13 0x120000ad4]
     13     if (i<=1)

(ladebug) cont
1! = 1
[1] stopped at [factorial:13 0x120000ad4]
     13     if (i<=1)

(ladebug) print f
Symbol f not visible in current scope.
Error: no value for f

(ladebug) where
>0  0x120000ad4 in factorial(i=2) sample.c:13
#1  0x120000a54 in main() sample.c:5

(ladebug) func main
main in sample.c line No. 5:
      5         f = factorial(i);

(ladebug) where
#0  0x120000ad4 in factorial(i=2) sample.c:13
>1  0x120000a54 in main() sample.c:5
(ladebug) print f
1
(ladebug)

The up and down commands let you specify a new current function scope by moving up or down a specified number of levels on the stack trace. If you enter the up or down commands without an argument, you move the current function pointer up or down one level.

In the previous example, instead of entering func main you can enter up 1. Note that the final stack trace in this example lists function main as the current function scope (denoted by the > character).

8.3.2 The Current File Scope: the file Command

The current file scope is automatically set to the name of the file containing the source code of the function you are debugging. When the function scope changes, the current file scope is updated automatically. Use the file command to display and change the current file scope. You can enter this command with no arguments to display the current file scope.

To change the file scope, enter the file command with the following syntax:

file  filename

Enter the name of the file exactly as it was entered on the compile command line. Use a preceding directory path if necessary.

Changing the current file scope lets you list a function in the new file or set a breakpoint on a line in the function. After loading the file with the file command, you can enter the list command to examine it.

Example 8-5 uses the file command to set the debugger file scope back to the main COBOL program, and then stops at line number 20 in that file.

Example 8-5 Using the file Command

(ladebug) file testa.cob
(ladebug) stop at 20
[#6: stop at "testa.cob":20]

When you change the current file scope, the function scope is reset. Running or continuing your program nullifies the file command and reloads the source code corresponding to the program you are debugging.

8.3.3 The Current Language Context: the $lang Debugger Variable

The debugger automatically identifies the language of the current function or code segment based on information embedded in the executable file. For example, if program execution is suspended in a C function, the current language is C. If the program executes a C++ function, the current language becomes C++. The current language determines the valid expression syntax for the debugger.

The debugger sets the $lang variable to the language of the current function or code segment. If the program is not running, $lang is set to the language of the module in which the main entry point resides.

By manually setting the $lang debugger variable, you can force the debugger to interpret expressions used in commands by the rules and semantics of a particular language. For example, you check the current setting of $lang and change it as follows:

(ladebug) print $lang
"C++"
(ladebug) set $lang = "C" 

8.4 Examining and Modifying Program Symbols

You can access program symbols when program execution is suspended in the function that defines the symbol or in any function called by the defining function. Before you can access a symbol, you must execute the program beyond the point where the symbol is declared. If you examine an expression before the variables used in the expression are initialized, the expression value may not be valid.

8.4.1 Evaluating Expressions: the print and whatis Commands

Use the print command to display the value of specific variables or expressions in functions active on the stack. You can also use the print command to evaluate complex expressions involving typecasts, pointer dereferences, multiple variables, constants, and any legal operators allowed by the language of the program you are debugging.

You cannot print a program symbol until you have started executing the program using the run or rerun command. You can use the set command to view the values of debugger variables before starting execution.

The syntax for the print command is as follows:

print  expression

The debugger formats expression values according to the type defined for them in the program. You can print an expression's type using the whatis command. The syntax for the whatis command is as follows:

whatis  expression

Example 8-6 uses the whatis command to examine the contexts of the data item SUB-1 in the COBOL program TESTA.

Example 8-6 Examining Data Items in a COBOL program

(ladebug) whatis sub-1
 unsigned short SUB-1
(ladebug) print sub-1
0
(ladebug)

Consider the following declarations in an Ada program:

type DAY is (MON,TUES,WED,THURS,FRI,SAT,SUN);
MY_DAY : DAY := MON;

Example 8-7 uses the whatis command to determine the storage representation for the variable MY_DAY.

Example 8-7 Determining the Type of a Variable

(ladebug) whatis MY_DAY
enum DAY { MON, TUES, WED, THURS, FRI, SAT, SUN }  MY_DAY;
(ladebug) print MY_DAY
MON

For an array, the debugger prints every cell in the array if you do not specify a specific cell.

Consider the following declarations in an Ada program:

type CAR is (BUICK,FORD,HONDA);
type CAR_ARRAY is array (CAR) of INTEGER;

CAR_NUM : CAR_ARRAY := (1,2,3);

Example 8-8 uses the print command to display a nonstring array.

Example 8-8 Printing Values of an Array

(ladebug) print CAR_NUM
[0] = 1,[1] = 2,[2] = 3

Example 8-9 shows how to print individual values of an array.

Example 8-9 Printing Individual Values of an Array

(ladebug) list 1, 4
      1 main() {
      2     int c[5],d;
      3     for (d=0 ; d<=5 ; d++) {
      4         c[d] = d;

(ladebug) stop in main
[#1: stop in main ]

(ladebug) run
[1] stopped at [main:3 0x1200010b4]
      3     for (d=0 ; d<=5 ; d++) {

(ladebug) whatis c
array [subrange 0 ... 4 of int] of int c

(ladebug) print c
[0] = 0,[1] = 0,[2] = -2147474264,[3] = 1023,[4] = 0

(ladebug) step
stopped at [main:4 0x120001068]
      4                c[d]=d;

(ladebug) <Return>
stopped at [main:6 0x1200010dc]
      6 }

(ladebug) print c
[0] = 0,[1] = 1,[2] = 2,[3] = 3,[4] = 4
(ladebug) print c[4]
4
(ladebug)

Expressions containing labels are not supported. Variables involving static anonymous unions and enumerated types cannot be printed. Printing a structure that is declared but not defined in a compilation unit generates an error message indicating that the structure is opaque.

8.4.2 Dereferencing Pointers: the * Operator

Variables containing addresses are called pointers. By dereferencing a pointer, you can print the value at the address pointed to by the pointer. In C programs, variables containing a pointer are dereferenced using the * operator. Example 8-10 shows how to dereference a pointer in C programs.

Example 8-10 Dereferencing a Pointer

(ladebug) list 1
      1 main()
      2 {
      3     int x, *c;
      4
      5     c = &x;
      6     x = 2;
      7     *c = 0;
      8 }

(ladebug) stop in main
[#1: stop in main ]

(ladebug) run
[1] stopped at [main:5 0x12000045c]
      5     c = &x;

(ladebug) whatis c
int * c


(ladebug) print c
0x11ffffe4c
(ladebug) print *c
2
(ladebug)

8.4.3 Listing Variables: the dump Command

The dump command lists an active function's local variables and parameters. You can specify a dump of a specific function by naming the function as an argument to the command. You can show all the variables and parameters in all currently active functions by entering a period after the dump command. In Example 8-11, you obtain a dump of all active functions from the sample program in Example 7-9.

Example 8-11 Displaying Information on Each Activation Level

(ladebug) dump
>0  0x120001224 in factorial(i=1) sample.c:13
i=1
f=0
(ladebug)

The function factorial has the parameter i but it has no local variables. The function main has two local variables, i and f.

8.4.4 Displaying a Variable's Scope: the which and whereis Commands

Your program may declare a particular symbol more than once. For example, in the program sample.c the symbol i is declared in the function main and again in the function factorial.

Because the debugger extends the visibility and scope rules of the programming language, the debugger may have access to more than one declaration of a symbol name. You can use the which command to determine which declaration exists in the current context. The which command displays the variable with its scope information fully qualified.

The whereis command lists all declarations of a variable together with each declaration's scope information fully qualified. Example 8-12 shows how to use the whereis and which commands to determine a variable's scope.

Example 8-12 Displaying a Variable's Scope

(ladebug) where
>0  0x120001230 in factorial(i=1) sample.c:14
#1  0x12000124c in factorial(i=2) sample.c:16
#2  0x120001194 in main() sample.c:5

(ladebug) print i
1

(ladebug) which i
"sample.c"`factorial.i

(ladebug) whereis i
"sample.c"`factorial.i
"sample.c"`main.i

(ladebug) func main
main in sample.c line No. 5:
      5         f = factorial(i);

(ladebug) print i
2
(ladebug) which i
"sample.c"`main.i
(ladebug)

The whereis command is useful for obtaining information needed to differentiate overloaded identifiers that are in different units, or within different routines in the same unit.

Example 8-13 shows how to set breakpoints in two Ada program routines, both named DO_ PRINT.

Example 8-13 Determining Overloaded Identifiers

(ladebug) whereis do_print
"overload.ada"`OVERLOAD`DO_PRINT
"overload.ada"`OVERLOAD`INNER`DO_PRINT
(ladebug) stop in "overload.ada"`OVERLOAD`DO_PRINT
[#1: stop in DO_PRINT ]
(ladebug) stop in "overload.ada"`OVERLOAD`INNER`DO_PRINT
[#2: stop in DO_PRINT ]
(ladebug)

8.4.5 Changing the Value of an Expression: the assign and patch Commands

Use the assign command to change the value associated with an expression in the debugger session. The new value is associated with the variable until the value is changed by the program during execution, or until you specifically change the value. The syntax for the assign command is as follows:

assign  expression = expression

The expression argument can be any expression that is valid in the current context and language.

Example 8-14 shows how to deposit the value -42 into the data item SUB-2 of a COBOL program named TESTA.

Example 8-14 Depositing a Value in an Expression

(ladebug) assign sub-2=-42
(ladebug) print sub-2
-42

Example 8-15 shows how to change the value associated with a variable and the value associated with an expression.

Example 8-15 Assigning Values to a Variable and an Expression

(ladebug) assign i = 5
(ladebug) print i
5
(ladebug) assign f = factorial(8)   1
(ladebug) print f
40320
(ladebug) assign i = f
(ladebug) print i
40320
(ladebug)

  1. This command calls the function factorial.

Use the patch command to change the value associated with an expression in the object file on the disk as well as the debugger process you are running. The syntax is as follows:

patch  expression1 = expression2

The expression argument can be any expression that is valid in the current context and language.

The patch command patches executable disk files to correct bad data or instructions. The text, initialized data, or read-only data areas can be patched. The bss segment cannot be patched because it does not exist in disk files.

For more information, see Chapter 22 and Part V, Command Reference.