【问题标题】:Pointer arithmetic in LLDB Python scriptsLLDB Python 脚本中的指针算法
【发布时间】:2013-08-30 08:37:30
【问题描述】:

我一直在尝试为 Xcode 中的自定义字符串类型创建自定义数据格式化程序。下面的代码让我得到字符串中第一个字符的地址:

def MyStringSummary(valobj, internal_dict):
    data_pointer = valobj.GetChildMemberWithName('AllocatorInstance').GetChildMemberWithName('Data')
    print data_pointer.GetValue()

打印出指针地址。当我查看该地址的内容时,我可以看到用于存储该数据的宽字符,所以我想我要做的就是将此指针转换为wchar_t,然后我就得到了第一个字符。我的第一个方法是:

if data_pointer.TypeIsPointerType():
    mychar = data_pointer.Dereference()
    print mychar.GetValue()
else:
    print "data_pointer is not a pointer!"

这证实了 data_pointer 一个指针,但是 Dereference() 调用似乎没有解决任何问题:mychar.GetValue() 只是返回 None。 另一个问题 - 然后我是否能够通过一个循环并将data_pointer 的地址每次增加一个固定数量并继续取消引用并找到下一个字符,然后将其添加到输出字符串中?如果是这样,我该怎么做?

编辑:

为了帮助澄清问题,我将发布一些关于字符串底层数据结构的信息。该定义太长,无法在此处发布(它也继承了它从泛型数组基类所做的大部分工作),但我会提供更多详细信息。

查看StringVar.AllocationInstance.Data 指针位置时,我可以看到我们为每个字符使用了16 位。我正在查看的字符串中的所有字符都只有 8 位,每个字符后面还有 8 位 0。所以,这就是我在调试器中执行此操作时发生的情况:

(lldb) p (char*)(StringVar.AllocatorInstance.Data)
(char *) $4 = 0x10653360 "P"
(lldb) p (char*)(StringVar.AllocatorInstance.Data)+1
(char *) $6 = 0x10653361 ""
(lldb) p (char*)(StringVar.AllocatorInstance.Data)+2
(char *) $7 = 0x10653362 "a"

所以我认为它一次只显示一个字符的原因是因为它认为每个 8 位字符都以以下 8 位为空终止。但是,当我投射到 unsigned short 时,我得到了这个:

(lldb) p (unsigned short*)(StringVar.AllocatorInstance.Data)
(unsigned short *) $9 = 0x10653360
(lldb) p *(unsigned short*)(StringVar.AllocatorInstance.Data)
(wchar_t) $10 = 80
(lldb) p (char*)(unsigned short*)(StringVar.AllocatorInstance.Data)
(char *) $11 = 0x10653360 "P"
(lldb) p (char*)((unsigned short*)(StringVar.AllocatorInstance.Data)+1)
(char *) $14 = 0x10653362 "a"
(lldb) p (char*)((unsigned short*)(StringVar.AllocatorInstance.Data)+2)
(char *) $18 = 0x10653364 "r"

...所以看起来转换为unsigned short 很好,只要我们将每个整数转换为一个字符。知道如何尝试将其放入 Python 数据格式化程序中吗?

【问题讨论】:

    标签: c++ python xcode pointers lldb


    【解决方案1】:

    没有任何源代码参考,这个问题比它应该的更难弄清楚。

    话虽如此,我的第一个赌注是你的 Char* 类型是一个“不透明”的引用,所以当你去引用它时,LLDB 对指针类型一无所知并且无法解析它。或者指针类型不是基本类型(int、char、float ......),因此没有值(值本质上是标量属性,结构或类或联合没有值,它们有成员)

    你能公布你的字符串类型的定义吗?

    从那里开始,有几种方法可以从内存位置提取一大块数据。你的字符串是 ASCII/UTF8 编码的吗?如果是这样,您可以只使用 Process.ReadCStringFromMemory 给它指针的值。这将一直读取直到找到第一个 0 终止符,或者直到达到某个最大长度(您希望避免从乱码内存中读取无限量的数据)

    如果不是这样,还有其他方法。

    同样,您可以提供的有关数据结构内部的信息越多,为它编写格式化程序就越容易。

    【讨论】:

    • 感谢您提供的信息 - 我更新了我的问题并提供了更多详细信息。这是一门奇怪的课……
    【解决方案2】:

    您的 Data 看起来可能是 UTF-16。我做了一个快速的 C 程序,看起来有点像你的问题描述,并在交互式 Python 解释器中进行了一些操作。我认为这可能足以为您指明编写自己的格式化程序的正确方向?

    int main ()
    {
        struct String *mystr = AllocateString();
        mystr->AllocatorInstance.len = 10;
        mystr->AllocatorInstance.Data = (void *) malloc (10);
        memset (mystr->AllocatorInstance.Data, 0, 10);
        ((char *)mystr->AllocatorInstance.Data)[0] = 'h';
        ((char *)mystr->AllocatorInstance.Data)[2] = 'e';
        ((char *)mystr->AllocatorInstance.Data)[4] = 'l';
        ((char *)mystr->AllocatorInstance.Data)[6] = 'l';
        ((char *)mystr->AllocatorInstance.Data)[8] = 'o';
    
        FreeString (mystr);
    }
    

    使用lldb.framelldb.process 快​​捷方式(仅在进行交互式script 时有效),我们可以轻松地将Data 读入python 字符串缓冲区:

    >>> valobj = lldb.frame.FindVariable("mystr")
    >>> address = valobj.GetChildMemberWithName('AllocatorInstance').GetChildMemberWithName('Data').GetValueAsUnsigned()
    >>> size = valobj.GetChildMemberWithName('AllocatorInstance').GetChildMemberWithName('len').GetValueAsUnsigned()
    >>> print address
    4296016096
    >>> print size
    10
    >>> err = lldb.SBError()
    >>> print err
    error: <NULL>
    >>> membuf = lldb.process.ReadMemory (address, size, err)
    >>> print err
    success
    >>> membuf
    'h\x00e\x00l\x00l\x00o\x00'
    

    从这一点开始,你可以做任何常见的 python 数组类型的事情 -

    >>> for b in membuf:
    ...   print ord(b)
    ... 
    104
    0
    101
    0
    108
    0
    108
    0
    111
    0
    

    我不确定你如何告诉 Python 这是 UTF-16 并且应该正确地内化为宽字符,这更像是一个 Python 问题而不是 lldb 问题——但我认为你最好的选择是不要使用SBValue 方法(因为您的 Data 指针具有像 void * 这样的无信息类型,就像我在测试程序中所做的那样),但要使用 SBProcess 内存读取方法。

    【讨论】:

    • 太棒了! ReadMemory 正是我想要的——正如你所说,数据的具体数据类型没有提供信息,所以 SBValue 方法没有帮助是有道理的。享受当之无愧的赏金!
    猜你喜欢
    • 2012-12-23
    • 2018-02-10
    • 2011-07-31
    • 2017-11-24
    • 1970-01-01
    • 2011-04-01
    • 1970-01-01
    相关资源
    最近更新 更多