* ada-lang.h (ada_find_printable_frame): Remove.

(ada_exception_catchpoint_p, ada_decode_exception_location)
        (ada_decode_assert_location): Add declaration.
        * ada-lang.c: Add include of annotate.h and valprint.h.
        (exception_catchpoint_kind): New enum.
        (function_name_from_pc, is_known_support_routine)
        (ada_find_printable_frame, ada_unhandled_exception_name_addr)
        (ada_exception_name_addr_1, ada_exception_name_addr)
        (print_it_exception, print_one_exception, print_mention_exception)
        (print_it_catch_exception, print_one_catch_exception)
        (print_mention_catch_exception, catch_exception_breakpoint_ops)
        (print_it_catch_exception_unhandled)
        (print_one_catch_exception_unhandled)
        (print_mention_catch_exception_unhandled, print_it_catch_assert)
        (print_one_catch_assert, print_mention_catch_assert)
        (ada_exception_catchpoint_p, error_breakpoint_runtime_sym_not_found)
        (ada_get_next_arg, catch_ada_exception_command_split)
        (ada_exception_sym_name, ada_exception_sym_name)
        (ada_exception_breakption_ops, ada_exception_catchpoint_cond_string)
        (ada_parse_catchpoint_condition, ada_exception_sal)
        (ada_decode_exception_location)
        (ada_decode_assert_location): New function.
        (catch_exception_unhandled_breakpoint_ops): New global variable.
        (catch_assert_breakpoint_ops): New global variable.
        * breakpoint.c: Add include of ada-lang.h.
        (print_one_breakpoint): Do not print the condition for Ada
        exception catchpoints.
        (create_ada_exception_breakpoint): New function.
        (catch_ada_exception_command, catch_assert_command): New function.
        (catch_command_1): Add support for the new "catch exception" and
        "catch assert" commands.
        (_initialize_breakpoint): Add help description for the new catch
        commands.
        * Makefile.in (ada-lang.o): Add dependency on annotate.h and
        valprint.h.
        (breakpoint.o): Add dependency on ada-lang.h.
This commit is contained in:
Joel Brobecker 2007-01-04 05:27:31 +00:00
parent 92559b5be6
commit f7f9143bd3
5 changed files with 943 additions and 10 deletions

View file

@ -1,3 +1,42 @@
2007-01-03 Joel Brobecker <brobecker@adacore.com>
* ada-lang.h (ada_find_printable_frame): Remove.
(ada_exception_catchpoint_p, ada_decode_exception_location)
(ada_decode_assert_location): Add declaration.
* ada-lang.c: Add include of annotate.h and valprint.h.
(exception_catchpoint_kind): New enum.
(function_name_from_pc, is_known_support_routine)
(ada_find_printable_frame, ada_unhandled_exception_name_addr)
(ada_exception_name_addr_1, ada_exception_name_addr)
(print_it_exception, print_one_exception, print_mention_exception)
(print_it_catch_exception, print_one_catch_exception)
(print_mention_catch_exception, catch_exception_breakpoint_ops)
(print_it_catch_exception_unhandled)
(print_one_catch_exception_unhandled)
(print_mention_catch_exception_unhandled, print_it_catch_assert)
(print_one_catch_assert, print_mention_catch_assert)
(ada_exception_catchpoint_p, error_breakpoint_runtime_sym_not_found)
(ada_get_next_arg, catch_ada_exception_command_split)
(ada_exception_sym_name, ada_exception_sym_name)
(ada_exception_breakption_ops, ada_exception_catchpoint_cond_string)
(ada_parse_catchpoint_condition, ada_exception_sal)
(ada_decode_exception_location)
(ada_decode_assert_location): New function.
(catch_exception_unhandled_breakpoint_ops): New global variable.
(catch_assert_breakpoint_ops): New global variable.
* breakpoint.c: Add include of ada-lang.h.
(print_one_breakpoint): Do not print the condition for Ada
exception catchpoints.
(create_ada_exception_breakpoint): New function.
(catch_ada_exception_command, catch_assert_command): New function.
(catch_command_1): Add support for the new "catch exception" and
"catch assert" commands.
(_initialize_breakpoint): Add help description for the new catch
commands.
* Makefile.in (ada-lang.o): Add dependency on annotate.h and
valprint.h.
(breakpoint.o): Add dependency on ada-lang.h.
2007-01-03 Pedro Alves <pedro_alves@portugalmail.pt>
* coffread.c (cs_to_section): If bfd_section is found, always

View file

@ -1,5 +1,5 @@
# Copyright (C) 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997,
# 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006
# 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007
# Free Software Foundation, Inc.
# This file is part of GDB.
@ -1694,7 +1694,7 @@ ada-lang.o: ada-lang.c $(defs_h) $(gdb_string_h) $(demangle_h) \
$(inferior_h) $(symfile_h) $(objfiles_h) $(breakpoint_h) \
$(gdbcore_h) $(hashtab_h) $(gdb_obstack_h) $(ada_lang_h) \
$(completer_h) $(gdb_stat_h) $(ui_out_h) $(block_h) $(infcall_h) \
$(dictionary_h) $(exceptions_h)
$(dictionary_h) $(exceptions_h) $(annotate_h) $(valprint_h)
ada-typeprint.o: ada-typeprint.c $(defs_h) $(gdb_obstack_h) $(bfd_h) \
$(symtab_h) $(gdbtypes_h) $(expression_h) $(value_h) $(gdbcore_h) \
$(target_h) $(command_h) $(gdbcmd_h) $(language_h) $(demangle_h) \
@ -1834,7 +1834,7 @@ breakpoint.o: breakpoint.c $(defs_h) $(symtab_h) $(frame_h) $(breakpoint_h) \
$(objfiles_h) $(source_h) $(linespec_h) $(completer_h) $(gdb_h) \
$(ui_out_h) $(cli_script_h) $(gdb_assert_h) $(block_h) $(solib_h) \
$(solist_h) $(observer_h) $(exceptions_h) $(gdb_events_h) $(mi_common_h) \
$(memattr_h)
$(memattr_h) $(ada_lang_h)
bsd-kvm.o: bsd-kvm.c $(defs_h) $(cli_cmds_h) $(command_h) $(frame_h) \
$(regcache_h) $(target_h) $(value_h) $(gdbcore_h) $(gdb_assert_h) \
$(readline_h) $(bsd_kvm_h)

View file

@ -1,7 +1,7 @@
/* Ada language support routines for GDB, the GNU debugger. Copyright (C)
1992, 1993, 1994, 1997, 1998, 1999, 2000, 2003, 2004, 2005 Free
Software Foundation, Inc.
1992, 1993, 1994, 1997, 1998, 1999, 2000, 2003, 2004, 2005, 2007
Free Software Foundation, Inc.
This file is part of GDB.
@ -53,6 +53,8 @@ Boston, MA 02110-1301, USA. */
#include "infcall.h"
#include "dictionary.h"
#include "exceptions.h"
#include "annotate.h"
#include "valprint.h"
#ifndef ADA_RETAIN_DOTS
#define ADA_RETAIN_DOTS 0
@ -8973,6 +8975,786 @@ ada_modulus (struct type * type)
return (ULONGEST) TYPE_HIGH_BOUND (type) + 1;
}
/* Ada exception catchpoint support:
---------------------------------
We support 3 kinds of exception catchpoints:
. catchpoints on Ada exceptions
. catchpoints on unhandled Ada exceptions
. catchpoints on failed assertions
Exceptions raised during failed assertions, or unhandled exceptions
could perfectly be caught with the general catchpoint on Ada exceptions.
However, we can easily differentiate these two special cases, and having
the option to distinguish these two cases from the rest can be useful
to zero-in on certain situations.
Exception catchpoints are a specialized form of breakpoint,
since they rely on inserting breakpoints inside known routines
of the GNAT runtime. The implementation therefore uses a standard
breakpoint structure of the BP_BREAKPOINT type, but with its own set
of breakpoint_ops.
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).
Conditions where EXP_STRING, COND, and COND_STRING are used:
When a user specifies the name of a specific exception in the case
of catchpoints on Ada exceptions, we store the name of that exception
in the EXP_STRING. We then translate this request into an actual
condition stored in COND_STRING, and then parse it into an expression
stored in COND. */
/* The different types of catchpoints that we introduced for catching
Ada exceptions. */
enum exception_catchpoint_kind
{
ex_catch_exception,
ex_catch_exception_unhandled,
ex_catch_assert
};
/* 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. */
static char *
function_name_from_pc (CORE_ADDR pc)
{
char *func_name;
if (!find_pc_partial_function (pc, &func_name, NULL, NULL))
return NULL;
return func_name;
}
/* True iff FRAME is very likely to be that of a function that is
part of the runtime system. This is all very heuristic, but is
intended to be used as advice as to what frames are uninteresting
to most users. */
static int
is_known_support_routine (struct frame_info *frame)
{
struct frame_info *next_frame = get_next_frame (frame);
/* If frame is not innermost, that normally means that frame->pc
points to *after* the call instruction, and we want to get the line
containing the call, never the next line. But if the next frame is
a signal_handler_caller or a dummy frame, then the next frame was
not entered as the result of a call, and we want to get the line
containing frame->pc. */
const int pc_is_after_call =
next_frame != NULL
&& get_frame_type (next_frame) != SIGTRAMP_FRAME
&& get_frame_type (next_frame) != DUMMY_FRAME;
struct symtab_and_line sal
= find_pc_line (get_frame_pc (frame), pc_is_after_call);
char *func_name;
int i;
struct stat st;
/* The heuristic:
1. The symtab is null (indicating no debugging symbols)
2. The symtab's filename does not exist.
3. The object file's name is one of the standard libraries.
4. The symtab's file name has the form of an Ada library source file.
5. The function at frame's PC has a GNAT-compiler-generated name. */
if (sal.symtab == NULL)
return 1;
/* On some systems (e.g. VxWorks), the kernel contains debugging
symbols; in this case, the filename referenced by these symbols
does not exists. */
if (stat (sal.symtab->filename, &st))
return 1;
for (i = 0; known_runtime_file_name_patterns[i] != NULL; i += 1)
{
re_comp (known_runtime_file_name_patterns[i]);
if (re_exec (sal.symtab->filename))
return 1;
}
if (sal.symtab->objfile != NULL)
{
for (i = 0; known_runtime_file_name_patterns[i] != NULL; i += 1)
{
re_comp (known_runtime_file_name_patterns[i]);
if (re_exec (sal.symtab->objfile->name))
return 1;
}
}
/* If the frame PC points after the call instruction, then we need to
decrement it in order to search for the function associated to this
PC. Otherwise, if the associated call was the last instruction of
the function, we might either find the wrong function or even fail
during the function name lookup. */
if (pc_is_after_call)
func_name = function_name_from_pc (get_frame_pc (frame) - 1);
else
func_name = function_name_from_pc (get_frame_pc (frame));
if (func_name == NULL)
return 1;
for (i = 0; known_auxiliary_function_name_patterns[i] != NULL; i += 1)
{
re_comp (known_auxiliary_function_name_patterns[i]);
if (re_exec (func_name))
return 1;
}
return 0;
}
/* Find the first frame that contains debugging information and that is not
part of the Ada run-time, starting from FI and moving upward. */
static void
ada_find_printable_frame (struct frame_info *fi)
{
for (; fi != NULL; fi = get_prev_frame (fi))
{
if (!is_known_support_routine (fi))
{
select_frame (fi);
break;
}
}
}
/* Assuming that the inferior just triggered an unhandled exception
catchpoint, return the address in inferior memory where the name
of the exception is stored.
Return zero if the address could not be computed. */
static CORE_ADDR
ada_unhandled_exception_name_addr (void)
{
int frame_level;
struct frame_info *fi;
/* To determine the name of this exception, we need to select
the frame corresponding to RAISE_SYM_NAME. This frame is
at least 3 levels up, so we simply skip the first 3 frames
without checking the name of their associated function. */
fi = get_current_frame ();
for (frame_level = 0; frame_level < 3; frame_level += 1)
if (fi != NULL)
fi = get_prev_frame (fi);
while (fi != NULL)
{
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)
break; /* We found the frame we were looking for... */
fi = get_prev_frame (fi);
}
if (fi == NULL)
return 0;
select_frame (fi);
return parse_and_eval_address ("id.full_name");
}
/* Assuming the inferior just triggered an Ada exception catchpoint
(of any type), return the address in inferior memory where the name
of the exception is stored, if applicable.
Return zero if the address could not be computed, or if not relevant. */
static CORE_ADDR
ada_exception_name_addr_1 (enum exception_catchpoint_kind ex,
struct breakpoint *b)
{
switch (ex)
{
case ex_catch_exception:
return (parse_and_eval_address ("e.full_name"));
break;
case ex_catch_exception_unhandled:
return ada_unhandled_exception_name_addr ();
break;
case ex_catch_assert:
return 0; /* Exception name is not relevant in this case. */
break;
default:
internal_error (__FILE__, __LINE__, _("unexpected catchpoint type"));
break;
}
return 0; /* Should never be reached. */
}
/* Same as ada_exception_name_addr_1, except that it intercepts and contains
any error that ada_exception_name_addr_1 might cause to be thrown.
When an error is intercepted, a warning with the error message is printed,
and zero is returned. */
static CORE_ADDR
ada_exception_name_addr (enum exception_catchpoint_kind ex,
struct breakpoint *b)
{
struct gdb_exception e;
CORE_ADDR result = 0;
TRY_CATCH (e, RETURN_MASK_ERROR)
{
result = ada_exception_name_addr_1 (ex, b);
}
if (e.reason < 0)
{
warning (_("failed to get exception name: %s"), e.message);
return 0;
}
return result;
}
/* Implement the PRINT_IT method in the breakpoint_ops structure
for all exception catchpoint kinds. */
static enum print_stop_action
print_it_exception (enum exception_catchpoint_kind ex, struct breakpoint *b)
{
const CORE_ADDR addr = ada_exception_name_addr (ex, b);
char exception_name[256];
if (addr != 0)
{
read_memory (addr, exception_name, sizeof (exception_name) - 1);
exception_name [sizeof (exception_name) - 1] = '\0';
}
ada_find_printable_frame (get_current_frame ());
annotate_catchpoint (b->number);
switch (ex)
{
case ex_catch_exception:
if (addr != 0)
printf_filtered (_("\nCatchpoint %d, %s at "),
b->number, exception_name);
else
printf_filtered (_("\nCatchpoint %d, exception at "), b->number);
break;
case ex_catch_exception_unhandled:
if (addr != 0)
printf_filtered (_("\nCatchpoint %d, unhandled %s at "),
b->number, exception_name);
else
printf_filtered (_("\nCatchpoint %d, unhandled exception at "),
b->number);
break;
case ex_catch_assert:
printf_filtered (_("\nCatchpoint %d, failed assertion at "),
b->number);
break;
}
return PRINT_SRC_AND_LOC;
}
/* Implement the PRINT_ONE method in the breakpoint_ops structure
for all exception catchpoint kinds. */
static void
print_one_exception (enum exception_catchpoint_kind ex,
struct breakpoint *b, CORE_ADDR *last_addr)
{
if (addressprint)
{
annotate_field (4);
ui_out_field_core_addr (uiout, "addr", b->loc->address);
}
annotate_field (5);
*last_addr = b->loc->address;
switch (ex)
{
case ex_catch_exception:
if (b->exp_string != NULL)
{
char *msg = xstrprintf (_("`%s' Ada exception"), b->exp_string);
ui_out_field_string (uiout, "what", msg);
xfree (msg);
}
else
ui_out_field_string (uiout, "what", "all Ada exceptions");
break;
case ex_catch_exception_unhandled:
ui_out_field_string (uiout, "what", "unhandled Ada exceptions");
break;
case ex_catch_assert:
ui_out_field_string (uiout, "what", "failed Ada assertions");
break;
default:
internal_error (__FILE__, __LINE__, _("unexpected catchpoint type"));
break;
}
}
/* Implement the PRINT_MENTION method in the breakpoint_ops structure
for all exception catchpoint kinds. */
static void
print_mention_exception (enum exception_catchpoint_kind ex,
struct breakpoint *b)
{
switch (ex)
{
case ex_catch_exception:
if (b->exp_string != NULL)
printf_filtered (_("Catchpoint %d: `%s' Ada exception"),
b->number, b->exp_string);
else
printf_filtered (_("Catchpoint %d: all Ada exceptions"), b->number);
break;
case ex_catch_exception_unhandled:
printf_filtered (_("Catchpoint %d: unhandled Ada exceptions"),
b->number);
break;
case ex_catch_assert:
printf_filtered (_("Catchpoint %d: failed Ada assertions"), b->number);
break;
default:
internal_error (__FILE__, __LINE__, _("unexpected catchpoint type"));
break;
}
}
/* Virtual table for "catch exception" breakpoints. */
static enum print_stop_action
print_it_catch_exception (struct breakpoint *b)
{
return print_it_exception (ex_catch_exception, b);
}
static void
print_one_catch_exception (struct breakpoint *b, CORE_ADDR *last_addr)
{
print_one_exception (ex_catch_exception, b, last_addr);
}
static void
print_mention_catch_exception (struct breakpoint *b)
{
print_mention_exception (ex_catch_exception, b);
}
static struct breakpoint_ops catch_exception_breakpoint_ops =
{
print_it_catch_exception,
print_one_catch_exception,
print_mention_catch_exception
};
/* Virtual table for "catch exception unhandled" breakpoints. */
static enum print_stop_action
print_it_catch_exception_unhandled (struct breakpoint *b)
{
return print_it_exception (ex_catch_exception_unhandled, b);
}
static void
print_one_catch_exception_unhandled (struct breakpoint *b, CORE_ADDR *last_addr)
{
print_one_exception (ex_catch_exception_unhandled, b, last_addr);
}
static void
print_mention_catch_exception_unhandled (struct breakpoint *b)
{
print_mention_exception (ex_catch_exception_unhandled, b);
}
static struct breakpoint_ops catch_exception_unhandled_breakpoint_ops = {
print_it_catch_exception_unhandled,
print_one_catch_exception_unhandled,
print_mention_catch_exception_unhandled
};
/* Virtual table for "catch assert" breakpoints. */
static enum print_stop_action
print_it_catch_assert (struct breakpoint *b)
{
return print_it_exception (ex_catch_assert, b);
}
static void
print_one_catch_assert (struct breakpoint *b, CORE_ADDR *last_addr)
{
print_one_exception (ex_catch_assert, b, last_addr);
}
static void
print_mention_catch_assert (struct breakpoint *b)
{
print_mention_exception (ex_catch_assert, b);
}
static struct breakpoint_ops catch_assert_breakpoint_ops = {
print_it_catch_assert,
print_one_catch_assert,
print_mention_catch_assert
};
/* Return non-zero if B is an Ada exception catchpoint. */
int
ada_exception_catchpoint_p (struct breakpoint *b)
{
return (b->ops == &catch_exception_breakpoint_ops
|| b->ops == &catch_exception_unhandled_breakpoint_ops
|| 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.
Return NULL if ARGPS does not contain any more tokens. */
static char *
ada_get_next_arg (char **argsp)
{
char *args = *argsp;
char *end;
char *result;
/* Skip any leading white space. */
while (isspace (*args))
args++;
if (args[0] == '\0')
return NULL; /* No more arguments. */
/* Find the end of the current argument. */
end = args;
while (*end != '\0' && !isspace (*end))
end++;
/* Adjust ARGSP to point to the start of the next argument. */
*argsp = end;
/* Make a copy of the current argument and return it. */
result = xmalloc (end - args + 1);
strncpy (result, args, end - args);
result[end - args] = '\0';
return result;
}
/* Split the arguments specified in a "catch exception" command.
Set EX to the appropriate catchpoint type.
Set EXP_STRING to the name of the specific exception if
specified by the user. */
static void
catch_ada_exception_command_split (char *args,
enum exception_catchpoint_kind *ex,
char **exp_string)
{
struct cleanup *old_chain = make_cleanup (null_cleanup, NULL);
char *exception_name;
exception_name = ada_get_next_arg (&args);
make_cleanup (xfree, exception_name);
/* Check that we do not have any more arguments. Anything else
is unexpected. */
while (isspace (*args))
args++;
if (args[0] != '\0')
error (_("Junk at end of expression"));
discard_cleanups (old_chain);
if (exception_name == NULL)
{
/* Catch all exceptions. */
*ex = ex_catch_exception;
*exp_string = NULL;
}
else if (strcmp (exception_name, "unhandled") == 0)
{
/* Catch unhandled exceptions. */
*ex = ex_catch_exception_unhandled;
*exp_string = NULL;
}
else
{
/* Catch a specific exception. */
*ex = ex_catch_exception;
*exp_string = exception_name;
}
}
/* Return the name of the symbol on which we should break in order to
implement a catchpoint of the EX kind. */
static const char *
ada_exception_sym_name (enum exception_catchpoint_kind ex)
{
switch (ex)
{
case ex_catch_exception:
return (raise_sym_name);
break;
case ex_catch_exception_unhandled:
return (raise_unhandled_sym_name);
break;
case ex_catch_assert:
return (raise_assert_sym_name);
break;
default:
internal_error (__FILE__, __LINE__,
_("unexpected catchpoint kind (%d)"), ex);
}
}
/* Return the breakpoint ops "virtual table" used for catchpoints
of the EX kind. */
static struct breakpoint_ops *
ada_exception_breakption_ops (enum exception_catchpoint_kind ex)
{
switch (ex)
{
case ex_catch_exception:
return (&catch_exception_breakpoint_ops);
break;
case ex_catch_exception_unhandled:
return (&catch_exception_unhandled_breakpoint_ops);
break;
case ex_catch_assert:
return (&catch_assert_breakpoint_ops);
break;
default:
internal_error (__FILE__, __LINE__,
_("unexpected catchpoint kind (%d)"), ex);
}
}
/* Return the condition that will be used to match the current exception
being raised with the exception that the user wants to catch. This
assumes that this condition is used when the inferior just triggered
an exception catchpoint.
The string returned is a newly allocated string that needs to be
deallocated later. */
static char *
ada_exception_catchpoint_cond_string (const char *exp_string)
{
return xstrprintf ("long_integer (e) = long_integer (&%s)", exp_string);
}
/* Return the expression corresponding to COND_STRING evaluated at SAL. */
static struct expression *
ada_parse_catchpoint_condition (char *cond_string,
struct symtab_and_line sal)
{
return (parse_exp_1 (&cond_string, block_for_pc (sal.pc), 0));
}
/* Return the symtab_and_line that should be used to insert an exception
catchpoint of the TYPE kind.
EX_STRING should contain the name of a specific exception
that the catchpoint should catch, or NULL otherwise.
The idea behind all the remaining parameters is that their names match
the name of certain fields in the breakpoint structure that are used to
handle exception catchpoints. This function returns the value to which
these fields should be set, depending on the type of catchpoint we need
to create.
If COND and COND_STRING are both non-NULL, any value they might
hold will be free'ed, and then replaced by newly allocated ones.
These parameters are left untouched otherwise. */
static struct symtab_and_line
ada_exception_sal (enum exception_catchpoint_kind ex, char *exp_string,
char **addr_string, char **cond_string,
struct expression **cond, struct breakpoint_ops **ops)
{
const char *sym_name;
struct symbol *sym;
struct symtab_and_line sal;
/* First 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);
sym = standard_lookup (sym_name, NULL, VAR_DOMAIN);
/* The symbol we're looking up is provided by a unit in the GNAT runtime
that should be compiled with debugging information. As a result, we
expect to find that symbol in the symtabs. If we don't find it, then
the target most likely does not support Ada exceptions, or we cannot
insert exception breakpoints yet, because the GNAT runtime hasn't been
loaded yet. */
/* brobecker/2006-12-26: It is conceivable that the runtime was compiled
in such a way that no debugging information is produced for the symbol
we are looking for. In this case, we could search the minimal symbols
as a fall-back mechanism. This would still be operating in degraded
mode, however, as we would still be missing the debugging information
that is needed in order to extract the name of the exception being
raised (this name is printed in the catchpoint message, and is also
used when trying to catch a specific exception). We do not handle
this case for now. */
if (sym == NULL)
error_breakpoint_runtime_sym_not_found (sym_name);
/* Make sure that the symbol we found corresponds to a function. */
if (SYMBOL_CLASS (sym) != LOC_BLOCK)
error (_("Symbol \"%s\" is not a function (class = %d)"),
sym_name, SYMBOL_CLASS (sym));
sal = find_function_start_sal (sym, 1);
/* Set ADDR_STRING. */
*addr_string = xstrdup (sym_name);
/* Set the COND and COND_STRING (if not NULL). */
if (cond_string != NULL && cond != NULL)
{
if (*cond_string != NULL)
{
xfree (*cond_string);
*cond_string = NULL;
}
if (*cond != NULL)
{
xfree (*cond);
*cond = NULL;
}
if (exp_string != NULL)
{
*cond_string = ada_exception_catchpoint_cond_string (exp_string);
*cond = ada_parse_catchpoint_condition (*cond_string, sal);
}
}
/* Set OPS. */
*ops = ada_exception_breakption_ops (ex);
return sal;
}
/* Parse the arguments (ARGS) of the "catch exception" command.
Set TYPE to the appropriate exception catchpoint type.
If the user asked the catchpoint to catch only a specific
exception, then save the exception name in ADDR_STRING.
See ada_exception_sal for a description of all the remaining
function arguments of this function. */
struct symtab_and_line
ada_decode_exception_location (char *args, char **addr_string,
char **exp_string, char **cond_string,
struct expression **cond,
struct breakpoint_ops **ops)
{
enum exception_catchpoint_kind ex;
catch_ada_exception_command_split (args, &ex, exp_string);
return ada_exception_sal (ex, *exp_string, addr_string, cond_string,
cond, ops);
}
struct symtab_and_line
ada_decode_assert_location (char *args, char **addr_string,
struct breakpoint_ops **ops)
{
/* Check that no argument where provided at the end of the command. */
if (args != NULL)
{
while (isspace (*args))
args++;
if (*args != '\0')
error (_("Junk at end of arguments."));
}
return ada_exception_sal (ex_catch_assert, NULL, addr_string, NULL, NULL,
ops);
}
/* Operators */
/* Information about operators given special treatment in functions
below. */

View file

@ -1,7 +1,8 @@
/* Ada language support definitions for GDB, the GNU debugger.
Copyright (C) 1992, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004,
2005 Free Software Foundation, Inc.
2005, 2007
Free Software Foundation, Inc.
This file is part of GDB.
@ -470,8 +471,6 @@ extern int ada_print_exception_breakpoint_nontask (struct breakpoint *);
extern void ada_print_exception_breakpoint_task (struct breakpoint *);
extern void ada_find_printable_frame (struct frame_info *fi);
extern void ada_reset_thread_registers (void);
extern int ada_build_task_list (void);
@ -486,4 +485,18 @@ extern struct symbol *lookup_symbol_in_language (const char *,
enum language,
int *,
struct symtab **);
extern int ada_exception_catchpoint_p (struct breakpoint *b);
extern struct symtab_and_line
ada_decode_exception_location (char *args, char **addr_string,
char **exp_string, char **cond_string,
struct expression **cond,
struct breakpoint_ops **ops);
extern struct symtab_and_line
ada_decode_assert_location (char *args, char **addr_string,
struct breakpoint_ops **ops);
#endif

View file

@ -1,7 +1,8 @@
/* Everything about breakpoints, for GDB.
Copyright (C) 1986, 1987, 1988, 1989, 1990, 1991, 1992, 1993, 1994,
1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006
1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006,
2007
Free Software Foundation, Inc.
This file is part of GDB.
@ -54,6 +55,7 @@
#include "observer.h"
#include "exceptions.h"
#include "memattr.h"
#include "ada-lang.h"
#include "gdb-events.h"
#include "mi/mi-common.h"
@ -3609,8 +3611,11 @@ print_one_breakpoint (struct breakpoint *b,
ui_out_text (uiout, "\n");
}
if (b->cond)
if (b->cond && !ada_exception_catchpoint_p (b))
{
/* We do not print the condition for Ada exception catchpoints
because the condition is an internal implementation detail
that we do not want to expose to the user. */
annotate_field (7);
ui_out_text (uiout, "\tstop only if ");
print_expression (b->cond, stb->stream);
@ -6507,6 +6512,86 @@ catch_exception_command_1 (enum exception_event_kind ex_event, char *arg,
warning (_("Unsupported with this platform/compiler combination."));
}
/* Create a breakpoint struct for Ada exception catchpoints. */
static void
create_ada_exception_breakpoint (struct symtab_and_line sal,
char *addr_string,
char *exp_string,
char *cond_string,
struct expression *cond,
struct breakpoint_ops *ops,
int tempflag,
int from_tty)
{
struct breakpoint *b;
if (from_tty)
{
describe_other_breakpoints (sal.pc, sal.section, -1);
/* FIXME: brobecker/2006-12-28: Actually, re-implement a special
version for exception catchpoints, because two catchpoints
used for different exception names will use the same address.
In this case, a "breakpoint ... also set at..." warning is
unproductive. Besides. the warning phrasing is also a bit
inapropriate, we should use the word catchpoint, and tell
the user what type of catchpoint it is. The above is good
enough for now, though. */
}
b = set_raw_breakpoint (sal, bp_breakpoint);
set_breakpoint_count (breakpoint_count + 1);
b->enable_state = bp_enabled;
b->disposition = tempflag ? disp_del : disp_donttouch;
b->number = breakpoint_count;
b->ignore_count = 0;
b->cond = cond;
b->addr_string = addr_string;
b->language = language_ada;
b->cond_string = cond_string;
b->exp_string = exp_string;
b->thread = -1;
b->ops = ops;
b->from_tty = from_tty;
mention (b);
}
/* Implement the "catch exception" command. */
static void
catch_ada_exception_command (char *arg, int tempflag, int from_tty)
{
struct symtab_and_line sal;
enum bptype type;
char *addr_string = NULL;
char *exp_string = NULL;
char *cond_string = NULL;
struct expression *cond = NULL;
struct breakpoint_ops *ops = NULL;
sal = ada_decode_exception_location (arg, &addr_string, &exp_string,
&cond_string, &cond, &ops);
create_ada_exception_breakpoint (sal, addr_string, exp_string,
cond_string, cond, ops, tempflag,
from_tty);
}
/* Implement the "catch assert" command. */
static void
catch_assert_command (char *arg, int tempflag, int from_tty)
{
struct symtab_and_line sal;
char *addr_string = NULL;
struct breakpoint_ops *ops = NULL;
sal = ada_decode_assert_location (arg, &addr_string, &ops);
create_ada_exception_breakpoint (sal, addr_string, NULL, NULL, NULL, ops,
tempflag, from_tty);
}
/* Cover routine to allow wrapping target_enable_exception_catchpoints
inside a catch_errors */
@ -6611,6 +6696,15 @@ catch_command_1 (char *arg, int tempflag, int from_tty)
{
error (_("Catch of stop not yet implemented"));
}
else if (strncmp (arg1_start, "exception", arg1_length) == 0)
{
catch_ada_exception_command (arg1_end + 1, tempflag, from_tty);
}
else if (strncmp (arg1_start, "assert", arg1_length) == 0)
{
catch_assert_command (arg1_end + 1, tempflag, from_tty);
}
/* This doesn't appear to be an event name */
@ -8117,6 +8211,11 @@ The act of your program's execution stopping may also be caught:\n\
C++ exceptions may be caught:\n\
\tcatch throw - all exceptions, when thrown\n\
\tcatch catch - all exceptions, when caught\n\
Ada exceptions may be caught:\n\
\tcatch exception - all exceptions, when raised\n\
\tcatch exception <name> - a particular exception, when raised\n\
\tcatch exception unhandled - all unhandled exceptions, when raised\n\
\tcatch assert - all failed assertions, when raised\n\
\n\
Do \"help set follow-fork-mode\" for info on debugging your program\n\
after a fork or vfork is caught.\n\n\