使用Xcode/LLDB打印/调试libc++ STL

47

我正在尝试在Xcode 8中使用LLDB调试基本的STL。我曾经可以像这样打印一个vector:

p myvector[0]

要查看第一个向量索引中的任何内容。现在当我这样做时,会出现以下错误:

error: Couldn't lookup symbols:
  __ZNSt3__16vectorI9my_classNS_9allocatorIS1_EEEixEm

相反,我必须输入这个:
p myvector.__begin_[0]

为了获得任何输出,需要进行一些设置。

我尝试从LLDB svn存储库中导入libcxx.py和unordered_multi.py脚本,但这似乎没有改变任何东西。

有人能够使用libc++从LLDB获取任何有用的输出吗?


你是否使用调试信息编译了代码?能否提供一个自包含的复现程序? - EricWF
1
当然启用了调试信息。 :) 这是一个可以重现问题的愚蠢项目。只需在 std::cout 行上设置断点,然后运行 lldb 命令“p myVector [0]”即可。当它命中时,您将收到一个错误。如果您改为使用“p myVector._begin[0]”,则会打印得很好。https://www.dropbox.com/s/ntjywxabxj3e4mc/Crap.zip?dl=0 - cjserio
2个回答

90
[]std::vector的运算符方法,因此要打印您想要的表达式,lldb必须能够调用[]方法。问题在于,在OS X上的STL非常注重内联所有可以内联的内容,并且不会浪费空间来生成相同函数的外部副本。这对于优化代码非常有用,但对于调试而言并不好,因为它没有[]运算符可供调用。这就是您看到的错误消息。
如果您只想查看此向量中的元素,则可以使用lldb的"STL数据格式化程序"来完成此工作。它们知道大多数STL类型的布局方式,并且可以打印大多数容器类型的元素。例如:
(lldb) expr my_vec[0]
error: Couldn't lookup symbols:
  __ZNSt3__16vectorI3FooNS_9allocatorIS1_EEEixEm

但是:

(lldb) expr my_vec
(std::__1::vector<Foo, std::__1::allocator<Foo> >) $0 = size=2 {
  [0] = (var1 = 10, var2 = 20)
  [1] = (var1 = 10, var2 = 20)
}

还有另一个命令"frame variable",可以检查静态对象,并钩入数据格式化程序。它不能调用函数和执行其他更复杂的表达式解析器任务,但它知道如何使用STL数据格式化程序来检索单个元素:

(lldb) frame var my_vec[1]
(Foo) my_vec[1] = (var1 = 10, var2 = 20)

您甚至可以使用帧变量的-L选项来定位向量的元素,然后将地址转换为传递给其他函数:

(lldb) frame var -L my_vec[1]
0x0000000100100348: (Foo) my_vec[1] = {
0x0000000100100348:   var1 = 10
0x000000010010034c:   var2 = 20
}
(lldb) expr printf("%d\n", ((class Foo *) 0x0000000100100348)->var1)
10
(int) $3 = 3

另一种解决调试问题的方法-如果你使用的是C++11-是将以下代码添加到程序中:
template class std::vector<MyClass>

在代码的某处添加这行代码。这将指示编译器为此类型特化版本生成所有模板函数的带外副本。这不是一个通用解决方案,您只需要在调试版本中执行它,但它确实允许您调用这些函数并在复杂表达式中使用它们。


1
非常详细的回答,Jim,我很感激! - cjserio
2
据我所知,即使在 -O0 的情况下,clang/STL 的组合在内联方面比gcc更加积极。 - Jim Ingham
3
根据一篇llvm-dev的文章: "是的,这是我们STL的一个问题,我们正在强制进行内联,需要在libc++方面修复,已经计划了,但我们还没有实施。" - Andreas Yankopolus
如果我有一个包含512个样本的向量,执行expr my_vec只会打印前255个元素。我该如何设置要显示的元素数量? - DEADBEEF
4
请问可以详细说明一下最后一个点,“template class std::vector<MyClass>”是如何帮助的吗?我尝试添加了类似的代码行,但出现了编译器错误。 - netskink
显示剩余2条评论

0

我也遇到了类似的问题:error: Couldn't lookup symbols:

我的解决方法是在源代码中明确使用所质疑的函数。

#include <vector>

template<typename T>
struct Vector : std::vector<T>
{
    Vector(size_t n)
    : std::vector<T>{n}
    {}

    T& operator[](size_t n)
    { return std::vector<T>::operator[](n); }
};

struct XXX
{
    int x;
};

void func()
{
    std::vector<XXX> a{10};
    Vector<XXX> b{10};

    auto x = b[0]; // gcc will produce an assembler code of operator[] for debug purpose
    1;  // as a break point
}

在第1行设置一个断点,然后运行它。

(lldb) p a[0]
error: Couldn't lookup symbols:
  __ZNSt3__16vectorI3XXXNS_9allocatorIS1_EEEixEm

(lldb) p b[0]
(XXX) $0 = (x = 0)

太棒了!这个函数在文本块中存在吗?

(lldb) image lookup -r -n 'XXX.*operator'
1 match found in /Users/xxx/Library/Developer/Xcode/DerivedData/xxx:
        Address: sandbox[0x00000001000011f0] (sandbox.__TEXT.__text + 256)
        Summary: sandbox`Vector<XXX>::operator[](unsigned long) at main.cpp:19

我不确定,但我之前学过这个。在调试阶段,而不是生产阶段。如果我们在模板的函数中的一行上设置断点,调试器会做什么?设置断点,实际上用陷阱或跳转替换一些现有的汇编代码,在应用模板的任何地方都要这样做吗?还是只在函数中设置一个断点?它被写成一个模板。因此,在生产阶段应该进行内联处理。然而,在调试阶段,该函数不会被内联处理,并且被写成普通函数。请不要简单地相信我在这里说的话。请自己确认。请查阅gcc、clang和lldb的文档。

MacOS 10.13.6Xcode Version 9.4.1中包含了_LIBCPP_INLINE_VISIBILITY宏:#include <vector>

template <class _Tp, class _Allocator>
inline _LIBCPP_INLINE_VISIBILITY
typename vector<_Tp, _Allocator>::reference
vector<_Tp, _Allocator>::operator[](size_type __n)
{
    _LIBCPP_ASSERT(__n < size(), "vector[] index out of bounds");
    return this->__begin_[__n];
}

_LIBCPP_INLINE_VISIBILITY#include <__config> 中被定义为:

#define _LIBCPP_INLINE_VISIBILITY __attribute__ ((__visibility__("hidden"), __always_inline__))

这些关键字hidden__always_inline__似乎控制着行为。

当我将inline _LIBCPP_INLINE_VISIBILITY添加到上面的示例解决方案代码中时:

    inline _LIBCPP_INLINE_VISIBILITY
    T& operator[](size_t n)
    { return std::vector<T>::operator[](n); }

导致了:

(lldb) p b[0]
error: Couldn't lookup symbols:
  __ZN6VectorI3XXXEixEm

我希望这能有所帮助,也希望有人能更深入地研究。


这种技术非常适用于自定义容器(而不是 STL),并且可以内联!只需将第一个通过[]运算符访问的元素强制转换为void即可。 - user10063119

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