最近遇到一個不錯的小例子, 可以比較完整地記錄用到的相關指令。更多關於 gdb 的說明, 見 gdb 初步心得。
問題
Ubuntu 下執行程式後看到 "Gtk-WARNING **: cannot open display:", 然後程式就掛了。
解決過程
為了獲取更多線索, 我想找出是那段程式輸出這個錯誤訊息。由 "Gtk-WARNING" 可知是 Gtk+ 函式庫輸出的錯誤訊息。所以得先取得 Gtk+ 的 debug symbol 和原始碼:
$ dpkg -l | grep gtk
...
ii libgtk2.0-0
...
找出已安裝的 Gtk+ 函式庫叫做 libgtk2.0, 接著找出它對應的 debug symbol package 和原始碼:
$ aptitude search libgtk2.0
i libgtk2.0-0 - GTK+ graphical user interface library
...
i libgtk2.0-0-dbg - GTK+ libraries and debugging symbols
...
i libgtk2.0-dev - development files for the GTK+ library
...
然後安裝 debug symbol, 還有取得 Gtk+ 的原始碼:
$ aptitude install libgtk2.0-0-dbg
$ apt-get source libgtk2.0-dev
從取得的原始碼找看看有沒有 "cannot open display":
$ cd gtk+2.0-2.24.10/
$ grep "cannot open display" -R .
./gtk/gtkmain.c: g_warning ("cannot open display: %s", display_name_arg ? display_name_arg : "");
./gdk/gdk.c: g_warning ("cannot open display: %s", display_name ? display_name : "");
./.pc/071_no_offscreen_widgets_grabbing.patch/gtk/gtkmain.c: g_warning ("cannot open display: %s", display_name_arg ? display_name_arg : "");
./.pc/100_overlay_scrollbar_loading.patch/gtk/gtkmain.c: g_warning ("cannot open display: %s", display_name_arg ? display_name_arg : "");
./ChangeLog.pre-2-12: * gtk/gtkmain.c: (gtk_init): Fix "cannot open display" error message
讀一下字串出現相關的位置, 找出函式 gtk_init_check 和 gdk_init_check。看來沒有找錯方向, 於是可以用 cgdb 執行程式, 進入 gdb 後輸入:
(gdb) b gtk_init_check
(gdb) b gdk_init_check
(gdb) directory /my/path/to/gtk+2.0-2.24.10/
(gdb) set substitute-path /.../gtk+2.0-2.24.10/ /my/path/to/gtk+2.0-2.24.10/
(gdb) r
- directory 用來載入 Gtk+ 原始碼。debug symbol package 裡沒有含這部份。
- 編譯封裝 Gtk+ 的路徑十之八九和我放 Gtk+ 原始碼的路徑不同, 所以要用 set substitute-path 替換路徑, gdb 才知道如何顯示對應的原始碼。上面的 "..." 是執行 backtrace 時看到的路徑, 這裡簡化用 "..." 表示。
再來就在中斷點附近輸出收到的值, 看看 backtrace, 看看附近的原始碼, 獲得更多線索後就解決問題了。原來是我忘了呼叫 setenv("DISPLAY", ":0"), gdk_init_check() 發現無法產生 GdkDisplay, 所以就掛了。