This chapter introduces the features and functions of the Ladebug command interface. It describes how to:
This chapter also presents an example debugging session from the command interface.
For an introduction to the Ladebug window interface, see Chapter 2.
There are several ways to invoke Ladebug from the command interface and bring your program under debugger control. For example, you can invoke Ladebug from the command interface and specify:
Once you have invoked Ladebug, you can bring a process or program under debugger control from the Ladebug prompt by attaching to a process or loading a program. For applications that fork and/or exec, you can also control whether to bring the child process under debugger control.
To bring a program or process under debugger control from the shell, choose the appropriate syntax for invoking Ladebug from among the following:
$ ladebug executable_file
$ ladebug executable_file core_file
$ ladebug -pid process_id executable_file
$ ladebug -k /umunix
$ ladebug -remote
$ ladebug -rn node_or_address [,udp_port]
For information on using the Ladebug prompt from within the window interface, see Section 2.4.
You can bring a program or process under debugger control after invoking Ladebug from the command interface or window interface. From the Ladebug prompt, you can:
(ladebug) load image_file [core_file]
(ladebug) attach process-id image_file
For information about attaching to a process, see Section 7.8.9 and Section 9.13. For information about loading a program, see Section 20.4.
You can enter several commands on a single line by separating the commands with a semicolon (;). The commands are executed in the order in which you enter them. Example 7-1 shows how to enter multiple commands on a single line.
(ladebug) stop in main;run
[#1: stop in main ]
[1] stopped at [main:4 0x120000a40]
4 for (i=1 ; i<3 ; i++) {
(ladebug) where
>0 0x120000a40 in main() sample.c:4
(ladebug)
You can enter multiline commands by using a backslash (\) at the end of a line to be continued.
The debugger predefines a set of debugger variables. You can display and modify these variables to alter debugger settings. You can also create new debugger variables to use within other commands, or as placeholders of important information.
All debugger variable names start with a dollar sign ($). The
set command, used alone, causes the display of all the
debugger variables with their current values. The set
command also lets you set the value of a debugger variable. Using
this command, you can redefine an existing debugger variable or
create a new debugger variable. The syntax for defining a debugger
variable with this command is as follows:
set variable = value
If the value of the variable is a text string, enclose the string
in quotes. Example 7-2 shows how to use
the set command to display and redefine debugger
variables. In this example, all the predefined variables are
displayed by the set command. Then the $lang
and $historylines variables are changed and
displayed. (The $lang variable determines the language
syntax and visibility rules the debugger uses; the value for the
$lang variable is a string enclosed in quotation
marks. The $historylines variable determines the
number of lines listed by the history command.)
(ladebug) set $ascii = 1 $beep = 1 $catchexecs = 0 $catchforks = 0 $curevent = 0 $curfile = (null) $curline = 0 $curpc = 0 $cursrcline = 0 $curthread = 0 $decints = 0 $editline = 1 $eventecho = 1 $hasmeta = 0 $hexints = 0 $historylines = 20 $indent = 1 $lang = "C" $listwindow = 20 $main = "main" $maxstrlen = 128 $octints = 0 $overloadmenu = 1 $pimode = 0 $prompt = "(ladebug) " $repeatmode = 1 $stackargs = 1 $stepg0 = 0 $stoponattach = 0 $stopparentonfork = 0 $threadlevel = "decthreads" $verbose = 0 (ladebug) set $lang = "C++" (ladebug) set $historylines = 40 (ladebug) print $lang "C++" (ladebug) print $historylines 40 (ladebug)
For more information on these debugger variables, see Part V, Command Reference.
Use the unset command to delete a debugger variable
that you created, or to return a debugger variable to its default
value. The syntax for the unset command is as follows:
unset variable
The debugger lets you use abbreviations for frequently used
commands. These abbreviations are called aliases. You
can list all available aliases by entering alias at
the debugger prompt. To view the definition of a single alias, enter
alias followed by the alias name.
To delete an alias, enter unalias followed by the
alias name.
Several aliases are predefined by the debugger. The predefined
aliases substitute one or two letters for whole commands. For
example, l is the alias for list
and q is the alias for quit. A
complete list of predefined aliases is in the description of the
alias command in Part V, Command
Reference, and is also displayed by the debugger in response to
the alias command with no arguments.
You can also create your own aliases. The alias
command syntax for creating your own alias is as follows:
alias aliasname "string"
After you define the alias, entering aliasname is
identical to entering string. Example 7-3 creates an alias that sets a breakpoint, runs your
program, and performs a stack trace.
(ladebug) alias cs
alias cs is not defined
(ladebug) alias cs "stop at 5; run; where"
(ladebug) alias cs
cs stop at 5; run; where
(ladebug) cs
.oS
[#1: stop at "sample.c":5 ]
[1] stopped at [main:5 0x120000b1c]
5 f = factorial(i);
>0 0x120000b1c in main() sample.c:5
(ladebug)
Aliases may also contain parameters. In Example 7-4, the alias defined in Example 7-3 is modified to specify the breakpoint's line number
when you enter the abbreviated alias command.
(ladebug) alias cs(x) "stop at x; run; where"
(ladebug) alias cs
cs(x) stop at x; run; where
(ladebug) cs(5)
[#1: stop at "sample.c":5 ]
[1] stopped at [main:5 0x120000b1c]
5 f = factorial(i);
>0 0x120000b1c in main() sample.c:5
(ladebug)
Aliases may have multiple parameters. The alias
command syntax for creating an alias with more than one parameter
is as follows:
alias aliasname (arg1, arg2, [, . . . ]) "string"
You can nest aliases. You can define one alias and use that alias in the definition of another alias. In Example 7-5, such an alias is defined and then used in the definition of another alias.
(ladebug) alias begin "bp main; run"
(ladebug) alias sp(x,v) ""begin; stop at x; p v""
(ladebug) alias sp
sp(x, v) begin; stop at x; print v
(ladebug) sp(10,i)
[#4: stop in main ]
[4] stopped at [main:4 0x120001180]
4 for (i=1 ; i<=3 ; i++) {
0
(ladebug)
Your definition of an alias can include a quoted string. See the
alias command in Part V, Command
Reference for an example.
The debugger maintains a list of the commands you enter. Using an
abbreviated command sequence, you can reenter a command without
retyping the entire command (a history feature). Pressing the
Return key at the debugger prompt repeats the last command, provided
the $repeatmode variable is set to 1, which is the
default. Entering two exclamation points (!!) at the debugger prompt
also repeats the last command (regardless of the setting of the
$repeatmode variable).
You can examine the list of recently entered commands by entering
the history command at the debugger prompt. The last
command entered is at the bottom of the numbered list. The number of
commands listed by the history command is determined
by the value of the $historylines debugger variable.
To enter a command on the list, type an exclamation point followed
by the number of the command on the history list. You can also
specify a command by indicating how recently the command was last
entered; for example, !-3 reenters the third-to-last
command you entered.
You can also reenter a command by entering an exclamation point
followed by the beginning of the command string. For example, to
reenter the command deactivate 3, enter the command
!dea. Example 7-6 uses the
history mechanism to reenter commands. You can also
use the arrow keys to reenter commands if $editline is
set to 1, which is the default.
(ladebug) stop in main
[#1: stop in main ]
(ladebug) run
[1] stopped at [main:4 0x120001180]
4 for (i=1 ; i<3 ; i++) {
(ladebug) next
stopped at [main:5 0x120001188]
5 f = factorial(i);
(ladebug) print i
1
(ladebug) next
stopped at [main:6 0x1200011a0]
6 printf("%d! = %d\en",i,f);
(ladebug) print f
1
(ladebug) print factorial(f)
1
(ladebug) delete all
(ladebug) stop in factorial
[#2: stop in factorial ]
(ladebug) rerun
[2] stopped at [factorial:13 0x120001224]
13 if (i<=1)
(ladebug) step
stopped at [factorial:14 0x120001230]
14 return (1);
(ladebug) <Return>
stopped at [factorial:17 0x120001264]
17 }
(ladebug) <Return>
stopped at [main:5 0x120001194]
5 f = factorial(i);
(ladebug) print f
0
(ladebug) list $curline - 5: 10
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\en",i,f);
7 fflush(stdout);
8 }
9 }
10 factorial(i)
(ladebug) cont
1! = 1
[2] stopped at [factorial:13 0x120001224]
13 if (i<=1)
(ladebug) where
>0 0x120001224 in factorial(i=2) sample.c:13
#1 0x120001194 in main() sample.c:5
(ladebug) cont
[2] stopped at [factorial:13 0x120001224]
13 if (i<=1)
(ladebug) where
>0 0x120001224 in factorial(i=1) sample.c:13
#1 0x12000124c in factorial(i=2) sample.c:16
#2 0x120001194 in main() sample.c:5
(ladebug) history
10: print f
11: print factorial(f)
12: delete all
13: stop in factorial
14: rerun
15: step
16: step
17: step
18: print f
19: list $curline-5:10
20: cont
21: where
22: cont
23: where
24: history
(ladebug) !12
delete all
The sh command allows you to execute Bourne shell
commands without exiting the debugger. The syntax for the sh
command is as follows:
sh command
The command argument is a valid operating system command expression.
Do not enclose the command in quotes, even if it consists of multiple words separated by spaces.
After the command finishes, a debugger prompt appears and you can continue with your debugging session.
Example 7-7 uses the shell command sh
to list information about a file.
(ladebug) sh ls -l sample.c -rw-r----- 1 Ladebug 259 May 15 13:08 sample.c (ladebug)
In Example 7-8 the grep shell
command displays the lines containing PROGRAM in the
Fortran source file data2.f90.
(ladebug) sh grep PROGRAM data2.f90
PROGRAM DATA
END PROGRAM DATA
You can also spawn the Bourne shell from the debugger
by issuing:
(ladebug) sh sh
Ladebug supports simple emacs style bindings for CTRL
keys and arrow keys to edit a command line, as follows:
CTRL-A | Move to the beginning of the line. |
CTRL-E
| Move to the end of the line. |
CTRL-D | Delete a character in place. |
CTRL-K |
Kill (cut) from the cursor to the end of line, into the cut buffer. |
CTRL-Y |
Yank (paste) from the cut buffer, at the position of the cursor. |
CTRL-P or up arrow
| Access items in the history, backward. |
CTRL-N or down arrow | Access items in the history, forward. |
CTRL-F or right arrow | Move the cursor to the right. |
CTRL-
B or left arrow | Move the cursor to the left. |
The debugger variable $editline enables these key
bindings. By default, this variable is set to 1, and they are
enabled. (For backward compatibility, you can set $editline
to 0. The $editline is also set to 0 when you
use emacs with Ladebug.)
The debugger variable $beep controls whether a beep
sounds when a user tries to perform an illegal action; for example,
moving the cursor past the end of a line, or "yanking" from an empty
cut buffer. By default, the $beep variable is set to
1, enabling the beep to sound.
For more information on using the set and
unset commands with debugger variables, see Section 7.3.
Command-line editing features that are not supported in the
current release include multiple editing modes (emacs
and vi ), multi-line editing, and binding arbitrary
keys to actions.
This section describes the steps necessary to compile and debug a
short C program. If you are new to source-level debugging, edit a
file called sample.c, type in the sample program, and
follow the instructions for the sample debugging session.
The sample debugging session shows you how to:
For information about basic debugging techniques, see Section 1.3. For information about the Ladebug commands used in this sample session, see Part V, Command Reference.
The sample program in Example 7-9 uses
only C constructs. The program is intended to print the factorials
of 1, 2, and 3 and then exit.
#include <stdio.h>
main() {
int i,f;
for (i=1 ; i<3 ; i++) {
f = factorial(i);
printf("%d! = %d\n",i,f);
fflush(stdout);
}
}
factorial(i)
int i;
{
if (i<=1)
return (1);
else
return (i * factorial(i-1) );
}
Example 7-10 demonstrates the steps
required to compile, link, and execute the sample program. These
instructions assume that the sample program is named sample.c
and that you are using the C compiler cc to
build your executable file:
-g option on the compiler command
line to instruct the compiler to include in the executable file
symbol-table information useful to the debugger.
-o option to instruct the
compiler to place the executable image in a file named
sample.
% cc -g sample.c -o sample % sample 1! = 1 2! = 2
Something is wrong; the program compiles and runs without an error
message but does not print the factorial of 3. You can
use the Ladebug debugger to determine the problem.
Example 7-11 demonstrates how to invoke
the debugger on the program by using the ladebug
command. When invoked, the debugger displays a startup banner and
some information about the program being debugged. The debugger
prompt, (ladebug) , is displayed when the debugger is
waiting for your next command.
(%) ladebug sample Welcome to the Ladebug Debugger Version 4.0 ------------------ object file name: sample Reading symbolic information ...done (ladebug)
At this point, you can examine the program being debugged, set breakpoints or tracepoints, or run the program under debugger control.
To look at the source code lines, enter the list
command using the following syntax:
list line_number
The debugger displays the compiler-generated number for each line in
the target program. Many debugger commands (including the list
command) and messages refer to these line numbers. Example 7-12 shows how to use the list
command to view the program source file.
(ladebug) list 1
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 }
10 factorial(i)
11 int i;
12 {
13 if (i<=1)
14 return (1);
15 else
16 return (i * factorial(i-1) );
17 }
(ladebug)
By default, the debugger lists 20 lines of source code at a time.
The list 1 command in this example specifies that the
listing is to begin with the first line of the program. The program
is less than 20 lines, so a listing beginning with line 1 displays
the entire program.
If you have a rough idea of where the error is occurring in your
program, you can set a breakpoint and run the program under debugger
control. A breakpoint set at a line number causes the debugger to
suspend program execution each time that line is encountered. To set
the breakpoint at a particular line number, enter the stop at
command using the following syntax:
stop at line_number
You can also set a breakpoint in a function so that the debugger
suspends program execution when it enters the specified function.
Using the following syntax, the stop in command lets
you set a breakpoint at a function:
stop in function_name
According to the sample program listing in Example 7-12, the call to the function factorial
is on line 5. The breakpoint command in Example 7-13 shows how to set a breakpoint on line 4.
(ladebug) stop at 4 [#1: stop at "sample.c":4 ] (ladebug)
The debugger confirms the breakpoint by assigning the breakpoint
a reference number and reiterating the breakpoint command. In this
example, the reference number is 1.
Use the run or rerun command to instruct
the debugger to execute your program. During execution, you can
examine your program's variables, trace the stack, or step through
the program line by line.
When the debugger reaches a breakpoint, the debugger displays the breakpoint that suspended execution and the line of code that will be executed next, if normal program execution is continued. In Example 7-14, program execution is suspended because of the breakpoint. The next line of code that will be executed if line-by-line execution is continued is line 4.
(ladebug) run
[1] stopped at [main:4 0x120001180]
4 for (i=1 ; i<3 ; i++) {
(ladebug)
Use the print command to examine the program state.
The syntax for the print command is as follows:
print expression
The expression argument is any expression containing one or more variables, constants, and operators that is valid in the current context. In Example 7-15 a variable is evaluated and the debugger prints the result.
(ladebug) print i 0 (ladebug)
The output shows that the value of the variable i is 0.
When program execution is suspended, you can continue execution on
a line-by-line basis by using the step and next
commands, or you can inspect the program state. After a
line executes, the debugger prompt returns. Pressing the Return key
repeats the previous command.
The step command executes the next line of code in
the program. If that line of code calls another function, and if
there is debugging information about that function available to
the debugger, the step command executes the called
function line by line. This is called stepping into a function. If
debugging information is not available to the debugger, as is the
case with the printf and fflush library
routines, the debugger will execute the called function and stop at
the next line of code in the function that initiated the call.
The next command also executes the next line of code
in the program. If that line of code calls another function, the
next command executes that function and stops at the
next line of code in the function that initiated the call. This
is called stepping over a function. The next command
steps over called functions; the step command
steps into called functions.
main
i changes to
1
factorial
After the debugger executes the function factorial, the
debugger returns to the function main and steps over
the library routines printf and fflush.
(ladebug) step
stopped at [main:5 0x120000b1c]
5 f = factorial(i);
(ladebug) print i
1
(ladebug) next
stopped at [main:6 0x120000b38]
6 printf("%d! = %d\n",i,f);
(ladebug) step
1! = 1
stopped at [main:7 0x120000a7c]
7 fflush(stdout);
(ladebug) step
stopped at [main:8 0x120000a48]
8 }
(ladebug)
The stack trace lets you follow the dynamic call chain from function
to function. The where command displays the stack
trace. The stack trace displays the most recently called function
on the top of the stack. Each function is followed by its calling
function, until all active functions are displayed.
Each function on the stack is placed on a separate line, and is associated with a number that corresponds to an activation level relative to the top of the stack. The most recently called function is on level 0, at the top of the stack.
Example 7-17 continues to step through
the sample program. As the program computes 2!, control
passes from main to factorial and
back in a predictable fashion. A stack trace taken while stepping
through the function factorial() for the second time
(when i equals 2 ) contains an entry
for function main and two entries for the recursive
function factorial.
(ladebug) step
stopped at [factorial:13 0x120001224]
13 if (i<=1)
(ladebug) <Return>
stopped at [factorial:16 0x12000123c]
16 return (i * factorial(i-1) );
(ladebug) <Return>
stopped at [factorial:13 0x120001224]
13 if (i<=1)
(ladebug) where
>0 0x120001224 in factorial(i=1) sample.c:13
#1 0x12000124c in factorial(i=2) sample.c:16
#2 0x120001194 in main() sample.c:5
(ladebug) step
stopped at [factorial:14 0x120001230]
14 return (1);
(ladebug) <Return>
stopped at [factorial:17 0x120001264]
17 }
(ladebug) <Return>
stopped at [factorial:16 0x12000123c]
16 return (i * factorial(i-1) );
(ladebug) <Return>
stopped at [factorial:17 0x120001264]
17 }
(ladebug) <Return>
stopped at [main:5 0x120001194]
5 f = factorial(i);
(ladebug) <Return>
stopped at [main:6 0x1200011a0]
6 printf("%d! = %d\n",i,f);
(ladebug) <Return>
2! = 2
stopped at [main:7 0x1200011c0]
7 fflush(stdout);
When you continue stepping through the program, control does not
pass back to factorial() to compute the factorial
of 3 (see Example 7-18).
Instead, the next line that is executed is the last line of
main() . The cont command instructs
the debugger to resume running the program. The program finishes
executing without printing the factorial of 3.
(ladebug) step
stopped at [main:9 0x120000b84]
9 }
(ladebug) cont
Thread has finished executing
(ladebug)
The problem in Example 7-9 may lie in the
bounds of the for construct:
for (i=1 ; i<3 ; i++) {
Careful examination confirms this hypothesis. When the variable
i is incremented to 3, the statement
i < 3 is false and a loop exits.
To fix the problem, change the statement as follows:
for (i=1 ; i<=3 ; i++) {
To make the change, edit the for construct in the
source file and recompile the program.
To edit the source file, choose one of the following:
run or
rerun command, the debugger will use the new
program. Previously set breakpoints and traces will still be
active.
quit command to leave the debugger
then edit the source file, recompile the program, and test
the program. If you want to retest the program under debugger
control, invoke the debugger again. After you quit the debugger,
all breakpoints, tracepoints, and other program-specific settings
are lost.
Another way to troubleshoot the problem in Example 7-9 is to trace the value of variable i
as the program executes. If you have not yet exited the debugger,
the breakpoint at line 4 is still active. You can enter the
delete command to delete the breakpoint at line 4. In
Example 7-19, the status
command is used to list the breakpoints or tracepoints that are
currently active and the delete command is used to
remove the breakpoint at line 4.
(ladebug) status
#1 PC==0x120001180 in main "sample.c":4 { break }
(ladebug) delete 1
(ladebug) status
(ladebug)
You can use the trace command to monitor program
variables and to monitor when functions are entered and exited.
With this command, you can set a tracepoint on a variable that is
visible from the current context at the time you set the breakpoint.
The syntax is as follows:
trace variable
When you run your program under debugger control, the debugger will
print a message when the variable changes value. The trace
command works at the function level; when a traced variable
is evaluated, and the subsequent message is printed when program
execution begins each function, not at the line of code
that caused the variable value to change.
In Example 7-20:
main
main using the run
command
trace
command and resume program execution using the cont
command
(ladebug) stop in main
[#2: stop in main ]
(ladebug) run
[2] stopped at [main:4 0x120000a40]
4 for (i=1 ; i<3 ; i++) {
(ladebug) trace i
[#3: trace i ]
(ladebug) cont
[3] Value of i changed before "sample.c":13
Old value = 0
New value = 1
1! = 1
[3] Value of i changed before "sample.c":13
Old value = 1
New value = 2
2! = 2
[3] Value of i changed before "../exit.c":12
Old value = 2
New value = 3
Thread has finished executing
(ladebug) "
Tracing variable i reveals that the loop did not
execute when i was equal to 3. This was
the same conclusion reached earlier by stepping through program
execution.
In this example, the trace command works well, even
though traces are computationally intensive and can dramatically
slow down program execution. For this reason, using traces may
not be appropriate in every situation. Each debugging problem is
different, and you may need to try several different methods on a
program before you uncover the problem.
Ladebug allows you to attach to a running process that is not under debugger control and debug the process.
Use the attach command to connect to a running
process by specifying the process ID and the associated image
file. Ladebug allows you to switch to debugging another process
in the same session by attaching to it or by loading it (see Section 20.4 for information about loading
a program). After you attach to a running process, you debug the
process as you would any process that is loaded by the debugger.
For common user scenarios for debugging attached processes, see Section 9.13.
You cannot issue the run or rerun
command on an attached process.
There are two ways to attach to a process. From the command line, the syntax is as follows:
$ ladebug -pid process_id
From the Ladebug prompt:
(ladebug) attach process_id image_file
The sample program in Example 7-9 has been modified slightly to show how to attach to (and detach from) a running process.
#include <stdio.h>
#include <unistd.h>
main() {
int i,f;
sleep (20);
for (i=1; i<3; i++) {
f = factorial(i);
printf("%d! = %d\n",i,f);
fflush(stdout);
}
}
factorial(i)
int i;
{
if (i<=1)
return (1);
else
return (i * factorial(i-1) );
}
Ladebug does not stop the running process when attaching to it. You
must type Ctrl/C to stop the process. You can also set the debugger
variable $stoponattach to 1 to cause Ladebug to stop
the attached process after attaching to it.
Example 7-21 shows how to attach to a process in a debugging session.
$ factorial & [1] 32625 1 $ ladebug -pid 32625 factorial 2 Welcome to the Ladebug Debugger Version 4.0-10 ------------------ object file name: factorial Reading symbolic information ...done 3 Attached to process id 32625 .... 4 ^CThread received signal INT 5 stopped at [<opaque> __usleep_thread(): ??? 0x3ff800ec850] (ladebug) stop in factorial 6 [#1: stop in int factorial(int) ] (ladebug) detach 7
The detach command lets you detach the debugger
from the previously attached process, based on the process ID you
specify from the process ID list. (See Example 7-21 for an example of attaching and detaching a
process.)
The syntax for the detach command is as follows:
detach [process_id]
The process_id parameter indicates the process
to which the debugger is attached. If you do not specify the
process_id parameter, Ladebug detaches from the
current process.
Detaching from a process removes the process information from the debugger, and disables your ability to debug the process.
Ladebug removes all user-specified breakpoints from the detached process. The process continues its program execution.
If other processes are attached to the process being debugged, the
detach command will not change the process's state.
The kill command terminates the process that executes
the program. If the process you terminate has child processes
associated with it, they are terminated also.
When a process is terminated, its process objects are not deleted
and Ladebug retains the symbolic debugging information. You can
issue run and rerun commands on that
application again.
Use the kill command to terminate a one or more
processes. The syntax of the kill command does not
take an argument.
The quit command will kill a process that was started
by Ladebug.
While displaying a process, you can stop it at any time by typing Ctrl/C.