straceコマンド

strace(1)コマンドの使い方とソースをざくっと見たのでメモ。
strace(1)はsolarisでいうところのtruss(1)と同じような感じ。
なので、プロセスハングはopen状態などの確認するためのコマンドとして有効だと思う。

以下、ソースメモ。
(ソースはかなり古いAPIも使われていて、そのうち廃止されそう。)

```
> strace -ft sleep 1
11:18:08 execve("/bin/sleep", ["sleep", "1"], [/* 64 vars */]) = 0
11:18:08 brk(0)                         = 0x949d000
11:18:08 access("/etc/ld.so.nohwcap", F_OK) = -1 ENOENT (No such file or directory)
11:18:08 mmap2(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb7772000
11:18:08 access("/etc/ld.so.preload", R_OK) = -1 ENOENT (No such file or directory)
11:18:08 open("/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
11:18:08 fstat64(3, {st_mode=S_IFREG|0644, st_size=134659, ...}) = 0
11:18:08 mmap2(NULL, 134659, PROT_READ, MAP_PRIVATE, 3, 0) = 0xb7751000
11:18:08 close(3)                       = 0
11:18:08 access("/etc/ld.so.nohwcap", F_OK) = -1 ENOENT (No such file or directory)
11:18:08 open("/lib/i386-linux-gnu/libc.so.6", O_RDONLY|O_CLOEXEC) = 3
11:18:08 read(3, "\177ELF\1\1\1\0\0\0\0\0\0\0\0\0\3\0\3\0\1\0\0\0\340\233\1\0004\0\0\0"..., 512) = 512
11:18:08 fstat64(3, {st_mode=S_IFREG|0755, st_size=1754876, ...}) = 0
11:18:08 mmap2(NULL, 1759868, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0xb75a3000
11:18:08 mmap2(0xb774b000, 12288, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x1a8000) = 0xb774b000
11:18:08 mmap2(0xb774e000, 10876, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0xb774e000
11:18:08 close(3)                       = 0
11:18:08 mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb75a2000
11:18:08 set_thread_area({entry_number:-1 -> 6, base_addr:0xb75a2940, limit:1048575, seg_32bit:1, contents:0, read_exec_only:0, limit_in_pages:1, seg_not_present:0, useable:1}) = 0
11:18:08 mprotect(0xb774b000, 8192, PROT_READ) = 0
11:18:08 mprotect(0x804e000, 4096, PROT_READ) = 0
11:18:08 mprotect(0xb7795000, 4096, PROT_READ) = 0
11:18:08 munmap(0xb7751000, 134659)     = 0
11:18:08 brk(0)                         = 0x949d000
11:18:08 brk(0x94be000)                 = 0x94be000
11:18:08 open("/usr/lib/locale/locale-archive", O_RDONLY|O_LARGEFILE|O_CLOEXEC) = 3
11:18:08 fstat64(3, {st_mode=S_IFREG|0644, st_size=9743888, ...}) = 0
11:18:08 mmap2(NULL, 2097152, PROT_READ, MAP_PRIVATE, 3, 0) = 0xb73a2000
11:18:08 close(3)                       = 0
11:18:08 nanosleep({1, 0}, NULL)        = 0
11:18:09 close(1)                       = 0
11:18:09 close(2)                       = 0
11:18:09 exit_group(0)                  = ?
11:18:09 +++ exited with 0 +++
```

```c:strace.c
int
main(int argc, char *argv[])
{
	init(argc, argv);
    ^^^^^^^^^^^^^^^^^!! most likely, option, user permission and signal check.
                        and thread id from procfs.

	while (trace())
    ^^^^^^^^^^^^^^^!! main loop, it will issue syscall ptrace(2) to get process info
		;

	cleanup();
    ^^^^^^^^^^^^^^^!! kill trace controller.
	fflush(NULL);
    ^^^^^^^^^^^^^^^!! flush a stream here for log file.
	if (shared_log != stderr)
		fclose(shared_log);
	if (popen_pid) {
		while (waitpid(popen_pid, NULL, 0) < 0 && errno == EINTR)
			;
	}
	if (exit_code > 0xff) {
		/* Avoid potential core file clobbering.  */
		struct_rlimit rlim = {0, 0};
		set_rlimit(RLIMIT_CORE, &rlim);

		/* Child was killed by a signal, mimic that.  */
		exit_code &= 0xff;
		signal(exit_code, SIG_DFL);
		raise(exit_code);
		/* Paranoia - what if this signal is not fatal?
		   Exit with 128 + signo then.  */
		exit_code += 128;
	}

	return exit_code;
}

static void
cleanup(void)
{
	unsigned int i;
	struct tcb *tcp;
	int fatal_sig;

	/* 'interrupted' is a volatile object, fetch it only once */
	fatal_sig = interrupted;
	if (!fatal_sig)
		fatal_sig = SIGTERM;

	for (i = 0; i < tcbtabsize; i++) {
		tcp = tcbtab[i];
		if (!tcp->pid)
			continue;
		if (debug_flag)
			error_msg("cleanup: looking at pid %u", tcp->pid);
		if (tcp->pid == strace_child) {
            ^^^^^^^^^^^^^^^^^^^^^^^^^!! kill tracer process here.
			kill(tcp->pid, SIGCONT);
			kill(tcp->pid, fatal_sig);
		}
		detach(tcp);
	}
	if (cflag)
		call_summary(shared_log);
}

[ptraceの使い方](http://www.ol.inf.uec.ac.jp/~oyama/jikken2-2011/pt.pdf)