From patchwork Mon Sep 22 03:07:37 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Patrick Palka X-Patchwork-Id: 2940 Received: (qmail 16813 invoked by alias); 22 Sep 2014 03:07:49 -0000 Mailing-List: contact gdb-patches-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: gdb-patches-owner@sourceware.org Delivered-To: mailing list gdb-patches@sourceware.org Received: (qmail 16798 invoked by uid 89); 22 Sep 2014 03:07:48 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-2.4 required=5.0 tests=AWL, BAYES_00, RCVD_IN_DNSWL_LOW autolearn=ham version=3.3.2 X-HELO: mail-qg0-f47.google.com Received: from mail-qg0-f47.google.com (HELO mail-qg0-f47.google.com) (209.85.192.47) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with (AES128-SHA encrypted) ESMTPS; Mon, 22 Sep 2014 03:07:47 +0000 Received: by mail-qg0-f47.google.com with SMTP id z107so2235752qgd.34 for ; Sun, 21 Sep 2014 20:07:44 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:from:to:cc:subject:date:message-id; bh=Af5+PsbrqvX+C/QMRNE9YhDn/YlhqwZGA6HHHGvCXuo=; b=KcsQqQzTQj/eaEOVrls176FOdFqTR0qae5GsbchWLkUsKi5v8WJLI4QbpdhIgaC91W hnz+pY7ozPEUVY5bXmRKG2pTkzteeh74ZhwaDe3kPIRxEnshKbFZFa8VjC4TUaeMo51p EDGKYVc1g0G+FdtQC3lQI25zw0aG+WJSXnaiIlUxooV4J+RSsrK90nIQcPLHbsj2t1Q5 o07xmIvZsvwDPkoK4msHlhO0a3WM2kmd7un1K5neSmk3wLid9kkUdhUZUzdtOT/lkx3S gcmcVZuDUd4q56CWLpjdlvDsLcsFlL8EFRDePrMZcgFWngBQqykCuZIpg0l85nulnNfc HbwA== X-Gm-Message-State: ALoCoQmF4ITMmtuodYvgTHgCMINLr8WbGBhKgCd/anCMmAsbXt27rsvLGHyKz00HbwNWxfLWw20l X-Received: by 10.224.20.9 with SMTP id d9mr18419112qab.7.1411355264848; Sun, 21 Sep 2014 20:07:44 -0700 (PDT) Received: from localhost.localdomain (ool-4353af5c.dyn.optonline.net. [67.83.175.92]) by mx.google.com with ESMTPSA id p11sm1619557qgp.45.2014.09.21.20.07.43 for (version=TLSv1.2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Sun, 21 Sep 2014 20:07:44 -0700 (PDT) From: Patrick Palka To: gdb-patches@sourceware.org Cc: Patrick Palka Subject: [PATCH 2/2] Support setting breakpoints on C++ virtual method pointers Date: Sun, 21 Sep 2014 23:07:37 -0400 Message-Id: <1411355257-10861-1-git-send-email-patrick@parcs.ath.cx> X-IsSubscribed: yes 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