使用 clang 编译时无法查看 std::string

Cannot view std::string when compiled with clang

g++ (海湾合作委员会) 5.2.0

clang 版本 3.7.1 (tags/RELEASE_371/final)

GNU gdb (GDB) 7.12

Gdb 由于某种原因在使用 clang 编译时无法定位 std::string 的定义。我已经自定义编译和构建 gcc 和 clang,因为 Centos 6.5 带有旧版本的 gcc。

示例代码

#include <string>

int main()
{
    std::string s("This is a string");

    return 0;
}

使用 g++ 编译并调试 - 工作正常

[~]$ g++ -ggdb3 -std=c++14 stl.cpp 
[~]$ gdb a.out
GNU gdb (GDB) 7.12
Reading symbols from a.out...done.
(gdb) break main
Breakpoint 1 at 0x400841: file stl.cpp, line 5.
(gdb) r
Starting program: /home/vagrant/a.out 

Breakpoint 1, main () at stl.cpp:5
5       std::string s("This is a string");
(gdb) n
7       return 0;
(gdb) p s
 = {static npos = <optimized out>, 
  _M_dataplus = {<std::allocator<char>> = {<__gnu_cxx::new_allocator<char>> = {<No data fields>}, <No data fields>}, _M_p = 0x612c20 "This is a string"}, _M_string_length = 16, {
    _M_local_buf = "0[=12=]0[=12=]0[=12=]0[=12=]0[=12=]0[=12=]0[=12=]00\b@[=12=]0[=12=]0[=12=]0[=12=]0", _M_allocated_capacity = 16}}
(gdb) 

检查它是否链接到我的 libstdc++ 的 rpm 构建版本而不是系统

[~]$ ldd a.out
    linux-vdso.so.1 =>  (0x00007ffd709e0000)
    libstdc++.so.6 => /opt/spotx-gcc/lib64/libstdc++.so.6 (0x00007f29318fa000)
    libm.so.6 => /lib64/libm.so.6 (0x00007f2931676000)
    libgcc_s.so.1 => /opt/spotx-gcc/lib64/libgcc_s.so.1 (0x00007f293145f000)
    libc.so.6 => /lib64/libc.so.6 (0x00007f29310cb000)
    /lib64/ld-linux-x86-64.so.2 (0x00007f2931c93000)

[~]$ objdump -T -C a.out
a.out:     file format elf64-x86-64
DYNAMIC SYMBOL TABLE:
0000000000000000  w   D  *UND*  0000000000000000              __gmon_start__
0000000000000000  w   D  *UND*  0000000000000000              _Jv_RegisterClasses
0000000000000000      DF *UND*  0000000000000000  GLIBC_2.2.5 __libc_start_main
0000000000000000  w   D  *UND*  0000000000000000              _ITM_deregisterTMCloneTable
0000000000000000  w   D  *UND*  0000000000000000              _ITM_registerTMCloneTable
0000000000000000      DF *UND*  0000000000000000  GLIBCXX_3.4.21 std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::~basic_string()
0000000000000000      DF *UND*  0000000000000000  GLIBCXX_3.4 std::allocator<char>::~allocator()
0000000000000000      DF *UND*  0000000000000000  GLIBCXX_3.4.21 std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::basic_string(char const*, std::allocator<char> const&)
0000000000000000      DF *UND*  0000000000000000  GLIBCXX_3.4 std::allocator<char>::allocator()
0000000000000000      DF *UND*  0000000000000000  GCC_3.0     _Unwind_Resume
0000000000400700      DF *UND*  0000000000000000  CXXABI_1.3  __gxx_personality_v0

如果我用 clang 尝试同样的操作,现在一切看起来都不错

[~]$ clang++ -std=c++14 -g stl.cpp
[~]$ gdb a.out
GNU gdb (GDB) 7.12
Reading symbols from a.out...done.
(gdb) break  main
Breakpoint 1 at 0x400853: file stl.cpp, line 5.
(gdb) r
Starting program: /home/vagrant/a.out 

Breakpoint 1, main () at stl.cpp:5
5       std::string s("This is a string");
(gdb) n
7       return 0;
(gdb) p s
 = <incomplete type>
(gdb) 

现在我得到一个不完整的类型 - 但正在使用相同的库

[~]$ ldd a.out
    linux-vdso.so.1 =>  (0x00007fff5352d000)
    libstdc++.so.6 => /opt/spotx-gcc/lib64/libstdc++.so.6 (0x00007f76b4023000)
    libm.so.6 => /lib64/libm.so.6 (0x00007f76b3d9f000)
    libgcc_s.so.1 => /opt/spotx-gcc/lib64/libgcc_s.so.1 (0x00007f76b3b88000)
    libc.so.6 => /lib64/libc.so.6 (0x00007f76b37f4000)
    /lib64/ld-linux-x86-64.so.2 (0x00007f76b43bc000)


[~]$ objdump -T -C a.out
a.out:     file format elf64-x86-64
DYNAMIC SYMBOL TABLE:
0000000000000000  w   D  *UND*  0000000000000000              __gmon_start__
0000000000000000  w   D  *UND*  0000000000000000              _Jv_RegisterClasses
0000000000000000      DF *UND*  0000000000000000  GLIBC_2.2.5 __libc_start_main
0000000000000000  w   D  *UND*  0000000000000000              _ITM_deregisterTMCloneTable
0000000000000000  w   D  *UND*  0000000000000000              _ITM_registerTMCloneTable
0000000000000000      DF *UND*  0000000000000000  GLIBCXX_3.4.21 std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::~basic_string()
0000000000000000      DF *UND*  0000000000000000  GLIBCXX_3.4 std::allocator<char>::~allocator()
0000000000000000      DF *UND*  0000000000000000  GLIBCXX_3.4.21 std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::basic_string(char const*, std::allocator<char> const&)
0000000000000000      DF *UND*  0000000000000000  GLIBCXX_3.4 std::allocator<char>::allocator()
0000000000000000      DF *UND*  0000000000000000  GCC_3.0     _Unwind_Resume
0000000000400700      DF *UND*  0000000000000000  CXXABI_1.3  __gxx_personality_v0

有没有人对在哪里看或我错过的东西有任何建议。两个编译器在构建它们时都是自举的 - 一切似乎都很好 - 它只是看起来 std::string is not defined when using clang.

我在 Fedora 上用系统 clang 重现了这个问题。

clang 似乎没有为 std::string 发出调试信息,因为有人告诉它 libstdc++ 提供了它。请参阅来自 bug 24202 的评论:

Looks like you don't have debug information for libstdc++ installed:

Missing separate debuginfos, use: dnf debuginfo-install libgcc-5.1.1-4.fc22.x86_64 libstdc++-5.1.1-4.fc22.x86_64

Clang 没有发出 std::string 的调试信息,因为它是 告诉 libstdc++ 提供它(但在你的情况下,它不是 安装);这是 GCC 显然对调试大小进行的优化 不执行。

如果您安装 libstdc++ 的调试信息,这是否有效?

我已经使用命令 dnf debuginfo-install libstdc++-6.2.1-2.fc25.x86_64 安装了 libstdc++ 的调试信息并解决了问题。

如 ks1322 所述,这是因为 clang 已决定不为 libstc++ 发出调试信息。

您可以通过提供以下标志来强制 clang 这样做: -D_GLIBCXX_DEBUG

我只会为调试版本提供标志,但如果调试是默认版本而发布版本是一个特殊目标,您应该将其删除:

release: CXXFLAGS := $(filter-out -D_GLIBCXX_DEBUG,$(CXXFLAGS)) -O2

这为我解决了同样的问题。

bug 24202 as linked by ks1322 中提到的最后一个解决方法值得一看:

-fno-limit-debug-info will make your debug info larger, slow link (if you're not using -gsplit-dwarf) and debugger performance. But, yes, will address this.

使用 -fno-limit-debug-info 强制 Clang 发出调试信息,例如std::string 以更大的二进制文件为代价,同时保持与其他库和其余 system/SDK.

的兼容性

正如 ks1322 和 Kevin 提到的,可以改用 -D_GLIBCXX_DEBUG 将 libstdc++ 切换为 debug mode 但这要付出高昂的代价:您 link 反对的任何库以及您使用的库交换 STL 容器(字符串、矢量等)也必须使用 -D_GLIBCXX_DEBUG 构建。意思是:你的 system/SDK 必须用一组单独的库来支持它,否则你将不得不自己重建它们。

clang 相信 libstd++ 的调试符号可用,因此您必须安装它们。请参阅 ks1322 的回答以了解如何在 Fedora 上执行此操作。在 Ubuntu、运行 上:

sudo apt-get install libstdc++6-dbgsym

在那之后,事情就会正常进行。

不要定义_GLIBCXX_DEBUG,因为那样会破坏 libstdc++ 的 abi。

-fno-limit-debug-info 会使 clang 发出比必要的更大的调试信息,所以我也建议不要这样做。只需安装 libstdc++ 的调试信息包。