当前位置:  开发笔记 > 编程语言 > 正文

如何在没有调试器的情况下调试程序?

如何解决《如何在没有调试器的情况下调试程序?》经验,为你挑选了3个好方法。

面试问题 -

一旦你的代码出现问题,通常很容易调试程序.你可以把手表,断点等放在一边.由于调试器,生活更容易.

但是如何在没有调试器的情况下调试程序?

我知道一种可能的方法是将print语句放在代码中的任何地方,以便检查问题.

除此之外还有其他方法吗?

作为一般性问题,它不受任何特定语言的限制.请分享您对如何做到的想法?

编辑 - 在提交您的答案时,请提及有关任何概念的有用资源(如果您有的话).例如,记录
这对那些根本不了解它的人会很有用.(这包括我,在某些情况下:)

更新: Michal Sznajderhas提出了一个真正的"最佳"答案,并使其成为一个社区维基.真的值得很多投票.

Michal Sznaj.. 54

实际上你有很多可能性.重新编译源代码或不重新编译.

重新编译.

额外的记录.进入程序日志或使用系统日志记录(例如,OutputDebugString或Windows上的事件日志).还可以使用以下步骤:

始终包括至少达到秒分辨率的时间戳.

考虑在多线程应用程序中添加thread-id.

添加一些不错的结构输出

不要打印只有%d的枚举.使用一些ToString()或创建一些EnumToString()功能(适合您的语言)

...并注意:记录更改时间,以便在多线程严重的情况下,您的问题可能会消失.

这里有更多细节.

引入更多断言

单元测试

"视听"监控:如果发生了什么事,请做其中之一

使用蜂鸣器

播放系统声音

通过启用硬件GPIO线闪一些LED(仅限嵌入式场景)

没有重新编译

如果您的应用程序使用任何类型的网络:Packet Sniffer或我将为您选择:Wireshark

如果使用database:monitor查询发送到数据库和数据库本身.

使用虚拟机测试与系统运行时完全相同的OS /硬件设置.

使用某种系统调用监视器.这包括

在Unix盒子strace或dtrace

从以前的Windows工具的Sysinternals工具,如http://technet.microsoft.com/en-us/sysinternals/bb896645.aspx,ProcessExplorer和一致好评

在Windows GUI的情况下:查看Spy ++或WPF Snoop(虽然我没有使用第二个)

考虑为您的平台使用一些分析工具.它将为您提供有关应用中发生的事情的概述.

[真正的硬核]硬件监控:使用示波器(又名O-Scope)监控硬件线路上的信号

源代码调试:你坐下来看看你的源代码,然后用一张纸和一支铅笔假装你是电脑.它所谓的代码分析或"我眼睛"的调试

源代码控制调试.比较"it"工作时和现在的代码差异.Bug可能在某处.

最后一些一般提示:

不要忘记Excel中的文本到列数据透视表.与一些文本工具(awk,grepperl)一起为您提供令人难以置信的分析包.如果您有超过32K的记录,请考虑使用Access作为数据源.

数据仓库的基础知识可能会有所帮助.使用简单的立方体,您可以在几分钟内分析大量的时态数据.

倾倒您的申请值得一提.无论是因为崩溃还是只是定期

始终生成调试符号(即使是发布版本).

几乎最后但并非最不重要:大多数市长平台都有一些内置的命令行调试器(甚至是Windows!).通过一些技巧,如条件调试和break-print-continue,您可以通过隐藏的错误获得相当不错的结果

真的最后但并非最不重要:用你的大脑来质疑一切.

一般来说,调试就像科学一样:你不会创造它而发现它.通常它喜欢在刑事案件中寻找凶手.所以给自己买一顶帽子,永不放弃.



1> Michal Sznaj..:

实际上你有很多可能性.重新编译源代码或不重新编译.

重新编译.

额外的记录.进入程序日志或使用系统日志记录(例如,OutputDebugString或Windows上的事件日志).还可以使用以下步骤:

始终包括至少达到秒分辨率的时间戳.

考虑在多线程应用程序中添加thread-id.

添加一些不错的结构输出

不要打印只有%d的枚举.使用一些ToString()或创建一些EnumToString()功能(适合您的语言)

...并注意:记录更改时间,以便在多线程严重的情况下,您的问题可能会消失.

这里有更多细节.

引入更多断言

单元测试

"视听"监控:如果发生了什么事,请做其中之一

使用蜂鸣器

播放系统声音

通过启用硬件GPIO线闪一些LED(仅限嵌入式场景)

没有重新编译

如果您的应用程序使用任何类型的网络:Packet Sniffer或我将为您选择:Wireshark

如果使用database:monitor查询发送到数据库和数据库本身.

使用虚拟机测试与系统运行时完全相同的OS /硬件设置.

使用某种系统调用监视器.这包括

在Unix盒子strace或dtrace

从以前的Windows工具的Sysinternals工具,如http://technet.microsoft.com/en-us/sysinternals/bb896645.aspx,ProcessExplorer和一致好评

在Windows GUI的情况下:查看Spy ++或WPF Snoop(虽然我没有使用第二个)

考虑为您的平台使用一些分析工具.它将为您提供有关应用中发生的事情的概述.

[真正的硬核]硬件监控:使用示波器(又名O-Scope)监控硬件线路上的信号

源代码调试:你坐下来看看你的源代码,然后用一张纸和一支铅笔假装你是电脑.它所谓的代码分析或"我眼睛"的调试

源代码控制调试.比较"it"工作时和现在的代码差异.Bug可能在某处.

最后一些一般提示:

不要忘记Excel中的文本到列数据透视表.与一些文本工具(awk,grepperl)一起为您提供令人难以置信的分析包.如果您有超过32K的记录,请考虑使用Access作为数据源.

数据仓库的基础知识可能会有所帮助.使用简单的立方体,您可以在几分钟内分析大量的时态数据.

倾倒您的申请值得一提.无论是因为崩溃还是只是定期

始终生成调试符号(即使是发布版本).

几乎最后但并非最不重要:大多数市长平台都有一些内置的命令行调试器(甚至是Windows!).通过一些技巧,如条件调试和break-print-continue,您可以通过隐藏的错误获得相当不错的结果

真的最后但并非最不重要:用你的大脑来质疑一切.

一般来说,调试就像科学一样:你不会创造它而发现它.通常它喜欢在刑事案件中寻找凶手.所以给自己买一顶帽子,永不放弃.


您可能希望添加到硬件监视,您可以使用O-Scope来观察GPIO线来测量执行时间和函数执行的频率.

2> Paul Hsieh..:

首先,调试实际上做了什么?高级调试器为您提供机器挂钩以暂停执行,检查变量并可能修改正在运行的程序的状态.大多数程序不需要所有这些来调试它们.有很多方法:

    跟踪:实现某种日志记录机制,或使用现有的日志记录机制,如dtrace().通常值得实现某种类似printf的函数,它可以将通常格式化的输出输出到系统日志中.然后将状态从程序中的关键点抛出到此日志中.信不信由你,在复杂的程序中,这比使用真正的调试器进行原始调试更有用.日志帮助你知道你是怎么得到了麻烦,而陷阱的崩溃调试器假设你可以反向工程你如何到达那里的,你已经处于任何状态.对于使用其他复杂库的应用程序,你不拥有该在它们中间崩溃,日志往往更有用.但是在编写日志消息时需要一定的纪律.

    程序/库自我意识:为了解决非常具体的崩溃事件,我经常在系统库上实现包装器,例如malloc/free/realloc,这些扩展可以执行诸如步行内存,检测双重释放,尝试释放未分配的指针之类的东西检查明显的缓冲区溢出等.通常你也可以为重要的内部数据类型做这类事情 - 通常你可以对链接列表之类的东西进行自我完整性检查(它们不能循环,它们不能点到LA-LA土地).即使对于像OS同步对象,往往你只需要知道哪个线程,还是什么文件和行号(可拍摄__FILE__,__LINE__)的同步对象的最后一个用户是帮助你找出竞争条件.

    如果你像我一样疯了,你可以在你自己的程序中实现自己的迷你调试器.这实际上只是自反射编程语言中的一种选择,或者在具有某些OS挂钩的C语言中.在Windows/DOS中编译C/C++时,可以实现"崩溃挂钩"回调,该回调在触发任何程序错误时执行.编译程序时,您可以构建一个.map文件来确定所有公共函数的相对地址(这样您就可以通过从.map中给出的地址减去main()的地址来计算加载器的初始偏移量.文件).因此,当发生崩溃时(例如,即使在运行期间按下^ C,您也可以找到无限循环),您可以获取堆栈指针并在返回地址内扫描它以获得偏移量.您通常可以查看您的寄存器,并实现一个简单的控制台,让您检查所有这些.瞧,你实现了一半真正的调试器.保持这种状态,您可以重现VxWorks的控制台调试机制.

    另一种方法是逻辑演绎.这与#1有关.基本上,程序中的任何崩溃或异常行为都会在停止按预期运行时发生.您需要有一些反馈方法来了解程序何时正常运行然后异常运行.然后,您的目标是找到程序从正确行为到错误行为的确切条件.使用printf()/日志或其他反馈(例如在嵌入式系统中启用设备 - PC有一个扬声器,但有些主板还有一个用于BIOS阶段报告的数字显示器;嵌入式系统通常会有一个COM端口,您可以使用)您可以通过程序的工具,至少推导出关于程序运行状态的良好和不良行为的二进制状态.

    相关方法是关于代码版本的逻辑推论.程序通常在一个状态下完美运行,但某些后续版本不再有效.如果您使用良好的源代码控制,并且在编程团队中强制执行"树顶必须始终正常工作"的理念,那么您可以使用二进制搜索来查找发生故障的代码的确切版本.然后,您可以使用差异来推断出哪些代码更改会暴露错误.如果差异太大,那么您的任务是尝试以较小的步骤重做代码更改,以便更有效地应用二进制搜索.



3> Scanningcrew..:

只有几个建议:

1)断言.这应该有助于您在计划的不同状态下制定一般期望.同时熟悉代码

2)单元测试.我有时使用这些来挖掘新代码并测试API

推荐阅读
牛尾巴2010
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有