Chinaunix首页 | 论坛 | 博客
  • 博客访问: 53306
  • 博文数量: 16
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 176
  • 用 户 组: 普通用户
  • 注册时间: 2013-03-05 15:17
个人简介

活在当下 眺望未来

文章分类

全部博文(16)

文章存档

2013年(16)

我的朋友

分类: LINUX

2013-05-29 11:51:38

程序core掉,要去debug,但是函数堆栈乱掉了,很恶心.....经过Google/wiki一番,找到两种解决办法.
1. 手动还原backtrace
  手动还原其实就是看栈里面的数据,自己还原函数栈,听起来很复杂其实也比较简单.手头上没有比较好的例子,所以大家就去看
  http://devpit.org/wiki/x86ManualBacktrace 上面的例子.那个例子很好,是x86下面的,amd64下面也是类似.
  amd64下面,无非就是寄存器变成rbp,字长增加了一倍.当然这边选择了手动寻找函数返回地址,然后info symbol打印出函数名,其实还可以通过gdb格式化来直接打印函数名:
  gdb>x/128ag rbp内的内容
  所以手动还原的办法就变得很简单:
  gdb>info reg rbp            *x86换成info reg ebp
  gdb>x/128ag  rbp内的内容        *x86换成 x/128aw ebp的内容
  这样就能看到函数栈.如果你想解析参数是啥,也是可以的,只是比较麻烦,苦力活儿....想解析参数,就要知道栈的布局,可以参考这篇文章:
  http://blog.csdn.net/liigo/archive/2006/12/23/1456938.aspx
  这个办法比较简单,很容易实践,但是有一个前提,如果栈的内容被冲刷干净了,你连毛都看不到(事实就是这样).所以你需要开始栈保护...至少你还能找到栈顶的函数...
  gcc有参数: -fstack-protector 和 -fstack-protector-all,强烈建议开启....
2. 手动记录backtrace
  开启了栈保护,这样至少会看到一个函数栈....如果想要知道更多的信息,对不起,没的...后来看公司内部的wiki,外加上google,得知很多人通过trace的办法来debug.:-D
  简单的说,在gcc2时代,提供了两个接口函数:
  void __cyg_profile_func_enter (void *this_fn, void *call_site)
  void __cyg_profile_func_exit  (void *this_fn, void *call_site)
  方便大家伙做profile,然后很多人用这俩函数来调试代码.:-D
   函数功能很简单,第一个就是函数入栈,第二就是函数出栈.所以你只要自己维护一个栈,然后在他入栈的时候你也入栈(只记录函数地址),出栈的时候你也出 栈.等程序挂了,你去看你自己维护的栈,这样就能搞到第二手的函数栈(第一手的可能被破坏了).然后在去info symbol或者x/num ag格式化打印也可以的.
  需要注意的是,编译需要加上参数-finstrumnet-function,而且这里函数的声明需要加上__attribute__ ((no_instrument_function))宏,否则他会无限递归调用下去,:-)
  如果是单线程,就搞一个栈就行了,如果多个线程,一个线程一个栈~~~
参考:
http://devpit.org/wiki/x86ManualBacktrace
http://blogold.chinaunix.net/u3/111887/showart_2182373.html
http://blog.csdn.net/liigo/archive/2006/12/23/1456938.aspx
/**********************************************************************
 * Make it Complex,and run away.
 *
 * From:         http://www.cnblogs.com/egmkang/
 * Email:         egmkang [at] 163.com
 * QQ Group:  20240291(慎入,可能没人打理)
 *
 **********************************************************************/


用打印方法调试
在客户项目那里混了半年,发现Top的客户确实是比我们牛逼。先说说调试的方法。
客户那边不依赖于GDB调试,因为他们可能觉得GDB依赖于系统 实现,不利于移植吧,所以客户的程序完全是依赖于打印调试的。这点很佩服他们的软件规划能力和项目管理,实现能力。说老实话,如果换了一家中国公司,每人 一个调试方法,要follow 一个rule是很不容易的。
  • 完善的调试菜单。调试菜单并不难实现,只是一个打印和字符接受的函数。在其中控制是开放某些打印信息。
  • 在每个模块中加上仔细规划打印输出,根据需求分成不同的基本。最好情况是在最高打印级别中可以可以发现所有的问题。打印级别可以很方便的动态控制。
  • 函数调用LOG
        如果能定位发生问题的模块,可以在该模块的在每个函数的调用入口加上打印一个函数名字+Enter,在返回处加上一个函数名字+Exit。对于每个模块用一个打印开关控制是否打印Trace信息。在调试菜单中控制这个打印开关。
       如果懒得加打印语句,可以利用gcc 的-finstrument-functions 选项来快速的加入调试信息。-finstrumnet-function会是的编译器在函数调用的开始和退出处调用
void __cyg_profile_func_enter (void *this_fn, void *call_site)
void __cyg_profile_func_exit  (void *this_fn, void *call_site)。 可以利用这两个函数来跟踪函数调用的过程。
在 实现这两个函数时要加入__attribute__ ((no_instrument_function));以避免编译器再调用这两个函数的时候也调用__cyg_profile_func_enter 和 __cyg_profile_func_exit 而造成循环调用。
      可以用dladdr()来获得this_fn的文件和函数名。code如下:
#define _GNU_SOURCE  // 由于dladdr是GNU扩展,不是dl的标准函数,因此在这句话必须加在文件的开始处

#include
#include
void __cyg_profile_func_enter (void *this_fn, void *call_site) __attribute__ ((no_instrument_function));
void __cyg_profile_func_exit  (void *this_fn, void *call_site) __attribute__ ((no_instrument_function));

void __cyg_profile_func_enter (void *this_fn, void *call_site)
{
    Dl_info DLInfo;
    dladdr(this_fn, &DLInfo);
    printf("Enter file %s\n",DLInfo.dli_fname);
    printf("functio  %s\n",DLInfo.dli_sname);
   
}


void __cyg_profile_func_exit  (void *this_fn, void *call_site)
{
}


  • 关于打印堆栈。可以用
        #include
        void *array[10];
        char **strings;
        size_t size;
        size_t i;
        size = backtrace(array, 10);
        strings = backtrace_symbols(array, size);
        for(i=0;i        {
            printf ("%d, %p  ,%s\n",i,array[i],strings[i]);
        }
     该方法需要编译器支持。
     但是需要在编译的时候加上-rdynamic 否则只能输出在内存中的绝对地址。
   
    在没有-rdynamic的时候,关于如何找到动态库的运行时地址还需要研究。
    可以在系统运行的时候发送
SIGSEGV给应用程序,产生当前进程的Coredump来获取动态库中函数的运行是地址。
    用GDB获取backtrace的方法(在有-g选项的时候可以看到,不需要-rdynamic):
    list <*address>

    在没有-g的时候,又该如何呢?
   

http://blogold.chinaunix.net/u3/111887/showart_2182373.html

阅读(1149) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~