Linux Debugging FileSystem
해당 포스트에서는 커스텀 디버깅 파일시스템을 통하여 커널 디버깅하는 방법을 설명합니다.
- 리눅스 소스코드의 fs 디렉토리 아래 다음 소스코드 작성
/* km_debugfs.c */
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/platform_device.h>
#include <linux/io.h>
#include <linux/init.h>
#include <linux/memblock.h>
#include <linux/slab.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/cpu.h>
#include <linux/delay.h>
#include <asm/setup.h>
#include <linux/input.h>
#include <linux/debugfs.h>
#include <linux/timer.h>
#include <linux/workqueue.h>
#include <linux/mutex.h>
#include <linux/uaccess.h>
#include <linux/memory.h>
uint32_t km_debug_state = 0x1000;
static struct dentry *km_kernel_debugfs_root;
static int km_kernel_debug_stat_get(void *data, u64 *val)
{
printk("[%s][L:%d][val:%d]\n", __func__, __LINE__, km_debug_state);
*val = km_debug_state;
return 0;
}
static int km_kernel_debug_stat_set(void *data, u64 val)
{
km_debug_state = (uint32_t)val;
printk("[km] [%s][L:%d], [km_debug_state:%lu], [value:%lu]\n",
__func__, __LINE__, (long unsigned int)km_debug_state, (long unsigned int)val);
return 0;
}
DEFINE_SIMPLE_ATTRIBUTE(km_kernel_debug_stat_fops, km_kernel_debug_stat_get,
km_kernel_debug_stat_set, "%llu\n");
static int km_kernel_debugfs_driver_probe(struct platform_device *pdev)
{
printk("[%s][L:%d]\n", __func__, __LINE__);
return 0;
}
static struct platform_driver km_kernel_debugfs_driver = {
.probe = km_kernel_debugfs_driver_probe,
.driver = {
.owner = THIS_MODULE,
.name = "km_debug",
},
};
static int __init km_kernel_debugfs_init(void)
{
printk("[%s][L:%d]\n", __func__, __LINE__);
km_kernel_debugfs_root = debugfs_create_dir("km_debug", NULL);
debugfs_create_file("val", S_IRUGO, km_kernel_debugfs_root, NULL, &km_kernel_debug_stat_fops);
return platform_driver_register(&km_kernel_debugfs_driver);
}
late_initcall(km_kernel_debugfs_init);
MODULE_DESCRIPTION("debugfs driver");
MODULE_LICENSE("GPL");
- Makefile의 obj-y 수정
obj-y := open.o read_write.o file_table.o super.o \
char_dev.o stat.o exec.o pipe.o namei.o fcntl.o \
ioctl.o readdir.o select.o dcache.o inode.o \
attr.o bad_inode.o file.o filesystems.o namespace.o \
seq_file.o xattr.o libfs.o fs-writeback.o \
pnode.o splice.o sync.o utimes.o d_path.o \
stack.o fs_struct.o statfs.o fs_pin.o nsfs.o \
fs_types.o fs_context.o fs_parser.o fsopen.o init.o km_debugfs.o
# 위 소스파일 이름이 km_debugfs.c라서 km_debugfs.o를 추가
# my_debugfs.c라고 작성했다면 my_debugfs.o를 추가
- 원하는 소스 코드 수정
// 리눅스 커널 소스코드 중 net/ipv4/ip_input.c 파일의 528 라인(ip_rcv_core 함수 종료)에
// 다음과 같이 print_skb 함수와 km_debug_state 선언 추가
static void print_skb(struct sk_buff *skb)
{
int i = 0, j = 0;
printk("%7s", "offset ");
for (i = 0; i < 16; i++) {
printk(KERN_CONT "%02x ", i);
if (!(i % 16 - 7))
printk(KERN_CONT "- ");
}
printk(KERN_CONT "\n");
for (i = 0; i < skb->len; i++) {
if (!(i % 16))
printk(KERN_CONT "0x%04x ", i);
printk(KERN_CONT "%02x ", skb->data[i]);
if (!(i % 16 - 7))
printk(KERN_CONT "- ");
if (!(i % 16 - 15)) {
printk(KERN_CONT "\t");
for (j = i - 15; j <= i; j++) {
printk(KERN_CONT "%c", skb->data[j] >= 0x20 && skb->data[j] < 0x80 ? skb->data[j] : '.');
}
printk(KERN_CONT "\n");
}
}
printk("\n");
}
extern uint32_t km_debug_state;
/*
* IP receive entry point
*/
int ip_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt,
struct net_device *orig_dev)
{
struct net *net = dev_net(dev);
skb = ip_rcv_core(skb, net);
if (skb == NULL)
return NET_RX_DROP;
/***** 추가된 소스 코드 *****/
if (km_debug_state == 16)
print_skb(skb);
/***************************/
return NF_HOOK(NFPROTO_IPV4, NF_INET_PRE_ROUTING,
net, NULL, skb, dev, NULL,
ip_rcv_finish);
}
- 커널 재빌드 및 설치
/sys/kernel/debug
디렉토리 아래 새로 생성된 디렉토리 확인 위 소스코드 그대로면 km_debug 디렉토리 생성- 콘솔에서
dmesg -w
명령으로 커널 메시지 확인 echo 16 > /sys/kernel/debug/km_debug/val
명령으로 디버깅 루틴 시작- 네트워크 사용 시 다음과 같은 결과 확인