diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2010-08-05 18:59:48 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2010-08-05 18:59:48 -0400 |
commit | 89a6c8cb9e6e11b6e3671dce7e037789b8f7cf62 (patch) | |
tree | 12b16a8abe303fd86c156ddfbb86caa469e45a98 /arch/mips/kernel | |
parent | 03c0c29aff7e56b722eb6c47eace222b140d0377 (diff) | |
parent | 3fa43aba08c5b5a4b407e402606fbe463239b14a (diff) |
Merge branch 'for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jwessel/linux-2.6-kgdb
* 'for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jwessel/linux-2.6-kgdb:
debug_core,kdb: fix crash when arch does not have single step
kgdb,x86: use macro HBP_NUM to replace magic number 4
kgdb,mips: remove unused kgdb_cpu_doing_single_step operations
mm,kdb,kgdb: Add a debug reference for the kdb kmap usage
KGDB: Remove set but unused newPC
ftrace,kdb: Allow dumping a specific cpu's buffer with ftdump
ftrace,kdb: Extend kdb to be able to dump the ftrace buffer
kgdb,powerpc: Replace hardcoded offset by BREAK_INSTR_SIZE
arm,kgdb: Add ability to trap into debugger on notify_die
gdbstub: do not directly use dbg_reg_def[] in gdb_cmd_reg_set()
gdbstub: Implement gdbserial 'p' and 'P' packets
kgdb,arm: Individual register get/set for arm
kgdb,mips: Individual register get/set for mips
kgdb,x86: Individual register get/set for x86
kgdb,kdb: individual register set and and get API
gdbstub: Optimize kgdb's "thread:" response for the gdb serial protocol
kgdb: remove custom hex_to_bin()implementation
Diffstat (limited to 'arch/mips/kernel')
-rw-r--r-- | arch/mips/kernel/kgdb.c | 211 |
1 files changed, 146 insertions, 65 deletions
diff --git a/arch/mips/kernel/kgdb.c b/arch/mips/kernel/kgdb.c index 9b78ff6e9b84..1f4e2fa64140 100644 --- a/arch/mips/kernel/kgdb.c +++ b/arch/mips/kernel/kgdb.c | |||
@@ -50,6 +50,151 @@ static struct hard_trap_info { | |||
50 | { 0, 0} /* Must be last */ | 50 | { 0, 0} /* Must be last */ |
51 | }; | 51 | }; |
52 | 52 | ||
53 | struct dbg_reg_def_t dbg_reg_def[DBG_MAX_REG_NUM] = | ||
54 | { | ||
55 | { "zero", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[0]) }, | ||
56 | { "at", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[1]) }, | ||
57 | { "v0", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[2]) }, | ||
58 | { "v1", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[3]) }, | ||
59 | { "a0", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[4]) }, | ||
60 | { "a1", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[5]) }, | ||
61 | { "a2", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[6]) }, | ||
62 | { "a3", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[7]) }, | ||
63 | { "t0", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[8]) }, | ||
64 | { "t1", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[9]) }, | ||
65 | { "t2", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[10]) }, | ||
66 | { "t3", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[11]) }, | ||
67 | { "t4", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[12]) }, | ||
68 | { "t5", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[13]) }, | ||
69 | { "t6", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[14]) }, | ||
70 | { "t7", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[15]) }, | ||
71 | { "s0", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[16]) }, | ||
72 | { "s1", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[17]) }, | ||
73 | { "s2", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[18]) }, | ||
74 | { "s3", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[19]) }, | ||
75 | { "s4", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[20]) }, | ||
76 | { "s5", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[21]) }, | ||
77 | { "s6", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[22]) }, | ||
78 | { "s7", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[23]) }, | ||
79 | { "t8", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[24]) }, | ||
80 | { "t9", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[25]) }, | ||
81 | { "k0", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[26]) }, | ||
82 | { "k1", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[27]) }, | ||
83 | { "gp", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[28]) }, | ||
84 | { "sp", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[29]) }, | ||
85 | { "s8", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[30]) }, | ||
86 | { "ra", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[31]) }, | ||
87 | { "sr", GDB_SIZEOF_REG, offsetof(struct pt_regs, cp0_status) }, | ||
88 | { "lo", GDB_SIZEOF_REG, offsetof(struct pt_regs, lo) }, | ||
89 | { "hi", GDB_SIZEOF_REG, offsetof(struct pt_regs, hi) }, | ||
90 | { "bad", GDB_SIZEOF_REG, offsetof(struct pt_regs, cp0_badvaddr) }, | ||
91 | { "cause", GDB_SIZEOF_REG, offsetof(struct pt_regs, cp0_cause) }, | ||
92 | { "pc", GDB_SIZEOF_REG, offsetof(struct pt_regs, cp0_epc) }, | ||
93 | { "f0", GDB_SIZEOF_REG, 0 }, | ||
94 | { "f1", GDB_SIZEOF_REG, 1 }, | ||
95 | { "f2", GDB_SIZEOF_REG, 2 }, | ||
96 | { "f3", GDB_SIZEOF_REG, 3 }, | ||
97 | { "f4", GDB_SIZEOF_REG, 4 }, | ||
98 | { "f5", GDB_SIZEOF_REG, 5 }, | ||
99 | { "f6", GDB_SIZEOF_REG, 6 }, | ||
100 | { "f7", GDB_SIZEOF_REG, 7 }, | ||
101 | { "f8", GDB_SIZEOF_REG, 8 }, | ||
102 | { "f9", GDB_SIZEOF_REG, 9 }, | ||
103 | { "f10", GDB_SIZEOF_REG, 10 }, | ||
104 | { "f11", GDB_SIZEOF_REG, 11 }, | ||
105 | { "f12", GDB_SIZEOF_REG, 12 }, | ||
106 | { "f13", GDB_SIZEOF_REG, 13 }, | ||
107 | { "f14", GDB_SIZEOF_REG, 14 }, | ||
108 | { "f15", GDB_SIZEOF_REG, 15 }, | ||
109 | { "f16", GDB_SIZEOF_REG, 16 }, | ||
110 | { "f17", GDB_SIZEOF_REG, 17 }, | ||
111 | { "f18", GDB_SIZEOF_REG, 18 }, | ||
112 | { "f19", GDB_SIZEOF_REG, 19 }, | ||
113 | { "f20", GDB_SIZEOF_REG, 20 }, | ||
114 | { "f21", GDB_SIZEOF_REG, 21 }, | ||
115 | { "f22", GDB_SIZEOF_REG, 22 }, | ||
116 | { "f23", GDB_SIZEOF_REG, 23 }, | ||
117 | { "f24", GDB_SIZEOF_REG, 24 }, | ||
118 | { "f25", GDB_SIZEOF_REG, 25 }, | ||
119 | { "f26", GDB_SIZEOF_REG, 26 }, | ||
120 | { "f27", GDB_SIZEOF_REG, 27 }, | ||
121 | { "f28", GDB_SIZEOF_REG, 28 }, | ||
122 | { "f29", GDB_SIZEOF_REG, 29 }, | ||
123 | { "f30", GDB_SIZEOF_REG, 30 }, | ||
124 | { "f31", GDB_SIZEOF_REG, 31 }, | ||
125 | { "fsr", GDB_SIZEOF_REG, 0 }, | ||
126 | { "fir", GDB_SIZEOF_REG, 0 }, | ||
127 | }; | ||
128 | |||
129 | int dbg_set_reg(int regno, void *mem, struct pt_regs *regs) | ||
130 | { | ||
131 | int fp_reg; | ||
132 | |||
133 | if (regno < 0 || regno >= DBG_MAX_REG_NUM) | ||
134 | return -EINVAL; | ||
135 | |||
136 | if (dbg_reg_def[regno].offset != -1 && regno < 38) { | ||
137 | memcpy((void *)regs + dbg_reg_def[regno].offset, mem, | ||
138 | dbg_reg_def[regno].size); | ||
139 | } else if (current && dbg_reg_def[regno].offset != -1 && regno < 72) { | ||
140 | /* FP registers 38 -> 69 */ | ||
141 | if (!(regs->cp0_status & ST0_CU1)) | ||
142 | return 0; | ||
143 | if (regno == 70) { | ||
144 | /* Process the fcr31/fsr (register 70) */ | ||
145 | memcpy((void *)¤t->thread.fpu.fcr31, mem, | ||
146 | dbg_reg_def[regno].size); | ||
147 | goto out_save; | ||
148 | } else if (regno == 71) { | ||
149 | /* Ignore the fir (register 71) */ | ||
150 | goto out_save; | ||
151 | } | ||
152 | fp_reg = dbg_reg_def[regno].offset; | ||
153 | memcpy((void *)¤t->thread.fpu.fpr[fp_reg], mem, | ||
154 | dbg_reg_def[regno].size); | ||
155 | out_save: | ||
156 | restore_fp(current); | ||
157 | } | ||
158 | |||
159 | return 0; | ||
160 | } | ||
161 | |||
162 | char *dbg_get_reg(int regno, void *mem, struct pt_regs *regs) | ||
163 | { | ||
164 | int fp_reg; | ||
165 | |||
166 | if (regno >= DBG_MAX_REG_NUM || regno < 0) | ||
167 | return NULL; | ||
168 | |||
169 | if (dbg_reg_def[regno].offset != -1 && regno < 38) { | ||
170 | /* First 38 registers */ | ||
171 | memcpy(mem, (void *)regs + dbg_reg_def[regno].offset, | ||
172 | dbg_reg_def[regno].size); | ||
173 | } else if (current && dbg_reg_def[regno].offset != -1 && regno < 72) { | ||
174 | /* FP registers 38 -> 69 */ | ||
175 | if (!(regs->cp0_status & ST0_CU1)) | ||
176 | goto out; | ||
177 | save_fp(current); | ||
178 | if (regno == 70) { | ||
179 | /* Process the fcr31/fsr (register 70) */ | ||
180 | memcpy(mem, (void *)¤t->thread.fpu.fcr31, | ||
181 | dbg_reg_def[regno].size); | ||
182 | goto out; | ||
183 | } else if (regno == 71) { | ||
184 | /* Ignore the fir (register 71) */ | ||
185 | memset(mem, 0, dbg_reg_def[regno].size); | ||
186 | goto out; | ||
187 | } | ||
188 | fp_reg = dbg_reg_def[regno].offset; | ||
189 | memcpy(mem, (void *)¤t->thread.fpu.fpr[fp_reg], | ||
190 | dbg_reg_def[regno].size); | ||
191 | } | ||
192 | |||
193 | out: | ||
194 | return dbg_reg_def[regno].name; | ||
195 | |||
196 | } | ||
197 | |||
53 | void arch_kgdb_breakpoint(void) | 198 | void arch_kgdb_breakpoint(void) |
54 | { | 199 | { |
55 | __asm__ __volatile__( | 200 | __asm__ __volatile__( |
@@ -84,64 +229,6 @@ static int compute_signal(int tt) | |||
84 | return SIGHUP; /* default for things we don't know about */ | 229 | return SIGHUP; /* default for things we don't know about */ |
85 | } | 230 | } |
86 | 231 | ||
87 | void pt_regs_to_gdb_regs(unsigned long *gdb_regs, struct pt_regs *regs) | ||
88 | { | ||
89 | int reg; | ||
90 | |||
91 | #if (KGDB_GDB_REG_SIZE == 32) | ||
92 | u32 *ptr = (u32 *)gdb_regs; | ||
93 | #else | ||
94 | u64 *ptr = (u64 *)gdb_regs; | ||
95 | #endif | ||
96 | |||
97 | for (reg = 0; reg < 32; reg++) | ||
98 | *(ptr++) = regs->regs[reg]; | ||
99 | |||
100 | *(ptr++) = regs->cp0_status; | ||
101 | *(ptr++) = regs->lo; | ||
102 | *(ptr++) = regs->hi; | ||
103 | *(ptr++) = regs->cp0_badvaddr; | ||
104 | *(ptr++) = regs->cp0_cause; | ||
105 | *(ptr++) = regs->cp0_epc; | ||
106 | |||
107 | /* FP REGS */ | ||
108 | if (!(current && (regs->cp0_status & ST0_CU1))) | ||
109 | return; | ||
110 | |||
111 | save_fp(current); | ||
112 | for (reg = 0; reg < 32; reg++) | ||
113 | *(ptr++) = current->thread.fpu.fpr[reg]; | ||
114 | } | ||
115 | |||
116 | void gdb_regs_to_pt_regs(unsigned long *gdb_regs, struct pt_regs *regs) | ||
117 | { | ||
118 | int reg; | ||
119 | |||
120 | #if (KGDB_GDB_REG_SIZE == 32) | ||
121 | const u32 *ptr = (u32 *)gdb_regs; | ||
122 | #else | ||
123 | const u64 *ptr = (u64 *)gdb_regs; | ||
124 | #endif | ||
125 | |||
126 | for (reg = 0; reg < 32; reg++) | ||
127 | regs->regs[reg] = *(ptr++); | ||
128 | |||
129 | regs->cp0_status = *(ptr++); | ||
130 | regs->lo = *(ptr++); | ||
131 | regs->hi = *(ptr++); | ||
132 | regs->cp0_badvaddr = *(ptr++); | ||
133 | regs->cp0_cause = *(ptr++); | ||
134 | regs->cp0_epc = *(ptr++); | ||
135 | |||
136 | /* FP REGS from current */ | ||
137 | if (!(current && (regs->cp0_status & ST0_CU1))) | ||
138 | return; | ||
139 | |||
140 | for (reg = 0; reg < 32; reg++) | ||
141 | current->thread.fpu.fpr[reg] = *(ptr++); | ||
142 | restore_fp(current); | ||
143 | } | ||
144 | |||
145 | /* | 232 | /* |
146 | * Similar to regs_to_gdb_regs() except that process is sleeping and so | 233 | * Similar to regs_to_gdb_regs() except that process is sleeping and so |
147 | * we may not be able to get all the info. | 234 | * we may not be able to get all the info. |
@@ -242,7 +329,7 @@ static struct notifier_block kgdb_notifier = { | |||
242 | }; | 329 | }; |
243 | 330 | ||
244 | /* | 331 | /* |
245 | * Handle the 's' and 'c' commands | 332 | * Handle the 'c' command |
246 | */ | 333 | */ |
247 | int kgdb_arch_handle_exception(int vector, int signo, int err_code, | 334 | int kgdb_arch_handle_exception(int vector, int signo, int err_code, |
248 | char *remcom_in_buffer, char *remcom_out_buffer, | 335 | char *remcom_in_buffer, char *remcom_out_buffer, |
@@ -250,20 +337,14 @@ int kgdb_arch_handle_exception(int vector, int signo, int err_code, | |||
250 | { | 337 | { |
251 | char *ptr; | 338 | char *ptr; |
252 | unsigned long address; | 339 | unsigned long address; |
253 | int cpu = smp_processor_id(); | ||
254 | 340 | ||
255 | switch (remcom_in_buffer[0]) { | 341 | switch (remcom_in_buffer[0]) { |
256 | case 's': | ||
257 | case 'c': | 342 | case 'c': |
258 | /* handle the optional parameter */ | 343 | /* handle the optional parameter */ |
259 | ptr = &remcom_in_buffer[1]; | 344 | ptr = &remcom_in_buffer[1]; |
260 | if (kgdb_hex2long(&ptr, &address)) | 345 | if (kgdb_hex2long(&ptr, &address)) |
261 | regs->cp0_epc = address; | 346 | regs->cp0_epc = address; |
262 | 347 | ||
263 | atomic_set(&kgdb_cpu_doing_single_step, -1); | ||
264 | if (remcom_in_buffer[0] == 's') | ||
265 | atomic_set(&kgdb_cpu_doing_single_step, cpu); | ||
266 | |||
267 | return 0; | 348 | return 0; |
268 | } | 349 | } |
269 | 350 | ||