2008-04-01
駄文 - C 言語の勉強
C で Hash table を作ってみた。 22 時から 4 時までの 6 時間でやっと完成。 orz
300 行くらい。まだまだ LL 脳が抜けない。
昔、仕事で使ってたんだけどなー。おっかしーなー
gdb のプロになりたい。
C 言語はエラー処理が大変、あとデータのインスペクトが難しい。
MacPorts の SpiderMonkey と CPAN の JavaScript::SpiderMonkey を一緒に入れる
MacPorts で SpiderMonkey を入れた場合は、以下の位置にライブラリファイルとインクルードファイルがあります。
/opt/local/lib/* /opt/local/include/*
なので、 JavaScript::SpiderMonkey をインストールする際には、 Makefile.PL の 38 行目あたりを以下のように修正しなければなりません。
my %possible_install_paths = ( "../js/src/*" => "../js/src", "/usr/lib" => "/usr/include", "/usr/local/lib" => "/usr/local/include", "/usr/lib/firefox" => "/usr/include/firefox", "/opt/local/lib" => "/opt/local/include", # この行を追加 );
テストが少しだけ失敗してたけど、とりあえずインストールはできました。
dtrace を使ったシステムコールのトレース
dtrace とは
Mac OS X Leopard から導入された、プログラムを書き換えることなくプログラムの情報を監視(トレース)できる便利ツールです。
使い方
たとえば、 vim という名前のプロセスからシステムコール stat, open, stat64 されたときに第一引数(ファイル名)を監視するには以下のようにします。
$ sudo dtrace -n "syscall::open:entry, syscall::stat:entry, syscall::stat64:entry / execname == \"vim\" / { trace(copyinstr(arg0)) } "
説明
まず、 -n というのは「probe」の「name」を指定して dtrace する!という意味です。
$ sudo dtrace [-n [[[ provider: ] module: ] func: ] name [[ predicate ] action ]]
probe とは
probe というのは、 監視ポイントのことです。
以下のコマンドで監視ポイントの一覧を見ることができます。
$ sudo dtrace -l
たくさんあるので、 grep するといいです。
$ sudo dtrace -l | grep syscall
とにかくいろんな情報を監視できるのが分かりますね!
probe の指定方法
probe は固有の数字か、「provider:module:func:name」というコロンで区切られた文字列で指定します。
文字列で指定する場合は、さっきのように -n を使います。
$ sudo dtrace -n syscall::open:entry
syscall には module 名がないのでコロンコロンになってます。
また、
数字で指定する場合は、以下のように -i を使います。
$ sudo dtrace -i 18270
この数字は sudo dtrace -l で分かります。
action とは
action とは監視した情報をどのようにトレースするかという情報です。中括弧で囲って書きます。
たとえば、 プロセス名とプロセス ID を trace したい場合は、以下のようにします。
$ sudo dtrace -n "syscall::open:entry { trace(execname); trace(pid) }"
この中括弧の中には、 d 言語(別の D 言語と誤解しないように)というスクリプトのステートメント(文)を書きます。
trace 以外にも様々な関数があり、 execname や pid 以外にも様々な変数があります。
predicate とは
predicate とは監視した情報をフィルタリングする場合に使います。スラッシュで囲って書きます。
ここには、 d 言語の式を書きます。
たとえば、以下のようにすれば vim という名前のプロセスか emacs という名前のプロセスだけをトレースすることができます。
$ sudo dtrace -n "syscall::open:entry / execname == \"emacs\" || pid == \"vim\" / { trace(execname); trace(pid) }"
d 言語の詳細なドキュメントは
ここにあります。
http://wikis.sun.com/display/DTrace/Documentation
d 言語を別のファイルにする
d 言語を別のファイルにすることもできます
#! /usr/sbin/dtrace -s
syscall::open:entry
/ execname == "emacs" || pid == "vim" /
{
trace(execname);
trace(pid);
}
profile:::tick-100sec
{
trace("timeout!\n")
exit(0)
}
パーミッションを設定すれば、そのまま実行できます。
実際に実行してみる
こんな感じです。
$ sudo dtrace -n "syscall::open:entry, syscall::stat:entry, syscall::stat64:entry / execname == \"vim\" / { trace(copyinr(arg0)) } " > dtrace.txt &
[1] 70629
dtrace: description 'syscall::open:entry, syscall::stat:entry, syscall::stat64:entry ' matched 3 probes
$ vim hoge
$ fg
sudo dtrace -n "syscall::open:entry, syscall::stat:entry, syscall::stat64:entry / execname == \"vim\" / { trace(copyinstr(arg0)) } " > dtrace.txt
^C
$ cat dtrace.txt
CPU ID FUNCTION:NAME
0 17970 stat:entry /usr/lib/libncurses.5.4.dylib
0 17970 stat:entry /usr/lib/libiconv.2.dylib
0 17970 stat:entry /usr/lib/libgcc_s.1.dylib
0 17970 stat:entry /usr/lib/libSystem.B.dylib
0 17970 stat:entry /usr/lib/system/libmathCommon.A.dylib
0 17604 open:entry /dev/dtracehelper
0 18270 stat64:entry /Users/amachang/Downloads
0 18270 stat64:entry /Users/amachang
0 17970 stat:entry /usr/share/vim/vim70
0 17970 stat:entry /usr/share/vim
0 18270 stat64:entry /Users/amachang/Downloads
0 17970 stat:entry hoge
0 17604 open:entry /usr/share/terminfo/78/xterm-color
0 17604 open:entry .
0 18270 stat64:entry /usr/share/vim
0 17970 stat:entry /usr/share/vim/vimrc
0 17970 stat:entry /usr/share/vim/vimrc
0 17604 open:entry .
0 18270 stat64:entry /Users/amachang
0 17970 stat:entry /Users/amachang/.vimrc
0 17970 stat:entry /Users/amachang/.vimrc
:
:
おおお dylib が読み込まれて、設定ファイルが読み込まれていく様が分かりますね!
まとめ
Leopard に元々入ってる Ruby や Perl などはパッチがあたっていて関数呼び出しなどがトレースできるらしいのですが、自分がやってみたらできませんでした。何故だろう?
とにかく ktrace の変わりに dtrace を使ってみてはいかがでしょうか。
objdump, objcopy を Mac に入れる
こっちのエントリはエイプリルフールネタではないよ
インストール
nm とか strings とかとあわせて binutils っていうツールなんですね
$ sudo install binutils
で、インストールできました。
内容
で、どんなものがインストールされたかというと
$ port contents binutils Port binutils contains: /opt/local/bin/gaddr2line /opt/local/bin/gar /opt/local/bin/gc++filt /opt/local/bin/gnm /opt/local/bin/gobjcopy /opt/local/bin/gobjdump /opt/local/bin/granlib /opt/local/bin/greadelf /opt/local/bin/gsize /opt/local/bin/gstrings /opt/local/bin/gstrip : :
って感じで、 /opt/local/bin の中に g というプリフィックスが付いた状態でインストールされていました。
OS X が元々用意している nm や strings などと区別して使うためなんですかね?
こんな感じ
$ gobjdump -d /bin/ls
??? /bin/ls ??:
unable to read unknown load command 0x1b
unable to read unknown load command 0x1d
/bin/ls: ?ե???????? mach-o-le
????????? LC_SEGMENT.__TEXT ?εե?????֥?:
00001000 <LC_SEGMENT.__TEXT>:
1000: ce into
1001: fa cli
1002: ed in (%dx),%eax
1003: fe 07 incb (%edi)
1005: 00 00 add %al,(%eax)
1007: 00 03 add %al,(%ebx)
1009: 00 00 add %al,(%eax)
100b: 00 02 add %al,(%edx)
100d: 00 00 add %al,(%eax)
100f: 00 0e add %cl,(%esi)
1011: 00 00 add %al,(%eax)
1013: 00 18 add %bl,(%eax)
1015: 05 00 00 85 00 add $0x850000,%eax
101a: 00 00 add %al,(%eax)
101c: 01 00 add %eax,(%eax)
なんかちょっと文字化けしてますが、普通に使えました。
ちゃんと、 mach-o-le にも対応してるんですね(あたりまえか
