抓虫日记之 kgdb 和 删除硬断点

DDD  2010年10月22日 星期五 16:05 | 2609次浏览 | 0条评论

为避免硬/软断点影响kgdb,在kgdb主程序kgdb_cpu_enter运行过程中,所有的断点是被disable的。
对于硬件断点来说,它会显示的调用kgdb_disable_hw_debug()来disable所有的硬件断点
在kgdb离开时,调用kgdb_correct_hw_break()来使能/增加需要激活的硬件断点。

A: 前言

自从Prasad Krishnan兄(也许该叫大叔)引入Hardware Breakpoint统一管理机制后,
结束了各个内核模块中对Hardware Breakpoint处理各自为政的状态,一统Hardware
Breakpoint的天下.

KGDB也无例外,为了对别人负责,也需要迁移到Hardware Breakpoint Layer, 其实
kgdb对使用Hardware Breakpoint Layer是很不爽的。为避免大家心里暗怨我瞎说,
特举例如下:

 1: 使用Hardware Breakpoint Layer,增加了kgdb对系统的依赖性,这潜在的影响
 
kgdb的稳定性。
 
2: 当kgdb用于早期调试时(如系统初始化阶段),Hardware Breakpoint Layer有
可能还没有初始化,那时候还是得kgdb自己来管理硬件断点。从这个角度来说kgdb支持
Hardware Breakpoint Layer确实比较鸡肋。
 
3: Hardware Breakpoint Layer依赖notifier_chain来实现的,有时候kgdb会避免
使用notifier_chain的(这样就可以单步调试notifier的相关代码),一旦使用了Hardware
Breakpoint Layer,就不能调试notifier的相关代码时,应该kgdb依赖它,kgdb是不能自己
调自己的。

迫于像大家看齐的压力,kgdb还是忍痛接受了Hardware Breakpoint Layer,反正
Hardware Breakpoint Layer还是有一个好处的,就是not evil,不会破坏别人的硬件断点设置,
这样别人不会来抱怨你冲掉他们的硬断点设置。

为了让kgdb这个怪物支持Hardware Breakpoint Layer,Hardware Breakpoint Layer
还是给予了一定的协助的,如提供一些无锁操作函数等等.如为原来有锁的release_bp_slot提供
一个无锁的dbg_release_bp_slot.
kgdb由于使用了NMI这个强大的DD,如果调用一些持锁的函数,基本有概率会”无理由”的把你
给锁住,哭都不知道找谁去。同样,在Jason大牛的一番艰苦奋战下,kgdb基本把Hardware
Breakpoint Layer给摆平了.

B: 问题和现象

但在某天某时某分(秒就算了),我发现在对硬断点增/减多次操作后,在操作就再也不成功了。
经过多次重启机器的麻木实验后,发现规律如下:
前四次是肯定可以成功,而后面的操作是肯定不可以成功。

而四正好是X86的硬件断点最大数,也就是Hardware Breakpoint Layer定义的最大操作数。
从这个表象上看,很可能是删除断点的时候没有删掉,于是开始dig kgdb硬断点相关代码.

kgdb增加硬断点简要流程:

 gdb
 
  -->
 
 发送
 
  "Z1+breakaddress"
 
 
  -->
 
 kgdb
 
 
kgdb -->
kernel / debug / gdbstub. c :
gdb_serial_stub ( ) -->
gdb_cmd_break ( ) -->
arch_kgdb_ops. set_hw_breakpoint ( ) -->
arch / x86 / kernel / kgdb. c
kgdb_set_hw_break ( ) -->
hw_break_reserve_slot ( ) -->
dbg_reserve_bp_slot ( ) -> 在所有CPU上注册硬断点 ( Hardware Breakpoint Layer API )

想了解为什么发送”Z1+breakaddress” 给kgdb就是增加硬断点的朋友,看参考附录里的gdb远程协议。

kgdb删除硬断点流程

 gdb
 
  -->
 
 发送
 
  "z1+breakaddress"
 
 
  -->
 
 kgdb
 
kgdb -->
kernel / debug / gdbstub. c :
gdb_serial_stub ( ) -->
gdb_cmd_break ( ) -->
arch_kgdb_ops. remove_hw_breakpoint ( ) -->
arch / x86 / kernel / kgdb. c
kgdb_remove_hw_break ( ) -->
hw_break_release_slot ( ) -->
dbg_release_bp_slot ( ) --> 在所有CPU上删除硬断点 ( Hardware Breakpoint Layer API )

C: 问题原因

从前面分析的原因来看,好像没问题啊,该加的加了,该删的删了,问题出在哪呢?

为避免硬/软断点影响kgdb,在kgdb主程序kgdb_cpu_enter运行过程中,所有的断点是被disable的。
对于硬件断点来说,它会显示的调用kgdb_disable_hw_debug()来disable所有的硬件断点,
在kgdb离开时,调用kgdb_correct_hw_break()来使能/增加需要激活的硬件断点。

来看看

kgdb_disable_hw_debug()的实现:

 arch
 
  /
 
 x86
 
  /
 
 kernel
 
  /
 
 kgdb.
 
  c
 
 
  :
 
 
kgdb_disable_hw_debug ( ) -->
arch_uninstall_hw_breakpoint ( ) -->
删除当前CPU上硬断点 ( Hardware Breakpoint Layer API )

从上面看出,kgdb_disable_hw_debug()只是删除当前cpu上的硬件断点,如果要达到
全部删除的效果,应该每个CPU都得调用一次,而当前的调用路径,只要master debug的CPU
才会调用,其它的CPU都不会运行.

D: BUG解决方法

解决方法很简单,就是所有的cpu都运行kgdb_disable_hw_debug(),解决方法见如下patch:

 debug_core: disable all hw_breakpoints after cpu enter kgdb
 
 
There is a issue that the disabled hw_breakpoint didn't
be uninstalled on slave_debug_cpu.
 
This patch fix that issue, it invokes kgdb_disable_hw_debug() to
uninstall all pre-enabled hw_breakpoints after master/slave_debug_cpus
enter kgdb. thus the disabled the hw_breakpoints have been disabled
by kgdb_disable_hw_debug().
 
The hw_breakpoint dis/enable operate flow should be:
 
master_debug_cpu slave_debug_cpu
\ /
kgdb_cpu_enter
|
kgdb_disable_hw_debug --> uninstall pre-enabled hw_breakpoint
|
do add/rm dis/enable operates to hw_breakpoints on master_debug_cpu..
|
correct_hw_break --> install the enabled hw_breakpoint
|
leave_kgdb
 
Signed-off-by: Dongdong Deng <dongdong.deng@windriver.com>
---
kernel/debug/debug_core.c | 6 ++++--
1 files changed, 4 insertions(+), 2 deletions(-)
 
diff --git a/kernel/debug/debug_core.c b/kernel/debug/debug_core.c
index ebefd47..4d58a66 100644
--- a/kernel/debug/debug_core.c
+++ b/kernel/debug/debug_core.c
@@ -497,6 +497,8 @@ acquirelock:
*/
atomic_inc(&cpu_in_kgdb[cpu]);
 
+ kgdb_disable_hw_debug(ks->linux_regs);
+
if (exception_level == 1)
goto cpu_master_loop;
 
@@ -570,8 +572,6 @@ return_normal:
if (dbg_io_ops->pre_exception)
dbg_io_ops->pre_exception();
 
- kgdb_disable_hw_debug(ks->linux_regs);
-
/*
* Get the passive CPU lock which will hold all the non-primary
* CPU in a spin state while the debugger is active
@@ -662,6 +662,8 @@ kgdb_restore:
else
kgdb_sstep_pid = 0;
}
+ if (arch_kgdb_ops.correct_hw_break)
+ arch_kgdb_ops.correct_hw_break();
if (trace_on)
tracing_on();
/* Free kgdb_active */
--
1.6.0.4

E: Others

1:如果对Hardware Breakpoint Layer感兴趣,可以看看Prasad Krishnan兄的论文:
Hardware Breakpoint (or watchpoint) usage in Linux Kernel

2: gdb远程协议,记录gdb与kgdb的通信规范:
gdb Remote Serial Protocol

本文转载地址:
http://www.kgdb.info/kgdb/kgdb-bugs-kgdb-and-remove-hardware-breakpoint/


 


	  

评论

我的评论:

发表评论

请 登录 后发表评论。还没有在Zeuux哲思注册吗?现在 注册 !

暂时没有评论

Zeuux © 2024

京ICP备05028076号