Printing/Debugging 带有 Xcode/LLDB 的 libc++ STL
Printing/Debugging libc++ STL with Xcode/LLDB
我正在尝试在 Xcode 8 中使用 LLDB 来调试非常基本的 STL。我曾经能够打印这样的矢量:
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 获得任何有用的输出?
[]
是 std::vector
上的运算符方法,因此要打印您想要的表达式,lldb 必须能够调用 []
方法。这里的问题是 OS X 上的 STL 积极内联它所能做的一切,而不是浪费 space 生成相同函数的外联副本。这对于优化代码非常有用,但对于调试却不太好,因为它使调试器无法调用 []
运算符。这就是您看到的错误消息。
如果您只想查看此向量中的元素,可以使用 lldb "STL data formatters" 为您完成这项工作。他们知道大多数 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> >) [=11=] = 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)
您甚至可以使用 frame var 的 -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
解决此问题进行调试的另一种方法 - 如果您使用的是 C++11 - 是放置:
template class std::vector<MyClass>
在您的代码中的某处。这将指示编译器为该专业化生成所有模板函数的外联副本。这不是一个很好的通用解决方案,您只想为调试版本执行此操作,但它确实允许您调用这些函数并在复杂表达式中使用它们。
类似的问题也发生在我身上: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) [=11=] = (x = 0)
宾果!!该函数是否存在于 TEXT 块中?
(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
我不确定,但我以前学过这个。在调试阶段,而不是生产阶段。如果我们在模板函数的一行上设置断点,调试器会做什么?设置断点,实际上用 trap 或 jump 替换一些现有的汇编代码,到处应用模板?或者只是在函数中设置一个断点?它被写成一个模板。所以它应该在生产阶段内联。然而,在调试阶段,该函数并未内联并作为普通函数编写。请不要简单地相信我在这里说的话。请自行确认。请参阅 gcc,
clang,
和 lldb.
的文档
#include <vector>
of MacOS 10.13.6, Xcode 9.4.1 版本有一个宏 _LIBCPP_INLINE_VISIBILITY
:
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
我希望能得到帮助,有人会更深入地研究。
我正在尝试在 Xcode 8 中使用 LLDB 来调试非常基本的 STL。我曾经能够打印这样的矢量:
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 获得任何有用的输出?
[]
是 std::vector
上的运算符方法,因此要打印您想要的表达式,lldb 必须能够调用 []
方法。这里的问题是 OS X 上的 STL 积极内联它所能做的一切,而不是浪费 space 生成相同函数的外联副本。这对于优化代码非常有用,但对于调试却不太好,因为它使调试器无法调用 []
运算符。这就是您看到的错误消息。
如果您只想查看此向量中的元素,可以使用 lldb "STL data formatters" 为您完成这项工作。他们知道大多数 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> >) [=11=] = 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)
您甚至可以使用 frame var 的 -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
解决此问题进行调试的另一种方法 - 如果您使用的是 C++11 - 是放置:
template class std::vector<MyClass>
在您的代码中的某处。这将指示编译器为该专业化生成所有模板函数的外联副本。这不是一个很好的通用解决方案,您只想为调试版本执行此操作,但它确实允许您调用这些函数并在复杂表达式中使用它们。
类似的问题也发生在我身上: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) [=11=] = (x = 0)
宾果!!该函数是否存在于 TEXT 块中?
(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
我不确定,但我以前学过这个。在调试阶段,而不是生产阶段。如果我们在模板函数的一行上设置断点,调试器会做什么?设置断点,实际上用 trap 或 jump 替换一些现有的汇编代码,到处应用模板?或者只是在函数中设置一个断点?它被写成一个模板。所以它应该在生产阶段内联。然而,在调试阶段,该函数并未内联并作为普通函数编写。请不要简单地相信我在这里说的话。请自行确认。请参阅 gcc,
clang,
和 lldb.
#include <vector>
of MacOS 10.13.6, Xcode 9.4.1 版本有一个宏 _LIBCPP_INLINE_VISIBILITY
:
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
我希望能得到帮助,有人会更深入地研究。