如何在gdb中打印<不完整类型>变量

56
有时候gdb会针对某些类型的变量打印出"incomplete type"。这是什么意思以及我们如何查看该值?

我是唯一一个即使结构在链接的目标文件中已经完全定义了,仍然会遇到这个错误的人吗?有没有办法将gdb指向头文件? - fuzzyTew
6个回答

38

这意味着该变量的类型未完全指定。例如:

struct hatstand;
struct hatstand *foo;

GDB知道foo是指向hatstand结构体的指针,但该结构体的成员尚未定义。因此,“不完整类型”。

要打印该值,您可以将其转换为兼容的类型。

例如,如果您知道foo实际上是指向lampshade结构体的指针:

print (struct lampshade *)foo

或者,你可以将其打印为通用指针,或者将其视为整数:

print (void *)foo
print (int)foo

请参阅GDB手册中的以下页面:


(提示:GDB是GNU调试器,用于调试程序)

一个简单的typedef typedef unsigned char byte怎么样?我想在 byte* 上看到数据。但是我得到了 data=<incomplete type>。并且 x/16b data 的结果是 “无法将该值转换为整数” - jww

9
我发现,如果您反汇编使用不完整结构类型的函数,则gdb会“发现”结构成员,并随后显示它们。例如,假设您有一个字符串结构体:
struct my_string {
    char * _string,
    int _size
} ;

使用指针创建并获取字符串的一些函数:

my_string * create_string(const char *) {...}
const char * get_string(my_string *){...}

还有一个创建字符串的测试:

int main(int argc, char *argv[]) {
    my_string *str = create_string("Hello World!") ;
    printf("String value: %s\n", get_string(str)) ;
    ...
}

在gdb中运行它并尝试'print *str',你会得到一个'incomplete type'的响应。但是,尝试'disassemble get_string'然后再'print *str',它将正确地显示结构和值。我不知道为什么这样做有效,但确实有效。

3

免责声明:我是一名Python开发人员,只有一些关于C++和Linux操作系统功能的基础知识,所以以下内容仅是我针对我个人遇到的问题提出的解决方案。

如果您正在使用来自第三方库的类型,请确保这些库没有缺少调试信息。

示例

Original Answer翻译成"最初的回答"
(gdb) info share Qt
From                To                  Syms Read   Shared Object Library
0x00007ffff5336080  0x00007ffff56ba585  Yes (*)     /usr/lib/x86_64-linux-gnu/libQt5Widgets.so.5
0x00007ffff4ad3510  0x00007ffff4ef0cbe  Yes (*)     /usr/lib/x86_64-linux-gnu/libQt5Gui.so.5
0x00007ffff47829c0  0x00007ffff47e1ba1  Yes (*)     /usr/lib/x86_64-linux-gnu/libQt5DBus.so.5
0x00007ffff40bb5e0  0x00007ffff439dd92  Yes (*)     /usr/lib/x86_64-linux-gnu/libQt5Core.so.5
0x00007ffff2e581e0  0x00007ffff2e78e4f  Yes (*)     /usr/lib/x86_64-linux-gnu/libQt5Xml.so.5
0x00007ffff28c8a00  0x00007ffff29d9999  Yes (*)     /usr/lib/x86_64-linux-gnu/libQt5Network.so.5
0x00007ffff2251750  0x00007ffff2252a46  Yes (*)     /usr/lib/x86_64-linux-gnu/libQt5X11Extras.so.5
0x00007ffff1cc9f80  0x00007ffff1cfc861  Yes (*)     /usr/lib/x86_64-linux-gnu/libQt5PrintSupport.so.5
0x00007fffee269c10  0x00007fffee297b57  Yes (*)     /usr/lib/x86_64-linux-gnu/libQt5Svg.so.5
0x00007fffed987560  0x00007fffed98b6a8  Yes (*)     /usr/lib/x86_64-linux-gnu/libQt5TextToSpeech.so.5
0x00007fffe980e130  0x00007fffe9900c0c  Yes (*)     /usr/lib/x86_64-linux-gnu/libQt5XcbQpa.so.5
0x00007fffe69ef650  0x00007fffe69ffe0d  Yes (*)     /usr/lib/x86_64-linux-gnu/libQt5QuickControls2.so.5
0x00007fffe5c0f890  0x00007fffe5eae1c1  Yes (*)     /usr/lib/x86_64-linux-gnu/libQt5Quick.so.5
0x00007fffe5522690  0x00007fffe581f636  Yes (*)     /usr/lib/x86_64-linux-gnu/libQt5Qml.so.5
0x00007fffe51996b0  0x00007fffe5221363  Yes (*)     /usr/lib/x86_64-linux-gnu/libQt5QuickTemplates2.so.5
(*): Shared library is missing debugging information.

在当前示例中,所有Qt库都缺少调试信息。这是因为qt库的调试信息来自单独的软件包,而这些软件包没有被安装。

每当我执行whatis命令时,一切都正常工作:


(gdb) whatis e
type = QEvent *

but when I tried to access it's members

(gdb) p e->type()
Couldn't find method QEvent::type

最初的回答:尝试获取详细的类型描述,并使其更加易于理解。
(gdb) ptype e
type = class QEvent {
  <incomplete type>
} *

解决方案(适用于Ubuntu上的Qt)

  1. 找出该文件属于操作系统分发中的哪个软件包
(注:Original Answer翻译成“最初的回答”)
$ dpkg -S /usr/lib/x86_64-linux-gnu/libQt5Core.so.5
libqt5core5a:amd64: /usr/lib/x86_64-linux-gnu/libQt5Core.so.5

最初的回答:
  1. 搜索相关软件包

    使用关键词libqt5core5a进行搜索,返回了2个软件包,一个是libqt5core5a本身,另一个是libqt5core5a-dbgsym。后者的描述为:“用于libqt5core5a的调试符号”。

  2. 安装带有调试符号的软件包(我还安装了一些其他必要的Qt库的调试符号)

$ sudo apt install libqt5core5a-dbgsym libqt5widgets5-dbgsym libqt5gui5-dbgsym
  1. gdb 中确保库现在有调试信息
注:Original Answer 翻译成 "最初的回答"。
(gdb) info share Qt
From                To                  Syms Read   Shared Object Library
0x00007ffff5336080  0x00007ffff56ba585  Yes         /usr/lib/x86_64-linux-gnu/libQt5Widgets.so.5
0x00007ffff4ad3510  0x00007ffff4ef0cbe  Yes         /usr/lib/x86_64-linux-gnu/libQt5Gui.so.5
0x00007ffff47829c0  0x00007ffff47e1ba1  Yes (*)     /usr/lib/x86_64-linux-gnu/libQt5DBus.so.5
0x00007ffff40bb5e0  0x00007ffff439dd92  Yes         /usr/lib/x86_64-linux-gnu/libQt5Core.so.5
0x00007ffff2e571e0  0x00007ffff2e77e4f  Yes (*)     /usr/lib/x86_64-linux-gnu/libQt5Xml.so.5
0x00007ffff28c7a00  0x00007ffff29d8999  Yes (*)     /usr/lib/x86_64-linux-gnu/libQt5Network.so.5
0x00007ffff2250750  0x00007ffff2251a46  Yes (*)     /usr/lib/x86_64-linux-gnu/libQt5X11Extras.so.5
0x00007ffff1cc8f80  0x00007ffff1cfb861  Yes (*)     /usr/lib/x86_64-linux-gnu/libQt5PrintSupport.so.5
0x00007fffee268c10  0x00007fffee296b57  Yes (*)     /usr/lib/x86_64-linux-gnu/libQt5Svg.so.5
0x00007fffed985560  0x00007fffed9896a8  Yes (*)     /usr/lib/x86_64-linux-gnu/libQt5TextToSpeech.so.5
0x00007fffe95fc130  0x00007fffe96eec0c  Yes (*)     /usr/lib/x86_64-linux-gnu/libQt5XcbQpa.so.5
0x00007fffe701f650  0x00007fffe702fe0d  Yes (*)     /usr/lib/x86_64-linux-gnu/libQt5QuickControls2.so.5
0x00007fffe623c890  0x00007fffe64db1c1  Yes (*)     /usr/lib/x86_64-linux-gnu/libQt5Quick.so.5
0x00007fffe5b4f690  0x00007fffe5e4c636  Yes (*)     /usr/lib/x86_64-linux-gnu/libQt5Qml.so.5
0x00007fffe57c66b0  0x00007fffe584e363  Yes (*)     /usr/lib/x86_64-linux-gnu/libQt5QuickTemplates2.so.5
(*): Shared library is missing debugging information.

现在使用Qt类型可以按预期工作。最初的回答是"Original Answer"。
(gdb) p e->type()
$4 = QEvent::Paint
(gdb) ptype e
type = class QEvent {
  public:
...
}

嗨,如果你只是想检查一些变量,它们的类型在头文件中定义,但实现在第三方库中,我发现使用-femit-class-debug-always是构建你自己应用的一个好选择。这样,你就可以避免使用第三方库的调试版本。在这里可以看到我详细的解释:asmwarrior/debug-tips - undefined

0

我不知道错误的完整含义,但正如Peter所指出的那样,相关方法的反汇编会执行某些操作,使得这些类型定义中的一些可用。

我的例子:

在一个类的.h文件中,该类包括一个内部辅助类的前向声明,以便外部类可以包含一个指向它的指针。相应的.cpp文件具有完整的内部辅助类定义。

在外部类的一个方法中断点时,gdb报告了对通过外部类实例的指针对内部类实例进行解引用的不完整类型。

在外部类的一个方法上发出disasemble命令,允许gdb使用先前失败的相同指针来理解内部类的结构。


0

我曾经遇到过同样的问题。如果你手动加载库中的符号:

set auto-solib-add off
attach thread_id
shared any_lib
shared another_lib

你需要使用相同的命令从声明该对象的库中加载符号。

0

在尝试在 Docker 容器内调试 libpam 时,我遇到了同样的问题。在尝试从 pam_sm_authenticate 打印 pamh 参数时,它显示为 <incomplete type>

起初,调试符号缺失,但即使从源代码构建库后,仍然无法解决该问题。

当我尝试使用 LLDB 而不是 GDB 时,我收到了此错误:

error: 'A' packet returned an error: 8

这导致我找到了this answer,其中提到ptrace系统调用似乎在容器内默认被禁用。
在我的情况下,我并不真的关心安全性,因为我只是使用容器来创建一个可重现的环境,因此,我通过添加以下参数--cap-add=SYS_PTRACE --security-opt seccomp=unconfineddocker run来允许执行。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接