This is the mail archive of the gdb-patches@sourceware.org mailing list for the GDB project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[PATCH 2/2] Support setting breakpoints on C++ virtual method pointers


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


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]