ソースコード以外の情報源
著者: 大和 正武 <yamato@redhat.com>生成日時: 20151102-17:59
Copyright © 2013 Red Hat, K.K. Copyright © 2015 Red Hat, K.K.
The text of and illustrations in this document are licensed by Red Hat under a Creative Commons Attribution–Share Alike 3.0 Unported license ("CC-BY-SA"). An explanation of CC-BY-SA is available at http://creativecommons.org/licenses/by-sa/3.0/. In accordance with CC-BY-SA, if you distribute this document or an adaptation of it, you must provide the URL for the original version.
はじめに
• ソースコードを読まずに済むのであれば、読まずに済ませる。 • 読む場合でも、基底知識があった方が効率が良い。 • ソースコード以外の情報源 • 文章 • プログラムの実行結果 • 実行環境文章
• ドメイン知識
• アルゴリズム、データ構造
文章: ドメイン知識
• ソフトウェアが扱う分野について一般的な知識を学習しておく。 • 公開されている仕様に沿ったソフトウェアであれば、仕様書を入手する。 • ネットワーク分野: RFC • コンパイラやカーネル: CPUの仕様書 • ソースコード中で実装している仕様に言及していることがある。 if (uh->check == 0) {/* RFC 2460 section 8.1 says that we SHOULD log this error. Well, it is reasonable.
*/
LIMIT_NETDEBUG(KERN_INFO "IPv6: udp checksum is 0\n"); goto discard;
}
文章: アルゴリズム、データ構造
特別なアルゴリズムやデータ構造を使っている場合、ソースコード中でその実 装にあたり参照 した論文や書籍について言及していることがあります。 ソースコードを読む前に読んでおくべ きです。
/*
* The first version of this code was based upon Yair Amir's PhD thesis: * http://www.cs.jhu.edu/~yairamir/phd.ps) (ch4,5).
*
* The current version of totemsrp implements the Totem protocol specified in: * http://citeseer.ist.psu.edu/amir95totem.html
... */
文章: ソフトウェアに同梱されたドキュメント
• オンラインマニュアル(man) • オンラインマニュアル(info) • パッケージに由来する情報 • ヘルプメッセージ
文章: ソフトウェアに同梱されたドキュメント
オンラインマニュアル(man)
manコマンドは引数で指定したトピックについて、ページャーで表示する。 man [セクション番号] TOPIC • TOPICにはコマンド名、システムコール名、ライブラリ関数名、設定ファイル名などを指定する。 • 良く使うセクション番号 1 実行プログラムまたはシェルのコマンド 2 システムコール(カーネルが提供する関数) 3 ライブラリコール(システムライブラリに含まれる関数) 7 概念(例: tcp)• キーワード検索をする: man -k キーワード
• manファイルを指定して閲覧する: man -l ファイル
文章: ソフトウェアに同梱されたドキュメント
オンラインマニュアル(info)
• GNUプロジェクトに由来するソフトウェアのマニュアルはinfo形式で提供される。 • glibc • gcc • gdb • make... • infoコマンドで閲覧する: info [TOPIC] • ハイパーリンクをサポートしている。 • * で始まる文字列はリンク • カーソルキーでカーソルを移動してリターンでジャンプする。 • ページ送り: スペースキー • qで終了する。^s 順方向インクリメンタルサーチ ^r 逆方向インクリメンタルサーチ リターン サーチ確定 • デモ
文章: ソフトウェアに同梱されたドキュメント
パッケージに由来する情報
• rpm -qiの出力中にDescriptionフィールドに指定したパッケージの最低限の情報が 記載され ている。 • manやinfoでは閲覧できな形式のドキュメントがパッケージに同梱されていることがある。 • /usr/share/doc/パッケージ名-バージョン名 以下に配置される。 • ドキュメントだけを保持する独立したパッケージが用意されていることがある。 • パッケージAに対してA-doc, A-docsあるいはA-manualなどといった名前がつけられる。文章: ソフトウェアに同梱されたドキュメント
ヘルプメッセージ
• 特別な引数を指定して実行するとヘルプメッセージ表示するプログラムがある。 • --help • -h • -? • help • コマンドラインの前に LANG=C とすると翻訳カタログの利用を避けることができる。 $ LANG=C ls --helpUsage: ls [OPTION]... [FILE]...
List information about the FILEs (the current directory by default).
Sort entries alphabetically if none of -cftuvSUX nor --sort is specified. Mandatory arguments to long options are mandatory for short options too. -a, --all do not ignore entries starting with .
-A, --almost-all do not list implied . and .. • 痕跡文字列として使える。
プログラムの実行結果
• 出力先
• 終了ステータス • ログ
プログラムの実行結果
出力先
標準出力(stdout) 正常に処理が進行した場合に対する、結果の出力先 標準エラー出力(stderr) 異常が発生した場合に対する、エラーや警告メッセージなどの出力先 特に指定しない限り、stdout, stderrはプログラムを起動したターミナルと関連付けられる。プログラムの実行結果
典型的な出力関数
• printf: 標準出力への書き出しに使う代表的な関数 printf("%s\n", "something normal data");
• fprintf: 標準エラー出力への書き出しに使う代表的な関数 fprintf(stderr, "%s\n", "something error message");
プログラムの実行結果
出力の保存
標準出力を保存する。 標準エラー出力の内容はそのままターミナルに出る。 # ./a.out > /tmp/stdout.txt 標準エラー出力の保存する。 標準出力の内容はそのままターミナルに出る。 # ./a.out 2> /tmp/stderr.txt 標準出力と標準エラー出力の内容を別々のファイルに保存する。 # ./a.out > /tmp/stdout.txt 2> /tmp/stderr.txt標準出力を捨てて標準エラー出力の内容を保存する。 # ./a.out > /dev/null 2> /tmp/stderr.txt
標準出力、標準エラー出力の両方をまとめて保存する。 # ./a.out > /tmp/stdout+err.txt 2>&1
プログラムの実行結果
終了ステータス
• プログラムは終了時、int型の値を一つだけその起動元に伝えることができる。 • 伝える側はmain関数の返り値、あるいはexit関数の引数に正数を指定する。 • 直前のプログラム実行に対する終了ステータスは$?というシェル変数に格納されている。 intmain(int argc, char** argv) { return 17; } $ gcc foo.c $ ./a.out $ echo $? 17 • 慣例として0は成功を意味する。
プログラムの実行結果
ログ
• 端末から切り離されて実行されるデーモンプログラムは、実行中に管理者へ伝えたいメッセージ があればログに記録する。 • 通常ログは/var/log/messagesに保存される。 • 閲覧にはルート権限が必要となる。 • 痕跡文字列の宝庫である。 # cat /var/log/messages ...Nov 7 01:04:16 localhost NetworkManager[631]: <info> dhclient started with pid 16694
Nov 7 01:04:16 localhost NetworkManager[631]: <info> Activation (em1) Stage 3 of 5 (IP Configure Start) complete. Nov 7 01:04:16 localhost dhclient[16694]: Internet Systems Consortium DHCP Client 4.2.4-P2
Nov 7 01:04:16 localhost dhclient[16694]: Copyright 2004-2012 Internet Systems Consortium. Nov 7 01:04:16 localhost dhclient[16694]: All rights reserved.
• ログの記録を依頼するにはsyslogライブラリ関数を用いる。 syslog(priority, "%s", "this is log message\n");
実行環境
linuxカーネルglibcライブラリ(図)
ハードウェア linuxカーネル glibc Cライブラリ プロセス1 プロセス2 プロセス3 プロセス4 straceを使うと 覗き見ることができる。 system call実行環境
linuxカーネルglibcライブラリ(説明)
プロセス • プログラムファイルを実行したときその実体をプロセスと言う。 • linuxカーネル上では複数のプロセスを同時に実行できる。 • プロセスは互いに独立している。 カーネル • 複数のプロセスの実行を管理する。 • ハードウェア資源へのアクセスを抽象化する。 • ハードウェア資源への同時アクセスを調停する。 • システムコール経由でサービスを提供する。 • 言語に依存しない。 • CPUに依存する。 libc • 標準Cライブラリ関数などアプリケーションで共通に使われる関数群実行環境
システムコール
• 種類 プログラム実行 • fork • clone • execve ファイルI/O • open • read • lseek • write • close ネットワーク I/O • socket• recv • send • bind • connect • accept • shutdown など • システムコールの失敗理由は負の正数で表現される。 • glibcの定義するラッパーがこの負の正数の絶対値をerrno大域変数に格納する。
実行環境
strace
straceを使うとコマンドラインで指定したプログラムを起動して、どのような システムコール が実行されているか確認できる。
$ strace /bin/echo "hello"
execve("/bin/echo", ["/bin/echo", "hello"], [/* 57 vars */]) = 0 brk(0) = 0xdb3000
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f168738e000 access("/etc/ld.so.preload", R_OK) = -1 ENOENT (No such file or directory)
open("/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3 ...
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f168738d000 write(1, "hello\n", 6hello
) = 6 close(1) = 0 munmap(0x7f168738d000, 4096) = 0 close(2) = 0 exit_group(0) = ? +++ exited with 0 +++
オプション-o FILE名とするとstraceの結果をファイルに保存できる: strace -o /tmp/log.strace /usr/bin/pwd
出力をlessで見たい場合
strace -o /tmp/log.strace /usr/bin/pwd 2>&1 | less とする。
実行環境
プロセス
プロセス process id(pid) == 452 実行コード 変数 定数 メモリ空間 ファイル記述子テーブル 1 0 2 3 n n+1 ターミナルより入力 ターミナルへ出力 ターミナルへ出力 ファイルを読み書き 他のプロセスと通信 ネットワークサーバと通信実行環境
プロセスID(pid)
• ある週間に実行されているプロセスを一意に識別する番号 • psコマンドで動作中のプロセス一覧を見ることができる。
$ ps ax
PID TTY STAT TIME COMMAND
1 ? Ss 0:03 /usr/lib/systemd/systemd --system --deserialize 40 2 ? S 0:00 [kthreadd] 3 ? S 0:01 [ksoftirqd/0] 5 ? S< 0:00 [kworker/0:0H] 7 ? S< 0:00 [kworker/u:0H] 8 ? S 0:09 [migration/0] ... 1857 ? Sl 0:01 /usr/libexec/mission-control-5 1867 ? Sl 1:32 /usr/libexec/ibus-ui-gtk3 1871 ? Sl 0:00 /usr/libexec/goa-daemon 1875 ? Sl 0:01 /usr/libexec/evolution-addressbook-factory
1923 ? Sl 1:38 /usr/libexec/ibus-engine-simple 1947 ? S 0:00 /usr/libexec/gvfsd-metadata
...
16047 ? Ss 0:04 sendmail: accepting connections
16084 ? Ss 0:00 sendmail: Queue runner@01:00:00 for /var/spool/clientmqueue • PIDを指定して動作中のプロセスにstraceをアタッチできる。
実行環境
メモリ空間
• プログラム(やライブラリ)の実行コードや変数群がプロセスのメモリ空間に配置される。 • 各プロセスでメモリ空間は独立している。 • /proc/PID/mapsを見ると用途がわかる。 #include <stdlib.h> int main(void) { void *c = malloc(1024); while (1); return 0; } $ gcc empty.c $ ./a.out &$ cat /proc/5550/maps 00400000-00401000 r-xp 00000000 08:02 524331 /tmp/a.out 00600000-00601000 rw-p 00000000 08:02 524331 /tmp/a.out 01dc9000-01dea000 rw-p 00000000 00:00 0 [heap] 3171400000-3171420000 r-xp 00000000 08:02 2228701 /usr/lib64/ld-2.15.so 317161f000-3171620000 r--p 0001f000 08:02 2228701 /usr/lib64/ld-2.15.so 3171620000-3171621000 rw-p 00020000 08:02 2228701 /usr/lib64/ld-2.15.so 3171621000-3171622000 rw-p 00000000 00:00 0 3171800000-31719ac000 r-xp 00000000 08:02 2232931 /usr/lib64/libc-2.15.so 31719ac000-3171bac000 ---p 001ac000 08:02 2232931 /usr/lib64/libc-2.15.so 3171bac000-3171bb0000 r--p 001ac000 08:02 2232931 /usr/lib64/libc-2.15.so 3171bb0000-3171bb2000 rw-p 001b0000 08:02 2232931 /usr/lib64/libc-2.15.so 3171bb2000-3171bb7000 rw-p 00000000 00:00 0 7f045f0b3000-7f045f0b6000 rw-p 00000000 00:00 0 7f045f0d4000-7f045f0d5000 rw-p 00000000 00:00 0 7fff368b5000-7fff368d6000 rw-p 00000000 00:00 0 [stack] 7fff36997000-7fff36998000 r-xp 00000000 00:00 0 [vdso] ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0 [vsyscall]
実行環境
ファイル記述子テーブル
• 様々なI/O • ファイルの読み書き • 他のプロセスとのやりとり • ネットワーク • ... • オープン中の全てのI/Oの経路に整数値(ファイル記述子)が与えられる。 • プロセス中で一意に定まる。 • システムコール(openやsocketなど)の結果として与えられる。 • /proc/PID/fdを見るとプロセスがオープンしている全てのファイル記述子を確認できる。 $ ps ax | grep emacs 2880 ? Rl 9:58 emacs13914 pts/3 S+ 0:00 grep --color=auto emacs $ ls -l /proc/2880/fd
ls -l /proc/2880/fd 合計 0
lr-x---. 1 yamato yamato 64 11月 8 14:50 0 -> /dev/null
lrwx---. 1 yamato yamato 64 11月 8 14:50 1 -> /home/yamato/.xsession-errors lrwx---. 1 yamato yamato 64 11月 8 14:50 10 -> anon_inode:[eventfd]
lrwx---. 1 yamato yamato 64 11月 8 14:50 11 -> socket:[38064] lrwx---. 1 yamato yamato 64 11月 8 14:50 12 -> socket:[37310] lrwx---. 1 yamato yamato 64 11月 8 14:50 13 -> /dev/ptmx
lrwx---. 1 yamato yamato 64 11月 8 14:50 14 -> /dev/ptmx
lrwx---. 1 yamato yamato 64 11月 8 14:50 2 -> /home/yamato/.xsession-errors lrwx---. 1 yamato yamato 64 11月 8 14:50 3 -> socket:[37275]
lrwx---. 1 yamato yamato 64 11月 8 14:50 4 -> anon_inode:[eventfd] lrwx---. 1 yamato yamato 64 11月 8 14:50 5 -> socket:[35318]
lrwx---. 1 yamato yamato 64 11月 8 14:50 6 -> anon_inode:[eventfd] lrwx---. 1 yamato yamato 64 11月 8 14:50 7 -> socket:[39422]
lrwx---. 1 yamato yamato 64 11月 8 14:50 8 -> anon_inode:[eventfd] lrwx---. 1 yamato yamato 64 11月 8 14:50 9 -> socket:[37988]