約15年前、古代のIRIXでgdbの
duel
コマンドを初めて見たとき。 異なるリンクリスト、構造体の配列、およびその他の類似の構造を表示することは、非常にクールなことでした。 彼らは、もしそれがLinuxにあれば夢見て、忘れていました。 約10年前、グーグルを思い出しました-DUEL、これは実際にはgdb 4.6の93番目のパッチであり、IRIXでユニークなものではありませんでした。 イデオロギー上の理由で、著者のみがパブリックドメインとしてリリースし、gdb-shniksもイデオロギーであり、GPLを望んでいたため、このパッチはアップストリームに入ることを脅かしませんでした。 私はそれを当時のgdb 6.6.2に移植し、gentooに提供し、7番目のgdbまで人生を楽しんだ。 その後、彼らはgentooから決闘を投げました。新しいgdbに移植するのは困難でした。誰もそれを取りませんでした。 そして最近、私は彼を復活させようとしました。 パッチの代わりにのみ(ソースからgdbと一緒に収集する必要があり、あらゆる種類の内部gdb関数を使用します)私はPythonでゼロから書きました。 Duel.py (新しいDuel実装が呼び出される)がその場でgdbにロードされるようになり、Python APIがドキュメント化されていないgdbオフセットのようにバージョン間で変更されないことを願っています。 会いましょう:DUELはgdbの高レベルのデータ分析言語です。
例
すぐに、彼ができることを示すために:
(gdb) dl table_list-->next_local->table_name tables->table_name = 0x7fffc40126b8 "t2" tables->next_local->table_name = 0x7fffc4012d18 "t1" tables-->next_local[[2]]->table_name = 0x7fffc4013388 "t1"
これはMariaDBデバッグからのものです。 このコマンドは、
TABLE_LIST
構造の
TABLE_LIST
リンクリストを
TABLE_LIST
、各リスト
TABLE_LIST::table_name
を表示し
TABLE_LIST::table_name
。
(gdb) dl longopts[0..].name @0 longopts[0].name = "help" longopts[1].name = "allow-suspicious-udfs" longopts[2].name = "ansi" <... cut ...> longopts[403].name = "session_track_schema" longopts[404].name = "session_track_transaction_info" longopts[405].name = "session_track_state_change"
そこから(テキストが乱雑にならないようにアドレスを切り取ります)。 コマンドラインオプションを指定する構造体の配列があります。 このコマンドはオプションの名前のみを表示し、配列全体を
name == 0
渡します。 そして、それらの数を計算するだけです。
(gdb) dl #/longopts[0..].name @0 #/longopts[0..].name@0 = 406
主なアイデア
デュエルは、式が多くの値を返すことができるという事実に基づいています。 例えば
(gdb) dl 1..4 1 = 1 2 = 2 3 = 3 4 = 4
またはここ
(gdb) dl my_long_options[1..4].(name,def_value) my_long_options[1].(name) = "allow-suspicious-udfs" my_long_options[1].(def_value) = 0 my_long_options[2].(name) = "ansi" my_long_options[2].(def_value) = 0 my_long_options[3].(name) = "autocommit" my_long_options[3].(def_value) = 1 my_long_options[4].(name) = "bind-address" my_long_options[4].(def_value) = 0
さらに、そのような式ジェネレーターは、単一の値が予想される場合に使用できます。 これは、考えられるすべての値の自動サイクルと見なすことができます。 2番目の例では、配列インデックスと構造体フィールドによる2サイクルですらあります。 このようなことは、配列、リスト、またはツリーなどを調べる必要がある場合に非常にうまく機能します。 特別な演算子を使用すると、ジェネレーターを停止する条件を簡単に記録できます。
オペレーター
構文はCに似ており、C-shny演算子は通常どおり機能します。 さらに興味深いのは、新しいDUEL固有の演算子です。 最も有用なものを検討してください。
範囲と列挙、..そして、
上記の両方の演算子の例を挙げました。 これらは使い慣れたデザインであり、他の言語でも使用されています。 この場合、範囲の端の1つを省略することができます。 たとえば
..20
ように範囲の終わりのみを指定した場合、範囲は0から始まり、
0..19
が書き込まれたかのように20の値が含まれ
0..19
。 開始点のみを指定すると、オープン範囲が得られます! 決闘は、宇宙の熱死(またはカウンターがオーバーフローするまでのいずれか早い方)まで数値を生成し続けないように、通常、オープンレンジと共に条件
@
による停止演算子を使用します。
条件による停止、@
式
x@y
では、式
x
は
y
偽である限り値を生成します。 例えば
(gdb) dl arr[0..]@(count > 10)
また、duelは、
arr[i].count
が10以下になるまで、
arr[]
配列の要素を出力します。
便利なショートカットとして、定数を第2オペランドとして使用できます。 次に、出力値がこの定数に等しくなると、生成が停止します。 つまり、
(gdb) dl str[0..]@0
'\0'
までの文字列のすべての文字を返します。 より実用的な例は、すべてのコマンドラインオプションを
argv
から取得することです。
(gdb) dl argv[0..]@0 argv[0] = "./mysqld" argv[1] = "--log-output=file" argv[2] = "--gdb" argv[3] = "--core-file"
同じ効果が達成されますが
(gdb) dl argv[..argc] argv[0] = "./mysqld" argv[1] = "--log-output=file" argv[2] = "--gdb" argv[3] = "--core-file"
ポインタをたどる->
ジェネレーター
a->b
、NULLにぶつかるまで、一連の値
a
、
a->b
、
a->b->b
などを生成します。 この方法で、単一リンクリストをどのように通過するかの例を既に示しました。 しかし、これは木に対してもまったく同じように機能します。例えば:
(gdb) dl tree-->(left,right)->info
ブラケットの計算{}
中括弧は通常の丸括弧のように機能しますが、出力内の式で値をさらに置き換えます。 例で表示する方が簡単です:
(gdb) dl i:=5 i = 5 (gdb) dl i+6 i+6 = 11 (gdb) dl {i}+6 5+6 = 11 (gdb) dl {i+6} 11 = 11
これは主に配列に必要です:
(gdb) dl if (my_long_options[i:=1..20].name[0] == 'd') my_long_options[i].name if(my_long_options[i].name[0] == 'd') my_long_options[i].name = "debug-abort-slave-event-count" if(my_long_options[i].name[0] == 'd') my_long_options[i].name = "debug-assert-on-error" if(my_long_options[i].name[0] == 'd') my_long_options[i].name = "debug-assert-if-crashed-table" if(my_long_options[i].name[0] == 'd') my_long_options[i].name = "debug-disconnect-slave-event-count" if(my_long_options[i].name[0] == 'd') my_long_options[i].name = "debug-exit-info" (gdb) dl if (my_long_options[i:=1..20].name[0] == 'd') my_long_options[{i}].name if(my_long_options[i].name[0] == 'd') my_long_options[16].name = "debug-abort-slave-event-count" if(my_long_options[i].name[0] == 'd') my_long_options[17].name = "debug-assert-on-error" if(my_long_options[i].name[0] == 'd') my_long_options[18].name = "debug-assert-if-crashed-table" if(my_long_options[i].name[0] == 'd') my_long_options[19].name = "debug-disconnect-slave-event-count" if(my_long_options[i].name[0] == 'd') my_long_options[20].name = "debug-exit-info"
ここで、中括弧は、配列のどの要素が条件を満たすかをすぐに示します。
フィルター<? >? <=? > =? ==? !=?
比較演算子のトピックに関するこれらのバリエーションは、実際にはフィルターとして機能します。 つまり、
x !=? y
x !=? y
、
x
の値のセットから、
y
と等しくないもののみが選択されます。 上記は
if
条件付きの例です。 フィルターを使用すると、同じ結果がより簡単になります。
(gdb) dl my_long_options[1..20].(name[0] ==? 'd' => name) my_long_options[16].(name) = "debug-abort-slave-event-count" my_long_options[17].(name) = "debug-assert-on-error" my_long_options[18].(name) = "debug-assert-if-crashed-table" my_long_options[19].(name) = "debug-disconnect-slave-event-count" my_long_options[20].(name) = "debug-exit-info"
その他のオペレーター
さらに、エイリアス、グループ演算子、条件演算子(
if
)、およびその他ほとんど必要のないものがあります。
高度な
ドキュメントからのいくつかの例を次に示します。
循環リストをたどります(先頭から始めて、再び
head
戻るまで標識に従ってください)。
(gdb) head-->(next!=?head)
配列
x[]
の2番目の正の要素を見つけます。 演算子
[[ ]]
は、シーケンスから要素を選択します。
(gdb) dl (x[0..] >? 0)[[2]]
単一リンクリストの最後のアイテムを見つけます。 ここでは、シーケンス内の要素の数を返す単項演算子
#/
、および選択演算子
[[ ]]
ます。
(gdb) head-->next[[#/head-->next - 1]]
次の要素よりも大きい配列の要素のみを返します。実際、配列が昇順でソートされているかどうかを確認します。
(gdb) dl x[i:=..100] >? x[i+1]
もう一度、最も重要なこと
そして最も重要なのは、gdbの決闘が機能することです(再び)。 Hello Worldよりも複雑なものをデバッグするときに非常に便利です。 通常の使用では、2つのポイント、コンマ、長い矢印
-->
および
@0
4つの構造で十分です。
リポジトリで私からそれを取ることができます: github.com/vuvova/gdb-tools
免責事項:DUEL自体は非常に立派で実績のあるインタープリターですが、Duel.pyはまったく新しいものですが、おそらくバグがあります。