#include "gdbcore.h"
#include "objfiles.h"
#include "regcache.h"
+#include "regset.h"
#include "symfile.h"
#include "gdb_assert.h"
#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. */
X86_64_XMM0_REGNUM + 14, X86_64_XMM0_REGNUM + 15,
/* Floating Point Registers 0-7. */
- X86_64_ST0_REGNUM + 0, X86_64_ST0_REGNUM + 1,
+ X86_64_ST0_REGNUM + 0, X86_64_ST0_REGNUM + 1,
X86_64_ST0_REGNUM + 2, X86_64_ST0_REGNUM + 3,
X86_64_ST0_REGNUM + 4, X86_64_ST0_REGNUM + 5,
X86_64_ST0_REGNUM + 6, X86_64_ST0_REGNUM + 7
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.
return 1;
}
-#define RET_INT_REGS 2
-#define RET_SSE_REGS 2
-
-/* Check if the structure in value_type is returned in registers or in
- memory. If this function returns 1, GDB will call
- STORE_STRUCT_RETURN and EXTRACT_STRUCT_VALUE_ADDRESS else
- STORE_RETURN_VALUE and EXTRACT_RETURN_VALUE will be used. */
-
-static int
-x86_64_use_struct_convention (int gcc_p, struct type *value_type)
-{
- enum x86_64_reg_class class[MAX_CLASSES];
- int n = classify_argument (value_type, class, 0);
- int needed_intregs;
- int needed_sseregs;
-
- return (!n ||
- !examine_argument (class, n, &needed_intregs, &needed_sseregs) ||
- needed_intregs > RET_INT_REGS || needed_sseregs > RET_SSE_REGS);
-}
-
-/* Extract from an array REGBUF containing the (raw) register state, a
- function return value of TYPE, and copy that, in virtual format,
- into VALBUF. */
-
-static void
-x86_64_extract_return_value (struct type *type, struct regcache *regcache,
- void *valbuf)
-{
- enum x86_64_reg_class class[MAX_CLASSES];
- int n = classify_argument (type, class, 0);
- int needed_intregs;
- int needed_sseregs;
- int intreg = 0;
- int ssereg = 0;
- int offset = 0;
- int ret_int_r[RET_INT_REGS] = { X86_64_RAX_REGNUM, X86_64_RDX_REGNUM };
- int ret_sse_r[RET_SSE_REGS] = { X86_64_XMM0_REGNUM, X86_64_XMM1_REGNUM };
-
- if (!n ||
- !examine_argument (class, n, &needed_intregs, &needed_sseregs) ||
- needed_intregs > RET_INT_REGS || needed_sseregs > RET_SSE_REGS)
- { /* memory class */
- CORE_ADDR addr;
- regcache_cooked_read (regcache, X86_64_RAX_REGNUM, &addr);
- read_memory (addr, valbuf, TYPE_LENGTH (type));
- return;
- }
- else
- {
- int i;
- for (i = 0; i < n; i++)
- {
- switch (class[i])
- {
- case X86_64_NO_CLASS:
- break;
- case X86_64_INTEGER_CLASS:
- regcache_cooked_read (regcache, ret_int_r[(intreg + 1) / 2],
- (char *) valbuf + offset);
- offset += 8;
- intreg += 2;
- break;
- case X86_64_INTEGERSI_CLASS:
- regcache_cooked_read_part (regcache, ret_int_r[intreg / 2],
- 0, 4, (char *) valbuf + offset);
- offset += 8;
- intreg++;
- break;
- case X86_64_SSEDF_CLASS:
- case X86_64_SSESF_CLASS:
- case X86_64_SSE_CLASS:
- regcache_cooked_read_part (regcache,
- ret_sse_r[(ssereg + 1) / 2], 0, 8,
- (char *) valbuf + offset);
- offset += 8;
- ssereg += 2;
- break;
- case X86_64_SSEUP_CLASS:
- regcache_cooked_read_part (regcache, ret_sse_r[ssereg / 2],
- 0, 8, (char *) valbuf + offset);
- offset += 8;
- ssereg++;
- break;
- case X86_64_X87_CLASS:
- regcache_cooked_read_part (regcache, X86_64_ST0_REGNUM,
- 0, 8, (char *) valbuf + offset);
- offset += 8;
- break;
- case X86_64_X87UP_CLASS:
- regcache_cooked_read_part (regcache, X86_64_ST0_REGNUM,
- 8, 2, (char *) valbuf + offset);
- offset += 8;
- break;
- case X86_64_MEMORY_CLASS:
- default:
- internal_error (__FILE__, __LINE__,
- "Unexpected argument class");
- }
- }
- }
-}
-
#define INT_REGS 6
#define SSE_REGS 8
{
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));
+
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;
}
-/* Write into the appropriate registers a function return value stored
- in VALBUF of type TYPE, given in virtual format. */
+/* Register classes as defined in the psABI. */
+
+enum amd64_reg_class
+{
+ AMD64_INTEGER,
+ AMD64_SSE,
+ AMD64_SSEUP,
+ AMD64_X87,
+ AMD64_X87UP,
+ AMD64_COMPLEX_X87,
+ AMD64_NO_CLASS,
+ AMD64_MEMORY
+};
+
+/* Return the union class of CLASS1 and CLASS2. See the psABI for
+ details. */
+
+static enum amd64_reg_class
+amd64_merge_classes (enum amd64_reg_class class1, enum amd64_reg_class class2)
+{
+ /* Rule (a): If both classes are equal, this is the resulting class. */
+ if (class1 == class2)
+ return class1;
+
+ /* Rule (b): If one of the classes is NO_CLASS, the resulting class
+ is the other class. */
+ if (class1 == AMD64_NO_CLASS)
+ return class2;
+ if (class2 == AMD64_NO_CLASS)
+ return class1;
+
+ /* Rule (c): If one of the classes is MEMORY, the result is MEMORY. */
+ if (class1 == AMD64_MEMORY || class2 == AMD64_MEMORY)
+ return AMD64_MEMORY;
+
+ /* Rule (d): If one of the classes is INTEGER, the result is INTEGER. */
+ if (class1 == AMD64_INTEGER || class2 == AMD64_INTEGER)
+ return AMD64_INTEGER;
+
+ /* Rule (e): If one of the classes is X87, X87UP, COMPLEX_X87 class,
+ MEMORY is used as class. */
+ if (class1 == AMD64_X87 || class1 == AMD64_X87UP
+ || class1 == AMD64_COMPLEX_X87 || class2 == AMD64_X87
+ || class2 == AMD64_X87UP || class2 == AMD64_COMPLEX_X87)
+ return AMD64_MEMORY;
+
+ /* Rule (f): Otherwise class SSE is used. */
+ return AMD64_SSE;
+}
+
+static void amd64_classify (struct type *type, enum amd64_reg_class class[2]);
+
+/* Classify TYPE according to the rules for aggregate (structures and
+ arrays) and union types, and store the result in CLASS. */
static void
-x86_64_store_return_value (struct type *type, struct regcache *regcache,
- const void *valbuf)
+amd64_classify_aggregate (struct type *type, enum amd64_reg_class class[2])
{
int len = TYPE_LENGTH (type);
- if (TYPE_CODE_FLT == TYPE_CODE (type))
+ /* 1. If the size of an object is larger than two eightbytes, or in
+ C++, is a non-POD structure or union type, or contains
+ unaligned fields, it has class memory. */
+ if (len > 16)
{
- ULONGEST fstat;
- char buf[FPU_REG_RAW_SIZE];
-
- /* Returning floating-point values is a bit tricky. Apart from
- storing the return value in %st(0), we have to simulate the
- state of the FPU at function return point. */
-
- /* Convert the value found in VALBUF to the extended
- floating-point format used by the FPU. This is probably
- not exactly how it would happen on the target itself, but
- it is the best we can do. */
- convert_typed_floating (valbuf, type, buf, builtin_type_i387_ext);
- regcache_raw_write (regcache, X86_64_ST0_REGNUM, buf);
-
- /* Set the top of the floating-point register stack to 7. The
- actual value doesn't really matter, but 7 is what a normal
- function return would end up with if the program started out
- with a freshly initialized FPU. */
- regcache_raw_read_unsigned (regcache, FSTAT_REGNUM, &fstat);
- fstat |= (7 << 11);
- regcache_raw_write_unsigned (regcache, FSTAT_REGNUM, fstat);
-
- /* Mark %st(1) through %st(7) as empty. Since we set the top of
- the floating-point register stack to 7, the appropriate value
- for the tag word is 0x3fff. */
- regcache_raw_write_unsigned (regcache, FTAG_REGNUM, 0x3fff);
+ class[0] = class[1] = AMD64_MEMORY;
+ return;
+ }
+
+ /* 2. Both eightbytes get initialized to class NO_CLASS. */
+ class[0] = class[1] = AMD64_NO_CLASS;
+
+ /* 3. Each field of an object is classified recursively so that
+ always two fields are considered. The resulting class is
+ calculated according to the classes of the fields in the
+ eightbyte: */
+
+ if (TYPE_CODE (type) == TYPE_CODE_ARRAY)
+ {
+ struct type *subtype = check_typedef (TYPE_TARGET_TYPE (type));
+
+ /* All fields in an array have the same type. */
+ amd64_classify (subtype, class);
+ if (len > 8 && class[1] == AMD64_NO_CLASS)
+ class[1] = class[0];
}
else
{
- int low_size = REGISTER_RAW_SIZE (0);
- int high_size = REGISTER_RAW_SIZE (1);
+ int i;
- if (len <= low_size)
- regcache_cooked_write_part (regcache, 0, 0, len, valbuf);
- else if (len <= (low_size + high_size))
+ /* Structure or union. */
+ gdb_assert (TYPE_CODE (type) == TYPE_CODE_STRUCT
+ || TYPE_CODE (type) == TYPE_CODE_UNION);
+
+ for (i = 0; i < TYPE_NFIELDS (type); i++)
{
- regcache_cooked_write_part (regcache, 0, 0, low_size, valbuf);
- regcache_cooked_write_part (regcache, 1, 0,
- len - low_size,
- (const char *) valbuf + low_size);
+ struct type *subtype = check_typedef (TYPE_FIELD_TYPE (type, i));
+ int pos = TYPE_FIELD_BITPOS (type, i) / 64;
+ enum amd64_reg_class subclass[2];
+
+ gdb_assert (pos == 0 || pos == 1);
+
+ amd64_classify (subtype, subclass);
+ class[pos] = amd64_merge_classes (class[pos], subclass[0]);
+ if (pos == 0)
+ class[1] = amd64_merge_classes (class[1], subclass[1]);
}
- else
- internal_error (__FILE__, __LINE__,
- "Cannot store return value of %d bytes long.", len);
}
+
+ /* 4. Then a post merger cleanup is done: */
+
+ /* Rule (a): If one of the classes is MEMORY, the whole argument is
+ passed in memory. */
+ if (class[0] == AMD64_MEMORY || class[1] == AMD64_MEMORY)
+ class[0] = class[1] = AMD64_MEMORY;
+
+ /* Rule (b): If SSEUP is not preceeded by SSE, it is converted to
+ SSE. */
+ if (class[0] == AMD64_SSEUP)
+ class[0] = AMD64_SSE;
+ if (class[1] == AMD64_SSEUP && class[0] != AMD64_SSE)
+ class[1] = AMD64_SSE;
+}
+
+/* Classify TYPE, and store the result in CLASS. */
+
+static void
+amd64_classify (struct type *type, enum amd64_reg_class class[2])
+{
+ enum type_code code = TYPE_CODE (type);
+ int len = TYPE_LENGTH (type);
+
+ class[0] = class[1] = AMD64_NO_CLASS;
+
+ /* Arguments of types (signed and unsigned) _Bool, char, short, int,
+ long, long long, and pointers are in the INTEGER class. */
+ if ((code == TYPE_CODE_INT || code == TYPE_CODE_ENUM
+ || code == TYPE_CODE_PTR || code == TYPE_CODE_REF)
+ && (len == 1 || len == 2 || len == 4 || len == 8))
+ class[0] = AMD64_INTEGER;
+
+ /* Arguments of types float, double and __m64 are in class SSE. */
+ else if (code == TYPE_CODE_FLT && (len == 4 || len == 8))
+ /* FIXME: __m64 . */
+ class[0] = AMD64_SSE;
+
+ /* Arguments of types __float128 and __m128 are split into two
+ halves. The least significant ones belong to class SSE, the most
+ significant one to class SSEUP. */
+ /* FIXME: __float128, __m128. */
+
+ /* The 64-bit mantissa of arguments of type long double belongs to
+ class X87, the 16-bit exponent plus 6 bytes of padding belongs to
+ class X87UP. */
+ else if (code == TYPE_CODE_FLT && len == 16)
+ /* Class X87 and X87UP. */
+ class[0] = AMD64_X87, class[1] = AMD64_X87UP;
+
+ /* Aggregates. */
+ else if (code == TYPE_CODE_ARRAY || code == TYPE_CODE_STRUCT
+ || code == TYPE_CODE_UNION)
+ amd64_classify_aggregate (type, class);
+}
+
+static enum return_value_convention
+amd64_return_value (struct gdbarch *gdbarch, struct type *type,
+ struct regcache *regcache,
+ void *readbuf, const void *writebuf)
+{
+ enum amd64_reg_class class[2];
+ int len = TYPE_LENGTH (type);
+ static int integer_regnum[] = { X86_64_RAX_REGNUM, X86_64_RDX_REGNUM };
+ static int sse_regnum[] = { X86_64_XMM0_REGNUM, X86_64_XMM1_REGNUM };
+ int integer_reg = 0;
+ int sse_reg = 0;
+ int i;
+
+ gdb_assert (!(readbuf && writebuf));
+
+ /* 1. Classify the return type with the classification algorithm. */
+ amd64_classify (type, class);
+
+ /* 2. If the type has class MEMORY, then the caller provides space
+ for the return value and passes the address of this storage in
+ %rdi as if it were the first argument to the function. In
+ effect, this address becomes a hidden first argument. */
+ if (class[0] == AMD64_MEMORY)
+ return RETURN_VALUE_STRUCT_CONVENTION;
+
+ gdb_assert (class[1] != AMD64_MEMORY);
+ gdb_assert (len <= 16);
+
+ for (i = 0; len > 0; i++, len -= 8)
+ {
+ int regnum = -1;
+ int offset = 0;
+
+ switch (class[i])
+ {
+ case AMD64_INTEGER:
+ /* 3. If the class is INTEGER, the next available register
+ of the sequence %rax, %rdx is used. */
+ regnum = integer_regnum[integer_reg++];
+ break;
+
+ case AMD64_SSE:
+ /* 4. If the class is SSE, the next available SSE register
+ of the sequence %xmm0, %xmm1 is used. */
+ regnum = sse_regnum[sse_reg++];
+ break;
+
+ case AMD64_SSEUP:
+ /* 5. If the class is SSEUP, the eightbyte is passed in the
+ upper half of the last used SSE register. */
+ gdb_assert (sse_reg > 0);
+ regnum = sse_regnum[sse_reg - 1];
+ offset = 8;
+ break;
+
+ case AMD64_X87:
+ /* 6. If the class is X87, the value is returned on the X87
+ stack in %st0 as 80-bit x87 number. */
+ regnum = X86_64_ST0_REGNUM;
+ if (writebuf)
+ i387_return_value (gdbarch, regcache);
+ break;
+
+ case AMD64_X87UP:
+ /* 7. If the class is X87UP, the value is returned together
+ with the previous X87 value in %st0. */
+ gdb_assert (i > 0 && class[0] == AMD64_X87);
+ regnum = X86_64_ST0_REGNUM;
+ offset = 8;
+ len = 2;
+ break;
+
+ case AMD64_NO_CLASS:
+ continue;
+
+ default:
+ gdb_assert (!"Unexpected register class.");
+ }
+
+ gdb_assert (regnum != -1);
+
+ if (readbuf)
+ regcache_raw_read_part (regcache, regnum, offset, min (len, 8),
+ (char *) readbuf + i * 8);
+ if (writebuf)
+ regcache_raw_write_part (regcache, regnum, offset, min (len, 8),
+ (const char *) writebuf + i * 8);
+ }
+
+ return RETURN_VALUE_REGISTER_CONVENTION;
}
\f
/* ...and fake a frame pointer. */
regcache_cooked_write (regcache, X86_64_RBP_REGNUM, buf);
- return sp;
+ return sp + 16;
}
\f
cache = x86_64_alloc_frame_cache ();
*this_cache = cache;
- frame_unwind_register (next_frame, X86_64_RBP_REGNUM, buf);
- cache->base = extract_unsigned_integer (buf, 8);
- if (cache->base == 0)
- return cache;
-
- /* For normal frames, %rip is stored at 8(%rbp). */
- cache->saved_regs[X86_64_RIP_REGNUM] = 8;
-
cache->pc = frame_func_unwind (next_frame);
if (cache->pc != 0)
x86_64_analyze_prologue (cache->pc, frame_pc_unwind (next_frame), cache);
frame_unwind_register (next_frame, X86_64_RSP_REGNUM, buf);
cache->base = extract_unsigned_integer (buf, 8) + cache->sp_offset;
}
+ else
+ {
+ frame_unwind_register (next_frame, X86_64_RBP_REGNUM, buf);
+ cache->base = extract_unsigned_integer (buf, 8);
+ }
/* Now that we have the base address for the stack frame we can
calculate the value of %rsp in the calling frame. */
cache->saved_sp = cache->base + 16;
+ /* For normal frames, %rip is stored at 8(%rbp). If we don't have a
+ frame we find it at the same offset from the reconstructed base
+ address. */
+ cache->saved_regs[X86_64_RIP_REGNUM] = 8;
+
/* Adjust all the saved registers such that they contain addresses
instead of offsets. */
for (i = 0; i < X86_64_NUM_SAVED_REGS; i++)
};
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);
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)
{
return frame_id_build (fp + 16, frame_pc_unwind (next_frame));
}
+/* 16 byte align the SP per frame requirements. */
+
+static CORE_ADDR
+x86_64_frame_align (struct gdbarch *gdbarch, CORE_ADDR sp)
+{
+ return sp & -(CORE_ADDR)16;
+}
+\f
+
+/* Supply register REGNUM from the floating-point register set REGSET
+ to register cache REGCACHE. If REGNUM is -1, do this for all
+ registers in REGSET. */
+
+static void
+x86_64_supply_fpregset (const struct regset *regset, struct regcache *regcache,
+ int regnum, const void *fpregs, size_t len)
+{
+ const struct gdbarch_tdep *tdep = regset->descr;
+
+ gdb_assert (len == tdep->sizeof_fpregset);
+ x86_64_supply_fxsave (regcache, regnum, fpregs);
+}
+
+/* Return the appropriate register set for the core section identified
+ by SECT_NAME and SECT_SIZE. */
+
+static const struct regset *
+x86_64_regset_from_core_section (struct gdbarch *gdbarch,
+ const char *sect_name, size_t sect_size)
+{
+ struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+
+ if (strcmp (sect_name, ".reg2") == 0 && sect_size == tdep->sizeof_fpregset)
+ {
+ if (tdep->fpregset == NULL)
+ {
+ tdep->fpregset = XMALLOC (struct regset);
+ tdep->fpregset->descr = tdep;
+ tdep->fpregset->supply_regset = x86_64_supply_fpregset;
+ }
+
+ return tdep->fpregset;
+ }
+
+ return i386_regset_from_core_section (gdbarch, sect_name, sect_size);
+}
+\f
+
void
x86_64_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
{
struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
- /* The x86-64 has 16 SSE registers. */
+ /* AMD64 generally uses `fxsave' instead of `fsave' for saving its
+ floating-point registers. */
+ tdep->sizeof_fpregset = I387_SIZEOF_FXSAVE;
+
+ /* AMD64 has an FPU and 16 SSE registers. */
+ tdep->st0_regnum = X86_64_ST0_REGNUM;
tdep->num_xmm_regs = 16;
/* This is what all the fuss is about. */
/* Call dummy code. */
set_gdbarch_push_dummy_call (gdbarch, x86_64_push_dummy_call);
+ set_gdbarch_frame_align (gdbarch, x86_64_frame_align);
+ set_gdbarch_frame_red_zone_size (gdbarch, 128);
+
+ 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);
+ set_gdbarch_return_value (gdbarch, amd64_return_value);
/* Override, since this is handled by x86_64_extract_return_value. */
set_gdbarch_extract_struct_value_address (gdbarch, NULL);
- set_gdbarch_use_struct_convention (gdbarch, x86_64_use_struct_convention);
set_gdbarch_skip_prologue (gdbarch, x86_64_skip_prologue);
/* Avoid wiring in the MMX registers for now. */
set_gdbarch_num_pseudo_regs (gdbarch, 0);
+ tdep->mm0_regnum = -1;
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);
+
+ /* If we have a register mapping, enable the generic core file support. */
+ if (tdep->gregset_reg_offset)
+ set_gdbarch_regset_from_core_section (gdbarch,
+ x86_64_regset_from_core_section);
}
\f
-#define I387_FISEG_REGNUM FISEG_REGNUM
-#define I387_FOSEG_REGNUM FOSEG_REGNUM
+#define I387_ST0_REGNUM X86_64_ST0_REGNUM
/* The 64-bit FXSAVE format differs from the 32-bit format in the
sense that the instruction pointer and data pointer are simply
bits of these pointers (instead of just the 16-bits of the segment
selector). */
-/* Fill GDB's register array with the floating-point and SSE register
- values in *FXSAVE. This function masks off any of the reserved
- bits in *FXSAVE. */
+/* Fill register REGNUM in REGCACHE with the appropriate
+ floating-point or SSE register value from *FXSAVE. If REGNUM is
+ -1, do this for all registers. This function masks off any of the
+ reserved bits in *FXSAVE. */
void
-x86_64_supply_fxsave (char *fxsave)
+x86_64_supply_fxsave (struct regcache *regcache, int regnum,
+ const void *fxsave)
{
- i387_supply_fxsave (fxsave);
+ i387_supply_fxsave (regcache, regnum, fxsave);
if (fxsave)
{
- supply_register (I387_FISEG_REGNUM, fxsave + 12);
- supply_register (I387_FOSEG_REGNUM, fxsave + 20);
+ const char *regs = fxsave;
+
+ if (regnum == -1 || regnum == I387_FISEG_REGNUM)
+ regcache_raw_supply (regcache, I387_FISEG_REGNUM, regs + 12);
+ if (regnum == -1 || regnum == I387_FOSEG_REGNUM)
+ regcache_raw_supply (regcache, I387_FOSEG_REGNUM, regs + 20);
}
}
/* Fill register REGNUM (if it is a floating-point or SSE register) in
- *FXSAVE with the value in GDB's register array. If REGNUM is -1, do
+ *FXSAVE with the value in GDB's register cache. If REGNUM is -1, do
this for all registers. This function doesn't touch any of the
reserved bits in *FXSAVE. */
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);
}