| Previous | Contents | Index |
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.
The current file scope is automatically set to the name of the file containing the source code of the function you are debugging. Use the file command in the command interface to display and change the current file scope.
After loading the file with the file command, you can enter the list command to examine it.
Example 2-14 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 2-14 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.
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 2-15 the current function scope is changed to function main so that a variable in main() can be displayed.
| Example 2-15 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).
2.6.1 Changing the Current Language Context
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" |
This chapter explains how to:
In addition to selecting debugger menu items, you can enter Ladebug commands at the debugger prompt (ladebug) or in the Command Message View of the GUI.
For more information on specific Ladebug commands mentioned in this
chapter, see Part 5.
3.1 Determining Where Execution Is Currently Paused
To determine where execution is currently paused within your program:
Use the
where
command in the command interface to display the stack trace of
currently active functions for the current thread.
3.2 Executing Your Program
The following sections explain how to:
For information about rerunning your program or running another program
from the current debugging session, see Section 1.6.6 and Section 1.6.7.
3.2.1 Starting or Resuming Program Execution
To start or resume program execution, follow the instructions in Section 1.6 and Section 1.6.8.
Once started, program execution continues until one of the following occurs:
Whenever the debugger suspends execution of the program, the source display display is updated and the current-location pointer marks the line whose code will execute next.
Letting your program run freely without debugger intervention is useful in situations such as the following:
You can use the run and rerun commands in the command interface to start execution of a program under debugger control.
Example 3-1 shows how to use the run and rerun commands.
| Example 3-1 Using the run, rerun, and cont Commands to Control Program Execution |
|---|
(ladebug) run -s > prog.output
Thread has finished executing
(ladebug) stop in main
[#1: stop in main ]
(ladebug) rerun
[1] stopped at [main:4 0x1200011c0]
4 for (i=1 ; i<3 ; i++) {
(ladebug)
|
In Example 3-2, a cont command resumes program execution after program execution is suspended by a breakpoint.
| Example 3-2 Continuing Program Execution |
|---|
(ladebug) stop in main
[#1: stop in main ]
(ladebug) run
[1] stopped at [main:4 0x120000b14]
4 for (i=1 ; i<3 ; i++) {
(ladebug) cont
1! = 1
2! = 2
Thread has finished executing
(ladebug)
|
You can terminate program execution by using the quit or kill
commands in the command interface.
3.2.2 Executing Your Program One Source Line at a Time
To execute one source line of your program, click on the Next button on the push-button panel or the Next pop-up menu item in the window or view of your choice. Note that the Next button executes a routine call, but does not step into it. It treats a routine call as a single line of execution.
After the line executes, the source display is updated and the current-location pointer marks the line whose code will execute next.
Executable lines have a toggle button to their left in the source pane.
Nonexecutable lines do not have a toggle button to their left in the source pane.
Keep in mind that if you optimized your code at compilation time, the
source code displayed might not reflect the code that is actually
executing (see Section 1.6.1).
3.2.3 Stepping into a Called Routine
When program execution is paused at a routine call statement, clicking on the Next push button executes the called routine in one step. The debugger suspends execution at the next source line in the calling routine (assuming no breakpoint was set within the called routine). "Stepping over" called routines lets you move through the code quickly without having to trace execution. Use the Next button to step over routines.
To "step into" a called routine so that you can execute it one line at a time:
Once execution is within the called routine, click on the Step or Next push button to execute the routine line by line.
Clicking on the Step button when execution is not paused at a routine call statement is the same as clicking on the Next push button.
You can also use the step command in the command interface to step through your program one line at a time.
In Example 3-3, two step commands continue executing a Fortran program into lines 10 and 11 after program execution has paused at line 9.
| Example 3-3 Stepping Through Program Execution |
|---|
(ladebug) stop at 9
[#2: stop at "squares.f90":9 ]
(ladebug) run
[2] stopped at [squares_:4 0x1200016dc]
9 DO 10 I = 1, N
(ladebug) step
stopped at [squares_:10 0x120001710]
10 IF(INARR(I) .NE. 0) THEN
(ladebug) step
stopped at [squares_:11 0x12000172c]
11 OUTARR(K) = INARR(I)**2
|
The next command entered in the command interface executes the called function to completion and returns to the debugger prompt with the program counter pointing at the source-code line immediately after the line containing the function call.
When you call a routine with limited symbolic information, you may not want to step into it. The debugger is under the control of the debugger variable $stepg0, which determines whether Ladebug will step into or bypass the routine. When $stepg0 is set to 0 (the default), the debugger steps over calls to routines compiled without the option that includes full symbolic debugging information. This means the debugger behaves as if a next command were entered, instead of a step command.
Setting $stepg0 to 1 causes the debugger
to step into these calls, rather than over them.
3.2.4 Returning from a Called Routine
When execution is suspended within a called routine, you can execute your program directly to the end of that routine by clicking on the Return button on the push-button panel on the Main Window, returning you to the calling routine.
The Return button is particularly useful if you have inadvertently stepped into a routine that is out of the scope of the bug you are tracking.
You can use the return command in the command interface to continue program execution.
In Example 3-4, the step command is used to step through program execution. When program execution enters the factorial function, the return command is used to finish the called function and return control to the program being debugged.
| Example 3-4 Using the return Command |
|---|
(ladebug) step
stopped at [main:5 0x120001188]
5 f = factorial(i);
(ladebug) [Return]
stopped at [factorial:13 0x120001224]
13 if (i<=1)
(ladebug) return
stopped at [main:5 0x120001194]
5 f = factorial(i);
(ladebug)
|
Use Continue to Line in the Source View pop-up menu to branch to a specified line.
Use the goto command in the command interface to branch to a specified line after execution is suspended.
Example 3-5 shows an example of the goto command.
| Example 3-5 Branching to a Specified Line |
|---|
(ladebug) list 1:9
1 #include <stdio.h>
2 main() {
3 int i,f;
> 4 for (i=1 ; i<3 ; i++) {
5 f = factorial(i);
6 printf("%d! = %d\n",i,f);
7 fflush(stdout);
8 }
9 }
(ladebug) goto 6
(ladebug) step
stopped at [main:7 0x1200011c0]
7 fflush(stdout);
(ladebug)
|
After a breakpoint or a signal suspends program execution, you can execute a single function in your program by using the call command in the command interface, or by including a function call in the expression argument of a debugger command. Calling a function lets you test the function's operation with a specific set of parameters.
When the function you call completes normally, the debugger restores the stack and current context that existed before the function was called.
While the program counter is saved and restored, calling a function does not shield the program state from alteration if the function you call allocates memory or alters global variables. If the function affects global program variables, for instance, those variables will be permanently changed. Functions compiled without the debugger option to include debugging information may lack important parameter information and are less likely to yield consistent results when called.
The call command executes the specified function with the parameters you supply and then returns control to you (at the debugger prompt) when the function returns. The call command discards the return value of the function. If you embed the function call in the expression argument of a print command, the debugger prints the return value after the function returns.
Example 3-6 shows both methods of calling a function.
| Example 3-6 Calling a Function from the Debugger Prompt |
|---|
(ladebug) call factorial(5) (ladebug) print factorial(5) 120 (ladebug) |
In this example, the call command results in the return value being discarded while the embedded call passes the return value of the function to the print command, which in turn prints the value. You can also embed the call within a more involved expression, as shown in Example 3-7.
| Example 3-7 Embedding a Function Call in an Expression |
|---|
(ladebug) print 341 + factorial(6) / 2 701 (ladebug) |
All breakpoints or tracepoints defined during the session are active when executing a called function. When program execution halts during function execution, you can examine program information, execute one line or instruction, continue execution of the function, or call another function.
When you call a function when execution is suspended in a called function, you are nesting function calls, as shown in Example 3-8.
| Example 3-8 Nesting Function Calls |
|---|
(ladebug) status
#1 PC==0x120001180 in main "sample.c":4 { break }
#2 PC==0x12000123c in factorial "sample.c":16 { break }
(ladebug) call factorial(5)
[2] stopped at [factorial:16 0x12000123c]
16 return (i * factorial(i-1) );
(ladebug) where
>0 0x12000123c in factorial(i=5) sample.c:16
(ladebug) print i
5
(ladebug) s
stopped at [factorial:13 0x120001224]
13 if (i<=1)
(ladebug) call factorial(15)
[2] stopped at [factorial:16 0x12000123c]
16 return (i * factorial(i-1) );
(ladebug) where
>0 0x12000123c in factorial(i=15) sample.c:16
(ladebug) disable 2
(ladebug) return
Called Procedure Returned
stopped at [factorial:13 0x120001224]
13 if (i<=1)
(ladebug) where
>0 0x120001224 in factorial(i=4) sample.c:13
#1 0x12000124c in factorial(i=5) sample.c:16
(ladebug) cont
Called Procedure Returned
stopped at [main:4 0x120001180]
4 for (i=1 ; i<=3 ; i++) {
(ladebug) where
>0 0x120001180 in main() sample.c:4
(ladebug)
|
The Ladebug debugger supports function calls and expression evaluations that call functions, with the following limitations:
| Previous | Next | Contents | Index |