S390: Defer PER info update until resume

For multi-threaded inferiors on S390 GNU/Linux targets, GDB tried to
update the PER info via ptrace() in a newly attached thread before
assuring that the thread is stopped.  Depending on the timing, this
could lead to a GDB internal error.  The patch defers the PER info
update until just before resuming the thread.

gdb/ChangeLog:

	* s390-linux-nat.c (struct arch_lwp_info): New.
	(s390_fix_watch_points): Rename to...
	(s390_prepare_to_resume): ...this.  Skip the PER info update
	unless the watch points have changed.
	(s390_refresh_per_info, s390_new_thread): New functions.
	(s390_insert_watchpoint): Call s390_refresh_per_info instead of
	s390_fix_watch_points.
	(s390_remove_watchpoint): Likewise.
	(_initialize_s390_nat): Reflect renaming of s390_fix_watch_points.
	Register s390_prepare_to_resume.
This commit is contained in:
Andreas Arnez 2015-03-11 11:11:44 +01:00 committed by Andreas Krebbel
parent f728387b9a
commit 183961935e
2 changed files with 58 additions and 4 deletions

View File

@ -1,3 +1,16 @@
2015-03-11 Andreas Arnez <arnez@linux.vnet.ibm.com>
* s390-linux-nat.c (struct arch_lwp_info): New.
(s390_fix_watch_points): Rename to...
(s390_prepare_to_resume): ...this. Skip the PER info update
unless the watch points have changed.
(s390_refresh_per_info, s390_new_thread): New functions.
(s390_insert_watchpoint): Call s390_refresh_per_info instead of
s390_fix_watch_points.
(s390_remove_watchpoint): Likewise.
(_initialize_s390_nat): Reflect renaming of s390_fix_watch_points.
Register s390_prepare_to_resume.
2015-03-09 Pedro Alves <palves@redhat.com>
Revert:

View File

@ -46,6 +46,14 @@
#define PTRACE_SETREGSET 0x4205
#endif
/* Per-thread arch-specific data. */
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;
@ -465,8 +473,10 @@ s390_stopped_by_watchpoint (struct target_ops *ops)
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 +486,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);
@ -509,6 +525,30 @@ s390_fix_watch_points (struct lwp_info *lp)
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,
@ -527,7 +567,7 @@ 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;
}
@ -556,7 +596,7 @@ s390_remove_watchpoint (struct target_ops *self,
xfree (area);
ALL_LWPS (lp)
s390_fix_watch_points (lp);
s390_refresh_per_info (lp);
return 0;
}
@ -699,5 +739,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);
}