diff --git a/gdb/ChangeLog b/gdb/ChangeLog index fa6543a781..773589de16 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,4 +1,17 @@ -2000-04-05 Scott Bambrough +2000-04-07 Scott Bambrough + + * ChangeLog: Correct date on last entry. + * arm-linux-tdep.c (arm_linux_push_arguments): New function. + * config/arm/tm-linux: Redefined PUSH_ARGUMENTS for Linux. + * config/arm/tm-embed: Fix build warning from redefinition of + LOWEST_PC. + * config/arm/tm-arm.h: Remove TARGET_BYTE_ORDER_SELECTABLE. + * config/arm/tm-wince.h: Remove TARGET_BYTE_ORDER_SELECTABLE and + TARGET_BYTE_ORDER. Add TARGET_BYTE_ORDER_SELECTABLE_P to + override default in tm-arm.h. Use default target byte order + from tm-arm.h. + +2000-04-07 Scott Bambrough * Makefile.in: Add dependency information for arm-linux-tdep.c. * config/djgpp/fnchange.lst: Add arm-linux-tdep.c, arm-linux-nat.c. diff --git a/gdb/arm-linux-tdep.c b/gdb/arm-linux-tdep.c index bf26300ff0..8a575a4ff4 100644 --- a/gdb/arm-linux-tdep.c +++ b/gdb/arm-linux-tdep.c @@ -22,6 +22,7 @@ #include "target.h" #include "value.h" #include "gdbtypes.h" +#include "floatformat.h" #ifdef GET_LONGJMP_TARGET @@ -76,6 +77,150 @@ arm_linux_extract_return_value (struct type *type, memcpy (valbuf, ®buf[REGISTER_BYTE (regnum)], TYPE_LENGTH (type)); } +/* Note: ScottB + + This function does not support passing parameters using the FPA + variant of the APCS. It passes any floating point arguments in the + general registers and/or on the stack. + + FIXME: This and arm_push_arguments should be merged. However this + function breaks on a little endian host, big endian target + using the COFF file format. ELF is ok. + + ScottB. */ + +/* Addresses for calling Thumb functions have the bit 0 set. + Here are some macros to test, set, or clear bit 0 of addresses. */ +#define IS_THUMB_ADDR(addr) ((addr) & 1) +#define MAKE_THUMB_ADDR(addr) ((addr) | 1) +#define UNMAKE_THUMB_ADDR(addr) ((addr) & ~1) + +CORE_ADDR +arm_linux_push_arguments (int nargs, value_ptr * args, CORE_ADDR sp, + int struct_return, CORE_ADDR struct_addr) +{ + char *fp; + int argnum, argreg, nstack_size; + + /* Walk through the list of args and determine how large a temporary + stack is required. Need to take care here as structs may be + passed on the stack, and we have to to push them. */ + nstack_size = -4 * REGISTER_SIZE; /* Some arguments go into A1-A4. */ + + if (struct_return) /* The struct address goes in A1. */ + nstack_size += REGISTER_SIZE; + + /* Walk through the arguments and add their size to nstack_size. */ + for (argnum = 0; argnum < nargs; argnum++) + { + int len; + struct type *arg_type; + + arg_type = check_typedef (VALUE_TYPE (args[argnum])); + len = TYPE_LENGTH (arg_type); + + /* ANSI C code passes float arguments as integers, K&R code + passes float arguments as doubles. Correct for this here. */ + if (TYPE_CODE_FLT == TYPE_CODE (arg_type) && REGISTER_SIZE == len) + nstack_size += FP_REGISTER_VIRTUAL_SIZE; + else + nstack_size += len; + } + + /* Allocate room on the stack, and initialize our stack frame + pointer. */ + fp = NULL; + if (nstack_size > 0) + { + sp -= nstack_size; + fp = (char *) sp; + } + + /* Initialize the integer argument register pointer. */ + argreg = A1_REGNUM; + + /* The struct_return pointer occupies the first parameter passing + register. */ + if (struct_return) + write_register (argreg++, struct_addr); + + /* Process arguments from left to right. Store as many as allowed + in the parameter passing registers (A1-A4), and save the rest on + the temporary stack. */ + for (argnum = 0; argnum < nargs; argnum++) + { + int len; + char *val; + double dbl_arg; + CORE_ADDR regval; + enum type_code typecode; + struct type *arg_type, *target_type; + + arg_type = check_typedef (VALUE_TYPE (args[argnum])); + target_type = TYPE_TARGET_TYPE (arg_type); + len = TYPE_LENGTH (arg_type); + typecode = TYPE_CODE (arg_type); + val = (char *) VALUE_CONTENTS (args[argnum]); + + /* ANSI C code passes float arguments as integers, K&R code + passes float arguments as doubles. The .stabs record for + for ANSI prototype floating point arguments records the + type as FP_INTEGER, while a K&R style (no prototype) + .stabs records the type as FP_FLOAT. In this latter case + the compiler converts the float arguments to double before + calling the function. */ + if (TYPE_CODE_FLT == typecode && REGISTER_SIZE == len) + { + /* Float argument in buffer is in host format. Read it and + convert to DOUBLEST, and store it in target double. */ + DOUBLEST dblval; + + len = TARGET_DOUBLE_BIT / TARGET_CHAR_BIT; + floatformat_to_doublest (HOST_FLOAT_FORMAT, val, &dblval); + store_floating (&dbl_arg, len, dblval); + val = (char *) &dbl_arg; + } + + /* If the argument is a pointer to a function, and it is a Thumb + function, set the low bit of the pointer. */ + if (TYPE_CODE_PTR == typecode + && NULL != target_type + && TYPE_CODE_FUNC == TYPE_CODE (target_type)) + { + CORE_ADDR regval = extract_address (val, len); + if (arm_pc_is_thumb (regval)) + store_address (val, len, MAKE_THUMB_ADDR (regval)); + } + + /* Copy the argument to general registers or the stack in + register-sized pieces. Large arguments are split between + registers and stack. */ + while (len > 0) + { + int partial_len = len < REGISTER_SIZE ? len : REGISTER_SIZE; + + if (argreg <= ARM_LAST_ARG_REGNUM) + { + /* It's an argument being passed in a general register. */ + regval = extract_address (val, partial_len); + write_register (argreg++, regval); + } + else + { + /* Push the arguments onto the stack. */ + write_memory ((CORE_ADDR) fp, val, REGISTER_SIZE); + fp += REGISTER_SIZE; + } + + len -= partial_len; + val += partial_len; + } + } + + /* Return adjusted stack pointer. */ + return sp; +} + void _initialize_arm_linux_tdep (void) { diff --git a/gdb/config/arm/tm-arm.h b/gdb/config/arm/tm-arm.h index 5ff75aa2b0..e64b77633d 100644 --- a/gdb/config/arm/tm-arm.h +++ b/gdb/config/arm/tm-arm.h @@ -25,11 +25,9 @@ struct type; struct value; -#define TARGET_BYTE_ORDER_SELECTABLE - /* Target byte order on ARM defaults to selectable, and defaults to little endian. */ -#define TARGET_BYTE_ORDER_SELECTABLE_P 1 +#define TARGET_BYTE_ORDER_SELECTABLE_P 1 #define TARGET_BYTE_ORDER_DEFAULT LITTLE_ENDIAN /* IEEE format floating point. */ diff --git a/gdb/config/arm/tm-embed.h b/gdb/config/arm/tm-embed.h index f42b4f2ead..5e9375c6f9 100644 --- a/gdb/config/arm/tm-embed.h +++ b/gdb/config/arm/tm-embed.h @@ -32,6 +32,7 @@ #define STACK_END_ADDR (0x01000000 - (TARGET_UPAGES * TARGET_NBPG)) /* The first 0x20 bytes are the trap vectors. */ +#undef LOWEST_PC #define LOWEST_PC 0x20 /* Override defaults. */ diff --git a/gdb/config/arm/tm-linux.h b/gdb/config/arm/tm-linux.h index 3d9bf1dcad..af2e809d75 100644 --- a/gdb/config/arm/tm-linux.h +++ b/gdb/config/arm/tm-linux.h @@ -26,9 +26,9 @@ #include "tm-linux.h" -/* Target byte order on ARM Linux is not selectable. */ +/* Target byte order on ARM Linux is little endian and not selectable. */ #undef TARGET_BYTE_ORDER_SELECTABLE_P -#define TARGET_BYTE_ORDER_SELECTABLE_P 0 +#define TARGET_BYTE_ORDER_SELECTABLE_P 0 /* Under ARM Linux the traditional way of performing a breakpoint is to execute a particular software interrupt, rather than use a particular @@ -60,6 +60,21 @@ extern void arm_linux_extract_return_value (struct type *, char[], char *); #define EXTRACT_RETURN_VALUE(TYPE,REGBUF,VALBUF) \ arm_linux_extract_return_value ((TYPE), (REGBUF), (VALBUF)) +/* Things needed for making the inferior call functions. + + FIXME: This and arm_push_arguments should be merged. However this + function breaks on a little endian host, big endian target + using the COFF file format. ELF is ok. + + ScottB. */ + +#undef PUSH_ARGUMENTS +#define PUSH_ARGUMENTS(nargs, args, sp, struct_return, struct_addr) \ + sp = arm_linux_push_arguments ((nargs), (args), (sp), (struct_return), \ + (struct_addr)) +extern CORE_ADDR arm_linux_push_arguments (int, struct value **, CORE_ADDR, + int, CORE_ADDR); + /* The first page is not writeable in ARM Linux. */ #undef LOWEST_PC #define LOWEST_PC 0x8000 diff --git a/gdb/config/arm/tm-wince.h b/gdb/config/arm/tm-wince.h index 9b4613506e..0de5fbe096 100644 --- a/gdb/config/arm/tm-wince.h +++ b/gdb/config/arm/tm-wince.h @@ -31,7 +31,8 @@ void wince_software_single_step (unsigned int, int); -#undef TARGET_BYTE_ORDER_SELECTABLE -#define TARGET_BYTE_ORDER LITTLE_ENDIAN +/* Target byte order is little endian and not selectable on WinCE. */ +#undef TARGET_BYTE_ORDER_SELECTABLE_P +#define TARGET_BYTE_ORDER_SELECTABLE_P 0 #endif /* TM_WINCE_H */