9 Controlling Program Execution

This chapter descibes how to use Ladebug from the command interface to execute a program under debugger control and debug the program. Your source language may be C, C++, COBOL, Ada, or Fortran. Your program may have one or more processes or threads.

This chapter describes how to:

This chapter describes basic program control and debugging of single-process applications. For more information on debugging multiprocess applications, see Chapter 20. For information on debugging multithreaded applications, see Chapter 19.

9.1 Starting Program Execution: the run and rerun Commands

Use the run and rerun commands to start execution of a program under debugger control. Ladebug picks up any new image on the disk and reloads the latest symbolic debugging information.

You can run the program with command-line arguments by entering them immediately after the run command. Command-line arguments can include flags and options recognized by the program as well as input and output redirections.

The rerun command runs the program with the arguments last used with the run command. Example 9-1 shows how to use the run and rerun commands.

Example 9-1 Using run and rerun to Begin 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)

If you enter any command-line arguments with the rerun command, the debugger discards the previous set of arguments and uses the new arguments.

9.2 Terminating Program Execution: the kill Command

You can terminate program execution by using the quit or kill commands. The quit command terminates both the debugger and the debugged process and returns you to the shell.

The kill command terminates the debugged process but leaves the debugger running. Any breakpoints and traces previously set will still be set. You can rerun the program after it has been killed.

9.3 Stepping Through Functions

After program execution suspends at a breakpoint or due to a signal, you can direct the debugger to execute only the next line or to continue execution until the current function or a named function exits.

The step and next commands let you execute your source code line by line in the debugger, which gives you the opportunity to examine variables and data structures. If the source-code line contains a function call, and the debugging information about the function is available to the debugger, the step and next commands behave differently.

9.3.1 The step Command

The step command steps through your program one line at a time following the flow of control exactly. It steps into the function call and returns to the debugger prompt with the program counter pointing at the first line in the function that was called.

In Example 9-2, two step commands continue executing a Fortran program into lines 10 and 11 after program execution has paused at line 9.

Example 9-2 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

9.3.2 The next Command

The next command 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.

If the debugging information for the function is not available to the debugger, then the debugger will step over the function regardless of whether the step or the next command was used.

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.

9.4 Resuming Program Execution

Use the cont command to resume program execution that has been suspended by a breakpoint or signal. Execution then continues until the next breakpoint or signal, or until the end of the program.

By entering a signal parameter value with the cont command, you can direct the debugger to send a signal to the program resuming program execution. This feature allows you to test your program's signal handling characteristics.

The signal parameter values can be either a signal number or a string name (for example, SIGSEGV). If you do not specify a parameter value, the default is 0, which allows the program to continue execution without the signal.

In Example 9-3, a cont command resumes program execution after program execution is suspended by a breakpoint.

Example 9-3 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)

9.5 Branching to a Specified Line: the goto Command

Use the goto command to branch to a specified line after execution is suspended. The source code between the line at which execution suspended and the line you specify is not executed.

To branch to a source code line, use the following syntax:

goto  line_number

The line_number argument must be a line of source code located in the same function in which execution is suspended.

Example 9-4 shows an example that uses the goto command.

Example 9-4 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)

9.6 Setting Breakpoints

The debugger lets you place breakpoints in your program. When program execution reaches one of these breakpoints, the debugger can either perform predefined actions and continue program execution or suspend program execution and return control to you. Breakpoints can:


Note
The stopi and wheni commands are specifically used for machine-level debugging. As such, breakpoints are set based on machine instruction addresses rather than line numbers. For more information on machine- level debugging, see Chapter 18.

Any breakpoints you define remain active until you exit the debugger, disable them using the disable command, or delete them using the delete command.

Table 9-1 lists the commands used for setting breakpoints.

Table 9-1 Commands for Setting Breakpoints

Command  Description 
stop   Without a variable argument, suspends program execution and returns to the prompt. With a variable argument, suspends program execution when a variable changes. 
stop if   Suspends execution when an expression evaluates to true. 
stop at   Suspends execution when a specific line number is encountered. 
stopi, stopi if, stopi at   For machine-level debugging; suspends program execution when the specified variable value changes, when an expression evaluates to true, or when a specified address is encountered. 
stop in   For C++ programming; see the Command Reference for specific forms of this command. 

9.6.1 Breakpoints That Suspend Program Execution

Use the stop and stopi commands to set a breakpoint that suspends program execution. When specified conditions are met, the debugger:

You can then use debugger commands to examine the program state, change program variable values, and continue program execution from the breakpoint.

To determine if program execution should halt, you can base the breakpoint on one or more of the following conditions:

To set a breakpoint that suspends program execution when an instruction corresponding to a line in the source code is reached, use the appropriate stop at command syntax.

9.6.1.1 The stop at Command

stop at  line_number

stop at  "file_name":line_number

The line_number argument specifies the line number in the source code of the current source file.

If the source code for your program spans multiple files, make sure that the file context is set to the correct file before you set your breakpoint. For example:

file  file_name

You must use quotation marks around the file_name argument as shown in the second form. For example, if the file name is sample.c and the line number is 4, you type

(ladebug) stop at "sample.c":4

After you enter a breakpoint command, the debugger confirms the breakpoint by displaying it and its reference number. Example 9-5 sets a breakpoint at line number 13 of the current source file.

Example 9-5 Setting a Breakpoint at a Line in C Source Code

(ladebug) stop at 13
[#1: stop at "sample.c":13 ]
(ladebug) run
[1] stopped at [factorial:13 0x120001224]
     13         if (i<=1)
(ladebug)

To set a breakpoint that suspends program execution when a memory address is reached, use the stopi at command.

9.6.1.2 The stopi at Command

stopi at  address

When program execution reaches the specified address, execution is suspended and the debugger prints the source instruction corresponding to the specified address. To specify the address in hexadecimal format, add the prefix 0x to the hexadecimal number. The debugger converts the address to decimal when it confirms the breakpoint command. Example 9-6 sets a breakpoint at the address of a particular line in the sample program.

Example 9-6 Setting a Breakpoint at an Address in the Source Code

(ladebug) stopi at 0x120000b14
[#1: stopi at 4831841044 ]
(ladebug) run
[1] stopped at [main:4 0x120000b14]
      4     for (i=1 ; i<3 ; i++) {
(ladebug)

To set a breakpoint that suspends execution at the first instruction in a program function, procedure, or statement, use the (stop in command.

9.6.1.3 The stop in Command

stop in  function

Note
With Version 4.0 (or higher) of the debugger, the stopi in command is no longer valid, and results in an error message. Replace stopi in in your code with stopi at for an address or stop in for a routine.

Example 9-7 shows how to set a breakpoint in a function.

Example 9-7 Setting a Breakpoint in a Function

(ladebug)  stop in factorial
[#1: stop in factorial ]
(ladebug)  run
[1] stopped at [factorial:13 0x120001224]
     13     if (i<=1)
(ladebug)

Functions and procedures in your executable file are usually each preceded by a prolog that contains information about the function or procedure but which is not of interest to most programmers while debugging their programs. The stop in command halts program execution after the prolog, at the first real sourcecode statement.

In Example 9-8 the stop in command sets a breakpoint at the beginning of an Ada program procedure named ADD_INTEGERS.

Example 9-8 Setting a Breakpoint at the Start of an Ada Procedure

(ladebug) stop in add_integers
[2] stop in add_integers
(ladebug)run
[2] stopped at [add_integers:3 +0x20002a69,0x120002a68]
    procedure add_integers is

9.6.1.4 The stop and stopi Commands

To set a breakpoint that stops program execution when the value of a program variable changes, use one of the following commands:

stop   variable

stopi   variable

The stop command checks the value of the specified variable every time program execution enters a function. The stopi command checks the value of the specified variable after every instruction. The stopi command enables you to determine precisely where a variable changes value, but slows program execution.

When you enter a trace, when, or stop command with a variable as an argument (but not in a conditional statement), the debugger records the address of the variable. Instead of looking up the variable name when checking the variable's value, the debugger dereferences the variable's absolute address. This ensures that the correct version of the variable is used regardless of the current context.

If the argument contains a variable as part of a larger expression that cannot be converted into an address and dereferenced, then the debugger must look up the variable name rather than dereference the variable's address. In this case, the debugger does the variable lookup in the current context, which may not be the context active at the time the trace, when, or stop command was entered.

Example 9-9 shows how to set a breakpoint on a variable.

Example 9-9 Setting a Breakpoint on a Variable

(ladebug)  stop i
[#2: stop if i changes ]
(ladebug)  run
[1] stopped at [main:4 0x120000b14]
      4     for (i=1 ; i<3 ; i++) {
(ladebug)  print i
0
(ladebug)  cont
Value of i changed before "sample.c":13
        Old value = 0
        New value = 1
[2] stopped at [factorial:13 0x120000bb8]
     13     if (i<=1)
(ladebug)  print i
1
(ladebug)

9.6.1.5 The stop if and stopi if Commands

To set a breakpoint that suspends program execution when the specified conditional expression evaluates to true, use one of the following commands:

stop if  (expression)

stopi if  (expression)

The debugger accepts any valid conditional expression in the language of the program you are debugging. Breakpoints that contain conditional expressions are sometimes called conditional breakpoints.

The stop if command checks each time a function is entered to see if the expression evaluates to true. The stopi if command checks after each machine instruction is executed to see if the expression evaluates to true. The stopi if version slows program execution considerably.

A variable included in a conditional expression may be undefined in the current scope at some time during program execution. If this is the case, the debugger prints an error message and suspends program execution as if the condition evaluated to true. Global variables work best in conditional statements.

Example 9-10 shows how to set a breakpoint with a user-defined expression.

Example 9-10 Setting a Conditional Breakpoint

(ladebug)  stop if (iter==2)
[#1: stop if iter==2 ]
(ladebug)  run
[1] stopped at [doit:20 0x120000e14]
     20         ++iter;
(ladebug)  print iter
2
(ladebug)

In this example, the breakpoint is activated only when the program variable iter equals 2.

9.6.1.6 Combining Optional Conditions to Customize Breakpoint Command

You can combine the optional conditions to further customize a breakpoint command. By combining the line number or function syntax with a conditional expression, you can create a breakpoint that halts program execution only if a line number or function is reached and an expression evaluates to true. Use one of the following commands to set this type of a breakpoint:

stop at line_number  if (expression)

stop in function  if (expression)

stopi at line_number  if (expression)

Example 9-11 creates a breakpoint that stops only if the program is executing the factorial function and the program variable i is equal to 2.

Example 9-11 Setting a Conditional Breakpoint in a Function

(ladebug)  stop in factorial if (i==2)
[#1: stop in factorial if i==2 ]
(ladebug)  run
1! = 1
[1] stopped at [factorial:13 0x120000bb8]
     13     if (i<=1)
(ladebug)  print 
2
(ladebug)

9.6.2 Breakpoints That Execute Debugger Commands: the when Commands

The when and wheni commands let you set breakpoints that execute debugger commands, (rather than suspend program execution) when the specified conditions are satisfied. To describe the conditions of the breakpoint, use the same condition syntaxes described in Section 9.6.1.

The syntax for the command that executes a set of debugger commands when a particular address or line number is reached is as follows:

when [variable]  at line_number {command [; . . . ] }

Use the following syntax for an address-oriented command:

wheni [variable]  at address {command [; . . . ] }

The commands in the argument must be enclosed in braces and separated by semicolons. These commands cause the statements in the command list to be executed immediately after the statements at the line number or address specified.

Example 9-12 creates a breakpoint that prints a stack trace when line 16 is reached.

Example 9-12 Setting a Breakpoint That Executes a Stack Trace

(ladebug)  when at 16 {where}
[#1: when at "sample.c":16 { where } ]
(ladebug)  run
1! = 1
[1] when [factorial:16 0x12000123c]
>0  0x12000123c in factorial(i=2) sample.c:16
#1  0x120001194 in main() sample.c:5
2! = 2
Thread has finished executing
(ladebug)

Example 9-13 creates a breakpoint that displays the contents of the expression HOLD-CHARS and SUB-1 in a COBOL program when line 50 is reached and then resumes execution.

Example 9-13 Setting a Breakpoint That Executes Multiple Commands

(ladebug) when at 50 {print chars of hold-chars; print SUB-1; cont;}
[#3 when at "testa.cob":50 ( print CHARS of HOLD-CHARS; print SUB-1; ; cont ; } ]

You can use the when and wheni commands to set breakpoints at function entry points, as shown in these syntax lines:

when [variable]  in function {command [; . . . ] }

wheni [variable]  in function {command [; . . . ] }

9.7 Setting Tracepoints: the trace commands

Tracepoints instruct the debugger to print a message when certain events occur during program execution. You can use tracepoints to notify you when program execution enters and exits program functions or when program variables change value. Tracepoints do not halt program execution but they do slow it down.

The debugger lets you set the following kinds of tracepoints:

You can base a tracepoint on the following conditions:

9.7.1 Tracepoints That Notify You of Function Entry and Exit

To set an entry/exit tracepoint unconditionally, enter either the trace or tracei command at the debugger prompt. An unconditional tracepoint is useful for following the execution flow of a program. If you use the tracei command, the debugger notifies you when each function's prolog (rather than the function itself) is entered. You can also specify conditions so tracing occurs only if program execution is:

Use one of the following command syntaxes to establish a conditional tracepoint:

trace at  line_number [if (expression)]

tracei at  address [if (expression)]

The expression argument can be any valid conditional expression in the language of the program being debugged. The expression can contain debugger variables, program variables, and constants.

Example 9-14 sets a tracepoint at line number 15 of the COBOL program TESTA.

Example 9-14 Setting a Tracepoint

(ladebug) trace at 15
[#3: trace at "testa.cob":15]

Example 9-15 shows a tracepoint that traces only if the program variable i is equal to 2 and execution is on line 5. When program execution reaches line 5, and i is equal to 2, the trace is activated and the debugger prints the current source line (line 5).

Example 9-15 Setting a Conditional Tracepoint

(ladebug) trace at 5 if (i==2)
[#1: trace at "sample.c":5 if i==2 ]
(ladebug) run
1! = 1
[1] trace [main:5 0x120000b1c]
>     5         f = factorial(i);
2! = 2
Thread has finished executing
(ladebug)

9.7.2 Tracepoints That Notify You of a Variable Value Change

You can set a tracepoint that prints a message if the value of a variable changes. Use one of the following commands to establish a variable tracepoint:

trace  variable

tracei  variable

When you use the trace command, the debugger evaluates the variable when execution enters a function. The debugger prints a message if the value of the variable is different than the value associated with that variable when the previously executed function was entered.

When you use the tracei command, the debugger evaluates the variable after each instruction is executed, and prints a message after the statement in which the value changed. Example 9-16 shows the difference between these two commands.

Example 9-16 Tracing Variables

(ladebug)  trace i
[#2: trace i ]
(ladebug)  tracei i
[#3: tracei i ]
(ladebug)  step
[3] Value of i changed before "sample.c":5
        Old value = 0
        New value = 1
stopped at [main:5 0x120001188]
      5         f = factorial(i);
(ladebug)  step
[2] Value of i changed before "sample.c":13
        Old value = 0
        New value = 1
stopped at [factorial:13 0x120001224]
     13     if (i<=1)
(ladebug)

You can also set a conditional tracepoint that notifies you of variable value changes, only if program execution is:

Use one of the following commands to establish a conditional variable tracepoint:

trace  variable [at line_number | in function]
              [if (expression)]

tracei  variable [at address | in function]
               [if (expression)]

9.8 Displaying, Deleting, Disabling, and Enabling Breakpoints and Tracepoints

This section describes the commands used to display, delete, disable, and enable breakpoints and tracepoints. It is written in terms of breakpoints but all of these commands are also applicable to tracepoints.

To list all the breakpoints known to the debugger, enter the status command.

To delete, disable, or enable a breakpoint, identify the breakpoint by its reference number. When breakpoints are created, they are associated with a reference number. This reference number is shown when:

Example 9-17 uses the status command to display active breakpoints in a COBOL program.

Example 9-17 Using status to Display Breakpoints

(ladebug) status
#1 PC==0x120001e14 in testa "testa.cob":2 {break}
#2 PC==0x120001ba4 in TESTB "testa.cob":47 {break}
#3 PC==0x120001c1c in TESTB "testa.cob":50
   {print CHARS of HOLD-CHARS; print SUB-1; ; cont ; ; }

9.8.1 Deleting Breakpoints and Tracepoints: the delete Commands

When a breakpoint is no longer needed, use the delete command to remove the breakpoint. To delete a single breakpoint, specify the reference number using the following syntax:

delete  number

To delete more than one breakpoint, separate the reference numbers with commas using the following syntax:

delete  number [, . . . ]

Example 9-18 shows breakpoints being deleted and the breakpoint status after each deletion.

Example 9-18 Deleting Breakpoints

(ladebug)  status
#1 PC==0x120001180 in main "sample.c":4 { break }
#2 (at Proc entry and if $trace0!=*0x11fffe48){trace-expr i;set $trace0=}
#3 if $trace1!=*0x11ffffe48 { trace-expr i; set $trace1 = *0x11ffffe48; }
(ladebug)  delete 1
(ladebug)  status
#2 (at Proc entry and if $trace0!=*0x11ffe48) {trace-expr i;set $trace0=}
#3 if $trace1!=*0x11ffffe48 { trace-expr i; set $trace1 = *0x11ffffe48; }
(ladebug)  delete 2,3
(ladebug)  status
(ladebug)

To delete all breakpoints known to the debugger, use one of the following commands:

delete all

delete *

9.8.2 Disabling Breakpoints and Tracepoints: the disable Commands

When you disable a breakpoint, the debugger ignores the breakpoint during program execution. A disabled breakpoint does not cause the program to suspend execution.

You can use the following disable commands to disable breakpoints:

disable  number

disable all

disable *

The disable * command has the same effect as disable all. It disables all breakpoints and all traces.

The disabled breakpoint is still displayed by the status command, but it is listed as disabled. Example 9-19 shows breakpoints being disabled.

Example 9-19 Disabling Breakpoints

(ladebug)  status
#1 PC==0x120000b14 in main "sample.c":4 { break }
#2 PC==0x120000bb8 in factorial "sample.c":13 { break }
#3 PC==0x120000b14 in main "sample.c":4 { break }
(ladebug)  disable 1
(ladebug)  status
#1 PC==0x120000b14 in main "sample.c":4 { break } Disabled
#2 PC==0x120000bb8 in factorial "sample.c":13 { break }
#3 PC==0x120000b14 in main "sample.c":4 { break }
(ladebug)  disable 2,3
(ladebug)  status
#1 PC==0x120000b14 in main "sample.c":4 { break } Disabled
#2 PC==0x120000bb8 in factorial "sample.c":13 { break } Disabled
#3 PC==0x120000b14 in main "sample.c":4 { break } Disabled
(ladebug)

9.8.3 Enabling Breakpoints and Tracepoints: the enable Commands

Disabled breakpoints remain deactivated until you enter the enable command to reactivate the breakpoint. You can use the following enable commands to enable disabled breakpoints:

enable  number

enable all

enable *

Example 9-20 shows the breakpoints that were disabled earlier and then reactivated with the enable command.

Example 9-20 Enabling Breakpoints

(ladebug)  status
#1 PC==0x4001b8 in main "sample.c":4 { break } Disabled
#2 PC==0x400250 in factorial "sample.c":13 { break } Disabled
#3 PC==0x4001b8 in main "sample.c":4 { break } Disabled
(ladebug)  enable 2
(ladebug)  status
#1 PC==0x4001b8 in main "sample.c":4 { break } Disabled
#2 PC==0x400250 in factorial "sample.c":13 { break }
#3 PC==0x4001b8 in main "sample.c":4 { break } Disabled
(ladebug)  enable all
(ladebug)  status
#1 PC==0x4001b8 in main "sample.c":4 { break }
#2 PC==0x400250 in factorial "sample.c":13 { break }
#3 PC==0x4001b8 in main "sample.c":4 { break }
(ladebug)

A breakpoint that has been reactivated with the enable command appears as an active breakpoint in the status list. Note that the last status list in this example is the same as the first status list in the preceding example (except for the PC values), showing three active breakpoints.

9.9 Returning from a Function: the return Command

The return command directs the debugger to continue program execution. The command syntax is as follows:

return [function]

The return command without any arguments directs the debugger to continue program execution until the current function exits. If you enter this command with an argument, the debugger continues program execution until the specified function returns.

The return command is also useful for finishing execution of a function you inadvertently stepped into with the step command.

In Example 9-21, 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 9-21 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)

9.10 Calling Functions: the call Command

After a breakpoint or a signal suspends program execution, you can execute a single function in your program by using the call command, 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 syntax for the call command is as follows:

call  function ([parameter[, . . . ]])

Specify the function as if you were calling the function from within your program. You can use both constants and locally visible variables as calling parameters. If the function you are calling has no parameters, specify empty parentheses.

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 9-22 shows both methods of calling a function.

Example 9-22 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 9-23.

Example 9-23 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 9-24.

Example 9-24 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:

9.11 Unaligned Data Accesses: the catch and ignore Commands

Unaligned data can slow program execution. You can use thecatch command to cause Ladebug to stop on each unaligned data access or the ignore command so the debugger does not stop.

catch unaligned

Enter the catch unaligned command to instruct the debugger to stop when unaligned access occurs in the debuggee process. The debugger:

Example 9-25 shows this:

Example 9-25 Catching Unaligned Access

(ladebug)  catch unaligned
(ladebug)  run

Unaligned access pid=12538 <unaligned_test> va=140002901
pc=120001168 ra=12000114c type=stl
Thread received signal BUS
stopped at [main:8 0x12000116c]
     8         temp = *j;          /* unaligned access */

You can distinguish between the SIGBUS of unaligned access and a normal SIGBUS because of the "unaligned access" message (issued by the kernel).

ignore unaligned

Enter the ignore unaligned command to instruct the debugger not to stop when unaligned access occurs. This is the default.

The unalignment functionality is implemented through the setsysinfo system call and SIGBUS. Ladebug makes the setsysinfo system call in the debuggee process so that unaligned accesses for attached processes are also caught.

Ladebug will preserve the previous user settings when these commands are issued.

If the user program executes a setsysinfo or uac (unaligned access control flag) that is inconsistent with the catch unaligned or ignore unaligned command, however, then the behavior of these commands will be affected.

If SIGBUS is ignored and then the catch unaligned command is issued:

(ladebug) ignore sigbus
(ladebug) catch unaligned
Warning: SIGBUS is currently being ignored  -
SIGBUS is being caught to catch Unaligned accesses.

If Ladebug is catching unaligned accesses and then SIGBUS is ignored:

(ladebug) catch unaligned
(ladebug) ignore sigbus
Warning: SIGBUS is currently being ignored  -
Cannot catch Unaligned accesses.

9.12 Using the pop Command

The pop command removes one or more execution frames from the call stack. The pop command undoes the work already done by the removed execution frames. It does not, however, reverse side effects such as changes to global variables. You may need to use the assign command to restore the values of global variables.

The pop command is useful when execution has already passed an error that needs to be corrected.

The syntax of the command is as follows:

pop [number_of_frames]

The optional argument is the number of execution frames to remove from the call stack. If you do not specify the argument, one frame is removed. If specified, the number must be a positive integer less than or equal to the number of frames currently on the call stack.

It is an error to issue the pop command when there is no running program.

The following fragment of a debugger session shows the use of the pop command:

Reading symbolic information ...done
(ladebug) bp factorial
[#1: stop in int factorial(int) ]
(ladebug) r
Factorial time has begun.
[1] stopped at [factorial:30 0x120001524]
     30   printf("entered factorial\n");
(ladebug) where
>0  0x120001524 in factorial(ii=1) c_listfunc_factorial.c:30
#1  0x12000140c in main() c_listfunc.c:41
(ladebug) pop
[1] stopped at [main:41 0x120001410]
     41     f = factorial(i);
(ladebug) c
[1] stopped at [factorial:30 0x120001524]
     30   printf("entered factorial\n");

9.13 Controlling the Debugging of Attached Processes: the attach and detach Commands

To attach to a running process, first invoke Ladebug with a process ID number and the matching image file from the command line or from within Ladebug using the attach command followed by the process ID and image file. For information on invoking Ladebug to attach to a running process, see Section 7.8.9.

After Ladebug attaches to a process, control is returned to the debugger when the process stops (for example, after having received a signal). You can also manually return control to the debugger by pressing Ctrl/C or by setting the debugger variable $stoponattach to 1 to stop the attached process.

Use the detach command to detach the debugger from the previously attached process, based on the process ID you specify. Ladebug only detaches the specified process and removes all the user-specified breakpoints from that process.

The following restrictions apply when you debug an attached process:

9.14 Debugging Programs with Stripped Images

The strip command removes the symbol table and relocation information ordinarily attached to the output of the assembler and loader. If you are debugging a binary image that has been stripped, only machine-level debugging is supported. For information on machine-level debugging, see Chapter 18.

9.15 Using Environment Variables Within the Debugger

Ladebug provides commands for manipulating the environment of subsequent debuggees with environment variables. From within the debugger, you can use the following commands:

setenv [env_variable [value]]
export [env_variable [= value]]

Sets the value of the specified environment variable. If no variable is specified, the command displays the values of all environment variables. If a variable is specified but no value is specified, then the variable is set to NULL.

setenv and export are synonyms.

printenv [env_variable]

Displays the value of the specified environment variable. If none is specified, the command displays the value of all environment variables.
unsetenv [env_variable]

Removes the specified environment variable. If no variable is specified, all environment variables are removed.

Manipulation of Subsequent Environments Without Affecting the Current Environment

The environment-manipulation commands apply to any subsequent debuggee environment but not to the current environment. For example:

% ladebug a.out
(ladebug) bpmain; run
Stopped in main
(ladebug) setenv LD_LIBRARY_PATH /usr/proj/libraries

At this point, the setting of the environment variable LD_LIBRARY_ PATH is not in effect; it does not apply to the current execution of the file a.out, which was started by the run command. The environment variable will be applied after you create a new debuggee by means of one of the following:

This functionality is useful because it allows you to have different environments: it allows an environment for processes created by Ladebug that is different from Ladebug's environment, and also different from the environment of the shell from which Ladebug was invoked.


Note
The environment-manipulation commands have no effect on other environments. For example, the debuggee program cannot affect the output of the Ladebug command setenv. Nor can the Ladebug command setenv affect subsequent debuggee calls to getenv(3), which, like putenv(3) and clearenv(3) , is an environment manipulation routine in libc.a.

Differences in Prior Versions

For Ladebug prior to Version 4.0, the only way to set environment variables was to set them in the shell, before invoking the debugger, using one of the following commands:

The environment thus created in the shell applies to the debugger and also is inherited by any debuggees subsequently created.

Two notable disadvantages of this method are as follows:

Differences from dbx Debugger Functionality

If you are familiar with the dbx debugger, it is important to be aware of the following differences: