Notice
Recent Posts
Recent Comments
Link
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
Tags
- slab
- lruvec
- slowpath
- Kernel
- page
- spinlock
- Network
- fastpath
- Android
- kafka
- 카프카
- Apache
- BLOCK
- proc
- Linux
- allocator
- memory
- mm_struct
- NDK
- slub
- commit
- vmalloc
- vm_area_struct
- kmalloc
- pmap
- devicedriver
- buddy_system
- multiqueue
- strex
- blk-mq
Archives
- Today
- Total
Art of Pr0gr4m
[Linux Kernel 5] Process Memory Viewer HOL 본문
이번 포스트에서는 메모리 학습의 마무리로 메모리 뷰어 모듈 제작 실습을 진행한다.
/proc/<pid>/maps 을 읽으면 다음과 같이 프로세스의 메모리 매핑 정보를 볼 수 있다.
필드별로 할당 주소, 권한(모드), offset, 디바이스 ID, inode, 매핑 대상 or 타입을 보여준다.
이와 유사하게 인자로 전달받은 pid (인자가 없다면 1번 프로세스)의 메모리 사이즈 및 매핑 정보를 출력하는 예제를 작성한다.
1. 프로세스 메모리 뷰어 예제 소스
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/seq_file.h>
#include <linux/sched/mm.h>
#include <linux/mm.h>
#include <linux/fs.h>
#include <linux/slab.h>
#ifndef find_task_by_pid
#define find_task_by_pid(nr) pid_task(find_vpid(nr), PIDTYPE_PID)
#endif
#define BUF_SIZE 1024
static int pid = 1;
module_param(pid, int, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);
static int is_stack(struct vm_area_struct *vma)
{
return vma->vm_start <= vma->vm_mm->start_stack &&
vma->vm_end >= vma->vm_mm->start_stack;
}
static void show_map(pid_t pid)
{
struct task_struct *task = NULL;
struct mm_struct *mm = NULL;
struct vm_area_struct *vma = NULL;
int flags = 0;
struct file *file = NULL;
dev_t dev = 0;
char *fullname;
char *buf = kmalloc(BUF_SIZE, GFP_KERNEL);
struct inode *inode;
int mm_count = 0;
if ((task = find_task_by_pid(pid)) == NULL) {
printk(KERN_ERR "find_task_by_pid error \n");
return;
}
if ((mm = get_task_mm(task)) == NULL) {
printk(KERN_ERR "get_task_mm error \n");
return;
}
down_read(&mm->mmap_sem);
vma = mm->mmap;
up_read(&mm->mmap_sem);
if (vma == NULL) {
printk(KERN_ERR "get vma error \n");
return;
}
printk("Address Mode Offset dev_t inode Mapping/Type\n");
down_read(&mm->mmap_sem);
for (mm_count = mm->map_count; mm_count > 0; mm_count--) {
file = vma->vm_file;
flags = vma->vm_flags;
// virtual address scope
printk(KERN_CONT "%08lx - %08lx ", vma->vm_start, vma->vm_end);
// virtual address privilege
printk(KERN_CONT "%c%c%c%c ",
flags & VM_READ ? 'r' : '-',
flags & VM_WRITE ? 'w' : '-',
flags & VM_EXEC ? 'x' : '-',
flags & VM_MAYSHARE ? 's' : 'p');
// virtual address offset
printk(KERN_CONT "%012lx ", vma->vm_pgoff << PAGE_SHIFT);
if (file) {
inode = file->f_inode;
dev = inode->i_sb->s_dev;
printk(KERN_CONT "%02x:%02x ", MAJOR(dev), MINOR(dev));
printk(KERN_CONT "%08lu ", inode->i_ino);
memset(buf, 0, BUF_SIZE);
fullname = d_path(&file->f_path, buf, BUF_SIZE);
printk(KERN_CONT "%s", fullname);
} else {
if (!vma->vm_mm) {
printk(KERN_CONT " [ vdso ]");
}
if (mm) {
if (vma->vm_start <= mm->brk && vma->vm_end >= mm->start_brk)
printk(KERN_CONT " [ heap ]");
else if (is_stack(vma))
printk(KERN_CONT " [ stack ]");
}
}
printk(KERN_CONT "\n");
vma = vma->vm_next;
}
up_read(&mm->mmap_sem);
kfree(buf);
}
#define PRINTK_DEC(str, val) \
printk(str, (val) << (PAGE_SHIFT - 10))
static int __init seq_init(void)
{
struct task_struct *task = NULL;
struct mm_struct *mm;
struct vm_area_struct *vm;
unsigned long text, lib, swap, anon, file, shmem;
unsigned long hiwater_vm, total_vm, hiwater_rss, total_rss;
if ((task = find_task_by_pid(pid)) == NULL) {
printk(KERN_ERR "find_task_by_pid error \n");
return -1;
}
printk("View Process [%s]\n", task->comm);
if ((mm = get_task_mm(task)) == NULL) {
printk(KERN_ERR "get_task_mm error \n");
return -1;
}
down_read(&mm->mmap_sem);
vm = mm->mmap;
anon = get_mm_counter(mm, MM_ANONPAGES);
file = get_mm_counter(mm, MM_FILEPAGES);
shmem = get_mm_counter(mm, MM_SHMEMPAGES);
hiwater_vm = total_vm = mm->total_vm;
if (hiwater_vm < mm->hiwater_vm)
hiwater_vm = mm->hiwater_vm;
hiwater_rss = total_rss = anon + file + shmem;
if (hiwater_rss < mm->hiwater_rss)
hiwater_rss = mm->hiwater_rss;
text = PAGE_ALIGN(mm->end_code) - (mm->start_code & PAGE_MASK);
text = min(text, mm->exec_vm << PAGE_SHIFT);
lib = (mm->exec_vm << PAGE_SHIFT) - text;
swap = get_mm_counter(mm, MM_SWAPENTS);
PRINTK_DEC("VmPeak : \t%8lu kB\n", hiwater_vm);
PRINTK_DEC("VmSize : \t%8lu kB\n", total_vm);
PRINTK_DEC("VmLock : \t%8lu kB\n", mm->locked_vm);
PRINTK_DEC("VmPin : \t%8llu kB\n", atomic64_read(&mm->pinned_vm));
PRINTK_DEC("VmHWM : \t%8lu kB\n", hiwater_rss);
PRINTK_DEC("VmRSS : \t%8lu kB\n", total_rss);
PRINTK_DEC("RssAnon: \t%8lu kB\n", anon);
PRINTK_DEC("RssFile: \t%8lu kB\n", file);
PRINTK_DEC("RssShm : \t%8lu kB\n", shmem);
PRINTK_DEC("VmData : \t%8lu kB\n", mm->data_vm);
PRINTK_DEC("VmStck : \t%8lu kB\n", mm->stack_vm);
printk("VmExec : \t%8lu kB\n", text >> 10);
printk("VmLib : \t%8lu kB\n", lib >> 10);
printk("VmPTE : \t%8lu kB\n", mm_pgtables_bytes(mm) >> 10);
PRINTK_DEC("VmSwap : \t%8lu kB\n", swap);
up_read(&mm->mmap_sem);
show_map(pid);
return 0;
}
static void __exit seq_exit(void)
{}
module_init(seq_init);
module_exit(seq_exit);
MODULE_LICENSE("GPL");
해당 예제는 /fs/proc/task_mmu.c 소스파일을 참고하여 작성한다.
find_task_by_pid 매크로는 pid 값으로 task_struct 구조체를 구하도록 정의하였다.
get_task_mm 함수로 task_struct에 설정되어 있는 mm_struct 구조체를 구한다.
mm_struct 내에 가상 메모리 정보를 가져오기 위하여 vm_area_struct 구조체를 구한다.
해당 구조체로부터 프로세스 각 영역에 대한 사이즈를 구하고 출력한다.
show_map 함수에선 vma 리스트에서 할당 영역, 모드, offset, dev_t, inode, 매핑 정보 등을 뽑아내 출력한다.
2. 실행 결과
정상적으로 procfs에서 제공한 결과와 같은 결과를 볼 수 있다.
'IT > Linux Kernel' 카테고리의 다른 글
[Linux Kernel] network (networking stack) (5) | 2021.07.14 |
---|---|
[Linux Kernel] spinlock (0) | 2020.07.10 |
[Linux Kernel 5] LRU (Memory Reclaim) (3) | 2020.05.17 |
[Linux Kernel 5] mmap (메모리 매핑) (2) | 2020.05.17 |
[Linux Kernel 5] Slab & Slub Allocator #2 (0) | 2020.05.17 |