lint對Linux而言並沒有很廣泛的用途,主要是因為大部份的人都能滿足於gcc所提供的警告訊息(warnings).可能最有用的就是-Wall
參數了---這個參數的用途是要求gcc將所有的警告訊息顯現出來.but probably has more mnemonic value if thought of as the thing you bang your head against.
網路上有一個實用的public domain lint,位於 ftp://larch.lcs.mit.edu/pub/Larch/lclint.我並不知道這個站到底有多好就是了.
你需要添加-g
的參數來編譯與連結程式,而且不可以用-fomit-frame-pointer
參數.事實上,你不需要重新編譯所有的程式,只需重新編譯目前你正在除錯的部份即可.
就a.out的格式(configurations)而言,共享程式庫(shared libraries)是以-fomit-frame-pointer
編譯而成,這個時候,gdb就變得英雄無用武之地了.連結時給定-g
的選項,應該就隱含著靜態連結(static linking)了;這就是為什麼要加-g的原因了.
如果連結器(linker)連結失敗,告訴你找不到libg.a,那就是在/usr/lib/
的目錄底下,少了libg.a
.libg.a是特殊的C語言偵錯程式庫(special debugging-enabled C library).一般在libc的套件內就會提供libg.a;不然的話(新版是這樣的),你可能需要拿libc的原始碼自己建立了.不過,實際上你應該不需要才對.不管是什麼目的,大部份的情況下,只需將libg.a連結到/usr/lib/libc.a
,你就能得到足夠的資訊了.
很多的GNU軟體在編譯連結時,都會設定-g
的選項,而這樣做會造成執行檔過大的問題(通常是靜態的).實際上,這並不是一個很熱門的想法.
如果程式本身有autoconf,產生了configure
命令稿,通常你就可以用./configure CFLAGS=
或是./configure CFLAGS=-O2
來關掉除錯資訊.不然的話,你得檢查檢查Makefile了.當然啦,假如你用的是ELF,程式便會以動態的方式連結(dynamically linked),不論是否有-g
的設定;因此你可以平常心把-g拿掉(strip)
.
據瞭解,一般人都使用gdb.你可以從GNU archive sites拿到原始程式;或者是到tsx-11拿可執行檔.xxgdb是一個X介面的除錯程式(debugger),植基於gdb(也就是說你得先安裝好gdb,才能再裝xxgdb).xxgdb的原始碼可以在ftp://ftp.x.org/contrib/xxgdb-1.08.tar.gz找到.
另外,UPS除錯程式已由Rick Sladkey移植成功.UPS可以在X底下活得很好,不像xxgdb那樣---僅僅是gdb的X前端介面(X front end).這支除錯程式有一大堆優良的特點,and if you spend any time debugging stuff, you probably should check it out.先前編譯(precompiled)好的Linux版與修正版(patches)的原始碼可以在ftp://sunsite.unc.edu/pub/Linux/devel/debuggers/找到.而最初的原始程式則放在 ftp://ftp.x.org/contrib/ups-2.45.2.tar.Z.
你可能會發現另一個用來除錯的工具strace,也是相當的有用.它可以顯示出由程序(process)所產生的系統呼叫,而且還擁有其它眾多繁複的功能(multiplicity),像是如果你手邊沒有原始碼的話,strace可以幫你找出(figure out)有那些路徑(path-names)已編譯進執行檔(binaries)內; exacerbating race conditions in programs that you suspect contain them;還有,strace可拿來學習程式是怎麼在電腦中執行的.最新的版本(目前是3.0.8)可在找到ftp://ftp.std.com/pub/jrs/.
早期典型的常駐程式(daemon programs)是執行fork()
,然後終止(terminate)父程序(parent).這樣的做法使得除錯的時間減短了.
瞭解(get around)這點的最簡單的方法就是替fork()
設一個breakpoint.當程式停止時,強迫fork()傳回0.
(gdb) list
1 #include <stdio.h>
2
3 main()
4 {
5 if(fork()==0) printf("child\n");
6 else printf("parent\n");
7 }
(gdb) break fork
Breakpoint 1 at 0x80003b8
(gdb) run
Starting program: /home/dan/src/hello/./fork
Breakpoint 1 at 0x400177c4
Breakpoint 1, 0x400177c4 in fork ()
(gdb) return 0
Make selected stack frame return now? (y or n) y
#0 0x80004a8 in main ()
at fork.c:5
5 if(fork()==0) printf("child\n");
(gdb) next
Single stepping until exit from function fork,
which has no line number information.
child
7 }
當Linux開機時,通常組態(configuration)會設定成不要產生核心檔案.要是你那麼喜歡它們的話,可以用shell的builtin命令使其重新生效:就C-shell相容的shell(如tcsh)而言,會是下面這樣:
% limit core unlimited
而類似Bourne shell的shell(sh,bash,zsh,pdksh)則使用下面的語法:
$ ulimit -c unlimited
如果你想要有個多才多藝(versatility)的核心檔命名(core file naming)(for
example, if you're trying to conduct a post-mortem using a debugger that's buggy itself) ,那麼你可以對你的核心程式(kernel)做一點小小的更動(mod).找一找fs/binfmt_aout.c
與fs/binfmt_elf.c
檔內與下列相符的程式片段(in newer kernels, you'll have to grep around a little in older ones):
memcpy(corefile,"core.",5);
#if 0
memcpy(corefile+5,current->comm,sizeof(current->comm));
#else
corefile[4] = '\0';
#endif
將0
換成1
.
Profiling是用來檢核一支程式中那些部份(which bits)是最常呼叫或是執行的時間最久的方法.這對程式的最佳化與找出何時時間是浪費掉的而言,是相當好的方式.你必須就你所要的時程資訊(timing information)的目的檔案(object files)加上-p
來編譯,而且如果要讓輸出的檔案(output files)有意義(make sense),你也會需要gprof
(來自binutils套件的命令).參閱gprof
的manual page,可得知其細節.
11/18/97譯