さて、前回までで、文字列データでオプションを指定しても、mreq 構造体で指定してもシステムコールとしては同じものが実行されるところまでを確認した。 今回は、Cのコードからシステムコールが実行されるまでの流れを追ってみようと思う。
setsockopt は定義としては glibc にあるようなので、glibcの動きをgdb で追ってみる。
glibcをgdbで追う. 不具合調査等で、Linuxのシステムのライブラリをgdbで追いたいことがある。例… | by Kazuhiro Masuda | Medium
の記事を参考に、まずは、GDBの準備とsetsockopt を用いるソースコードのコンパイルを行っておく。
gdbを実行し、 setsockopt
でブレークポイントを設定し、プログラムを実行する。
% sudo gdb ./soc_test (gdb) b setsockopt (gdb) r (gdb) n 39 setsockopt(sock, 263, 1, mreq2, sizeof(mreq2)); (gdb) n Breakpoint 2, setsockopt () at ../sysdeps/unix/syscall-template.S:84 84 T_PSEUDO (SYSCALL_SYMBOL, SYSCALL_NAME, SYSCALL_NARGS) (gdb) n 85 ret
すると、上記のように syscall-template.S
ファイルが実行されていることが分かった。
このファイルはなんだろうと調べてみると、
によると、システムコールをラップするときに用いられるファイルらしい。
ラッパーを使用するシステムコールのリストは、syscalls.listファイルに保持されます。(日本語訳)
とのことで、手元のファイルを確認してみると、以下にそれっぽいファイルがあり、 setsocopt
関数が見える。
sysdeps/unix/sysv/linux/x86_64/syscalls.list
# File name Caller Syscall name # args Strong name Weak names arch_prctl EXTRA arch_prctl i:ii __arch_prctl arch_prctl modify_ldt EXTRA modify_ldt i:ipi __modify_ldt modify_ldt syscall_clock_gettime EXTRA clock_gettime Ei:ip __syscall_clock_gettime # proper socket implementations: bind - bind i:ipi __bind bind getpeername - getpeername i:ipp __getpeername getpeername getsockname - getsockname i:ipp __getsockname getsockname getsockopt - getsockopt i:iiiBN __getsockopt getsockopt listen - listen i:ii __listen listen setsockopt - setsockopt i:iiibn __setsockopt setsockopt shutdown - shutdown i:ii __shutdown shutdown socket - socket i:iii __socket socket socketpair - socketpair i:iiif __socketpair socketpair
つまり、glibc的には setsocopt
はシステムコールをラップしていて、右から左に流しているように見える。
ということで、次はカーネルの中に入って setsocopt
を覗いてみることで、 optval
引数をどのように扱っているかを確認していく。
疑問メモ
sysdeps/unix/sysv/linux/setsockopt.c ここにそれっぽいのがあるけど、この辺のコードは経由しないのか?