X-Git-Url: http://git.efficios.com/?a=blobdiff_plain;f=gdb%2Fs390-linux-nat.c;h=ae0e2c6d94106d244ed03638a66a0c8fad823c56;hb=7fe8399de97e50f631ce28ceb42515862a927556;hp=cf3f7d7c8288d795ec9e666857f8f79bf4a94513;hpb=6682d9595ed8d9b9bba5470bfd7fd1ccd378f19a;p=deliverable%2Fbinutils-gdb.git diff --git a/gdb/s390-linux-nat.c b/gdb/s390-linux-nat.c index cf3f7d7c82..ae0e2c6d94 100644 --- a/gdb/s390-linux-nat.c +++ b/gdb/s390-linux-nat.c @@ -1,5 +1,5 @@ /* S390 native-dependent code for GDB, the GNU debugger. - Copyright (C) 2001-2013 Free Software Foundation, Inc. + Copyright (C) 2001-2016 Free Software Foundation, Inc. Contributed by D.J. Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com) for IBM Deutschland Entwicklung GmbH, IBM Corporation. @@ -26,65 +26,72 @@ #include "linux-nat.h" #include "auxv.h" #include "gregset.h" +#include "regset.h" +#include "nat/linux-ptrace.h" #include "s390-linux-tdep.h" #include "elf/common.h" #include -#include +#include "nat/gdb_ptrace.h" #include #include #include #include -#ifndef PTRACE_GETREGSET -#define PTRACE_GETREGSET 0x4204 -#endif +/* Per-thread arch-specific data. */ -#ifndef PTRACE_SETREGSET -#define PTRACE_SETREGSET 0x4205 -#endif +struct arch_lwp_info +{ + /* Non-zero if the thread's PER info must be re-written. */ + int per_info_changed; +}; static int have_regset_last_break = 0; static int have_regset_system_call = 0; static int have_regset_tdb = 0; +static int have_regset_vxrs = 0; -/* Map registers to gregset/ptrace offsets. - These arrays are defined in s390-tdep.c. */ +/* Register map for 32-bit executables running under a 64-bit + kernel. */ #ifdef __s390x__ -#define regmap_gregset s390x_regmap_gregset -#else -#define regmap_gregset s390_regmap_gregset +static const struct regcache_map_entry s390_64_regmap_gregset[] = + { + /* Skip PSWM and PSWA, since they must be handled specially. */ + { 2, REGCACHE_MAP_SKIP, 8 }, + { 1, S390_R0_UPPER_REGNUM, 4 }, { 1, S390_R0_REGNUM, 4 }, + { 1, S390_R1_UPPER_REGNUM, 4 }, { 1, S390_R1_REGNUM, 4 }, + { 1, S390_R2_UPPER_REGNUM, 4 }, { 1, S390_R2_REGNUM, 4 }, + { 1, S390_R3_UPPER_REGNUM, 4 }, { 1, S390_R3_REGNUM, 4 }, + { 1, S390_R4_UPPER_REGNUM, 4 }, { 1, S390_R4_REGNUM, 4 }, + { 1, S390_R5_UPPER_REGNUM, 4 }, { 1, S390_R5_REGNUM, 4 }, + { 1, S390_R6_UPPER_REGNUM, 4 }, { 1, S390_R6_REGNUM, 4 }, + { 1, S390_R7_UPPER_REGNUM, 4 }, { 1, S390_R7_REGNUM, 4 }, + { 1, S390_R8_UPPER_REGNUM, 4 }, { 1, S390_R8_REGNUM, 4 }, + { 1, S390_R9_UPPER_REGNUM, 4 }, { 1, S390_R9_REGNUM, 4 }, + { 1, S390_R10_UPPER_REGNUM, 4 }, { 1, S390_R10_REGNUM, 4 }, + { 1, S390_R11_UPPER_REGNUM, 4 }, { 1, S390_R11_REGNUM, 4 }, + { 1, S390_R12_UPPER_REGNUM, 4 }, { 1, S390_R12_REGNUM, 4 }, + { 1, S390_R13_UPPER_REGNUM, 4 }, { 1, S390_R13_REGNUM, 4 }, + { 1, S390_R14_UPPER_REGNUM, 4 }, { 1, S390_R14_REGNUM, 4 }, + { 1, S390_R15_UPPER_REGNUM, 4 }, { 1, S390_R15_REGNUM, 4 }, + { 16, S390_A0_REGNUM, 4 }, + { 1, REGCACHE_MAP_SKIP, 4 }, { 1, S390_ORIG_R2_REGNUM, 4 }, + { 0 } + }; + +static const struct regset s390_64_gregset = + { + s390_64_regmap_gregset, + regcache_supply_regset, + regcache_collect_regset + }; + +#define S390_PSWM_OFFSET 0 +#define S390_PSWA_OFFSET 8 #endif -#define regmap_fpregset s390_regmap_fpregset - -/* Fill the regset described by MAP into REGCACHE, using the values - from REGP. The MAP array represents each register as a pair - (offset, regno) of short integers and is terminated with -1. */ - -static void -s390_native_supply (struct regcache *regcache, const short *map, - const gdb_byte *regp) -{ - for (; map[0] >= 0; map += 2) - regcache_raw_supply (regcache, map[1], regp ? regp + map[0] : NULL); -} - -/* Collect the register REGNO out of the regset described by MAP from - REGCACHE into REGP. If REGNO == -1, do this for all registers in - this regset. */ - -static void -s390_native_collect (const struct regcache *regcache, const short *map, - int regno, gdb_byte *regp) -{ - for (; map[0] >= 0; map += 2) - if (regno == -1 || regno == map[1]) - regcache_raw_collect (regcache, map[1], regp + map[0]); -} - /* Fill GDB's register array with the general-purpose register values in *REGP. @@ -100,28 +107,15 @@ supply_gregset (struct regcache *regcache, const gregset_t *regp) if (gdbarch_ptr_bit (gdbarch) == 32) { enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); - ULONGEST pswm = 0, pswa = 0; + ULONGEST pswm, pswa; gdb_byte buf[4]; - const short *map; - - for (map = regmap_gregset; map[0] >= 0; map += 2) - { - const gdb_byte *p = (const gdb_byte *) regp + map[0]; - int regno = map[1]; - - if (regno == S390_PSWM_REGNUM) - pswm = extract_unsigned_integer (p, 8, byte_order); - else if (regno == S390_PSWA_REGNUM) - pswa = extract_unsigned_integer (p, 8, byte_order); - else - { - if ((regno >= S390_R0_REGNUM && regno <= S390_R15_REGNUM) - || regno == S390_ORIG_R2_REGNUM) - p += 4; - regcache_raw_supply (regcache, regno, p); - } - } + regcache_supply_regset (&s390_64_gregset, regcache, -1, + regp, sizeof (gregset_t)); + pswm = extract_unsigned_integer ((const gdb_byte *) regp + + S390_PSWM_OFFSET, 8, byte_order); + pswa = extract_unsigned_integer ((const gdb_byte *) regp + + S390_PSWA_OFFSET, 8, byte_order); store_unsigned_integer (buf, 4, byte_order, (pswm >> 32) | 0x80000); regcache_raw_supply (regcache, S390_PSWM_REGNUM, buf); store_unsigned_integer (buf, 4, byte_order, @@ -131,7 +125,8 @@ supply_gregset (struct regcache *regcache, const gregset_t *regp) } #endif - s390_native_supply (regcache, regmap_gregset, (const gdb_byte *) regp); + regcache_supply_regset (&s390_gregset, regcache, -1, regp, + sizeof (gregset_t)); } /* Fill register REGNO (if it is a general-purpose register) in @@ -145,28 +140,8 @@ fill_gregset (const struct regcache *regcache, gregset_t *regp, int regno) struct gdbarch *gdbarch = get_regcache_arch (regcache); if (gdbarch_ptr_bit (gdbarch) == 32) { - gdb_byte *psw_p[2]; - const short *map; - - for (map = regmap_gregset; map[0] >= 0; map += 2) - { - gdb_byte *p = (gdb_byte *) regp + map[0]; - int reg = map[1]; - - if (reg >= S390_PSWM_REGNUM && reg <= S390_PSWA_REGNUM) - psw_p[reg - S390_PSWM_REGNUM] = p; - - else if (regno == -1 || regno == reg) - { - if ((reg >= S390_R0_REGNUM && reg <= S390_R15_REGNUM) - || reg == S390_ORIG_R2_REGNUM) - { - memset (p, 0, 4); - p += 4; - } - regcache_raw_collect (regcache, reg, p + 4); - } - } + regcache_collect_regset (&s390_64_gregset, regcache, regno, + regp, sizeof (gregset_t)); if (regno == -1 || regno == S390_PSWM_REGNUM || regno == S390_PSWA_REGNUM) @@ -174,25 +149,36 @@ fill_gregset (const struct regcache *regcache, gregset_t *regp, int regno) enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); ULONGEST pswa, pswm; gdb_byte buf[4]; + gdb_byte *pswm_p = (gdb_byte *) regp + S390_PSWM_OFFSET; + gdb_byte *pswa_p = (gdb_byte *) regp + S390_PSWA_OFFSET; - regcache_raw_collect (regcache, S390_PSWM_REGNUM, buf); - pswm = extract_unsigned_integer (buf, 4, byte_order); - regcache_raw_collect (regcache, S390_PSWA_REGNUM, buf); - pswa = extract_unsigned_integer (buf, 4, byte_order); + pswm = extract_unsigned_integer (pswm_p, 8, byte_order); if (regno == -1 || regno == S390_PSWM_REGNUM) - store_unsigned_integer (psw_p[0], 8, byte_order, - ((pswm & 0xfff7ffff) << 32) | - (pswa & 0x80000000)); + { + pswm &= 0x80000000; + regcache_raw_collect (regcache, S390_PSWM_REGNUM, buf); + pswm |= (extract_unsigned_integer (buf, 4, byte_order) + & 0xfff7ffff) << 32; + } + if (regno == -1 || regno == S390_PSWA_REGNUM) - store_unsigned_integer (psw_p[1], 8, byte_order, - pswa & 0x7fffffff); + { + regcache_raw_collect (regcache, S390_PSWA_REGNUM, buf); + pswa = extract_unsigned_integer (buf, 4, byte_order); + pswm ^= (pswm ^ pswa) & 0x80000000; + pswa &= 0x7fffffff; + store_unsigned_integer (pswa_p, 8, byte_order, pswa); + } + + store_unsigned_integer (pswm_p, 8, byte_order, pswm); } return; } #endif - s390_native_collect (regcache, regmap_gregset, regno, (gdb_byte *) regp); + regcache_collect_regset (&s390_gregset, regcache, regno, regp, + sizeof (gregset_t)); } /* Fill GDB's register array with the floating-point register values @@ -200,7 +186,8 @@ fill_gregset (const struct regcache *regcache, gregset_t *regp, int regno) void supply_fpregset (struct regcache *regcache, const fpregset_t *regp) { - s390_native_supply (regcache, regmap_fpregset, (const gdb_byte *) regp); + regcache_supply_regset (&s390_fpregset, regcache, -1, regp, + sizeof (fpregset_t)); } /* Fill register REGNO (if it is a general-purpose register) in @@ -209,7 +196,8 @@ supply_fpregset (struct regcache *regcache, const fpregset_t *regp) void fill_fpregset (const struct regcache *regcache, fpregset_t *regp, int regno) { - s390_native_collect (regcache, regmap_fpregset, regno, (gdb_byte *) regp); + regcache_collect_regset (&s390_fpregset, regcache, regno, regp, + sizeof (fpregset_t)); } /* Find the TID for the current inferior thread to use with ptrace. */ @@ -235,7 +223,7 @@ fetch_regs (struct regcache *regcache, int tid) parea.len = sizeof (regs); parea.process_addr = (addr_t) ®s; parea.kernel_addr = offsetof (struct user_regs_struct, psw); - if (ptrace (PTRACE_PEEKUSR_AREA, tid, (long) &parea) < 0) + if (ptrace (PTRACE_PEEKUSR_AREA, tid, (long) &parea, 0) < 0) perror_with_name (_("Couldn't get registers")); supply_gregset (regcache, (const gregset_t *) ®s); @@ -252,12 +240,12 @@ store_regs (const struct regcache *regcache, int tid, int regnum) parea.len = sizeof (regs); parea.process_addr = (addr_t) ®s; parea.kernel_addr = offsetof (struct user_regs_struct, psw); - if (ptrace (PTRACE_PEEKUSR_AREA, tid, (long) &parea) < 0) + if (ptrace (PTRACE_PEEKUSR_AREA, tid, (long) &parea, 0) < 0) perror_with_name (_("Couldn't get registers")); fill_gregset (regcache, ®s, regnum); - if (ptrace (PTRACE_POKEUSR_AREA, tid, (long) &parea) < 0) + if (ptrace (PTRACE_POKEUSR_AREA, tid, (long) &parea, 0) < 0) perror_with_name (_("Couldn't write registers")); } @@ -272,7 +260,7 @@ fetch_fpregs (struct regcache *regcache, int tid) parea.len = sizeof (fpregs); parea.process_addr = (addr_t) &fpregs; parea.kernel_addr = offsetof (struct user_regs_struct, fp_regs); - if (ptrace (PTRACE_PEEKUSR_AREA, tid, (long) &parea) < 0) + if (ptrace (PTRACE_PEEKUSR_AREA, tid, (long) &parea, 0) < 0) perror_with_name (_("Couldn't get floating point status")); supply_fpregset (regcache, (const fpregset_t *) &fpregs); @@ -289,21 +277,22 @@ store_fpregs (const struct regcache *regcache, int tid, int regnum) parea.len = sizeof (fpregs); parea.process_addr = (addr_t) &fpregs; parea.kernel_addr = offsetof (struct user_regs_struct, fp_regs); - if (ptrace (PTRACE_PEEKUSR_AREA, tid, (long) &parea) < 0) + if (ptrace (PTRACE_PEEKUSR_AREA, tid, (long) &parea, 0) < 0) perror_with_name (_("Couldn't get floating point status")); fill_fpregset (regcache, &fpregs, regnum); - if (ptrace (PTRACE_POKEUSR_AREA, tid, (long) &parea) < 0) + if (ptrace (PTRACE_POKEUSR_AREA, tid, (long) &parea, 0) < 0) perror_with_name (_("Couldn't write floating point status")); } -/* Fetch all registers in the kernel's register set whose number is REGSET, - whose size is REGSIZE, and whose layout is described by REGMAP, from - process/thread TID and store their values in GDB's register cache. */ +/* Fetch all registers in the kernel's register set whose number is + REGSET_ID, whose size is REGSIZE, and whose layout is described by + REGSET, from process/thread TID and store their values in GDB's + register cache. */ static void fetch_regset (struct regcache *regcache, int tid, - int regset, int regsize, const short *regmap) + int regset_id, int regsize, const struct regset *regset) { gdb_byte *buf = alloca (regsize); struct iovec iov; @@ -311,23 +300,23 @@ fetch_regset (struct regcache *regcache, int tid, iov.iov_base = buf; iov.iov_len = regsize; - if (ptrace (PTRACE_GETREGSET, tid, (long) regset, (long) &iov) < 0) + if (ptrace (PTRACE_GETREGSET, tid, (long) regset_id, (long) &iov) < 0) { if (errno == ENODATA) - s390_native_supply (regcache, regmap, NULL); + regcache_supply_regset (regset, regcache, -1, NULL, regsize); else perror_with_name (_("Couldn't get register set")); } else - s390_native_supply (regcache, regmap, buf); + regcache_supply_regset (regset, regcache, -1, buf, regsize); } -/* Store all registers in the kernel's register set whose number is REGSET, - whose size is REGSIZE, and whose layout is described by REGMAP, from - GDB's register cache back to process/thread TID. */ +/* Store all registers in the kernel's register set whose number is + REGSET_ID, whose size is REGSIZE, and whose layout is described by + REGSET, from GDB's register cache back to process/thread TID. */ static void store_regset (struct regcache *regcache, int tid, - int regset, int regsize, const short *regmap) + int regset_id, int regsize, const struct regset *regset) { gdb_byte *buf = alloca (regsize); struct iovec iov; @@ -335,12 +324,12 @@ store_regset (struct regcache *regcache, int tid, iov.iov_base = buf; iov.iov_len = regsize; - if (ptrace (PTRACE_GETREGSET, tid, (long) regset, (long) &iov) < 0) + if (ptrace (PTRACE_GETREGSET, tid, (long) regset_id, (long) &iov) < 0) perror_with_name (_("Couldn't get register set")); - s390_native_collect (regcache, regmap, -1, buf); + regcache_collect_regset (regset, regcache, -1, buf, regsize); - if (ptrace (PTRACE_SETREGSET, tid, (long) regset, (long) &iov) < 0) + if (ptrace (PTRACE_SETREGSET, tid, (long) regset_id, (long) &iov) < 0) perror_with_name (_("Couldn't set register set")); } @@ -379,17 +368,29 @@ s390_linux_fetch_inferior_registers (struct target_ops *ops, if (regnum == -1 || regnum == S390_LAST_BREAK_REGNUM) fetch_regset (regcache, tid, NT_S390_LAST_BREAK, 8, (gdbarch_ptr_bit (get_regcache_arch (regcache)) == 32 - ? s390_regmap_last_break : s390x_regmap_last_break)); + ? &s390_last_break_regset : &s390x_last_break_regset)); if (have_regset_system_call) if (regnum == -1 || regnum == S390_SYSTEM_CALL_REGNUM) fetch_regset (regcache, tid, NT_S390_SYSTEM_CALL, 4, - s390_regmap_system_call); + &s390_system_call_regset); if (have_regset_tdb) if (regnum == -1 || S390_IS_TDBREGSET_REGNUM (regnum)) fetch_regset (regcache, tid, NT_S390_TDB, s390_sizeof_tdbregset, - s390_regmap_tdb); + &s390_tdb_regset); + + if (have_regset_vxrs) + { + if (regnum == -1 || (regnum >= S390_V0_LOWER_REGNUM + && regnum <= S390_V15_LOWER_REGNUM)) + fetch_regset (regcache, tid, NT_S390_VXRS_LOW, 16 * 8, + &s390_vxrs_low_regset); + if (regnum == -1 || (regnum >= S390_V16_REGNUM + && regnum <= S390_V31_REGNUM)) + fetch_regset (regcache, tid, NT_S390_VXRS_HIGH, 16 * 16, + &s390_vxrs_high_regset); + } } /* Store register REGNUM back into the child process. If REGNUM is @@ -411,7 +412,19 @@ s390_linux_store_inferior_registers (struct target_ops *ops, if (have_regset_system_call) if (regnum == -1 || regnum == S390_SYSTEM_CALL_REGNUM) store_regset (regcache, tid, NT_S390_SYSTEM_CALL, 4, - s390_regmap_system_call); + &s390_system_call_regset); + + if (have_regset_vxrs) + { + if (regnum == -1 || (regnum >= S390_V0_LOWER_REGNUM + && regnum <= S390_V15_LOWER_REGNUM)) + store_regset (regcache, tid, NT_S390_VXRS_LOW, 16 * 8, + &s390_vxrs_low_regset); + if (regnum == -1 || (regnum >= S390_V16_REGNUM + && regnum <= S390_V31_REGNUM)) + store_regset (regcache, tid, NT_S390_VXRS_HIGH, 16 * 16, + &s390_vxrs_high_regset); + } } @@ -433,7 +446,7 @@ struct watch_area static struct watch_area *watch_base = NULL; static int -s390_stopped_by_watchpoint (void) +s390_stopped_by_watchpoint (struct target_ops *ops) { per_lowcore_bits per_lowcore; ptrace_area parea; @@ -446,7 +459,7 @@ s390_stopped_by_watchpoint (void) parea.len = sizeof (per_lowcore); parea.process_addr = (addr_t) & per_lowcore; parea.kernel_addr = offsetof (struct user_regs_struct, per_info.lowcore); - if (ptrace (PTRACE_PEEKUSR_AREA, s390_inferior_tid (), &parea) < 0) + if (ptrace (PTRACE_PEEKUSR_AREA, s390_inferior_tid (), &parea, 0) < 0) perror_with_name (_("Couldn't retrieve watchpoint status")); result = (per_lowcore.perc_storage_alteration == 1 @@ -456,15 +469,17 @@ s390_stopped_by_watchpoint (void) { /* Do not report this watchpoint again. */ memset (&per_lowcore, 0, sizeof (per_lowcore)); - if (ptrace (PTRACE_POKEUSR_AREA, s390_inferior_tid (), &parea) < 0) + if (ptrace (PTRACE_POKEUSR_AREA, s390_inferior_tid (), &parea, 0) < 0) perror_with_name (_("Couldn't clear watchpoint status")); } return result; } +/* Each time before resuming a thread, update its PER info. */ + static void -s390_fix_watch_points (struct lwp_info *lp) +s390_prepare_to_resume (struct lwp_info *lp) { int tid; @@ -474,6 +489,12 @@ s390_fix_watch_points (struct lwp_info *lp) CORE_ADDR watch_lo_addr = (CORE_ADDR)-1, watch_hi_addr = 0; struct watch_area *area; + if (lp->arch_private == NULL + || !lp->arch_private->per_info_changed) + return; + + lp->arch_private->per_info_changed = 0; + tid = ptid_get_lwp (lp->ptid); if (tid == 0) tid = ptid_get_pid (lp->ptid); @@ -487,7 +508,7 @@ s390_fix_watch_points (struct lwp_info *lp) parea.len = sizeof (per_info); parea.process_addr = (addr_t) & per_info; parea.kernel_addr = offsetof (struct user_regs_struct, per_info); - if (ptrace (PTRACE_PEEKUSR_AREA, tid, &parea) < 0) + if (ptrace (PTRACE_PEEKUSR_AREA, tid, &parea, 0) < 0) perror_with_name (_("Couldn't retrieve watchpoint status")); if (watch_base) @@ -503,16 +524,41 @@ s390_fix_watch_points (struct lwp_info *lp) per_info.starting_addr = watch_lo_addr; per_info.ending_addr = watch_hi_addr; - if (ptrace (PTRACE_POKEUSR_AREA, tid, &parea) < 0) + if (ptrace (PTRACE_POKEUSR_AREA, tid, &parea, 0) < 0) perror_with_name (_("Couldn't modify watchpoint status")); } +/* Make sure that LP is stopped and mark its PER info as changed, so + the next resume will update it. */ + +static void +s390_refresh_per_info (struct lwp_info *lp) +{ + if (lp->arch_private == NULL) + lp->arch_private = XCNEW (struct arch_lwp_info); + + lp->arch_private->per_info_changed = 1; + + if (!lp->stopped) + linux_stop_lwp (lp); +} + +/* When attaching to a new thread, mark its PER info as changed. */ + +static void +s390_new_thread (struct lwp_info *lp) +{ + lp->arch_private = XCNEW (struct arch_lwp_info); + lp->arch_private->per_info_changed = 1; +} + static int -s390_insert_watchpoint (CORE_ADDR addr, int len, int type, +s390_insert_watchpoint (struct target_ops *self, + CORE_ADDR addr, int len, enum target_hw_bp_type type, struct expression *cond) { struct lwp_info *lp; - struct watch_area *area = xmalloc (sizeof (struct watch_area)); + struct watch_area *area = XNEW (struct watch_area); if (!area) return -1; @@ -524,12 +570,13 @@ s390_insert_watchpoint (CORE_ADDR addr, int len, int type, watch_base = area; ALL_LWPS (lp) - s390_fix_watch_points (lp); + s390_refresh_per_info (lp); return 0; } static int -s390_remove_watchpoint (CORE_ADDR addr, int len, int type, +s390_remove_watchpoint (struct target_ops *self, + CORE_ADDR addr, int len, enum target_hw_bp_type type, struct expression *cond) { struct lwp_info *lp; @@ -552,18 +599,20 @@ s390_remove_watchpoint (CORE_ADDR addr, int len, int type, xfree (area); ALL_LWPS (lp) - s390_fix_watch_points (lp); + s390_refresh_per_info (lp); return 0; } static int -s390_can_use_hw_breakpoint (int type, int cnt, int othertype) +s390_can_use_hw_breakpoint (struct target_ops *self, + enum bptype type, int cnt, int othertype) { return type == bp_hardware_watchpoint; } static int -s390_region_ok_for_hw_watchpoint (CORE_ADDR addr, int cnt) +s390_region_ok_for_hw_watchpoint (struct target_ops *self, + CORE_ADDR addr, int cnt) { return 1; } @@ -610,19 +659,6 @@ s390_auxv_parse (struct target_ops *ops, gdb_byte **readptr, return 1; } -#ifdef __s390x__ -static unsigned long -s390_get_hwcap (void) -{ - CORE_ADDR field; - - if (target_auxv_search (¤t_target, AT_HWCAP, &field)) - return (unsigned long) field; - - return 0; -} -#endif - static const struct target_desc * s390_read_description (struct target_ops *ops) { @@ -633,27 +669,41 @@ s390_read_description (struct target_ops *ops) have_regset_system_call = check_regset (tid, NT_S390_SYSTEM_CALL, 4); -#ifdef __s390x__ /* If GDB itself is compiled as 64-bit, we are running on a machine in z/Architecture mode. If the target is running in 64-bit addressing mode, report s390x architecture. If the target is running in 31-bit addressing mode, but the kernel supports using 64-bit registers in that mode, report s390 architecture with 64-bit GPRs. */ - - have_regset_tdb = (s390_get_hwcap () & HWCAP_S390_TE) ? - check_regset (tid, NT_S390_TDB, s390_sizeof_tdbregset) : 0; - - if (s390_target_wordsize () == 8) - return (have_regset_tdb ? tdesc_s390x_te_linux64 : - have_regset_system_call? tdesc_s390x_linux64v2 : - have_regset_last_break? tdesc_s390x_linux64v1 : - tdesc_s390x_linux64); - - if (s390_get_hwcap () & HWCAP_S390_HIGH_GPRS) - return (have_regset_tdb ? tdesc_s390_te_linux64 : - have_regset_system_call? tdesc_s390_linux64v2 : - have_regset_last_break? tdesc_s390_linux64v1 : - tdesc_s390_linux64); +#ifdef __s390x__ + { + CORE_ADDR hwcap = 0; + + target_auxv_search (¤t_target, AT_HWCAP, &hwcap); + have_regset_tdb = (hwcap & HWCAP_S390_TE) + && check_regset (tid, NT_S390_TDB, s390_sizeof_tdbregset); + + have_regset_vxrs = (hwcap & HWCAP_S390_VX) + && check_regset (tid, NT_S390_VXRS_LOW, 16 * 8) + && check_regset (tid, NT_S390_VXRS_HIGH, 16 * 16); + + if (s390_target_wordsize () == 8) + return (have_regset_vxrs ? + (have_regset_tdb ? tdesc_s390x_tevx_linux64 : + tdesc_s390x_vx_linux64) : + have_regset_tdb ? tdesc_s390x_te_linux64 : + have_regset_system_call ? tdesc_s390x_linux64v2 : + have_regset_last_break ? tdesc_s390x_linux64v1 : + tdesc_s390x_linux64); + + if (hwcap & HWCAP_S390_HIGH_GPRS) + return (have_regset_vxrs ? + (have_regset_tdb ? tdesc_s390_tevx_linux64 : + tdesc_s390_vx_linux64) : + have_regset_tdb ? tdesc_s390_te_linux64 : + have_regset_system_call ? tdesc_s390_linux64v2 : + have_regset_last_break ? tdesc_s390_linux64v1 : + tdesc_s390_linux64); + } #endif /* If GDB itself is compiled as 31-bit, or if we're running a 31-bit inferior @@ -692,5 +742,6 @@ _initialize_s390_nat (void) /* Register the target. */ linux_nat_add_target (t); - linux_nat_set_new_thread (t, s390_fix_watch_points); + linux_nat_set_new_thread (t, s390_new_thread); + linux_nat_set_prepare_to_resume (t, s390_prepare_to_resume); }