diff options
author | Jason Wessel <jason.wessel@windriver.com> | 2012-03-21 11:17:03 -0400 |
---|---|---|
committer | Jason Wessel <jason.wessel@windriver.com> | 2012-03-29 18:41:25 -0400 |
commit | 98b54aa1a2241b59372468bd1e9c2d207bdba54b (patch) | |
tree | 0a6cc3bc8426434a176e0fcb3c2da23d383a5a3b /kernel/debug | |
parent | 23bbd8e346f1ef3fc1219c79cea53d8d52b207d8 (diff) |
kgdb,debug_core: pass the breakpoint struct instead of address and memory
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.
Cc: stable@vger.kernel.org # >= 2.6.36
Signed-off-by: Jason Wessel <jason.wessel@windriver.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 3f88a45e6f0a..a7e52ca94563 100644 --- a/kernel/debug/debug_core.c +++ b/kernel/debug/debug_core.c | |||
@@ -161,37 +161,39 @@ early_param("nokgdbroundup", opt_nokgdbroundup); | |||
161 | * Weak aliases for breakpoint management, | 161 | * Weak aliases for breakpoint management, |
162 | * can be overriden by architectures when needed: | 162 | * can be overriden by architectures when needed: |
163 | */ | 163 | */ |
164 | int __weak kgdb_arch_set_breakpoint(unsigned long addr, char *saved_instr) | 164 | int __weak kgdb_arch_set_breakpoint(struct kgdb_bkpt *bpt) |
165 | { | 165 | { |
166 | int err; | 166 | int err; |
167 | 167 | ||
168 | err = probe_kernel_read(saved_instr, (char *)addr, BREAK_INSTR_SIZE); | 168 | err = probe_kernel_read(bpt->saved_instr, (char *)bpt->bpt_addr, |
169 | BREAK_INSTR_SIZE); | ||
169 | if (err) | 170 | if (err) |
170 | return err; | 171 | return err; |
171 | 172 | err = probe_kernel_write((char *)bpt->bpt_addr, | |
172 | return probe_kernel_write((char *)addr, arch_kgdb_ops.gdb_bpt_instr, | 173 | arch_kgdb_ops.gdb_bpt_instr, BREAK_INSTR_SIZE); |
173 | BREAK_INSTR_SIZE); | 174 | return err; |
174 | } | 175 | } |
175 | 176 | ||
176 | int __weak kgdb_arch_remove_breakpoint(unsigned long addr, char *bundle) | 177 | int __weak kgdb_arch_remove_breakpoint(struct kgdb_bkpt *bpt) |
177 | { | 178 | { |
178 | return probe_kernel_write((char *)addr, | 179 | return probe_kernel_write((char *)bpt->bpt_addr, |
179 | (char *)bundle, BREAK_INSTR_SIZE); | 180 | (char *)bpt->saved_instr, BREAK_INSTR_SIZE); |
180 | } | 181 | } |
181 | 182 | ||
182 | int __weak kgdb_validate_break_address(unsigned long addr) | 183 | int __weak kgdb_validate_break_address(unsigned long addr) |
183 | { | 184 | { |
184 | char tmp_variable[BREAK_INSTR_SIZE]; | 185 | struct kgdb_bkpt tmp; |
185 | int err; | 186 | int err; |
186 | /* Validate setting the breakpoint and then removing it. In the | 187 | /* Validate setting the breakpoint and then removing it. If the |
187 | * remove fails, the kernel needs to emit a bad message because we | 188 | * remove fails, the kernel needs to emit a bad message because we |
188 | * are deep trouble not being able to put things back the way we | 189 | * are deep trouble not being able to put things back the way we |
189 | * found them. | 190 | * found them. |
190 | */ | 191 | */ |
191 | err = kgdb_arch_set_breakpoint(addr, tmp_variable); | 192 | tmp.bpt_addr = addr; |
193 | err = kgdb_arch_set_breakpoint(&tmp); | ||
192 | if (err) | 194 | if (err) |
193 | return err; | 195 | return err; |
194 | err = kgdb_arch_remove_breakpoint(addr, tmp_variable); | 196 | err = kgdb_arch_remove_breakpoint(&tmp); |
195 | if (err) | 197 | if (err) |
196 | printk(KERN_ERR "KGDB: Critical breakpoint error, kernel " | 198 | printk(KERN_ERR "KGDB: Critical breakpoint error, kernel " |
197 | "memory destroyed at: %lx", addr); | 199 | "memory destroyed at: %lx", addr); |
@@ -235,7 +237,6 @@ static void kgdb_flush_swbreak_addr(unsigned long addr) | |||
235 | */ | 237 | */ |
236 | int dbg_activate_sw_breakpoints(void) | 238 | int dbg_activate_sw_breakpoints(void) |
237 | { | 239 | { |
238 | unsigned long addr; | ||
239 | int error; | 240 | int error; |
240 | int ret = 0; | 241 | int ret = 0; |
241 | int i; | 242 | int i; |
@@ -244,16 +245,15 @@ int dbg_activate_sw_breakpoints(void) | |||
244 | if (kgdb_break[i].state != BP_SET) | 245 | if (kgdb_break[i].state != BP_SET) |
245 | continue; | 246 | continue; |
246 | 247 | ||
247 | addr = kgdb_break[i].bpt_addr; | 248 | error = kgdb_arch_set_breakpoint(&kgdb_break[i]); |
248 | error = kgdb_arch_set_breakpoint(addr, | ||
249 | kgdb_break[i].saved_instr); | ||
250 | if (error) { | 249 | if (error) { |
251 | ret = error; | 250 | ret = error; |
252 | printk(KERN_INFO "KGDB: BP install failed: %lx", addr); | 251 | printk(KERN_INFO "KGDB: BP install failed: %lx", |
252 | kgdb_break[i].bpt_addr); | ||
253 | continue; | 253 | continue; |
254 | } | 254 | } |
255 | 255 | ||
256 | kgdb_flush_swbreak_addr(addr); | 256 | kgdb_flush_swbreak_addr(kgdb_break[i].bpt_addr); |
257 | kgdb_break[i].state = BP_ACTIVE; | 257 | kgdb_break[i].state = BP_ACTIVE; |
258 | } | 258 | } |
259 | return ret; | 259 | return ret; |
@@ -302,7 +302,6 @@ int dbg_set_sw_break(unsigned long addr) | |||
302 | 302 | ||
303 | int dbg_deactivate_sw_breakpoints(void) | 303 | int dbg_deactivate_sw_breakpoints(void) |
304 | { | 304 | { |
305 | unsigned long addr; | ||
306 | int error; | 305 | int error; |
307 | int ret = 0; | 306 | int ret = 0; |
308 | int i; | 307 | int i; |
@@ -310,15 +309,14 @@ int dbg_deactivate_sw_breakpoints(void) | |||
310 | for (i = 0; i < KGDB_MAX_BREAKPOINTS; i++) { | 309 | for (i = 0; i < KGDB_MAX_BREAKPOINTS; i++) { |
311 | if (kgdb_break[i].state != BP_ACTIVE) | 310 | if (kgdb_break[i].state != BP_ACTIVE) |
312 | continue; | 311 | continue; |
313 | addr = kgdb_break[i].bpt_addr; | 312 | error = kgdb_arch_remove_breakpoint(&kgdb_break[i]); |
314 | error = kgdb_arch_remove_breakpoint(addr, | ||
315 | kgdb_break[i].saved_instr); | ||
316 | if (error) { | 313 | if (error) { |
317 | printk(KERN_INFO "KGDB: BP remove failed: %lx\n", addr); | 314 | printk(KERN_INFO "KGDB: BP remove failed: %lx\n", |
315 | kgdb_break[i].bpt_addr); | ||
318 | ret = error; | 316 | ret = error; |
319 | } | 317 | } |
320 | 318 | ||
321 | kgdb_flush_swbreak_addr(addr); | 319 | kgdb_flush_swbreak_addr(kgdb_break[i].bpt_addr); |
322 | kgdb_break[i].state = BP_SET; | 320 | kgdb_break[i].state = BP_SET; |
323 | } | 321 | } |
324 | return ret; | 322 | return ret; |
@@ -352,7 +350,6 @@ int kgdb_isremovedbreak(unsigned long addr) | |||
352 | 350 | ||
353 | int dbg_remove_all_break(void) | 351 | int dbg_remove_all_break(void) |
354 | { | 352 | { |
355 | unsigned long addr; | ||
356 | int error; | 353 | int error; |
357 | int i; | 354 | int i; |
358 | 355 | ||
@@ -360,12 +357,10 @@ int dbg_remove_all_break(void) | |||
360 | for (i = 0; i < KGDB_MAX_BREAKPOINTS; i++) { | 357 | for (i = 0; i < KGDB_MAX_BREAKPOINTS; i++) { |
361 | if (kgdb_break[i].state != BP_ACTIVE) | 358 | if (kgdb_break[i].state != BP_ACTIVE) |
362 | goto setundefined; | 359 | goto setundefined; |
363 | addr = kgdb_break[i].bpt_addr; | 360 | error = kgdb_arch_remove_breakpoint(&kgdb_break[i]); |
364 | error = kgdb_arch_remove_breakpoint(addr, | ||
365 | kgdb_break[i].saved_instr); | ||
366 | if (error) | 361 | if (error) |
367 | printk(KERN_ERR "KGDB: breakpoint remove failed: %lx\n", | 362 | printk(KERN_ERR "KGDB: breakpoint remove failed: %lx\n", |
368 | addr); | 363 | kgdb_break[i].bpt_addr); |
369 | setundefined: | 364 | setundefined: |
370 | kgdb_break[i].state = BP_UNDEFINED; | 365 | kgdb_break[i].state = BP_UNDEFINED; |
371 | } | 366 | } |