【发布时间】:2022-01-05 00:14:27
【问题描述】:
我正在用 python 为 gdb 编写一个漂亮的打印机,并且正在慢慢掌握这种方法。试图找到有关该系统如何工作的实际文档以及这些方法的预期结果示例,就像拔牙一样。我在这里和那里找到了一些零碎的东西,但没有什么是包罗万象的。我发现的一些信息是通过反复试验得到的,进展缓慢。
到目前为止,看起来漂亮的打印机的to_string() 只允许返回一个字符串(当然),但children() 可以返回一个string 或一对string 和value,其中value 是一个 Python 值或描述为 here 的值对象,它是正在打印的 ac/c++ 对象的包装器。实际上,我曾希望我可以返回一个漂亮的打印机对象并调用它,但可惜,事实并非如此。我可以返回一个字符串,但我希望有效负载元素在 VSCode 之类的 IDE 中是可折叠的,为此我需要返回一个值对象。与此等效的是Natvis 中的Synthetic Item。
我有一个作为缓冲区的 c++ 类。原始的,它包含一个字节向量,我需要以可读的方式对其进行处理。
给出我收集到的约束条件,如果我可以使用伪类型将指针包装在代理值对象中,我可能能够将字节分解为可用的单元。这是我所说的硬编码示例:
#include <cstdint>
struct alignas(std::uint16_t) buffer {
enum id : char { id1, id2 };
// structure is: payload_size, id, payload[]
char buf[11] = { 2, id1, 1, 0, 2, 3
, 0, id1
, 1, id2, 1
};
char* end = std::end(buf);
};
int main() {
buffer b;
return 0;
}
在大端机器上的return 0; 上设置断点,我希望显示如下内容:
(gdb) p b
$1 = buffer @ 0xaddre55 = { id1[2] = {1, 2, 3}, id1[0] = {}, id2 = {1} }
这是迄今为止我得到的漂亮打印机 python 代码:
class bufferPacketPrinter:
def __init__(self, p_begin, p_end) -> None:
self.p_begin = p_begin # begining of packet
self.p_end = p_end # end of packet
self.cmd_id = self.p_begin[1].cast('buffer::id')
self.payload_size = self.p_begin[0].cast('unsigned char').cast('int')
def to_string(self):
return 'packet {}[{}]' \
.format(self.cmd_id, self.payload_size)
def children(self):
payload = self.p_begin + 2
if self.cmd_id == 'id1':
if self.payload_size == 0:
return '{}'
elif self.payload_size == 3:
yield payload.cast(gdb.lookup_type('std::uint16_t').pointer())
payload += 2
yield payload[0].cast(gdb.lookup_type('unsigned char')).cast(gdb.lookup_type('int'))
payload += 1
return payload[0].cast(gdb.lookup_type('unsigned char')).cast(gdb.lookup_type('int'))
elif self.cmd_id == 'id2':
if self.payload_size == 1:
return payload[0]
return 'Invalid payload size of ' + str(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 'buffer @ {}'.format(self.val.address)
def children(self):
payload_size = self.begin[0].cast('unsigned char').cast('int')
while self.begin != self.end:
yield ??? # <=== Here is where the magic that I need is to happen
self.begin += 2 + payload_size
(我还在学习python和这个API,所以如果有任何错误,请告诉我。)
倒数第二行yield ??? 是我坚持的。有任何想法吗?如果这不是这样做的方法,请告诉我另一种方法。
【问题讨论】:
-
你为什么不从
children()返回string/string对? -
@ssbssa,因为我希望孩子们可以在像 VSCode 这样的 IDE 中折叠。
-
我曾经也需要类似的东西,所以我extended gdb 这样你就可以在
children中返回另一个漂亮的打印机,但我从未在 gdb 本身之外对其进行过测试。 -
@ssbssa,太好了!我想我可以尝试重建 gdb,但是在编译诸如编译器之类的东西时,我的成功非常有限。似乎总是有一些突出的错误使系统无法编译。 :( :D 我去看看。
-
除了伪类型之外,您还可以创建一个真正的类型。请参阅Can we define a new data type in a GDB session - Stack Overflow(但不确定它与 Visual Studio 的配合如何)
标签: python c++ gdb pretty-print gdb-python