(gdb) p/t table->read_set->bitmap[0] @ (table->read_set->n_bits+7)/8
「でたらめはどうだ」と思った。 そしてすべてをまとめて......
PythonのPretty Printerはクラスです。 コンストラクターで、出力される値がコンストラクターに渡されます(これは単なるスカラーではなく、
gdb.Value
)。 また、このクラスには
to_string()
メソッドがあり、実際には、見たいものを返します。 たとえば、次のように:
class BitmapPrinter: def __init__(self, val): self.val = val def to_string(self): s='' for i in range((self.val['n_bits']+7)//8): s = format(int(self.val['bitmap'][i]), '032b') + s return "b'" + s[-int(self.val['n_bits']):] + "'" class StringPrinter: def __init__(self, val): self.val = val def to_string(self): return '_' + self.val['str_charset']['name'].string() + \ ' "' + self.val['Ptr'].string('ascii', 'strict', self.val['str_length']) + '"'
それだけではありません。 この
gdb.Value
の型をチェックし、クラスを使用するかどうかを決定する関数もあります。 簡単にするために、
gdb.printing
モジュールには、次のような正規表現を使用する既製の実装があります。
import gdb.printing def build_pretty_printer(): pp = gdb.printing.RegexpCollectionPrettyPrinter( "my_library") pp.add_printer('String', '^String$', StringPrinter) pp.add_printer('bitmap', '^st_bitmap$', BitmapPrinter) return pp gdb.printing.register_pretty_printer( gdb.current_objfile(), my_library.build_pretty_printer()
引数には、
pp.add_printer()
名前、タイプの正規名、およびこのタイプを出力するクラスがあります。
私の好みのために-少し複雑。 クラスには多くの余計なものがあります。本当に必要なのは
to_string()
メソッドだけです。他のすべてはクラスからクラスにコピーされます。 プリンターの登録コードも少し多く、タイプ名が3回続けて繰り返されます。
はい、ポインターは処理されません。 私はそれがgdbのようになりたいです:
(gdb) p opt_tc_log_file $2 = 0x555556204273 "tc.log" (gdb) p table->field[0] $3 = (Field_varstring *) 0x555557437a88
つまり、ポインターがある場合、タイプ、アドレスが表示され、値は文字列と同じになります。 これを行うには、
StringPtrPrinter
と
BitmapPtrPrinter
2つのクラスをリベットします
to_string()
ほぼ同じですが、アドレスも表示します。 また、チェックを前後に追加することで、すでに書き込まれているものを展開して、
val
がポインターであるときにキャッチし、それに応じてアドレスを出力できるようにすることができます。 何らかの方法で、コピーしてコピーします。 クラスからクラスへの同じコード。 すぐに飽きて、すべてを単純化し始めました。 理想的には、これらのプリンターを次のように書きたいと思いました。
@PrettyPrinter def String(val): return '_' + val['str_charset']['name'].string() + \ ' "' + val['Ptr'].string('ascii', 'strict', val['str_length']) + '"' @PrettyPrinter def st_bitmap(val): s='' for i in range((val['n_bits']+7)//8): s = format(int(val['bitmap'][i]), '032b') + s return "b'" + s[-int(val['n_bits']):] + "'"
ビジネスでのみ。 残りは単独で動作します。 しかし、それが私の手なのか、デコレータと
gdb.printing
共謀したのかは
gdb.printing
ませんが、ラッパーがラッパーの上に座ってラッパーを追いかけていることが
gdb.printing
ました。
ここにコードがあります
import gdb.printing def PrettyPrinter(arg): name = getattr(arg, '__name__', arg) def PrettyPrinterWrapperWrapperWrapper(func): class PrettyPrinterWrapperWrapper: class PrettyPrinterWrapper: def __init__(self, prefix, val, cb): self.prefix = prefix self.val = val self.cb = cb def to_string(self): return self.prefix + self.cb(self.val) def __init__(self, name, cb): self.name = name self.enabled = True self.cb = cb def __call__(self, val): prefix = '' if val.type.code == gdb.TYPE_CODE_PTR: prefix = '({}) {:#08x} '.format(str(val.type), long(val)) try: val = val.dereference() except: return None valtype = val.type.unqualified() if valtype.name == self.name: return self.PrettyPrinterWrapper(prefix, val, self.cb) if valtype.strip_typedefs().name == self.name: return self.PrettyPrinterWrapper(prefix, val, self.cb) return None pp = PrettyPrinterWrapperWrapper(name, func) gdb.printing.register_pretty_printer(None, pp, True) return func if callable(arg): return PrettyPrinterWrapperWrapperWrapper(arg) return PrettyPrinterWrapperWrapperWrapper
要するに、それはどのように機能しますか? デコレータは単に関数名を取得し、このタイプのきれいなプリンタを登録します。 関数自体と
gdb.Value
値は、どちらも
gdb.Value
クラスのコンストラクターに渡されます。 そして
to_string()
により、この値でこの関数を呼び出します。
さらに、プリティプリンタをgdbに登録するには、呼び出し可能な別のクラスが必要であり、使用するプリティプリンタを選択します。 最初の例では、これはネイティブのgdb-shny
gdb.printing.RegexpCollectionPrettyPrinter
ですが、これは必要ないので、ポーカーと遊女の独自のクラスがあります。 値がポインタであるときを自動的に検出し、
(Typename *) address
を出力し
(Typename *) address
。 そして、対応するPrettyPrinterWrapperを作成して返します。 typedefをサポートします。 もちろん、PrettyPrinterWrapperWrapperと呼ばれます。 それから私もそれが面白いと思った。
その後、
Alter_inplace_info::HA_ALTER_FLAGS
ような名前で判明したため、Pythonで関数を作成できなかったため、デコレーターに引数として型名を受け入れさせる必要がありました。
@PrettyPrinter('Alter_inplace_info::HA_ALTER_FLAGS') def HA_ALTER_FLAGS(val): s='' ...
これを行う方法は? Pythonでは、そのようなデコレータは1つの引数で呼び出され、関数自体をデコレートする新しいデコレータを返します。 ここで私はすでに病気でしたが、止めるには遅すぎました。 デコレータが作成し、それ自体がPrettyPrinterWrapperWrapperオブジェクトを作成する関数は、当然ながらPrettyPrinterWrapperWrapperWrapperとして知られるようになりました。 幸い、この段階ですべてが機能し、ラッパーbacchanaliaは停止しました。
しかし、プリンター自体は今では簡単でエレガントに書かれています。
@PrettyPrinter def sql_mode_t(val): s='' modes=['STRICT_TRANS_TABLES', 'STRICT_ALL_TABLES', 'NO_ZERO_IN_DATE', 'TRADITIONAL', 'NO_AUTO_CREATE_USER', 'HIGH_NOT_PRECEDENCE', 'NO_ENGINE_SUBSTITUTION', 'PAD_CHAR_TO_FULL_LENGTH'] for i in range(0,len(modes)): if val & (1 << i): s += ',' + modes[i] return s[1:]
使用中、これらすべてが完全に自動的にデバッグに必要な美しさを誘発します:
(gdb) p table->alias $1 = _binary "t3" (gdb) p &table->alias $2 = (String *) 0x7fffd409c250 _binary "t3" (gdb) p table->read_set[0] $3 = b'10011' (gdb) p thd->variables.sql_mode $4 = STRICT_TRANS_TABLES,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION (gdb) p ha_alter_info.handler_flags $5 = ADD_INDEX,DROP_INDEX,ADD_PK_INDEX,ALTER_STORED_COLUMN_ORDER
はい、自宅でそのようなデコレータを使用したい人のために-これはすべてPython 2です。3番目の場合、あなたはファイルでそれを処理する必要があります。 パッチは大歓迎です。