前のVerぐらいから、リポジトリに載らなくなって寂しいemerald。
個人的には気に入ってるウィンドウデコレータなので、使いつづけたいのが本音。
というわけで、
http://ameblo.jp/newcomer-t/entry-11236483466.html
あたりを参考にさせてもらいつつ導入…してみたが、自分の環境では見事にsegfault。残念すぎる。
同じ症状の人は他にもいるようで、↑の元記事の
http://iamfuss.deviantart.com/journal/Install-emerald-for-Ubuntu-12-04-292806813
でも言われている。
折角なので、gdbの練習がてら、デバッグ/修正をやってみた。
gdbまともに使うのは初めてなので、試行錯誤も含めて備忘録としてまとめ。
本家に報告したいけど、どうやっていいか分からん…
野良パッケージを作っておいたので、欲しい人は自己責任でどうぞ。
http://miraimaker.com/archive/emerald_0.9.5-fix-for-ubuntu-12.04-1_amd64.deb
まずはソースコードの取得とmake install。
/usr/local/binにパス通してなくて、別に多少ごちゃついてもいいやって人は適宜configureの—prefix引数を変更すること。
$ git clone git://anongit.compiz.org/fusion/decorators/emerald $ cd emerald $ ./autogen.sh && make clean && make distclean && ./configure --prefix=/usr/local && make && sudo make install
で、emeraldのgitリポジトリがあるディレクトリ内でそのままgdbを走らせる。
元々GTKのデコレータとかが走ってる場合は、emerald —replaceとかやって強制終了。乱暴だなー。
そのままemeraldが動いた人はおめでとう。ダメな人はsegfaultで落ちるはず。
落ちたら、以下のコマンドでgdbに食わせつつ再実行。
$ gdb emerald GNU gdb (Ubuntu/Linaro 7.4-2012.04-0ubuntu1) 7.4-2012.04 Copyright (C) 2012 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 "x86_64-linux-gnu". For bug reporting instructions, please see: <http://bugs.launchpad.net/gdb-linaro/>... Reading symbols from /usr/local/bin/emerald...done. (gdb)
この「分かってる奴だけ触っていいよ^^」的なコンソールにおののきながら、とりあえずrun。
(gdb) r
Starting program: /usr/local/bin/emerald
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
[New Thread 0x7fffef558700 (LWP 28023)]
[New Thread 0x7fffedce6700 (LWP 28024)]
Program received signal SIGSEGV, Segmentation fault.
decor_quads_to_property (data=0x20, n=<optimized out>, pixmap=46137490, frame=0x7fffffffd9b0, border=0x7fffffffd9b0, max_frame=0x7fffffffd9b0,
max_border=0x7fffffffd9b0, min_width=0, min_height=0, quad=0x7fffffffc9a0, nQuad=8, frame_type=16777215, frame_state=0, frame_actions=0)
at /usr/include/x86_64-linux-gnu/bits/string3.h:52
52 return __builtin___memcpy_chk (__dest, __src, __len, __bos0 (__dest));
(gdb)
見事にコケました。
なんかぱっと見、string3.hの52行目で落ちてるんだけど、先に答え言うと、これは標準?ライブラリのmemcpy関数呼び出しで死んでるらしい。
んで、decor_quads_to_property関数の中でそれが起きてると。
…とりあえずバックトレースを眺めてみよう。
(gdb) bt
#0 decor_quads_to_property (data=0x20, n=<optimized out>, pixmap=46137490, frame=0x7fffffffd9b0, border=0x7fffffffd9b0, max_frame=0x7fffffffd9b0,
max_border=0x7fffffffd9b0, min_width=0, min_height=0, quad=0x7fffffffc9a0, nQuad=8, frame_type=16777215, frame_state=0, frame_actions=0)
at /usr/include/x86_64-linux-gnu/bits/string3.h:52
#1 0x000000000040d59e in update_default_decorations (screen=<optimized out>, fs_inact=0x61a070, fs_act=<optimized out>) at main.c:2437
#2 0x00000000004116e1 in update_settings (ws=0x6188b0) at main.c:5339
#3 0x0000000000406bd7 in main (argc=1, argv=0x7fffffffdb88) at main.c:5633
(gdb)
#1を見ると、main.cの2437行目で呼んでるみたい。
emerald/src/main.cを見ると、確かに呼んでいる。
どうも、引数がおかしそうな感じだなー。
…ところでdecor_quads_to_property関数ってどこで定義されてんの?
gdbで詳細を見てみよう。
(gdb) info symbol decor_quads_to_property decor_quads_to_property in section .text of /usr/lib/libdecoration.so.0 (gdb)
…libdecoration.soとやらで定義されてるらしい。
emeraldのソースにはそんなの無かったっぽいしなぁ…別のパッケージ?
$ aptitude search libdecoration i libdecoration0 - Compiz window decoration library p libdecoration0:i386 - Compiz window decoration library i libdecoration0-dev - Compiz window decoration library - development files p libdecoration0-dev:i386 - Compiz window decoration library - development files
あったあった。じゃ、libdecoration0のソースを取得して眺めてみよう。
ソース取得時に結構なファイルをカレントディレクトリに残すから、専用のディレクトリを作成して…
$ cd ~/ $ mkdir src $ cd src $ apt-get source libdecoration0
なんと、compizのソースが全部落ちてきた。
パッケージ概要にも書かれている通り、compizのウィンドウ装飾で使われるライブラリだから、一緒に開発されてるのかな。
面倒だけど、とりあえず当該ソースを探してみる。
$ cd compiz-0.9.7.6 $ find -name libdecoration* ./libdecoration $ cd libdecoration $ ls CMakeLists.txt config.h.libdecoration.in decoration.c libdecoration.pc.in
decoration.cがそれっぽいので、中を見てみると、中にdecor_quads_to_property関数を発見!
さて、定義を見てみよう。
157 void
158 decor_quads_to_property (long *data,
159 unsigned int n,
160 Pixmap pixmap,
161 decor_extents_t *frame,
162 decor_extents_t *border,
163 decor_extents_t *max_frame,
164 decor_extents_t *max_border,
165 int min_width,
166 int min_height,
167 decor_quad_t *quad,
168 int nQuad,
169 unsigned int frame_type,
170 unsigned int frame_state,
171 unsigned int frame_actions)
172 {
へー…全然わからん。
とりあえず、さっきgdbで見た引数の内容と照らし合わせてみると…
decor_quads_to_property (data=0x20, n=<optimized out>, pixmap=46137490, frame=0x7fffffffd9b0, border=0x7fffffffd9b0, max_frame=0x7fffffffd9b0,
max_border=0x7fffffffd9b0, min_width=0, min_height=0, quad=0x7fffffffc9a0, nQuad=8, frame_type=16777215, frame_state=0, frame_actions=0)
…なんか最初の引数からしておかしい。
関数定義ではポインタを渡さないといけないはずなのに、渡してるのはどうみても値だよね?
で、decor_quads_to_propertyの開幕で、
175 data += PROP_HEADER_SIZE + n * (BASE_PROP_SIZE + QUAD_PROP_SIZE * N_QUADS_MAX); 176 177 memcpy (data++, &pixmap, sizeof (Pixmap));
…とかやってる。
えーと、dataが0x20で、それに多少足したり掛けたりしたとこで、どうみても正常なアドレスになりそうもない。んでmemcpyに失敗。
原因はこれっぽいなぁ。
…で、dataにはどういうアドレスが入るといいのか。元のemerald/src/main.cで、dataにアドレスを代入しているところを見てみよう。
$ grep "data =" main.c -n 419: long *data = NULL; 443: data = malloc (sizeof (long) * (2 + size * 6)); 475: long* data = NULL; 507: data = decor_alloc_property (1, WINDOW_DECORATION_TYPE_PIXMAP); 1933: long* data = NULL; 1944: data = decor_alloc_property (1, WINDOW_DECORATION_TYPE_PIXMAP); 2349: long *data = NULL; 2375: data = decor_alloc_property (1, WINDOW_DECORATION_TYPE_PIXMAP); 2942: data = NULL; 2959: data = NULL;
なるほど、基本はdecor_alloc_property関数でポインタを取得するらしい。
さっき止まったのは2437行目だから、一番近そうな2375行目をターゲットにしよう。
gdbをもう一回立ち上げて、ブレークポイントを張る。2375行目と、コケる直前の2435行目に。
(gdb) b 2375 Breakpoint 1 at 0x40d2b8: file main.c, line 2375. (gdb) b 2435 Breakpoint 2 at 0x40d500: file main.c, line 2435. (gdb) r Starting program: /usr/local/bin/emerald [Thread debugging using libthread_db enabled] Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1". [New Thread 0x7fffef558700 (LWP 29141)] [New Thread 0x7fffedce6700 (LWP 29142)] Breakpoint 2, update_default_decorations (screen=<optimized out>, fs_inact=0x61a070, fs_act=<optimized out>) at main.c:2435 2435 (*d.draw) (&d);
あらら、2375行目は通らないで、2435行目に来てしまった。
p dataとかやって中を見ても、当然代入はされてない。
他にdataに値を代入してるところは、このupdate_default_decorations関数にはなさそうだし…2375行目を通らない理由を探してみよう。
2367 if (ws->shadow_pixmap)
2368 {
...略...
2374
2375 data = decor_alloc_property (1, WINDOW_DECORATION_TYPE_PIXMAP);
2376
...略...
2387 }
2388 else
2389 XDeleteProperty(xdisplay, xroot, bareAtom);
なんか、ws->shadow_pixmapとやらがセットされてないと通らないらしい。
実際、gdbでp ws->shadow_pixmapとかすると0x0が返ってくる。
面倒なので、強引にdataをセットしてみよう。decor_alloc_propertyの引数はよくわからんけど、さっきのgrepで見た感じは大体全部一緒っぽいし。
さっきの2375行目を、if文の前に持ってきて…
diff --git a/src/main.c b/src/main.c
index 520738c..0462ddf 100644
--- a/src/main.c
+++ b/src/main.c
@@ -2363,6 +2363,7 @@ update_default_decorations(GdkScreen * screen, frame_settings * fs_act,
bareAtom = XInternAtom(xdisplay, DECOR_BARE_ATOM_NAME, FALSE);
activeAtom = XInternAtom(xdisplay, DECOR_ACTIVE_ATOM_NAME, FALSE);
+ data = decor_alloc_property (1, WINDOW_DECORATION_TYPE_PIXMAP);
if (ws->shadow_pixmap)
{
@@ -2372,7 +2373,6 @@ update_default_decorations(GdkScreen * screen, frame_settings * fs_act,
nQuad = set_shadow_quads(quads, width, height, ws);
- data = decor_alloc_property (1, WINDOW_DECORATION_TYPE_PIXMAP);
decor_quads_to_property(data, 0, GDK_PIXMAP_XID(ws->shadow_pixmap),
&ws->shadow_extents, &ws->shadow_extents, &ws->shadow_extents, &ws->shadow_extents,
それじゃ、試しにmakeして再実行。
$ make clean && make && sudo make install $ emerald --replace
おー、動いた動いた!すごい適当な修正だけど、まぁいいか。

![yoyoyonoyo:
「ゆっくり・・・」/「いちむー」のイラスト [pixiv]](http://24.media.tumblr.com/tumblr_lyr6i7Jft51r3y9eto1_500.jpg)