From: Joel Brobecker Date: Thu, 4 Jan 2007 05:27:31 +0000 (+0000) Subject: * ada-lang.h (ada_find_printable_frame): Remove. X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=f7f9143bd35af446945ae923c80e28c48b048f8f;p=binutils-gdb.git * 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. --- diff --git a/gdb/ChangeLog b/gdb/ChangeLog index 74359c975d9..5762fda3e5c 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,42 @@ +2007-01-03 Joel Brobecker + + * 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 * coffread.c (cs_to_section): If bfd_section is found, always diff --git a/gdb/Makefile.in b/gdb/Makefile.in index 46c1976beca..361297d6805 100644 --- a/gdb/Makefile.in +++ b/gdb/Makefile.in @@ -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) diff --git a/gdb/ada-lang.c b/gdb/ada-lang.c index 76968d9b421..5b687e34212 100644 --- a/gdb/ada-lang.c +++ b/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. */ diff --git a/gdb/ada-lang.h b/gdb/ada-lang.h index 99059090237..fbb68125cc9 100644 --- a/gdb/ada-lang.h +++ b/gdb/ada-lang.h @@ -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 diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c index 9101750c95c..a9d47613d64 100644 --- a/gdb/breakpoint.c +++ b/gdb/breakpoint.c @@ -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 - 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\