diff --git a/gdb/ChangeLog b/gdb/ChangeLog index 6d12caef9b..f7870b8586 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,9 @@ +2008-09-05 Ulrich Weigand + + * gnu-v3-abi.c (gnuv3_decode_method_ptr): New function. + (gnuv3_print_method_ptr): Use it. + (gnuv3_method_ptr_to_value): Likewise. + 2008-09-05 Ulrich Weigand * nto-tdep.h (struct nto_target_ops): Add gdbarch parameter to diff --git a/gdb/gnu-v3-abi.c b/gdb/gnu-v3-abi.c index 2059f3043a..ab77072b0e 100644 --- a/gdb/gnu-v3-abi.c +++ b/gdb/gnu-v3-abi.c @@ -489,6 +489,46 @@ gnuv3_find_method_in (struct type *domain, CORE_ADDR voffset, return NULL; } +/* Decode GNU v3 method pointer. */ + +static int +gnuv3_decode_method_ptr (const gdb_byte *contents, + CORE_ADDR *value_p, + LONGEST *adjustment_p) +{ + struct type *funcptr_type = builtin_type_void_func_ptr; + struct type *offset_type = builtin_type_long; + CORE_ADDR ptr_value; + LONGEST voffset, adjustment; + int vbit; + + /* Extract the pointer to member. The first element is either a pointer + or a vtable offset. For pointers, we need to use extract_typed_address + to allow the back-end to convert the pointer to a GDB address -- but + vtable offsets we must handle as integers. At this point, we do not + yet know which case we have, so we extract the value under both + interpretations and choose the right one later on. */ + ptr_value = extract_typed_address (contents, funcptr_type); + voffset = extract_signed_integer (contents, TYPE_LENGTH (funcptr_type)); + contents += TYPE_LENGTH (funcptr_type); + adjustment = extract_signed_integer (contents, TYPE_LENGTH (offset_type)); + + if (!gdbarch_vbit_in_delta (current_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; +} + /* GNU v3 implementation of cplus_print_method_ptr. */ static void @@ -504,21 +544,7 @@ gnuv3_print_method_ptr (const gdb_byte *contents, domain = TYPE_DOMAIN_TYPE (type); /* Extract the pointer to member. */ - ptr_value = extract_typed_address (contents, builtin_type_void_func_ptr); - contents += TYPE_LENGTH (builtin_type_void_func_ptr); - adjustment = extract_signed_integer (contents, - TYPE_LENGTH (builtin_type_long)); - - if (!gdbarch_vbit_in_delta (current_gdbarch)) - { - vbit = ptr_value & 1; - ptr_value = ptr_value ^ vbit; - } - else - { - vbit = adjustment & 1; - adjustment = adjustment >> 1; - } + vbit = gnuv3_decode_method_ptr (contents, &ptr_value, &adjustment); /* Check for NULL. */ if (ptr_value == 0 && vbit == 0) @@ -625,21 +651,8 @@ gnuv3_method_ptr_to_value (struct value **this_p, struct value *method_ptr) method_type = TYPE_TARGET_TYPE (check_typedef (value_type (method_ptr))); - ptr_value = extract_typed_address (contents, builtin_type_void_func_ptr); - contents += TYPE_LENGTH (builtin_type_void_func_ptr); - adjustment = extract_signed_integer (contents, - TYPE_LENGTH (builtin_type_long)); - - if (!gdbarch_vbit_in_delta (current_gdbarch)) - { - vbit = ptr_value & 1; - ptr_value = ptr_value ^ vbit; - } - else - { - vbit = adjustment & 1; - adjustment = adjustment >> 1; - } + /* Extract the pointer to member. */ + vbit = gnuv3_decode_method_ptr (contents, &ptr_value, &adjustment); /* First convert THIS to match the containing type of the pointer to member. This cast may adjust the value of THIS. */