Title and Contents

Part I
A Quick Introduction to Using the Ladebug Debugger

Part I provides all the information you need to make simple use of the debugger.

Chapter 1 - Overview

You look for a bug by doing the following:

  1. Find a repeatable reproducer of the bug — the simpler the reproducer is, the simpler the following steps will be to do.

  2. Prepare your program for debugging.

  3. Start the debugger.

  4. Give commands to the debugger.

  5. Do whatever it takes to reproduce the bug, so that the breakpoints will stop the process close to where the bug has caused something detectably wrong to happen.

  6. Look around to determine the location of the bug:

1.1 Preparing a Program for Debugging

Compile and link your program using the -g switch.

If the problem only occurs in optimized code, use the -g3 switch.


1.2 Starting the Debugger

Before you start the debugger, make sure that you have correctly set the size information for your terminal; otherwise, the debugger's command line editing support may act unpredictably. For example, if your terminal is 47x80, you may need to set the following: Following are four basic alternatives for running the debugger on a process:
  1. Have the debugger create the process using the shell command line to identify the executable to run:
        % ladebug a.out
        Welcome to the Ladebug Debugger Version 4.0-58
        ------------------
        object file name: /usr/users/user1/a.out
        Reading symbolic information ...done
        (ladebug) stop in main
        [#1: stop in int main(void) ]
        (ladebug) run
    
  2. Have the debugger create the process using the debugger commands to identify the executable to run:
        % ladebug
        Welcome to the Ladebug Debugger Version 4.0-58
        (ladebug) load a.out
        Reading symbolic information ...done
        (ladebug) stop in main
        [#1: stop in int main(void) ]
        (ladebug) run
    
  3. Have the debugger attach to a running process using the shell command line to identify the process and the executable file that process is running:
        % a.out &
        [2] 27859
        % jobs	
        [2]  Running
        ...
        % ladebug a.out -pid 27859
        Attached to process id 27859  
        ....
    
    Press Ctrl/C to interrupt the process.

  4. Have the debugger attach to a running process using the debugger commands to identify the process and the executable file that process is running:
        % a.out &
        [2] 27859
        % jobs
        [2]  Running
        ...
        % ladebug
        (ladebug) attach 27859 a.out
        Attached to process id 27859  
        ....
    
    Press Ctrl/C to interrupt the process.

NOTE: In the case of Fortran, routine main at which your program stops is not your main program unit. Rather, it is a main routine supplied by the Fortran system that performs some initialization and then calls your code. Just step forward a couple of times (probably twice) and you will soon step into your code.

1.3 Entering Debugger Commands

The debugger issues a prompt when it is ready for the next command from the terminal:

When you enter commands, you use the left and right arrow keys to move within the line and the up and down arrow keys to recall previous commands for editing. When you finish entering a command, press the Enter key to submit the completed line to the debugger for processing.

You can continue a line by ending the line to be continued with a backslash (\) character.

On a blank line, press the Enter key to re-execute the most recent valid command.

Following are two very useful commands:

1.4 Scripting or Repeating Previous Commands

To execute debugger commands from a script, use the source command as follows: The source command causes the debugger to read and execute Ladebug commands from filename.

1.5 Context for Executing Commands

Although the debugger supports debugging multiple processes, it operates only on a single process at a time, known as the current process.

Processes contain one or more threads of execution. The threads execute functions. Functions are sequences of instructions that come from source lines within source files.

As you enter debugger commands to manipulate your process, it would be very tedious to have to repeatedly specify which thread, source file, and so on you wish the command to be applied to. To prevent this, each time the debugger stops the process, it re-establishes a static context and a dynamic context for your commands. The components of the static context are independent of this run of your program; the components of the dynamic context are dependent on this run.

You can change most of these individually to point to other instances, as described in the relevant portions of this manual, and the debugger will modify the rest of the static and dynamic context to keep the various components consistent.

1.6 Running a Program Under Debugger Control

As was shown previously, you can tell the debugger how to create a process, or to attach to an existing process.

After you specify the program (either on the shell command line or by using the load command), but before you have requested the debugger to create the process, you can still do things that seem to require a running process, for example, you can create breakpoints and examine sources. Any breakpoints that you create will be inserted into the process as soon as possible after it executes your program.

To have the debugger create a process (rather than attach to an existing process), you request it to run, specifying, if necessary, any input and output redirection and arguments as follows:

	% ladebug a.out
        Welcome to the Ladebug Debugger Version 4.0-58
	(ladebug) run
or
	(ladebug) run args
or
	(ladebug) run > output-file
or
	(ladebug) run args > output-file < input-file
The result of using any of the preceding command variations is similar to having attached to a running process. The rerun command repeats the previous run command with the same arguments and files.

1.7 Pausing the Process at the Problem

Following are the four most common ways to pause a process:
  1. Press Ctrl/C:

  2. Wait until the process raises some signal. It will do this when there is an arithmetic exception, an illegal instruction, or an unsatisfiable memory access, such as an attempt to write to memory for which protection is set to read-only.

  3. Create a breakpoint before you run or continue the process:

  4. Create a watchpoint before you run or continue the process:

1.8 Examining the Paused Process

The following sections describe how to examine components of the paused process.

1.8.1 Looking at the Source Files

You can perform the following operations on source files: Following is an example that shows listing lines and using the / command to search for a string:
    % ladebug a.out
Aliases are shorthand forms of longer commands. This example shows using the W alias, which lists up to 20 lines around the current line. Note that a right bracket (>) marks the current line.

1.8.2 Looking at the Threads (Tru64 UNIX Only)

In a multithreaded application, you can obtain information about the thread that stopped or about all the threads and you can then change the context to look more closely at a different thread. Note that a right bracket marks the current thread.

You can select any thread to be the focus of commands that show things. For example:

1.8.3 Looking at the Call Stack

You can examine the call stack of any thread. Even if you are not using threads explicitly, your process will have one thread running your code. You can move up and down the stack, and examine the source being executed at each call. For example:

1.8.4 Looking at the Data

You can look at variables and evaluate expressions involving them. For example:

1.8.5 Looking at the Signal State

The debugger shows you the signal that stopped the thread. For example:

1.8.6 Looking at the Generated Code

You can print memory as instructions or as data. Note that * marks the current instruction. You can examine registers. For example:

1.9 Continuing Execution of the Process

After you are satisfied that you understand what is going on, you can move the process forward and see what happens. The following table shows the aliases and commands you can use to do this.

Desired Behavior
Alias
Command
Can Take Repeat Count
Continue until another interesting thing happens
c
cont
Yes
Single step by line, but step over calls
n
next
Yes
Single step to a new line, stepping into calls
s
step
Yes
Continue until control returns to the caller
return
No
Single step by instruction, over calls
ni
nexti
Yes
Single step by instruction, into calls
si
stepi
Yes

The following example demonstrates stepping through lines of source code.

The following example demonstrates stepping at the instruction level:

1.10 Snapshots as an Undo Mechanism

Often when you move the process forward, you accidentally go too far. For example, you may step over a call that you should have stepped into.

In a program that does not use multiple threads, you can use snapshots to save your state before you step over the call. Then clone that snapshot to position another process just before the call so you can step into it.

The following example shows the stages of a snapshot being used in this way:

  1. The first stage is to build the program and start debugging.
  2. The next stage is to stop the process just before the call and take a snapshot. You can see you are just before the call because the right bracket (>) to the left of the source list shows the line about to be executed.
  3. You now step over the call. The execution is now after the call, shown by the right bracket (>) being on the following source line.
  4. Oh, how you wish you hadn't done that! No problem, just clone that snapshot you made.
  5. Now you are in a new process before the call is executed.

    NOTE: fork() was used by the debugger both to create the snapshot and to clone it.