Preface:
基本上有兩種方法來 debug Nachos: external & internal. external debugger 透過外部載入 Nachos 的程式, 並使用 interactive 方法與使用者互動, 你可以一行行 debug 程式並檢查相關變數的設定, 常見的有 GDB. internal debugger 就是在你的程式加入 debug message, 透過這些訊息來判斷問題出在哪裡, 最常用也最沒有效率, 因為你無法一步步除錯, 且無法知道執行當下的變數(除非你把他們都印出來 orz)與執行環境.
Internal Debugging in Nachos:
在 Nachos 的原代碼中你會發現一些代碼使用 DEBUG 巨集來列印訊息, 範例如下:
- DEBUG(dbgSys, "Received Exception " << which << " type: " << type << "\n");
- const char dbgAll = '+'; // turn on all debug messages
- const char dbgThread = 't'; // threads
- const char dbgSynch = 's'; // locks, semaphores, condition vars
- const char dbgInt = 'i'; // interrupt emulation
- const char dbgMach = 'm'; // machine emulation
- const char dbgDisk = 'd'; // disk emulation
- const char dbgFile = 'f'; // file system
- const char dbgAddr = 'a'; // address spaces
- const char dbgNet = 'n'; // network emulation
- const char dbgSys = 'u'; // systemcall
- const char dbJohn = 'j'; // Debug by John
底下為 internal debugging 相關的內容:
- The Trace Facility
Each debugging message printed by the trace facility has a type. You can control which types of messages are actually printed using command line arguments to Nachos. The -d flag controls this. For example:
will print debugging messages related to threads ("t") and the disk ("d") emulation. If you do not use -d, the trace facility will be silent. Using -d + will cause trace messages of all types to be printed. Remember, however, that one of the nice features of this facility is that you can focus on only those messages that you are interested in. Having to wade through reams of irrelevant trace output is almost as bad as not having any trace output at all.
- Single Stepping
The single-step facility is enabled by the -s command-line argument. It causes the machine simulation to single-step through instruction execution. After each instruction is executed, the machine will print the values of all of its registers, as well as the current simulated time. It will also print a prompt. Your options are to execute one more instruction, to execute instructions until a specified time is reached, or to exit single-step mode and run without further interruption. Most of the time, you will find that you do not need this facility. However, those interested in the details of the machine emulation may wish to play with it.
- Assertions
The assertion facility allows you to state explicitly things that you believe will be true at a certain point in your program's execution. The assertion is tested and if it is found to be false, the program is terminated and a message is printed indicating which assertion failed. For example, the following piece of code can be found the Nachos main function:
- myId = kernel->procTable->GetNewProcId(-1);
- ASSERT(myId >= 0);
External Debugger:
在 external debugger 的部分, 接下來要介紹工具 GDB 並透過範例說明如何使用該工具進行 Nachos 的除錯.
- Using GDB with Nachos
執行 gdb -h 後你可以知道 gdb 更多的使用訊息, 而兩個下命令的語法如下:
上面的 executable-file 就是你要進行偵錯的程式, 這邊就是 nachos 執行檔. 執行上面另一命令後會進行 interactive mode. 首先執行命令如下:
接著假設你要在 Nachos 上執行 halt 的 user program, 且你想要知道執行後 register 上面的值, 你可以如下面給定命令:
透過 break 命令可以設定 Nachos 執行時設定斷點在某個特殊的行數或是函數, 更多的用法可以參考 這裡; 在這裡我們設定程式執行到 AddrSpace::InitRegisters (初始化 Registers) 時中斷. 接著run 命令告訴 gdb 開始跑 Nachos, 任何跟在 run 命令後面的參數都會被 pass 到要 debug 的程式.
在這邊當 Nachos 執行到 AddrSpace::InitRegisters 時會中斷, 並顯示訊息說明該中斷點在 ../userprog/addrspace.cc:215. 接著停在 Console 等待下一個命令的輸入. 這個時候你可以檢視目前程式使用變數的值與 call stack 的狀況; 除此之外你可以從當前中斷點一步步執行程式 (透過命令 step/next) 或是繼續執行程式 (透過命令 continue); 甚至你可以動態更改程式變數的值或檢視當前執行位置的代碼 (list).
接下來底下是執行的過程:
另外一個非常有用的命令是 bt: 它會秀出目前 call stack 的狀態, 這樣你可以知道之前你是執行那些函數後到目前執行點:
這樣的好處是當你的程式發生問題時 (segmentation fault), gdb 會停在 Console prompt mode, 此時你可以使用 bt 來 trace 到底程式時執行到那些函數時發生問題. 最後執行 continue 繼續執行:
上面由 "Inferior 1 (process 16569) exited normally" 知道 debug 的程式正常結束執行. 在 gdb Console prompt mode 可以執行命令 quit 離開並回到原先 shell 的 console. 最後任何你要用 gdb 進行 debug 的程式都必須使用參數 -g 編譯, 如此 gdb 才能夠正常執行, 在 Nachos 的 Makefile 預設已經使用該參數:
Supplement:
* GDB 入門 : 使用 GDB 來除錯
* Debugging with GDB - Seventh Edition, for GDB version 4.17
沒有留言:
張貼留言