PowerAda Advanced Usage

From OC Systems Wiki!
Jump to: navigation, search


This section describes a number of more advanced uses of adbg. Most require that commands be entered directly in the command area at the top of the main window, rather than being accessed through menus. Some involve starting the debugger with a number of command-line switches.

More advanced topics are covered in Appendix F, "Debugger Command Reference".

Recording a Debugging Session

At your request, the debugger can keep a log of a debugging session. This log contains your commands and comments in addition to the debugger's responses, which are marked as comments. You may open and close log files at any time during a debugging session, but you may only open one log file at a time.

Log files are useful for later analysis, for documenting a program's behavior, or for making comparisons after program modifications. For more information on how to use the LOG command, see "Recording a Debugging Session: LOG" in Appendix F.

Executing Pre-Recorded Debugger Commands

You can use script files to drive the debugger with a series of commands. This feature is convenient for debugging large, complex programs when you may not be able to complete a debugging session in one sitting. By causing the debugger to repeat a previous set of actions, you can continue a debugging session from where you last stopped. You can easily use log files as script files because the debugger's output appears as comments within the log file. Like a log file, the debugger can read one script file at any time during a debugging session. Script files can contain calls to other script files. See "Executing Pre-Recorded Commands: SCRIPT" in Appendix F to find out how to use this feature.

Abbreviating Sequences of Debugger Commands

You can use a MACRO command to define a sequence of debugger commands. This can speed up the debugging process by combining a series of commands that you otherwise would have to enter yourself. See "Abbreviating Sequences of Debugger Commands: MACRO" in Appendix F on how to use this mechanism.

Executing Commands at Start-up

The debugger searches for an optional file called .adbgrc when it starts. The current directory is searched first, then your home directory. If the debugger finds this file, it reads a sequence of debugger commands and runs them as part of its initialization. For instance, you can place variable assignment statements in this file so that the variables will always be defined when you start the debugger. You can use the -f option of adbg to specify an additional start-up file.

Trapping Unhandled Exceptions

An unhandled exception would normally cause an Ada program to end. When the debugger is running, however, any unhandled exception is trapped, and the debugger intervenes and displays the source location at which the exception was raised (if the exception is raised in a unit for which debugging information is present). This action allows you to examine the state of the target program at the point where the exception was raised.

The detection of unhandled exceptions can slow execution of the target program. To avoid this, use the command UNTRAP UNHANDLED. For more information on this command, see "Removing Exception Traps: UNTRAP" in Appendix F.

Handling Code That Lacks Debugger Information

The debugger does not have the information necessary to follow operating system calls, run-time support calls, calls to Ada packages that were compiled with the -k option, and calls to C functions that were not compiled with the -g option.

When Ada files are compiled with the -k option, the debugger cannot provide breakpoints or examine variables at the source level because it cannot resolve any explicit or implied references. Programs written in other languages can also use a different run-time structure than Ada programs, and the debugger might not be aware of such a structure.

In all of these cases, the debugger behaves the same way: it treats the call as a single operation and provides no form of source level debugging inside that operation. If a task switch occurs during the execution of an outside routine, the debugger may report the current source location for the suspended task as a hexadecimal machine address. If an outside routine is in the dynamic call chain, the debugger may only display the call chain up to the point where the outside routine was called. A call chain display shows a run-time support call as a machine address.

Debugging Generic Instantiations

To debug generic instantiations, you must compile the instantiation of the generic unit without the -k option. You do not have to compile the generic unit itself without -k. You can then set breakpoints via an extended line number mechanism and debug a particular instantiation of the generic. However, you cannot set a breakpoint in the actual generic and expect it to pause on each instantiation of that generic.

The extended line number allows you to identify multiple instantiations of a generic. It is an ordered set of integers separated with period characters as follows:

Integer [.Integer[s]] ...

Every integer in this set is a line number within the compilation of some compilation unit. The leftmost integer is that of the point of instantiation in the compilation unit. Subsequent integers refer to lines within instantiated generics. The Integer s refers to the line number in specification of the generic and the Integer without the s refers to the line number in the body of the generic. For example:

123.54

Line 123 instantiates a generic and line 54 is the body of that instantiation.

10.20s

Line 10 instantiates a generic and line 20 is the specification of that instantiation.

51.10s.73

Line 51 instantiates a generic and line 10 is the specification of that instantiation which itself instantiates a generic and is in line 73 of the body of that last instantiation.

If the source for the generic template has been deleted, renamed, or moved since compiling the generic, you will not be able to display the source when running the debugger. However, if you know the lines in the generic where you can set breakpoints, you can still debug the generic instantiation.

The following example illustrates extended line numbers.

generic
  type swap_type is private;
procedure exchange (x, y : in out swap_type);
procedure exchange (x, y : in out swap_type) is
  temp : swap_type := x;
begin
  x := y;
  y := temp;
end exchange;
------------------------------------------------
with exchange;
procedure testgen is
  gen_type1a, gen_type1b : integer;
  gen_type2a, gen_type2b : positive;
  procedure gen1 is new exchange (integer);
  procedure gen2 is new exchange (positive);
begin
  gen_type1a := 0;
  gen_type1b := 3;
  gen1(gen_type1a, gen_type1b);
  gen_type2a := 2;
  gen_type2b := 3;
  gen2(gen_type2a, gen_type2b);
end testgen;

After compiling the above two compilation units, the user runs the adbg command on testgen. For example:

  Debug 1> source 1-16
  1: with exchange;
  2: procedure testgen is
  3:   gen_type1a, gen_type1b : integer;
  4:   gen_type2a, gen_type2b : positive;
  5:
  6:   procedure gen1 is new exchange (integer);
  7:   procedure gen2 is new exchange (positive);
  8:
  9: begin
 10=   gen_type1a := 0;
 11=   gen_type1b := 3;
 12=   gen1(gen_type1a, gen_type1b);
 13=   gen_type2a := 2;
 14=   gen_type2b := 3;
 15=   gen2(gen_type2a, gen_type2b);
 16: end testgen;
 Debug 2> run
 Program Ready
 Debug 3> break 12
 Breakpoint set at 12,sec/testgen (testgen)
 Debug 4> continue
 12>   gen1(gen_type1a, gen_type1b);
 Breakpoint encountered at 12,sec/testgen (testgen)
 Debug 5> step
 6.6=   temp : swap_type := x;
 Step to 6.6,sec/testgen (gen1)
 Debug 6> where
 Program and View position: 6.6,sec/testgen (gen1)
 Debug 7>  source
 6.1: generic
 6.2:   type swap_type is private;
 6.3: procedure exchange (x, y : in out swap_type);
 6.4:
 6.5: procedure exchange (x, y : in out swap_type) is
 6.6=   temp : swap_type := x;
 6.7: begin
 6.8=   x := y;
 6.9>   y := temp;
 6.10: end exchange;
 <End of source file>
 Debug 8> break 6.9
 Breakpoint set at 6.9,sec/testgen (gen1)
 Debug 9> continue
 6.9>   y := temp;
 Breakpoint encountered at 6.9,sec/testgen (gen1)
 Debug 10> ? x
 X <In Out> => 3
 Debug 11> continue
 Program Completed Normally.

The commands shown after the Debug x> prompt are the commands entered by the user. The rest is the output of the debugger.

Debugging a Core File

The -c option allows the user to specify a core file to be read by the debugger. The syntax is:

adbg -x t.exe -c <core filename>

Note that the core file must be specified. There is no default as with dbx. The core file name can include a full path name. The program cannot be continued from a core file but program state can be examined. This program state includes the call stack and local and global variables.

Note that the -x parameter is necessary to use a core file.

Note also that to fully debug a problem using a core file, a full core must be dumped.

To get a full core dump in AIX 4.x, you have to:

  1. figure out which signal(s) are going to generate the core file;
  2. call sigaction() for those signals, specifying SA_FULLDUMP in the signal action flags;
  3. make sure that nobody else specifies a sigaction() for those signals, since the flags are set to the value last passed in;
  4. make sure ulimit lets you have a core file as big as you anticipate; and
  5. make sure there is enough space in the file system to hold the core file.

The same requirements exist for AIX 4.1 except that there is a system configuration option that lets the default value of full or partial be set on a system wide basis. This option can be set through SMIT.

Remote Debugging

Remote debugging means that the target program (the program being debugged) is executing on a different machine than the debugger itself. This is useful when the Ada libraries are impossible or inefficient to access in the environment where the target program must run. Remote debugging is indicated by the -r user@host_name option on the adbg command line; this must be used with the -a pid option, as described below.

There are two restrictions when using the debugger in remote mode:

  1. The target program must already be running on the target machine. This implies that the -a option must be used to attach to an already running target program.
  2. Target program I/O is not managed by adbg when in remote mode. This means that prompts for input required by the target program will occur on the target machine, not through adbg, and output from the target program will not be captured in an adbg log file or sent to adbg output windows.

The debugger starts a remote agent on the target machine. The remote agent must be installed on the target machine. The local debugger uses the POWERADA_REMOTE environment variable to locate the remote agent as the remote machine. POWERADA_REMOTE should be defined as the path of the directory containing the remote agent, Adbgagent. The default for POWERADA_REMOTE if it is undefined is $POWERADA/adarte/bin.