]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blobdiff - gdb/gnu-v3-abi.c
PR c++/15176:
[thirdparty/binutils-gdb.git] / gdb / gnu-v3-abi.c
index 0ba6ab54f527002d7b27b1d1b178803fa3ebfa33..fa12879b7866d17c21046fc2edf578eedbedcc20 100644 (file)
@@ -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.
 
 #include "valprint.h"
 #include "c-lang.h"
 #include "exceptions.h"
+#include "typeprint.h"
 
 #include "gdb_assert.h"
 #include "gdb_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)
 {
@@ -130,28 +137,28 @@ build_gdb_vtable_type (struct gdbarch *arch)
   /* ptrdiff_t vcall_and_vbase_offsets[0]; */
   FIELD_NAME (*field) = "vcall_and_vbase_offsets";
   FIELD_TYPE (*field) = lookup_array_range_type (ptrdiff_type, 0, -1);
-  FIELD_BITPOS (*field) = offset * TARGET_CHAR_BIT;
+  SET_FIELD_BITPOS (*field, offset * TARGET_CHAR_BIT);
   offset += TYPE_LENGTH (FIELD_TYPE (*field));
   field++;
 
   /* ptrdiff_t offset_to_top; */
   FIELD_NAME (*field) = "offset_to_top";
   FIELD_TYPE (*field) = ptrdiff_type;
-  FIELD_BITPOS (*field) = offset * TARGET_CHAR_BIT;
+  SET_FIELD_BITPOS (*field, offset * TARGET_CHAR_BIT);
   offset += TYPE_LENGTH (FIELD_TYPE (*field));
   field++;
 
   /* void *type_info; */
   FIELD_NAME (*field) = "type_info";
   FIELD_TYPE (*field) = void_ptr_type;
-  FIELD_BITPOS (*field) = offset * TARGET_CHAR_BIT;
+  SET_FIELD_BITPOS (*field, offset * TARGET_CHAR_BIT);
   offset += TYPE_LENGTH (FIELD_TYPE (*field));
   field++;
 
   /* void (*virtual_functions[0]) (); */
   FIELD_NAME (*field) = "virtual_functions";
   FIELD_TYPE (*field) = lookup_array_range_type (ptr_to_void_fn_type, 0, -1);
-  FIELD_BITPOS (*field) = offset * TARGET_CHAR_BIT;
+  SET_FIELD_BITPOS (*field, offset * TARGET_CHAR_BIT);
   offset += TYPE_LENGTH (FIELD_TYPE (*field));
   field++;
 
@@ -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);
@@ -430,8 +450,9 @@ gnuv3_baseclass_offset (struct type *type, int index,
   ptr_type = builtin_type (gdbarch)->builtin_data_ptr;
 
   /* If it isn't a virtual base, this is easy.  The offset is in the
-     type definition.  */
-  if (!BASETYPE_VIA_VIRTUAL (type, index))
+     type definition.  Likewise for Java, which doesn't really have
+     virtual inheritance in the C++ sense.  */
+  if (!BASETYPE_VIA_VIRTUAL (type, index) || TYPE_CPLUS_REALLY_JAVA (type))
     return TYPE_BASECLASS_BITPOS (type, index) / 8;
 
   /* To access a virtual base, we need to use the vbase offset stored in
@@ -591,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)
@@ -609,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);
     }
 
@@ -620,7 +641,12 @@ gnuv3_print_method_ptr (const gdb_byte *contents,
       print_longest (stream, 'd', 1, ptr_value);
     }
   else
-    print_address_demangle (gdbarch, ptr_value, stream, demangle);
+    {
+      struct value_print_options opts;
+
+      get_user_print_options (&opts);
+      print_address_demangle (&opts, gdbarch, ptr_value, stream, demangle);
+    }
 
   if (adjustment)
     {
@@ -798,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.  */
@@ -869,8 +894,9 @@ print_one_vtable (struct gdbarch *gdbarch, struct value *value,
 
   for (i = 0; i <= max_voffset; ++i)
     {
+      /* Initialize it just to avoid a GCC false warning.  */
+      CORE_ADDR addr = 0;
       struct value *vfn;
-      CORE_ADDR addr;
       volatile struct gdb_exception ex;
 
       printf_filtered ("[%d]: ", i);
@@ -889,8 +915,7 @@ print_one_vtable (struct gdbarch *gdbarch, struct value *value,
       if (ex.reason < 0)
        printf_filtered (_("<error: %s>"), ex.message);
       else
-       print_function_pointer_address (gdbarch, addr, gdb_stdout,
-                                       opts->addressprint);
+       print_function_pointer_address (opts, gdbarch, addr, gdb_stdout);
       printf_filtered ("\n");
     }
 }
@@ -906,7 +931,7 @@ gnuv3_print_vtable (struct value *value)
   struct value_print_options opts;
   htab_t offset_hash;
   struct cleanup *cleanup;
-  VEC (value_and_voffset_p) *result_vec;
+  VEC (value_and_voffset_p) *result_vec = NULL;
   struct value_and_voffset *iter;
   int i, count;
 
@@ -965,6 +990,217 @@ 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;
+}
+
+/* Get the type name given a type_info object.  */
+
+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.  */
 
@@ -982,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;
@@ -1064,7 +1300,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
@@ -1096,6 +1333,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";
@@ -1114,6 +1353,9 @@ 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.skip_trampoline = gnuv3_skip_trampoline;
   gnu_v3_abi_ops.pass_by_reference = gnuv3_pass_by_reference;
 }
@@ -1126,4 +1368,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);
 }