gdb決闘-コマンドラインに対するリスト、ツリー、ハッシュテーブル


約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では、式xy偽である限り値を生成します。 例えば

 (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にぶつかるまで、一連の値aa->ba->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 !=? yxの値のセットから、 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はまったく新しいものですが、おそらくバグがあります。

Source: https://habr.com/ru/post/J328180/


All Articles