diff options
| author | Jason Wessel <jason.wessel@windriver.com> | 2012-03-21 11:17:03 -0400 |
|---|---|---|
| committer | Luis Henriques <luis.henriques@canonical.com> | 2012-05-01 05:59:58 -0400 |
| commit | 2409d45dcdfca6cc71baca76c0c26f53f0eddc51 (patch) | |
| tree | 64694c48c8b40359fa3b2d2f05de7676a2bf7a82 /kernel/debug | |
| parent | 392c5be4c753bd06f7bfc9bd169248edba3443fe (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.c | 53 |
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 | */ |
| 160 | int __weak kgdb_arch_set_breakpoint(unsigned long addr, char *saved_instr) | 160 | int __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 | ||
| 172 | int __weak kgdb_arch_remove_breakpoint(unsigned long addr, char *bundle) | 173 | int __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 | ||
| 178 | int __weak kgdb_validate_break_address(unsigned long addr) | 179 | int __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 | */ |
| 232 | int dbg_activate_sw_breakpoints(void) | 234 | int 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 | ||
| 299 | int dbg_deactivate_sw_breakpoints(void) | 299 | int 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 | ||
| 349 | int dbg_remove_all_break(void) | 347 | int 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); |
| 365 | setundefined: | 360 | setundefined: |
| 366 | kgdb_break[i].state = BP_UNDEFINED; | 361 | kgdb_break[i].state = BP_UNDEFINED; |
| 367 | } | 362 | } |
