+/* Objects of this type are stored in a hash table and a vector when
+ printing the vtables for a class. */
+
+struct value_and_voffset
+{
+ /* The value representing the object. */
+ struct value *value;
+
+ /* The maximum vtable offset we've found for any object at this
+ offset in the outermost object. */
+ int max_voffset;
+};
+
+/* Hash function for value_and_voffset. */
+
+static hashval_t
+hash_value_and_voffset (const void *p)
+{
+ const struct value_and_voffset *o = (const struct value_and_voffset *) p;
+
+ return value_address (o->value) + value_embedded_offset (o->value);
+}
+
+/* Equality function for value_and_voffset. */
+
+static int
+eq_value_and_voffset (const void *a, const void *b)
+{
+ const struct value_and_voffset *ova = (const struct value_and_voffset *) a;
+ const struct value_and_voffset *ovb = (const struct value_and_voffset *) b;
+
+ return (value_address (ova->value) + value_embedded_offset (ova->value)
+ == value_address (ovb->value) + value_embedded_offset (ovb->value));
+}
+
+/* Comparison function for value_and_voffset. */
+
+static bool
+compare_value_and_voffset (const struct value_and_voffset *va,
+ const struct value_and_voffset *vb)
+{
+ CORE_ADDR addra = (value_address (va->value)
+ + value_embedded_offset (va->value));
+ CORE_ADDR addrb = (value_address (vb->value)
+ + value_embedded_offset (vb->value));
+
+ return addra < addrb;
+}
+
+/* A helper function used when printing vtables. This determines the
+ key (most derived) sub-object at each address and also computes the
+ maximum vtable offset seen for the corresponding vtable. Updates
+ OFFSET_HASH and OFFSET_VEC with a new value_and_voffset object, if
+ needed. VALUE is the object to examine. */
+
+static void
+compute_vtable_size (htab_t offset_hash,
+ std::vector<value_and_voffset *> *offset_vec,
+ struct value *value)
+{
+ int i;
+ struct type *type = check_typedef (value_type (value));
+ void **slot;
+ struct value_and_voffset search_vo, *current_vo;
+
+ gdb_assert (TYPE_CODE (type) == TYPE_CODE_STRUCT);
+
+ /* If the object is not dynamic, then we are done; as it cannot have
+ dynamic base types either. */
+ if (!gnuv3_dynamic_class (type))
+ return;
+
+ /* Update the hash and the vec, if needed. */
+ search_vo.value = value;
+ slot = htab_find_slot (offset_hash, &search_vo, INSERT);
+ if (*slot)
+ current_vo = (struct value_and_voffset *) *slot;
+ else
+ {
+ current_vo = XNEW (struct value_and_voffset);
+ current_vo->value = value;
+ current_vo->max_voffset = -1;
+ *slot = current_vo;
+ offset_vec->push_back (current_vo);
+ }
+
+ /* Update the value_and_voffset object with the highest vtable
+ offset from this class. */
+ for (i = 0; i < TYPE_NFN_FIELDS (type); ++i)
+ {
+ int j;
+ struct fn_field *fn = TYPE_FN_FIELDLIST1 (type, i);
+
+ for (j = 0; j < TYPE_FN_FIELDLIST_LENGTH (type, i); ++j)
+ {
+ if (TYPE_FN_FIELD_VIRTUAL_P (fn, j))
+ {
+ int voffset = TYPE_FN_FIELD_VOFFSET (fn, j);
+
+ if (voffset > current_vo->max_voffset)
+ current_vo->max_voffset = voffset;
+ }
+ }
+ }
+
+ /* Recurse into base classes. */
+ for (i = 0; i < TYPE_N_BASECLASSES (type); ++i)
+ compute_vtable_size (offset_hash, offset_vec, value_field (value, i));
+}
+
+/* Helper for gnuv3_print_vtable that prints a single vtable. */
+
+static void
+print_one_vtable (struct gdbarch *gdbarch, struct value *value,
+ int max_voffset,
+ struct value_print_options *opts)
+{
+ int i;
+ struct type *type = check_typedef (value_type (value));
+ struct value *vtable;
+ CORE_ADDR vt_addr;
+
+ vtable = gnuv3_get_vtable (gdbarch, type,
+ value_address (value)
+ + value_embedded_offset (value));
+ vt_addr = value_address (value_field (vtable,
+ vtable_field_virtual_functions));
+
+ printf_filtered (_("vtable for '%s' @ %s (subobject @ %s):\n"),
+ TYPE_SAFE_NAME (type),
+ paddress (gdbarch, vt_addr),
+ paddress (gdbarch, (value_address (value)
+ + value_embedded_offset (value))));
+
+ for (i = 0; i <= max_voffset; ++i)
+ {
+ /* Initialize it just to avoid a GCC false warning. */
+ CORE_ADDR addr = 0;
+ int got_error = 0;
+ struct value *vfn;
+
+ printf_filtered ("[%d]: ", i);
+
+ vfn = value_subscript (value_field (vtable,
+ vtable_field_virtual_functions),
+ i);
+
+ if (gdbarch_vtable_function_descriptors (gdbarch))
+ vfn = value_addr (vfn);
+
+ try
+ {
+ addr = value_as_address (vfn);
+ }
+ catch (const gdb_exception_error &ex)
+ {
+ fprintf_styled (gdb_stdout, metadata_style.style (),
+ _("<error: %s>"), ex.what ());
+ got_error = 1;
+ }
+
+ if (!got_error)
+ print_function_pointer_address (opts, gdbarch, addr, gdb_stdout);
+ printf_filtered ("\n");
+ }
+}
+
+/* Implementation of the print_vtable method. */
+
+static void
+gnuv3_print_vtable (struct value *value)
+{
+ struct gdbarch *gdbarch;
+ struct type *type;
+ struct value *vtable;
+ struct value_print_options opts;
+ int count;
+
+ value = coerce_ref (value);
+ type = check_typedef (value_type (value));
+ if (TYPE_CODE (type) == TYPE_CODE_PTR)
+ {
+ value = value_ind (value);
+ type = check_typedef (value_type (value));
+ }
+
+ get_user_print_options (&opts);
+
+ /* Respect 'set print object'. */
+ if (opts.objectprint)
+ {
+ value = value_full_object (value, NULL, 0, 0, 0);
+ type = check_typedef (value_type (value));
+ }
+
+ gdbarch = get_type_arch (type);
+
+ vtable = NULL;
+ if (TYPE_CODE (type) == TYPE_CODE_STRUCT)
+ vtable = gnuv3_get_vtable (gdbarch, type,
+ value_as_address (value_addr (value)));
+
+ if (!vtable)
+ {
+ printf_filtered (_("This object does not have a virtual function table\n"));
+ return;
+ }
+
+ htab_up offset_hash (htab_create_alloc (1, hash_value_and_voffset,
+ eq_value_and_voffset,
+ xfree, xcalloc, xfree));
+ std::vector<value_and_voffset *> result_vec;
+
+ compute_vtable_size (offset_hash.get (), &result_vec, value);
+ std::sort (result_vec.begin (), result_vec.end (),
+ compare_value_and_voffset);
+
+ count = 0;
+ for (value_and_voffset *iter : result_vec)
+ {
+ if (iter->max_voffset >= 0)
+ {
+ if (count > 0)
+ printf_filtered ("\n");
+ print_one_vtable (gdbarch, iter->value, iter->max_voffset, &opts);
+ ++count;
+ }
+ }
+}
+
+/* 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 = XCNEWVEC (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 * TARGET_CHAR_BIT, NULL);
+ TYPE_NFIELDS (t) = field - field_list;
+ TYPE_FIELDS (t) = field_list;
+ TYPE_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).symbol;
+ if (typeinfo == NULL)
+ typeinfo_type
+ = (struct 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 value *result;
+ std::string type_name;
+ gdb::unique_xmalloc_ptr<char> 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);
+
+ type_name = type_to_string (type);
+ if (type_name.empty ())
+ error (_("cannot find typeinfo for unnamed type"));
+
+ /* 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 (type_name.c_str ());
+ const char *name = (canonical == nullptr
+ ? type_name.c_str ()
+ : canonical.get ());
+
+ 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_STRUCT
+ && 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'"),
+ name);
+ typeinfo_value = value_field (vtable, vtable_field_type_info);
+ result = value_ind (value_cast (make_pointer_type (typeinfo_type, NULL),
+ typeinfo_value));
+ }
+ else
+ {
+ std::string sym_name = std::string ("typeinfo for ") + name;
+ bound_minimal_symbol minsym
+ = lookup_minimal_symbol (sym_name.c_str (), NULL, NULL);
+
+ if (minsym.minsym == NULL)
+ error (_("could not find typeinfo symbol for '%s'"), name);
+
+ result = value_at_lazy (typeinfo_type, BMSYMBOL_VALUE_ADDRESS (minsym));
+ }
+
+ return result;
+}
+
+/* Implement the 'get_typename_from_type_info' method. */
+
+static std::string
+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 = typeinfo_sym.minsym->demangled_name ();
+ if (symname == NULL || strncmp (symname, TYPEINFO_PREFIX,
+ TYPEINFO_PREFIX_LEN))
+ error (_("typeinfo symbol '%s' has unexpected name"),
+ typeinfo_sym.minsym->linkage_name ());
+ class_name = symname + TYPEINFO_PREFIX_LEN;
+
+ /* Strip off @plt and version suffixes. */
+ atsign = strchr (class_name, '@');
+ if (atsign != NULL)
+ return std::string (class_name, atsign - class_name);
+ return class_name;
+}
+
+/* Implement the 'get_type_from_type_info' method. */
+
+static struct type *
+gnuv3_get_type_from_type_info (struct value *type_info_ptr)
+{
+ /* 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. */
+ std::string type_name = gnuv3_get_typename_from_type_info (type_info_ptr);
+ expression_up expr (parse_expression (type_name.c_str ()));
+ struct value *type_val = evaluate_type (expr.get ());
+ return value_type (type_val);
+}
+