LLDB中的视图数组:与Xcode 4.1中GDB的'@'运算符等效


78

我想查看一个指针指向的元素数组。在GDB中,可以通过使用操作符'@'将指向的内存视为给定长度的人工数组来完成。

*pointer @ length

length我要查看的元素数量在哪里。

上面的语法在Xcode 4.1随附的LLDB中不起作用。

有什么方法可以在LLDB中完成上述工作吗?


1
将近一年后,lldb中似乎仍然没有这种功能(我正在将LLDB-112.2与Xcode 4.3.3配合使用)-增添了一笔赏金,希望有人能提出一个可用的解决方法(除了返回gdb之外)。
Paul R

Answers:


138

在lldb中,有两种方法可以做到这一点。

最常见的是,您使用parraylldb命令,该命令使用aCOUNT和an EXPRESSION; EXPRESSION被评估并且应该导致指向内存的指针。lldb然后将COUNT在该地址打印该类型的项目。例如

parray 10 ptr

哪里ptr是类型int *

或者,可以通过将指针转换为指向数组的指针来完成此操作。

例如,如果您有一个int* ptr,并且想要将其查看为十个整数的数组,则可以执行

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

由于此方法仅依赖于标准C功能,因此无需任何插件或特殊设置即可使用。它也可以与其他调试器(例如GDB或CDB)一起使用,即使它们也具有用于打印数组的专用语法。


3
这是一个很好的答案-它值得更多的投票。无需自定义脚本或其他任何东西,它甚至可以与结构一起使用。
比尔

22
对于那些使用Xcode GUI的指针仅显示第一个数据元素的用户,请执行以下操作:right click on data pointer > View value as... > Custom Type...在expression字段put中*(double(*)[10])value_type。这将打印出所指向的10个值。您可以将double和10修改为所需的类型/数量。
安德鲁·洪特,2015年

感谢@AndrewHundt提供与GUI相关的帮助。那正是我想要的。
weezma2004

@ weezma2004如果您可以对评论进行投票,我将不胜感激:-) @ Siyuan Ren也许该信息可以纳入您的答案?
Andrew Hundt 2015年

@AndrewHundt完成。直到现在,您甚至都不知道您可以对评论进行投票。:)
weezma2004

35

从Xcode 8.0中的lldb开始,有一个新的内置parray命令。所以你可以说:

(lldb) parray <COUNT> <EXPRESSION>

将由结果指向的内存打印EXPRESSION为数组COUNT将表达式为表达式指向的类型元素。

如果计数存储在当前帧中可用的变量中,请记住您可以执行以下操作:

(lldb) parray `count_variable` pointer_to_malloced_array

这是lldb的常规功能,在lldb中用反引号括起来的任何命令行参数都将被评估为返回整数的表达式,然后在执行命令之前将整数替换为该参数。


有没有一种方法可以永久设置此变量,因此我不必每次运行应用程序时都将其输入lldb命令提示符中?
MarcusJ

不太清楚你的意思。如果您有lldb命令,则希望多次使用逐字记录,您可以使用它command alias来创建快捷方式。
Jim Ingham

28

我发现的唯一方法是通过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

2
提示:如果你需要做一些修改,键入“脚本重装(粒子阵列)”之后重新加载脚本(参见libertypages.com/clarktech/?p=4303
拉菲

@拉菲:谢谢你的提示。而且,至于lldb / Python信息的每个链接(如果有价值),因为官方文档仍然有限。
Martin R

1
@MartinR,因为在我的实验中,值“ a”必须是存在于堆栈框架中的直接指针,并且如果其为任何类型的表达式均不起作用。(例如,指针投射,应用偏移等)
NoahR 2014年

当我尝试在结构中打印数组时,我得到AttributeError: 'NoneType' object has no attribute 'FindVariable'
fpg1503,2016年

15

使用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];


2
我在那里真的什么都不懂,但是它很有用,非常有帮助!您从哪里学到这么棒的lldb技巧?
弥敦道

从现在开始打印的所有float *不会显示为64个元素的数组吗?
uliwitness

是的,它确实。您可以在不再需要类型摘要时将其删除。仍然比仅看到第一个价值更好。
davidA

13

从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”:a.at-> x,a.at-> y,a.at [2],a.at [3],a.at [4],因为GetChildAtIndex()返回成员集料。

    我通过在循环内部解析“ a.at” +“ [” + str(i)+“]”来解决此问题,而不是解析“ a.at”,然后获取其子级。

  3. 添加了一个可选的“ first”参数(用法:parray [FIRST] COUNT),该参数在您具有大量元素时非常有用。

  4. 使它在初始化时执行“命令脚本添加-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(或Python)要求对first和count的分配位于单独的行上。除此之外,这很好用!谢谢你!
Kaelin Colclasure

我花了一个小时来使Martin R适应我的具体情况,感谢GetValueForVariablePath提示!
拉菲2013年

伟大的尝试,非常有用。对于大多数感兴趣的指针表达式,我正在GetValueForVariablePath返回No Value。我在Xcode 5.0中使用lldb-300.2.47。对于int array[8],在按预期方式工作时parry array 8返回No Value八次print array[0]
NoahR 2013年

1
我相信问题在于lldb.frame是在模块导入时设置的,因此,您需要使用命令来获取当前帧:target = debugger.GetSelectedTarget()process = target.GetProcess()thread = process.GetSelectedThread()frame = thread.GetSelectedFrame(),然后使用frame.GetValueForVariablePath而不是lldb.frame.GetValueForVariablePath
Dave Reed

@DaveReed的以上评论解决了部分问题。简单的指针用法开始起作用。(当前帧中的指针变量,无类型转换或算术运算)。我想做更复杂的表达,所以我改了GetValueForVariablePathEvaluateExpression因为我仍然在看No value。现在,像这样的指针表达作品:parray ((double*)sourcePointer+1) 5。根据API文档,这两个函数的返回类型相同,因此EvaluateExpression似乎是更好的方法。
NoahR 2014年

12

似乎尚不支持。

您可以使用内存读取功能(内存读取/ x),例如

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

从该指针打印浮点数十次。此功能应与gdb的@相同。


2
您可以使用反引号来计算指针表达式,例如:(lldb) memory read -ff -c10 `test`
pmdj

1
这应该是公认的答案!这很容易并且可以直接使用
wxs

1
并保存一些键入内容x/10f test
wardw

5

我试图添加评论,但这对于发布完整答案不是很好,所以我做出了自己的答案。这解决了获得“无价值”的问题。您需要获取当前帧,因为我相信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) + "]")

哎呀。在看到您的答案之前先对您的评论发表评论。这样,便可以使用简单的指针。(当前帧中的指针变量,无类型转换或算术运算)。我想做更复杂的表达式,所以我将GetValueForVariablePath更改为EvaluateExpression,因为我仍然没有看到值。现在,类似这样的指针表达式起作用了:parray((double *)sourcePointer + 1)5.每个函数的返回类型在API文档中都是相同的,因此EvaluateExpression似乎是更好的选择。你同意吗?
NoahR 2014年

好吧,其中一个区别是的输出EvaluateExpression分配给lldb变量,并且不打印数组索引。因此,输出如下所示:(double) $68 = 0
NoahR 2014年

1
@ dave-reed,如何将该脚本安装或附加到lldb?我应该将其保存在某个地方,然后添加到.lldbinit吗?
Shmidt

3

要检查变量,您可以使用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是不支持该标志


2

好了,您最好编写自己的自定义C函数并使用以下命令调用它:

call (int)myprint(args)

并非如此-您可以将Python版本实时添加到LLDB会话中,而不必重新启动程序并重现错误。
比尔
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.