一. 跟蹤time系統調用
使用gdb調試跟蹤系統調用內核函數sys_time
過程如下:

- 對sys_time設置斷點之后,在menuOS中執行time命令,發現系統停在systime處,輸入S單步執行,知道函數return i;
- sys_time返回之后進入匯編代碼處理,gdb無法繼續跟蹤。
- 如果在syscall設置斷點(entry32.S),然后輸入c之后,發現是不會在sys_call處停下來的(因為這里是一處系統調用函數而不是正常函數)。
二. 系統調用在內核代碼中的處理過程
1.系統調用在內核代碼中的工作機制和初始化
整個系統調用過程中,時間很重要。
以system_call為例,int 0x80指令與sys_call是通過中斷向量聯系起來的,而API和對應的sys是通過系統調用號聯系起來的

用戶態時,系統調用xyz()使用int 0x80,它對應調用system_call
右邊的處理過程(匯編代碼)非常重要,通過系統調用號匹配起來
2.系統調用機制的初始化
trap_init函數里面有一個set_system_trap_gate函數,其中涉及到了系統調用的中斷向量SYSCALL_VECTOR和匯編代碼入口system_call,一旦執行int 0x80,CPU直接跳轉到system_call來執行。

3.簡化后便於理解的system_call偽代碼
- systemcall的位置就在ENTRY(systemcall)處,其他中斷的處理過程與此類似。

-
SAVE_ALL:保存現場
- call *sys_call_table(,%eax,4)調用了系統調度處理函數,eax存的是系統調用號,是實際的系統調度程序。
- sys_call_table:系統調用分派表
-
syscall_after_all:保存返回值
- 若有sys_exit_work,則進入sys_exit_work:會有一個進程調度時機。
- work_pending -> work_notifysig,用來處理信號
- 可能call schedule:進程調度代碼
- 可能跳轉到restore_all,恢復現場。
- work_pending -> work_notifysig,用來處理信號
-
若無sys_exit_work,就執行restore_all恢復,返回用戶態。
-
INTERRUPT_RETURN <=> iret,結束。
偽代碼簡化了下

SAVE_ALL與sys_call_table系統調用分派表,對應的處理函數分別是:
sys_call_table(,%eax,4)
JMP(EAX*4 + system_xxx)
1.在系統調用返回之前,可能發生進程調度,進程調度里就會出現進程上下文的切換 2.進程間通信可能有信號需要處理
4.簡單瀏覽system_call到iret之間的主要代碼
- SAVE_ALL:保存現場
- syscall_call:調用了系統調用處理函數
- restore all:恢復現場(因為系統調用處理函數也算是一種特殊的“中斷”)
- syscallexitwork:如3.中所述
- INTERRUPT RETURN:也就是iret,系統調用到此結束
三.system_call到iret過程流程圖
等會看下視頻補張圖
三、總結
(一)從系統調用處理過程到一般的中斷處理過程
1. 保存現場
- 在系統調用時,用SAVE_ALL來保存系統調用時的上下文。
- 中斷處理的第一步也是要保存中斷程序現場。
- 中斷處理完之后,可以返回到原來被中斷的地方,在原有的運行環境下繼續正確的執行下去。
2. 確定中斷信息
- 在系統調用中,需要將系統調用號通過eax傳入,通過
sys_call_table查詢到調用的系統調用,然后跳轉到相應的程序進行處理。 - 中斷處理時系統也需要有一個中斷號,通過檢索中斷向量表,了解中斷的類型和設備。
3. 處理中斷
- 跳轉到相應的中斷處理程序后,對中斷進行處理。
4. 返回
- 系統調用時最后要restore_all恢復系統調用時的現場,並用iret返回用戶態。
- 同樣,執行完中斷處理程序,內核也要執行特定指令序列,恢復中斷時現場,並使得進程回到用戶態。
(二)給menuOS增加命令的方法:
- 強制刪除menu (rm menu -rf)
- 更新menu代碼至最新版本(git clone https://github.com/mengning/menu.git)
- 在test.c中main函數中增加MenuConfig,以及增加上周自己選擇Getegid,GetegidAsm的代碼
- Make roofts自動編譯,生成,和啟動根文件系統
(三)使用gdb跟蹤調試內核的方法:
qemu -kernel linux-3.18.6/arch/x86/boot/bzImage -initrd rootfs.img -s -S
gdb
(gdb)file linux-3.18.6/vmlinux # 在gdb界面中targe remote之前加載符號表
(gdb)target remote:1234 # 建立gdb和gdbserver之間的連接,按c 讓qemu上的Linux繼續運行
(gdb)break start_kernel # 斷點的設置,注意尋找對應的系統調用函數名字,例如time命令對應sys_time
