如果我只想查看一些局部变量,我该怎么办?
背景:我们在生产中遇到了问题,生产中的二进制文件中没有符号信息。
您的问题中没有提到操作系统,所以如果您使用的是 Linux
1) 在生产服务器上安装带有调试信息的程序
2)如果您不能这样做,请分析您感兴趣的函数的汇编代码并从汇编程序中获取局部变量的值
然后使用 SystemTap 跟踪您的程序。
让我用一个简单的例子来说明这两种方法。
一、C++程序分析:
>cat main.cpp
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int f(int arg)
{
int a = arg+1;
int b = arg+2;
int c = a + b;
printf ("printf in program: f, c: %d\n", c);
return c;
}
int main(int argc, char *argv[])
{
printf ("f: %p\n", &f);
int sum = 0;
while (true) {
for (int i= atoi(argv[1]); i < atoi(argv[2]); ++i) {
sum += f(i);
}
sleep(5);
}
printf("Sum: %d\n", sum);
return 0;
}
所以我想在函数 f() 中获取局部变量“c”的值。
1) 如果符号信息可用
>cat measure_f.stp
probe process("a.out").statement("*@main.cpp:10")
{
printf("SystemTap, time: %s, the local variable c :%d\n", ctime(gettimeofday_s()), $c)
}
>sudo stap measure_f.stp -c "./a.out 21 23"
f: 0x400634
printf in program: f, c: 45
printf in program: f, c: 47
SystemTap, time: Fri Dec 27 12:59:31 2013, the local variable c :45
SystemTap, time: Fri Dec 27 12:59:31 2013, the local variable c :47
printf in program: f, c: 45
printf in program: f, c: 47
SystemTap, time: Fri Dec 27 12:59:36 2013, the local variable c :45
SystemTap, time: Fri Dec 27 12:59:36 2013, the local variable c :47
1) 如果符号信息不可用,则使用汇编程序
先反汇编你的函数,找到你要监控的地址
(gdb) disassemble /m f
Dump of assembler code for function f(int):
6 {
0x0000000000400634 <+0>: push %rbp
0x0000000000400635 <+1>: mov %rsp,%rbp
0x0000000000400638 <+4>: sub $0x20,%rsp
0x000000000040063c <+8>: mov %edi,-0x14(%rbp)
7 int a = arg+1;
0x000000000040063f <+11>: mov -0x14(%rbp),%eax
0x0000000000400642 <+14>: add $0x1,%eax
0x0000000000400645 <+17>: mov %eax,-0xc(%rbp)
8 int b = arg+2;
0x0000000000400648 <+20>: mov -0x14(%rbp),%eax
0x000000000040064b <+23>: add $0x2,%eax
0x000000000040064e <+26>: mov %eax,-0x8(%rbp)
9 int c = a + b;
0x0000000000400651 <+29>: mov -0x8(%rbp),%eax
0x0000000000400654 <+32>: mov -0xc(%rbp),%edx
0x0000000000400657 <+35>: lea (%rdx,%rax,1),%eax
0x000000000040065a <+38>: mov %eax,-0x4(%rbp)
10 printf ("printf in program: f, c: %d\n", c);
0x000000000040065d <+41>: mov -0x4(%rbp),%eax
0x0000000000400660 <+44>: mov %eax,%esi
0x0000000000400662 <+46>: mov $0x4007f8,%edi
0x0000000000400667 <+51>: mov $0x0,%eax
0x000000000040066c <+56>: callq 0x4004f8 <printf@plt>
11 return c;
0x0000000000400671 <+61>: mov -0x4(%rbp),%eax
12 }
0x0000000000400674 <+64>: leaveq
0x0000000000400675 <+65>: retq
如您所见,为了获取局部变量 c,必须在 0x000000000040065a 上获取寄存器 %eax
> cat measure_f_2.stp
probe begin
{
printf("Monitoring process %d\n", $1)
}
probe process($1).statement(0x000000000040065a).absolute
{
printf("SystemTap (2), time: %s, the local variable c (rax):%d\n", ctime(gettimeofday_s()), register("rax"))
}
所以我开始“./a.out 21 23”,然后运行我的 SystemTap 脚本
>sudo stap measure_f_2.stp 11564
Monitoring process 11564
SystemTap (2), time: Fri Dec 27 13:15:09 2013, the local variable c (rax):45
SystemTap (2), time: Fri Dec 27 13:15:09 2013, the local variable c (rax):47
SystemTap (2), time: Fri Dec 27 13:15:14 2013, the local variable c (rax):45
SystemTap (2), time: Fri Dec 27 13:15:14 2013, the local variable c (rax):47