ls 명령어 분석 with strace

2025. 7. 29. 14:06·Linux

일단 strace 실행

strace ls

execve("/usr/bin/ls", ["ls"], 0xffffd2497820 /* 62 vars */) = 0
brk(NULL)                               = 0xc63a27921000
mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xe8c8d6ac7000
faccessat(AT_FDCWD, "/etc/ld.so.preload", R_OK) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=66659, ...}) = 0
mmap(NULL, 66659, PROT_READ, MAP_PRIVATE, 3, 0) = 0xe8c8d6ab6000
close(3)                                = 0
openat(AT_FDCWD, "/lib/aarch64-linux-gnu/libselinux.so.1", O_RDONLY|O_CLOEXEC) = 3
read(3, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0\267\0\1\0\0\0\0\0\0\0\0\0\0\0"..., 832) = 832
fstat(3, {st_mode=S_IFREG|0644, st_size=198800, ...}) = 0
mmap(NULL, 337472, PROT_NONE, MAP_PRIVATE|MAP_ANONYMOUS|MAP_DENYWRITE, -1, 0) = 0xe8c8d6a3b000
mmap(0xe8c8d6a40000, 271936, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0) = 0xe8c8d6a40000
munmap(0xe8c8d6a3b000, 20480)           = 0
munmap(0xe8c8d6a83000, 42560)           = 0
mprotect(0xe8c8d6a6c000, 77824, PROT_NONE) = 0
mmap(0xe8c8d6a7f000, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x2f000) = 0xe8c8d6a7f000
mmap(0xe8c8d6a81000, 5696, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0xe8c8d6a81000
close(3)                                = 0
openat(AT_FDCWD, "/lib/aarch64-linux-gnu/libc.so.6", O_RDONLY|O_CLOEXEC) = 3
read(3, "\177ELF\2\1\1\3\0\0\0\0\0\0\0\0\3\0\267\0\1\0\0\0\360\206\2\0\0\0\0\0"..., 832) = 832
fstat(3, {st_mode=S_IFREG|0755, st_size=1722920, ...}) = 0
mmap(NULL, 1892240, PROT_NONE, MAP_PRIVATE|MAP_ANONYMOUS|MAP_DENYWRITE, -1, 0) = 0xe8c8d6872000
mmap(0xe8c8d6880000, 1826704, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0) = 0xe8c8d6880000
munmap(0xe8c8d6872000, 57344)           = 0
munmap(0xe8c8d6a3e000, 8080)            = 0
mprotect(0xe8c8d6a1a000, 77824, PROT_NONE) = 0
mmap(0xe8c8d6a2d000, 20480, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x19d000) = 0xe8c8d6a2d000
mmap(0xe8c8d6a32000, 49040, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0xe8c8d6a32000
close(3)                                = 0
openat(AT_FDCWD, "/lib/aarch64-linux-gnu/libpcre2-8.so.0", O_RDONLY|O_CLOEXEC) = 3
read(3, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0\267\0\1\0\0\0\0\0\0\0\0\0\0\0"..., 832) = 832
fstat(3, {st_mode=S_IFREG|0644, st_size=592328, ...}) = 0
mmap(NULL, 721536, PROT_NONE, MAP_PRIVATE|MAP_ANONYMOUS|MAP_DENYWRITE, -1, 0) = 0xe8c8d67cf000
mmap(0xe8c8d67d0000, 656000, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0) = 0xe8c8d67d0000
munmap(0xe8c8d67cf000, 4096)            = 0
munmap(0xe8c8d6871000, 57984)           = 0
mprotect(0xe8c8d6858000, 94208, PROT_NONE) = 0
mmap(0xe8c8d686f000, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x8f000) = 0xe8c8d686f000
close(3)                                = 0
mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xe8c8d6a8c000
set_tid_address(0xe8c8d6a8c0f0)         = 2446818
set_robust_list(0xe8c8d6a8c100, 24)     = 0
rseq(0xe8c8d6a8c740, 0x20, 0, 0xd428bc00) = 0
mprotect(0xe8c8d6a2d000, 12288, PROT_READ) = 0
mprotect(0xe8c8d686f000, 4096, PROT_READ) = 0
mprotect(0xe8c8d6a7f000, 4096, PROT_READ) = 0
mprotect(0xc63a25a9e000, 8192, PROT_READ) = 0
mprotect(0xe8c8d6acc000, 8192, PROT_READ) = 0
prlimit64(0, RLIMIT_STACK, NULL, {rlim_cur=8192*1024, rlim_max=RLIM64_INFINITY}) = 0
munmap(0xe8c8d6ab6000, 66659)           = 0
statfs("/sys/fs/selinux", 0xffffda5b90a0) = -1 ENOENT (No such file or directory)
statfs("/selinux", 0xffffda5b90a0)      = -1 ENOENT (No such file or directory)
getrandom("\xd4\xa1\x6b\x89\x50\x53\x8f\x5f", 8, GRND_NONBLOCK) = 8
brk(NULL)                               = 0xc63a27921000
brk(0xc63a27942000)                     = 0xc63a27942000
openat(AT_FDCWD, "/proc/filesystems", O_RDONLY|O_CLOEXEC) = 3
fstat(3, {st_mode=S_IFREG|0444, st_size=0, ...}) = 0
read(3, "nodev\tsysfs\nnodev\ttmpfs\nnodev\tbd"..., 1024) = 400
read(3, "", 1024)                       = 0
close(3)                                = 0
faccessat(AT_FDCWD, "/etc/selinux/config", F_OK) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/usr/lib/locale/locale-archive", O_RDONLY|O_CLOEXEC) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=4407424, ...}) = 0
mmap(NULL, 4407424, PROT_READ, MAP_PRIVATE, 3, 0) = 0xe8c8d6200000
close(3)                                = 0
ioctl(1, TCGETS, {c_iflag=ICRNL|IXON|IUTF8, c_oflag=NL0|CR0|TAB0|BS0|VT0|FF0|OPOST|ONLCR, c_cflag=B38400|CS8|CREAD, c_lflag=ISIG|ICANON|ECHO|ECHOE|ECHOK|IEXTEN|ECHOCTL|ECHOKE, ...}) = 0
ioctl(1, TIOCGWINSZ, {ws_row=36, ws_col=126, ws_xpixel=0, ws_ypixel=0}) = 0
openat(AT_FDCWD, ".", O_RDONLY|O_NONBLOCK|O_CLOEXEC|O_DIRECTORY) = 3
fstat(3, {st_mode=S_IFDIR|0775, st_size=4096, ...}) = 0
getdents64(3, 0xc63a27928740 /* 9 entries */, 32768) = 280
getdents64(3, 0xc63a27928740 /* 0 entries */, 32768) = 0
close(3)                                = 0
fstat(1, {st_mode=S_IFCHR|0620, st_rdev=makedev(0x88, 0), ...}) = 0
write(1, "fact  factorial.c  simple  simpl"..., 83fact  factorial.c  simple  simple.c  stack_syscall.c  syscall_test  syscall_test.c
) = 83
close(1)                                = 0
close(2)                                = 0
exit_group(0)                           = ?
+++ exited with 0 +++

엄청나게 뭐가 많이 나오는데..
아무튼 이런 시스템 콜 실행 흐름을 가진다.


호출한 시스템콜의 호출 목록

  • int execve(const char *pathname, char *const _Nullable argv[], char *const _Nullable envp[])
    • 성공: 리턴 없음
    • 실패: -1
  • int brk(void *addr)
    • 성공: 0
    • 실패: -1
  • void mmap(void addr[.length], size_t length, int prot, int flags)
    • 성공: 매핑된 곳의 포인터 리턴
    • 실패: MAP_FAILED (-1)
  • int faccessat(int dirfd, const char *pathname, int mode, int flags)
    • 성공: 0
    • 실패: -1
  • int openat(int dirfd, const char *pathname, int flags, ...)
    • 성공: new file descriptor
    • 실패: -1
  • int fstat(int fd, struct stat *statbuf)
    • 성공: 0
    • 실패: -1
  • int close(int fd)
    • 성공: 0
    • 실패: -1
  • ssize_t read(int fd, void buf[.count], size_t count)
    • 성공: 읽은 바이트 수
    • 실패: -1
  • int munmap(void addr[.length], size_t length)
    • 성공: 0
    • 실패: -1
  • int mprotect(void addr[.len], size_t len, int prot)
    • 성공: 0
    • 실패: -1
  • set_tid_address(SYS_set_tid_address, int *tidptr)
    • 항상 성공:  caller's thread ID
  • set_robust_list()
    • 성공: 0
    • 실패: error code
  • rseq
  • int prlimit64(pid_t pid, int resource, const struct rlimit *Nullable new limit, struct rlimit  *_Nullable old_limit)
    • 성공: 0
    • 실패: -1
  • int statfs(const char *path, struct statfs *buf)
    • 성공: 0
    • 실패: -1
  • ssize_t getrandom(viod buf[.buflen], size_t buflen, unsigned int flags)
    • 성공: 버퍼에서 읽은 바이트 수
    • 실패: -1
  • int ioctl(int fd, unsigned long op, ...)
    • 성공: 0
    • 실패: -1
  • ssize_t getdents64(int fd, void dirp[.count], size_t count)
    • 성공: 읽은 바이트 수, 디렉토리의 끝이면 0리턴
    • 실패: -1
  • ssize_t write(int fd, const void buf[.count], size_t count)
    • 성공: 쓴 바이트 수
    • 실패: -1
  • exit_group

종류별 시스템콜 총 호출 횟수

호출 횟수 시스템콜
15 mmap
1 execve
8 mprotect
9 close
7 openat
8 fstat
7 munmap
5 read
2 statfs
3 brk
1 set_robust_list
2 faccessat
2 getdents64
1 set_tid_address
2 ioctl
1 prlimit64
1 rseq
1 write
1 getrandom

ls 명령어에서 읽기 성공한 모든 파일의 경로

  • /etc/ld.so.cache
  • /lib/aarch64-linux-gnu/libselinux.so.1
  • /lib/aarch64-linux-gnu/libc.so.6
  • /lib/aarch64-linux-gnu/libpcre2-8.so.0
  • /proc/filesystems
  • /usr/lib/locale/locale-archive
  • .  (현재 디렉토리)

자주 나오는 시스템 콜

  • openat : 특정 디렉토리를 기준으로 상대경로로 파일을 연다.
  • read : 특정 바이트 수 만큼 파일에서 읽어서 버퍼에 넣는다.
  • write : 특정 바이트 수만큼 버퍼에서 파일로 쓴다.
  • close : 파일 디스크립터를 닫는다. 다른 곳에서 접근할 수 없다.
  • execve : 특정 경로에 있는 프로그램을 실행한다.

ls 명령어 원리

이부분이 핵심이라고 생각됨

차근차근 분석해보자

openat(AT_FDCWD, ".", O_RDONLY|O_NONBLOCK|O_CLOEXEC|O_DIRECTORY) = 3
fstat(3, {st_mode=S_IFDIR|0775, st_size=4096, ...}) = 0
getdents64(3, 0xc63a27928740 /* 9 entries */, 32768) = 280
getdents64(3, 0xc63a27928740 /* 0 entries */, 32768) = 0
close(3)                                = 0
fstat(1, {st_mode=S_IFCHR|0620, st_rdev=makedev(0x88, 0), ...}) = 0
write(1, "fact  factorial.c  simple  simpl"..., 83fact  factorial.c  simple  simple.c  stack_syscall.c  syscall_test  syscall_test.c
) = 83
close(1)                                = 0
close(2)                                = 0
exit_group(0)
  1. 현재 디렉토리를 열고 fd(파일 디스크립터) 3을 할당 -> openat
  2. fd=3이 가리키고있는 파일의 정보 획득 -> fstat
  3. 해당 디렉토리의 엔트리를 가져온다 -> getdent
  4. fd=1의 정보를 가져온다 -> fstat
  5. 가져온 정보를 fd=1에 쓴다 -> write
fd=1은 표준 출력으로 사용자 화면에 출력하는 용도

파일 디스크립터

  • 0번 : stdin
  • 1번 : stdout
  • 2번 : stderr

'Linux' 카테고리의 다른 글

디바이스 드라이버  (0) 2025.08.01
커널 모듈 (insmod, lsmod, rmmod) 커널 API  (5) 2025.07.30
Kernel 및 System call 디버그 with GDB  (0) 2025.07.28
커널 시스템콜 추가  (3) 2025.07.25
Makefile  (2) 2025.07.24
'Linux' 카테고리의 다른 글
  • 디바이스 드라이버
  • 커널 모듈 (insmod, lsmod, rmmod) 커널 API
  • Kernel 및 System call 디버그 with GDB
  • 커널 시스템콜 추가
Jminu
Jminu
  • Jminu
    뇌 구조가 바이너리
    Jminu
  • 전체
    오늘
    어제
    • 분류 전체보기
      • C프로그래밍
        • 오류해결
        • 개인 공부
        • Programming Lab(학교수업)
        • MemoryTracker
      • C++
        • 개인 공부
      • 자료구조(Data Structure)
      • ARM arch
        • Cortex-M
        • FreeRTOS
      • 컴퓨터 공학(Computer Science)
        • OS
        • 컴퓨터 구조
      • Qualcomm 기업과제
      • Linux
      • Web
      • 똥글
      • 백준
      • Git 학습
        • 오류해결
        • 학습중
      • Python
        • 오류해결
        • 개인 공부
  • 블로그 메뉴

    • 태그
  • 링크

  • 공지사항

  • 인기 글

  • 태그

    시스템콜
    commit
    arm
    파일 입출력
    백준
    리눅스
    Git
    소수
    순환
    스택
    rubik pi
    앤드류모튼
    Branch
    자료구조
    버퍼
    커널
    토발즈
    이진 트리
    Qualcomm
    동적메모리
    C++
    INIT
    드라이버 분석
    파이썬
    포인터
    피보나치
    커널 기여
    c언어
    yolo
    rubikpi3
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.3
Jminu
ls 명령어 분석 with strace
상단으로

티스토리툴바