web-dev-qa-db-ja.com

LLDBの配列の表示:Xcode 4.1のGDBの「@」演算子に相当

ポインターが指す要素の配列を表示したいと思います。 GDBでは、これは、演算子「@」を次のように使用して、指定されたメモリを指定された長さの人工配列として扱うことで実行できます。

*pointer @ length

ここで、lengthは表示したい要素の数です。

上記の構文は、Xcode 4.1で提供されるLLDBでは機能しません。

LLDBで上記を達成する方法はありますか?

71
midinastasurazz

実際には、ポインターを配列へのポインターにキャストすることにより、それを行う簡単な方法があります。

たとえば、int* ptrがあり、それを10個の整数の配列として表示する場合、次のようにできます。

p *(int(*)[10])ptr

標準のC機能のみに依存しているため、このメソッドはプラグインや特別な設定なしで機能します。 GDBやCDBなどの他のデバッガーでも同様に機能しますが、配列を印刷するための特殊な構文もあります。

119
Siyuan Ren

Xcode 8.0のlldb以降、新しい組み込みparrayコマンドがあります。だからあなたは言うことができます:

(lldb) parray <COUNT> <EXPRESSION>

EXPRESSIONの結果が指すメモリを、式が指す型のCOUNT要素の配列として出力します。

現在のフレームで使用可能な変数にカウントが保存されている場合、次のことができることを忘れないでください。

(lldb) parray `count_variable` pointer_to_malloced_array

これはlldbの一般的な機能です。バッククォートで囲まれたlldbのコマンドライン引数は、整数を返す式として評価され、コマンド実行前に整数が引数に置き換えられます。

29
Jim Ingham

私が見つけた唯一の方法は、Pythonスクリプトモジュール:

""" File: parray.py """
import lldb
import shlex

def parray(debugger, command, result, dict):
    args = shlex.split(command)
    va = lldb.frame.FindVariable(args[0])
    for i in range(0, int(args[1])):
        print va.GetChildAtIndex(i, 0, 1)

Lldbでコマンド「parray」を定義します。

(lldb) command script import /path/to/parray.py
(lldb) command script add --function parray.parray parray

これで、「parray 可変長」を使用できます。

(lldb) parray a 5
(double) *a = 0
(double) [1] = 0
(double) [2] = 1.14468
(double) [3] = 2.28936
(double) [4] = 3.43404
26
Martin R

Xcode 4.5.1(これはあなたを助けるかもしれませんが)で、lldbコンソールでこれを行うことができます:

(lldb) type summary add -s "${var[0-63]}" "float *"
(lldb) frame variable pointer
  (float *) pointer = 0x000000010ba92950 [0.0,1.0,2.0,3.0, ... ,63.0]

この例では、「ポインター」が64個のfloatの配列であると想定しています。float pointer[64];

15
davidA

Martin Rの回答から始めて、次のように改善しました。

  1. ポインターが単純な変数ではない場合、例えば:

    struct {
      int* at;
      size_t size;
    } a;
    

    次に、「parray a.at 5」が失敗します。

    「FindVariable」を「GetValueForVariablePath」に置き換えることでこれを修正しました。

  2. 配列内の要素が集合体である場合、たとえば:

    struct {
      struct { float x; float y; }* at;
      size_t size;
    } a;
    

    次に、「parray a.at 5」が出力されます。GetChildAtIndex()がメンバーを返すため、a.at-> x、a.at-> y、a.at [2]、a.at [3]、a.at [4]が出力されます。集合体の。

    「a.at」を解決してからその子を取得するのではなく、ループ内で「a.at」+「[」+ str(i)+「]」を解決することでこれを修正しました。

  3. オプションの「最初の」引数(使用法:parray [FIRST] COUNT)が追加されました。これは、膨大な数の要素がある場合に役立ちます。

  4. Initで「コマンドスクリプトadd -f parray.parray parray」を実行しました

変更したバージョンは次のとおりです。

import lldb
import shlex

def parray(debugger, command, result, dict):
  args = shlex.split(command)
  if len(args) == 2:
    count = int(args[1])
    indices = range(count)
  Elif len(args) == 3:
    first = int(args[1]), count = int(args[2])
    indices = range(first, first + count)
  else:
    print 'Usage: parray ARRAY [FIRST] COUNT'
    return
  for i in indices:
    print lldb.frame.GetValueForVariablePath(args[0] + "[" + str(i) + "]")

def __lldb_init_module(debugger, internal_dict):
  debugger.HandleCommand('command script add -f parray.parray parray')
12
jng

まだサポートされていないようです。

次のようなメモリ読み取り機能(メモリ読み取り/ x)を使用できます。

(lldb) memory read -ff -c10 `test`

そのポインターからフロートを10回印刷します。これは、gdbの@と同じ機能でなければなりません。

12
w-m

コメントを追加しようとしましたが、完全な回答を投稿するのには向いていなかったので、自分で回答しました。これにより、「値なし」を取得することで問題が解決します。 lldb.frameはモジュールのインポート時に設定されるため、.lldbinitからモジュールをロードする場合、ブレークポイントで停止したときに現在のフレームが存在しないと思われるため、現在のフレームを取得する必要があります。ブレークポイントで停止したときにスクリプトをインポートまたは再ロードすると、他のバージョンが機能します。以下のバージョンは常に動作するはずです。

import lldb
import shlex

@lldb.command('parray', 'command script add -f parray.parray parray')
def parray(debugger, command, result, dict):

    target = debugger.GetSelectedTarget()
    process = target.GetProcess()
    thread = process.GetSelectedThread()
    frame = thread.GetSelectedFrame()

    args = shlex.split(command)
    if len(args) == 2:
        count = int(args[1])
        indices = range(count)
    Elif len(args) == 3:
        first = int(args[1])
        count = int(args[2])
        indices = range(first, first + count)
    else:
        print 'Usage: parray ARRAY [FIRST] COUNT'
        return

    for i in indices:
        print frame.GetValueForVariablePath(args[0] + "[" + str(i) + "]")
4
Dave Reed

その時点で、独自のカスタムC関数を作成し、次のコマンドで呼び出すこともできます。

call (int)myprint(args)
1
Elektraglide

変数を検査するには、frame variableコマンド(fr vは最短の一意のプレフィックスです)-Z必要なことを正確に行うフラグ:

(lldb) fr v buffer -Z5
(int64_t *) buffer = 0x000000010950c000 {
  (int64_t) [0] = 0
  (int64_t) [1] = 0
  (int64_t) [2] = 0
  (int64_t) [3] = 0
  (int64_t) [4] = 0
}

残念ながらexpressionはそのフラグをサポートしていません

0
Holger