aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/debug
diff options
context:
space:
mode:
authorJason Wessel <jason.wessel@windriver.com>2012-03-21 11:17:03 -0400
committerLuis Henriques <luis.henriques@canonical.com>2012-05-01 05:59:58 -0400
commit2409d45dcdfca6cc71baca76c0c26f53f0eddc51 (patch)
tree64694c48c8b40359fa3b2d2f05de7676a2bf7a82 /kernel/debug
parent392c5be4c753bd06f7bfc9bd169248edba3443fe (diff)
kgdb,debug_core: pass the breakpoint struct instead of address and memory
BugLink: http://bugs.launchpad.net/bugs/983326 commit 98b54aa1a2241b59372468bd1e9c2d207bdba54b upstream. There is extra state information that needs to be exposed in the kgdb_bpt structure for tracking how a breakpoint was installed. The debug_core only uses the the probe_kernel_write() to install breakpoints, but this is not enough for all the archs. Some arch such as x86 need to use text_poke() in order to install a breakpoint into a read only page. Passing the kgdb_bpt structure to kgdb_arch_set_breakpoint() and kgdb_arch_remove_breakpoint() allows other archs to set the type variable which indicates how the breakpoint was installed. Signed-off-by: Jason Wessel <jason.wessel@windriver.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> Signed-off-by: Tim Gardner <tim.gardner@canonical.com>
Diffstat (limited to 'kernel/debug')
-rw-r--r--kernel/debug/debug_core.c53
1 files changed, 24 insertions, 29 deletions
diff --git a/kernel/debug/debug_core.c b/kernel/debug/debug_core.c
index bad6786dee8..5ee24d10632 100644
--- a/kernel/debug/debug_core.c
+++ b/kernel/debug/debug_core.c
@@ -157,37 +157,39 @@ early_param("nokgdbroundup", opt_nokgdbroundup);
157 * Weak aliases for breakpoint management, 157 * Weak aliases for breakpoint management,
158 * can be overriden by architectures when needed: 158 * can be overriden by architectures when needed:
159 */ 159 */
160int __weak kgdb_arch_set_breakpoint(unsigned long addr, char *saved_instr) 160int __weak kgdb_arch_set_breakpoint(struct kgdb_bkpt *bpt)
161{ 161{
162 int err; 162 int err;
163 163
164 err = probe_kernel_read(saved_instr, (char *)addr, BREAK_INSTR_SIZE); 164 err = probe_kernel_read(bpt->saved_instr, (char *)bpt->bpt_addr,
165 BREAK_INSTR_SIZE);
165 if (err) 166 if (err)
166 return err; 167 return err;
167 168 err = probe_kernel_write((char *)bpt->bpt_addr,
168 return probe_kernel_write((char *)addr, arch_kgdb_ops.gdb_bpt_instr, 169 arch_kgdb_ops.gdb_bpt_instr, BREAK_INSTR_SIZE);
169 BREAK_INSTR_SIZE); 170 return err;
170} 171}
171 172
172int __weak kgdb_arch_remove_breakpoint(unsigned long addr, char *bundle) 173int __weak kgdb_arch_remove_breakpoint(struct kgdb_bkpt *bpt)
173{ 174{
174 return probe_kernel_write((char *)addr, 175 return probe_kernel_write((char *)bpt->bpt_addr,
175 (char *)bundle, BREAK_INSTR_SIZE); 176 (char *)bpt->saved_instr, BREAK_INSTR_SIZE);
176} 177}
177 178
178int __weak kgdb_validate_break_address(unsigned long addr) 179int __weak kgdb_validate_break_address(unsigned long addr)
179{ 180{
180 char tmp_variable[BREAK_INSTR_SIZE]; 181 struct kgdb_bkpt tmp;
181 int err; 182 int err;
182 /* Validate setting the breakpoint and then removing it. In the 183 /* Validate setting the breakpoint and then removing it. If the
183 * remove fails, the kernel needs to emit a bad message because we 184 * remove fails, the kernel needs to emit a bad message because we
184 * are deep trouble not being able to put things back the way we 185 * are deep trouble not being able to put things back the way we
185 * found them. 186 * found them.
186 */ 187 */
187 err = kgdb_arch_set_breakpoint(addr, tmp_variable); 188 tmp.bpt_addr = addr;
189 err = kgdb_arch_set_breakpoint(&tmp);
188 if (err) 190 if (err)
189 return err; 191 return err;
190 err = kgdb_arch_remove_breakpoint(addr, tmp_variable); 192 err = kgdb_arch_remove_breakpoint(&tmp);
191 if (err) 193 if (err)
192 printk(KERN_ERR "KGDB: Critical breakpoint error, kernel " 194 printk(KERN_ERR "KGDB: Critical breakpoint error, kernel "
193 "memory destroyed at: %lx", addr); 195 "memory destroyed at: %lx", addr);
@@ -231,7 +233,6 @@ static void kgdb_flush_swbreak_addr(unsigned long addr)
231 */ 233 */
232int dbg_activate_sw_breakpoints(void) 234int dbg_activate_sw_breakpoints(void)
233{ 235{
234 unsigned long addr;
235 int error; 236 int error;
236 int ret = 0; 237 int ret = 0;
237 int i; 238 int i;
@@ -240,16 +241,15 @@ int dbg_activate_sw_breakpoints(void)
240 if (kgdb_break[i].state != BP_SET) 241 if (kgdb_break[i].state != BP_SET)
241 continue; 242 continue;
242 243
243 addr = kgdb_break[i].bpt_addr; 244 error = kgdb_arch_set_breakpoint(&kgdb_break[i]);
244 error = kgdb_arch_set_breakpoint(addr,
245 kgdb_break[i].saved_instr);
246 if (error) { 245 if (error) {
247 ret = error; 246 ret = error;
248 printk(KERN_INFO "KGDB: BP install failed: %lx", addr); 247 printk(KERN_INFO "KGDB: BP install failed: %lx",
248 kgdb_break[i].bpt_addr);
249 continue; 249 continue;
250 } 250 }
251 251
252 kgdb_flush_swbreak_addr(addr); 252 kgdb_flush_swbreak_addr(kgdb_break[i].bpt_addr);
253 kgdb_break[i].state = BP_ACTIVE; 253 kgdb_break[i].state = BP_ACTIVE;
254 } 254 }
255 return ret; 255 return ret;
@@ -298,7 +298,6 @@ int dbg_set_sw_break(unsigned long addr)
298 298
299int dbg_deactivate_sw_breakpoints(void) 299int dbg_deactivate_sw_breakpoints(void)
300{ 300{
301 unsigned long addr;
302 int error; 301 int error;
303 int ret = 0; 302 int ret = 0;
304 int i; 303 int i;
@@ -306,15 +305,14 @@ int dbg_deactivate_sw_breakpoints(void)
306 for (i = 0; i < KGDB_MAX_BREAKPOINTS; i++) { 305 for (i = 0; i < KGDB_MAX_BREAKPOINTS; i++) {
307 if (kgdb_break[i].state != BP_ACTIVE) 306 if (kgdb_break[i].state != BP_ACTIVE)
308 continue; 307 continue;
309 addr = kgdb_break[i].bpt_addr; 308 error = kgdb_arch_remove_breakpoint(&kgdb_break[i]);
310 error = kgdb_arch_remove_breakpoint(addr,
311 kgdb_break[i].saved_instr);
312 if (error) { 309 if (error) {
313 printk(KERN_INFO "KGDB: BP remove failed: %lx\n", addr); 310 printk(KERN_INFO "KGDB: BP remove failed: %lx\n",
311 kgdb_break[i].bpt_addr);
314 ret = error; 312 ret = error;
315 } 313 }
316 314
317 kgdb_flush_swbreak_addr(addr); 315 kgdb_flush_swbreak_addr(kgdb_break[i].bpt_addr);
318 kgdb_break[i].state = BP_SET; 316 kgdb_break[i].state = BP_SET;
319 } 317 }
320 return ret; 318 return ret;
@@ -348,7 +346,6 @@ int kgdb_isremovedbreak(unsigned long addr)
348 346
349int dbg_remove_all_break(void) 347int dbg_remove_all_break(void)
350{ 348{
351 unsigned long addr;
352 int error; 349 int error;
353 int i; 350 int i;
354 351
@@ -356,12 +353,10 @@ int dbg_remove_all_break(void)
356 for (i = 0; i < KGDB_MAX_BREAKPOINTS; i++) { 353 for (i = 0; i < KGDB_MAX_BREAKPOINTS; i++) {
357 if (kgdb_break[i].state != BP_ACTIVE) 354 if (kgdb_break[i].state != BP_ACTIVE)
358 goto setundefined; 355 goto setundefined;
359 addr = kgdb_break[i].bpt_addr; 356 error = kgdb_arch_remove_breakpoint(&kgdb_break[i]);
360 error = kgdb_arch_remove_breakpoint(addr,
361 kgdb_break[i].saved_instr);
362 if (error) 357 if (error)
363 printk(KERN_ERR "KGDB: breakpoint remove failed: %lx\n", 358 printk(KERN_ERR "KGDB: breakpoint remove failed: %lx\n",
364 addr); 359 kgdb_break[i].bpt_addr);
365setundefined: 360setundefined:
366 kgdb_break[i].state = BP_UNDEFINED; 361 kgdb_break[i].state = BP_UNDEFINED;
367 } 362 }