X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=gdb%2Fs390-linux-tdep.c;h=32a5ed6aa191cdef92ad6da9c40536e96ec7f4a5;hb=f486487f558686c05d4f4d91a75638b9da399044;hp=803779ccb198f4857e7be1ac0924513a54d9bbc2;hpb=60abeae4f219a7a445d11ebaf72d2939413ffe80;p=deliverable%2Fbinutils-gdb.git diff --git a/gdb/s390-linux-tdep.c b/gdb/s390-linux-tdep.c index 803779ccb1..32a5ed6aa1 100644 --- a/gdb/s390-linux-tdep.c +++ b/gdb/s390-linux-tdep.c @@ -54,6 +54,8 @@ #include "cli/cli-utils.h" #include #include "elf/common.h" +#include "elf/s390.h" +#include "elf-bfd.h" #include "features/s390-linux32.c" #include "features/s390-linux32v1.c" @@ -62,25 +64,45 @@ #include "features/s390-linux64v1.c" #include "features/s390-linux64v2.c" #include "features/s390-te-linux64.c" +#include "features/s390-vx-linux64.c" +#include "features/s390-tevx-linux64.c" #include "features/s390x-linux64.c" #include "features/s390x-linux64v1.c" #include "features/s390x-linux64v2.c" #include "features/s390x-te-linux64.c" +#include "features/s390x-vx-linux64.c" +#include "features/s390x-tevx-linux64.c" #define XML_SYSCALL_FILENAME_S390 "syscalls/s390-linux.xml" #define XML_SYSCALL_FILENAME_S390X "syscalls/s390x-linux.xml" +enum s390_abi_kind +{ + ABI_LINUX_S390, + ABI_LINUX_ZSERIES +}; + +enum s390_vector_abi_kind +{ + S390_VECTOR_ABI_NONE, + S390_VECTOR_ABI_128 +}; + /* The tdep structure. */ struct gdbarch_tdep { /* ABI version. */ - enum { ABI_LINUX_S390, ABI_LINUX_ZSERIES } abi; + enum s390_abi_kind abi; + + /* Vector ABI. */ + enum s390_vector_abi_kind vector_abi; /* Pseudo register numbers. */ int gpr_full_regnum; int pc_regnum; int cc_regnum; + int v0_full_regnum; int have_linux_v1; int have_linux_v2; @@ -148,61 +170,83 @@ s390_write_pc (struct regcache *regcache, CORE_ADDR pc) static const short s390_dwarf_regmap[] = { - /* General Purpose Registers. */ + /* 0-15: General Purpose Registers. */ S390_R0_REGNUM, S390_R1_REGNUM, S390_R2_REGNUM, S390_R3_REGNUM, S390_R4_REGNUM, S390_R5_REGNUM, S390_R6_REGNUM, S390_R7_REGNUM, S390_R8_REGNUM, S390_R9_REGNUM, S390_R10_REGNUM, S390_R11_REGNUM, S390_R12_REGNUM, S390_R13_REGNUM, S390_R14_REGNUM, S390_R15_REGNUM, - /* Floating Point Registers. */ + /* 16-31: Floating Point Registers / Vector Registers 0-15. */ S390_F0_REGNUM, S390_F2_REGNUM, S390_F4_REGNUM, S390_F6_REGNUM, S390_F1_REGNUM, S390_F3_REGNUM, S390_F5_REGNUM, S390_F7_REGNUM, S390_F8_REGNUM, S390_F10_REGNUM, S390_F12_REGNUM, S390_F14_REGNUM, S390_F9_REGNUM, S390_F11_REGNUM, S390_F13_REGNUM, S390_F15_REGNUM, - /* Control Registers (not mapped). */ + /* 32-47: Control Registers (not mapped). */ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - /* Access Registers. */ + /* 48-63: Access Registers. */ S390_A0_REGNUM, S390_A1_REGNUM, S390_A2_REGNUM, S390_A3_REGNUM, S390_A4_REGNUM, S390_A5_REGNUM, S390_A6_REGNUM, S390_A7_REGNUM, S390_A8_REGNUM, S390_A9_REGNUM, S390_A10_REGNUM, S390_A11_REGNUM, S390_A12_REGNUM, S390_A13_REGNUM, S390_A14_REGNUM, S390_A15_REGNUM, - /* Program Status Word. */ + /* 64-65: Program Status Word. */ S390_PSWM_REGNUM, S390_PSWA_REGNUM, + /* 66-67: Reserved. */ + -1, -1, + + /* 68-83: Vector Registers 16-31. */ + S390_V16_REGNUM, S390_V18_REGNUM, S390_V20_REGNUM, S390_V22_REGNUM, + S390_V17_REGNUM, S390_V19_REGNUM, S390_V21_REGNUM, S390_V23_REGNUM, + S390_V24_REGNUM, S390_V26_REGNUM, S390_V28_REGNUM, S390_V30_REGNUM, + S390_V25_REGNUM, S390_V27_REGNUM, S390_V29_REGNUM, S390_V31_REGNUM, + + /* End of "official" DWARF registers. The remainder of the map is + for GDB internal use only. */ + /* GPR Lower Half Access. */ S390_R0_REGNUM, S390_R1_REGNUM, S390_R2_REGNUM, S390_R3_REGNUM, S390_R4_REGNUM, S390_R5_REGNUM, S390_R6_REGNUM, S390_R7_REGNUM, S390_R8_REGNUM, S390_R9_REGNUM, S390_R10_REGNUM, S390_R11_REGNUM, S390_R12_REGNUM, S390_R13_REGNUM, S390_R14_REGNUM, S390_R15_REGNUM, - - /* GNU/Linux-specific registers (not mapped). */ - -1, -1, -1, }; +enum { s390_dwarf_reg_r0l = ARRAY_SIZE (s390_dwarf_regmap) - 16 }; + /* Convert DWARF register number REG to the appropriate register number used by GDB. */ static int s390_dwarf_reg_to_regnum (struct gdbarch *gdbarch, int reg) { struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); + int gdb_reg = -1; - /* In a 32-on-64 debug scenario, debug info refers to the full 64-bit - GPRs. Note that call frame information still refers to the 32-bit - lower halves, because s390_adjust_frame_regnum uses register numbers - 66 .. 81 to access GPRs. */ + /* In a 32-on-64 debug scenario, debug info refers to the full + 64-bit GPRs. Note that call frame information still refers to + the 32-bit lower halves, because s390_adjust_frame_regnum uses + special register numbers to access GPRs. */ if (tdep->gpr_full_regnum != -1 && reg >= 0 && reg < 16) return tdep->gpr_full_regnum + reg; if (reg >= 0 && reg < ARRAY_SIZE (s390_dwarf_regmap)) - return s390_dwarf_regmap[reg]; + gdb_reg = s390_dwarf_regmap[reg]; + + if (tdep->v0_full_regnum == -1) + { + if (gdb_reg >= S390_V16_REGNUM && gdb_reg <= S390_V31_REGNUM) + gdb_reg = -1; + } + else + { + if (gdb_reg >= S390_F0_REGNUM && gdb_reg <= S390_F15_REGNUM) + gdb_reg = gdb_reg - S390_F0_REGNUM + tdep->v0_full_regnum; + } - warning (_("Unmapped DWARF Register #%d encountered."), reg); - return -1; + return gdb_reg; } /* Translate a .eh_frame register to DWARF register, or adjust a @@ -211,7 +255,7 @@ static int s390_adjust_frame_regnum (struct gdbarch *gdbarch, int num, int eh_frame_p) { /* See s390_dwarf_reg_to_regnum for comments. */ - return (num >= 0 && num < 16)? num + 66 : num; + return (num >= 0 && num < 16) ? num + s390_dwarf_reg_r0l : num; } @@ -225,6 +269,29 @@ regnum_is_gpr_full (struct gdbarch_tdep *tdep, int regnum) && regnum <= tdep->gpr_full_regnum + 15); } +/* Check whether REGNUM indicates a full vector register (v0-v15). + These pseudo-registers are composed of f0-f15 and v0l-v15l. */ + +static int +regnum_is_vxr_full (struct gdbarch_tdep *tdep, int regnum) +{ + return (tdep->v0_full_regnum != -1 + && regnum >= tdep->v0_full_regnum + && regnum <= tdep->v0_full_regnum + 15); +} + +/* Return the name of register REGNO. Return the empty string for + registers that shouldn't be visible. */ + +static const char * +s390_register_name (struct gdbarch *gdbarch, int regnum) +{ + if (regnum >= S390_V0_LOWER_REGNUM + && regnum <= S390_V15_LOWER_REGNUM) + return ""; + return tdesc_register_name (gdbarch, regnum); +} + static const char * s390_pseudo_register_name (struct gdbarch *gdbarch, int regnum) { @@ -245,6 +312,15 @@ s390_pseudo_register_name (struct gdbarch *gdbarch, int regnum) return full_name[regnum - tdep->gpr_full_regnum]; } + if (regnum_is_vxr_full (tdep, regnum)) + { + static const char *full_name[] = { + "v0", "v1", "v2", "v3", "v4", "v5", "v6", "v7", + "v8", "v9", "v10", "v11", "v12", "v13", "v14", "v15" + }; + return full_name[regnum - tdep->v0_full_regnum]; + } + internal_error (__FILE__, __LINE__, _("invalid regnum")); } @@ -262,6 +338,9 @@ s390_pseudo_register_type (struct gdbarch *gdbarch, int regnum) if (regnum_is_gpr_full (tdep, regnum)) return builtin_type (gdbarch)->builtin_uint64; + if (regnum_is_vxr_full (tdep, regnum)) + return tdesc_find_type (gdbarch, "vec128"); + internal_error (__FILE__, __LINE__, _("invalid regnum")); } @@ -323,6 +402,19 @@ s390_pseudo_register_read (struct gdbarch *gdbarch, struct regcache *regcache, return status; } + if (regnum_is_vxr_full (tdep, regnum)) + { + enum register_status status; + + regnum -= tdep->v0_full_regnum; + + status = regcache_raw_read (regcache, S390_F0_REGNUM + regnum, buf); + if (status == REG_VALID) + status = regcache_raw_read (regcache, + S390_V0_LOWER_REGNUM + regnum, buf + 8); + return status; + } + internal_error (__FILE__, __LINE__, _("invalid regnum")); } @@ -370,22 +462,34 @@ s390_pseudo_register_write (struct gdbarch *gdbarch, struct regcache *regcache, return; } + if (regnum_is_vxr_full (tdep, regnum)) + { + regnum -= tdep->v0_full_regnum; + regcache_raw_write (regcache, S390_F0_REGNUM + regnum, buf); + regcache_raw_write (regcache, S390_V0_LOWER_REGNUM + regnum, buf + 8); + return; + } + internal_error (__FILE__, __LINE__, _("invalid regnum")); } /* 'float' values are stored in the upper half of floating-point - registers, even though we are otherwise a big-endian platform. */ + registers, even though we are otherwise a big-endian platform. The + same applies to a 'float' value within a vector. */ static struct value * s390_value_from_register (struct gdbarch *gdbarch, struct type *type, int regnum, struct frame_id frame_id) { + struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); struct value *value = default_value_from_register (gdbarch, type, regnum, frame_id); check_typedef (type); - if (regnum >= S390_F0_REGNUM && regnum <= S390_F15_REGNUM - && TYPE_LENGTH (type) < 8) + if ((regnum >= S390_F0_REGNUM && regnum <= S390_F15_REGNUM + && TYPE_LENGTH (type) < 8) + || regnum_is_vxr_full (tdep, regnum) + || (regnum >= S390_V16_REGNUM && regnum <= S390_V31_REGNUM)) set_value_offset (value, 0); return value; @@ -410,6 +514,12 @@ s390_pseudo_register_reggroup_p (struct gdbarch *gdbarch, int regnum, if (group == save_reggroup || group == restore_reggroup) return regnum == tdep->pc_regnum || regnum == tdep->cc_regnum; + if (group == vector_reggroup) + return regnum_is_vxr_full (tdep, regnum); + + if (group == general_reggroup && regnum_is_vxr_full (tdep, regnum)) + return 0; + return default_register_reggroup_p (gdbarch, regnum, group); } @@ -469,6 +579,18 @@ static const struct regcache_map_entry s390_regmap_tdb[] = { 0 } }; +static const struct regcache_map_entry s390_regmap_vxrs_low[] = + { + { 16, S390_V0_LOWER_REGNUM, 8 }, + { 0 } + }; + +static const struct regcache_map_entry s390_regmap_vxrs_high[] = + { + { 16, S390_V16_REGNUM, 16 }, + { 0 } + }; + /* Supply the TDB regset. Like regcache_supply_regset, but invalidate the TDB registers unless the TDB format field is valid. */ @@ -529,6 +651,18 @@ const struct regset s390_tdb_regset = { regcache_collect_regset }; +const struct regset s390_vxrs_low_regset = { + s390_regmap_vxrs_low, + regcache_supply_regset, + regcache_collect_regset +}; + +const struct regset s390_vxrs_high_regset = { + s390_regmap_vxrs_high, + regcache_supply_regset, + regcache_collect_regset +}; + /* Iterate over supported core file register note sections. */ static void @@ -567,37 +701,54 @@ s390_iterate_over_regset_sections (struct gdbarch *gdbarch, S390_TDB_DWORD0_REGNUM))) cb (".reg-s390-tdb", s390_sizeof_tdbregset, &s390_tdb_regset, "s390 TDB", cb_data); + + if (tdep->v0_full_regnum != -1) + { + cb (".reg-s390-vxrs-low", 16 * 8, &s390_vxrs_low_regset, + "s390 vector registers 0-15 lower half", cb_data); + cb (".reg-s390-vxrs-high", 16 * 16, &s390_vxrs_high_regset, + "s390 vector registers 16-31", cb_data); + } } static const struct target_desc * s390_core_read_description (struct gdbarch *gdbarch, struct target_ops *target, bfd *abfd) { - asection *high_gprs = bfd_get_section_by_name (abfd, ".reg-s390-high-gprs"); - asection *v1 = bfd_get_section_by_name (abfd, ".reg-s390-last-break"); - asection *v2 = bfd_get_section_by_name (abfd, ".reg-s390-system-call"); asection *section = bfd_get_section_by_name (abfd, ".reg"); CORE_ADDR hwcap = 0; + int high_gprs, v1, v2, te, vx; target_auxv_search (target, AT_HWCAP, &hwcap); if (!section) return NULL; + high_gprs = (bfd_get_section_by_name (abfd, ".reg-s390-high-gprs") + != NULL); + v1 = (bfd_get_section_by_name (abfd, ".reg-s390-last-break") != NULL); + v2 = (bfd_get_section_by_name (abfd, ".reg-s390-system-call") != NULL); + vx = (hwcap & HWCAP_S390_VX); + te = (hwcap & HWCAP_S390_TE); + switch (bfd_section_size (abfd, section)) { case s390_sizeof_gregset: if (high_gprs) - return ((hwcap & HWCAP_S390_TE) ? tdesc_s390_te_linux64 : - v2? tdesc_s390_linux64v2 : - v1? tdesc_s390_linux64v1 : tdesc_s390_linux64); + return (te && vx ? tdesc_s390_tevx_linux64 : + vx ? tdesc_s390_vx_linux64 : + te ? tdesc_s390_te_linux64 : + v2 ? tdesc_s390_linux64v2 : + v1 ? tdesc_s390_linux64v1 : tdesc_s390_linux64); else - return (v2? tdesc_s390_linux32v2 : - v1? tdesc_s390_linux32v1 : tdesc_s390_linux32); + return (v2 ? tdesc_s390_linux32v2 : + v1 ? tdesc_s390_linux32v1 : tdesc_s390_linux32); case s390x_sizeof_gregset: - return ((hwcap & HWCAP_S390_TE) ? tdesc_s390x_te_linux64 : - v2? tdesc_s390x_linux64v2 : - v1? tdesc_s390x_linux64v1 : tdesc_s390x_linux64); + return (te && vx ? tdesc_s390x_tevx_linux64 : + vx ? tdesc_s390x_vx_linux64 : + te ? tdesc_s390x_te_linux64 : + v2 ? tdesc_s390x_linux64v2 : + v1 ? tdesc_s390x_linux64v1 : tdesc_s390x_linux64); default: return NULL; @@ -1322,15 +1473,23 @@ static CORE_ADDR s390_skip_prologue (struct gdbarch *gdbarch, CORE_ADDR pc) { struct s390_prologue_data data; - CORE_ADDR skip_pc; + CORE_ADDR skip_pc, func_addr; + + if (find_pc_partial_function (pc, NULL, &func_addr, NULL)) + { + CORE_ADDR post_prologue_pc + = skip_prologue_using_sal (gdbarch, func_addr); + if (post_prologue_pc != 0) + return max (pc, post_prologue_pc); + } + skip_pc = s390_analyze_prologue (gdbarch, pc, (CORE_ADDR)-1, &data); return skip_pc ? skip_pc : pc; } -/* Return true if we are in the functin's epilogue, i.e. after the - instruction that destroyed the function's stack frame. */ +/* Implmement the stack_frame_destroyed_p gdbarch method. */ static int -s390_in_function_epilogue_p (struct gdbarch *gdbarch, CORE_ADDR pc) +s390_stack_frame_destroyed_p (struct gdbarch *gdbarch, CORE_ADDR pc) { int word_size = gdbarch_ptr_bit (gdbarch) / 8; @@ -1678,9 +1837,9 @@ s390_prologue_frame_unwind_cache (struct frame_info *this_frame, && (next_frame == NULL || get_frame_type (get_next_frame (this_frame)) != NORMAL_FRAME)) { - /* See the comment in s390_in_function_epilogue_p on why this is + /* See the comment in s390_stack_frame_destroyed_p on why this is not completely reliable ... */ - if (s390_in_function_epilogue_p (gdbarch, get_frame_pc (this_frame))) + if (s390_stack_frame_destroyed_p (gdbarch, get_frame_pc (this_frame))) { memset (&data, 0, sizeof (data)); size = 0; @@ -1810,7 +1969,6 @@ static struct s390_unwind_cache * s390_frame_unwind_cache (struct frame_info *this_frame, void **this_prologue_cache) { - volatile struct gdb_exception ex; struct s390_unwind_cache *info; if (*this_prologue_cache) @@ -1823,15 +1981,19 @@ s390_frame_unwind_cache (struct frame_info *this_frame, info->frame_base = -1; info->local_base = -1; - TRY_CATCH (ex, RETURN_MASK_ERROR) + TRY { /* Try to use prologue analysis to fill the unwind cache. If this fails, fall back to reading the stack backchain. */ if (!s390_prologue_frame_unwind_cache (this_frame, info)) s390_backchain_frame_unwind_cache (this_frame, info); } - if (ex.reason < 0 && ex.error != NOT_AVAILABLE_ERROR) - throw_exception (ex); + CATCH (ex, RETURN_MASK_ERROR) + { + if (ex.error != NOT_AVAILABLE_ERROR) + throw_exception (ex); + } + END_CATCH return info; } @@ -2237,202 +2399,262 @@ s390_dwarf2_frame_init_reg (struct gdbarch *gdbarch, int regnum, /* Dummy function calls. */ -/* Return non-zero if TYPE is an integer-like type, zero otherwise. - "Integer-like" types are those that should be passed the way - integers are: integers, enums, ranges, characters, and booleans. */ -static int -is_integer_like (struct type *type) -{ - enum type_code code = TYPE_CODE (type); - - return (code == TYPE_CODE_INT - || code == TYPE_CODE_ENUM - || code == TYPE_CODE_RANGE - || code == TYPE_CODE_CHAR - || code == TYPE_CODE_BOOL); -} - -/* Return non-zero if TYPE is a pointer-like type, zero otherwise. - "Pointer-like" types are those that should be passed the way - pointers are: pointers and references. */ -static int -is_pointer_like (struct type *type) -{ - enum type_code code = TYPE_CODE (type); - - return (code == TYPE_CODE_PTR - || code == TYPE_CODE_REF); -} - - -/* Return non-zero if TYPE is a `float singleton' or `double - singleton', zero otherwise. - - A `T singleton' is a struct type with one member, whose type is - either T or a `T singleton'. So, the following are all float - singletons: +/* Unwrap any single-field structs in TYPE and return the effective + "inner" type. E.g., yield "float" for all these cases: - struct { float x }; - struct { struct { float x; } x; }; - struct { struct { struct { float x; } x; } x; }; + float x; + struct { float x }; + struct { struct { float x; } x; }; + struct { struct { struct { float x; } x; } x; }; - ... and so on. + However, if an inner type is smaller than MIN_SIZE, abort the + unwrapping. */ - All such structures are passed as if they were floats or doubles, - as the (revised) ABI says. */ -static int -is_float_singleton (struct type *type) +static struct type * +s390_effective_inner_type (struct type *type, unsigned int min_size) { - if (TYPE_CODE (type) == TYPE_CODE_STRUCT && TYPE_NFIELDS (type) == 1) + while (TYPE_CODE (type) == TYPE_CODE_STRUCT + && TYPE_NFIELDS (type) == 1) { - struct type *singleton_type = TYPE_FIELD_TYPE (type, 0); - CHECK_TYPEDEF (singleton_type); + struct type *inner = check_typedef (TYPE_FIELD_TYPE (type, 0)); - return (TYPE_CODE (singleton_type) == TYPE_CODE_FLT - || TYPE_CODE (singleton_type) == TYPE_CODE_DECFLOAT - || is_float_singleton (singleton_type)); + if (TYPE_LENGTH (inner) < min_size) + break; + type = inner; } - return 0; + return type; } +/* Return non-zero if TYPE should be passed like "float" or + "double". */ -/* Return non-zero if TYPE is a struct-like type, zero otherwise. - "Struct-like" types are those that should be passed as structs are: - structs and unions. - - As an odd quirk, not mentioned in the ABI, GCC passes float and - double singletons as if they were a plain float, double, etc. (The - corresponding union types are handled normally.) So we exclude - those types here. *shrug* */ static int -is_struct_like (struct type *type) +s390_function_arg_float (struct type *type) { - enum type_code code = TYPE_CODE (type); - - return (code == TYPE_CODE_UNION - || (code == TYPE_CODE_STRUCT && ! is_float_singleton (type))); -} - + /* Note that long double as well as complex types are intentionally + excluded. */ + if (TYPE_LENGTH (type) > 8) + return 0; -/* Return non-zero if TYPE is a float-like type, zero otherwise. - "Float-like" types are those that should be passed as - floating-point values are. + /* A struct containing just a float or double is passed like a float + or double. */ + type = s390_effective_inner_type (type, 0); - You'd think this would just be floats, doubles, long doubles, etc. - But as an odd quirk, not mentioned in the ABI, GCC passes float and - double singletons as if they were a plain float, double, etc. (The - corresponding union types are handled normally.) So we include - those types here. *shrug* */ -static int -is_float_like (struct type *type) -{ return (TYPE_CODE (type) == TYPE_CODE_FLT - || TYPE_CODE (type) == TYPE_CODE_DECFLOAT - || is_float_singleton (type)); + || TYPE_CODE (type) == TYPE_CODE_DECFLOAT); } +/* Return non-zero if TYPE should be passed like a vector. */ static int -is_power_of_two (unsigned int n) +s390_function_arg_vector (struct type *type) { - return ((n & (n - 1)) == 0); -} + if (TYPE_LENGTH (type) > 16) + return 0; -/* Return non-zero if TYPE should be passed as a pointer to a copy, - zero otherwise. */ -static int -s390_function_arg_pass_by_reference (struct type *type) -{ - if (TYPE_LENGTH (type) > 8) - return 1; + /* Structs containing just a vector are passed like a vector. */ + type = s390_effective_inner_type (type, TYPE_LENGTH (type)); - return (is_struct_like (type) && !is_power_of_two (TYPE_LENGTH (type))) - || TYPE_CODE (type) == TYPE_CODE_COMPLEX - || (TYPE_CODE (type) == TYPE_CODE_ARRAY && TYPE_VECTOR (type)); + return TYPE_CODE (type) == TYPE_CODE_ARRAY && TYPE_VECTOR (type); } -/* Return non-zero if TYPE should be passed in a float register - if possible. */ +/* Determine whether N is a power of two. */ + static int -s390_function_arg_float (struct type *type) +is_power_of_two (unsigned int n) { - if (TYPE_LENGTH (type) > 8) - return 0; - - return is_float_like (type); + return n && ((n & (n - 1)) == 0); } -/* Return non-zero if TYPE should be passed in an integer register - (or a pair of integer registers) if possible. */ +/* For an argument whose type is TYPE and which is not passed like a + float or vector, return non-zero if it should be passed like "int" + or "long long". */ + static int s390_function_arg_integer (struct type *type) { + enum type_code code = TYPE_CODE (type); + if (TYPE_LENGTH (type) > 8) return 0; - return is_integer_like (type) - || is_pointer_like (type) - || (is_struct_like (type) && is_power_of_two (TYPE_LENGTH (type))); + if (code == TYPE_CODE_INT + || code == TYPE_CODE_ENUM + || code == TYPE_CODE_RANGE + || code == TYPE_CODE_CHAR + || code == TYPE_CODE_BOOL + || code == TYPE_CODE_PTR + || code == TYPE_CODE_REF) + return 1; + + return ((code == TYPE_CODE_UNION || code == TYPE_CODE_STRUCT) + && is_power_of_two (TYPE_LENGTH (type))); } -/* Return ARG, a `SIMPLE_ARG', sign-extended or zero-extended to a full - word as required for the ABI. */ -static LONGEST -extend_simple_arg (struct gdbarch *gdbarch, struct value *arg) -{ - enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); - struct type *type = check_typedef (value_type (arg)); +/* Argument passing state: Internal data structure passed to helper + routines of s390_push_dummy_call. */ - /* Even structs get passed in the least significant bits of the - register / memory word. It's not really right to extract them as - an integer, but it does take care of the extension. */ - if (TYPE_UNSIGNED (type)) - return extract_unsigned_integer (value_contents (arg), - TYPE_LENGTH (type), byte_order); - else - return extract_signed_integer (value_contents (arg), - TYPE_LENGTH (type), byte_order); -} +struct s390_arg_state + { + /* Register cache, or NULL, if we are in "preparation mode". */ + struct regcache *regcache; + /* Next available general/floating-point/vector register for + argument passing. */ + int gr, fr, vr; + /* Current pointer to copy area (grows downwards). */ + CORE_ADDR copy; + /* Current pointer to parameter area (grows upwards). */ + CORE_ADDR argp; + }; +/* Prepare one argument ARG for a dummy call and update the argument + passing state AS accordingly. If the regcache field in AS is set, + operate in "write mode" and write ARG into the inferior. Otherwise + run "preparation mode" and skip all updates to the inferior. */ -/* Return the alignment required by TYPE. */ -static int -alignment_of (struct type *type) +static void +s390_handle_arg (struct s390_arg_state *as, struct value *arg, + struct gdbarch_tdep *tdep, int word_size, + enum bfd_endian byte_order, int is_unnamed) { - int alignment; + struct type *type = check_typedef (value_type (arg)); + unsigned int length = TYPE_LENGTH (type); + int write_mode = as->regcache != NULL; - if (is_integer_like (type) - || is_pointer_like (type) - || TYPE_CODE (type) == TYPE_CODE_FLT - || TYPE_CODE (type) == TYPE_CODE_DECFLOAT) - alignment = TYPE_LENGTH (type); - else if (TYPE_CODE (type) == TYPE_CODE_STRUCT - || TYPE_CODE (type) == TYPE_CODE_UNION) + if (s390_function_arg_float (type)) { - int i; + /* The GNU/Linux for S/390 ABI uses FPRs 0 and 2 to pass + arguments. The GNU/Linux for zSeries ABI uses 0, 2, 4, and + 6. */ + if (as->fr <= (tdep->abi == ABI_LINUX_S390 ? 2 : 6)) + { + /* When we store a single-precision value in an FP register, + it occupies the leftmost bits. */ + if (write_mode) + regcache_cooked_write_part (as->regcache, + S390_F0_REGNUM + as->fr, + 0, length, + value_contents (arg)); + as->fr += 2; + } + else + { + /* When we store a single-precision value in a stack slot, + it occupies the rightmost bits. */ + as->argp = align_up (as->argp + length, word_size); + if (write_mode) + write_memory (as->argp - length, value_contents (arg), + length); + } + } + else if (tdep->vector_abi == S390_VECTOR_ABI_128 + && s390_function_arg_vector (type)) + { + static const char use_vr[] = {24, 26, 28, 30, 25, 27, 29, 31}; - alignment = 1; - for (i = 0; i < TYPE_NFIELDS (type); i++) + if (!is_unnamed && as->vr < ARRAY_SIZE (use_vr)) { - int field_alignment - = alignment_of (check_typedef (TYPE_FIELD_TYPE (type, i))); + int regnum = S390_V24_REGNUM + use_vr[as->vr] - 24; - if (field_alignment > alignment) - alignment = field_alignment; + if (write_mode) + regcache_cooked_write_part (as->regcache, regnum, + 0, length, + value_contents (arg)); + as->vr++; + } + else + { + if (write_mode) + write_memory (as->argp, value_contents (arg), length); + as->argp = align_up (as->argp + length, word_size); } } - else - alignment = 1; + else if (s390_function_arg_integer (type) && length <= word_size) + { + /* Initialize it just to avoid a GCC false warning. */ + ULONGEST val = 0; - /* Check that everything we ever return is a power of two. Lots of - code doesn't want to deal with aligning things to arbitrary - boundaries. */ - gdb_assert ((alignment & (alignment - 1)) == 0); + if (write_mode) + { + /* Place value in least significant bits of the register or + memory word and sign- or zero-extend to full word size. + This also applies to a struct or union. */ + val = TYPE_UNSIGNED (type) + ? extract_unsigned_integer (value_contents (arg), + length, byte_order) + : extract_signed_integer (value_contents (arg), + length, byte_order); + } - return alignment; -} + if (as->gr <= 6) + { + if (write_mode) + regcache_cooked_write_unsigned (as->regcache, + S390_R0_REGNUM + as->gr, + val); + as->gr++; + } + else + { + if (write_mode) + write_memory_unsigned_integer (as->argp, word_size, + byte_order, val); + as->argp += word_size; + } + } + else if (s390_function_arg_integer (type) && length == 8) + { + if (as->gr <= 5) + { + if (write_mode) + { + regcache_cooked_write (as->regcache, + S390_R0_REGNUM + as->gr, + value_contents (arg)); + regcache_cooked_write (as->regcache, + S390_R0_REGNUM + as->gr + 1, + value_contents (arg) + word_size); + } + as->gr += 2; + } + else + { + /* If we skipped r6 because we couldn't fit a DOUBLE_ARG + in it, then don't go back and use it again later. */ + as->gr = 7; + if (write_mode) + write_memory (as->argp, value_contents (arg), length); + as->argp += length; + } + } + else + { + /* This argument type is never passed in registers. Place the + value in the copy area and pass a pointer to it. Use 8-byte + alignment as a conservative assumption. */ + as->copy = align_down (as->copy - length, 8); + if (write_mode) + write_memory (as->copy, value_contents (arg), length); + + if (as->gr <= 6) + { + if (write_mode) + regcache_cooked_write_unsigned (as->regcache, + S390_R0_REGNUM + as->gr, + as->copy); + as->gr++; + } + else + { + if (write_mode) + write_memory_unsigned_integer (as->argp, word_size, + byte_order, as->copy); + as->argp += word_size; + } + } +} /* Put the actual parameter values pointed to by ARGS[0..NARGS-1] in place to be passed to a function, as specified by the "GNU/Linux @@ -2448,6 +2670,7 @@ alignment_of (struct type *type) Our caller has taken care of any type promotions needed to satisfy prototypes or the old K&R argument-passing rules. */ + static CORE_ADDR s390_push_dummy_call (struct gdbarch *gdbarch, struct value *function, struct regcache *regcache, CORE_ADDR bp_addr, @@ -2458,151 +2681,55 @@ s390_push_dummy_call (struct gdbarch *gdbarch, struct value *function, int word_size = gdbarch_ptr_bit (gdbarch) / 8; enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); int i; + struct s390_arg_state arg_state, arg_prep; + CORE_ADDR param_area_start, new_sp; + struct type *ftype = check_typedef (value_type (function)); - /* If the i'th argument is passed as a reference to a copy, then - copy_addr[i] is the address of the copy we made. */ - CORE_ADDR *copy_addr = alloca (nargs * sizeof (CORE_ADDR)); + if (TYPE_CODE (ftype) == TYPE_CODE_PTR) + ftype = check_typedef (TYPE_TARGET_TYPE (ftype)); - /* Reserve space for the reference-to-copy area. */ - for (i = 0; i < nargs; i++) - { - struct value *arg = args[i]; - struct type *type = check_typedef (value_type (arg)); + arg_prep.copy = sp; + arg_prep.gr = struct_return ? 3 : 2; + arg_prep.fr = 0; + arg_prep.vr = 0; + arg_prep.argp = 0; + arg_prep.regcache = NULL; - if (s390_function_arg_pass_by_reference (type)) - { - sp -= TYPE_LENGTH (type); - sp = align_down (sp, alignment_of (type)); - copy_addr[i] = sp; - } - } + /* Initialize arg_state for "preparation mode". */ + arg_state = arg_prep; - /* Reserve space for the parameter area. As a conservative - simplification, we assume that everything will be passed on the - stack. Since every argument larger than 8 bytes will be - passed by reference, we use this simple upper bound. */ - sp -= nargs * 8; + /* Update arg_state.copy with the start of the reference-to-copy area + and arg_state.argp with the size of the parameter area. */ + for (i = 0; i < nargs; i++) + s390_handle_arg (&arg_state, args[i], tdep, word_size, byte_order, + TYPE_VARARGS (ftype) && i >= TYPE_NFIELDS (ftype)); - /* After all that, make sure it's still aligned on an eight-byte - boundary. */ - sp = align_down (sp, 8); + param_area_start = align_down (arg_state.copy - arg_state.argp, 8); /* Allocate the standard frame areas: the register save area, the - word reserved for the compiler (which seems kind of meaningless), - and the back chain pointer. */ - sp -= 16*word_size + 32; - - /* Now we have the final SP value. Make sure we didn't underflow; - on 31-bit, this would result in addresses with the high bit set, - which causes confusion elsewhere. Note that if we error out - here, stack and registers remain untouched. */ - if (gdbarch_addr_bits_remove (gdbarch, sp) != sp) + word reserved for the compiler, and the back chain pointer. */ + new_sp = param_area_start - (16 * word_size + 32); + + /* Now we have the final stack pointer. Make sure we didn't + underflow; on 31-bit, this would result in addresses with the + high bit set, which causes confusion elsewhere. Note that if we + error out here, stack and registers remain untouched. */ + if (gdbarch_addr_bits_remove (gdbarch, new_sp) != new_sp) error (_("Stack overflow")); + /* Pass the structure return address in general register 2. */ + if (struct_return) + regcache_cooked_write_unsigned (regcache, S390_R2_REGNUM, struct_addr); - /* Finally, place the actual parameters, working from SP towards - higher addresses. The code above is supposed to reserve enough - space for this. */ - { - int fr = 0; - int gr = 2; - CORE_ADDR starg = sp + 16*word_size + 32; - - /* A struct is returned using general register 2. */ - if (struct_return) - { - regcache_cooked_write_unsigned (regcache, S390_R0_REGNUM + gr, - struct_addr); - gr++; - } + /* Initialize arg_state for "write mode". */ + arg_state = arg_prep; + arg_state.argp = param_area_start; + arg_state.regcache = regcache; - for (i = 0; i < nargs; i++) - { - struct value *arg = args[i]; - struct type *type = check_typedef (value_type (arg)); - unsigned length = TYPE_LENGTH (type); - - if (s390_function_arg_pass_by_reference (type)) - { - /* Actually copy the argument contents to the stack slot - that was reserved above. */ - write_memory (copy_addr[i], value_contents (arg), length); - - if (gr <= 6) - { - regcache_cooked_write_unsigned (regcache, S390_R0_REGNUM + gr, - copy_addr[i]); - gr++; - } - else - { - write_memory_unsigned_integer (starg, word_size, byte_order, - copy_addr[i]); - starg += word_size; - } - } - else if (s390_function_arg_float (type)) - { - /* The GNU/Linux for S/390 ABI uses FPRs 0 and 2 to pass arguments, - the GNU/Linux for zSeries ABI uses 0, 2, 4, and 6. */ - if (fr <= (tdep->abi == ABI_LINUX_S390 ? 2 : 6)) - { - /* When we store a single-precision value in an FP register, - it occupies the leftmost bits. */ - regcache_cooked_write_part (regcache, S390_F0_REGNUM + fr, - 0, length, value_contents (arg)); - fr += 2; - } - else - { - /* When we store a single-precision value in a stack slot, - it occupies the rightmost bits. */ - starg = align_up (starg + length, word_size); - write_memory (starg - length, value_contents (arg), length); - } - } - else if (s390_function_arg_integer (type) && length <= word_size) - { - if (gr <= 6) - { - /* Integer arguments are always extended to word size. */ - regcache_cooked_write_signed (regcache, S390_R0_REGNUM + gr, - extend_simple_arg (gdbarch, - arg)); - gr++; - } - else - { - /* Integer arguments are always extended to word size. */ - write_memory_signed_integer (starg, word_size, byte_order, - extend_simple_arg (gdbarch, arg)); - starg += word_size; - } - } - else if (s390_function_arg_integer (type) && length == 2*word_size) - { - if (gr <= 5) - { - regcache_cooked_write (regcache, S390_R0_REGNUM + gr, - value_contents (arg)); - regcache_cooked_write (regcache, S390_R0_REGNUM + gr + 1, - value_contents (arg) + word_size); - gr += 2; - } - else - { - /* If we skipped r6 because we couldn't fit a DOUBLE_ARG - in it, then don't go back and use it again later. */ - gr = 7; - - write_memory (starg, value_contents (arg), length); - starg += length; - } - } - else - internal_error (__FILE__, __LINE__, _("unknown argument type")); - } - } + /* Write all parameters. */ + for (i = 0; i < nargs; i++) + s390_handle_arg (&arg_state, args[i], tdep, word_size, byte_order, + TYPE_VARARGS (ftype) && i >= TYPE_NFIELDS (ftype)); /* Store return PSWA. In 31-bit mode, keep addressing mode bit. */ if (word_size == 4) @@ -2614,11 +2741,11 @@ s390_push_dummy_call (struct gdbarch *gdbarch, struct value *function, regcache_cooked_write_unsigned (regcache, S390_RETADDR_REGNUM, bp_addr); /* Store updated stack pointer. */ - regcache_cooked_write_unsigned (regcache, S390_SP_REGNUM, sp); + regcache_cooked_write_unsigned (regcache, S390_SP_REGNUM, new_sp); /* We need to return the 'stack part' of the frame ID, which is actually the top of the register save area. */ - return sp + 16*word_size + 32; + return param_area_start; } /* Assuming THIS_FRAME is a dummy, return the frame ID of that @@ -2645,110 +2772,113 @@ s390_frame_align (struct gdbarch *gdbarch, CORE_ADDR addr) } -/* Function return value access. */ +/* Helper for s390_return_value: Set or retrieve a function return + value if it resides in a register. */ -static enum return_value_convention -s390_return_value_convention (struct gdbarch *gdbarch, struct type *type) +static void +s390_register_return_value (struct gdbarch *gdbarch, struct type *type, + struct regcache *regcache, + gdb_byte *out, const gdb_byte *in) { - if (TYPE_LENGTH (type) > 8) - return RETURN_VALUE_STRUCT_CONVENTION; + enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); + int word_size = gdbarch_ptr_bit (gdbarch) / 8; + int length = TYPE_LENGTH (type); + int code = TYPE_CODE (type); - switch (TYPE_CODE (type)) + if (code == TYPE_CODE_FLT || code == TYPE_CODE_DECFLOAT) { - case TYPE_CODE_STRUCT: - case TYPE_CODE_UNION: - case TYPE_CODE_ARRAY: - case TYPE_CODE_COMPLEX: - return RETURN_VALUE_STRUCT_CONVENTION; - - default: - return RETURN_VALUE_REGISTER_CONVENTION; + /* Float-like value: left-aligned in f0. */ + if (in != NULL) + regcache_cooked_write_part (regcache, S390_F0_REGNUM, + 0, length, in); + else + regcache_cooked_read_part (regcache, S390_F0_REGNUM, + 0, length, out); + } + else if (code == TYPE_CODE_ARRAY) + { + /* Vector: left-aligned in v24. */ + if (in != NULL) + regcache_cooked_write_part (regcache, S390_V24_REGNUM, + 0, length, in); + else + regcache_cooked_read_part (regcache, S390_V24_REGNUM, + 0, length, out); } + else if (length <= word_size) + { + /* Integer: zero- or sign-extended in r2. */ + if (out != NULL) + regcache_cooked_read_part (regcache, S390_R2_REGNUM, + word_size - length, length, out); + else if (TYPE_UNSIGNED (type)) + regcache_cooked_write_unsigned + (regcache, S390_R2_REGNUM, + extract_unsigned_integer (in, length, byte_order)); + else + regcache_cooked_write_signed + (regcache, S390_R2_REGNUM, + extract_signed_integer (in, length, byte_order)); + } + else if (length == 2 * word_size) + { + /* Double word: in r2 and r3. */ + if (in != NULL) + { + regcache_cooked_write (regcache, S390_R2_REGNUM, in); + regcache_cooked_write (regcache, S390_R3_REGNUM, + in + word_size); + } + else + { + regcache_cooked_read (regcache, S390_R2_REGNUM, out); + regcache_cooked_read (regcache, S390_R3_REGNUM, + out + word_size); + } + } + else + internal_error (__FILE__, __LINE__, _("invalid return type")); } + +/* Implement the 'return_value' gdbarch method. */ + static enum return_value_convention s390_return_value (struct gdbarch *gdbarch, struct value *function, struct type *type, struct regcache *regcache, gdb_byte *out, const gdb_byte *in) { - enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); - int word_size = gdbarch_ptr_bit (gdbarch) / 8; enum return_value_convention rvc; - int length; type = check_typedef (type); - rvc = s390_return_value_convention (gdbarch, type); - length = TYPE_LENGTH (type); - if (in) + switch (TYPE_CODE (type)) { - switch (rvc) - { - case RETURN_VALUE_REGISTER_CONVENTION: - if (TYPE_CODE (type) == TYPE_CODE_FLT - || TYPE_CODE (type) == TYPE_CODE_DECFLOAT) - { - /* When we store a single-precision value in an FP register, - it occupies the leftmost bits. */ - regcache_cooked_write_part (regcache, S390_F0_REGNUM, - 0, length, in); - } - else if (length <= word_size) - { - /* Integer arguments are always extended to word size. */ - if (TYPE_UNSIGNED (type)) - regcache_cooked_write_unsigned (regcache, S390_R2_REGNUM, - extract_unsigned_integer (in, length, byte_order)); - else - regcache_cooked_write_signed (regcache, S390_R2_REGNUM, - extract_signed_integer (in, length, byte_order)); - } - else if (length == 2*word_size) - { - regcache_cooked_write (regcache, S390_R2_REGNUM, in); - regcache_cooked_write (regcache, S390_R3_REGNUM, in + word_size); - } - else - internal_error (__FILE__, __LINE__, _("invalid return type")); - break; - - case RETURN_VALUE_STRUCT_CONVENTION: - error (_("Cannot set function return value.")); - break; - } + case TYPE_CODE_STRUCT: + case TYPE_CODE_UNION: + case TYPE_CODE_COMPLEX: + rvc = RETURN_VALUE_STRUCT_CONVENTION; + break; + case TYPE_CODE_ARRAY: + rvc = (gdbarch_tdep (gdbarch)->vector_abi == S390_VECTOR_ABI_128 + && TYPE_LENGTH (type) <= 16 && TYPE_VECTOR (type)) + ? RETURN_VALUE_REGISTER_CONVENTION + : RETURN_VALUE_STRUCT_CONVENTION; + break; + default: + rvc = TYPE_LENGTH (type) <= 8 + ? RETURN_VALUE_REGISTER_CONVENTION + : RETURN_VALUE_STRUCT_CONVENTION; } - else if (out) - { - switch (rvc) - { - case RETURN_VALUE_REGISTER_CONVENTION: - if (TYPE_CODE (type) == TYPE_CODE_FLT - || TYPE_CODE (type) == TYPE_CODE_DECFLOAT) - { - /* When we store a single-precision value in an FP register, - it occupies the leftmost bits. */ - regcache_cooked_read_part (regcache, S390_F0_REGNUM, - 0, length, out); - } - else if (length <= word_size) - { - /* Integer arguments occupy the rightmost bits. */ - regcache_cooked_read_part (regcache, S390_R2_REGNUM, - word_size - length, length, out); - } - else if (length == 2*word_size) - { - regcache_cooked_read (regcache, S390_R2_REGNUM, out); - regcache_cooked_read (regcache, S390_R3_REGNUM, out + word_size); - } - else - internal_error (__FILE__, __LINE__, _("invalid return type")); - break; - case RETURN_VALUE_STRUCT_CONVENTION: - error (_("Function return value unknown.")); - break; - } + if (in != NULL || out != NULL) + { + if (rvc == RETURN_VALUE_REGISTER_CONVENTION) + s390_register_return_value (gdbarch, type, regcache, out, in); + else if (in != NULL) + error (_("Cannot set function return value.")); + else + error (_("Function return value unknown.")); } return rvc; @@ -2849,11 +2979,13 @@ s390_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches) struct tdesc_arch_data *tdesc_data = NULL; struct gdbarch *gdbarch; struct gdbarch_tdep *tdep; - int tdep_abi; + enum s390_abi_kind tdep_abi; + enum s390_vector_abi_kind vector_abi; int have_upper = 0; int have_linux_v1 = 0; int have_linux_v2 = 0; int have_tdb = 0; + int have_vx = 0; int first_pseudo_reg, last_pseudo_reg; static const char *const stap_register_prefixes[] = { "%", NULL }; static const char *const stap_register_indirection_prefixes[] = { "(", @@ -2913,6 +3045,14 @@ s390_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches) "tr0", "tr1", "tr2", "tr3", "tr4", "tr5", "tr6", "tr7", "tr8", "tr9", "tr10", "tr11", "tr12", "tr13", "tr14", "tr15" }; + static const char *const vxrs_low[] = { + "v0l", "v1l", "v2l", "v3l", "v4l", "v5l", "v6l", "v7l", "v8l", + "v9l", "v10l", "v11l", "v12l", "v13l", "v14l", "v15l", + }; + static const char *const vxrs_high[] = { + "v16", "v17", "v18", "v19", "v20", "v21", "v22", "v23", "v24", + "v25", "v26", "v27", "v28", "v29", "v30", "v31", + }; const struct tdesc_feature *feature; int i, valid_p = 1; @@ -3001,6 +3141,21 @@ s390_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches) have_tdb = 1; } + /* Vector registers. */ + feature = tdesc_find_feature (tdesc, "org.gnu.gdb.s390.vx"); + if (feature) + { + for (i = 0; i < 16; i++) + valid_p &= tdesc_numbered_register (feature, tdesc_data, + S390_V0_LOWER_REGNUM + i, + vxrs_low[i]); + for (i = 0; i < 16; i++) + valid_p &= tdesc_numbered_register (feature, tdesc_data, + S390_V16_REGNUM + i, + vxrs_high[i]); + have_vx = 1; + } + if (!valid_p) { tdesc_data_cleanup (tdesc_data); @@ -3008,6 +3163,18 @@ s390_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches) } } + /* Determine vector ABI. */ + vector_abi = S390_VECTOR_ABI_NONE; +#ifdef HAVE_ELF + if (have_vx + && info.abfd != NULL + && info.abfd->format == bfd_object + && bfd_get_flavour (info.abfd) == bfd_target_elf_flavour + && bfd_elf_get_obj_attr_int (info.abfd, OBJ_ATTR_GNU, + Tag_GNU_S390_ABI_Vector) == 2) + vector_abi = S390_VECTOR_ABI_128; +#endif + /* Find a candidate among extant architectures. */ for (arches = gdbarch_list_lookup_by_info (arches, &info); arches != NULL; @@ -3018,6 +3185,8 @@ s390_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches) continue; if (tdep->abi != tdep_abi) continue; + if (tdep->vector_abi != vector_abi) + continue; if ((tdep->gpr_full_regnum != -1) != have_upper) continue; if (tdesc_data != NULL) @@ -3028,6 +3197,7 @@ s390_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches) /* Otherwise create a new gdbarch for the specified machine type. */ tdep = XCNEW (struct gdbarch_tdep); tdep->abi = tdep_abi; + tdep->vector_abi = vector_abi; tdep->have_linux_v1 = have_linux_v1; tdep->have_linux_v2 = have_linux_v2; tdep->have_tdb = have_tdb; @@ -3050,7 +3220,7 @@ s390_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches) set_gdbarch_inner_than (gdbarch, core_addr_lessthan); set_gdbarch_breakpoint_from_pc (gdbarch, s390_breakpoint_from_pc); set_gdbarch_skip_prologue (gdbarch, s390_skip_prologue); - set_gdbarch_in_function_epilogue_p (gdbarch, s390_in_function_epilogue_p); + set_gdbarch_stack_frame_destroyed_p (gdbarch, s390_stack_frame_destroyed_p); set_gdbarch_num_regs (gdbarch, S390_NUM_REGS); set_gdbarch_sp_regnum (gdbarch, S390_SP_REGNUM); @@ -3070,6 +3240,7 @@ s390_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches) set_tdesc_pseudo_register_reggroup_p (gdbarch, s390_pseudo_register_reggroup_p); tdesc_use_registers (gdbarch, tdesc, tdesc_data); + set_gdbarch_register_name (gdbarch, s390_register_name); /* Assign pseudo register numbers. */ first_pseudo_reg = gdbarch_num_regs (gdbarch); @@ -3080,6 +3251,12 @@ s390_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches) tdep->gpr_full_regnum = last_pseudo_reg; last_pseudo_reg += 16; } + tdep->v0_full_regnum = -1; + if (have_vx) + { + tdep->v0_full_regnum = last_pseudo_reg; + last_pseudo_reg += 16; + } tdep->pc_regnum = last_pseudo_reg++; tdep->cc_regnum = last_pseudo_reg++; set_gdbarch_pc_regnum (gdbarch, tdep->pc_regnum); @@ -3112,8 +3289,7 @@ s390_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches) set_gdbarch_displaced_step_fixup (gdbarch, s390_displaced_step_fixup); set_gdbarch_displaced_step_free_closure (gdbarch, simple_displaced_step_free_closure); - set_gdbarch_displaced_step_location (gdbarch, - displaced_step_at_entry_point); + set_gdbarch_displaced_step_location (gdbarch, linux_displaced_step_location); set_gdbarch_max_insn_length (gdbarch, S390_MAX_INSTR_SIZE); /* Note that GNU/Linux is the only OS supported on this @@ -3142,7 +3318,7 @@ s390_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches) s390_address_class_type_flags_to_name); set_gdbarch_address_class_name_to_type_flags (gdbarch, s390_address_class_name_to_type_flags); - set_xml_syscall_file_name (gdbarch, XML_SYSCALL_FILENAME_S390); + set_xml_syscall_file_name (gdbarch, XML_SYSCALL_FILENAME_S390X); break; } @@ -3154,8 +3330,6 @@ s390_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches) set_gdbarch_fetch_tls_load_module_address (gdbarch, svr4_fetch_objfile_link_map); - set_gdbarch_get_siginfo_type (gdbarch, linux_get_siginfo_type); - /* SystemTap functions. */ set_gdbarch_stap_register_prefixes (gdbarch, stap_register_prefixes); set_gdbarch_stap_register_indirection_prefixes (gdbarch, @@ -3186,8 +3360,12 @@ _initialize_s390_tdep (void) initialize_tdesc_s390_linux64v1 (); initialize_tdesc_s390_linux64v2 (); initialize_tdesc_s390_te_linux64 (); + initialize_tdesc_s390_vx_linux64 (); + initialize_tdesc_s390_tevx_linux64 (); initialize_tdesc_s390x_linux64 (); initialize_tdesc_s390x_linux64v1 (); initialize_tdesc_s390x_linux64v2 (); initialize_tdesc_s390x_te_linux64 (); + initialize_tdesc_s390x_vx_linux64 (); + initialize_tdesc_s390x_tevx_linux64 (); }