能够挽救这一切的正是软件调试技术,它通过重现软件缺陷问题,定位和查找问题根源,最终解决问题。
抓住那只虫子!
软件调试的英文原词是software debug,调试的单词是“debug”,它是在bug一词前面加上词头“de”,意为分离或去除bug。

bug的本意是“昆虫”,但在20世纪40年代左右,据说是因为业内流传的一个故事,人们在那之后开始广泛地用这个单词来指代计算机程序中的错误。
彼时的电子计算机体积庞大,数量稀少,大都应用在军事领域,在1947年,由美国海军出资生产的Mark II制造完成。这年的9月9日,当人们测试计算机时,它突然发生了故障。
在几个小时检查后,工作人员发现一只飞蛾死在面板F的第70号继电器中。在取出这只飞蛾后,计算机便恢复了正常。当时为Mark II计算机工作的著名女科学家Grace Hopper将这只飞蛾粘贴到了当天的工作手册中,并在上面加了一行注释——“First actual case of bug being found”。
在那之后,人们就在bug前加上了“de”来表示去除bug的行为,由此,软件调试的概念在业内出现。
实际上,用debug来表示软件调试的过程并不够准确,因为软件调试实际上包含了寻找bug和去除bug两个过程,但由于那个年代计算机刚诞生不久,只有科学家级别的人才会编程,程序也远远没有现在这么复杂多变,大都是开发人员一人承担分析需求、设计、开发、测试等所有工作,寻找bug远没有今天如此困难,所以,debug的名称也被沿用至今。
代码的镜子
随着计算机技术的发展,技术人员逐渐发现软件调试的重要性在不断提升。
首先,调试是找到软件问题的最有效的办法,没有任何一个程序员能够写出完美的代码,借助软件调试的标准流程和方法,debug过程的效率被大幅提升,软件研发后投入使用的间隔期被缩短,而且,随着软件更加庞大复杂,软件调试自然就在其中扮演着越来越重要的角色了。
其次,调试也能够帮助程序员提升编写代码的能力,软件调试相当于一面镜子,帮助程序员来检查程序的执行过程,是否如自己预想实现的一样,从而意识到编程中存在的不足和瑕疵,加深对软件的系统的理解,提高对代码的感知力和控制力。
虽然对于软件研发好处多多,但是真正进行软件调试的工作,却并不容易,也并不轻松。
这一方面是因为软件调试的难度很大,著名的计算机科学家布莱恩·柯林汉(Brian Kernighan)就曾说过,“软件调试要比编写代码困难一倍,如果你发挥了最大的才智编写代码,那么你的智商便不足以调试它。”
另一方面是任务量很多。软件调试几乎存在于软件生命周期的每个阶段。而且,软件调试所花费的人力和时间往往相当可观。据不完全统计,一半以上的软件工程师把一半以上的时间用在软件调试上。很多时候,调试一个软件问题可能就需要几天乃至几周的时间。
所以,从这个角度来看,提高软件工程师的调试效率对于提高软件团队的工作效率有着重要意义。
常见的“捉虫“技术
身为一名软件从业者,如何学好软件调试,如何提升软件调试的效率?
软件调试的基本过程是:
▪ 重现故障。在调试系统上重复导致的故障。
▪ 定位根源。利用各种调试工具,寻找导致软件故障的根源。
▪ 探索和实现解决方案。根据寻找到的故障根源,设计解决方案。
这其中,第二步定位根源是软件调试的最核心步骤,也是调试过程的灵魂,如果能够高效快速的完成第二步,就能够学好软件调试,大大提升debug的效率。
为此,从业者需要掌握几种常用调试技术:
1.断点
断点是调试器调试时最常用的技术之一。它的基本原理是在某一位置设置一个中断点,当cpu执行到这个位置时,便停止被调试的程序。中断到调试器中,让调试者分析和调试。
2.单步执行
单步执行:应用程序按照某个步长,一步一步执行。根据步长大小可以分为:每次执行一条汇编指令、每次执行源代码一条语句和每次执行一个程序分支和每次执行一个任务(线程)。
3.打印输出调试信息
这是一种很普遍的软件调试方式。其基本思想是在程序中编写专门用于打印调试信息的语句,将程序运行的位置、状态和变量值打印出来。在Windows中,驱动程序可以通过Dbgprint/DbgPrintEx来打印调试信息。应用程序可以通过OutputDebugString来打印调试信息。控制台程序可以通过print打印。
4.日志
与输出调试信息类似,日志是另一种辅助调试手段。其基本思想是在程序中加入特定代码将程序运行的状态信息写到日志文件或数据库中。
5.事件追踪
打印调试信息和日志都是以文本的方式输出和记录信息的,因此不适合处理数据量庞大且速度要求高的情况。而事件追踪机制这是对这一需求而设计的。它使用结构化的二进制来记录数据。观察时在转换成文本形式。它非常适用于监视频繁且复杂的软件过程。
6.栈回溯
目前主流的cpu架构都是使用栈来进行函数调用的。栈上记录了函数的返回地址。通过递归式的寻找放在栈上的函数的返回地址,便可以追溯出当前线程的函数调用序列。这就是栈回溯的基本原理。
7.反汇编
反汇编是将目标代码翻译成汇编代码。符号文件对于反汇编具有重要意义。反汇编工具可以通过调试符号得到函数名称或是变量名称。这使得汇编代码具有良好的可读性。WinDbg的u和ul命令用于反汇编。
8.观察和修改数据
观察被调试程序的数据是了解程序内部状态的一种直接方法。很多调试器提供了查看和修改数据的功能。WinDbg的d和e系列命令用以查看和修改数据。r系列命令可以修改和查看寄存器值。
在掌握这些技术的基础上,从业者还需多实战,在实际的项目中多积累经验,提升对系统和代码的整体认识。
谈软件调试的实战,这本被业界称为“百科全书”的调试书就必须安利给大家了!
2018年,知名软件调试技术专家张银奎将自己多年来的调试心得汇集于《软件调试 第2版 卷1:硬件基础》中,大量技术背景知识以及具有代表性的技术细节为饱受bug之苦的软件从业者拨开了云雾。这本书也自然而然在豆瓣评分中获得了9.0的高分!
今年,同系列的卷2也隆重登场,围绕Windows平台调试的“生态”系统(ecosystem)、异常(exception)和调试器三条主线,介绍软件调试的相关原理和机制,探讨可调试性(debuggability)的内涵、意义,以及实现软件可调试性的原则和方法,总结软件调试的理论和最佳实践。
图书推荐
软件调试 第2版 卷2 Windows平台调试 上、下册
作者: 张银奎
软件调试 第2版 卷2 Windows平台调试 上、下册
作者:张银奎
当当
软件调试 第2版 卷2 Windows平台调试 上、下册(异步图书出品)
作者:张银奎
京东
内容简介:
本书是国内当前集中介绍软件调试主题的权威著作。本书第2 卷分为5 篇,共30 章,主要围绕Windows系统展开介绍。本书理论与实践结合,不仅涵盖了相关的技术背景知识,还深入研讨了大量具有代表性的技术细节,是学习软件调试技术的珍贵资料。
本书适合所有从事软件开发工作的读者阅读,特别适合从事软件开发、测试和支持的技术人员阅读。
软件调试 第2版 卷1 硬件基础
作者: 张银奎
软件调试 第2版 卷1:硬件基础
作者:张银奎
当当
软件调试 第2版 卷1:硬件基础(异步图书出品)
作者:张银奎
京东
内容简介:
本书堪称是软件调试的“百科全书”。作者围绕软件调试的“生态”系统(ecosystem)、异常(exception)和调试器 3 条主线,介绍软件调试的相关原理和机制,探讨可调试性(debuggability)的内涵、意义以及实现软件可调试性的原则和方法,总结软件调试的方法和技巧。
本书理论与实践紧密结合,既涵盖了相关的技术背景知识,又针对大量具有代表性和普遍意义的技术细节进行了讨论,是学习软件调试技术的宝贵资料。本书适合所有从事软件开发工作的读者阅读,特别适合从事软件开发、测试、支持的技术人员,从事反病毒、网络安全、版权保护等工作的技术人员,以及高等院校相关专业的教师和学生学习参考。