使用jprobe构建镜像协议栈的原理与感悟

突然回想起了往事,那是2007年的冬天的一个周五,我在看我的老湿调试Linux协议栈的IP层,只见他修改了路由查找的逻辑,然后直接make install了一下就即时生效了,当时我只知道的是,修改了这个逻辑需要重新编译内核,而他并没有重新编译,好像只是编译了一个文件...编译内核这个耗时又无聊的工作阻碍了我对Linux内核的探索进度,直到今天,我依然对编译内核有相当的恐惧,不怕出错,而是怕磁盘空间不够,initrd的组装拆解之类,太繁琐了。我之所以知道2007年的那天是周五,是因为第二天我要加班,没有谁逼我,我自愿的,因为我想知道师父是怎么做到不重新编译内核就能改变非模块的内核代码处理逻辑的,第二天的收获很多,不但知道了他使用了“镜像协议栈”,还额外赚了一天的加班费,我还记得周六加完班我和老婆去吃了一家叫做石工坊的羊排火锅,人家赠送了一只绿色的兔子玩偶。现在那个玩偶还在,我家小小特别喜欢,就是这么一堆看似无关却又巧合的事,让我在这个周末觉得必须写下一点什么。
       好吧,从kprobe开始吧。如果我面试一个搞Linux内核的人,问他怎么调试内核,他回答先加入printk然后重新编译最后载入新内核运行,看dmesg,我会让他先等上几分钟,然后人事就会告诉他让他回去等通知。幸运的是,我没有碰到这样的人让我面试来展现我五十步笑百步的半瓶子晃荡作风,也从来没有碰到过如此不仁慈的面试者,我曾经在一次找工作的时候真的就是这么说的,人家也真的让我去等通知,然而我真的就等到了通知,通知入职的时间以及体检事宜...说这些的目的是想展示一个调试内核的利器,kprobe。它可以动态修改内核地址空间代码的二进制指令,然后执行任意你想让它执行的代码段,这也许应该可以称为二进制动态编程!多么黑的技术,完全无视源代码的逻辑,完全无视编译器的苦功,直接就这么把二进制机器码给改了。
       kprobe的工作原理很简单,比如你有一个函数func,你可以在func被调用前和调用后各插入一段代码,我们假设func指令是
begin
go
end

kprobe要做的就是替换掉begin,将其变为:
jmp prefunc
当然在替换前还要保存原有的,以便执行完我们的钩子函数prefunc还能跳回原来的逻辑,至于复杂的jmp细节(长短跳,相对绝对跳之类的)以及Intel的INT 3调试模式单步模式本文不再赘述,赘这个字用得好,因为所有这些细节都是累赘,你换个非Intel平台的话,你就知道这些是多么累赘了,不过对一辈子不换平台的那些人来讲,理解这些细节就成了资本,因此想了解这些,还是去看雪吧,找级别高态度好的问,或者潜水也行,我觉得看雪的信息量已经够大了,基本上都能找到现成的。
       虽然我不提倡在本文讲Intel的细节,但是有一个除外,那就是prefunc钩子函数的参数问题,比如我想钩住vfs_write函数,它的声明如下:
[plain]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. ssize_t vfs_write(struct file *file, const char __user *buf, size_t count, loff_t *pos);  
如果这个prefunc钩子函数的参数和vfs_write的一样那多好啊,整个逻辑就成了:
[plain]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. ssize_t prefunc(struct file *file, const char __user *buf, size_t count, loff_t *pos)  
  2. {  
  3.     todo_something(.....);  
  4.     return vfs_write(file, buf, count, pos);  
  5. }  
但是不幸的是,kprobe做不到。因为它是基于INT 3异常/中断来处理的,而Intel的异常/中断的处理有一套特定的规程,即保存所有的上下文环境,因此它的参数就只有struct pt_regs *regs一个,即所有的寄存器信息。要想还原vfs_write的参数,你必须针对这个regs参数做一个“深度解析”才行,而这又一次将你引入了平台相关的地狱,如果你在X86平台,你就不得不对它的寄存器使用规约做一番详细的了解才能还原被钩函数的参数,对于X86来讲,参数保存在栈中(也可以通过寄存器传参),要想还原被钩函数的参数现场,你要分析的就是regs->sp,下面我就不说了。
       说了上述不幸,来点幸运的,那就是Linux内核提供了一种kprobe之上的机制,帮你实现了上面说的那些本应该由你自己完成的工作,这就是jprobe。总的来讲,jprobe的要点在于它实际上就是一个kprobe的prefunc,它的prefunc是这么实现的:
[plain]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. prefunc(kprobe, regs)  
  2. {  
  3.     保存regs寄存器现场  
  4.     保存栈的内容  //因为jprobe使用和被钩函数相同的栈,可能会改变栈的内容  
  5.     替换regs里面ip指针为jprobe钩子的指针  
  6.     返回  
  7. }  
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
JProbe Suite ——提高开发效率,改善JAVA应用性能 * 轻松发现和消除性能瓶颈 * 查找问题代码 * 节省后续硬件及开发投入 * 增加应用发布信心 * 与开发过程集成,改善应用性能 JProbe Suite是一种能节省开发时间、降低开发费用、改善Java应用运行速度及和扩展能力的强大工具套件,在全球各地拥有大量用户。通过JProbe Suite,开发和测试小组可以全面诊断应用性能、内存使用、线程及代码覆盖等问题。无须修改应用,JProbe就能对桌面或远程服务器上的应用进行分析,实现强大的信息展示和Java代码性能诊断功能。利用JProbe先进的数据收集功能,可以实现自动化的性能信息采集,缩短应用开发和优化周期。 JProbe在简单易用的集成化套件中,为servlet、JSP和EJB应用代码提供了强大的Java性能分析、内存纠错、代码覆盖及线程分析功能。 JProbe Profiler JProbe Profiler * JProbe Profiler JProbe Profiler内置了Call Graph调用关系图和高级数据采集机制,可实现方法和代码行级的高精度性能诊断。 主要功能: 方法和行级分析:确定方法的热点,并以逐行方式挖掘分析性能状态。 计算运行时间或CPU时间占用:跟踪用户体验或计算瓶颈; 9种指标:多角度确定问题根源; 高级过滤和触发器:确定要诊断分析的关键代码区域; 快照对比技术:预测代码修改对性能的影响; 高级打印和输出功能:支持PDF、文本、HTML或Excel兼容的CSV格式。 JProbe Memory Debugger JProbe Memory Debugger可帮助开发人员快速查找Java代码的内存泄露和对象循环。内置的图形化实时内存使用和对象视图,有助于开发人员理解应用的内存使用,设法减少内存消耗以提高应用性能。 主要功能: 识别内存泄漏:通过易用的两步分析,跟踪运行时的内存增长; Memory Instance Calculator:计算内存泄露量; 智能化内存分析:通过Leak Doctor发现可能的内存泄露源; Aggregate Memory Footprint:理解对象创建的实际开销; Reference Graph 和 Instance Detail:跟踪内存使用和对象引用; 垃圾回收分析:检测过多的短期对象和垃圾收集详情; Snapshot 比对:确定代码改变对内存使用的影响。 JProbe Coverage *JProbe Coverage 帮助开发人员查找未执行代码,精确计算已执行代码,简化对测试工作可靠性和精确度的评估。 主要功能: Coverage Browser 和 Source Views:迅速确定未测试代码或死代码; Conditional Coverage Analysis: 分析特定条件所覆盖的代码范围,包括含有多个条件语句的代码行; Filter Catch Blocks: 更精确的覆盖范围报告; 批处理模式: 可通过批处理方式运行,简化与夜间编译/测试系统的整合; 报表功能: 以XML、纯文本、CSV或者HTML格式输出覆盖范围报告,以实现个性化的分析; Snapshot合并: 对多次运行中的覆盖范围数据进行合并; 可与下列应用服务器整合 o BEA WebLogic Server o IBM WebSphere Application Server o Sun Java System Application Server o Apache Tomcat o Oracle9i Application Server o JBoss o Macromedia JRun ........ 可与下列开发环境整合 o IBM WebSphere Studio Application Developer (WSAD) o Eclipse o Borland JBuilder o IntelliJ IDEA o Sun Java Studio o JBoss o Oracle Jdeveloper

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值