Просмотр массива в 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
не поддерживает этот флаг