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