らんだむな記憶

blogというものを体験してみようか!的なー

gdb様のお通りだー

printfデバッグ様のお通りだー - らんだむな記憶入口は正しそうだと分かったが、その先がよく分からん。これだとprintfデバッグのコストが大分高くつく。ということで、気が進まないがgdbを使おう。

bootstrapのほうはあまり見たくなくて、configureのほうをいぢくっとく。

$ diff -Naur configure.orig configure
--- configure.orig      2016-01-02 00:38:43.520700700 +0900
+++ configure   2016-01-02 00:41:57.829813638 +0900
@@ -5215,7 +5215,7 @@
   CFLAGS=$ac_save_CFLAGS
 elif test $ac_cv_prog_cc_g = yes; then
   if test "$GCC" = yes; then
-    CFLAGS="-g -O2"
+    CFLAGS="-g -ggdb -O0"
   else
     CFLAGS="-g"
   fi

で、本当にうまくいっているか不安なので、ビルド時にverboseなログを見たい。個人的には常に見たいけど「CC hoge」みたいな恥ずかしがり屋なビルドログにしていることが多い。すべて晒せ!ということで、

./configure --disable-silent-rules

して再ビルド。「-g -ggdb -O0」が見えるね。いけてそう。
...おや?「fontforge」自体はシェルスクリプトなのか...。最近こういうの多いな...。実行形式の上にスクリプトが薄いwrapperとして用意されているやつ。面倒なんだよねー
よいしょっと。

$ diff -Naur fontforge.orig fontforge
--- fontforge.orig      2016-01-02 00:56:05.153294137 +0900
+++ fontforge   2016-01-02 00:57:30.591995002 +0900
@@ -114,7 +114,8 @@
         $ECHO "fontforge:fontforge:${LINENO}: newargv[0]: $progdir/$program" 1>&2
         func_lt_dump_args ${1+"$@"} 1>&2
       fi
-      exec "$progdir/$program" ${1+"$@"}
+      gdb "$progdir/$program" ${1+"$@"}
+      #exec "$progdir/$program" ${1+"$@"}
 
       $ECHO "$0: cannot exec $program $*" 1>&2
       exit 1

で、

(gdb) b charview.c:CVMenuRound2Int
No source file named charview.c.

あれ?めんどいなぁ~... まだ該当部分のコードがメモリ上にロードされてないってこと??
後からattachしてみるかな。

$ gdb --pid=`ps aux | grep lt-fontforge | grep -v grep | awk '{print $2}'`
...
Attaching to process xxxx
Could not attach to process.  If your uid matches the uid of the target

あら、なんかダメだ。う~む。

よく分からんので、一旦gdbをかませた状態で起動させて、rで当分走らせておいて、グリフ一覧が出た頃合いで、Ctrl+Cでgdbのコンソールを呼び出す。そして、

(gdb) b charview.c:CVMenuRound2Int
Breakpoint 1 at 0x7ffff786503a: file charview.c, line 9707.

で、なんかbreak point置けたね。色々よく分からんけど、まぁ、いいや。
それ、また走っとけ。

(gdb) c

で、ぽちぽちぽちっと。よっしゃ、来たッ

Breakpoint 1, CVMenuRound2Int (gw=0x900dd0, UNUSED_mi=0x90f4f0, UNUSED_e=0x7fffffffb5f0) at charview.c:9707
9707            printf("*** CVMenuRound2Int: enter\n");
(gdb) list
9702        }
9703        CVCharChangedUpdate(&cv->b);
9704    }
9705
9706    static void CVMenuRound2Int(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
9707            printf("*** CVMenuRound2Int: enter\n");
9708            {
9709        CharView *cv = (CharView *) GDrawGetUserData(gw);
9710        _CVMenuRound2Int(cv,1.0);
9711            }

で、n, n, sとか。ステップ実行、ステップイン。dddとかのGUIフロントエンドかまさんとやってられんな。

(gdb) s
SplinePointRound (sp=0x913d40, factor=1) at splinechar.c:711
711         if ( sp->prev!=NULL && sp->next!=NULL && sp->next->order2 &&
(gdb) list
706     }
707
708     void SplinePointRound(SplinePoint *sp,real factor) {
709         BasePoint noff, poff;
710
711         if ( sp->prev!=NULL && sp->next!=NULL && sp->next->order2 &&
712                 sp->ttfindex == 0xffff ) {
713             /* For interpolated points we want to round the controls */
714             /* and then interpolated based on that */
715             sp->nextcp.x = rint(sp->nextcp.x*factor)/factor;
(gdb) n
724             noff.x = rint((sp->nextcp.x - sp->me.x)*factor)/factor;
(gdb) p sp->me.x
$1 = 407.2998046875
(gdb) p sp->nextcp.x
$2 = 417.7998046875
(gdb) p factor
$3 = 1

それっぽく値がとれてる。Unified Font Object表現で言えば、最初のアンカーとコントロールポイントのx座標が以下だからね。

  <outline>
    <contour>
      <point x="407.3" y="696.2" type="curve" smooth="yes"/>
      <point x="417.8" y="699.9"/>

う~ん。SplinePointRound @splinechar.c を見ている感じだと、ここは素朴な計算に見えるなぁ。座標丸め後のデータは問題ないけど、これをUnified Font Objectに変換して出力するほうがまずいのかもしれんなー。

(gdb) b splinechar.c:724
Breakpoint 2 at 0x7ffff58c39de: file splinechar.c, line 724.
(gdb) condition 2 sp->me.x > 164 && sp->me.x < 165 && sp->me.y > 52 && sp->me.y < 53
(gdb) c
Continuing.

で問題の起こる箇所に関する条件でブレークさせてみる。
ふーむ。特別な何かという感じでもないな。

条件付きのbreak pointについては次のサイトを参考にした: gdb の使い方・デバッグ方法まとめ

―――――・・・

printfデバッグのコストが大分高くつくとか以前に、年賀状の住所とかblogのタイトル用の自分フォントを用意しちゃおうかなぁーとかいう動機から考えてこんなことをしているのはコスト高すぎだろということにそろそろ気付く。
作業用BGMを欠かすことができない。年始からエアコンの効いた部屋で徹夜でデバッガですゎとか洒落にならん(汗)