linux程序分析工具介绍(一)—-”/proc”
写在最前面:在开始本文之前,笔者认为先有必要介绍一下linux下的man,如果读者手头用linux系统,直接在终端输入man man便可以看到详细的说明,我在这里简单的总结一下,man命令是用来查看linux下各种命令、工具等的用户手册(manual)的。一种比较常用的用法是”man n field”,这里的n是要查找的手册了类型,field是关键字。在这里介绍一下n:
- 0 /usr/include下的头文件
- 1 可执行程序和shell命令
- 2 系统调用
- 3 系统库函数
- 4 /dev下的特殊文件
- 5 文件格式和约定(比如/etc/passwd)
- 6 游戏
- 7 其它
- 8 仅root可用的系统管理命令
- 9 内核相关的内容
通常情况下,如果不加n的话,系统会按一定的顺序,有时候得到的可能不是你想要的,这时候就需要加上n了,这就是我要介绍n的目的。比如,你man printf,系统返回的肯定是shell命令printf,你要看库函数printf怎么办呢,那就man 3 printf,that’s ok
下面进入今天的正题,/proc是linux系统为我们用户提供的一个可以用来访问系统相关数据及信息的一个伪文件 系统,通过它我们不仅可以获取指定某个进程的相关信息,还可以获取系统整体的运行情况及信息。因为本文讲的是分析程序的工具,所以本文将侧重介绍通过/proc来分析程序本身,关于如何通过/proc来查看系统相关信息,可以通过man 5 proc来看(这也是我开始就讲man的一个原因 )。 - /proc/[number]/cmdline 程序命令行参数,以’\0′分隔的字符串文件(在程序中,可以通过直接读此文件,获取程序的命令行参数,但不推荐这么做,这样做了程序的可移植性不好 )
- /proc/[number]/cwd 程序的当前工作路径的软链接(readlink就可以得到被链接的目录)
- /proc/[number]/environ 程序的当前环境变量,以’\0′分隔的字符串文件
- /proc/[number]/exe 程序的可执行文件的软链接(通过readlink可以获取程序可执行文件的完整路径)
- /proc/[number]/fd 程序当前正在使用的fd,这些fd都链向实际的文件
- /proc/[number]/maps 程序的地址空间分布和访问权限(通过这些信息,可以查看进程的地址是否在合法的范围)
- /proc/[number]/smaps (since Linux 2.6.14) 程序的每块内存映射区域的内存使用情况
- /proc/[number]/stat 程序的状态信息,ps命令得到的程序信息就是从此处获取的,因此详细的因容可以ps命令
- /proc/[number]/statm 程序的内存页(page)状态
- /proc/[number]/status stat和statm合起来的信息,以一种比较方便用户读的方式展示
linux程序分析工具介绍(二)—-ldd,nm
本文要介绍的ldd和nm是linux下,两个用来分析程序很实用的工具。ldd是用来分析程序运行时需要依赖的动态库的工具;nm是用来查看指定程序中的符号表相关内容的工具。下面通过例子,分别来介绍一下这两个工具:
1. ldd, 先看下面的例子, 用ldd查看cs程序所依赖的动态库:
在上面的例子中,ldd的结果可以分为三列来看:
- 第一列:程序需要依赖什么库
- 第二列: 系统提供的与程序需要的库所对应的库
- 第三列:库加载的开始地址
通过上面的信息,我们可以得到以下几个信息:
- (1) 通过对比第一列和第二列,我们可以分析程序需要依赖的库和系统实际提供的,是否相匹配
- (2) 通过观察第三列,我们可以知道在当前的库中的符号在对应的进程的地址空间中的开始位置
2. nm, 通过下面的例子,我们来介绍nm工具:
先看一下这个简单的程序:接下来,我们编译该程序,然后看nm的结果:
上面便是test这个程序中所有的符号,首先需要介绍一下上面的内容的格式:
- 第一列:当前符号的地址
- 第二列:当前符号的类型(关于类型的说明,感兴趣的朋友可以man nm详阅)
- 第三列:当前符号的名称
在上面的结果中,像_ZN4Test5HelloEv这样的符号,很多读者朋友可能会被它搞晕,这里介绍个小技巧,在nm的时候,加上-C选项,就可以把这些难以识别的符号,转换成便于我们阅读的符号TestHello()。这个主要是c++中的mangle机制所导致的,加上-C就是指定列出的符号是demangle了的。说了这么多,到底nm对我们程序有啥具体的帮助呢,我觉得主要有以下几个方面:
(1)判断指定程序中有没有定义指定的符号 (比较常用的方式:nm -C proc | grep symbol)
(2)解决程序编译时undefined reference的错误,以及mutiple definition的错误
(3)查看某个符号的地址,以及在进程空间的大概位置(bss, data, text区,具体可以通过第二列的类型来判断)