Fwd: [patch] Set calling convention of methods

Jonas Maebe
2009-06-18T21:45:00Z

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

Ping.

Begin forwarded message:

> From: Jonas Maebe <jonas.maebe@elis.ugent.be>
> Date: Wed 10 Jun 2009 22:44:23 GMT+02:00
> To: tromey@redhat.com
> Cc: Mark Kettenis <mark.kettenis@xs4all.nl>, gdb-
> patches@sourceware.org
> Subject: Re: [patch] Set calling convention of methods
>
>
> 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: 3 bytes --]

>