Debug相关的边边角角

大学四年,自夸努力上进,看了很多专业书,一到实习工做,立刻显示出菜鸟的本性,连基本的程序调试都不会。大学时程序调试不是用printf输出运行时变量内容,就是肉眼看代码,小的算法Demo和功能代码,这样子调试就当是卖萌了;工做时一个服务器程序近万个源代码文件,客户端崩溃只有dump文件和日志信息反馈到服务器上,卖萌式的debug已经没法知足需求了。这段时间抽空看了一些关于debug的文档资料,加上工做半年来的一些实践,在这里小小的总结一下,大部份内容都是本身在阅读文档和实践中的一些想法,抛砖引玉,一些错误和不足,欢迎你们指出。算法

l  程序的debug信息sass

对于编译器来讲(好比gcc),若是直接对程序进行编译,不保留编译时的信息,则编译后的汇编代码(固然最后是符合操做系统支持的格式的binary可执行文件)根本彻底不知道源代码的任何信息,不知道汇编代码与源代码之间的关系,好比源代码中的函数名称、变量的类型和名称等。好比在使用GDB进行程序调试的时候,step(单步调试)命令默认是不进入共享库函数(.lib,.so,.a等文件)的,由于共享库函数都是不带调试信息的二进制代码文件,固然共享库文件通常来讲也都是已经调试好了的没有bug的文件。服务器

在Unix/Linux环境下,使用gcc的-g选项会将调试信息编码输出到编译后的可执行目标代码文件中,这些调试信息通常来讲包括:函数

  1. 自定义的变量类型信息(struct、class等)
  2. 函数的名称信息和入口地址(运行时虚拟内存地址)
  3. 全局变量的名称的地址
  4. 参数,局部变量的名字及其在堆栈中的偏移量

上面这些信息是确定的,我认为,应该还包括源代码和编译后的汇编代码之间的对应关系,在如今的编译技术下,汇编代码和源代码之间的一一对应关系彻底不可能从汇编代码倒推出来了。工具

用一个简单的31行的C语言Demo程序文件作试验,使用一样的编译优化级别,不使用-g选项编译出来的可执行目标代码文件的大小是6.85KB,使用-g选项后编译出的大小为8.79KB,而源代码文件的大小为404Byte,可见在使用-g选项后在可执行目标代码文件中调试信息所占文件大小的比重。当将源文件从当前目录下删除后,在调试目标代码文件时使用list指令,将出现No such file or directory的提示,可见在目标代码文件中保存的是源文件的路径信息。性能

在Windows环境中,调试信息并不被编码到最后的可执行目标文件中,而是经过一个和最后生成的.exe同名的.pdb文件来保存。在使用windbg或者VS来调试Windows下的程序的时候,须要设置和加载相应的.pdb文件,不然给出的调试信息极可能就是错误的。相关的信息能够查看:http://www.wintellect.com/blogs/jrobbins/pdb-files-what-every-developer-must-know(PDB Files: What Every Developer Must Know)。学习

 另外还有两点须要说明一下:开发工具

  1. 如今的编译器均可以设置代码优化等级,编译器会使用一些我这种菜鸟连作梦都想不到的高级的方式来优化代码,在优化过程当中,编译器会剔除不少局部变量,合并部分代码,调整一些代码的执行顺序,甚至可能删除代码。在高优化等级下调试代码的时候,不少程序中不少局部变量的值可能会看不到,一些断点可能就彻底跟不到。因此,若是须要调试程序,仍是将代码的优化等级调至最低比较稳当,在gcc和VS中均可以进行相应的设置。固然,在最后发布程序时调至高等级的优化级别就能够了。
  2. 在关于pdb文件介绍的上述博文中,提到了调试信息除了上面提到的4点以外,还包括了 Frame Pointer Omission 数据(FPO)。FPO的直译就是”省略帧指引”,这个东西比较高端的样子,查了一下资料,大概意思是:在通常函数调用的时候,会在程序的当前栈中保存调用者函数的栈帧指针(寄存器ebp的值),而后将当前栈指针esp保存到ebp中,而后再将栈指针esp减去必定值,用以分配函数的局部变量的内存地址,最后在函数退出的时候,会围绕寄存在ebp中的值进行一系列的弹栈恢复到原调用者函数的执行环境。EPO的使用是去除了这一系列过程当中的保存栈帧指针ebp和恢复的过程,直接经过栈指针esp的操做来进行局部变量的地址分配和函数参数的传递,这样就将寄存器ebp解放了出来,能够用来保存常用的变量,减小了其保存和恢复的过程,提升了程序的性能。通常来讲,EPO只有x86处理器支持。

l  一些Tips优化

  1. 远程调试。VS和GDB都支持远程调试,GDB尚未试过,VS支持使用TCP/IP和PIPE两种方式来链接远程的Windows虚拟机服务器,链接并Attach上在虚拟机上运行的服务器进程,这时你在本地使用VS打开的服务器代码上进行打断点,就和调试本地代码同样简单和轻松。不得不说,VS真是一个伟大的开发工具。
  2. 在GDB中,有不少指令能够用来查看代码的汇编和堆栈信息。Info frame能够查看当前栈帧信息,dissassemle <function name>指令能够将内存中对应函数的汇编代码dump出来,一遍的程序调试用不着看汇编代码找bug这么高端的东西,可是可使用这两个指令结合《深刻理解计算机系统》(《Computer System A Programmer’s Perspective》)一书的第三章研究源代码和汇编之间的关系。
  3. 学习GDB推荐网上的一个近30页的文档《Linux下GDB教程》,具体和指令相关的东西本身多用用就熟悉了,最经常使用的就是break(b,打断点),Print(p,输出变量),Continue(c,继续执行),我本身也须要多用用。

 

整篇就是本身的读书笔记和一些理解,有什么错误,请你们指出。邮箱:wangjian_pg@sohu.com。编码

相关文章
相关标签/搜索