Impresión/depuración de libc++ STL con XCode/LLDB
(2)
Estoy intentando usar LLDB dentro de Xcode 8 para depurar STL muy básico. Solía poder imprimir un vector como este:
p myvector[0]
Para ver lo que haya en el primer índice vectorial. Ahora cuando hago eso, me sale este error:
error: Couldn''t lookup symbols:
__ZNSt3__16vectorI9my_classNS_9allocatorIS1_EEEixEm
En su lugar, tengo que escribir esto:
p myvector.__begin_[0] in order to get any output.
Intenté importar los scripts libcxx.py y unordered_multi.py desde el repositorio svn de LLDB, pero eso no parece cambiar nada.
¿Alguien ha podido obtener algún resultado útil de LLDB con libc ++?
El problema similar también ocurre conmigo: error: Couldn''t lookup symbols:
Mi solución es usar explícitamente la función cuestionada en algún lugar del código fuente.
#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
}
Establecer un punto de interrupción en la línea de 1; y ejecutarlo.
(lldb) p a[0]
error: Couldn''t lookup symbols:
__ZNSt3__16vectorI3XXXNS_9allocatorIS1_EEEixEm
(lldb) p b[0]
(XXX) $0 = (x = 0)
¡¡Bingo!! ¿Existe la función en un bloque de texto?
(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
No estoy seguro, pero había aprendido esto antes. En una etapa de depuración, en lugar de la etapa de producción. Si establecemos un punto de interrupción en una línea en una función de una plantilla, ¿qué haría un depurador? ¿Establecer puntos de interrupción, en realidad reemplazar algún código de ensamblador existente con trampa o salto, aquí y allá en todas partes donde se aplica la plantilla? ¿O simplemente estableciendo un único punto de interrupción en una función? Está escrito como una plantilla. Por lo tanto, debe estar en línea en una etapa de producción. En una etapa de depuración, sin embargo, la función no está en línea y escrita como una función normal. Por favor no solo crea lo que digo aquí. Por favor confirme por usted mismo. Consulte la documentación de gcc,
clang,
y lldb.
#include <vector>
de MacOS 10.13.6, Xcode Versión 9.4.1 tiene una macro _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];
}
La _LIBCPP_INLINE_VISIBILITY
se define en #include <__config>
como:
#define _LIBCPP_INLINE_VISIBILITY __attribute__ ((__visibility__("hidden"), __always_inline__))
Tales palabras clave hidden
y __always_inline__
parecen controlar el comportamiento.
Cuando agregué en inline _LIBCPP_INLINE_VISIBILITY
al código de solución de ejemplo anterior:
inline _LIBCPP_INLINE_VISIBILITY
T& operator[](size_t n)
{ return std::vector<T>::operator[](n); }
resultó en:
(lldb) p b[0]
error: Couldn''t lookup symbols:
__ZN6VectorI3XXXEixEm
Espero que la ayuda y que alguien mire mucho más profundamente.
[]
es un método de operador en std::vector
, por lo que para imprimir la expresión que desee, lldb tendría que poder llamar al método []
. El problema aquí es que el STL en OS X es agresivo en cuanto a incorporar todo lo que puede, y no perder espacio produciendo copias fuera de línea de las mismas funciones. Eso es genial para el código optimizado, pero no tan bueno para la depuración porque deja al depurador sin que el operador []
llame. Ese es el mensaje de error que estás viendo.
Si solo desea ver los elementos en este vector, puede usar los "formateadores de datos STL" de lldb para hacer este trabajo por usted. Saben cómo se distribuyen la mayoría de los tipos de STL y pueden imprimir los elementos de la mayoría de los tipos de contenedores. Por ejemplo:
(lldb) expr my_vec[0]
error: Couldn''t lookup symbols:
__ZNSt3__16vectorI3FooNS_9allocatorIS1_EEEixEm
pero:
(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)
}
También hay otro comando "variable de cuadro" que puede inspeccionar objetos estáticos y enganchar a los formateadores de datos. No puede llamar a funciones y realizar otras tareas de análisis de expresiones más complejas, pero sabe cómo usar los formateadores de datos STL para recuperar elementos individuales:
(lldb) frame var my_vec[1]
(Foo) my_vec[1] = (var1 = 10, var2 = 20)
Incluso puede usar la opción de var de marco var para ubicar los elementos del vector, y luego puede convertir la dirección para pasarla a otras funciones:
(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
Otra forma de solucionar esto para la depuración, si está utilizando C ++ 11, es poniendo:
template class std::vector<MyClass>
en su código en alguna parte. Eso le indicará al compilador que emita copias fuera de línea de todas las funciones de la plantilla para esta especialización. Esa no es una gran solución general, y solo desea hacerlo para compilaciones de depuración, pero le permite llamar a estas funciones y usarlas en expresiones complejas.