X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=gdb%2Fs390-linux-nat.c;h=b549246e7c8e0259aca43cfd8e55bbcc4eb234bf;hb=373c3dad74da78c46bc1fe4280a26d07e5b54cdd;hp=4cd3192a42089e74beacfa7363c13cab791c6798;hpb=2492f0d005f0390eabb3deb58aa7db7fcd716763;p=binutils-gdb.git diff --git a/gdb/s390-linux-nat.c b/gdb/s390-linux-nat.c index 4cd3192a420..b549246e7c8 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,25 +27,18 @@ #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 - -#ifndef PTRACE_SETREGSET -#define PTRACE_SETREGSET 0x4205 -#endif - /* Per-thread arch-specific data. */ struct arch_lwp_info @@ -230,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); @@ -247,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")); } @@ -267,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); @@ -284,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")); } @@ -301,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; @@ -325,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; @@ -345,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; @@ -437,36 +430,158 @@ s390_linux_store_inferior_registers (struct target_ops *ops, /* Hardware-assisted watchpoint handling. */ -/* We maintain a list of all currently active watchpoints in order - to properly handle watchpoint removal. +/* For each process we maintain a list of all currently active + watchpoints, in order to properly handle watchpoint removal. The only thing we actually need is the total address space area spanned by the watchpoints. */ -struct watch_area +typedef struct watch_area { - struct watch_area *next; CORE_ADDR lo_addr; CORE_ADDR hi_addr; +} s390_watch_area; + +DEF_VEC_O (s390_watch_area); + +/* Hardware debug state. */ + +struct s390_debug_reg_state +{ + VEC_s390_watch_area *watch_areas; +}; + +/* Per-process data. */ + +struct s390_process_info +{ + struct s390_process_info *next; + pid_t pid; + struct s390_debug_reg_state state; }; -static struct watch_area *watch_base = NULL; +static struct s390_process_info *s390_process_list = NULL; + +/* Find process data for process PID. */ + +static struct s390_process_info * +s390_find_process_pid (pid_t pid) +{ + struct s390_process_info *proc; + + for (proc = s390_process_list; proc; proc = proc->next) + if (proc->pid == pid) + return proc; + + return NULL; +} + +/* Add process data for process PID. Returns newly allocated info + object. */ + +static struct s390_process_info * +s390_add_process (pid_t pid) +{ + struct s390_process_info *proc = XCNEW (struct s390_process_info); + + proc->pid = pid; + proc->next = s390_process_list; + s390_process_list = proc; + + return proc; +} + +/* Get data specific info for process PID, creating it if necessary. + Never returns NULL. */ + +static struct s390_process_info * +s390_process_info_get (pid_t pid) +{ + struct s390_process_info *proc; + + proc = s390_find_process_pid (pid); + if (proc == NULL) + proc = s390_add_process (pid); + + return proc; +} + +/* Get hardware debug state for process PID. */ + +static struct s390_debug_reg_state * +s390_get_debug_reg_state (pid_t pid) +{ + return &s390_process_info_get (pid)->state; +} + +/* Called whenever GDB is no longer debugging process PID. It deletes + data structures that keep track of hardware debug state. */ + +static void +s390_forget_process (pid_t pid) +{ + struct s390_process_info *proc, **proc_link; + + proc = s390_process_list; + proc_link = &s390_process_list; + + while (proc != NULL) + { + if (proc->pid == pid) + { + VEC_free (s390_watch_area, proc->state.watch_areas); + *proc_link = proc->next; + xfree (proc); + return; + } + + proc_link = &proc->next; + proc = *proc_link; + } +} + +/* linux_nat_new_fork hook. */ + +static void +s390_linux_new_fork (struct lwp_info *parent, pid_t child_pid) +{ + pid_t parent_pid; + struct s390_debug_reg_state *parent_state; + struct s390_debug_reg_state *child_state; + + /* NULL means no watchpoint has ever been set in the parent. In + that case, there's nothing to do. */ + if (lwp_arch_private_info (parent) == NULL) + return; + + /* GDB core assumes the child inherits the watchpoints/hw breakpoints of + the parent. So copy the debug state from parent to child. */ + + parent_pid = ptid_get_pid (parent->ptid); + parent_state = s390_get_debug_reg_state (parent_pid); + child_state = s390_get_debug_reg_state (child_pid); + + child_state->watch_areas = VEC_copy (s390_watch_area, + parent_state->watch_areas); +} static int s390_stopped_by_watchpoint (struct target_ops *ops) { + struct s390_debug_reg_state *state + = s390_get_debug_reg_state (ptid_get_pid (inferior_ptid)); per_lowcore_bits per_lowcore; ptrace_area parea; int result; /* Speed up common case. */ - if (!watch_base) + if (VEC_empty (s390_watch_area, state->watch_areas)) return 0; 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 @@ -476,7 +591,7 @@ 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")); } @@ -489,37 +604,42 @@ static void s390_prepare_to_resume (struct lwp_info *lp) { int tid; + pid_t pid = ptid_get_pid (ptid_of_lwp (lp)); per_struct per_info; ptrace_area parea; CORE_ADDR watch_lo_addr = (CORE_ADDR)-1, watch_hi_addr = 0; - struct watch_area *area; + unsigned ix; + s390_watch_area *area; + struct arch_lwp_info *lp_priv = lwp_arch_private_info (lp); + struct s390_debug_reg_state *state = s390_get_debug_reg_state (pid); - if (lp->arch_private == NULL - || !lp->arch_private->per_info_changed) + if (lp_priv == NULL || !lp_priv->per_info_changed) return; - lp->arch_private->per_info_changed = 0; + lp_priv->per_info_changed = 0; - tid = ptid_get_lwp (lp->ptid); + tid = ptid_get_lwp (ptid_of_lwp (lp)); if (tid == 0) - tid = ptid_get_pid (lp->ptid); - - for (area = watch_base; area; area = area->next) - { - watch_lo_addr = min (watch_lo_addr, area->lo_addr); - watch_hi_addr = max (watch_hi_addr, area->hi_addr); - } + tid = pid; 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) + if (!VEC_empty (s390_watch_area, state->watch_areas)) { + for (ix = 0; + VEC_iterate (s390_watch_area, state->watch_areas, ix, area); + ix++) + { + watch_lo_addr = min (watch_lo_addr, area->lo_addr); + watch_hi_addr = max (watch_hi_addr, area->hi_addr); + } + per_info.control_regs.bits.em_storage_alteration = 1; per_info.control_regs.bits.storage_alt_space_ctl = 1; } @@ -531,23 +651,19 @@ s390_prepare_to_resume (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. */ +/* Mark the PER info as changed, so the next resume will update it. */ static void -s390_refresh_per_info (struct lwp_info *lp) +s390_mark_per_info_changed (struct lwp_info *lp) { - if (lp->arch_private == NULL) - lp->arch_private = XCNEW (struct arch_lwp_info); + if (lwp_arch_private_info (lp) == NULL) + lwp_set_arch_private_info (lp, XCNEW (struct arch_lwp_info)); - lp->arch_private->per_info_changed = 1; - - if (!lp->stopped) - linux_stop_lwp (lp); + lwp_arch_private_info (lp)->per_info_changed = 1; } /* When attaching to a new thread, mark its PER info as changed. */ @@ -555,64 +671,77 @@ s390_refresh_per_info (struct lwp_info *lp) static void s390_new_thread (struct lwp_info *lp) { - lp->arch_private = XCNEW (struct arch_lwp_info); - lp->arch_private->per_info_changed = 1; + s390_mark_per_info_changed (lp); } +/* Iterator callback for s390_refresh_per_info. */ + static int -s390_insert_watchpoint (struct target_ops *self, - CORE_ADDR addr, int len, int type, - struct expression *cond) +s390_refresh_per_info_cb (struct lwp_info *lp, void *arg) { - struct lwp_info *lp; - struct watch_area *area = xmalloc (sizeof (struct watch_area)); + s390_mark_per_info_changed (lp); - if (!area) - return -1; + if (!lwp_is_stopped (lp)) + linux_stop_lwp (lp); + return 0; +} - area->lo_addr = addr; - area->hi_addr = addr + len - 1; +/* Make sure that threads are stopped and mark PER info as changed. */ - area->next = watch_base; - watch_base = area; +static int +s390_refresh_per_info (void) +{ + ptid_t pid_ptid = pid_to_ptid (ptid_get_pid (current_lwp_ptid ())); - ALL_LWPS (lp) - s390_refresh_per_info (lp); + iterate_over_lwps (pid_ptid, s390_refresh_per_info_cb, NULL); return 0; } static int -s390_remove_watchpoint (struct target_ops *self, - 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, **parea; + s390_watch_area area; + struct s390_debug_reg_state *state + = s390_get_debug_reg_state (ptid_get_pid (inferior_ptid)); - for (parea = &watch_base; *parea; parea = &(*parea)->next) - if ((*parea)->lo_addr == addr - && (*parea)->hi_addr == addr + len - 1) - break; + area.lo_addr = addr; + area.hi_addr = addr + len - 1; + VEC_safe_push (s390_watch_area, state->watch_areas, &area); - if (!*parea) + return s390_refresh_per_info (); +} + +static int +s390_remove_watchpoint (struct target_ops *self, + CORE_ADDR addr, int len, enum target_hw_bp_type type, + struct expression *cond) +{ + unsigned ix; + s390_watch_area *area; + struct s390_debug_reg_state *state + = s390_get_debug_reg_state (ptid_get_pid (inferior_ptid)); + + for (ix = 0; + VEC_iterate (s390_watch_area, state->watch_areas, ix, area); + ix++) { - fprintf_unfiltered (gdb_stderr, - "Attempt to remove nonexistent watchpoint.\n"); - return -1; + if (area->lo_addr == addr && area->hi_addr == addr + len - 1) + { + VEC_unordered_remove (s390_watch_area, state->watch_areas, ix); + return s390_refresh_per_info (); + } } - area = *parea; - *parea = area->next; - xfree (area); - - ALL_LWPS (lp) - s390_refresh_per_info (lp); - return 0; + fprintf_unfiltered (gdb_stderr, + "Attempt to remove nonexistent watchpoint.\n"); + return -1; } 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; } @@ -751,4 +880,6 @@ _initialize_s390_nat (void) linux_nat_add_target (t); linux_nat_set_new_thread (t, s390_new_thread); linux_nat_set_prepare_to_resume (t, s390_prepare_to_resume); + linux_nat_set_forget_process (t, s390_forget_process); + linux_nat_set_new_fork (t, s390_linux_new_fork); }