David Howells | e460d64 | 2011-03-18 16:54:31 +0000 | [diff] [blame] | 1 | /* kgdb support for MN10300 |
| 2 | * |
| 3 | * Copyright (C) 2010 Red Hat, Inc. All Rights Reserved. |
| 4 | * Written by David Howells (dhowells@redhat.com) |
| 5 | * |
| 6 | * This program is free software; you can redistribute it and/or |
| 7 | * modify it under the terms of the GNU General Public Licence |
| 8 | * as published by the Free Software Foundation; either version |
| 9 | * 2 of the Licence, or (at your option) any later version. |
| 10 | */ |
| 11 | |
David Howells | 5141c46 | 2011-03-18 16:54:32 +0000 | [diff] [blame] | 12 | #include <linux/slab.h> |
David Howells | e460d64 | 2011-03-18 16:54:31 +0000 | [diff] [blame] | 13 | #include <linux/ptrace.h> |
| 14 | #include <linux/kgdb.h> |
| 15 | #include <linux/uaccess.h> |
| 16 | #include <unit/leds.h> |
| 17 | #include <unit/serial.h> |
| 18 | #include <asm/debugger.h> |
| 19 | #include <asm/serial-regs.h> |
| 20 | #include "internal.h" |
| 21 | |
| 22 | /* |
David Howells | 5141c46 | 2011-03-18 16:54:32 +0000 | [diff] [blame] | 23 | * Software single-stepping breakpoint save (used by __switch_to()) |
| 24 | */ |
| 25 | static struct thread_info *kgdb_sstep_thread; |
| 26 | u8 *kgdb_sstep_bp_addr[2]; |
| 27 | u8 kgdb_sstep_bp[2]; |
| 28 | |
| 29 | /* |
David Howells | e460d64 | 2011-03-18 16:54:31 +0000 | [diff] [blame] | 30 | * Copy kernel exception frame registers to the GDB register file |
| 31 | */ |
| 32 | void pt_regs_to_gdb_regs(unsigned long *gdb_regs, struct pt_regs *regs) |
| 33 | { |
| 34 | unsigned long ssp = (unsigned long) (regs + 1); |
| 35 | |
| 36 | gdb_regs[GDB_FR_D0] = regs->d0; |
| 37 | gdb_regs[GDB_FR_D1] = regs->d1; |
| 38 | gdb_regs[GDB_FR_D2] = regs->d2; |
| 39 | gdb_regs[GDB_FR_D3] = regs->d3; |
| 40 | gdb_regs[GDB_FR_A0] = regs->a0; |
| 41 | gdb_regs[GDB_FR_A1] = regs->a1; |
| 42 | gdb_regs[GDB_FR_A2] = regs->a2; |
| 43 | gdb_regs[GDB_FR_A3] = regs->a3; |
| 44 | gdb_regs[GDB_FR_SP] = (regs->epsw & EPSW_nSL) ? regs->sp : ssp; |
| 45 | gdb_regs[GDB_FR_PC] = regs->pc; |
| 46 | gdb_regs[GDB_FR_MDR] = regs->mdr; |
| 47 | gdb_regs[GDB_FR_EPSW] = regs->epsw; |
| 48 | gdb_regs[GDB_FR_LIR] = regs->lir; |
| 49 | gdb_regs[GDB_FR_LAR] = regs->lar; |
| 50 | gdb_regs[GDB_FR_MDRQ] = regs->mdrq; |
| 51 | gdb_regs[GDB_FR_E0] = regs->e0; |
| 52 | gdb_regs[GDB_FR_E1] = regs->e1; |
| 53 | gdb_regs[GDB_FR_E2] = regs->e2; |
| 54 | gdb_regs[GDB_FR_E3] = regs->e3; |
| 55 | gdb_regs[GDB_FR_E4] = regs->e4; |
| 56 | gdb_regs[GDB_FR_E5] = regs->e5; |
| 57 | gdb_regs[GDB_FR_E6] = regs->e6; |
| 58 | gdb_regs[GDB_FR_E7] = regs->e7; |
| 59 | gdb_regs[GDB_FR_SSP] = ssp; |
| 60 | gdb_regs[GDB_FR_MSP] = 0; |
| 61 | gdb_regs[GDB_FR_USP] = regs->sp; |
| 62 | gdb_regs[GDB_FR_MCRH] = regs->mcrh; |
| 63 | gdb_regs[GDB_FR_MCRL] = regs->mcrl; |
| 64 | gdb_regs[GDB_FR_MCVF] = regs->mcvf; |
| 65 | gdb_regs[GDB_FR_DUMMY0] = 0; |
| 66 | gdb_regs[GDB_FR_DUMMY1] = 0; |
| 67 | gdb_regs[GDB_FR_FS0] = 0; |
| 68 | } |
| 69 | |
| 70 | /* |
| 71 | * Extracts kernel SP/PC values understandable by gdb from the values |
| 72 | * saved by switch_to(). |
| 73 | */ |
| 74 | void sleeping_thread_to_gdb_regs(unsigned long *gdb_regs, struct task_struct *p) |
| 75 | { |
| 76 | gdb_regs[GDB_FR_SSP] = p->thread.sp; |
| 77 | gdb_regs[GDB_FR_PC] = p->thread.pc; |
| 78 | gdb_regs[GDB_FR_A3] = p->thread.a3; |
| 79 | gdb_regs[GDB_FR_USP] = p->thread.usp; |
| 80 | gdb_regs[GDB_FR_FPCR] = p->thread.fpu_state.fpcr; |
| 81 | } |
| 82 | |
| 83 | /* |
| 84 | * Fill kernel exception frame registers from the GDB register file |
| 85 | */ |
| 86 | void gdb_regs_to_pt_regs(unsigned long *gdb_regs, struct pt_regs *regs) |
| 87 | { |
| 88 | regs->d0 = gdb_regs[GDB_FR_D0]; |
| 89 | regs->d1 = gdb_regs[GDB_FR_D1]; |
| 90 | regs->d2 = gdb_regs[GDB_FR_D2]; |
| 91 | regs->d3 = gdb_regs[GDB_FR_D3]; |
| 92 | regs->a0 = gdb_regs[GDB_FR_A0]; |
| 93 | regs->a1 = gdb_regs[GDB_FR_A1]; |
| 94 | regs->a2 = gdb_regs[GDB_FR_A2]; |
| 95 | regs->a3 = gdb_regs[GDB_FR_A3]; |
| 96 | regs->sp = gdb_regs[GDB_FR_SP]; |
| 97 | regs->pc = gdb_regs[GDB_FR_PC]; |
| 98 | regs->mdr = gdb_regs[GDB_FR_MDR]; |
| 99 | regs->epsw = gdb_regs[GDB_FR_EPSW]; |
| 100 | regs->lir = gdb_regs[GDB_FR_LIR]; |
| 101 | regs->lar = gdb_regs[GDB_FR_LAR]; |
| 102 | regs->mdrq = gdb_regs[GDB_FR_MDRQ]; |
| 103 | regs->e0 = gdb_regs[GDB_FR_E0]; |
| 104 | regs->e1 = gdb_regs[GDB_FR_E1]; |
| 105 | regs->e2 = gdb_regs[GDB_FR_E2]; |
| 106 | regs->e3 = gdb_regs[GDB_FR_E3]; |
| 107 | regs->e4 = gdb_regs[GDB_FR_E4]; |
| 108 | regs->e5 = gdb_regs[GDB_FR_E5]; |
| 109 | regs->e6 = gdb_regs[GDB_FR_E6]; |
| 110 | regs->e7 = gdb_regs[GDB_FR_E7]; |
| 111 | regs->sp = gdb_regs[GDB_FR_SSP]; |
| 112 | /* gdb_regs[GDB_FR_MSP]; */ |
| 113 | // regs->usp = gdb_regs[GDB_FR_USP]; |
| 114 | regs->mcrh = gdb_regs[GDB_FR_MCRH]; |
| 115 | regs->mcrl = gdb_regs[GDB_FR_MCRL]; |
| 116 | regs->mcvf = gdb_regs[GDB_FR_MCVF]; |
| 117 | /* gdb_regs[GDB_FR_DUMMY0]; */ |
| 118 | /* gdb_regs[GDB_FR_DUMMY1]; */ |
| 119 | |
| 120 | // regs->fpcr = gdb_regs[GDB_FR_FPCR]; |
| 121 | // regs->fs0 = gdb_regs[GDB_FR_FS0]; |
| 122 | } |
| 123 | |
| 124 | struct kgdb_arch arch_kgdb_ops = { |
| 125 | .gdb_bpt_instr = { 0xff }, |
| 126 | .flags = KGDB_HW_BREAKPOINT, |
| 127 | }; |
| 128 | |
David Howells | 5141c46 | 2011-03-18 16:54:32 +0000 | [diff] [blame] | 129 | static const unsigned char mn10300_kgdb_insn_sizes[256] = |
| 130 | { |
| 131 | /* 1 2 3 4 5 6 7 8 9 a b c d e f */ |
| 132 | 1, 3, 3, 3, 1, 3, 3, 3, 1, 3, 3, 3, 1, 3, 3, 3, /* 0 */ |
| 133 | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 1 */ |
| 134 | 2, 2, 2, 2, 3, 3, 3, 3, 2, 2, 2, 2, 3, 3, 3, 3, /* 2 */ |
| 135 | 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 1, 1, 1, 1, /* 3 */ |
| 136 | 1, 1, 2, 2, 1, 1, 2, 2, 1, 1, 2, 2, 1, 1, 2, 2, /* 4 */ |
| 137 | 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, /* 5 */ |
| 138 | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 6 */ |
| 139 | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 7 */ |
| 140 | 2, 1, 1, 1, 1, 2, 1, 1, 1, 1, 2, 1, 1, 1, 1, 2, /* 8 */ |
| 141 | 2, 1, 1, 1, 1, 2, 1, 1, 1, 1, 2, 1, 1, 1, 1, 2, /* 9 */ |
| 142 | 2, 1, 1, 1, 1, 2, 1, 1, 1, 1, 2, 1, 1, 1, 1, 2, /* a */ |
| 143 | 2, 1, 1, 1, 1, 2, 1, 1, 1, 1, 2, 1, 1, 1, 1, 2, /* b */ |
| 144 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 2, 2, /* c */ |
| 145 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* d */ |
| 146 | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* e */ |
| 147 | 0, 2, 2, 2, 2, 2, 2, 4, 0, 3, 0, 4, 0, 6, 7, 1 /* f */ |
| 148 | }; |
| 149 | |
David Howells | e460d64 | 2011-03-18 16:54:31 +0000 | [diff] [blame] | 150 | /* |
David Howells | 5141c46 | 2011-03-18 16:54:32 +0000 | [diff] [blame] | 151 | * Attempt to emulate single stepping by means of breakpoint instructions. |
| 152 | * Although there is a single-step trace flag in EPSW, its use is not |
| 153 | * sufficiently documented and is only intended for use with the JTAG debugger. |
| 154 | */ |
| 155 | static int kgdb_arch_do_singlestep(struct pt_regs *regs) |
| 156 | { |
| 157 | unsigned long arg; |
| 158 | unsigned size; |
| 159 | u8 *pc = (u8 *)regs->pc, *sp = (u8 *)(regs + 1), cur; |
| 160 | u8 *x = NULL, *y = NULL; |
| 161 | int ret; |
| 162 | |
| 163 | ret = probe_kernel_read(&cur, pc, 1); |
| 164 | if (ret < 0) |
| 165 | return ret; |
| 166 | |
| 167 | size = mn10300_kgdb_insn_sizes[cur]; |
| 168 | if (size > 0) { |
| 169 | x = pc + size; |
| 170 | goto set_x; |
| 171 | } |
| 172 | |
| 173 | switch (cur) { |
| 174 | /* Bxx (d8,PC) */ |
| 175 | case 0xc0 ... 0xca: |
| 176 | ret = probe_kernel_read(&arg, pc + 1, 1); |
| 177 | if (ret < 0) |
| 178 | return ret; |
| 179 | x = pc + 2; |
| 180 | if (arg >= 0 && arg <= 2) |
| 181 | goto set_x; |
| 182 | y = pc + (s8)arg; |
| 183 | goto set_x_and_y; |
| 184 | |
| 185 | /* LXX (d8,PC) */ |
| 186 | case 0xd0 ... 0xda: |
| 187 | x = pc + 1; |
| 188 | if (regs->pc == regs->lar) |
| 189 | goto set_x; |
| 190 | y = (u8 *)regs->lar; |
| 191 | goto set_x_and_y; |
| 192 | |
| 193 | /* SETLB - loads the next four bytes into the LIR register |
| 194 | * (which mustn't include a breakpoint instruction) */ |
| 195 | case 0xdb: |
| 196 | x = pc + 5; |
| 197 | goto set_x; |
| 198 | |
| 199 | /* JMP (d16,PC) or CALL (d16,PC) */ |
| 200 | case 0xcc: |
| 201 | case 0xcd: |
| 202 | ret = probe_kernel_read(&arg, pc + 1, 2); |
| 203 | if (ret < 0) |
| 204 | return ret; |
| 205 | x = pc + (s16)arg; |
| 206 | goto set_x; |
| 207 | |
| 208 | /* JMP (d32,PC) or CALL (d32,PC) */ |
| 209 | case 0xdc: |
| 210 | case 0xdd: |
| 211 | ret = probe_kernel_read(&arg, pc + 1, 4); |
| 212 | if (ret < 0) |
| 213 | return ret; |
| 214 | x = pc + (s32)arg; |
| 215 | goto set_x; |
| 216 | |
| 217 | /* RETF */ |
| 218 | case 0xde: |
| 219 | x = (u8 *)regs->mdr; |
| 220 | goto set_x; |
| 221 | |
| 222 | /* RET */ |
| 223 | case 0xdf: |
| 224 | ret = probe_kernel_read(&arg, pc + 2, 1); |
| 225 | if (ret < 0) |
| 226 | return ret; |
| 227 | ret = probe_kernel_read(&x, sp + (s8)arg, 4); |
| 228 | if (ret < 0) |
| 229 | return ret; |
| 230 | goto set_x; |
| 231 | |
| 232 | case 0xf0: |
| 233 | ret = probe_kernel_read(&cur, pc + 1, 1); |
| 234 | if (ret < 0) |
| 235 | return ret; |
| 236 | |
| 237 | if (cur >= 0xf0 && cur <= 0xf7) { |
| 238 | /* JMP (An) / CALLS (An) */ |
| 239 | switch (cur & 3) { |
| 240 | case 0: x = (u8 *)regs->a0; break; |
| 241 | case 1: x = (u8 *)regs->a1; break; |
| 242 | case 2: x = (u8 *)regs->a2; break; |
| 243 | case 3: x = (u8 *)regs->a3; break; |
| 244 | } |
| 245 | goto set_x; |
| 246 | } else if (cur == 0xfc) { |
| 247 | /* RETS */ |
| 248 | ret = probe_kernel_read(&x, sp, 4); |
| 249 | if (ret < 0) |
| 250 | return ret; |
| 251 | goto set_x; |
| 252 | } else if (cur == 0xfd) { |
| 253 | /* RTI */ |
| 254 | ret = probe_kernel_read(&x, sp + 4, 4); |
| 255 | if (ret < 0) |
| 256 | return ret; |
| 257 | goto set_x; |
| 258 | } else { |
| 259 | x = pc + 2; |
| 260 | goto set_x; |
| 261 | } |
| 262 | break; |
| 263 | |
| 264 | /* potential 3-byte conditional branches */ |
| 265 | case 0xf8: |
| 266 | ret = probe_kernel_read(&cur, pc + 1, 1); |
| 267 | if (ret < 0) |
| 268 | return ret; |
| 269 | x = pc + 3; |
| 270 | |
| 271 | if (cur >= 0xe8 && cur <= 0xeb) { |
| 272 | ret = probe_kernel_read(&arg, pc + 2, 1); |
| 273 | if (ret < 0) |
| 274 | return ret; |
| 275 | if (arg >= 0 && arg <= 3) |
| 276 | goto set_x; |
| 277 | y = pc + (s8)arg; |
| 278 | goto set_x_and_y; |
| 279 | } |
| 280 | goto set_x; |
| 281 | |
| 282 | case 0xfa: |
| 283 | ret = probe_kernel_read(&cur, pc + 1, 1); |
| 284 | if (ret < 0) |
| 285 | return ret; |
| 286 | |
| 287 | if (cur == 0xff) { |
| 288 | /* CALLS (d16,PC) */ |
| 289 | ret = probe_kernel_read(&arg, pc + 2, 2); |
| 290 | if (ret < 0) |
| 291 | return ret; |
| 292 | x = pc + (s16)arg; |
| 293 | goto set_x; |
| 294 | } |
| 295 | |
| 296 | x = pc + 4; |
| 297 | goto set_x; |
| 298 | |
| 299 | case 0xfc: |
| 300 | ret = probe_kernel_read(&cur, pc + 1, 1); |
| 301 | if (ret < 0) |
| 302 | return ret; |
| 303 | |
| 304 | if (cur == 0xff) { |
| 305 | /* CALLS (d32,PC) */ |
| 306 | ret = probe_kernel_read(&arg, pc + 2, 4); |
| 307 | if (ret < 0) |
| 308 | return ret; |
| 309 | x = pc + (s32)arg; |
| 310 | goto set_x; |
| 311 | } |
| 312 | |
| 313 | x = pc + 6; |
| 314 | goto set_x; |
| 315 | } |
| 316 | |
| 317 | return 0; |
| 318 | |
| 319 | set_x: |
| 320 | kgdb_sstep_bp_addr[0] = x; |
| 321 | kgdb_sstep_bp_addr[1] = NULL; |
| 322 | ret = probe_kernel_read(&kgdb_sstep_bp[0], x, 1); |
| 323 | if (ret < 0) |
| 324 | return ret; |
| 325 | ret = probe_kernel_write(x, &arch_kgdb_ops.gdb_bpt_instr, 1); |
| 326 | if (ret < 0) |
| 327 | return ret; |
| 328 | kgdb_sstep_thread = current_thread_info(); |
| 329 | debugger_local_cache_flushinv_one(x); |
| 330 | return ret; |
| 331 | |
| 332 | set_x_and_y: |
| 333 | kgdb_sstep_bp_addr[0] = x; |
| 334 | kgdb_sstep_bp_addr[1] = y; |
| 335 | ret = probe_kernel_read(&kgdb_sstep_bp[0], x, 1); |
| 336 | if (ret < 0) |
| 337 | return ret; |
| 338 | ret = probe_kernel_read(&kgdb_sstep_bp[1], y, 1); |
| 339 | if (ret < 0) |
| 340 | return ret; |
| 341 | ret = probe_kernel_write(x, &arch_kgdb_ops.gdb_bpt_instr, 1); |
| 342 | if (ret < 0) |
| 343 | return ret; |
| 344 | ret = probe_kernel_write(y, &arch_kgdb_ops.gdb_bpt_instr, 1); |
| 345 | if (ret < 0) { |
| 346 | probe_kernel_write(kgdb_sstep_bp_addr[0], |
| 347 | &kgdb_sstep_bp[0], 1); |
| 348 | } else { |
| 349 | kgdb_sstep_thread = current_thread_info(); |
| 350 | } |
| 351 | debugger_local_cache_flushinv_one(x); |
| 352 | debugger_local_cache_flushinv_one(y); |
| 353 | return ret; |
| 354 | } |
| 355 | |
| 356 | /* |
| 357 | * Remove emplaced single-step breakpoints, returning true if we hit one of |
| 358 | * them. |
| 359 | */ |
| 360 | static bool kgdb_arch_undo_singlestep(struct pt_regs *regs) |
| 361 | { |
| 362 | bool hit = false; |
| 363 | u8 *x = kgdb_sstep_bp_addr[0], *y = kgdb_sstep_bp_addr[1]; |
| 364 | u8 opcode; |
| 365 | |
| 366 | if (kgdb_sstep_thread == current_thread_info()) { |
| 367 | if (x) { |
| 368 | if (x == (u8 *)regs->pc) |
| 369 | hit = true; |
| 370 | if (probe_kernel_read(&opcode, x, |
| 371 | 1) < 0 || |
| 372 | opcode != 0xff) |
| 373 | BUG(); |
| 374 | probe_kernel_write(x, &kgdb_sstep_bp[0], 1); |
| 375 | debugger_local_cache_flushinv_one(x); |
| 376 | } |
| 377 | if (y) { |
| 378 | if (y == (u8 *)regs->pc) |
| 379 | hit = true; |
| 380 | if (probe_kernel_read(&opcode, y, |
| 381 | 1) < 0 || |
| 382 | opcode != 0xff) |
| 383 | BUG(); |
| 384 | probe_kernel_write(y, &kgdb_sstep_bp[1], 1); |
| 385 | debugger_local_cache_flushinv_one(y); |
| 386 | } |
| 387 | } |
| 388 | |
| 389 | kgdb_sstep_bp_addr[0] = NULL; |
| 390 | kgdb_sstep_bp_addr[1] = NULL; |
| 391 | kgdb_sstep_thread = NULL; |
| 392 | return hit; |
| 393 | } |
| 394 | |
| 395 | /* |
| 396 | * Catch a single-step-pending thread being deleted and make sure the global |
| 397 | * single-step state is cleared. At this point the breakpoints should have |
| 398 | * been removed by __switch_to(). |
| 399 | */ |
Thomas Gleixner | c03a6a7 | 2012-05-05 15:05:45 +0000 | [diff] [blame] | 400 | void arch_release_thread_info(struct thread_info *ti) |
David Howells | 5141c46 | 2011-03-18 16:54:32 +0000 | [diff] [blame] | 401 | { |
| 402 | if (kgdb_sstep_thread == ti) { |
| 403 | kgdb_sstep_thread = NULL; |
| 404 | |
| 405 | /* However, we may now be running in degraded mode, with most |
| 406 | * of the CPUs disabled until such a time as KGDB is reentered, |
| 407 | * so force immediate reentry */ |
| 408 | kgdb_breakpoint(); |
| 409 | } |
David Howells | 5141c46 | 2011-03-18 16:54:32 +0000 | [diff] [blame] | 410 | } |
| 411 | |
| 412 | /* |
| 413 | * Handle unknown packets and [CcsDk] packets |
| 414 | * - at this point breakpoints have been installed |
David Howells | e460d64 | 2011-03-18 16:54:31 +0000 | [diff] [blame] | 415 | */ |
| 416 | int kgdb_arch_handle_exception(int vector, int signo, int err_code, |
| 417 | char *remcom_in_buffer, char *remcom_out_buffer, |
| 418 | struct pt_regs *regs) |
| 419 | { |
| 420 | long addr; |
| 421 | char *ptr; |
| 422 | |
| 423 | switch (remcom_in_buffer[0]) { |
| 424 | case 'c': |
David Howells | 5141c46 | 2011-03-18 16:54:32 +0000 | [diff] [blame] | 425 | case 's': |
David Howells | e460d64 | 2011-03-18 16:54:31 +0000 | [diff] [blame] | 426 | /* try to read optional parameter, pc unchanged if no parm */ |
| 427 | ptr = &remcom_in_buffer[1]; |
| 428 | if (kgdb_hex2long(&ptr, &addr)) |
| 429 | regs->pc = addr; |
David Howells | 5141c46 | 2011-03-18 16:54:32 +0000 | [diff] [blame] | 430 | case 'D': |
| 431 | case 'k': |
| 432 | atomic_set(&kgdb_cpu_doing_single_step, -1); |
David Howells | e460d64 | 2011-03-18 16:54:31 +0000 | [diff] [blame] | 433 | |
David Howells | 5141c46 | 2011-03-18 16:54:32 +0000 | [diff] [blame] | 434 | if (remcom_in_buffer[0] == 's') { |
| 435 | kgdb_arch_do_singlestep(regs); |
| 436 | kgdb_single_step = 1; |
| 437 | atomic_set(&kgdb_cpu_doing_single_step, |
| 438 | raw_smp_processor_id()); |
| 439 | } |
| 440 | return 0; |
David Howells | e460d64 | 2011-03-18 16:54:31 +0000 | [diff] [blame] | 441 | } |
| 442 | return -1; /* this means that we do not want to exit from the handler */ |
| 443 | } |
| 444 | |
| 445 | /* |
| 446 | * Handle event interception |
| 447 | * - returns 0 if the exception should be skipped, -ERROR otherwise. |
| 448 | */ |
| 449 | int debugger_intercept(enum exception_code excep, int signo, int si_code, |
| 450 | struct pt_regs *regs) |
| 451 | { |
| 452 | int ret; |
| 453 | |
David Howells | 5141c46 | 2011-03-18 16:54:32 +0000 | [diff] [blame] | 454 | if (kgdb_arch_undo_singlestep(regs)) { |
| 455 | excep = EXCEP_TRAP; |
| 456 | signo = SIGTRAP; |
| 457 | si_code = TRAP_TRACE; |
| 458 | } |
| 459 | |
David Howells | e460d64 | 2011-03-18 16:54:31 +0000 | [diff] [blame] | 460 | ret = kgdb_handle_exception(excep, signo, si_code, regs); |
| 461 | |
| 462 | debugger_local_cache_flushinv(); |
| 463 | |
| 464 | return ret; |
| 465 | } |
| 466 | |
| 467 | /* |
| 468 | * Determine if we've hit a debugger special breakpoint |
| 469 | */ |
| 470 | int at_debugger_breakpoint(struct pt_regs *regs) |
| 471 | { |
| 472 | return regs->pc == (unsigned long)&__arch_kgdb_breakpoint; |
| 473 | } |
| 474 | |
| 475 | /* |
| 476 | * Initialise kgdb |
| 477 | */ |
| 478 | int kgdb_arch_init(void) |
| 479 | { |
| 480 | return 0; |
| 481 | } |
| 482 | |
| 483 | /* |
| 484 | * Do something, perhaps, but don't know what. |
| 485 | */ |
| 486 | void kgdb_arch_exit(void) |
| 487 | { |
| 488 | } |
| 489 | |
| 490 | #ifdef CONFIG_SMP |
| 491 | void debugger_nmi_interrupt(struct pt_regs *regs, enum exception_code code) |
| 492 | { |
| 493 | kgdb_nmicallback(arch_smp_processor_id(), regs); |
| 494 | debugger_local_cache_flushinv(); |
| 495 | } |
| 496 | |
| 497 | void kgdb_roundup_cpus(unsigned long flags) |
| 498 | { |
| 499 | smp_jump_to_debugger(); |
| 500 | } |
| 501 | #endif |