Debugging 声明大小字符串类型的lldb摘要字符串
我想为nim语言的内置字符串类型提供一个格式化程序,但不知何故,我未能提供它。Nim编译为c,您在这里看到的字符串类型的c表示形式:Debugging 声明大小字符串类型的lldb摘要字符串,debugging,lldb,Debugging,Lldb,我想为nim语言的内置字符串类型提供一个格式化程序,但不知何故,我未能提供它。Nim编译为c,您在这里看到的字符串类型的c表示形式: #if defined(__GNUC__) || defined(__clang__) || defined(_MSC_VER) # define SEQ_DECL_SIZE /* empty is correct! */ #else # define SEQ_DECL_SIZE 1000000 #endif typedef char NIM_CHAR; ty
#if defined(__GNUC__) || defined(__clang__) || defined(_MSC_VER)
# define SEQ_DECL_SIZE /* empty is correct! */
#else
# define SEQ_DECL_SIZE 1000000
#endif
typedef char NIM_CHAR;
typedef long long int NI64;
typedef NI64 NI;
struct TGenericSeq {NI len; NI reserved; };
struct NimStringDesc {TGenericSeq Sup; NIM_CHAR data[SEQ_DECL_SIZE]; };
下面是我在lldb会话中尝试的输出:
(lldb) frame variable *longstring
(NimStringDesc) *longstring = {
Sup = (len = 9, reserved = 15)
data = {}
}
(lldb) frame variable longstring->data
(NIM_CHAR []) longstring->data = {}
(lldb) type summary add --summary-string "${&var[0]%s}" "NIM_CHAR []"
(lldb) frame variable longstring->data
(NIM_CHAR []) longstring->data = {}
(lldb) type summary add --summary-string "${var%s}" "NIM_CHAR *"
(lldb) frame variable longstring->data
(NIM_CHAR []) longstring->data = {}
(lldb) frame variable &longstring->data[0]
(NIM_CHAR *) &[0] = 0x00007ffff7f3a060 "9 - 3 - 2"
(lldb) frame variable *longstring
(lldb) type summary add --summary-string "${var.data%s}" "NimStringDesc"
(lldb) frame variable *longstring
(NimStringDesc) *longstring = NIM_CHAR [] @ 0x7ffff7f3a060
(lldb) type summary add --summary-string "${&var.data[0]%s}" "NimStringDesc"
(lldb) frame variable *longstring
(NimStringDesc) *longstring = {
Sup = (len = 9, reserved = 15)
data = {}
}
(lldb)
我简直无法管理,输出将只是被解释为
'\0'
终止的c字符串的数据。您尝试过的摘要字符串语法(根据设计)没有c语法丰富
由于您使用的是零大小的数组,我认为我们没有任何神奇的规定将其视为指向字符串的指针。您可能想提交一个关于它的bug,但在这种情况下,它是否会帮助您是有争议的。因为您的字符串是长度编码的,所以它实际上不需要以零结尾,这是LLDB能够理解的唯一提示,即何时停止读取指向字符的指针
在您的情况下,您将不得不求助于Python格式化程序
您需要的是:
- 字符串缓冲区的内存位置
- 字符串缓冲区的长度
- 从内存中读出数据的过程
def NimStringSummary(valobj,stuff):
l = valobj.GetChildMemberWithName('Sup').GetChildMemberWithName('len').GetValueAsUnsigned(0)
s = valobj.GetChildMemberWithName('data').AddressOf()
return '"%s"'% valobj.process.ReadMemory(s.GetValueAsUnsigned(0),l,lldb.SBError())
如您所见,首先它读取长度字段的值;
然后读取数据缓冲区的地址;然后,它使用值来自的进程来读取字符串内容,并以引号返回
现在,这是一个概念证明。如果在生产中使用它,您会很快遇到一些问题:
如果您的字符串缓冲区尚未初始化,并且它显示缓冲区的大小为20GB,该怎么办?您将不得不限制您愿意读取的数据的大小。对于类似字符串的类型,它具有(char*,std::string,Swift.string,…)的内置知识,LLDB打印出被截断的缓冲区,后跟…,例如
(const char*) buffer = "myBufferIsVeryLong"...
如果指向数据的指针无效怎么办?您应该检查s.GetValueAsUnsigned(0)实际上不是零-如果是,您可能希望打印一条错误消息,如“null buffer”
另外,这里我只是传递了一个SBError,然后忽略它——最好传递一个,然后检查它
总而言之,你最终会得到这样的结果:
import lldb
import os
def NimStringSummary(valobj,stuff):
l = valobj.GetChildMemberWithName('Sup').GetChildMemberWithName('len').GetValueAsUnsigned(0)
if l == 0: return '""'
if l > 1024: l = 1024
s = valobj.GetChildMemberWithName('data').AddressOf()
addr = s.GetValueAsUnsigned(0)
if addr == 0: return '<null buffer>'
err = lldb.SBError()
buf = valobj.process.ReadMemory(s.GetValueAsUnsigned(0),l,err)
if err.Fail(): return '<error: %s>' % str(err)
return '"%s"' % buf
def __lldb_init_module(debugger, internal_dict):
debugger.HandleCommand("type summary add NimStringDesc -F %s.NimStringSummary" % os.path.splitext(os.path.basename(__file__))[0])
导入lldb
导入操作系统
def NimStringSummary(valobj,stuff):
l=valobj.GetChildMemberWithName('Sup')。GetChildMemberWithName('len')。GetValueAsUnsigned(0)
如果l==0:返回''''
如果l>1024:l=1024
s=valobj.GetChildMemberWithName('data').AddressOf()
地址=s.GetValueAsUnsigned(0)
如果addr==0:返回“”
err=lldb.SBError()
buf=valobj.process.ReadMemory(s.GetValueAsUnsigned(0),l,err)
if err.Fail():返回“”%str(err)
返回''%s''%buf
def _lldb _init_模块(调试器,内部命令):
debugger.HandleCommand(“类型摘要添加NimStringDesc-F%s.NimStringSummary”%os.path.splitext(os.path.basename(_文件__))[0])
另外一个技巧是_lldb_init_module函数——每当您“命令脚本导入”python文件时,lldb就会自动调用该函数。这将允许您将“命令脚本导入”添加到~/.lldbinit文件中,并在所有调试会话中自动获取格式化程序
希望这有帮助 谢谢你的回答,这对我帮助很大。我会尽快尝试一下。但是在您已经访问Sup成员之后,您正在检查
数据的地址为0
。数据的地址永远不能是0
,因为字符串是直接嵌入Sup之后的,它不是指针。我保持原样,因为这是我在Stackoverflow上得到的最好答案,非常感谢。一切正常,解释得很好。恩里科-这是纯金。谢谢你写这篇文章!