diff options
Diffstat (limited to 'arch/x86/kernel/kgdb.c')
-rw-r--r-- | arch/x86/kernel/kgdb.c | 489 |
1 files changed, 311 insertions, 178 deletions
diff --git a/arch/x86/kernel/kgdb.c b/arch/x86/kernel/kgdb.c index dd74fe7273b1..852b81967a37 100644 --- a/arch/x86/kernel/kgdb.c +++ b/arch/x86/kernel/kgdb.c | |||
@@ -42,73 +42,101 @@ | |||
42 | #include <linux/init.h> | 42 | #include <linux/init.h> |
43 | #include <linux/smp.h> | 43 | #include <linux/smp.h> |
44 | #include <linux/nmi.h> | 44 | #include <linux/nmi.h> |
45 | #include <linux/hw_breakpoint.h> | ||
45 | 46 | ||
46 | #include <asm/debugreg.h> | 47 | #include <asm/debugreg.h> |
47 | #include <asm/apicdef.h> | 48 | #include <asm/apicdef.h> |
48 | #include <asm/system.h> | 49 | #include <asm/system.h> |
49 | |||
50 | #include <asm/apic.h> | 50 | #include <asm/apic.h> |
51 | 51 | ||
52 | /* | 52 | struct dbg_reg_def_t dbg_reg_def[DBG_MAX_REG_NUM] = |
53 | * Put the error code here just in case the user cares: | ||
54 | */ | ||
55 | static int gdb_x86errcode; | ||
56 | |||
57 | /* | ||
58 | * Likewise, the vector number here (since GDB only gets the signal | ||
59 | * number through the usual means, and that's not very specific): | ||
60 | */ | ||
61 | static int gdb_x86vector = -1; | ||
62 | |||
63 | /** | ||
64 | * pt_regs_to_gdb_regs - Convert ptrace regs to GDB regs | ||
65 | * @gdb_regs: A pointer to hold the registers in the order GDB wants. | ||
66 | * @regs: The &struct pt_regs of the current process. | ||
67 | * | ||
68 | * Convert the pt_regs in @regs into the format for registers that | ||
69 | * GDB expects, stored in @gdb_regs. | ||
70 | */ | ||
71 | void pt_regs_to_gdb_regs(unsigned long *gdb_regs, struct pt_regs *regs) | ||
72 | { | 53 | { |
73 | #ifndef CONFIG_X86_32 | 54 | #ifdef CONFIG_X86_32 |
74 | u32 *gdb_regs32 = (u32 *)gdb_regs; | 55 | { "ax", 4, offsetof(struct pt_regs, ax) }, |
56 | { "cx", 4, offsetof(struct pt_regs, cx) }, | ||
57 | { "dx", 4, offsetof(struct pt_regs, dx) }, | ||
58 | { "bx", 4, offsetof(struct pt_regs, bx) }, | ||
59 | { "sp", 4, offsetof(struct pt_regs, sp) }, | ||
60 | { "bp", 4, offsetof(struct pt_regs, bp) }, | ||
61 | { "si", 4, offsetof(struct pt_regs, si) }, | ||
62 | { "di", 4, offsetof(struct pt_regs, di) }, | ||
63 | { "ip", 4, offsetof(struct pt_regs, ip) }, | ||
64 | { "flags", 4, offsetof(struct pt_regs, flags) }, | ||
65 | { "cs", 4, offsetof(struct pt_regs, cs) }, | ||
66 | { "ss", 4, offsetof(struct pt_regs, ss) }, | ||
67 | { "ds", 4, offsetof(struct pt_regs, ds) }, | ||
68 | { "es", 4, offsetof(struct pt_regs, es) }, | ||
69 | { "fs", 4, -1 }, | ||
70 | { "gs", 4, -1 }, | ||
71 | #else | ||
72 | { "ax", 8, offsetof(struct pt_regs, ax) }, | ||
73 | { "bx", 8, offsetof(struct pt_regs, bx) }, | ||
74 | { "cx", 8, offsetof(struct pt_regs, cx) }, | ||
75 | { "dx", 8, offsetof(struct pt_regs, dx) }, | ||
76 | { "si", 8, offsetof(struct pt_regs, dx) }, | ||
77 | { "di", 8, offsetof(struct pt_regs, di) }, | ||
78 | { "bp", 8, offsetof(struct pt_regs, bp) }, | ||
79 | { "sp", 8, offsetof(struct pt_regs, sp) }, | ||
80 | { "r8", 8, offsetof(struct pt_regs, r8) }, | ||
81 | { "r9", 8, offsetof(struct pt_regs, r9) }, | ||
82 | { "r10", 8, offsetof(struct pt_regs, r10) }, | ||
83 | { "r11", 8, offsetof(struct pt_regs, r11) }, | ||
84 | { "r12", 8, offsetof(struct pt_regs, r12) }, | ||
85 | { "r13", 8, offsetof(struct pt_regs, r13) }, | ||
86 | { "r14", 8, offsetof(struct pt_regs, r14) }, | ||
87 | { "r15", 8, offsetof(struct pt_regs, r15) }, | ||
88 | { "ip", 8, offsetof(struct pt_regs, ip) }, | ||
89 | { "flags", 4, offsetof(struct pt_regs, flags) }, | ||
90 | { "cs", 4, offsetof(struct pt_regs, cs) }, | ||
91 | { "ss", 4, offsetof(struct pt_regs, ss) }, | ||
75 | #endif | 92 | #endif |
76 | gdb_regs[GDB_AX] = regs->ax; | 93 | }; |
77 | gdb_regs[GDB_BX] = regs->bx; | 94 | |
78 | gdb_regs[GDB_CX] = regs->cx; | 95 | int dbg_set_reg(int regno, void *mem, struct pt_regs *regs) |
79 | gdb_regs[GDB_DX] = regs->dx; | 96 | { |
80 | gdb_regs[GDB_SI] = regs->si; | 97 | if ( |
81 | gdb_regs[GDB_DI] = regs->di; | ||
82 | gdb_regs[GDB_BP] = regs->bp; | ||
83 | gdb_regs[GDB_PC] = regs->ip; | ||
84 | #ifdef CONFIG_X86_32 | 98 | #ifdef CONFIG_X86_32 |
85 | gdb_regs[GDB_PS] = regs->flags; | 99 | regno == GDB_SS || regno == GDB_FS || regno == GDB_GS || |
86 | gdb_regs[GDB_DS] = regs->ds; | 100 | #endif |
87 | gdb_regs[GDB_ES] = regs->es; | 101 | regno == GDB_SP || regno == GDB_ORIG_AX) |
88 | gdb_regs[GDB_CS] = regs->cs; | 102 | return 0; |
89 | gdb_regs[GDB_FS] = 0xFFFF; | 103 | |
90 | gdb_regs[GDB_GS] = 0xFFFF; | 104 | if (dbg_reg_def[regno].offset != -1) |
91 | if (user_mode_vm(regs)) { | 105 | memcpy((void *)regs + dbg_reg_def[regno].offset, mem, |
92 | gdb_regs[GDB_SS] = regs->ss; | 106 | dbg_reg_def[regno].size); |
93 | gdb_regs[GDB_SP] = regs->sp; | 107 | return 0; |
94 | } else { | 108 | } |
95 | gdb_regs[GDB_SS] = __KERNEL_DS; | 109 | |
96 | gdb_regs[GDB_SP] = kernel_stack_pointer(regs); | 110 | char *dbg_get_reg(int regno, void *mem, struct pt_regs *regs) |
111 | { | ||
112 | if (regno == GDB_ORIG_AX) { | ||
113 | memcpy(mem, ®s->orig_ax, sizeof(regs->orig_ax)); | ||
114 | return "orig_ax"; | ||
97 | } | 115 | } |
98 | #else | 116 | if (regno >= DBG_MAX_REG_NUM || regno < 0) |
99 | gdb_regs[GDB_R8] = regs->r8; | 117 | return NULL; |
100 | gdb_regs[GDB_R9] = regs->r9; | 118 | |
101 | gdb_regs[GDB_R10] = regs->r10; | 119 | if (dbg_reg_def[regno].offset != -1) |
102 | gdb_regs[GDB_R11] = regs->r11; | 120 | memcpy(mem, (void *)regs + dbg_reg_def[regno].offset, |
103 | gdb_regs[GDB_R12] = regs->r12; | 121 | dbg_reg_def[regno].size); |
104 | gdb_regs[GDB_R13] = regs->r13; | 122 | |
105 | gdb_regs[GDB_R14] = regs->r14; | 123 | switch (regno) { |
106 | gdb_regs[GDB_R15] = regs->r15; | 124 | #ifdef CONFIG_X86_32 |
107 | gdb_regs32[GDB_PS] = regs->flags; | 125 | case GDB_SS: |
108 | gdb_regs32[GDB_CS] = regs->cs; | 126 | if (!user_mode_vm(regs)) |
109 | gdb_regs32[GDB_SS] = regs->ss; | 127 | *(unsigned long *)mem = __KERNEL_DS; |
110 | gdb_regs[GDB_SP] = kernel_stack_pointer(regs); | 128 | break; |
129 | case GDB_SP: | ||
130 | if (!user_mode_vm(regs)) | ||
131 | *(unsigned long *)mem = kernel_stack_pointer(regs); | ||
132 | break; | ||
133 | case GDB_GS: | ||
134 | case GDB_FS: | ||
135 | *(unsigned long *)mem = 0xFFFF; | ||
136 | break; | ||
111 | #endif | 137 | #endif |
138 | } | ||
139 | return dbg_reg_def[regno].name; | ||
112 | } | 140 | } |
113 | 141 | ||
114 | /** | 142 | /** |
@@ -161,83 +189,100 @@ void sleeping_thread_to_gdb_regs(unsigned long *gdb_regs, struct task_struct *p) | |||
161 | gdb_regs[GDB_SP] = p->thread.sp; | 189 | gdb_regs[GDB_SP] = p->thread.sp; |
162 | } | 190 | } |
163 | 191 | ||
164 | /** | ||
165 | * gdb_regs_to_pt_regs - Convert GDB regs to ptrace regs. | ||
166 | * @gdb_regs: A pointer to hold the registers we've received from GDB. | ||
167 | * @regs: A pointer to a &struct pt_regs to hold these values in. | ||
168 | * | ||
169 | * Convert the GDB regs in @gdb_regs into the pt_regs, and store them | ||
170 | * in @regs. | ||
171 | */ | ||
172 | void gdb_regs_to_pt_regs(unsigned long *gdb_regs, struct pt_regs *regs) | ||
173 | { | ||
174 | #ifndef CONFIG_X86_32 | ||
175 | u32 *gdb_regs32 = (u32 *)gdb_regs; | ||
176 | #endif | ||
177 | regs->ax = gdb_regs[GDB_AX]; | ||
178 | regs->bx = gdb_regs[GDB_BX]; | ||
179 | regs->cx = gdb_regs[GDB_CX]; | ||
180 | regs->dx = gdb_regs[GDB_DX]; | ||
181 | regs->si = gdb_regs[GDB_SI]; | ||
182 | regs->di = gdb_regs[GDB_DI]; | ||
183 | regs->bp = gdb_regs[GDB_BP]; | ||
184 | regs->ip = gdb_regs[GDB_PC]; | ||
185 | #ifdef CONFIG_X86_32 | ||
186 | regs->flags = gdb_regs[GDB_PS]; | ||
187 | regs->ds = gdb_regs[GDB_DS]; | ||
188 | regs->es = gdb_regs[GDB_ES]; | ||
189 | regs->cs = gdb_regs[GDB_CS]; | ||
190 | #else | ||
191 | regs->r8 = gdb_regs[GDB_R8]; | ||
192 | regs->r9 = gdb_regs[GDB_R9]; | ||
193 | regs->r10 = gdb_regs[GDB_R10]; | ||
194 | regs->r11 = gdb_regs[GDB_R11]; | ||
195 | regs->r12 = gdb_regs[GDB_R12]; | ||
196 | regs->r13 = gdb_regs[GDB_R13]; | ||
197 | regs->r14 = gdb_regs[GDB_R14]; | ||
198 | regs->r15 = gdb_regs[GDB_R15]; | ||
199 | regs->flags = gdb_regs32[GDB_PS]; | ||
200 | regs->cs = gdb_regs32[GDB_CS]; | ||
201 | regs->ss = gdb_regs32[GDB_SS]; | ||
202 | #endif | ||
203 | } | ||
204 | |||
205 | static struct hw_breakpoint { | 192 | static struct hw_breakpoint { |
206 | unsigned enabled; | 193 | unsigned enabled; |
207 | unsigned type; | ||
208 | unsigned len; | ||
209 | unsigned long addr; | 194 | unsigned long addr; |
210 | } breakinfo[4]; | 195 | int len; |
196 | int type; | ||
197 | struct perf_event * __percpu *pev; | ||
198 | } breakinfo[HBP_NUM]; | ||
199 | |||
200 | static unsigned long early_dr7; | ||
211 | 201 | ||
212 | static void kgdb_correct_hw_break(void) | 202 | static void kgdb_correct_hw_break(void) |
213 | { | 203 | { |
214 | unsigned long dr7; | ||
215 | int correctit = 0; | ||
216 | int breakbit; | ||
217 | int breakno; | 204 | int breakno; |
218 | 205 | ||
219 | get_debugreg(dr7, 7); | 206 | for (breakno = 0; breakno < HBP_NUM; breakno++) { |
220 | for (breakno = 0; breakno < 4; breakno++) { | 207 | struct perf_event *bp; |
221 | breakbit = 2 << (breakno << 1); | 208 | struct arch_hw_breakpoint *info; |
222 | if (!(dr7 & breakbit) && breakinfo[breakno].enabled) { | 209 | int val; |
223 | correctit = 1; | 210 | int cpu = raw_smp_processor_id(); |
224 | dr7 |= breakbit; | 211 | if (!breakinfo[breakno].enabled) |
225 | dr7 &= ~(0xf0000 << (breakno << 2)); | 212 | continue; |
226 | dr7 |= ((breakinfo[breakno].len << 2) | | 213 | if (dbg_is_early) { |
227 | breakinfo[breakno].type) << | ||
228 | ((breakno << 2) + 16); | ||
229 | set_debugreg(breakinfo[breakno].addr, breakno); | 214 | set_debugreg(breakinfo[breakno].addr, breakno); |
230 | 215 | early_dr7 |= encode_dr7(breakno, | |
231 | } else { | 216 | breakinfo[breakno].len, |
232 | if ((dr7 & breakbit) && !breakinfo[breakno].enabled) { | 217 | breakinfo[breakno].type); |
233 | correctit = 1; | 218 | set_debugreg(early_dr7, 7); |
234 | dr7 &= ~breakbit; | 219 | continue; |
235 | dr7 &= ~(0xf0000 << (breakno << 2)); | ||
236 | } | ||
237 | } | 220 | } |
221 | bp = *per_cpu_ptr(breakinfo[breakno].pev, cpu); | ||
222 | info = counter_arch_bp(bp); | ||
223 | if (bp->attr.disabled != 1) | ||
224 | continue; | ||
225 | bp->attr.bp_addr = breakinfo[breakno].addr; | ||
226 | bp->attr.bp_len = breakinfo[breakno].len; | ||
227 | bp->attr.bp_type = breakinfo[breakno].type; | ||
228 | info->address = breakinfo[breakno].addr; | ||
229 | info->len = breakinfo[breakno].len; | ||
230 | info->type = breakinfo[breakno].type; | ||
231 | val = arch_install_hw_breakpoint(bp); | ||
232 | if (!val) | ||
233 | bp->attr.disabled = 0; | ||
234 | } | ||
235 | if (!dbg_is_early) | ||
236 | hw_breakpoint_restore(); | ||
237 | } | ||
238 | |||
239 | static int hw_break_reserve_slot(int breakno) | ||
240 | { | ||
241 | int cpu; | ||
242 | int cnt = 0; | ||
243 | struct perf_event **pevent; | ||
244 | |||
245 | if (dbg_is_early) | ||
246 | return 0; | ||
247 | |||
248 | for_each_online_cpu(cpu) { | ||
249 | cnt++; | ||
250 | pevent = per_cpu_ptr(breakinfo[breakno].pev, cpu); | ||
251 | if (dbg_reserve_bp_slot(*pevent)) | ||
252 | goto fail; | ||
253 | } | ||
254 | |||
255 | return 0; | ||
256 | |||
257 | fail: | ||
258 | for_each_online_cpu(cpu) { | ||
259 | cnt--; | ||
260 | if (!cnt) | ||
261 | break; | ||
262 | pevent = per_cpu_ptr(breakinfo[breakno].pev, cpu); | ||
263 | dbg_release_bp_slot(*pevent); | ||
264 | } | ||
265 | return -1; | ||
266 | } | ||
267 | |||
268 | static int hw_break_release_slot(int breakno) | ||
269 | { | ||
270 | struct perf_event **pevent; | ||
271 | int cpu; | ||
272 | |||
273 | if (dbg_is_early) | ||
274 | return 0; | ||
275 | |||
276 | for_each_online_cpu(cpu) { | ||
277 | pevent = per_cpu_ptr(breakinfo[breakno].pev, cpu); | ||
278 | if (dbg_release_bp_slot(*pevent)) | ||
279 | /* | ||
280 | * The debugger is responisble for handing the retry on | ||
281 | * remove failure. | ||
282 | */ | ||
283 | return -1; | ||
238 | } | 284 | } |
239 | if (correctit) | 285 | return 0; |
240 | set_debugreg(dr7, 7); | ||
241 | } | 286 | } |
242 | 287 | ||
243 | static int | 288 | static int |
@@ -245,12 +290,16 @@ kgdb_remove_hw_break(unsigned long addr, int len, enum kgdb_bptype bptype) | |||
245 | { | 290 | { |
246 | int i; | 291 | int i; |
247 | 292 | ||
248 | for (i = 0; i < 4; i++) | 293 | for (i = 0; i < HBP_NUM; i++) |
249 | if (breakinfo[i].addr == addr && breakinfo[i].enabled) | 294 | if (breakinfo[i].addr == addr && breakinfo[i].enabled) |
250 | break; | 295 | break; |
251 | if (i == 4) | 296 | if (i == HBP_NUM) |
252 | return -1; | 297 | return -1; |
253 | 298 | ||
299 | if (hw_break_release_slot(i)) { | ||
300 | printk(KERN_ERR "Cannot remove hw breakpoint at %lx\n", addr); | ||
301 | return -1; | ||
302 | } | ||
254 | breakinfo[i].enabled = 0; | 303 | breakinfo[i].enabled = 0; |
255 | 304 | ||
256 | return 0; | 305 | return 0; |
@@ -259,46 +308,73 @@ kgdb_remove_hw_break(unsigned long addr, int len, enum kgdb_bptype bptype) | |||
259 | static void kgdb_remove_all_hw_break(void) | 308 | static void kgdb_remove_all_hw_break(void) |
260 | { | 309 | { |
261 | int i; | 310 | int i; |
311 | int cpu = raw_smp_processor_id(); | ||
312 | struct perf_event *bp; | ||
262 | 313 | ||
263 | for (i = 0; i < 4; i++) | 314 | for (i = 0; i < HBP_NUM; i++) { |
264 | memset(&breakinfo[i], 0, sizeof(struct hw_breakpoint)); | 315 | if (!breakinfo[i].enabled) |
316 | continue; | ||
317 | bp = *per_cpu_ptr(breakinfo[i].pev, cpu); | ||
318 | if (bp->attr.disabled == 1) | ||
319 | continue; | ||
320 | if (dbg_is_early) | ||
321 | early_dr7 &= ~encode_dr7(i, breakinfo[i].len, | ||
322 | breakinfo[i].type); | ||
323 | else | ||
324 | arch_uninstall_hw_breakpoint(bp); | ||
325 | bp->attr.disabled = 1; | ||
326 | } | ||
265 | } | 327 | } |
266 | 328 | ||
267 | static int | 329 | static int |
268 | kgdb_set_hw_break(unsigned long addr, int len, enum kgdb_bptype bptype) | 330 | kgdb_set_hw_break(unsigned long addr, int len, enum kgdb_bptype bptype) |
269 | { | 331 | { |
270 | unsigned type; | ||
271 | int i; | 332 | int i; |
272 | 333 | ||
273 | for (i = 0; i < 4; i++) | 334 | for (i = 0; i < HBP_NUM; i++) |
274 | if (!breakinfo[i].enabled) | 335 | if (!breakinfo[i].enabled) |
275 | break; | 336 | break; |
276 | if (i == 4) | 337 | if (i == HBP_NUM) |
277 | return -1; | 338 | return -1; |
278 | 339 | ||
279 | switch (bptype) { | 340 | switch (bptype) { |
280 | case BP_HARDWARE_BREAKPOINT: | 341 | case BP_HARDWARE_BREAKPOINT: |
281 | type = 0; | 342 | len = 1; |
282 | len = 1; | 343 | breakinfo[i].type = X86_BREAKPOINT_EXECUTE; |
283 | break; | 344 | break; |
284 | case BP_WRITE_WATCHPOINT: | 345 | case BP_WRITE_WATCHPOINT: |
285 | type = 1; | 346 | breakinfo[i].type = X86_BREAKPOINT_WRITE; |
286 | break; | 347 | break; |
287 | case BP_ACCESS_WATCHPOINT: | 348 | case BP_ACCESS_WATCHPOINT: |
288 | type = 3; | 349 | breakinfo[i].type = X86_BREAKPOINT_RW; |
289 | break; | 350 | break; |
290 | default: | 351 | default: |
291 | return -1; | 352 | return -1; |
292 | } | 353 | } |
293 | 354 | switch (len) { | |
294 | if (len == 1 || len == 2 || len == 4) | 355 | case 1: |
295 | breakinfo[i].len = len - 1; | 356 | breakinfo[i].len = X86_BREAKPOINT_LEN_1; |
296 | else | 357 | break; |
358 | case 2: | ||
359 | breakinfo[i].len = X86_BREAKPOINT_LEN_2; | ||
360 | break; | ||
361 | case 4: | ||
362 | breakinfo[i].len = X86_BREAKPOINT_LEN_4; | ||
363 | break; | ||
364 | #ifdef CONFIG_X86_64 | ||
365 | case 8: | ||
366 | breakinfo[i].len = X86_BREAKPOINT_LEN_8; | ||
367 | break; | ||
368 | #endif | ||
369 | default: | ||
297 | return -1; | 370 | return -1; |
298 | 371 | } | |
299 | breakinfo[i].enabled = 1; | ||
300 | breakinfo[i].addr = addr; | 372 | breakinfo[i].addr = addr; |
301 | breakinfo[i].type = type; | 373 | if (hw_break_reserve_slot(i)) { |
374 | breakinfo[i].addr = 0; | ||
375 | return -1; | ||
376 | } | ||
377 | breakinfo[i].enabled = 1; | ||
302 | 378 | ||
303 | return 0; | 379 | return 0; |
304 | } | 380 | } |
@@ -313,25 +389,26 @@ kgdb_set_hw_break(unsigned long addr, int len, enum kgdb_bptype bptype) | |||
313 | */ | 389 | */ |
314 | void kgdb_disable_hw_debug(struct pt_regs *regs) | 390 | void kgdb_disable_hw_debug(struct pt_regs *regs) |
315 | { | 391 | { |
392 | int i; | ||
393 | int cpu = raw_smp_processor_id(); | ||
394 | struct perf_event *bp; | ||
395 | |||
316 | /* Disable hardware debugging while we are in kgdb: */ | 396 | /* Disable hardware debugging while we are in kgdb: */ |
317 | set_debugreg(0UL, 7); | 397 | set_debugreg(0UL, 7); |
318 | } | 398 | for (i = 0; i < HBP_NUM; i++) { |
319 | 399 | if (!breakinfo[i].enabled) | |
320 | /** | 400 | continue; |
321 | * kgdb_post_primary_code - Save error vector/code numbers. | 401 | if (dbg_is_early) { |
322 | * @regs: Original pt_regs. | 402 | early_dr7 &= ~encode_dr7(i, breakinfo[i].len, |
323 | * @e_vector: Original error vector. | 403 | breakinfo[i].type); |
324 | * @err_code: Original error code. | 404 | continue; |
325 | * | 405 | } |
326 | * This is needed on architectures which support SMP and KGDB. | 406 | bp = *per_cpu_ptr(breakinfo[i].pev, cpu); |
327 | * This function is called after all the slave cpus have been put | 407 | if (bp->attr.disabled == 1) |
328 | * to a know spin state and the primary CPU has control over KGDB. | 408 | continue; |
329 | */ | 409 | arch_uninstall_hw_breakpoint(bp); |
330 | void kgdb_post_primary_code(struct pt_regs *regs, int e_vector, int err_code) | 410 | bp->attr.disabled = 1; |
331 | { | 411 | } |
332 | /* primary processor is completely in the debugger */ | ||
333 | gdb_x86vector = e_vector; | ||
334 | gdb_x86errcode = err_code; | ||
335 | } | 412 | } |
336 | 413 | ||
337 | #ifdef CONFIG_SMP | 414 | #ifdef CONFIG_SMP |
@@ -378,9 +455,7 @@ int kgdb_arch_handle_exception(int e_vector, int signo, int err_code, | |||
378 | struct pt_regs *linux_regs) | 455 | struct pt_regs *linux_regs) |
379 | { | 456 | { |
380 | unsigned long addr; | 457 | unsigned long addr; |
381 | unsigned long dr6; | ||
382 | char *ptr; | 458 | char *ptr; |
383 | int newPC; | ||
384 | 459 | ||
385 | switch (remcomInBuffer[0]) { | 460 | switch (remcomInBuffer[0]) { |
386 | case 'c': | 461 | case 'c': |
@@ -391,8 +466,6 @@ int kgdb_arch_handle_exception(int e_vector, int signo, int err_code, | |||
391 | linux_regs->ip = addr; | 466 | linux_regs->ip = addr; |
392 | case 'D': | 467 | case 'D': |
393 | case 'k': | 468 | case 'k': |
394 | newPC = linux_regs->ip; | ||
395 | |||
396 | /* clear the trace bit */ | 469 | /* clear the trace bit */ |
397 | linux_regs->flags &= ~X86_EFLAGS_TF; | 470 | linux_regs->flags &= ~X86_EFLAGS_TF; |
398 | atomic_set(&kgdb_cpu_doing_single_step, -1); | 471 | atomic_set(&kgdb_cpu_doing_single_step, -1); |
@@ -404,20 +477,6 @@ int kgdb_arch_handle_exception(int e_vector, int signo, int err_code, | |||
404 | raw_smp_processor_id()); | 477 | raw_smp_processor_id()); |
405 | } | 478 | } |
406 | 479 | ||
407 | get_debugreg(dr6, 6); | ||
408 | if (!(dr6 & 0x4000)) { | ||
409 | int breakno; | ||
410 | |||
411 | for (breakno = 0; breakno < 4; breakno++) { | ||
412 | if (dr6 & (1 << breakno) && | ||
413 | breakinfo[breakno].type == 0) { | ||
414 | /* Set restore flag: */ | ||
415 | linux_regs->flags |= X86_EFLAGS_RF; | ||
416 | break; | ||
417 | } | ||
418 | } | ||
419 | } | ||
420 | set_debugreg(0UL, 6); | ||
421 | kgdb_correct_hw_break(); | 480 | kgdb_correct_hw_break(); |
422 | 481 | ||
423 | return 0; | 482 | return 0; |
@@ -485,8 +544,7 @@ static int __kgdb_notify(struct die_args *args, unsigned long cmd) | |||
485 | break; | 544 | break; |
486 | 545 | ||
487 | case DIE_DEBUG: | 546 | case DIE_DEBUG: |
488 | if (atomic_read(&kgdb_cpu_doing_single_step) == | 547 | if (atomic_read(&kgdb_cpu_doing_single_step) != -1) { |
489 | raw_smp_processor_id()) { | ||
490 | if (user_mode(regs)) | 548 | if (user_mode(regs)) |
491 | return single_step_cont(regs, args); | 549 | return single_step_cont(regs, args); |
492 | break; | 550 | break; |
@@ -501,7 +559,7 @@ static int __kgdb_notify(struct die_args *args, unsigned long cmd) | |||
501 | return NOTIFY_DONE; | 559 | return NOTIFY_DONE; |
502 | } | 560 | } |
503 | 561 | ||
504 | if (kgdb_handle_exception(args->trapnr, args->signr, args->err, regs)) | 562 | if (kgdb_handle_exception(args->trapnr, args->signr, cmd, regs)) |
505 | return NOTIFY_DONE; | 563 | return NOTIFY_DONE; |
506 | 564 | ||
507 | /* Must touch watchdog before return to normal operation */ | 565 | /* Must touch watchdog before return to normal operation */ |
@@ -509,6 +567,24 @@ static int __kgdb_notify(struct die_args *args, unsigned long cmd) | |||
509 | return NOTIFY_STOP; | 567 | return NOTIFY_STOP; |
510 | } | 568 | } |
511 | 569 | ||
570 | int kgdb_ll_trap(int cmd, const char *str, | ||
571 | struct pt_regs *regs, long err, int trap, int sig) | ||
572 | { | ||
573 | struct die_args args = { | ||
574 | .regs = regs, | ||
575 | .str = str, | ||
576 | .err = err, | ||
577 | .trapnr = trap, | ||
578 | .signr = sig, | ||
579 | |||
580 | }; | ||
581 | |||
582 | if (!kgdb_io_module_registered) | ||
583 | return NOTIFY_DONE; | ||
584 | |||
585 | return __kgdb_notify(&args, cmd); | ||
586 | } | ||
587 | |||
512 | static int | 588 | static int |
513 | kgdb_notify(struct notifier_block *self, unsigned long cmd, void *ptr) | 589 | kgdb_notify(struct notifier_block *self, unsigned long cmd, void *ptr) |
514 | { | 590 | { |
@@ -542,6 +618,51 @@ int kgdb_arch_init(void) | |||
542 | return register_die_notifier(&kgdb_notifier); | 618 | return register_die_notifier(&kgdb_notifier); |
543 | } | 619 | } |
544 | 620 | ||
621 | static void kgdb_hw_overflow_handler(struct perf_event *event, int nmi, | ||
622 | struct perf_sample_data *data, struct pt_regs *regs) | ||
623 | { | ||
624 | kgdb_ll_trap(DIE_DEBUG, "debug", regs, 0, 0, SIGTRAP); | ||
625 | } | ||
626 | |||
627 | void kgdb_arch_late(void) | ||
628 | { | ||
629 | int i, cpu; | ||
630 | struct perf_event_attr attr; | ||
631 | struct perf_event **pevent; | ||
632 | |||
633 | /* | ||
634 | * Pre-allocate the hw breakpoint structions in the non-atomic | ||
635 | * portion of kgdb because this operation requires mutexs to | ||
636 | * complete. | ||
637 | */ | ||
638 | hw_breakpoint_init(&attr); | ||
639 | attr.bp_addr = (unsigned long)kgdb_arch_init; | ||
640 | attr.bp_len = HW_BREAKPOINT_LEN_1; | ||
641 | attr.bp_type = HW_BREAKPOINT_W; | ||
642 | attr.disabled = 1; | ||
643 | for (i = 0; i < HBP_NUM; i++) { | ||
644 | if (breakinfo[i].pev) | ||
645 | continue; | ||
646 | breakinfo[i].pev = register_wide_hw_breakpoint(&attr, NULL); | ||
647 | if (IS_ERR(breakinfo[i].pev)) { | ||
648 | printk(KERN_ERR "kgdb: Could not allocate hw" | ||
649 | "breakpoints\nDisabling the kernel debugger\n"); | ||
650 | breakinfo[i].pev = NULL; | ||
651 | kgdb_arch_exit(); | ||
652 | return; | ||
653 | } | ||
654 | for_each_online_cpu(cpu) { | ||
655 | pevent = per_cpu_ptr(breakinfo[i].pev, cpu); | ||
656 | pevent[0]->hw.sample_period = 1; | ||
657 | pevent[0]->overflow_handler = kgdb_hw_overflow_handler; | ||
658 | if (pevent[0]->destroy != NULL) { | ||
659 | pevent[0]->destroy = NULL; | ||
660 | release_bp_slot(*pevent); | ||
661 | } | ||
662 | } | ||
663 | } | ||
664 | } | ||
665 | |||
545 | /** | 666 | /** |
546 | * kgdb_arch_exit - Perform any architecture specific uninitalization. | 667 | * kgdb_arch_exit - Perform any architecture specific uninitalization. |
547 | * | 668 | * |
@@ -550,6 +671,13 @@ int kgdb_arch_init(void) | |||
550 | */ | 671 | */ |
551 | void kgdb_arch_exit(void) | 672 | void kgdb_arch_exit(void) |
552 | { | 673 | { |
674 | int i; | ||
675 | for (i = 0; i < 4; i++) { | ||
676 | if (breakinfo[i].pev) { | ||
677 | unregister_wide_hw_breakpoint(breakinfo[i].pev); | ||
678 | breakinfo[i].pev = NULL; | ||
679 | } | ||
680 | } | ||
553 | unregister_die_notifier(&kgdb_notifier); | 681 | unregister_die_notifier(&kgdb_notifier); |
554 | } | 682 | } |
555 | 683 | ||
@@ -582,6 +710,11 @@ unsigned long kgdb_arch_pc(int exception, struct pt_regs *regs) | |||
582 | return instruction_pointer(regs); | 710 | return instruction_pointer(regs); |
583 | } | 711 | } |
584 | 712 | ||
713 | void kgdb_arch_set_pc(struct pt_regs *regs, unsigned long ip) | ||
714 | { | ||
715 | regs->ip = ip; | ||
716 | } | ||
717 | |||
585 | struct kgdb_arch arch_kgdb_ops = { | 718 | struct kgdb_arch arch_kgdb_ops = { |
586 | /* Breakpoint instruction: */ | 719 | /* Breakpoint instruction: */ |
587 | .gdb_bpt_instr = { 0xcc }, | 720 | .gdb_bpt_instr = { 0xcc }, |