LLDB Python对iOS变量的访问?

LLDB Python对iOS变量的访问?,ios,lldb,Ios,Lldb,作为调试可能与UIView相关的问题的一部分,我想编写一个从LLDB运行的python脚本。我曾想过提取断点中视图的所有设置和所有视图子级,以便比较状态。我查看了WWDC关于这个主题的视频,然后花时间在lldb.llvm.org/scripting.html上阅读了一些内容,但没有发现它们有什么帮助。通过网络搜索示例,结果与这些示例没有本质上的区别 我的问题是,我试图找出如何在断点处访问iOS变量。我所看到的例子做了一些事情,比如转换数字和模拟shell命令。有趣的东西,但对我的目的没有用处。我

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

我的问题是,我试图找出如何在断点处访问iOS变量。我所看到的例子做了一些事情,比如转换数字和模拟shell命令。有趣的东西,但对我的目的没有用处。我一直在阅读“脚本帮助(lldb.SBValue)”之类的帮助信息,但进展缓慢,因为结果非常巨大,而且不清楚使用模式是什么。我觉得一个关于如何遍历几个iOS对象的好例子可以帮助我理解这个系统。有人知道一个或可以共享一段代码吗

更新:

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

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'

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

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

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

也许这会有帮助。下面是一个示例,说明如何在遇到断点时转储简单的局部变量。我没有正确地显示char*数组,我不确定应该如何获取这些数组的数据,以便像“frame variable”那样显示它,但我会在以后有空的时候解决这个问题

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中使用frame variable命令在给定的停止位置探索变量,这与通过“frame”对象中提供给断点python命令的SBFrame访问变量的基本方式相同


希望这能帮助你开始。

谢谢,这确实让我开始了。我认为我需要深入研究类型表示,找出如何区分我感兴趣的东西和我想忽略的东西。这是我第一次感觉自己踏进了这扇门。除了使用“frame variable”在lldb中的特定位置导航变量外,还可以使用交互式python模式——在lldb控制台中键入“script”以进入该模式(在空行上键入control-D以退出)。您可以将当前帧设置为“lldb.frame”,其他所有操作如上所述。NB脚本模式显然可以锁定在Xcode中(有时?总是?我不是很肯定),因此如果您正在原型化一些python,您可能希望在探索SBValue等对象时使用命令行lldb。没错,我能够在lldb中的python控制台中测试一些东西,但这是一个很大的难题,因为光标键不起作用。我发现使用“脚本重新加载(模块)”和运行命令更容易,尽管有时第一次调用会失败。使用您的脚本并添加一些类型筛选,我可以获得所需内容的良好显示。但是,我还没有弄清楚如何从ViewController的_视图遍历到子视图。有人吗?谢谢,杰森,那个片段帮了大忙!我已经看过了,但它们似乎没有解决我面临的问题。不过,看看这些是如何构造并添加到系统中的是很有用的,谢谢!
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)