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 +#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)); } @@ -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