forked from Imagelibrary/binutils-gdb
* 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:
786
gdb/ada-lang.c
786
gdb/ada-lang.c
@@ -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. */
|
||||
|
||||
Reference in New Issue
Block a user