请注意:>原作者:张澍> 原创作品转载请注明出处> 《Linux内核分析》MOOC课程http://mooc.study.163.com/course/USTC-1000029000
1.实验步骤
1.1 GDB代码中调试menu_os
Linux中编辑运行:
$ qemu -kernel linux-3.18.6/arch/x86/boot/bzImage -initrd rootfs.img -s -S #运行menu_os
$gdb #启动GDB
(gdb) file linux-3.18.6/vmlinux #加载内核
(gdb) target remote :1234 #链接到menu_os
(gdb) b start_kernel #在start_kernel处设置断点
(gdb) c #运行到断点:start_kernel处
(gdb) list #查看此处代码
(gdb) b sys_time #在start_kernel处设置断点
(gdb) c
(gdb) s #但步执行
(gdb) finish #执行完此函数“get_seconds()”
#注意:sys_time返回后进入汇编代码处理GDB无法继续跟踪
(gdb) b system_call
(gdb) c #此时menu_os界面显示time命令返回
运行显示
犹豫sys_time返回后进入汇编代码处理GDB无法继续跟踪,故接下来在Linux源码中直接查看
1.2 Linux源码中跟踪
#文件位置:linux-3.18.6/init/main.c
start_kernel() -> trap_init() ->
#文件位置:linux-3.18.6/arch/x86/kernel/traps.c
trap_init() ->
#ifdefCONFIG_X86_32
set_system_trap_gate(SYSCALL_VECTOR, &system_call);
set_bit(SYSCALL_VECTOR, used_vectors);
#endif
$0x80 -> system_call ->
#文件位置:linux-3.18.6/arch/x86/kernel/entry_32.S
ENTRY(system_call) #系统调用终端处理函数
SAVE_ALL //保存现场
syscall_call:
*sys_call_table(,%eax,4) #根据系统调用号调用相应的系统内核函数
syscall_exit:
testl $_TIF_ALLWORK_MASK, %ecx #检查当前的任务是否需要处理syscall_exit_work (如传入某信号)
jne syscall_exit_work
#如果不需要处理
restore_all:
TRACE_IRQS_IRET
irq_return:
INTERRUPT_RETURN #系统调用处理结束
#如果需要处理
syscall_exit_work:
testl $_TIF_WORK_SYSCALL_EXIT, %ecx
jz work_pending #跳转到 work_pending
END(syscall_exit_work)
work_pending:
testb $_TIF_NEED_RESCHED, %cl
jz work_notifysig #处理信号
work_resched:
call schedule #进程调度
jz restore_all
work_notifysig:
... #处理信号
END(work_pending) #返回系统调用
ENDPROC(system_call)
2.总结
系统调用处理过程:
- 用户态调用系统API,触发“int 0x80中断”
- 内核收到“int 0x80中断”后进入内核态
- 内核态中根据系统调用号调用相应的系统内核函数
- 进行相应的进程调度与信号处理
- 返回系统调用重新回到用户态