/* Target-dependent code for GDB, the GNU debugger.
- Copyright 2001 Free Software Foundation, Inc.
+
+ Copyright 2001, 2002 Free Software Foundation, Inc.
+
Contributed by D.J. Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com)
for IBM Deutschland Entwicklung GmbH, IBM Corporation.
#include "floatformat.h"
#include "regcache.h"
#include "value.h"
-
+#include "gdb_assert.h"
/* Number of bytes of storage in the actual machine representation
- for register N.
- Note that the unsigned cast here forces the result of the
- subtraction to very high positive values if N < S390_FP0_REGNUM */
+ for register N. */
int
s390_register_raw_size (int reg_nr)
{
- return ((unsigned) reg_nr - S390_FP0_REGNUM) <
- S390_NUM_FPRS ? S390_FPR_SIZE : 4;
+ if (S390_FP0_REGNUM <= reg_nr
+ && reg_nr < S390_FP0_REGNUM + S390_NUM_FPRS)
+ return S390_FPR_SIZE;
+ else
+ return 4;
}
int
if ((*info->read_memory_func) (at, &instr[0], 2, info))
return -1;
instrlen = s390_instrlen[instr[0] >> 6];
- if ((*info->read_memory_func) (at + 2, &instr[2], instrlen - 2, info))
- return -1;
+ if (instrlen > 2)
+ {
+ if ((*info->read_memory_func) (at + 2, &instr[2], instrlen - 2, info))
+ return -1;
+ }
return instrlen;
}
-char *
+const char *
s390_register_name (int reg_nr)
{
static char *register_names[] = {
"pswm", "pswa",
- "gpr0", "gpr1", "gpr2", "gpr3", "gpr4", "gpr5", "gpr6", "gpr7",
- "gpr8", "gpr9", "gpr10", "gpr11", "gpr12", "gpr13", "gpr14", "gpr15",
+ "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
+ "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15",
"acr0", "acr1", "acr2", "acr3", "acr4", "acr5", "acr6", "acr7",
"acr8", "acr9", "acr10", "acr11", "acr12", "acr13", "acr14", "acr15",
"cr0", "cr1", "cr2", "cr3", "cr4", "cr5", "cr6", "cr7",
"cr8", "cr9", "cr10", "cr11", "cr12", "cr13", "cr14", "cr15",
"fpc",
- "fpr0", "fpr1", "fpr2", "fpr3", "fpr4", "fpr5", "fpr6", "fpr7",
- "fpr8", "fpr9", "fpr10", "fpr11", "fpr12", "fpr13", "fpr14", "fpr15"
+ "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7",
+ "f8", "f9", "f10", "f11", "f12", "f13", "f14", "f15"
};
- if (reg_nr >= S390_LAST_REGNUM)
+ if (reg_nr <= S390_LAST_REGNUM)
+ return register_names[reg_nr];
+ else
return NULL;
- return register_names[reg_nr];
}
}
+/* Return true if REGIDX is the number of a register used to pass
+ arguments, false otherwise. */
+static int
+is_arg_reg (int regidx)
+{
+ return 2 <= regidx && regidx <= 6;
+}
+
/* s390_get_frame_info based on Hartmuts
prologue definition in
int gprs_saved[S390_NUM_GPRS];
int fprs_saved[S390_NUM_FPRS];
int regidx, instrlen;
- int save_link_regidx, subtract_sp_regidx;
- int const_pool_state, save_link_state;
- int frame_pointer_found, varargs_state;
+ int const_pool_state;
+ int varargs_state;
int loop_cnt, gdb_gpr_store, gdb_fpr_store;
- int frame_pointer_regidx = 0xf;
int offset, expected_offset;
int err = 0;
disassemble_info info;
+ /* Have we seen an instruction initializing the frame pointer yet?
+ If we've seen an `lr %r11, %r15', then frame_pointer_found is
+ non-zero, and frame_pointer_regidx == 11. Otherwise,
+ frame_pointer_found is zero and frame_pointer_regidx is 15,
+ indicating that we're using the stack pointer as our frame
+ pointer. */
+ int frame_pointer_found = 0;
+ int frame_pointer_regidx = 0xf;
+
+ /* What we've seen so far regarding saving the back chain link:
+ 0 -- nothing yet; sp still has the same value it had at the entry
+ point. Since not all functions allocate frames, this is a
+ valid state for the prologue to finish in.
+ 1 -- We've saved the original sp in some register other than the
+ frame pointer (hard-coded to be %r11, yuck).
+ save_link_regidx is the register we saved it in.
+ 2 -- We've seen the initial `bras' instruction of the sequence for
+ reserving more than 32k of stack:
+ bras %rX, .+8
+ .long N
+ s %r15, 0(%rX)
+ where %rX is not the constant pool register.
+ subtract_sp_regidx is %rX, and fextra_info->stack_bought is N.
+ 3 -- We've reserved space for a new stack frame. This means we
+ either saw a simple `ahi %r15,-N' in state 1, or the final
+ `s %r15, ...' in state 2.
+ 4 -- The frame and link are now fully initialized. We've
+ reserved space for the new stack frame, and stored the old
+ stack pointer captured in the back chain pointer field. */
+ int save_link_state = 0;
+ int save_link_regidx, subtract_sp_regidx;
+
/* What we've seen so far regarding r12 --- the GOT (Global Offset
Table) pointer. We expect to see `l %r12, N(%r13)', which loads
r12 with the offset from the constant pool to the GOT, and then
When got_state is 1, then got_load_addr is the address of the
load instruction, and got_load_len is the length of that
instruction. */
- int got_state;
+ int got_state= 0;
CORE_ADDR got_load_addr = 0, got_load_len = 0;
- const_pool_state = save_link_state = got_state = varargs_state = 0;
- frame_pointer_found = 0;
+ const_pool_state = varargs_state = 0;
+
memset (gprs_saved, 0, sizeof (gprs_saved));
memset (fprs_saved, 0, sizeof (fprs_saved));
info.read_memory_func = dis_asm_read_memory;
{
if (fi && fi->frame)
{
- orig_sp = fi->frame + fextra_info->stack_bought;
+ orig_sp = fi->frame;
+ if (! init_extra_info && fextra_info->initialised)
+ orig_sp += fextra_info->stack_bought;
saved_regs = fi->saved_regs;
}
if (init_extra_info || !fextra_info->initialised)
continue;
}
+ /* Check for an fp-relative STG, ST, or STM. This is probably
+ spilling an argument from a register out into a stack slot.
+ This could be a user instruction, but if we haven't included
+ any other suspicious instructions in the prologue, this
+ could only be an initializing store, which isn't too bad to
+ skip. The consequences of not including arg-to-stack spills
+ are more serious, though --- you don't see the proper values
+ of the arguments. */
+ if ((save_link_state == 3 || save_link_state == 4)
+ && ((instr[0] == 0x50 /* st %rA, D(%rX,%rB) */
+ && (instr[1] & 0xf) == 0 /* %rX is zero, no index reg */
+ && is_arg_reg ((instr[1] >> 4) & 0xf)
+ && ((instr[2] >> 4) & 0xf) == frame_pointer_regidx)
+ || (instr[0] == 0x90 /* stm %rA, %rB, D(%rC) */
+ && is_arg_reg ((instr[1] >> 4) & 0xf)
+ && is_arg_reg (instr[1] & 0xf)
+ && ((instr[2] >> 4) & 0xf) == frame_pointer_regidx)))
+ {
+ valid_prologue = 1;
+ continue;
+ }
+
/* check for STD */
if (instr[0] == 0x60 && (instr[2] >> 4) == 0xf)
{
/* Alternatively check for the complex construction for
buying more than 32k of stack
BRAS gprx,.+8
- long vals %r15,0(%gprx) gprx currently r1 */
+ long val
+ s %r15,0(%gprx) gprx currently r1 */
if ((save_link_state == 1) && (instr[0] == 0xa7)
&& ((instr[1] & 0xf) == 0x5) && (instr[2] == 0)
&& (instr[3] == 0x4) && ((instr[1] >> 4) != CONST_POOL_REGIDX))
fextra_info->skip_prologue_function_start =
(good_prologue ? test_pc : pc);
}
+ if (saved_regs)
+ /* The SP's element of the saved_regs array holds the old SP,
+ not the address at which it is saved. */
+ saved_regs[S390_SP_REGNUM] = orig_sp;
return err;
}
{
if (fi->extra_info && fi->extra_info->saved_pc_valid)
return fi->extra_info->saved_pc;
+
+ if (deprecated_generic_find_dummy_frame (fi->pc, fi->frame))
+ return generic_read_register_dummy (fi->pc, fi->frame, S390_PC_REGNUM);
+
s390_frame_init_saved_regs (fi);
if (fi->extra_info)
{
fi->extra_info->saved_pc_valid = 1;
- if (fi->extra_info->good_prologue)
- {
- if (fi->saved_regs[S390_RETADDR_REGNUM])
- {
- return (fi->extra_info->saved_pc =
- ADDR_BITS_REMOVE (read_memory_integer
- (fi->saved_regs[S390_RETADDR_REGNUM],
- S390_GPR_SIZE)));
- }
- }
+ if (fi->extra_info->good_prologue
+ && fi->saved_regs[S390_RETADDR_REGNUM])
+ fi->extra_info->saved_pc
+ = ADDR_BITS_REMOVE (read_memory_integer
+ (fi->saved_regs[S390_RETADDR_REGNUM],
+ S390_GPR_SIZE));
+ else
+ fi->extra_info->saved_pc
+ = ADDR_BITS_REMOVE (read_register (S390_RETADDR_REGNUM));
+ return fi->extra_info->saved_pc;
}
return 0;
}
{
CORE_ADDR prev_fp = 0;
- if (thisframe->prev && thisframe->prev->frame)
- prev_fp = thisframe->prev->frame;
+ if (deprecated_generic_find_dummy_frame (thisframe->pc, thisframe->frame))
+ return generic_read_register_dummy (thisframe->pc, thisframe->frame,
+ S390_SP_REGNUM);
else
{
int sigreturn = 0;
{
if (thisframe->saved_regs)
{
-
int regno;
- regno =
- ((prev_fextra_info.frame_pointer_saved_pc
- && thisframe->
- saved_regs[S390_FRAME_REGNUM]) ? S390_FRAME_REGNUM :
- S390_SP_REGNUM);
+ if (prev_fextra_info.frame_pointer_saved_pc
+ && thisframe->saved_regs[S390_FRAME_REGNUM])
+ regno = S390_FRAME_REGNUM;
+ else
+ regno = S390_SP_REGNUM;
+
if (thisframe->saved_regs[regno])
- prev_fp =
- read_memory_integer (thisframe->saved_regs[regno],
- S390_GPR_SIZE);
+ {
+ /* The SP's entry of `saved_regs' is special. */
+ if (regno == S390_SP_REGNUM)
+ prev_fp = thisframe->saved_regs[regno];
+ else
+ prev_fp =
+ read_memory_integer (thisframe->saved_regs[regno],
+ S390_GPR_SIZE);
+ }
}
}
}
int len = TYPE_LENGTH (valtype);
if (TYPE_CODE (valtype) == TYPE_CODE_FLT)
- {
- if (len > (TARGET_FLOAT_BIT >> 3))
- memcpy (valbuf, ®buf[REGISTER_BYTE (S390_FP0_REGNUM)], len);
- else
- {
- /* float */
- DOUBLEST val;
-
- floatformat_to_doublest (&floatformat_ieee_double_big,
- ®buf[REGISTER_BYTE (S390_FP0_REGNUM)],
- &val);
- store_floating (valbuf, len, val);
- }
- }
+ memcpy (valbuf, ®buf[REGISTER_BYTE (S390_FP0_REGNUM)], len);
else
{
int offset = 0;
if (TYPE_CODE (valtype) == TYPE_CODE_FLT)
{
- DOUBLEST tempfloat = extract_floating (valbuf, TYPE_LENGTH (valtype));
-
- floatformat_from_doublest (&floatformat_ieee_double_big, &tempfloat,
- reg_buff);
- write_register_bytes (REGISTER_BYTE (S390_FP0_REGNUM), reg_buff,
- S390_FPR_SIZE);
+ if (TYPE_LENGTH (valtype) == 4
+ || TYPE_LENGTH (valtype) == 8)
+ write_register_bytes (REGISTER_BYTE (S390_FP0_REGNUM), valbuf,
+ TYPE_LENGTH (valtype));
+ else
+ error ("GDB is unable to return `long double' values "
+ "on this architecture.");
}
else
{
/* Not the most efficent code in the world */
int
-s390_fp_regnum ()
+s390_fp_regnum (void)
{
int regno = S390_SP_REGNUM;
struct frame_extra_info fextra_info;
}
CORE_ADDR
-s390_read_fp ()
+s390_read_fp (void)
{
return read_register (s390_fp_regnum ());
}
-void
-s390_write_fp (CORE_ADDR val)
+static void
+s390_pop_frame_regular (struct frame_info *frame)
{
- write_register (s390_fp_regnum (), val);
+ int regnum;
+
+ write_register (S390_PC_REGNUM, FRAME_SAVED_PC (frame));
+
+ /* Restore any saved registers. */
+ if (frame->saved_regs)
+ {
+ for (regnum = 0; regnum < NUM_REGS; regnum++)
+ if (frame->saved_regs[regnum] != 0)
+ {
+ ULONGEST value;
+
+ value = read_memory_unsigned_integer (frame->saved_regs[regnum],
+ REGISTER_RAW_SIZE (regnum));
+ write_register (regnum, value);
+ }
+
+ /* Actually cut back the stack. Remember that the SP's element of
+ saved_regs is the old SP itself, not the address at which it is
+ saved. */
+ write_register (S390_SP_REGNUM, frame->saved_regs[S390_SP_REGNUM]);
+ }
+
+ /* Throw away any cached frame information. */
+ flush_cached_frames ();
}
+/* Destroy the innermost (Top-Of-Stack) stack frame, restoring the
+ machine state that was in effect before the frame was created.
+ Used in the contexts of the "return" command, and of
+ target function calls from the debugger. */
void
-s390_push_dummy_frame ()
+s390_pop_frame (void)
{
- CORE_ADDR orig_sp = read_register (S390_SP_REGNUM), new_sp;
- void *saved_regs = alloca (REGISTER_BYTES);
-
- new_sp = (orig_sp - (REGISTER_BYTES + S390_GPR_SIZE));
- read_register_bytes (0, (char *) saved_regs, REGISTER_BYTES);
- /* Use saved copy instead of orig_sp as this will have the correct endianness */
- write_memory (new_sp, (char *) saved_regs + REGISTER_BYTE (S390_SP_REGNUM),
- S390_GPR_SIZE);
- write_memory (new_sp + S390_GPR_SIZE, (char *) &saved_regs, REGISTER_BYTES);
- write_register (S390_SP_REGNUM, new_sp);
+ /* This function checks for and handles generic dummy frames, and
+ calls back to our function for ordinary frames. */
+ generic_pop_current_frame (s390_pop_frame_regular);
}
-/* pop the innermost frame, go back to the caller.
- Used in `call_function_by_hand' to remove an artificial stack
- frame. */
-void
-s390_pop_frame ()
+
+/* Return non-zero if TYPE is an integer-like type, zero otherwise.
+ "Integer-like" types are those that should be passed the way
+ integers are: integers, enums, ranges, characters, and booleans. */
+static int
+is_integer_like (struct type *type)
+{
+ enum type_code code = TYPE_CODE (type);
+
+ return (code == TYPE_CODE_INT
+ || code == TYPE_CODE_ENUM
+ || code == TYPE_CODE_RANGE
+ || code == TYPE_CODE_CHAR
+ || code == TYPE_CODE_BOOL);
+}
+
+
+/* Return non-zero if TYPE is a pointer-like type, zero otherwise.
+ "Pointer-like" types are those that should be passed the way
+ pointers are: pointers and references. */
+static int
+is_pointer_like (struct type *type)
+{
+ enum type_code code = TYPE_CODE (type);
+
+ return (code == TYPE_CODE_PTR
+ || code == TYPE_CODE_REF);
+}
+
+
+/* Return non-zero if TYPE is a `float singleton' or `double
+ singleton', zero otherwise.
+
+ A `T singleton' is a struct type with one member, whose type is
+ either T or a `T singleton'. So, the following are all float
+ singletons:
+
+ struct { float x };
+ struct { struct { float x; } x; };
+ struct { struct { struct { float x; } x; } x; };
+
+ ... and so on.
+
+ WHY THE HECK DO WE CARE ABOUT THIS??? Well, it turns out that GCC
+ passes all float singletons and double singletons as if they were
+ simply floats or doubles. This is *not* what the ABI says it
+ should do. */
+static int
+is_float_singleton (struct type *type)
+{
+ return (TYPE_CODE (type) == TYPE_CODE_STRUCT
+ && TYPE_NFIELDS (type) == 1
+ && (TYPE_CODE (TYPE_FIELD_TYPE (type, 0)) == TYPE_CODE_FLT
+ || is_float_singleton (TYPE_FIELD_TYPE (type, 0))));
+}
+
+
+/* Return non-zero if TYPE is a struct-like type, zero otherwise.
+ "Struct-like" types are those that should be passed as structs are:
+ structs and unions.
+
+ As an odd quirk, not mentioned in the ABI, GCC passes float and
+ double singletons as if they were a plain float, double, etc. (The
+ corresponding union types are handled normally.) So we exclude
+ those types here. *shrug* */
+static int
+is_struct_like (struct type *type)
+{
+ enum type_code code = TYPE_CODE (type);
+
+ return (code == TYPE_CODE_UNION
+ || (code == TYPE_CODE_STRUCT && ! is_float_singleton (type)));
+}
+
+
+/* Return non-zero if TYPE is a float-like type, zero otherwise.
+ "Float-like" types are those that should be passed as
+ floating-point values are.
+
+ You'd think this would just be floats, doubles, long doubles, etc.
+ But as an odd quirk, not mentioned in the ABI, GCC passes float and
+ double singletons as if they were a plain float, double, etc. (The
+ corresponding union types are handled normally.) So we exclude
+ those types here. *shrug* */
+static int
+is_float_like (struct type *type)
+{
+ return (TYPE_CODE (type) == TYPE_CODE_FLT
+ || is_float_singleton (type));
+}
+
+
+/* Return non-zero if TYPE is considered a `DOUBLE_OR_FLOAT', as
+ defined by the parameter passing conventions described in the
+ "GNU/Linux for S/390 ELF Application Binary Interface Supplement".
+ Otherwise, return zero. */
+static int
+is_double_or_float (struct type *type)
+{
+ return (is_float_like (type)
+ && (TYPE_LENGTH (type) == 4
+ || TYPE_LENGTH (type) == 8));
+}
+
+
+/* Return non-zero if TYPE is considered a `SIMPLE_ARG', as defined by
+ the parameter passing conventions described in the "GNU/Linux for
+ S/390 ELF Application Binary Interface Supplement". Return zero
+ otherwise. */
+static int
+is_simple_arg (struct type *type)
{
- CORE_ADDR new_sp = read_register (S390_SP_REGNUM), orig_sp;
- void *saved_regs = alloca (REGISTER_BYTES);
+ unsigned length = TYPE_LENGTH (type);
+
+ /* This is almost a direct translation of the ABI's language, except
+ that we have to exclude 8-byte structs; those are DOUBLE_ARGs. */
+ return ((is_integer_like (type) && length <= 4)
+ || is_pointer_like (type)
+ || (is_struct_like (type) && length != 8)
+ || (is_float_like (type) && length == 16));
+}
+
+
+/* Return non-zero if TYPE should be passed as a pointer to a copy,
+ zero otherwise. TYPE must be a SIMPLE_ARG, as recognized by
+ `is_simple_arg'. */
+static int
+pass_by_copy_ref (struct type *type)
+{
+ unsigned length = TYPE_LENGTH (type);
+
+ return ((is_struct_like (type) && length != 1 && length != 2 && length != 4)
+ || (is_float_like (type) && length == 16));
+}
+
+
+/* Return ARG, a `SIMPLE_ARG', sign-extended or zero-extended to a full
+ word as required for the ABI. */
+static LONGEST
+extend_simple_arg (struct value *arg)
+{
+ struct type *type = VALUE_TYPE (arg);
+
+ /* Even structs get passed in the least significant bits of the
+ register / memory word. It's not really right to extract them as
+ an integer, but it does take care of the extension. */
+ if (TYPE_UNSIGNED (type))
+ return extract_unsigned_integer (VALUE_CONTENTS (arg),
+ TYPE_LENGTH (type));
+ else
+ return extract_signed_integer (VALUE_CONTENTS (arg),
+ TYPE_LENGTH (type));
+}
+
+
+/* Return non-zero if TYPE is a `DOUBLE_ARG', as defined by the
+ parameter passing conventions described in the "GNU/Linux for S/390
+ ELF Application Binary Interface Supplement". Return zero
+ otherwise. */
+static int
+is_double_arg (struct type *type)
+{
+ unsigned length = TYPE_LENGTH (type);
+
+ return ((is_integer_like (type)
+ || is_struct_like (type))
+ && length == 8);
+}
+
+
+/* Round ADDR up to the next N-byte boundary. N must be a power of
+ two. */
+static CORE_ADDR
+round_up (CORE_ADDR addr, int n)
+{
+ /* Check that N is really a power of two. */
+ gdb_assert (n && (n & (n-1)) == 0);
+ return ((addr + n - 1) & -n);
+}
+
+
+/* Round ADDR down to the next N-byte boundary. N must be a power of
+ two. */
+static CORE_ADDR
+round_down (CORE_ADDR addr, int n)
+{
+ /* Check that N is really a power of two. */
+ gdb_assert (n && (n & (n-1)) == 0);
+ return (addr & -n);
+}
+
+
+/* Return the alignment required by TYPE. */
+static int
+alignment_of (struct type *type)
+{
+ int alignment;
+
+ if (is_integer_like (type)
+ || is_pointer_like (type)
+ || TYPE_CODE (type) == TYPE_CODE_FLT)
+ alignment = TYPE_LENGTH (type);
+ else if (TYPE_CODE (type) == TYPE_CODE_STRUCT
+ || TYPE_CODE (type) == TYPE_CODE_UNION)
+ {
+ int i;
+ alignment = 1;
+ for (i = 0; i < TYPE_NFIELDS (type); i++)
+ {
+ int field_alignment = alignment_of (TYPE_FIELD_TYPE (type, i));
+
+ if (field_alignment > alignment)
+ alignment = field_alignment;
+ }
+ }
+ else
+ alignment = 1;
+
+ /* Check that everything we ever return is a power of two. Lots of
+ code doesn't want to deal with aligning things to arbitrary
+ boundaries. */
+ gdb_assert ((alignment & (alignment - 1)) == 0);
- read_memory (new_sp + S390_GPR_SIZE, (char *) saved_regs, REGISTER_BYTES);
- write_register_bytes (0, (char *) &saved_regs, REGISTER_BYTES);
+ return alignment;
}
-/* used by call function by hand
- struct_return indicates that this function returns a structure &
- therefore gpr2 stores a pointer to the structure to be returned as
- opposed to the first argument.
- Currently I haven't seen a TYPE_CODE_INT whose size wasn't 2^n or less
- than S390_GPR_SIZE this is good because I don't seem to have to worry
- about sign extending pushed arguments (i.e. a signed char currently
- comes into this code with a size of 4 ). */
+/* Put the actual parameter values pointed to by ARGS[0..NARGS-1] in
+ place to be passed to a function, as specified by the "GNU/Linux
+ for S/390 ELF Application Binary Interface Supplement".
+
+ SP is the current stack pointer. We must put arguments, links,
+ padding, etc. whereever they belong, and return the new stack
+ pointer value.
+
+ If STRUCT_RETURN is non-zero, then the function we're calling is
+ going to return a structure by value; STRUCT_ADDR is the address of
+ a block we've allocated for it on the stack.
+
+ Our caller has taken care of any type promotions needed to satisfy
+ prototypes or the old K&R argument-passing rules. */
CORE_ADDR
s390_push_arguments (int nargs, struct value **args, CORE_ADDR sp,
int struct_return, CORE_ADDR struct_addr)
{
- int num_float_args, num_gpr_args, orig_num_gpr_args, argno;
- int second_pass, len, arglen, gprs_required;
- CORE_ADDR outgoing_args_ptr, outgoing_args_space;
- struct value *arg;
- struct type *type;
- int max_num_gpr_args = 5 - (struct_return ? 1 : 0);
- int arg0_regnum = S390_GP0_REGNUM + 2 + (struct_return ? 1 : 0);
- char *reg_buff = alloca (max (S390_FPR_SIZE, REGISTER_SIZE)), *value;
-
- for (second_pass = 0; second_pass <= 1; second_pass++)
- {
- if (second_pass)
- outgoing_args_ptr = sp + S390_STACK_FRAME_OVERHEAD;
- else
- outgoing_args_ptr = 0;
- num_float_args = 0;
- num_gpr_args = 0;
- for (argno = 0; argno < nargs; argno++)
- {
- arg = args[argno];
- type = check_typedef (VALUE_TYPE (arg));
- len = TYPE_LENGTH (type);
- if (TYPE_CODE (type) == TYPE_CODE_FLT)
- {
- int all_float_registers_used =
- num_float_args > (GDB_TARGET_IS_ESAME ? 3 : 1);
+ int i;
+ int pointer_size = (TARGET_PTR_BIT / TARGET_CHAR_BIT);
- if (second_pass)
- {
- DOUBLEST tempfloat =
- extract_floating (VALUE_CONTENTS (arg), len);
-
-
- floatformat_from_doublest (all_float_registers_used &&
- len == (TARGET_FLOAT_BIT >> 3)
- ? &floatformat_ieee_single_big
- : &floatformat_ieee_double_big,
- &tempfloat, reg_buff);
- if (all_float_registers_used)
- write_memory (outgoing_args_ptr, reg_buff, len);
- else
- write_register_bytes (REGISTER_BYTE ((S390_FP0_REGNUM)
- +
- (2 *
- num_float_args)),
- reg_buff, S390_FPR_SIZE);
- }
- if (all_float_registers_used)
- outgoing_args_ptr += len;
- num_float_args++;
- }
- else
- {
- gprs_required = ((len + (S390_GPR_SIZE - 1)) / S390_GPR_SIZE);
+ /* The number of arguments passed by reference-to-copy. */
+ int num_copies;
- value =
- s390_promote_integer_argument (type, VALUE_CONTENTS (arg),
- reg_buff, &arglen);
+ /* If the i'th argument is passed as a reference to a copy, then
+ copy_addr[i] is the address of the copy we made. */
+ CORE_ADDR *copy_addr = alloca (nargs * sizeof (CORE_ADDR));
- orig_num_gpr_args = num_gpr_args;
- num_gpr_args += gprs_required;
- if (num_gpr_args > max_num_gpr_args)
- {
- if (second_pass)
- write_memory (outgoing_args_ptr, value, arglen);
- outgoing_args_ptr += arglen;
- }
- else
- {
- if (second_pass)
- write_register_bytes (REGISTER_BYTE (arg0_regnum)
- +
- (orig_num_gpr_args * S390_GPR_SIZE),
- value, arglen);
- }
- }
- }
- if (!second_pass)
- {
- outgoing_args_space = outgoing_args_ptr;
- /* Align to 16 bytes because because I like alignment &
- some of the kernel code requires 8 byte stack alignment at least. */
- sp = (sp - (S390_STACK_FRAME_OVERHEAD + outgoing_args_ptr)) & (-16);
- }
+ /* Build the reference-to-copy area. */
+ num_copies = 0;
+ for (i = 0; i < nargs; i++)
+ {
+ struct value *arg = args[i];
+ struct type *type = VALUE_TYPE (arg);
+ unsigned length = TYPE_LENGTH (type);
+ if (is_simple_arg (type)
+ && pass_by_copy_ref (type))
+ {
+ sp -= length;
+ sp = round_down (sp, alignment_of (type));
+ write_memory (sp, VALUE_CONTENTS (arg), length);
+ copy_addr[i] = sp;
+ num_copies++;
+ }
}
- return sp;
+ /* Reserve space for the parameter area. As a conservative
+ simplification, we assume that everything will be passed on the
+ stack. */
+ {
+ int i;
+
+ for (i = 0; i < nargs; i++)
+ {
+ struct value *arg = args[i];
+ struct type *type = VALUE_TYPE (arg);
+ int length = TYPE_LENGTH (type);
+
+ sp = round_down (sp, alignment_of (type));
+
+ /* SIMPLE_ARG values get extended to 32 bits. Assume every
+ argument is. */
+ if (length < 4) length = 4;
+ sp -= length;
+ }
+ }
+
+ /* Include space for any reference-to-copy pointers. */
+ sp = round_down (sp, pointer_size);
+ sp -= num_copies * pointer_size;
+
+ /* After all that, make sure it's still aligned on an eight-byte
+ boundary. */
+ sp = round_down (sp, 8);
+
+ /* Finally, place the actual parameters, working from SP towards
+ higher addresses. The code above is supposed to reserve enough
+ space for this. */
+ {
+ int fr = 0;
+ int gr = 2;
+ CORE_ADDR starg = sp;
+
+ for (i = 0; i < nargs; i++)
+ {
+ struct value *arg = args[i];
+ struct type *type = VALUE_TYPE (arg);
+
+ if (is_double_or_float (type)
+ && fr <= 2)
+ {
+ /* When we store a single-precision value in an FP register,
+ it occupies the leftmost bits. */
+ write_register_bytes (REGISTER_BYTE (S390_FP0_REGNUM + fr),
+ VALUE_CONTENTS (arg),
+ TYPE_LENGTH (type));
+ fr += 2;
+ }
+ else if (is_simple_arg (type)
+ && gr <= 6)
+ {
+ /* Do we need to pass a pointer to our copy of this
+ argument? */
+ if (pass_by_copy_ref (type))
+ write_register (S390_GP0_REGNUM + gr, copy_addr[i]);
+ else
+ write_register (S390_GP0_REGNUM + gr, extend_simple_arg (arg));
+
+ gr++;
+ }
+ else if (is_double_arg (type)
+ && gr <= 5)
+ {
+ write_register_gen (S390_GP0_REGNUM + gr,
+ VALUE_CONTENTS (arg));
+ write_register_gen (S390_GP0_REGNUM + gr + 1,
+ VALUE_CONTENTS (arg) + 4);
+ gr += 2;
+ }
+ else
+ {
+ /* The `OTHER' case. */
+ enum type_code code = TYPE_CODE (type);
+ unsigned length = TYPE_LENGTH (type);
+
+ /* If we skipped r6 because we couldn't fit a DOUBLE_ARG
+ in it, then don't go back and use it again later. */
+ if (is_double_arg (type) && gr == 6)
+ gr = 7;
+
+ if (is_simple_arg (type))
+ {
+ /* Simple args are always either extended to 32 bits,
+ or pointers. */
+ starg = round_up (starg, 4);
+
+ /* Do we need to pass a pointer to our copy of this
+ argument? */
+ if (pass_by_copy_ref (type))
+ write_memory_signed_integer (starg, pointer_size,
+ copy_addr[i]);
+ else
+ /* Simple args are always extended to 32 bits. */
+ write_memory_signed_integer (starg, 4,
+ extend_simple_arg (arg));
+ starg += 4;
+ }
+ else
+ {
+ /* You'd think we should say:
+ starg = round_up (starg, alignment_of (type));
+ Unfortunately, GCC seems to simply align the stack on
+ a four-byte boundary, even when passing doubles. */
+ starg = round_up (starg, 4);
+ write_memory (starg, VALUE_CONTENTS (arg), length);
+ starg += length;
+ }
+ }
+ }
+ }
+
+ /* Allocate the standard frame areas: the register save area, the
+ word reserved for the compiler (which seems kind of meaningless),
+ and the back chain pointer. */
+ sp -= 96;
+
+ /* Write the back chain pointer into the first word of the stack
+ frame. This will help us get backtraces from within functions
+ called from GDB. */
+ write_memory_unsigned_integer (sp, (TARGET_PTR_BIT / TARGET_CHAR_BIT),
+ read_fp ());
+
+ return sp;
}
-void
-s390_fix_call_dummy (char *dummy, CORE_ADDR pc, CORE_ADDR fun, int nargs,
- struct value **args, struct type *value_type,
- int using_gcc)
+
+static int
+s390_use_struct_convention (int gcc_p, struct type *value_type)
{
- store_unsigned_integer (dummy + 4, REGISTER_SIZE, fun);
+ enum type_code code = TYPE_CODE (value_type);
+
+ return (code == TYPE_CODE_STRUCT
+ || code == TYPE_CODE_UNION);
}
struct type *
s390_register_virtual_type (int regno)
{
- return ((unsigned) regno - S390_FPC_REGNUM) <
- S390_NUM_FPRS ? builtin_type_double : builtin_type_int;
+ if (S390_FP0_REGNUM <= regno && regno < S390_FP0_REGNUM + S390_NUM_FPRS)
+ return builtin_type_double;
+ else
+ return builtin_type_int;
}
-static unsigned char *
+const static unsigned char *
s390_breakpoint_from_pc (CORE_ADDR *pcptr, int *lenptr)
{
static unsigned char breakpoint[] = { 0x0, 0x1 };
return fextra_info.skip_prologue_function_start;
}
-/* pc_in_call_dummy_on stack may work for us must test this */
-int
-s390_pc_in_call_dummy (CORE_ADDR pc, CORE_ADDR sp, CORE_ADDR frame_address)
-{
- return pc > sp && pc < (sp + 4096);
-}
-
/* Immediately after a function call, return the saved pc.
Can't go through the frames for this because on some machines
the new frame is not set up until the new function executes
static CORE_ADDR
s390_push_return_address (CORE_ADDR pc, CORE_ADDR sp)
{
+ write_register (S390_RETADDR_REGNUM, CALL_DUMMY_ADDRESS ());
return sp;
}
struct gdbarch *
s390_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
{
-
- /* instruction sequence for s390 call dummy is as follows
- bras %r1,.+8 ; 0xA7150004
- long basraddr ; 0x00000000
- l %r1,0(%r1) ; 0x58101000
- basr %r14,%r1 ; 0x0DE1
- breakpoint ; 0x0001 */
- static LONGEST s390_call_dummy_words[] = { 0xA7150004, 0x00000000,
- 0x58101000, 0x0DE10001
- };
- /* instruction sequence for esame call dummy is as follows
- bras %r1,.+12 ; 0xA7150006
- long basraddr ; 0x0000000000000000
- lg %r1,0(%r1) ; 0xE31010000004
- basr %r14,%r1 ; 0x0DE1
- breakpoint ; 0x0001 */
- static LONGEST s390x_call_dummy_words[] = { 0xA715000600000000,
- 0x00000000E3101000,
- 0x00040DE100010000
- };
+ static LONGEST s390_call_dummy_words[] = { 0 };
struct gdbarch *gdbarch;
struct gdbarch_tdep *tdep;
int elf_flags;
gdbarch = gdbarch_alloc (&info, NULL);
set_gdbarch_believe_pcc_promotion (gdbarch, 0);
+ set_gdbarch_char_signed (gdbarch, 0);
- /* We don't define set_gdbarch_call_dummy_breakpoint_offset
- as we already have a breakpoint inserted. */
- set_gdbarch_use_generic_dummy_frames (gdbarch, 0);
-
- set_gdbarch_call_dummy_location (gdbarch, ON_STACK);
- set_gdbarch_call_dummy_start_offset (gdbarch, 0);
- set_gdbarch_pc_in_call_dummy (gdbarch, s390_pc_in_call_dummy);
set_gdbarch_frame_args_skip (gdbarch, 0);
set_gdbarch_frame_args_address (gdbarch, s390_frame_args_address);
set_gdbarch_frame_chain (gdbarch, s390_frame_chain);
/* We can't do this */
set_gdbarch_frame_num_args (gdbarch, frame_num_args_unknown);
set_gdbarch_store_struct_return (gdbarch, s390_store_struct_return);
- set_gdbarch_extract_return_value (gdbarch, s390_extract_return_value);
- set_gdbarch_store_return_value (gdbarch, s390_store_return_value);
+ set_gdbarch_deprecated_extract_return_value (gdbarch, s390_extract_return_value);
+ set_gdbarch_deprecated_store_return_value (gdbarch, s390_store_return_value);
/* Amount PC must be decremented by after a breakpoint.
This is often the number of bytes in BREAKPOINT
but not always. */
set_gdbarch_decr_pc_after_break (gdbarch, 2);
set_gdbarch_pop_frame (gdbarch, s390_pop_frame);
- set_gdbarch_push_dummy_frame (gdbarch, s390_push_dummy_frame);
- set_gdbarch_push_arguments (gdbarch, s390_push_arguments);
- set_gdbarch_ieee_float (gdbarch, 1);
/* Stack grows downward. */
set_gdbarch_inner_than (gdbarch, core_addr_lessthan);
/* Offset from address of function to start of its code.
set_gdbarch_init_extra_frame_info (gdbarch, s390_init_extra_frame_info);
set_gdbarch_init_frame_pc_first (gdbarch, s390_init_frame_pc_first);
set_gdbarch_read_fp (gdbarch, s390_read_fp);
- set_gdbarch_write_fp (gdbarch, s390_write_fp);
/* This function that tells us whether the function invocation represented
by FI does not have a frame on the stack associated with it. If it
does not, FRAMELESS is set to 1, else 0. */
set_gdbarch_num_regs (gdbarch, S390_NUM_REGS);
set_gdbarch_cannot_fetch_register (gdbarch, s390_cannot_fetch_register);
set_gdbarch_cannot_store_register (gdbarch, s390_cannot_fetch_register);
- set_gdbarch_get_saved_register (gdbarch, generic_get_saved_register);
- set_gdbarch_use_struct_convention (gdbarch, generic_use_struct_convention);
+ set_gdbarch_get_saved_register (gdbarch, generic_unwind_get_saved_register);
+ set_gdbarch_use_struct_convention (gdbarch, s390_use_struct_convention);
set_gdbarch_frame_chain_valid (gdbarch, func_frame_chain_valid);
set_gdbarch_register_name (gdbarch, s390_register_name);
set_gdbarch_stab_reg_to_regnum (gdbarch, s390_stab_reg_to_regnum);
set_gdbarch_dwarf_reg_to_regnum (gdbarch, s390_stab_reg_to_regnum);
set_gdbarch_dwarf2_reg_to_regnum (gdbarch, s390_stab_reg_to_regnum);
+ set_gdbarch_deprecated_extract_struct_value_address
+ (gdbarch, generic_cannot_extract_struct_value_address);
- /* Stuff below here wouldn't be required if gdbarch.sh was a little */
- /* more intelligent */
- set_gdbarch_call_dummy_breakpoint_offset_p (gdbarch, 0);
+ /* Parameters for inferior function calls. */
set_gdbarch_call_dummy_p (gdbarch, 1);
+ set_gdbarch_use_generic_dummy_frames (gdbarch, 1);
+ set_gdbarch_call_dummy_length (gdbarch, 0);
+ set_gdbarch_call_dummy_location (gdbarch, AT_ENTRY_POINT);
+ set_gdbarch_call_dummy_address (gdbarch, entry_point_address);
+ set_gdbarch_call_dummy_start_offset (gdbarch, 0);
+ set_gdbarch_pc_in_call_dummy (gdbarch, pc_in_call_dummy_at_entry_point);
+ set_gdbarch_push_dummy_frame (gdbarch, generic_push_dummy_frame);
+ set_gdbarch_push_arguments (gdbarch, s390_push_arguments);
+ set_gdbarch_save_dummy_frame_tos (gdbarch, generic_save_dummy_frame_tos);
+ set_gdbarch_call_dummy_breakpoint_offset_p (gdbarch, 1);
+ set_gdbarch_call_dummy_breakpoint_offset (gdbarch, 0);
set_gdbarch_call_dummy_stack_adjust_p (gdbarch, 0);
- set_gdbarch_extract_struct_value_address (gdbarch, 0);
- set_gdbarch_fix_call_dummy (gdbarch, s390_fix_call_dummy);
+ set_gdbarch_fix_call_dummy (gdbarch, generic_fix_call_dummy);
set_gdbarch_push_return_address (gdbarch, s390_push_return_address);
+ set_gdbarch_sizeof_call_dummy_words (gdbarch,
+ sizeof (s390_call_dummy_words));
+ set_gdbarch_call_dummy_words (gdbarch, s390_call_dummy_words);
+ set_gdbarch_coerce_float_to_double (gdbarch,
+ standard_coerce_float_to_double);
switch (info.bfd_arch_info->mach)
{
- case bfd_mach_s390_esa:
+ case bfd_mach_s390_31:
set_gdbarch_register_size (gdbarch, 4);
- set_gdbarch_call_dummy_length (gdbarch, 16);
set_gdbarch_register_raw_size (gdbarch, s390_register_raw_size);
set_gdbarch_register_virtual_size (gdbarch, s390_register_raw_size);
set_gdbarch_register_virtual_type (gdbarch, s390_register_virtual_type);
set_gdbarch_addr_bits_remove (gdbarch, s390_addr_bits_remove);
-
- set_gdbarch_sizeof_call_dummy_words (gdbarch,
- sizeof (s390_call_dummy_words));
- set_gdbarch_call_dummy_words (gdbarch, s390_call_dummy_words);
set_gdbarch_register_bytes (gdbarch, S390_REGISTER_BYTES);
break;
- case bfd_mach_s390_esame:
+ case bfd_mach_s390_64:
set_gdbarch_register_size (gdbarch, 8);
- set_gdbarch_call_dummy_length (gdbarch, 22);
set_gdbarch_register_raw_size (gdbarch, s390x_register_raw_size);
set_gdbarch_register_virtual_size (gdbarch, s390x_register_raw_size);
set_gdbarch_register_virtual_type (gdbarch,
set_gdbarch_long_bit (gdbarch, 64);
set_gdbarch_long_long_bit (gdbarch, 64);
set_gdbarch_ptr_bit (gdbarch, 64);
- set_gdbarch_sizeof_call_dummy_words (gdbarch,
- sizeof (s390x_call_dummy_words));
- set_gdbarch_call_dummy_words (gdbarch, s390x_call_dummy_words);
set_gdbarch_register_bytes (gdbarch, S390X_REGISTER_BYTES);
break;
}
void
-_initialize_s390_tdep ()
+_initialize_s390_tdep (void)
{
/* Hook us into the gdbarch mechanism. */