Recommanded Free YOUTUBE Lecture: <% selectedImage[1] %>

Contents

strace

리눅스상에서 작동하는 C 코드들은 모두 시스템콜(:12)을 주어진 임무를 수행한다. 그러므로 프로그램의 시스템콜이 호출되는 것을 추적할 수 있다면, 프로그램을 디버깅하거나 제대로 작동되는지에 대한 중요한 정보를 얻을 수 있을 것이다.

strace에 대해서

strace는 프로그램이 실행될동안 호출하는 시스템콜을 추적할 수 있는 툴 이다. 여기에 더불어 프로세스가 받은 signal에 대한 정보도 얻을 수 있다. strace를 이용하는 가장 간단한 경우는 strace 다음에 실행시킬 프로그램을 명시하는 것으로, 그러면 프로그램이 종료될때까지의 시스템콜 혹은 시그널 정보를 얻을 수 있게 된다.

strace의 사용방법은 다음과 같다.
$ strace
usage: strace [-dffhiqrtttTvVxx] [-a column] [-e expr] ... [-o file]
              [-p pid] ... [-s strsize] [-u username] [-E var=val] ...
              [command [arg ...]]
   or: strace -c [-e expr] ... [-O overhead] [-S sortby] [-E var=val] ...
              [command [arg ...]]

시스템콜 추적하기

strace를 테스트하기 위해서 간단한 셈플프로그램을 만들었다. 프로그램의 이름은 test.c으로 했다.
#include <stdio.h>

int main(int argc, char **argv)
{
  return 0;
}

이제 프로그램을 컴파일한후, strace를 이용해서 프로그램을 실행시킨다.
$ strace ./mytest2 
execve("./mytest2", ["./mytest2"], [/* 47 vars */]) = 0
brk(0)                                  = 0x804a000
access("/etc/ld.so.nohwcap", F_OK)      = -1 ENOENT (No such file or directory)
mmap2(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb7f9c000
close(3)                                = 0
access("/etc/ld.so.nohwcap", F_OK)      = -1 ENOENT (No such file or directory)
open("/lib/tls/i686/cmov/libc.so.6", O_RDONLY) = 3
read(3, "\177ELF\1\1\1\0\0\0\0\0\0\0\0\0\3\0\3\0\1\0\0\0\260a\1"..., 512) = 512
....
....
fstat64(3, {st_mode=S_IFREG|0644, st_size=1339816, ...}) = 0
mmap2(NULL, 1349136, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0xb7e3c000
mmap2(0xb7f83000, 9744, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0xb7f83000
close(3)                                = 0
mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb7e3b000
mprotect(0xb7f80000, 4096, PROT_READ)   = 0
munmap(0xb7f86000, 89519)               = 0
exit_group(0)                           = ?
Process 22425 detached

strace를 실행시키면 가장 먼저, 매개변수로 주어진 프로그램을 execv 를 이용해서 실행시킨다. 여기에서, 인자는 ./mytest2를 줬고, 47개의 환경변수를 넘겼음을 확인할 수 있다. 이 환경변수는 strace를 실행시킨, shell에서 복사된 것들이다.
execve("./mytest2", ["./mytest2"], [/* 47 vars */]) = 0
이제 brk(0), close(2), open(2), read(2)와 같은 시스템함수들을 호출하는 것을 확인할 수 있다. 최종적으로 exit_group 를 호출해서 프로세스를 종료시키고, 쉘로 detached 된다.

시그널 추적및 보고서만들기

strace를 이용하면 시그널을 추적하고, 이에 대한 보고서를 만들 수도 있다. 다음과 같은 C코드를 준비하자.
#include <stdio.h>

int main()
{
  int i;
  for(i=0;i>=0;i++)
  {
    printf("infinity\n");
  }
  return 0;
}

다음과 같이 strace를 사용해보자.
$ strace -o trace.txt ./mytest3
이제 적당한 시기에 ctrl+c 를 눌러스 SIGINT signal을 발생시킨다. strace를 이용한 모든 결과는 trace.txt에서 확인할 수 있다.
...
...
write(1, "infinity\n", 9)               = 9
write(1, "infinity\n", 9)               = 9
write(1, "infinity\n", 9)               = 9
write(1, "infinity\n", 9)               = 9
write(1, "infinity\n", 9)               = 9
write(1, "infinity\n", 9)               = 9
--- SIGINT (Interrupt) @ 0 (0) ---
+++ killed by SIGINT +++
SIGINT 시그널을 받고, 프로세스가 종료되었음을 알 수 있다.

시스템콜 통계

또한 -c 옵션을 이용해서 시스템콜에 대한 통계를 낼 수도 있다.
$ strace -o trace.txt -c ./mytest3
$ cat trace.txt
% time     seconds  usecs/call     calls    errors syscall
------ ----------- ----------- --------- --------- ----------------
100.00    0.000472           0     35067         1 write
  0.00    0.000000           0         1           read
  0.00    0.000000           0        18        16 open
  0.00    0.000000           0         2           close
  0.00    0.000000           0         1           execve
  0.00    0.000000           0         3         3 access
  0.00    0.000000           0         1           brk
  0.00    0.000000           0         1           munmap
  0.00    0.000000           0         1           mprotect
  0.00    0.000000           0         7           mmap2
  0.00    0.000000           0        16        15 stat64
  0.00    0.000000           0         3           fstat64
  0.00    0.000000           0         1           set_thread_area
------ ----------- ----------- --------- --------- ----------------
100.00    0.000472                 35122        35 total

실행 중인 프로세스 추적하기

-p 옵션으로 실행 중인 프로세스를 추적할 수 있다.
# strace -p [pid]
forkvfork(2)도 추적하려면 f와 F옵션을 사용하면 된다.
# strace -fF -p [pid]

실행 중인 데몬(:12) 프로세스의 상태를 확인하기 위해 사용할 수 있다.
  1. 데몬이 멈췄다. 어느 지점에서 멈췄는지 확인할 수 있다.
  2. 클라이언트가 연결을 하지 못한다. 클라이언트는 connect(2)함수를 호출했는지, 서버는 accept(2)함수가 제대로 호출 되었는지 확인할 수 있다.
호출한 시스템 콜에 대한 호출빈도, 에러, CPU 타임 정보를 확인할 수도 있다. Ctrl+C를 누르면 레포팅된다.
$ sudo strace -r -p 12051 -c
Process 12051 attached - interrupt to quit
^CProcess 12051 detached
% time     seconds  usecs/call     calls    errors syscall
------ ----------- ----------- --------- --------- ----------------
 98.20    0.016002         182        88           poll
  0.87    0.000142           0       703           write
  0.77    0.000125           0       572           futex
  0.16    0.000026           0      1670       439 read
  0.00    0.000000           0         1           restart_syscall
------ ----------- ----------- --------- --------- ----------------
100.00    0.016295                  3034       439 total

마치며

gdb, ltrace, strace를 함께 사용한다면, 좀더 쉽게 프로그램의 성능과 문제점등을 파악할 수 있을 것이다.