#include "x86-64-tdep.h"
#include "i387-tdep.h"
-/* Register numbers of various important registers. */
-
-#define X86_64_RAX_REGNUM 0 /* %rax */
-#define X86_64_RDX_REGNUM 3 /* %rdx */
-#define X86_64_RDI_REGNUM 5 /* %rdi */
-#define X86_64_RBP_REGNUM 6 /* %rbp */
-#define X86_64_RSP_REGNUM 7 /* %rsp */
-#define X86_64_RIP_REGNUM 16 /* %rip */
-#define X86_64_EFLAGS_REGNUM 17 /* %eflags */
-#define X86_64_ST0_REGNUM 22 /* %st0 */
-#define X86_64_XMM0_REGNUM 38 /* %xmm0 */
-#define X86_64_XMM1_REGNUM 39 /* %xmm1 */
+/* Register information. */
struct x86_64_register_info
{
static int x86_64_dwarf_regmap[] =
{
/* General Purpose Registers RAX, RDX, RCX, RBX, RSI, RDI. */
- X86_64_RAX_REGNUM, X86_64_RDX_REGNUM, 3, 2,
+ X86_64_RAX_REGNUM, X86_64_RDX_REGNUM, 2, 1,
4, X86_64_RDI_REGNUM,
/* Frame Pointer Register RBP. */
return regnum;
}
+
+/* Return nonzero if a value of type TYPE stored in register REGNUM
+ needs any special handling. */
+
+static int
+x86_64_convert_register_p (int regnum, struct type *type)
+{
+ return i386_fp_regnum_p (regnum);
+}
\f
/* The returning of values is done according to the special algorithm.
{
int intreg = 0;
int ssereg = 0;
+ /* For varargs functions we have to pass the total number of SSE
+ registers used in %rax. So, let's count this number. */
+ int total_sse_args = 0;
+ /* Once an SSE/int argument is passed on the stack, all subsequent
+ arguments are passed there. */
+ int sse_stack = 0;
+ int int_stack = 0;
+ unsigned total_sp;
int i;
+ char buf[8];
static int int_parameter_registers[INT_REGS] =
{
X86_64_RDI_REGNUM, 4, /* %rdi, %rsi */
int stack_values_count = 0;
int *stack_values;
stack_values = alloca (nargs * sizeof (int));
+
+ /* Before storing anything to the stack we must skip
+ the "Red zone" (see the "Function calling sequence" section
+ of AMD64 ABI).
+ It could have already been skipped in the function's
+ prologue, but we don't care and will easily skip it once again. */
+ sp -= 128;
+
for (i = 0; i < nargs; i++)
{
enum x86_64_reg_class class[MAX_CLASSES];
int needed_sseregs;
if (!n ||
- !examine_argument (class, n, &needed_intregs, &needed_sseregs)
- || intreg / 2 + needed_intregs > INT_REGS
- || ssereg / 2 + needed_sseregs > SSE_REGS)
+ !examine_argument (class, n, &needed_intregs, &needed_sseregs))
{ /* memory class */
stack_values[stack_values_count++] = i;
}
else
{
int j;
+ int offset = 0;
+
+ if (intreg / 2 + needed_intregs > INT_REGS)
+ int_stack = 1;
+ if (ssereg / 2 + needed_sseregs > SSE_REGS)
+ sse_stack = 1;
+ if (!sse_stack)
+ total_sse_args += needed_sseregs;
+
for (j = 0; j < n; j++)
{
- int offset = 0;
switch (class[j])
{
case X86_64_NO_CLASS:
break;
case X86_64_INTEGER_CLASS:
- regcache_cooked_write
- (regcache, int_parameter_registers[(intreg + 1) / 2],
- VALUE_CONTENTS_ALL (args[i]) + offset);
- offset += 8;
- intreg += 2;
+ if (int_stack)
+ stack_values[stack_values_count++] = i;
+ else
+ {
+ regcache_cooked_write
+ (regcache, int_parameter_registers[(intreg + 1) / 2],
+ VALUE_CONTENTS_ALL (args[i]) + offset);
+ offset += 8;
+ intreg += 2;
+ }
break;
case X86_64_INTEGERSI_CLASS:
- {
- LONGEST val = extract_signed_integer
- (VALUE_CONTENTS_ALL (args[i]) + offset, 4);
- regcache_cooked_write_signed
- (regcache, int_parameter_registers[intreg / 2], val);
-
- offset += 8;
- intreg++;
- break;
- }
+ if (int_stack)
+ stack_values[stack_values_count++] = i;
+ else
+ {
+ LONGEST val = extract_signed_integer
+ (VALUE_CONTENTS_ALL (args[i]) + offset, 4);
+ regcache_cooked_write_signed
+ (regcache, int_parameter_registers[intreg / 2], val);
+
+ offset += 8;
+ intreg++;
+ }
+ break;
case X86_64_SSEDF_CLASS:
case X86_64_SSESF_CLASS:
case X86_64_SSE_CLASS:
- regcache_cooked_write
- (regcache, sse_parameter_registers[(ssereg + 1) / 2],
- VALUE_CONTENTS_ALL (args[i]) + offset);
- offset += 8;
- ssereg += 2;
+ if (sse_stack)
+ stack_values[stack_values_count++] = i;
+ else
+ {
+ regcache_cooked_write
+ (regcache, sse_parameter_registers[(ssereg + 1) / 2],
+ VALUE_CONTENTS_ALL (args[i]) + offset);
+ offset += 8;
+ ssereg += 2;
+ }
break;
case X86_64_SSEUP_CLASS:
- regcache_cooked_write
- (regcache, sse_parameter_registers[ssereg / 2],
- VALUE_CONTENTS_ALL (args[i]) + offset);
- offset += 8;
- ssereg++;
+ if (sse_stack)
+ stack_values[stack_values_count++] = i;
+ else
+ {
+ regcache_cooked_write
+ (regcache, sse_parameter_registers[ssereg / 2],
+ VALUE_CONTENTS_ALL (args[i]) + offset);
+ offset += 8;
+ ssereg++;
+ }
break;
case X86_64_X87_CLASS:
case X86_64_MEMORY_CLASS:
}
}
+ /* We have to make sure that the stack is 16-byte aligned after the
+ setup. Let's calculate size of arguments first, align stack and
+ then fill in the arguments. */
+ total_sp = 0;
+ for (i = 0; i < stack_values_count; i++)
+ {
+ struct value *arg = args[stack_values[i]];
+ int len = TYPE_LENGTH (VALUE_ENCLOSING_TYPE (arg));
+ total_sp += (len + 7) & ~7;
+ }
+ /* total_sp is now a multiple of 8, if it is not a multiple of 16,
+ change the stack pointer so that it will be afterwards correctly
+ aligned. */
+ if (total_sp & 15)
+ sp -= 8;
+
/* Push any remaining arguments onto the stack. */
while (--stack_values_count >= 0)
{
struct value *arg = args[stack_values[stack_values_count]];
int len = TYPE_LENGTH (VALUE_ENCLOSING_TYPE (arg));
- /* Make sure the stack stays eightbyte-aligned. */
+ /* Make sure the stack is 8-byte-aligned. */
sp -= (len + 7) & ~7;
write_memory (sp, VALUE_CONTENTS_ALL (arg), len);
}
+ /* Write number of SSE type arguments to RAX to take care of varargs
+ functions. */
+ store_unsigned_integer (buf, 8, total_sse_args);
+ regcache_cooked_write (regcache, X86_64_RAX_REGNUM, buf);
+
return sp;
}
{
int len = TYPE_LENGTH (type);
- if (TYPE_CODE_FLT == TYPE_CODE (type))
+ /* First handle long doubles. */
+ if (TYPE_CODE_FLT == TYPE_CODE (type) && len == 16)
{
ULONGEST fstat;
char buf[FPU_REG_RAW_SIZE];
for the tag word is 0x3fff. */
regcache_raw_write_unsigned (regcache, FTAG_REGNUM, 0x3fff);
}
+ else if (TYPE_CODE_FLT == TYPE_CODE (type))
+ {
+ /* Handle double and float variables. */
+ regcache_cooked_write_part (regcache, X86_64_XMM0_REGNUM,
+ 0, len, valbuf);
+ }
+ /* XXX: What about complex floating point types? */
else
{
int low_size = REGISTER_RAW_SIZE (0);
\f
static CORE_ADDR
-x86_64_push_dummy_call (struct gdbarch *gdbarch, struct regcache *regcache,
- CORE_ADDR dummy_addr, int nargs, struct value **args,
- CORE_ADDR sp, int struct_return, CORE_ADDR struct_addr)
+x86_64_push_dummy_call (struct gdbarch *gdbarch, CORE_ADDR func_addr,
+ struct regcache *regcache, CORE_ADDR bp_addr,
+ int nargs, struct value **args, CORE_ADDR sp,
+ int struct_return, CORE_ADDR struct_addr)
{
char buf[8];
/* Store return address. */
sp -= 8;
- store_unsigned_integer (buf, 8, dummy_addr);
+ store_unsigned_integer (buf, 8, bp_addr);
write_memory (sp, buf, 8);
/* Finally, update the stack pointer... */
/* ...and fake a frame pointer. */
regcache_cooked_write (regcache, X86_64_RBP_REGNUM, buf);
- return sp;
+ return sp + 16;
}
\f
};
static const struct frame_unwind *
-x86_64_frame_p (CORE_ADDR pc)
+x86_64_frame_sniffer (struct frame_info *next_frame)
{
return &x86_64_frame_unwind;
}
};
static const struct frame_unwind *
-x86_64_sigtramp_frame_p (CORE_ADDR pc)
+x86_64_sigtramp_frame_sniffer (struct frame_info *next_frame)
{
+ CORE_ADDR pc = frame_pc_unwind (next_frame);
char *name;
find_pc_partial_function (pc, &name, NULL, NULL);
if (PC_IN_SIGTRAMP (pc, name))
- return &x86_64_sigtramp_frame_unwind;
+ {
+ gdb_assert (gdbarch_tdep (current_gdbarch)->sigcontext_addr);
+
+ return &x86_64_sigtramp_frame_unwind;
+ }
return NULL;
}
x86_64_frame_base_address
};
-static void
-x86_64_save_dummy_frame_tos (CORE_ADDR sp)
-{
- generic_save_dummy_frame_tos (sp + 16);
-}
-
static struct frame_id
x86_64_unwind_dummy_id (struct gdbarch *gdbarch, struct frame_info *next_frame)
{
/* Call dummy code. */
set_gdbarch_push_dummy_call (gdbarch, x86_64_push_dummy_call);
+ set_gdbarch_convert_register_p (gdbarch, x86_64_convert_register_p);
+ set_gdbarch_register_to_value (gdbarch, i387_register_to_value);
+ set_gdbarch_value_to_register (gdbarch, i387_value_to_register);
+
set_gdbarch_extract_return_value (gdbarch, x86_64_extract_return_value);
set_gdbarch_store_return_value (gdbarch, x86_64_store_return_value);
/* Override, since this is handled by x86_64_extract_return_value. */
set_gdbarch_num_pseudo_regs (gdbarch, 0);
set_gdbarch_unwind_dummy_id (gdbarch, x86_64_unwind_dummy_id);
- set_gdbarch_save_dummy_frame_tos (gdbarch, x86_64_save_dummy_frame_tos);
/* FIXME: kettenis/20021026: This is ELF-specific. Fine for now,
since all supported x86-64 targets are ELF, but that might change
in the future. */
set_gdbarch_in_solib_call_trampoline (gdbarch, in_plt_section);
- frame_unwind_append_predicate (gdbarch, x86_64_sigtramp_frame_p);
- frame_unwind_append_predicate (gdbarch, x86_64_frame_p);
+ frame_unwind_append_sniffer (gdbarch, x86_64_sigtramp_frame_sniffer);
+ frame_unwind_append_sniffer (gdbarch, x86_64_frame_sniffer);
frame_base_set_default (gdbarch, &x86_64_frame_base);
}
\f
i387_fill_fxsave (fxsave, regnum);
if (regnum == -1 || regnum == I387_FISEG_REGNUM)
- regcache_collect (regnum, fxsave + 12);
+ regcache_collect (I387_FISEG_REGNUM, fxsave + 12);
if (regnum == -1 || regnum == I387_FOSEG_REGNUM)
- regcache_collect (regnum, fxsave + 20);
+ regcache_collect (I387_FOSEG_REGNUM, fxsave + 20);
}