8

所以我正在调试这个程序,这个程序是我从这个即将毕业的博士生那里继承来的,或者在学生完成论文后发生的任何事情。无论如何,现在调试它是我的责任。该程序基本上接收几个文本文件并处理它们。我遇到的问题(段错误)是因为程序试图访问尚未初始化的数组。我想知道是否有任何调试工具可以让您运行程序,并比较程序运行的两条不同路径。我想我可以手动完成程序,但我宁愿不这样做,因为它相当大,而且我还没有掌握它。我一直在使用 GDB 和 Valgrind(以及使用 g++ -wall 来显示警告),这就是我走到这一步的方式。

4

3 回答 3

5

这些建议是针对 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-functionsGCC 及其相关选项。

-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". 您可以实现挂钩以在每次调用函数时进行记录。您没有获得函数名称,但您可以在之后使用objdumpor对指针进行后处理addr2line

于 2013-06-21T16:51:03.650 回答
4

我认为您选择 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://lcamt​​uf.coredump.cx/fenris/whatis.shtml ),它还可以打印出代码的调用图。在阅读您的要求时,我认为 Fenris 最接近,因为它还允许您“可视化”所采用的代码路径。

于 2013-06-21T16:47:47.263 回答
3

GDB 可以让您逐行“单步执行”您的程序。一些技巧:

  1. 只需在 main (type b main) 处中断,然后按n+ Enter 键执行当前行并继续下一行。
  2. s如果您想进入函数,请 按+ Enter 键(即进入被调用的函数并从那里继续)。
  3. 键入p+ 变量名以打印出值(真的很高兴知道该变量是否已初始化,提示提示...)
  4. 如果您从命令行运行 GDB 并想要一个 GUI 包装器,请使用 Emacs。只需键入emacs program.c,然后键入Alt + x,然后键入gdb。输入可执行文件的名称,然后按 Enter。现在您可以看到更多代码,并且仍然使用 gdb 命令进行调试。
于 2013-06-21T16:51:33.373 回答