| Index: gdb/gnu-v3-abi.c
|
| diff --git a/gdb/gnu-v3-abi.c b/gdb/gnu-v3-abi.c
|
| index 3a83e2d48b5424588cfe55fdae81aeaf63bb6440..e5b4fc80d5c22684bd57cb78059d3b2745b7eedf 100644
|
| --- a/gdb/gnu-v3-abi.c
|
| +++ b/gdb/gnu-v3-abi.c
|
| @@ -1,7 +1,7 @@
|
| /* Abstraction of GNU v3 abi.
|
| Contributed by Jim Blandy <jimb@redhat.com>
|
|
|
| - Copyright (C) 2001-2003, 2005-2012 Free Software Foundation, Inc.
|
| + Copyright (C) 2001-2013 Free Software Foundation, Inc.
|
|
|
| This file is part of GDB.
|
|
|
| @@ -27,12 +27,19 @@
|
| #include "valprint.h"
|
| #include "c-lang.h"
|
| #include "exceptions.h"
|
| +#include "typeprint.h"
|
|
|
| #include "gdb_assert.h"
|
| -#include "gdb_string.h"
|
| +#include <string.h>
|
|
|
| static struct cp_abi_ops gnu_v3_abi_ops;
|
|
|
| +/* A gdbarch key for std::type_info, in the event that it can't be
|
| + found in the debug info. */
|
| +
|
| +static struct gdbarch_data *std_type_info_gdbarch_data;
|
| +
|
| +
|
| static int
|
| gnuv3_is_vtable_name (const char *name)
|
| {
|
| @@ -282,6 +289,7 @@ gnuv3_rtti_type (struct value *value,
|
| const char *class_name;
|
| struct type *run_time_type;
|
| LONGEST offset_to_top;
|
| + char *atsign;
|
|
|
| /* We only have RTTI for class objects. */
|
| if (TYPE_CODE (values_type) != TYPE_CODE_CLASS)
|
| @@ -305,7 +313,7 @@ gnuv3_rtti_type (struct value *value,
|
| /* Find the linker symbol for this vtable. */
|
| vtable_symbol
|
| = lookup_minimal_symbol_by_pc (value_address (vtable)
|
| - + value_embedded_offset (vtable));
|
| + + value_embedded_offset (vtable)).minsym;
|
| if (! vtable_symbol)
|
| return NULL;
|
|
|
| @@ -326,6 +334,18 @@ gnuv3_rtti_type (struct value *value,
|
| }
|
| class_name = vtable_symbol_name + 11;
|
|
|
| + /* Strip off @plt and version suffixes. */
|
| + atsign = strchr (class_name, '@');
|
| + if (atsign != NULL)
|
| + {
|
| + char *copy;
|
| +
|
| + copy = alloca (atsign - class_name + 1);
|
| + memcpy (copy, class_name, atsign - class_name);
|
| + copy[atsign - class_name] = '\0';
|
| + class_name = copy;
|
| + }
|
| +
|
| /* Try to look up the class name as a type name. */
|
| /* FIXME: chastain/2003-11-26: block=NULL is bogus. See pr gdb/1465. */
|
| run_time_type = cp_lookup_rtti_type (class_name, NULL);
|
| @@ -592,8 +612,8 @@ gnuv3_print_method_ptr (const gdb_byte *contents,
|
| possible paths to the method based on the adjustment. */
|
| if (physname)
|
| {
|
| - char *demangled_name = cplus_demangle (physname,
|
| - DMGL_ANSI | DMGL_PARAMS);
|
| + char *demangled_name = gdb_demangle (physname,
|
| + DMGL_ANSI | DMGL_PARAMS);
|
|
|
| fprintf_filtered (stream, "&virtual ");
|
| if (demangled_name == NULL)
|
| @@ -610,7 +630,7 @@ gnuv3_print_method_ptr (const gdb_byte *contents,
|
| {
|
| /* Found a non-virtual function: print out the type. */
|
| fputs_filtered ("(", stream);
|
| - c_print_type (type, "", stream, -1, 0);
|
| + c_print_type (type, "", stream, -1, 0, &type_print_raw_options);
|
| fputs_filtered (") ", stream);
|
| }
|
|
|
| @@ -804,7 +824,6 @@ compute_vtable_size (htab_t offset_hash,
|
| struct type *type = check_typedef (value_type (value));
|
| void **slot;
|
| struct value_and_voffset search_vo, *current_vo;
|
| - CORE_ADDR addr = value_address (value) + value_embedded_offset (value);
|
|
|
| /* If the object is not dynamic, then we are done; as it cannot have
|
| dynamic base types either. */
|
| @@ -971,13 +990,224 @@ gnuv3_print_vtable (struct value *value)
|
| do_cleanups (cleanup);
|
| }
|
|
|
| +/* Return a GDB type representing `struct std::type_info', laid out
|
| + appropriately for ARCH.
|
| +
|
| + We use this function as the gdbarch per-architecture data
|
| + initialization function. */
|
| +
|
| +static void *
|
| +build_std_type_info_type (struct gdbarch *arch)
|
| +{
|
| + struct type *t;
|
| + struct field *field_list, *field;
|
| + int offset;
|
| + struct type *void_ptr_type
|
| + = builtin_type (arch)->builtin_data_ptr;
|
| + struct type *char_type
|
| + = builtin_type (arch)->builtin_char;
|
| + struct type *char_ptr_type
|
| + = make_pointer_type (make_cv_type (1, 0, char_type, NULL), NULL);
|
| +
|
| + field_list = xmalloc (sizeof (struct field [2]));
|
| + memset (field_list, 0, sizeof (struct field [2]));
|
| + field = &field_list[0];
|
| + offset = 0;
|
| +
|
| + /* The vtable. */
|
| + FIELD_NAME (*field) = "_vptr.type_info";
|
| + FIELD_TYPE (*field) = void_ptr_type;
|
| + SET_FIELD_BITPOS (*field, offset * TARGET_CHAR_BIT);
|
| + offset += TYPE_LENGTH (FIELD_TYPE (*field));
|
| + field++;
|
| +
|
| + /* The name. */
|
| + FIELD_NAME (*field) = "__name";
|
| + FIELD_TYPE (*field) = char_ptr_type;
|
| + SET_FIELD_BITPOS (*field, offset * TARGET_CHAR_BIT);
|
| + offset += TYPE_LENGTH (FIELD_TYPE (*field));
|
| + field++;
|
| +
|
| + gdb_assert (field == (field_list + 2));
|
| +
|
| + t = arch_type (arch, TYPE_CODE_STRUCT, offset, NULL);
|
| + TYPE_NFIELDS (t) = field - field_list;
|
| + TYPE_FIELDS (t) = field_list;
|
| + TYPE_TAG_NAME (t) = "gdb_gnu_v3_type_info";
|
| + INIT_CPLUS_SPECIFIC (t);
|
| +
|
| + return t;
|
| +}
|
| +
|
| +/* Implement the 'get_typeid_type' method. */
|
| +
|
| +static struct type *
|
| +gnuv3_get_typeid_type (struct gdbarch *gdbarch)
|
| +{
|
| + struct symbol *typeinfo;
|
| + struct type *typeinfo_type;
|
| +
|
| + typeinfo = lookup_symbol ("std::type_info", NULL, STRUCT_DOMAIN, NULL);
|
| + if (typeinfo == NULL)
|
| + typeinfo_type = gdbarch_data (gdbarch, std_type_info_gdbarch_data);
|
| + else
|
| + typeinfo_type = SYMBOL_TYPE (typeinfo);
|
| +
|
| + return typeinfo_type;
|
| +}
|
| +
|
| +/* Implement the 'get_typeid' method. */
|
| +
|
| +static struct value *
|
| +gnuv3_get_typeid (struct value *value)
|
| +{
|
| + struct type *typeinfo_type;
|
| + struct type *type;
|
| + struct gdbarch *gdbarch;
|
| + struct cleanup *cleanup;
|
| + struct value *result;
|
| + char *typename, *canonical;
|
| +
|
| + /* We have to handle values a bit trickily here, to allow this code
|
| + to work properly with non_lvalue values that are really just
|
| + disguised types. */
|
| + if (value_lval_const (value) == lval_memory)
|
| + value = coerce_ref (value);
|
| +
|
| + type = check_typedef (value_type (value));
|
| +
|
| + /* In the non_lvalue case, a reference might have slipped through
|
| + here. */
|
| + if (TYPE_CODE (type) == TYPE_CODE_REF)
|
| + type = check_typedef (TYPE_TARGET_TYPE (type));
|
| +
|
| + /* Ignore top-level cv-qualifiers. */
|
| + type = make_cv_type (0, 0, type, NULL);
|
| + gdbarch = get_type_arch (type);
|
| +
|
| + typename = type_to_string (type);
|
| + if (typename == NULL)
|
| + error (_("cannot find typeinfo for unnamed type"));
|
| + cleanup = make_cleanup (xfree, typename);
|
| +
|
| + /* We need to canonicalize the type name here, because we do lookups
|
| + using the demangled name, and so we must match the format it
|
| + uses. E.g., GDB tends to use "const char *" as a type name, but
|
| + the demangler uses "char const *". */
|
| + canonical = cp_canonicalize_string (typename);
|
| + if (canonical != NULL)
|
| + {
|
| + make_cleanup (xfree, canonical);
|
| + typename = canonical;
|
| + }
|
| +
|
| + typeinfo_type = gnuv3_get_typeid_type (gdbarch);
|
| +
|
| + /* We check for lval_memory because in the "typeid (type-id)" case,
|
| + the type is passed via a not_lval value object. */
|
| + if (TYPE_CODE (type) == TYPE_CODE_CLASS
|
| + && value_lval_const (value) == lval_memory
|
| + && gnuv3_dynamic_class (type))
|
| + {
|
| + struct value *vtable, *typeinfo_value;
|
| + CORE_ADDR address = value_address (value) + value_embedded_offset (value);
|
| +
|
| + vtable = gnuv3_get_vtable (gdbarch, type, address);
|
| + if (vtable == NULL)
|
| + error (_("cannot find typeinfo for object of type '%s'"), typename);
|
| + typeinfo_value = value_field (vtable, vtable_field_type_info);
|
| + result = value_ind (value_cast (make_pointer_type (typeinfo_type, NULL),
|
| + typeinfo_value));
|
| + }
|
| + else
|
| + {
|
| + char *sym_name;
|
| + struct minimal_symbol *minsym;
|
| +
|
| + sym_name = concat ("typeinfo for ", typename, (char *) NULL);
|
| + make_cleanup (xfree, sym_name);
|
| + minsym = lookup_minimal_symbol (sym_name, NULL, NULL);
|
| +
|
| + if (minsym == NULL)
|
| + error (_("could not find typeinfo symbol for '%s'"), typename);
|
| +
|
| + result = value_at_lazy (typeinfo_type, SYMBOL_VALUE_ADDRESS (minsym));
|
| + }
|
| +
|
| + do_cleanups (cleanup);
|
| + return result;
|
| +}
|
| +
|
| +/* Implement the 'get_typename_from_type_info' method. */
|
| +
|
| +static char *
|
| +gnuv3_get_typename_from_type_info (struct value *type_info_ptr)
|
| +{
|
| + struct gdbarch *gdbarch = get_type_arch (value_type (type_info_ptr));
|
| + struct bound_minimal_symbol typeinfo_sym;
|
| + CORE_ADDR addr;
|
| + const char *symname;
|
| + const char *class_name;
|
| + const char *atsign;
|
| +
|
| + addr = value_as_address (type_info_ptr);
|
| + typeinfo_sym = lookup_minimal_symbol_by_pc (addr);
|
| + if (typeinfo_sym.minsym == NULL)
|
| + error (_("could not find minimal symbol for typeinfo address %s"),
|
| + paddress (gdbarch, addr));
|
| +
|
| +#define TYPEINFO_PREFIX "typeinfo for "
|
| +#define TYPEINFO_PREFIX_LEN (sizeof (TYPEINFO_PREFIX) - 1)
|
| + symname = SYMBOL_DEMANGLED_NAME (typeinfo_sym.minsym);
|
| + if (symname == NULL || strncmp (symname, TYPEINFO_PREFIX,
|
| + TYPEINFO_PREFIX_LEN))
|
| + error (_("typeinfo symbol '%s' has unexpected name"),
|
| + SYMBOL_LINKAGE_NAME (typeinfo_sym.minsym));
|
| + class_name = symname + TYPEINFO_PREFIX_LEN;
|
| +
|
| + /* Strip off @plt and version suffixes. */
|
| + atsign = strchr (class_name, '@');
|
| + if (atsign != NULL)
|
| + return savestring (class_name, atsign - class_name);
|
| + return xstrdup (class_name);
|
| +}
|
| +
|
| +/* Implement the 'get_type_from_type_info' method. */
|
| +
|
| +static struct type *
|
| +gnuv3_get_type_from_type_info (struct value *type_info_ptr)
|
| +{
|
| + char *typename;
|
| + struct cleanup *cleanup;
|
| + struct value *type_val;
|
| + struct expression *expr;
|
| + struct type *result;
|
| +
|
| + typename = gnuv3_get_typename_from_type_info (type_info_ptr);
|
| + cleanup = make_cleanup (xfree, typename);
|
| +
|
| + /* We have to parse the type name, since in general there is not a
|
| + symbol for a type. This is somewhat bogus since there may be a
|
| + mis-parse. Another approach might be to re-use the demangler's
|
| + internal form to reconstruct the type somehow. */
|
| +
|
| + expr = parse_expression (typename);
|
| + make_cleanup (xfree, expr);
|
| +
|
| + type_val = evaluate_type (expr);
|
| + result = value_type (type_val);
|
| +
|
| + do_cleanups (cleanup);
|
| + return result;
|
| +}
|
| +
|
| /* Determine if we are currently in a C++ thunk. If so, get the address
|
| of the routine we are thunking to and continue to there instead. */
|
|
|
| static CORE_ADDR
|
| gnuv3_skip_trampoline (struct frame_info *frame, CORE_ADDR stop_pc)
|
| {
|
| - CORE_ADDR real_stop_pc, method_stop_pc;
|
| + CORE_ADDR real_stop_pc, method_stop_pc, func_addr;
|
| struct gdbarch *gdbarch = get_frame_arch (frame);
|
| struct minimal_symbol *thunk_sym, *fn_sym;
|
| struct obj_section *section;
|
| @@ -988,7 +1218,7 @@ gnuv3_skip_trampoline (struct frame_info *frame, CORE_ADDR stop_pc)
|
| real_stop_pc = stop_pc;
|
|
|
| /* Find the linker symbol for this potential thunk. */
|
| - thunk_sym = lookup_minimal_symbol_by_pc (real_stop_pc);
|
| + thunk_sym = lookup_minimal_symbol_by_pc (real_stop_pc).minsym;
|
| section = find_pc_section (real_stop_pc);
|
| if (thunk_sym == NULL || section == NULL)
|
| return 0;
|
| @@ -1006,6 +1236,16 @@ gnuv3_skip_trampoline (struct frame_info *frame, CORE_ADDR stop_pc)
|
| return 0;
|
|
|
| method_stop_pc = SYMBOL_VALUE_ADDRESS (fn_sym);
|
| +
|
| + /* Some targets have minimal symbols pointing to function descriptors
|
| + (powerpc 64 for example). Make sure to retrieve the address
|
| + of the real function from the function descriptor before passing on
|
| + the address to other layers of GDB. */
|
| + func_addr = gdbarch_convert_from_func_ptr_addr (gdbarch, method_stop_pc,
|
| + ¤t_target);
|
| + if (func_addr != 0)
|
| + method_stop_pc = func_addr;
|
| +
|
| real_stop_pc = gdbarch_skip_trampoline_code
|
| (gdbarch, frame, method_stop_pc);
|
| if (real_stop_pc == 0)
|
| @@ -1070,7 +1310,8 @@ gnuv3_pass_by_reference (struct type *type)
|
| with the mangled name. We don't have a convenient function
|
| to strip off both leading scope qualifiers and trailing
|
| template arguments yet. */
|
| - if (!is_constructor_name (TYPE_FN_FIELD_PHYSNAME (fn, fieldelem)))
|
| + if (!is_constructor_name (TYPE_FN_FIELD_PHYSNAME (fn, fieldelem))
|
| + && !TYPE_FN_FIELD_CONSTRUCTOR (fn, fieldelem))
|
| continue;
|
|
|
| /* If this method takes two arguments, and the second argument is
|
| @@ -1102,6 +1343,8 @@ init_gnuv3_ops (void)
|
| {
|
| vtable_type_gdbarch_data
|
| = gdbarch_data_register_post_init (build_gdb_vtable_type);
|
| + std_type_info_gdbarch_data
|
| + = gdbarch_data_register_post_init (build_std_type_info_type);
|
|
|
| gnu_v3_abi_ops.shortname = "gnu-v3";
|
| gnu_v3_abi_ops.longname = "GNU G++ Version 3 ABI";
|
| @@ -1120,6 +1363,11 @@ init_gnuv3_ops (void)
|
| gnu_v3_abi_ops.make_method_ptr = gnuv3_make_method_ptr;
|
| gnu_v3_abi_ops.method_ptr_to_value = gnuv3_method_ptr_to_value;
|
| gnu_v3_abi_ops.print_vtable = gnuv3_print_vtable;
|
| + gnu_v3_abi_ops.get_typeid = gnuv3_get_typeid;
|
| + gnu_v3_abi_ops.get_typeid_type = gnuv3_get_typeid_type;
|
| + gnu_v3_abi_ops.get_type_from_type_info = gnuv3_get_type_from_type_info;
|
| + gnu_v3_abi_ops.get_typename_from_type_info
|
| + = gnuv3_get_typename_from_type_info;
|
| gnu_v3_abi_ops.skip_trampoline = gnuv3_skip_trampoline;
|
| gnu_v3_abi_ops.pass_by_reference = gnuv3_pass_by_reference;
|
| }
|
| @@ -1132,4 +1380,5 @@ _initialize_gnu_v3_abi (void)
|
| init_gnuv3_ops ();
|
|
|
| register_cp_abi (&gnu_v3_abi_ops);
|
| + set_cp_abi_as_auto_default (gnu_v3_abi_ops.shortname);
|
| }
|
|
|