X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=gdb%2Fs390-linux-nat.c;h=e91297b6e011d047b2e8ffe658b0ca333c6cf982;hb=93daf339a4d9496ecde15d3b1e852fbdb38c07d0;hp=367b6109ff007cf7c7f5771ccec01fdfd8c934dc;hpb=550bdf96cae94bc3e6c0f7e7e9a6793399dd8fe6;p=deliverable%2Fbinutils-gdb.git diff --git a/gdb/s390-linux-nat.c b/gdb/s390-linux-nat.c index 367b6109ff..e91297b6e0 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,24 +27,25 @@ #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; @@ -148,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; } @@ -212,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); @@ -229,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")); } @@ -249,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); @@ -266,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")); } @@ -283,7 +294,7 @@ static void fetch_regset (struct regcache *regcache, int tid, int regset_id, int regsize, const struct regset *regset) { - gdb_byte *buf = alloca (regsize); + void *buf = alloca (regsize); struct iovec iov; iov.iov_base = buf; @@ -307,7 +318,7 @@ static void store_regset (struct regcache *regcache, int tid, int regset_id, int regsize, const struct regset *regset) { - gdb_byte *buf = alloca (regsize); + void *buf = alloca (regsize); struct iovec iov; iov.iov_base = buf; @@ -327,7 +338,7 @@ store_regset (struct regcache *regcache, int tid, static int check_regset (int tid, int regset, int regsize) { - gdb_byte *buf = alloca (regsize); + void *buf = alloca (regsize); struct iovec iov; iov.iov_base = buf; @@ -448,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 @@ -458,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; @@ -476,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); @@ -489,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) @@ -505,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; @@ -527,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; @@ -556,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; } @@ -699,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); }