From patchwork Wed Mar 26 13:23:02 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Julian Brown X-Patchwork-Id: 294 Return-Path: X-Original-To: siddhesh@wilcox.dreamhost.com Delivered-To: siddhesh@wilcox.dreamhost.com Received: from homiemail-mx21.g.dreamhost.com (caibbdcaaahb.dreamhost.com [208.113.200.71]) by wilcox.dreamhost.com (Postfix) with ESMTP id 3F794360078 for ; Wed, 26 Mar 2014 06:23:24 -0700 (PDT) Received: by homiemail-mx21.g.dreamhost.com (Postfix, from userid 14314964) id 00F131FDC7A0; Wed, 26 Mar 2014 06:23:23 -0700 (PDT) X-Original-To: gdb@patchwork.siddhesh.in Delivered-To: x14314964@homiemail-mx21.g.dreamhost.com Received: from sourceware.org (server1.sourceware.org [209.132.180.131]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by homiemail-mx21.g.dreamhost.com (Postfix) with ESMTPS id C9DDE1F5E2DD for ; Wed, 26 Mar 2014 06:23:23 -0700 (PDT) DomainKey-Signature: a=rsa-sha1; c=nofws; d=sourceware.org; h=list-id :list-unsubscribe:list-subscribe:list-archive:list-post :list-help:sender:date:from:to:subject:message-id:mime-version :content-type; q=dns; s=default; b=QUhhMsyprpjaR3w8kYAkpLpE6CoJb a+SxzUgTQUbnSd3/JmDlmh6B+KB/8ILVZmjJLZDeMOH11BDp+zHAIC8ch+Pr0dLB l/nKqBQ3zvRM66oXkVMIG/RcVPJA/fogIJfz0uLQMMVUiOLycWqvFaLlOGG1RLgd V1gWZDZy3L4hY4= DKIM-Signature: v=1; a=rsa-sha1; c=relaxed; d=sourceware.org; h=list-id :list-unsubscribe:list-subscribe:list-archive:list-post :list-help:sender:date:from:to:subject:message-id:mime-version :content-type; s=default; bh=FsMS/36+GrhkuDPDyejp0R/rE7Y=; b=QKp Z5W3zFX5vkCZ1pqtolI8005hz+LyUiHmcC54FsUOMrkB8JDaOV+qtXO+ceOVocst VmzlW7otQB25j861xsGDMBYiaw4M6gQtv2B+D6vApTJ1dQhbvsV0/RXKlCxA+LYu PeAfqhvBK98HLsGl2vuhi0082sL2T1obDTPor6WA= Received: (qmail 19196 invoked by alias); 26 Mar 2014 13:23:22 -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 19183 invoked by uid 89); 26 Mar 2014 13:23:20 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-1.8 required=5.0 tests=AWL, BAYES_00, KAM_ADVERT2 autolearn=no version=3.3.2 X-HELO: relay1.mentorg.com Received: from relay1.mentorg.com (HELO relay1.mentorg.com) (192.94.38.131) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Wed, 26 Mar 2014 13:23:19 +0000 Received: from svr-orw-fem-01.mgc.mentorg.com ([147.34.98.93]) by relay1.mentorg.com with esmtp id 1WSnnX-000223-I4 from Julian_Brown@mentor.com for gdb-patches@sourceware.org; Wed, 26 Mar 2014 06:23:15 -0700 Received: from SVR-IES-FEM-03.mgc.mentorg.com ([137.202.0.108]) by svr-orw-fem-01.mgc.mentorg.com over TLS secured channel with Microsoft SMTPSVC(6.0.3790.4675); Wed, 26 Mar 2014 06:23:15 -0700 Received: from octopus (137.202.0.76) by SVR-IES-FEM-03.mgc.mentorg.com (137.202.0.108) with Microsoft SMTP Server id 14.2.247.3; Wed, 26 Mar 2014 13:23:11 +0000 Date: Wed, 26 Mar 2014 13:23:02 +0000 From: Julian Brown To: Subject: [PATCH] Fix "thiscall" method calling convention for inferior calls (PR15559) Message-ID: <20140326132302.09b6fc35@octopus> MIME-Version: 1.0 X-IsSubscribed: yes X-DH-Original-To: gdb@patchwork.siddhesh.in Hi, This is an adaptation of the patch in PR15559 that handles calling inferior methods (on win32/mingw32) using the "thiscall" calling convention -- i.e. with the "this" pointer in the ecx register. Instead of attempting to detect the GCC version used to compile a particular function/method to determine the calling convention to use (which didn't seem to work well for me), I've introduced a new GNU-specific Dwarf code to represent the calling convention in question. GCC does not emit the tag at present: I will submit the GCC part of the fix (to emit the Dwarf tag as appropriate) shortly. Testing (cross to mingw32 from Linux) gives testsuite result improvements as follows: FAIL -> PASS: default/gdb.sum:gdb.cp/bs15503.exp: print (const char *) (s=s.substr(0,4)) FAIL -> PASS: default/gdb.sum:gdb.cp/bs15503.exp: print (const char *) s FAIL -> PASS: default/gdb.sum:gdb.cp/bs15503.exp: print (const char *) s.substr(0,4) FAIL -> PASS: default/gdb.sum:gdb.cp/bs15503.exp: print s.length() FAIL -> PASS: default/gdb.sum:gdb.cp/bs15503.exp: print s[0] FAIL -> PASS: default/gdb.sum:gdb.cp/bs15503.exp: print s[s.length()-1] FAIL -> PASS: default/gdb.sum:gdb.cp/classes.exp: call class_param.Aptr_a (&g_A) FAIL -> PASS: default/gdb.sum:gdb.cp/classes.exp: call class_param.Aptr_a (&g_B) FAIL -> PASS: default/gdb.sum:gdb.cp/classes.exp: call class_param.Aptr_x (&g_A) FAIL -> PASS: default/gdb.sum:gdb.cp/classes.exp: call class_param.Aptr_x (&g_B) FAIL -> PASS: default/gdb.sum:gdb.cp/classes.exp: call class_param.Aref_a (g_A) FAIL -> PASS: default/gdb.sum:gdb.cp/classes.exp: call class_param.Aref_a (g_B) FAIL -> PASS: default/gdb.sum:gdb.cp/classes.exp: call class_param.Aref_x (g_A) FAIL -> PASS: default/gdb.sum:gdb.cp/classes.exp: call class_param.Aref_x (g_B) FAIL -> PASS: default/gdb.sum:gdb.cp/classes.exp: call class_param.Aval_a (g_A) FAIL -> PASS: default/gdb.sum:gdb.cp/classes.exp: call class_param.Aval_a (g_B) FAIL -> PASS: default/gdb.sum:gdb.cp/classes.exp: call class_param.Aval_x (g_A) FAIL -> PASS: default/gdb.sum:gdb.cp/classes.exp: call class_param.Aval_x (g_B) FAIL -> PASS: default/gdb.sum:gdb.cp/classes.exp: calling method for small class FAIL -> PASS: default/gdb.sum:gdb.cp/gdb2384.exp: gdb2384 FAIL -> PASS: default/gdb.sum:gdb.cp/gdb2384.exp: gdb2384 (second) FAIL -> PASS: default/gdb.sum:gdb.cp/gdb2384.exp: print d1.meth () FAIL -> PASS: default/gdb.sum:gdb.cp/gdb2384.exp: print d2.meth() FAIL -> PASS: default/gdb.sum:gdb.cp/overload.exp: print bar(a) FAIL -> PASS: default/gdb.sum:gdb.cp/overload.exp: print bar(b) FAIL -> PASS: default/gdb.sum:gdb.cp/overload.exp: print bar(c) FAIL -> PASS: default/gdb.sum:gdb.cp/overload.exp: print bar(d) FAIL -> PASS: default/gdb.sum:gdb.cp/overload.exp: print call overloaded func 10 args FAIL -> PASS: default/gdb.sum:gdb.cp/overload.exp: print call overloaded func 11 args FAIL -> PASS: default/gdb.sum:gdb.cp/overload.exp: print call overloaded func 2 args FAIL -> PASS: default/gdb.sum:gdb.cp/overload.exp: print call overloaded func 3 args FAIL -> PASS: default/gdb.sum:gdb.cp/overload.exp: print call overloaded func 4 args FAIL -> PASS: default/gdb.sum:gdb.cp/overload.exp: print call overloaded func 5 args FAIL -> PASS: default/gdb.sum:gdb.cp/overload.exp: print call overloaded func 6 args FAIL -> PASS: default/gdb.sum:gdb.cp/overload.exp: print call overloaded func 7 args FAIL -> PASS: default/gdb.sum:gdb.cp/overload.exp: print call overloaded func 8 args FAIL -> PASS: default/gdb.sum:gdb.cp/overload.exp: print call overloaded func 9 args FAIL -> PASS: default/gdb.sum:gdb.cp/overload.exp: print call overloaded func char arg FAIL -> PASS: default/gdb.sum:gdb.cp/overload.exp: print call overloaded func char\* arg FAIL -> PASS: default/gdb.sum:gdb.cp/overload.exp: print call overloaded func double arg FAIL -> PASS: default/gdb.sum:gdb.cp/overload.exp: print call overloaded func float arg FAIL -> PASS: default/gdb.sum:gdb.cp/overload.exp: print call overloaded func int arg FAIL -> PASS: default/gdb.sum:gdb.cp/overload.exp: print call overloaded func int\* arg FAIL -> PASS: default/gdb.sum:gdb.cp/overload.exp: print call overloaded func long arg FAIL -> PASS: default/gdb.sum:gdb.cp/overload.exp: print call overloaded func short arg FAIL -> PASS: default/gdb.sum:gdb.cp/overload.exp: print call overloaded func signed char arg FAIL -> PASS: default/gdb.sum:gdb.cp/overload.exp: print call overloaded func unsigned char arg FAIL -> PASS: default/gdb.sum:gdb.cp/overload.exp: print call overloaded func unsigned int arg FAIL -> PASS: default/gdb.sum:gdb.cp/overload.exp: print call overloaded func unsigned long arg FAIL -> PASS: default/gdb.sum:gdb.cp/overload.exp: print call overloaded func unsigned short arg FAIL -> PASS: default/gdb.sum:gdb.cp/overload.exp: print call overloaded func void arg FAIL -> PASS: default/gdb.sum:gdb.cp/overload.exp: print foo_instance1.overloadfnarg(23, intintfunc) FAIL -> PASS: default/gdb.sum:gdb.cp/overload.exp: re-selected 'main' frame after inferior call FAIL -> PASS: default/gdb.sum:gdb.cp/smartp.exp: p sp4->a FAIL -> PASS: default/gdb.sum:gdb.cp/smartp.exp: p sp4->b FAIL -> PASS: default/gdb.sum:gdb.cp/templates.exp: continue to line 770 FAIL -> PASS: default/gdb.sum:gdb.cp/templates.exp: print fint FAIL -> PASS: default/gdb.sum:gdb.cp/templates.exp: print fvpchar FAIL -> PASS: default/gdb.sum:gdb.cp/templates.exp: print t5i.value() FAIL -> PASS: default/gdb.sum:gdb.cp/templates.exp: ptype bazint FAIL -> PASS: default/gdb.sum:gdb.cp/templates.exp: ptype bazint2 FAIL -> PASS: default/gdb.sum:gdb.cp/templates.exp: ptype bint FAIL -> PASS: default/gdb.sum:gdb.cp/templates.exp: ptype bint2 FAIL -> PASS: default/gdb.sum:gdb.cp/templates.exp: ptype fchar FAIL -> PASS: default/gdb.sum:gdb.cp/templates.exp: ptype fint FAIL -> PASS: default/gdb.sum:gdb.cp/templates.exp: ptype quxint FAIL -> PASS: default/gdb.sum:gdb.cp/templates.exp: ptype siip FAIL -> PASS: default/gdb.sum:gdb.cp/userdef.exp: print !one FAIL -> PASS: default/gdb.sum:gdb.cp/userdef.exp: print ++one FAIL -> PASS: default/gdb.sum:gdb.cp/userdef.exp: print +one FAIL -> PASS: default/gdb.sum:gdb.cp/userdef.exp: print --one FAIL -> PASS: default/gdb.sum:gdb.cp/userdef.exp: print -one FAIL -> PASS: default/gdb.sum:gdb.cp/userdef.exp: print one % two FAIL -> PASS: default/gdb.sum:gdb.cp/userdef.exp: print one & two FAIL -> PASS: default/gdb.sum:gdb.cp/userdef.exp: print one && two FAIL -> PASS: default/gdb.sum:gdb.cp/userdef.exp: print one * two FAIL -> PASS: default/gdb.sum:gdb.cp/userdef.exp: print one + two FAIL -> PASS: default/gdb.sum:gdb.cp/userdef.exp: print one += 7 FAIL -> PASS: default/gdb.sum:gdb.cp/userdef.exp: print one - two FAIL -> PASS: default/gdb.sum:gdb.cp/userdef.exp: print one ^ two FAIL -> PASS: default/gdb.sum:gdb.cp/userdef.exp: print one | two FAIL -> PASS: default/gdb.sum:gdb.cp/userdef.exp: print one++ FAIL -> PASS: default/gdb.sum:gdb.cp/userdef.exp: print one-- FAIL -> PASS: default/gdb.sum:gdb.cp/userdef.exp: print two = one FAIL -> PASS: default/gdb.sum:gdb.cp/userdef.exp: print ~one FAIL -> PASS: default/gdb.sum:gdb.cp/virtfunc.exp: next to pAa->f call FAIL -> PASS: default/gdb.sum:gdb.cp/virtfunc.exp: next to pDe->vg call FAIL -> PASS: default/gdb.sum:gdb.cp/virtfunc.exp: print pADe->vg() FAIL -> PASS: default/gdb.sum:gdb.cp/virtfunc.exp: print pBe->vvb() FAIL -> PASS: default/gdb.sum:gdb.cp/virtfunc.exp: print pDd->vg() FAIL -> PASS: default/gdb.sum:gdb.cp/virtfunc.exp: print pDe->vg() FAIL -> PASS: default/gdb.sum:gdb.cp/virtfunc.exp: print pDe->vvb() FAIL -> PASS: default/gdb.sum:gdb.cp/virtfunc.exp: print pEe->fvb() FAIL -> PASS: default/gdb.sum:gdb.cp/virtfunc.exp: print pEe->vd() FAIL -> PASS: default/gdb.sum:gdb.cp/virtfunc.exp: print pEe->vvb() FAIL -> PASS: default/gdb.sum:gdb.cp/virtfunc.exp: print pVB->vvb() FAIL -> PASS: default/gdb.sum:gdb.cp/virtfunc.exp: step through thunk into E::vg Removed FAIL: default/gdb.sum:gdb.cp/templates.exp: ptype fvpchar Removed FAIL: default/gdb.sum:gdb.cp/virtfunc.exp: print pEe->D::vg() OK to apply (pending approval of the GCC part of the patch), or any comments? Thanks, Julian ChangeLog include/ * dwarf2.h (enum dwarf_calling_convention): Add code for DW_CC_GNU_thiscall_i386. gdb/ * dwarf2read.c (dwarf2_add_member_fn): Add calling convention argument to smash_to_method_type call. (quirk_gcc_member_function_pointer): Likewise. (read_tag_ptr_to_member_type): Likewise. (smash_to_method_type): Add CALLING_CONVENTION argument. Initialise func-specific type for method types, and set the calling convention as appropriate. (init_type): Call INIT_FUNC_SPECIFIC for method types as well as function types. * gdbtypes.h (struct main_type): Adjust comment for FUNC_STUFF. (struct func_type): Adjust comment. * stabsread.c (read_type): Add dummy calling-convention argument to smash_to_method_type call. * i386-tdep.c (utils.h, infcall.h, dwarf2.h): Include files. (i386_push_dummy_call): Handle "thiscall" calling convention. diff --git a/gdb/dwarf2read.c b/gdb/dwarf2read.c index 705dc2d..8b784ac 100644 --- a/gdb/dwarf2read.c +++ b/gdb/dwarf2read.c @@ -12578,7 +12578,8 @@ dwarf2_add_member_fn (struct field_info *fip, struct die_info *die, TYPE_TARGET_TYPE (this_type), TYPE_FIELDS (this_type), TYPE_NFIELDS (this_type), - TYPE_VARARGS (this_type)); + TYPE_VARARGS (this_type), + TYPE_CALLING_CONVENTION (this_type)); /* Handle static member functions. Dwarf2 has no clean way to discern C++ static and non-static @@ -12782,7 +12783,8 @@ quirk_gcc_member_function_pointer (struct type *type, struct objfile *objfile) new_type = alloc_type (objfile); smash_to_method_type (new_type, domain_type, TYPE_TARGET_TYPE (pfn_type), TYPE_FIELDS (pfn_type), TYPE_NFIELDS (pfn_type), - TYPE_VARARGS (pfn_type)); + TYPE_VARARGS (pfn_type), + TYPE_CALLING_CONVENTION (pfn_type)); smash_to_methodptr_type (type, new_type); } @@ -13943,7 +13945,8 @@ read_tag_ptr_to_member_type (struct die_info *die, struct dwarf2_cu *cu) smash_to_method_type (new_type, domain, TYPE_TARGET_TYPE (to_type), TYPE_FIELDS (to_type), TYPE_NFIELDS (to_type), - TYPE_VARARGS (to_type)); + TYPE_VARARGS (to_type), + TYPE_CALLING_CONVENTION (to_type)); type = lookup_methodptr_type (new_type); } else diff --git a/gdb/gdbtypes.c b/gdb/gdbtypes.c index 98cb873..bee1b09 100644 --- a/gdb/gdbtypes.c +++ b/gdb/gdbtypes.c @@ -1174,7 +1174,7 @@ smash_to_methodptr_type (struct type *type, struct type *to_type) void smash_to_method_type (struct type *type, struct type *domain, struct type *to_type, struct field *args, - int nargs, int varargs) + int nargs, int varargs, unsigned int calling_convention) { smash_type (type); TYPE_TARGET_TYPE (type) = to_type; @@ -1185,6 +1185,8 @@ smash_to_method_type (struct type *type, struct type *domain, TYPE_VARARGS (type) = 1; TYPE_LENGTH (type) = 1; /* In practice, this is never needed. */ TYPE_CODE (type) = TYPE_CODE_METHOD; + INIT_FUNC_SPECIFIC (type); + TYPE_CALLING_CONVENTION (type) = calling_convention; } /* Return a typename for a struct/union/enum type without "struct ", @@ -2082,6 +2084,7 @@ init_type (enum type_code code, int length, int flags, TYPE_SPECIFIC_FIELD (type) = TYPE_SPECIFIC_FLOATFORMAT; break; case TYPE_CODE_FUNC: + case TYPE_CODE_METHOD: INIT_FUNC_SPECIFIC (type); break; } diff --git a/gdb/gdbtypes.h b/gdb/gdbtypes.h index c6943ef..a9fd5a2 100644 --- a/gdb/gdbtypes.h +++ b/gdb/gdbtypes.h @@ -685,7 +685,7 @@ struct main_type const struct floatformat **floatformat; - /* * For TYPE_CODE_FUNC types, */ + /* * For TYPE_CODE_FUNC and TYPE_CODE_METHOD types, */ struct func_type *func_stuff; } type_specific; @@ -982,7 +982,7 @@ struct gnat_aux_type struct type* descriptive_type; }; -/* * For TYPE_CODE_FUNC types. */ +/* * For TYPE_CODE_FUNC and TYPE_CODE_METHOD types. */ struct func_type { @@ -1598,7 +1598,8 @@ extern struct type *lookup_methodptr_type (struct type *); extern void smash_to_method_type (struct type *type, struct type *domain, struct type *to_type, struct field *args, - int nargs, int varargs); + int nargs, int varargs, + unsigned int calling_convention); extern void smash_to_memberptr_type (struct type *, struct type *, struct type *); diff --git a/gdb/i386-tdep.c b/gdb/i386-tdep.c index be40b20..1025e07 100644 --- a/gdb/i386-tdep.c +++ b/gdb/i386-tdep.c @@ -45,6 +45,9 @@ #include "remote.h" #include "exceptions.h" #include "gdb_assert.h" +#include "utils.h" +#include "infcall.h" +#include "dwarf2.h" #include #include "i386-tdep.h" @@ -2529,6 +2532,21 @@ i386_push_dummy_call (struct gdbarch *gdbarch, struct value *function, int i; int write_pass; int args_space = 0; + struct type *func_type = value_type (function); + int i386_windows_thiscall = 0; + + if (func_type) + { + func_type = check_typedef (func_type); + + if (TYPE_CODE (func_type) == TYPE_CODE_PTR) + func_type = check_typedef (TYPE_TARGET_TYPE (func_type)); + + if ((TYPE_CODE (func_type) == TYPE_CODE_METHOD + || TYPE_CODE (func_type) == TYPE_CODE_FUNC) + && TYPE_CALLING_CONVENTION (func_type) == DW_CC_GNU_thiscall_i386) + i386_windows_thiscall = 1; + } /* Determine the total space required for arguments and struct return address in a first pass (allowing for 16-byte-aligned @@ -2551,7 +2569,7 @@ i386_push_dummy_call (struct gdbarch *gdbarch, struct value *function, args_space += 4; } - for (i = 0; i < nargs; i++) + for (i = i386_windows_thiscall; i < nargs; i++) { int len = TYPE_LENGTH (value_enclosing_type (args[i])); @@ -2603,6 +2621,13 @@ i386_push_dummy_call (struct gdbarch *gdbarch, struct value *function, /* ...and fake a frame pointer. */ regcache_cooked_write (regcache, I386_EBP_REGNUM, buf); + if (i386_windows_thiscall) + { + /* ARGS[0] refers to the last argument which is the this pointer. */ + regcache_cooked_write (regcache, I386_ECX_REGNUM, + value_contents_all (args[0])); + } + /* MarkK wrote: This "+ 8" is all over the place: (i386_frame_this_id, i386_sigtramp_frame_this_id, i386_dummy_id). It's there, since all frame unwinders for diff --git a/gdb/stabsread.c b/gdb/stabsread.c index b40cf78..ff4ab10 100644 --- a/gdb/stabsread.c +++ b/gdb/stabsread.c @@ -1959,7 +1959,7 @@ again: return error_type (pp, objfile); type = dbx_alloc_type (typenums, objfile); smash_to_method_type (type, domain, return_type, args, - nargs, varargs); + nargs, varargs, 0); } break; diff --git a/include/dwarf2.h b/include/dwarf2.h index 120e2c1..eb9ee5e 100644 --- a/include/dwarf2.h +++ b/include/dwarf2.h @@ -182,6 +182,7 @@ enum dwarf_calling_convention DW_CC_GNU_renesas_sh = 0x40, DW_CC_GNU_borland_fastcall_i386 = 0x41, + DW_CC_GNU_thiscall_i386 = 0x42, /* This DW_CC_ value is not currently generated by any toolchain. It is used internally to GDB to indicate OpenCL C functions that have been