【问题标题】:LLDB Python access of iOS variables?iOS变量的LLDB Python访问?
【发布时间】:2012-10-01 07:04:13
【问题描述】:

作为调试可能与我的 UIVIews 相关的问题的一部分,我想编写一个 Python 脚本以从 LLDB 运行。我曾想过在断点和所有视图子项中提取视图的所有设置,以允许我比较状态。我查看了有关该主题的 WWDC 视频,然后花时间阅读 lldb.llvm.org/scripting.html 上的内容,但没有发现它们很有帮助。在网络上搜索示例并没有发现与这些有本质区别的内容。

我的问题是我试图弄清楚如何在断点处访问 iOS 变量。我见过的示例执行转换数字和模拟 shell 命令之类的操作。有趣的东西,但对我的目的没有用。我一直在使用“脚本帮助(lldb.SBValue)”等来阅读帮助信息,但是由于结果很大并且不清楚使用模式是什么,所以进展缓慢。我觉得如何遍历几个 iOS 对象的一个​​不错的例子可以帮助我理解系统。有谁知道或者可以分享一段代码?

更新:

我写这篇文章是为了帮助我找出我的 UIView 使用中的一个错误。我想做更多的工作来完善它,看看我是否可以显示整个视图树,但这足以解决我的问题,所以我将它放在这里以节省其他人一些时间。

import lldb
max_depth = 6
filters = {'_view':'UIView *', '_layer':'CALayer *', '_viewFlags':'struct'}

def print_value(var, depth, prefix):
    """ print values and recurse """
    global max_depth
    local_depth = max_depth - depth
    pad = ' ' * local_depth
    name = var.GetName()
    typ = str(var.GetType()).split('\n')[0].split('{')[0].split(':')[0].strip()

    found = name in filters.keys() # only visit filter items children
    if found:
        found = (filters.get(name) == typ)

    value = var.GetValue()
    if value is None or str(value) == '0x00000000':
        value = ''
    else:
        value = ' Val: %s' % value

    if var.GetNumChildren() == 0 and var.IsInScope():
        path = lldb.SBStream()
        var.GetExpressionPath(path)
        path = ' pathData: %s' % path.GetData()
    else:
        path = ''

    print '^' * local_depth, prefix, ' Adr:', var.GetAddress(), ' Name:', name, ' Type:', typ, value, path

    if var.GetNumChildren() > 0:
        if local_depth < 2 or found:
            print pad, var.GetNumChildren(), 'children, to depth', local_depth + 1
            counter = 0
            for subvar in var:
                subprefix = '%d/%d' % (counter, var.GetNumChildren())
                print_value(subvar, depth - 1, subprefix)
                counter += 1

def printvh (debugger, command_line, result, dict):
    """ print view hierarchy """
    global max_depth
    args = command_line.split()
    if len(args) > 0:
        var = lldb.frame.FindVariable(args[0])
        depth = max_depth
        if len(args) > 1:
            depth = int(args[1])
            max_depth = depth
        print_value(var, depth, 'ROOT')
    else:
        print 'pass a variable name and optional depth'

我在 .lldbinit 中添加了以下内容:

script import os, sys
# So that files in my dir takes precedence.
script sys.path[:0] = [os.path.expanduser("~/lldbpy")]
script import views
command script add -f views.printvh printvh

这样我就可以在 LLDB 提示符下键入“printvh self 3”。

【问题讨论】:

    标签: ios lldb


    【解决方案1】:

    也许这会有所帮助。下面是一个示例,说明如何在遇到断点时转储简单的局部变量。我没有正确显示 char* 数组,我不确定我应该如何获取这些数据以显示它,就像“帧变量”会显示它一样,但我会在稍后有空闲时间时弄清楚这一点。

    struct datastore {
      int val1;
      int val2;
      struct {
         int val3;
      } subdata;
      char *name;
    };
    
    int main (int argc, char **argv)
    {
      struct datastore data = {1, 5, {3}, "a string"};
      return data.val2;
    }
    
    Current executable set to 'a.out' (x86_64).
    (lldb) br se -l 13
    Breakpoint created: 1: file ='a.c', line = 13, locations = 1
    (lldb) br comm add -s python
    Enter your Python command(s). Type 'DONE' to end.
    > def printvar_or_children(var):
    >   if var.GetNumChildren() == 0 and var.IsInScope():
    >     path = lldb.SBStream()
    >     var.GetExpressionPath(path)
    >     print '%s: %s' % (path.GetData(), var.GetValue())
    >   else: 
    >     for subvar in var:
    >       printvar_or_children(subvar)
    > 
    > print 'variables visible at breakpoint %s' % bp_loc
    > for var in frame.arguments:
    >   printvar_or_children(var)
    > for var in frame.locals:
    >   printvar_or_children(var)
    > 
    > DONE
    (lldb) r
    variables visible at breakpoint 1.1: where = a.out`main + 51 at a.c:13, address = 0x0000000100000f33, resolved, hit count = 1 
    argc: 1
    *(*(argv)): '/'
    data.val1: 1
    data.val2: 5
    data.subdata.val3: 3
    *(data.name): 'a'
    Process 84865 stopped
    * thread #1: tid = 0x1f03, 0x0000000100000f33 a.out`main + 51 at a.c:13, stop reason = breakpoint 1.1
        frame #0: 0x0000000100000f33 a.out`main + 51 at a.c:13
       10   int main (int argc, char **argv)
       11   {
       12     struct datastore data = {1, 5, {3}, "a string"};
    -> 13     return data.val2;
    (lldb)
    

    提示 - 出于理智考虑,我在侧面文本编辑器中处理了 python,并在实验时将其粘贴到 lldb 中。

    如果您使用 lldb 中的帧变量命令在给定的停止位置探索变量,这与您可以通过提供给“帧”对象中的断点 python 命令的 SBFrame 访问它们的基本方式相同。

    希望对您有所帮助。

    【讨论】:

    • 谢谢,这确实让我开始了。我认为我需要深入研究类型表示并弄清楚如何区分我感兴趣的事物和我想忽略的事物。我第一次觉得自己的脚踩在了门上。
    • 除了使用“frame variable”在lldb中的特定位置导航你的变量,你还可以使用交互式python模式——在lldb控制台输入“script”进入模式(空行上的 control-D 退出)。您可以将当前帧获取为“lldb.frame”,其他一切都如上所示。 NB 脚本模式显然可以在 Xcode 中锁定(有时?总是?我不肯定)所以如果你正在对一些 python 进行原型设计,你可能希望在探索 SBValue 等对象时使用命令行 lldb。
    • 对,我可以在 LLDB 的 python 控制台中测试一些东西,但这是一个很大的痛苦,因为光标键不起作用。我发现它更容易使用:“script reload(module)”并运行命令,尽管有时第一次调用会失败。获取您的脚本并为类型添加一些过滤,我可以很好地显示我需要的内容。但是,我还没有弄清楚如何从 ViewController 的 _view 遍历到子视图。有人吗?
    • 感谢 Jason,sn-p 帮了大忙!
    【解决方案2】:

    您是否尝试查看存储在以下位置的 python LLDB 格式化模板:

    XCode.app/Contents/SharedFrameworks/LLDB.framework/Resources/Python/lldb/formatters/objc
    

    【讨论】:

    • 我已经浏览了它们,但它们似乎并没有解决我面临的问题。但是,看看这些是如何构建并添加到系统中的,这很有用,谢谢!
    猜你喜欢
    • 1970-01-01
    • 2012-11-29
    • 1970-01-01
    • 1970-01-01
    • 2022-08-11
    • 2010-11-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多