diff options
| -rw-r--r-- | arch/ia64/kernel/process.c | 6 | ||||
| -rw-r--r-- | arch/ia64/kernel/ptrace.c | 82 | ||||
| -rw-r--r-- | include/asm-ia64/ptrace.h | 7 | ||||
| -rw-r--r-- | include/asm-ia64/thread_info.h | 2 |
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 | ||
| 189 | static int pal_halt = 1; | 195 | static 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 | ||
| 550 | static long | ||
| 551 | ia64_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 | |||
| 570 | typedef long (*syncfunc_t)(struct task_struct *, struct switch_stack *, | ||
| 571 | unsigned long, unsigned long); | ||
| 572 | |||
| 573 | static 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 | */ | ||
| 597 | void 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 | */ | ||
| 608 | void 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 | |||
| 550 | static inline int | 616 | static inline int |
| 551 | thread_matches (struct task_struct *thread, unsigned long addr) | 617 | thread_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|\ |
