The last remaining implementation of arch_ptrace_attach is ia64's ptrace_attach_sync_user_rbs which was added at the end of 2007 in commit aa91a2e90044 ("[IA64] Synchronize RBS on PTRACE_ATTACH"). Reading the comments and examining the code ptrace_attach_sync_user_rbs has the sole purpose of saving registers to the stack when ptrace_attach changes TASK_STOPPED to TASK_TRACED. In all other cases arch_ptrace_stop takes care of the register saving. In commit d79fdd6d96f4 ("ptrace: Clean transitions between TASK_STOPPED and TRACED") modified ptrace_attach to wake up the thread and enter ptrace_stop normally even when the thread starts out stopped. This makes ptrace_attach_sync_user_rbs completely unnecessary. So just remove it. I read through the code to verify that ptrace_attach_sync_user_rbs is unnecessary. What I found is that the code is quite dead. Reading ptrace_attach_sync_user_rbs it is easy to see that the it does nothing unless __state == TASK_STOPPED. Calling arch_ptrace_attach (aka ptrace_attach_sync_user_rbs) after ptrace_traceme it is easy to see that because we are talking about the current process the value of __state is TASK_RUNNING. Which means ptrace_attach_sync_user_rbs does nothing. The only other call of arch_ptrace_attach (aka ptrace_attach_sync_user_rbs) is after ptrace_attach. If the task is running (and PTRACE_SEIZE is not specified), a SIGSTOP is sent which results in do_signal_stop setting JOBCTL_TRAP_STOP on the target task (as it is ptraced) and the target task stopping in ptrace_stop with __state == TASK_TRACED. If the task was already stopped then ptrace_attach sets JOBCTL_TRAPPING and JOBCTL_TRAP_STOP, wakes it out of __TASK_STOPPED, and waits until the JOBCTL_TRAPPING_BIT is clear. At which point the task stops in ptrace_stop. In both cases there are a couple of funning excpetions such as if the traced task receiveds a SIGCONT, or is set a fatal signal. However in all of those cases the tracee never stops in __state TASK_STOPPED. Which is a long way of saying that ptrace_attach_sync_user_rbs is guaranteed never to do anything.
Unified · Split
| @@ -139,10 +139,6 @@ static inline long regs_return_value(struct pt_regs *regs) · 138 unmodified lines | |||
| 139 | #define arch_ptrace_stop_needed() \ | 139 | #define arch_ptrace_stop_needed() \ |
| 140 | (!test_thread_flag(TIF_RESTORE_RSE)) | 140 | (!test_thread_flag(TIF_RESTORE_RSE)) |
| 141 | 141 | ||
| 142 | extern void ptrace_attach_sync_user_rbs (struct task_struct *); | ||
| 143 | #define arch_ptrace_attach(child) \ | ||
| 144 | ptrace_attach_sync_user_rbs(child) | ||
| 145 | |||
| 146 | #define arch_has_single_step() (1) | 142 | #define arch_has_single_step() (1) |
| 147 | #define arch_has_block_step() (1) | 143 | #define arch_has_block_step() (1) |
| 148 | 144 | ||
| @@ -617,63 +617,6 @@ void ia64_sync_krbs(void) · 616 unmodified lines | |||
| 617 | unw_init_running(do_sync_rbs, ia64_sync_kernel_rbs); | 617 | unw_init_running(do_sync_rbs, ia64_sync_kernel_rbs); |
| 618 | } | 618 | } |
| 619 | 619 | ||
| 620 | /* | ||
| 621 | * After PTRACE_ATTACH, a thread's register backing store area in user | ||
| 622 | * space is assumed to contain correct data whenever the thread is | ||
| 623 | * stopped. arch_ptrace_stop takes care of this on tracing stops. | ||
| 624 | * But if the child was already stopped for job control when we attach | ||
| 625 | * to it, then it might not ever get into ptrace_stop by the time we | ||
| 626 | * want to examine the user memory containing the RBS. | ||
| 627 | */ | ||
| 628 | void | ||
| 629 | ptrace_attach_sync_user_rbs (struct task_struct *child) | ||
| 630 | { | ||
| 631 | int stopped = 0; | ||
| 632 | struct unw_frame_info info; | ||
| 633 | |||
| 634 | /* | ||
| 635 | * If the child is in TASK_STOPPED, we need to change that to | ||
| 636 | * TASK_TRACED momentarily while we operate on it. This ensures | ||
| 637 | * that the child won't be woken up and return to user mode while | ||
| 638 | * we are doing the sync. (It can only be woken up for SIGKILL.) | ||
| 639 | */ | ||
| 640 | |||
| 641 | read_lock(&tasklist_lock); | ||
| 642 | if (child->sighand) { | ||
| 643 | spin_lock_irq(&child->sighand->siglock); | ||
| 644 | if (READ_ONCE(child->__state) == TASK_STOPPED && | ||
| 645 | !test_and_set_tsk_thread_flag(child, TIF_RESTORE_RSE)) { | ||
| 646 | set_notify_resume(child); | ||
| 647 | |||
| 648 | WRITE_ONCE(child->__state, TASK_TRACED); | ||
| 649 | stopped = 1; | ||
| 650 | } | ||
| 651 | spin_unlock_irq(&child->sighand->siglock); | ||
| 652 | } | ||
| 653 | read_unlock(&tasklist_lock); | ||
| 654 | |||
| 655 | if (!stopped) | ||
| 656 | return; | ||
| 657 | |||
| 658 | unw_init_from_blocked_task(&info, child); | ||
| 659 | do_sync_rbs(&info, ia64_sync_user_rbs); | ||
| 660 | |||
| 661 | /* | ||
| 662 | * Now move the child back into TASK_STOPPED if it should be in a | ||
| 663 | * job control stop, so that SIGCONT can be used to wake it up. | ||
| 664 | */ | ||
| 665 | read_lock(&tasklist_lock); | ||
| 666 | if (child->sighand) { | ||
| 667 | spin_lock_irq(&child->sighand->siglock); | ||
| 668 | if (READ_ONCE(child->__state) == TASK_TRACED && | ||
| 669 | (child->signal->flags & SIGNAL_STOP_STOPPED)) { | ||
| 670 | WRITE_ONCE(child->__state, TASK_STOPPED); | ||
| 671 | } | ||
| 672 | spin_unlock_irq(&child->sighand->siglock); | ||
| 673 | } | ||
| 674 | read_unlock(&tasklist_lock); | ||
| 675 | } | ||
| 676 | |||
| 677 | /* | 620 | /* |
| 678 | * Write f32-f127 back to task->thread.fph if it has been modified. | 621 | * Write f32-f127 back to task->thread.fph if it has been modified. |
| 679 | */ | 622 | */ |
| @@ -1285,10 +1285,6 @@ int ptrace_request(struct task_struct *child, long request, · 1284 unmodified lines | |||
| 1285 | return ret; | 1285 | return ret; |
| 1286 | } | 1286 | } |
| 1287 | 1287 | ||
| 1288 | #ifndef arch_ptrace_attach | ||
| 1289 | #define arch_ptrace_attach(child) do { } while (0) | ||
| 1290 | #endif | ||
| 1291 | |||
| 1292 | SYSCALL_DEFINE4(ptrace, long, request, long, pid, unsigned long, addr, | 1288 | SYSCALL_DEFINE4(ptrace, long, request, long, pid, unsigned long, addr, |
| 1293 | unsigned long, data) | 1289 | unsigned long, data) |
| 1294 | { | 1290 | { |
| @@ -1297,8 +1293,6 @@ SYSCALL_DEFINE4(ptrace, long, request, long, pid, unsigned long, addr, · 2 unmodified lines | |||
| 1297 | 1293 | ||
| 1298 | if (request == PTRACE_TRACEME) { | 1294 | if (request == PTRACE_TRACEME) { |
| 1299 | ret = ptrace_traceme(); | 1295 | ret = ptrace_traceme(); |
| 1300 | if (!ret) | ||
| 1301 | arch_ptrace_attach(current); | ||
| 1302 | goto out; | 1296 | goto out; |
| 1303 | } | 1297 | } |
| 1304 | 1298 | ||
| @@ -1310,12 +1304,6 @@ SYSCALL_DEFINE4(ptrace, long, request, long, pid, unsigned long, addr, · 5 unmodified lines | |||
| 1310 | 1304 | ||
| 1311 | if (request == PTRACE_ATTACH || request == PTRACE_SEIZE) { | 1305 | if (request == PTRACE_ATTACH || request == PTRACE_SEIZE) { |
| 1312 | ret = ptrace_attach(child, request, addr, data); | 1306 | ret = ptrace_attach(child, request, addr, data); |
| 1313 | /* | ||
| 1314 | * Some architectures need to do book-keeping after | ||
| 1315 | * a ptrace attach. | ||
| 1316 | */ | ||
| 1317 | if (!ret) | ||
| 1318 | arch_ptrace_attach(child); | ||
| 1319 | goto out_put_task_struct; | 1307 | goto out_put_task_struct; |
| 1320 | } | 1308 | } |
| 1321 | 1309 | ||
| @@ -1455,12 +1443,6 @@ COMPAT_SYSCALL_DEFINE4(ptrace, compat_long_t, request, compat_long_t, pid, · 133 unmodified lines | |||
| 1455 | 1443 | ||
| 1456 | if (request == PTRACE_ATTACH || request == PTRACE_SEIZE) { | 1444 | if (request == PTRACE_ATTACH || request == PTRACE_SEIZE) { |
| 1457 | ret = ptrace_attach(child, request, addr, data); | 1445 | ret = ptrace_attach(child, request, addr, data); |
| 1458 | /* | ||
| 1459 | * Some architectures need to do book-keeping after | ||
| 1460 | * a ptrace attach. | ||
| 1461 | */ | ||
| 1462 | if (!ret) | ||
| 1463 | arch_ptrace_attach(child); | ||
| 1464 | goto out_put_task_struct; | 1446 | goto out_put_task_struct; |
| 1465 | } | 1447 | } |
| 1466 | 1448 | ||