読者です 読者をやめる 読者になる 読者になる

emacs + gdbの組み合わせが素敵( ´∀`)ノ

debug

この前のDebug Hacks Nightで実演していたemacs + gdbの組み合わせは便利!!
今まではタブが使えるターミナルで一個目のタブでemacs、2個目のタブでgdbとゆう感じでやってたけど1画面で見れるし、
gdbでの実行状態とemacs上のカーソルが連携してくれるからすごく楽ヽ( ´∀`)ノ
唯一の欠点は縦の表示領域が狭くなることくらいか。

これのおかげでgimageviewがセグフォルトする件を無理やり直すことができた(v^ー゚)ヤッタネ!!
#今までは写真を4、5枚表示したら落ちてたけど、
#いまのところ落ちていないだけだけど。。。。
でも、正しい直し方をしているとは思えないのでパッチを送るのは控えたい・゚・(つД`)・゚・ ウェ

でもでも、取り合えずデバッグのメモは残すことに。

通常自分は、パッケージをちゃんと作るときはcowbuilderでビルドするんですが、今回はこんな感じでビルドを実行
1.dpkg-checkbuilddepsコマンドで足りないものをインスコ
2.debian/rurlsのdh_stripをコメントアウト
#stripされると必要な情報消えちゃうから
3.dch -iで適当にchangelog追加
4.debuild -us -uc -rfakerootでビルド
5.出来たバイナリをインストール

そんでデバッグ開始!
#今さっきやったばっかりですが、うろ覚えです。。
まずは本当にどこで落ちているか知りたいので普通にgdbを起動してgimvを実行する。
おっと、runの前にソースがあるディレクとをgdbに教えてあげる。

$gdb /usr/bin/gimv
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-linux-gnu"...
(gdb) source /home/masami/build/gimageview/gimageview-0.2.27/src
(gdb) r
[Thread debugging using libthread_db enabled]
[New Thread 0x7f51c6728780 (LWP 19183)]

そうするとこんな感じでメッセージが拾えたので、次はemacsからgdbを動かす。

Program received signal SIGSEGV, Segmentation fault.
[Switching to Thread 0x7f0267edb780 (LWP 7347)]
0x0000000000427bc2 in gimv_zlist_moveto (list=0x12bf000, index=<value optimized out>) at gimv_zlist.c:2389

ソースコード的にはここで、adjがNULLだったのでNULLポインタアクセスで死んでたと。

adj->value += (cell_area.y - adj->page_size) + cell_area.height;

それではemacs+gdbデバッグ開始。

$emacs gimv_zlist.c

このファイルの2389行目の関数名を調べるとgimv_zlist_moveto()だと分かった。
gdbemacsから起動するのはM-x gdb。実行するコマンドは/usr/bin/gimvを指定。
gdbが起動したら先ほどと同じくsourceコマンドもしておいた。
次に落ちる関数が分かっているので、この関数にブレークポイントを設定。

ブレーク張って動かしたことで分かったのが、(次/前)の写真へ移動するときにこの間数が呼ばれているということ。
やっているのは、写真の大きさによって画面のサイズをリサイズしているような感じ。

この関数の処理をgdbで見ていると、落ちる原因になっている変数はGIMV_SCROLLEDといマクロを使ってリストから構造体のメンバを代入した結果はいつもNULLが返ってきていた。

  } else { /* vertical list */

      adj = GIMV_SCROLLED(list)->v_adjustment;

      if (cell_area.y < 0) {
         adj->value += cell_area.y;
#ifdef USE_GTK2
         g_signal_emit_by_name (G_OBJECT(adj), "value_changed");
#else /* USE_GTK2 */
         gtk_signal_emit_by_name (GTK_OBJECT(adj), "value_changed");
#endif /* USE_GTK2 */
      }

      if (cell_area.y + cell_area.height > GTK_WIDGET(list)->allocation.height) {
         adj->value += (cell_area.y - adj->page_size) + cell_area.height;
#ifdef USE_GTK2
         g_signal_emit_by_name (G_OBJECT(adj), "value_changed");
#else /* USE_GTK2 */
         gtk_signal_emit_by_name (GTK_OBJECT(adj), "value_changed");
#endif /* USE_GTK2 */
      }
   }

これの原因はなんとなく、(多分)stderrに出力されている、↓のメッセージが怪しい気が・・・

(gimv:19176): Gtk-WARNING **: gtk_scrolled_window_add(): cannot add non scrollable widget use gtk_scrolled_window_add_with_viewport() instead

ということで、正しい直し方はgtkウィジェットの使い方を最新のGtkに合わせて上げれば良い気がした。
でも、gtk_scrolled_window_add()を呼んでいる箇所がsrcディレクトリで見つけられなかったので、
この関数にある写真切り替わり時のリサイズ周りの処理を消すという力業で今日のデバッグは糸冬

--- gimageview-0.2.27.old/src/gimv_zlist.c	2004-09-21 17:44:32.000000000 +0900
+++ gimageview-0.2.27/src/gimv_zlist.c	2009-06-02 22:39:38.000000000 +0900
@@ -2349,7 +2349,7 @@
       return;
 
    gimv_zlist_cell_area (list, index, &cell_area);
-
+#if 0
    if (list->flags & GIMV_ZLIST_HORIZONTAL) { /* horizontal list */
 
       adj = GIMV_SCROLLED(list)->h_adjustment;
@@ -2394,6 +2394,7 @@
 #endif /* USE_GTK2 */
       }
    }
+#endif // 0
 }