This is the mail archive of the
gdb-patches@sourceware.org
mailing list for the GDB project.
[PATCH 2/2] Support setting breakpoints on C++ virtual method pointers
- From: Patrick Palka <patrick at parcs dot ath dot cx>
- To: gdb-patches at sourceware dot org
- Cc: Patrick Palka <patrick at parcs dot ath dot cx>
- Date: Mon, 22 Sep 2014 19:37:18 -0400
- Subject: [PATCH 2/2] Support setting breakpoints on C++ virtual method pointers
- Authentication-results: sourceware.org; auth=none
- References: <1411355257-10861-1-git-send-email-patrick at parcs dot ath dot cx>
This patch adds support for setting breakpoints on C++ virtual method
pointers. In essence, to be able to do:
struct x
{
virtual void f ();
}
void x::f () { }
(gdb) break *&x::f
This functionality is achieved by augmenting the function
gnuv3_method_ptr_to_value() to be able to resolve virtual methods even
without a "this" object, by looking up the symbolic name of the pointer
to virtual method within the symbol table (this is what
gnuv3_print_method_ptr() does, too). Then value_as_address() is
augmented to hook into cplus_method_ptr_to_value() when it's given a
TYPE_CODE_METHOD_PTR value.
Tested on x86_64-unknown-linux-gnu.
gdb/ChangeLog
* gnu-v3-abi.c (gnuv3_method_ptr_to_value): Support method
resolution without a given "this" object.
* value.c (value_as_address): Handle TYPE_CODE_METHODPTR values.
gdb/testsuite/ChangeLog
* gdb.cp/method-ptr.exp (check_virtual_method_ptr_resolution):
Also test setting a breakpoint on the given pointer to virtual
method.
---
gdb/gnu-v3-abi.c | 65 +++++++++++++++++++++++++------------
gdb/testsuite/gdb.cp/method-ptr.exp | 6 ++++
gdb/value.c | 8 +++++
3 files changed, 58 insertions(+), 21 deletions(-)
diff --git a/gdb/gnu-v3-abi.c b/gdb/gnu-v3-abi.c
index ccb0be6..718694b 100644
--- a/gdb/gnu-v3-abi.c
+++ b/gdb/gnu-v3-abi.c
@@ -719,36 +719,59 @@ gnuv3_method_ptr_to_value (struct value **this_p, struct value *method_ptr)
gdbarch = get_type_arch (domain_type);
vbit = gnuv3_decode_method_ptr (gdbarch, 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. */
- *this_p = value_cast (final_type, *this_p);
+ if (this_p != NULL)
+ {
+ /* First convert THIS to match the containing type of the pointer to
+ member. This cast may adjust the value of THIS. */
+ *this_p = value_cast (final_type, *this_p);
- /* Then apply whatever adjustment is necessary. This creates a somewhat
- strange pointer: it claims to have type FINAL_TYPE, but in fact it
- might not be a valid FINAL_TYPE. For instance, it might be a
- base class of FINAL_TYPE. And if it's not the primary base class,
- then printing it out as a FINAL_TYPE object would produce some pretty
- garbage.
+ /* Then apply whatever adjustment is necessary. This creates a somewhat
+ strange pointer: it claims to have type FINAL_TYPE, but in fact it
+ might not be a valid FINAL_TYPE. For instance, it might be a
+ base class of FINAL_TYPE. And if it's not the primary base class,
+ then printing it out as a FINAL_TYPE object would produce some pretty
+ garbage.
- But we don't really know the type of the first argument in
- METHOD_TYPE either, which is why this happens. We can't
- dereference this later as a FINAL_TYPE, but once we arrive in the
- called method we'll have debugging information for the type of
- "this" - and that'll match the value we produce here.
+ But we don't really know the type of the first argument in
+ METHOD_TYPE either, which is why this happens. We can't
+ dereference this later as a FINAL_TYPE, but once we arrive in the
+ called method we'll have debugging information for the type of
+ "this" - and that'll match the value we produce here.
- You can provoke this case by casting a Base::* to a Derived::*, for
- instance. */
- *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);
+ You can provoke this case by casting a Base::* to a Derived::*, for
+ instance. */
+ *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);
+
+ /* If we don't have a "this" object to apply the method pointer to,
+ then retrieve the value of the virtual method by looking up its
+ symbolic name within the symbol table. */
+ if (this_p == NULL)
+ {
+ const char *physname;
+ struct symbol *sym;
+
+ physname = gnuv3_find_method_in (domain_type, voffset, adjustment);
+ if (physname == NULL)
+ return NULL;
+
+ sym = lookup_symbol (physname, NULL, VAR_DOMAIN, NULL);
+ if (sym == NULL)
+ return NULL;
+
+ return value_of_variable (sym, NULL);
+ }
+ else
+ 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);
diff --git a/gdb/testsuite/gdb.cp/method-ptr.exp b/gdb/testsuite/gdb.cp/method-ptr.exp
index 732b861..42461ab 100644
--- a/gdb/testsuite/gdb.cp/method-ptr.exp
+++ b/gdb/testsuite/gdb.cp/method-ptr.exp
@@ -39,6 +39,12 @@ proc check_virtual_method_ptr_resolution { name symbol } {
# Printing the expression &NAME should show the resolved symbol SYMBOL.
gdb_test "print &$name" "\\$$decimal = &virtual $symbol\\(\\)\\s"
+
+ # Breaking on the expression &NAME should break on the symbol SYMBOL.
+ set breakpoint_line [gdb_get_line_number $symbol]
+ gdb_test "break *&$name" \
+ "Breakpoint $decimal at .*, line $breakpoint_line\\.\\s"
+ delete_breakpoints
}
check_virtual_method_ptr_resolution "x::f" "x::f"
diff --git a/gdb/value.c b/gdb/value.c
index fdc8858d..cef29e9 100644
--- a/gdb/value.c
+++ b/gdb/value.c
@@ -2639,6 +2639,14 @@ value_as_address (struct value *val)
return gdbarch_addr_bits_remove (gdbarch, value_as_long (val));
#else
+ if (TYPE_CODE (value_type (val)) == TYPE_CODE_METHODPTR)
+ {
+ val = cplus_method_ptr_to_value (NULL, val);
+ if (val == NULL)
+ error (_("Method pointer can't be converted to address."));
+ }
+
+
/* There are several targets (IA-64, PowerPC, and others) which
don't represent pointers to functions as simply the address of
the function's entry point. For example, on the IA-64, a
--
2.1.1.273.g97b8860