首页 > kgdb, kgdb抓虫日记 > 抓虫日记之 kgdb 和 删除硬断点

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

2010年10月22日 发表评论 阅读评论

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还是忍痛接受了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定义的最大操作数。
从这个表象上看,很可能是kgdb没有把要删除的断点给删掉,于是开始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:

[patch 1/2]debug_core: disable hw_breakpoints on all cores in kgdb_cpu_enter()

[patch 2/2]x86,kgdb: remove unnecessary call to kgdb_correct_hw_break()

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-bugs-kgdb-and-remove-hardware-breakpoint/
版权所有 © 转载时必须以链接形式注明作者和原始出处!