2019-2020-1 20209329《Linux内核原理与分析》第六周作业
作业信息
这个作业属于哪个课程 | <2020-2021-1Linux内核原理与分析)> |
---|---|
这个作业要求在哪里 | <2020-2021-1Linux内核原理与分析第六周作业> |
这个作业的目标 | <使用gdb跟踪分析一个系统调用内核函数> |
作业正文 | https://i.cnblogs.com/posts/edit;postId=13972028 本博客链接 |
《Linux内核原理与分析》第六周作业
一、给MenuOS增加命令
(1)先用rm -rf menu强制删除当前menu目录,然后用git clone重新克隆一个新的menu。
(2)在test.c中加入getpid(),再次使用make rootfs,使用新写入的GPid查看返回的pid值
二.使用gdb跟踪系统调用内核函数sys_time
(1)返回的LinuxKernel目录下,调试内核
qemu -kernel linux-3.18.6/arch/x86/boot/bzImage/ -initrd rootfs.img -S -s
(2)水平新建一个shell使用gdb调试
在新的shell中进入gdb,并输入一下代码开始调试
file linux-3.18.6/vmlinux
target remote:1234
b sys_time
(3)跟踪系统调用内核的函数sys_time
输入c继续运行menu,并在menu系统中执行time命令
断点停在了SYSCALL_DEFINE1,这是个宏定义,对应着sys_time函数。
继续调试,执行到get_seconds函数,用finish跳过。接着一步步调试
当执行到return i之后,出现无法调试的情况,这是因为这时返回到system_call为主的汇编代码,gdb不支持这部分调试功能。输入c继续执行
menu中的命令执行完毕。
(3)sys_call处理过程
ENTRY(system_call)
RINGO_INT_FRAME
ASM_CLAC
push1_cfi %eax /*保存系统调用号*/
SAVE_ALL /*保存现场,将用到的所有CPU寄存器保存到栈中*/
GET_THREAD_INFO(%ebp) /*ebp用于存放当前进程thread_info结构的地址*/
test1 $_TIF_WORK_SYSCALL_ENTRY,TI_flags(%ebp)
jnz syscall_trace_entry
cmp1 $(nr_syscalls),%eax /*检查系统调用号(系统调用号应小于NR_syscalls)*/
jae syscall_badsys /*不合法,跳入异常处理*/
syscall_call:
call *sys_call_table(,%eax,4) /*合法,对照系统调用号在系统调用表中寻找相应的系统调用的内核处理函数*/
movl %eax,PT_EAX(%esp)/*保存返回值到栈中*/
syscall_exit:
testl $_TIF_ALLWORK_MASK, %ecx/*检查是否需要处理信号*/
jne syscall_exit_work /*需要,进入 syscall_exit_work*/
restore_all:
TRACE_IRQS_IRET /*不需要,执行restore_all恢复,返回用户态*/
irq_return:
INTERRUPT_RETURN /*相当于iret*/
(4)流程图
总结
从系统调用处理过程的入口开始,可以看到SAVE_ALL保存现场,然后找到system_call和sys_call_table。call *sys_call_table(,%eax,4)就是调用了系统调用的内核处理函数,之后restore_all和最后一个INTERRUPT_RETURN(iret)用于恢复现场并返回系统调用到用户态结束,在这个过程中,如果有其他任务需要处理,就需要执行syscall_exit_work,最后再跳转到return_all,接着执行iret。