strace 기초 — 시스템 콜 추적으로 프로그램 내부 들여다보기

strace의 ptrace 기반 동작 원리, 기본/고급 옵션, -e trace 필터, -c 통계, 실전 디버깅 시나리오(파일 없음·권한 거부·네트워크 연결 실패) 해결법을 설명합니다.

· 6 min read · PALDYN Team

지난 글에서 메모리 누수를 조사하는 도구들을 살펴봤습니다. 이번에는 strace — 프로그램이 커널에 어떤 시스템 콜을 보내는지 실시간으로 추적하는 도구를 알아봅니다. 소스 코드 없이도 프로그램이 어떤 파일을 열려 하는지, 왜 실패하는지, 어떤 네트워크 연결을 시도하는지 파악할 수 있습니다.

동작 원리

strace는 Linux의 ptrace() 시스템 콜을 이용합니다. 대상 프로세스가 시스템 콜을 호출할 때마다 커널이 strace를 깨워 진입/종료 시점의 레지스터 값을 읽게 합니다. 소스 코드 수정이나 라이브러리 치환 없이 순수하게 커널 레벨에서 관찰합니다.

strace 동작 원리

strace 출력 형식:

syscall_name(인자1, 인자2, ...) = 반환값

에러 시에는 -1 ERRNO_NAME (설명) 형태로 표시됩니다.

기본 사용법

# 새 프로세스 실행하며 추적
strace ls /tmp

# 실행 중인 프로세스에 attach
sudo strace -p 1234

# 자식 프로세스까지 추적 (-f)
sudo strace -f -p 1234

# 표준 에러 대신 파일에 저장
sudo strace -o /tmp/trace.log -p 1234

# 타임스탬프 포함
strace -tt ls /tmp

# 각 시스템 콜 소요 시간
strace -T ls /tmp

필터링 옵션

출력이 너무 많을 때 -e trace 옵션으로 특정 카테고리만 볼 수 있습니다.

strace 명령어

# 파일 접근 관련 콜만
strace -e trace=file ls

# 네트워크 관련 콜만 (실행 중 프로세스)
sudo strace -e trace=network -p 1234

# 특정 콜 이름 지정
strace -e openat,read,write cat /etc/hosts

# 프로세스 생성 관련
strace -e trace=process bash -c "echo hello"

# 메모리 관련
strace -e trace=memory ./my_program

통계 모드 (-c)

어떤 시스템 콜이 얼마나 자주, 얼마나 오래 호출되는지 요약합니다.

strace -c ls /

# 출력 예시:
# % time     seconds  usecs/call     calls    errors syscall
# ------ ----------- ----------- --------- --------- ----------------
#  38.16    0.000291          36         8           mmap
#  21.05    0.000160          40         4           read
#  15.79    0.000120          24         5           openat
#  10.53    0.000080          80         1           execve

성능 프로파일링보다 디버깅에 더 유용합니다. 어떤 콜이 에러가 많은지 (errors 컬럼) 한눈에 볼 수 있습니다.

실전 디버깅 시나리오

1. 파일을 찾지 못하는 앱

No such file or directory 에러가 나는 앱이 어떤 경로를 찾는지 파악합니다.

# ENOENT(파일 없음) 발생 위치 찾기
strace -e openat ./my_app 2>&1 | grep ENOENT

# 출력:
# openat(AT_FDCWD, "/etc/myapp/config.yml", O_RDONLY) = -1 ENOENT
# openat(AT_FDCWD, "/home/user/.myapp.yml", O_RDONLY) = -1 ENOENT
# → 앱이 찾는 설정 파일 위치를 정확히 알 수 있음

2. 권한 거부 문제

strace -e openat,access -p 1234 2>&1 | grep EACCES

# openat(AT_FDCWD, "/var/log/app.log", O_WRONLY|O_APPEND) = -1 EACCES
# → 로그 파일 쓰기 권한 없음 → chmod or 사용자 변경

3. 네트워크 연결 실패

strace -e connect,socket,sendto -p 1234 2>&1 | grep -E 'connect|REFUSED|TIMEOUT'

# connect(4, {sa_family=AF_INET, sin_port=htons(5432), sin_addr="127.0.0.1"}, 16) = -1 ECONNREFUSED
# → PostgreSQL 포트 5432에 연결 실패 → DB 실행 여부 확인

4. 느린 프로세스 원인 분석

# 시간이 오래 걸리는 콜 찾기 (10ms 이상)
strace -T -p 1234 2>&1 | awk -F'<' '$2+0 > 0.01 {print}'

# read(5, ...) = 1024 <0.032156>  ← 32ms 소요
# → slow I/O 위치 파악

5. 실행 파일이 로드하는 라이브러리

strace -e openat ./my_binary 2>&1 | grep '.so'

# openat(AT_FDCWD, "/lib/x86_64-linux-gnu/libssl.so.3", O_RDONLY) = 3
# openat(AT_FDCWD, "/lib/x86_64-linux-gnu/libcrypto.so.3", O_RDONLY) = 3

주의사항

성능 오버헤드: strace는 모든 시스템 콜마다 컨텍스트 스위치를 유발합니다. I/O 집약적인 프로세스에서는 10배 이상 느려질 수 있습니다. 프로덕션 환경에서는 짧은 시간만 사용하거나 -e trace 필터로 범위를 좁혀야 합니다.

더 낮은 오버헤드 대안: perf trace는 strace와 비슷하지만 eBPF 기반이라 오버헤드가 훨씬 낮습니다.

# perf trace (strace 대안, 낮은 오버헤드)
sudo perf trace -p 1234

# 특정 콜만
sudo perf trace -e openat -p 1234

보안: ptrace는 프로세스의 메모리를 읽을 수 있는 강력한 권한입니다. 다른 사용자의 프로세스를 추적하려면 root 권한이 필요하고, /proc/sys/kernel/yama/ptrace_scope 설정에 따라 제한될 수 있습니다.


지난 글: 메모리 누수 조사 — valgrind·heaptrack·smaps로 원인 찾기


읽어주셔서 감사합니다. 😊