一.使用gdb跟踪分析一个系统调用内核函数
1.在test.c文件中添加time函数与采用c语言内嵌汇编的time函数.具体实现请看下图.
2.然后在main函数中添加MenuConfig函数,进行注册。这样当Menuos运行起来时,界面就会多出time与time-asm选项。
3.通过make rootfs命令运行
采用gdb调试的过程
- qemu -kernel linux-3.18.6/arch/x86/boot/bzImage -initrd rootfs.img -s -S
- gdb
- file linux-3.18.6/vmlinux
- target remote:1234
- b start_kernel
- b sys_time
gdb单步调试命令n,继续运行c,跳入函数内核s.
二.分析system_call代码的执行过程
当用户调用一个系统调用时,系统会自动通过int $0x80进入内核,同时通过中断向量进入system_call函数.然后开始执行system_call过程。
490ENTRY(system_call) 491 RING0_INT_FRAME # can‘t unwind into user space anyway 492 ASM_CLAC 493 pushl_cfi %eax # save orig_eax 494 SAVE_ALL #保存寄存器上下文环境 495 GET_THREAD_INFO(%ebp) 496 # system call tracing in operation / emulation 497 testl $_TIF_WORK_SYSCALL_ENTRY,TI_flags(%ebp) 498 jnz syscall_trace_entry 499 cmpl $(NR_syscalls), %eax 500 jae syscall_badsys 501syscall_call: 502 call *sys_call_table(,%eax,4) #通过eax寄存器存储的具体系统调用号来去system_call表中去执行具体的系统调用 503syscall_after_call: 504 movl %eax,PT_EAX(%esp) #系统调用执行完之后用eax保存返回值 505syscall_exit: 506 LOCKDEP_SYS_EXIT 507 DISABLE_INTERRUPTS(CLBR_ANY) # make sure we don‘t miss an interrupt 508 # setting need_resched or sigpending 509 # between sampling and the iret 510 TRACE_IRQS_OFF 511 movl TI_flags(%ebp), %ecx 512 testl $_TIF_ALLWORK_MASK, %ecx # current->work,判断当前是否需要继续执行syscall_exit_word过程 513 jne syscall_exit_work #若需要,则进入syscall_exit_work过程 514 515restore_all: 516 TRACE_IRQS_IRET #恢复上下文环境
这段代码的总体流程就是:
- 保存当前进程环境(SAVE_ALL)
- 执行具体的系统调用,并保存返回值
- 判断当前是否还需要执行其他的任务(即syscall_exit_work).
- 恢复上下文环境。
接下来具体看看syscall_exit_work执行了哪些具体任务
656syscall_exit_work: 657 testl $_TIF_WORK_SYSCALL_EXIT, %ecx 658 jz work_pending #进入work_pending 659 TRACE_IRQS_ON 660 ENABLE_INTERRUPTS(CLBR_ANY) # could let syscall_trace_leave() call 661 # schedule() instead 662 movl %esp, %eax 663 call syscall_trace_leave 664 jmp resume_userspace 665END(syscall_exit_work)
work_pending的主要工作是判断当前进程是否有信号或者进程通信的任务来处理。
593work_pending: 594 testb $_TIF_NEED_RESCHED, %cl 595 jz work_notifysig #如果有信号处理,则进入work_notifysig过程 596work_resched: 597 call schedule #是否需要进行进程调度,如果有进程调度的任务,则进入 598 LOCKDEP_SYS_EXIT 599 DISABLE_INTERRUPTS(CLBR_ANY) # make sure we don‘t miss an interrupt 600 # setting need_resched or sigpending 601 # between sampling and the iret 602 TRACE_IRQS_OFF 603 movl TI_flags(%ebp), %ecx 604 andl $_TIF_WORK_MASK, %ecx # is there any work to be done other 605 # than syscall tracing? 606 jz restore_all #返回进行上下文 607 testb $_TIF_NEED_RESCHED, %cl 608 jnz work_resched 609
因此在进程执行完某个系统调用的过程后,在返回值之前,会检查是否进程有信号需要处理和是否有进程调度的任务需要执行。
三.实验总结
更加进一步地深入学习了在用户调用一个系统调用时,内核底层的执行过程。
时间: 2024-10-07 08:55:53