lldb显示PointerIntPair

2022-04-30 17:19:35
标签: llvm pointerintpair synthetic summary lldb

在调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.效果是我们想要的.

此时已经可以在左边的树上直接显示出内置指针对象的成员了。


阅读(0) 收藏(0) 转载(0) 举报/Report
相关阅读

新浪BLOG意见反馈留言板 欢迎批评指正

新浪简介 | About Sina | 广告服务 | 联系我们 | 招聘信息 | 网站律师 | SINA English | 产品答疑

新浪公司 版权所有