打印更多的用户态段错误信息

    在调试上层程序时,经常会遇到的错误是段错误,当出现段错误时,系统往往只会给出一个 segmention error,而在没有更多的信息(默认不产生core dump),在这种情况下,可以通过修改内核启动参数来使能调试模式,让用户态出现段错误时,打印出更多的提示信息,有助于定位错误。

     分析流程:

     先从在内核态的段错误出发,当产生内核态的段错误时,通常会打印出如下字段:

      Unable to handle kernel paging request at virtual address 56000050

     鉴于主流的体系结构为arm,我们可以在内核目录 arch/arm/ 目录下面,通过如下方式来定位:

    

     找到对于代码所在的文件:

   1:  static void
   2:  __do_kernel_fault(struct mm_struct *mm, unsigned long addr, unsigned int fsr,
   3:            struct pt_regs *regs)
   4:  {
   5:      /*
   6:       * Are we prepared to handle this kernel fault?
   7:       */
   8:      if (fixup_exception(regs))
   9:          return;
  10:   
  11:      /*
  12:       * No handler, we‘ll have to terminate things with extreme prejudice.
  13:       */
  14:      bust_spinlocks(1);
  15:      printk(KERN_ALERT
  16:          "Unable to handle kernel %s at virtual address %08lx\n",
  17:          (addr < PAGE_SIZE) ? "NULL pointer dereference" :
  18:          "paging request", addr);
  19:   
  20:      show_pte(mm, addr);
  21:      die("Oops", regs, fsr);
  22:      bust_spinlocks(0);
  23:      do_exit(SIGKILL);
  24:  }
   
  此函数在这里被调用:
   1:  void do_bad_area(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
   2:  {
   3:      struct task_struct *tsk = current;
   4:      struct mm_struct *mm = tsk->active_mm;
   5:   
   6:      /*
   7:       * If we are in kernel mode at this point, we
   8:       * have no context to handle this fault with.
   9:       */
  10:      if (user_mode(regs))
  11:          __do_user_fault(tsk, addr, fsr, SIGSEGV, SEGV_MAPERR, regs);
  12:      else
  13:          __do_kernel_fault(mm, addr, fsr, regs);
  14:  }

.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }

    从上面可以看出,如果是在用户态访问了非法区域,会调用__do_user_fault函数,在内核态的话,会调用__do_kernel_fault函数。

    我们进入__do_user_fault来查看:

   1:  static void
   2:  __do_user_fault(struct task_struct *tsk, unsigned long addr,
   3:          unsigned int fsr, unsigned int sig, int code,
   4:          struct pt_regs *regs)
   5:  {
   6:      struct siginfo si;
   7:   
   8:  #ifdef CONFIG_DEBUG_USER
   9:      if (user_debug & UDBG_SEGV) {
  10:          printk(KERN_DEBUG "%s: unhandled page fault (%d) at 0x%08lx, code 0x%03x\n",
  11:                 tsk->comm, sig, addr, fsr);
  12:          show_pte(tsk->mm, addr);
  13:          show_regs(regs);
  14:      }
  15:  #endif
  16:  .....
  17:   
  18:  }
   从上述可以看出,要想在用户态打印更多的调试信息,需要
   1. 内核配置 CONFIG_DEBUG_USER 宏
   2. user_debug & UDBG_SEGV 为真 ,其中 UDBG_SEGV = (1 << 3) ,而全局变量user_debug初始化为0, 

    #define UDBG_UNDEFINED   (1 << 0)   //产生未定义指令信息

    #define UDBG_SYSCALL     (1 << 1)   //产生非法的系统调用

    #define UDBG_BADABORT    (1 << 2)   
    #define UDBG_SEGV        (1 << 3)   //产生段错误信息

    #define UDBG_BUS         (1 << 4)   

   1:   
   2:  #ifdef CONFIG_DEBUG_USER
   3:  unsigned int user_debug;
   4:   
   5:  static int __init user_debug_setup(char *str)
   6:  {
   7:      get_option(&str, &user_debug);
   8:      return 1;
   9:  }
  10:  __setup("user_debug=", user_debug_setup);
  11:  #endif

.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }

.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }      分析到这里,我们就知道了,可以通过Uboot传递给内核的启动参数 bootargs,设置 user_debug = 0xFF,开启所有用户态调试信息

   

    此后,在执行用户态程序时,当出现段错误,会显示许多信息,在这里,有用的值是pc值。

        

    我们可以通过反汇编应用程序来分析此pc值对于的具体哪一句汇编指令:

    arm-linux-objdump –D test_debug > test_debug.dis , 在test_debug.dis中搜索 PC值:84ac,对比发生错误时的寄存器信息。

   

Technorati 标签: 调试

时间: 2024-08-03 04:37:41

打印更多的用户态段错误信息的相关文章

linux下打印用户态段错误信息的一种方法

引自:韦东山嵌入式视频第二期 “第31课第3节_应用调试之配置修改内核打印用户态段错误信息_P” 第6分钟起. 1.配置内核支持DEBUG_USER  (勾选 Kernel hacking -> Verbose user fault messages[*] 即可)(视频第8:23) 2.设置bootargs,添加参数 user_debug = 0xFF 即可. user_debug的每一位代表设置不同的模式,具体模式可参考文件:include/asm-arm/System.h下的UDBG_XXX

Linux 段错误详解

By Falcon of TinyLab.org 2015/05/12 背景 笔者早年写过一篇:<可恶的"Segmentation faults"之初级总结篇>,网络转载甚多.多年下来,关于段错误的讨论依旧很热烈,该问题也还是很常见.所以打算在这里再系统地梳理一下该问题的来龙去脉. 什么是段错误 下面是来自 Answers.com 的定义: A segmentation fault (often shortened to segfault) is a particular

你的java/c/c++程序崩溃了?揭秘段错误(Segmentation fault)(3)

前言 接上两篇: 你的C/C++程序为什么无法运行?揭秘Segmentation fault (1) 你的C/C++程序为什么无法运行?揭秘Segmentation fault (2) 写到这里,越跟,越发现真的是内核上很白,非一般的白. 但是既然是研究,就定住心,把段错误搞到清楚明白. 本篇将作为终篇,来结束这个系列,也算是对段错误和程序调试.寻找崩溃原因(通常不会给你那么完美的stackstrace和人性化的错误提示)的再深入. 本篇使用到的工具或命令: dmesg strace gdb l

Linux环境下段错误的产生原因及调试方法小结(转)

最近在Linux环境下做C语言项目,由于是在一个原有项目基础之上进行二次开发,而且 项目工程庞大复杂,出现了不少问题,其中遇到最多.花费时间最长的问题就是著名的“段错误”(Segmentation Fault).借此机会系统学习了一下,这里对Linux环境下的段错误做个小结,方便以后同类问题的排查与解决. 1. 段错误是什么 一句话来说,段错误是指访问的内存超出了系统给这个程序所设定的内存空间,例如访问了不存在的内存地址.访问了系统保护的内存地址.访问了只读的内存地址等等情况.这里贴一个对于“段

Linux环境下段错误的产生原因及调试方法小结

最近在Linux环境下做C语言项目,由于是在一个原有项目基础之上进行二次开发,而且项目工程庞大复杂,出现了不少问题,其中遇到最多.花费时间最长的问题就是著名的“段错误”(Segmentation Fault).借此机会系统学习了一下,这里对Linux环境下的段错误做个小结,方便以后同类问题的排查与解决. 1. 段错误是什么 一句话来说,段错误是指访问的内存超出了系统给这个程序所设定的内存空间,例如访问了不存在的内存地址.访问了系统保护的内存地址.访问了只读的内存地址等等情况.这里贴一个对于“段错

【转】【调试技巧】Linux环境下段错误的产生原因及调试方法小结

本文转自:http://www.cnblogs.com/panfeng412/archive/2011/11/06/segmentation-fault-in-linux.html 最近在Linux环境下做C语言项目,由于是在一个原有项目基础之上进行二次开发,而且项目工程庞大复杂,出现了不少问题,其中遇到最多.花费时间最长的问题就是著名的“段错误”(Segmentation Fault).借此机会系统学习了一下,这里对Linux环境下的段错误做个小结,方便以后同类问题的排查与解决. 1. 段错误

Linux环境下段错误的产生原因及调试方法小结(转载)

转载自http://www.cnblogs.com/panfeng412/archive/2011/11/06/2237857.html 最近在Linux环境下做C语言项目,由于是在一个原有项目基础之上进行二次开发,而且项目工程庞大复杂,出现了不少问题,其中遇到最多.花费时间 最长的问题就是著名的“段错误”(Segmentation Fault).借此机会系统学习了一下,这里对Linux环境下的段错误做个小结,方便以后同类问题的排查与解决. 1. 段错误是什么 一句话来说,段错误是指访问的内存超

Linux 下段错误 core文件

什么是core dump? core的意思是内存,dump的意思是扔出来,堆出来:当一个程序奔溃时,在进程当前工作目录的core文件中复制了该进程的存储图像.core文件仅仅是一个内存映像(同时加上调试信息),主要用来调试的. 为什么没有core文件生成呢? 有时候程序down了,但是core文件却没有生成.core文件的生成跟你当前系统的环境设置有关系,可以用下面的语句设置一下便生成core文件了 在linux平台下,设置core dump文件生成的方法:1. 在终端中输入ulimit -c

段错误详解

Linux环境下段错误的产生原因及调试方法小结 最近在Linux环境下做C语言项目,由于是在一个原有项目基础之上进行二次开发,而且项目工程庞大复杂,出现了不少问题,其中遇到最多.花费时间最长的问题就是著名的“段错误”(Segmentation Fault).借此机会系统学习了一下,这里对Linux环境下的段错误做个小结,方便以后同类问题的排查与解决. 1. 段错误是什么 一句话来说,段错误是指访问的内存超出了系统给这个程序所设定的内存空间,例如访问了不存在的内存地址.访问了系统保护的内存地址.访