-/* Ada language support routines for GDB, the GNU debugger. Copyright (C)
+/* Ada language support routines for GDB, the GNU debugger.
- 1992, 1993, 1994, 1997, 1998, 1999, 2000, 2003, 2004, 2005, 2007, 2008,
- 2009 Free Software Foundation, Inc.
+ Copyright (C) 1992-1994, 1997-2000, 2003-2005, 2007-2012 Free
+ Software Foundation, Inc.
This file is part of GDB.
#include "observer.h"
#include "vec.h"
#include "stack.h"
+#include "gdb_vecs.h"
#include "psymtab.h"
#include "value.h"
#include "mi/mi-common.h"
#include "arch-utils.h"
#include "exceptions.h"
+#include "cli/cli-utils.h"
/* Define whether or not the C operator '/' truncates towards zero for
differently signed operands (truncation direction is undefined in C).
accessible through a component ("tsd") in the object tag. But this
is no longer the case, so we cache it for each inferior. */
struct type *tsd_type;
+
+ /* The exception_support_info data. This data is used to determine
+ how to implement support for Ada exception catchpoints in a given
+ inferior. */
+ const struct exception_support_info *exception_info;
};
/* Our key to this module's inferior data. */
non-range scalar type. */
static struct type *
-base_type (struct type *type)
+get_base_type (struct type *type)
{
while (type != NULL && TYPE_CODE (type) == TYPE_CODE_RANGE)
{
return 1;
if (TYPE_CODE (func_type) == TYPE_CODE_FUNC)
- return_type = base_type (TYPE_TARGET_TYPE (func_type));
+ return_type = get_base_type (TYPE_TARGET_TYPE (func_type));
else
- return_type = base_type (func_type);
+ return_type = get_base_type (func_type);
if (return_type == NULL)
return 1;
- context_type = base_type (context_type);
+ context_type = get_base_type (context_type);
if (TYPE_CODE (return_type) == TYPE_CODE_ENUM)
return context_type == NULL || return_type == context_type;
char *args2;
int choice, j;
- while (isspace (*args))
- args += 1;
+ args = skip_spaces (args);
if (*args == '\0' && n_chosen == 0)
error_no_arg (_("one or more choice numbers"));
else if (*args == '\0')
\f
/* Symbol Lookup */
+/* Return nonzero if wild matching should be used when searching for
+ all symbols matching LOOKUP_NAME.
+
+ LOOKUP_NAME is expected to be a symbol name after transformation
+ for Ada lookups (see ada_name_for_lookup). */
+
+static int
+should_use_wild_match (const char *lookup_name)
+{
+ return (strstr (lookup_name, "__") == NULL);
+}
+
/* Return the result of a standard (literal, C-like) lookup of NAME in
given DOMAIN, visible from lexical block BLOCK. */
{
struct objfile *objfile;
struct minimal_symbol *msymbol;
- int wild_match;
+ const int wild_match = should_use_wild_match (name);
+ /* Special case: If the user specifies a symbol name inside package
+ Standard, do a non-wild matching of the symbol name without
+ the "standard__" prefix. This was primarily introduced in order
+ to allow the user to specifically access the standard exceptions
+ using, for instance, Standard.Constraint_Error when Constraint_Error
+ is ambiguous (due to the user defining its own Constraint_Error
+ entity inside its program). */
if (strncmp (name, "standard__", sizeof ("standard__") - 1) == 0)
- {
- name += sizeof ("standard__") - 1;
- wild_match = 0;
- }
- else
- wild_match = (strstr (name, "__") == NULL);
+ name += sizeof ("standard__") - 1;
ALL_MSYMBOLS (objfile, msymbol)
{
i = 0;
while (i < nsyms)
{
- int remove = 0;
+ int remove_p = 0;
/* If two symbols have the same name and one of them is a stub type,
the get rid of the stub. */
&& SYMBOL_LINKAGE_NAME (syms[j].sym) != NULL
&& strcmp (SYMBOL_LINKAGE_NAME (syms[i].sym),
SYMBOL_LINKAGE_NAME (syms[j].sym)) == 0)
- remove = 1;
+ remove_p = 1;
}
}
&& SYMBOL_CLASS (syms[i].sym) == SYMBOL_CLASS (syms[j].sym)
&& SYMBOL_VALUE_ADDRESS (syms[i].sym)
== SYMBOL_VALUE_ADDRESS (syms[j].sym))
- remove = 1;
+ remove_p = 1;
}
}
- if (remove)
+ if (remove_p)
{
for (j = i + 1; j < nsyms; j += 1)
syms[j - 1] = syms[j];
if (is_name_suffix (string1))
return 0;
else
- return -1;
+ return 1;
}
/* FALLTHROUGH */
default:
struct objfile *objfile;
struct match_data data;
+ memset (&data, 0, sizeof data);
data.obstackp = obstackp;
- data.arg_sym = NULL;
ALL_OBJFILES (objfile)
{
struct symbol *sym;
struct block *block;
const char *name;
- int wild_match;
+ const int wild_match = should_use_wild_match (name0);
int cacheIfUnique;
int ndefns;
/* Search specified block and its superiors. */
- wild_match = (strstr (name0, "__") == NULL);
name = name0;
block = (struct block *) block0; /* FIXME: No cast ought to be
needed, but adding const will
entity inside its program). */
if (strncmp (name0, "standard__", sizeof ("standard__") - 1) == 0)
{
- wild_match = 0;
block = NULL;
name = name0 + sizeof ("standard__") - 1;
}
return ndefns;
}
+/* If NAME is the name of an entity, return a string that should
+ be used to look that entity up in Ada units. This string should
+ be deallocated after use using xfree.
+
+ NAME can have any form that the "break" or "print" commands might
+ recognize. In other words, it does not have to be the "natural"
+ name, or the "encoded" name. */
+
+char *
+ada_name_for_lookup (const char *name)
+{
+ char *canon;
+ int nlen = strlen (name);
+
+ if (name[0] == '<' && name[nlen - 1] == '>')
+ {
+ canon = xmalloc (nlen - 1);
+ memcpy (canon, name + 1, nlen - 2);
+ canon[nlen - 2] = '\0';
+ }
+ else
+ canon = xstrdup (ada_encode (ada_fold_name (name)));
+ return canon;
+}
+
+/* Implementation of the la_iterate_over_symbols method. */
+
+static void
+ada_iterate_over_symbols (const struct block *block,
+ const char *name, domain_enum domain,
+ int (*callback) (struct symbol *, void *),
+ void *data)
+{
+ int ndefs, i;
+ struct ada_symbol_info *results;
+
+ ndefs = ada_lookup_symbol_list (name, block, domain, &results);
+ for (i = 0; i < ndefs; ++i)
+ {
+ if (! (*callback) (results[i].sym, data))
+ break;
+ }
+}
+
struct symbol *
ada_lookup_encoded_symbol (const char *name, const struct block *block0,
domain_enum namespace, struct block **block_found)
[.$][0-9]+ [nested subprogram suffix, on platforms such as GNU/Linux]
___[0-9]+ [nested subprogram suffix, on platforms such as HP/UX]
+ TKB [subprogram suffix for task bodies]
_E[0-9]+[bs]$ [protected object entry suffixes]
(X[nb]*)?((\$|__)[0-9](_?[0-9]+)|___(JM|LJM|X([FDBUP].*|R[^T]?)))?$
return 1;
}
+ /* "TKB" suffixes are used for subprograms implementing task bodies. */
+
+ if (strcmp (str, "TKB") == 0)
+ return 1;
+
#if 0
/* FIXME: brobecker/2005-09-23: Protected Object subprograms end
with a N at the end. Unfortunately, the compiler uses the same
return sym_name;
}
-DEF_VEC_P (char_ptr);
-
/* A companion function to ada_make_symbol_completion_list().
Check if SYM_NAME represents a symbol which name would be suitable
to complete TEXT (TEXT_LEN is the length of TEXT), in which case
/* A callback for expand_partial_symbol_names. */
static int
-ada_expand_partial_symbol_name (const char *name, void *user_data)
+ada_expand_partial_symbol_name (const struct language_defn *language,
+ const char *name, void *user_data)
{
struct add_partial_datum *data = user_data;
arg1 = coerce_ref (arg1);
arg2 = coerce_ref (arg2);
- type1 = base_type (ada_check_typedef (value_type (arg1)));
- type2 = base_type (ada_check_typedef (value_type (arg2)));
+ type1 = get_base_type (ada_check_typedef (value_type (arg1)));
+ type2 = get_base_type (ada_check_typedef (value_type (arg2)));
if (TYPE_CODE (type1) != TYPE_CODE_INT
|| TYPE_CODE (type2) != TYPE_CODE_INT)
*pos += 3;
if (noside != EVAL_NORMAL)
{
- int i;
-
for (i = 0; i < n; i += 1)
ada_evaluate_subexp (NULL, exp, pos, noside);
return container;
{
switch (exp->elts[*pos].opcode)
{
- case OP_CHOICES:
- aggregate_assign_from_choices (container, lhs, exp, pos, indices,
+ case OP_CHOICES:
+ aggregate_assign_from_choices (container, lhs, exp, pos, indices,
+ &num_indices, max_indices,
+ low_index, high_index);
+ break;
+ case OP_POSITIONAL:
+ aggregate_assign_positional (container, lhs, exp, pos, indices,
&num_indices, max_indices,
low_index, high_index);
- break;
- case OP_POSITIONAL:
- aggregate_assign_positional (container, lhs, exp, pos, indices,
- &num_indices, max_indices,
- low_index, high_index);
- break;
- case OP_OTHERS:
- if (i != n-1)
- error (_("Misplaced 'others' clause"));
- aggregate_assign_others (container, lhs, exp, pos, indices,
- num_indices, low_index, high_index);
- break;
- default:
- error (_("Internal error: bad aggregate clause"));
+ break;
+ case OP_OTHERS:
+ if (i != n-1)
+ error (_("Misplaced 'others' clause"));
+ aggregate_assign_others (container, lhs, exp, pos, indices,
+ num_indices, low_index, high_index);
+ break;
+ default:
+ error (_("Internal error: bad aggregate clause"));
}
}
int
ada_is_modular_type (struct type *type)
{
- struct type *subranged_type = base_type (type);
+ struct type *subranged_type = get_base_type (type);
return (subranged_type != NULL && TYPE_CODE (type) == TYPE_CODE_RANGE
&& TYPE_CODE (subranged_type) == TYPE_CODE_INT
ada_unhandled_exception_name_addr_from_raise
};
-/* For each executable, we sniff which exception info structure to use
- and cache it in the following global variable. */
+/* Return nonzero if we can detect the exception support routines
+ described in EINFO.
-static const struct exception_support_info *exception_info = NULL;
+ This function errors out if an abnormal situation is detected
+ (for instance, if we find the exception support routines, but
+ that support is found to be incomplete). */
+
+static int
+ada_has_this_exception_support (const struct exception_support_info *einfo)
+{
+ struct symbol *sym;
+
+ /* 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. */
+
+ sym = standard_lookup (einfo->catch_exception_sym, NULL, VAR_DOMAIN);
+ if (sym == NULL)
+ {
+ /* Perhaps we did not find our symbol because the Ada runtime was
+ compiled without debugging info, or simply stripped of it.
+ It happens on some GNU/Linux distributions for instance, where
+ users have to install a separate debug package in order to get
+ the runtime's debugging info. In that situation, let the user
+ know why we cannot insert an Ada exception catchpoint.
+
+ Note: Just for the purpose of inserting our Ada exception
+ catchpoint, we could rely purely on the associated minimal symbol.
+ But we would be operating in degraded mode anyway, since we are
+ still lacking the debugging info needed later on 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 (lookup_minimal_symbol (einfo->catch_exception_sym, NULL, NULL))
+ error (_("Your Ada runtime appears to be missing some debugging "
+ "information.\nCannot insert Ada exception catchpoint "
+ "in this configuration."));
+
+ return 0;
+ }
+
+ /* 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)"),
+ SYMBOL_LINKAGE_NAME (sym), SYMBOL_CLASS (sym));
+
+ return 1;
+}
/* Inspect the Ada runtime and determine which exception info structure
should be used to provide support for exception catchpoints.
- This function will always set exception_info, or raise an error. */
+ This function will always set the per-inferior exception_info,
+ or raise an error. */
static void
ada_exception_support_info_sniffer (void)
{
+ struct ada_inferior_data *data = get_ada_inferior_data (current_inferior ());
struct symbol *sym;
/* If the exception info is already known, then no need to recompute it. */
- if (exception_info != NULL)
+ if (data->exception_info != NULL)
return;
/* Check the latest (default) exception support info. */
- sym = standard_lookup (default_exception_support_info.catch_exception_sym,
- NULL, VAR_DOMAIN);
- if (sym != NULL)
+ if (ada_has_this_exception_support (&default_exception_support_info))
{
- exception_info = &default_exception_support_info;
+ data->exception_info = &default_exception_support_info;
return;
}
/* Try our fallback exception suport info. */
- sym = standard_lookup (exception_support_info_fallback.catch_exception_sym,
- NULL, VAR_DOMAIN);
- if (sym != NULL)
+ if (ada_has_this_exception_support (&exception_support_info_fallback))
{
- exception_info = &exception_support_info_fallback;
+ data->exception_info = &exception_support_info_fallback;
return;
}
out by the linker... In any case, at this point it is not worth
supporting this feature. */
- error (_("Cannot insert catchpoints in this configuration."));
-}
-
-/* An observer of "executable_changed" events.
- Its role is to clear certain cached values that need to be recomputed
- each time a new executable is loaded by GDB. */
-
-static void
-ada_executable_changed_observer (void)
-{
- /* If the executable changed, then it is possible that the Ada runtime
- is different. So we need to invalidate the exception support info
- cache. */
- exception_info = NULL;
+ error (_("Cannot insert Ada exception catchpoints in this configuration."));
}
/* True iff FRAME is very likely to be that of a function that is
{
int frame_level;
struct frame_info *fi;
+ struct ada_inferior_data *data = get_ada_inferior_data (current_inferior ());
/* To determine the name of this exception, we need to select
the frame corresponding to RAISE_SYM_NAME. This frame is
find_frame_funname (fi, &func_name, &func_lang, NULL);
if (func_name != NULL
- && strcmp (func_name, exception_info->catch_exception_sym) == 0)
+ && strcmp (func_name, data->exception_info->catch_exception_sym) == 0)
break; /* We found the frame we were looking for... */
fi = get_prev_frame (fi);
}
ada_exception_name_addr_1 (enum exception_catchpoint_kind ex,
struct breakpoint *b)
{
+ struct ada_inferior_data *data = get_ada_inferior_data (current_inferior ());
+
switch (ex)
{
case ex_catch_exception:
break;
case ex_catch_exception_unhandled:
- return exception_info->unhandled_exception_name_addr ();
+ return data->exception_info->unhandled_exception_name_addr ();
break;
case ex_catch_assert:
ada_exception_name_addr (enum exception_catchpoint_kind ex,
struct breakpoint *b)
{
- struct gdb_exception e;
+ volatile struct gdb_exception e;
CORE_ADDR result = 0;
TRY_CATCH (e, RETURN_MASK_ERROR)
static enum print_stop_action
print_it_exception (enum exception_catchpoint_kind ex, bpstat bs)
{
+ struct ui_out *uiout = current_uiout;
struct breakpoint *b = bs->breakpoint_at;
annotate_catchpoint (b->number);
print_one_exception (enum exception_catchpoint_kind ex,
struct breakpoint *b, struct bp_location **last_loc)
{
+ struct ui_out *uiout = current_uiout;
struct ada_catchpoint *c = (struct ada_catchpoint *) b;
struct value_print_options opts;
struct breakpoint *b)
{
struct ada_catchpoint *c = (struct ada_catchpoint *) b;
+ struct ui_out *uiout = current_uiout;
ui_out_text (uiout, b->disposition == disp_del ? _("Temporary catchpoint ")
: _("Catchpoint "));
char *end;
char *result;
- /* Skip any leading white space. */
-
- while (isspace (*args))
- args++;
-
+ args = skip_spaces (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++;
+ end = skip_to_space (args);
/* Adjust ARGSP to point to the start of the next argument. */
/* Check that we do not have any more arguments. Anything else
is unexpected. */
- while (isspace (*args))
- args++;
+ args = skip_spaces (args);
if (args[0] != '\0')
error (_("Junk at end of expression"));
static const char *
ada_exception_sym_name (enum exception_catchpoint_kind ex)
{
- gdb_assert (exception_info != NULL);
+ struct ada_inferior_data *data = get_ada_inferior_data (current_inferior ());
+
+ gdb_assert (data->exception_info != NULL);
switch (ex)
{
case ex_catch_exception:
- return (exception_info->catch_exception_sym);
+ return (data->exception_info->catch_exception_sym);
break;
case ex_catch_exception_unhandled:
- return (exception_info->catch_exception_unhandled_sym);
+ return (data->exception_info->catch_exception_unhandled_sym);
break;
case ex_catch_assert:
- return (exception_info->catch_assert_sym);
+ return (data->exception_info->catch_assert_sym);
break;
default:
internal_error (__FILE__, __LINE__,
{
const char *sym_name;
struct symbol *sym;
- struct symtab_and_line sal;
/* First, find out which exception support info to use. */
ada_exception_support_info_sniffer ();
/* Then lookup the function on which we will break in order to catch
the Ada exceptions requested by the user. */
-
sym_name = ada_exception_sym_name (ex);
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 (_("Unable to break on '%s' in this configuration."), sym_name);
-
- /* Make sure that the symbol we found corresponds to a function. */
- if (SYMBOL_CLASS (sym) != LOC_BLOCK)
- error (_("Symbol \"%s\" is not a function (class = %d)"),
- sym_name, SYMBOL_CLASS (sym));
+ /* We can assume that SYM is not NULL at this stage. If the symbol
+ did not exist, ada_exception_support_info_sniffer would have
+ raised an exception.
- sal = find_function_start_sal (sym, 1);
+ Also, ada_exception_support_info_sniffer should have already
+ verified that SYM is a function symbol. */
+ gdb_assert (sym != NULL);
+ gdb_assert (SYMBOL_CLASS (sym) == LOC_BLOCK);
/* Set ADDR_STRING. */
-
*addr_string = xstrdup (sym_name);
/* Set OPS. */
*ops = ada_exception_breakpoint_ops (ex);
- return sal;
+ return find_function_start_sal (sym, 1);
}
/* Parse the arguments (ARGS) of the "catch exception" command.
ops, tempflag, from_tty);
c->excep_string = excep_string;
create_excep_cond_exprs (c);
- install_breakpoint (0, &c->base);
+ install_breakpoint (0, &c->base, 1);
}
/* Implement the "catch exception" command. */
if (args != NULL)
{
- while (isspace (*args))
- args++;
+ args = skip_spaces (args);
if (*args != '\0')
error (_("Junk at end of arguments."));
}
ada_print_array_index,
default_pass_by_reference,
c_get_string,
+ compare_names,
+ ada_iterate_over_symbols,
LANG_MAGIC
};
(256, htab_hash_string, (int (*)(const void *, const void *)) streq,
NULL, xcalloc, xfree);
- observer_attach_executable_changed (ada_executable_changed_observer);
-
/* Setup per-inferior data. */
observer_attach_inferior_exit (ada_inferior_exit);
ada_inferior_data