Chinaunix首页 | 论坛 | 博客
  • 博客访问: 2336732
  • 博文数量: 527
  • 博客积分: 10343
  • 博客等级: 上将
  • 技术积分: 5565
  • 用 户 组: 普通用户
  • 注册时间: 2005-07-26 23:05
文章分类

全部博文(527)

文章存档

2014年(4)

2012年(13)

2011年(19)

2010年(91)

2009年(136)

2008年(142)

2007年(80)

2006年(29)

2005年(13)

我的朋友

分类: LINUX

2010-11-09 16:06:44

我尝试做UT测试时,发现有些测试的情况UT不能覆盖,于是想动手扩大范围,不管它算是什么测试,反正能自动化地验证程序是个好事。在这个过程中我使用了一些极端变态的做法来测试,比如:

程序要动态地,周期性地读取/proc/stat 文件的内容,以此计算cpu负载。该文件第一行的格式如下:

cpu  39794 68 117063 34980272 185392 0 2746 6106

cpu 后面的4个数字分别代表 用户空间, nice 过的用户空间, system空间和idle的时间, 单位是1/100秒。

原来的程序用unsigned long来保存这个数字,但至少2.6内核中,内核本身早就用64位整数来保存这个数了。所以一个4核的CPU在运行几个月后,unsigned long会溢出。顺便说一句,典型的windows或linux下,
sizeof(unsigned long)与sizeof(unsigned int)一样,都是4字节整数。

出现这个溢出之后,程序在计算CPU负载时总是会返回100%,这显然是个错误的值。

那么怎么样在测试中模拟这个 /proc/stat文件,手工把它加到 unsigned int的上限 4294967295呢?
如果它是普通文件,就简单了,但它是个内核中的pseudo file system, 而且只读不写。这就麻烦了。我前后想过几个方案:

1. 写一个内核模块, 或许是filter模块(貌似是windows驱动的概念),需要时把它insmod到内核中,动态修改。
2. chroot.
这两个方法都涉及大量的工作,其中chroot貌似简单一些,但在产品级的程序中,一个ELF可执行文件往往依赖很多.so,需要模拟出的root 目录很大,而且很容易漏掉一些,导致程序行为异常。最终放弃这个的原因是snmp agent不能连接到snmpd的socket上,即使用mksock 创建了相应的socket设备文件也不行。于是放弃。

3. 通过LD_PRELOAD指定一个.so文件,在main执行之前就修改进程。类似的方法我在其它地方用过,肯定可以工作,但涉及额外的编程和调试,因为先想到了下面用gdb动态修改程序变量的办法,所以没有继续尝试下去。

好了,终于说到正题了。我希望通过gdb 随时暂停一个程序,修改它的一些变量,然后让它继续运行,程序的行为预先会根据变量进行调整,具体说,我把 /proc/stat 保存在一个
static char s_proc_stat_fname[]中,程序会打开这个文件读取其中内容。gdb只需要修改这个变量即可。下面是命令:

gdb -p $(pidof prog) --silent -ex 'x/s strcpy(s_proc_stat_fname, "/prox/stat")' -ex 'set confirm off' -ex 'quit' 2>/dev/null

其中set confirm off很重要,避免了与gdb的交互,让它静默地执行预定义的命令,然后功成身退。

测试脚本希望预先知道可执行程序能否被gdb加载调试符号。

交互式使用gdb时,给定了要调试的文件, gdb会在启动后向标准输出输出一条信息, 标明是否成功地加载了符号信息。

可以利用这一点,在gdb脚本中预先判断gdb能否成功加载被调试程序的符号信息。


# detect whether debug symbols for a given program can be load successfully by gdb
# arg 1: target program to detect
function has_debug_symbol()
{
    prog="$1"
    gdb --silent -ex 'quit' $prog 2> /dev/null | grep -i 'no debugging symbols found'
}

如果程序有一大堆.so文件,它们各自另有符号文件,gdb会向stderr上输出它们的加载信息, 很多, 很烦。 2>/dev/null 为的是避免这个。

顺便说一下,判断调试器使用的调试信息,使用file 命令的输出是不行的。它输出的是否stripped不是指调试器要使用的调试信息。
阅读(1612) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~