我想查看一个指针指向的元素数组。在 GDB 中,这可以通过将指向的内存视为给定长度的人工数组来完成,使用运算符“@”作为
*pointer @ length
length
我要查看的元素数量在哪里。
上述语法在 Xcode 4.1 提供的 LLDB 中不起作用。
有什么方法可以在 LLDB 中完成上述操作?
在 lldb 中有两种方法可以做到这一点。
最常见的是,您使用parray
lldb 命令,该命令采用 aCOUNT
和一个EXPRESSION
; EXPRESSION
被评估并且应该产生一个指向内存的指针。然后 lldb 将COUNT
在该地址打印该类型的项目。例如
parray 10 ptr
哪里ptr
是类型int *
。
或者,可以通过将指针转换为指向数组的指针来完成。
例如,如果您有一个int* ptr
,并且您想将其视为一个由十个整数组成的数组,您可以这样做
p *(int(*)[10])ptr
因为它仅依赖于标准 C 功能,所以此方法无需任何插件或特殊设置即可工作。它同样适用于 GDB 或 CDB 等其他调试器,即使它们也有用于打印数组的专用语法。
从 Xcode 8.0 中的 lldb 开始,有一个新的内置 parray 命令。所以你可以说:
(lldb) parray <COUNT> <EXPRESSION>
将结果指向的内存打印为表达式指向的类型EXPRESSION
的元素数组。COUNT
如果计数存储在当前帧中可用的变量中,请记住您可以执行以下操作:
(lldb) parray `count_variable` pointer_to_malloced_array
这是一个通用的 lldb 功能,在 lldb 中用反引号括起来的任何命令行参数都被评估为一个返回整数的表达式,然后在命令执行之前整数被替换为参数。
我发现的唯一方法是通过 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
现在您可以使用“数组变长”:
(lldb) parray a 5
(double) *a = 0
(double) [1] = 0
(double) [2] = 1.14468
(double) [3] = 2.28936
(double) [4] = 3.43404
使用 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];
好像还不支持。
您可以使用内存读取功能(内存读取/ x),如
(lldb) memory read -ff -c10 `test`
从该指针打印十次浮点数。这应该与 gdb 的 @ 功能相同。
从 Martin R 的回答开始,我对其进行了如下改进:
如果指针不是一个简单的变量,例如:
struct {
int* at;
size_t size;
} a;
然后“parray a.at 5”失败。
我通过用“GetValueForVariablePath”替换“FindVariable”来解决这个问题。
现在,如果您的数组中的元素是聚合的,例如:
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),这在您拥有大量元素时很有用。
让它在初始化时执行“命令脚本添加 -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')
我尝试添加评论,但这对于发布完整答案并不好,所以我做出了自己的答案。这解决了获得“无价值”的问题。您需要获取当前帧,因为我相信 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) + "]")
要检查变量,您可以使用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
的是不支持该标志
那时,您不妨编写自己的自定义 C 函数并使用以下命令调用它:
call (int)myprint(args)