* [RFA] sh-tdep.c: Follow up patch to implement two different ABIs
@ 2003-09-17 16:11 Corinna Vinschen
2003-09-23 20:34 ` Elena Zannoni
0 siblings, 1 reply; 12+ messages in thread
From: Corinna Vinschen @ 2003-09-17 16:11 UTC (permalink / raw)
To: gdb-patches
Hi,
the below patch is a follow up patch which relies on the pending sh frame
stuff patch. This patch now adds the ability to switch between two
different ABIs on the gdb command line, the "gcc" and the "renesas" ABI.
The patch also implements the differences between these ABIs which changes
the way how arguments are passed and values are returned. Additionally it
fixes the argument passing of doubles in the gcc ABI on sh variations with
FPU. The changes in detail:
- Add the commands `set calling_convention <foo>' and
`show calling_convention' with <foo> being one of "gcc" and "renesas".
Default to "gcc".
- Differ between a fpu and a nofpu version of sh_use_struct_convention.
The nofpu version behaves like the fpu version, except that it uses
struct convention also for all types >= 8 bytes when the Renesas ABI
is active. This especially affects long longs and doubles which are
then passed on the stack.
- The Renesas ABI passes the address in which structs have to be returned
not in r2 as the gcc ABI, but instead this return address is pushed
onto the stack after all arguments have been pushed. This affects
sh_extract_struct_value_address() as well as the sh_push_dummy_call*()
functions.
- To simplify the sh_push_dummy_call*() functions, I created two helper
functions which took the part of right-justifying values < 4 byte,
called sh_justify_value_in_reg(), and to count the number of bytes
to be allocated on stack for all arguments, called sh_stack_allocsize().
- Two new functions are now used to evaluate the next floating point
register to use for an argument. The tricky part with floats is
that gcc and Renesas ABI are different in two situations:
- gcc passes floats in little-endian mode using regsters criss-crossing,
fr5, fr4, fr7, fr6, fr9, fr8 ... In big-endian mode or in Renesas
ABI, the order is simple fr4, fr5, fr6, ...
- In both ABIs doubles are passed in even register pairs, fr4/fr5,
fr6/fr7, ... The difference is when a register is skipped to pass
the next double. Example:
void foo(float a, double b, float c);
In gcc ABI, a is passed in fr4, b then skips the odd-numbered fr5
register, so it's passed in fr6/fr7 and c is then passed in the next
free register, fr8.
In Renesas ABI, a is passed in fr4, b is passed as in gcc ABI in
fr6/fr7 but c is passed in the lowest unused register, in this example
in fr5.
- In the Renesas ABI for CPUs with FPU, long longs are not passed in
registers but on stack.
- The struct_return code in both sh_push_dummy_call*() functions is moved
to the end of the function since it must be done after the argument
passing for the Rensas ABI.
- I renamed the flag `odd_sized_struct' to a more descriptive name,
`pass_on_stack' since the old name does in no way reflect how the
decision about passing on stack or in register is actually made. The
actual decision is as follows:
- On FPU CPUs, pass in registers unless the datatype is bigger than
16 bytes. Renesas ABI additionally passes long longs on the stack
as well.
- On non-FPU CPUs, doubles and long doubles are passed always on the stack.
- On all CPUs, everything else is passed in registers until the argument
registers are filled up, the remaining arguments are passed on stack.
If an argument doesn't fit entirely in the remaining registers, it's
split between regs and stack as see fit.
- The code and comment that some data is sometimes passed in registers
*and* stack simultaneously is dropped. That's not how it works.
Seems to be something sh5 specific but that's now in sh64-tdep.c.
- Also in sh_push_dummy_call*(), the code which adds 4 for every 4 bytes
managed, is changed from e.g.
len -= register_size (gdbarch, argreg);
to
len -= 4;
The reason is that the original line is not exactly correct. It adds the
register_size of the *next* register, not the register actually filled
with data. Since all data and registers in question are 4 byte regs (and
the target specific code should know that anyway), I've simplified the
affected code.
Corinna
ChangeLog:
==========
* sh-tdep.c (sh_cc_gcc): New static string.
(sh_cc_renesas): Ditto.
(sh_cc_enum): New array pointing to calling convention strings.
(sh_active_calling_convention): New variable pointing to
current active calling convention.
(sh_use_struct_convention_fpu): New function.
(sh_use_struct_convention_nofpu): New function.
(sh_use_struct_convention): Remove. Superseeded by the previous
two functions.
(sh_extract_struct_value_address): Care for Renesas ABI.
(sh_justify_value_in_reg): New function.
(sh_stack_allocsize): Ditto.
(flt_argreg_array): New array used for floating point argument
passing.
(sh_init_flt_argreg): New function.
(sh_next_flt_argreg): Ditto.
(sh_push_dummy_call_fpu): Simplify. Rename "odd_sized_struct" to
"pass_on_stack". Use new helper functions. Accomodate Renesas ABI.
Fix argument passing strategy.
(sh_push_dummy_call_nofpu): Ditto.
(sh_gdbarch_init): Accomodate new sh_use_struct_convention_fpu and
sh_use_struct_convention_nofpu functions.
(_initialize_sh_tdep): Initialize new "set calling_convention",
"show calling_convention" commands.
--- sh-tdep.c.AFTERPATCH2 2003-09-15 17:14:33.000000000 +0200
+++ sh-tdep.c 2003-09-16 18:17:39.000000000 +0200
@@ -55,6 +55,17 @@
/* registers numbers shared with the simulator */
#include "gdb/sim-sh.h"
+static const char sh_cc_gcc[] = "gcc";
+static const char sh_cc_renesas[] = "renesas";
+static const char *sh_cc_enum[] =
+{
+ sh_cc_gcc,
+ sh_cc_renesas,
+ NULL
+};
+
+static const char *sh_active_calling_convention = sh_cc_gcc;
+
static void (*sh_show_regs) (void);
#define SH_NUM_REGS 59
@@ -569,10 +580,25 @@ sh_skip_prologue (CORE_ADDR start_pc)
/* Should call_function allocate stack space for a struct return? */
static int
-sh_use_struct_convention (int gcc_p, struct type *type)
+sh_use_struct_convention_fpu (int gcc_p, struct type *type)
+{
+ int len = TYPE_LENGTH (type);
+ int nelem = TYPE_NFIELDS (type);
+
+ return ((len != 1 && len != 2 && len != 4 && len != 8) || nelem != 1) &&
+ (len != 8 || TYPE_LENGTH (TYPE_FIELD_TYPE (type, 0)) != 4);
+}
+
+static int
+sh_use_struct_convention_nofpu (int gcc_p, struct type *type)
{
int len = TYPE_LENGTH (type);
int nelem = TYPE_NFIELDS (type);
+
+ /* The Renesas ABI returns long longs/doubles etc. always on stack. */
+ if (sh_active_calling_convention == sh_cc_renesas && len >= 8)
+ return 1;
+
return ((len != 1 && len != 2 && len != 4 && len != 8) || nelem != 1) &&
(len != 8 || TYPE_LENGTH (TYPE_FIELD_TYPE (type, 0)) != 4);
}
@@ -584,8 +610,13 @@ static CORE_ADDR
sh_extract_struct_value_address (struct regcache *regcache)
{
ULONGEST addr;
-
- regcache_cooked_read_unsigned (regcache, STRUCT_RETURN_REGNUM, &addr);
+ if (sh_active_calling_convention != sh_cc_renesas)
+ regcache_cooked_read_unsigned (regcache, STRUCT_RETURN_REGNUM, &addr);
+ else
+ {
+ regcache_cooked_read_unsigned (regcache, SP_REGNUM, &addr);
+ addr = read_memory_unsigned_integer (addr, 4);
+ }
return addr;
}
@@ -647,6 +678,102 @@ sh_frame_align (struct gdbarch *ignore,
not displace any of the other arguments passed in via registers R4
to R7. */
+/* Helper function to justify value in register according to endianess. */
+static char *
+sh_justify_value_in_reg (struct value *val, int len)
+{
+ static char valbuf[4];
+
+ memset (valbuf, 0, sizeof (valbuf));
+ if (len < 4)
+ {
+ /* value gets right-justified in the register or stack word */
+ if (TARGET_BYTE_ORDER == BFD_ENDIAN_BIG)
+ memcpy (valbuf + (4 - len), (char *) VALUE_CONTENTS (val), len);
+ else
+ memcpy (valbuf, (char *) VALUE_CONTENTS (val), len);
+ return valbuf;
+ }
+ return (char *) VALUE_CONTENTS (val);
+}
+
+/* Helper function to eval number of bytes to allocate on stack. */
+static CORE_ADDR
+sh_stack_allocsize (int nargs, struct value **args)
+{
+ int stack_alloc = 0;
+ while (nargs-- > 0)
+ stack_alloc += ((TYPE_LENGTH (VALUE_TYPE (args[nargs])) + 3) & ~3);
+ return stack_alloc;
+}
+
+/* Helper functions for getting the float arguments right. Registers usage
+ depends on the ABI and the endianess. The comments should enlighten how
+ it's intended to work. */
+
+/* This array stores which of the float arg registers are already in use. */
+static int flt_argreg_array[FLOAT_ARGLAST_REGNUM - FLOAT_ARG0_REGNUM + 1];
+
+/* This function just resets the above array to "no reg used so far". */
+static void
+sh_init_flt_argreg (void)
+{
+ memset (flt_argreg_array, 0, sizeof flt_argreg_array);
+}
+
+/* This function returns the next register to use for float arg passing.
+ It returns either a valid value between FLOAT_ARG0_REGNUM and
+ FLOAT_ARGLAST_REGNUM if a register is available, otherwise it returns
+ FLOAT_ARGLAST_REGNUM + 1 to indicate that no register is available.
+
+ Note that register number 0 in flt_argreg_array corresponds with the
+ real float register fr4. In contrast to FLOAT_ARG0_REGNUM (value is
+ 29) the parity of the register number is preserved, which is important
+ for the double register passing test (see the "argreg & 1" test below). */
+static int
+sh_next_flt_argreg (int len)
+{
+ int argreg;
+
+ /* First search for the next free register. */
+ for (argreg = 0; argreg <= FLOAT_ARGLAST_REGNUM - FLOAT_ARG0_REGNUM; ++argreg)
+ if (!flt_argreg_array[argreg])
+ break;
+
+ /* No register left? */
+ if (argreg > FLOAT_ARGLAST_REGNUM - FLOAT_ARG0_REGNUM)
+ return FLOAT_ARGLAST_REGNUM + 1;
+
+ if (len == 8)
+ {
+ /* Doubles are always starting in a even register number. */
+ if (argreg & 1)
+ {
+ /* In gcc ABI, the skipped register is lost for further argument
+ passing now. Not so in Renesas ABI. */
+ if (sh_active_calling_convention != sh_cc_renesas)
+ flt_argreg_array[argreg] = 1;
+
+ ++argreg;
+
+ /* No register left? */
+ if (argreg > FLOAT_ARGLAST_REGNUM - FLOAT_ARG0_REGNUM)
+ return FLOAT_ARGLAST_REGNUM + 1;
+ }
+ /* Also mark the next register as used. */
+ flt_argreg_array[argreg + 1] = 1;
+ }
+ else if (TARGET_BYTE_ORDER == BFD_ENDIAN_LITTLE
+ && sh_active_calling_convention != sh_cc_renesas)
+ {
+ /* In little endian, gcc passes floats like this: f5, f4, f7, f6, ... */
+ if (!flt_argreg_array[argreg + 1])
+ ++argreg;
+ }
+ flt_argreg_array[argreg] = 1;
+ return FLOAT_ARG0_REGNUM + argreg;
+}
+
static CORE_ADDR
sh_push_dummy_call_fpu (struct gdbarch *gdbarch,
CORE_ADDR func_addr,
@@ -656,77 +783,61 @@ sh_push_dummy_call_fpu (struct gdbarch *
CORE_ADDR sp, int struct_return,
CORE_ADDR struct_addr)
{
- int stack_offset, stack_alloc;
- int argreg, flt_argreg;
+ int stack_offset = 0;
+ int argreg = ARG0_REGNUM;
+ int flt_argreg;
int argnum;
struct type *type;
CORE_ADDR regval;
char *val;
- char valbuf[4];
int len;
- int odd_sized_struct;
+ int pass_on_stack;
/* first force sp to a 4-byte alignment */
sp = sh_frame_align (gdbarch, sp);
- if (struct_return)
- regcache_cooked_write_unsigned (regcache,
- STRUCT_RETURN_REGNUM,
- struct_addr);
-
- /* Now make sure there's space on the stack */
- for (argnum = 0, stack_alloc = 0; argnum < nargs; argnum++)
- stack_alloc += ((TYPE_LENGTH (VALUE_TYPE (args[argnum])) + 3) & ~3);
- sp -= stack_alloc; /* make room on stack for args */
+ /* make room on stack for args */
+ sp -= sh_stack_allocsize (nargs, args);
+
+ /* Initialize float argument mechanism. */
+ sh_init_flt_argreg ();
/* Now load as many as possible of the first arguments into
registers, and push the rest onto the stack. There are 16 bytes
in four registers available. Loop thru args from first to last. */
-
- argreg = ARG0_REGNUM;
- flt_argreg = FLOAT_ARG0_REGNUM;
- for (argnum = 0, stack_offset = 0; argnum < nargs; argnum++)
+ for (argnum = 0; argnum < nargs; argnum++)
{
type = VALUE_TYPE (args[argnum]);
len = TYPE_LENGTH (type);
- memset (valbuf, 0, sizeof (valbuf));
- if (len < 4)
- {
- /* value gets right-justified in the register or stack word */
- if (TARGET_BYTE_ORDER == BFD_ENDIAN_BIG)
- memcpy (valbuf + (4 - len),
- (char *) VALUE_CONTENTS (args[argnum]), len);
- else
- memcpy (valbuf, (char *) VALUE_CONTENTS (args[argnum]), len);
- val = valbuf;
- }
- else
- val = (char *) VALUE_CONTENTS (args[argnum]);
+ val = sh_justify_value_in_reg (args[argnum], len);
+
+ /* Some decisions have to be made how various types are handled.
+ This also differs in different ABIs. */
+ pass_on_stack = 0;
+ if (len > 16)
+ pass_on_stack = 1; /* Types bigger than 16 bytes are passed on stack. */
+ else if (sh_active_calling_convention == sh_cc_renesas
+ && TYPE_CODE (type) == TYPE_CODE_INT && len == 8)
+ pass_on_stack = 1; /* So are long longs in renesas ABI */
+
+ /* Find out the next register to use for a floating point value. */
+ if (TYPE_CODE (type) == TYPE_CODE_FLT)
+ flt_argreg = sh_next_flt_argreg (len);
- if (len > 4 && (len & 3) != 0)
- odd_sized_struct = 1; /* Such structs go entirely on stack. */
- else if (len > 16)
- odd_sized_struct = 1; /* So do aggregates bigger than 4 words. */
- else
- odd_sized_struct = 0;
while (len > 0)
{
if ((TYPE_CODE (type) == TYPE_CODE_FLT
&& flt_argreg > FLOAT_ARGLAST_REGNUM)
|| argreg > ARGLAST_REGNUM
- || odd_sized_struct)
+ || pass_on_stack)
{
- /* must go on the stack */
write_memory (sp + stack_offset, val, 4);
stack_offset += 4;
}
- /* NOTE WELL!!!!! This is not an "else if" clause!!!
- That's because some *&^%$ things get passed on the stack
- AND in the registers! */
- if (TYPE_CODE (type) == TYPE_CODE_FLT &&
- flt_argreg > 0 && flt_argreg <= FLOAT_ARGLAST_REGNUM)
+ else if (TYPE_CODE (type) == TYPE_CODE_FLT
+ && flt_argreg <= FLOAT_ARGLAST_REGNUM)
{
- /* Argument goes in a single-precision fp reg. */
+ /* Argument goes in a float argument register. */
regval = extract_unsigned_integer (val, register_size (gdbarch,
argreg));
regcache_cooked_write_unsigned (regcache, flt_argreg++, regval);
@@ -741,11 +852,25 @@ sh_push_dummy_call_fpu (struct gdbarch *
/* Store the value 4 bytes at a time. This means that things
larger than 4 bytes may go partly in registers and partly
on the stack. */
- len -= register_size (gdbarch, argreg);
- val += register_size (gdbarch, argreg);
+ len -= 4;
+ val += 4;
}
}
+ if (struct_return)
+ {
+ if (sh_active_calling_convention != sh_cc_renesas)
+ /* Using the gcc ABI, the "struct return pointer" pseudo-argument has
+ its own dedicated register */
+ regcache_cooked_write_unsigned (regcache,
+ STRUCT_RETURN_REGNUM,
+ struct_addr);
+ else
+ /* If the function uses the renesas ABI, subtract another 4 bytes from
+ the stack and store the struct return address there. */
+ write_memory_unsigned_integer (sp -= 4, 4, struct_addr);
+ }
+
/* Store return address. */
regcache_cooked_write_unsigned (regcache, PR_REGNUM, bp_addr);
@@ -764,69 +889,45 @@ sh_push_dummy_call_nofpu (struct gdbarch
CORE_ADDR sp, int struct_return,
CORE_ADDR struct_addr)
{
- int stack_offset, stack_alloc;
- int argreg;
+ int stack_offset = 0;
+ int argreg = ARG0_REGNUM;
int argnum;
struct type *type;
CORE_ADDR regval;
char *val;
- char valbuf[4];
int len;
- int odd_sized_struct;
+ int pass_on_stack;
/* first force sp to a 4-byte alignment */
sp = sh_frame_align (gdbarch, sp);
- if (struct_return)
- regcache_cooked_write_unsigned (regcache,
- STRUCT_RETURN_REGNUM,
- struct_addr);
-
- /* Now make sure there's space on the stack */
- for (argnum = 0, stack_alloc = 0; argnum < nargs; argnum++)
- stack_alloc += ((TYPE_LENGTH (VALUE_TYPE (args[argnum])) + 3) & ~3);
- sp -= stack_alloc; /* make room on stack for args */
+ /* make room on stack for args */
+ sp -= sh_stack_allocsize (nargs, args);
/* Now load as many as possible of the first arguments into
registers, and push the rest onto the stack. There are 16 bytes
in four registers available. Loop thru args from first to last. */
-
- argreg = ARG0_REGNUM;
- for (argnum = 0, stack_offset = 0; argnum < nargs; argnum++)
+ for (argnum = 0; argnum < nargs; argnum++)
{
type = VALUE_TYPE (args[argnum]);
len = TYPE_LENGTH (type);
- memset (valbuf, 0, sizeof (valbuf));
- if (len < 4)
- {
- /* value gets right-justified in the register or stack word */
- if (TARGET_BYTE_ORDER == BFD_ENDIAN_BIG)
- memcpy (valbuf + (4 - len),
- (char *) VALUE_CONTENTS (args[argnum]), len);
- else
- memcpy (valbuf, (char *) VALUE_CONTENTS (args[argnum]), len);
- val = valbuf;
- }
- else
- val = (char *) VALUE_CONTENTS (args[argnum]);
+ val = sh_justify_value_in_reg (args[argnum], len);
+
+ /* Some decisions have to be made how various types are handled.
+ This also differs in different ABIs. */
+ pass_on_stack = 0;
+ if (TYPE_CODE (type) == TYPE_CODE_FLT && len > 4
+ && sh_active_calling_convention == sh_cc_renesas)
+ pass_on_stack = 1; /* Renesas ABI pushes doubles entirely on stack. */
- if (len > 4 && (len & 3) != 0)
- odd_sized_struct = 1; /* such structs go entirely on stack */
- else
- odd_sized_struct = 0;
while (len > 0)
{
- if (argreg > ARGLAST_REGNUM
- || odd_sized_struct)
+ if (argreg > ARGLAST_REGNUM || pass_on_stack)
{
- /* must go on the stack */
write_memory (sp + stack_offset, val, 4);
stack_offset += 4;
}
- /* NOTE WELL!!!!! This is not an "else if" clause!!!
- That's because some *&^%$ things get passed on the stack
- AND in the registers! */
- if (argreg <= ARGLAST_REGNUM)
+ else if (argreg <= ARGLAST_REGNUM)
{
/* there's room in a register */
regval = extract_unsigned_integer (val, register_size (gdbarch,
@@ -836,11 +937,25 @@ sh_push_dummy_call_nofpu (struct gdbarch
/* Store the value 4 bytes at a time. This means that things
larger than 4 bytes may go partly in registers and partly
on the stack. */
- len -= register_size (gdbarch, argreg);
- val += register_size (gdbarch, argreg);
+ len -= 4;
+ val += 4;
}
}
+ if (struct_return)
+ {
+ if (sh_active_calling_convention != sh_cc_renesas)
+ /* Using the gcc ABI, the "struct return pointer" pseudo-argument has
+ its own dedicated register */
+ regcache_cooked_write_unsigned (regcache,
+ STRUCT_RETURN_REGNUM,
+ struct_addr);
+ else
+ /* If the function uses the renesas ABI, subtract another 4 bytes from
+ the stack and store the struct return address there. */
+ write_memory_unsigned_integer (sp -= 4, 4, struct_addr);
+ }
+
/* Store return address. */
regcache_cooked_write_unsigned (regcache, PR_REGNUM, bp_addr);
@@ -2060,7 +2175,6 @@ sh_gdbarch_init (struct gdbarch_info inf
set_gdbarch_print_registers_info (gdbarch, sh_print_registers_info);
set_gdbarch_breakpoint_from_pc (gdbarch, sh_breakpoint_from_pc);
- set_gdbarch_use_struct_convention (gdbarch, sh_use_struct_convention);
set_gdbarch_print_insn (gdbarch, gdb_print_insn_sh);
set_gdbarch_register_sim_regno (gdbarch, legacy_register_sim_regno);
@@ -2079,6 +2193,7 @@ sh_gdbarch_init (struct gdbarch_info inf
set_gdbarch_push_dummy_code (gdbarch, sh_push_dummy_code);
set_gdbarch_push_dummy_call (gdbarch, sh_push_dummy_call_nofpu);
+ set_gdbarch_use_struct_convention (gdbarch, sh_use_struct_convention_nofpu);
set_gdbarch_frame_args_skip (gdbarch, 0);
set_gdbarch_frameless_function_invocation (gdbarch,
@@ -2114,6 +2229,7 @@ sh_gdbarch_init (struct gdbarch_info inf
set_gdbarch_store_return_value (gdbarch, sh3e_sh4_store_return_value);
set_gdbarch_extract_return_value (gdbarch, sh3e_sh4_extract_return_value);
set_gdbarch_push_dummy_call (gdbarch, sh_push_dummy_call_fpu);
+ set_gdbarch_use_struct_convention (gdbarch, sh_use_struct_convention_fpu);
break;
case bfd_mach_sh_dsp:
@@ -2135,6 +2251,7 @@ sh_gdbarch_init (struct gdbarch_info inf
set_gdbarch_store_return_value (gdbarch, sh3e_sh4_store_return_value);
set_gdbarch_extract_return_value (gdbarch, sh3e_sh4_extract_return_value);
set_gdbarch_push_dummy_call (gdbarch, sh_push_dummy_call_fpu);
+ set_gdbarch_use_struct_convention (gdbarch, sh_use_struct_convention_fpu);
break;
case bfd_mach_sh3_dsp:
@@ -2152,6 +2269,7 @@ sh_gdbarch_init (struct gdbarch_info inf
set_gdbarch_store_return_value (gdbarch, sh3e_sh4_store_return_value);
set_gdbarch_extract_return_value (gdbarch, sh3e_sh4_extract_return_value);
set_gdbarch_push_dummy_call (gdbarch, sh_push_dummy_call_fpu);
+ set_gdbarch_use_struct_convention (gdbarch, sh_use_struct_convention_fpu);
break;
default:
@@ -2178,4 +2296,11 @@ _initialize_sh_tdep (void)
gdbarch_register (bfd_arch_sh, sh_gdbarch_init, NULL);
add_com ("regs", class_vars, sh_show_regs_command, "Print all registers");
+
+ add_show_from_set (
+ add_set_enum_cmd ("calling_convention", class_vars, sh_cc_enum,
+ &sh_active_calling_convention,
+ "Set calling convention used when calling target "
+ "functions from GDB.",
+ &setlist), &showlist);
}
--
Corinna Vinschen
Cygwin Developer
Red Hat, Inc.
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [RFA] sh-tdep.c: Follow up patch to implement two different ABIs
2003-09-17 16:11 [RFA] sh-tdep.c: Follow up patch to implement two different ABIs Corinna Vinschen
@ 2003-09-23 20:34 ` Elena Zannoni
2003-09-23 21:27 ` Andrew Cagney
` (2 more replies)
0 siblings, 3 replies; 12+ messages in thread
From: Elena Zannoni @ 2003-09-23 20:34 UTC (permalink / raw)
To: gdb-patches
Corinna Vinschen writes:
> Hi,
>
> the below patch is a follow up patch which relies on the pending sh frame
> stuff patch. This patch now adds the ability to switch between two
> different ABIs on the gdb command line, the "gcc" and the "renesas" ABI.
> The patch also implements the differences between these ABIs which changes
> the way how arguments are passed and values are returned. Additionally it
> fixes the argument passing of doubles in the gcc ABI on sh variations with
> FPU. The changes in detail:
I think this patch has too much stuff in it. Can you change it to fix
the gcc abi (the fpu stuff), and then add the rest for the renesas
variant?
>
> - Add the commands `set calling_convention <foo>' and
> `show calling_convention' with <foo> being one of "gcc" and "renesas".
> Default to "gcc".
Should be using hyphen, not underscore. What happens if you have a
file compiled with renesas ABI but you set the calling convention to
the gcc (or vice versa)? How are the abi supported by gcc? Is there a
-with-abi-renesas to be given when one compiles the tests? I.e. is it
possible to run the testsuite with the one specific abi?
>
> - Differ between a fpu and a nofpu version of sh_use_struct_convention.
> The nofpu version behaves like the fpu version, except that it uses
> struct convention also for all types >= 8 bytes when the Renesas ABI
> is active. This especially affects long longs and doubles which are
> then passed on the stack.
>
> - The Renesas ABI passes the address in which structs have to be returned
> not in r2 as the gcc ABI, but instead this return address is pushed
> onto the stack after all arguments have been pushed. This affects
> sh_extract_struct_value_address() as well as the sh_push_dummy_call*()
> functions.
>
> - To simplify the sh_push_dummy_call*() functions, I created two helper
> functions which took the part of right-justifying values < 4 byte,
> called sh_justify_value_in_reg(), and to count the number of bytes
> to be allocated on stack for all arguments, called sh_stack_allocsize().
>
> - Two new functions are now used to evaluate the next floating point
> register to use for an argument. The tricky part with floats is
> that gcc and Renesas ABI are different in two situations:
>
> - gcc passes floats in little-endian mode using regsters criss-crossing,
> fr5, fr4, fr7, fr6, fr9, fr8 ... In big-endian mode or in Renesas
> ABI, the order is simple fr4, fr5, fr6, ...
>
> - In both ABIs doubles are passed in even register pairs, fr4/fr5,
> fr6/fr7, ... The difference is when a register is skipped to pass
> the next double. Example:
>
> void foo(float a, double b, float c);
>
> In gcc ABI, a is passed in fr4, b then skips the odd-numbered fr5
> register, so it's passed in fr6/fr7 and c is then passed in the next
> free register, fr8.
>
> In Renesas ABI, a is passed in fr4, b is passed as in gcc ABI in
> fr6/fr7 but c is passed in the lowest unused register, in this example
> in fr5.
>
> - In the Renesas ABI for CPUs with FPU, long longs are not passed in
> registers but on stack.
>
> - The struct_return code in both sh_push_dummy_call*() functions is moved
> to the end of the function since it must be done after the argument
> passing for the Rensas ABI.
>
> - I renamed the flag `odd_sized_struct' to a more descriptive name,
> `pass_on_stack' since the old name does in no way reflect how the
> decision about passing on stack or in register is actually made. The
> actual decision is as follows:
>
> - On FPU CPUs, pass in registers unless the datatype is bigger than
> 16 bytes. Renesas ABI additionally passes long longs on the stack
> as well.
>
> - On non-FPU CPUs, doubles and long doubles are passed always on the stack.
>
> - On all CPUs, everything else is passed in registers until the argument
> registers are filled up, the remaining arguments are passed on stack.
> If an argument doesn't fit entirely in the remaining registers, it's
> split between regs and stack as see fit.
>
> - The code and comment that some data is sometimes passed in registers
> *and* stack simultaneously is dropped. That's not how it works.
> Seems to be something sh5 specific but that's now in sh64-tdep.c.
>
Actually this is part of the original port as contributed by Steve
Chamberlain. Is this true of gcc or of the original hitachi abi?
> - Also in sh_push_dummy_call*(), the code which adds 4 for every 4 bytes
> managed, is changed from e.g.
>
> len -= register_size (gdbarch, argreg);
>
> to
>
> len -= 4;
>
> The reason is that the original line is not exactly correct. It adds the
> register_size of the *next* register, not the register actually filled
> with data. Since all data and registers in question are 4 byte regs (and
> the target specific code should know that anyway), I've simplified the
> affected code.
>
I don't like to have harcoded register sizes, if argreg is wrong, is
there a way to get the correct parameter?
elena
>
> Corinna
>
>
> ChangeLog:
> ==========
>
> * sh-tdep.c (sh_cc_gcc): New static string.
> (sh_cc_renesas): Ditto.
> (sh_cc_enum): New array pointing to calling convention strings.
> (sh_active_calling_convention): New variable pointing to
> current active calling convention.
> (sh_use_struct_convention_fpu): New function.
> (sh_use_struct_convention_nofpu): New function.
> (sh_use_struct_convention): Remove. Superseeded by the previous
> two functions.
> (sh_extract_struct_value_address): Care for Renesas ABI.
> (sh_justify_value_in_reg): New function.
> (sh_stack_allocsize): Ditto.
> (flt_argreg_array): New array used for floating point argument
> passing.
> (sh_init_flt_argreg): New function.
> (sh_next_flt_argreg): Ditto.
> (sh_push_dummy_call_fpu): Simplify. Rename "odd_sized_struct" to
> "pass_on_stack". Use new helper functions. Accomodate Renesas ABI.
> Fix argument passing strategy.
> (sh_push_dummy_call_nofpu): Ditto.
> (sh_gdbarch_init): Accomodate new sh_use_struct_convention_fpu and
> sh_use_struct_convention_nofpu functions.
> (_initialize_sh_tdep): Initialize new "set calling_convention",
> "show calling_convention" commands.
>
> --- sh-tdep.c.AFTERPATCH2 2003-09-15 17:14:33.000000000 +0200
> +++ sh-tdep.c 2003-09-16 18:17:39.000000000 +0200
> @@ -55,6 +55,17 @@
> /* registers numbers shared with the simulator */
> #include "gdb/sim-sh.h"
>
> +static const char sh_cc_gcc[] = "gcc";
> +static const char sh_cc_renesas[] = "renesas";
> +static const char *sh_cc_enum[] =
> +{
> + sh_cc_gcc,
> + sh_cc_renesas,
> + NULL
> +};
> +
> +static const char *sh_active_calling_convention = sh_cc_gcc;
> +
> static void (*sh_show_regs) (void);
>
> #define SH_NUM_REGS 59
> @@ -569,10 +580,25 @@ sh_skip_prologue (CORE_ADDR start_pc)
>
> /* Should call_function allocate stack space for a struct return? */
> static int
> -sh_use_struct_convention (int gcc_p, struct type *type)
> +sh_use_struct_convention_fpu (int gcc_p, struct type *type)
> +{
> + int len = TYPE_LENGTH (type);
> + int nelem = TYPE_NFIELDS (type);
> +
> + return ((len != 1 && len != 2 && len != 4 && len != 8) || nelem != 1) &&
> + (len != 8 || TYPE_LENGTH (TYPE_FIELD_TYPE (type, 0)) != 4);
> +}
> +
> +static int
> +sh_use_struct_convention_nofpu (int gcc_p, struct type *type)
> {
> int len = TYPE_LENGTH (type);
> int nelem = TYPE_NFIELDS (type);
> +
> + /* The Renesas ABI returns long longs/doubles etc. always on stack. */
> + if (sh_active_calling_convention == sh_cc_renesas && len >= 8)
> + return 1;
> +
> return ((len != 1 && len != 2 && len != 4 && len != 8) || nelem != 1) &&
> (len != 8 || TYPE_LENGTH (TYPE_FIELD_TYPE (type, 0)) != 4);
> }
> @@ -584,8 +610,13 @@ static CORE_ADDR
> sh_extract_struct_value_address (struct regcache *regcache)
> {
> ULONGEST addr;
> -
> - regcache_cooked_read_unsigned (regcache, STRUCT_RETURN_REGNUM, &addr);
> + if (sh_active_calling_convention != sh_cc_renesas)
> + regcache_cooked_read_unsigned (regcache, STRUCT_RETURN_REGNUM, &addr);
> + else
> + {
> + regcache_cooked_read_unsigned (regcache, SP_REGNUM, &addr);
> + addr = read_memory_unsigned_integer (addr, 4);
> + }
> return addr;
> }
>
> @@ -647,6 +678,102 @@ sh_frame_align (struct gdbarch *ignore,
> not displace any of the other arguments passed in via registers R4
> to R7. */
>
> +/* Helper function to justify value in register according to endianess. */
> +static char *
> +sh_justify_value_in_reg (struct value *val, int len)
> +{
> + static char valbuf[4];
> +
> + memset (valbuf, 0, sizeof (valbuf));
> + if (len < 4)
> + {
> + /* value gets right-justified in the register or stack word */
> + if (TARGET_BYTE_ORDER == BFD_ENDIAN_BIG)
> + memcpy (valbuf + (4 - len), (char *) VALUE_CONTENTS (val), len);
> + else
> + memcpy (valbuf, (char *) VALUE_CONTENTS (val), len);
> + return valbuf;
> + }
> + return (char *) VALUE_CONTENTS (val);
> +}
> +
> +/* Helper function to eval number of bytes to allocate on stack. */
> +static CORE_ADDR
> +sh_stack_allocsize (int nargs, struct value **args)
> +{
> + int stack_alloc = 0;
> + while (nargs-- > 0)
> + stack_alloc += ((TYPE_LENGTH (VALUE_TYPE (args[nargs])) + 3) & ~3);
> + return stack_alloc;
> +}
> +
> +/* Helper functions for getting the float arguments right. Registers usage
> + depends on the ABI and the endianess. The comments should enlighten how
> + it's intended to work. */
> +
> +/* This array stores which of the float arg registers are already in use. */
> +static int flt_argreg_array[FLOAT_ARGLAST_REGNUM - FLOAT_ARG0_REGNUM + 1];
> +
> +/* This function just resets the above array to "no reg used so far". */
> +static void
> +sh_init_flt_argreg (void)
> +{
> + memset (flt_argreg_array, 0, sizeof flt_argreg_array);
> +}
> +
> +/* This function returns the next register to use for float arg passing.
> + It returns either a valid value between FLOAT_ARG0_REGNUM and
> + FLOAT_ARGLAST_REGNUM if a register is available, otherwise it returns
> + FLOAT_ARGLAST_REGNUM + 1 to indicate that no register is available.
> +
> + Note that register number 0 in flt_argreg_array corresponds with the
> + real float register fr4. In contrast to FLOAT_ARG0_REGNUM (value is
> + 29) the parity of the register number is preserved, which is important
> + for the double register passing test (see the "argreg & 1" test below). */
> +static int
> +sh_next_flt_argreg (int len)
> +{
> + int argreg;
> +
> + /* First search for the next free register. */
> + for (argreg = 0; argreg <= FLOAT_ARGLAST_REGNUM - FLOAT_ARG0_REGNUM; ++argreg)
> + if (!flt_argreg_array[argreg])
> + break;
> +
> + /* No register left? */
> + if (argreg > FLOAT_ARGLAST_REGNUM - FLOAT_ARG0_REGNUM)
> + return FLOAT_ARGLAST_REGNUM + 1;
> +
> + if (len == 8)
> + {
> + /* Doubles are always starting in a even register number. */
> + if (argreg & 1)
> + {
> + /* In gcc ABI, the skipped register is lost for further argument
> + passing now. Not so in Renesas ABI. */
> + if (sh_active_calling_convention != sh_cc_renesas)
> + flt_argreg_array[argreg] = 1;
> +
> + ++argreg;
> +
> + /* No register left? */
> + if (argreg > FLOAT_ARGLAST_REGNUM - FLOAT_ARG0_REGNUM)
> + return FLOAT_ARGLAST_REGNUM + 1;
> + }
> + /* Also mark the next register as used. */
> + flt_argreg_array[argreg + 1] = 1;
> + }
> + else if (TARGET_BYTE_ORDER == BFD_ENDIAN_LITTLE
> + && sh_active_calling_convention != sh_cc_renesas)
> + {
> + /* In little endian, gcc passes floats like this: f5, f4, f7, f6, ... */
> + if (!flt_argreg_array[argreg + 1])
> + ++argreg;
> + }
> + flt_argreg_array[argreg] = 1;
> + return FLOAT_ARG0_REGNUM + argreg;
> +}
> +
> static CORE_ADDR
> sh_push_dummy_call_fpu (struct gdbarch *gdbarch,
> CORE_ADDR func_addr,
> @@ -656,77 +783,61 @@ sh_push_dummy_call_fpu (struct gdbarch *
> CORE_ADDR sp, int struct_return,
> CORE_ADDR struct_addr)
> {
> - int stack_offset, stack_alloc;
> - int argreg, flt_argreg;
> + int stack_offset = 0;
> + int argreg = ARG0_REGNUM;
> + int flt_argreg;
> int argnum;
> struct type *type;
> CORE_ADDR regval;
> char *val;
> - char valbuf[4];
> int len;
> - int odd_sized_struct;
> + int pass_on_stack;
>
> /* first force sp to a 4-byte alignment */
> sp = sh_frame_align (gdbarch, sp);
>
> - if (struct_return)
> - regcache_cooked_write_unsigned (regcache,
> - STRUCT_RETURN_REGNUM,
> - struct_addr);
> -
> - /* Now make sure there's space on the stack */
> - for (argnum = 0, stack_alloc = 0; argnum < nargs; argnum++)
> - stack_alloc += ((TYPE_LENGTH (VALUE_TYPE (args[argnum])) + 3) & ~3);
> - sp -= stack_alloc; /* make room on stack for args */
> + /* make room on stack for args */
> + sp -= sh_stack_allocsize (nargs, args);
> +
> + /* Initialize float argument mechanism. */
> + sh_init_flt_argreg ();
>
> /* Now load as many as possible of the first arguments into
> registers, and push the rest onto the stack. There are 16 bytes
> in four registers available. Loop thru args from first to last. */
> -
> - argreg = ARG0_REGNUM;
> - flt_argreg = FLOAT_ARG0_REGNUM;
> - for (argnum = 0, stack_offset = 0; argnum < nargs; argnum++)
> + for (argnum = 0; argnum < nargs; argnum++)
> {
> type = VALUE_TYPE (args[argnum]);
> len = TYPE_LENGTH (type);
> - memset (valbuf, 0, sizeof (valbuf));
> - if (len < 4)
> - {
> - /* value gets right-justified in the register or stack word */
> - if (TARGET_BYTE_ORDER == BFD_ENDIAN_BIG)
> - memcpy (valbuf + (4 - len),
> - (char *) VALUE_CONTENTS (args[argnum]), len);
> - else
> - memcpy (valbuf, (char *) VALUE_CONTENTS (args[argnum]), len);
> - val = valbuf;
> - }
> - else
> - val = (char *) VALUE_CONTENTS (args[argnum]);
> + val = sh_justify_value_in_reg (args[argnum], len);
> +
> + /* Some decisions have to be made how various types are handled.
> + This also differs in different ABIs. */
> + pass_on_stack = 0;
> + if (len > 16)
> + pass_on_stack = 1; /* Types bigger than 16 bytes are passed on stack. */
> + else if (sh_active_calling_convention == sh_cc_renesas
> + && TYPE_CODE (type) == TYPE_CODE_INT && len == 8)
> + pass_on_stack = 1; /* So are long longs in renesas ABI */
> +
> + /* Find out the next register to use for a floating point value. */
> + if (TYPE_CODE (type) == TYPE_CODE_FLT)
> + flt_argreg = sh_next_flt_argreg (len);
>
> - if (len > 4 && (len & 3) != 0)
> - odd_sized_struct = 1; /* Such structs go entirely on stack. */
> - else if (len > 16)
> - odd_sized_struct = 1; /* So do aggregates bigger than 4 words. */
> - else
> - odd_sized_struct = 0;
> while (len > 0)
> {
> if ((TYPE_CODE (type) == TYPE_CODE_FLT
> && flt_argreg > FLOAT_ARGLAST_REGNUM)
> || argreg > ARGLAST_REGNUM
> - || odd_sized_struct)
> + || pass_on_stack)
> {
> - /* must go on the stack */
> write_memory (sp + stack_offset, val, 4);
> stack_offset += 4;
> }
> - /* NOTE WELL!!!!! This is not an "else if" clause!!!
> - That's because some *&^%$ things get passed on the stack
> - AND in the registers! */
> - if (TYPE_CODE (type) == TYPE_CODE_FLT &&
> - flt_argreg > 0 && flt_argreg <= FLOAT_ARGLAST_REGNUM)
> + else if (TYPE_CODE (type) == TYPE_CODE_FLT
> + && flt_argreg <= FLOAT_ARGLAST_REGNUM)
> {
> - /* Argument goes in a single-precision fp reg. */
> + /* Argument goes in a float argument register. */
> regval = extract_unsigned_integer (val, register_size (gdbarch,
> argreg));
> regcache_cooked_write_unsigned (regcache, flt_argreg++, regval);
> @@ -741,11 +852,25 @@ sh_push_dummy_call_fpu (struct gdbarch *
> /* Store the value 4 bytes at a time. This means that things
> larger than 4 bytes may go partly in registers and partly
> on the stack. */
> - len -= register_size (gdbarch, argreg);
> - val += register_size (gdbarch, argreg);
> + len -= 4;
> + val += 4;
> }
> }
>
> + if (struct_return)
> + {
> + if (sh_active_calling_convention != sh_cc_renesas)
> + /* Using the gcc ABI, the "struct return pointer" pseudo-argument has
> + its own dedicated register */
> + regcache_cooked_write_unsigned (regcache,
> + STRUCT_RETURN_REGNUM,
> + struct_addr);
> + else
> + /* If the function uses the renesas ABI, subtract another 4 bytes from
> + the stack and store the struct return address there. */
> + write_memory_unsigned_integer (sp -= 4, 4, struct_addr);
> + }
> +
> /* Store return address. */
> regcache_cooked_write_unsigned (regcache, PR_REGNUM, bp_addr);
>
> @@ -764,69 +889,45 @@ sh_push_dummy_call_nofpu (struct gdbarch
> CORE_ADDR sp, int struct_return,
> CORE_ADDR struct_addr)
> {
> - int stack_offset, stack_alloc;
> - int argreg;
> + int stack_offset = 0;
> + int argreg = ARG0_REGNUM;
> int argnum;
> struct type *type;
> CORE_ADDR regval;
> char *val;
> - char valbuf[4];
> int len;
> - int odd_sized_struct;
> + int pass_on_stack;
>
> /* first force sp to a 4-byte alignment */
> sp = sh_frame_align (gdbarch, sp);
>
> - if (struct_return)
> - regcache_cooked_write_unsigned (regcache,
> - STRUCT_RETURN_REGNUM,
> - struct_addr);
> -
> - /* Now make sure there's space on the stack */
> - for (argnum = 0, stack_alloc = 0; argnum < nargs; argnum++)
> - stack_alloc += ((TYPE_LENGTH (VALUE_TYPE (args[argnum])) + 3) & ~3);
> - sp -= stack_alloc; /* make room on stack for args */
> + /* make room on stack for args */
> + sp -= sh_stack_allocsize (nargs, args);
>
> /* Now load as many as possible of the first arguments into
> registers, and push the rest onto the stack. There are 16 bytes
> in four registers available. Loop thru args from first to last. */
> -
> - argreg = ARG0_REGNUM;
> - for (argnum = 0, stack_offset = 0; argnum < nargs; argnum++)
> + for (argnum = 0; argnum < nargs; argnum++)
> {
> type = VALUE_TYPE (args[argnum]);
> len = TYPE_LENGTH (type);
> - memset (valbuf, 0, sizeof (valbuf));
> - if (len < 4)
> - {
> - /* value gets right-justified in the register or stack word */
> - if (TARGET_BYTE_ORDER == BFD_ENDIAN_BIG)
> - memcpy (valbuf + (4 - len),
> - (char *) VALUE_CONTENTS (args[argnum]), len);
> - else
> - memcpy (valbuf, (char *) VALUE_CONTENTS (args[argnum]), len);
> - val = valbuf;
> - }
> - else
> - val = (char *) VALUE_CONTENTS (args[argnum]);
> + val = sh_justify_value_in_reg (args[argnum], len);
> +
> + /* Some decisions have to be made how various types are handled.
> + This also differs in different ABIs. */
> + pass_on_stack = 0;
> + if (TYPE_CODE (type) == TYPE_CODE_FLT && len > 4
> + && sh_active_calling_convention == sh_cc_renesas)
> + pass_on_stack = 1; /* Renesas ABI pushes doubles entirely on stack. */
>
> - if (len > 4 && (len & 3) != 0)
> - odd_sized_struct = 1; /* such structs go entirely on stack */
> - else
> - odd_sized_struct = 0;
> while (len > 0)
> {
> - if (argreg > ARGLAST_REGNUM
> - || odd_sized_struct)
> + if (argreg > ARGLAST_REGNUM || pass_on_stack)
> {
> - /* must go on the stack */
> write_memory (sp + stack_offset, val, 4);
> stack_offset += 4;
> }
> - /* NOTE WELL!!!!! This is not an "else if" clause!!!
> - That's because some *&^%$ things get passed on the stack
> - AND in the registers! */
> - if (argreg <= ARGLAST_REGNUM)
> + else if (argreg <= ARGLAST_REGNUM)
> {
> /* there's room in a register */
> regval = extract_unsigned_integer (val, register_size (gdbarch,
> @@ -836,11 +937,25 @@ sh_push_dummy_call_nofpu (struct gdbarch
> /* Store the value 4 bytes at a time. This means that things
> larger than 4 bytes may go partly in registers and partly
> on the stack. */
> - len -= register_size (gdbarch, argreg);
> - val += register_size (gdbarch, argreg);
> + len -= 4;
> + val += 4;
> }
> }
>
> + if (struct_return)
> + {
> + if (sh_active_calling_convention != sh_cc_renesas)
> + /* Using the gcc ABI, the "struct return pointer" pseudo-argument has
> + its own dedicated register */
> + regcache_cooked_write_unsigned (regcache,
> + STRUCT_RETURN_REGNUM,
> + struct_addr);
> + else
> + /* If the function uses the renesas ABI, subtract another 4 bytes from
> + the stack and store the struct return address there. */
> + write_memory_unsigned_integer (sp -= 4, 4, struct_addr);
> + }
> +
> /* Store return address. */
> regcache_cooked_write_unsigned (regcache, PR_REGNUM, bp_addr);
>
> @@ -2060,7 +2175,6 @@ sh_gdbarch_init (struct gdbarch_info inf
> set_gdbarch_print_registers_info (gdbarch, sh_print_registers_info);
>
> set_gdbarch_breakpoint_from_pc (gdbarch, sh_breakpoint_from_pc);
> - set_gdbarch_use_struct_convention (gdbarch, sh_use_struct_convention);
>
> set_gdbarch_print_insn (gdbarch, gdb_print_insn_sh);
> set_gdbarch_register_sim_regno (gdbarch, legacy_register_sim_regno);
> @@ -2079,6 +2193,7 @@ sh_gdbarch_init (struct gdbarch_info inf
>
> set_gdbarch_push_dummy_code (gdbarch, sh_push_dummy_code);
> set_gdbarch_push_dummy_call (gdbarch, sh_push_dummy_call_nofpu);
> + set_gdbarch_use_struct_convention (gdbarch, sh_use_struct_convention_nofpu);
>
> set_gdbarch_frame_args_skip (gdbarch, 0);
> set_gdbarch_frameless_function_invocation (gdbarch,
> @@ -2114,6 +2229,7 @@ sh_gdbarch_init (struct gdbarch_info inf
> set_gdbarch_store_return_value (gdbarch, sh3e_sh4_store_return_value);
> set_gdbarch_extract_return_value (gdbarch, sh3e_sh4_extract_return_value);
> set_gdbarch_push_dummy_call (gdbarch, sh_push_dummy_call_fpu);
> + set_gdbarch_use_struct_convention (gdbarch, sh_use_struct_convention_fpu);
> break;
>
> case bfd_mach_sh_dsp:
> @@ -2135,6 +2251,7 @@ sh_gdbarch_init (struct gdbarch_info inf
> set_gdbarch_store_return_value (gdbarch, sh3e_sh4_store_return_value);
> set_gdbarch_extract_return_value (gdbarch, sh3e_sh4_extract_return_value);
> set_gdbarch_push_dummy_call (gdbarch, sh_push_dummy_call_fpu);
> + set_gdbarch_use_struct_convention (gdbarch, sh_use_struct_convention_fpu);
> break;
>
> case bfd_mach_sh3_dsp:
> @@ -2152,6 +2269,7 @@ sh_gdbarch_init (struct gdbarch_info inf
> set_gdbarch_store_return_value (gdbarch, sh3e_sh4_store_return_value);
> set_gdbarch_extract_return_value (gdbarch, sh3e_sh4_extract_return_value);
> set_gdbarch_push_dummy_call (gdbarch, sh_push_dummy_call_fpu);
> + set_gdbarch_use_struct_convention (gdbarch, sh_use_struct_convention_fpu);
> break;
>
> default:
> @@ -2178,4 +2296,11 @@ _initialize_sh_tdep (void)
> gdbarch_register (bfd_arch_sh, sh_gdbarch_init, NULL);
>
> add_com ("regs", class_vars, sh_show_regs_command, "Print all registers");
> +
> + add_show_from_set (
> + add_set_enum_cmd ("calling_convention", class_vars, sh_cc_enum,
> + &sh_active_calling_convention,
> + "Set calling convention used when calling target "
> + "functions from GDB.",
> + &setlist), &showlist);
> }
>
> --
> Corinna Vinschen
> Cygwin Developer
> Red Hat, Inc.
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [RFA] sh-tdep.c: Follow up patch to implement two different ABIs
2003-09-23 20:34 ` Elena Zannoni
@ 2003-09-23 21:27 ` Andrew Cagney
2003-09-24 8:44 ` Corinna Vinschen
2003-09-24 9:56 ` SH follow up, part 1 (was Re: [RFA] sh-tdep.c: Follow up patch to implement two different ABIs) Corinna Vinschen
2003-09-24 10:39 ` SH follow up, part 2 " Corinna Vinschen
2 siblings, 1 reply; 12+ messages in thread
From: Andrew Cagney @ 2003-09-23 21:27 UTC (permalink / raw)
To: Corinna Vinschen; +Cc: Elena Zannoni, gdb-patches
> I think this patch has too much stuff in it. Can you change it to fix
> the gcc abi (the fpu stuff), and then add the rest for the renesas
> variant?
>
>
>
> >
> > - Add the commands `set calling_convention <foo>' and
> > `show calling_convention' with <foo> being one of "gcc" and "renesas".
> > Default to "gcc".
FYI, given it's sh specific, it should be:
set/show sh calling-convention <tab>
I suspect there should also be an "auto" option.
Andrew
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [RFA] sh-tdep.c: Follow up patch to implement two different ABIs
2003-09-23 21:27 ` Andrew Cagney
@ 2003-09-24 8:44 ` Corinna Vinschen
0 siblings, 0 replies; 12+ messages in thread
From: Corinna Vinschen @ 2003-09-24 8:44 UTC (permalink / raw)
To: gdb-patches
On Tue, Sep 23, 2003 at 05:27:51PM -0400, Andrew Cagney wrote:
> > > - Add the commands `set calling_convention <foo>' and
> > > `show calling_convention' with <foo> being one of "gcc" and "renesas".
> > > Default to "gcc".
>
> FYI, given it's sh specific, it should be:
>
> set/show sh calling-convention <tab>
>
> I suspect there should also be an "auto" option.
Nope. There's no "auto" mode currently to support.
Corinna
--
Corinna Vinschen
Cygwin Developer
Red Hat, Inc.
^ permalink raw reply [flat|nested] 12+ messages in thread
* SH follow up, part 1 (was Re: [RFA] sh-tdep.c: Follow up patch to implement two different ABIs)
2003-09-23 20:34 ` Elena Zannoni
2003-09-23 21:27 ` Andrew Cagney
@ 2003-09-24 9:56 ` Corinna Vinschen
2003-09-25 21:39 ` Elena Zannoni
2003-09-24 10:39 ` SH follow up, part 2 " Corinna Vinschen
2 siblings, 1 reply; 12+ messages in thread
From: Corinna Vinschen @ 2003-09-24 9:56 UTC (permalink / raw)
To: gdb-patches
On Tue, Sep 23, 2003 at 04:44:03PM -0400, Elena Zannoni wrote:
> I think this patch has too much stuff in it. Can you change it to fix
> the gcc abi (the fpu stuff), and then add the rest for the renesas
> variant?
Ok, step 1:
- To simplify the sh_push_dummy_call*() functions, I created two helper
functions which took the part of right-justifying values < 4 byte,
called sh_justify_value_in_reg(), and to count the number of bytes
to be allocated on stack for all arguments, called sh_stack_allocsize().
- Two new functions are now used to evaluate the next floating point
register to use for an argument:
- gcc passes floats in little-endian mode using regsters criss-crossing,
fr5, fr4, fr7, fr6, fr9, fr8 ... In big-endian mode the order is simple
fr4, fr5, fr6, ...
- Doubles are passed in even register pairs, fr4/fr5, fr6/fr7, ...
Example:
void foo(float a, double b, float c);
a is passed in fr4, b then skips the odd-numbered fr5 register, so it's
passed in fr6/fr7 and c is then passed in the next free register, fr8.
- I renamed the flag `odd_sized_struct' to a more descriptive name,
`pass_on_stack' since the old name does in no way reflect how the
decision about passing on stack or in register is actually made. The
actual decision is as follows:
- On FPU CPUs, pass in registers unless the datatype is bigger than 16 bytes.
- On non-FPU CPUs, no special case exists.
- On all CPUs, everything else is passed in registers until the argument
registers are filled up, the remaining arguments are passed on stack.
If an argument doesn't fit entirely in the remaining registers, it's
split between regs and stack as see fit.
- The code and comment that some data is sometimes passed in registers
*and* stack simultaneously is dropped. That's not how it works.
> Actually this is part of the original port as contributed by Steve
> Chamberlain. Is this true of gcc or of the original hitachi abi?
Neither, nor. It must have been some sort of misunderstanding or a bug
in an ancient gcc. I talked about this with Alexandre Oliva and he has
no idea when this has ever been the case for gcc at all.
- Also in sh_push_dummy_call*(), the code which adds 4 for every 4 bytes
managed, is changed from e.g.
len -= register_size (gdbarch, argreg);
to
len -= 4;
The reason is that the original line is not exactly correct. It adds the
register_size of the *next* register, not the register actually filled
with data. Since all data and registers in question are 4 byte regs (and
the target specific code should know that anyway), I've simplified the
affected code.
> I don't like to have harcoded register sizes, if argreg is wrong, is
> there a way to get the correct parameter?
All registers are always 4 byte. It's easy enough and an additional comment
would be sufficient.
If you don't like that and want to use register_size correctly in that case,
it would have to look like this:
--- sh-tdep.c 2003-09-24 11:29:00.000000000 +0200
+++ sh-tdep.c.weia 2003-09-24 11:46:28.000000000 +0200
@@ -1046,7 +1046,7 @@ sh_push_dummy_call_fpu (struct gdbarch *
struct type *type;
CORE_ADDR regval;
char *val;
- int len;
+ int len, reg_size;
int pass_on_stack;
/* first force sp to a 4-byte alignment */
@@ -1098,6 +1098,7 @@ sh_push_dummy_call_fpu (struct gdbarch *
&& flt_argreg <= FLOAT_ARGLAST_REGNUM)
{
/* Argument goes in a float argument register. */
+ reg_size = register_size (gdbarch, flt_argreg);
regval = extract_unsigned_integer (val, register_size (gdbarch,
argreg));
regcache_cooked_write_unsigned (regcache, flt_argreg++, regval);
@@ -1105,6 +1106,7 @@ sh_push_dummy_call_fpu (struct gdbarch *
else if (argreg <= ARGLAST_REGNUM)
{
/* there's room in a register */
+ reg_size = register_size (gdbarch, argreg);
regval = extract_unsigned_integer (val, register_size (gdbarch,
argreg));
regcache_cooked_write_unsigned (regcache, argreg++, regval);
@@ -1112,8 +1114,8 @@ sh_push_dummy_call_fpu (struct gdbarch *
/* Store the value 4 bytes at a time. This means that things
larger than 4 bytes may go partly in registers and partly
on the stack. */
- len -= 4;
- val += 4;
+ len -= reg_size;
+ val += reg_size;
}
}
Corinna
ChangeLog:
==========
* sh-tdep.c (sh_justify_value_in_reg): New function.
(sh_stack_allocsize): Ditto.
(flt_argreg_array): New array used for floating point argument
passing.
(sh_init_flt_argreg): New function.
(sh_next_flt_argreg): Ditto.
(sh_push_dummy_call_fpu): Simplify. Rename "odd_sized_struct" to
"pass_on_stack". Use new helper functions. Accomodate Renesas ABI.
Fix argument passing strategy.
(sh_push_dummy_call_nofpu): Ditto.
Index: sh-tdep.c
===================================================================
RCS file: /cvs/src/src/gdb/sh-tdep.c,v
retrieving revision 1.141
diff -u -p -r1.141 sh-tdep.c
--- sh-tdep.c 16 Sep 2003 18:56:35 -0000 1.141
+++ sh-tdep.c 24 Sep 2003 09:29:10 -0000
@@ -938,6 +938,98 @@ sh_frame_align (struct gdbarch *ignore,
not displace any of the other arguments passed in via registers R4
to R7. */
+/* Helper function to justify value in register according to endianess. */
+static char *
+sh_justify_value_in_reg (struct value *val, int len)
+{
+ static char valbuf[4];
+
+ memset (valbuf, 0, sizeof (valbuf));
+ if (len < 4)
+ {
+ /* value gets right-justified in the register or stack word */
+ if (TARGET_BYTE_ORDER == BFD_ENDIAN_BIG)
+ memcpy (valbuf + (4 - len), (char *) VALUE_CONTENTS (val), len);
+ else
+ memcpy (valbuf, (char *) VALUE_CONTENTS (val), len);
+ return valbuf;
+ }
+ return (char *) VALUE_CONTENTS (val);
+}
+
+/* Helper function to eval number of bytes to allocate on stack. */
+static CORE_ADDR
+sh_stack_allocsize (int nargs, struct value **args)
+{
+ int stack_alloc = 0;
+ while (nargs-- > 0)
+ stack_alloc += ((TYPE_LENGTH (VALUE_TYPE (args[nargs])) + 3) & ~3);
+ return stack_alloc;
+}
+
+/* Helper functions for getting the float arguments right. Registers usage
+ depends on the ABI and the endianess. The comments should enlighten how
+ it's intended to work. */
+
+/* This array stores which of the float arg registers are already in use. */
+static int flt_argreg_array[FLOAT_ARGLAST_REGNUM - FLOAT_ARG0_REGNUM + 1];
+
+/* This function just resets the above array to "no reg used so far". */
+static void
+sh_init_flt_argreg (void)
+{
+ memset (flt_argreg_array, 0, sizeof flt_argreg_array);
+}
+
+/* This function returns the next register to use for float arg passing.
+ It returns either a valid value between FLOAT_ARG0_REGNUM and
+ FLOAT_ARGLAST_REGNUM if a register is available, otherwise it returns
+ FLOAT_ARGLAST_REGNUM + 1 to indicate that no register is available.
+
+ Note that register number 0 in flt_argreg_array corresponds with the
+ real float register fr4. In contrast to FLOAT_ARG0_REGNUM (value is
+ 29) the parity of the register number is preserved, which is important
+ for the double register passing test (see the "argreg & 1" test below). */
+static int
+sh_next_flt_argreg (int len)
+{
+ int argreg;
+
+ /* First search for the next free register. */
+ for (argreg = 0; argreg <= FLOAT_ARGLAST_REGNUM - FLOAT_ARG0_REGNUM; ++argreg)
+ if (!flt_argreg_array[argreg])
+ break;
+
+ /* No register left? */
+ if (argreg > FLOAT_ARGLAST_REGNUM - FLOAT_ARG0_REGNUM)
+ return FLOAT_ARGLAST_REGNUM + 1;
+
+ if (len == 8)
+ {
+ /* Doubles are always starting in a even register number. */
+ if (argreg & 1)
+ {
+ flt_argreg_array[argreg] = 1;
+
+ ++argreg;
+
+ /* No register left? */
+ if (argreg > FLOAT_ARGLAST_REGNUM - FLOAT_ARG0_REGNUM)
+ return FLOAT_ARGLAST_REGNUM + 1;
+ }
+ /* Also mark the next register as used. */
+ flt_argreg_array[argreg + 1] = 1;
+ }
+ else if (TARGET_BYTE_ORDER == BFD_ENDIAN_LITTLE)
+ {
+ /* In little endian, gcc passes floats like this: f5, f4, f7, f6, ... */
+ if (!flt_argreg_array[argreg + 1])
+ ++argreg;
+ }
+ flt_argreg_array[argreg] = 1;
+ return FLOAT_ARG0_REGNUM + argreg;
+}
+
static CORE_ADDR
sh_push_dummy_call_fpu (struct gdbarch *gdbarch,
CORE_ADDR func_addr,
@@ -947,15 +1039,15 @@ sh_push_dummy_call_fpu (struct gdbarch *
CORE_ADDR sp, int struct_return,
CORE_ADDR struct_addr)
{
- int stack_offset, stack_alloc;
- int argreg, flt_argreg;
+ int stack_offset = 0;
+ int argreg = ARG0_REGNUM;
+ int flt_argreg;
int argnum;
struct type *type;
CORE_ADDR regval;
char *val;
- char valbuf[4];
int len;
- int odd_sized_struct;
+ int pass_on_stack;
/* first force sp to a 4-byte alignment */
sp = sh_frame_align (gdbarch, sp);
@@ -967,65 +1059,51 @@ sh_push_dummy_call_fpu (struct gdbarch *
STRUCT_RETURN_REGNUM,
struct_addr);
- /* Now make sure there's space on the stack */
- for (argnum = 0, stack_alloc = 0; argnum < nargs; argnum++)
- stack_alloc += ((TYPE_LENGTH (VALUE_TYPE (args[argnum])) + 3) & ~3);
- sp -= stack_alloc; /* make room on stack for args */
+ /* make room on stack for args */
+ sp -= sh_stack_allocsize (nargs, args);
+
+ /* Initialize float argument mechanism. */
+ sh_init_flt_argreg ();
/* Now load as many as possible of the first arguments into
registers, and push the rest onto the stack. There are 16 bytes
in four registers available. Loop thru args from first to last. */
-
- argreg = ARG0_REGNUM;
- flt_argreg = FLOAT_ARG0_REGNUM;
- for (argnum = 0, stack_offset = 0; argnum < nargs; argnum++)
+ for (argnum = 0; argnum < nargs; argnum++)
{
type = VALUE_TYPE (args[argnum]);
len = TYPE_LENGTH (type);
- memset (valbuf, 0, sizeof (valbuf));
- if (len < 4)
- {
- /* value gets right-justified in the register or stack word */
- if (TARGET_BYTE_ORDER == BFD_ENDIAN_BIG)
- memcpy (valbuf + (4 - len),
- (char *) VALUE_CONTENTS (args[argnum]), len);
- else
- memcpy (valbuf, (char *) VALUE_CONTENTS (args[argnum]), len);
- val = valbuf;
- }
- else
- val = (char *) VALUE_CONTENTS (args[argnum]);
+ val = sh_justify_value_in_reg (args[argnum], len);
+
+ /* Some decisions have to be made how various types are handled.
+ This also differs in different ABIs. */
+ pass_on_stack = 0;
+ if (len > 16)
+ pass_on_stack = 1; /* Types bigger than 16 bytes are passed on stack. */
+
+ /* Find out the next register to use for a floating point value. */
+ if (TYPE_CODE (type) == TYPE_CODE_FLT)
+ flt_argreg = sh_next_flt_argreg (len);
- if (len > 4 && (len & 3) != 0)
- odd_sized_struct = 1; /* Such structs go entirely on stack. */
- else if (len > 16)
- odd_sized_struct = 1; /* So do aggregates bigger than 4 words. */
- else
- odd_sized_struct = 0;
while (len > 0)
{
if ((TYPE_CODE (type) == TYPE_CODE_FLT
- && flt_argreg > FLOAT_ARGLAST_REGNUM)
+ && flt_argreg > FLOAT_ARGLAST_REGNUM)
|| argreg > ARGLAST_REGNUM
- || odd_sized_struct)
- {
- /* must go on the stack */
+ || pass_on_stack)
+ {
write_memory (sp + stack_offset, val, 4);
stack_offset += 4;
}
- /* NOTE WELL!!!!! This is not an "else if" clause!!!
- That's because some *&^%$ things get passed on the stack
- AND in the registers! */
- if (TYPE_CODE (type) == TYPE_CODE_FLT &&
- flt_argreg > 0 && flt_argreg <= FLOAT_ARGLAST_REGNUM)
+ else if (TYPE_CODE (type) == TYPE_CODE_FLT
+ && flt_argreg <= FLOAT_ARGLAST_REGNUM)
{
- /* Argument goes in a single-precision fp reg. */
+ /* Argument goes in a float argument register. */
regval = extract_unsigned_integer (val, register_size (gdbarch,
argreg));
regcache_cooked_write_unsigned (regcache, flt_argreg++, regval);
}
else if (argreg <= ARGLAST_REGNUM)
- {
+ {
/* there's room in a register */
regval = extract_unsigned_integer (val, register_size (gdbarch,
argreg));
@@ -1034,8 +1112,8 @@ sh_push_dummy_call_fpu (struct gdbarch *
/* Store the value 4 bytes at a time. This means that things
larger than 4 bytes may go partly in registers and partly
on the stack. */
- len -= register_size (gdbarch, argreg);
- val += register_size (gdbarch, argreg);
+ len -= 4;
+ val += 4;
}
}
@@ -1057,15 +1135,13 @@ sh_push_dummy_call_nofpu (struct gdbarch
CORE_ADDR sp, int struct_return,
CORE_ADDR struct_addr)
{
- int stack_offset, stack_alloc;
- int argreg;
+ int stack_offset = 0;
+ int argreg = ARG0_REGNUM;
int argnum;
struct type *type;
CORE_ADDR regval;
char *val;
- char valbuf[4];
int len;
- int odd_sized_struct;
/* first force sp to a 4-byte alignment */
sp = sh_frame_align (gdbarch, sp);
@@ -1077,52 +1153,27 @@ sh_push_dummy_call_nofpu (struct gdbarch
STRUCT_RETURN_REGNUM,
struct_addr);
- /* Now make sure there's space on the stack */
- for (argnum = 0, stack_alloc = 0; argnum < nargs; argnum++)
- stack_alloc += ((TYPE_LENGTH (VALUE_TYPE (args[argnum])) + 3) & ~3);
- sp -= stack_alloc; /* make room on stack for args */
+ /* make room on stack for args */
+ sp -= sh_stack_allocsize (nargs, args);
/* Now load as many as possible of the first arguments into
registers, and push the rest onto the stack. There are 16 bytes
in four registers available. Loop thru args from first to last. */
-
- argreg = ARG0_REGNUM;
- for (argnum = 0, stack_offset = 0; argnum < nargs; argnum++)
- {
+ for (argnum = 0; argnum < nargs; argnum++)
+ {
type = VALUE_TYPE (args[argnum]);
len = TYPE_LENGTH (type);
- memset (valbuf, 0, sizeof (valbuf));
- if (len < 4)
- {
- /* value gets right-justified in the register or stack word */
- if (TARGET_BYTE_ORDER == BFD_ENDIAN_BIG)
- memcpy (valbuf + (4 - len),
- (char *) VALUE_CONTENTS (args[argnum]), len);
- else
- memcpy (valbuf, (char *) VALUE_CONTENTS (args[argnum]), len);
- val = valbuf;
- }
- else
- val = (char *) VALUE_CONTENTS (args[argnum]);
+ val = sh_justify_value_in_reg (args[argnum], len);
- if (len > 4 && (len & 3) != 0)
- odd_sized_struct = 1; /* such structs go entirely on stack */
- else
- odd_sized_struct = 0;
while (len > 0)
{
- if (argreg > ARGLAST_REGNUM
- || odd_sized_struct)
- {
- /* must go on the stack */
+ if (argreg > ARGLAST_REGNUM)
+ {
write_memory (sp + stack_offset, val, 4);
- stack_offset += 4;
+ stack_offset += 4;
}
- /* NOTE WELL!!!!! This is not an "else if" clause!!!
- That's because some *&^%$ things get passed on the stack
- AND in the registers! */
- if (argreg <= ARGLAST_REGNUM)
- {
+ else if (argreg <= ARGLAST_REGNUM)
+ {
/* there's room in a register */
regval = extract_unsigned_integer (val, register_size (gdbarch,
argreg));
@@ -1131,8 +1182,8 @@ sh_push_dummy_call_nofpu (struct gdbarch
/* Store the value 4 bytes at a time. This means that things
larger than 4 bytes may go partly in registers and partly
on the stack. */
- len -= register_size (gdbarch, argreg);
- val += register_size (gdbarch, argreg);
+ len -= 4;
+ val += 4;
}
}
--
Corinna Vinschen
Cygwin Developer
Red Hat, Inc.
^ permalink raw reply [flat|nested] 12+ messages in thread
* SH follow up, part 2 (was Re: [RFA] sh-tdep.c: Follow up patch to implement two different ABIs)
2003-09-23 20:34 ` Elena Zannoni
2003-09-23 21:27 ` Andrew Cagney
2003-09-24 9:56 ` SH follow up, part 1 (was Re: [RFA] sh-tdep.c: Follow up patch to implement two different ABIs) Corinna Vinschen
@ 2003-09-24 10:39 ` Corinna Vinschen
2003-09-25 21:44 ` Elena Zannoni
2 siblings, 1 reply; 12+ messages in thread
From: Corinna Vinschen @ 2003-09-24 10:39 UTC (permalink / raw)
To: gdb-patches
On Tue, Sep 23, 2003 at 04:44:03PM -0400, Elena Zannoni wrote:
> Corinna Vinschen writes:
And now part 2.
> > - Add the commands `set calling_convention <foo>' and
> > `show calling_convention' with <foo> being one of "gcc" and "renesas".
> > Default to "gcc".
>
> Should be using hyphen, not underscore. What happens if you have a
Done. I followed Andrew's suggestion to change this to
set sh calling-convention ...
show sh calling-convention
> file compiled with renesas ABI but you set the calling convention to
> the gcc (or vice versa)? How are the abi supported by gcc? Is there a
> -with-abi-renesas to be given when one compiles the tests? I.e. is it
> possible to run the testsuite with the one specific abi?
Currently there's no way to differ between these two ABIs automatically
though that might change at some later point. The user has to change
the ABI on the command line by hand. The compiler option was -mhitachi,
gcc is just changing to -mrenesas to reflect the company name change.
So the changes introduced with this patch are:
- Differ between a fpu and a nofpu version of sh_use_struct_convention.
The nofpu version behaves like the fpu version, except that it uses
struct convention also for all types >= 8 bytes when the Renesas ABI
is active. This especially affects long longs and doubles which are
then passed on the stack.
- The Renesas ABI passes the address in which structs have to be returned
not in r2 as the gcc ABI, but instead this return address is pushed
onto the stack after all arguments have been pushed. This affects
sh_extract_struct_value_address() as well as the sh_push_dummy_call*()
functions.
- sh_next_flt_argreg() now also takes the ABI into account. The differences
are:
- In Renesas ABI, the criss-crossing register usage in little endian
mode for doubles doesn't happen.
- In both ABIs doubles are passed in even register pairs, fr4/fr5,
fr6/fr7, ... The difference is when a register is skipped to pass
the next double. Example:
void foo(float a, double b, float c);
In gcc ABI, a is passed in fr4, b then skips the odd-numbered fr5
register, so it's passed in fr6/fr7 and c is then passed in the next
free register, fr8.
In Renesas ABI, a is passed in fr4, b is passed as in gcc ABI in
fr6/fr7 but c is passed in the lowest unused register, in this example
in fr5.
- In the Renesas ABI for CPUs with FPU, long longs are not passed in
registers but on stack.
- The struct_return code in both sh_push_dummy_call*() functions is moved
to the end of the function since it must be done after the argument
passing for the Rensas ABI.
- `pass_on_stack' takes the Renesas ABI into account:
- On FPU CPUs, Renesas ABI passes long longs always on the stack.
- On non-FPU CPUs, Renesas ABI passes doubles and long doubles always
on the stack.
Corinna
ChangeLog:
==========
* sh-tdep.c (sh_cc_gcc): New static string.
(sh_cc_renesas): Ditto.
(sh_cc_enum): New array pointing to calling convention strings.
(sh_active_calling_convention): New variable pointing to
current active calling convention.
(sh_use_struct_convention_fpu): New function.
(sh_use_struct_convention_nofpu): New function.
(sh_use_struct_convention): Remove. Superseeded by the previous
two functions.
(sh_extract_struct_value_address): Care for Renesas ABI.
(sh_next_flt_argreg): Accomodate Renesas ABI.
(sh_push_dummy_call_fpu): Ditto.
(sh_push_dummy_call_nofpu): Ditto.
(sh_gdbarch_init): Accomodate new sh_use_struct_convention_fpu and
sh_use_struct_convention_nofpu functions.
(show_sh_command): New function.
(set_sh_command): New function.
(_initialize_sh_tdep): Initialize new "set sh calling-convention",
"show sh calling-convention" commands.
--- sh-tdep.c.MIDNEW 2003-09-24 12:01:46.000000000 +0200
+++ sh-tdep.c.NEW 2003-09-24 12:24:10.000000000 +0200
@@ -55,6 +55,21 @@
/* registers numbers shared with the simulator */
#include "gdb/sim-sh.h"
+/* List of "set sh ..." and "show sh ..." commands. */
+static struct cmd_list_element *setshcmdlist = NULL;
+static struct cmd_list_element *showshcmdlist = NULL;
+
+static const char sh_cc_gcc[] = "gcc";
+static const char sh_cc_renesas[] = "renesas";
+static const char *sh_cc_enum[] =
+{
+ sh_cc_gcc,
+ sh_cc_renesas,
+ NULL
+};
+
+static const char *sh_active_calling_convention = sh_cc_gcc;
+
static void (*sh_show_regs) (void);
#define SH_NUM_REGS 59
@@ -569,10 +584,25 @@ sh_skip_prologue (CORE_ADDR start_pc)
/* Should call_function allocate stack space for a struct return? */
static int
-sh_use_struct_convention (int gcc_p, struct type *type)
+sh_use_struct_convention_fpu (int gcc_p, struct type *type)
{
int len = TYPE_LENGTH (type);
int nelem = TYPE_NFIELDS (type);
+
+ return ((len != 1 && len != 2 && len != 4 && len != 8) || nelem != 1) &&
+ (len != 8 || TYPE_LENGTH (TYPE_FIELD_TYPE (type, 0)) != 4);
+}
+
+static int
+sh_use_struct_convention_nofpu (int gcc_p, struct type *type)
+{
+ int len = TYPE_LENGTH (type);
+ int nelem = TYPE_NFIELDS (type);
+
+ /* The Renesas ABI returns long longs/doubles etc. always on stack. */
+ if (sh_active_calling_convention == sh_cc_renesas && len >= 8)
+ return 1;
+
return ((len != 1 && len != 2 && len != 4 && len != 8) || nelem != 1) &&
(len != 8 || TYPE_LENGTH (TYPE_FIELD_TYPE (type, 0)) != 4);
}
@@ -584,8 +614,13 @@ static CORE_ADDR
sh_extract_struct_value_address (struct regcache *regcache)
{
ULONGEST addr;
-
- regcache_cooked_read_unsigned (regcache, STRUCT_RETURN_REGNUM, &addr);
+ if (sh_active_calling_convention != sh_cc_renesas)
+ regcache_cooked_read_unsigned (regcache, STRUCT_RETURN_REGNUM, &addr);
+ else
+ {
+ regcache_cooked_read_unsigned (regcache, SP_REGNUM, &addr);
+ addr = read_memory_unsigned_integer (addr, 4);
+ }
return addr;
}
@@ -653,7 +688,7 @@ sh_justify_value_in_reg (struct value *v
{
static char valbuf[4];
- memset (valbuf, 0, sizeof (valbuf));
+ memset (valbuf, 0, sizeof (valbuf));
if (len < 4)
{
/* value gets right-justified in the register or stack word */
@@ -664,7 +699,7 @@ sh_justify_value_in_reg (struct value *v
return valbuf;
}
return (char *) VALUE_CONTENTS (val);
-}
+}
/* Helper function to eval number of bytes to allocate on stack. */
static CORE_ADDR
@@ -718,18 +753,22 @@ sh_next_flt_argreg (int len)
/* Doubles are always starting in a even register number. */
if (argreg & 1)
{
- flt_argreg_array[argreg] = 1;
+ /* In gcc ABI, the skipped register is lost for further argument
+ passing now. Not so in Renesas ABI. */
+ if (sh_active_calling_convention != sh_cc_renesas)
+ flt_argreg_array[argreg] = 1;
++argreg;
- /* No register left? */
+ /* No register left? */
if (argreg > FLOAT_ARGLAST_REGNUM - FLOAT_ARG0_REGNUM)
return FLOAT_ARGLAST_REGNUM + 1;
}
/* Also mark the next register as used. */
flt_argreg_array[argreg + 1] = 1;
}
- else if (TARGET_BYTE_ORDER == BFD_ENDIAN_LITTLE)
+ else if (TARGET_BYTE_ORDER == BFD_ENDIAN_LITTLE
+ && sh_active_calling_convention != sh_cc_renesas)
{
/* In little endian, gcc passes floats like this: f5, f4, f7, f6, ... */
if (!flt_argreg_array[argreg + 1])
@@ -761,13 +800,6 @@ sh_push_dummy_call_fpu (struct gdbarch *
/* first force sp to a 4-byte alignment */
sp = sh_frame_align (gdbarch, sp);
- /* The "struct return pointer" pseudo-argument has its own dedicated
- register */
- if (struct_return)
- regcache_cooked_write_unsigned (regcache,
- STRUCT_RETURN_REGNUM,
- struct_addr);
-
/* make room on stack for args */
sp -= sh_stack_allocsize (nargs, args);
@@ -787,7 +819,10 @@ sh_push_dummy_call_fpu (struct gdbarch *
This also differs in different ABIs. */
pass_on_stack = 0;
if (len > 16)
- pass_on_stack = 1; /* Types bigger than 16 bytes are passed on stack. */
+ pass_on_stack = 1; /* Types bigger than 16 bytes are passed on stack. */
+ else if (sh_active_calling_convention == sh_cc_renesas
+ && TYPE_CODE (type) == TYPE_CODE_INT && len == 8)
+ pass_on_stack = 1; /* So are long longs in renesas ABI */
/* Find out the next register to use for a floating point value. */
if (TYPE_CODE (type) == TYPE_CODE_FLT)
@@ -796,10 +831,10 @@ sh_push_dummy_call_fpu (struct gdbarch *
while (len > 0)
{
if ((TYPE_CODE (type) == TYPE_CODE_FLT
- && flt_argreg > FLOAT_ARGLAST_REGNUM)
+ && flt_argreg > FLOAT_ARGLAST_REGNUM)
|| argreg > ARGLAST_REGNUM
|| pass_on_stack)
- {
+ {
write_memory (sp + stack_offset, val, 4);
stack_offset += 4;
}
@@ -812,7 +847,7 @@ sh_push_dummy_call_fpu (struct gdbarch *
regcache_cooked_write_unsigned (regcache, flt_argreg++, regval);
}
else if (argreg <= ARGLAST_REGNUM)
- {
+ {
/* there's room in a register */
regval = extract_unsigned_integer (val, register_size (gdbarch,
argreg));
@@ -826,6 +861,20 @@ sh_push_dummy_call_fpu (struct gdbarch *
}
}
+ if (struct_return)
+ {
+ if (sh_active_calling_convention != sh_cc_renesas)
+ /* Using the gcc ABI, the "struct return pointer" pseudo-argument has
+ its own dedicated register */
+ regcache_cooked_write_unsigned (regcache,
+ STRUCT_RETURN_REGNUM,
+ struct_addr);
+ else
+ /* If the function uses the renesas ABI, subtract another 4 bytes from
+ the stack and store the struct return address there. */
+ write_memory_unsigned_integer (sp -= 4, 4, struct_addr);
+ }
+
/* Store return address. */
regcache_cooked_write_unsigned (regcache, PR_REGNUM, bp_addr);
@@ -851,17 +900,11 @@ sh_push_dummy_call_nofpu (struct gdbarch
CORE_ADDR regval;
char *val;
int len;
+ int pass_on_stack;
/* first force sp to a 4-byte alignment */
sp = sh_frame_align (gdbarch, sp);
- /* The "struct return pointer" pseudo-argument has its own dedicated
- register */
- if (struct_return)
- regcache_cooked_write_unsigned (regcache,
- STRUCT_RETURN_REGNUM,
- struct_addr);
-
/* make room on stack for args */
sp -= sh_stack_allocsize (nargs, args);
@@ -869,20 +912,27 @@ sh_push_dummy_call_nofpu (struct gdbarch
registers, and push the rest onto the stack. There are 16 bytes
in four registers available. Loop thru args from first to last. */
for (argnum = 0; argnum < nargs; argnum++)
- {
+ {
type = VALUE_TYPE (args[argnum]);
len = TYPE_LENGTH (type);
val = sh_justify_value_in_reg (args[argnum], len);
+ /* Some decisions have to be made how various types are handled.
+ This also differs in different ABIs. */
+ pass_on_stack = 0;
+ if (TYPE_CODE (type) == TYPE_CODE_FLT && len > 4
+ && sh_active_calling_convention == sh_cc_renesas)
+ pass_on_stack = 1; /* Renesas ABI pushes doubles entirely on stack. */
+
while (len > 0)
{
- if (argreg > ARGLAST_REGNUM)
- {
+ if (argreg > ARGLAST_REGNUM || pass_on_stack)
+ {
write_memory (sp + stack_offset, val, 4);
- stack_offset += 4;
+ stack_offset += 4;
}
else if (argreg <= ARGLAST_REGNUM)
- {
+ {
/* there's room in a register */
regval = extract_unsigned_integer (val, register_size (gdbarch,
argreg));
@@ -896,6 +946,20 @@ sh_push_dummy_call_nofpu (struct gdbarch
}
}
+ if (struct_return)
+ {
+ if (sh_active_calling_convention != sh_cc_renesas)
+ /* Using the gcc ABI, the "struct return pointer" pseudo-argument has
+ its own dedicated register */
+ regcache_cooked_write_unsigned (regcache,
+ STRUCT_RETURN_REGNUM,
+ struct_addr);
+ else
+ /* If the function uses the renesas ABI, subtract another 4 bytes from
+ the stack and store the struct return address there. */
+ write_memory_unsigned_integer (sp -= 4, 4, struct_addr);
+ }
+
/* Store return address. */
regcache_cooked_write_unsigned (regcache, PR_REGNUM, bp_addr);
@@ -2115,7 +2179,6 @@ sh_gdbarch_init (struct gdbarch_info inf
set_gdbarch_print_registers_info (gdbarch, sh_print_registers_info);
set_gdbarch_breakpoint_from_pc (gdbarch, sh_breakpoint_from_pc);
- set_gdbarch_use_struct_convention (gdbarch, sh_use_struct_convention);
set_gdbarch_print_insn (gdbarch, gdb_print_insn_sh);
set_gdbarch_register_sim_regno (gdbarch, legacy_register_sim_regno);
@@ -2134,6 +2197,7 @@ sh_gdbarch_init (struct gdbarch_info inf
set_gdbarch_push_dummy_code (gdbarch, sh_push_dummy_code);
set_gdbarch_push_dummy_call (gdbarch, sh_push_dummy_call_nofpu);
+ set_gdbarch_use_struct_convention (gdbarch, sh_use_struct_convention_nofpu);
set_gdbarch_frame_args_skip (gdbarch, 0);
set_gdbarch_frameless_function_invocation (gdbarch,
@@ -2169,6 +2233,7 @@ sh_gdbarch_init (struct gdbarch_info inf
set_gdbarch_store_return_value (gdbarch, sh3e_sh4_store_return_value);
set_gdbarch_extract_return_value (gdbarch, sh3e_sh4_extract_return_value);
set_gdbarch_push_dummy_call (gdbarch, sh_push_dummy_call_fpu);
+ set_gdbarch_use_struct_convention (gdbarch, sh_use_struct_convention_fpu);
break;
case bfd_mach_sh_dsp:
@@ -2190,6 +2255,7 @@ sh_gdbarch_init (struct gdbarch_info inf
set_gdbarch_store_return_value (gdbarch, sh3e_sh4_store_return_value);
set_gdbarch_extract_return_value (gdbarch, sh3e_sh4_extract_return_value);
set_gdbarch_push_dummy_call (gdbarch, sh_push_dummy_call_fpu);
+ set_gdbarch_use_struct_convention (gdbarch, sh_use_struct_convention_fpu);
break;
case bfd_mach_sh3_dsp:
@@ -2207,6 +2273,7 @@ sh_gdbarch_init (struct gdbarch_info inf
set_gdbarch_store_return_value (gdbarch, sh3e_sh4_store_return_value);
set_gdbarch_extract_return_value (gdbarch, sh3e_sh4_extract_return_value);
set_gdbarch_push_dummy_call (gdbarch, sh_push_dummy_call_fpu);
+ set_gdbarch_use_struct_convention (gdbarch, sh_use_struct_convention_fpu);
break;
default:
@@ -2223,6 +2290,19 @@ sh_gdbarch_init (struct gdbarch_info inf
return gdbarch;
}
+static void
+show_sh_command (char *args, int from_tty)
+{
+ help_list (showshcmdlist, "show sh ", all_commands, gdb_stdout);
+}
+
+static void
+set_sh_command (char *args, int from_tty)
+{
+ printf_unfiltered ("\"set sh\" must be followed by an appropriate subcommand.\n");
+ help_list (setshcmdlist, "set sh ", all_commands, gdb_stdout);
+}
+
extern initialize_file_ftype _initialize_sh_tdep; /* -Wmissing-prototypes */
void
@@ -2233,4 +2313,16 @@ _initialize_sh_tdep (void)
gdbarch_register (bfd_arch_sh, sh_gdbarch_init, NULL);
add_com ("regs", class_vars, sh_show_regs_command, "Print all registers");
+
+ add_prefix_cmd ("sh", no_class, set_sh_command, "SH specific commands.",
+ &setshcmdlist, "set sh ", 0, &setlist);
+ add_prefix_cmd ("sh", no_class, show_sh_command, "SH specific commands.",
+ &showshcmdlist, "show sh ", 0, &showlist);
+
+ add_show_from_set (
+ add_set_enum_cmd ("calling-convention", class_vars, sh_cc_enum,
+ &sh_active_calling_convention,
+ "Set calling convention used when calling target "
+ "functions from GDB.",
+ &setshcmdlist), &showshcmdlist);
}
--
Corinna Vinschen
Cygwin Developer
Red Hat, Inc.
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: SH follow up, part 1 (was Re: [RFA] sh-tdep.c: Follow up patch to implement two different ABIs)
2003-09-24 9:56 ` SH follow up, part 1 (was Re: [RFA] sh-tdep.c: Follow up patch to implement two different ABIs) Corinna Vinschen
@ 2003-09-25 21:39 ` Elena Zannoni
2003-09-26 11:14 ` Corinna Vinschen
0 siblings, 1 reply; 12+ messages in thread
From: Elena Zannoni @ 2003-09-25 21:39 UTC (permalink / raw)
To: gdb-patches
Corinna Vinschen writes:
> On Tue, Sep 23, 2003 at 04:44:03PM -0400, Elena Zannoni wrote:
> > I think this patch has too much stuff in it. Can you change it to fix
> > the gcc abi (the fpu stuff), and then add the rest for the renesas
> > variant?
>
> Ok, step 1:
>
Seems ok, are there diffs in the test results before&after? Are these
explanations also in the code? If not, can you please add them?
> - To simplify the sh_push_dummy_call*() functions, I created two helper
> functions which took the part of right-justifying values < 4 byte,
> called sh_justify_value_in_reg(), and to count the number of bytes
> to be allocated on stack for all arguments, called sh_stack_allocsize().
>
> - Two new functions are now used to evaluate the next floating point
> register to use for an argument:
>
> - gcc passes floats in little-endian mode using regsters criss-crossing,
> fr5, fr4, fr7, fr6, fr9, fr8 ... In big-endian mode the order is simple
> fr4, fr5, fr6, ...
>
> - Doubles are passed in even register pairs, fr4/fr5, fr6/fr7, ...
> Example:
>
> void foo(float a, double b, float c);
>
> a is passed in fr4, b then skips the odd-numbered fr5 register, so it's
> passed in fr6/fr7 and c is then passed in the next free register, fr8.
>
> - I renamed the flag `odd_sized_struct' to a more descriptive name,
> `pass_on_stack' since the old name does in no way reflect how the
> decision about passing on stack or in register is actually made. The
> actual decision is as follows:
>
> - On FPU CPUs, pass in registers unless the datatype is bigger than 16 bytes.
>
> - On non-FPU CPUs, no special case exists.
>
> - On all CPUs, everything else is passed in registers until the argument
> registers are filled up, the remaining arguments are passed on stack.
> If an argument doesn't fit entirely in the remaining registers, it's
> split between regs and stack as see fit.
>
> - The code and comment that some data is sometimes passed in registers
> *and* stack simultaneously is dropped. That's not how it works.
>
> > Actually this is part of the original port as contributed by Steve
> > Chamberlain. Is this true of gcc or of the original hitachi abi?
>
> Neither, nor. It must have been some sort of misunderstanding or a bug
> in an ancient gcc. I talked about this with Alexandre Oliva and he has
> no idea when this has ever been the case for gcc at all.
>
> - Also in sh_push_dummy_call*(), the code which adds 4 for every 4 bytes
> managed, is changed from e.g.
>
> len -= register_size (gdbarch, argreg);
>
> to
>
> len -= 4;
>
> The reason is that the original line is not exactly correct. It adds the
> register_size of the *next* register, not the register actually filled
> with data. Since all data and registers in question are 4 byte regs (and
> the target specific code should know that anyway), I've simplified the
> affected code.
>
> > I don't like to have harcoded register sizes, if argreg is wrong, is
> > there a way to get the correct parameter?
>
> All registers are always 4 byte. It's easy enough and an additional comment
> would be sufficient.
>
> If you don't like that and want to use register_size correctly in that case,
> it would have to look like this:
>
Yes please.
When you are done with this rewrite, it would be good to pass the file
through gdb_indent.sh.
elena
> --- sh-tdep.c 2003-09-24 11:29:00.000000000 +0200
> +++ sh-tdep.c.weia 2003-09-24 11:46:28.000000000 +0200
> @@ -1046,7 +1046,7@@ sh_push_dummy_call_fpu (struct gdbarch *
> struct type *type;
> CORE_ADDR regval;
> char *val;
> - int len;
> + int len, reg_size;
> int pass_on_stack;
>
> /* first force sp to a 4-byte alignment */
> @@ -1098,6 +1098,7 @@ sh_push_dummy_call_fpu (struct gdbarch *
> && flt_argreg <= FLOAT_ARGLAST_REGNUM)
> {
> /* Argument goes in a float argument register. */
> + reg_size = register_size (gdbarch, flt_argreg);
> regval = extract_unsigned_integer (val, register_size (gdbarch,
> argreg));
> regcache_cooked_write_unsigned (regcache, flt_argreg++, regval);
> @@ -1105,6 +1106,7 @@ sh_push_dummy_call_fpu (struct gdbarch *
> else if (argreg <= ARGLAST_REGNUM)
> {
> /* there's room in a register */
> + reg_size = register_size (gdbarch, argreg);
> regval = extract_unsigned_integer (val, register_size (gdbarch,
> argreg));
> regcache_cooked_write_unsigned (regcache, argreg++, regval);
> @@ -1112,8 +1114,8 @@ sh_push_dummy_call_fpu (struct gdbarch *
> /* Store the value 4 bytes at a time. This means that things
> larger than 4 bytes may go partly in registers and partly
> on the stack. */
> - len -= 4;
> - val += 4;
> + len -= reg_size;
> + val += reg_size;
> }
> }
>
> Corinna
>
>
> ChangeLog:
> ==========
>
> * sh-tdep.c (sh_justify_value_in_reg): New function.
> (sh_stack_allocsize): Ditto.
> (flt_argreg_array): New array used for floating point argument
> passing.
> (sh_init_flt_argreg): New function.
> (sh_next_flt_argreg): Ditto.
> (sh_push_dummy_call_fpu): Simplify. Rename "odd_sized_struct" to
> "pass_on_stack". Use new helper functions. Accomodate Renesas ABI.
> Fix argument passing strategy.
> (sh_push_dummy_call_nofpu): Ditto.
>
> Index: sh-tdep.c
> ===================================================================
> RCS file: /cvs/src/src/gdb/sh-tdep.c,v
> retrieving revision 1.141
> diff -u -p -r1.141 sh-tdep.c
> --- sh-tdep.c 16 Sep 2003 18:56:35 -0000 1.141
> +++ sh-tdep.c 24 Sep 2003 09:29:10 -0000
> @@ -938,6 +938,98 @@ sh_frame_align (struct gdbarch *ignore,
> not displace any of the other arguments passed in via registers R4
> to R7. */
>
> +/* Helper function to justify value in register according to endianess. */
> +static char *
> +sh_justify_value_in_reg (struct value *val, int len)
> +{
> + static char valbuf[4];
> +
> + memset (valbuf, 0, sizeof (valbuf));
> + if (len < 4)
> + {
> + /* value gets right-justified in the register or stack word */
> + if (TARGET_BYTE_ORDER == BFD_ENDIAN_BIG)
> + memcpy (valbuf + (4 - len), (char *) VALUE_CONTENTS (val), len);
> + else
> + memcpy (valbuf, (char *) VALUE_CONTENTS (val), len);
> + return valbuf;
> + }
> + return (char *) VALUE_CONTENTS (val);
> +}
> +
> +/* Helper function to eval number of bytes to allocate on stack. */
> +static CORE_ADDR
> +sh_stack_allocsize (int nargs, struct value **args)
> +{
> + int stack_alloc = 0;
> + while (nargs-- > 0)
> + stack_alloc += ((TYPE_LENGTH (VALUE_TYPE (args[nargs])) + 3) & ~3);
> + return stack_alloc;
> +}
> +
> +/* Helper functions for getting the float arguments right. Registers usage
> + depends on the ABI and the endianess. The comments should enlighten how
> + it's intended to work. */
> +
> +/* This array stores which of the float arg registers are already in use. */
> +static int flt_argreg_array[FLOAT_ARGLAST_REGNUM - FLOAT_ARG0_REGNUM + 1];
> +
> +/* This function just resets the above array to "no reg used so far". */
> +static void
> +sh_init_flt_argreg (void)
> +{
> + memset (flt_argreg_array, 0, sizeof flt_argreg_array);
> +}
> +
> +/* This function returns the next register to use for float arg passing.
> + It returns either a valid value between FLOAT_ARG0_REGNUM and
> + FLOAT_ARGLAST_REGNUM if a register is available, otherwise it returns
> + FLOAT_ARGLAST_REGNUM + 1 to indicate that no register is available.
> +
> + Note that register number 0 in flt_argreg_array corresponds with the
> + real float register fr4. In contrast to FLOAT_ARG0_REGNUM (value is
> + 29) the parity of the register number is preserved, which is important
> + for the double register passing test (see the "argreg & 1" test below). */
> +static int
> +sh_next_flt_argreg (int len)
> +{
> + int argreg;
> +
> + /* First search for the next free register. */
> + for (argreg = 0; argreg <= FLOAT_ARGLAST_REGNUM - FLOAT_ARG0_REGNUM; ++argreg)
> + if (!flt_argreg_array[argreg])
> + break;
> +
> + /* No register left? */
> + if (argreg > FLOAT_ARGLAST_REGNUM - FLOAT_ARG0_REGNUM)
> + return FLOAT_ARGLAST_REGNUM + 1;
> +
> + if (len == 8)
> + {
> + /* Doubles are always starting in a even register number. */
> + if (argreg & 1)
> + {
> + flt_argreg_array[argreg] = 1;
> +
> + ++argreg;
> +
> + /* No register left? */
> + if (argreg > FLOAT_ARGLAST_REGNUM - FLOAT_ARG0_REGNUM)
> + return FLOAT_ARGLAST_REGNUM + 1;
> + }
> + /* Also mark the next register as used. */
> + flt_argreg_array[argreg + 1] = 1;
> + }
> + else if (TARGET_BYTE_ORDER == BFD_ENDIAN_LITTLE)
> + {
> + /* In little endian, gcc passes floats like this: f5, f4, f7, f6, ... */
> + if (!flt_argreg_array[argreg + 1])
> + ++argreg;
> + }
> + flt_argreg_array[argreg] = 1;
> + return FLOAT_ARG0_REGNUM + argreg;
> +}
> +
> static CORE_ADDR
> sh_push_dummy_call_fpu (struct gdbarch *gdbarch,
> CORE_ADDR func_addr,
> @@ -947,15 +1039,15 @@ sh_push_dummy_call_fpu (struct gdbarch *
> CORE_ADDR sp, int struct_return,
> CORE_ADDR struct_addr)
> {
> - int stack_offset, stack_alloc;
> - int argreg, flt_argreg;
> + int stack_offset = 0;
> + int argreg = ARG0_REGNUM;
> + int flt_argreg;
> int argnum;
> struct type *type;
> CORE_ADDR regval;
> char *val;
> - char valbuf[4];
> int len;
> - int odd_sized_struct;
> + int pass_on_stack;
>
> /* first force sp to a 4-byte alignment */
> sp = sh_frame_align (gdbarch, sp);
> @@ -967,65 +1059,51 @@ sh_push_dummy_call_fpu (struct gdbarch *
> STRUCT_RETURN_REGNUM,
> struct_addr);
>
> - /* Now make sure there's space on the stack */
> - for (argnum = 0, stack_alloc = 0; argnum < nargs; argnum++)
> - stack_alloc += ((TYPE_LENGTH (VALUE_TYPE (args[argnum])) + 3) & ~3);
> - sp -= stack_alloc; /* make room on stack for args */
> + /* make room on stack for args */
> + sp -= sh_stack_allocsize (nargs, args);
> +
> + /* Initialize float argument mechanism. */
> + sh_init_flt_argreg ();
>
> /* Now load as many as possible of the first arguments into
> registers, and push the rest onto the stack. There are 16 bytes
> in four registers available. Loop thru args from first to last. */
> -
> - argreg = ARG0_REGNUM;
> - flt_argreg = FLOAT_ARG0_REGNUM;
> - for (argnum = 0, stack_offset = 0; argnum < nargs; argnum++)
> + for (argnum = 0; argnum < nargs; argnum++)
> {
> type = VALUE_TYPE (args[argnum]);
> len = TYPE_LENGTH (type);
> - memset (valbuf, 0, sizeof (valbuf));
> - if (len < 4)
> - {
> - /* value gets right-justified in the register or stack word */
> - if (TARGET_BYTE_ORDER == BFD_ENDIAN_BIG)
> - memcpy (valbuf + (4 - len),
> - (char *) VALUE_CONTENTS (args[argnum]), len);
> - else
> - memcpy (valbuf, (char *) VALUE_CONTENTS (args[argnum]), len);
> - val = valbuf;
> - }
> - else
> - val = (char *) VALUE_CONTENTS (args[argnum]);
> + val = sh_justify_value_in_reg (args[argnum], len);
> +
> + /* Some decisions have to be made how various types are handled.
> + This also differs in different ABIs. */
> + pass_on_stack = 0;
> + if (len > 16)
> + pass_on_stack = 1; /* Types bigger than 16 bytes are passed on stack. */
> +
> + /* Find out the next register to use for a floating point value. */
> + if (TYPE_CODE (type) == TYPE_CODE_FLT)
> + flt_argreg = sh_next_flt_argreg (len);
>
> - if (len > 4 && (len & 3) != 0)
> - odd_sized_struct = 1; /* Such structs go entirely on stack. */
> - else if (len > 16)
> - odd_sized_struct = 1; /* So do aggregates bigger than 4 words. */
> - else
> - odd_sized_struct = 0;
> while (len > 0)
> {
> if ((TYPE_CODE (type) == TYPE_CODE_FLT
> - && flt_argreg > FLOAT_ARGLAST_REGNUM)
> + && flt_argreg > FLOAT_ARGLAST_REGNUM)
> || argreg > ARGLAST_REGNUM
> - || odd_sized_struct)
> - {
> - /* must go on the stack */
> + || pass_on_stack)
> + {
> write_memory (sp + stack_offset, val, 4);
> stack_offset += 4;
> }
> - /* NOTE WELL!!!!! This is not an "else if" clause!!!
> - That's because some *&^%$ things get passed on the stack
> - AND in the registers! */
> - if (TYPE_CODE (type) == TYPE_CODE_FLT &&
> - flt_argreg > 0 && flt_argreg <= FLOAT_ARGLAST_REGNUM)
> + else if (TYPE_CODE (type) == TYPE_CODE_FLT
> + && flt_argreg <= FLOAT_ARGLAST_REGNUM)
> {
> - /* Argument goes in a single-precision fp reg. */
> + /* Argument goes in a float argument register. */
> regval = extract_unsigned_integer (val, register_size (gdbarch,
> argreg));
> regcache_cooked_write_unsigned (regcache, flt_argreg++, regval);
> }
> else if (argreg <= ARGLAST_REGNUM)
> - {
> + {
> /* there's room in a register */
> regval = extract_unsigned_integer (val, register_size (gdbarch,
> argreg));
> @@ -1034,8 +1112,8 @@ sh_push_dummy_call_fpu (struct gdbarch *
> /* Store the value 4 bytes at a time. This means that things
> larger than 4 bytes may go partly in registers and partly
> on the stack. */
> - len -= register_size (gdbarch, argreg);
> - val += register_size (gdbarch, argreg);
> + len -= 4;
> + val += 4;
> }
> }
>
> @@ -1057,15 +1135,13 @@ sh_push_dummy_call_nofpu (struct gdbarch
> CORE_ADDR sp, int struct_return,
> CORE_ADDR struct_addr)
> {
> - int stack_offset, stack_alloc;
> - int argreg;
> + int stack_offset = 0;
> + int argreg = ARG0_REGNUM;
> int argnum;
> struct type *type;
> CORE_ADDR regval;
> char *val;
> - char valbuf[4];
> int len;
> - int odd_sized_struct;
>
> /* first force sp to a 4-byte alignment */
> sp = sh_frame_align (gdbarch, sp);
> @@ -1077,52 +1153,27 @@ sh_push_dummy_call_nofpu (struct gdbarch
> STRUCT_RETURN_REGNUM,
> struct_addr);
>
> - /* Now make sure there's space on the stack */
> - for (argnum = 0, stack_alloc = 0; argnum < nargs; argnum++)
> - stack_alloc += ((TYPE_LENGTH (VALUE_TYPE (args[argnum])) + 3) & ~3);
> - sp -= stack_alloc; /* make room on stack for args */
> + /* make room on stack for args */
> + sp -= sh_stack_allocsize (nargs, args);
>
> /* Now load as many as possible of the first arguments into
> registers, and push the rest onto the stack. There are 16 bytes
> in four registers available. Loop thru args from first to last. */
> -
> - argreg = ARG0_REGNUM;
> - for (argnum = 0, stack_offset = 0; argnum < nargs; argnum++)
> - {
> + for (argnum = 0; argnum < nargs; argnum++)
> + {
> type = VALUE_TYPE (args[argnum]);
> len = TYPE_LENGTH (type);
> - memset (valbuf, 0, sizeof (valbuf));
> - if (len < 4)
> - {
> - /* value gets right-justified in the register or stack word */
> - if (TARGET_BYTE_ORDER == BFD_ENDIAN_BIG)
> - memcpy (valbuf + (4 - len),
> - (char *) VALUE_CONTENTS (args[argnum]), len);
> - else
> - memcpy (valbuf, (char *) VALUE_CONTENTS (args[argnum]), len);
> - val = valbuf;
> - }
> - else
> - val = (char *) VALUE_CONTENTS (args[argnum]);
> + val = sh_justify_value_in_reg (args[argnum], len);
>
> - if (len > 4 && (len & 3) != 0)
> - odd_sized_struct = 1; /* such structs go entirely on stack */
> - else
> - odd_sized_struct = 0;
> while (len > 0)
> {
> - if (argreg > ARGLAST_REGNUM
> - || odd_sized_struct)
> - {
> - /* must go on the stack */
> + if (argreg > ARGLAST_REGNUM)
> + {
> write_memory (sp + stack_offset, val, 4);
> - stack_offset += 4;
> + stack_offset += 4;
> }
> - /* NOTE WELL!!!!! This is not an "else if" clause!!!
> - That's because some *&^%$ things get passed on the stack
> - AND in the registers! */
> - if (argreg <= ARGLAST_REGNUM)
> - {
> + else if (argreg <= ARGLAST_REGNUM)
> + {
> /* there's room in a register */
> regval = extract_unsigned_integer (val, register_size (gdbarch,
> argreg));
> @@ -1131,8 +1182,8 @@ sh_push_dummy_call_nofpu (struct gdbarch
> /* Store the value 4 bytes at a time. This means that things
> larger than 4 bytes may go partly in registers and partly
> on the stack. */
> - len -= register_size (gdbarch, argreg);
> - val += register_size (gdbarch, argreg);
> + len -= 4;
> + val += 4;
> }
> }
>
> --
> Corinna Vinschen
> Cygwin Developer
> Red Hat, Inc.
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: SH follow up, part 2 (was Re: [RFA] sh-tdep.c: Follow up patch to implement two different ABIs)
2003-09-24 10:39 ` SH follow up, part 2 " Corinna Vinschen
@ 2003-09-25 21:44 ` Elena Zannoni
2003-09-26 11:15 ` Corinna Vinschen
0 siblings, 1 reply; 12+ messages in thread
From: Elena Zannoni @ 2003-09-25 21:44 UTC (permalink / raw)
To: gdb-patches
Corinna Vinschen writes:
> On Tue, Sep 23, 2003 at 04:44:03PM -0400, Elena Zannoni wrote:
> > Corinna Vinschen writes:
>
> And now part 2.
>
> > > - Add the commands `set calling_convention <foo>' and
> > > `show calling_convention' with <foo> being one of "gcc" and "renesas".
> > > Default to "gcc".
> >
> > Should be using hyphen, not underscore. What happens if you have a
>
> Done. I followed Andrew's suggestion to change this to
>
> set sh calling-convention ...
> show sh calling-convention
>
> > file compiled with renesas ABI but you set the calling convention to
> > the gcc (or vice versa)? How are the abi supported by gcc? Is there a
> > -with-abi-renesas to be given when one compiles the tests? I.e. is it
> > possible to run the testsuite with the one specific abi?
>
> Currently there's no way to differ between these two ABIs automatically
> though that might change at some later point. The user has to change
> the ABI on the command line by hand. The compiler option was -mhitachi,
> gcc is just changing to -mrenesas to reflect the company name change.
Hmm but then the user can set the calling convention to the wrong one.
Also the finish command, I am afraid, will be confused. There should
be something detecting the calling convention from the executable. Is
the info recorded in the file anywhere? I.e. would readelf/objdump
show it?
>
> So the changes introduced with this patch are:
>
> - Differ between a fpu and a nofpu version of sh_use_struct_convention.
> The nofpu version behaves like the fpu version, except that it uses
> struct convention also for all types >= 8 bytes when the Renesas ABI
> is active. This especially affects long longs and doubles which are
> then passed on the stack.
>
> - The Renesas ABI passes the address in which structs have to be returned
> not in r2 as the gcc ABI, but instead this return address is pushed
> onto the stack after all arguments have been pushed. This affects
> sh_extract_struct_value_address() as well as the sh_push_dummy_call*()
> functions.
>
> - sh_next_flt_argreg() now also takes the ABI into account. The differences
> are:
>
> - In Renesas ABI, the criss-crossing register usage in little endian
> mode for doubles doesn't happen.
>
> - In both ABIs doubles are passed in even register pairs, fr4/fr5,
> fr6/fr7, ... The difference is when a register is skipped to pass
> the next double. Example:
>
> void foo(float a, double b, float c);
>
> In gcc ABI, a is passed in fr4, b then skips the odd-numbered fr5
> register, so it's passed in fr6/fr7 and c is then passed in the next
> free register, fr8.
>
> In Renesas ABI, a is passed in fr4, b is passed as in gcc ABI in
> fr6/fr7 but c is passed in the lowest unused register, in this example
> in fr5.
>
> - In the Renesas ABI for CPUs with FPU, long longs are not passed in
> registers but on stack.
>
> - The struct_return code in both sh_push_dummy_call*() functions is moved
> to the end of the function since it must be done after the argument
> passing for the Rensas ABI.
>
> - `pass_on_stack' takes the Renesas ABI into account:
>
> - On FPU CPUs, Renesas ABI passes long longs always on the stack.
>
> - On non-FPU CPUs, Renesas ABI passes doubles and long doubles always
> on the stack.
>
These descriptions should be comments in the file, the more verbiage
the better.
I don't have anything in particular against these patches, but I'd like
to have a better idea about how to solve this calling convention issue
before the changes go in.
elena
> Corinna
>
>
> ChangeLog:
> ==========
>
> * sh-tdep.c (sh_cc_gcc): New static string.
> (sh_cc_renesas): Ditto.
> (sh_cc_enum): New array pointing to calling convention strings.
> (sh_active_calling_convention): New variable pointing to
> current active calling convention.
> (sh_use_struct_convention_fpu): New function.
> (sh_use_struct_convention_nofpu): New function.
> (sh_use_struct_convention): Remove. Superseeded by the previous
> two functions.
> (sh_extract_struct_value_address): Care for Renesas ABI.
> (sh_next_flt_argreg): Accomodate Renesas ABI.
> (sh_push_dummy_call_fpu): Ditto.
> (sh_push_dummy_call_nofpu): Ditto.
> (sh_gdbarch_init): Accomodate new sh_use_struct_convention_fpu and
> sh_use_struct_convention_nofpu functions.
> (show_sh_command): New function.
> (set_sh_command): New function.
> (_initialize_sh_tdep): Initialize new "set sh calling-convention",
> "show sh calling-convention" commands.
>
> --- sh-tdep.c.MIDNEW 2003-09-24 12:01:46.000000000 +0200
> +++ sh-tdep.c.NEW 2003-09-24 12:24:10.000000000 +0200
> @@ -55,6 +55,21 @@
> /* registers numbers shared with the simulator */
> #include "gdb/sim-sh.h"
>
> +/* List of "set sh ..." and "show sh ..." commands. */
> +static struct cmd_list_element *setshcmdlist = NULL;
> +static struct cmd_list_element *showshcmdlist = NULL;
> +
> +static const char sh_cc_gcc[] = "gcc";
> +static const char sh_cc_renesas[] = "renesas";
> +static const char *sh_cc_enum[] =
> +{
> + sh_cc_gcc,
> + sh_cc_renesas,
> + NULL
> +};
> +
> +static const char *sh_active_calling_convention = sh_cc_gcc;
> +
> static void (*sh_show_regs) (void);
>
> #define SH_NUM_REGS 59
> @@ -569,10 +584,25 @@ sh_skip_prologue (CORE_ADDR start_pc)
>
> /* Should call_function allocate stack space for a struct return? */
> static int
> -sh_use_struct_convention (int gcc_p, struct type *type)
> +sh_use_struct_convention_fpu (int gcc_p, struct type *type)
> {
> int len = TYPE_LENGTH (type);
> int nelem = TYPE_NFIELDS (type);
> +
> + return ((len != 1 && len != 2 && len != 4 && len != 8) || nelem != 1) &&
> + (len != 8 || TYPE_LENGTH (TYPE_FIELD_TYPE (type, 0)) != 4);
> +}
> +
> +static int
> +sh_use_struct_convention_nofpu (int gcc_p, struct type *type)
> +{
> + int len = TYPE_LENGTH (type);
> + int nelem = TYPE_NFIELDS (type);
> +
> + /* The Renesas ABI returns long longs/doubles etc. always on stack. */
> + if (sh_active_calling_convention == sh_cc_renesas && len >= 8)
> + return 1;
> +
> return ((len != 1 && len != 2 && len != 4 && len != 8) || nelem != 1) &&
> (len != 8 || TYPE_LENGTH (TYPE_FIELD_TYPE (type, 0)) != 4);
> }
> @@ -584,8 +614,13 @@ static CORE_ADDR
> sh_extract_struct_value_address (struct regcache *regcache)
> {
> ULONGEST addr;
> -
> - regcache_cooked_read_unsigned (regcache, STRUCT_RETURN_REGNUM, &addr);
> + if (sh_active_calling_convention != sh_cc_renesas)
> + regcache_cooked_read_unsigned (regcache, STRUCT_RETURN_REGNUM, &addr);
> + else
> + {
> + regcache_cooked_read_unsigned (regcache, SP_REGNUM, &addr);
> + addr = read_memory_unsigned_integer (addr, 4);
> + }
> return addr;
> }
>
> @@ -653,7 +688,7 @@ sh_justify_value_in_reg (struct value *v
> {
> static char valbuf[4];
>
> - memset (valbuf, 0, sizeof (valbuf));
> + memset (valbuf, 0, sizeof (valbuf));
> if (len < 4)
> {
> /* value gets right-justified in the register or stack word */
> @@ -664,7 +699,7 @@ sh_justify_value_in_reg (struct value *v
> return valbuf;
> }
> return (char *) VALUE_CONTENTS (val);
> -}
> +}
>
> /* Helper function to eval number of bytes to allocate on stack. */
> static CORE_ADDR
> @@ -718,18 +753,22 @@ sh_next_flt_argreg (int len)
> /* Doubles are always starting in a even register number. */
> if (argreg & 1)
> {
> - flt_argreg_array[argreg] = 1;
> + /* In gcc ABI, the skipped register is lost for further argument
> + passing now. Not so in Renesas ABI. */
> + if (sh_active_calling_convention != sh_cc_renesas)
> + flt_argreg_array[argreg] = 1;
>
> ++argreg;
>
> - /* No register left? */
> + /* No register left? */
> if (argreg > FLOAT_ARGLAST_REGNUM - FLOAT_ARG0_REGNUM)
> return FLOAT_ARGLAST_REGNUM + 1;
> }
> /* Also mark the next register as used. */
> flt_argreg_array[argreg + 1] = 1;
> }
> - else if (TARGET_BYTE_ORDER == BFD_ENDIAN_LITTLE)
> + else if (TARGET_BYTE_ORDER == BFD_ENDIAN_LITTLE
> + && sh_active_calling_convention != sh_cc_renesas)
> {
> /* In little endian, gcc passes floats like this: f5, f4, f7, f6, ... */
> if (!flt_argreg_array[argreg + 1])
> @@ -761,13 +800,6 @@ sh_push_dummy_call_fpu (struct gdbarch *
> /* first force sp to a 4-byte alignment */
> sp = sh_frame_align (gdbarch, sp);
>
> - /* The "struct return pointer" pseudo-argument has its own dedicated
> - register */
> - if (struct_return)
> - regcache_cooked_write_unsigned (regcache,
> - STRUCT_RETURN_REGNUM,
> - struct_addr);
> -
> /* make room on stack for args */
> sp -= sh_stack_allocsize (nargs, args);
>
> @@ -787,7 +819,10 @@ sh_push_dummy_call_fpu (struct gdbarch *
> This also differs in different ABIs. */
> pass_on_stack = 0;
> if (len > 16)
> - pass_on_stack = 1; /* Types bigger than 16 bytes are passed on stack. */
> + pass_on_stack = 1; /* Types bigger than 16 bytes are passed on stack. */
> + else if (sh_active_calling_convention == sh_cc_renesas
> + && TYPE_CODE (type) == TYPE_CODE_INT && len == 8)
> + pass_on_stack = 1; /* So are long longs in renesas ABI */
>
> /* Find out the next register to use for a floating point value. */
> if (TYPE_CODE (type) == TYPE_CODE_FLT)
> @@ -796,10 +831,10 @@ sh_push_dummy_call_fpu (struct gdbarch *
> while (len > 0)
> {
> if ((TYPE_CODE (type) == TYPE_CODE_FLT
> - && flt_argreg > FLOAT_ARGLAST_REGNUM)
> + && flt_argreg > FLOAT_ARGLAST_REGNUM)
> || argreg > ARGLAST_REGNUM
> || pass_on_stack)
> - {
> + {
> write_memory (sp + stack_offset, val, 4);
> stack_offset += 4;
> }
> @@ -812,7 +847,7 @@ sh_push_dummy_call_fpu (struct gdbarch *
> regcache_cooked_write_unsigned (regcache, flt_argreg++, regval);
> }
> else if (argreg <= ARGLAST_REGNUM)
> - {
> + {
> /* there's room in a register */
> regval = extract_unsigned_integer (val, register_size (gdbarch,
> argreg));
> @@ -826,6 +861,20 @@ sh_push_dummy_call_fpu (struct gdbarch *
> }
> }
>
> + if (struct_return)
> + {
> + if (sh_active_calling_convention != sh_cc_renesas)
> + /* Using the gcc ABI, the "struct return pointer" pseudo-argument has
> + its own dedicated register */
> + regcache_cooked_write_unsigned (regcache,
> + STRUCT_RETURN_REGNUM,
> + struct_addr);
> + else
> + /* If the function uses the renesas ABI, subtract another 4 bytes from
> + the stack and store the struct return address there. */
> + write_memory_unsigned_integer (sp -= 4, 4, struct_addr);
> + }
> +
> /* Store return address. */
> regcache_cooked_write_unsigned (regcache, PR_REGNUM, bp_addr);
>
> @@ -851,17 +900,11 @@ sh_push_dummy_call_nofpu (struct gdbarch
> CORE_ADDR regval;
> char *val;
> int len;
> + int pass_on_stack;
>
> /* first force sp to a 4-byte alignment */
> sp = sh_frame_align (gdbarch, sp);
>
> - /* The "struct return pointer" pseudo-argument has its own dedicated
> - register */
> - if (struct_return)
> - regcache_cooked_write_unsigned (regcache,
> - STRUCT_RETURN_REGNUM,
> - struct_addr);
> -
> /* make room on stack for args */
> sp -= sh_stack_allocsize (nargs, args);
>
> @@ -869,20 +912,27 @@ sh_push_dummy_call_nofpu (struct gdbarch
> registers, and push the rest onto the stack. There are 16 bytes
> in four registers available. Loop thru args from first to last. */
> for (argnum = 0; argnum < nargs; argnum++)
> - {
> + {
> type = VALUE_TYPE (args[argnum]);
> len = TYPE_LENGTH (type);
> val = sh_justify_value_in_reg (args[argnum], len);
>
> + /* Some decisions have to be made how various types are handled.
> + This also differs in different ABIs. */
> + pass_on_stack = 0;
> + if (TYPE_CODE (type) == TYPE_CODE_FLT && len > 4
> + && sh_active_calling_convention == sh_cc_renesas)
> + pass_on_stack = 1; /* Renesas ABI pushes doubles entirely on stack. */
> +
> while (len > 0)
> {
> - if (argreg > ARGLAST_REGNUM)
> - {
> + if (argreg > ARGLAST_REGNUM || pass_on_stack)
> + {
> write_memory (sp + stack_offset, val, 4);
> - stack_offset += 4;
> + stack_offset += 4;
> }
> else if (argreg <= ARGLAST_REGNUM)
> - {
> + {
> /* there's room in a register */
> regval = extract_unsigned_integer (val, register_size (gdbarch,
> argreg));
> @@ -896,6 +946,20 @@ sh_push_dummy_call_nofpu (struct gdbarch
> }
> }
>
> + if (struct_return)
> + {
> + if (sh_active_calling_convention != sh_cc_renesas)
> + /* Using the gcc ABI, the "struct return pointer" pseudo-argument has
> + its own dedicated register */
> + regcache_cooked_write_unsigned (regcache,
> + STRUCT_RETURN_REGNUM,
> + struct_addr);
> + else
> + /* If the function uses the renesas ABI, subtract another 4 bytes from
> + the stack and store the struct return address there. */
> + write_memory_unsigned_integer (sp -= 4, 4, struct_addr);
> + }
> +
> /* Store return address. */
> regcache_cooked_write_unsigned (regcache, PR_REGNUM, bp_addr);
>
> @@ -2115,7 +2179,6 @@ sh_gdbarch_init (struct gdbarch_info inf
> set_gdbarch_print_registers_info (gdbarch, sh_print_registers_info);
>
> set_gdbarch_breakpoint_from_pc (gdbarch, sh_breakpoint_from_pc);
> - set_gdbarch_use_struct_convention (gdbarch, sh_use_struct_convention);
>
> set_gdbarch_print_insn (gdbarch, gdb_print_insn_sh);
> set_gdbarch_register_sim_regno (gdbarch, legacy_register_sim_regno);
> @@ -2134,6 +2197,7 @@ sh_gdbarch_init (struct gdbarch_info inf
>
> set_gdbarch_push_dummy_code (gdbarch, sh_push_dummy_code);
> set_gdbarch_push_dummy_call (gdbarch, sh_push_dummy_call_nofpu);
> + set_gdbarch_use_struct_convention (gdbarch, sh_use_struct_convention_nofpu);
>
> set_gdbarch_frame_args_skip (gdbarch, 0);
> set_gdbarch_frameless_function_invocation (gdbarch,
> @@ -2169,6 +2233,7 @@ sh_gdbarch_init (struct gdbarch_info inf
> set_gdbarch_store_return_value (gdbarch, sh3e_sh4_store_return_value);
> set_gdbarch_extract_return_value (gdbarch, sh3e_sh4_extract_return_value);
> set_gdbarch_push_dummy_call (gdbarch, sh_push_dummy_call_fpu);
> + set_gdbarch_use_struct_convention (gdbarch, sh_use_struct_convention_fpu);
> break;
>
> case bfd_mach_sh_dsp:
> @@ -2190,6 +2255,7 @@ sh_gdbarch_init (struct gdbarch_info inf
> set_gdbarch_store_return_value (gdbarch, sh3e_sh4_store_return_value);
> set_gdbarch_extract_return_value (gdbarch, sh3e_sh4_extract_return_value);
> set_gdbarch_push_dummy_call (gdbarch, sh_push_dummy_call_fpu);
> + set_gdbarch_use_struct_convention (gdbarch, sh_use_struct_convention_fpu);
> break;
>
> case bfd_mach_sh3_dsp:
> @@ -2207,6 +2273,7 @@ sh_gdbarch_init (struct gdbarch_info inf
> set_gdbarch_store_return_value (gdbarch, sh3e_sh4_store_return_value);
> set_gdbarch_extract_return_value (gdbarch, sh3e_sh4_extract_return_value);
> set_gdbarch_push_dummy_call (gdbarch, sh_push_dummy_call_fpu);
> + set_gdbarch_use_struct_convention (gdbarch, sh_use_struct_convention_fpu);
> break;
>
> default:
> @@ -2223,6 +2290,19 @@ sh_gdbarch_init (struct gdbarch_info inf
> return gdbarch;
> }
>
> +static void
> +show_sh_command (char *args, int from_tty)
> +{
> + help_list (showshcmdlist, "show sh ", all_commands, gdb_stdout);
> +}
> +
> +static void
> +set_sh_command (char *args, int from_tty)
> +{
> + printf_unfiltered ("\"set sh\" must be followed by an appropriate subcommand.\n");
> + help_list (setshcmdlist, "set sh ", all_commands, gdb_stdout);
> +}
> +
> extern initialize_file_ftype _initialize_sh_tdep; /* -Wmissing-prototypes */
>
> void
> @@ -2233,4 +2313,16 @@ _initialize_sh_tdep (void)
> gdbarch_register (bfd_arch_sh, sh_gdbarch_init, NULL);
>
> add_com ("regs", class_vars, sh_show_regs_command, "Print all registers");
> +
> + add_prefix_cmd ("sh", no_class, set_sh_command, "SH specific commands.",
> + &setshcmdlist, "set sh ", 0, &setlist);
> + add_prefix_cmd ("sh", no_class, show_sh_command, "SH specific commands.",
> + &showshcmdlist, "show sh ", 0, &showlist);
> +
> + add_show_from_set (
> + add_set_enum_cmd ("calling-convention", class_vars, sh_cc_enum,
> + &sh_active_calling_convention,
> + "Set calling convention used when calling target "
> + "functions from GDB.",
> + &setshcmdlist), &showshcmdlist);
> }
>
> --
> Corinna Vinschen
> Cygwin Developer
> Red Hat, Inc.
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: SH follow up, part 1 (was Re: [RFA] sh-tdep.c: Follow up patch to implement two different ABIs)
2003-09-25 21:39 ` Elena Zannoni
@ 2003-09-26 11:14 ` Corinna Vinschen
2003-10-01 20:26 ` Elena Zannoni
0 siblings, 1 reply; 12+ messages in thread
From: Corinna Vinschen @ 2003-09-26 11:14 UTC (permalink / raw)
To: gdb-patches
On Thu, Sep 25, 2003 at 05:48:50PM -0400, Elena Zannoni wrote:
> Corinna Vinschen writes:
> > Ok, step 1:
>
> Seems ok, are there diffs in the test results before&after?
No.
> Are these
> explanations also in the code?
Yes.
> > If you don't like that and want to use register_size correctly in that case,
> > it would have to look like this:
>
> Yes please.
>
> When you are done with this rewrite, it would be good to pass the file
> through gdb_indent.sh.
Yes. Anything else left before approval?
Corinna
ChangeLog:
==========
* sh-tdep.c (sh_justify_value_in_reg): New function.
(sh_stack_allocsize): Ditto.
(flt_argreg_array): New array used for floating point argument
passing.
(sh_init_flt_argreg): New function.
(sh_next_flt_argreg): Ditto.
(sh_push_dummy_call_fpu): Simplify. Rename "odd_sized_struct" to
"pass_on_stack". Use new helper functions. Accomodate Renesas ABI.
Fix argument passing strategy.
(sh_push_dummy_call_nofpu): Ditto.
Index: sh-tdep.c
===================================================================
RCS file: /cvs/src/src/gdb/sh-tdep.c,v
retrieving revision 1.142
diff -u -p -r1.142 sh-tdep.c
--- sh-tdep.c 25 Sep 2003 08:55:53 -0000 1.142
+++ sh-tdep.c 26 Sep 2003 11:09:31 -0000
@@ -77,15 +77,14 @@ struct sh_frame_cache
static const char *
sh_generic_register_name (int reg_nr)
{
- static char *register_names[] =
- {
- "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
- "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15",
- "pc", "pr", "gbr", "vbr", "mach", "macl", "sr",
+ static char *register_names[] = {
+ "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
+ "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15",
+ "pc", "pr", "gbr", "vbr", "mach", "macl", "sr",
"fpul", "fpscr",
- "fr0", "fr1", "fr2", "fr3", "fr4", "fr5", "fr6", "fr7",
- "fr8", "fr9", "fr10", "fr11", "fr12", "fr13", "fr14", "fr15",
- "ssr", "spc",
+ "fr0", "fr1", "fr2", "fr3", "fr4", "fr5", "fr6", "fr7",
+ "fr8", "fr9", "fr10", "fr11", "fr12", "fr13", "fr14", "fr15",
+ "ssr", "spc",
"r0b0", "r1b0", "r2b0", "r3b0", "r4b0", "r5b0", "r6b0", "r7b0",
"r0b1", "r1b1", "r2b1", "r3b1", "r4b1", "r5b1", "r6b1", "r7b1",
};
@@ -99,17 +98,16 @@ sh_generic_register_name (int reg_nr)
static const char *
sh_sh_register_name (int reg_nr)
{
- static char *register_names[] =
- {
- "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
- "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15",
- "pc", "pr", "gbr", "vbr", "mach", "macl", "sr",
- "", "",
- "", "", "", "", "", "", "", "",
- "", "", "", "", "", "", "", "",
- "", "",
- "", "", "", "", "", "", "", "",
- "", "", "", "", "", "", "", "",
+ static char *register_names[] = {
+ "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
+ "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15",
+ "pc", "pr", "gbr", "vbr", "mach", "macl", "sr",
+ "", "",
+ "", "", "", "", "", "", "", "",
+ "", "", "", "", "", "", "", "",
+ "", "",
+ "", "", "", "", "", "", "", "",
+ "", "", "", "", "", "", "", "",
};
if (reg_nr < 0)
return NULL;
@@ -121,15 +119,14 @@ sh_sh_register_name (int reg_nr)
static const char *
sh_sh3_register_name (int reg_nr)
{
- static char *register_names[] =
- {
- "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
- "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15",
- "pc", "pr", "gbr", "vbr", "mach", "macl", "sr",
- "", "",
- "", "", "", "", "", "", "", "",
- "", "", "", "", "", "", "", "",
- "ssr", "spc",
+ static char *register_names[] = {
+ "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
+ "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15",
+ "pc", "pr", "gbr", "vbr", "mach", "macl", "sr",
+ "", "",
+ "", "", "", "", "", "", "", "",
+ "", "", "", "", "", "", "", "",
+ "ssr", "spc",
"r0b0", "r1b0", "r2b0", "r3b0", "r4b0", "r5b0", "r6b0", "r7b0",
"r0b1", "r1b1", "r2b1", "r3b1", "r4b1", "r5b1", "r6b1", "r7b1"
};
@@ -143,15 +140,14 @@ sh_sh3_register_name (int reg_nr)
static const char *
sh_sh3e_register_name (int reg_nr)
{
- static char *register_names[] =
- {
- "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
- "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15",
- "pc", "pr", "gbr", "vbr", "mach", "macl", "sr",
+ static char *register_names[] = {
+ "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
+ "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15",
+ "pc", "pr", "gbr", "vbr", "mach", "macl", "sr",
"fpul", "fpscr",
- "fr0", "fr1", "fr2", "fr3", "fr4", "fr5", "fr6", "fr7",
- "fr8", "fr9", "fr10", "fr11", "fr12", "fr13", "fr14", "fr15",
- "ssr", "spc",
+ "fr0", "fr1", "fr2", "fr3", "fr4", "fr5", "fr6", "fr7",
+ "fr8", "fr9", "fr10", "fr11", "fr12", "fr13", "fr14", "fr15",
+ "ssr", "spc",
"r0b0", "r1b0", "r2b0", "r3b0", "r4b0", "r5b0", "r6b0", "r7b0",
"r0b1", "r1b1", "r2b1", "r3b1", "r4b1", "r5b1", "r6b1", "r7b1",
};
@@ -165,15 +161,14 @@ sh_sh3e_register_name (int reg_nr)
static const char *
sh_sh2e_register_name (int reg_nr)
{
- static char *register_names[] =
- {
- "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
- "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15",
- "pc", "pr", "gbr", "vbr", "mach", "macl", "sr",
+ static char *register_names[] = {
+ "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
+ "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15",
+ "pc", "pr", "gbr", "vbr", "mach", "macl", "sr",
"fpul", "fpscr",
- "fr0", "fr1", "fr2", "fr3", "fr4", "fr5", "fr6", "fr7",
- "fr8", "fr9", "fr10", "fr11", "fr12", "fr13", "fr14", "fr15",
- "", "",
+ "fr0", "fr1", "fr2", "fr3", "fr4", "fr5", "fr6", "fr7",
+ "fr8", "fr9", "fr10", "fr11", "fr12", "fr13", "fr14", "fr15",
+ "", "",
"", "", "", "", "", "", "", "",
"", "", "", "", "", "", "", "",
};
@@ -187,17 +182,16 @@ sh_sh2e_register_name (int reg_nr)
static const char *
sh_sh_dsp_register_name (int reg_nr)
{
- static char *register_names[] =
- {
- "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
- "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15",
- "pc", "pr", "gbr", "vbr", "mach", "macl", "sr",
- "", "dsr",
- "a0g", "a0", "a1g", "a1", "m0", "m1", "x0", "x1",
- "y0", "y1", "", "", "", "", "", "mod",
- "", "",
- "rs", "re", "", "", "", "", "", "",
- "", "", "", "", "", "", "", "",
+ static char *register_names[] = {
+ "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
+ "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15",
+ "pc", "pr", "gbr", "vbr", "mach", "macl", "sr",
+ "", "dsr",
+ "a0g", "a0", "a1g", "a1", "m0", "m1", "x0", "x1",
+ "y0", "y1", "", "", "", "", "", "mod",
+ "", "",
+ "rs", "re", "", "", "", "", "", "",
+ "", "", "", "", "", "", "", "",
};
if (reg_nr < 0)
return NULL;
@@ -209,18 +203,17 @@ sh_sh_dsp_register_name (int reg_nr)
static const char *
sh_sh3_dsp_register_name (int reg_nr)
{
- static char *register_names[] =
- {
- "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
- "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15",
- "pc", "pr", "gbr", "vbr", "mach", "macl", "sr",
- "", "dsr",
- "a0g", "a0", "a1g", "a1", "m0", "m1", "x0", "x1",
- "y0", "y1", "", "", "", "", "", "mod",
- "ssr", "spc",
- "rs", "re", "", "", "", "", "", "",
- "r0b", "r1b", "r2b", "r3b", "r4b", "r5b", "r6b", "r7b"
- "", "", "", "", "", "", "", "",
+ static char *register_names[] = {
+ "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
+ "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15",
+ "pc", "pr", "gbr", "vbr", "mach", "macl", "sr",
+ "", "dsr",
+ "a0g", "a0", "a1g", "a1", "m0", "m1", "x0", "x1",
+ "y0", "y1", "", "", "", "", "", "mod",
+ "ssr", "spc",
+ "rs", "re", "", "", "", "", "", "",
+ "r0b", "r1b", "r2b", "r3b", "r4b", "r5b", "r6b", "r7b"
+ "", "", "", "", "", "", "", "",
};
if (reg_nr < 0)
return NULL;
@@ -232,28 +225,27 @@ sh_sh3_dsp_register_name (int reg_nr)
static const char *
sh_sh4_register_name (int reg_nr)
{
- static char *register_names[] =
- {
+ static char *register_names[] = {
/* general registers 0-15 */
- "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
- "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15",
+ "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
+ "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15",
/* 16 - 22 */
- "pc", "pr", "gbr", "vbr", "mach", "macl", "sr",
+ "pc", "pr", "gbr", "vbr", "mach", "macl", "sr",
/* 23, 24 */
"fpul", "fpscr",
/* floating point registers 25 - 40 */
- "fr0", "fr1", "fr2", "fr3", "fr4", "fr5", "fr6", "fr7",
- "fr8", "fr9", "fr10", "fr11", "fr12", "fr13", "fr14", "fr15",
+ "fr0", "fr1", "fr2", "fr3", "fr4", "fr5", "fr6", "fr7",
+ "fr8", "fr9", "fr10", "fr11", "fr12", "fr13", "fr14", "fr15",
/* 41, 42 */
- "ssr", "spc",
+ "ssr", "spc",
/* bank 0 43 - 50 */
"r0b0", "r1b0", "r2b0", "r3b0", "r4b0", "r5b0", "r6b0", "r7b0",
/* bank 1 51 - 58 */
"r0b1", "r1b1", "r2b1", "r3b1", "r4b1", "r5b1", "r6b1", "r7b1",
/* double precision (pseudo) 59 - 66 */
- "dr0", "dr2", "dr4", "dr6", "dr8", "dr10", "dr12", "dr14",
+ "dr0", "dr2", "dr4", "dr6", "dr8", "dr10", "dr12", "dr14",
/* vectors (pseudo) 67 - 70 */
- "fv0", "fv4", "fv8", "fv12",
+ "fv0", "fv4", "fv8", "fv12",
/* FIXME: missing XF 71 - 86 */
/* FIXME: missing XD 87 - 94 */
};
@@ -268,8 +260,8 @@ static const unsigned char *
sh_breakpoint_from_pc (CORE_ADDR *pcptr, int *lenptr)
{
/* 0xc3c3 is trapa #c3, and it works in big and little endian modes */
- static unsigned char breakpoint[] = {0xc3, 0xc3};
-
+ static unsigned char breakpoint[] = { 0xc3, 0xc3 };
+
*lenptr = sizeof (breakpoint);
return breakpoint;
}
@@ -369,7 +361,7 @@ sh_push_dummy_code (struct gdbarch *gdba
/* Disassemble an instruction. */
static int
-gdb_print_insn_sh (bfd_vma memaddr, disassemble_info *info)
+gdb_print_insn_sh (bfd_vma memaddr, disassemble_info * info)
{
info->endian = TARGET_BYTE_ORDER;
return print_insn_sh (memaddr, info);
@@ -378,7 +370,7 @@ gdb_print_insn_sh (bfd_vma memaddr, disa
static CORE_ADDR
sh_analyze_prologue (CORE_ADDR pc, CORE_ADDR current_pc,
struct sh_frame_cache *cache)
-{
+{
ULONGEST inst;
CORE_ADDR opc;
int offset;
@@ -422,7 +414,7 @@ sh_analyze_prologue (CORE_ADDR pc, CORE_
cache->sp_offset -= offset;
}
else if (IS_MOVW_PCREL_TO_REG (inst))
- {
+ {
if (sav_reg < 0)
{
reg = GET_TARGET_REG (inst);
@@ -431,12 +423,12 @@ sh_analyze_prologue (CORE_ADDR pc, CORE_
sav_reg = reg;
offset = (((inst & 0xff) ^ 0x80) - 0x80) << 1;
sav_offset =
- read_memory_integer (((pc + 4) & ~3) + offset, 2);
+ read_memory_integer (((pc + 4) & ~3) + offset, 2);
}
}
}
else if (IS_MOVL_PCREL_TO_REG (inst))
- {
+ {
if (sav_reg < 0)
{
reg = (inst & 0x0f00) >> 8;
@@ -445,12 +437,12 @@ sh_analyze_prologue (CORE_ADDR pc, CORE_
sav_reg = reg;
offset = (((inst & 0xff) ^ 0x80) - 0x80) << 1;
sav_offset =
- read_memory_integer (((pc + 4) & ~3) + offset, 4);
+ read_memory_integer (((pc + 4) & ~3) + offset, 4);
}
}
}
else if (IS_SUB_REG_FROM_SP (inst))
- {
+ {
reg = GET_SOURCE_REG (inst);
if (sav_reg > 0 && reg == sav_reg)
{
@@ -470,7 +462,7 @@ sh_analyze_prologue (CORE_ADDR pc, CORE_
}
}
else if (IS_MOV_SP_FP (inst))
- {
+ {
if (!cache->uses_fp)
cache->uses_fp = 1;
/* At this point, only allow argument register moves to other
@@ -483,28 +475,28 @@ sh_analyze_prologue (CORE_ADDR pc, CORE_
{
inst = read_memory_integer (pc, 2);
if (IS_MOV_ARG_TO_IND_R14 (inst))
- {
+ {
reg = GET_SOURCE_REG (inst);
if (cache->sp_offset > 0)
- cache->saved_regs[reg] = cache->sp_offset;
+ cache->saved_regs[reg] = cache->sp_offset;
}
else if (IS_MOV_ARG_TO_IND_R14_WITH_DISP (inst))
- {
+ {
reg = GET_SOURCE_REG (inst);
offset = (inst & 0xf) * 4;
if (cache->sp_offset > offset)
cache->saved_regs[reg] = cache->sp_offset - offset;
}
else if (IS_MOV_ARG_TO_REG (inst))
- continue;
+ continue;
else
break;
}
break;
}
-#if 0 /* This used to just stop when it found an instruction that
- was not considered part of the prologue. Now, we just
- keep going looking for likely instructions. */
+#if 0 /* This used to just stop when it found an instruction that
+ was not considered part of the prologue. Now, we just
+ keep going looking for likely instructions. */
else
break;
#endif
@@ -574,7 +566,7 @@ sh_use_struct_convention (int gcc_p, str
int len = TYPE_LENGTH (type);
int nelem = TYPE_NFIELDS (type);
return ((len != 1 && len != 2 && len != 4 && len != 8) || nelem != 1) &&
- (len != 8 || TYPE_LENGTH (TYPE_FIELD_TYPE (type, 0)) != 4);
+ (len != 8 || TYPE_LENGTH (TYPE_FIELD_TYPE (type, 0)) != 4);
}
/* Extract from an array REGBUF containing the (raw) register state
@@ -647,102 +639,184 @@ sh_frame_align (struct gdbarch *ignore,
not displace any of the other arguments passed in via registers R4
to R7. */
+/* Helper function to justify value in register according to endianess. */
+static char *
+sh_justify_value_in_reg (struct value *val, int len)
+{
+ static char valbuf[4];
+
+ memset (valbuf, 0, sizeof (valbuf));
+ if (len < 4)
+ {
+ /* value gets right-justified in the register or stack word */
+ if (TARGET_BYTE_ORDER == BFD_ENDIAN_BIG)
+ memcpy (valbuf + (4 - len), (char *) VALUE_CONTENTS (val), len);
+ else
+ memcpy (valbuf, (char *) VALUE_CONTENTS (val), len);
+ return valbuf;
+ }
+ return (char *) VALUE_CONTENTS (val);
+}
+
+/* Helper function to eval number of bytes to allocate on stack. */
+static CORE_ADDR
+sh_stack_allocsize (int nargs, struct value **args)
+{
+ int stack_alloc = 0;
+ while (nargs-- > 0)
+ stack_alloc += ((TYPE_LENGTH (VALUE_TYPE (args[nargs])) + 3) & ~3);
+ return stack_alloc;
+}
+
+/* Helper functions for getting the float arguments right. Registers usage
+ depends on the ABI and the endianess. The comments should enlighten how
+ it's intended to work. */
+
+/* This array stores which of the float arg registers are already in use. */
+static int flt_argreg_array[FLOAT_ARGLAST_REGNUM - FLOAT_ARG0_REGNUM + 1];
+
+/* This function just resets the above array to "no reg used so far". */
+static void
+sh_init_flt_argreg (void)
+{
+ memset (flt_argreg_array, 0, sizeof flt_argreg_array);
+}
+
+/* This function returns the next register to use for float arg passing.
+ It returns either a valid value between FLOAT_ARG0_REGNUM and
+ FLOAT_ARGLAST_REGNUM if a register is available, otherwise it returns
+ FLOAT_ARGLAST_REGNUM + 1 to indicate that no register is available.
+
+ Note that register number 0 in flt_argreg_array corresponds with the
+ real float register fr4. In contrast to FLOAT_ARG0_REGNUM (value is
+ 29) the parity of the register number is preserved, which is important
+ for the double register passing test (see the "argreg & 1" test below). */
+static int
+sh_next_flt_argreg (int len)
+{
+ int argreg;
+
+ /* First search for the next free register. */
+ for (argreg = 0; argreg <= FLOAT_ARGLAST_REGNUM - FLOAT_ARG0_REGNUM;
+ ++argreg)
+ if (!flt_argreg_array[argreg])
+ break;
+
+ /* No register left? */
+ if (argreg > FLOAT_ARGLAST_REGNUM - FLOAT_ARG0_REGNUM)
+ return FLOAT_ARGLAST_REGNUM + 1;
+
+ if (len == 8)
+ {
+ /* Doubles are always starting in a even register number. */
+ if (argreg & 1)
+ {
+ flt_argreg_array[argreg] = 1;
+
+ ++argreg;
+
+ /* No register left? */
+ if (argreg > FLOAT_ARGLAST_REGNUM - FLOAT_ARG0_REGNUM)
+ return FLOAT_ARGLAST_REGNUM + 1;
+ }
+ /* Also mark the next register as used. */
+ flt_argreg_array[argreg + 1] = 1;
+ }
+ else if (TARGET_BYTE_ORDER == BFD_ENDIAN_LITTLE)
+ {
+ /* In little endian, gcc passes floats like this: f5, f4, f7, f6, ... */
+ if (!flt_argreg_array[argreg + 1])
+ ++argreg;
+ }
+ flt_argreg_array[argreg] = 1;
+ return FLOAT_ARG0_REGNUM + argreg;
+}
+
static CORE_ADDR
-sh_push_dummy_call_fpu (struct gdbarch *gdbarch,
+sh_push_dummy_call_fpu (struct gdbarch *gdbarch,
CORE_ADDR func_addr,
- struct regcache *regcache,
+ struct regcache *regcache,
CORE_ADDR bp_addr, int nargs,
- struct value **args,
+ struct value **args,
CORE_ADDR sp, int struct_return,
CORE_ADDR struct_addr)
{
- int stack_offset, stack_alloc;
- int argreg, flt_argreg;
+ int stack_offset = 0;
+ int argreg = ARG0_REGNUM;
+ int flt_argreg;
int argnum;
struct type *type;
CORE_ADDR regval;
char *val;
- char valbuf[4];
- int len;
- int odd_sized_struct;
+ int len, reg_size;
+ int pass_on_stack;
/* first force sp to a 4-byte alignment */
sp = sh_frame_align (gdbarch, sp);
+ /* The "struct return pointer" pseudo-argument has its own dedicated
+ register */
if (struct_return)
regcache_cooked_write_unsigned (regcache,
- STRUCT_RETURN_REGNUM,
- struct_addr);
+ STRUCT_RETURN_REGNUM, struct_addr);
- /* Now make sure there's space on the stack */
- for (argnum = 0, stack_alloc = 0; argnum < nargs; argnum++)
- stack_alloc += ((TYPE_LENGTH (VALUE_TYPE (args[argnum])) + 3) & ~3);
- sp -= stack_alloc; /* make room on stack for args */
+ /* make room on stack for args */
+ sp -= sh_stack_allocsize (nargs, args);
+
+ /* Initialize float argument mechanism. */
+ sh_init_flt_argreg ();
/* Now load as many as possible of the first arguments into
registers, and push the rest onto the stack. There are 16 bytes
in four registers available. Loop thru args from first to last. */
-
- argreg = ARG0_REGNUM;
- flt_argreg = FLOAT_ARG0_REGNUM;
- for (argnum = 0, stack_offset = 0; argnum < nargs; argnum++)
+ for (argnum = 0; argnum < nargs; argnum++)
{
type = VALUE_TYPE (args[argnum]);
len = TYPE_LENGTH (type);
- memset (valbuf, 0, sizeof (valbuf));
- if (len < 4)
- {
- /* value gets right-justified in the register or stack word */
- if (TARGET_BYTE_ORDER == BFD_ENDIAN_BIG)
- memcpy (valbuf + (4 - len),
- (char *) VALUE_CONTENTS (args[argnum]), len);
- else
- memcpy (valbuf, (char *) VALUE_CONTENTS (args[argnum]), len);
- val = valbuf;
- }
- else
- val = (char *) VALUE_CONTENTS (args[argnum]);
+ val = sh_justify_value_in_reg (args[argnum], len);
+
+ /* Some decisions have to be made how various types are handled.
+ This also differs in different ABIs. */
+ pass_on_stack = 0;
+ if (len > 16)
+ pass_on_stack = 1; /* Types bigger than 16 bytes are passed on stack. */
+
+ /* Find out the next register to use for a floating point value. */
+ if (TYPE_CODE (type) == TYPE_CODE_FLT)
+ flt_argreg = sh_next_flt_argreg (len);
- if (len > 4 && (len & 3) != 0)
- odd_sized_struct = 1; /* Such structs go entirely on stack. */
- else if (len > 16)
- odd_sized_struct = 1; /* So do aggregates bigger than 4 words. */
- else
- odd_sized_struct = 0;
while (len > 0)
{
- if ((TYPE_CODE (type) == TYPE_CODE_FLT
- && flt_argreg > FLOAT_ARGLAST_REGNUM)
- || argreg > ARGLAST_REGNUM
- || odd_sized_struct)
- {
- /* must go on the stack */
- write_memory (sp + stack_offset, val, 4);
- stack_offset += 4;
+ if ((TYPE_CODE (type) == TYPE_CODE_FLT
+ && flt_argreg > FLOAT_ARGLAST_REGNUM)
+ || argreg > ARGLAST_REGNUM || pass_on_stack)
+ {
+ /* The remainder of the data goes entirely on the stack,
+ 4-byte aligned. */
+ reg_size = (len + 3) & ~3;
+ write_memory (sp + stack_offset, val, reg_size);
+ stack_offset += reg_size;
}
- /* NOTE WELL!!!!! This is not an "else if" clause!!!
- That's because some *&^%$ things get passed on the stack
- AND in the registers! */
- if (TYPE_CODE (type) == TYPE_CODE_FLT &&
- flt_argreg > 0 && flt_argreg <= FLOAT_ARGLAST_REGNUM)
+ else if (TYPE_CODE (type) == TYPE_CODE_FLT
+ && flt_argreg <= FLOAT_ARGLAST_REGNUM)
{
- /* Argument goes in a single-precision fp reg. */
- regval = extract_unsigned_integer (val, register_size (gdbarch,
- argreg));
+ /* Argument goes in a float argument register. */
+ reg_size = register_size (gdbarch, flt_argreg);
+ regval = extract_unsigned_integer (val, reg_size);
regcache_cooked_write_unsigned (regcache, flt_argreg++, regval);
}
else if (argreg <= ARGLAST_REGNUM)
- {
+ {
/* there's room in a register */
- regval = extract_unsigned_integer (val, register_size (gdbarch,
- argreg));
+ reg_size = register_size (gdbarch, argreg);
+ regval = extract_unsigned_integer (val, reg_size);
regcache_cooked_write_unsigned (regcache, argreg++, regval);
}
- /* Store the value 4 bytes at a time. This means that things
- larger than 4 bytes may go partly in registers and partly
+ /* Store the value reg_size bytes at a time. This means that things
+ larger than reg_size bytes may go partly in registers and partly
on the stack. */
- len -= register_size (gdbarch, argreg);
- val += register_size (gdbarch, argreg);
+ len -= reg_size;
+ val += reg_size;
}
}
@@ -756,88 +830,65 @@ sh_push_dummy_call_fpu (struct gdbarch *
}
static CORE_ADDR
-sh_push_dummy_call_nofpu (struct gdbarch *gdbarch,
+sh_push_dummy_call_nofpu (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,
+ struct regcache *regcache,
+ CORE_ADDR bp_addr,
+ int nargs, struct value **args,
+ CORE_ADDR sp, int struct_return,
CORE_ADDR struct_addr)
{
- int stack_offset, stack_alloc;
- int argreg;
+ int stack_offset = 0;
+ int argreg = ARG0_REGNUM;
int argnum;
struct type *type;
CORE_ADDR regval;
char *val;
- char valbuf[4];
- int len;
- int odd_sized_struct;
+ int len, reg_size;
/* first force sp to a 4-byte alignment */
sp = sh_frame_align (gdbarch, sp);
+ /* The "struct return pointer" pseudo-argument has its own dedicated
+ register */
if (struct_return)
regcache_cooked_write_unsigned (regcache,
- STRUCT_RETURN_REGNUM,
- struct_addr);
+ STRUCT_RETURN_REGNUM, struct_addr);
- /* Now make sure there's space on the stack */
- for (argnum = 0, stack_alloc = 0; argnum < nargs; argnum++)
- stack_alloc += ((TYPE_LENGTH (VALUE_TYPE (args[argnum])) + 3) & ~3);
- sp -= stack_alloc; /* make room on stack for args */
+ /* make room on stack for args */
+ sp -= sh_stack_allocsize (nargs, args);
/* Now load as many as possible of the first arguments into
registers, and push the rest onto the stack. There are 16 bytes
in four registers available. Loop thru args from first to last. */
-
- argreg = ARG0_REGNUM;
- for (argnum = 0, stack_offset = 0; argnum < nargs; argnum++)
+ for (argnum = 0; argnum < nargs; argnum++)
{
type = VALUE_TYPE (args[argnum]);
len = TYPE_LENGTH (type);
- memset (valbuf, 0, sizeof (valbuf));
- if (len < 4)
- {
- /* value gets right-justified in the register or stack word */
- if (TARGET_BYTE_ORDER == BFD_ENDIAN_BIG)
- memcpy (valbuf + (4 - len),
- (char *) VALUE_CONTENTS (args[argnum]), len);
- else
- memcpy (valbuf, (char *) VALUE_CONTENTS (args[argnum]), len);
- val = valbuf;
- }
- else
- val = (char *) VALUE_CONTENTS (args[argnum]);
+ val = sh_justify_value_in_reg (args[argnum], len);
- if (len > 4 && (len & 3) != 0)
- odd_sized_struct = 1; /* such structs go entirely on stack */
- else
- odd_sized_struct = 0;
while (len > 0)
{
- if (argreg > ARGLAST_REGNUM
- || odd_sized_struct)
- {
- /* must go on the stack */
- write_memory (sp + stack_offset, val, 4);
- stack_offset += 4;
+ if (argreg > ARGLAST_REGNUM)
+ {
+ /* The remainder of the data goes entirely on the stack,
+ 4-byte aligned. */
+ reg_size = (len + 3) & ~3;
+ write_memory (sp + stack_offset, val, reg_size);
+ stack_offset += reg_size;
}
- /* NOTE WELL!!!!! This is not an "else if" clause!!!
- That's because some *&^%$ things get passed on the stack
- AND in the registers! */
- if (argreg <= ARGLAST_REGNUM)
- {
+ else if (argreg <= ARGLAST_REGNUM)
+ {
/* there's room in a register */
- regval = extract_unsigned_integer (val, register_size (gdbarch,
- argreg));
+ reg_size = register_size (gdbarch, argreg);
+ regval = extract_unsigned_integer (val, reg_size);
regcache_cooked_write_unsigned (regcache, argreg++, regval);
}
- /* Store the value 4 bytes at a time. This means that things
- larger than 4 bytes may go partly in registers and partly
+ /* Store the value reg_size bytes at a time. This means that things
+ larger than reg_size bytes may go partly in registers and partly
on the stack. */
- len -= register_size (gdbarch, argreg);
- val += register_size (gdbarch, argreg);
+ len -= reg_size;
+ val += reg_size;
}
}
@@ -861,7 +912,7 @@ sh_default_extract_return_value (struct
int len = TYPE_LENGTH (type);
int return_register = R0_REGNUM;
int offset;
-
+
if (len <= 4)
{
ULONGEST c;
@@ -873,7 +924,7 @@ sh_default_extract_return_value (struct
{
int i, regnum = R0_REGNUM;
for (i = 0; i < len; i += 4)
- regcache_raw_read (regcache, regnum++, (char *)valbuf + i);
+ regcache_raw_read (regcache, regnum++, (char *) valbuf + i);
}
else
error ("bad size for return value");
@@ -888,7 +939,7 @@ sh3e_sh4_extract_return_value (struct ty
int len = TYPE_LENGTH (type);
int i, regnum = FP0_REGNUM;
for (i = 0; i < len; i += 4)
- regcache_raw_read (regcache, regnum++, (char *)valbuf + i);
+ regcache_raw_read (regcache, regnum++, (char *) valbuf + i);
}
else
sh_default_extract_return_value (type, regcache, valbuf);
@@ -916,7 +967,7 @@ sh_default_store_return_value (struct ty
{
int i, regnum = R0_REGNUM;
for (i = 0; i < len; i += 4)
- regcache_raw_write (regcache, regnum++, (char *)valbuf + i);
+ regcache_raw_write (regcache, regnum++, (char *) valbuf + i);
}
}
@@ -924,12 +975,12 @@ static void
sh3e_sh4_store_return_value (struct type *type, struct regcache *regcache,
const void *valbuf)
{
- if (TYPE_CODE (type) == TYPE_CODE_FLT)
+ if (TYPE_CODE (type) == TYPE_CODE_FLT)
{
int len = TYPE_LENGTH (type);
int i, regnum = FP0_REGNUM;
for (i = 0; i < len; i += 4)
- regcache_raw_write (regcache, regnum++, (char *)valbuf + i);
+ regcache_raw_write (regcache, regnum++, (char *) valbuf + i);
}
else
sh_default_store_return_value (type, regcache, valbuf);
@@ -951,24 +1002,17 @@ sh_generic_show_regs (void)
(long) read_register (GBR_REGNUM),
(long) read_register (VBR_REGNUM));
- printf_filtered ("\nR0-R7 %08lx %08lx %08lx %08lx %08lx %08lx %08lx %08lx\n",
- (long) read_register (0),
- (long) read_register (1),
- (long) read_register (2),
- (long) read_register (3),
- (long) read_register (4),
- (long) read_register (5),
- (long) read_register (6),
- (long) read_register (7));
+ printf_filtered
+ ("\nR0-R7 %08lx %08lx %08lx %08lx %08lx %08lx %08lx %08lx\n",
+ (long) read_register (0), (long) read_register (1),
+ (long) read_register (2), (long) read_register (3),
+ (long) read_register (4), (long) read_register (5),
+ (long) read_register (6), (long) read_register (7));
printf_filtered ("R8-R15 %08lx %08lx %08lx %08lx %08lx %08lx %08lx %08lx\n",
- (long) read_register (8),
- (long) read_register (9),
- (long) read_register (10),
- (long) read_register (11),
- (long) read_register (12),
- (long) read_register (13),
- (long) read_register (14),
- (long) read_register (15));
+ (long) read_register (8), (long) read_register (9),
+ (long) read_register (10), (long) read_register (11),
+ (long) read_register (12), (long) read_register (13),
+ (long) read_register (14), (long) read_register (15));
}
static void
@@ -985,27 +1029,20 @@ sh3_show_regs (void)
(long) read_register (GBR_REGNUM),
(long) read_register (VBR_REGNUM));
printf_filtered (" SSR=%08lx SPC=%08lx",
- (long) read_register (SSR_REGNUM),
+ (long) read_register (SSR_REGNUM),
(long) read_register (SPC_REGNUM));
- printf_filtered ("\nR0-R7 %08lx %08lx %08lx %08lx %08lx %08lx %08lx %08lx\n",
- (long) read_register (0),
- (long) read_register (1),
- (long) read_register (2),
- (long) read_register (3),
- (long) read_register (4),
- (long) read_register (5),
- (long) read_register (6),
- (long) read_register (7));
+ printf_filtered
+ ("\nR0-R7 %08lx %08lx %08lx %08lx %08lx %08lx %08lx %08lx\n",
+ (long) read_register (0), (long) read_register (1),
+ (long) read_register (2), (long) read_register (3),
+ (long) read_register (4), (long) read_register (5),
+ (long) read_register (6), (long) read_register (7));
printf_filtered ("R8-R15 %08lx %08lx %08lx %08lx %08lx %08lx %08lx %08lx\n",
- (long) read_register (8),
- (long) read_register (9),
- (long) read_register (10),
- (long) read_register (11),
- (long) read_register (12),
- (long) read_register (13),
- (long) read_register (14),
- (long) read_register (15));
+ (long) read_register (8), (long) read_register (9),
+ (long) read_register (10), (long) read_register (11),
+ (long) read_register (12), (long) read_register (13),
+ (long) read_register (14), (long) read_register (15));
}
@@ -1023,46 +1060,23 @@ sh2e_show_regs (void)
(long) read_register (GBR_REGNUM),
(long) read_register (VBR_REGNUM));
printf_filtered (" FPUL=%08lx FPSCR=%08lx",
- (long) read_register (FPUL_REGNUM),
- (long) read_register (FPSCR_REGNUM));
+ (long) read_register (FPUL_REGNUM),
+ (long) read_register (FPSCR_REGNUM));
- printf_filtered ("\nR0-R7 %08lx %08lx %08lx %08lx %08lx %08lx %08lx %08lx\n",
- (long) read_register (0),
- (long) read_register (1),
- (long) read_register (2),
- (long) read_register (3),
- (long) read_register (4),
- (long) read_register (5),
- (long) read_register (6),
- (long) read_register (7));
+ printf_filtered
+ ("\nR0-R7 %08lx %08lx %08lx %08lx %08lx %08lx %08lx %08lx\n",
+ (long) read_register (0), (long) read_register (1),
+ (long) read_register (2), (long) read_register (3),
+ (long) read_register (4), (long) read_register (5),
+ (long) read_register (6), (long) read_register (7));
printf_filtered ("R8-R15 %08lx %08lx %08lx %08lx %08lx %08lx %08lx %08lx\n",
- (long) read_register (8),
- (long) read_register (9),
- (long) read_register (10),
- (long) read_register (11),
- (long) read_register (12),
- (long) read_register (13),
- (long) read_register (14),
- (long) read_register (15));
+ (long) read_register (8), (long) read_register (9),
+ (long) read_register (10), (long) read_register (11),
+ (long) read_register (12), (long) read_register (13),
+ (long) read_register (14), (long) read_register (15));
- printf_filtered (("FP0-FP7 %08lx %08lx %08lx %08lx %08lx %08lx %08lx %08lx\n"),
- (long) read_register (FP0_REGNUM + 0),
- (long) read_register (FP0_REGNUM + 1),
- (long) read_register (FP0_REGNUM + 2),
- (long) read_register (FP0_REGNUM + 3),
- (long) read_register (FP0_REGNUM + 4),
- (long) read_register (FP0_REGNUM + 5),
- (long) read_register (FP0_REGNUM + 6),
- (long) read_register (FP0_REGNUM + 7));
- printf_filtered (("FP8-FP15 %08lx %08lx %08lx %08lx %08lx %08lx %08lx %08lx\n"),
- (long) read_register (FP0_REGNUM + 8),
- (long) read_register (FP0_REGNUM + 9),
- (long) read_register (FP0_REGNUM + 10),
- (long) read_register (FP0_REGNUM + 11),
- (long) read_register (FP0_REGNUM + 12),
- (long) read_register (FP0_REGNUM + 13),
- (long) read_register (FP0_REGNUM + 14),
- (long) read_register (FP0_REGNUM + 15));
+ printf_filtered (("FP0-FP7 %08lx %08lx %08lx %08lx %08lx %08lx %08lx %08lx\n"), (long) read_register (FP0_REGNUM + 0), (long) read_register (FP0_REGNUM + 1), (long) read_register (FP0_REGNUM + 2), (long) read_register (FP0_REGNUM + 3), (long) read_register (FP0_REGNUM + 4), (long) read_register (FP0_REGNUM + 5), (long) read_register (FP0_REGNUM + 6), (long) read_register (FP0_REGNUM + 7));
+ printf_filtered (("FP8-FP15 %08lx %08lx %08lx %08lx %08lx %08lx %08lx %08lx\n"), (long) read_register (FP0_REGNUM + 8), (long) read_register (FP0_REGNUM + 9), (long) read_register (FP0_REGNUM + 10), (long) read_register (FP0_REGNUM + 11), (long) read_register (FP0_REGNUM + 12), (long) read_register (FP0_REGNUM + 13), (long) read_register (FP0_REGNUM + 14), (long) read_register (FP0_REGNUM + 15));
}
static void
@@ -1085,43 +1099,20 @@ sh3e_show_regs (void)
(long) read_register (FPUL_REGNUM),
(long) read_register (FPSCR_REGNUM));
- printf_filtered ("\nR0-R7 %08lx %08lx %08lx %08lx %08lx %08lx %08lx %08lx\n",
- (long) read_register (0),
- (long) read_register (1),
- (long) read_register (2),
- (long) read_register (3),
- (long) read_register (4),
- (long) read_register (5),
- (long) read_register (6),
- (long) read_register (7));
+ printf_filtered
+ ("\nR0-R7 %08lx %08lx %08lx %08lx %08lx %08lx %08lx %08lx\n",
+ (long) read_register (0), (long) read_register (1),
+ (long) read_register (2), (long) read_register (3),
+ (long) read_register (4), (long) read_register (5),
+ (long) read_register (6), (long) read_register (7));
printf_filtered ("R8-R15 %08lx %08lx %08lx %08lx %08lx %08lx %08lx %08lx\n",
- (long) read_register (8),
- (long) read_register (9),
- (long) read_register (10),
- (long) read_register (11),
- (long) read_register (12),
- (long) read_register (13),
- (long) read_register (14),
- (long) read_register (15));
+ (long) read_register (8), (long) read_register (9),
+ (long) read_register (10), (long) read_register (11),
+ (long) read_register (12), (long) read_register (13),
+ (long) read_register (14), (long) read_register (15));
- printf_filtered (("FP0-FP7 %08lx %08lx %08lx %08lx %08lx %08lx %08lx %08lx\n"),
- (long) read_register (FP0_REGNUM + 0),
- (long) read_register (FP0_REGNUM + 1),
- (long) read_register (FP0_REGNUM + 2),
- (long) read_register (FP0_REGNUM + 3),
- (long) read_register (FP0_REGNUM + 4),
- (long) read_register (FP0_REGNUM + 5),
- (long) read_register (FP0_REGNUM + 6),
- (long) read_register (FP0_REGNUM + 7));
- printf_filtered (("FP8-FP15 %08lx %08lx %08lx %08lx %08lx %08lx %08lx %08lx\n"),
- (long) read_register (FP0_REGNUM + 8),
- (long) read_register (FP0_REGNUM + 9),
- (long) read_register (FP0_REGNUM + 10),
- (long) read_register (FP0_REGNUM + 11),
- (long) read_register (FP0_REGNUM + 12),
- (long) read_register (FP0_REGNUM + 13),
- (long) read_register (FP0_REGNUM + 14),
- (long) read_register (FP0_REGNUM + 15));
+ printf_filtered (("FP0-FP7 %08lx %08lx %08lx %08lx %08lx %08lx %08lx %08lx\n"), (long) read_register (FP0_REGNUM + 0), (long) read_register (FP0_REGNUM + 1), (long) read_register (FP0_REGNUM + 2), (long) read_register (FP0_REGNUM + 3), (long) read_register (FP0_REGNUM + 4), (long) read_register (FP0_REGNUM + 5), (long) read_register (FP0_REGNUM + 6), (long) read_register (FP0_REGNUM + 7));
+ printf_filtered (("FP8-FP15 %08lx %08lx %08lx %08lx %08lx %08lx %08lx %08lx\n"), (long) read_register (FP0_REGNUM + 8), (long) read_register (FP0_REGNUM + 9), (long) read_register (FP0_REGNUM + 10), (long) read_register (FP0_REGNUM + 11), (long) read_register (FP0_REGNUM + 12), (long) read_register (FP0_REGNUM + 13), (long) read_register (FP0_REGNUM + 14), (long) read_register (FP0_REGNUM + 15));
}
static void
@@ -1142,36 +1133,26 @@ sh3_dsp_show_regs (void)
(long) read_register (SSR_REGNUM),
(long) read_register (SPC_REGNUM));
- printf_filtered (" DSR=%08lx",
- (long) read_register (DSR_REGNUM));
+ printf_filtered (" DSR=%08lx", (long) read_register (DSR_REGNUM));
- printf_filtered ("\nR0-R7 %08lx %08lx %08lx %08lx %08lx %08lx %08lx %08lx\n",
- (long) read_register (0),
- (long) read_register (1),
- (long) read_register (2),
- (long) read_register (3),
- (long) read_register (4),
- (long) read_register (5),
- (long) read_register (6),
- (long) read_register (7));
+ printf_filtered
+ ("\nR0-R7 %08lx %08lx %08lx %08lx %08lx %08lx %08lx %08lx\n",
+ (long) read_register (0), (long) read_register (1),
+ (long) read_register (2), (long) read_register (3),
+ (long) read_register (4), (long) read_register (5),
+ (long) read_register (6), (long) read_register (7));
printf_filtered ("R8-R15 %08lx %08lx %08lx %08lx %08lx %08lx %08lx %08lx\n",
- (long) read_register (8),
- (long) read_register (9),
- (long) read_register (10),
- (long) read_register (11),
- (long) read_register (12),
- (long) read_register (13),
- (long) read_register (14),
- (long) read_register (15));
-
- printf_filtered ("A0G=%02lx A0=%08lx M0=%08lx X0=%08lx Y0=%08lx RS=%08lx MOD=%08lx\n",
- (long) read_register (A0G_REGNUM) & 0xff,
- (long) read_register (A0_REGNUM),
- (long) read_register (M0_REGNUM),
- (long) read_register (X0_REGNUM),
- (long) read_register (Y0_REGNUM),
- (long) read_register (RS_REGNUM),
- (long) read_register (MOD_REGNUM));
+ (long) read_register (8), (long) read_register (9),
+ (long) read_register (10), (long) read_register (11),
+ (long) read_register (12), (long) read_register (13),
+ (long) read_register (14), (long) read_register (15));
+
+ printf_filtered
+ ("A0G=%02lx A0=%08lx M0=%08lx X0=%08lx Y0=%08lx RS=%08lx MOD=%08lx\n",
+ (long) read_register (A0G_REGNUM) & 0xff,
+ (long) read_register (A0_REGNUM), (long) read_register (M0_REGNUM),
+ (long) read_register (X0_REGNUM), (long) read_register (Y0_REGNUM),
+ (long) read_register (RS_REGNUM), (long) read_register (MOD_REGNUM));
printf_filtered ("A1G=%02lx A1=%08lx M1=%08lx X1=%08lx Y1=%08lx RE=%08lx\n",
(long) read_register (A1G_REGNUM) & 0xff,
(long) read_register (A1_REGNUM),
@@ -1202,28 +1183,22 @@ sh4_show_regs (void)
(long) read_register (FPUL_REGNUM),
(long) read_register (FPSCR_REGNUM));
- printf_filtered ("\nR0-R7 %08lx %08lx %08lx %08lx %08lx %08lx %08lx %08lx\n",
- (long) read_register (0),
- (long) read_register (1),
- (long) read_register (2),
- (long) read_register (3),
- (long) read_register (4),
- (long) read_register (5),
- (long) read_register (6),
- (long) read_register (7));
+ printf_filtered
+ ("\nR0-R7 %08lx %08lx %08lx %08lx %08lx %08lx %08lx %08lx\n",
+ (long) read_register (0), (long) read_register (1),
+ (long) read_register (2), (long) read_register (3),
+ (long) read_register (4), (long) read_register (5),
+ (long) read_register (6), (long) read_register (7));
printf_filtered ("R8-R15 %08lx %08lx %08lx %08lx %08lx %08lx %08lx %08lx\n",
- (long) read_register (8),
- (long) read_register (9),
- (long) read_register (10),
- (long) read_register (11),
- (long) read_register (12),
- (long) read_register (13),
- (long) read_register (14),
- (long) read_register (15));
+ (long) read_register (8), (long) read_register (9),
+ (long) read_register (10), (long) read_register (11),
+ (long) read_register (12), (long) read_register (13),
+ (long) read_register (14), (long) read_register (15));
printf_filtered ((pr
? "DR0-DR6 %08lx%08lx %08lx%08lx %08lx%08lx %08lx%08lx\n"
- : "FP0-FP7 %08lx %08lx %08lx %08lx %08lx %08lx %08lx %08lx\n"),
+ :
+ "FP0-FP7 %08lx %08lx %08lx %08lx %08lx %08lx %08lx %08lx\n"),
(long) read_register (FP0_REGNUM + 0),
(long) read_register (FP0_REGNUM + 1),
(long) read_register (FP0_REGNUM + 2),
@@ -1232,9 +1207,9 @@ sh4_show_regs (void)
(long) read_register (FP0_REGNUM + 5),
(long) read_register (FP0_REGNUM + 6),
(long) read_register (FP0_REGNUM + 7));
- printf_filtered ((pr
- ? "DR8-DR14 %08lx%08lx %08lx%08lx %08lx%08lx %08lx%08lx\n"
- : "FP8-FP15 %08lx %08lx %08lx %08lx %08lx %08lx %08lx %08lx\n"),
+ printf_filtered ((pr ?
+ "DR8-DR14 %08lx%08lx %08lx%08lx %08lx%08lx %08lx%08lx\n" :
+ "FP8-FP15 %08lx %08lx %08lx %08lx %08lx %08lx %08lx %08lx\n"),
(long) read_register (FP0_REGNUM + 8),
(long) read_register (FP0_REGNUM + 9),
(long) read_register (FP0_REGNUM + 10),
@@ -1259,36 +1234,26 @@ sh_dsp_show_regs (void)
(long) read_register (GBR_REGNUM),
(long) read_register (VBR_REGNUM));
- printf_filtered (" DSR=%08lx",
- (long) read_register (DSR_REGNUM));
+ printf_filtered (" DSR=%08lx", (long) read_register (DSR_REGNUM));
- printf_filtered ("\nR0-R7 %08lx %08lx %08lx %08lx %08lx %08lx %08lx %08lx\n",
- (long) read_register (0),
- (long) read_register (1),
- (long) read_register (2),
- (long) read_register (3),
- (long) read_register (4),
- (long) read_register (5),
- (long) read_register (6),
- (long) read_register (7));
+ printf_filtered
+ ("\nR0-R7 %08lx %08lx %08lx %08lx %08lx %08lx %08lx %08lx\n",
+ (long) read_register (0), (long) read_register (1),
+ (long) read_register (2), (long) read_register (3),
+ (long) read_register (4), (long) read_register (5),
+ (long) read_register (6), (long) read_register (7));
printf_filtered ("R8-R15 %08lx %08lx %08lx %08lx %08lx %08lx %08lx %08lx\n",
- (long) read_register (8),
- (long) read_register (9),
- (long) read_register (10),
- (long) read_register (11),
- (long) read_register (12),
- (long) read_register (13),
- (long) read_register (14),
- (long) read_register (15));
-
- printf_filtered ("A0G=%02lx A0=%08lx M0=%08lx X0=%08lx Y0=%08lx RS=%08lx MOD=%08lx\n",
- (long) read_register (A0G_REGNUM) & 0xff,
- (long) read_register (A0_REGNUM),
- (long) read_register (M0_REGNUM),
- (long) read_register (X0_REGNUM),
- (long) read_register (Y0_REGNUM),
- (long) read_register (RS_REGNUM),
- (long) read_register (MOD_REGNUM));
+ (long) read_register (8), (long) read_register (9),
+ (long) read_register (10), (long) read_register (11),
+ (long) read_register (12), (long) read_register (13),
+ (long) read_register (14), (long) read_register (15));
+
+ printf_filtered
+ ("A0G=%02lx A0=%08lx M0=%08lx X0=%08lx Y0=%08lx RS=%08lx MOD=%08lx\n",
+ (long) read_register (A0G_REGNUM) & 0xff,
+ (long) read_register (A0_REGNUM), (long) read_register (M0_REGNUM),
+ (long) read_register (X0_REGNUM), (long) read_register (Y0_REGNUM),
+ (long) read_register (RS_REGNUM), (long) read_register (MOD_REGNUM));
printf_filtered ("A1G=%02lx A1=%08lx M1=%08lx X1=%08lx Y1=%08lx RE=%08lx\n",
(long) read_register (A1G_REGNUM) & 0xff,
(long) read_register (A1_REGNUM),
@@ -1302,7 +1267,7 @@ static void
sh_show_regs_command (char *args, int from_tty)
{
if (sh_show_regs)
- (*sh_show_regs)();
+ (*sh_show_regs) ();
}
/* Return the GDB type object for the "standard" data type
@@ -1311,8 +1276,7 @@ static struct type *
sh_sh3e_register_type (struct gdbarch *gdbarch, int reg_nr)
{
if ((reg_nr >= FP0_REGNUM
- && (reg_nr <= FP_LAST_REGNUM))
- || (reg_nr == FPUL_REGNUM))
+ && (reg_nr <= FP_LAST_REGNUM)) || (reg_nr == FPUL_REGNUM))
return builtin_type_float;
else
return builtin_type_int;
@@ -1331,14 +1295,11 @@ static struct type *
sh_sh4_register_type (struct gdbarch *gdbarch, int reg_nr)
{
if ((reg_nr >= FP0_REGNUM
- && (reg_nr <= FP_LAST_REGNUM))
- || (reg_nr == FPUL_REGNUM))
+ && (reg_nr <= FP_LAST_REGNUM)) || (reg_nr == FPUL_REGNUM))
return builtin_type_float;
- else if (reg_nr >= DR0_REGNUM
- && reg_nr <= DR_LAST_REGNUM)
+ else if (reg_nr >= DR0_REGNUM && reg_nr <= DR_LAST_REGNUM)
return builtin_type_double;
- else if (reg_nr >= FV0_REGNUM
- && reg_nr <= FV_LAST_REGNUM)
+ else if (reg_nr >= FV0_REGNUM && reg_nr <= FV_LAST_REGNUM)
return sh_sh4_build_float_register_type (3);
else
return builtin_type_int;
@@ -1378,31 +1339,32 @@ sh_default_register_type (struct gdbarch
static void
sh_sh4_register_convert_to_virtual (int regnum, struct type *type,
- char *from, char *to)
+ char *from, char *to)
{
- if (regnum >= DR0_REGNUM
- && regnum <= DR_LAST_REGNUM)
+ if (regnum >= DR0_REGNUM && regnum <= DR_LAST_REGNUM)
{
DOUBLEST val;
- floatformat_to_doublest (&floatformat_ieee_double_littlebyte_bigword, from, &val);
+ floatformat_to_doublest (&floatformat_ieee_double_littlebyte_bigword,
+ from, &val);
store_typed_floating (to, type, val);
}
else
- error ("sh_register_convert_to_virtual called with non DR register number");
+ error
+ ("sh_register_convert_to_virtual called with non DR register number");
}
static void
sh_sh4_register_convert_to_raw (struct type *type, int regnum,
const void *from, void *to)
{
- if (regnum >= DR0_REGNUM
- && regnum <= DR_LAST_REGNUM)
+ if (regnum >= DR0_REGNUM && regnum <= DR_LAST_REGNUM)
{
DOUBLEST val = extract_typed_floating (from, type);
- floatformat_from_doublest (&floatformat_ieee_double_littlebyte_bigword, &val, to);
+ floatformat_from_doublest (&floatformat_ieee_double_littlebyte_bigword,
+ &val, to);
}
else
- error("sh_register_convert_to_raw called with non DR register number");
+ error ("sh_register_convert_to_raw called with non DR register number");
}
/* For vectors of 4 floating point registers. */
@@ -1411,8 +1373,7 @@ fv_reg_base_num (int fv_regnum)
{
int fp_regnum;
- fp_regnum = FP0_REGNUM +
- (fv_regnum - FV0_REGNUM) * 4;
+ fp_regnum = FP0_REGNUM + (fv_regnum - FV0_REGNUM) * 4;
return fp_regnum;
}
@@ -1422,8 +1383,7 @@ dr_reg_base_num (int dr_regnum)
{
int fp_regnum;
- fp_regnum = FP0_REGNUM +
- (dr_regnum - DR0_REGNUM) * 2;
+ fp_regnum = FP0_REGNUM + (dr_regnum - DR0_REGNUM) * 2;
return fp_regnum;
}
@@ -1434,32 +1394,33 @@ sh_pseudo_register_read (struct gdbarch
int base_regnum, portion;
char temp_buffer[MAX_REGISTER_SIZE];
- if (reg_nr >= DR0_REGNUM
- && reg_nr <= DR_LAST_REGNUM)
+ if (reg_nr >= DR0_REGNUM && reg_nr <= DR_LAST_REGNUM)
{
base_regnum = dr_reg_base_num (reg_nr);
- /* Build the value in the provided buffer. */
+ /* Build the value in the provided buffer. */
/* Read the real regs for which this one is an alias. */
for (portion = 0; portion < 2; portion++)
- regcache_raw_read (regcache, base_regnum + portion,
+ regcache_raw_read (regcache, base_regnum + portion,
(temp_buffer
- + register_size (gdbarch, base_regnum) * portion));
+ + register_size (gdbarch,
+ base_regnum) * portion));
/* We must pay attention to the endiannes. */
sh_sh4_register_convert_to_virtual (reg_nr,
- gdbarch_register_type (gdbarch, reg_nr),
+ gdbarch_register_type (gdbarch,
+ reg_nr),
temp_buffer, buffer);
}
- else if (reg_nr >= FV0_REGNUM
- && reg_nr <= FV_LAST_REGNUM)
+ else if (reg_nr >= FV0_REGNUM && reg_nr <= FV_LAST_REGNUM)
{
base_regnum = fv_reg_base_num (reg_nr);
/* Read the real regs for which this one is an alias. */
for (portion = 0; portion < 4; portion++)
- regcache_raw_read (regcache, base_regnum + portion,
+ regcache_raw_read (regcache, base_regnum + portion,
((char *) buffer
- + register_size (gdbarch, base_regnum) * portion));
+ + register_size (gdbarch,
+ base_regnum) * portion));
}
}
@@ -1470,23 +1431,22 @@ sh_pseudo_register_write (struct gdbarch
int base_regnum, portion;
char temp_buffer[MAX_REGISTER_SIZE];
- if (reg_nr >= DR0_REGNUM
- && reg_nr <= DR_LAST_REGNUM)
+ if (reg_nr >= DR0_REGNUM && reg_nr <= DR_LAST_REGNUM)
{
base_regnum = dr_reg_base_num (reg_nr);
/* We must pay attention to the endiannes. */
- sh_sh4_register_convert_to_raw (gdbarch_register_type (gdbarch, reg_nr), reg_nr,
- buffer, temp_buffer);
+ sh_sh4_register_convert_to_raw (gdbarch_register_type (gdbarch, reg_nr),
+ reg_nr, buffer, temp_buffer);
/* Write the real regs for which this one is an alias. */
for (portion = 0; portion < 2; portion++)
- regcache_raw_write (regcache, base_regnum + portion,
+ regcache_raw_write (regcache, base_regnum + portion,
(temp_buffer
- + register_size (gdbarch, base_regnum) * portion));
+ + register_size (gdbarch,
+ base_regnum) * portion));
}
- else if (reg_nr >= FV0_REGNUM
- && reg_nr <= FV_LAST_REGNUM)
+ else if (reg_nr >= FV0_REGNUM && reg_nr <= FV_LAST_REGNUM)
{
base_regnum = fv_reg_base_num (reg_nr);
@@ -1494,7 +1454,8 @@ sh_pseudo_register_write (struct gdbarch
for (portion = 0; portion < 4; portion++)
regcache_raw_write (regcache, base_regnum + portion,
((char *) buffer
- + register_size (gdbarch, base_regnum) * portion));
+ + register_size (gdbarch,
+ base_regnum) * portion));
}
}
@@ -1504,12 +1465,12 @@ do_fv_register_info (struct gdbarch *gdb
int fv_regnum)
{
int first_fp_reg_num = fv_reg_base_num (fv_regnum);
- fprintf_filtered (file, "fv%d\t0x%08x\t0x%08x\t0x%08x\t0x%08x\n",
- fv_regnum - FV0_REGNUM,
- (int) read_register (first_fp_reg_num),
- (int) read_register (first_fp_reg_num + 1),
- (int) read_register (first_fp_reg_num + 2),
- (int) read_register (first_fp_reg_num + 3));
+ fprintf_filtered (file, "fv%d\t0x%08x\t0x%08x\t0x%08x\t0x%08x\n",
+ fv_regnum - FV0_REGNUM,
+ (int) read_register (first_fp_reg_num),
+ (int) read_register (first_fp_reg_num + 1),
+ (int) read_register (first_fp_reg_num + 2),
+ (int) read_register (first_fp_reg_num + 3));
}
/* Double precision registers. */
@@ -1519,8 +1480,8 @@ do_dr_register_info (struct gdbarch *gdb
{
int first_fp_reg_num = dr_reg_base_num (dr_regnum);
- fprintf_filtered (file, "dr%d\t0x%08x%08x\n",
- dr_regnum - DR0_REGNUM,
+ fprintf_filtered (file, "dr%d\t0x%08x%08x\n",
+ dr_regnum - DR0_REGNUM,
(int) read_register (first_fp_reg_num),
(int) read_register (first_fp_reg_num + 1));
}
@@ -1532,11 +1493,9 @@ sh_print_pseudo_register (struct gdbarch
if (regnum < NUM_REGS || regnum >= NUM_REGS + NUM_PSEUDO_REGS)
internal_error (__FILE__, __LINE__,
"Invalid pseudo register number %d\n", regnum);
- else if (regnum >= DR0_REGNUM
- && regnum <= DR_LAST_REGNUM)
+ else if (regnum >= DR0_REGNUM && regnum <= DR_LAST_REGNUM)
do_dr_register_info (gdbarch, file, regnum);
- else if (regnum >= FV0_REGNUM
- && regnum <= FV_LAST_REGNUM)
+ else if (regnum >= FV0_REGNUM && regnum <= FV_LAST_REGNUM)
do_fv_register_info (gdbarch, file, regnum);
}
@@ -1544,7 +1503,7 @@ static void
sh_do_fp_register (struct gdbarch *gdbarch, struct ui_file *file, int regnum)
{ /* do values for FP (float) regs */
char *raw_buffer;
- double flt; /* double extracted from raw hex data */
+ double flt; /* double extracted from raw hex data */
int inv;
int j;
@@ -1555,7 +1514,7 @@ sh_do_fp_register (struct gdbarch *gdbar
if (!frame_register_read (get_selected_frame (), regnum, raw_buffer))
error ("can't read register %d (%s)", regnum, REGISTER_NAME (regnum));
- /* Get the register as a number */
+ /* Get the register as a number */
flt = unpack_double (builtin_type_float, raw_buffer, &inv);
/* Print the name and some spaces. */
@@ -1591,7 +1550,7 @@ sh_do_register (struct gdbarch *gdbarch,
/* Get the data in raw format. */
if (!frame_register_read (get_selected_frame (), regnum, raw_buffer))
fprintf_filtered (file, "*value not available*\n");
-
+
val_print (gdbarch_register_type (gdbarch, regnum), raw_buffer, 0, 0,
file, 'x', 1, 0, Val_pretty_default);
fprintf_filtered (file, "\t");
@@ -1609,7 +1568,8 @@ sh_print_register (struct gdbarch *gdbar
else if (regnum >= 0 && regnum < NUM_REGS)
{
- if (TYPE_CODE (gdbarch_register_type (gdbarch, regnum)) == TYPE_CODE_FLT)
+ if (TYPE_CODE (gdbarch_register_type (gdbarch, regnum)) ==
+ TYPE_CODE_FLT)
sh_do_fp_register (gdbarch, file, regnum); /* FP regs */
else
sh_do_register (gdbarch, file, regnum); /* All other regs */
@@ -1642,18 +1602,19 @@ sh_print_registers_info (struct gdbarch
processor, so don't display anything. */
if (REGISTER_NAME (regnum) == NULL
|| *(REGISTER_NAME (regnum)) == '\0')
- {
+ {
regnum++;
continue;
}
- if (TYPE_CODE (gdbarch_register_type (gdbarch, regnum)) == TYPE_CODE_FLT)
+ if (TYPE_CODE (gdbarch_register_type (gdbarch, regnum)) ==
+ TYPE_CODE_FLT)
{
if (fpregs)
{
/* true for "INFO ALL-REGISTERS" command */
sh_do_fp_register (gdbarch, file, regnum); /* FP regs */
- regnum ++;
+ regnum++;
}
else
regnum += (FP_LAST_REGNUM - FP0_REGNUM); /* skip FP regs */
@@ -1697,24 +1658,24 @@ sh_linux_svr4_fetch_link_map_offsets (vo
lmo.r_debug_size = 8; /* 20 not actual size but all we need */
lmo.r_map_offset = 4;
- lmo.r_map_size = 4;
+ lmo.r_map_size = 4;
lmo.link_map_size = 20; /* 552 not actual size but all we need */
lmo.l_addr_offset = 0;
- lmo.l_addr_size = 4;
+ lmo.l_addr_size = 4;
lmo.l_name_offset = 4;
- lmo.l_name_size = 4;
+ lmo.l_name_size = 4;
lmo.l_next_offset = 12;
- lmo.l_next_size = 4;
+ lmo.l_next_size = 4;
lmo.l_prev_offset = 16;
- lmo.l_prev_size = 4;
+ lmo.l_prev_size = 4;
}
- return lmp;
+ return lmp;
}
#endif /* SVR4_SHARED_LIBS */
@@ -1752,16 +1713,16 @@ sh_alloc_frame_cache (void)
/* Frameless until proven otherwise. */
cache->uses_fp = 0;
-
+
/* Saved registers. We initialize these to -1 since zero is a valid
offset (that's where fp is supposed to be stored). */
for (i = 0; i < SH_NUM_REGS; i++)
{
cache->saved_regs[i] = -1;
}
-
+
return cache;
-}
+}
static struct sh_frame_cache *
sh_frame_cache (struct frame_info *next_frame, void **this_cache)
@@ -1789,7 +1750,7 @@ sh_frame_cache (struct frame_info *next_
current_pc = frame_pc_unwind (next_frame);
if (cache->pc != 0)
sh_analyze_prologue (cache->pc, current_pc, cache);
-
+
if (!cache->uses_fp)
{
/* We didn't find a valid frame, which means that CACHE->base
@@ -1832,10 +1793,10 @@ sh_frame_prev_register (struct frame_inf
*addrp = 0;
*realnump = -1;
if (valuep)
- {
- /* Store the value. */
- store_unsigned_integer (valuep, 4, cache->saved_sp);
- }
+ {
+ /* Store the value. */
+ store_unsigned_integer (valuep, 4, cache->saved_sp);
+ }
return;
}
@@ -1852,22 +1813,22 @@ sh_frame_prev_register (struct frame_inf
*addrp = cache->saved_regs[regnum];
*realnump = -1;
if (valuep)
- {
- /* Read the value in from memory. */
- read_memory (*addrp, valuep,
- register_size (current_gdbarch, regnum));
- }
+ {
+ /* Read the value in from memory. */
+ read_memory (*addrp, valuep,
+ register_size (current_gdbarch, regnum));
+ }
return;
}
frame_register_unwind (next_frame, regnum,
- optimizedp, lvalp, addrp, realnump, valuep);
+ optimizedp, lvalp, addrp, realnump, valuep);
}
static void
sh_frame_this_id (struct frame_info *next_frame, void **this_cache,
- struct frame_id *this_id)
-{
+ struct frame_id *this_id)
+{
struct sh_frame_cache *cache = sh_frame_cache (next_frame, this_cache);
/* This marks the outermost frame. */
@@ -1875,10 +1836,9 @@ sh_frame_this_id (struct frame_info *nex
return;
*this_id = frame_id_build (cache->saved_sp, cache->pc);
-}
+}
-static const struct frame_unwind sh_frame_unwind =
-{
+static const struct frame_unwind sh_frame_unwind = {
NORMAL_FRAME,
sh_frame_this_id,
sh_frame_prev_register
@@ -1911,19 +1871,18 @@ sh_unwind_dummy_id (struct gdbarch *gdba
static CORE_ADDR
sh_frame_base_address (struct frame_info *next_frame, void **this_cache)
-{
+{
struct sh_frame_cache *cache = sh_frame_cache (next_frame, this_cache);
-
+
return cache->base;
}
-
-static const struct frame_base sh_frame_base =
-{
+
+static const struct frame_base sh_frame_base = {
&sh_frame_unwind,
sh_frame_base_address,
sh_frame_base_address,
sh_frame_base_address
-};
+};
/* The epilogue is defined here as the area at the end of a function,
either on the `ret' instruction itself or after an instruction which
@@ -1938,41 +1897,41 @@ sh_in_function_epilogue_p (struct gdbarc
ULONGEST inst;
/* The sh epilogue is max. 14 bytes long. Give another 14 bytes
for a nop and some fixed data (e.g. big offsets) which are
- unfortunately also treated as part of the function (which
- means, they are below func_end. */
+ unfortunately also treated as part of the function (which
+ means, they are below func_end. */
CORE_ADDR addr = func_end - 28;
if (addr < func_addr + 4)
- addr = func_addr + 4;
+ addr = func_addr + 4;
if (pc < addr)
return 0;
/* First search forward until hitting an rts. */
while (addr < func_end
- && !IS_RTS (read_memory_unsigned_integer (addr, 2)))
+ && !IS_RTS (read_memory_unsigned_integer (addr, 2)))
addr += 2;
if (addr >= func_end)
- return 0;
+ return 0;
/* At this point we should find a mov.l @r15+,r14 instruction,
either before or after the rts. If not, then the function has
- probably no "normal" epilogue and we bail out here. */
+ probably no "normal" epilogue and we bail out here. */
inst = read_memory_unsigned_integer (addr - 2, 2);
if (IS_RESTORE_FP (read_memory_unsigned_integer (addr - 2, 2)))
- addr -= 2;
+ addr -= 2;
else if (!IS_RESTORE_FP (read_memory_unsigned_integer (addr + 2, 2)))
return 0;
/* Step over possible lds.l @r15+,pr. */
inst = read_memory_unsigned_integer (addr - 2, 2);
if (IS_LDS (inst))
- {
+ {
addr -= 2;
inst = read_memory_unsigned_integer (addr - 2, 2);
}
/* Step over possible mov r14,r15. */
if (IS_MOV_FP_SP (inst))
- {
+ {
addr -= 2;
inst = read_memory_unsigned_integer (addr - 2, 2);
}
@@ -1980,7 +1939,7 @@ sh_in_function_epilogue_p (struct gdbarc
/* Now check for FP adjustments, using add #imm,r14 or add rX, r14
instructions. */
while (addr > func_addr + 4
- && (IS_ADD_REG_TO_FP (inst) || IS_ADD_IMM_FP (inst)))
+ && (IS_ADD_REG_TO_FP (inst) || IS_ADD_IMM_FP (inst)))
{
addr -= 2;
inst = read_memory_unsigned_integer (addr - 2, 2);
@@ -2002,33 +1961,33 @@ sh_gdbarch_init (struct gdbarch_info inf
sh_show_regs = sh_generic_show_regs;
switch (info.bfd_arch_info->mach)
{
- case bfd_mach_sh2e:
- sh_show_regs = sh2e_show_regs;
- break;
- case bfd_mach_sh_dsp:
- sh_show_regs = sh_dsp_show_regs;
- break;
+ case bfd_mach_sh2e:
+ sh_show_regs = sh2e_show_regs;
+ break;
+ case bfd_mach_sh_dsp:
+ sh_show_regs = sh_dsp_show_regs;
+ break;
- case bfd_mach_sh3:
- sh_show_regs = sh3_show_regs;
- break;
+ case bfd_mach_sh3:
+ sh_show_regs = sh3_show_regs;
+ break;
- case bfd_mach_sh3e:
- sh_show_regs = sh3e_show_regs;
- break;
+ case bfd_mach_sh3e:
+ sh_show_regs = sh3e_show_regs;
+ break;
- case bfd_mach_sh3_dsp:
- sh_show_regs = sh3_dsp_show_regs;
- break;
+ case bfd_mach_sh3_dsp:
+ sh_show_regs = sh3_dsp_show_regs;
+ break;
- case bfd_mach_sh4:
- sh_show_regs = sh4_show_regs;
- break;
+ case bfd_mach_sh4:
+ sh_show_regs = sh4_show_regs;
+ break;
- case bfd_mach_sh5:
- sh_show_regs = sh64_show_regs;
- /* SH5 is handled entirely in sh64-tdep.c */
- return sh64_gdbarch_init (info, arches);
+ case bfd_mach_sh5:
+ sh_show_regs = sh64_show_regs;
+ /* SH5 is handled entirely in sh64-tdep.c */
+ return sh64_gdbarch_init (info, arches);
}
/* If there is already a candidate, use it. */
@@ -2091,8 +2050,7 @@ sh_gdbarch_init (struct gdbarch_info inf
set_gdbarch_unwind_dummy_id (gdbarch, sh_unwind_dummy_id);
frame_base_set_default (gdbarch, &sh_frame_base);
- set_gdbarch_in_function_epilogue_p (gdbarch,
- sh_in_function_epilogue_p);
+ set_gdbarch_in_function_epilogue_p (gdbarch, sh_in_function_epilogue_p);
switch (info.bfd_arch_info->mach)
{
@@ -2102,7 +2060,7 @@ sh_gdbarch_init (struct gdbarch_info inf
case bfd_mach_sh2:
set_gdbarch_register_name (gdbarch, sh_sh_register_name);
- break;
+ break;
case bfd_mach_sh2e:
/* doubles on sh2e and sh3e are actually 4 byte. */
@@ -2112,7 +2070,8 @@ sh_gdbarch_init (struct gdbarch_info inf
set_gdbarch_register_type (gdbarch, sh_sh3e_register_type);
set_gdbarch_fp0_regnum (gdbarch, 25);
set_gdbarch_store_return_value (gdbarch, sh3e_sh4_store_return_value);
- set_gdbarch_extract_return_value (gdbarch, sh3e_sh4_extract_return_value);
+ set_gdbarch_extract_return_value (gdbarch,
+ sh3e_sh4_extract_return_value);
set_gdbarch_push_dummy_call (gdbarch, sh_push_dummy_call_fpu);
break;
@@ -2133,7 +2092,8 @@ sh_gdbarch_init (struct gdbarch_info inf
set_gdbarch_register_type (gdbarch, sh_sh3e_register_type);
set_gdbarch_fp0_regnum (gdbarch, 25);
set_gdbarch_store_return_value (gdbarch, sh3e_sh4_store_return_value);
- set_gdbarch_extract_return_value (gdbarch, sh3e_sh4_extract_return_value);
+ set_gdbarch_extract_return_value (gdbarch,
+ sh3e_sh4_extract_return_value);
set_gdbarch_push_dummy_call (gdbarch, sh_push_dummy_call_fpu);
break;
@@ -2150,7 +2110,8 @@ sh_gdbarch_init (struct gdbarch_info inf
set_gdbarch_pseudo_register_read (gdbarch, sh_pseudo_register_read);
set_gdbarch_pseudo_register_write (gdbarch, sh_pseudo_register_write);
set_gdbarch_store_return_value (gdbarch, sh3e_sh4_store_return_value);
- set_gdbarch_extract_return_value (gdbarch, sh3e_sh4_extract_return_value);
+ set_gdbarch_extract_return_value (gdbarch,
+ sh3e_sh4_extract_return_value);
set_gdbarch_push_dummy_call (gdbarch, sh_push_dummy_call_fpu);
break;
@@ -2168,13 +2129,13 @@ sh_gdbarch_init (struct gdbarch_info inf
return gdbarch;
}
-extern initialize_file_ftype _initialize_sh_tdep; /* -Wmissing-prototypes */
+extern initialize_file_ftype _initialize_sh_tdep; /* -Wmissing-prototypes */
void
_initialize_sh_tdep (void)
{
struct cmd_list_element *c;
-
+
gdbarch_register (bfd_arch_sh, sh_gdbarch_init, NULL);
add_com ("regs", class_vars, sh_show_regs_command, "Print all registers");
--
Corinna Vinschen
Cygwin Developer
Red Hat, Inc.
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: SH follow up, part 2 (was Re: [RFA] sh-tdep.c: Follow up patch to implement two different ABIs)
2003-09-25 21:44 ` Elena Zannoni
@ 2003-09-26 11:15 ` Corinna Vinschen
0 siblings, 0 replies; 12+ messages in thread
From: Corinna Vinschen @ 2003-09-26 11:15 UTC (permalink / raw)
To: gdb-patches
On Thu, Sep 25, 2003 at 05:54:43PM -0400, Elena Zannoni wrote:
> Corinna Vinschen writes:
> > Currently there's no way to differ between these two ABIs automatically
> > though that might change at some later point. The user has to change
> > the ABI on the command line by hand. The compiler option was -mhitachi,
> > gcc is just changing to -mrenesas to reflect the company name change.
>
> Hmm but then the user can set the calling convention to the wrong one.
> Also the finish command, I am afraid, will be confused. There should
> be something detecting the calling convention from the executable. Is
> the info recorded in the file anywhere? I.e. would readelf/objdump
> show it?
No. I started a discussion about this on gdb four weeks ago but at this
point there is no chance to find this out. The automatism requires some
work in gcc and gdb which is not done yet and which is not target
dependent. It's another step. This patch only contains the first step
necessary to allow to debug two ABIs for sh. It requires user
intervention. If the changes for automating the ABI stuff are done, the
next target dependent step is to add the "auto" flag and to make it the
default.
> These descriptions should be comments in the file, the more verbiage
> the better.
The comments are in the code.
> I don't have anything in particular against these patches, but I'd like
> to have a better idea about how to solve this calling convention issue
> before the changes go in.
http://sources.redhat.com/ml/gdb/2003-08/msg00252.html
Corinna
--
Corinna Vinschen
Cygwin Developer
Red Hat, Inc.
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: SH follow up, part 1 (was Re: [RFA] sh-tdep.c: Follow up patch to implement two different ABIs)
2003-09-26 11:14 ` Corinna Vinschen
@ 2003-10-01 20:26 ` Elena Zannoni
2003-10-02 10:47 ` Corinna Vinschen
0 siblings, 1 reply; 12+ messages in thread
From: Elena Zannoni @ 2003-10-01 20:26 UTC (permalink / raw)
To: gdb-patches
Corinna Vinschen writes:
> On Thu, Sep 25, 2003 at 05:48:50PM -0400, Elena Zannoni wrote:
> > Corinna Vinschen writes:
> > > Ok, step 1:
> >
> > Seems ok, are there diffs in the test results before&after?
>
> No.
>
> > Are these
> > explanations also in the code?
>
> Yes.
>
> > > If you don't like that and want to use register_size correctly in that case,
> > > it would have to look like this:
> >
> > Yes please.
> >
> > When you are done with this rewrite, it would be good to pass the file
> > through gdb_indent.sh.
>
> Yes. Anything else left before approval?
>
No, but check in the patch with the changes corresponding to the
changelog entries below.
After that, check in the reindentation, and add a new changelog entry
saying you ran it through gdb_indent.sh.
thanks
elena
ChangeLog:
==========
* sh-tdep.c (sh_justify_value_in_reg): New function.
(sh_stack_allocsize): Ditto.
(flt_argreg_array): New array used for floating point argument
passing.
(sh_init_flt_argreg): New function.
(sh_next_flt_argreg): Ditto.
(sh_push_dummy_call_fpu): Simplify. Rename "odd_sized_struct" to
"pass_on_stack". Use new helper functions. Accomodate Renesas ABI.
Fix argument passing strategy.
(sh_push_dummy_call_nofpu): Ditto.
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: SH follow up, part 1 (was Re: [RFA] sh-tdep.c: Follow up patch to implement two different ABIs)
2003-10-01 20:26 ` Elena Zannoni
@ 2003-10-02 10:47 ` Corinna Vinschen
0 siblings, 0 replies; 12+ messages in thread
From: Corinna Vinschen @ 2003-10-02 10:47 UTC (permalink / raw)
To: gdb-patches
On Wed, Oct 01, 2003 at 04:37:03PM -0400, Elena Zannoni wrote:
> No, but check in the patch with the changes corresponding to the
> changelog entries below.
>
> After that, check in the reindentation, and add a new changelog entry
> saying you ran it through gdb_indent.sh.
Done.
Thanks,
Corinna
--
Corinna Vinschen
Cygwin Developer
Red Hat, Inc.
^ permalink raw reply [flat|nested] 12+ messages in thread
end of thread, other threads:[~2003-10-02 10:47 UTC | newest]
Thread overview: 12+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2003-09-17 16:11 [RFA] sh-tdep.c: Follow up patch to implement two different ABIs Corinna Vinschen
2003-09-23 20:34 ` Elena Zannoni
2003-09-23 21:27 ` Andrew Cagney
2003-09-24 8:44 ` Corinna Vinschen
2003-09-24 9:56 ` SH follow up, part 1 (was Re: [RFA] sh-tdep.c: Follow up patch to implement two different ABIs) Corinna Vinschen
2003-09-25 21:39 ` Elena Zannoni
2003-09-26 11:14 ` Corinna Vinschen
2003-10-01 20:26 ` Elena Zannoni
2003-10-02 10:47 ` Corinna Vinschen
2003-09-24 10:39 ` SH follow up, part 2 " Corinna Vinschen
2003-09-25 21:44 ` Elena Zannoni
2003-09-26 11:15 ` Corinna Vinschen
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox