软件的可调试性简析

日期:2013-10-15点击次数:8850

 

       编码和调试是程序员日常工作中最主要的两项任务,它们是相辅相成的,编写具有可调试性的代码,对提高调试效率、节省调试时间益处巨大。反过来,调试可以让程序员切身体会程序的实际运行过程,提炼编码和设计过程中的问题,加深对整个系统的理解,提高对代码的控制力。

       如何才能编写出调式性高的代码呢?最根本的方式,就是做到未雨绸缪。深刻的领悟设计模式,将整个程序分成不同的功能模块,每个模块再分解出不同的功能层次,每个层次再分解成细颗粒度的函数体。这样的好处,既可以精炼冗余的代码,又可以提高整体代码的逻辑性、健壮性、封装性、可移植性、可维护性、可调试性。当遇到Bug的时候,通过逐渐缩小范围,便可以更快的定位到更小的颗粒范围、分析问题、解决问题。

       当然,无论理论上还是实际中,世界上没有无Bug的软件,只是多少而已。如何能够更多的减少Bug,更快的发现并解决Bug呢?需要满足以下几种原则:

      •最短距离原则,使错误检测代码距离失败操作的距离最短。这就要求函数内如果有调用失败的代码存在,就需要将这个错误及时的消化掉,如果不能够处理,就需要返回到函数外,外部才能够做出相应的处理,将这个错误的处理路径缩至最短,可以最大限度的避免问题的放大。

      •最小范围原则,即使错误报告或调试信息所能定位到的范围尽可能小。就是说让调试人员能够更加正确的利用到调试信息,这就要求程序员在编码的时候,一定要保证代码返回的各种错误信息的正确性和唯一性。不准确的错误信息比没有错误信息反而会造成更多的困惑。

       •立刻终止原则,当检测到严重的错误时,使程序立刻终止并报告第一现场的信息。当程序遇到严重的错误时,如果不能够及时地停掉程序,将有可能造成更大的问题。这就要求程序员在遇到不法逾越过去的系统级错误的时候,一定要加强这方面的判断,及时的退出程序。

       •可追溯原则,使代码的执行轨迹和数据变化过程可以追溯。所谓可追溯,即调试人员能够非常清晰的了解程序的代码及数据是如何被执行和变化的。通常采用日志或打印输出的形式对整个程序中所关心的执行路径和数据记录下来,以便可以快速的追踪问题的所在。

       •可控制原则,通过简单的方式就可以控制程序的执行轨迹。一个复杂的程序将会有多条、几十条、甚至上万条的执行轨迹,如何能够快速的选择其中一条轨迹进行追踪调试,而且按照这个轨迹即可重现问题的所在对提高解决问题的效率至关重要。

       •可重复原则,使程序的行为可以被简单的重复。就是要求在重复调试某一段代码的时候,能够很方便的进行其他周边任务初始化的工作,而不是需要烦杂的手工准备这些初始化的工作。这样就可以提高局部代码的调试效率。

       •可观察原则,使软件的特征和内部状态可以被方便的观察。这个原则就是标定某个程序是否可以不用其他额外的工具即可以通过程序本身观察到代码的静态或动态的状况。需要越是复杂或稀少的工具才能完成调试,就意味可观察性越差。

       •可辨识原则,可以简单的辨识出每个模块乃至类或函数的版本。这就要求我们为每个模块设置出内部的编译版本号,最好在编写模块的时候也能够给出相应的设置版本或获取版本的函数,可以非常方便的判断出这个模块或类的版本。在对应产出文件的程序中这点尤为重要,通常我们需要采用向前兼容的方式,来消除新版本对旧版本的兼容性问题。

 

    通过对以上各种原则的分析,我们来看一下哪类的程序调试性更好。开发期的程序比产品期程序调试效率要高。

    在开发期我们可以通过各种调试器对源代码进行细微的调试,可以采取假数据、假的分支流程模拟出产品实际的运行状态,可以非常便捷的发现问题的所在。

       而在产品期,软件产品已经成型,程序文件通常是Release版,内部不含有附加调试信息,运行环境也是在客户的机器上,通常不能通过常规的调试器进行源码的调试,这些障碍会大大的降低调试的效率。通常我们会采用打印日志文件的形式,来记录软件出问题前的各种状态。这样我们即可以按照这个状态重现程序流程,识别最终的执行轨迹,找到问题根源,并解决问题。如果日志文件仍不能够解决问题,就需要通过其他的调试器进行反汇编的调试,这要求调试人员的水平也相应提高,会造成更大的成本消耗。

       因此,这就要求我们尽量在开发期进行更加细致的调试与测试,将问题尽量解决在产品发布前。

应用层程序比内核层程序可调试性要高。

       根据CPU对安全的要求,分成4个等级的程序Ring0~Ring3级。如Windows只采用了Ring0和Ring3级。Ring0级为内核层,只有相应的权限及调用相应的Ring0级API,才能进行Ring0级程序的开发,即我们常说的驱动开发。驱动程序有很多的优点,如程序权限高,可以进行系统底层操作,可以开机自启动,不易被用户察觉,用户不易关闭等等特点,大量的被病毒、木马和杀毒软件所采用。但同时也暴露了很多的问题,如稳定性、安全性差,出现问题即造成整个操作系统的瘫痪;开发难度高,调用的都是内核级API,普通的程序员接触不多;可调试性差,以上多个原则表现的都不尽人意,普通的调试器无法调试,通常采用日志、打印信息和双机联调(虚拟机、源码机)的方式进行调试。

       Ring3层为是应用层程序,相应的权限也是比驱动程序的要求低的多,任何的应用层程序均可以通过普通的调试器进行源码调试。

       这样就要求我们在架构设计软件的时候,无必要采用驱动程序的情况下,就尽量不采用驱动程序去完成需求。

当然如果真的要面对以上所说的糟糕状况,也是有相应的方法来解决的。现在让我们看一下,在产品期或内核层可以采用的几款调试器。

       WinDbg:Windows平台著名的调试器,为微软公司开发的调试利器,即可以调试应用层又可以调试内核层程序。即可本地调试,又可以远程调试。可以源码调试,也可以进行反汇编调试。

       DbgView:可以捕获程序中由TRACE(debug版本)和OutputDebugString输出的信息。可以通过各种条件的设定来过滤信息的显示。可以接收应用层又可以接收内核层的输出信息。

       OllyDbg:一个常用的应用层(现也只可以应用层)逆向和破解的利器。可以动态的进行反汇编跟踪程序的执行轨迹,可以通过各种API函数、消息设定各种断点,判断爆破点实现软件的破解、脱壳等等操作。

       IDA:一个高效的静态反汇编工具,高版本可以逆向出高级语言部分源码,可以分析出程序的框架,及代码块间的逻辑,是一个逆向的利器。即可以调试应用层又可以调试内核层程序。



                                                                                                                
软件部   钟生晖

姓名:
性别:
电话:
E-mail
问题:
问题描述: