LLDB中QJsonArray自定义调试可视化异常求助
解决LLDB中QJsonArray嵌套类型调试可视化的问题
问题描述
为Qt的QJsonArray等类型编写LLDB自定义调试可视化器时,遇到两个核心问题:
- 嵌套QJsonArray/QJsonObject显示为空,当前通过
EvaluateExpression方法无法正确解析嵌套类型 - 无字段、仅含
getSomething()类属性的自定义类型也存在类似无法可视化的问题
原实现代码如下:
原Python合成提供器代码
class qJsonArray_SyntheticProvider: def __init__(self, valobj, internal_dict): self.valobj = valobj def num_children(self): try: s = self.valobj.EvaluateExpression("size()").GetValueAsUnsigned(0) return s except: return 0; def get_child_index(self,name): try: return int(name.lstrip('[').rstrip(']')) except: return None def get_child_at_index(self,index): if index < 0: return None if index >= self.num_children(): return None if not self.valobj.IsValid(): return None try: element_type = self.valobj.EvaluateExpression("at(%d).type()" % index).GetValueAsUnsigned(0) if element_type == 1: element = self.valobj.EvaluateExpression("at(%d).toBool(false)" % index) elif element_type == 2: element = self.valobj.EvaluateExpression("at(%d).toDouble(0)" % index) elif element_type == 3: element = self.valobj.EvaluateExpression("at(%d).toString()" % index) elif element_type == 4: # doesn't work -> array type element = self.valobj.EvaluateExpression("at(%d).toArray()" % index) elif element_type == 5: # doesn't work -> object type element = self.valobj.EvaluateExpression("at(%d).toObject()" % index) else: return None return (self.valobj .CreateValueFromData("[%d]" % index, element.GetData(), element.GetType())) except: return None
原C++测试代码
QJsonArray arr; arr.push_back(1); arr.push_back("test"); QJsonArray nested_arr; nested_arr.push_back(3); arr.push_back(nested_arr);
原摘要提供器代码
def qjsonarray_summary(value, unused): num_elements = value.EvaluateExpression("size()").GetValueAsUnsigned(0) return "(%d elements)" % num_elements
核心问题分析
CreateValueFromData误用:toArray()/toObject()返回临时对象,其内存地址在表达式执行后会失效,导致LLDB无法正确读取嵌套类型的数据。EvaluateExpression局限性:频繁调用该方法会降低调试效率,且依赖运行时环境;对于无字段的自定义类型,直接调用getter方法返回的临时对象无法被LLDB持久化解析。
优化实现方案
方案1:直接读取QJsonArray内部存储(推荐)
Qt的QJsonArray内部通过QList<QJsonValue>存储数据,直接读取私有成员可绕过临时对象问题,同时提升调试效率。
修改后的代码实现
合成提供器代码
class qJsonArray_SyntheticProvider: def __init__(self, valobj, internal_dict): self.valobj = valobj # 适配Qt版本:内部存储的私有成员名,Qt5/6可能为'd'->'array',需根据实际调试结构调整 self.internal_list = self.valobj.GetChildMemberWithName('d').GetChildMemberWithName('array') def num_children(self): try: # 直接读取QList的子元素数量,无需调用size()方法 return self.internal_list.GetNumChildren() except: return 0 def get_child_index(self, name): try: return int(name.lstrip('[').rstrip(']')) except: return None def get_child_at_index(self, index): if index < 0 or index >= self.num_children() or not self.valobj.IsValid(): return None try: # 直接获取内部QList中的QJsonValue对象 json_val = self.internal_list.GetChildAtIndex(index) # QJsonValue的类型字段't',对应QJsonValue::Type的枚举值 val_type = json_val.GetChildMemberWithName('t').GetValueAsUnsigned(0) # 根据类型返回对应的值对象 if val_type == 1: # QJsonValue::Bool return json_val.GetChildMemberWithName('b').CreateValueFromExpression("[%d]" % index) elif val_type == 2: # QJsonValue::Double return json_val.GetChildMemberWithName('d').CreateValueFromExpression("[%d]" % index) elif val_type == 3: # QJsonValue::String return json_val.GetChildMemberWithName('s').CreateValueFromExpression("[%d]" % index) elif val_type == 4: # QJsonValue::Array # 直接返回内部的QJsonArray对象,无需调用toArray() return json_val.GetChildMemberWithName('a').CreateValueFromExpression("[%d]" % index) elif val_type == 5: # QJsonValue::Object # 直接返回内部的QJsonObject对象,无需调用toObject() return json_val.GetChildMemberWithName('o').CreateValueFromExpression("[%d]" % index) else: return None except: return None
摘要提供器代码
def qjsonarray_summary(value, unused): try: internal_list = value.GetChildMemberWithName('d').GetChildMemberWithName('array') num_elements = internal_list.GetNumChildren() return "(%d elements)" % num_elements except: return "(0 elements)"
方案2:嵌套类型临时对象修复(兼容私有成员不可访问场景)
如果无法直接读取Qt私有成员,可通过获取原始对象的引用地址来创建值对象:
# 在get_child_at_index的array/object分支替换为: element = self.valobj.EvaluateExpression("&at(%d).toArray()" % index) return self.valobj.CreateValueFromAddress("[%d]" % index, element.GetValueAsUnsigned(), element.GetType().GetPointerType().GetPointeeType())
自定义无字段类型通用处理
对于仅含getter方法的自定义类型,需获取返回值的原始内存地址,而非临时对象:
# 示例:处理MyType类的getX()方法 def mytype_synthetic_provider(valobj, internal_dict): class Provider: def num_children(self): return 1 def get_child_at_index(self, index): if index !=0: return None # 获取getX()返回值的地址,而非临时值 addr = valobj.EvaluateExpression("&getX()").GetValueAsUnsigned() return valobj.CreateValueFromAddress("x", addr, valobj.GetTarget().FindFirstRegisteredType("int")) return Provider()
注意事项
- Qt版本适配:不同Qt版本的私有成员命名可能不同,需通过LLDB命令
po *arr.d查看实际内存结构调整成员名。 - 调试版本Qt:使用调试版本Qt可避免私有成员被隐藏,提升可视化稳定性。
- 性能优化:减少
EvaluateExpression调用,优先通过直接读取成员变量的方式实现可视化。
内容的提问来源于stack exchange,提问作者Chebz
相关产品推荐
相关产品推荐

