web-dev-qa-db-ja.com

XCode / LLDBを使用したlibc ++ STLの印刷/デバッグ

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から有用な出力を得ることができましたか?

39
cjserio

[]std::vectorの演算子メソッドであるため、目的の式を出力するには、lldbが[]メソッドを呼び出せる必要があります。ここでの問題は、OS XのSTLは可能な限りすべてをインライン化することに積極的であり、同じ関数の行コピーから生成されるスペースを無駄にしないことです。これは最適化されたコードには適していますが、デバッガーに呼び出す[]演算子がないため、デバッグにはあまり適していません。それはあなたが見ているエラーメッセージです。

このベクター内の要素のみを表示する場合は、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> >) $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>

あなたのコードのどこかに。これは、この特殊化のために、すべてのテンプレート関数の行外コピーを出力するようコンパイラーに指示します。これは優れた一般的なソリューションではなく、デバッグビルドにのみ使用したいのですが、これらの関数を呼び出して複雑な式で使用することができます。

82
Jim Ingham

同様の問題が私にも発生します: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)

ビンゴ!!関数は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

よくわかりませんが、これは以前に学びました。実稼働段階ではなく、デバッグ段階。テンプレートの関数内の行にブレークポイントを設定した場合、デバッガーは何をしますか?ブレークポイントを設定し、実際にいくつかの既存のアセンブラーコードをトラップまたはジャンプに置き換えます。または、関数に単一のブレークポイントを設定するだけですか?テンプレートとして書かれています。したがって、生産段階でインライン化する必要があります。ただし、デバッグ段階では、関数はインライン化されず、通常の関数として記述されます。ここで言っていることを単純に信じないでください。ご自身で確認してください。 gcc,clang,およびlldb.のドキュメントを参照してください

#include <vector> 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

私はその助けと誰かがもっと深く調べることを願っています。

0
Tora