aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86/kernel/ptrace.c
diff options
context:
space:
mode:
authorIngo Molnar <mingo@elte.hu>2008-07-25 05:37:07 -0400
committerIngo Molnar <mingo@elte.hu>2008-07-25 05:37:07 -0400
commit0e2f65ee30eee2db054f7fd73f462c5da33ec963 (patch)
tree26c61eb7745da0c0d9135e9d12088f570cb8530d /arch/x86/kernel/ptrace.c
parentda7878d75b8520c9ae00d27dfbbce546a7bfdfbb (diff)
parentfb2e405fc1fc8b20d9c78eaa1c7fd5a297efde43 (diff)
Merge branch 'linus' into x86/pebs
Conflicts: arch/x86/Kconfig.cpu arch/x86/kernel/cpu/intel.c arch/x86/kernel/setup_64.c Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'arch/x86/kernel/ptrace.c')
-rw-r--r--arch/x86/kernel/ptrace.c155
1 files changed, 58 insertions, 97 deletions
diff --git a/arch/x86/kernel/ptrace.c b/arch/x86/kernel/ptrace.c
index 170f0932f70f..ba19bb49bd09 100644
--- a/arch/x86/kernel/ptrace.c
+++ b/arch/x86/kernel/ptrace.c
@@ -1037,13 +1037,13 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
1037 return copy_regset_to_user(child, &user_x86_32_view, 1037 return copy_regset_to_user(child, &user_x86_32_view,
1038 REGSET_XFP, 1038 REGSET_XFP,
1039 0, sizeof(struct user_fxsr_struct), 1039 0, sizeof(struct user_fxsr_struct),
1040 datap); 1040 datap) ? -EIO : 0;
1041 1041
1042 case PTRACE_SETFPXREGS: /* Set the child extended FPU state. */ 1042 case PTRACE_SETFPXREGS: /* Set the child extended FPU state. */
1043 return copy_regset_from_user(child, &user_x86_32_view, 1043 return copy_regset_from_user(child, &user_x86_32_view,
1044 REGSET_XFP, 1044 REGSET_XFP,
1045 0, sizeof(struct user_fxsr_struct), 1045 0, sizeof(struct user_fxsr_struct),
1046 datap); 1046 datap) ? -EIO : 0;
1047#endif 1047#endif
1048 1048
1049#if defined CONFIG_X86_32 || defined CONFIG_IA32_EMULATION 1049#if defined CONFIG_X86_32 || defined CONFIG_IA32_EMULATION
@@ -1451,8 +1451,6 @@ const struct user_regset_view *task_user_regset_view(struct task_struct *task)
1451#endif 1451#endif
1452} 1452}
1453 1453
1454#ifdef CONFIG_X86_32
1455
1456void send_sigtrap(struct task_struct *tsk, struct pt_regs *regs, int error_code) 1454void send_sigtrap(struct task_struct *tsk, struct pt_regs *regs, int error_code)
1457{ 1455{
1458 struct siginfo info; 1456 struct siginfo info;
@@ -1471,89 +1469,10 @@ void send_sigtrap(struct task_struct *tsk, struct pt_regs *regs, int error_code)
1471 force_sig_info(SIGTRAP, &info, tsk); 1469 force_sig_info(SIGTRAP, &info, tsk);
1472} 1470}
1473 1471
1474/* notification of system call entry/exit
1475 * - triggered by current->work.syscall_trace
1476 */
1477int do_syscall_trace(struct pt_regs *regs, int entryexit)
1478{
1479 int is_sysemu = test_thread_flag(TIF_SYSCALL_EMU);
1480 /*
1481 * With TIF_SYSCALL_EMU set we want to ignore TIF_SINGLESTEP for syscall
1482 * interception
1483 */
1484 int is_singlestep = !is_sysemu && test_thread_flag(TIF_SINGLESTEP);
1485 int ret = 0;
1486
1487 /* do the secure computing check first */
1488 if (!entryexit)
1489 secure_computing(regs->orig_ax);
1490
1491 if (unlikely(current->audit_context)) {
1492 if (entryexit)
1493 audit_syscall_exit(AUDITSC_RESULT(regs->ax),
1494 regs->ax);
1495 /* Debug traps, when using PTRACE_SINGLESTEP, must be sent only
1496 * on the syscall exit path. Normally, when TIF_SYSCALL_AUDIT is
1497 * not used, entry.S will call us only on syscall exit, not
1498 * entry; so when TIF_SYSCALL_AUDIT is used we must avoid
1499 * calling send_sigtrap() on syscall entry.
1500 *
1501 * Note that when PTRACE_SYSEMU_SINGLESTEP is used,
1502 * is_singlestep is false, despite his name, so we will still do
1503 * the correct thing.
1504 */
1505 else if (is_singlestep)
1506 goto out;
1507 }
1508
1509 if (!(current->ptrace & PT_PTRACED))
1510 goto out;
1511
1512 /* If a process stops on the 1st tracepoint with SYSCALL_TRACE
1513 * and then is resumed with SYSEMU_SINGLESTEP, it will come in
1514 * here. We have to check this and return */
1515 if (is_sysemu && entryexit)
1516 return 0;
1517
1518 /* Fake a debug trap */
1519 if (is_singlestep)
1520 send_sigtrap(current, regs, 0);
1521
1522 if (!test_thread_flag(TIF_SYSCALL_TRACE) && !is_sysemu)
1523 goto out;
1524
1525 /* the 0x80 provides a way for the tracing parent to distinguish
1526 between a syscall stop and SIGTRAP delivery */
1527 /* Note that the debugger could change the result of test_thread_flag!*/
1528 ptrace_notify(SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD) ? 0x80:0));
1529
1530 /*
1531 * this isn't the same as continuing with a signal, but it will do
1532 * for normal use. strace only continues with a signal if the
1533 * stopping signal is not SIGTRAP. -brl
1534 */
1535 if (current->exit_code) {
1536 send_sig(current->exit_code, current, 1);
1537 current->exit_code = 0;
1538 }
1539 ret = is_sysemu;
1540out:
1541 if (unlikely(current->audit_context) && !entryexit)
1542 audit_syscall_entry(AUDIT_ARCH_I386, regs->orig_ax,
1543 regs->bx, regs->cx, regs->dx, regs->si);
1544 if (ret == 0)
1545 return 0;
1546
1547 regs->orig_ax = -1; /* force skip of syscall restarting */
1548 if (unlikely(current->audit_context))
1549 audit_syscall_exit(AUDITSC_RESULT(regs->ax), regs->ax);
1550 return 1;
1551}
1552
1553#else /* CONFIG_X86_64 */
1554
1555static void syscall_trace(struct pt_regs *regs) 1472static void syscall_trace(struct pt_regs *regs)
1556{ 1473{
1474 if (!(current->ptrace & PT_PTRACED))
1475 return;
1557 1476
1558#if 0 1477#if 0
1559 printk("trace %s ip %lx sp %lx ax %d origrax %d caller %lx tiflags %x ptrace %x\n", 1478 printk("trace %s ip %lx sp %lx ax %d origrax %d caller %lx tiflags %x ptrace %x\n",
@@ -1575,39 +1494,81 @@ static void syscall_trace(struct pt_regs *regs)
1575 } 1494 }
1576} 1495}
1577 1496
1578asmlinkage void syscall_trace_enter(struct pt_regs *regs) 1497#ifdef CONFIG_X86_32
1498# define IS_IA32 1
1499#elif defined CONFIG_IA32_EMULATION
1500# define IS_IA32 test_thread_flag(TIF_IA32)
1501#else
1502# define IS_IA32 0
1503#endif
1504
1505/*
1506 * We must return the syscall number to actually look up in the table.
1507 * This can be -1L to skip running any syscall at all.
1508 */
1509asmregparm long syscall_trace_enter(struct pt_regs *regs)
1579{ 1510{
1511 long ret = 0;
1512
1513 /*
1514 * If we stepped into a sysenter/syscall insn, it trapped in
1515 * kernel mode; do_debug() cleared TF and set TIF_SINGLESTEP.
1516 * If user-mode had set TF itself, then it's still clear from
1517 * do_debug() and we need to set it again to restore the user
1518 * state. If we entered on the slow path, TF was already set.
1519 */
1520 if (test_thread_flag(TIF_SINGLESTEP))
1521 regs->flags |= X86_EFLAGS_TF;
1522
1580 /* do the secure computing check first */ 1523 /* do the secure computing check first */
1581 secure_computing(regs->orig_ax); 1524 secure_computing(regs->orig_ax);
1582 1525
1583 if (test_thread_flag(TIF_SYSCALL_TRACE) 1526 if (unlikely(test_thread_flag(TIF_SYSCALL_EMU)))
1584 && (current->ptrace & PT_PTRACED)) 1527 ret = -1L;
1528
1529 if (ret || test_thread_flag(TIF_SYSCALL_TRACE))
1585 syscall_trace(regs); 1530 syscall_trace(regs);
1586 1531
1587 if (unlikely(current->audit_context)) { 1532 if (unlikely(current->audit_context)) {
1588 if (test_thread_flag(TIF_IA32)) { 1533 if (IS_IA32)
1589 audit_syscall_entry(AUDIT_ARCH_I386, 1534 audit_syscall_entry(AUDIT_ARCH_I386,
1590 regs->orig_ax, 1535 regs->orig_ax,
1591 regs->bx, regs->cx, 1536 regs->bx, regs->cx,
1592 regs->dx, regs->si); 1537 regs->dx, regs->si);
1593 } else { 1538#ifdef CONFIG_X86_64
1539 else
1594 audit_syscall_entry(AUDIT_ARCH_X86_64, 1540 audit_syscall_entry(AUDIT_ARCH_X86_64,
1595 regs->orig_ax, 1541 regs->orig_ax,
1596 regs->di, regs->si, 1542 regs->di, regs->si,
1597 regs->dx, regs->r10); 1543 regs->dx, regs->r10);
1598 } 1544#endif
1599 } 1545 }
1546
1547 return ret ?: regs->orig_ax;
1600} 1548}
1601 1549
1602asmlinkage void syscall_trace_leave(struct pt_regs *regs) 1550asmregparm void syscall_trace_leave(struct pt_regs *regs)
1603{ 1551{
1604 if (unlikely(current->audit_context)) 1552 if (unlikely(current->audit_context))
1605 audit_syscall_exit(AUDITSC_RESULT(regs->ax), regs->ax); 1553 audit_syscall_exit(AUDITSC_RESULT(regs->ax), regs->ax);
1606 1554
1607 if ((test_thread_flag(TIF_SYSCALL_TRACE) 1555 if (test_thread_flag(TIF_SYSCALL_TRACE))
1608 || test_thread_flag(TIF_SINGLESTEP))
1609 && (current->ptrace & PT_PTRACED))
1610 syscall_trace(regs); 1556 syscall_trace(regs);
1611}
1612 1557
1613#endif /* CONFIG_X86_32 */ 1558 /*
1559 * If TIF_SYSCALL_EMU is set, we only get here because of
1560 * TIF_SINGLESTEP (i.e. this is PTRACE_SYSEMU_SINGLESTEP).
1561 * We already reported this syscall instruction in
1562 * syscall_trace_enter(), so don't do any more now.
1563 */
1564 if (unlikely(test_thread_flag(TIF_SYSCALL_EMU)))
1565 return;
1566
1567 /*
1568 * If we are single-stepping, synthesize a trap to follow the
1569 * system call instruction.
1570 */
1571 if (test_thread_flag(TIF_SINGLESTEP) &&
1572 (current->ptrace & PT_PTRACED))
1573 send_sigtrap(current, regs, 0);
1574}