This is the mail archive of the
gdb-patches@sourceware.org
mailing list for the GDB project.
RE: [RFC] Improve windows amd64 call command
- From: "Pierre Muller" <pierre dot muller at ics-cnrs dot unistra dot fr>
- To: "'Joel Brobecker'" <brobecker at adacore dot com>
- Cc: <gdb-patches at sourceware dot org>
- Date: Fri, 13 Sep 2013 23:55:32 +0200
- Subject: RE: [RFC] Improve windows amd64 call command
- Authentication-results: sourceware.org; auth=none
- References: <000301cea9b9$4b298820$e17c9860$ at muller@ics-cnrs.unistra.fr> <20130904220309 dot GA3226 at adacore dot com>
I tried to merge the two patches
and I will send a new RFA in
the other thread.
Pierre Muller
> -----Message d'origine-----
> De : gdb-patches-owner@sourceware.org [mailto:gdb-patches-
> owner@sourceware.org] De la part de Joel Brobecker
> Envoyé : jeudi 5 septembre 2013 00:03
> À : Pierre Muller
> Cc : gdb-patches@sourceware.org
> Objet : Re: [RFC] Improve windows amd64 call command
>
> > 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
>
> Hi Pierre. I think you patch is the same as the first one I initially
> proposed, and got rejected by Mark saying that we should really have our
> own separate code for Windows as the two ABIs are really completely
> different. Since then, I've re-implemented the calling convention
> following that advice. The patch is posted at:
> http://www.sourceware.org/ml/gdb-patches/2013-01/msg00332.html
>
> I cannot believe it was 8 months ago! I was waiting on Mark's input,
> and then meant to just go ahead and finish it up, and since then,
> life has taken over.
>
> Can you try my patch and see if it works as well for you? (assuming
> it still applies - otherwise, I will rebase for you tomorrow).
> If not, we could work together to finalize it and get it in for
> everyone to enjoy.
>
> >
> > 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 <muller@sourceware.org>
> >
> > * 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,
>
> --
> Joel