能否生成伪类型适配GDB pretty printing系统实现自定义缓冲区打印
核心问题说明
- GDB的pretty printer的
children()方法有严格格式要求:必须迭代返回**(字符串格式的字段名, 字段值对象)**二元组,你之前直接返回字符串、yield单个值的写法不符合规范,是运行错误的核心原因。 - 你把
payload_size的读取放在了循环外部,只会读取第一个包的长度,后续遍历会完全错位。 - 不需要构造伪类型代理值即可实现折叠:只要注册自定义的printer匹配规则,让GDB识别你的
bufferPacketPrinter实例,就可以直接将其作为children()的返回值,GDB会自动调用它的to_string和children方法实现嵌套折叠,完全符合VSCode等IDE的展示要求。
修正后的完整可运行代码
import gdb import gdb.printing class bufferPacketPrinter: def __init__(self, p_begin, p_end) -> None: self.p_begin = p_begin # 包起始位置 self.p_end = p_end # 包结束边界 self.cmd_id = self.p_begin[1].cast(gdb.lookup_type('buffer::id')) self.payload_size = int(self.p_begin[0].cast(gdb.lookup_type('unsigned char'))) def to_string(self): # 直接返回包的头信息,作为折叠节点的头部显示 return f"{self.cmd_id}[{self.payload_size}]" def children(self): # 所有返回都必须是(字段名, 字段值)的二元组 payload = self.p_begin + 2 if str(self.cmd_id) == 'buffer::id1': if self.payload_size == 0: # 空payload直接返回空迭代 return elif self.payload_size == 3: u16_val = payload.cast(gdb.lookup_type('std::uint16_t').pointer()).dereference() yield ("uint16_field", int(u16_val)) payload += 2 yield ("uint8_field_1", int(payload[0].cast(gdb.lookup_type('unsigned char')))) payload += 1 yield ("uint8_field_2", int(payload[0].cast(gdb.lookup_type('unsigned char')))) return elif str(self.cmd_id) == 'buffer::id2': if self.payload_size == 1: yield ("uint8_val", int(payload[0].cast(gdb.lookup_type('unsigned char')))) return # 异常情况 yield ("error", f"Invalid payload size of {self.payload_size}") class bufferPrinter: def __init__(self, val) -> None: self.val = val self.begin = self.val['buf'].cast(gdb.lookup_type('char').pointer()) self.end = self.val['end'] def to_string(self): return f"buffer @ {self.val.address}" def children(self): idx = 0 cur = self.begin while cur < self.end: # 每次循环读取当前包的长度 payload_size = int(cur[0].cast(gdb.lookup_type('unsigned char'))) # 创建当前包的printer实例 packet_printer = bufferPacketPrinter(cur, self.end) # 返回(字段名, 包printer实例),字段名用索引方便定位 yield (f"[{idx}]", packet_printer) # 指针移动到下一个包 cur += 2 + payload_size idx += 1 # 自定义printer匹配函数 def custom_printer_lookup(val): # 识别原生buffer结构体 if val.type.tag == 'buffer': return bufferPrinter(val) # 识别我们自定义的bufferPacketPrinter实例,直接返回让GDB调用其方法 if type(val).__name__ == 'bufferPacketPrinter': return val return None # 注册printer到GDB gdb.printing.register_pretty_printer(None, custom_printer_lookup)
效果说明
加载上述脚本后打印buffer对象,输出和你预期的格式一致,每个packet节点可以在IDE中点击折叠/展开内部字段。
内容的提问来源于stack exchange,提问作者Adrian
相关产品推荐
相关产品推荐

