ルギア君の戯言

雑多な記事。

gdb の使い方 - その2

今回は大きなプログラムをデバッグしてみましょう。
ここでは rosegarden をデバッグしてみることにします。

デバッグシンボルの生成

gcc に渡すだけなら、-g でよかったのですが、make を使うものは make が gcc などを呼び出すので少々厄介です。
プログラムによっていくつかのパターンがあります。

cmake の場合

rosegarden のトップディレクトリを見ると、

[lugia@lugia-castle rosegarden-1.7.2]$ ls
AUTHORS         CMakeLists.txt           Doxyfile  README       cmake_admin            data  rosegarden.lsm      src
CMakeCache.txt  CMakeLists.txt.optflags  INSTALL   RGbuild      cmake_install.cmake    docs  rosegarden.spec     version.txt
CMakeFiles      COPYING                  Makefile  TRANSLATORS  cmake_uninstall.cmake  po    rosegarden.spec.in

のように CMakeLists.txt のあるものは cmake でビルドするものです。
デバッグシンボルの生成をするには、

$ cmake -DCMAKE_BUILD_TYPE=Debug .
$ make
$ sudo make install

でできます。

autotools の場合

トップディレクトリを見て configure または configure.in と言う名前の実行ファイル(正確にはスクリプト)がある場合。

$ aclocal
$ autoconf
$ automake
$ ./configure --enable-debug [その他のオプション]
$ make
$ sudo make install
Momonga Linux のパッケージ

${TOPDIR} は .OmoiKondara のあるディレクトリ。

$ cd ${TOPDIR}
$ ../tools/OmoiKondara -G -fi rosegarden

相対パスは適宜修正のこと。
rosegarden はパッケージ名。
f を忘れない。SKIP になってしまう。

どれにも当てはまらない場合
$ (Makefile がなければ生成)
$ export CFLAGS=-g && make
$ sudo make install

使用言語が C++ なら CXXFLAGS=-g に変える。

さあ、デバッグ開始だ。

パスが通っているプログラムをデバッグする場合は、プログラム名だけ指定するでは自動的に探してくれる。

[lugia@lugia-castle pkgs]$ gdb rosegarden
GNU gdb Momonga Linux 5 (6.8-8m.mo5)
Copyright (C) 2008 Free Software Foundation, Inc.
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 "i686-momonga-linux"...
(gdb)

さあ、開始。

(gdb) run                                                                    
Starting program: /usr/bin/rosegarden                                        
warning: linux_test_for_tracefork: unexpected result from waitpid (15827, status 0x57f)
Detaching after fork from child process 15829.                                         
kbuildsycoca running...                                                                
Reusing existing ksycoca                                                               

Program exited normally.
(gdb) PluginFactory::instance(dssi): creating new DSSIPluginFactory
LADSPAPluginFactory::discoverPlugins - discovering plugins; path is [/home/lugia/.dssi] [/usr/local/lib/dssi] [/usr/lib/dssi] 
...(後略)...

おや? 途中でプログラムが終了してますね。見えますか?
これではデバッグできませんね。


help を表示してみましょう。

(gdb) run --help
Starting program: /usr/bin/rosegarden --help
使用法: rosegarden [Qt-オプション] [KDE-オプション] [オプション] [File] 

Rosegarden - シーケンサと譜面エディタ

一般的なオプション:
  --help                    オプションに関するヘルプを表示
  --help-qt                 Qt に特有なオプションを表示
  --help-kde                KDE に特有なオプションを表示
  --help-all                すべてのオプションを表示
  --author                  著作者情報
  -v, --version             バージョン情報を表示
  --license                 ライセンス情報を表示
  --                        オプションの最後

オプション:
  --nosequencer             シーケンサは使えません (編集のみサポート)
  --nosplash                スプラッシュスクリーンを表示しない
  --nofork                  バックグラウンドで自動的に起動しない
  --existingsequencer       もしも見付かれば、シーケンサプロセスに接続
  --ignoreversion           インストールされたバージョンを無視 - 開発者のみ

引数:
  File                      ファイルをオープン

Program exited with code 0376.
(gdb)

ということなので、今回デバッグするところはシーケンサでは無いので、--nosequencer も付けて

(gdb) run --nosequencer --nofork --nosplash
Starting program: /usr/bin/rosegarden --nosequencer --nofork --nosplash
kbuildsycoca running...
Composition::getTrackById(0) - WARNING - track id not found, this is probably a BUG /home/lugia/Momonga/pkgs/rosegarden/BUILD/rosegarden-1.7.2/src/base/Composition.cpp:1533
Available track ids are:
RosegardenGUIApp::awaitDialogClearance: entering
RosegardenGUIApp::awaitDialogClearance: exiting
TrackButtons::slotUpdateTracks

WARNING: Unstable LilyPond version detected, selecting next language version up

はい。ここでメインウィンドウがでてきて止まります。
とりあえず、落ちてしまう操作をやってみましょう。今回やった操作は

WARNING: please edit ~/.scim/global and change /DefaultConfigModule to kconfig

Program received signal SIGABRT, Aborted.
0x00110416 in __kernel_vsyscall ()
(gdb)

この操作をやると、SIGABRT を発行しているということですね。
さて、では bt の出番がやって参りました。

(gdb) bt                                 
#0  0x00110416 in __kernel_vsyscall ()
#1  0x00c85440 in raise () from /lib/libc.so.6
#2  0x00c86e08 in abort () from /lib/libc.so.6
#3  0x00cc93e3 in ?? () from /lib/libc.so.6
#4  0x00ccb305 in free () from /lib/libc.so.6
#5  0x0032a281 in operator delete () from /usr/lib/libstdc++.so.6
#6  0x0868f4ba in ~HSpinBox (this=0xa61be50) at /home/lugia/Momonga/pkgs/rosegarden/BUILD/rosegarden-1.7.2/src/gui/widgets/HSpinBox.h:32
#7  0x028617c7 in QWidget::~QWidget () from /usr/lib/qt-3.3.7/lib/libqt-mt.so.3
#8  0x02b783f5 in QFrame::~QFrame () from /usr/lib/qt-3.3.7/lib/libqt-mt.so.3
#9  0x028617c7 in QWidget::~QWidget () from /usr/lib/qt-3.3.7/lib/libqt-mt.so.3
#10 0x028e280b in QGroupBox::~QGroupBox () from /usr/lib/qt-3.3.7/lib/libqt-mt.so.3
#11 0x028617c7 in QWidget::~QWidget () from /usr/lib/qt-3.3.7/lib/libqt-mt.so.3
#12 0x02b8d7b5 in QVBox::~QVBox () from /usr/lib/qt-3.3.7/lib/libqt-mt.so.3
#13 0x028617c7 in QWidget::~QWidget () from /usr/lib/qt-3.3.7/lib/libqt-mt.so.3
#14 0x029bbd78 in QDialog::~QDialog () from /usr/lib/qt-3.3.7/lib/libqt-mt.so.3
#15 0x0414cc84 in KDialogBase::~KDialogBase () from /usr/lib/libkdeui.so.4
#16 0x08439694 in ~TempoDialog (this=0xbfffe1f8)
    at /home/lugia/Momonga/pkgs/rosegarden/BUILD/rosegarden-1.7.2/src/gui/dialogs/TempoDialog.cpp:189
#17 0x08592035 in Rosegarden::TempoView::slotPopupEditor (this=0x8e06180, qitem=0x91323c8)
    at /home/lugia/Momonga/pkgs/rosegarden/BUILD/rosegarden-1.7.2/src/gui/editors/tempo/TempoView.cpp:793
#18 0x0859546d in Rosegarden::TempoView::qt_invoke (this=0x8e06180, _id=109, _o=0xbfffe524)
    at /home/lugia/Momonga/pkgs/rosegarden/BUILD/rosegarden-1.7.2/RGbuild/TempoView.moc:167
#19 0x028270ca in QObject::activate_signal () from /usr/lib/qt-3.3.7/lib/libqt-mt.so.3
#20 0x02b80401 in QListView::doubleClicked () from /usr/lib/qt-3.3.7/lib/libqt-mt.so.3
#21 0x04127925 in KListView::contentsMouseDoubleClickEvent () from /usr/lib/libkdeui.so.4
#22 0x029459e0 in QScrollView::viewportMouseDoubleClickEvent () from /usr/lib/qt-3.3.7/lib/libqt-mt.so.3
#23 0x02944561 in QScrollView::eventFilter () from /usr/lib/qt-3.3.7/lib/libqt-mt.so.3
#24 0x029107e6 in QListView::eventFilter () from /usr/lib/qt-3.3.7/lib/libqt-mt.so.3
#25 0x02827183 in QObject::activate_filters () from /usr/lib/qt-3.3.7/lib/libqt-mt.so.3
#26 0x028271eb in QObject::event () from /usr/lib/qt-3.3.7/lib/libqt-mt.so.3
#27 0x028618fc in QWidget::event () from /usr/lib/qt-3.3.7/lib/libqt-mt.so.3
#28 0x027c156d in QApplication::internalNotify () from /usr/lib/qt-3.3.7/lib/libqt-mt.so.3
#29 0x027c2774 in QApplication::notify () from /usr/lib/qt-3.3.7/lib/libqt-mt.so.3
#30 0x039eff72 in KApplication::notify () from /usr/lib/libkdecore.so.4
#31 0x0275ad5e in QApplication::sendSpontaneousEvent () from /usr/lib/qt-3.3.7/lib/libqt-mt.so.3
#32 0x02757d08 in QETWidget::translateMouseEvent () from /usr/lib/qt-3.3.7/lib/libqt-mt.so.3
#33 0x02756fbe in QApplication::x11ProcessEvent () from /usr/lib/qt-3.3.7/lib/libqt-mt.so.3
#34 0x0276acf4 in QEventLoop::processEvents () from /usr/lib/qt-3.3.7/lib/libqt-mt.so.3
#35 0x027d9de0 in QEventLoop::enterLoop () from /usr/lib/qt-3.3.7/lib/libqt-mt.so.3
#36 0x027d9c76 in QEventLoop::exec () from /usr/lib/qt-3.3.7/lib/libqt-mt.so.3
#37 0x027c1bff in QApplication::exec () from /usr/lib/qt-3.3.7/lib/libqt-mt.so.3
#38 0x083808ec in main (argc=4, argv=0xbffff284)
    at /home/lugia/Momonga/pkgs/rosegarden/BUILD/rosegarden-1.7.2/src/gui/application/main.cpp:733

上から順に見ていきましょ。
上の方は libc と qt ですから、今回のデバッグの対象ではありません。それをわけると、#6 の ~HSpinBox と #16 の ~TempoDialog が rosegarden の関数ですね。ですから、ここに breakpoint を置きたいのですが、C++ のコンストラクタとデストラクタにブレークポイントを設定することができません。
なので、そのもうひとつ上の Rosegarden::TempoView::slotPopupEditor をブレークポイントに設定しましょう。

(gdb) run
Starting program: /usr/bin/rosegarden --nosplash --nosequencer --nofork
kbuildsycoca running...
Composition::getTrackById(0) - WARNING - track id not found, this is probably a BUG /home/lugia/Momonga/pkgs/rosegarden/BUILD/rosegarden-1.7.2/src/base/Composition.cpp:1533
Available track ids are:
RosegardenGUIApp::awaitDialogClearance: entering
RosegardenGUIApp::awaitDialogClearance: exiting
Comparing current version "1.7.2" with latest version "1.7.2"

WARNING: Unstable LilyPond version detected, selecting next language version up

2回目以降の run は前回の引数がそのまま使われます。
便利ですね。

Breakpoint 1, Rosegarden::TempoView::slotPopupEditor (this=0x910dc70, qitem=0x9149920)
    at /home/lugia/Momonga/pkgs/rosegarden/BUILD/rosegarden-1.7.2/src/gui/editors/tempo/TempoView.cpp:768
768         TempoListItem *item = dynamic_cast<TempoListItem *>(qitem);
(gdb) u
769         if (!item)
(gdb)
772         timeT time = item->getTime();
(gdb)
774         switch (item->getType()) {
(gdb)
778             TempoDialog dialog(this, getDocument(), true);
(gdb)
779             dialog.setTempoPosition(time);
(gdb)
787                     SIGNAL(changeTempo(timeT,
(gdb)
792             dialog.exec();
(gdb)
コマンド 省略形
until u
continue c
step s

覚えておくと良いかもしれません。
目的のダイアログがでてきました。
OKを押すと

Program received signal SIGABRT, Aborted.
0x00110416 in __kernel_vsyscall ()
(gdb)

となってしまいますので、step-in したいのですが、相手は GUI なので、難しいところです。
やってみれば判ります。ここでは省略(コラ
ということで何とかして #3 に設定したいところですね。できますよ。
関数名として指定できないだけですので(ぁ

/...(省略).../rosegarden-1.7.2/src/gui/widgets/HSpinBox.h

の中身を見ながらこのファイル内でブレークできそうなところを探します。
・・・無さそうですね。
残念! 他の関数はおろかデストラクタも定義されていませんでした。


ということは標準のデストラクタを呼び出しているので、もしかしたら rosegarden が問題じゃない・・・かも知れませんね。