Просмотр массива в LLDB: эквивалент оператора GDB '@' в Xcode 4.1

Я хотел бы просмотреть массив элементов, на которые указывает указатель. В GDB это можно сделать, рассматривая остроконечную память как искусственный массив заданной длины, используя оператор '@' как

*pointer @ length

где length - количество элементов, которые я хочу просмотреть.

Вышеупомянутый синтаксис не работает в LLDB, поставляемом с Xcode 4.1.

Есть ли способ выполнить описанное выше в LLDB?

Ответ 1

На самом деле есть простой способ сделать это, наведя указатель на указатель на массив.

Например, если у вас есть int* ptr, и вы хотите просмотреть его как массив из десяти целых чисел, вы можете сделать

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

Поскольку он использует только стандартные функции C, этот метод работает без каких-либо плагинов или специальных настроек. Он также работает с другими отладчиками, такими как GDB или CDB, хотя они также имеют специализированные синтаксисы для печати массивов.

Ответ 2

Начиная с lldb в Xcode 8.0, появляется новая встроенная команда parray. Поэтому вы можете сказать:

(lldb) parray <COUNT> <EXPRESSION>

чтобы напечатать память, на которую указывает результат EXPRESSION, в виде массива элементов COUNT типа, на который указывает выражение.

Если счетчик хранится в переменной, доступной в текущем кадре, помните, что вы можете сделать:

(lldb) parray `count_variable` pointer_to_malloced_array

Для общей функции lldb любой аргумент командной строки в lldb, окруженный обратными циклами, оценивается как выражение, которое возвращает целое число, а затем целое число заменяется аргументом перед выполнением команды.

Ответ 3

Единственный способ, которым я нашел, - это использовать скриптовый модуль 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)

Определите команду "parray" в lldb:

(lldb) command script import /path/to/parray.py
(lldb) command script add --function 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

Ответ 4

С 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 pointer[64];

Ответ 5

Он пока не поддерживается.

Вы можете использовать функцию чтения памяти (чтение/чтение памяти), например

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

чтобы напечатать поплавок десять раз с этого указателя. Это функции должны быть такими же, как gdb @.

Ответ 6

Начиная с ответа Martin R, я улучшил его следующим образом:

  • Если указатель не является простой переменной, например:

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

    Затем "parray a.at 5" терпит неудачу.

    Я исправил это, заменив "FindVariable" на "GetValueForVariablePath".

  • Теперь, если элементы в вашем массиве являются агрегатами, например:

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

    Затем "parray a.at 5" печатает: a.at- > x, a.at- > y, a.at [2], a.at [3], a.at [4], потому что GetChildAtIndex ( ) возвращает элементы агрегатов.

    Я исправил это, разрешив "a.at" + "[" + str (i) + "]" внутри цикла вместо разрешения "a.at", а затем извлекая его дочерние элементы.

  • Добавлен необязательный "первый" аргумент (использование: parray [FIRST] COUNT), что полезно, когда у вас есть огромное количество элементов.

  • Сделал это командой "script добавить -f parray.parray parray" в init

Вот моя измененная версия:

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')

Ответ 7

Я попытался добавить комментарий, но это было не очень удобно для публикации полного ответа, поэтому я сделал свой собственный ответ. Это решает проблему с получением "Нет значения". Вам нужно получить текущий фрейм, поскольку я полагаю, что lldb.frame установлен во время импорта модуля, поэтому он не имеет текущего кадра, когда вы останавливаетесь в точке останова, если вы загружаете модуль из .lldbinit. Другая версия будет работать, если вы импортируете или перезагрузите script, когда остановитесь в точке останова. Следующая версия должна всегда работать.

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) + "]")

Ответ 8

Хорошо в этот момент вы можете написать свою собственную функцию C и вызвать ее с помощью:

call (int)myprint(args)

Ответ 9

Для проверки переменных вы можете использовать команду 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 не поддерживает этот флаг