所以我正在调试这个程序,这个程序是我从这个即将毕业的博士生那里继承来的,或者在学生完成论文后发生的任何事情。无论如何,现在调试它是我的责任。该程序基本上接收几个文本文件并处理它们。我遇到的问题(段错误)是因为程序试图访问尚未初始化的数组。我想知道是否有任何调试工具可以让您运行程序,并比较程序运行的两条不同路径。我想我可以手动完成程序,但我宁愿不这样做,因为它相当大,而且我还没有掌握它。我一直在使用 GDB 和 Valgrind(以及使用 g++ -wall 来显示警告),这就是我走到这一步的方式。
3 回答
这些建议是针对 GCC 的。您可以使用gcov
覆盖率工具详细了解程序的哪些部分已执行以及执行频率。您必须将一些特殊选项传递给 GCC 以生成正确的检测和输出以gcov
进行处理。
--coverage
此选项用于编译和链接为覆盖分析而检测的代码。该选项是-fprofile-arcs -ftest-coverage
(编译时)和-lgcov
(链接时)的同义词。有关更多详细信息,请参阅这些选项的文档。
然后,当您执行程序时,会生成一些分析和覆盖数据。然后,您可以调用gcov
以分析该输出。以下是从上面的链接中获取的输出示例:
-: 0:Source:tmp.c
-: 0:Graph:tmp.gcno
-: 0:Data:tmp.gcda
-: 0:Runs:1
-: 0:Programs:1
-: 1:#include <stdio.h>
-: 2:
-: 3:int main (void)
1: 4:{
1: 5: int i, total;
-: 6:
1: 7: total = 0;
-: 8:
11: 9: for (i = 0; i < 10; i++)
10: 10: total += i;
-: 11:
1: 12: if (total != 45)
#####: 13: printf ("Failure\n");
-: 14: else
1: 15: printf ("Success\n");
1: 16: return 0;
-: 17:}
如果你想实现你自己的工具来记录程序的调用历史,你可以使用-finstrument-functions
GCC 及其相关选项。
-finstrument-functions
生成用于进入和退出函数的检测调用。在函数进入之后和函数退出之前,使用当前函数的地址及其调用站点调用以下分析函数。(在某些平台上,__builtin_return_address
不能超出当前功能,因此调用站点信息可能无法用于分析功能。)
void __cyg_profile_func_enter (void *this_fn,
void *call_site);
void __cyg_profile_func_exit (void *this_fn,
void *call_site);
第一个参数是当前函数的起始地址,可以在符号表中准确查找。
在 C++ 中,这些钩子的实现应声明为extern "C"
. 您可以实现挂钩以在每次调用函数时进行记录。您没有获得函数名称,但您可以在之后使用objdump
or对指针进行后处理addr2line
。
我认为您选择 GDB 和 valgrind 等工具的方向是正确的。
使用 GDB,您可以编写程序在两种情况下的执行脚本,并在发生段错误时查看调用堆栈。然后,您可以在该位置放置一个断点,并使用不会使程序崩溃的参数再次运行,并调查两者的差异。
使用实际上是一套工具 ( http://valgrind.org/info/tools.html ) 的 valgrind,您可以使用 callgrind 和 kcachegrind 取得一些成功。Callgrind 为您提供调用图,而 kcachegrind ( http://kcachegrind.sourceforge.net/cgi-bin/show.cgi/KcacheGrindIndex ) 允许您可视化它们。我将它们都用于大型 C 代码库的性能分析。
另一个可以帮助您的工具是 Fenris ( http://lcamtuf.coredump.cx/fenris/whatis.shtml ),它还可以打印出代码的调用图。在阅读您的要求时,我认为 Fenris 最接近,因为它还允许您“可视化”所采用的代码路径。
GDB 可以让您逐行“单步执行”您的程序。一些技巧:
- 只需在 main (type
b main
) 处中断,然后按n
+ Enter 键执行当前行并继续下一行。 s
如果您想进入函数,请 按+ Enter 键(即进入被调用的函数并从那里继续)。- 键入
p
+ 变量名以打印出值(真的很高兴知道该变量是否已初始化,提示提示...) - 如果您从命令行运行 GDB 并想要一个 GUI 包装器,请使用 Emacs。只需键入
emacs program.c
,然后键入Alt + x
,然后键入gdb
。输入可执行文件的名称,然后按 Enter。现在您可以看到更多代码,并且仍然使用 gdb 命令进行调试。