From 5cc8a508d19e3474cba64583597c54d8f2f05e5e Mon Sep 17 00:00:00 2001 From: Joel Brobecker Date: Sat, 21 Sep 2013 00:56:12 +0200 Subject: [PATCH 2/2] Pierre's modifications for amd64-windows funcalls ... with some minor edits from Joel, mostly style, but with one bug correction (array return values). ChangeLog to provided later, as this patch should be broken down into individual pieces. --- gdb/amd64-windows-tdep.c | 157 ++++++++++++++++++++++++++++++++++----------- 1 files changed, 118 insertions(+), 39 deletions(-) diff --git a/gdb/amd64-windows-tdep.c b/gdb/amd64-windows-tdep.c index c09262a..b1a145f 100644 --- a/gdb/amd64-windows-tdep.c +++ b/gdb/amd64-windows-tdep.c @@ -32,6 +32,7 @@ #include "coff/pe.h" #include "libcoff.h" #include "value.h" +#include "inferior.h" /* The registers used to pass integer arguments during a function call. */ static int amd64_windows_dummy_call_integer_regs[] = @@ -43,6 +44,64 @@ static int amd64_windows_dummy_call_integer_regs[] = }; /* Return nonzero if an argument of type TYPE should be passed + via one of the XMM registers. */ + +static int +amd64_windows_passed_by_xmm_register (struct type *type) +{ + switch (TYPE_CODE (type)) + { + case TYPE_CODE_TYPEDEF: + return (TYPE_TARGET_TYPE (type) != NULL + && amd64_windows_passed_by_xmm_register + (TYPE_TARGET_TYPE (type))); + + case TYPE_CODE_STRUCT: + case TYPE_CODE_UNION: + return (TYPE_NFIELDS (type) == 1 + && amd64_windows_passed_by_xmm_register + (TYPE_FIELD_TYPE (type, 0))); + + case TYPE_CODE_FLT: + case TYPE_CODE_DECFLOAT: + return (TYPE_LENGTH (type) == 4 || TYPE_LENGTH (type) == 8); + + default: + return 0; + } +} + +/* Return nonzero if an return value of type TYPE should be passed + in XMM0 register. */ + +static int +amd64_windows_return_in_xmm0_register (struct type *type) +{ + if (amd64_windows_passed_by_xmm_register (type)) + return 1; + else + { + /* __m128, __m128d and __m128i types are returned in $xmm0 also. + But they are not stored in XMM registers as arguments, + at least not in GCC 4.7.6 x86_64-w64-mingw32 target. + Note: The TYPE_VECTOR check should prevent other arrays from + being treated as special xmm types. + Note: This all works for the "unique" __fastcall calling convention + as defined by Microsoft. The newer __vectorcall convention + does support passing __m128X type parameters in xmm registers + using /Gv option of Microsoft compilers. */ + struct type *ltype = check_typedef (type); + + return (ltype != NULL + && TYPE_CODE (ltype) == TYPE_CODE_ARRAY + && (TYPE_CODE (TYPE_TARGET_TYPE (ltype)) == TYPE_CODE_FLT + || TYPE_CODE (TYPE_TARGET_TYPE (ltype)) == TYPE_CODE_INT) + && TYPE_VECTOR (ltype) + && TYPE_LENGTH (ltype) == 16); + } +} + +/* Return nonzero if an argument of type TYPE should be passed via one of the integer registers. */ static int @@ -50,6 +109,25 @@ amd64_windows_passed_by_integer_register (struct type *type) { switch (TYPE_CODE (type)) { + case TYPE_CODE_TYPEDEF: + return (TYPE_TARGET_TYPE (type) != NULL + && amd64_windows_passed_by_integer_register + (TYPE_TARGET_TYPE (type))); + + case TYPE_CODE_STRUCT: + case TYPE_CODE_UNION: + /* If only one field, exclude float type accepted as xmm reg. */ + if (TYPE_NFIELDS (type) == 1) + { + struct type *ftype = TYPE_FIELD_TYPE (type, 0); + + if (amd64_windows_passed_by_xmm_register (ftype)) + return 0; + else + return amd64_windows_passed_by_integer_register (ftype); + } + /* Struct/Union with several fields: Pass Through. */ + case TYPE_CODE_INT: case TYPE_CODE_ENUM: case TYPE_CODE_BOOL: @@ -57,8 +135,7 @@ amd64_windows_passed_by_integer_register (struct type *type) case TYPE_CODE_CHAR: case TYPE_CODE_PTR: case TYPE_CODE_REF: - case TYPE_CODE_STRUCT: - case TYPE_CODE_UNION: + case TYPE_CODE_COMPLEX: return (TYPE_LENGTH (type) == 1 || TYPE_LENGTH (type) == 2 || TYPE_LENGTH (type) == 4 @@ -69,17 +146,6 @@ amd64_windows_passed_by_integer_register (struct type *type) } } -/* Return nonzero if an argument of type TYPE should be passed - via one of the XMM registers. */ - -static int -amd64_windows_passed_by_xmm_register (struct type *type) -{ - return ((TYPE_CODE (type) == TYPE_CODE_FLT - || TYPE_CODE (type) == TYPE_CODE_DECFLOAT) - && (TYPE_LENGTH (type) == 4 || TYPE_LENGTH (type) == 8)); -} - /* Return non-zero iff an argument of the given TYPE should be passed by pointer. */ @@ -103,7 +169,8 @@ amd64_windows_passed_by_pointer (struct type *type) the value of each argument. SP is value of the Stack Pointer. */ static CORE_ADDR -amd64_windows_adjust_args_passed_by_pointer (struct value **args, +amd64_windows_adjust_args_passed_by_pointer (struct gdbarch *gdbarch, + struct value **args, int nargs, CORE_ADDR sp) { int i; @@ -125,6 +192,10 @@ amd64_windows_adjust_args_passed_by_pointer (struct value **args, args[i] = value_addr (value_from_contents_and_address (type, valbuf, sp)); + if (debug_infrun) + printf_filtered ("Parameter #%d, length %d copied on stack" + " at address %s, and passed as pointer\n", + i, len, paddress (gdbarch, sp)); } return sp; @@ -134,8 +205,9 @@ amd64_windows_adjust_args_passed_by_pointer (struct value **args, REGCACHE is the register cache. */ static void -amd64_windows_store_arg_in_reg (struct regcache *regcache, - struct value *arg, int regno) +amd64_windows_store_arg_in_reg (struct gdbarch *gdbarch, + struct regcache *regcache, + struct value *arg, int regno, int i) { struct type *type = value_type (arg); const gdb_byte *valbuf = value_contents (arg); @@ -145,6 +217,10 @@ amd64_windows_store_arg_in_reg (struct regcache *regcache, memset (buf, 0, sizeof buf); memcpy (buf, valbuf, min (TYPE_LENGTH (type), 8)); regcache_cooked_write (regcache, regno, buf); + if (debug_infrun) + printf_filtered ("Parameter #%d, length %d copied to register %s\n", + i, TYPE_LENGTH (type), + i386_pseudo_register_name(gdbarch, regno)); } /* Push the arguments for an inferior function call, and return @@ -154,7 +230,8 @@ amd64_windows_store_arg_in_reg (struct regcache *regcache, amd64_windows_push_dummy_call. */ static CORE_ADDR -amd64_windows_push_arguments (struct regcache *regcache, int nargs, +amd64_windows_push_arguments (struct gdbarch *gdbarch, + struct regcache *regcache, int nargs, struct value **args, CORE_ADDR sp, int struct_return) { @@ -174,7 +251,8 @@ amd64_windows_push_arguments (struct regcache *regcache, int nargs, struct value **args1 = alloca (nargs * sizeof (struct value *)); memcpy (args1, args, nargs * sizeof (struct value *)); - sp = amd64_windows_adjust_args_passed_by_pointer (args1, nargs, sp); + sp = amd64_windows_adjust_args_passed_by_pointer (gdbarch, args1, + nargs, sp); args = args1; } @@ -193,20 +271,20 @@ amd64_windows_push_arguments (struct regcache *regcache, int nargs, if (amd64_windows_passed_by_integer_register (type)) { amd64_windows_store_arg_in_reg - (regcache, args[i], - amd64_windows_dummy_call_integer_regs[reg_idx]); + (gdbarch, regcache, args[i], + amd64_windows_dummy_call_integer_regs[reg_idx], i); on_stack_p = 0; reg_idx++; } else if (amd64_windows_passed_by_xmm_register (type)) { amd64_windows_store_arg_in_reg - (regcache, args[i], AMD64_XMM0_REGNUM + reg_idx); + (gdbarch, regcache, args[i], AMD64_XMM0_REGNUM + reg_idx, i); /* In case of varargs, these parameters must also be passed via the integer registers. */ amd64_windows_store_arg_in_reg - (regcache, args[i], - amd64_windows_dummy_call_integer_regs[reg_idx]); + (gdbarch, regcache, args[i], + amd64_windows_dummy_call_integer_regs[reg_idx], i); on_stack_p = 0; reg_idx++; } @@ -231,6 +309,11 @@ amd64_windows_push_arguments (struct regcache *regcache, int nargs, const gdb_byte *valbuf = value_contents (stack_args[i]); write_memory (sp + element * 8, valbuf, TYPE_LENGTH (type)); + if (debug_infrun) + printf_filtered ("Parameter #%d, length %d copied on stack" + " at address %s\n", + i, TYPE_LENGTH (type), + paddress (gdbarch, sp + element * 8)); element += ((TYPE_LENGTH (type) + 7) / 8); } @@ -250,7 +333,7 @@ amd64_windows_push_dummy_call gdb_byte buf[8]; /* Pass arguments. */ - sp = amd64_windows_push_arguments (regcache, nargs, args, sp, + sp = amd64_windows_push_arguments (gdbarch, regcache, nargs, args, sp, struct_return); /* Pass "hidden" argument". */ @@ -295,21 +378,12 @@ amd64_windows_return_value (struct gdbarch *gdbarch, struct value *function, /* See if our value is returned through a register. If it is, then store the associated register number in REGNUM. */ - switch (TYPE_CODE (type)) + if (amd64_windows_return_in_xmm0_register (type)) + regnum = AMD64_XMM0_REGNUM; + else if (len == 1 || len == 2 || len == 4 || len == 8) { - case TYPE_CODE_FLT: - case TYPE_CODE_DECFLOAT: - /* __m128, __m128i, __m128d, floats, and doubles are returned - via XMM0. */ - if (len == 4 || len == 8 || len == 16) - regnum = AMD64_XMM0_REGNUM; - break; - default: - /* All other values that are 1, 2, 4 or 8 bytes long are returned - via RAX. */ - if (len == 1 || len == 2 || len == 4 || len == 8) - regnum = AMD64_RAX_REGNUM; - break; + /* All values of this size are returned via RAX. */ + regnum = AMD64_RAX_REGNUM; } if (regnum < 0) @@ -322,8 +396,10 @@ amd64_windows_return_value (struct gdbarch *gdbarch, struct value *function, regcache_raw_read_unsigned (regcache, AMD64_RAX_REGNUM, &addr); 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; - } + } else { /* Extract the return value from the register where it was stored. */ @@ -331,6 +407,9 @@ amd64_windows_return_value (struct gdbarch *gdbarch, struct value *function, regcache_raw_read_part (regcache, regnum, 0, len, readbuf); if (writebuf) regcache_raw_write_part (regcache, regnum, 0, len, writebuf); + if (debug_infrun) + printf_filtered ("Return value in register %s\n", + gdbarch_register_name (gdbarch, regnum)); return RETURN_VALUE_REGISTER_CONVENTION; } } -- 1.6.6.1