webentwicklung-frage-antwort-db.com.de

Libc ++ - STL mit XCode/LLDB drucken/debuggen

Ich versuche, LLDB in Xcode 8 zu verwenden, um sehr einfache STL zu debuggen. Ich war in der Lage, einen Vektor wie folgt zu drucken:

p myvector[0]

um zu sehen, was im ersten Vektorindex war. Wenn ich das mache, bekomme ich folgende Fehlermeldung:

error: Couldn't lookup symbols:
  __ZNSt3__16vectorI9my_classNS_9allocatorIS1_EEEixEm

Stattdessen muss ich Folgendes eingeben:

p myvector.__begin_[0]

um eine Ausgabe zu erhalten.

Ich habe versucht, die Skripte libcxx.py und unordered_multi.py aus dem LLDB-svn-Repository zu importieren.

Hat jemand mit libc ++ nützliche Ausgabe von LLDB bekommen?

36
cjserio

[] ist eine Operatormethode für std::vector. Um den gewünschten Ausdruck zu drucken, muss lldb die []-Methode aufrufen können. Das Problem hierbei ist, dass die STL unter OS X aggressiv ist, alles Mögliche zu inlinieren und keinen Platz zu verschwenden, der die Produktion von Funktionen außerhalb der Zeile verursacht. Das ist großartig für optimierten Code, aber nicht so gut für das Debuggen, da der Debugger keinen []-Operator aufrufen muss. Das ist die Fehlermeldung, die Sie sehen.

Wenn Sie nur die Elemente in diesem Vektor sehen möchten, können Sie die lldb "STL-Datenformatierer" verwenden, um diese Arbeit für Sie auszuführen. Sie wissen, wie die meisten STL-Typen angeordnet sind, und können die Elemente der meisten Containertypen drucken. Zum Beispiel:

(lldb) expr my_vec[0]
error: Couldn't lookup symbols:
  __ZNSt3__16vectorI3FooNS_9allocatorIS1_EEEixEm

aber:

(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)
}

Es gibt auch einen anderen Befehl "frame variable" , der statische Objekte untersuchen kann und in die Datenformatierer einhakt. Es kann keine Funktionen aufrufen und keine anderen komplexeren Parseraufgaben für Ausdrucke ausführen, aber es kann mit den STL-Datenformatierern einzelne Elemente abgerufen werden:

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

Sie können sogar die -L-Option von frame var verwenden, um die Elemente des Vektors zu lokalisieren, und dann können Sie die Adresse umwandeln, um sie an andere Funktionen zu übergeben:

(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

Eine andere Möglichkeit, dieses Problem beim Debuggen zu umgehen - wenn Sie C++ 11 verwenden - besteht darin, Folgendes anzugeben:

template class std::vector<MyClass>

irgendwo in deinem Code. Dadurch wird der Compiler angewiesen, Out-of-Line-Kopien aller Vorlagenfunktionen für diese Spezialisierung auszugeben. Dies ist keine großartige allgemeine Lösung, und Sie möchten dies nur für Debugbuilds tun, aber Sie können diese Funktionen aufrufen und in komplexen Ausdrücken verwenden.

77
Jim Ingham

Das ähnliche Problem tritt auch bei mir auf: error: Couldn't lookup symbols:

Meine Lösung ist, die fragliche Funktion irgendwo in einem Quellcode explizit zu verwenden.

#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
}

Setzen Sie einen Haltepunkt in der Zeile 1; und führe es aus.

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

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

Bingo!! Existiert die Funktion in einem TEXT-Block?

(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

Ich bin nicht sicher, aber ich hatte das schon vorher gelernt. In einer Debugging-Phase anstelle der Produktionsphase. Wenn wir einen Haltepunkt in einer Zeile in einer Funktion einer Vorlage setzen, was würde ein Debugger tun? Haltepunkte setzen, tatsächlich vorhandenen Assembler-Code durch Trap oder Jump ersetzen, hier und dort, wo die Vorlage angewendet wird? Oder einfach nur einen Haltepunkt in einer Funktion setzen? Es ist als Vorlage geschrieben. Es sollte also in einer Produktionsphase festgelegt werden. In einer Debugging-Phase wird die Funktion jedoch nicht als normale Funktion eingebettet und geschrieben. Bitte glaube nicht einfach, was ich hier sage. Bitte bestätigen Sie es selbst. Siehe Dokumentation von gcc,clang, und lldb.

#include <vector> von MacOS 10.13.6, Xcode Version 9.4.1 hat ein Makro _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];
}

Der _LIBCPP_INLINE_VISIBILITY ist in #include <__config> definiert als:

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

Solche Schlüsselwörter hidden und __always_inline__ scheinen das Verhalten zu steuern.

Wenn ich inline _LIBCPP_INLINE_VISIBILITY zum obigen Beispielcode hinzugefügt habe:

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

führte zu:

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

Ich hoffe, dass diese Hilfe und jemand viel tiefer in die Sache hineinschauen.

0
Tora