LLDB Python脚本中的指针算法

2024-10-01 13:33:57 发布

您现在位置:Python中文网/ 问答频道 /正文

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

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

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

^{pr2}$

这证实了data\u pointer指针,但是Dereference()调用似乎没有解决任何问题:mychar.GetValue()只返回{}。 另一个问题是,我是否可以通过一个循环,每次将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数据格式化程序中吗?在


Tags: 字符串程序data地址字符short指针char
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字符串缓冲区:

^{pr2}$

从这一点开始,您可以执行任何常见的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内存读取方法。在

在没有任何源代码引用的情况下,这个问题比应该的要难一些。在

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

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

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

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

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

相关问题 更多 >