Re: [patch] Set calling convention of methods

Jonas Maebe
2009-07-06T20:50:47Z

[-- Attachment #1: Type: text/plain, Size: 1650 bytes --]

Ping.

On 04 Jun 2009, at 20:17, Tom Tromey wrote:

>>>>>> "Jonas" == Jonas Maebe <jonas.maebe@elis.ugent.be> writes:
>
> Jonas> It took quite a while, but I'm happy to say that my copyright
> Jonas> assignment is now complete. I've received my confirmation
> mail from
> Jonas> FSF that they received all necessary documents.
>
> Thanks. Could you send the URLs of the last versions of your pending
> patches? That would help.

I've attached my first patch. Other patches will modify code in this
one, so I'd prefer to get this one out of the way first.

To Mark: it's slightly different from the last one that I previously
sent you. There was still a bug whereby the address of the complex
function result was pushed in the wrong order in case it has to passed
on the stack (parameters are pushed from right to right, and the
function result should be pushed before the rightmost parameter rather
than after the leftmost). Hence, I moved the code to push the function
result address from the end to the start of the loop pushing the
memory parameter.

This patch is against the current git://sourceware.org/git/gdb.git

Thanks,

Jonas

2009-06-10 Jonas Maebe <jonas.maebe@elis.ugent.be>

Add support for the "Borland fastcall" calling convention.

* elf/dwarf2.h: Add DW_CC_GNU_borland_fastcall_i386 constant.
* i386-tdep.c: #include elf/dwarf2.h
(i386_borland_fastcall_push_dummy_call): New.
(i386_push_dummy_generic_call): Renamed i386_push_dummy_call.
(i386_push_dummy_call): New dispatch function that calls
i386_generic_push_dummy_call or i386_push_dummy_borland_fast_call
depending on the calling convention.

[-- Attachment #2: gdb_borland_fastcall5.patch --]
[-- Type: application/octet-stream, Size: 7655 bytes --]

diff --git a/gdb/i386-tdep.c b/gdb/i386-tdep.c
index 60526b0..d559707 100644
--- a/gdb/i386-tdep.c
+++ b/gdb/i386-tdep.c
@@ -53,6 +53,8 @@
#include "record.h"
#include <stdint.h>

+#include "elf/dwarf2.h"
+
/* Register names. */

static char *i386_register_names[] =
@@ -1408,7 +1410,7 @@ i386_frame_this_id (struct frame_info *this_frame, void **this_cache,
if (cache->base == 0)
return;

- /* See the end of i386_push_dummy_call. */
+ /* See the end of i386_generic_push_dummy_call. */
(*this_id) = frame_id_build (cache->base + 8, cache->pc);
}

@@ -1517,7 +1519,7 @@ i386_sigtramp_frame_this_id (struct frame_info *this_frame, void **this_cache,
struct i386_frame_cache *cache =
i386_sigtramp_frame_cache (this_frame, this_cache);

- /* See the end of i386_push_dummy_call. */
+ /* See the end of i386_generic_push_dummy_call. */
(*this_id) = frame_id_build (cache->base + 8, get_frame_pc (this_frame));
}

@@ -1594,7 +1596,7 @@ i386_dummy_id (struct gdbarch *gdbarch, struct frame_info *this_frame)

fp = get_frame_register_unsigned (this_frame, I386_EBP_REGNUM);

- /* See the end of i386_push_dummy_call. */
+ /* See the end of i386_generic_push_dummy_call. */
return frame_id_build (fp + 8, get_frame_pc (this_frame));
}
\f
@@ -1661,10 +1663,10 @@ i386_16_byte_align_p (struct type *type)
}

static CORE_ADDR
-i386_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
- struct regcache *regcache, CORE_ADDR bp_addr, int nargs,
- struct value **args, CORE_ADDR sp, int struct_return,
- CORE_ADDR struct_addr)
+i386_generic_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
+ struct regcache *regcache, CORE_ADDR bp_addr,
+ int nargs, struct value **args, CORE_ADDR sp,
+ int struct_return, CORE_ADDR struct_addr)
{
gdb_byte buf[4];
int i;
@@ -1756,6 +1758,162 @@ i386_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
return sp + 8;
}

+/* Borland fastcall: register parameters are passed from left to right, then
+ stack parameters also from left to right. The first three unstructured
+ parameters <= 32 bits are passed in %eax, %edx and %ecx. The others are
+ passed on the stack. Furthermore, in case of a struct return by reference,
+ the address of this struct is passed as the last parameter. */
+static CORE_ADDR
+i386_borland_fastcall_push_dummy_call (struct gdbarch *gdbarch,
+ struct value *function,
+ struct regcache *regcache,
+ CORE_ADDR bp_addr, int nargs,
+ struct value **args, CORE_ADDR sp,
+ int struct_return, CORE_ADDR struct_addr)
+{
+ static const int para_regs[3] = { I386_EAX_REGNUM, I386_EDX_REGNUM,
+ I386_ECX_REGNUM };
+
+ gdb_byte buf[4];
+ int reg_paras[3] = { -1, -1, -1 };
+ int i, j;
+ int write_pass;
+ int para_regnum = 0;
+
+ /* First assign the register parameters (left to right). */
+ for (i = 0; i < nargs && para_regnum < 3; i++)
+ {
+ struct type *type = check_typedef (value_enclosing_type (args[i]));
+ int len = TYPE_LENGTH (type);
+
+ if (len <= 4
+ && TYPE_CODE (type) != TYPE_CODE_ARRAY
+ && TYPE_CODE (type) != TYPE_CODE_STRUCT
+ && TYPE_CODE (type) != TYPE_CODE_FLT)
+ {
+ regcache_cooked_write (regcache, para_regs[para_regnum],
+ value_contents_all (args[i]));
+ reg_paras[para_regnum] = i;
+ para_regnum++;
+ }
+ }
+ if (struct_return)
+ {
+ if (para_regnum < 3)
+ {
+ store_unsigned_integer (buf, 4, struct_addr);
+ regcache_cooked_write (regcache, para_regs[para_regnum],
+ buf);
+ /* Use the otherwise invalid "nargs" argument index to denote the
+ function result. */
+ reg_paras[para_regnum] = nargs;
+ para_regnum++;
+ }
+ }
+
+ /* Now process the stack parameters from left to right. */
+ for (write_pass = 0; write_pass < 2; write_pass++)
+ {
+ int args_space = 0;
+ int have_16_byte_aligned_arg = 0;
+
+ /* If we have a struct_return then para_regnum cannot be 0, since at
+ least this return struct would have been passed in a register.
+ Additionally, if it is passed via a register, it will always be in
+ the last used position of the reg_paras array. */
+ if (struct_return
+ && reg_paras[para_regnum-1] != nargs)
+ {
+ if (write_pass)
+ {
+ /* Push value address. */
+ store_unsigned_integer (buf, 4, struct_addr);
+ write_memory (sp + args_space, buf, 4);
+ }
+ args_space += 4;
+ }
+
+ for (i = nargs - 1; i >= 0; i--)
+ {
+ struct type *type = check_typedef (value_enclosing_type (args[i]));
+ int len = TYPE_LENGTH (type);
+ int processed = 0;
+
+ /* Skip parameters already assigned to registers. */
+ for (j = 0; j < para_regnum; j++)
+ if (reg_paras[j] == i)
+ {
+ processed = 1;
+ break;
+ }
+ if (processed)
+ continue;
+
+ if (i386_16_byte_align_p (value_enclosing_type (args[i])))
+ {
+ args_space = align_up (args_space, 16);
+ have_16_byte_aligned_arg = 1;
+ }
+ if (write_pass)
+ {
+ write_memory (sp + args_space,
+ value_contents_all (args[i]), len);
+ }
+ args_space += align_up (len, 4);
+ }
+
+ if (!write_pass)
+ {
+ /* Early exit if nothing to do. */
+ if (!args_space)
+ break;
+ if (have_16_byte_aligned_arg)
+ args_space = align_up (args_space, 16);
+ sp -= args_space;
+ }
+ }
+
+ /* Store return address. */
+ sp -= 4;
+ store_unsigned_integer (buf, 4, bp_addr);
+ write_memory (sp, buf, 4);
+
+ /* Finally, update the stack pointer... */
+ store_unsigned_integer (buf, 4, sp);
+ regcache_cooked_write (regcache, I386_ESP_REGNUM, buf);
+
+ /* ...and fake a frame pointer. */
+ regcache_cooked_write (regcache, I386_EBP_REGNUM, buf);
+
+ /* See the end of i386_generic_push_dummy_call. */
+ return sp + 8;
+}
+
+static CORE_ADDR
+i386_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
+ struct regcache *regcache, CORE_ADDR bp_addr, int nargs,
+ struct value **args, CORE_ADDR sp, int struct_return,
+ CORE_ADDR struct_addr)
+{
+ struct type *type = check_typedef (value_type (function));
+
+ /* Look up the target type in case of a function/method pointer. */
+ while (type
+ && can_dereference (type))
+ type = TYPE_TARGET_TYPE (type);
+
+ /* Check calling convention. */
+ if (type
+ && TYPE_CALLING_CONVENTION (type) == DW_CC_GNU_borland_fastcall_i386)
+ return i386_borland_fastcall_push_dummy_call (gdbarch, function, regcache,
+ bp_addr, nargs, args, sp,
+ struct_return, struct_addr);
+ else
+ return i386_generic_push_dummy_call (gdbarch, function, regcache, bp_addr,
+ nargs, args, sp, struct_return,
+ struct_addr);
+}
+
/* These registers are used for returning integers (and on some
targets also for returning `struct' and `union' values when their
size and alignment match an integer type). */
diff --git a/include/elf/dwarf2.h b/include/elf/dwarf2.h
index a7448dc..efa786e 100644
--- a/include/elf/dwarf2.h
+++ b/include/elf/dwarf2.h
@@ -662,7 +662,8 @@ enum dwarf_calling_convention
DW_CC_normal = 0x1,
DW_CC_program = 0x2,
DW_CC_nocall = 0x3,
- DW_CC_GNU_renesas_sh = 0x40
+ DW_CC_GNU_renesas_sh = 0x40,
+ DW_CC_GNU_borland_fastcall_i386 = 0x41
};

#define DW_CC_lo_user 0x40

[-- Attachment #3: Type: text/plain, Size: 1 bytes --]