aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/ia64/kernel/process.c6
-rw-r--r--arch/ia64/kernel/ptrace.c82
-rw-r--r--include/asm-ia64/ptrace.h7
-rw-r--r--include/asm-ia64/thread_info.h2
4 files changed, 97 insertions, 0 deletions
diff --git a/arch/ia64/kernel/process.c b/arch/ia64/kernel/process.c
index 5c9efe626563..be6c6f7be027 100644
--- a/arch/ia64/kernel/process.c
+++ b/arch/ia64/kernel/process.c
@@ -163,6 +163,8 @@ void tsk_clear_notify_resume(struct task_struct *tsk)
163 if (tsk->thread.pfm_needs_checking) 163 if (tsk->thread.pfm_needs_checking)
164 return; 164 return;
165#endif 165#endif
166 if (test_ti_thread_flag(task_thread_info(tsk), TIF_RESTORE_RSE))
167 return;
166 clear_ti_thread_flag(task_thread_info(tsk), TIF_NOTIFY_RESUME); 168 clear_ti_thread_flag(task_thread_info(tsk), TIF_NOTIFY_RESUME);
167} 169}
168 170
@@ -184,6 +186,10 @@ do_notify_resume_user (sigset_t *unused, struct sigscratch *scr, long in_syscall
184 /* deal with pending signal delivery */ 186 /* deal with pending signal delivery */
185 if (test_thread_flag(TIF_SIGPENDING)||test_thread_flag(TIF_RESTORE_SIGMASK)) 187 if (test_thread_flag(TIF_SIGPENDING)||test_thread_flag(TIF_RESTORE_SIGMASK))
186 ia64_do_signal(scr, in_syscall); 188 ia64_do_signal(scr, in_syscall);
189
190 /* copy user rbs to kernel rbs */
191 if (unlikely(test_thread_flag(TIF_RESTORE_RSE)))
192 ia64_sync_krbs();
187} 193}
188 194
189static int pal_halt = 1; 195static int pal_halt = 1;
diff --git a/arch/ia64/kernel/ptrace.c b/arch/ia64/kernel/ptrace.c
index 2e96f17b2f3b..2de5a524a0ee 100644
--- a/arch/ia64/kernel/ptrace.c
+++ b/arch/ia64/kernel/ptrace.c
@@ -547,6 +547,72 @@ ia64_sync_user_rbs (struct task_struct *child, struct switch_stack *sw,
547 return 0; 547 return 0;
548} 548}
549 549
550static long
551ia64_sync_kernel_rbs (struct task_struct *child, struct switch_stack *sw,
552 unsigned long user_rbs_start, unsigned long user_rbs_end)
553{
554 unsigned long addr, val;
555 long ret;
556
557 /* now copy word for word from user rbs to kernel rbs: */
558 for (addr = user_rbs_start; addr < user_rbs_end; addr += 8) {
559 if (access_process_vm(child, addr, &val, sizeof(val), 0)
560 != sizeof(val))
561 return -EIO;
562
563 ret = ia64_poke(child, sw, user_rbs_end, addr, val);
564 if (ret < 0)
565 return ret;
566 }
567 return 0;
568}
569
570typedef long (*syncfunc_t)(struct task_struct *, struct switch_stack *,
571 unsigned long, unsigned long);
572
573static void do_sync_rbs(struct unw_frame_info *info, void *arg)
574{
575 struct pt_regs *pt;
576 unsigned long urbs_end;
577 syncfunc_t fn = arg;
578
579 if (unw_unwind_to_user(info) < 0)
580 return;
581 pt = task_pt_regs(info->task);
582 urbs_end = ia64_get_user_rbs_end(info->task, pt, NULL);
583
584 fn(info->task, info->sw, pt->ar_bspstore, urbs_end);
585}
586
587/*
588 * when a thread is stopped (ptraced), debugger might change thread's user
589 * stack (change memory directly), and we must avoid the RSE stored in kernel
590 * to override user stack (user space's RSE is newer than kernel's in the
591 * case). To workaround the issue, we copy kernel RSE to user RSE before the
592 * task is stopped, so user RSE has updated data. we then copy user RSE to
593 * kernel after the task is resummed from traced stop and kernel will use the
594 * newer RSE to return to user. TIF_RESTORE_RSE is the flag to indicate we need
595 * synchronize user RSE to kernel.
596 */
597void ia64_ptrace_stop(void)
598{
599 if (test_and_set_tsk_thread_flag(current, TIF_RESTORE_RSE))
600 return;
601 tsk_set_notify_resume(current);
602 unw_init_running(do_sync_rbs, ia64_sync_user_rbs);
603}
604
605/*
606 * This is called to read back the register backing store.
607 */
608void ia64_sync_krbs(void)
609{
610 clear_tsk_thread_flag(current, TIF_RESTORE_RSE);
611 tsk_clear_notify_resume(current);
612
613 unw_init_running(do_sync_rbs, ia64_sync_kernel_rbs);
614}
615
550static inline int 616static inline int
551thread_matches (struct task_struct *thread, unsigned long addr) 617thread_matches (struct task_struct *thread, unsigned long addr)
552{ 618{
@@ -1422,6 +1488,7 @@ sys_ptrace (long request, pid_t pid, unsigned long addr, unsigned long data)
1422 struct task_struct *child; 1488 struct task_struct *child;
1423 struct switch_stack *sw; 1489 struct switch_stack *sw;
1424 long ret; 1490 long ret;
1491 struct unw_frame_info info;
1425 1492
1426 lock_kernel(); 1493 lock_kernel();
1427 ret = -EPERM; 1494 ret = -EPERM;
@@ -1453,6 +1520,8 @@ sys_ptrace (long request, pid_t pid, unsigned long addr, unsigned long data)
1453 1520
1454 if (request == PTRACE_ATTACH) { 1521 if (request == PTRACE_ATTACH) {
1455 ret = ptrace_attach(child); 1522 ret = ptrace_attach(child);
1523 if (!ret)
1524 arch_ptrace_attach(child);
1456 goto out_tsk; 1525 goto out_tsk;
1457 } 1526 }
1458 1527
@@ -1481,6 +1550,11 @@ sys_ptrace (long request, pid_t pid, unsigned long addr, unsigned long data)
1481 /* write the word at location addr */ 1550 /* write the word at location addr */
1482 urbs_end = ia64_get_user_rbs_end(child, pt, NULL); 1551 urbs_end = ia64_get_user_rbs_end(child, pt, NULL);
1483 ret = ia64_poke(child, sw, urbs_end, addr, data); 1552 ret = ia64_poke(child, sw, urbs_end, addr, data);
1553
1554 /* Make sure user RBS has the latest data */
1555 unw_init_from_blocked_task(&info, child);
1556 do_sync_rbs(&info, ia64_sync_user_rbs);
1557
1484 goto out_tsk; 1558 goto out_tsk;
1485 1559
1486 case PTRACE_PEEKUSR: 1560 case PTRACE_PEEKUSR:
@@ -1634,6 +1708,10 @@ syscall_trace_enter (long arg0, long arg1, long arg2, long arg3,
1634 && (current->ptrace & PT_PTRACED)) 1708 && (current->ptrace & PT_PTRACED))
1635 syscall_trace(); 1709 syscall_trace();
1636 1710
1711 /* copy user rbs to kernel rbs */
1712 if (test_thread_flag(TIF_RESTORE_RSE))
1713 ia64_sync_krbs();
1714
1637 if (unlikely(current->audit_context)) { 1715 if (unlikely(current->audit_context)) {
1638 long syscall; 1716 long syscall;
1639 int arch; 1717 int arch;
@@ -1671,4 +1749,8 @@ syscall_trace_leave (long arg0, long arg1, long arg2, long arg3,
1671 || test_thread_flag(TIF_SINGLESTEP)) 1749 || test_thread_flag(TIF_SINGLESTEP))
1672 && (current->ptrace & PT_PTRACED)) 1750 && (current->ptrace & PT_PTRACED))
1673 syscall_trace(); 1751 syscall_trace();
1752
1753 /* copy user rbs to kernel rbs */
1754 if (test_thread_flag(TIF_RESTORE_RSE))
1755 ia64_sync_krbs();
1674} 1756}
diff --git a/include/asm-ia64/ptrace.h b/include/asm-ia64/ptrace.h
index f4ef87a36236..13435f778b0c 100644
--- a/include/asm-ia64/ptrace.h
+++ b/include/asm-ia64/ptrace.h
@@ -292,6 +292,7 @@ struct switch_stack {
292 unsigned long, long); 292 unsigned long, long);
293 extern void ia64_flush_fph (struct task_struct *); 293 extern void ia64_flush_fph (struct task_struct *);
294 extern void ia64_sync_fph (struct task_struct *); 294 extern void ia64_sync_fph (struct task_struct *);
295 extern void ia64_sync_krbs(void);
295 extern long ia64_sync_user_rbs (struct task_struct *, struct switch_stack *, 296 extern long ia64_sync_user_rbs (struct task_struct *, struct switch_stack *,
296 unsigned long, unsigned long); 297 unsigned long, unsigned long);
297 298
@@ -303,6 +304,12 @@ struct switch_stack {
303 extern void ia64_increment_ip (struct pt_regs *pt); 304 extern void ia64_increment_ip (struct pt_regs *pt);
304 extern void ia64_decrement_ip (struct pt_regs *pt); 305 extern void ia64_decrement_ip (struct pt_regs *pt);
305 306
307 extern void ia64_ptrace_stop(void);
308 #define arch_ptrace_stop(code, info) \
309 ia64_ptrace_stop()
310 #define arch_ptrace_stop_needed(code, info) \
311 (!test_thread_flag(TIF_RESTORE_RSE))
312
306#endif /* !__KERNEL__ */ 313#endif /* !__KERNEL__ */
307 314
308/* pt_all_user_regs is used for PTRACE_GETREGS PTRACE_SETREGS */ 315/* pt_all_user_regs is used for PTRACE_GETREGS PTRACE_SETREGS */
diff --git a/include/asm-ia64/thread_info.h b/include/asm-ia64/thread_info.h
index 5a2c47957069..93d83cbe0c8c 100644
--- a/include/asm-ia64/thread_info.h
+++ b/include/asm-ia64/thread_info.h
@@ -94,6 +94,7 @@ extern void tsk_clear_notify_resume(struct task_struct *tsk);
94#define TIF_MCA_INIT 18 /* this task is processing MCA or INIT */ 94#define TIF_MCA_INIT 18 /* this task is processing MCA or INIT */
95#define TIF_DB_DISABLED 19 /* debug trap disabled for fsyscall */ 95#define TIF_DB_DISABLED 19 /* debug trap disabled for fsyscall */
96#define TIF_FREEZE 20 /* is freezing for suspend */ 96#define TIF_FREEZE 20 /* is freezing for suspend */
97#define TIF_RESTORE_RSE 21 /* user RBS is newer than kernel RBS */
97 98
98#define _TIF_SYSCALL_TRACE (1 << TIF_SYSCALL_TRACE) 99#define _TIF_SYSCALL_TRACE (1 << TIF_SYSCALL_TRACE)
99#define _TIF_SYSCALL_AUDIT (1 << TIF_SYSCALL_AUDIT) 100#define _TIF_SYSCALL_AUDIT (1 << TIF_SYSCALL_AUDIT)
@@ -107,6 +108,7 @@ extern void tsk_clear_notify_resume(struct task_struct *tsk);
107#define _TIF_MCA_INIT (1 << TIF_MCA_INIT) 108#define _TIF_MCA_INIT (1 << TIF_MCA_INIT)
108#define _TIF_DB_DISABLED (1 << TIF_DB_DISABLED) 109#define _TIF_DB_DISABLED (1 << TIF_DB_DISABLED)
109#define _TIF_FREEZE (1 << TIF_FREEZE) 110#define _TIF_FREEZE (1 << TIF_FREEZE)
111#define _TIF_RESTORE_RSE (1 << TIF_RESTORE_RSE)
110 112
111/* "work to do on user-return" bits */ 113/* "work to do on user-return" bits */
112#define TIF_ALLWORK_MASK (_TIF_SIGPENDING|_TIF_NOTIFY_RESUME|_TIF_SYSCALL_AUDIT|\ 114#define TIF_ALLWORK_MASK (_TIF_SIGPENDING|_TIF_NOTIFY_RESUME|_TIF_SYSCALL_AUDIT|\