Blame view
arch/x86/kernel/step.c
5.52 KB
fa1e03eae x86: single_step ... |
1 2 3 4 5 6 |
/* * x86 single-step support code, common to 32-bit and 64-bit. */ #include <linux/sched.h> #include <linux/mm.h> #include <linux/ptrace.h> |
254e0a6bf x86: Use get_desc... |
7 |
#include <asm/desc.h> |
fa1e03eae x86: single_step ... |
8 |
|
37cd9cf3d x86: common x86_3... |
9 |
unsigned long convert_ip_to_linear(struct task_struct *child, struct pt_regs *regs) |
fa1e03eae x86: single_step ... |
10 11 |
{ unsigned long addr, seg; |
65ea5b034 x86: rename the s... |
12 |
addr = regs->ip; |
fa1e03eae x86: single_step ... |
13 |
seg = regs->cs & 0xffff; |
65ea5b034 x86: rename the s... |
14 |
if (v8086_mode(regs)) { |
7122ec815 x86: single_step:... |
15 16 17 |
addr = (addr & 0xffff) + (seg << 4); return addr; } |
fa1e03eae x86: single_step ... |
18 19 20 21 22 23 24 |
/* * We'll assume that the code segments in the GDT * are all zero-based. That is largely true: the * TLS segments are used for data, and the PNPBIOS * and APM bios ones we just ignore here. */ |
3f80c1adc x86: single_step ... |
25 |
if ((seg & SEGMENT_TI_MASK) == SEGMENT_LDT) { |
254e0a6bf x86: Use get_desc... |
26 |
struct desc_struct *desc; |
fa1e03eae x86: single_step ... |
27 28 29 30 31 32 33 34 35 |
unsigned long base; seg &= ~7UL; mutex_lock(&child->mm->context.lock); if (unlikely((seg >> 3) >= child->mm->context.size)) addr = -1L; /* bogus selector, access would fault */ else { desc = child->mm->context.ldt + seg; |
254e0a6bf x86: Use get_desc... |
36 |
base = get_desc_base(desc); |
fa1e03eae x86: single_step ... |
37 38 |
/* 16-bit code segment? */ |
254e0a6bf x86: Use get_desc... |
39 |
if (!desc->d) |
fa1e03eae x86: single_step ... |
40 41 42 43 44 45 46 47 48 49 50 51 52 |
addr &= 0xffff; addr += base; } mutex_unlock(&child->mm->context.lock); } return addr; } static int is_setting_trap_flag(struct task_struct *child, struct pt_regs *regs) { int i, copied; unsigned char opcode[15]; |
37cd9cf3d x86: common x86_3... |
53 |
unsigned long addr = convert_ip_to_linear(child, regs); |
fa1e03eae x86: single_step ... |
54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 |
copied = access_process_vm(child, addr, opcode, sizeof(opcode), 0); for (i = 0; i < copied; i++) { switch (opcode[i]) { /* popf and iret */ case 0x9d: case 0xcf: return 1; /* CHECKME: 64 65 */ /* opcode and address size prefixes */ case 0x66: case 0x67: continue; /* irrelevant prefixes (segment overrides and repeats) */ case 0x26: case 0x2e: case 0x36: case 0x3e: case 0x64: case 0x65: |
5f76cb1f6 x86: single_step ... |
71 |
case 0xf0: case 0xf2: case 0xf3: |
fa1e03eae x86: single_step ... |
72 |
continue; |
7122ec815 x86: single_step:... |
73 |
#ifdef CONFIG_X86_64 |
fa1e03eae x86: single_step ... |
74 |
case 0x40 ... 0x4f: |
318f5a2a6 x86-64: Add user_... |
75 |
if (!user_64bit_mode(regs)) |
fa1e03eae x86: single_step ... |
76 77 78 79 |
/* 32-bit mode: register increment */ return 0; /* 64-bit mode: REX prefix */ continue; |
7122ec815 x86: single_step:... |
80 |
#endif |
fa1e03eae x86: single_step ... |
81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 |
/* CHECKME: f2, f3 */ /* * pushf: NOTE! We should probably not let * the user see the TF bit being set. But * it's more pain than it's worth to avoid * it, and a debugger could emulate this * all in user space if it _really_ cares. */ case 0x9c: default: return 0; } } return 0; } |
10faa81e1 x86: debugctlmsr ... |
98 99 100 101 |
/* * Enable single-stepping. Return nonzero if user mode is not using TF itself. */ static int enable_single_step(struct task_struct *child) |
fa1e03eae x86: single_step ... |
102 103 |
{ struct pt_regs *regs = task_pt_regs(child); |
6718d0d6d x86 ptrace: block... |
104 |
unsigned long oflags; |
fa1e03eae x86: single_step ... |
105 106 |
/* |
380fdd758 x86 ptrace: user-... |
107 108 109 110 111 112 113 114 115 116 117 118 119 |
* If we stepped into a sysenter/syscall insn, it trapped in * kernel mode; do_debug() cleared TF and set TIF_SINGLESTEP. * If user-mode had set TF itself, then it's still clear from * do_debug() and we need to set it again to restore the user * state so we don't wrongly set TIF_FORCED_TF below. * If enable_single_step() was used last and that is what * set TIF_SINGLESTEP, then both TF and TIF_FORCED_TF are * already set and our bookkeeping is fine. */ if (unlikely(test_tsk_thread_flag(child, TIF_SINGLESTEP))) regs->flags |= X86_EFLAGS_TF; /* |
fa1e03eae x86: single_step ... |
120 121 122 123 124 |
* Always set TIF_SINGLESTEP - this guarantees that * we single-step system calls etc.. This will also * cause us to set TF when returning to user mode. */ set_tsk_thread_flag(child, TIF_SINGLESTEP); |
6718d0d6d x86 ptrace: block... |
125 |
oflags = regs->flags; |
fa1e03eae x86: single_step ... |
126 127 |
/* Set TF on the kernel stack.. */ |
65ea5b034 x86: rename the s... |
128 |
regs->flags |= X86_EFLAGS_TF; |
fa1e03eae x86: single_step ... |
129 130 131 132 133 |
/* * ..but if TF is changed by the instruction we will trace, * don't mark it as being "us" that set it, so that we * won't clear it by hand later. |
6718d0d6d x86 ptrace: block... |
134 135 136 137 |
* * Note that if we don't actually execute the popf because * of a signal arriving right now or suchlike, we will lose * track of the fact that it really was "us" that set it. |
fa1e03eae x86: single_step ... |
138 |
*/ |
6718d0d6d x86 ptrace: block... |
139 140 |
if (is_setting_trap_flag(child, regs)) { clear_tsk_thread_flag(child, TIF_FORCED_TF); |
10faa81e1 x86: debugctlmsr ... |
141 |
return 0; |
6718d0d6d x86 ptrace: block... |
142 143 144 145 146 147 148 149 |
} /* * If TF was already set, check whether it was us who set it. * If not, we should never attempt a block step. */ if (oflags & X86_EFLAGS_TF) return test_tsk_thread_flag(child, TIF_FORCED_TF); |
fa1e03eae x86: single_step ... |
150 |
|
e1f287735 x86 single_step: ... |
151 |
set_tsk_thread_flag(child, TIF_FORCED_TF); |
10faa81e1 x86: debugctlmsr ... |
152 153 154 155 156 |
return 1; } /* |
10faa81e1 x86: debugctlmsr ... |
157 158 159 160 161 162 163 164 |
* Enable single or block step. */ static void enable_step(struct task_struct *child, bool block) { /* * Make sure block stepping (BTF) is not enabled unless it should be. * Note that we don't try to worry about any is_setting_trap_flag() * instructions after the first when using block stepping. |
0d2eb44f6 x86: Fix common m... |
165 |
* So no one should try to use debugger block stepping in a program |
10faa81e1 x86: debugctlmsr ... |
166 167 |
* that uses user-mode single stepping itself. */ |
ea8e61b7b x86, ptrace: Fix ... |
168 169 170 171 172 173 174 175 176 177 178 179 180 |
if (enable_single_step(child) && block) { unsigned long debugctl = get_debugctlmsr(); debugctl |= DEBUGCTLMSR_BTF; update_debugctlmsr(debugctl); set_tsk_thread_flag(child, TIF_BLOCKSTEP); } else if (test_tsk_thread_flag(child, TIF_BLOCKSTEP)) { unsigned long debugctl = get_debugctlmsr(); debugctl &= ~DEBUGCTLMSR_BTF; update_debugctlmsr(debugctl); clear_tsk_thread_flag(child, TIF_BLOCKSTEP); } |
10faa81e1 x86: debugctlmsr ... |
181 182 183 184 185 186 187 188 189 190 |
} void user_enable_single_step(struct task_struct *child) { enable_step(child, 0); } void user_enable_block_step(struct task_struct *child) { enable_step(child, 1); |
fa1e03eae x86: single_step ... |
191 192 193 194 |
} void user_disable_single_step(struct task_struct *child) { |
10faa81e1 x86: debugctlmsr ... |
195 196 197 |
/* * Make sure block stepping (BTF) is disabled. */ |
ea8e61b7b x86, ptrace: Fix ... |
198 199 200 201 202 203 204 |
if (test_tsk_thread_flag(child, TIF_BLOCKSTEP)) { unsigned long debugctl = get_debugctlmsr(); debugctl &= ~DEBUGCTLMSR_BTF; update_debugctlmsr(debugctl); clear_tsk_thread_flag(child, TIF_BLOCKSTEP); } |
10faa81e1 x86: debugctlmsr ... |
205 |
|
fa1e03eae x86: single_step ... |
206 207 208 209 |
/* Always clear TIF_SINGLESTEP... */ clear_tsk_thread_flag(child, TIF_SINGLESTEP); /* But touch TF only if it was set by us.. */ |
e1f287735 x86 single_step: ... |
210 |
if (test_and_clear_tsk_thread_flag(child, TIF_FORCED_TF)) |
65ea5b034 x86: rename the s... |
211 |
task_pt_regs(child)->flags &= ~X86_EFLAGS_TF; |
fa1e03eae x86: single_step ... |
212 |
} |