X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=gdb%2Fs390-linux-nat.c;h=ae0e2c6d94106d244ed03638a66a0c8fad823c56;hb=173981bc49c9e8fce9271cb47714952dbe2ec627;hp=3cfa0f5c1a8ffacc4fe99dda523d3b95869a7160;hpb=32d0add0a654c1204ab71dc8a55d9374538c4b33;p=deliverable%2Fbinutils-gdb.git diff --git a/gdb/s390-linux-nat.c b/gdb/s390-linux-nat.c index 3cfa0f5c1a..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-2015 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. @@ -27,28 +27,30 @@ #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; /* Register map for 32-bit executables running under a 64-bit kernel. */ @@ -147,19 +149,29 @@ 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 ((gdb_byte *) regp + S390_PSWM_OFFSET, 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 ((gdb_byte *) regp + S390_PSWA_OFFSET, 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; } @@ -211,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); @@ -228,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")); } @@ -248,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); @@ -265,12 +277,12 @@ 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")); } @@ -367,6 +379,18 @@ s390_linux_fetch_inferior_registers (struct target_ops *ops, if (regnum == -1 || S390_IS_TDBREGSET_REGNUM (regnum)) fetch_regset (regcache, tid, NT_S390_TDB, s390_sizeof_tdbregset, &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 @@ -389,6 +413,18 @@ s390_linux_store_inferior_registers (struct target_ops *ops, if (regnum == -1 || regnum == S390_SYSTEM_CALL_REGNUM) store_regset (regcache, tid, NT_S390_SYSTEM_CALL, 4, &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); + } } @@ -423,7 +459,7 @@ s390_stopped_by_watchpoint (struct target_ops *ops) 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 @@ -433,15 +469,17 @@ s390_stopped_by_watchpoint (struct target_ops *ops) { /* 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; @@ -451,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); @@ -464,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) @@ -480,17 +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 (struct target_ops *self, - CORE_ADDR addr, int len, int type, + 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; @@ -502,13 +570,13 @@ s390_insert_watchpoint (struct target_ops *self, watch_base = area; ALL_LWPS (lp) - s390_fix_watch_points (lp); + s390_refresh_per_info (lp); return 0; } static int s390_remove_watchpoint (struct target_ops *self, - CORE_ADDR addr, int len, int type, + CORE_ADDR addr, int len, enum target_hw_bp_type type, struct expression *cond) { struct lwp_info *lp; @@ -531,13 +599,13 @@ s390_remove_watchpoint (struct target_ops *self, xfree (area); ALL_LWPS (lp) - s390_fix_watch_points (lp); + s390_refresh_per_info (lp); return 0; } static int s390_can_use_hw_breakpoint (struct target_ops *self, - int type, int cnt, int othertype) + enum bptype type, int cnt, int othertype) { return type == bp_hardware_watchpoint; } @@ -591,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) { @@ -614,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 @@ -673,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); }