Debug相關的邊邊角角

大學四年,自誇努力上進,看了很多專業書,一到實習工做,立刻顯示出菜鳥的本性,連基本的程序調試都不會。大學時程序調試不是用printf輸出運行時變量內容,就是肉眼看代碼,小的算法Demo和功能代碼,這樣子調試就當是賣萌了;工做時一個服務器程序近萬個源代碼文件,客戶端崩潰只有dump文件和日誌信息反饋到服務器上,賣萌式的debug已經沒法知足需求了。這段時間抽空看了一些關於debug的文檔資料,加上工做半年來的一些實踐,在這裏小小的總結一下,大部份內容都是本身在閱讀文檔和實踐中的一些想法,拋磚引玉,一些錯誤和不足,歡迎你們指出。算法

l  程序的debug信息sass

對於編譯器來講(好比gcc),若是直接對程序進行編譯,不保留編譯時的信息,則編譯後的彙編代碼(固然最後是符合操做系統支持的格式的binary可執行文件)根本徹底不知道源代碼的任何信息,不知道彙編代碼與源代碼之間的關係,好比源代碼中的函數名稱、變量的類型和名稱等。好比在使用GDB進行程序調試的時候,step(單步調試)命令默認是不進入共享庫函數(.lib,.so,.a等文件)的,由於共享庫函數都是不帶調試信息的二進制代碼文件,固然共享庫文件通常來講也都是已經調試好了的沒有bug的文件。服務器

在Unix/Linux環境下,使用gcc的-g選項會將調試信息編碼輸出到編譯後的可執行目標代碼文件中,這些調試信息通常來講包括:函數

  1. 自定義的變量類型信息(struct、class等)
  2. 函數的名稱信息和入口地址(運行時虛擬內存地址)
  3. 全局變量的名稱的地址
  4. 參數,局部變量的名字及其在堆棧中的偏移量

上面這些信息是確定的,我認爲,應該還包括源代碼和編譯後的彙編代碼之間的對應關係,在如今的編譯技術下,彙編代碼和源代碼之間的一一對應關係徹底不可能從彙編代碼倒推出來了。工具

用一個簡單的31行的C語言Demo程序文件作試驗,使用一樣的編譯優化級別,不使用-g選項編譯出來的可執行目標代碼文件的大小是6.85KB,使用-g選項後編譯出的大小爲8.79KB,而源代碼文件的大小爲404Byte,可見在使用-g選項後在可執行目標代碼文件中調試信息所佔文件大小的比重。當將源文件從當前目錄下刪除後,在調試目標代碼文件時使用list指令,將出現No such file or directory的提示,可見在目標代碼文件中保存的是源文件的路徑信息。性能

在Windows環境中,調試信息並不被編碼到最後的可執行目標文件中,而是經過一個和最後生成的.exe同名的.pdb文件來保存。在使用windbg或者VS來調試Windows下的程序的時候,須要設置和加載相應的.pdb文件,不然給出的調試信息極可能就是錯誤的。相關的信息能夠查看:http://www.wintellect.com/blogs/jrobbins/pdb-files-what-every-developer-must-know(PDB Files: What Every Developer Must Know)。學習

 另外還有兩點須要說明一下:開發工具

  1. 如今的編譯器均可以設置代碼優化等級,編譯器會使用一些我這種菜鳥連作夢都想不到的高級的方式來優化代碼,在優化過程當中,編譯器會剔除不少局部變量,合併部分代碼,調整一些代碼的執行順序,甚至可能刪除代碼。在高優化等級下調試代碼的時候,不少程序中不少局部變量的值可能會看不到,一些斷點可能就徹底跟不到。因此,若是須要調試程序,仍是將代碼的優化等級調至最低比較穩當,在gcc和VS中均可以進行相應的設置。固然,在最後發佈程序時調至高等級的優化級別就能夠了。
  2. 在關於pdb文件介紹的上述博文中,提到了調試信息除了上面提到的4點以外,還包括了 Frame Pointer Omission 數據(FPO)。FPO的直譯就是」省略幀指引」,這個東西比較高端的樣子,查了一下資料,大概意思是:在通常函數調用的時候,會在程序的當前棧中保存調用者函數的棧幀指針(寄存器ebp的值),而後將當前棧指針esp保存到ebp中,而後再將棧指針esp減去必定值,用以分配函數的局部變量的內存地址,最後在函數退出的時候,會圍繞寄存在ebp中的值進行一系列的彈棧恢復到原調用者函數的執行環境。EPO的使用是去除了這一系列過程當中的保存棧幀指針ebp和恢復的過程,直接經過棧指針esp的操做來進行局部變量的地址分配和函數參數的傳遞,這樣就將寄存器ebp解放了出來,能夠用來保存常用的變量,減小了其保存和恢復的過程,提升了程序的性能。通常來講,EPO只有x86處理器支持。

l  一些Tips優化

  1. 遠程調試。VS和GDB都支持遠程調試,GDB尚未試過,VS支持使用TCP/IP和PIPE兩種方式來鏈接遠程的Windows虛擬機服務器,鏈接並Attach上在虛擬機上運行的服務器進程,這時你在本地使用VS打開的服務器代碼上進行打斷點,就和調試本地代碼同樣簡單和輕鬆。不得不說,VS真是一個偉大的開發工具。
  2. 在GDB中,有不少指令能夠用來查看代碼的彙編和堆棧信息。Info frame能夠查看當前棧幀信息,dissassemle <function name>指令能夠將內存中對應函數的彙編代碼dump出來,一遍的程序調試用不着看彙編代碼找bug這麼高端的東西,可是可使用這兩個指令結合《深刻理解計算機系統》(《Computer System A Programmer’s Perspective》)一書的第三章研究源代碼和彙編之間的關係。
  3. 學習GDB推薦網上的一個近30頁的文檔《Linux下GDB教程》,具體和指令相關的東西本身多用用就熟悉了,最經常使用的就是break(b,打斷點),Print(p,輸出變量),Continue(c,繼續執行),我本身也須要多用用。

 

整篇就是本身的讀書筆記和一些理解,有什麼錯誤,請你們指出。郵箱:wangjian_pg@sohu.com。編碼

相關文章
相關標籤/搜索