GNAT GPL User's Guide: Running and Debugging Ada Programs

[ < ] | [ > ] |  | [ << ] | [ Up ] | [ >> ] |  |  |  |  | [Top] | [Contents] | [Index] | [ ? ]

# 32. Running and Debugging Ada Programs

This chapter discusses how to debug Ada programs.

An incorrect Ada program may be handled in three ways by the GNAT compiler:

1. The illegality may be a violation of the static semantics of Ada. In that case GNAT diagnoses the constructs in the program that are illegal. It is then a straightforward matter for the user to modify those parts of the program.

2. The illegality may be a violation of the dynamic semantics of Ada. In that case the program compiles and executes, but may generate incorrect results, or may terminate abnormally with some exception.

3. When presented with a program that contains convoluted errors, GNAT itself may terminate abnormally without providing full diagnostics on the incorrect user program.

> 32.1 The GNAT Debugger GDB |  |
> 32.2 Running GDB |  |
> 32.3 Introduction to GDB Commands |  |
> 32.4 Using Ada Expressions |  |
> 32.5 Calling User-Defined Subprograms |  |
> 32.6 Using the Next Command in a Function |  |
> 32.7 Stopping when Ada Exceptions are Raised |  |
> 32.8 Ada Tasks |  |
> 32.9 Debugging Generic Units |  |
> 32.10 Remote Debugging with gdbserver |  |
> 32.11 GNAT Abnormal Termination or Failure to Terminate |  |
> 32.12 Naming Conventions for GNAT Source Files |  |
> 32.13 Getting Internal Debugging Information |  |
> 32.14 Stack Traceback |  |

[ < ] | [ > ] |  | [ << ] | [ Up ] | [ >> ] |  |  |  |  | [Top] | [Contents] | [Index] | [ ? ]

## 32.1 The GNAT Debugger GDB

`GDB` is a general purpose, platform-independent debugger that can be used to debug mixed-language programs compiled with `gcc`, and in particular is capable of debugging Ada programs compiled with GNAT. The latest versions of `GDB` are Ada-aware and can handle complex Ada data structures.

See section `Debugging with GDB' in Debugging with GDB, for full details on the usage of `GDB`, including a section on its usage on programs. This manual should be consulted for full details. The section that follows is a brief introduction to the philosophy and use of `GDB`.

When GNAT programs are compiled, the compiler optionally writes debugging information into the generated object file, including information on line numbers, and on declared types and variables. This information is separate from the generated code. It makes the object files considerably larger, but it does not add to the size of the actual executable that will be loaded into memory, and has no impact on run-time performance. The generation of debug information is triggered by the use of the -g switch in the `gcc` or `gnatmake` command used to carry out the compilations. It is important to emphasize that the use of these options does not change the generated code.

The debugging information is written in standard system formats that are used by many tools, including debuggers and profilers. The format of the information is typically designed to describe C types and semantics, but GNAT implements a translation scheme which allows full details about Ada types and variables to be encoded into these standard C formats. Details of this encoding scheme may be found in the file exp_dbug.ads in the GNAT source distribution. However, the details of this encoding are, in general, of no interest to a user, since `GDB` automatically performs the necessary decoding.

When a program is bound and linked, the debugging information is collected from the object files, and stored in the executable image of the program. Again, this process significantly increases the size of the generated executable file, but it does not increase the size of the executable program itself. Furthermore, if this program is run in the normal manner, it runs exactly as if the debug information were not present, and takes no more actual memory.

However, if the program is run under control of `GDB`, the debugger is activated. The image of the program is loaded, at which point it is ready to run. If a run command is given, then the program will run exactly as it would have if `GDB` were not present. This is a crucial part of the `GDB` design philosophy. `GDB` is entirely non-intrusive until a breakpoint is encountered. If no breakpoint is ever hit, the program will run exactly as it would if no debugger were present. When a breakpoint is hit, `GDB` accesses the debugging information and can respond to user commands to inspect variables, and more generally to report on the state of execution.

[ < ] | [ > ] |  | [ << ] | [ Up ] | [ >> ] |  |  |  |  | [Top] | [Contents] | [Index] | [ ? ]

## 32.2 Running GDB

This section describes how to initiate the debugger.

The debugger can be launched from a `GPS` menu or directly from the command line. The description below covers the latter use. All the commands shown can be used in the `GPS` debug console window, but there are usually more GUI-based ways to achieve the same effect.

The command to run `GDB` is

    $ gdb program

where `program` is the name of the executable file. This activates the debugger and results in a prompt for debugger commands. The simplest command is simply `run`, which causes the program to run exactly as if the debugger were not present. The following section describes some of the additional commands that can be given to `GDB`.

[ < ] | [ > ] |  | [ << ] | [ Up ] | [ >> ] |  |  |  |  | [Top] | [Contents] | [Index] | [ ? ]

## 32.3 Introduction to GDB Commands

`GDB` contains a large repertoire of commands. See section `Debugging with GDB' in Debugging with GDB, for extensive documentation on the use of these commands, together with examples of their use. Furthermore, the command `help` invoked from within GDB activates a simple help facility which summarizes the available commands and their options. In this section we summarize a few of the most commonly used commands to give an idea of what `GDB` is about. You should create a simple program with debugging information and experiment with the use of these `GDB` commands on the program as you read through the following section.

`set args arguments`
  The arguments list above is a list of arguments to be passed to the program on a subsequent run command, just as though the arguments had been entered on a normal invocation of the program. The `set args` command is not needed if the program does not require arguments.

`run`
  The `run` command causes execution of the program to start from the beginning. If the program is already running, that is to say if you are currently positioned at a breakpoint, then a prompt will ask for confirmation that you want to abandon the current execution and restart.

`breakpoint location`
  The breakpoint command sets a breakpoint, that is to say a point at which execution will halt and `GDB` will await further commands. location is either a line number within a file, given in the format `file:linenumber`, or it is the name of a subprogram. If you request that a breakpoint be set on a subprogram that is overloaded, a prompt will ask you to specify on which of those subprograms you want to breakpoint. You can also specify that all of them should be breakpointed. If the program is run and execution encounters the breakpoint, then the program stops and `GDB` signals that the breakpoint was encountered by printing the line of code before which the program is halted.

`catch exception name`
  This command causes the program execution to stop whenever exception name is raised. If name is omitted, then the execution is suspended when any exception is raised.

`print expression`
  This will print the value of the given expression. Most simple Ada expression formats are properly handled by `GDB`, so the expression can contain function calls, variables, operators, and attribute references.

`continue`
  Continues execution following a breakpoint, until the next breakpoint or the termination of the program.

`step`
  Executes a single line after a breakpoint. If the next statement is a subprogram call, execution continues into (the first statement of) the called subprogram.

`next`
  Executes a single line. If this line is a subprogram call, executes and returns from the call.

`list`
  Lists a few lines around the current source location. In practice, it is usually more convenient to have a separate edit window open with the relevant source file displayed. Successive applications of this command print subsequent lines. The command can be given an argument which is a line number, in which case it displays a few lines around the specified one.

`backtrace`
  Displays a backtrace of the call chain. This command is typically used after a breakpoint has occurred, to examine the sequence of calls that leads to the current breakpoint. The display includes one line for each activation record (frame) corresponding to an active subprogram.

`up`
  At a breakpoint, `GDB` can display the values of variables local to the current frame. The command `up` can be used to examine the contents of other active frames, by moving the focus up the stack, that is to say from callee to caller, one frame at a time.

`down`
  Moves the focus of `GDB` down from the frame currently being examined to the frame of its callee (the reverse of the previous command),

`frame n`
  Inspect the frame with the given number. The value 0 denotes the frame of the current breakpoint, that is to say the top of the call stack.

`kill`
  Kills the child process in which the program is running under GDB. This may be useful for several purposes:
  - It allows you to recompile and relink your program, since on many systems you cannot regenerate an executable file while it is running in a process.
  - You can run your program outside the debugger, on systems that do not permit executing a program outside GDB while breakpoints are set within GDB.
  - It allows you to debug a core dump rather than a running process.

The above list is a very short introduction to the commands that `GDB` provides. Important additional capabilities, including conditional breakpoints, the ability to execute command sequences on a breakpoint, the ability to debug at the machine instruction level and many other features are described in detail in section `Debugging with GDB' in Debugging with GDB. Note that most commands can be abbreviated (for example, c for continue, bt for backtrace).

[ < ] | [ > ] |  | [ << ] | [ Up ] | [ >> ] |  |  |  |  | [Top] | [Contents] | [Index] | [ ? ]

## 32.4 Using Ada Expressions

`GDB` supports a fairly large subset of Ada expression syntax, with some extensions. The philosophy behind the design of this subset is

- That `GDB` should provide basic literals and access to operations for arithmetic, dereferencing, field selection, indexing, and subprogram calls, leaving more sophisticated computations to subprograms written into the program (which therefore may be called from `GDB`).

- That type safety and strict adherence to Ada language restrictions are not particularly important to the `GDB` user.

- That brevity is important to the `GDB` user.

Thus, for brevity, the debugger acts as if there were implicit `with` and `use` clauses in effect for all user-written packages, thus making it unnecessary to fully qualify most names with their packages, regardless of context. Where this causes ambiguity, `GDB` asks the user's intent.

For details on the supported Ada syntax, see section `Debugging with GDB' in Debugging with GDB.

[ < ] | [ > ] |  | [ << ] | [ Up ] | [ >> ] |  |  |  |  | [Top] | [Contents] | [Index] | [ ? ]

## 32.5 Calling User-Defined Subprograms

An important capability of `GDB` is the ability to call user-defined subprograms while debugging. This is achieved simply by entering a subprogram call statement in the form:

    call subprogram-name (parameters)

The keyword `call` can be omitted in the normal case where the `subprogram-name` does not coincide with any of the predefined `GDB` commands.

The effect is to invoke the given subprogram, passing it the list of parameters that is supplied. The parameters can be expressions and can include variables from the program being debugged. The subprogram must be defined at the library level within your program, and `GDB` will call the subprogram within the environment of your program execution (which means that the subprogram is free to access or even modify variables within your program).

The most important use of this facility is in allowing the inclusion of debugging routines that are tailored to particular data structures in your program. Such debugging routines can be written to provide a suitably high-level description of an abstract type, rather than a low-level dump of its physical layout. After all, the standard `GDB print` command only knows the physical layout of your types, not their abstract meaning. Debugging routines can provide information at the desired semantic level and are thus enormously useful.

For example, when debugging GNAT itself, it is crucial to have access to the contents of the tree nodes used to represent the program internally. But tree nodes are represented simply by an integer value (which in turn is an index into a table of nodes). Using the `print` command on a tree node would simply print this integer value, which is not very useful. But the PN routine (defined in file treepr.adb in the GNAT sources) takes a tree node as input, and displays a useful high level representation of the tree node, which includes the syntactic category of the node, its position in the source, the integers that denote descendant nodes and parent node, as well as varied semantic information. To study this example in more detail, you might want to look at the body of the PN procedure in the stated file.

[ < ] | [ > ] |  | [ << ] | [ Up ] | [ >> ] |  |  |  |  | [Top] | [Contents] | [Index] | [ ? ]

## 32.6 Using the Next Command in a Function

When you use the `next` command in a function, the current source location will advance to the next statement as usual. A special case arises in the case of a `return` statement.

Part of the code for a return statement is the "epilog" of the function. This is the code that returns to the caller. There is only one copy of this epilog code, and it is typically associated with the last return statement in the function if there is more than one return. In some implementations, this epilog is associated with the first statement of the function.

The result is that if you use the `next` command from a return statement that is not the last return statement of the function you may see a strange apparent jump to the last return statement or to the start of the function. You should simply ignore this odd jump. The value returned is always that from the first return statement that was stepped through.

[ < ] | [ > ] |  | [ << ] | [ Up ] | [ >> ] |  |  |  |  | [Top] | [Contents] | [Index] | [ ? ]

## 32.7 Stopping when Ada Exceptions are Raised

You can set catchpoints that stop the program execution when your program raises selected exceptions.

`catch exception`
  Set a catchpoint that stops execution whenever (any task in the) program raises any exception.

`catch exception name`
  Set a catchpoint that stops execution whenever (any task in the) program raises the exception name.

`catch exception unhandled`
  Set a catchpoint that stops executing whenever (any task in the) program raises an exception for which there is no handler.

`info exceptions`
`info exceptions regexp`
  The `info exceptions` command permits the user to examine all defined exceptions within Ada programs. With a regular expression, regexp, as argument, prints out only those exceptions whose name matches regexp.

[ < ] | [ > ] |  | [ << ] | [ Up ] | [ >> ] |  |  |  |  | [Top] | [Contents] | [Index] | [ ? ]

## 32.8 Ada Tasks

`GDB` allows the following task-related commands:

`info tasks`
  This command shows a list of current Ada tasks, as in the following example:

      (gdb) info tasks
        ID       TID P-ID   Thread Pri State                 Name
         1   8088000   0   807e000  15 Child Activation Wait main_task
         2   80a4000   1   80ae000  15 Accept/Select Wait    b
         3   809a800   1   80a4800  15 Child Activation Wait a
      *  4   80ae800   3   80b8000  15 Running               c

  In this listing, the asterisk before the first task indicates it to be the currently running task. The first column lists the task ID that is used to refer to tasks in the following commands.

`break linespec task taskid`
`break linespec task taskid if ...`
  These commands are like the `break ... thread ...`. linespec specifies source lines.

  Use the qualifier ``task taskid'` with a breakpoint command to specify that you only want `GDB` to stop the program when a particular Ada task reaches this breakpoint. taskid is one of the numeric task identifiers assigned by `GDB`, shown in the first column of the ``info tasks'` display.

  If you do not specify ``task taskid'` when you set a breakpoint, the breakpoint applies to all tasks of your program.

  You can use the `task` qualifier on conditional breakpoints as well; in this case, place ``task taskid'` before the breakpoint condition (before the `if`).

`task taskno`

  This command allows switching to the task referred by taskno. In particular, this allows browsing of the backtrace of the specified task. It is advisable to switch back to the original task before continuing execution otherwise the scheduling of the program may be perturbed.

For more detailed information on the tasking support, see section `Debugging with GDB' in Debugging with GDB.

[ < ] | [ > ] |  | [ << ] | [ Up ] | [ >> ] |  |  |  |  | [Top] | [Contents] | [Index] | [ ? ]

## 32.9 Debugging Generic Units

GNAT always uses code expansion for generic instantiation. This means that each time an instantiation occurs, a complete copy of the original code is made, with appropriate substitutions of formals by actuals.

It is not possible to refer to the original generic entities in `GDB`, but it is always possible to debug a particular instance of a generic, by using the appropriate expanded names. For example, if we have

    procedure g is

       generic package k is
          procedure kp (v1 : in out integer);
       end k;

       package body k is
          procedure kp (v1 : in out integer) is
          begin
             v1 := v1 + 1;
          end kp;
       end k;

       package k1 is new k;
       package k2 is new k;

       var : integer := 1;

    begin
       k1.kp (var);
       k2.kp (var);
       k1.kp (var);
       k2.kp (var);
    end;

Then to break on a call to procedure kp in the k2 instance, simply use the command:

    (gdb) break g.k2.kp

When the breakpoint occurs, you can step through the code of the instance in the normal manner and examine the values of local variables, as for other units.

[ < ] | [ > ] |  | [ << ] | [ Up ] | [ >> ] |  |  |  |  | [Top] | [Contents] | [Index] | [ ? ]

## 32.10 Remote Debugging with gdbserver

On platforms where gdbserver is supported, it is possible to use this tool to debug your application remotely. This can be useful in situations where the program needs to be run on a target host that is different from the host used for development, particularly when the target has a limited amount of resources (either CPU and/or memory).

To do so, start your program using gdbserver on the target machine. gdbserver then automatically suspends the execution of your program at its entry point, waiting for a debugger to connect to it. The following commands starts an application and tells gdbserver to wait for a connection with the debugger on localhost port 4444.

    $ gdbserver localhost:4444 program
    Process program created; pid = 5685
    Listening on port 4444

Once gdbserver has started listening, we can tell the debugger to establish a connection with this gdbserver, and then start the same debugging session as if the program was being debugged on the same host, directly under the control of GDB.

    $ gdb program
    (gdb) target remote targethost:4444
    Remote debugging using targethost:4444
    0x00007f29936d0af0 in ?? () from /lib64/ld-linux-x86-64.so.
    (gdb) b foo.adb:3
    Breakpoint 1 at 0x401f0c: file foo.adb, line 3.
    (gdb) continue
    Continuing.

    Breakpoint 1, foo () at foo.adb:4
    4       end foo;

It is also possible to use gdbserver to attach to an already running program, in which case the execution of that program is simply suspended until the connection between the debugger and gdbserver is established.

For more information on how to use gdbserver, section `Using the gdbserver Program' in Debugging with GDB. GNAT GPL provides support for gdbserver on x86-linux, x86-windows and x86_64-linux.

[ < ] | [ > ] |  | [ << ] | [ Up ] | [ >> ] |  |  |  |  | [Top] | [Contents] | [Index] | [ ? ]

## 32.11 GNAT Abnormal Termination or Failure to Terminate

When presented with programs that contain serious errors in syntax or semantics, GNAT may on rare occasions experience problems in operation, such as aborting with a segmentation fault or illegal memory access, raising an internal exception, terminating abnormally, or failing to terminate at all. In such cases, you can activate various features of GNAT that can help you pinpoint the construct in your program that is the likely source of the problem.

The following strategies are presented in increasing order of difficulty, corresponding to your experience in using GNAT and your familiarity with compiler internals.

1. Run `gcc` with the ``-gnatf'`. This first switch causes all errors on a given line to be reported. In its absence, only the first error on a line is displayed.

   The ``-gnatdO'` switch causes errors to be displayed as soon as they are encountered, rather than after compilation is terminated. If GNAT terminates prematurely or goes into an infinite loop, the last error message displayed may help to pinpoint the culprit.

2. Run `gcc` with the ``-v (verbose)'` switch. In this mode, `gcc` produces ongoing information about the progress of the compilation and provides the name of each procedure as code is generated. This switch allows you to find which Ada procedure was being compiled when it encountered a code generation problem.

3. Run `gcc` with the ``-gnatdc'` switch. This is a GNAT specific switch that does for the front-end what ``-v'` does for the back end. The system prints the name of each unit, either a compilation unit or nested unit, as it is being analyzed.
4. Finally, you can start `gdb` directly on the `gnat1` executable. `gnat1` is the front-end of GNAT, and can be run independently (normally it is just called from `gcc`). You can use `gdb` on `gnat1` as you would on a C program (but see section 32.1 The GNAT Debugger GDB for caveats). The `where` command is the first line of attack; the variable `lineno` (seen by `print lineno`), used by the second phase of `gnat1` and by the `gcc` backend, indicates the source line at which the execution stopped, and `input_file name` indicates the name of the source file.

[ < ] | [ > ] |  | [ << ] | [ Up ] | [ >> ] |  |  |  |  | [Top] | [Contents] | [Index] | [ ? ]

## 32.12 Naming Conventions for GNAT Source Files

In order to examine the workings of the GNAT system, the following brief description of its organization may be helpful:

- Files with prefix ``sc'` contain the lexical scanner.

- All files prefixed with ``par'` are components of the parser. The numbers correspond to chapters of the Ada Reference Manual. For example, parsing of select statements can be found in ``par-ch9.adb'`.

- All files prefixed with ``sem'` perform semantic analysis. The numbers correspond to chapters of the Ada standard. For example, all issues involving context clauses can be found in ``sem_ch10.adb'`. In addition, some features of the language require sufficient special processing to justify their own semantic files: sem_aggr for aggregates, sem_disp for dynamic dispatching, etc.

- All files prefixed with ``exp'` perform normalization and expansion of the intermediate representation (abstract syntax tree, or AST). these files use the same numbering scheme as the parser and semantics files. For example, the construction of record initialization procedures is done in ``exp_ch3.adb'`.

- The files prefixed with ``bind'` implement the binder, which verifies the consistency of the compilation, determines an order of elaboration, and generates the bind file.

- The files ``atree.ads'` and ``atree.adb'` detail the low-level data structures used by the front-end.

- The files ``sinfo.ads'` and ``sinfo.adb'` detail the structure of the abstract syntax tree as produced by the parser.

- The files ``einfo.ads'` and ``einfo.adb'` detail the attributes of all entities, computed during semantic analysis.

- Library management issues are dealt with in files with prefix ``lib'`.

- Ada files with the prefix ``a-'` are children of `Ada`, as defined in Annex A.

- Files with prefix ``i-'` are children of `Interfaces`, as defined in Annex B.

- Files with prefix ``s-'` are children of `System`. This includes both language-defined children and GNAT run-time routines.

- Files with prefix ``g-'` are children of `GNAT`. These are useful general-purpose packages, fully documented in their specs. All the other ``.c'` files are modifications of common `gcc` files.

[ < ] | [ > ] |  | [ << ] | [ Up ] | [ >> ] |  |  |  |  | [Top] | [Contents] | [Index] | [ ? ]

## 32.13 Getting Internal Debugging Information

Most compilers have internal debugging switches and modes. GNAT does also, except GNAT internal debugging switches and modes are not secret. A summary and full description of all the compiler and binder debug flags are in the file ``debug.adb'`. You must obtain the sources of the compiler to see the full detailed effects of these flags.

The switches that print the source of the program (reconstructed from the internal tree) are of general interest for user programs, as are the options to print the full internal tree, and the entity table (the symbol table information). The reconstructed source provides a readable version of the program after the front-end has completed analysis and expansion, and is useful when studying the performance of specific constructs. For example, constraint checks are indicated, complex aggregates are replaced with loops and assignments, and tasking primitives are replaced with run-time calls.

[ < ] | [ > ] |  | [ << ] | [ Up ] | [ >> ] |  |  |  |  | [Top] | [Contents] | [Index] | [ ? ]

## 32.14 Stack Traceback

Traceback is a mechanism to display the sequence of subprogram calls that leads to a specified execution point in a program. Often (but not always) the execution point is an instruction at which an exception has been raised. This mechanism is also known as stack unwinding because it obtains its information by scanning the run-time stack and recovering the activation records of all active subprograms. Stack unwinding is one of the most important tools for program debugging.

The first entry stored in traceback corresponds to the deepest calling level, that is to say the subprogram currently executing the instruction from which we want to obtain the traceback.

Note that there is no runtime performance penalty when stack traceback is enabled, and no exception is raised during program execution.

> 32.14.1 Non-Symbolic Traceback |  |
> 32.14.2 Symbolic Traceback |  |

[ < ] | [ > ] |  | [ << ] | [ Up ] | [ >> ] |  |  |  |  | [Top] | [Contents] | [Index] | [ ? ]

### 32.14.1 Non-Symbolic Traceback

Note: this feature is not supported on all platforms. See ``GNAT.Traceback spec in g-traceb.ads'` for a complete list of supported platforms.

> 32.14.1.1 Tracebacks From an Unhandled Exception |  |
> 32.14.1.2 Tracebacks From Exception Occurrences |  |
> 32.14.1.3 Tracebacks From Anywhere in a Program |  |

[ < ] | [ > ] |  | [ << ] | [ Up ] | [ >> ] |  |  |  |  | [Top] | [Contents] | [Index] | [ ? ]

#### 32.14.1.1 Tracebacks From an Unhandled Exception

A runtime non-symbolic traceback is a list of addresses of call instructions. To enable this feature you must use the ``-E'` `gnatbind`'s option. With this option a stack traceback is stored as part of exception information. You can retrieve this information using the `addr2line` tool.

Here is a simple example:

    procedure STB is

       procedure P1 is
       begin
          raise Constraint_Error;
       end P1;

       procedure P2 is
       begin
          P1;
       end P2;

    begin
       P2;
    end STB;

    $ gnatmake stb -bargs -E
    $ stb

    Execution terminated by unhandled exception
    Exception name: CONSTRAINT_ERROR
    Message: stb.adb:5
    Call stack traceback locations:
    0x401373 0x40138b 0x40139c 0x401335 0x4011c4 0x4011f1 0x77e892a4

As we see the traceback lists a sequence of addresses for the unhandled exception `CONSTRAINT_ERROR` raised in procedure P1. It is easy to guess that this exception come from procedure P1. To translate these addresses into the source lines where the calls appear, the `addr2line` tool, described below, is invaluable. The use of this tool requires the program to be compiled with debug information.

    $ gnatmake -g stb -bargs -E
    $ stb

    Execution terminated by unhandled exception
    Exception name: CONSTRAINT_ERROR
    Message: stb.adb:5
    Call stack traceback locations:
    0x401373 0x40138b 0x40139c 0x401335 0x4011c4 0x4011f1 0x77e892a4

    $ addr2line --exe=stb 0x401373 0x40138b 0x40139c 0x401335 0x4011c4
       0x4011f1 0x77e892a4

    00401373 at d:/stb/stb.adb:5
    0040138B at d:/stb/stb.adb:10
    0040139C at d:/stb/stb.adb:14
    00401335 at d:/stb/b~stb.adb:104
    004011C4 at /build/.../crt1.c:200
    004011F1 at /build/.../crt1.c:222
    77E892A4 in ?? at ??:0

The `addr2line` tool has several other useful options:

`--functions`
  to get the function name corresponding to any location

`--demangle=gnat`
  to use the gnat decoding mode for the function names. Note that for binutils version 2.9.x the option is simply ``--demangle'`.

    $ addr2line --exe=stb --functions --demangle=gnat 0x401373 0x40138b
       0x40139c 0x401335 0x4011c4 0x4011f1

    00401373 in stb.p1 at d:/stb/stb.adb:5
    0040138B in stb.p2 at d:/stb/stb.adb:10
    0040139C in stb at d:/stb/stb.adb:14
    00401335 in main at d:/stb/b~stb.adb:104
    004011C4 in <__mingw_CRTStartup> at /build/.../crt1.c:200
    004011F1 in <mainCRTStartup> at /build/.../crt1.c:222

From this traceback we can see that the exception was raised in ``stb.adb'` at line 5, which was reached from a procedure call in ``stb.adb'` at line 10, and so on. The ``b~std.adb'` is the binder file, which contains the call to the main program. See section 4.1 Running `gnatbind`. The remaining entries are assorted runtime routines, and the output will vary from platform to platform.

It is also possible to use `GDB` with these traceback addresses to debug the program. For example, we can break at a given code location, as reported in the stack traceback:

    $ gdb -nw stb
    Furthermore, this feature is not implemented inside Windows DLL. Only
    the non-symbolic traceback is reported in this case.

    (gdb) break *0x401373
    Breakpoint 1 at 0x401373: file stb.adb, line 5.

It is important to note that the stack traceback addresses do not change when debug information is included. This is particularly useful because it makes it possible to release software without debug information (to minimize object size), get a field report that includes a stack traceback whenever an internal bug occurs, and then be able to retrieve the sequence of calls with the same program compiled with debug information.

[ < ] | [ > ] |  | [ << ] | [ Up ] | [ >> ] |  |  |  |  | [Top] | [Contents] | [Index] | [ ? ]

#### 32.14.1.2 Tracebacks From Exception Occurrences

Non-symbolic tracebacks are obtained by using the ``-E'` binder argument. The stack traceback is attached to the exception information string, and can be retrieved in an exception handler within the Ada program, by means of the Ada facilities defined in `Ada.Exceptions`. Here is a simple example:

    with Ada.Text_IO;
    with Ada.Exceptions;

    procedure STB is

       use Ada;
       use Ada.Exceptions;

       procedure P1 is
          K : Positive := 1;
       begin
          K := K - 1;
       exception
          when E : others =>
             Text_IO.Put_Line (Exception_Information (E));
       end P1;

       procedure P2 is
       begin
          P1;
       end P2;

    begin
       P2;
    end STB;

This program will output:

    $ stb

    Exception name: CONSTRAINT_ERROR
    Message: stb.adb:12
    Call stack traceback locations:
    0x4015e4 0x401633 0x401644 0x401461 0x4011c4 0x4011f1 0x77e892a4

[ < ] | [ > ] |  | [ << ] | [ Up ] | [ >> ] |  |  |  |  | [Top] | [Contents] | [Index] | [ ? ]

#### 32.14.1.3 Tracebacks From Anywhere in a Program

It is also possible to retrieve a stack traceback from anywhere in a program. For this you need to use the `GNAT.Traceback` API. This package includes a procedure called `Call_Chain` that computes a complete stack traceback, as well as useful display procedures described below. It is not necessary to use the ``-E gnatbind'` option in this case, because the stack traceback mechanism is invoked explicitly.

In the following example we compute a traceback at a specific location in the program, and we display it using `GNAT.Debug_Utilities.Image` to convert addresses to strings:

    with Ada.Text_IO;
    with GNAT.Traceback;
    with GNAT.Debug_Utilities;

    procedure STB is

       use Ada;
       use GNAT;
       use GNAT.Traceback;

       procedure P1 is
          TB  : Tracebacks_Array (1 .. 10);
          --  We are asking for a maximum of 10 stack frames.
          Len : Natural;
          --  Len will receive the actual number of stack frames returned.
       begin
          Call_Chain (TB, Len);

          Text_IO.Put ("In STB.P1 : ");

          for K in 1 .. Len loop
             Text_IO.Put (Debug_Utilities.Image (TB (K)));
             Text_IO.Put (' ');
          end loop;

          Text_IO.New_Line;
       end P1;

       procedure P2 is
       begin
          P1;
       end P2;

    begin
       P2;
    end STB;

    $ gnatmake -g stb
    $ stb

    In STB.P1 : 16#0040_F1E4# 16#0040_14F2# 16#0040_170B# 16#0040_171C#
    16#0040_1461# 16#0040_11C4# 16#0040_11F1# 16#77E8_92A4#

You can then get further information by invoking the `addr2line` tool as described earlier (note that the hexadecimal addresses need to be specified in C format, with a leading "0x").

[ < ] | [ > ] |  | [ << ] | [ Up ] | [ >> ] |  |  |  |  | [Top] | [Contents] | [Index] | [ ? ]

### 32.14.2 Symbolic Traceback

A symbolic traceback is a stack traceback in which procedure names are associated with each code location.

Note that this feature is not supported on all platforms. See ``GNAT.Traceback.Symbolic spec in g-trasym.ads'` for a complete list of currently supported platforms.

Note that the symbolic traceback requires that the program be compiled with debug information. If it is not compiled with debug information only the non-symbolic information will be valid.

> 32.14.2.1 Tracebacks From Exception Occurrences |  |
> 32.14.2.2 Tracebacks From Anywhere in a Program |  |

[ < ] | [ > ] |  | [ << ] | [ Up ] | [ >> ] |  |  |  |  | [Top] | [Contents] | [Index] | [ ? ]

#### 32.14.2.1 Tracebacks From Exception Occurrences

    with Ada.Text_IO;
    with GNAT.Traceback.Symbolic;

    procedure STB is

       procedure P1 is
       begin
          raise Constraint_Error;
       end P1;

       procedure P2 is
       begin
          P1;
       end P2;

       procedure P3 is
       begin
          P2;
       end P3;

    begin
       P3;
    exception
       when E : others =>
          Ada.Text_IO.Put_Line (GNAT.Traceback.Symbolic.Symbolic_Traceback (E));
    end STB;

    $ gnatmake -g .\stb -bargs -E
    $ stb

    0040149F in stb.p1 at stb.adb:8
    004014B7 in stb.p2 at stb.adb:13
    004014CF in stb.p3 at stb.adb:18
    004015DD in ada.stb at stb.adb:22
    00401461 in main at b~stb.adb:168
    004011C4 in __mingw_CRTStartup at crt1.c:200
    004011F1 in mainCRTStartup at crt1.c:222
    77E892A4 in ?? at ??:0

In the above example the ".\" syntax in the `gnatmake` command is currently required by `addr2line` for files that are in the current working directory. Moreover, the exact sequence of linker options may vary from platform to platform. The above ``-largs'` section is for Windows platforms. By contrast, under Unix there is no need for the ``-largs'` section. Differences across platforms are due to details of linker implementation.

[ < ] | [ > ] |  | [ << ] | [ Up ] | [ >> ] |  |  |  |  | [Top] | [Contents] | [Index] | [ ? ]

#### 32.14.2.2 Tracebacks From Anywhere in a Program

It is possible to get a symbolic stack traceback from anywhere in a program, just as for non-symbolic tracebacks. The first step is to obtain a non-symbolic traceback, and then call `Symbolic_Traceback` to compute the symbolic information. Here is an example:

    with Ada.Text_IO;
    with GNAT.Traceback;
    with GNAT.Traceback.Symbolic;

    procedure STB is

       use Ada;
       use GNAT.Traceback;
       use GNAT.Traceback.Symbolic;

       procedure P1 is
          TB  : Tracebacks_Array (1 .. 10);
          --  We are asking for a maximum of 10 stack frames.
          Len : Natural;
          --  Len will receive the actual number of stack frames returned.
       begin
          Call_Chain (TB, Len);
          Text_IO.Put_Line (Symbolic_Traceback (TB (1 .. Len)));
       end P1;

       procedure P2 is
       begin
          P1;
       end P2;

    begin
       P2;
    end STB;

[ << ] | [ >> ] |  |  |  |  |  | [Top] | [Contents] | [Index] | [ ? ]

This document was generated by GNAT Mailserver on April, 17 2014 using texi2html