Add support for exception handling with multiple versions of

the Ada runtime:
        * ada-lang.c: Update general comments on how Ada exception catchpoints
        are implemented.
        (raise_sym_name, raise_unhandled_sym_name, raise_assert_sym_name)
        (__gnat_raise_nodefer_with_msg): Delete.
        (ada_unhandled_exception_name_addr_ftype): New type.
        (exception_support_info): New type.
        (ada_unhandled_exception_name_addr): Add forward declaration.
        (ada_unhandled_exception_name_addr_from_raise): Likewise.
        (default_exception_support_info): New constant.
        (exception_support_info_fallback): Likewise.
        (exception_info): New global variable.
        (ada_exception_support_info_sniffer): New function.
        (ada_executable_changed_observer): Likewise.
        (ada_unhandled_exception_name_addr_from_raise): Renamed from
        ada_unhandled_exception_name_addr.
        (ada_unhandled_exception_name_addr): Reimplement to match the
        latest Ada runtime implementation.
        (error_breakpoint_runtime_sym_not_found): Delete.
        (ada_exception_sym_name): Get the exception sym name from
        exception_info rather than hardcoding it.
        (ada_exception_sal): Add call to ada_exception_support_info_sniffer.
        Update error handling.
        * Makefile.in (ada-lang.o): Add dependency on observer.h.
This commit is contained in:
Joel Brobecker 2007-03-29 21:57:02 +00:00
parent 9c577e8950
commit 0259addd36
2 changed files with 188 additions and 57 deletions

View File

@ -1,3 +1,31 @@
2007-03-29 Joel Brobecker <brobecker@adacore.com>
Add support for exception handling with multiple versions of
the Ada runtime:
* ada-lang.c: Update general comments on how Ada exception catchpoints
are implemented.
(raise_sym_name, raise_unhandled_sym_name, raise_assert_sym_name)
(__gnat_raise_nodefer_with_msg): Delete.
(ada_unhandled_exception_name_addr_ftype): New type.
(exception_support_info): New type.
(ada_unhandled_exception_name_addr): Add forward declaration.
(ada_unhandled_exception_name_addr_from_raise): Likewise.
(default_exception_support_info): New constant.
(exception_support_info_fallback): Likewise.
(exception_info): New global variable.
(ada_exception_support_info_sniffer): New function.
(ada_executable_changed_observer): Likewise.
(ada_unhandled_exception_name_addr_from_raise): Renamed from
ada_unhandled_exception_name_addr.
(ada_unhandled_exception_name_addr): Reimplement to match the
latest Ada runtime implementation.
(error_breakpoint_runtime_sym_not_found): Delete.
(ada_exception_sym_name): Get the exception sym name from
exception_info rather than hardcoding it.
(ada_exception_sal): Add call to ada_exception_support_info_sniffer.
Update error handling.
* Makefile.in (ada-lang.o): Add dependency on observer.h.
2007-03-29 Daniel Jacobowitz <dan@codesourcery.com>
* Makefile.in (coff_solib_h, coff-solib.o, i386v-nat.o, lynx-nat.o)

View File

@ -56,6 +56,7 @@ Boston, MA 02110-1301, USA. */
#include "annotate.h"
#include "valprint.h"
#include "source.h"
#include "observer.h"
#ifndef ADA_RETAIN_DOTS
#define ADA_RETAIN_DOTS 0
@ -290,23 +291,6 @@ static char *ada_completer_word_break_characters =
static const char ADA_MAIN_PROGRAM_SYMBOL_NAME[]
= "__gnat_ada_main_program_name";
/* The name of the runtime function called when an exception is raised. */
static const char raise_sym_name[] = "__gnat_raise_nodefer_with_msg";
/* The name of the runtime function called when an unhandled exception
is raised. */
static const char raise_unhandled_sym_name[] = "__gnat_unhandled_exception";
/* The name of the runtime function called when an assert failure is
raised. */
static const char raise_assert_sym_name[] =
"system__assertions__raise_assert_failure";
/* A string that reflects the longest exception expression rewrite,
aside from the exception name. */
static const char longest_exception_template[] =
"'__gnat_raise_nodefer_with_msg' if long_integer(e) = long_integer(&)";
/* Limit on the number of warnings to raise per expression evaluation. */
static int warning_limit = 2;
@ -8967,6 +8951,12 @@ ada_modulus (struct type * type)
breakpoint structure of the BP_BREAKPOINT type, but with its own set
of breakpoint_ops.
Support in the runtime for exception catchpoints have been changed
a few times already, and these changes affect the implementation
of these catchpoints. In order to be able to support several
variants of the runtime, we use a sniffer that will determine
the runtime variant used by the program being debugged.
At this time, we do not support the use of conditions on Ada exception
catchpoints. The COND and COND_STRING fields are therefore set
to NULL (most of the time, see below).
@ -8989,6 +8979,136 @@ enum exception_catchpoint_kind
ex_catch_assert
};
typedef CORE_ADDR (ada_unhandled_exception_name_addr_ftype) (void);
/* A structure that describes how to support exception catchpoints
for a given executable. */
struct exception_support_info
{
/* The name of the symbol to break on in order to insert
a catchpoint on exceptions. */
const char *catch_exception_sym;
/* The name of the symbol to break on in order to insert
a catchpoint on unhandled exceptions. */
const char *catch_exception_unhandled_sym;
/* The name of the symbol to break on in order to insert
a catchpoint on failed assertions. */
const char *catch_assert_sym;
/* Assuming that the inferior just triggered an unhandled exception
catchpoint, this function is responsible for returning the address
in inferior memory where the name of that exception is stored.
Return zero if the address could not be computed. */
ada_unhandled_exception_name_addr_ftype *unhandled_exception_name_addr;
};
static CORE_ADDR ada_unhandled_exception_name_addr (void);
static CORE_ADDR ada_unhandled_exception_name_addr_from_raise (void);
/* The following exception support info structure describes how to
implement exception catchpoints with the latest version of the
Ada runtime (as of 2007-03-06). */
static const struct exception_support_info default_exception_support_info =
{
"__gnat_debug_raise_exception", /* catch_exception_sym */
"__gnat_unhandled_exception", /* catch_exception_unhandled_sym */
"__gnat_debug_raise_assert_failure", /* catch_assert_sym */
ada_unhandled_exception_name_addr
};
/* The following exception support info structure describes how to
implement exception catchpoints with a slightly older version
of the Ada runtime. */
static const struct exception_support_info exception_support_info_fallback =
{
"__gnat_raise_nodefer_with_msg", /* catch_exception_sym */
"__gnat_unhandled_exception", /* catch_exception_unhandled_sym */
"system__assertions__raise_assert_failure", /* catch_assert_sym */
ada_unhandled_exception_name_addr_from_raise
};
/* For each executable, we sniff which exception info structure to use
and cache it in the following global variable. */
static const struct exception_support_info *exception_info = NULL;
/* Inspect the Ada runtime and determine which exception info structure
should be used to provide support for exception catchpoints.
This function will always set exception_info, or raise an error. */
static void
ada_exception_support_info_sniffer (void)
{
struct symbol *sym;
/* If the exception info is already known, then no need to recompute it. */
if (exception_info != NULL)
return;
/* Check the latest (default) exception support info. */
sym = standard_lookup (default_exception_support_info.catch_exception_sym,
NULL, VAR_DOMAIN);
if (sym != NULL)
{
exception_info = &default_exception_support_info;
return;
}
/* Try our fallback exception suport info. */
sym = standard_lookup (exception_support_info_fallback.catch_exception_sym,
NULL, VAR_DOMAIN);
if (sym != NULL)
{
exception_info = &exception_support_info_fallback;
return;
}
/* Sometimes, it is normal for us to not be able to find the routine
we are looking for. This happens when the program is linked with
the shared version of the GNAT runtime, and the program has not been
started yet. Inform the user of these two possible causes if
applicable. */
if (ada_update_initial_language (language_unknown, NULL) != language_ada)
error (_("Unable to insert catchpoint. Is this an Ada main program?"));
/* If the symbol does not exist, then check that the program is
already started, to make sure that shared libraries have been
loaded. If it is not started, this may mean that the symbol is
in a shared library. */
if (ptid_get_pid (inferior_ptid) == 0)
error (_("Unable to insert catchpoint. Try to start the program first."));
/* At this point, we know that we are debugging an Ada program and
that the inferior has been started, but we still are not able to
find the run-time symbols. That can mean that we are in
configurable run time mode, or that a-except as been optimized
out by the linker... In any case, at this point it is not worth
supporting this feature. */
error (_("Cannot insert catchpoints in this configuration."));
}
/* An observer of "executable_changed" events.
Its role is to clear certain cached values that need to be recomputed
each time a new executable is loaded by GDB. */
static void
ada_executable_changed_observer (void *unused)
{
/* If the executable changed, then it is possible that the Ada runtime
is different. So we need to invalidate the exception support info
cache. */
exception_info = NULL;
}
/* Return the name of the function at PC, NULL if could not find it.
This function only checks the debugging information, not the symbol
table. */
@ -9088,6 +9208,17 @@ ada_find_printable_frame (struct frame_info *fi)
static CORE_ADDR
ada_unhandled_exception_name_addr (void)
{
return parse_and_eval_address ("e.full_name");
}
/* Same as ada_unhandled_exception_name_addr, except that this function
should be used when the inferior uses an older version of the runtime,
where the exception name needs to be extracted from a specific frame
several frames up in the callstack. */
static CORE_ADDR
ada_unhandled_exception_name_addr_from_raise (void)
{
int frame_level;
struct frame_info *fi;
@ -9106,7 +9237,7 @@ ada_unhandled_exception_name_addr (void)
const char *func_name =
function_name_from_pc (get_frame_address_in_block (fi));
if (func_name != NULL
&& strcmp (func_name, raise_sym_name) == 0)
&& strcmp (func_name, exception_info->catch_exception_sym) == 0)
break; /* We found the frame we were looking for... */
fi = get_prev_frame (fi);
}
@ -9135,7 +9266,7 @@ ada_exception_name_addr_1 (enum exception_catchpoint_kind ex,
break;
case ex_catch_exception_unhandled:
return ada_unhandled_exception_name_addr ();
return exception_info->unhandled_exception_name_addr ();
break;
case ex_catch_assert:
@ -9386,39 +9517,6 @@ ada_exception_catchpoint_p (struct breakpoint *b)
|| b->ops == &catch_assert_breakpoint_ops);
}
/* Cause the appropriate error if no appropriate runtime symbol is
found to set a breakpoint, using ERR_DESC to describe the
breakpoint. */
static void
error_breakpoint_runtime_sym_not_found (const char *err_desc)
{
/* If we are not debugging an Ada program, we cannot put exception
catchpoints! */
if (ada_update_initial_language (language_unknown, NULL) != language_ada)
error (_("Unable to break on %s. Is this an Ada main program?"),
err_desc);
/* If the symbol does not exist, then check that the program is
already started, to make sure that shared libraries have been
loaded. If it is not started, this may mean that the symbol is
in a shared library. */
if (ptid_get_pid (inferior_ptid) == 0)
error (_("Unable to break on %s. Try to start the program first."),
err_desc);
/* At this point, we know that we are debugging an Ada program and
that the inferior has been started, but we still are not able to
find the run-time symbols. That can mean that we are in
configurable run time mode, or that a-except as been optimized
out by the linker... In any case, at this point it is not worth
supporting this feature. */
error (_("Cannot break on %s in this configuration."), err_desc);
}
/* Return a newly allocated copy of the first space-separated token
in ARGSP, and then adjust ARGSP to point immediately after that
token.
@ -9512,16 +9610,18 @@ catch_ada_exception_command_split (char *args,
static const char *
ada_exception_sym_name (enum exception_catchpoint_kind ex)
{
gdb_assert (exception_info != NULL);
switch (ex)
{
case ex_catch_exception:
return (raise_sym_name);
return (exception_info->catch_exception_sym);
break;
case ex_catch_exception_unhandled:
return (raise_unhandled_sym_name);
return (exception_info->catch_exception_unhandled_sym);
break;
case ex_catch_assert:
return (raise_assert_sym_name);
return (exception_info->catch_assert_sym);
break;
default:
internal_error (__FILE__, __LINE__,
@ -9600,7 +9700,10 @@ ada_exception_sal (enum exception_catchpoint_kind ex, char *exp_string,
struct symbol *sym;
struct symtab_and_line sal;
/* First lookup the function on which we will break in order to catch
/* First, find out which exception support info to use. */
ada_exception_support_info_sniffer ();
/* Then lookup the function on which we will break in order to catch
the Ada exceptions requested by the user. */
sym_name = ada_exception_sym_name (ex);
@ -9624,7 +9727,7 @@ ada_exception_sal (enum exception_catchpoint_kind ex, char *exp_string,
this case for now. */
if (sym == NULL)
error_breakpoint_runtime_sym_not_found (sym_name);
error (_("Unable to break on '%s' in this configuration."), sym_name);
/* Make sure that the symbol we found corresponds to a function. */
if (SYMBOL_CLASS (sym) != LOC_BLOCK)