<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>ものぐさ備忘録 &#187; debugger</title>
	<atom:link href="http://www.ginriki.net/wd/category/%e3%83%87%e3%83%90%e3%83%83%e3%82%ac/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.ginriki.net/wd</link>
	<description>ソフトウェア関係の話を中心とした備忘録的日記</description>
	<lastBuildDate>Sun, 16 Jan 2011 20:07:53 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.8.5</generator>
	<language>ja</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>NetBeans on windowsでLinux上のrubyプログラムをリモートデバッグするためのproxy</title>
		<link>http://www.ginriki.net/wd/2010/09/27/204/</link>
		<comments>http://www.ginriki.net/wd/2010/09/27/204/#comments</comments>
		<pubDate>Sun, 26 Sep 2010 21:38:37 +0000</pubDate>
		<dc:creator>ginriki</dc:creator>
				<category><![CDATA[NetBeans]]></category>
		<category><![CDATA[Ruby]]></category>
		<category><![CDATA[Ruby on Rails]]></category>
		<category><![CDATA[debugger]]></category>

		<guid isPermaLink="false">http://www.ginriki.net/wd/?p=204</guid>
		<description><![CDATA[NetBeansのリモートデバッグについて、以前の記事で、以下のように書きましたが、
注意点としては、リモートと同じフルパス上にソースコードを置く必要がある点です。リモート先で、/var/www/railsprjにRoR [...]]]></description>
			<content:encoded><![CDATA[<p>NetBeansのリモートデバッグについて、<a href="http://www.ginriki.net/wd/2010/07/12/172/">以前の記事</a>で、以下のように書きましたが、</p>
<blockquote><p>注意点としては、リモートと同じフルパス上にソースコードを置く必要がある点です。リモート先で、/var/www/railsprjにRoRのプロジェクトコードが置いてあるなら、ローカルでも/var/www/railsprjにプロジェクトコードを置く必要があります。</p></blockquote>
<p>このままだと、Windows上のNetBeansでLinux上のRailsがリモートデバッグできません。<br />
そこで、NetBeansとFast Debugger(ruby-debug-ide)の間に挟むproxyを用意して、proxyの中でファイルパス変換することでリモートデバッグできるようにしました。<sup>1</sup></p>
<p>せっかくなので、以下にproxyのソースコードを置いておきます(MIT Licenseにしときました)。</p>
<ul>
<li><a href="http://www.ginriki.net/wd/wp-content/uploads/src/ruby-debug-ide-proxy.rb">ruby-debug-ide-proxy.rb</a></li>
</ul>
<p>以下の構成で、基本的な機能(変数チェック、ステップ実行、breakpointセット辺り)が動作するのは確認しました。<br />
Railsがデバッグできるかどうかは、まだ試してません。</p>
<pre>
[NetBeans (Debuger GUI)] on Windows
  ↓↑
[proxy] on Windows/Linux
  ↓↑
[ruby process (+ruby-debug-ide)]  on Linux

・CRuby 1.8.7 および JRuby 1.5.1でproxy動作確認した。
</pre>
<p>なお、実際にデバッグするときは、NetBeansが動くマシン上にもデバッグ対象のソースコードを置かないとソースコードデバッグできません。<br />
例えば、ソースコードは以下のように配置します。</p>
<pre>
・ruby-debug-ide側
/home/user/script
|---test.rb
\---lib
      \---somelib.rb

・NetBeans側
C:\win_script
|---test.rb
\---lib
      \---somelib.rb
</pre>
<p><BR/></p>
<h1>proxyを使ったデバッグの仕方</h1>
<p><BR/></p>
<p>以下の手順でproxyの起動やNetBeansからproxyへの接続を行えば、後は普通にデバッグできます。</p>
<ol>
<li>ruby-debug-ide付きでRuby process起動(<a href="http://www.ginriki.net/wd/2010/07/12/172/">以前の記事参照</a>)</li>
<li>proxy起動（Linux上で起動するか、NetBeans on Windows上で起動するかはお好みで)。</li>
<li>NetBeansでproxyへの接続。</li>
</ol>
<p>1, 2の手順はどちらが先でもＯＫです。<br />
1は以前の記事と同じなので、2, 3の説明だけ書きます。</p>
<h3>2. proxy起動 </h3>
<p>proxyスクリプトをオプション指定して起動するだけです。proxyスクリプトのオプションは以下の通り。</p>
<pre>
Usage: ruby-debug-ide-proxy.rb -t <rdb_host> [-p listen_port] [--rdbprefix prefix] [--ideprefix prefix] [-d]

Example: ruby-debug-ide-proxy.rb -t localhost --rdbprefix "/home/user/script" --ideprefix "C:\\win_script" -d
</pre>
<p>Exampleの例を説明すると、</p>
<ul>
<li> localhostのruby-debug-ideに接続して(接続先portは1234。指定するときはlocalhost:6000のようにする。)、</li>
<li>proxyを経由してNetBeansにデバッグデータ(XML)を送るときは、/home/user/script &#8211;> C:\\win_script　への変換を行い、</li>
<li>proxyを経由してNetBeansからデバッグコマンド(breakpointセットなど)を指示するときは、C:\\win_script &#8211;> /home/user/scriptへの変換を行い、</li>
<li>proxy実行時は、DEBUGログを出力する</li>
</ul>
<p>という指定になります。</p>
<h3>3. NetBeansからproxyへの接続</h3>
<p>NetBeansのメニューから「デバッグ -> デバッガを接続」を選択し、proxyが動作するホスト名やポート番号を指定して接続してください。<br />
NetBeansからproxyに接続した時、proxyからruby-debug-ideへの接続が自動的に行われます。</p>
<p>正しくデバッガ接続できた場合、以下のようなログがproxyプログラムの端末に出力されます。</p>
<pre>
I, [2010-09-27T03:43:21.124000 #2240]  INFO -- : proxy will replace /home/user/script with C:\win_script
I, [2010-09-27T03:43:21.468000 #2240]  INFO -- : proxy listens on 0.0.0.0:7000
I, [2010-09-27T03:43:24.530000 #2240]  INFO -- : proxy connects to 192.168.1.7:1234
I, [2010-09-27T03:43:24.530000 #2240]  INFO -- : debug start
</pre>
<p>後は、普通にNetBeansのデバッガGUIが使えます。<br />
例えば、デバッガGUIからbreakpointをセットすると、以下のログがproxy端末上に出ます。(-dを指定して起動した場合のみ）</p>
<pre>
D, [2010-09-27T03:43:24.546000 #2240] DEBUG -- : (ide -> proxy) b C:\win_script\test.rb:5
D, [2010-09-27T03:43:24.546000 #2240] DEBUG -- : (proxy -> rdb) b /home/user/script/test.rb:5
D, [2010-09-27T03:43:24.562000 #2240] DEBUG -- : (rdb -> proxy) <breakpointAdded no="1" location="/home/user/script/test.rb:5"/>
D, [2010-09-27T03:43:24.624000 #2240] DEBUG -- : (proxy -> ide) <breakpointAdded no='1' location='C:/win_script/test.rb:5'/>
</pre>
<p>手順は以上です。</p>
<p>Ruby/Railsの場合、デバッガはプログラムの動作理解に使うものというのが私の認識です<sup>2</sup>。なので、Ruby/Rails全般に慣れていない人がデバッガ利用者だと思うので、手順はもう少し簡潔にしたいですが、そうするにはIDE内を修正するしかないかな・・・。</p>
<ol class="footnotes"><li id="footnote_0_204" class="footnote">本当は、NetBeansのIDE内部でファイルパス変換するように修正するべきだと思いますが、面倒だったのでproxyにしました。</li><li id="footnote_1_204" class="footnote">デバッグは、printfデバッグの方が効率がいいと思ってます。</li></ol>]]></content:encoded>
			<wfw:commentRss>http://www.ginriki.net/wd/2010/09/27/204/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>NetBeansからRuby on Rails(RoR)のリモートデバッグ</title>
		<link>http://www.ginriki.net/wd/2010/07/12/172/</link>
		<comments>http://www.ginriki.net/wd/2010/07/12/172/#comments</comments>
		<pubDate>Sun, 11 Jul 2010 15:39:07 +0000</pubDate>
		<dc:creator>ginriki</dc:creator>
				<category><![CDATA[NetBeans]]></category>
		<category><![CDATA[Ruby]]></category>
		<category><![CDATA[Ruby on Rails]]></category>
		<category><![CDATA[debugger]]></category>
		<category><![CDATA[RoR]]></category>

		<guid isPermaLink="false">http://www.ginriki.net/wd/?p=172</guid>
		<description><![CDATA[NetBeansには、rubyのデバッガフロントエンドが同梱されています。
今回は、それを使ってRuby on Rails(以下RoR)のリモートデバッグをするためのメモです。
個人的には、RoRが動いてるマシンにssh [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://ja.netbeans.org/">NetBeans</a>には、rubyのデバッガフロントエンドが同梱されています。<br />
今回は、それを使ってRuby on Rails(以下RoR)のリモートデバッグをするためのメモです。</p>
<p>個人的には、RoRが動いてるマシンにsshでログインした後、emacsと<a href="http://www.freedom.ne.jp/toki/ruby.html">rubydb3x.el</a>を使う方がメリットがある<sup>1</sup>と思いますが、emacsの場合デバッガ用GUIはありません。GUIに慣れてる人はNetBeansの方が楽なので、そういう人向けにまとめます。</p>
<p>なお、NetBeansをインストールしたローカルマシンで、RoRも動かす場合のデバッグ方法は、<a href="http://wiki.netbeans.org/RubyDebugging">NetBeansのwiki</a>を参照してください。</p>
<p>まあ、ローカルマシン上でデバッグする場合も、リモートマシンと接続してデバッグする場合もやり方はほとんど変わりません。</p>
<p>どちらの場合も、デバッギプロセス（と同じプロセス上で動くruby-debug-ide)がTCP(デフォルトだと1234)をListenし、Netbeansからそこに接続してデバッグを開始します。Netbeansから接続するデバッギプロセスがlocalhostにいるか、リモート先のホストにいるかの違いしかないです。<br />
接続後、Netbeansからruby-debug-ideへbreakpointをしかける場所などを指示します。</p>
<p>デバッグ方法そのものは、ローカル・リモートともに一緒ですが、リモートのホストに対してローカルのNetBeansを接続してデバッグするには、リモート先のホストで以下の作業が必要です。</p>
<ol>
<li>rubyインストール (解説略)</li>
<li>RubyGemsインストール (解説略)</li>
<li>RoRインストール・プロジェクト作成 (解説略)</li>
<li>ruby-debug-ideインストール</li>
<li>リモート先のRoRプロジェクトのソースコードを、ローカルにも展開</li>
<li>ruby-debug-ide付きでRoRプロジェクトのWebサーバ起動</li>
</ol>
<p>4, 5, 6の手順は、あまりネット上で見かけないので順に解説します。</p>
<h3>ruby-debug-ideインストール</h3>
<p>Linuxだと、gemで簡単にインストールできます。(gcc, ruby-develをインストールしておけば。)<br />
Fedora8だと以下で終わりでした。</p>
<pre>
$ gem install ruby-debug
$ gem install ruby-debug-ide
</pre>
<p>Windows（のmswin版ruby）の場合、コンパイル環境の用意が面倒なので、コンパイル済みgemをダウンロードした上でインストールします。<sup>2</sup></p>
<pre>&gt; gem install -l linecache-0.43-mswin32.gem
&gt; gem install -l ruby-debug-base-0.10.3-mswin32.gem
&gt; del ruby-debug-base-0.10.3-mswin32.gem
&gt; gem install ruby-debug
&gt; gem install ruby-debug-ide -v 0.4.6</pre>
<p>コンパイル済みgem (linecache, ruby-debug-base)は以下２つのリンク先から<br />
それぞれダウンロードしてください。</p>
<ul>
<li><a href="http://rubyforge.org/frs/?group_id=5040&#038;release_id=22842">linecache</a></li>
<li><a href="http://rubyforge.org/frs/?group_id=1900&#038;release_id=28306">ruby-debug-base</a></li>
</ul>
<h3>リモート先のRoRプロジェクトのソースコードを、ローカルにも展開</h3>
<p>ローカルにもソースコードを置かないと、breakpointで止まった時にNetbeansにソースコードが読み込まれません。<br />
注意点としては、リモートと同じフルパス上にソースコードを置く必要がある点です。リモート先で、/var/www/railsprjにRoRのプロジェクトコードが置いてあるなら、ローカルでも/var/www/railsprjにプロジェクトコードを置く必要があります。<sup>3</sup></p>
<p>この辺の挙動理解には、<a href=http://wiki.netbeans.org/RubyDebugging#Checking_debugger_engine_functionality">NetBeans wikiのChecking debugger engine functionality</a>とか、<a href="http://debug-commons.rubyforge.org/protocol-spec.html">ruby-debug-ide protocol</a>とかを参考にして、実際にruby-debug-ideとtelnetで会話するといいです。</p>
<h3>ruby-debug-ide付きでRuby on RailsプロジェクトのWebサーバ起動</h3>
<p>以下な感じでRoR Webサーバ起動します。(-dも付けると、NetBeansとの通信時の処理が良く見えます。)</p>
<pre>
$ rdebug-ide --stop script/server -h 0.0.0.0
Fast Debugger (ruby-debug-ide 0.4.6) listens on 0.0.0.0:1234
</pre>
<h3>NetBeansからruby-debug-ideに接続</h3>
<p>NetBeans IDEのメニュー -> デバッグ -> 接続をクリックし、ダイアログにリモート先ホスト名とポート番号(1234)を指定して接続します。<br />
&#8211;stopを指定してあるので、RoRの処理先頭でstopするはずです。<br />
あとは、IDEからbreakpoint指定するなり、なんなり自由に操作します。<br />
watch変数として、paramsを追加しておくといい感じです。</p>
<ol class="footnotes"><li id="footnote_0_172" class="footnote">sshのポート(TCP 22)が開いてることは普通にありますが、デバッガ・デバッギ通信用のポートがfirewallで遮断されることは良くあります。</li><li id="footnote_1_172" class="footnote">最近だと、Visual C++は無料で手に入りますがmswin版rubyをコンパイルしたVisual C++と同じバージョンをインストールする必要しないと「MSC version unmatch」エラーが出てめんどくさいです。<a href="http://rubyforge.org/tracker/index.php?func=detail&#038;aid=16774&#038;group_id=1900&#038;atid=7436">http://rubyforge.org/tracker/index.php?func=detail&#038;aid=16774&#038;group_id=1900&#038;atid=7436</a></li><li id="footnote_2_172" class="footnote">WindowsとLinuxだとフルパスを一致させることが不可能なので、例えば、Windows上のNetBeansからLinux上のRoRがデバッグができないという点でかなりアレな仕様です。誰もやってないなら修正パッチ作るかな。</li></ol>]]></content:encoded>
			<wfw:commentRss>http://www.ginriki.net/wd/2010/07/12/172/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>kprobes &#8211; カーネルへ動的にプローブ挿入</title>
		<link>http://www.ginriki.net/wd/2009/07/13/60/</link>
		<comments>http://www.ginriki.net/wd/2009/07/13/60/#comments</comments>
		<pubDate>Sun, 12 Jul 2009 22:00:42 +0000</pubDate>
		<dc:creator>ginriki</dc:creator>
				<category><![CDATA[debugger]]></category>
		<category><![CDATA[kprobes]]></category>
		<category><![CDATA[linux]]></category>

		<guid isPermaLink="false">http://www.ginriki.net/wd/?p=60</guid>
		<description><![CDATA[Debug Hacksを読んでたら、kprobesっていうデバッグツールの話があった。
自分でモジュール作ってinsmodするだけで、カーネル再コンパイルなしで、ある実行地点でのカーネル内変数を調べるツールだそうで。
プ [...]]]></description>
			<content:encoded><![CDATA[<p>Debug Hacksを読んでたら、kprobesっていうデバッグツールの話があった。<br />
自分でモジュール作ってinsmodするだけで、カーネル再コンパイルなしで、ある実行地点でのカーネル内変数を調べるツールだそうで。</p>
<p>プロセスのユーザ空間（＝デバッギのユーザ空間）に対してデバッガプロセスがプローブする場合は<sup>1</sup></p>
<ol>
<li>デバッガプロセスがptrace辺りを使ってデバッギのメモリ空間上の指定アドレス上にあるアセンブリ命令をint 3に書き変えて<sup>2</sup></li>
<li>デバッギプロセス実行中にそのint 3命令実行して発生したSIGTRAPをデバッガプロセスがフック(=これも事前にptraceで設定する）して</li>
<li>デバッガプロセスがptraceでデバッギプロセスのメモリ空間から値をread</li>
</ol>
<p>っていう流れが普通だと思う。<a href="http://www.google.co.jp/codesearch/p?hl=ja&#038;sa=N&#038;cd=5&#038;ct=rc#6MUOKTZ2awo/linux-2.6.19.3/arch/x86_64/kernel/kprobes.c&#038;q=kprobes.c&#038;l=468">kprobes.c</a>のコメントを見てみると、kprobesの場合もカーネルの指定命令アドレスにint 3を入れてるらしい。</p>
<pre>
/*
 * Called after single-stepping.  p->addr is the address of the
 * instruction whose first byte has been replaced by the "int 3"
 * instruction.  To avoid the SMP problems that can occur when we
 * temporarily put back the original opcode to single-step, we
 * single-stepped a copy of the instruction.  The address of this
 * copy is p->ainsn.insn. ...
 * ...
 */
</pre>
<p>ただ、SMPの関係で色々対策が必要なんだね<sup>3</sup>。int 3を実行した後、例外ベクタにジャンプしてからどういう手順で処理してるかについてイメージがわかないから、今度ソース読んでみようかな。</p>
<p>あと、kprobesだと見たい変数（とくにローカル変数などCPUアーキテクチャとデバッグ情報からアドレスを割り出す必要のあるもの）のアドレスを探すのが大変だけど、<br />
kprobes+GDBでそこを解決しようとしてるのが<a href=http://www.red-bean.com/trac/tracepoints/">tracepoints</a>ってやつらしい。ふむふむ。</p>
<ol class="footnotes"><li id="footnote_0_60" class="footnote">以前、<a href="http://www.ginriki.net/wd/2007/05/28/14/">デバッガについて書いた記事</a>もどうぞ。</li><li id="footnote_1_60" class="footnote">int 3はIA-32とかIntel architectureの場合の話です</li><li id="footnote_2_60" class="footnote">デバッギプロセスにプローブする場合に必要なマルチスレッド対策とどの程度一緒なのかは、まだよくわからない。</li></ol>]]></content:encoded>
			<wfw:commentRss>http://www.ginriki.net/wd/2009/07/13/60/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>crashコマンド使ってみた</title>
		<link>http://www.ginriki.net/wd/2009/07/13/58/</link>
		<comments>http://www.ginriki.net/wd/2009/07/13/58/#comments</comments>
		<pubDate>Sun, 12 Jul 2009 17:37:05 +0000</pubDate>
		<dc:creator>ginriki</dc:creator>
				<category><![CDATA[CentOS]]></category>
		<category><![CDATA[GDB]]></category>
		<category><![CDATA[crash]]></category>
		<category><![CDATA[debugger]]></category>
		<category><![CDATA[linux]]></category>

		<guid isPermaLink="false">http://www.ginriki.net/wd/?p=58</guid>
		<description><![CDATA[Kernelのコアダンプファイルを解析するのに、crashコマンドが便利だという話を聞いたので、練習として触ってみました。
手元にCentOS 5のマシンがあるので、それを使います。
解析にあたってkernelのデバッグ情報がいるので、debuginfoのRPMをインストール]]></description>
			<content:encoded><![CDATA[<p>Kernelのコアダンプファイルを解析するのに、crashコマンドが便利だという話を聞いたので、練習として触ってみました。</p>
<p>手元にCentOS 5のマシンがあるので、それを使います。</p>
<p>解析にあたってkernelのデバッグ情報がいるので、debuginfoのRPMをインストールします<sup>1</sup>。</p>
<pre>
 $ uname -a
Linux localhost.localdomain 2.6.18-128.1.16.el5 #1 SMP Tue Jun 30 06:10:28 EDT 2009 i686 i686 i386 GNU/Linux

 $ wget http://debuginfo.centos.org/5/i386/kernel-debuginfo-2.6.18-128.1.16.el5.i686.rpm
 $ wget http://debuginfo.centos.org/5/i386/kernel-debuginfo-common-2.6.18-128.1.16.el5.i686.rpm
 $ rpm -ivh kernel-debuginfo-common-2.6.18-128.1.16.el5.i686.rpm kernel-debuginfo-2.6.18-128.1.16.el5.i686.rpm
</pre>
<p>んで、crashコマンド実行。<br />
SVR4 UNIXのcrashコマンドをベースにGDBを統合したやつだそうで<sup>2</sup>、GDBになじんでる私には結構使いやすいです。</p>
<div class="igBar"><span id="lcode-2"><a href="#" onclick="javascript:showPlainTxt('code-2'); return false;">PLAIN TEXT</a></span></div>
<div class="syntax_hilite"><span class="langName">CODE:</span>
<div id="code-2">
<div class="code">
<ol>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">$ crash</div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; &nbsp; &nbsp; KERNEL: /usr/lib/debug/lib/modules/<span style="color:#800000;color:#800000;">2</span>.<span style="color:#800000;color:#800000;">6</span>.<span style="color:#800000;color:#800000;">18</span>-<span style="color:#800000;color:#800000;">128</span>.<span style="color:#800000;color:#800000;">1</span>.<span style="color:#800000;color:#800000;">16</span>.<span style="">el5</span>/vmlinux</div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; &nbsp; DUMPFILE: /dev/crash</div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; &nbsp; &nbsp; &nbsp; CPUS: <span style="color:#800000;color:#800000;">1</span></div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; &nbsp; &nbsp; &nbsp; DATE: Mon Jul <span style="color:#800000;color:#800000;">13</span> <span style="color:#800000;color:#800000;">02</span>:<span style="color:#800000;color:#800000;">17</span>:<span style="color:#800000;color:#800000;">05</span> <span style="color:#800000;color:#800000;">2009</span></div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; &nbsp; &nbsp; UPTIME: <span style="color:#800000;color:#800000;">06</span>:<span style="color:#800000;color:#800000;">52</span>:<span style="color:#800000;color:#800000;">42</span></div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">LOAD AVERAGE: <span style="color:#800000;color:#800000;">0</span>.<span style="color:#800000;color:#800000;">16</span>, <span style="color:#800000;color:#800000;">0</span>.<span style="color:#800000;color:#800000;">03</span>, <span style="color:#800000;color:#800000;">0</span>.<span style="color:#800000;color:#800000;">01</span></div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; &nbsp; &nbsp; &nbsp;TASKS: <span style="color:#800000;color:#800000;">86</span></div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; &nbsp; NODENAME: localhost.<span style="">localdomain</span></div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; &nbsp; &nbsp;RELEASE: <span style="color:#800000;color:#800000;">2</span>.<span style="color:#800000;color:#800000;">6</span>.<span style="color:#800000;color:#800000;">18</span>-<span style="color:#800000;color:#800000;">128</span>.<span style="color:#800000;color:#800000;">1</span>.<span style="color:#800000;color:#800000;">16</span>.<span style="">el5</span></div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; &nbsp; &nbsp;VERSION: #1 SMP Tue Jun <span style="color:#800000;color:#800000;">30</span> <span style="color:#800000;color:#800000;">06</span>:<span style="color:#800000;color:#800000;">10</span>:<span style="color:#800000;color:#800000;">28</span> EDT <span style="color:#800000;color:#800000;">2009</span></div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; &nbsp; &nbsp;MACHINE: i686&nbsp; <span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#800000;color:#800000;">1197</span> Mhz<span style="color:#006600; font-weight:bold;">&#41;</span></div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; &nbsp; &nbsp; MEMORY: <span style="color:#800000;color:#800000;">758</span>.<span style="color:#800000;color:#800000;">9</span> MB</div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;PID: <span style="color:#800000;color:#800000;">3848</span></div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; &nbsp; &nbsp;COMMAND: <span style="color:#CC0000;">"crash"</span></div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; &nbsp; &nbsp; &nbsp; TASK: ef67c000&nbsp; <span style="color:#006600; font-weight:bold;">&#91;</span>THREAD_INFO: d9120000<span style="color:#006600; font-weight:bold;">&#93;</span></div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;CPU: <span style="color:#800000;color:#800000;">0</span></div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; &nbsp; &nbsp; &nbsp;STATE: TASK_RUNNING <span style="color:#006600; font-weight:bold;">&#40;</span>ACTIVE<span style="color:#006600; font-weight:bold;">&#41;</span></div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp;crash&gt; set <span style="color:#800000;color:#800000;">1</span></div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; &nbsp; PID: <span style="color:#800000;color:#800000;">1</span></div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">COMMAND: <span style="color:#CC0000;">"init"</span></div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; &nbsp;TASK: c16f5aa0&nbsp; <span style="color:#006600; font-weight:bold;">&#91;</span>THREAD_INFO: c16f6000<span style="color:#006600; font-weight:bold;">&#93;</span></div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; &nbsp; CPU: <span style="color:#800000;color:#800000;">0</span></div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; STATE: TASK_INTERRUPTIBLE</div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp;crash&gt; p $tmp = jiffies</div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; $<span style="color:#800000;color:#800000;">1</span> = <span style="color:#800000;color:#800000;">24873000</span></div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp;crash&gt; x modprobe_path</div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; 0xc0680be0 &lt;modprobe_path&gt;:&nbsp; &nbsp; &nbsp;das</div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp;crash&gt; show convenience</div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; &nbsp;$tmp = <span style="color:#800000;color:#800000;">24873000</span></div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; &nbsp;$__ = void</div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; &nbsp;$_ = <span style="color:#006600; font-weight:bold;">&#40;</span>examine_i_type *<span style="color:#006600; font-weight:bold;">&#41;</span> 0xc0680be0 <span style="color:#CC0000;">"/sbin/modprobe"</span></div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp;crash&gt; exit </div>
</li>
</ol>
</div>
</div>
</div>
<p>
gdbスクリプトをsourceで読み込むこともできる。<br />
まだ、まともな使い方は全然してないけど、Debug Hacksにいろいろ書いてあるので、それを読みながらやる予定。<br />
<table class="amazonBanner amazonTable" summary="Debug Hacks -デバッグを極めるテクニック&amp;ツール">
	<tbody>
		<tr>
			<td rowspan="4" class="amazonImageTable"><a href="http://ecx.images-amazon.com/images/I/41TmOAawDsL.jpg" title="Debug Hacks -デバッグを極めるテクニック&amp;ツール"><img src="http://ecx.images-amazon.com/images/I/41TmOAawDsL._SL160_.jpg" alt="Debug Hacks -デバッグを極めるテクニック&amp;ツール" style="border:none ! important; width:100px;" /></a></td> 
			<td style="height:36px;" class="amazonName"><a href="http://www.amazon.co.jp/Debug-Hacks-%E3%83%87%E3%83%90%E3%83%83%E3%82%B0%E3%82%92%E6%A5%B5%E3%82%81%E3%82%8B%E3%83%86%E3%82%AF%E3%83%8B%E3%83%83%E3%82%AF-%E3%83%84%E3%83%BC%E3%83%AB-%E5%90%89%E5%B2%A1/dp/4873114047%3FSubscriptionId%3DAKIAJCPLMOWTU2MWO7FQ%26tag%3Dgikogeek-22%26linkCode%3Dxm2%26camp%3D2025%26creative%3D165953%26creativeASIN%3D4873114047" title="Debug Hacks -デバッグを極めるテクニック&amp;ツール">Debug Hacks -デバッグを極めるテクニック&amp;ツール</a></td>
		</tr>
		<tr>
			<td style="height:36px;"><a href="http://www.amazon.co.jp/review/product/4873114047%3FSubscriptionId%3DAKIAJCPLMOWTU2MWO7FQ%26tag%3Dgikogeek-22%26linkCode%3Dxm2%26camp%3D2025%26creative%3D5143%26creativeASIN%3D4873114047" title="Debug Hacks -デバッグを極めるテクニック&amp;ツール" class="bold">レビューを見る </a></td>
		</tr>
		<tr>
			<td style="height:36px;"><a href="http://www.amazon.co.jp/gp/registry/wishlist/add-item.html%3Fasin.0%3D4873114047%26SubscriptionId%3DAKIAJCPLMOWTU2MWO7FQ%26tag%3Dgikogeek-22%26linkCode%3Dxm2%26camp%3D2025%26creative%3D5143%26creativeASIN%3D4873114047" title="Debug Hacks -デバッグを極めるテクニック&amp;ツール">欲しいものリストに追加</a></td>
		</tr>
		<tr>
			<td style="height:36px;"><span class="amazonPrice">価格:3360円 在庫あり。</span><span class="amazonCopy"><small>powered by <a href="http://www.amazon.co.jp/">Amazon.co.jp</a></small></span></td>
		</tr>
	</tbody>
</table></p>
<ol class="footnotes"><li id="footnote_0_58" class="footnote">最初、yumでinstallしたら、なぜか2.6.18-92.1.6.el5.centos.plusが入りました。kernelバージョンと合ってないので、rpmコマンドで入れなおし。</li><li id="footnote_1_58" class="footnote"><a href="http://people.redhat.com/anderson/crash_whitepaper/">Crash Whitepaper</a>のAbstract参照</li></ol>]]></content:encoded>
			<wfw:commentRss>http://www.ginriki.net/wd/2009/07/13/58/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>IA-32のjmp, call命令でTrapするGDBスクリプト</title>
		<link>http://www.ginriki.net/wd/2008/12/03/48/</link>
		<comments>http://www.ginriki.net/wd/2008/12/03/48/#comments</comments>
		<pubDate>Wed, 03 Dec 2008 12:30:05 +0000</pubDate>
		<dc:creator>ginriki</dc:creator>
				<category><![CDATA[GDB]]></category>
		<category><![CDATA[assembly]]></category>
		<category><![CDATA[debugger]]></category>
		<category><![CDATA[gdbscript]]></category>

		<guid isPermaLink="false">http://www.gikogeek.net/wd/?p=48</guid>
		<description><![CDATA[jmp/call命令の実行直前までプログラムを進めるGDBスクリプトです。
こういう用途に使えるGDBコマンドがないようなので、自分で作りました。
必要な方はご自由に使ってください。
- script.gdb
使い方は以 [...]]]></description>
			<content:encoded><![CDATA[<p>jmp/call命令の実行直前までプログラムを進めるGDBスクリプトです。<br />
こういう用途に使えるGDBコマンドがないようなので、自分で作りました。<br />
必要な方はご自由に使ってください。<br />
- <a href="http://www.ginriki.net/wd/wp-content/uploads/2008/12/script.gdb">script.gdb</a></p>
<p>使い方は以下の通り、</p>
<pre>$ gdb a.out
(gdb) source script.gdb
(gdb) break main
(gdb) run
＃ main関数でbreak

(gdb) run_until_call_jmp
＃ main関数内のcall or jmp命令直前で停止</pre>
<h4>jmp,call命令のop codeの調べ方</h4>
<p>IA-32命令セットにおける、JMP, CALLのオペコードは下記の通りになりますIA-32 インテル アーキテクチャ・ソフトウェア・ディベロッパーズ・マニュアル 中巻より抜粋。<a href="http://www.intel.com/jp/download/index.htm">http://www.intel.com/jp/download/index.htm</a></p>
<p><a href="http://www.gikogeek.net/wd/wp-content/uploads/2008/12/jmp_op.png"><img class="aligncenter size-full wp-image-49" title="jmp_op" src="http://www.gikogeek.net/wd/wp-content/uploads/2008/12/jmp_op.png" alt="JMP命令のオペコード" width="500" height="154" /></a><br />
<a href="http://www.gikogeek.net/wd/wp-content/uploads/2008/12/call_op1.png"><img class="aligncenter size-full wp-image-51" title="call_op1" src="http://www.gikogeek.net/wd/wp-content/uploads/2008/12/call_op1.png" alt="callオペコード" width="499" height="140" /></a></p>
<p>cb、cw、cd、cpは、オペコードの後に続く1,2,4,6バイトの値です。<br />
jmpやcall命令では、jmp/call先のアドレス値を表しています。</p>
<p>/2とか/3とかっていうのは、ModR/Mバイトのdigit(＝ op codeの一部) 上記マニュアルの2章（特に2.4～2.6)参照を表してます。<br />
op codeの一部なので、当然、命令を判定する際にdigitのチェックが必要です。</p>
<p>digitは/0～/7まであり、ModR/Mバイトの下位3bitに対応します。</p>
<p>例えば32bitの絶対間接nearジャンプのオペコードは下記になります。</p>
<pre>16進表記:  FF /4
2進表記 :  11111111 xxxxx100</pre>
<p>xxxxxの部分の値によって、ジャンプ先のアドレス値として参照するレジスタ/メモリアドレスが変化します。<br />
例えば、eaxレジスタに格納されたアドレス値へジャンプする場合は、xxxxx=11000 です。</p>
<p>こんな感じで命令のop codeを調べて実装したのが上記のGDBスクリプトです。<br />
スクリプトを改造する時の参考にしてください。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.ginriki.net/wd/2008/12/03/48/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Bilingual Debuggerプロジェクト紹介（だけしとく・・・)</title>
		<link>http://www.ginriki.net/wd/2008/01/24/31/</link>
		<comments>http://www.ginriki.net/wd/2008/01/24/31/#comments</comments>
		<pubDate>Thu, 24 Jan 2008 00:00:00 +0000</pubDate>
		<dc:creator>ginriki</dc:creator>
				<category><![CDATA[C言語]]></category>
		<category><![CDATA[OSS]]></category>
		<category><![CDATA[Ruby]]></category>
		<category><![CDATA[debugger]]></category>

		<guid isPermaLink="false">http://www.gikogeek.net/wd/?p=31</guid>
		<description><![CDATA[
ひさびさ。
実はだいぶ前なんですが、Sourceforge.jpにプロジェクト立ち上げました。
http://sourceforge.jp/projects/bdbg
C/C++とRubyという２つの言語のデバッガ(g [...]]]></description>
			<content:encoded><![CDATA[<div class="section">
<p>ひさびさ。</p>
<p>実はだいぶ前なんですが、Sourceforge.jpにプロジェクト立ち上げました。</p>
<p><a href="http://sourceforge.jp/projects/bdbg" target="_blank">http://sourceforge.jp/projects/bdbg</a></p>
<p>C/C++とRubyという２つの言語のデバッガ(gdbとrdb)を切り替えて使うことを可能にするツールをアップしてあります。</p>
<p>VC# 2003以降のデバッガに備わっている、C#とC/C++デバッガの切り替え機能を想像してもらえれば大体あってます。</p>
<p>詳しくは<a href="http://sourceforge.jp/projects/bdbg/wiki/bdrb%E3%81%AE%E5%88%A9%E7%94%A8%E3%83%9E%E3%83%8B%E3%83%A5%E3%82%A2%E3%83%AB" target="_blank">Wikiに書いたマニュアル</a>を見てください。</p>
<p>Fedora6でしか動作チェックしてないので、うまくコンパイルできないとかあれば、ブログコメントかSorceforgeのフォーラムにでも書いてくれれば対処します。</p>
<p>＃返事が遅くても怒らないでくだせえ</p>
<p>バイト＋就活＋レポートのトリプル攻撃のため、このプロジェクトに割り当てる時間がないれす。</p>
</div>
]]></content:encoded>
			<wfw:commentRss>http://www.ginriki.net/wd/2008/01/24/31/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>ocamldebugの調査</title>
		<link>http://www.ginriki.net/wd/2007/07/16/26/</link>
		<comments>http://www.ginriki.net/wd/2007/07/16/26/#comments</comments>
		<pubDate>Sun, 15 Jul 2007 20:24:04 +0000</pubDate>
		<dc:creator>ginriki</dc:creator>
				<category><![CDATA[Ocaml]]></category>
		<category><![CDATA[debugger]]></category>

		<guid isPermaLink="false">http://www.gikogeek.net/wd/?p=26</guid>
		<description><![CDATA[
ML言語の一種であるOcamlに付属している、ocamldebugというデバッガについて調べたのでメモ。
かなり間違っている可能性があるので、注意。

 gdbライクなCUI

 break,info,helpコマンド [...]]]></description>
			<content:encoded><![CDATA[<div class="section">
<p>ML言語の一種であるOcamlに付属している、ocamldebugというデバッガについて調べたのでメモ。</p>
<p>かなり間違っている可能性があるので、注意。</p>
<ul>
<li> gdbライクなCUI
<ul>
<li> break,info,helpコマンド等、gdbを知っている人なら何となく使えるようにコマンド名がつけられてます</li>
<li> でも、printコマンドで関数呼び出しや代入が行えないなど<span class="footnote"><a href="/gikogeek/#f1" name="fn1" title="http://caml.inria.fr/pub/docs/manual-ocaml.bak/manual030.htmlの16.7項に書かれているBNF記法を見る限りできないよなあ・・・たぶん">*1</a></span>、gdbと違う点もあるので注意</li>
</ul>
</li>
<li> breakで停止できるのは、eventと呼ばれる箇所でのみ
<ul>
<li> <a href="http://caml.inria.fr/pub/docs/manual-ocaml.bak/manual030.html">Ocamlマニュアル</a>のEventsの項目にeventとなる箇所が書いてある</li>
</ul>
</li>
<li> debuggerとdebugeeは別プロセス
<ul>
<li> Unixだと、BSDソケットを使ってプロセス間通信することでdebugee上に存在する変数の値の参照等を行っている。ここらへんは、Javaデバッガの実装に近い</li>
</ul>
</li>
<li> 日本語の処理関係は、まだ弱いらしい
<ul>
<li> <a href="http://www.h2.dion.ne.jp/~pana/camldebug/camldebug.html" target="_blank">http://www.h2.dion.ne.jp/~pana/camldebug/camldebug.html</a>のような件</li>
</ul>
</li>
<li> mlコード内のprint_int, print_string等の標準出力への出力用関数の処理は、ocamldebugでステップ実行している間は実際には行われない
<ul>
<li> debugeeの実行が終了した段階で出力される</li>
<li> 出力をバッファしてるのかな？</li>
<li> おそらく、ファイル出力やTCP等によるデータ送信も同様</li>
<li> タイムトラベル機能（後述）のためにこのような実装になってる？</li>
<li> ファイルからの入力がどうなるかはまだ調べてない</li>
</ul>
</li>
<li> 変数の値等の状態も含めて実行を前の地点まで巻き戻して、そこから再実行する機能がある（タイムトラベル機能）
<ul>
<li> ocamldebugが適切なタイミングでcheckpointを取り、それを利用して実行の巻き戻しを行う</li>
<li> 巻き戻した地点がcheckpointを取った地点と一致しない場合は、最寄のcheckpointからその地点まで再実行して停止？</li>
<li> checkpointを取るための実装にはforkを使ってる<span class="footnote"><a href="/gikogeek/#f2" name="fn2" title="http://caml.inria.fr/pub/docs/manual-ocaml/manual030.htmlのTurning reverse execution on and offの項目に書いてある">*2</a></span></li>
<li> プロセスIDが巻き戻す前と後で違うなど、完全に状態を巻き戻すことはできないため、いやらしいプログラムの実行を巻き戻すと挙動がおかしくなった</li>
</ul>
</li>
</ul>
<p></p>
<p>ocamldebugはOcamlで実装されているので、私には読めん・・・</p>
</div>
<div class="footnote">
<p class="footnote"><a href="/gikogeek/#fn1" name="f1">*1</a>：<a href="http://caml.inria.fr/pub/docs/manual-ocaml.bak/manual030.html" target="_blank">http://caml.inria.fr/pub/docs/manual-ocaml.bak/manual030.html</a>の16.7項に書かれているBNF記法を見る限りできないよなあ・・・たぶん</p>
<p class="footnote"><a href="/gikogeek/#fn2" name="f2">*2</a>：<a href="http://caml.inria.fr/pub/docs/manual-ocaml/manual030.html" target="_blank">http://caml.inria.fr/pub/docs/manual-ocaml/manual030.html</a>のTurning reverse execution on and offの項目に書いてある</p>
</div>
]]></content:encoded>
			<wfw:commentRss>http://www.ginriki.net/wd/2007/07/16/26/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>補足</title>
		<link>http://www.ginriki.net/wd/2007/06/05/17/</link>
		<comments>http://www.ginriki.net/wd/2007/06/05/17/#comments</comments>
		<pubDate>Tue, 05 Jun 2007 14:04:16 +0000</pubDate>
		<dc:creator>ginriki</dc:creator>
				<category><![CDATA[Ruby]]></category>
		<category><![CDATA[debugger]]></category>

		<guid isPermaLink="false">http://www.gikogeek.net/wd/?p=17</guid>
		<description><![CDATA[
バックトレースがうまくとれない件ですが、これに対処しようとした場合、test.rbのdebuggerメソッドでbreakした瞬間に、Ruby言語上のstack frameに関するデータ構造をアセンブラ（C言語）レベルで [...]]]></description>
			<content:encoded><![CDATA[<div class="section">
<p>バックトレースがうまくとれない件ですが、これに対処しようとした場合、test.rbのdebuggerメソッドでbreakした瞬間に、Ruby言語上のstack frameに関するデータ構造をアセンブラ（C言語）レベルで読み込んで解析する必要があると思います。</p>
<p>でも、これを言語実装者側のサポートなしに実現するのはかなり大変でしょう。大変な理由を思いつく限りで列挙すると、</p>
<ul>
<li> Rubyのstack frameを拡張ライブラリが直接読み込むことができない？
<ul>
<li> Rubyの実装に詳しいわけではないので、直接読み込めないというのは勘なのですが、セキュリティの観点から考えて、拡張ライブラリがstack frameをいじれないのは当然だと思う</li>
</ul>
</li>
<li> debuggerとdebuggeeが同一プロセスであるため、Rubyのstack frameに直接アクセスできたとしても、stackのどの部分がdebuggerのもので、どの部分がdebuggeeのものか区別が難しい
<ul>
<li> 同一プロセス上にあるから、gdbで言うところのprintコマンドが簡単に実現できるという利点もあるのですが、バックトレースは実装しにくくなります</li>
<li> debuggerとdebuggeeが同一プロセスであるというのは、C, Javaのデバッガと大きく異なる点でもあります</li>
</ul>
</li>
</ul>
<p>こんな感じでしょうか。</p>
<p>まあ、PythonやRubyの場合は、printやpを使ってデバッグしろってことでしょうかねえ。</p>
</div>
]]></content:encoded>
			<wfw:commentRss>http://www.ginriki.net/wd/2007/06/05/17/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>デバッガの実装（Ruby/Python編）</title>
		<link>http://www.ginriki.net/wd/2007/06/05/16/</link>
		<comments>http://www.ginriki.net/wd/2007/06/05/16/#comments</comments>
		<pubDate>Tue, 05 Jun 2007 13:47:01 +0000</pubDate>
		<dc:creator>ginriki</dc:creator>
				<category><![CDATA[debugger]]></category>

		<guid isPermaLink="false">http://www.gikogeek.net/wd/?p=16</guid>
		<description><![CDATA[
]]></description>
			<content:encoded><![CDATA[<div class="section">
<p>最後に、Ruby,Pythonのデバッガの実装について調べてみました。</p>
<p>Pythonには、pdb。 Rubyにはdebug.rbというデバッガが存在します。</p>
<p>これらは、各言語が提供するフック関数を利用して実装されています。フック関数を設定する関数（メソッド）は以下になります。</p>
<ul>
<li> Python
<ul>
<li> sys.settrace (Cレベルでは、ceval.cのPy_tracefunc関数<span class="footnote"><a href="/gikogeek/#f1" name="fn1" title="http://www.python.jp/doc/2.3.5/api/profiling.html">*1</a></span> )</li>
</ul>
</li>
<li> Ruby
<ul>
<li> Kernel#set_trace_func (Cレベルでは、eval.cのset_trace_func関数）</li>
</ul>
</li>
</ul>
<p>Pythonのsys.settraceの引数で渡した関数は、以下のタイミングで呼び出されます<span class="footnote"><a href="/gikogeek/#f2" name="fn2" title="http://docs.python.org/lib/debugger-hooks.html (英語)より抜粋">*2</a></span></p>
<ul>
<li> call: なんらかの関数呼び出し時</li>
<li> line: Pythonインタプリタが新しい行を実行する時</li>
<li> return: 関数の呼び出しからreturnする寸前</li>
<li> exception: 例外が発生した時</li>
<li> c_call: (拡張ライブラリ等の）C関数が呼び出されるとき</li>
<li> c_return: C関数から返ってきたとき</li>
<li> c_exception: C関数内部でPythonの例外が発生した時</li>
</ul>
<p>また、RubyのKernel#set_trace_funcの引数で渡した関数は、以下のタイミングで呼び出されます<span class="footnote"><a href="/gikogeek/#f3" name="fn3" title="http://www.ruby-lang.org/ja/man/?cmd=view;name=%C1%C8%A4%DF%B9%FE%A4%DF%B4%D8%BF%F4 より抜粋">*3</a></span>。</p>
<ul>
<li>"line" ... 式の評価。</li>
<li>"call" ... メソッドの呼び出し。</li>
<li>"return" ... メソッド呼び出しからのリターン。</li>
<li>"c-call" ... Cで記述されたメソッドの呼び出し。</li>
<li>"c-return" ... Cで記述されたメソッド呼び出しからのリターン。</li>
<li>"class" ... クラス定義、特異クラス定義、モジュール定義への突入。</li>
<li>"end" ... クラス定義、特異クラス定義、モジュール定義の終了。</li>
<li>"raise" ... 例外の発生。</li>
</ul>
<p>フック関数が呼び出されるときに、そのときの文脈（どのようなローカル変数が存在するか、次に行われる処理では、どのクラスの何のメソッドを呼ぼうとしているのか等）が引数として渡されます。フック関数はそれを記録、処理していくことで、breakpoint, バックトレース等が実現できます。</p>
<p></p>
<p>フック関数方式のデバッガは、以下のような利点があります。</p>
<ul>
<li> デバッガ実装のために、言語実装者側が提供するべき機能の実装負担が少ない（フック関数に関する実装のみ）</li>
<li> デバッガ実装者側は、その言語だけでデバッガ実装を行うことができる</li>
</ul>
<p>しかし、さきほど上で述べたすべてのタイミングでフック関数が呼び出される（そして、フック関数に渡す引数の用意も毎回行われる）ため、デバッグ時はプログラムの動作がかなり遅くなります。</p>
<p>特にRubyでrequire等ライブラリのロードを行うと、require内部でもフック関数が呼び出されるためにとても遅いです。</p>
<p>動作の遅さを解消するために、Rubyのdebug.rbと違って、拡張ライブラリも用いて（C言語も用いて）デバッガを実装することによって、フック関数<span class="footnote"><a href="/gikogeek/#f4" name="fn4" title="Kenel#set_trace_funcではなく、さらに低レベルのeval.cのrb_add_event_hookを使うようですね">*4</a></span>をなるべく用いない高速なデバッガを作った人もいらっしゃいます。</p>
<p><a href="http://rubyforge.org/projects/ruby-debug/" target="_blank">http://rubyforge.org/projects/ruby-debug/</a></p>
<p>少し使ってみましたが、フック関数が設定されてないうちは、バックトレースがうまく取れないようですね。</p>
<p>まあ、それでも十分に役に立つデバッガだと思います。</p>
<pre class="syntax-highlight">
test.rb:
require &#39;rubygems&#39;
require &#39;ruby-debug&#39;

def hoge()
debugger
p &#34;hoge&#34;
end
hoge()
hoge()
</pre>
<pre class="syntax-highlight">
$ ruby test.rb
test.rb:6 p &#34;hoge&#34;
(rdb:1) backtrace
--&#62; #0 test.rb:6 in &#39;hoge&#39;
(rdb:1) c
&#34;hoge&#34;
test.rb:6 p &#34;hoge&#34;
(rdb:1) backtrace
--&#62; #0 test.rb:6 in &#39;hoge&#39;
#1 test.rb:10
(rdb:1)
</pre>
</div>
<div class="footnote">
<p class="footnote"><a href="/gikogeek/#fn1" name="f1">*1</a>：<a href="http://www.python.jp/doc/2.3.5/api/profiling.html" target="_blank">http://www.python.jp/doc/2.3.5/api/profiling.html</a></p>
<p class="footnote"><a href="/gikogeek/#fn2" name="f2">*2</a>：<a href="http://docs.python.org/lib/debugger-hooks.html" target="_blank">http://docs.python.org/lib/debugger-hooks.html</a> (英語)より抜粋</p>
<p class="footnote"><a href="/gikogeek/#fn3" name="f3">*3</a>：<a href="http://www.ruby-lang.org/ja/man/?cmd=view;name=%C1%C8%A4%DF%B9%FE%A4%DF%B4%D8%BF%F4" target="_blank">http://www.ruby-lang.org/ja/man/?cmd=view;name=%C1%C8%A4%DF%B9%FE%A4%DF%B4%D8%BF%F4</a> より抜粋</p>
<p class="footnote"><a href="/gikogeek/#fn4" name="f4">*4</a>：Kenel#set_trace_funcではなく、さらに低レベルのeval.cのrb_add_event_hookを使うようですね</p>
</div>
]]></content:encoded>
			<wfw:commentRss>http://www.ginriki.net/wd/2007/06/05/16/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>デバッガの実装（Java編）</title>
		<link>http://www.ginriki.net/wd/2007/06/01/15/</link>
		<comments>http://www.ginriki.net/wd/2007/06/01/15/#comments</comments>
		<pubDate>Fri, 01 Jun 2007 09:22:28 +0000</pubDate>
		<dc:creator>ginriki</dc:creator>
				<category><![CDATA[debugger]]></category>

		<guid isPermaLink="false">http://www.gikogeek.net/wd/?p=15</guid>
		<description><![CDATA[
]]></description>
			<content:encoded><![CDATA[<div class="section">
<p>次はJavaのデバッガについて調べました。</p>
<h4>背景</h4>
<p>Javaプログラムの実行は、Java Virtual Machine(以下JVM)上に存在する仮想的なCPUがbytecode(仮想的なCPUが解釈する機械語)を解釈、処理をしていくことによって、行われます。</p>
<p>bytecodeはJavaコードをjavacでコンパイルしたときに生成されるコードでもあります。</p>
<p>JavaコードとCコード、bytecodeとアセンブリコードが、それぞれ似たような存在です。</p>
<p></p>
<p>OSから見た場合、JVMとJVM上で動くJavaプログラムは一つのプロセスにすぎません。</p>
<p>よって、OSが提供するデバッグAPIを用いたデバッガでJavaプログラムをデバッグすることが可能ですが、JVMの実行コード(アセンブリコード）やJVMが扱うデータ、JVM上で動くJavaプログラムの実行コード(bytecode)やJavaプログラムが扱うデータがごちゃごちゃしていて、デバッグするのは大変です。</p>
<p>JVM自身に関する情報とJavaプログラムに関する情報を切り分けて、デバッガ利用者へ提示するようにデバッガを実装すれば良いのですが、JVMの実装が変更になった時、それにあわせてデバッガを実装しなおす必要がでてきます。</p>
<p>また、実装の異なる複数のJVMに対応したデバッガを用意するのは困難ですし、デバッグAPIはOS依存なので、複数のOSで動作するデバッガを用意するのも困難です。</p>
<p></p>
<h4>JPDAとそれを利用したデバッガ実装</h4>
<p>そこで、Sunは、以下の３つの仕様を定めることで、JVMやOSの違いによる問題を解消しています<span class="footnote"><a href="/gikogeek/#f1" name="fn1" title="Java2 sdk 1.4時点">*1</a></span>。</p>
<ul>
<li> JVMTI(Virtual Machine Debug Interface)
<ul>
<li>JVMが提供するデバッグ機能の仕様
<ul>
<li> Javaプログラム上の変数情報の要求や、breakpointイベントの発生通知等の機能等</li>
</ul>
</li>
</ul>
</li>
<li> JDWP(Java Debug Wire Protocol)
<ul>
<li>debugeeとdebuggerでやり取りされるデバッグ情報や要求の形式に関する仕様</li>
</ul>
</li>
<li> JDI(Java Debug Interface)
<ul>
<li> debugger側の実装に利用するpure Javaのインターフェイスに関する仕様</li>
</ul>
</li>
</ul>
<p>これら３つの仕様を総称してJPDA(Java Platform Debugger Architecture)と呼びます。</p>
<p></p>
<p>Sun自身が、各仕様を満たした、リファレンス実装を提供しているので、デバッガ製作者はJDIを利用して、主にユーザインターフェイス部分を実装するだけでデバッガが作れるようです。</p>
<p>また、JVMの実装者は、JVMTIの仕様を満たすようにJVMを実装し、JDWPとJDIに関する実装はSunのリファレンス実装を利用すれば、新しく実装したJVM上で動作するJavaプログラムのデバッグを、既存のデバッガで行うことができるんでしょう（たぶん）。</p>
<p></p>
<h4>メモ</h4>
<ul>
<li>JPDAに関するドキュメント</li>
</ul>
<p><a href="http://sdc.sun.co.jp/java/docs/j2se/1.4/ja/docs/ja/guide/jpda/index.html" target="_blank">http://sdc.sun.co.jp/java/docs/j2se/1.4/ja/docs/ja/guide/jpda/index.html</a></p>
<ul>
<li>Java Debugger
<ul>
<li> CUIベース
<ul>
<li> jdb</li>
<li> jdebug</li>
</ul>
</li>
<li> GUIベース
<ul>
<li> jswat</li>
</ul>
</li>
</ul>
</li>
</ul>
<ul>
<li>JVMの種類
<ul>
<li> Sun JVM</li>
<li> IBM JVM</li>
<li> WebLogic JRockit JVM</li>
<li> Microsoft JVM</li>
</ul>
</li>
</ul>
</div>
<div class="footnote">
<p class="footnote"><a href="/gikogeek/#fn1" name="f1">*1</a>：Java2 sdk 1.4時点</p>
</div>
]]></content:encoded>
			<wfw:commentRss>http://www.ginriki.net/wd/2007/06/01/15/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

