这是一个很大的话题,我也只能把我所知道的总结出来,也许还有更好的手段,留待以后补充.
首先,我把调试手段分为硬件和软件.
软件手段早为大家所熟知.其中最简单的就是著名的printf().通常这个函数把存在内存中的需要显示的字符传到串口(客户机调试)或者内存(本级调试).再由串口或者显示驱动打印在屏幕上.值得注意的是,如果是打印到内存再显示,必须使用多线程方式,不然本级内存写入速度非常快,而显示速度通常很慢.
更高级一点的方式是利用单步中断.原理是处理器每运行一条指令,就触发一个中断,然后原来的上下文就不动了,中断处理程序接手,这时既可以把各种信息显示出来显示在本机,也可以送到某个串口实现客户机调试.GDB,XGBG,Visual C++,ICE等就是这样的强大的调试工具,可以调试源代码.他们之间的差异是有些可以调试用户态,有些针对内核态代码.
很多时候,我们的代码会调用系统调用,而系统调用是看不到源代码的.但是我们可以通过一个叫做strace命令跟踪系统调用,并了解输入参数.这样,结合printf使用,很多时候我们就不使用GDB等工具而得到程序的运行情况.如果再配合文本分析脚本,那就可以抓取所需要的调试信息.
针对有些通用的协议,如APCI, USB,我们可以找到一些已近做好的分析工具,他们利用strace或者ptrace函数,记录相应协议产生的系统调用序列,并给出有意义的输出.利用这样一些工具我们可以比较容易的分析驱动程序或者操作系统的动作.
硬件手段一般为人所熟知的是JTAG.它的原理是使用一套额外的,处理器控制总线之外的信号,可以独立的控制各个器件或者芯片内模块.由于速度低,结构简单,它非常稳定,哪怕是处理器系统出错,无法访问模块,它也可以提供可靠的手段来控制那个模块.当然,只是简单的控制,而无法做到高速数据传输.这也就是他稳定的原因.通过JTAG,我们可以像单步中断一样控制访问处理器和芯片组,在停掉软件包括中断处理程序的情况下来调试.这里的调试指的是客户机调试,配合强大的软件,我们也可以做到源代码调试.不过JTAG方式有个限制,就是在真正卖出去的芯片上,那些管脚基本是给屏蔽的,就算连上线,芯片内部也会通过熔丝(fuse)等手段使其失效,