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); |
} |