當前位置:
首頁 > 知識 > Caffeinated 6.828:實驗工具指南

Caffeinated 6.828:實驗工具指南

Caffeinated 6.828:實驗工具指南

打開今日頭條,查看更多精彩圖片

編譯自: https://pdos.csail.mit.edu/6.828/2018/labguide.html

作者: Csail.mit

譯者: qhwdw

熟悉你的環境對高效率的開發和調試來說是至關重要的。本文將為你簡單概述一下 JOS 環境和非常有用的 GDB 和 QEMU 命令。話雖如此,但你仍然應該去閱讀 GDB 和 QEMU 手冊,來理解這些強大的工具如何使用。


調試小貼士

內核

GDB 是你的朋友。使用 qemu-gdb target(或它的變體 qemu-gdb-nox)使 QEMU 等待 GDB 去綁定。下面在調試內核時用到的一些命令,可以去查看 GDB 的資料。

如果你遭遇意外的中斷、異常、或三重故障,你可以使用 -d 參數要求 QEMU 去產生一個詳細的中斷日誌。

調試虛擬內存問題時,嘗試 QEMU 的監視命令 info mem(提供內存高級概述)或 info pg(提供更多細節內容)。注意,這些命令僅顯示當前頁表。

(在實驗 4 以後)去調試多個 CPU 時,使用 GDB 的線程相關命令,比如 thread 和 info threads。


用戶環境(在實驗 3 以後)

GDB 也可以去調試用戶環境,但是有些事情需要注意,因為 GDB 無法區分開多個用戶環境或區分開用戶環境與內核環境。

你可以使用 make run-name(或編輯 kern/init.c 目錄)來指定 JOS 啟動的用戶環境,為使 QEMU 等待 GDB 去綁定,使用 run-name-gdb 的變體。

你可以符號化調試用戶代碼,就像調試內核代碼一樣,但是你要告訴 GDB,哪個符號表用到符號文件命令上,因為它一次僅能夠使用一個符號表。提供的 .gdbinit 用於載入內核符號表 obj/kern/kernel。對於一個用戶環境,這個符號表在它的 ELF 二進位文件中,因此你可以使用 symbol-file obj/user/name 去載入它。不要從任何 .o 文件中載入符號,因為它們不會被鏈接器遷移進去(庫是靜態鏈接進 JOS 用戶二進位文件中的,因此這些符號已經包含在每個用戶二進位文件中了)。確保你得到了正確的用戶二進位文件;在不同的二進位文件中,庫函數被鏈接為不同的 EIP,而 GDB 並不知道更多的內容!

(在實驗 4 以後)因為 GDB 綁定了整個虛擬機,所以它可以將時鐘中斷看作為一種控制轉移。這使得從底層上不可能實現步進用戶代碼,因為一個時鐘中斷無形中保證了片刻之後虛擬機可以再次運行。因此可以使用 stepi 命令,因為它阻止了中斷,但它僅可以步進一個彙編指令。斷點一般來說可以正常工作,但要注意,因為你可能在不同的環境(完全不同的一個二進位文件)上遇到同一個 EIP。


參考

JOS makefile

JOS 的 GNUmakefile 包含了在各種方式中運行的 JOS 的許多假目標。所有這些目標都配置 QEMU 去監聽 GDB 連接(*-gdb 目標也等待這個連接)。要在運行中的 QEMU 上啟動它,只需要在你的實驗目錄中簡單地運行 gdb 即可。我們提供了一個 .gdbinit 文件,它可以在 QEMU 中自動指向到 GDB、載入內核符號文件、以及在 16 位和 32 位模式之間切換。退出 GDB 將關閉 QEMU。

  • make qemu
  • 在一個新窗口中構建所有的東西並使用 VGA 控制台和你的終端中的串列控制台啟動 QEMU。想退出時,既可以關閉 VGA 窗口,也可以在你的終端中按 Ctrl-c 或 Ctrl-a x。
  • make qemu-nox
  • 和 make qemu 一樣,但僅使用串列控制台來運行。想退出時,按下 Ctrl-a x。這種方式在通過 SSH 撥號連接到 Athena 上時非常有用,因為 VGA 窗口會佔用許多帶寬。
  • make qemu-gdb
  • 和 make qemu 一樣,但它與任意時間被動接受 GDB 不同,而是暫停第一個機器指令並等待一個 GDB 連接。
  • make qemu-nox-gdb
  • 它是 qemu-nox 和 qemu-gdb 目標的組合。
  • make run-nam
  • (在實驗 3 以後)運行用戶程序 name。例如,make run-hello 運行 user/hello.c。
  • make run-name-nox,run-name-gdb, run-name-gdb-nox
  • (在實驗 3 以後)與 qemu 目標變數對應的 run-name 的變體。

makefile 也接受幾個非常有用的變數:

  • make V=1 …
  • 詳細模式。輸出正在運行的每個命令,包括參數。
  • make V=1 grade
  • 在評級測試失敗後停止,並將 QEMU 的輸出放入 jos.out 文件中以備檢查。
  • make QEMUEXTRA=" _args_ " …
  • 指定傳遞給 QEMU 的額外參數。

JOS obj/

在構建 JOS 時,makefile 也產生一些額外的輸出文件,這些文件在調試時非常有用:

  • obj/boot/boot.asm、obj/kern/kernel.asm、obj/user/hello.asm、等等。
  • 引導載入器、內核、和用戶程序的彙編代碼列表。
  • obj/kern/kernel.sym、obj/user/hello.sym、等等。
  • 內核和用戶程序的符號表。
  • obj/boot/boot.out、obj/kern/kernel、obj/user/hello、等等。
  • 內核和用戶程序鏈接的 ELF 鏡像。它們包含了 GDB 用到的符號信息。

GDB

完整的 GDB 命令指南請查看 GDB 手冊 。下面是一些在 6.828 課程中非常有用的命令,它們中的一些在操作系統開發之外的領域幾乎用不到。

  • Ctrl-c
  • 在當前指令處停止機器並打斷進入到 GDB。如果 QEMU 有多個虛擬的 CPU,所有的 CPU 都會停止。
  • c(或 continue)
  • 繼續運行,直到下一個斷點或 Ctrl-c。
  • si(或 stepi)
  • 運行一個機器指令。
  • b function 或 b file:line(或 breakpoint)
  • 在給定的函數或行上設置一個斷點。
  • b * addr(或 breakpoint)
  • 在 EIP 的 addr 處設置一個斷點。
  • set print pretty
  • 啟用數組和結構的美化輸出。
  • info registers
  • 輸出通用寄存器 eip、eflags、和段選擇器。更多更全的機器寄存器狀態轉儲,查看 QEMU 自己的 info registers 命令。
  • x/ N x addr
  • 以十六進位顯示虛擬地址 addr 處開始的 N 個詞的轉儲。如果 N 省略,默認為 1。addr 可以是任何表達式。
  • x/ N i addr
  • 顯示從 addr 處開始的 N 個彙編指令。使用 $eip 作為 addr 將顯示當前指令指針寄存器中的指令。
  • symbol-file file
  • (在實驗 3 以後)切換到符號文件 file 上。當 GDB 綁定到 QEMU 後,它並不是虛擬機中進程邊界內的一部分,因此我們要去告訴它去使用哪個符號。默認情況下,我們配置 GDB 去使用內核符號文件 obj/kern/kernel。如果機器正在運行用戶代碼,比如是 hello.c,你就需要使用 symbol-file obj/user/hello 去切換到 hello 的符號文件。

QEMU 將每個虛擬 CPU 表示為 GDB 中的一個線程,因此你可以使用 GDB 中所有的線程相關的命令去查看或維護 QEMU 的虛擬 CPU。

  • thread n
  • GDB 在一個時刻只關注於一個線程(即:CPU)。這個命令將關注的線程切換到 n,n 是從 0 開始編號的。
  • info threads
  • 列出所有的線程(即:CPU),包括它們的狀態(活動還是停止)和它們在什麼函數中。

QEMU

QEMU 包含一個內置的監視器,它能夠有效地檢查和修改機器狀態。想進入到監視器中,在運行 QEMU 的終端中按入 Ctrl-a c 即可。再次按下 Ctrl-a c 將切換回串列控制台。

監視器命令的完整參考資料,請查看 QEMU 手冊 。下面是 6.828 課程中用到的一些有用的命令:

  • xp/ N x paddr
  • 顯示從物理地址 paddr 處開始的 N 個詞的十六進位轉儲。如果 N 省略,默認為 1。這是 GDB 的 x 命令模擬的物理內存。
  • info registers
  • 顯示機器內部寄存器狀態的一個完整轉儲。實踐中,對於段選擇器,這將包含機器的 隱藏 段狀態和局部、全局、和中斷描述符表加任務狀態寄存器。隱藏狀態是在載入段選擇器後,虛擬的 CPU 從 GDT/LDT 中讀取的信息。下面是實驗 1 中 JOS 內核處於運行中時的 CS 信息和每個欄位的含義:

CS =0008 10000000 ffffffff 10cf9a00 DPL=0 CS32 [-R-]

  • CS =0008
  • 代碼選擇器可見部分。我們使用段 0x8。這也告訴我們參考全局描述符表(0x8&4=0),並且我們的 CPL(當前許可權級別)是 0x8&3=0。
  • 10000000
  • 這是段基址。線性地址 = 邏輯地址 + 0x10000000。
  • ffffffff
  • 這是段限制。訪問線性地址 0xffffffff 以上將返回段違規異常。
  • 10cf9a00
  • 段的原始標誌,QEMU 將在接下來的幾個欄位中解碼這些對我們有用的標誌。
  • DPL=0
  • 段的許可權級別。一旦代碼以許可權 0 運行,它將就能夠載入這個段。
  • CS32
  • 這是一個 32 位代碼段。對於數據段(不要與 DS 寄存器混淆了),另外的值還包括 DS,而對於本地描述符表是 LDT。
  • [-R-]
  • 這個段是只讀的。
  • info mem
  • (在實驗 2 以後)顯示映射的虛擬內存和許可權。比如:

ef7c0000-ef800000 00040000 urw

efbf8000-efc00000 00008000 -rw

  • 這告訴我們從 0xef7c0000 到 0xef800000 的 0x00040000 位元組的內存被映射為讀取/寫入/用戶可訪問,而映射在 0xefbf8000 到 0xefc00000 之間的內存許可權是讀取/寫入,但是僅限於內核可訪問。
  • info pg
  • (在實驗 2 以後)顯示當前頁表結構。它的輸出類似於 info mem,但與頁目錄條目和頁表條目是有區別的,並且為每個條目給了單獨的許可權。重複的 PTE 和整個頁表被摺疊為一個單行。例如:

VPN range Entry Flags Physical page

[00000-003ff] PDE[000] -------UWP

[00200-00233] PTE[200-233] -------U-P 00380 0037e 0037d 0037c 0037b 0037a ..

[00800-00bff] PDE[002] ----A--UWP

[00800-00801] PTE[000-001] ----A--U-P 0034b 00349

[00802-00802] PTE[002] -------U-P 00348

  • 這裡各自顯示了兩個頁目錄條目、虛擬地址範圍 0x00000000 到 0x003fffff 以及 0x00800000 到 0x00bfffff。 所有的 PDE 都存在於內存中、可寫入、並且用戶可訪問,而第二個 PDE 也是可訪問的。這些頁表中的第二個映射了三個頁、虛擬地址範圍 0x00800000 到 0x00802fff,其中前兩個頁是存在於內存中的、可寫入、並且用戶可訪問的,而第三個僅存在於內存中,並且用戶可訪問。這些 PTE 的第一個條目映射在物理頁 0x34b 處。

QEMU 也有一些非常有用的命令行參數,使用 QEMUEXTRA 變數可以將參數傳遞給 JOS 的 makefile。

  • make QEMUEXTRA="-d int" ...
  • 記錄所有的中斷和一個完整的寄存器轉儲到 qemu.log 文件中。你可以忽略前兩個日誌條目、「SMM: enter」 和 「SMM: after RMS」,因為這些是在進入引導載入器之前生成的。在這之後的日誌條目看起來像下面這樣:

4: v=30 e=0000 i=1 cpl=3 IP=001b:00800e2e pc=00800e2e SP=0023:eebfdf28 EAX=00000005

EAX=00000005 EBX=00001002 ECX=00200000 EDX=00000000

ESI=00000805 EDI=00200000 EBP=eebfdf60 ESP=eebfdf28

...

  • 第一行描述了中斷。4: 只是一個日誌記錄計數器。v 提供了十六進程的向量號。e 提供了錯誤代碼。i=1 表示它是由一個 int 指令(相對一個硬體產生的中斷而言)產生的。剩下的行的意思很明顯。對於一個寄存器轉儲而言,接下來看到的就是寄存器信息。
  • 注意:如果你運行的是一個 0.15 版本之前的 QEMU,日誌將寫入到 /tmp 目錄,而不是當前目錄下。

via: https://pdos.csail.mit.edu/6.828/2018/labguide.html

作者: csail.mit 選題: lujun9972 譯者: qhwdw 校對: wxy

本文由 LCTT 原創編譯, Linux中國 榮譽推出


點擊「了解更多」可訪問文內鏈接

喜歡這篇文章嗎?立刻分享出去讓更多人知道吧!

本站內容充實豐富,博大精深,小編精選每日熱門資訊,隨時更新,點擊「搶先收到最新資訊」瀏覽吧!


請您繼續閱讀更多來自 Linux技術 的精彩文章:

如何使用 chkconfig 和 systemctl 命令啟用或禁用 Linux 服務
如何在 Ubuntu 上安裝 Cinnamon 桌面環境

TAG:Linux技術 |