Strace
trace system calls and signals
strace는 linux에서 발생하는 문제들을 해결할 수 있는 여러 툴 중 system call을 추적할 수 있는 강력한 툴입니다.
System call은 open, write, read, mmap... 등등 여러분들도 잘 알고 계신 함수들입니다. System calls은 User process가 kernel에 어떠한 작업을 요청하기 위한 인터페이스 역할을 합니다.
(그림 출처 : Self-Service Linux : Mastering the Art of Problem Determination)
여기서 말하는 요청이란 User process에서는 접근할 수 없는 disk, network, memory 같은 시스템 자원에 접근하고 IPC, 시스템 정보와 같은 커널 기능에 접근하기 위함입니다. 이런 system call을 이용한 작업 중 문제가 발생한 경우 strace를 사용하여 분석하게 됩니다!. strace는 프로세스가 파일을 열지 못하거나 메모리를 할당하지 못하는 경우 등 다양한 경우에 strace를 이용해 분석이 가능합니다. 한 가지 명심할 점은 오직 System call만 확인할 수 있을 뿐 여러분들이 작성한 함수들은 확인할 수 없다는 것 유의해주세요! 좀 더 자세한 정보를 원하시는 분들은 man page를 참조해 주세요.
strace의 단순한 예제를 보고 지나가도록 하죠. 아래 예제 코드가 있습니다. /tmp/foo 파일을 열기 위해 open system call을 호출하고, 성공했다면, "open success"를 실패했다면 "open fail"을 출력하는 매우 단순한 코드입니다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <stdio.h> int main( ) { int fd ; fd = open("/tmp/foo", O_RDONLY); if (fd < 0) { printf("open fail"); return -1; } printf("open success"); return 0; } | cs |
위 코드를 gcc를 이용해 빌드한 후 strace를 이용해 분석해 봅시다!! 아래 그 결과가 있습니다.
$ gcc strace_test.c -o strace_test
$ strace -o result ./strace_test
처음보시는 분들도 계시고, strace를 접해본적이 있으신 분들은 낯익은 결과 텍스트들이 보일 것입니다. 자 여기서 몇몇 라인을 살펴보겠습니다.
Line 26 : open("/tmp/foo", O_RDONLY) = -1 ENOENT (No such file or directory)
코드에서 작성했던 open 함수입니다. READ_ONLY 옵션을 줘서 파일 오픈을 요청하였지만, 실패하였고 -1을 리턴합니다. 뒤에 연속된 내용을 보니, ENOENT (No such file or directory) 입니다. ENOENT 에러를 몰라서 /tmp/foo란 파일이 없어서 발생한 것을 바로 알 수 있습니다.
Line 30 : write(1, "open fail", 9) = 9
Line 13-17
이 라인에 대한 설명을 길게 하면 여기서 끝이 없을 것 같네요. mmap을 이용해서 libc의 정보를 메로리에 로드하고 protection을 제거하는 작업등을 합니다. 추가로 bss section을 위한 메모리 세그먼트를 생성하는 작업을 합니다. 무슨 말씀인지 이해가 지금은 안되실텐데요.. 추후에 ELF 에 대해 별도로 다루어야 할 것 같네요.
Line 18 : close(3)
libc 라이브러리 파일 디스크립터를 닫습니다.
그 이후에는 실제 작성한 예제 프로그램에서 수행하는 system call이라고 판단하시면 됩니다. 지금은 strace를 위한 설명하고 있으니, 깊은 내용은 기회가 된다면 나중에 다뤄보겠습니다! 그럼 지금부터 strace의 유용한 몇 가지 옵션에 대해 소개하겠습니다.
System call 사이의 상대시간 출력하기. [ strace -r ]
각 System call의 시간 차이를 출력해 줍니다. 결과를 보기면 제일 앞에 시간이 붙는걸 보실 수 있는데, 증가하는게 아닙니다. 바로 앞의 system call 호출 이후에 시간 차이입니다. 즉 각 system call 호출 사이의 시간입니다. 하나의 system call 호출 후 다음 system call까지 얼마의 시간이 걸리는지 파악할 수 있습니다.
System call의 수행 시간 출력하기 [ strace -T ]
각 System call이 얼마의 시간동안 수행됬는지확인할 수 있는 옵션입니다. 굉장히 유용할 것 같네요. 파일 Operation을 수행하는 동작 외에도 여러 System call에서 어느정도 시간이 걸리는지 명확하게 파악할 수 있을 것 같습니다. 이 옵션은 매우 로드가 크지만, 그 만큼 결과는 유용하게 사용할 수 있습니다.
System call의 호출 횟수 및 시간 측정하기 [ strace -c ]
어떤 System call이 몇번 호출됫고, 총 수행 시간, 그리고 어떤 Error가 있었는지 Report 형식으로 정리해서 출력해주는 옵션입니다. 여기의 time은 cpu time입니다.
System call의 상세한 내용 모두 보기! [ strace -v ]
그 전 strace의 결과에서는 Line 11 : read(3, "\177ELF\2\1\1\3\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0P\t\2\0\0\0\0\0"..., 832) = 832 와 같이 ...으로 정보가 모두 표시되지 않는 경우들이 있었습니다. -v 옵션은 그런 정보들을 모두 표시해주죠! 특히 stat, uname과 같은 system call 정보 확인할 때 자주 사용됩니다.
만약 read, write system call의 정보를 추가로 확인하고 싶다면 아래와 같이 -s 옵션을 사용하시면 좋을 것 같습니다 :D
실행 중인 프로세스에 strace 붙이기! [ strace -p ]
실행 중인 프로세스에도 strace를 붙일 수 있습니다!! -p 옵션을 이용하시면 됩니다. 저는 gedit 프로그램을 실행시킨 후 PID를 이용해 strace를 붙여보았습니다. 아래와 같은 결과를 얻을 수 있네요.
그 외에도 굉장히 많은 옵션들이 있습니다. 다른 옵션들은 man page를 참고해 보세요 !!
추후에 strace를 사용했을 때 발생할만한 문제들에 대해서 살펴보겠습니다.
지금까지 긴 글 읽어주셔서 감사합니다!
'Linux > Debugging & Testing' 카테고리의 다른 글
/Proc FileSystem - Kernel (0) | 2018.04.10 |
---|---|
/Proc FileSystem - Process in More detail (2) | 2018.04.10 |
/Proc Filesystem - Process (0) | 2018.03.20 |
pwndbg (0) | 2017.05.04 |
Software Based Memory Testing (0) | 2016.09.18 |