linux下远程调试

日期:2015-04-03点击次数:8489

上回讲述了在windows下有关远程调试的内容,这次想用一个小例子,讲述下在linux下远程调试,借鉴了网上一些内容。光说不练假把式,实战出真知,不喜欢空谈理论的文章,玄乎其玄,云里雾里,让人难以接受。闲话少说,看我本次教程写的小Demo以及调试环境:
两台主机:
被调试机器:IP 192.168.0.227;OS CentOS 6.3 64位
客户端机器:IP 192.168.0.228;OS CentOS 6.3 64位
被调试机器安装的调试器gdb版本为7.2,确认gdbserver已经安装(gdbserver是gdb里面的一个小程序,用于远程调试)。客户端机器gdb版本也为7.2。
接下来就是Demo,一个很简单的测试程序,加载了两个动态库(.so)。
libadd.so源代码:
 
libadd.c
int add(int a, int b)
{
return a+b;
}
 
libsub.so源代码:
libsub.c
int sub(int a, int b)
{
return a - b;
}
 
测试程序test源代码:
 
public.h
 
int add(int a, int b);
int sub(int a, int b);
 
///////////////////////////////////////////////////////////////////////////
test.c
 
#include <stdio.h>
#include <unistd.h>
#include "public.h"
 
int main(int argc, char* argv[])
{
while(1) 
{
int sum = add(1, 2);
printf("1 + 2 = %d\n", sum);
 
int c = sub(4, 5);
printf("4 - 5 = %d\n", c);
 
sleep(1);
}
 
return 0;
}
 
test.c 使用了一个while循环,模拟下线程运行,不想写的太复杂。
 
然后是我写的Makefile,用于编译链接。
Makefile:
 
CC = gcc
 
CFLAGS = -O2 -Wall -g  -fPIC -I.
 
LDFLAGS =  -L. -ladd -lsub
 
ADDOBJ = ./libadd.o
SUBOBJ = ./libsub.o
TARGETOBJ = ./test.o
 
LIBADD = ./libadd.so
LIBSUB = ./libsub.so
TARGET = ./test
 
all:$(TARGET) $(LIBADD) $(LIBSUB)
 
%.o : %.c
$(CC) $(CFLAGS) $< -c -o $@
 
$(TARGET):$(TARGETOBJ) $(LIBADD) $(LIBSUB)
$(CC) $(TARGETOBJ) -o $@ $(LDFLAGS)
 
$(LIBADD):$(ADDOBJ)
$(CC) $< -fPIC -shared -o $@
 
$(LIBSUB):$(SUBOBJ)
$(CC) $< -fPIC -shared -o $@
 
clean:
rm -rf $(TARGET) $(LIBADD) $(LIBSUB) *.o
 
 
在客户端192.168.0.228上/home下建立test目录,将libadd.c,libsub.c,public.h,test.c,Makefile拷贝到test目录下。编译链接程序:
cd /home/test
make
 
 
 
编译后生成了3个二进制文件:libadd.so,libsub.so,test。
下面就是在被调试机器192.168.0.227下,也在/home目录下新建一个test目录,将192.168.0.228上面刚生成的libadd.so,libsub.so,test拷贝到新建目录test中。
 
紧接着是在192.168.0.227下执行test程序,并使用gdbserver 附加 test进程,以方便在192.168.0.228上进行远程调试。
192.168.0.227机器上:
cd /home/test
./test
 
然后就是获取test的进程ID,并使用gdbserver附加:
 
 
至此,被调试机器227环境已经准备完毕,再看看228上面的步骤: 192.168.0.228机器上:
cd /home/test
gdb test
 
 
要远程调试227上的程序,就得指定远程机器ip和被调试端口:
在gdb上使用target remote命令指定。
 
 
指定以后,下面就可以远程调试227上的test程序了。先使用list命令看看test.c源代码,以便于在行号上设置断点:
 
 
我在第9行设置断点,以调试libadd.so中的add接口函数:
 
 
然后使用 c命令继续程序运行,程序在第9行(断点处)停顿,
紧接着使用step命令,以进入add函数代码进行调试,奇怪的事情发生了,227上的test程序突然crash掉了。在网上查了查原因,大致了解了远程调试so需要自己指定so加载的.text段的地址,gdb不能自动计算。
 
知道了原因,然后我使用cat命令以查看227上test进程的映射表: 192.168.0.227上的步骤:
 
 
查看/home/test/libsub.so的首行:
7f69265db000-7f69265dc000 r-xp 00000000 fd:00 1703940   /home/test/libsub.so
再查看/home/test/libadd.so的首行:
7f69267dd000-7f69267de000 r-xp 00000000 fd:00 1703939   /home/test/libadd.so
 
确定出libadd.so加载到进程test的虚拟地址是0x7f69267dd000。
确定出libsub.so加载到进程test的虚拟地址是0x7f69265db000。
 
下面一步是查看在libadd.so上.text代码段的偏移:
 
 
确认出代码段的偏移地址是00000460。
然后就能计算出libadd.so代码段在进程test中的虚拟地址:
libadd.so .text VA = 0x7f69267dd000 + 0x460 = 0x7f69267dd460。
 
使用同样的方法,确定libsub.so .text段的虚拟地址:
 
 
libsub.so .text VA= 0x7f69265db000 + 0x460 = 0x7f69265db460。
 
获取到libadd.so,libsub.so .text的虚拟地址后,就能在228上调试这两个动态库了。
192.168.0.228上的调试步骤:
使用add-symbol-file指令指定libadd.so的代码段VA:
 
 
紧接着在add函数下断点:
 
 
下面就可以调试add函数了,看下面的步骤:
 
 
使用相同的步骤调试libsub.so中的sub函数:
 
 
 
 
至此,就可以随便调试libadd.so,libsub.so中的代码了。但有个限制,就是在main函数中,不能使用step指令进入add,sub函数中调试,只能使用b add,b sub直接在so中下断点。
这篇教程虽然只是讲述在PC上的远程调试,但其使用范围不限于PC机。可以使用此方法远程调试嵌入式设备,可以调试Android设备上的NDK程序。有兴趣的同学可以试试。




软件部       向国春

上一篇:birt使用下一篇:ONVIF开发总结
姓名:
性别:
电话:
E-mail
问题:
问题描述: