荔园在线

荔园之美,在春之萌芽,在夏之绽放,在秋之收获,在冬之沉淀

[回到开始] [上一篇][下一篇]


发信人: Ohoh (Linux), 信区: Linux
标  题: GCC HOWTO中译版V0.2 --- 5. 除错与监管
发信站: 荔园晨风BBS站 (Thu Nov 22 23:20:37 2001), 转信

5.1 预防重於治疗(lint)
lint对Linux而言并没有很广泛的用途,主要是因为大部份的人都能满足於gcc所提
供的警告讯息。可能最有用的就是-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。我并不知道这个站到底有多好就是了。


5.2 除错
我要怎样做才能将除错资讯放到一支程式里头?
你需要添加-g的参数来编译与连结程式,而且不可以用-fomit-frame-pointer参数
。事实上,你不需要重新编译所有的程式,只需重新编译目前你正在除错的部份即
可。


就a.out的组态而言,共享程式库是以-fomit-frame-pointer编译而成,这个时候
,gdb就变得英雄无用武之地了。连结时给定-g的选项,应该就隐含著静态连结的
意义了;这就是为什麽要加-g的原因了。


如果连结器连结失败,告诉你找不到libg.a,那就是在/usr/lib/的目录底下,少
了libg.a。libg.a是一个C语言很特别的侦错程式库。一般在libc的套件内就会提
供libg.a;不然的话(新版是这样的),你可能需要拿libc的原始码自己设置了,
不过,实际上你应该不需要才对。不管是什麽目的,大部份的情况下,只需将
libg.a连结到/usr/lib/libc.a,你就能得到足够的资讯了。


那,能不能把除错资讯给拿掉?
很多的GNU软体在编译连结时,都会设定-g的选项;这样做会造成执行档过大的问
题(通常是静态的连结)。实际上,这并不是一个很热门的想法。

如果程式本身有autoconf,产生了configure命令稿,通常你就可以用./configure
 CFLAGS=或是./configure CFLAGS=-O2来关掉除错资讯。不然的话,你得检查检查
Makefile了。当然啦,假如你用的是ELF,程式便会以动态的方式来连结,不论是
否有-g的设定;因此你可以平常心把-g拿掉。



实用的软体
据了解,大部份的人都是用gdb来除错。你可以从 GNU archive sites拿到原始程
式;或者是到 tsx-11拿可执行档。xxgdb是一个X介面的除错程式,植基於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)。这支除错程式有一大堆优
良的特点,而且如果你得花时间去除一支破烂的程式,建议你考虑考虑xxgdb。事
先编译好的Linux版与修正版的原始码可以在 ftp://sunsite.unc.
edu/pub/Linux/devel/debuggers/找到。而最初的原始程式则放在 ftp://ftp.x.
org/contrib/ups-2.45.2.tar.Z。

你可能会发现另一个用来除错的工具strace,也是相当的有用。它可以显示出由程
序所产生的系统呼叫,而且还拥有其它众多繁复的功能,像是如果你手边没有原始
码的话,strace可以帮你找出有那些路径名称(path-names)已编译进执行档内;
 exacerbating race conditions in programs that you suspect contain
them;还有,strace可拿来学习程式是怎麽在电脑中执行的。最新的版本(目前是
3.0.8)可在找到 ftp://ftp.std.com/pub/jrs/。



背景程式(常驻程式)
早期典型的常驻程式(daemon programs)是执行fork(),然後终止父程序。这样的
做法使得除错的时间减短了。


了解这点的最简单的方法就是替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开机时,通常组态会设定成不要产生核心档案。要是你那麽喜欢它们的话
,可以用shell的builtin命令使其重新生效:就C-shell相容的shell(如tcsh)而
言,会是下面这样:


% limit core unlimited

而类似Bourne shell的shell(sh, bash, zsh, pdksh)则使用下面的语法:

$ ulimit -c unlimited

如果你想要有个多才多艺的核心档命名(core file naming)(for example,
if you're trying to conduct a post-mortem using a debugger that's
buggy itself),那麽你可以对你的核心程式做一点小小的更动。找一找
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.


5.3 监管
监管(Profiling)是用来检核一支程式中那些部份是最常呼叫或是执行的时间最
久的方法。这对程式的最佳化与找出何时时间是浪费掉的而言,是相当好的方式。
你必须就你所要的时程资讯(timing information)的目的档加上-p来编译,而且
如果要让输出的档案有意义,你也会需要gprof(来自binutils套件的命令)。参
阅gprof的manual page,可得知其细节。


--
                ╔═══════════════════╗
                ║  欢迎来  深圳大学荔园晨风  Linux 版  ║
                ╚═══════════════════╝

※ 来源:·荔园晨风BBS站 bbs.szu.edu.cn·[FROM: 192.168.1.119]


[回到开始] [上一篇][下一篇]

荔园在线首页 友情链接:深圳大学 深大招生 荔园晨风BBS S-Term软件 网络书店