How do you read a segfault kernel log message
这是一个非常简单的问题,我正在尝试调试一个应用程序,它在
以下是我的问题:
是否有关于segfault上的差异错误号的文档,在本例中是错误6,但我看到了错误4、5
到目前为止,我能够用符号编译,当我执行
- sp=堆栈指针?
- IP=指令指针
- 在=?????
- myapp[8048000+24000]=符号地址?
当报告指向程序而不是共享库时
运行
在
以下是字段的细分:
address —代码试图访问的内存中的位置(很可能10 和11 是我们希望设置为有效值的指针的偏移量,而不是指向0 )。ip —指令指针,即试图执行此操作的代码所在的位置。sp 堆栈指针error —特定于体系结构的标志;请参阅arch/*/mm/fault.c 了解您的平台。
基于我有限的知识,你的假设是正确的。
sp =堆栈指针ip =指令指针myapp[8048000+24000] =地址
如果我在调试问题,我会修改代码以生成核心转储,或者在崩溃时记录堆栈回溯。您也可以在(或附加)gdb下运行程序。
错误代码只是页面错误的体系结构错误代码,似乎是特定于体系结构的错误代码。它们通常记录在内核源代码的
- 位0==0表示找不到页面,1表示保护故障
- 位1==0表示读,1表示写
- 位2==0表示内核,1表示用户模式
我的
- 位3==1表示错误是指令获取
If it's a shared library
You're hosed, unfortunately; it's not possible to know where the
libraries were placed in memory by the dynamic linker after-the-fact.
嗯,仍然有可能检索信息,不是从二进制文件,而是从对象。但您需要对象的基地址。这些信息仍然在coredump中,在link-map结构中。
因此,首先要将结构链接图导入gdb。因此,让我们用调试符号编译一个程序,并将其添加到gdb中。
链接C
1 2 | #include <link.h> toto(){struct link_map * s = 0x400;} |
从u coredump.sh获取u baseaddru
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 | #!/bin/bash BINARY=$(which myapplication) IsBinPIE () { readelf -h $1|grep 'Type' |grep"EXEC">/dev/null || return 0 return 1 } Hex2Decimal () { export number="`echo"$1" | sed -e 's:^0[xX]::' | tr '[a-f]' '[A-F]'`" export number=`echo"ibase=16; $number" | bc` } GetBinaryLength () { if [ $# != 1 ]; then echo"Error, no argument provided" fi IsBinPIE $1 || (echo"ET_EXEC file, need a base_address"; exit 0) export totalsize=0 # Get PT_LOAD's size segment out of Program Header Table (ELF format) export sizes="$(readelf -l $1 |grep LOAD |awk '{print $6}'|tr ' ' ' ')" for size in $sizes do Hex2Decimal"$size"; export totalsize=$(expr $number + $totalsize); export totalsize=$(expr $number + $totalsize) done return $totalsize } if [ $# = 1 ]; then echo"Using binary $1" IsBinPIE $1 && (echo"NOT ET_EXEC, need a base_address..."; exit 0) BINARY=$1 fi gcc -g3 -fPIC -shared link.c -o link.so GOTADDR=$(readelf -S $BINARY|grep -E '\.got.plt[ \t]'|awk '{print $4}') echo"First do the following command :" echo file $BINARY echo add-symbol-file ./link.so 0x0 read echo"Now copy/paste the following into your gdb session with attached coredump" cat <<EOF set \$linkmapaddr = *(0x$GOTADDR + 4) set \$mylinkmap = (struct link_map *) \$linkmapaddr while (\$mylinkmap != 0) if (\$mylinkmap->l_addr) printf"add-symbol-file .%s %#.08x ", \$mylinkmap->l_name, \$mylinkmap->l_addr end set \$mylinkmap = \$mylinkmap->l_next end |
它将在一组gdb命令中打印整个链接映射内容。
它本身可能看起来不必要,但是使用我们所讨论的共享对象的基地址,您可以通过直接在另一个gdb实例中调试涉及的共享对象,从地址中获取更多信息。保持第一个gdb具有符号的idee。
注意:脚本相当不完整,我怀疑您可能会在添加符号文件的第二个参数中添加用此值打印的和:
1 | readelf -S $SO_PATH|grep -E '\.text[ \t]'|awk '{print $5}' |
其中$so_path是添加符号文件的第一个参数
希望它有帮助