使用gdb跟踪系统调用内核函数sys_time
查看 linux-3.18.6/arch/x86/syscalls/syscall_32.tbl
13 i386 time sys_time compat_sys_time
可以得知,13号系统调用time对应的内核处理函数是sys_time
1. 设置断点 b sys_time
2. 设置断点 b system_call
可以看到,在system_call的地方,并没有停下,因为system_call不是一个正常的函数,它是一段汇编代码,怎么让系统停在system_call的位置进行调试?
查看 linux-3.18.6/arch/x86/kernel/entry_32.S
gdb应该可以发现system_call它声明了一个函数原型,但它实际上不是一个函数,而只是一段汇编代码的起点
系统调用的机制的初始化
\init\main.c
start_kernel
\arch\x86\kernel\traps.c
#ifdef
CONFIG_X86_32
set_system_trap_gate(SYSCALL_VECTOR, &system_call);
set_bit(SYSCALL_VECTOR, used_vectors);
#endif
系统调用的工作机制一旦在start_kernel()初始化好之后,在代码中一旦出现int 0x80的指令,它就会立即跳转到system_call这个位置
490ENTRY(system_call)
这个位置是执行完int 0x80这条指令的下一条指令
490ENTRY(system_call) # 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存放系统调用号,相当于调用sys_time 503syscall_after_call: 504 movl %eax,PT_EAX(%esp) # store the return value 保存返回值 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 513 jne syscall_exit_work # 一旦进入到syscall_exit_work里面,会有进程调度时机 514 515restore_all: 516 TRACE_IRQS_IRET 517restore_all_notrace: # 返回到用户态 518#ifdef CONFIG_X86_ESPFIX32 519 movl PT_EFLAGS(%esp), %eax # mix EFLAGS, SS and CS 520 # Warning: PT_OLDSS(%esp) contains the wrong/random values if we 521 # are returning to the kernel. 522 # See comments in process.c:copy_thread() for details. 523 movb PT_OLDSS(%esp), %ah 524 movb PT_CS(%esp), %al 525 andl $(X86_EFLAGS_VM | (SEGMENT_TI_MASK << 8) | SEGMENT_RPL_MASK), %eax 526 cmpl $((SEGMENT_LDT << 8) | USER_RPL), %eax 527 CFI_REMEMBER_STATE 528 je ldt_ss # returning to user-space with LDT SS 529#endif 530restore_nocheck: 531 RESTORE_REGS 4 # skip orig_eax/error_code 532irq_return: 533 INTERRUPT_RETURN # 这个地方就是iret,系统调用的处理过程到此结束
系统调用处理过程的汇编伪代码
当一个系统调用发生的时候,它进入内核处理系统调用,内核提供了一些服务,在这个服务结束返回到用户态之前,可能会发生进程调度,在进程调度里面,就会发生进程上下文的切换
可以把内核抽象成很多中不同的中断处理过程的集合
(完)