DDD もどき
休みを利用して、浅草から出ている屋形船に乗ってきた。浅草から隅田川を下って、お台場 のレインボーブリッジをくぐり、全部で16の橋の下を 通ると言う全2時間のコース。食べ放題、飲み放題で8000円。それだけの価値は ありましたねぇ。
船遊びなんて、何年ぶりだろう? 隅田川と友好河川になっていると言うセーヌ川は知らない けれど、ライン川とか、アムステルダムの運河めぐり以来かな。
東京があんなに水の豊かな所だったなんて、認識を新たにしましたよ。川と言えども適当に 船が揺れてくれたおかげで、ビールが回るのも心なしか早い。揚げたての江戸前てんぷらが おいしかった。外人さんには、六本木に行くより、浅草でも巡って、船遊びをお勧めしたいね。
両岸に立ち並ぶビル、面白かった。住友のツインビルとか、リバーシティ21とか、バンダイ とか聖路加とか、そして月島のあのビルは、あの方のお住まいがあるのかな。SICPがらみで 高みに登ってみたいものだ。
そして、今押上に作っているスカイツリーが完成したら、タワーの見物がてら、神谷バー経由で 水上バスにでも乗って、フジテレビ方面にでも行きたいな。
DDDって、壊れてる?
前回、ArchLinuxに入れたDDD、配列をグラフ表示させようとすると、Starting gnuplotと 表示が出たままになってしまい、何も表示されないんだ。ArchLinuxの担当者が下手こいた かと思って、FreeBSDでもやってみた。
debugにかけられるターゲットは、こんな他愛もないやつね。
1 #include <stdio.h> 2 #include <math.h> 3 4 #define SIZE 4096 5 double r[SIZE]; 6 7 main (){ 8 int i; 9 10 for (i = 0; i < SIZE; i++){ 11 r[i] = sqrt(i); 12 } 13 for (i = 0; i < SIZE; i++){ 14 printf("%d %f\n", i, r[i] ); 15 } 16 }
cc -g test.c -lm こういう風にコンパイルして、a.outを作る。そして、ddd a.outして DDDを起動する。
GNU DDD 3.3.12 (i386-portbld-freebsd8.0), by Dorothea L(gdb) break test.c:13 Breakpoint 1 at 0x8048446: file test.c, line 13. (gdb) run Breakpoint 1, main () at test.c:13 (gdb) graph plot r (gdb)
13行目にブレークポイントを置いて実行。止まったら、配列 r には、INDEXの平方根が 充填されてるはず。rをマウスでなぞる(反転)と、plotと言うボタンが有効になるので 押す。 操作はこれでいいはずなんだけど。。グラフが出てこないんだ。
Starting gnuplot... が、つれなく出てくるだけ。 こうならないんだよなあ。グラフ表示は、gnuplotへ 下請け(嗚呼、IT風に言うと、アウトソーシングかな)に出しているんだな。そうすると、 下請けが働いているか、まず査察するか。
6787 2 S+ 0:00.67 ddd a.out 6788 3 Is+ 0:00.09 gdb -q -fullname a.out 6789 3 TX 0:00.01 /usr/home/sakae/ddd/a.out 6790 2 I+ 0:00.03 gnuplot -bg grey96 -font -*-lucidatypewriter-medium-r
これ見ると、動いてるみたいだよ。なんで結果が表示されない? LinuxでもFreeBSDでも 動かんと言う事は、本社側(DDD)が腐っているのかなあ。現実にはよくあるし。。。
世界のみんなに評判を聞いてみるかな。ddd ”Starting gnuplot”で、google先生に 聞いてみた。そしたら、fedoraの人やdebianの人やcygwinの人まで、同じ症例に 悩まされている事が判明! なんてこったい。
でも、一つヒントを貰えたよ。.ddd/logを見ろと。DDD本社へは、証拠を送って改善 依頼してあるようだ。へー、そうなんだ。
<- "(gdb) " # Creating display... # Creating display...done. >> "set term xlib\n" "set parametric\n" "set urange [0:1]\n" "set vrange [0:1]\n" "set trange [0:1]" >> "set noborder\n" "plot \"/var/tmp//dddzPXaFy\" title \"r\"" 2010.05.03 10:54:37 -> "output &r\n" # Display 1: r (enabled, scope main) << "G0 6291459\n" "QD\n" "QF\n" : "L-002\n" "E\n" "t0000-0.839442, -0.265854" 2010.05.03 10:54:37 <- "(double (*)[4096]) 0x80496a0" 2010.05.03 10:54:37 <- "(gdb) " # Display 1: r (enabled, scope main, address 0x80496a0) 2010.05.03 11:08:04 -> "quit\n"
これを見ると、どうやら下請けのgnuplotはちゃんと仕事をこなして、本社へ物を納品してる っぽい。やっぱり本社がサボってるんだな。
DDD News -*- text -*- ******** DDD-3.3.12 ========== - Consolidated support for pydb, bashdb and remake. - Miscellaneous bug fixes. - DDD development is now hosted by the GNU project at http://savannah.gnu.org/projects/ddd - You can download the latest code from the Subversion repository at savannah.gnu.org. - The preferred location for bug reports is the Savannah bug tracker `http://savannah.gnu.org/bugs/?group=ddd'. - The current maintainer of DDD is Peter Wainwright <peter.wainwright@ieee.org>.
これ、DDDニュースです。独自路線から、GNU傘下になったんですかね。Bug潰しは進んで いないように見受けられるぞ。
ええい、もうDDDなんてあてに出来んわ! 自分がgnuplotを操る事にしよう。でも、その 前に難題があるなあ。
gdbと交信せよ
やりたい事は、gdbを使って任意の場所で停止させ、その時の任意の配列に入っている 値をグラフ表示したいんだ。グラフ表示は、gunplotに丸投げしちゃおう。DDDみたいに、 内部で加工とかしようとするから、Bugの温床になるんだな。
すると、gbdからいかにdataをgnuplotに渡すかが、鍵になりそう。手元にASCIIから出てた gdbのマニュアル本があるけど、ちと情報不足の感がある。こういう時は、本家を訪ねる のが吉かな。
こちらが最新みたいだけど、 ちょっとずるして、 gdb manual あんちょこも見つけた。
つらつらと見てたら、emacsからgdbをよく使ってる事を思い出した。emacsとgdbのやりとり は、どうしてるのだろう? ヒントがありそうだな。
41712 2 S+ 0:01.53 emacs -fg gray -bg black -cr gold -geometry 80x42 test.c 41713 p0 Ss+ 0:00.06 /usr/bin/gdb --annotate=3 a.out 41714 p0 TX 0:00.01 /usr/home/sakae/ddd/a.out
これを見ると、annotateモードで実行すればよさそうな事が分かる。で、実際に やってみると、結構応答がうざい。よって、もう少し別の方法でやってみる。
MYDDD
いろいろ検討したけど、gdbとgnuplotの両方を旨く操る本社機構が必要という結論に達した。 本社は、余計なことはせず、接着剤の機能だけに徹するのが吉。
接着剤に最適なrubyをリハビリのために使ってみる。
#!/usr/local/bin/ruby # Usage: mydd.rb a.out # add gdb-cmd: plot array[n] @ length def show(p) while ln = p.gets next if ln =~ /^\&/ # dsable echo return if ln =~ /\(gdb\)/ # gdb/mi prompt print ln # result end end def rungdb(target) p = IO.popen("gdb -q -i mi #{target}", "w+") show(p) return true,p end def fin(p) p.print '-gdb-exit' return false end def do_cmd(cmd, p) p.print cmd show(p) end def graph(cmd, p) p.print cmd.sub(/plot/, 'output') g = IO.popen('gnuplot -persist','w') g.print 'plot "-" with lines ', "\n" while ln = p.gets next if ln =~ /^\&/ if ln =~ /\(gdb\)/ g.print "e\n" g.close return end if ln =~ /[-+]?(?:[0-9]+(\.[0-9]*)?|(\.[0-9]+))([eE][-+]?[0-9]+)?/ # number g.print $&, "\n" end end end ### main target = ARGV.shift run,p = rungdb(target) do_cmd("set print elements 0 \n", p) # unlimited print array size do_cmd("set print repeats 0 \n", p) # print same elements do_cmd("b main \n", p) # set break on main while(run) do print 'mydd> ' cmd = gets if cmd =~ /plot/ # plot cmd graph(cmd, p) elsif cmd =~ /quit/ # quit cmd to gdb-exit run = fin(p) else do_cmd(cmd, p) # other gdb cmd end end system('pkill gnuplot_x11') # clean up
相変わらず、class定義、何それ? のレベルで、matzさんに怒られそうだけど、いにしえの 昔からの私のスタイルなんで、お目こぼしを。
[sakae@cdr /usr/home/sakae/ddd]$ ./mydd.rb a.out ^done ^done ^done mydd> break 13 ^done mydd> run ^done,reason="breakpoint-hit",bkptno="1",thread-id="0",frame={addr="0x08048410",func="main",args=[],file="test.c",line="7"} mydd> cont ^done,reason="breakpoint-hit",bkptno="2",thread-id="0",frame={addr="0x08048446",func="main",args=[],file="test.c",line="13"} mydd> plot r[0] @ 4096 mydd> plot r[1000] @ 500 mydd> quit
上記は実行例である。そそっかしい自分のために、break main した状態で、プロンプトが 出るようにしてるけど、うざかったら、コメントにしてください。
plotコマンドの @ に続く数値は、幾つ分のデータをグラフに取り込むかの指定になります。 配列の途中からグラフ表示するように指定しても、INDEX番号を表すX軸は O からの表示 になりますので、笑って許してください。(表示範囲をグラフのtitleにでも出せば、良い のでしょうが)
quitコマンドを発行すると、ターゲットプログラムがrunning中でも、有無を言わさず終了 し、グラフ表示も消されてしまいますので、あしからず。
Arch Linuxでは難有り
FreeBSDのgdbは、
[sakae@cdr ~]$ gdb -v GNU gdb 6.1.1 [FreeBSD]
こんな具合。ArchLinuxのそれは、gdb7.Xだった。多分そのせいだろうと思うけど、plotの 表示がおかしくなった。gdbとのやりとりが、現在進行形の機構を使ったからかな?
.gdbinitあたりに
define dumparry set $COUNT = $arg2 set $INDEX = $arg1 while $COUNT output $arg0[$INDEX] echo \n set $INDEX = $INDEX + 1 set $COUNT = $COUNT - 1 end end
とでもしておいて、output r[10] @ 20 の所を dumparry r 10 20 とでもすれば良いのかな? 考えるよりも手を動かしてみよう。gbdとセッションして、相手の手のうちを把握。 以下は、それを元に調整してみたもの。gbd 7.1から進化したら、また手のうちが 変わるのだろうか?
#!/usr/bin/ruby # Usage: mydd.rb a.out # add gdb-cmd: plot array[n] @ length def show(p) while ln = p.gets next if ln =~ /^\&/ # dsable echo break if ln =~ /\*running/ return if ln =~ /\(gdb\)/ # gdb/mi prompt print ln end p.gets # dummy read for (gdb) while ln = p.gets return if ln =~ /\(gdb\)/ # gdb/mi prompt print ln end end def rungdb(target) p = IO.popen("gdb -q -i mi #{target}", "w+") show(p) return true,p end def do_cmd(cmd, p) p.print cmd show(p) end def graph(cmd, p) system('pkill gnuplot') # clean up p.print cmd g = IO.popen('gnuplot -persist','w') g.print 'plot "-" with lines', "\n" while ln = p.gets next if ln =~ /^\&/ if ln =~ /[-+]?(?:[0-9]+(\.[0-9]*)?|(\.[0-9]+))([eE][-+]?[0-9]+)?/ # number g.print $&, "\n" end if ln =~ /\(gdb\)/ g.print "e\n" g.close return end end end ### main target = ARGV.shift run,p = rungdb(target) do_cmd("set print elements 0 \n", p) # unlimited print array size do_cmd("set print repeats 0 \n", p) # print same elements while(run) do print 'mydd> ' cmd = gets if cmd =~ /plot/ # plot cmd graph(cmd.sub(/plot/, 'output'), p) elsif cmd =~ /quit/ # quit cmd to gdb-exit p.print '-gdb-exit' run = false else do_cmd(cmd, p) # other gdb cmd end end system('pkill gnuplot') # clean up