[RFA 2/2] amd64-windows: Arguments passed by pointer

Joel Brobecker
2012-10-24T17:23:57Z

This patch provides support for arguments passed by pointer in
inferior function calls.

gdb/ChangeLog:

* i386-tdep.h (struct gdbarch_tdep): Add new field
"handle_args_passed_by_pointer".
* amd64-tdep.c (amd64_push_arguments): Add handling of
arguments to be passed by pointer.
* amd64-windows-tdep.c: #include "value.h".
(amd64_windows_passed_by_pointer): New function.
(amd64_windows_handle_args_passed_by_pointer): New function.
(amd64_windows_init_abi): Set tdep->handle_args_passed_by_pointer.

Tested on amd64-windows and amd64-linux.
OK to commit?

Thanks,
--
Joel

---
gdb/amd64-tdep.c | 12 +++++++++++
gdb/amd64-windows-tdep.c | 53 ++++++++++++++++++++++++++++++++++++++++++++++
gdb/i386-tdep.h | 14 ++++++++++++
3 files changed, 79 insertions(+)

diff --git a/gdb/amd64-tdep.c b/gdb/amd64-tdep.c
index c6ee493..d464a35 100644
--- a/gdb/amd64-tdep.c
+++ b/gdb/amd64-tdep.c
@@ -771,6 +771,18 @@ amd64_push_arguments (struct regcache *regcache, int nargs,

gdb_assert (tdep->classify);

+ if (tdep->handle_args_passed_by_pointer)
+ {
+ /* Make a copy of the array of arguments, and let
+ handle_args_passed_by_pointer transform those that need
+ to be passed by pointer. */
+ struct value **args1 = alloca (nargs * sizeof (struct value *));
+
+ memcpy (args1, args, nargs * sizeof (struct value *));
+ sp = tdep->handle_args_passed_by_pointer (args1, nargs, sp);
+ args = args1;
+ }
+
/* Reserve a register for the "hidden" argument. */
if (struct_return)
integer_reg++;
diff --git a/gdb/amd64-windows-tdep.c b/gdb/amd64-windows-tdep.c
index 3e8a830..0b616f3 100644
--- a/gdb/amd64-windows-tdep.c
+++ b/gdb/amd64-windows-tdep.c
@@ -25,6 +25,7 @@
#include "regcache.h"
#include "windows-tdep.h"
#include "frame.h"
+#include "value.h"

/* The registers used to pass integer arguments during a function call. */
static int amd64_windows_dummy_call_integer_regs[] =
@@ -35,6 +36,56 @@ static int amd64_windows_dummy_call_integer_regs[] =
9 /* %r9 */
};

+/* Return non-zero iff an argument of the given TYPE should be passed
+ by pointer. */
+
+static int
+amd64_windows_passed_by_pointer (struct type *type)
+{
+ /* Only structs and unions are passed by pointer. */
+ if (TYPE_CODE (type) != TYPE_CODE_STRUCT
+ && TYPE_CODE (type) != TYPE_CODE_UNION)
+ return 0;
+
+ /* Among these, only struct/unions whose size is different from
+ 1, 2, 4 or 8 bytes are passed by pointer. */
+ return (TYPE_LENGTH (type) != 1
+ && TYPE_LENGTH (type) != 2
+ && TYPE_LENGTH (type) != 4
+ && TYPE_LENGTH (type) != 8);
+}
+
+/* Implement the "handle_args_passed_by_pointer" in the gdbarch_tdep
+ structure for amd64-windows. */
+
+static CORE_ADDR
+amd64_windows_handle_args_passed_by_pointer (struct value **args,
+ int nargs, CORE_ADDR sp)
+{
+ int i;
+
+ for (i = 0; i < nargs; i++)
+ if (amd64_windows_passed_by_pointer (value_type (args[i])))
+ {
+ struct type *type = value_type (args[i]);
+ const gdb_byte *valbuf = value_contents (args[i]);
+ const int len = TYPE_LENGTH (type);
+
+ /* Store a copy of that argument on the stack, aligned to
+ a 16 bytes boundary, and then use the copy's address as
+ the argument. */
+
+ sp -= len;
+ sp &= ~0xf;
+ write_memory (sp, valbuf, len);
+
+ args[i] =
+ value_addr (value_from_contents_and_address (type, valbuf, sp));
+ }
+
+ return sp;
+}
+
/* Implement the "classify" method in the gdbarch_tdep structure
for amd64-windows. */

@@ -212,6 +263,8 @@ amd64_windows_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
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->handle_args_passed_by_pointer =
+ amd64_windows_handle_args_passed_by_pointer;
tdep->classify = amd64_windows_classify;
tdep->integer_param_regs_saved_in_caller_frame = 1;
set_gdbarch_return_value (gdbarch, amd64_windows_return_value);
diff --git a/gdb/i386-tdep.h b/gdb/i386-tdep.h
index 01b0936..ce38600 100644
--- a/gdb/i386-tdep.h
+++ b/gdb/i386-tdep.h
@@ -81,6 +81,20 @@ struct gdbarch_tdep
int call_dummy_num_integer_regs;
int *call_dummy_integer_regs;

+ /* Only used on platforms where some arguments are to be passed
+ by pointer (the caller is expected to make a copy of the argument
+ and then pass its address as the argument).
+
+ For each argument that should be passed by pointer, reserve some
+ stack space, store a copy of the argument on the stack, and replace
+ the argument by its address. Return the new Stack Pointer value.
+
+ NARGS is the number of arguments. ARGS is the array containing
+ the value of each argument. SP is value of the Stack Pointer. */
+
+ CORE_ADDR (*handle_args_passed_by_pointer) (struct value **args,
+ int nargs, CORE_ADDR sp);
+
/* Used on amd64 only. Classify TYPE according to calling conventions,
and store the result in CLASS. */
void (*classify) (struct type *type, enum amd64_reg_class class[2]);
--
1.7.9.5