没有调试工具的调试技术

Debugging techniques without debugging tools

本文关键字:调试 技术 调试工具      更新时间:2023-10-16

我发现自己陷入了在几乎没有任何调试工具的情况下调试Qt应用程序的困难境地:应用程序似乎开始使用越来越多的CPU,因为它一次又一次地运行相同的操作;数小时后CPU完全饱和。

该应用程序运行在ARM Linux嵌入式设备上,gdb似乎不起作用,使用所提供的工具链可能很难发现问题。strace似乎只报告计时器活动(这是一个OpenGL应用程序,所以这是意料之中的事)。ltrace不可用,编译它导致了一项艰巨的任务,可能毫无用处。我没有写应用程序,但源代码是可用的。

在消耗那么多资源时,我还能做些什么来发现应用程序正忙于做什么吗?我有没有办法跟踪应用程序所做的所有方法调用?我有没有其他技巧可以用来猜测问题,或者把注意力集中在哪里?

编辑:这是gdb的问题之一:只有gdb在ARM上报告的回溯中有问号。即使编写一个模拟segfault的十行应用程序也会导致这种情况。

您能在机器上启用核心转储吗?然后,当它播放时,您可以向它发送一个SIGABRT,并将核心转储复制到您的开发机器上,然后使用交叉调试器对其进行检查,并提供源代码和未剥离的可执行文件。

同样重要的是,下次要吸取惨痛的教训,不要使用如此糟糕的支持工具链。

如果这是一个选项,您可以尝试另一个至少支持gdbserver的工具链,如果不支持gdb的话。我对CodeSourcery ARM Lite工具链非常满意。

编辑:针对您的情况的gdb有两种风格:

  • 在开发主机上运行的交叉gdb
  • 在目标上运行的本地gdb

gdbserver允许您在开发主机上运行交叉gdb,并连接到目标以远程调试在其上运行的东西。因此,核心转储或gdbserver是使用交叉gdb检查目标上的东西的两种方法,但单独使用gdbserver对您没有多大帮助。

如果您的交叉编译器类似于arm-none-linux-gnueabi-gcc,请查看您的开发主机上是否有可用的arm-none-linux-gnueabi-gdb

您可以尝试在应用程序中放置一些调试代码。

选择一些信号,比如SIGINT。添加此信号的信号处理程序。在此处理程序中,打印堆栈跟踪或至少打印指令指针值。然后启动应用程序并多次发送SIGINT来查看应用程序在做什么。

尝试记录不同函数的执行时间。首先记录最有可能的候选者的执行时间,如果您已经消除了它们,则继续执行程序中其他不太可能的函数。

记录消息的最简单方法是使用std::cout(或printf),并将消息重定向到一个文件,以便以后可以看到日志。

您可以尝试运行ARM版本的Zoom探查器-这应该会告诉您代码的大部分时间花在哪里-您可以在30天的评估许可证上免费下载它。

假设gcc有类似于MSVC文件和行宏的东西,可以扩展到当前文件和当前行,那么您可以创建自己的伪评测函数。把这个放在标题中:

void MyPseudoProfileLog(const char* file, int line, int* count);
#define MY_PSEUDO_PROFILE_LOG(file, line) { static int count = 0; MyPseudoProfileLog(file, line, &count); }

这在一个cpp文件中(如果你把它放在头中,你会得到静态变量的多个副本,每个包含头的cpp文件一个):

void MyPseudoProfileLog(const char* file, int line, int* count)
{
    static FILE* f = NULL;
    const int max_count = 1000;
    if (++(*count) == max_count)
    {
        *count = 0;
        if (!f)
            f = fopen("/tmp/my_pseudo_profile_log.log");
        fprintf(f, "file="%s", line=%d was passed %d timesn", file, line, max_count);
        fflush(f);
    }
}

然后你可以粘贴

MY_PSEUDO_PROFILE_LOG(__FILE__, __LINE__);

到代码中的各个位置,查看它们被调用的频率。请记住,这不是线程安全的,所以只能在主线程中使用。