| Index: gdb/gnu-v3-abi.c
|
| diff --git a/gdb/gnu-v3-abi.c b/gdb/gnu-v3-abi.c
|
| index a461bb0e674a0dfe2c599c693d33cc390751f805..3a83e2d48b5424588cfe55fdae81aeaf63bb6440 100644
|
| --- a/gdb/gnu-v3-abi.c
|
| +++ b/gdb/gnu-v3-abi.c
|
| @@ -26,6 +26,7 @@
|
| #include "objfiles.h"
|
| #include "valprint.h"
|
| #include "c-lang.h"
|
| +#include "exceptions.h"
|
|
|
| #include "gdb_assert.h"
|
| #include "gdb_string.h"
|
| @@ -129,28 +130,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++;
|
|
|
| @@ -429,8 +430,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
|
| @@ -619,7 +621,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)
|
| {
|
| @@ -725,6 +732,245 @@ gnuv3_method_ptr_to_value (struct value **this_p, struct value *method_ptr)
|
| return value_from_pointer (lookup_pointer_type (method_type), ptr_value);
|
| }
|
|
|
| +/* 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;
|
| +};
|
| +
|
| +typedef struct value_and_voffset *value_and_voffset_p;
|
| +DEF_VEC_P (value_and_voffset_p);
|
| +
|
| +/* Hash function for value_and_voffset. */
|
| +
|
| +static hashval_t
|
| +hash_value_and_voffset (const void *p)
|
| +{
|
| + const struct value_and_voffset *o = 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 = a;
|
| + const struct value_and_voffset *ovb = b;
|
| +
|
| + return (value_address (ova->value) + value_embedded_offset (ova->value)
|
| + == value_address (ovb->value) + value_embedded_offset (ovb->value));
|
| +}
|
| +
|
| +/* qsort comparison function for value_and_voffset. */
|
| +
|
| +static int
|
| +compare_value_and_voffset (const void *a, const void *b)
|
| +{
|
| + const struct value_and_voffset * const *ova = a;
|
| + CORE_ADDR addra = (value_address ((*ova)->value)
|
| + + value_embedded_offset ((*ova)->value));
|
| + const struct value_and_voffset * const *ovb = b;
|
| + CORE_ADDR addrb = (value_address ((*ovb)->value)
|
| + + value_embedded_offset ((*ovb)->value));
|
| +
|
| + if (addra < addrb)
|
| + return -1;
|
| + if (addra > addrb)
|
| + return 1;
|
| + return 0;
|
| +}
|
| +
|
| +/* 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,
|
| + VEC (value_and_voffset_p) **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;
|
| + 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. */
|
| + 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 = *slot;
|
| + else
|
| + {
|
| + current_vo = XNEW (struct value_and_voffset);
|
| + current_vo->value = value;
|
| + current_vo->max_voffset = -1;
|
| + *slot = current_vo;
|
| + VEC_safe_push (value_and_voffset_p, *offset_vec, 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;
|
| + struct value *vfn;
|
| + volatile struct gdb_exception ex;
|
| +
|
| + 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_CATCH (ex, RETURN_MASK_ERROR)
|
| + {
|
| + addr = value_as_address (vfn);
|
| + }
|
| + if (ex.reason < 0)
|
| + printf_filtered (_("<error: %s>"), ex.message);
|
| + else
|
| + 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;
|
| + htab_t offset_hash;
|
| + struct cleanup *cleanup;
|
| + VEC (value_and_voffset_p) *result_vec = NULL;
|
| + struct value_and_voffset *iter;
|
| + int i, 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 = 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;
|
| + }
|
| +
|
| + offset_hash = htab_create_alloc (1, hash_value_and_voffset,
|
| + eq_value_and_voffset,
|
| + xfree, xcalloc, xfree);
|
| + cleanup = make_cleanup_htab_delete (offset_hash);
|
| + make_cleanup (VEC_cleanup (value_and_voffset_p), &result_vec);
|
| +
|
| + compute_vtable_size (offset_hash, &result_vec, value);
|
| +
|
| + qsort (VEC_address (value_and_voffset_p, result_vec),
|
| + VEC_length (value_and_voffset_p, result_vec),
|
| + sizeof (value_and_voffset_p),
|
| + compare_value_and_voffset);
|
| +
|
| + count = 0;
|
| + for (i = 0; VEC_iterate (value_and_voffset_p, result_vec, i, iter); ++i)
|
| + {
|
| + if (iter->max_voffset >= 0)
|
| + {
|
| + if (count > 0)
|
| + printf_filtered ("\n");
|
| + print_one_vtable (gdbarch, iter->value, iter->max_voffset, &opts);
|
| + ++count;
|
| + }
|
| + }
|
| +
|
| + do_cleanups (cleanup);
|
| +}
|
| +
|
| /* 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. */
|
|
|
| @@ -735,7 +981,7 @@ gnuv3_skip_trampoline (struct frame_info *frame, CORE_ADDR stop_pc)
|
| struct gdbarch *gdbarch = get_frame_arch (frame);
|
| struct minimal_symbol *thunk_sym, *fn_sym;
|
| struct obj_section *section;
|
| - char *thunk_name, *fn_name;
|
| + const char *thunk_name, *fn_name;
|
|
|
| real_stop_pc = gdbarch_skip_trampoline_code (gdbarch, frame, stop_pc);
|
| if (real_stop_pc == 0)
|
| @@ -804,7 +1050,7 @@ gnuv3_pass_by_reference (struct type *type)
|
| fieldelem++)
|
| {
|
| struct fn_field *fn = TYPE_FN_FIELDLIST1 (type, fieldnum);
|
| - char *name = TYPE_FN_FIELDLIST_NAME (type, fieldnum);
|
| + const char *name = TYPE_FN_FIELDLIST_NAME (type, fieldnum);
|
| struct type *fieldtype = TYPE_FN_FIELD_TYPE (fn, fieldelem);
|
|
|
| /* If this function is marked as artificial, it is compiler-generated,
|
| @@ -873,6 +1119,7 @@ init_gnuv3_ops (void)
|
| gnu_v3_abi_ops.method_ptr_size = gnuv3_method_ptr_size;
|
| 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.skip_trampoline = gnuv3_skip_trampoline;
|
| gnu_v3_abi_ops.pass_by_reference = gnuv3_pass_by_reference;
|
| }
|
|
|