应用程序段错误调试

1、段错误(SIGSEGV)的产生

  从用户态程序开发的角度,我们并不需要理解操作系统复杂的内存管理机制,这是和硬件平台相关的。但是了解内核发送SIGSEGV信号的流程,对我们理解SIGSEGV是很有帮助的。
  这里写图片描述
  红色部分展示了内核发送SIGSEGV 信号给用户态程序的总体流程。当用户态 程序访问一个会引发SIGSEGV 的地址时,硬件首先产生一个page fault,即“缺页异常”。 在内核的page fault 处理函数中,首先判断该地址是否属于用户态程序的地址空间。32位系统中虚拟存储空间占4GB空间。Linux内核将这4G字节的空间分为两部分。用户态程序的地址空间为[0x00000000,0xBFFFFFFF],内核地址空间为[0xC0000000,0xFFFFFFFF]。如果该地址属于用户态地址空间,检查访问的类型是否和该内存区域的类型是否匹配,不匹配,则发送SIGSEGV 信号;如果该地址不属于用户态地址空间,检查访问该地址的操作是否发生在用户态,如果是,发送SIGSEGV 信号。 当程序不正常退出时,内核会在当前目录产生core文件(一个内存的映像,同时加上调试信息),然后利用gdb查看core文件,可以指示出导致程序出错位置的文件和行数。

2、core文件的产生

 2.1 系统配置

  确定系统是否配置支持dump core的功能。通过ulimit -c或ulimit -a,如果为0,则不会产生对应的coredump,需要进行修改和设置。使用 ulimit –c [size]这里的size的单位是blocks,一般1block=512bytes在不知 size的大小的时候,可以ulimit -c unlimited。

 2.2 程序编译

  1.用gcc(或者交叉编译工具)进行编译时,选择-g选项。
  2.不能进行strip操作,否则你将看不见程序的函数名、变量名,代替这些将是运行时的内存地址。

 2.3 core的存储位置

  core文件默认的存储位置与对应的可执行程序在同一目录下,文件名是core,大家可以通过下面的命令看到core文件的存储位置和格式:cat /proc/sys/kernel/core_pattern。
  其中core_pattern的格式见下面说明:
   %% 单个%字符
   %p 所dump进程的进程ID
   %u 所dump进程的实际用户ID
   %g 所dump进程的实际组ID
   %s 导致本次core dump的信号
   %t core dump的时间 (由1970年1月1日计起的秒数)
   %h 主机名
   %e 程序文件名
   其中/proc/sys/kernel/core_uses_pid。如果这个文件的内容被配置成1,即使core_pattern中没有设置%p,最后生成的core dump文件名仍会加上进程ID。以下是参数设置例子:

   echo "1" > /proc/sys/kernel/core_uses_pid 
   sysctl -w kernel.core_uses_pid=1;
   echo "/persistent/core-%e-%p-%t" > core_pattern;
   sysctl -w kernel.core_pattern=/persistent/core-%e-%p-%t

  注意:这里是指在进程当前工作目录的下创建。通常与程序在相同的路径下。但如果程序中调用了chdir函数,则有可能改变了当前工作目录。这时core文件创建在chdir指定的路径下。有好多程序崩溃了,我们却找不到core文件放在什么位置。和chdir函数就有关系。当然程序崩溃了不一定都产生core文件。

 2.4 什么时候不产生core文件

  ( a )进程是设置-用户-ID,而且当前用户并非程序文件的所有者
  ( b )进程是设置-组-ID,而且当前用户并非该程序文件的组所有者
  ( c )用户没有写当前工作目录的许可权
  ( d )文件太大。core文件的许可权(假定该文件在此之前并不存在)通常是用户读/,组读和其他读
  友情提醒:当环境当好后,可以使用在终端执行 “kill -11 应用程序PID”命令,然后查看是否回生成core文件。

3、使用gdb调试

  发生core dump之后, 用gdb进行查看core文件的内容, 以定位文件中引发段错误的行。如下:

gdb [exec file] [core file]
如: arm-none-linux-gnueabi-gdb queuetest core
执行结果如下:
root@silent:/home/lianxi# arm-none-linux-gnueabi-gdb queuetest core
GNU gdb (Sourcery G++ Lite 2009q1-203) 6.8.50.20081022-cvs
Copyright (C) 2008 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "--host=i686-pc-linux-gnu --target=arm-none-linux-gnueabi".
For bug reporting instructions, please see:
<https://support.codesourcery.com/GNUToolchain/>...
Error while mapping shared library sections:
lib/libdl.so.2: No such file or directory.
Error while mapping shared library sections:
lib/libgcc_s.so.1: No such file or directory.
Error while mapping shared library sections:
lib/libc.so.6: No such file or directory.
Error while mapping shared library sections:
lib/ld-linux.so.3: No such file or directory.
Symbol file not found for /lib/libdl.so.2
Symbol file not found for /lib/libgcc_s.so.1
Symbol file not found for /lib/libc.so.6
Symbol file not found for /lib/ld-linux.so.3

warning: Unable to find dynamic linker.
GDB will be unable to debug shared library initializers
and track explicitly loaded dynamic code.
Core was generated by `./queuetest'.
Program terminated with signal 11, Segmentation fault.
#0  0x00008548 in main (argc=1, argv=0xbeb26e24) at main.c:38
38      printf("ptr = %d\n", *ptr);
(gdb) where
#0  0x00008548 in main (argc=1, argv=0xbeb26e24) at main.c:38

  gdb中键入where,就会看到程序崩溃时堆栈信息(当前函数之前的所有已调用函数的列表),显然错误出现main.c:38中。
  但往往调试没这么简单,所以还得记住几个常用的gdb命令,结合查看分析
  bt 查看堆栈信息
  bt full 完全显示函数之间相互调用时传递的参数值和函数的内部变量值
  where 显示在哪儿down掉
  info locals 显示目前的区域参数
  info threads 显示当前可调试的所有线程,每个线程会有一个gdb为其分配的ID,后面操作线程的时候会用这个ID,前面有*的是当前调试的线程。
  thread id 切换当前调试的线程为指定ID的线程
  list 往下列出代码
  info frame 查看桢的详细信息
  thread apply all command 让所有被调试线程执行gdb命令command
  x/nfu 查看内存信息

  注:在交叉编译环境中,经常发现库找不到的情况,这是因为没有指定库路径的原因。可以通过以下两个命令设置。

set solib-absolute-prefix 路径
set solib-search-path  路径
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值