You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

核心问题分析

  1. CreateValueFromData误用:toArray()/toObject()返回临时对象,其内存地址在表达式执行后会失效,导致LLDB无法正确读取嵌套类型的数据。
  2. 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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.09 08:38:12