gdb/gnu-v3-abi.c - gdb
Global variables defined
Data types defined
Functions defined
Macros defined
Source code
- #include "defs.h"
- #include "value.h"
- #include "cp-abi.h"
- #include "cp-support.h"
- #include "demangle.h"
- #include "objfiles.h"
- #include "valprint.h"
- #include "c-lang.h"
- #include "typeprint.h"
- static struct cp_abi_ops gnu_v3_abi_ops;
- static struct gdbarch_data *std_type_info_gdbarch_data;
- static int
- gnuv3_is_vtable_name (const char *name)
- {
- return strncmp (name, "_ZTV", 4) == 0;
- }
- static int
- gnuv3_is_operator_name (const char *name)
- {
- return strncmp (name, "operator", 8) == 0;
- }
- static struct gdbarch_data *vtable_type_gdbarch_data;
- enum {
- vtable_field_vcall_and_vbase_offsets,
- vtable_field_offset_to_top,
- vtable_field_type_info,
- vtable_field_virtual_functions
- };
- static void *
- build_gdb_vtable_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 *ptr_to_void_fn_type
- = builtin_type (arch)->builtin_func_ptr;
-
- struct type *ptrdiff_type
- = arch_integer_type (arch, gdbarch_ptr_bit (arch), 0, "ptrdiff_t");
-
-
- field_list = xmalloc (sizeof (struct field [4]));
- memset (field_list, 0, sizeof (struct field [4]));
- field = &field_list[0];
- offset = 0;
-
- FIELD_NAME (*field) = "vcall_and_vbase_offsets";
- FIELD_TYPE (*field) = lookup_array_range_type (ptrdiff_type, 0, -1);
- SET_FIELD_BITPOS (*field, offset * TARGET_CHAR_BIT);
- offset += TYPE_LENGTH (FIELD_TYPE (*field));
- field++;
-
- FIELD_NAME (*field) = "offset_to_top";
- FIELD_TYPE (*field) = ptrdiff_type;
- SET_FIELD_BITPOS (*field, offset * TARGET_CHAR_BIT);
- offset += TYPE_LENGTH (FIELD_TYPE (*field));
- field++;
-
- FIELD_NAME (*field) = "type_info";
- FIELD_TYPE (*field) = void_ptr_type;
- SET_FIELD_BITPOS (*field, offset * TARGET_CHAR_BIT);
- offset += TYPE_LENGTH (FIELD_TYPE (*field));
- field++;
-
- FIELD_NAME (*field) = "virtual_functions";
- FIELD_TYPE (*field) = lookup_array_range_type (ptr_to_void_fn_type, 0, -1);
- SET_FIELD_BITPOS (*field, offset * TARGET_CHAR_BIT);
- offset += TYPE_LENGTH (FIELD_TYPE (*field));
- field++;
-
- gdb_assert (field == (field_list + 4));
- 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_abi_vtable";
- INIT_CPLUS_SPECIFIC (t);
- return make_type_with_address_space (t, TYPE_INSTANCE_FLAG_CODE_SPACE);
- }
- static struct type *
- vtable_ptrdiff_type (struct gdbarch *gdbarch)
- {
- struct type *vtable_type = gdbarch_data (gdbarch, vtable_type_gdbarch_data);
-
- return TYPE_FIELD_TYPE (vtable_type, vtable_field_offset_to_top);
- }
- static int
- vtable_address_point_offset (struct gdbarch *gdbarch)
- {
- struct type *vtable_type = gdbarch_data (gdbarch, vtable_type_gdbarch_data);
- return (TYPE_FIELD_BITPOS (vtable_type, vtable_field_virtual_functions)
- / TARGET_CHAR_BIT);
- }
- static int
- gnuv3_dynamic_class (struct type *type)
- {
- int fieldnum, fieldelem;
- if (TYPE_CPLUS_DYNAMIC (type))
- return TYPE_CPLUS_DYNAMIC (type) == 1;
- ALLOCATE_CPLUS_STRUCT_TYPE (type);
- for (fieldnum = 0; fieldnum < TYPE_N_BASECLASSES (type); fieldnum++)
- if (BASETYPE_VIA_VIRTUAL (type, fieldnum)
- || gnuv3_dynamic_class (TYPE_FIELD_TYPE (type, fieldnum)))
- {
- TYPE_CPLUS_DYNAMIC (type) = 1;
- return 1;
- }
- for (fieldnum = 0; fieldnum < TYPE_NFN_FIELDS (type); fieldnum++)
- for (fieldelem = 0; fieldelem < TYPE_FN_FIELDLIST_LENGTH (type, fieldnum);
- fieldelem++)
- {
- struct fn_field *f = TYPE_FN_FIELDLIST1 (type, fieldnum);
- if (TYPE_FN_FIELD_VIRTUAL_P (f, fieldelem))
- {
- TYPE_CPLUS_DYNAMIC (type) = 1;
- return 1;
- }
- }
- TYPE_CPLUS_DYNAMIC (type) = -1;
- return 0;
- }
- static struct value *
- gnuv3_get_vtable (struct gdbarch *gdbarch,
- struct type *container_type, CORE_ADDR container_addr)
- {
- struct type *vtable_type = gdbarch_data (gdbarch,
- vtable_type_gdbarch_data);
- struct type *vtable_pointer_type;
- struct value *vtable_pointer;
- CORE_ADDR vtable_address;
-
- if (!gnuv3_dynamic_class (check_typedef (container_type)))
- return NULL;
-
-
- vtable_pointer_type = lookup_pointer_type (vtable_type);
-
- vtable_pointer = value_at (vtable_pointer_type, container_addr);
- vtable_address = value_as_address (vtable_pointer);
-
- return value_at_lazy (vtable_type,
- vtable_address
- - vtable_address_point_offset (gdbarch));
- }
- static struct type *
- gnuv3_rtti_type (struct value *value,
- int *full_p, int *top_p, int *using_enc_p)
- {
- struct gdbarch *gdbarch;
- struct type *values_type = check_typedef (value_type (value));
- struct value *vtable;
- struct minimal_symbol *vtable_symbol;
- const char *vtable_symbol_name;
- const char *class_name;
- struct type *run_time_type;
- LONGEST offset_to_top;
- char *atsign;
-
- if (TYPE_CODE (values_type) != TYPE_CODE_STRUCT)
- return NULL;
-
- if (TYPE_CPLUS_REALLY_JAVA (values_type))
- return NULL;
-
- gdbarch = get_type_arch (values_type);
- if (using_enc_p)
- *using_enc_p = 0;
- vtable = gnuv3_get_vtable (gdbarch, value_type (value),
- value_as_address (value_addr (value)));
- if (vtable == NULL)
- return NULL;
-
- vtable_symbol
- = lookup_minimal_symbol_by_pc (value_address (vtable)
- + value_embedded_offset (vtable)).minsym;
- if (! vtable_symbol)
- return NULL;
-
- vtable_symbol_name = MSYMBOL_DEMANGLED_NAME (vtable_symbol);
- if (vtable_symbol_name == NULL
- || strncmp (vtable_symbol_name, "vtable for ", 11))
- {
- warning (_("can't find linker symbol for virtual table for `%s' value"),
- TYPE_SAFE_NAME (values_type));
- if (vtable_symbol_name)
- warning (_(" found `%s' instead"), vtable_symbol_name);
- return NULL;
- }
- class_name = vtable_symbol_name + 11;
-
- 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;
- }
-
- FIXME
- run_time_type = cp_lookup_rtti_type (class_name, NULL);
- if (run_time_type == NULL)
- return NULL;
-
- offset_to_top
- = value_as_long (value_field (vtable, vtable_field_offset_to_top));
- if (full_p)
- *full_p = (- offset_to_top == value_embedded_offset (value)
- && (TYPE_LENGTH (value_enclosing_type (value))
- >= TYPE_LENGTH (run_time_type)));
- if (top_p)
- *top_p = - offset_to_top;
- return run_time_type;
- }
- static struct value *
- gnuv3_get_virtual_fn (struct gdbarch *gdbarch, struct value *container,
- struct type *fntype, int vtable_index)
- {
- struct value *vtable, *vfn;
-
- vtable = gnuv3_get_vtable (gdbarch, value_type (container),
- value_as_address (value_addr (container)));
- gdb_assert (vtable != NULL);
-
- vfn = value_subscript (value_field (vtable, vtable_field_virtual_functions),
- vtable_index);
-
- if (gdbarch_vtable_function_descriptors (gdbarch))
- vfn = value_addr (vfn);
-
- vfn = value_cast (lookup_pointer_type (fntype), vfn);
- return vfn;
- }
- static struct value *
- gnuv3_virtual_fn_field (struct value **value_p,
- struct fn_field *f, int j,
- struct type *vfn_base, int offset)
- {
- struct type *values_type = check_typedef (value_type (*value_p));
- struct gdbarch *gdbarch;
-
- if (TYPE_CODE (values_type) != TYPE_CODE_STRUCT)
- error (_("Only classes can have virtual functions."));
-
- gdbarch = get_type_arch (values_type);
-
- if (vfn_base != values_type)
- *value_p = value_cast (vfn_base, *value_p);
- return gnuv3_get_virtual_fn (gdbarch, *value_p, TYPE_FN_FIELD_TYPE (f, j),
- TYPE_FN_FIELD_VOFFSET (f, j));
- }
- static int
- gnuv3_baseclass_offset (struct type *type, int index,
- const bfd_byte *valaddr, int embedded_offset,
- CORE_ADDR address, const struct value *val)
- {
- struct gdbarch *gdbarch;
- struct type *ptr_type;
- struct value *vtable;
- struct value *vbase_array;
- long int cur_base_offset, base_offset;
-
- gdbarch = get_type_arch (type);
- ptr_type = builtin_type (gdbarch)->builtin_data_ptr;
-
- if (!BASETYPE_VIA_VIRTUAL (type, index) || TYPE_CPLUS_REALLY_JAVA (type))
- return TYPE_BASECLASS_BITPOS (type, index) / 8;
-
- cur_base_offset = TYPE_BASECLASS_BITPOS (type, index) / 8;
- if (cur_base_offset >= - vtable_address_point_offset (gdbarch))
- error (_("Expected a negative vbase offset (old compiler?)"));
- cur_base_offset = cur_base_offset + vtable_address_point_offset (gdbarch);
- if ((- cur_base_offset) % TYPE_LENGTH (ptr_type) != 0)
- error (_("Misaligned vbase offset."));
- cur_base_offset = cur_base_offset / ((int) TYPE_LENGTH (ptr_type));
- vtable = gnuv3_get_vtable (gdbarch, type, address + embedded_offset);
- gdb_assert (vtable != NULL);
- vbase_array = value_field (vtable, vtable_field_vcall_and_vbase_offsets);
- base_offset = value_as_long (value_subscript (vbase_array, cur_base_offset));
- return base_offset;
- }
- static const char *
- gnuv3_find_method_in (struct type *domain, CORE_ADDR voffset,
- LONGEST adjustment)
- {
- int i;
-
- if (adjustment == 0)
- {
- int len;
- len = TYPE_NFN_FIELDS (domain);
- for (i = 0; i < len; i++)
- {
- int len2, j;
- struct fn_field *f;
- f = TYPE_FN_FIELDLIST1 (domain, i);
- len2 = TYPE_FN_FIELDLIST_LENGTH (domain, i);
- check_stub_method_group (domain, i);
- for (j = 0; j < len2; j++)
- if (TYPE_FN_FIELD_VOFFSET (f, j) == voffset)
- return TYPE_FN_FIELD_PHYSNAME (f, j);
- }
- }
-
- for (i = 0; i < TYPE_N_BASECLASSES (domain); i++)
- {
- int pos;
- struct type *basetype;
- if (BASETYPE_VIA_VIRTUAL (domain, i))
- continue;
- pos = TYPE_BASECLASS_BITPOS (domain, i) / 8;
- basetype = TYPE_FIELD_TYPE (domain, i);
-
- if (adjustment >= pos && adjustment < pos + TYPE_LENGTH (basetype))
- return gnuv3_find_method_in (basetype, voffset, adjustment - pos);
- }
- return NULL;
- }
- static int
- gnuv3_decode_method_ptr (struct gdbarch *gdbarch,
- const gdb_byte *contents,
- CORE_ADDR *value_p,
- LONGEST *adjustment_p)
- {
- struct type *funcptr_type = builtin_type (gdbarch)->builtin_func_ptr;
- struct type *offset_type = vtable_ptrdiff_type (gdbarch);
- enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
- CORE_ADDR ptr_value;
- LONGEST voffset, adjustment;
- int vbit;
-
- ptr_value = extract_typed_address (contents, funcptr_type);
- voffset = extract_signed_integer (contents,
- TYPE_LENGTH (funcptr_type), byte_order);
- contents += TYPE_LENGTH (funcptr_type);
- adjustment = extract_signed_integer (contents,
- TYPE_LENGTH (offset_type), byte_order);
- if (!gdbarch_vbit_in_delta (gdbarch))
- {
- vbit = voffset & 1;
- voffset = voffset ^ vbit;
- }
- else
- {
- vbit = adjustment & 1;
- adjustment = adjustment >> 1;
- }
- *value_p = vbit? voffset : ptr_value;
- *adjustment_p = adjustment;
- return vbit;
- }
- static void
- gnuv3_print_method_ptr (const gdb_byte *contents,
- struct type *type,
- struct ui_file *stream)
- {
- struct type *domain = TYPE_DOMAIN_TYPE (type);
- struct gdbarch *gdbarch = get_type_arch (domain);
- CORE_ADDR ptr_value;
- LONGEST adjustment;
- int vbit;
-
- vbit = gnuv3_decode_method_ptr (gdbarch, contents, &ptr_value, &adjustment);
-
- if (ptr_value == 0 && vbit == 0)
- {
- fprintf_filtered (stream, "NULL");
- return;
- }
-
- if (vbit)
- {
- CORE_ADDR voffset;
- const char *physname;
-
- voffset = ptr_value / TYPE_LENGTH (vtable_ptrdiff_type (gdbarch));
- physname = gnuv3_find_method_in (domain, voffset, adjustment);
-
- if (physname)
- {
- char *demangled_name = gdb_demangle (physname,
- DMGL_ANSI | DMGL_PARAMS);
- fprintf_filtered (stream, "&virtual ");
- if (demangled_name == NULL)
- fputs_filtered (physname, stream);
- else
- {
- fputs_filtered (demangled_name, stream);
- xfree (demangled_name);
- }
- return;
- }
- }
- else if (ptr_value != 0)
- {
-
- fputs_filtered ("(", stream);
- c_print_type (type, "", stream, -1, 0, &type_print_raw_options);
- fputs_filtered (") ", stream);
- }
-
- if (vbit)
- {
- fprintf_filtered (stream, "&virtual table offset ");
- print_longest (stream, 'd', 1, ptr_value);
- }
- else
- {
- struct value_print_options opts;
- get_user_print_options (&opts);
- print_address_demangle (&opts, gdbarch, ptr_value, stream, demangle);
- }
- if (adjustment)
- {
- fprintf_filtered (stream, ", this adjustment ");
- print_longest (stream, 'd', 1, adjustment);
- }
- }
- static int
- gnuv3_method_ptr_size (struct type *type)
- {
- struct gdbarch *gdbarch = get_type_arch (type);
- return 2 * TYPE_LENGTH (builtin_type (gdbarch)->builtin_data_ptr);
- }
- static void
- gnuv3_make_method_ptr (struct type *type, gdb_byte *contents,
- CORE_ADDR value, int is_virtual)
- {
- struct gdbarch *gdbarch = get_type_arch (type);
- int size = TYPE_LENGTH (builtin_type (gdbarch)->builtin_data_ptr);
- enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
- FIXME
- if (!gdbarch_vbit_in_delta (gdbarch))
- {
- store_unsigned_integer (contents, size, byte_order, value | is_virtual);
- store_unsigned_integer (contents + size, size, byte_order, 0);
- }
- else
- {
- store_unsigned_integer (contents, size, byte_order, value);
- store_unsigned_integer (contents + size, size, byte_order, is_virtual);
- }
- }
- static struct value *
- gnuv3_method_ptr_to_value (struct value **this_p, struct value *method_ptr)
- {
- struct gdbarch *gdbarch;
- const gdb_byte *contents = value_contents (method_ptr);
- CORE_ADDR ptr_value;
- struct type *domain_type, *final_type, *method_type;
- LONGEST adjustment;
- int vbit;
- domain_type = TYPE_DOMAIN_TYPE (check_typedef (value_type (method_ptr)));
- final_type = lookup_pointer_type (domain_type);
- method_type = TYPE_TARGET_TYPE (check_typedef (value_type (method_ptr)));
-
- gdbarch = get_type_arch (domain_type);
- vbit = gnuv3_decode_method_ptr (gdbarch, contents, &ptr_value, &adjustment);
-
- *this_p = value_cast (final_type, *this_p);
-
- *this_p = value_cast (builtin_type (gdbarch)->builtin_data_ptr, *this_p);
- *this_p = value_ptradd (*this_p, adjustment);
- *this_p = value_cast (final_type, *this_p);
- if (vbit)
- {
- LONGEST voffset;
- voffset = ptr_value / TYPE_LENGTH (vtable_ptrdiff_type (gdbarch));
- return gnuv3_get_virtual_fn (gdbarch, value_ind (*this_p),
- method_type, voffset);
- }
- else
- return value_from_pointer (lookup_pointer_type (method_type), ptr_value);
- }
- struct value_and_voffset
- {
-
- struct value *value;
-
- int max_voffset;
- };
- typedef struct value_and_voffset *value_and_voffset_p;
- DEF_VEC_P (value_and_voffset_p);
- 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);
- }
- 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));
- }
- 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;
- }
- 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;
-
- if (!gnuv3_dynamic_class (type))
- return;
-
- 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);
- }
-
- 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;
- }
- }
- }
-
- for (i = 0; i < TYPE_N_BASECLASSES (type); ++i)
- compute_vtable_size (offset_hash, offset_vec, value_field (value, i));
- }
- 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)
- {
-
- 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");
- }
- }
- 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);
-
- 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);
- }
- 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;
-
- 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++;
-
- 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;
- }
- 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;
- }
- 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;
-
- if (value_lval_const (value) == lval_memory)
- value = coerce_ref (value);
- type = check_typedef (value_type (value));
-
- if (TYPE_CODE (type) == TYPE_CODE_REF)
- type = check_typedef (TYPE_TARGET_TYPE (type));
-
- 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);
-
- canonical = cp_canonicalize_string (typename);
- if (canonical != NULL)
- {
- make_cleanup (xfree, canonical);
- typename = canonical;
- }
- typeinfo_type = gnuv3_get_typeid_type (gdbarch);
-
- 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'"), 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 bound_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.minsym == NULL)
- error (_("could not find typeinfo symbol for '%s'"), typename);
- result = value_at_lazy (typeinfo_type, BMSYMBOL_VALUE_ADDRESS (minsym));
- }
- do_cleanups (cleanup);
- return result;
- }
- 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 = MSYMBOL_DEMANGLED_NAME (typeinfo_sym.minsym);
- if (symname == NULL || strncmp (symname, TYPEINFO_PREFIX,
- TYPEINFO_PREFIX_LEN))
- error (_("typeinfo symbol '%s' has unexpected name"),
- MSYMBOL_LINKAGE_NAME (typeinfo_sym.minsym));
- class_name = symname + TYPEINFO_PREFIX_LEN;
-
- atsign = strchr (class_name, '@');
- if (atsign != NULL)
- return savestring (class_name, atsign - class_name);
- return xstrdup (class_name);
- }
- 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);
-
- expr = parse_expression (typename);
- make_cleanup (xfree, expr);
- type_val = evaluate_type (expr);
- result = value_type (type_val);
- do_cleanups (cleanup);
- return result;
- }
- static CORE_ADDR
- gnuv3_skip_trampoline (struct frame_info *frame, CORE_ADDR stop_pc)
- {
- CORE_ADDR real_stop_pc, method_stop_pc, func_addr;
- struct gdbarch *gdbarch = get_frame_arch (frame);
- struct bound_minimal_symbol thunk_sym, fn_sym;
- struct obj_section *section;
- const char *thunk_name, *fn_name;
- real_stop_pc = gdbarch_skip_trampoline_code (gdbarch, frame, stop_pc);
- if (real_stop_pc == 0)
- real_stop_pc = stop_pc;
-
- thunk_sym = lookup_minimal_symbol_by_pc (real_stop_pc);
- section = find_pc_section (real_stop_pc);
- if (thunk_sym.minsym == NULL || section == NULL)
- return 0;
-
- thunk_name = MSYMBOL_DEMANGLED_NAME (thunk_sym.minsym);
- if (thunk_name == NULL || strstr (thunk_name, " thunk to ") == NULL)
- return 0;
- fn_name = strstr (thunk_name, " thunk to ") + strlen (" thunk to ");
- fn_sym = lookup_minimal_symbol (fn_name, NULL, section->objfile);
- if (fn_sym.minsym == NULL)
- return 0;
- method_stop_pc = BMSYMBOL_VALUE_ADDRESS (fn_sym);
-
- 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)
- real_stop_pc = method_stop_pc;
- return real_stop_pc;
- }
- static int
- gnuv3_pass_by_reference (struct type *type)
- {
- int fieldnum, fieldelem;
- CHECK_TYPEDEF (type);
-
- if (TYPE_CODE (type) != TYPE_CODE_STRUCT
- && TYPE_CODE (type) != TYPE_CODE_UNION)
- return 0;
-
- if (gnuv3_dynamic_class (type))
- return 1;
- for (fieldnum = 0; fieldnum < TYPE_NFN_FIELDS (type); fieldnum++)
- for (fieldelem = 0; fieldelem < TYPE_FN_FIELDLIST_LENGTH (type, fieldnum);
- fieldelem++)
- {
- struct fn_field *fn = TYPE_FN_FIELDLIST1 (type, fieldnum);
- const char *name = TYPE_FN_FIELDLIST_NAME (type, fieldnum);
- struct type *fieldtype = TYPE_FN_FIELD_TYPE (fn, fieldelem);
-
- if (TYPE_FN_FIELD_ARTIFICIAL (fn, fieldelem))
- continue;
-
- if (name[0] == '~')
- return 1;
-
- FIXME
- if (!is_constructor_name (TYPE_FN_FIELD_PHYSNAME (fn, fieldelem))
- && !TYPE_FN_FIELD_CONSTRUCTOR (fn, fieldelem))
- continue;
-
- if (TYPE_NFIELDS (fieldtype) == 2)
- {
- struct type *arg_type = TYPE_FIELD_TYPE (fieldtype, 1);
- if (TYPE_CODE (arg_type) == TYPE_CODE_REF)
- {
- struct type *arg_target_type;
- arg_target_type = check_typedef (TYPE_TARGET_TYPE (arg_type));
- if (class_types_same_p (arg_target_type, type))
- return 1;
- }
- }
- }
-
- for (fieldnum = 0; fieldnum < TYPE_NFIELDS (type); fieldnum++)
- if (! field_is_static (&TYPE_FIELD (type, fieldnum))
- && gnuv3_pass_by_reference (TYPE_FIELD_TYPE (type, fieldnum)))
- return 1;
- return 0;
- }
- static void
- 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";
- gnu_v3_abi_ops.doc = "G++ Version 3 ABI";
- gnu_v3_abi_ops.is_destructor_name =
- (enum dtor_kinds (*) (const char *))is_gnu_v3_mangled_dtor;
- gnu_v3_abi_ops.is_constructor_name =
- (enum ctor_kinds (*) (const char *))is_gnu_v3_mangled_ctor;
- gnu_v3_abi_ops.is_vtable_name = gnuv3_is_vtable_name;
- gnu_v3_abi_ops.is_operator_name = gnuv3_is_operator_name;
- gnu_v3_abi_ops.rtti_type = gnuv3_rtti_type;
- gnu_v3_abi_ops.virtual_fn_field = gnuv3_virtual_fn_field;
- gnu_v3_abi_ops.baseclass_offset = gnuv3_baseclass_offset;
- gnu_v3_abi_ops.print_method_ptr = gnuv3_print_method_ptr;
- 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.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;
- }
- extern initialize_file_ftype _initialize_gnu_v3_abi;
- void
- _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);
- }