在调clang源码时,要显示PointerIntPair的值很累。它是一个指针和一个Int存在一个值中。
前面的文章可以看它的实现。这篇介绍如何用type summary来显示它。
之前的文章也说过如何实现type summary以及type synthetic.
总结有以下几点
1. 用type summary来调python,或者进到script命令调试。
2. 在type synthetic中,init少干活,会报错,尽量把heavy的逻辑放到update里做。
3. 像这个case,内存中不存在我们的值,所以CreateValueFromData来创建对象。
4.
对于得到Children的逻辑,不能忘记实现"Value"这个逻辑,否则valobj.GetChildMemberWithName('Value')得不到正确的值。
internal_type =
valobj.GetType().GetTemplateArgumentType(0)
if internal_type.IsPointerType():
real_interal_type =
internal_type.GetPointeeType()
real_interal_type_name =
real_interal_type.GetUnqualifiedType().GetName()
这段判断模板第一个参数是指针。GetUnqualifiedType()可以去掉const
PointerLikeTypeTraits_NumLowBitsAvailable这里是最难的,PointLikeTypeTraits在lldb中不可用,它的代码基本是编译期决定。
所以只能先实现第一个参数是指针的逻辑。
按源码分析,PointLikeTypeTraits是根据alignof(T)来决定一些主要参数。
于是,
target = valobj.target
options = lldb.SBExOptions()
options.SetIgnoreBreakpoints(True)
result =
target.EvaluateEx("alignof(%s)" %
str(real_interal_type_name), options)
PointerLikeTypeTraits_NumLowBitsAvailable =
int(math.log(int(str(result).split("=")[1]), 2))
用来得到alignof(T)的值。
后面的逻辑就是照着PointLikeTypeTraits的逻辑出来的,如果是其他Traits,逻辑就不同了。目前没想到太好办法,除非一个一个实现出来。
可能对lldb如何分析解释执行代码理解不透彻。还需要继续努力。
直接上代码。
import lldb.formatters.Logger
import math
#command script import
/Users/conanchen/Desktop/blog/2022/PointerIntPair.py
#type summary add -F PointerIntPair.PointerIntPairSummary
-x "llvm::PointerIntPair<"
#type synthetic add --python-class
PointerIntPair.PointerIntPairChildrenProvider -x
"llvm::PointerIntPair<"
def create_SBData(int_value):
SBData = lldb.SBData()
Int64Array = list()
Int64Array.append(int_value)
SBData.SetDataFromUInt64Array(Int64Array)
return SBData
def PointerIntPairSummary(valobj,internal_dict,options):
Value_val =
valobj.GetChildMemberWithName('Value')
value = Value_val.GetValueAsUnsigned(0)
internal_type =
valobj.GetType().GetTemplateArgumentType(0)
PointerLikeTypeTraits_NumLowBitsAvailable = 2
if internal_type.IsPointerType():
real_interal_type =
internal_type.GetPointeeType()
real_interal_type_name =
real_interal_type.GetUnqualifiedType().GetName()
target = valobj.target
options = lldb.SBExOptions()
options.SetIgnoreBreakpoints(True)
result =
target.EvaluateEx("alignof(%s)" %
str(real_interal_type_name), options)
PointerLikeTypeTraits_NumLowBitsAvailable =
int(math.log(int(str(result).split("=")[1]), 2))
value_type_name = valobj.GetType().GetName()
int_bits =
value_type_name.split(",")[1]
int_type =
valobj.GetType().GetTemplateArgumentType(2)
PointerBitMask = ~((1
<<
PointerLikeTypeTraits_NumLowBitsAvailable) - 1)
Pointer_Value = value &
PointerBitMask
IntShift =
PointerLikeTypeTraits_NumLowBitsAvailable - int(int_bits)
IntMask = (1 <<
int(int_bits)) - 1
Int_Value = (value >>
IntShift) & IntMask
if internal_type.IsPointerType():
return "\nInternal Value: " + str(hex(value)) +
\
"\nInternal Type: " + value_type_name + \
'\nPointer: ' + str(hex(Pointer_Value)) +
'\nInt: ' + str(Int_Value) + '\nIntBits:
' + str(int_bits) + '\nIntType: ' +
str(int_type) + \
"\nNumLowBitsAvailable:" +
str(PointerLikeTypeTraits_NumLowBitsAvailable) + \
"\nIntShift:" + str(IntShift) +
"\nIntMask:" + str(IntMask) + '\nType: '
+ str(internal_type) + \
"\nIsPointerType:" +
str(internal_type.IsPointerType()) + \
"\nPointeeType:" + str(real_interal_type_name) +
"\n"
return "\nInternal Value: " + str(hex(value)) +
\
"\nInternal Type: " + value_type_name + \
'\nPointer: ' + str(hex(Pointer_Value)) +
'\nInt: ' + str(Int_Value) + '\nIntBits:
' + str(int_bits) + '\nIntType: ' +
str(int_type) + \
"\nNumLowBitsAvailable:" +
str(PointerLikeTypeTraits_NumLowBitsAvailable) + \
"\nIntShift:" + str(IntShift) +
"\nIntMask:" + str(IntMask) + '\nType: '
+ str(internal_type) + \
"\nIsPointerType:" +
str(internal_type.IsPointerType()) + "\n"
class PointerIntPairChildrenProvider:
def __init__(self, valobj, internal_dict):
#this call should initialize the Python object using
valobj as the variable to provide synthetic children for
self.valobj = valobj
self.children_count = 3
def num_children(self):
#this call should return the number of children that you
want your object to have
return self.children_count
def get_child_index(self,name):
#this call should return the index of the synthetic child
whose name is given as argument
if name == "Value":
return 0
if name == 'Pointer':
return 1
elif name == "Int":
return 2
def get_child_at_index(self,index):
#this call should return a new LLDB SBValue object
representing the child at the index given as argument
if index < 0:
return None
if index > self.num_children():
return None
if self.valobj.IsValid() == False:
return None
if index == 0:
return self.valobj.CreateChildAtOffset("Value", 0,
self.Value_type)
elif index == 1:
return self.valobj.CreateValueFromData("Pointer",
self.Pointer_Data, self.internal_type)
elif index == 2:
return self.valobj.CreateValueFromData("Int",
self.Int_Data, self.int_type)
return None
def update(self):
#this call should be used to update the internal state of
this Python object whenever the state of the variables in LLDB
changes.[1]
try:
self.Value_val =
self.valobj.GetChildMemberWithName('Value')
self.Value_type = self.Value_val.GetType()
self.value =
self.Value_val.GetValueAsUnsigned(0)
self.internal_type =
self.valobj.GetType().GetTemplateArgumentType(0)
self.value_type_name =
self.valobj.GetType().GetName()
self.int_bits =
self.value_type_name.split(",")[1]
self.PointerLikeTypeTraits_NumLowBitsAvailable =
2
if self.internal_type.IsPointerType():
real_interal_type =
self.internal_type.GetPointeeType()
real_interal_type_name =
real_interal_type.GetUnqualifiedType().GetName()
target = self.valobj.target
options = lldb.SBExOptions()
options.SetIgnoreBreakpoints(True)
result =
target.EvaluateEx("alignof(%s)" %
str(real_interal_type_name), options)
self.PointerLikeTypeTraits_NumLowBitsAvailable =
int(math.log(int(str(result).split("=")[1]), 2))
self.PointerBitMask = ~((1
<<
self.PointerLikeTypeTraits_NumLowBitsAvailable) - 1)
self.int_type =
self.valobj.GetType().GetTemplateArgumentType(2)
self.Pointer_Value = self.value &
self.PointerBitMask
self.Pointer_Data =
create_SBData(self.Pointer_Value)
self.IntShift =
self.PointerLikeTypeTraits_NumLowBitsAvailable -
int(self.int_bits)
self.IntMask = (1 <<
int(self.int_bits)) - 1
self.Int_Value = (self.value
>> self.IntShift) &
self.IntMask
self.Int_Data = create_SBData(self.Int_Value)
except:
pass
return True
def has_children(self):
return self.num_children() > 0
#this call should return True if this object might have
children, and False if this object can be guaranteed not to have
children.[2]
def get_value(self):
#this call can return an SBValue to be presented as the
value of the synthetic value under consideration.[3]
pass
这是原来结果
(lldb) p X
(clang::SrcMgr::FileInfo) $4 = {
IncludeLoc = (ID = 0)
NumCreatedFIDs = 0
HasLineDirectives = 0
ContentAndKind = (Value =
5041605120)
}
修改之后
(lldb) p X
(clang::SrcMgr::FileInfo) $5 = {
IncludeLoc = (ID = 0)
NumCreatedFIDs = 0
HasLineDirectives = 0
ContentAndKind =
Internal Value: 0x12c80ca00
Internal Type: llvm::PointerIntPair, llvm::PointerIntPairInfo
> >
Pointer: 0x12c80ca00
Int: 0
IntBits: 3
IntType: enum CharacteristicKind {
C_User,
C_System,
C_ExternCSystem,
C_User_ModuleMap,
C_System_ModuleMap
}
NumLowBitsAvailable:3
IntShift:0
IntMask:7
Type: const class clang::SrcMgr::ContentCache *
IsPointerType:True
PointeeType:clang::SrcMgr::ContentCache
}
去掉Summary之后
(lldb) p X
(clang::SrcMgr::FileInfo) $25 = {
IncludeLoc = (ID = 0)
NumCreatedFIDs = 0
HasLineDirectives = 0
ContentAndKind = {
Value = 5041605120
Pointer = 0x3135303631343035
Int = C_User
}
}
会直接显示synthetic.效果是我们想要的.
此时已经可以在左边的树上直接显示出内置指针对象的成员了。
lldb显示PointerIntPair
在调clang源码时,要显示PointerIntPair的值很累。它是一个指针和一个Int存在一个值中。
前面的文章可以看它的实现。这篇介绍如何用type summary来显示它。
之前的文章也说过如何实现type summary以及type synthetic.
总结有以下几点
1. 用type summary来调python,或者进到script命令调试。
2. 在type synthetic中,init少干活,会报错,尽量把heavy的逻辑放到update里做。
3. 像这个case,内存中不存在我们的值,所以CreateValueFromData来创建对象。
4. 对于得到Children的逻辑,不能忘记实现"Value"这个逻辑,否则valobj.GetChildMemberWithName('Value')得不到正确的值。
internal_type = valobj.GetType().GetTemplateArgumentType(0)
if internal_type.IsPointerType():
real_interal_type = internal_type.GetPointeeType()
real_interal_type_name = real_interal_type.GetUnqualifiedType().GetName()
这段判断模板第一个参数是指针。GetUnqualifiedType()可以去掉const
PointerLikeTypeTraits_NumLowBitsAvailable这里是最难的,PointLikeTypeTraits在lldb中不可用,它的代码基本是编译期决定。
所以只能先实现第一个参数是指针的逻辑。
按源码分析,PointLikeTypeTraits是根据alignof(T)来决定一些主要参数。
于是,
target = valobj.target
options = lldb.SBExOptions()
options.SetIgnoreBreakpoints(True)
result = target.EvaluateEx("alignof(%s)" % str(real_interal_type_name), options)
PointerLikeTypeTraits_NumLowBitsAvailable = int(math.log(int(str(result).split("=")[1]), 2))
用来得到alignof(T)的值。
后面的逻辑就是照着PointLikeTypeTraits的逻辑出来的,如果是其他Traits,逻辑就不同了。目前没想到太好办法,除非一个一个实现出来。
可能对lldb如何分析解释执行代码理解不透彻。还需要继续努力。
直接上代码。
import lldb.formatters.Logger
import math
#command script import /Users/conanchen/Desktop/blog/2022/PointerIntPair.py
#type summary add -F PointerIntPair.PointerIntPairSummary -x "llvm::PointerIntPair<"
#type synthetic add --python-class PointerIntPair.PointerIntPairChildrenProvider -x "llvm::PointerIntPair<"
def create_SBData(int_value):
SBData = lldb.SBData()
Int64Array = list()
Int64Array.append(int_value)
SBData.SetDataFromUInt64Array(Int64Array)
return SBData
def PointerIntPairSummary(valobj,internal_dict,options):
Value_val = valobj.GetChildMemberWithName('Value')
value = Value_val.GetValueAsUnsigned(0)
internal_type = valobj.GetType().GetTemplateArgumentType(0)
PointerLikeTypeTraits_NumLowBitsAvailable = 2
if internal_type.IsPointerType():
real_interal_type = internal_type.GetPointeeType()
real_interal_type_name = real_interal_type.GetUnqualifiedType().GetName()
target = valobj.target
options = lldb.SBExOptions()
options.SetIgnoreBreakpoints(True)
result = target.EvaluateEx("alignof(%s)" % str(real_interal_type_name), options)
PointerLikeTypeTraits_NumLowBitsAvailable = int(math.log(int(str(result).split("=")[1]), 2))
value_type_name = valobj.GetType().GetName()
int_bits = value_type_name.split(",")[1]
int_type = valobj.GetType().GetTemplateArgumentType(2)
PointerBitMask = ~((1 << PointerLikeTypeTraits_NumLowBitsAvailable) - 1)
Pointer_Value = value & PointerBitMask
IntShift = PointerLikeTypeTraits_NumLowBitsAvailable - int(int_bits)
IntMask = (1 << int(int_bits)) - 1
Int_Value = (value >> IntShift) & IntMask
if internal_type.IsPointerType():
return "\nInternal Value: " + str(hex(value)) + \
"\nInternal Type: " + value_type_name + \
'\nPointer: ' + str(hex(Pointer_Value)) + '\nInt: ' + str(Int_Value) + '\nIntBits: ' + str(int_bits) + '\nIntType: ' + str(int_type) + \
"\nNumLowBitsAvailable:" + str(PointerLikeTypeTraits_NumLowBitsAvailable) + \
"\nIntShift:" + str(IntShift) + "\nIntMask:" + str(IntMask) + '\nType: ' + str(internal_type) + \
"\nIsPointerType:" + str(internal_type.IsPointerType()) + \
"\nPointeeType:" + str(real_interal_type_name) + "\n"
return "\nInternal Value: " + str(hex(value)) + \
"\nInternal Type: " + value_type_name + \
'\nPointer: ' + str(hex(Pointer_Value)) + '\nInt: ' + str(Int_Value) + '\nIntBits: ' + str(int_bits) + '\nIntType: ' + str(int_type) + \
"\nNumLowBitsAvailable:" + str(PointerLikeTypeTraits_NumLowBitsAvailable) + \
"\nIntShift:" + str(IntShift) + "\nIntMask:" + str(IntMask) + '\nType: ' + str(internal_type) + \
"\nIsPointerType:" + str(internal_type.IsPointerType()) + "\n"
class PointerIntPairChildrenProvider:
def __init__(self, valobj, internal_dict):
#this call should initialize the Python object using valobj as the variable to provide synthetic children for
self.valobj = valobj
self.children_count = 3
def num_children(self):
#this call should return the number of children that you want your object to have
return self.children_count
def get_child_index(self,name):
#this call should return the index of the synthetic child whose name is given as argument
if name == "Value":
return 0
if name == 'Pointer':
return 1
elif name == "Int":
return 2
def get_child_at_index(self,index):
#this call should return a new LLDB SBValue object representing the child at the index given as argument
if index < 0:
return None
if index > self.num_children():
return None
if self.valobj.IsValid() == False:
return None
if index == 0:
return self.valobj.CreateChildAtOffset("Value", 0, self.Value_type)
elif index == 1:
return self.valobj.CreateValueFromData("Pointer", self.Pointer_Data, self.internal_type)
elif index == 2:
return self.valobj.CreateValueFromData("Int", self.Int_Data, self.int_type)
return None
def update(self):
#this call should be used to update the internal state of this Python object whenever the state of the variables in LLDB changes.[1]
try:
self.Value_val = self.valobj.GetChildMemberWithName('Value')
self.Value_type = self.Value_val.GetType()
self.value = self.Value_val.GetValueAsUnsigned(0)
self.internal_type = self.valobj.GetType().GetTemplateArgumentType(0)
self.value_type_name = self.valobj.GetType().GetName()
self.int_bits = self.value_type_name.split(",")[1]
self.PointerLikeTypeTraits_NumLowBitsAvailable = 2
if self.internal_type.IsPointerType():
real_interal_type = self.internal_type.GetPointeeType()
real_interal_type_name = real_interal_type.GetUnqualifiedType().GetName()
target = self.valobj.target
options = lldb.SBExOptions()
options.SetIgnoreBreakpoints(True)
result = target.EvaluateEx("alignof(%s)" % str(real_interal_type_name), options)
self.PointerLikeTypeTraits_NumLowBitsAvailable = int(math.log(int(str(result).split("=")[1]), 2))
self.PointerBitMask = ~((1 << self.PointerLikeTypeTraits_NumLowBitsAvailable) - 1)
self.int_type = self.valobj.GetType().GetTemplateArgumentType(2)
self.Pointer_Value = self.value & self.PointerBitMask
self.Pointer_Data = create_SBData(self.Pointer_Value)
self.IntShift = self.PointerLikeTypeTraits_NumLowBitsAvailable - int(self.int_bits)
self.IntMask = (1 << int(self.int_bits)) - 1
self.Int_Value = (self.value >> self.IntShift) & self.IntMask
self.Int_Data = create_SBData(self.Int_Value)
except:
pass
return True
def has_children(self):
return self.num_children() > 0
#this call should return True if this object might have children, and False if this object can be guaranteed not to have children.[2]
def get_value(self):
#this call can return an SBValue to be presented as the value of the synthetic value under consideration.[3]
pass
这是原来结果
(lldb) p X
(clang::SrcMgr::FileInfo) $4 = {
IncludeLoc = (ID = 0)
NumCreatedFIDs = 0
HasLineDirectives = 0
ContentAndKind = (Value = 5041605120)
}
修改之后
(lldb) p X
(clang::SrcMgr::FileInfo) $5 = {
IncludeLoc = (ID = 0)
NumCreatedFIDs = 0
HasLineDirectives = 0
ContentAndKind =
Internal Value: 0x12c80ca00
Internal Type: llvm::PointerIntPair, llvm::PointerIntPairInfo > >
Pointer: 0x12c80ca00
Int: 0
IntBits: 3
IntType: enum CharacteristicKind {
C_User,
C_System,
C_ExternCSystem,
C_User_ModuleMap,
C_System_ModuleMap
}
NumLowBitsAvailable:3
IntShift:0
IntMask:7
Type: const class clang::SrcMgr::ContentCache *
IsPointerType:True
PointeeType:clang::SrcMgr::ContentCache
}
去掉Summary之后
(lldb) p X
(clang::SrcMgr::FileInfo) $25 = {
IncludeLoc = (ID = 0)
NumCreatedFIDs = 0
HasLineDirectives = 0
ContentAndKind = {
Value = 5041605120
Pointer = 0x3135303631343035
Int = C_User
}
}
会直接显示synthetic.效果是我们想要的.
此时已经可以在左边的树上直接显示出内置指针对象的成员了。