本文共 3172 字,大约阅读时间需要 10 分钟。
原创作品转载请注明出处 《Linux内核分析》MOOC课程
git clone https://github.com/mengning/menu.gitcd menumake rootfs
即可完成环境的配置。
1.2然后我们打开test.c文件加入上次实验写的系统调用函数 加入两个函数int newdir(int argc, char *argv[]){ if(mkdir("new dir", S_IRWXU) == 0) printf("new dir create success\n"); else printf("new dir create failed\n"); return 0; }int newdirAsm(int argc, char *argv[]){ char *dirName = "new dirAsm"; mode_t mode = S_IRWXU; int returnValue = 0; asm ( "movl $39, %%eax\r\n" "movl %1, %%ebx\r\n" "movl %2, %%ecx\r\n" "int $0x80\r\n" "movl %%eax, %0" :"=m"(returnValue) :"d"(dirName),"D"(mode) ); if(returnValue == 0) printf("new dirAsm create success\n"); else printf("new dirAsm create failed\n"); return 0;}
并且在main函数里面加入
MenuConfig("newdir","create a new directory",newdir);MenuConfig("newdir-asm","create a new directory(asm)",newdirAsm);
完成之后我们重新编译,make rootfs编译并且进入内核。
输入newdir和newdir-asm就会发现命令生效了 2. 跟踪中断处理的代码 我们使用gdb来调试跟踪一下MenuOS中mkdir的系统调用过程。 首先在终端输入qemu -kernel linux-3.18.6/arch/x86/boot/bzImage -initrd rootfs.img -s –S
并且在另一个终端打开gdb
输入gdbtui(gdb)file linux-3.18.6/vmlinux #加载符号表(gdb)target remote:1234 #建立gdb和gdbserver之间的连接(gdb)b sys_mkdir #在sys_mkdir建立断点(gdb)c
然后我们在qemu中输入newdir,会触发断点,然后我们进入gdb跟踪调试
断点停到SYSCALL_DEFINE2. 这个SYSCALL_DEFINE2在这里其实就是asmlinkage long sys_mkdir(const char __user *pathname, umode_t mode)
因为:我们打开源码中/linux-3.18.6/include/linux/syscalls.h文件,会看到一堆宏定义。
我们拿刚才那个定义为例:、#define SYSCALL_DEFINE2(name, ...) SYSCALL_DEFINEx(2, _##name, __VA_ARGS__)
这是把SYSCALL_DEFINE2定义为SYSCALL_DEFINEx然后把name与下划线连接(##表示前后两个参数当做串连接)
然后看下SYSCALL_DEFINEx的定义#define SYSCALL_DEFINEx(x, sname, ...) \ SYSCALL_METADATA(sname, x, __VA_ARGS__) \ __SYSCALL_DEFINEx(x, sname, __VA_ARGS__)
我们继续找到__SYSCALL_DEFINEx的定义。
#define __SYSCALL_DEFINEx(x, name, ...) \asmlinkage long sys##name(__MAP(x,__SC_DECL,__VA_ARGS__))…
剩余部分省略
__这里把SYSCALL_DEFINEx定义为asmlinkage long sys##name… 而name就是前面的_name,在这里也就是_mkdir。 所以SYSCALL2_DEFINE2定义为了asmlinkage long sys_mkdir,正式我们要找的系统调用。 弄清楚了之后,接下来我们继续跟踪。 我们在此处x/s pathname打印一下参数,看到参数正是我们要创建的文件夹名字 我们按s步入执行,发现进入了一个函数SYSCALL_DEFINE3,根据上面的理解,这里应该是sys_mkdirat系统调用 我们来看下这个函数里面的操作user_path_create security_path_mkdirvfs_mkdirdone_path_create
我们步入执行进入user_path_create
里面会调用kern_path_create 然后进入kern_path_create,里面还会调用do_path_lookup 然后我们返回到SYSCALL_DEFINE3中执行完毕,会跳入到schedule中 如果继续执行的话就会进入到不可调试的部分只能通过阅读代码来跟踪了。 上面的调用过程我们来用一个流程图来描述一下: 3. 分析系统调用过程的汇编代码 /linux-3.18.6/arch/x86/kernel/entry_32.S中ENTRY(system_call)与ENDPROC(system_call)之间的内容就是完成系统调用的汇编代码。 提取出主要的处理过程就是:ENTRY(system_call)SAVE_ALLsystem_call: call *sys_call_table(,%eax,4)#根据系统调用号来调用系统调用的处理函数…system_exit: testl $_TIF_ALLWORK_MASK, %ecx #判断当前任务是否需要处理syscall_exit_work jne syscall_exit_work #如果需要处理则跳转到syscall_exit_workrestore_all: RESTORE_INT_REGS #不需要处理的话进行RESTORE_ALLirq_return: INTERRUPT_RETURN #返回ENDPROC(system_call)
整个中断处理的过程我们可以用一个流程图画出来