函数库文件中的符号表-nm命令

来源:互联网 发布:php环境 编辑:程序博客网 时间:2024/05/16 04:54

nm命令可以列出一个函数库文件中的符号表。它对于静态的函数库和共享的函数库都起作用。对于一个给定的函数库,nm命令可以列出函数库中定义的所有符号,包括每个符号的值和类型。还可以给出在原程序中这个函数(符号)是在多少行定义的,不过这必须要求编译该函数库的时候加“-l”选项。

关于符号的类型,这里我们再多讨论一下。符号的类型是以一个字母的形式显示的,小写字母表示这个符号是本地(local)的,而大写字母则表示这个符号是全局的(global,externel)。一般来说,类型有一下几种:T、D、B、U、W。各自的含义如下:T表示在代码段中定义的一般变量符号;D表示时初始化过的数据段;B表示初始化的数据段;U表示没有定义的,在这个库里面使用了,但是在其他库中定义的符号;W,weak的缩写,表示如果其他函数库中也有对这个符号的定义,则其他符号的定义可以覆盖这个定义。


如果你知道一个函数的名字,但是你不知道这个函数在什么库中定义的,那么可以用mn的“-o”选项和grep命令来查找库的名字。-o选项使得显示的每一行都有这个函数库文件名。例如,你要查找“cos”这个是在什么地方定义的,大致可以用下面的命令:

nm  libUserDecorate.so -A -l 2> /dev/null |grep init_cnf
libUserDecorate.so:0002e476 T _ZN3ZBP18UserDecorateServer8init_cnfEPKc  /data/home/macky/svn/isd_qqvipserver_rep/Decorate_proj/trunk/operate_server/src/main/user_decorate_server.cpp:76

 

关于nm的更详细的用法:man nm

 

转同事steven的一篇故障定位文章:

上线通知存在两个问题:

1, 共享内存泄漏

2, 共享内存attach后没有dettach。上线通知对共享内存的使用比较特殊,会在各个函数中调用attach以使用共享内存。这样,在每次使用后没有dettach的后果是:shm的nattach数量不断递增,到一定程度导致程序core。这个问题查了好久也没有查出原因,之前在析构函数中加printf,发现根本没有调用析构函数。在打算修改共享内存的使用方法时(共享内存只在启动时attach,避免在功能函数中attach),still大师帮忙找出问题的关键所在。

 

下面分别谈谈这两个问题的分析与定位。

1, 共享内存泄漏定位

Ø 在出问题的机器上查看共享内存使用情况,用ipcs m查看结果存在大量如下共享内存段:

------ Shared Memory Segments --------

key        shmid      owner      perms      bytes      nattch     status  

0x00000000 1835059    user_00     600        204800     0                       

0x00000000 1867828    user_00     600        20         0

Shm的key为0,大小固定。

Ø 在开发机上启动程序时统计大小为204800的共享内存块的个数。ipcs -m|grep 204800|wc –l,发现每启动一次,个数增加1.

Ø 查看上线通知进程id

Ø 查看各个进程的共享内存使用情况:

为便于显示,省略时间戳信息。

1) Cache_main进程:

2) Notify_worker进程id为11639)

主角出现,该worker使用了大小为204800的shm块,并且key为0.

3) Weihu_worker(进程id为11637)

发现只用到了一个16M的shm,为worker与proxy之间的shm。

Ø 结论:Notify_worker进程每次启动时都会创建一块shm大小为204800的共享内存块。到初始化函数中检查,并无对应的创建过程;后来比对与以前版本的区别发现之前版本有对应的创建过程,这个是由于自己注释掉之后没有立即重新编译,后来忘记了这事:(

以后使用共享内存要多注意检查!!!

2, 共享内存attach后没有dettach,导致core。

首先,查看进程中析构函数的汇编码。执行gdb cache_main

disassemble main,出现很多信息,找到如下关注信息:

反汇编CShmQueue,如下:

 

继续反汇编~CShmQueue,如下:

发现该函数为空函数,按照代码逻辑来说该函数应该去析构其成员CShm和CSem对象,从而dettach共享内存。进而推测该函数在链接成共享内存时被替换。

 

写一个简单的脚本对所有的静态库进行反汇编并利用CShmQueue过滤结果,发现libcredence2.a中有如下显示:

发现该~CShmQueue为T,强类型函数。

 

再看看我们自身的析构函数,使用nm -C CNotitySvr.o |grep CShmQueue 查看如下: 

发现该~CShmQueue为W,弱类型函数,因为我们的析构函数是内联函数。

也可以查看更详细信息如下,确定这个析构函数是我们自身的:

注意:如果在CShmQueue实现的静态库中用nm是查不到内联析构函数的,只有在使用这个类的目标文件中可以查到。

 

最后,确定我们的~CShmQueue是被libcredence2.a中同名析构函数覆盖,之所以编译时候没有警告或者错误提示,是因为我们的析构函数是内联函数。

解决方法:

Ø 使用命名空间对类的作用域进行限制。

Ø 以后类实现时,构造函数和析构函数尽量放在源文件中,或者用特定的名字空间进行限制。

 

延伸阅读(库文档的开发与使用)http://www.cppblog.com/amazon/archive/2010/01/12/105471.html