From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 13577 invoked by alias); 4 Sep 2013 21:54:29 -0000 Mailing-List: contact gdb-patches-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: gdb-patches-owner@sourceware.org Received: (qmail 13565 invoked by uid 89); 4 Sep 2013 21:54:29 -0000 Received: from mailhost.u-strasbg.fr (HELO mailhost.u-strasbg.fr) (130.79.222.218) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Wed, 04 Sep 2013 21:54:29 +0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-0.8 required=5.0 tests=AWL,BAYES_00,MSGID_MULTIPLE_AT autolearn=no version=3.3.2 X-HELO: mailhost.u-strasbg.fr Received: from mailhost.u-strasbg.fr (localhost [127.0.0.1]) by antispam (Postfix) with ESMTP id DE5F62205F4 for ; Wed, 4 Sep 2013 23:54:18 +0200 (CEST) Received: from mailhost.u-strasbg.fr (localhost [127.0.0.1]) by antivirus (Postfix) with ESMTP id CC35E22017E for ; Wed, 4 Sep 2013 23:54:18 +0200 (CEST) Received: from md13.u-strasbg.fr (md13.u-strasbg.fr [130.79.200.248]) by mr8.u-strasbg.fr (Postfix) with ESMTP id BC8732205F4 for ; Wed, 4 Sep 2013 23:54:17 +0200 (CEST) Received: from ms16.u-strasbg.fr (ms16.u-strasbg.fr [130.79.204.116]) by md13.u-strasbg.fr (8.14.3/jtpda-5.5pre1) with ESMTP id r84LsHKE010943 for ; Wed, 4 Sep 2013 23:54:17 +0200 (envelope-from pierre.muller@ics-cnrs.unistra.fr) Received: from E6510Muller (lec67-4-82-230-53-140.fbx.proxad.net [82.230.53.140]) (Authenticated sender: mullerp) by ms16.u-strasbg.fr (Postfix) with ESMTPSA id 5C1AB1FD8E for ; Wed, 4 Sep 2013 23:54:15 +0200 (CEST) From: "Pierre Muller" To: Subject: [RFC] Improve windows amd64 call command Date: Wed, 04 Sep 2013 21:54:00 -0000 Message-ID: <000301cea9b9$4b298820$e17c9860$@muller@ics-cnrs.unistra.fr> MIME-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit X-SW-Source: 2013-09/txt/msg00145.txt.bz2 Currently, mingw64 GDB does a poor job when it comes to handling call command. This is because it uses the SYS V ABI, while windows OS uses a separate ABI called Microsoft x64 calling convention in http://en.wikipedia.org/wiki/X86_calling_conventions#x86-64_calling_conventi ons This patch removes all failures in gdb.base/call*.exp when using x86_6'-w64-mingw32-gcc version 4.7.3, but some of those results might be GCC version dependent... It would also be nice to know what happens if a Microsoft compiler is used... The only regression I found in gdb.base is in varargs.exp: < FAIL: gdb.base/varargs.exp: print find_max_float_real(4, fc1, fc2, fc3, fc4) < FAIL: gdb.base/varargs.exp: print find_max_double_real(4, dc1, dc2, dc3, dc4) < FAIL: gdb.base/varargs.exp: print find_max_long_double_real(4, ldc1, ldc2, ldc3, ldc4) --- > FAIL: gdb.base/varargs.exp: print find_max_double(5,1.0,17.0,2.0,3.0,4.0) It's isn't a true regression, as there is only one failure instead of three, but the one failure seemed to pass without the change... I didn't investigate that yet. The overall change for gdb.base testsuite runs is 253 failures instead of 327 without the patch. Comments welcome, Pierre Muller GDB pascal language maintainer 2013-09-03 Pierre Muller * i386-tdep.h (struct gdbarch_tdep): Add new fields, neede to handle amd64 windows specfic calling conventions. * amd64-tdep.c (amd64_dummy_call_fp_regs): New array. (amd64_return_value): Add debug infrun information. (amd64_push_arguments): handle new fields of gdbarch_tdep structure. (amd64_push_dummy_call): Likewise. (amd64_init_abi): Initialize added fields. * amd64-windows-tdep.c (amd64_windows_dummy_call_fp_regs): New array. (amd64_windows_classify): Try to comply with Windows ABI. (amd64_windows_return_value): Do not use $xmm0 return register for "long double" return type. (amd64_windows_init_abi): Initialize new fields of gdbarch_tdep. Index: src/gdb/i386-tdep.h =================================================================== RCS file: /cvs/src/src/gdb/i386-tdep.h,v retrieving revision 1.82 diff -u -p -r1.82 i386-tdep.h --- src/gdb/i386-tdep.h 1 Jan 2013 06:32:45 -0000 1.82 +++ src/gdb/i386-tdep.h 4 Sep 2013 21:21:34 -0000 @@ -80,6 +80,10 @@ struct gdbarch_tdep are passed through the stack on x86. */ int call_dummy_num_integer_regs; int *call_dummy_integer_regs; + /* Used on amd64 only. The floating point registers used to pass + reals when making function calls. */ + int call_dummy_num_fp_regs; + int *call_dummy_fp_regs; /* Used on amd64 only. Classify TYPE according to calling conventions, and store the result in CLASS. */ @@ -104,6 +108,14 @@ struct gdbarch_tdep above). */ int integer_param_regs_saved_in_caller_frame; + /* Used on amd64 only. + + If non-zero, integer and floating point registers are coupled: + Either ECX or XMM0 are used as first register argument, + but second will be EDX or XMM1, never ECX nor XMM0, this + coupled behavior is used in Microsoft x64 ABI. */ + int integer_and_fp_regs_coupled; + /* Floating-point registers. */ struct regset *fpregset; size_t sizeof_fpregset; Index: src/gdb/amd64-tdep.c =================================================================== RCS file: /cvs/src/src/gdb/amd64-tdep.c,v retrieving revision 1.117 diff -u -p -r1.117 amd64-tdep.c --- src/gdb/amd64-tdep.c 1 Jan 2013 06:32:37 -0000 1.117 +++ src/gdb/amd64-tdep.c 4 Sep 2013 21:21:36 -0000 @@ -103,6 +103,16 @@ static int amd64_dummy_call_integer_regs 9 /* %r9 */ }; +/* The registers used to pass floating point arguments in function call. */ +static int amd64_dummy_call_fp_regs[] = +{ + /* %xmm0 ... %xmm7 */ + AMD64_XMM0_REGNUM + 0, AMD64_XMM1_REGNUM, + AMD64_XMM0_REGNUM + 2, AMD64_XMM0_REGNUM + 3, + AMD64_XMM0_REGNUM + 4, AMD64_XMM0_REGNUM + 5, + AMD64_XMM0_REGNUM + 6, AMD64_XMM0_REGNUM + 7, +}; + /* DWARF Register Number Mapping as defined in the System V psABI, section 3.6. */ @@ -650,6 +660,8 @@ amd64_return_value (struct gdbarch *gdba read_memory (addr, readbuf, TYPE_LENGTH (type)); } + if (debug_infrun) + printf_filtered (_("Return value as memory address in RAX\n")); return RETURN_VALUE_ABI_RETURNS_ADDRESS; } @@ -674,6 +686,8 @@ amd64_return_value (struct gdbarch *gdba regcache_raw_write_unsigned (regcache, AMD64_FTAG_REGNUM, 0xfff); } + if (debug_infrun) + printf_filtered (_("Complex X87 return value in ST0/ST1\n")); return RETURN_VALUE_REGISTER_CONVENTION; } @@ -739,6 +753,9 @@ amd64_return_value (struct gdbarch *gdba if (writebuf) regcache_raw_write_part (regcache, regnum, offset, min (len, 8), writebuf + i * 8); + if (debug_infrun) + printf_filtered (_("Return value in register %s\n"), + gdbarch_register_name (gdbarch, regnum)); } return RETURN_VALUE_REGISTER_CONVENTION; @@ -753,15 +770,10 @@ amd64_push_arguments (struct regcache *r struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); int *integer_regs = tdep->call_dummy_integer_regs; int num_integer_regs = tdep->call_dummy_num_integer_regs; + int *sse_regs = tdep->call_dummy_fp_regs; + int num_sse_regs = tdep->call_dummy_num_fp_regs; + int regs_coupled = tdep->integer_and_fp_regs_coupled; - static int sse_regnum[] = - { - /* %xmm0 ... %xmm7 */ - AMD64_XMM0_REGNUM + 0, AMD64_XMM1_REGNUM, - AMD64_XMM0_REGNUM + 2, AMD64_XMM0_REGNUM + 3, - AMD64_XMM0_REGNUM + 4, AMD64_XMM0_REGNUM + 5, - AMD64_XMM0_REGNUM + 6, AMD64_XMM0_REGNUM + 7, - }; struct value **stack_args = alloca (nargs * sizeof (struct value *)); /* An array that mirrors the stack_args array. For all arguments that are passed by MEMORY, if that argument's address also needs @@ -769,8 +781,10 @@ amd64_push_arguments (struct regcache *r that register number (or a negative value otherwise). */ int *arg_addr_regno = alloca (nargs * sizeof (int)); int num_stack_args = 0; - int num_elements = 0; - int element = 0; + int total_64bit_elements = 0; + int stack_64bit_elements = 0; + int indirect_element = 0; + int addr_element = 0; int integer_reg = 0; int sse_reg = 0; int i; @@ -798,19 +812,27 @@ amd64_push_arguments (struct regcache *r for (j = 0; j < 2; j++) { if (class[j] == AMD64_INTEGER) - needed_integer_regs++; + { + needed_integer_regs++; + if (regs_coupled) + needed_sse_regs++; + } else if (class[j] == AMD64_SSE) - needed_sse_regs++; + { + needed_sse_regs++; + if (regs_coupled) + needed_integer_regs++; + } } /* Check whether enough registers are available, and if the argument should be passed in registers at all. */ if (integer_reg + needed_integer_regs > num_integer_regs - || sse_reg + needed_sse_regs > ARRAY_SIZE (sse_regnum) + || sse_reg + needed_sse_regs > num_sse_regs || (needed_integer_regs == 0 && needed_sse_regs == 0)) { /* The argument will be passed on the stack. */ - num_elements += ((len + 7) / 8); + total_64bit_elements += ((len + 7) / 8); stack_args[num_stack_args] = args[i]; /* If this is an AMD64_MEMORY argument whose address must also be passed in one of the integer registers, reserve that @@ -818,11 +840,29 @@ amd64_push_arguments (struct regcache *r we can store the argument address as soon as we know it. */ if (class[0] == AMD64_MEMORY && tdep->memory_args_by_pointer - && integer_reg < tdep->call_dummy_num_integer_regs) - arg_addr_regno[num_stack_args] = - tdep->call_dummy_integer_regs[integer_reg++]; + && integer_reg < num_integer_regs) + { + arg_addr_regno[num_stack_args] = + tdep->call_dummy_integer_regs[integer_reg++]; + if (debug_infrun) + printf_filtered (_("Arg. %d (len=%d on stack)," + " addr. in register %s\n"), + i, len, gdbarch_register_name (gdbarch, + arg_addr_regno[num_stack_args])); + if (regs_coupled) + sse_reg++; + } else - arg_addr_regno[num_stack_args] = -1; + { + arg_addr_regno[num_stack_args] = -1; + if (tdep->memory_args_by_pointer + && len != 1 && len != 2 && len != 4 && len != 8) + total_64bit_elements += 1; + stack_64bit_elements += 1; + if (debug_infrun) + printf_filtered (_("Arg. %d (len=%d on stack)\n"), + i, len); + } num_stack_args++; } else @@ -842,15 +882,28 @@ amd64_push_arguments (struct regcache *r { case AMD64_INTEGER: regnum = integer_regs[integer_reg++]; + if (debug_infrun) + printf_filtered (_("Arg. %d in register %s\n"), + i, gdbarch_register_name (gdbarch, regnum)); + if (regs_coupled) + sse_reg++; break; case AMD64_SSE: - regnum = sse_regnum[sse_reg++]; + regnum = sse_regs[sse_reg++]; + if (debug_infrun) + printf_filtered (_("Arg. %d in register %s\n"), + i, gdbarch_register_name (gdbarch, regnum)); + if (regs_coupled) + integer_reg++; break; case AMD64_SSEUP: gdb_assert (sse_reg > 0); - regnum = sse_regnum[sse_reg - 1]; + if (debug_infrun) + printf_filtered (_("Arg. %d in register %s at offset 8\n"), + i, gdbarch_register_name (gdbarch, regnum)); + regnum = sse_regs[sse_reg - 1]; offset = 8; break; @@ -867,7 +920,7 @@ amd64_push_arguments (struct regcache *r } /* Allocate space for the arguments on the stack. */ - sp -= num_elements * 8; + sp -= total_64bit_elements * 8; /* The psABI says that "The end of the input argument area shall be aligned on a 16 byte boundary." */ @@ -878,9 +931,20 @@ amd64_push_arguments (struct regcache *r { struct type *type = value_type (stack_args[i]); const gdb_byte *valbuf = value_contents (stack_args[i]); - CORE_ADDR arg_addr = sp + element * 8; + int len = TYPE_LENGTH (type); + CORE_ADDR arg_addr; + int indirect = (arg_addr_regno[i] > 0) + || (tdep->memory_args_by_pointer + && len != 1 && len != 2 && len != 4 && len != 8); + if (indirect) + arg_addr = sp + (stack_64bit_elements + indirect_element) * 8; + else + arg_addr = sp + addr_element * 8; - write_memory (arg_addr, valbuf, TYPE_LENGTH (type)); + write_memory (arg_addr, valbuf, len); + if (debug_infrun) + printf_unfiltered (_("Stack arg. %d (len=%d) at addr. %s\n"), + i, len, paddress (gdbarch, arg_addr)); if (arg_addr_regno[i] >= 0) { /* We also need to store the address of that argument in @@ -890,8 +954,34 @@ amd64_push_arguments (struct regcache *r store_unsigned_integer (buf, 8, byte_order, arg_addr); regcache_cooked_write (regcache, arg_addr_regno[i], buf); + if (debug_infrun) + printf_unfiltered (_("Stack arg. %d addr. stored in reg. %s\n"), + i, gdbarch_register_name (gdbarch, + arg_addr_regno[i])); } - element += ((TYPE_LENGTH (type) + 7) / 8); + else if (indirect) + { + /* We also need to store the address of that argument in + the given register. */ + gdb_byte buf[8]; + enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); + CORE_ADDR arg_addrp = sp + addr_element * 8; + + store_unsigned_integer (buf, 8, byte_order, arg_addr); + write_memory (arg_addrp, buf, 8); + + if (debug_infrun) + printf_unfiltered (_("Stack arg. %d addr. stored at addr. %s\n"), + i, paddress (gdbarch, arg_addrp)); + } + if (indirect) + { + indirect_element += ((len + 7) / 8); + if (arg_addr_regno[i] < 0) + addr_element += 1; + } + else + addr_element += ((len + 7) / 8); } /* The psABI says that "For calls that may call functions that use @@ -899,7 +989,7 @@ amd64_push_arguments (struct regcache *r containing ellipsis (...) in the declaration) %al is used as hidden argument to specify the number of SSE registers used. */ regcache_raw_write_unsigned (regcache, AMD64_RAX_REGNUM, sse_reg); - return sp; + return sp; } static CORE_ADDR @@ -913,7 +1003,11 @@ amd64_push_dummy_call (struct gdbarch *g gdb_byte buf[8]; /* Pass arguments. */ + if (debug_infrun) + printf_unfiltered (_("Start sp=%s\n"), paddress (gdbarch, sp)); sp = amd64_push_arguments (regcache, nargs, args, sp, struct_return); + if (debug_infrun) + printf_unfiltered (_("sp after push args=%s\n"), paddress (gdbarch, sp)); /* Pass "hidden" argument". */ if (struct_return) @@ -929,19 +1023,33 @@ amd64_push_dummy_call (struct gdbarch *g /* Reserve some memory on the stack for the integer-parameter registers, if required by the ABI. */ if (tdep->integer_param_regs_saved_in_caller_frame) - sp -= tdep->call_dummy_num_integer_regs * 8; + { + sp -= tdep->call_dummy_num_integer_regs * 8; + if (debug_infrun) + printf_unfiltered (_("sp after integer reg. saved area=%s\n"), + paddress (gdbarch, sp)); + + } /* Store return address. */ sp -= 8; store_unsigned_integer (buf, 8, byte_order, bp_addr); write_memory (sp, buf, 8); + if (debug_infrun) + printf_unfiltered (_("Return addr. %s stored at %s\n"), + paddress (gdbarch, bp_addr), paddress (gdbarch, sp)); + /* Finally, update the stack pointer... */ store_unsigned_integer (buf, 8, byte_order, sp); regcache_cooked_write (regcache, AMD64_RSP_REGNUM, buf); + if (debug_infrun) + printf_unfiltered (_("Setting RSP to %s\n"), paddress (gdbarch, sp)); /* ...and fake a frame pointer. */ regcache_cooked_write (regcache, AMD64_RBP_REGNUM, buf); + if (debug_infrun) + printf_unfiltered (_("Setting RBP to %s\n"), paddress (gdbarch, sp)); return sp + 16; } @@ -2924,7 +3032,11 @@ amd64_init_abi (struct gdbarch_info info tdep->call_dummy_num_integer_regs = ARRAY_SIZE (amd64_dummy_call_integer_regs); tdep->call_dummy_integer_regs = amd64_dummy_call_integer_regs; + tdep->call_dummy_num_fp_regs = + ARRAY_SIZE (amd64_dummy_call_fp_regs); + tdep->call_dummy_fp_regs = amd64_dummy_call_fp_regs; tdep->classify = amd64_classify; + tdep->integer_and_fp_regs_coupled = 0; set_gdbarch_convert_register_p (gdbarch, i387_convert_register_p); set_gdbarch_register_to_value (gdbarch, i387_register_to_value); Index: src/gdb/amd64-windows-tdep.c =================================================================== RCS file: /cvs/src/src/gdb/amd64-windows-tdep.c,v retrieving revision 1.17 diff -u -p -r1.17 amd64-windows-tdep.c --- src/gdb/amd64-windows-tdep.c 2 Sep 2013 09:28:02 -0000 1.17 +++ src/gdb/amd64-windows-tdep.c 4 Sep 2013 21:21:36 -0000 @@ -31,6 +31,7 @@ #include "coff/i386.h" #include "coff/pe.h" #include "libcoff.h" +#include "buildsym.h" /* The registers used to pass integer arguments during a function call. */ static int amd64_windows_dummy_call_integer_regs[] = @@ -41,6 +42,14 @@ static int amd64_windows_dummy_call_inte 9 /* %r9 */ }; +/* The registers used to pass floating point arguments in function call. */ +static int amd64_windows_dummy_call_fp_regs[] = +{ + /* %xmm0 ... %xmm7 */ + AMD64_XMM0_REGNUM + 0, AMD64_XMM1_REGNUM, + AMD64_XMM0_REGNUM + 2, AMD64_XMM0_REGNUM + 3, +}; + /* Implement the "classify" method in the gdbarch_tdep structure for amd64-windows. */ @@ -64,13 +73,45 @@ amd64_windows_classify (struct type *typ || TYPE_LENGTH (type) == 4 || TYPE_LENGTH (type) == 8) { - class[0] = AMD64_INTEGER; - class[1] = AMD64_NO_CLASS; + if (TYPE_NFIELDS (type) == 1) + { + struct type *subtype = check_typedef ( + TYPE_FIELD_TYPE (type, 0)); + + amd64_windows_classify (subtype, class); + } + else + { + class[0] = AMD64_INTEGER; + class[1] = AMD64_NO_CLASS; + } } else class[0] = class[1] = AMD64_MEMORY; break; + /* Pass all complex types in memory. */ + case TYPE_CODE_COMPLEX: + if (TYPE_LENGTH (type) == 8) + { + class[0] = AMD64_INTEGER; + class[1] = AMD64_NO_CLASS; + } + else + class[0] = class[1] = AMD64_MEMORY; + break; + + case TYPE_CODE_FLT: + /* For "long double" type, + GNU C compiler still uses x87 coprocessor. + Parameters are passed by memory address. */ + if ((TYPE_CODE (type) == TYPE_CODE_FLT) + && (processing_gcc_compilation != 0) + && ((TYPE_LENGTH(type) == 12) || (TYPE_LENGTH(type) == 16))) + { + class[0] = class[1] = AMD64_MEMORY; + break; + } default: /* For all the other types, the conventions are the same as with the System V ABI. */ @@ -94,6 +135,11 @@ amd64_windows_return_value (struct gdbar { case TYPE_CODE_FLT: case TYPE_CODE_DECFLOAT: + /* GNU C compiler still uses coprocessor by default. */ + if ((TYPE_CODE (type) == TYPE_CODE_FLT) + && (processing_gcc_compilation != 0) + && ((len == 12) || (len == 16))) + break; /* __m128, __m128i, __m128d, floats, and doubles are returned via XMM0. */ if (len == 4 || len == 8 || len == 16) @@ -979,9 +1025,13 @@ amd64_windows_init_abi (struct gdbarch_i tdep->call_dummy_num_integer_regs = ARRAY_SIZE (amd64_windows_dummy_call_integer_regs); tdep->call_dummy_integer_regs = amd64_windows_dummy_call_integer_regs; + tdep->call_dummy_num_fp_regs = + ARRAY_SIZE (amd64_windows_dummy_call_fp_regs); + tdep->call_dummy_fp_regs = amd64_windows_dummy_call_fp_regs; tdep->classify = amd64_windows_classify; tdep->memory_args_by_pointer = 1; tdep->integer_param_regs_saved_in_caller_frame = 1; + tdep->integer_and_fp_regs_coupled = 1; set_gdbarch_return_value (gdbarch, amd64_windows_return_value); set_gdbarch_skip_main_prologue (gdbarch, amd64_skip_main_prologue); set_gdbarch_skip_trampoline_code (gdbarch,