이번 글에서는 Proc filesystem에서 process 관련된 내용을 좀 더 이해하기 위해 별도로 글을 작성하게 되었습니다.
여러분들이 Terminal에서 "cd /proc/self" 명령어로 해당 디렉토리로 이동하게 되면 현재 실행중인 쉘에 대한 정보를 가진 디렉토리입니다. 해당 디렉토리를 살펴보죠.
linuxias@desktop:/proc/self$ ls -al total 0 dr-xr-xr-x 9 linuxias linuxias 0 7월 9 22:20 . dr-xr-xr-x 260 root root 0 7월 9 21:59 .. dr-xr-xr-x 2 linuxias linuxias 0 7월 9 22:20 attr -rw-r--r-- 1 linuxias linuxias 0 7월 9 22:20 autogroup -r-------- 1 linuxias linuxias 0 7월 9 22:20 auxv -r--r--r-- 1 linuxias linuxias 0 7월 9 22:20 cgroup --w------- 1 linuxias linuxias 0 7월 9 22:20 clear_refs -r--r--r-- 1 linuxias linuxias 0 7월 9 22:20 cmdline -rw-r--r-- 1 linuxias linuxias 0 7월 9 22:20 comm -rw-r--r-- 1 linuxias linuxias 0 7월 9 22:20 coredump_filter -r--r--r-- 1 linuxias linuxias 0 7월 9 22:20 cpuset lrwxrwxrwx 1 linuxias linuxias 0 7월 9 22:20 cwd -> /proc/5666 -r-------- 1 linuxias linuxias 0 7월 9 22:20 environ lrwxrwxrwx 1 linuxias linuxias 0 7월 9 22:20 exe -> /bin/bash dr-x------ 2 linuxias linuxias 0 7월 9 22:20 fd dr-x------ 2 linuxias linuxias 0 7월 9 22:20 fdinfo -rw-r--r-- 1 linuxias linuxias 0 7월 9 22:20 gid_map -r-------- 1 linuxias linuxias 0 7월 9 22:20 io -r--r--r-- 1 linuxias linuxias 0 7월 9 22:20 limits -rw-r--r-- 1 linuxias linuxias 0 7월 9 22:20 loginuid dr-x------ 2 linuxias linuxias 0 7월 9 22:20 map_files -r--r--r-- 1 linuxias linuxias 0 7월 9 22:20 maps -rw------- 1 linuxias linuxias 0 7월 9 22:20 mem -r--r--r-- 1 linuxias linuxias 0 7월 9 22:20 mountinfo -r--r--r-- 1 linuxias linuxias 0 7월 9 22:20 mounts -r-------- 1 linuxias linuxias 0 7월 9 22:20 mountstats dr-xr-xr-x 5 linuxias linuxias 0 7월 9 22:20 net dr-x--x--x 2 linuxias linuxias 0 7월 9 22:20 ns -r--r--r-- 1 linuxias linuxias 0 7월 9 22:20 numa_maps -rw-r--r-- 1 linuxias linuxias 0 7월 9 22:20 oom_adj -r--r--r-- 1 linuxias linuxias 0 7월 9 22:20 oom_score -rw-r--r-- 1 linuxias linuxias 0 7월 9 22:20 oom_score_adj -r-------- 1 linuxias linuxias 0 7월 9 22:20 pagemap -r-------- 1 linuxias linuxias 0 7월 9 22:20 patch_state -r-------- 1 linuxias linuxias 0 7월 9 22:20 personality -rw-r--r-- 1 linuxias linuxias 0 7월 9 22:20 projid_map lrwxrwxrwx 1 linuxias linuxias 0 7월 9 22:20 root -> / -rw-r--r-- 1 linuxias linuxias 0 7월 9 22:20 sched -r--r--r-- 1 linuxias linuxias 0 7월 9 22:20 schedstat -r--r--r-- 1 linuxias linuxias 0 7월 9 22:20 sessionid -rw-r--r-- 1 linuxias linuxias 0 7월 9 22:20 setgroups -r--r--r-- 1 linuxias linuxias 0 7월 9 22:20 smaps -r--r--r-- 1 linuxias linuxias 0 7월 9 22:20 smaps_rollup -r-------- 1 linuxias linuxias 0 7월 9 22:20 stack -r--r--r-- 1 linuxias linuxias 0 7월 9 22:20 stat -r--r--r-- 1 linuxias linuxias 0 7월 9 22:20 statm -r--r--r-- 1 linuxias linuxias 0 7월 9 22:20 status -r-------- 1 linuxias linuxias 0 7월 9 22:20 syscall dr-xr-xr-x 3 linuxias linuxias 0 7월 9 22:20 task -r--r--r-- 1 linuxias linuxias 0 7월 9 22:20 timers -rw-rw-rw- 1 linuxias linuxias 0 7월 9 22:20 timerslack_ns -rw-r--r-- 1 linuxias linuxias 0 7월 9 22:20 uid_map -r--r--r-- 1 linuxias linuxias 0 7월 9 22:20 wchan | cs |
특이한 건 모든 파일의 크기가 0이지만 많은 정보들을 여러분에게 제공할 것입니다. 파일 사이즈가 0인 이유는 파일일 기본적으로 정보를 저장하고 있는것이 아닌, 커널의 데이터 구조 내부를 투영시켜주는(?) 창과같은 역할을 하기 때문에 실제 데이터를 가지고 있진 않습니다. 다시 말해 실제 데이터를 가지고 있는 파일이 아닙니다. 이 특별한 파일들은 실제 데이터는 없지만 파일시스템 오퍼레이션(read, write 등) 에 대해 수행이 가능합니다. 파일시스템 오퍼레이션이 수행되면 커널은 요청된 오퍼레이션을 인식하고 디스크에서 읽거나 쓰는 것 처럼 동적으로 수행하게 됩니다.(echo, cat 등의 명령어도 적용이 가능하다는 얘기입니다.)
그럼 여기서 좀 더 디테일한 내용들을 살펴보겠습니다.
/proc/<pid>/maps
linuxias@desktop:/proc/self$ cat maps 00400000-004f4000 r-xp 00000000 08:01 786932 /bin/bash 006f3000-006f4000 r--p 000f3000 08:01 786932 /bin/bash 006f4000-006fd000 rw-p 000f4000 08:01 786932 /bin/bash 006fd000-00703000 rw-p 00000000 00:00 0 00c90000-00f17000 rw-p 00000000 00:00 0 [heap] 7f989e760000-7f989e76b000 r-xp 00000000 08:01 6822306 /lib/x86_64-linux-gnu/libnss_files-2.23.so 7f989e76b000-7f989e96a000 ---p 0000b000 08:01 6822306 /lib/x86_64-linux-gnu/libnss_files-2.23.so 7f989e96a000-7f989e96b000 r--p 0000a000 08:01 6822306 /lib/x86_64-linux-gnu/libnss_files-2.23.so 7f989e96b000-7f989e96c000 rw-p 0000b000 08:01 6822306 /lib/x86_64-linux-gnu/libnss_files-2.23.so 7f989e96c000-7f989e972000 rw-p 00000000 00:00 0 7f989e972000-7f989e97d000 r-xp 00000000 08:01 6822310 /lib/x86_64-linux-gnu/libnss_nis-2.23.so 7f989e97d000-7f989eb7c000 ---p 0000b000 08:01 6822310 /lib/x86_64-linux-gnu/libnss_nis-2.23.so 7f989eb7c000-7f989eb7d000 r--p 0000a000 08:01 6822310 /lib/x86_64-linux-gnu/libnss_nis-2.23.so 7f989eb7d000-7f989eb7e000 rw-p 0000b000 08:01 6822310 /lib/x86_64-linux-gnu/libnss_nis-2.23.so 7f989eb7e000-7f989eb94000 r-xp 00000000 08:01 6822290 /lib/x86_64-linux-gnu/libnsl-2.23.so 7f989eb94000-7f989ed93000 ---p 00016000 08:01 6822290 /lib/x86_64-linux-gnu/libnsl-2.23.so 7f989ed93000-7f989ed94000 r--p 00015000 08:01 6822290 /lib/x86_64-linux-gnu/libnsl-2.23.so 7f989ed94000-7f989ed95000 rw-p 00016000 08:01 6822290 /lib/x86_64-linux-gnu/libnsl-2.23.so 7f989ed95000-7f989ed97000 rw-p 00000000 00:00 0 7f989ed97000-7f989ed9f000 r-xp 00000000 08:01 6822301 /lib/x86_64-linux-gnu/libnss_compat-2.23.so 7f989ed9f000-7f989ef9e000 ---p 00008000 08:01 6822301 /lib/x86_64-linux-gnu/libnss_compat-2.23.so 7f989ef9e000-7f989ef9f000 r--p 00007000 08:01 6822301 /lib/x86_64-linux-gnu/libnss_compat-2.23.so 7f989ef9f000-7f989efa0000 rw-p 00008000 08:01 6822301 /lib/x86_64-linux-gnu/libnss_compat-2.23.so 7f989efa0000-7f989f3b8000 r--p 00000000 08:01 12584711 /usr/lib/locale/locale-archive 7f989f3b8000-7f989f578000 r-xp 00000000 08:01 6822293 /lib/x86_64-linux-gnu/libc-2.23.so 7f989f578000-7f989f778000 ---p 001c0000 08:01 6822293 /lib/x86_64-linux-gnu/libc-2.23.so 7f989f778000-7f989f77c000 r--p 001c0000 08:01 6822293 /lib/x86_64-linux-gnu/libc-2.23.so 7f989f77c000-7f989f77e000 rw-p 001c4000 08:01 6822293 /lib/x86_64-linux-gnu/libc-2.23.so 7f989f77e000-7f989f782000 rw-p 00000000 00:00 0 7f989f782000-7f989f785000 r-xp 00000000 08:01 6822295 /lib/x86_64-linux-gnu/libdl-2.23.so 7f989f785000-7f989f984000 ---p 00003000 08:01 6822295 /lib/x86_64-linux-gnu/libdl-2.23.so 7f989f984000-7f989f985000 r--p 00002000 08:01 6822295 /lib/x86_64-linux-gnu/libdl-2.23.so 7f989f985000-7f989f986000 rw-p 00003000 08:01 6822295 /lib/x86_64-linux-gnu/libdl-2.23.so 7f989f986000-7f989f9ab000 r-xp 00000000 08:01 6820485 /lib/x86_64-linux-gnu/libtinfo.so.5.9 7f989f9ab000-7f989fbaa000 ---p 00025000 08:01 6820485 /lib/x86_64-linux-gnu/libtinfo.so.5.9 7f989fbaa000-7f989fbae000 r--p 00024000 08:01 6820485 /lib/x86_64-linux-gnu/libtinfo.so.5.9 7f989fbae000-7f989fbaf000 rw-p 00028000 08:01 6820485 /lib/x86_64-linux-gnu/libtinfo.so.5.9 7f989fbaf000-7f989fbd5000 r-xp 00000000 08:01 6822291 /lib/x86_64-linux-gnu/ld-2.23.so 7f989fdad000-7f989fdb1000 rw-p 00000000 00:00 0 7f989fdcd000-7f989fdd4000 r--s 00000000 08:01 12857131 /usr/lib/x86_64-linux-gnu/gconv/gconv-modules.cache 7f989fdd4000-7f989fdd5000 r--p 00025000 08:01 6822291 /lib/x86_64-linux-gnu/ld-2.23.so 7f989fdd5000-7f989fdd6000 rw-p 00026000 08:01 6822291 /lib/x86_64-linux-gnu/ld-2.23.so 7f989fdd6000-7f989fdd7000 rw-p 00000000 00:00 0 7ffe9814f000-7ffe98171000 rw-p 00000000 00:00 0 [stack] 7ffe981dd000-7ffe981e0000 r--p 00000000 00:00 0 [vvar] 7ffe981e0000-7ffe981e2000 r-xp 00000000 00:00 0 [vdso] ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0 [vsyscall] | cs |
정리해보면 아래와 같습니다. perms에 표기된 p는 private이란 의미로 copy on wirte입니다.
address |
00400000-004f4000 |
perms |
r-xp |
offset |
00000000 |
dev(major:minor) |
08:01 |
inode |
786932 |
pathname |
/bin/bash |
0x400000-0x4f4000는 해당 entry가 사용중인 주소 공간입니다. r-xp는 mapping된 영역이 readable, executable, private 퍼미션임을 알 수 있습니다. 08:01은 디바이스의 주번호(major)와 부번호(minor)번호를 알려주고 있습니다. 786932는 inode를 가리키는 값입니다.
위에서 출력한 maps 파일의 각 라인을 자세히 살펴보면 /bin/bash 실행파일의 주소 매핑에 대한 출력임을 알 수 있습니다. 세세하게 분석하게 되면 다양한 정보를 알 수 있게됩니다.
Code Segment
code segment는 text segment라고도 불리며 많은 사람들이 text segment가 더 익숙한 용어일 수 있습니다. text segment는 text section을 포함하고 있는 segment입니다. Code segment에는 실행할 수 있는 모든 코드들이 모여있는 메모리 공간입니다.
실행할 수 있는 코드가 저장된 메모리 공간은 읽고, 실행할 수 있는 권한은 필요하나, 쓰기 권한은 필요없습니다. 조금만 생각해 보시면 왜 그런지 쉽게 이해 되실텐데요, 실행되는 코드가 변경되어 버린다면 여러 다른 문제들이 발생할 수 있습니다.
gbd와 같은 디버거를 사용하여 프로그램을 디버깅 할 때 이런 메모리 구조를 이해하는 건 매우 중요합니다. 디버깅 시에 다양한 메모리 주소에 대해 살펴볼 것이고 그때 해당 주소가 어느 메모리 특성을 가진 세그먼트, 섹션에 해당하는지 빠르게 파악할 수 있기 때문이죠.
Data Segment
우리는 지금 /bin/bash 프로그램을 이용한 예제를 살펴보고 있습니다. 그 중 Data segment에 대해 조금 살펴보겠습니다.
006f4000-006fd000 rw-p 000f4000 08:01 786932 /bin/bash
위의 mapping 정보를 보면 code segment와 매우 유사함을 알 수 있습니다. 차이를 보면 매핑되는 주소와 퍼미션이 다르네요. data 영역은 읽고 쓸수는 있지만, 실행할 수 있는 영역은 아닙니다. 즉 실행 가능한 Instruction을 메모리 상에 작성한다 하여도 실행할 수 없습니다. 데이터는 계속 변해야하므로 쓰기 권한도 가지게 됩니다. Data segments에 위치하는 변수들은 초기화된 전역변수들입니다. 간단한 프로그램을 작성하여 전역변수를 주소를 출력해 보면 위와 같은 데이터 영역 내에 존재할 것 입니다. 변수, 데이터가 위치하는 또다른 곳은 stack와 heap 영역입니다. 각 영역은 나중에 살펴볼 예정입니다.
Heap Segment
이름에서 알 수 있듯이 이 Segment에는 Heap 변수들이 위치하게 됩니다. Heap 변수란 malloc(), new()와 같은 API를 통해 runtime 중에 동적으로 할당 요청되는 녀석들입니다. 추가로 Heap segment에는 bss section도 포함되어 있습니다. bss section은 초기화되지 않은 전역변수들이 위치하는 메모리 영역입니다. 위에서 Data segment에서는 초기화된 전역변수가 위치했다면 초기화되지 않은 변수들은 여기 위치하게 되죠. 그럼 왜 초기화 유무에 따라 전역변수의 위치를 나눠놓았을까요? 초기화되었든 되지 않았던 전역변수는 하나로 묶어 놓는게 더 편하지 않을까? 라고 생각하시는 분도 계실텐데요. 나눠놓은 이유는 저장공간을 위해서 입니다. 초기화가 되지 않은 변수들은 디스크 공간에 저장해 놓을 필요가 없게되므로 그 만큼 디스크 이미지 상의 저장되는 사이즈가 줄어드는 것이죠. 이런 이유로 나눠 놓고 있습니다.
Mapped Base / Shard Libraries
계속해서 maps 파일에서 살펴볼 부분은 mapped based address라고 불리워지는 부분입니다. 이 영역은 실행파일의 공유 라이브러리가 로드되는 위치를 정의하고 있습니다.
/lib/x86_64-linux-gnu/ld-2.23.so 는 프로세스가 시작할 때 처음으로 로드되어지는 공유 라이브러리입니다. 링커 자기 자신이죠. 기본적으로 하나 이상의 공유 라이브러리에서 링크되는 실행 파일을 만들 때 링커는 실행 파일에 암시 적으로 링크됩니다. 링커가 모든 외부 요소를 해결해야하기 때문에 심볼을 링크 된 공유 라이브러리에 저장하려면 먼저 메모리에 매핑해야하며, 이것이 링커가 항상 실행 파일에 표시되는 첫 번째 공유 라이브러리가되는 이유입니다. 링커가 매핑된 이후 실행파일에 연관된 모든 공유 라이브러리가 maps 파일에 나타납니다. maps 파일은 보시면 다양한 공유 라이브러리들이 매핑된 것을 볼 수 있습니다. ldd 명령어를 보면 더 정리된 내용으로 한눈에 보실 수 있습니다.
linuxias@desktop:~/privateProject/Example/linux/proc (master)$ ldd /bin/bash
linux-vdso.so.1 => (0x00007ffddbae1000)
libtinfo.so.5 => /lib/x86_64-linux-gnu/libtinfo.so.5 (0x00007fb113665000)
libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007fb113461000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fb113097000)
/lib64/ld-linux-x86-64.so.2 (0x00007fb11388e000)
Stack Segment
이 글에서 알아볼 마지막 Segment는 Stack입니다. Stack은 모두 이해하고 계신테니 간단히 설명하고 지나가겠습니다. Stack은 지역 변수들이나 함수 파라미터등 다양한 요소들을 위한 공간입니다. 말 그대로 Stack 자료구조와 같이 Push / Pop 동작을하며 동적으로 크기가 변경되죠. 스택에 대해 다룰내용은 많으니 나중에 Stack 관련 주제만 따로 다뤄보겠습니다.
'Linux > Debugging & Testing' 카테고리의 다른 글
[valgrind] Memory debugging & profiling tool (0) | 2018.07.26 |
---|---|
/Proc FileSystem - Kernel (0) | 2018.04.10 |
/Proc Filesystem - Process (0) | 2018.03.20 |
Strace - trace system calls and signals (0) | 2018.03.19 |
pwndbg (0) | 2017.05.04 |