私は、Python で gdb 用のきれいなプリンターを作成しており、ゆっくりと方法論のコツをつかんでいます。このシステムがどのように機能し、メソッドから予想される結果の例を示す実際のドキュメントを見つけようとするのは、歯を抜くようなものです。あちこちで小片を見つけましたが、すべてを網羅しているものはありません。私が把握した情報の一部は、試行錯誤の結果であり、ゆっくりと進んでいます。
これまでのところ、プリティ プリンターは文字列のみを返すことが許可されているようですto_string()
が (確かに)、 はaまたはとのペアをchildren()
返すことができます。印刷されている /c++ オブジェクト。私は実際には、きれいなプリンター オブジェクトを返して、それを呼び出せることを望んでいましたが、残念ながら、そうではありませんでした。文字列を返すこともできますが、VSCode などの IDE でペイロード要素を折りたたみ可能にしたいので、値オブジェクトを返す必要があります。これに相当するのは、Natvis の合成アイテムです。string
string
value
value
バッファーである 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
(この API だけでなく python も勉強中なので、エラーがあれば教えてください。)
最後から2番目の行yield ???
は、私が立ち往生しているものです。何か案は?これでダメなら別の方法を教えてください。