linux系统调用追踪及调试

目录

一 自定义创建syscall debug系统调用

1 添加系统调用号

2 申明一个系统调用

3 实现系统调用

4 内核使用核系统调用

5 内核和用户使用

二 使用strace工具


本文介绍调试系统调用的两种方法

一 自定义创建syscall debug系统调用

自定义的debug系统调用需要自己申请一个系统调用接口,用一个flag的标志来控制打印。

平台aarch64

1 添加系统调用号

diff --git a/include/uapi/asm-generic/unistd.h b/include/uapi/asm-generic/unistd.h
index d901272..ea4d459 100644
--- a/include/uapi/asm-generic/unistd.h
+++ b/include/uapi/asm-generic/unistd.h
@@ -740,9 +740,13 @@ __SC_COMP(__NR_io_pgetevents, sys_io_pgetevents, compat_sys_io_pgetevents)
 __SYSCALL(__NR_rseq, sys_rseq)
 #define __NR_kexec_file_load 294
 __SYSCALL(__NR_kexec_file_load,     sys_kexec_file_load)
+#define __NR_debug_syscall 295
+__SYSCALL(__NR_debug_syscall, sys_debug_syscall)
+
 
 #undef __NR_syscalls
-#define __NR_syscalls 295
+/* #define __NR_syscalls 296 */
+#define __NR_syscalls 300

该实验是在linux5.0中进行的,平台ARM64,默认只有295个系统调用。当添加一个系统调用需要人为修改系统调用个数。

x86的修改

diff --git a/arch/x86/entry/syscalls/syscall_64.tbl b/arch/x86/entry/syscalls/syscall_64.tbl
index 18b5500ea8bf..f142ffc74dec 100644
--- a/arch/x86/entry/syscalls/syscall_64.tbl
+++ b/arch/x86/entry/syscalls/syscall_64.tbl
@@ -370,7 +370,7 @@
 446    common  landlock_restrict_self  sys_landlock_restrict_self
 447    common  memfd_secret            sys_memfd_secret
 448    common  process_mrelease        sys_process_mrelease
-
+449 common  debug_syscall              sys_debug_syscall
 #
 # Due to a historical design error, certain syscalls are numbered differently
 # in x32 as compared to native x86_64.  These syscalls have numbers 512-547.

2 申明一个系统调用

diff --git a/include/linux/syscalls.h b/include/linux/syscalls.h
index 257cccb..d0954ed 100644
--- a/include/linux/syscalls.h
+++ b/include/linux/syscalls.h
@@ -1315,4 +1315,6 @@ static inline unsigned int ksys_personality(unsigned int personality)
 	return old;
 }
 
+asmlinkage long sys_debug_syscall(int enable);
+
 #endif

3 实现系统调用

diff --git a/kernel/sys.c b/kernel/sys.c
index f7eb62e..f5c39bb 100644
--- a/kernel/sys.c
+++ b/kernel/sys.c
@@ -2583,6 +2583,20 @@ SYSCALL_DEFINE1(sysinfo, struct sysinfo __user *, info)
 	return 0;
 }
 
+int syscall_debug_enable;
+EXPORT_SYMBOL(syscall_debug_enable);
+
+SYSCALL_DEFINE1(debug_syscall, int, enable)
+{
+	if (enable)
+		syscall_debug_enable = 1;
+	else
+		syscall_debug_enable = 0;
+
+	return 0;
+}
+
+
 #ifdef CONFIG_COMPAT
 struct compat_sysinfo {
 	s32 uptime;

创建的系统调用函数为debug_syscall,作用是控制一个全局变量。其中的参数enable来自用户层。

4 内核使用核系统调用

diff --git a/include/linux/kernel.h b/include/linux/kernel.h
index 8f0e68e..c4f1a58 100644
--- a/include/linux/kernel.h
+++ b/include/linux/kernel.h
@@ -1033,4 +1033,25 @@ static inline void ftrace_dump(enum ftrace_dump_mode oops_dump_mode) { }
 	 /* OTHER_WRITABLE?  Generally considered a bad idea. */		\
 	 BUILD_BUG_ON_ZERO((perms) & 2) +					\
 	 (perms))
+
+#define syscall_debug(...)				\
+({										\
+	 extern int syscall_debug_enable;	\
+	 if (syscall_debug_enable)			\
+		pr_notice(__VA_ARGS__);			\
+})
+
+#define syscall_debug_enable()			\
+({										\
+	 extern int syscall_debug_enable;	\
+	 syscall_debug_enable = 1			\
+})
+
+#define syscall_debug_disable()			\
+({										\
+	 extern int syscall_debug_enable;	\
+	 syscall_debug_enable = 0			\
+})
+
+
 #endif

上述实现的系统调用,我们在内核中用来做打印开关使用,见 syscall_debug 实现,可以像prink一样使用这个接口

5 内核和用户使用

介绍内核和用户两种使用方法

内核里使用:要打印的地方使用syscall_debug_enable函数,然后任性打印,完事后使用syscall_debug_disable函数

应用层使用:

明确系统调用号

#define __NR_debug_syscall 295

使用接口syscall

       #include <unistd.h>
       #include <sys/syscall.h>   /* For SYS_xxx definitions */

       long syscall(long number, ...);

比如开启打印

syscall(__NR_debug_syscall, 1);

关闭打印

syscall(__NR_debug_syscall, 0);

注意内核里直接使用syscall_debug代替printk

手动添加的方法可以追踪目标系统调用。往往一个函数陷入内核会触发多个系统调用,添加上述调试代码可以避免这个问题。

二 使用strace工具

平台aarch64

下载源码GitHub - strace/strace: strace is a diagnostic, debugging and instructional userspace utility for Linux

解压进入目录

执行

./bootstrap

sudo ./configure --prefix=/xxx/strace/output-aarch64/ --host=aarch64-linux CC=/xxx/bin/aarch64-linux-gnu-gcc LD=/xxx/bin/aarch64-linux-gnu-ld --enable-mpers=no

sudo make LDFLAGS+='-static -pthread'    静态编译,如果不需要静态编译直接make

make install

生成如下tree output-aarch64/
output-aarch64/
├── bin
│   ├── strace
│   ├── strace-graph
│   └── strace-log-merge
└── share
    └── man
        └── man1
            ├── strace.1
            └── strace-log-merge.1

4 directories, 5 files

将strace工具放根文件系统就可以使用了

来追一下

 ./strace /mnt/my_fork
execve("/mnt/my_fork", ["/mnt/my_fork"], 0x7fff6c5680 /* 8 vars */) = 0
brk(NULL)                               = 0x28151000
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) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/lib/tls/aarch64/libc.so.6", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
newfstatat(AT_FDCWD, "/lib/tls/aarch64", 0x7febd1b840, 0) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/lib/tls/libc.so.6", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
newfstatat(AT_FDCWD, "/lib/tls", 0x7febd1b840, 0) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/lib/aarch64/libc.so.6", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
newfstatat(AT_FDCWD, "/lib/aarch64", 0x7febd1b840, 0) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/lib/libc.so.6", 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\0h\370\1\0\0\0\0\0"..., 832) = 832
fstat(3, {st_mode=S_IFREG|0755, st_size=15355504, ...}) = 0
mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f923e7000
mmap(NULL, 1360488, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7f92273000
mprotect(0x7f923a6000, 65536, PROT_NONE) = 0
mmap(0x7f923b6000, 24576, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x133000) = 0x7f923b6000
mmap(0x7f923bc000, 12904, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x7f923bc000
close(3)                                = 0
mprotect(0x7f923b6000, 16384, PROT_READ) = 0
mprotect(0x410000, 4096, PROT_READ)     = 0
mprotect(0x7f923eb000, 4096, PROT_READ) = 0
clone(child_stack=NULL, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD, child_tidptr=0x7f923e7c20) = 1254
fstat(1, {st_mode=S_IFCHR|0600, st_rdev=makedev(0x5, 0x1), ...}) = 0
=====child=====
ioctl(1, TCGETS, {B38400 opost isig icanon echo ...}) = 0
--- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_EXITED, si_pid=1254, si_uid=0, si_status=0, si_utime=0, si_stime=0} ---
brk(NULL)                               = 0x28151000
brk(0x28173000)                         = 0x28173000
write(1, "=====parent=====\n", 17=====parent=====
)      = 17
nanosleep({tv_sec=1, tv_nsec=0}, 0x7febd1c680) = 0
exit_group(0)                           = ?
+++ exited with 0 +++

=========================================================================

编译方法也可以使用参考的方法

vi build_static_example.sh

修改BUILDFLAG="--prefix=/xxx/strace/output-aarch64/ --host=aarch64-linux CC=/xxx/bin/aarch64-linux-gnu-gcc LD=/xxx/bin/aarch64-linux-gnu-ld --enable-mpers=no"

修改CC=“/xxx/bin/aarch64-linux-gnu-gcc”

在CFLAGS中添加 -pthread

sudo执行脚本

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值