一个调试工具编写的发现(原创)
2008-01-28 16:50
288 查看
0.转载请保留原创:http://www.cppblog.com/jinglexy
MSN and Email: jinglexy at yahoo dot com dot cn
前不久写的一个调试器,公司很多模块使用linux环境,由于使用平台的缘故,bug非常多,于是编写了一个简单的调试器:大致功能是捕获程序异常,打印调用栈(也包括调用函数名),对运行的进程进行代码或函数调试,内核简单调试等。代码量并不大,有效代码行不超过3000行,花了10工作日完成,可能是时间紧迫吧,后期调试用了3周,汗哪!
1.使用ptrace系统调用关联一个进程后,需要waitpid(pid, NULL, WUNTRACED);一下,这个调试了很长时间才发现的,我猜测可能是因为ptrace后,不像信号立即 进入目标进程的处理。需要调度到目标进程后,进入do_waitpid()处理函数以设置正确的调试状态。如果不这样做,会导致释放管理进程失败。比较流行的调试工具gdb就是使用ptrace实现的,在gcc编译过程中也会插入专门的调试信息。原理比较简单,实现起来细节需要注意的也很多。
2.在跟踪程序异常时的调用栈中发现的:montavista编译环境的一个bug?(不能捕获动态库中的异常,主要是因为动态库加载时地址都不固定,使用了一种叫做got的技术,可以阅读coly大侠翻译的《连接器与加载器》一书,非常棒)
当程序收到异常信号后,内核进入do_signal()处理,在arch/arm/kernel/signal.c文件,
do_signal() -- > handle_signal() --> setup_rt_frame()
setup_rt_frame会拷贝上下文环境的数据结构到用户空间,
就是它的参数 siginfo_t *info,这个数据结构内部包含了上下文的数据结构struct ucontext ,
定义在:include/asm-arm/ucontext.h,内容如下:
struct ucontext {
unsigned long uc_flags;
struct ucontext *uc_link;
stack_t uc_stack;
struct sigcontext uc_mcontext;
sigset_t uc_sigmask; /* mask last for extensibility */
};
在arm_v5t_le-gcc中,上下文结构定义如下:
/opt/montavista/pro/devkit/arm/v5t_le/target/usr/include/sys/ucontext.h文件
typedef struct ucontext
{
unsigned long int uc_flags;
struct ucontext *uc_link;
__sigset_t uc_sigmask;
stack_t uc_stack;
mcontext_t uc_mcontext;
long int uc_filler[5];
} ucontext_t;
在上面数据结构中, __sigset_t uc_sigmask;被定义在上下文环境之前,
而在内核中 fp指针在 uc_mcontext的arm_fp域中(先将uc_mcontext强制转换成struct sigcontext结构
在asm-arm/sigcontext.h定义),
也就是第14个 int 成员, 由于上面的stack_t 占内存为3个 int型,所以在nipdebug调试库中修补为
*bp = ct->uc_sigmask.__val[17];
结论:montavista编译环境的ucontext.h文件定义上下文环境的数据结构位置不正确,
而该数据结构在/opt/arm/arm-linux/sys-include/sys/ucontext.h(即arm9)中定义是正确的,
/opt/ppc/include/sys/ucontext.h(ppc交叉编译)中也是正确的。
MSN and Email: jinglexy at yahoo dot com dot cn
前不久写的一个调试器,公司很多模块使用linux环境,由于使用平台的缘故,bug非常多,于是编写了一个简单的调试器:大致功能是捕获程序异常,打印调用栈(也包括调用函数名),对运行的进程进行代码或函数调试,内核简单调试等。代码量并不大,有效代码行不超过3000行,花了10工作日完成,可能是时间紧迫吧,后期调试用了3周,汗哪!
1.使用ptrace系统调用关联一个进程后,需要waitpid(pid, NULL, WUNTRACED);一下,这个调试了很长时间才发现的,我猜测可能是因为ptrace后,不像信号立即 进入目标进程的处理。需要调度到目标进程后,进入do_waitpid()处理函数以设置正确的调试状态。如果不这样做,会导致释放管理进程失败。比较流行的调试工具gdb就是使用ptrace实现的,在gcc编译过程中也会插入专门的调试信息。原理比较简单,实现起来细节需要注意的也很多。
2.在跟踪程序异常时的调用栈中发现的:montavista编译环境的一个bug?(不能捕获动态库中的异常,主要是因为动态库加载时地址都不固定,使用了一种叫做got的技术,可以阅读coly大侠翻译的《连接器与加载器》一书,非常棒)
当程序收到异常信号后,内核进入do_signal()处理,在arch/arm/kernel/signal.c文件,
do_signal() -- > handle_signal() --> setup_rt_frame()
setup_rt_frame会拷贝上下文环境的数据结构到用户空间,
就是它的参数 siginfo_t *info,这个数据结构内部包含了上下文的数据结构struct ucontext ,
定义在:include/asm-arm/ucontext.h,内容如下:
struct ucontext {
unsigned long uc_flags;
struct ucontext *uc_link;
stack_t uc_stack;
struct sigcontext uc_mcontext;
sigset_t uc_sigmask; /* mask last for extensibility */
};
在arm_v5t_le-gcc中,上下文结构定义如下:
/opt/montavista/pro/devkit/arm/v5t_le/target/usr/include/sys/ucontext.h文件
typedef struct ucontext
{
unsigned long int uc_flags;
struct ucontext *uc_link;
__sigset_t uc_sigmask;
stack_t uc_stack;
mcontext_t uc_mcontext;
long int uc_filler[5];
} ucontext_t;
在上面数据结构中, __sigset_t uc_sigmask;被定义在上下文环境之前,
而在内核中 fp指针在 uc_mcontext的arm_fp域中(先将uc_mcontext强制转换成struct sigcontext结构
在asm-arm/sigcontext.h定义),
也就是第14个 int 成员, 由于上面的stack_t 占内存为3个 int型,所以在nipdebug调试库中修补为
*bp = ct->uc_sigmask.__val[17];
结论:montavista编译环境的ucontext.h文件定义上下文环境的数据结构位置不正确,
而该数据结构在/opt/arm/arm-linux/sys-include/sys/ucontext.h(即arm9)中定义是正确的,
/opt/ppc/include/sys/ucontext.h(ppc交叉编译)中也是正确的。
相关文章推荐
- 发现一个比较好用的动画制作工具 spine
- 发现一个很有用的前端工具网站
- 推荐一个IE6下js调试工具(Companion.JS)
- 编写一个数组的工具类
- (原创)设计一个Tomcat访问日志分析工具
- Share一个原创需求管理及错误跟踪工具ReqMgr
- 发现一个特给力的编写HTML/CSS的插件
- 发现了一个JSON字符串在线格式化工具
- 一个谷歌浏览器的调试工具设置
- 介绍Junit,一个用来在项目中进行测试和调试的工具
- 《c primer pius》第六章第14题,发现网上好多都有问题,编写一个程序读入一行输入,然后反向打印该行,您可以把输入存储在一个char数组中
- 发现一个挺好用的adb logcat工具
- [编写高质量代码:改善java程序的151个建议]建议42,如何让一个工具类不可实例化
- 发现一个很不错的linux/unix工具screen: 管理远程会话
- [原创]自己编写的一个JS无边距滚动的类
- 发现IE下的优秀JavaScript调试工具Companion.JS
- 2010年写的一个小工具发现原来只需一行命令即可!
- RVDS和MDK嵌入式开发工具调试脚本编写
- 一直没有发现的调试工具,valgrind
- 发现了Eclipse调试Android的时候的一个小技巧哦!DDMS快速进入断点状态