linux模擬
Ⅰ 使用 Ptrace 去攔截和模擬 Linux 系統調用
ptrace(2) 系統調用在類 Unix 系統上是通過原生調試器監測被調試進程的主要機制,也是實現 strace(系統調用跟蹤)的常見方法。使用 Ptrace,跟蹤器可以暫停被跟蹤進程,檢查和設置寄存器和內存,監視系統調用,甚至可以攔截系統調用。
通過攔截功能,跟蹤器可以篡改系統調用參數,篡改系統調用的返回值,甚至阻塞某些系統調用。這意味著一個跟蹤器本身完全可以提供系統調用服務,這非常有趣,因為它意味著一個跟蹤器可以模擬一個完整的外部操作系統,而這些都是在沒有得到內核任何幫助的情況下由 Ptrace 實現的。
然而,同一時間只能有一個進程被一個跟蹤器附著,因此在那個進程的調試期間,不可能再使用諸如 GDB 這樣的工具去模擬一個外部操作系統。此外,模擬系統調用的開銷非常高。
本文將專注於 x86-64 Linux 的 Ptrace,並將使用一些 Linux 專用的擴展。同時,本文將忽略掉一些錯誤檢查,但完整的源代碼仍然會包含這些錯誤檢查。
以下是一個可直接運行的示例代碼示例:github.com/skeeto/ptrac...
strace 的基本實現回顧:它不是 DTrace,但 strace 仍然非常有用。Ptrace 一直沒有被標准化。它的介面在不同的操作系統上非常類似,尤其是在核心功能方面,但是在不同的系統之間仍然存在細微的差別。
最小化的 strace 不需要任何選項,因此需要做的第一件事情是假設它至少有一個參數,在 argv 尾部的 fork(2) 和 exec(2) 被跟蹤進程。但是在載入目標程序之前,新的進程將告知內核,目標程序將被它的父進程繼續跟蹤。被跟蹤進程將被這個 Ptrace 系統調用暫停。
父進程使用wait(2) 等待子進程的 PTRACE_TRACEME,當 wait(2) 返回後,子進程將被暫停。
在允許子進程繼續運行之前,我們告訴操作系統,被跟蹤進程和它的父進程應該一同被終止。一個真實的 strace 實現可能會設置其它的選擇,比如:PTRACE_O_TRACEFORK。
剩餘部分就是一個簡單的、無休止的循環了,每循環一次捕獲一個系統調用。循環體總共有四步:這個 PTRACE_SYSCALL 請求被用於等待下一個系統調用時開始,和等待那個系統調用退出。當 wait(2) 返回時,進行了系統調用的線程的寄存器中寫入了該系統調用的系統調用號及其參數。接下來是採集系統調用信息,這是各個系統架構不同的地方。接下來是它的另一個 PTRACE_SYSCALL 和 wait(2),然後是另一個 PTRACE_GETREGS 去獲取結果。結果保存在 rax 中。
系統調用攔截:假設我們想使用 Ptrace 去實現如 OpenBSD 的 pledge(2) 這樣的功能,它是一個進程承諾只使用一套受限的系統調用。初步想法是,許多程序一般都有一個初始化階段,這個階段它們都需要進行許多的系統訪問(比如,打開文件、綁定套接字、等等)。初始化完成以後,它們進行一個主循環,在主循環中它們處理輸入,並且僅使用所需的、很少的一套系統調用。
使用與 strace 相同的模型,但不是輸出所有的系統調用,我們既能夠阻塞某些系統調用,也可以在它的行為異常時簡單地終止被跟蹤進程。終止它很容易:只需要在跟蹤器中調用 exit(2)。因此,它也可以被設置為去終止被跟蹤進程。阻塞系統調用和允許子進程繼續運行都只是些雕蟲小技而已。
最棘手的部分是當系統調用啟動後沒有辦法去中斷它。當跟蹤器在入口從 wait(2) 中返回到系統調用時,從一開始停止一個系統調用的僅有方式是,終止被跟蹤進程。然而,我們不僅可以「搞亂」系統調用的參數,也可以改變系統調用號本身,將它修改為一個不存在的系統調用。返回時,在 errno 中通過正常的內部信號,我們就可以報告一個「友好的」錯誤信息。
跟蹤器與被跟蹤進程如何溝通?使用人為的系統調用!
創建一個人為的系統調用:對於我的這個類似於 pledge 的系統調用 —— 我可以通過調用 xpledge() 將它與真實的系統調用區分開 —— 我設置 10000 作為它的系統調用號,這是一個非常大的數字,真實的系統調用中從來不會用到它。
為演示需要,我同時構建了一個非常小的介面,這在實踐中並不是個好主意。它與 OpenBSD 的 pledge(2) 稍有一些相似之處,它使用了一個字元串介面。事實上,設計一個健壯且安全的許可權集是非常復雜的,正如在 pledge(2) 的手冊頁面上所顯示的那樣。
跟蹤器可以使用一個假冒的東西去代替系統調用號,允許它失敗,以及為系統調用本身提供服務。但那樣做的效率很低。其實質上是對每個系統調用做了三個上下文切換:一個是在入口上停止,一個是讓系統調用總是以失敗告終,還有一個是在系統調用退出時停止。
從 2005 年以後,對於這個技術,PTrace 的 Linux 版本有更高效的操作:PTRACE_SYSEMU。PTrace 僅在每個系統調用發出時停止一次,在允許被跟蹤進程繼續運行之前,由跟蹤器為系統調用提供服務。
使用 PTRACE_SYSEMU 跟蹤器、一個載入器(用於代替 exec(2)),和這個二進製程序所需要(或僅運行靜態的二進製程序)的任何系統庫,你就可以在任何具有(足夠)穩定的系統調用 ABI 的相同架構的機器上運行一個二進製程序,無需系統調用,這個二進製程序可以一直運行。
實際上,這聽起來有點像一個有趣的周末項目。參見 nullprogram.com/blog/20... 了解更多內容。
Ⅱ Linux下VCS2014和Verdi2015的聯合模擬
VCS和Verdi是IC設計中的常用工具,分別是Synopsys公司的VCS和Nocas公司(已被Synopsys收購)的Verdi。雖然兩者都需要在Linux環境中運行,對於習慣於Windows環境的用戶來說,這可能不太友好,但在大型項目開發時,Linux環境的便利性對於管理和團隊協作至關重要,同樣適用於FPGA開發。
有許多開源鏡像可用於在虛擬機上快速安裝IC開發所需的全套工具,簡化了安裝過程。然而,使用過程中可能會遇到各種問題,例如VCS和Verdi的聯合模擬。要實現VCS2014和Verdi2015的聯合模擬,需要生成可以從Verdi識別的.fsdb文件,這需要在Testbench中添加特定代碼,並執行Makefile中的「com」編譯命令。
在嘗試生成.fsdb文件的過程中,可能會遇到系統找不到Testbench中新增的系統函數的問題。解決此問題需要在Makefile中添加「-fsdb」選項,並確保在環境變數中正確設置了NOVAS_HOME路徑。有時,錯誤信息可能指示環境變數設置未生效,這是因為需要在設置環境變數後重新啟動虛擬機,否則設置將無效。
另一個常見的問題是版本兼容性問題,特別是在32位和64位版本之間。然而,經過多次嘗試後發現,使用「-full64」選項在64位模式下進行編譯,可以解決此類問題,生成可用於64位Verdi的.fsdb文件。這需要在Makefile中的「-fsdb」命令基礎上添加此選項。
成功生成.fsdb文件後,下一步是在Verdi中打開並進行聯合模擬。在聯合模擬過程中,可能出現與庫路徑相關的問題,但通過查閱資料並進行適當的調整,可以解決這類問題。在完成所有步驟後,若一切順利,即可在Verdi中打開.fsdb文件,實現VCS和Verdi的聯合模擬。
雖然這是一個相對較小的問題,但對新手來說可能會是一個挑戰。解決這類問題需要耐心、細心和向他人求教的態度。感謝那些幫助我解決此問題的熱心朋友,我將秉持同樣的熱情,幫助更多的人。