diff options
Diffstat (limited to 'arch/x86/kernel/ptrace.c')
-rw-r--r-- | arch/x86/kernel/ptrace.c | 65 |
1 files changed, 37 insertions, 28 deletions
diff --git a/arch/x86/kernel/ptrace.c b/arch/x86/kernel/ptrace.c index 017d937639fe..2d96aab82a48 100644 --- a/arch/x86/kernel/ptrace.c +++ b/arch/x86/kernel/ptrace.c | |||
@@ -48,6 +48,7 @@ enum x86_regset { | |||
48 | REGSET_FP, | 48 | REGSET_FP, |
49 | REGSET_XFP, | 49 | REGSET_XFP, |
50 | REGSET_IOPERM64 = REGSET_XFP, | 50 | REGSET_IOPERM64 = REGSET_XFP, |
51 | REGSET_XSTATE, | ||
51 | REGSET_TLS, | 52 | REGSET_TLS, |
52 | REGSET_IOPERM32, | 53 | REGSET_IOPERM32, |
53 | }; | 54 | }; |
@@ -140,30 +141,6 @@ static const int arg_offs_table[] = { | |||
140 | #endif | 141 | #endif |
141 | }; | 142 | }; |
142 | 143 | ||
143 | /** | ||
144 | * regs_get_argument_nth() - get Nth argument at function call | ||
145 | * @regs: pt_regs which contains registers at function entry. | ||
146 | * @n: argument number. | ||
147 | * | ||
148 | * regs_get_argument_nth() returns @n th argument of a function call. | ||
149 | * Since usually the kernel stack will be changed right after function entry, | ||
150 | * you must use this at function entry. If the @n th entry is NOT in the | ||
151 | * kernel stack or pt_regs, this returns 0. | ||
152 | */ | ||
153 | unsigned long regs_get_argument_nth(struct pt_regs *regs, unsigned int n) | ||
154 | { | ||
155 | if (n < ARRAY_SIZE(arg_offs_table)) | ||
156 | return *(unsigned long *)((char *)regs + arg_offs_table[n]); | ||
157 | else { | ||
158 | /* | ||
159 | * The typical case: arg n is on the stack. | ||
160 | * (Note: stack[0] = return address, so skip it) | ||
161 | */ | ||
162 | n -= ARRAY_SIZE(arg_offs_table); | ||
163 | return regs_get_kernel_stack_nth(regs, 1 + n); | ||
164 | } | ||
165 | } | ||
166 | |||
167 | /* | 144 | /* |
168 | * does not yet catch signals sent when the child dies. | 145 | * does not yet catch signals sent when the child dies. |
169 | * in exit.c or in signal.c. | 146 | * in exit.c or in signal.c. |
@@ -702,7 +679,7 @@ static unsigned long ptrace_get_debugreg(struct task_struct *tsk, int n) | |||
702 | } else if (n == 6) { | 679 | } else if (n == 6) { |
703 | val = thread->debugreg6; | 680 | val = thread->debugreg6; |
704 | } else if (n == 7) { | 681 | } else if (n == 7) { |
705 | val = ptrace_get_dr7(thread->ptrace_bps); | 682 | val = thread->ptrace_dr7; |
706 | } | 683 | } |
707 | return val; | 684 | return val; |
708 | } | 685 | } |
@@ -778,8 +755,11 @@ int ptrace_set_debugreg(struct task_struct *tsk, int n, unsigned long val) | |||
778 | return rc; | 755 | return rc; |
779 | } | 756 | } |
780 | /* All that's left is DR7 */ | 757 | /* All that's left is DR7 */ |
781 | if (n == 7) | 758 | if (n == 7) { |
782 | rc = ptrace_write_dr7(tsk, val); | 759 | rc = ptrace_write_dr7(tsk, val); |
760 | if (!rc) | ||
761 | thread->ptrace_dr7 = val; | ||
762 | } | ||
783 | 763 | ||
784 | ret_path: | 764 | ret_path: |
785 | return rc; | 765 | return rc; |
@@ -1584,7 +1564,7 @@ long compat_arch_ptrace(struct task_struct *child, compat_long_t request, | |||
1584 | 1564 | ||
1585 | #ifdef CONFIG_X86_64 | 1565 | #ifdef CONFIG_X86_64 |
1586 | 1566 | ||
1587 | static const struct user_regset x86_64_regsets[] = { | 1567 | static struct user_regset x86_64_regsets[] __read_mostly = { |
1588 | [REGSET_GENERAL] = { | 1568 | [REGSET_GENERAL] = { |
1589 | .core_note_type = NT_PRSTATUS, | 1569 | .core_note_type = NT_PRSTATUS, |
1590 | .n = sizeof(struct user_regs_struct) / sizeof(long), | 1570 | .n = sizeof(struct user_regs_struct) / sizeof(long), |
@@ -1597,6 +1577,12 @@ static const struct user_regset x86_64_regsets[] = { | |||
1597 | .size = sizeof(long), .align = sizeof(long), | 1577 | .size = sizeof(long), .align = sizeof(long), |
1598 | .active = xfpregs_active, .get = xfpregs_get, .set = xfpregs_set | 1578 | .active = xfpregs_active, .get = xfpregs_get, .set = xfpregs_set |
1599 | }, | 1579 | }, |
1580 | [REGSET_XSTATE] = { | ||
1581 | .core_note_type = NT_X86_XSTATE, | ||
1582 | .size = sizeof(u64), .align = sizeof(u64), | ||
1583 | .active = xstateregs_active, .get = xstateregs_get, | ||
1584 | .set = xstateregs_set | ||
1585 | }, | ||
1600 | [REGSET_IOPERM64] = { | 1586 | [REGSET_IOPERM64] = { |
1601 | .core_note_type = NT_386_IOPERM, | 1587 | .core_note_type = NT_386_IOPERM, |
1602 | .n = IO_BITMAP_LONGS, | 1588 | .n = IO_BITMAP_LONGS, |
@@ -1622,7 +1608,7 @@ static const struct user_regset_view user_x86_64_view = { | |||
1622 | #endif /* CONFIG_X86_64 */ | 1608 | #endif /* CONFIG_X86_64 */ |
1623 | 1609 | ||
1624 | #if defined CONFIG_X86_32 || defined CONFIG_IA32_EMULATION | 1610 | #if defined CONFIG_X86_32 || defined CONFIG_IA32_EMULATION |
1625 | static const struct user_regset x86_32_regsets[] = { | 1611 | static struct user_regset x86_32_regsets[] __read_mostly = { |
1626 | [REGSET_GENERAL] = { | 1612 | [REGSET_GENERAL] = { |
1627 | .core_note_type = NT_PRSTATUS, | 1613 | .core_note_type = NT_PRSTATUS, |
1628 | .n = sizeof(struct user_regs_struct32) / sizeof(u32), | 1614 | .n = sizeof(struct user_regs_struct32) / sizeof(u32), |
@@ -1641,6 +1627,12 @@ static const struct user_regset x86_32_regsets[] = { | |||
1641 | .size = sizeof(u32), .align = sizeof(u32), | 1627 | .size = sizeof(u32), .align = sizeof(u32), |
1642 | .active = xfpregs_active, .get = xfpregs_get, .set = xfpregs_set | 1628 | .active = xfpregs_active, .get = xfpregs_get, .set = xfpregs_set |
1643 | }, | 1629 | }, |
1630 | [REGSET_XSTATE] = { | ||
1631 | .core_note_type = NT_X86_XSTATE, | ||
1632 | .size = sizeof(u64), .align = sizeof(u64), | ||
1633 | .active = xstateregs_active, .get = xstateregs_get, | ||
1634 | .set = xstateregs_set | ||
1635 | }, | ||
1644 | [REGSET_TLS] = { | 1636 | [REGSET_TLS] = { |
1645 | .core_note_type = NT_386_TLS, | 1637 | .core_note_type = NT_386_TLS, |
1646 | .n = GDT_ENTRY_TLS_ENTRIES, .bias = GDT_ENTRY_TLS_MIN, | 1638 | .n = GDT_ENTRY_TLS_ENTRIES, .bias = GDT_ENTRY_TLS_MIN, |
@@ -1663,6 +1655,23 @@ static const struct user_regset_view user_x86_32_view = { | |||
1663 | }; | 1655 | }; |
1664 | #endif | 1656 | #endif |
1665 | 1657 | ||
1658 | /* | ||
1659 | * This represents bytes 464..511 in the memory layout exported through | ||
1660 | * the REGSET_XSTATE interface. | ||
1661 | */ | ||
1662 | u64 xstate_fx_sw_bytes[USER_XSTATE_FX_SW_WORDS]; | ||
1663 | |||
1664 | void update_regset_xstate_info(unsigned int size, u64 xstate_mask) | ||
1665 | { | ||
1666 | #ifdef CONFIG_X86_64 | ||
1667 | x86_64_regsets[REGSET_XSTATE].n = size / sizeof(u64); | ||
1668 | #endif | ||
1669 | #if defined CONFIG_X86_32 || defined CONFIG_IA32_EMULATION | ||
1670 | x86_32_regsets[REGSET_XSTATE].n = size / sizeof(u64); | ||
1671 | #endif | ||
1672 | xstate_fx_sw_bytes[USER_XSTATE_XCR0_WORD] = xstate_mask; | ||
1673 | } | ||
1674 | |||
1666 | const struct user_regset_view *task_user_regset_view(struct task_struct *task) | 1675 | const struct user_regset_view *task_user_regset_view(struct task_struct *task) |
1667 | { | 1676 | { |
1668 | #ifdef CONFIG_IA32_EMULATION | 1677 | #ifdef CONFIG_IA32_EMULATION |