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



では、式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はまったく新しいものですが、おそらくバグがあります。



All Articles