上一章我们介绍了 core dump 产生的基本原理。本章我们将针对 AIX 操作系统,介绍 core dump 定位相关的背景知识。
可以通过 /etc/security/limits 文件对各用户的基本配置参数包括 core 大小进行限制。或者通过 ulimit 更改当前环境下的 core 大小限制。
默认情况下,应用进程生成 core dump 时都使用文件名 core。为了避免同一工作目录下的进程 core 相互覆盖,可以定义环境变量 CORE_NAMING=true,然后启动进程,这样将生成名为 core.pid.ddhhmmss 的文件。可以使用 file core 命令查看 core 是哪个进程产生的。
默认情况下,应用进程 dump 时会包含所有的共享内存,如果 dump 时想排除共享内存内容,可以在启动进程之前设置环境变量 CORE_NOSHM=true.
系统有一个参数 fullcore 用于控制是否在程序 coredump 时生成完整的 core。为避免信息丢失,建议打开 fullcore。可以使用 lsattr –El sys0 查询是否将 fullcore 打开,使用 chdev -l sys0 -a fullcore=true 将 fullcore 状态更改为打开。也可以在程序内部调用 sigaction 例程设置 fullcore,参考如下测试程序:
//test.C #include <iostream> #include <signal.h> int main(int argc, char* argv[]) { char str[10]; struct sigaction s; s.sa_handler = SIG_DFL; s.sa_mask.losigs = 0; s.sa_mask.hisigs = 0; s.sa_flags = SA_FULLDUMP; sigaction(SIGSEGV,&s,(struct sigaction *) NULL); std::cout << " input str!/n" << std::endl; std::cin >> str; return 0; } |
应用进程的 core 产生在其当前工作目录下,可以在应用程序内部使用 chdir 函数切换当前工作目录。使用 procwdx 命令可以查看进程的当前工作目录。系统的 core 生成在 lg_dumplv 下,并在重启时转移到 /var/adm/ras/ 目录下(如果有足够空间的话,否则继续保留在 lg_dumplv,并随时有可能被覆盖)。
可以使用 errpt -a 查看标识 C0AA5338 SYSDUMP(系统 core)、B6048838 CORE_DUMP(进程 core)的详细错误信息,获取生成 core 的进程以及 core 文件位置。使用 snap –ac 收集系统的 dump 信息。
如果可能 , 直接在发生 coredump 的机器上用 dbx 分析出结果 , 这样是最方便的分析方法 . 这种情况下注意不要直接以 root 用户登录然后用 dbx 分析 , 而必须在应用程序所属的用户下进行此操作 , 因为 core 可能需要依赖应用程序运行时对应环境下的某些库 , 这样就要借助应用程序的环境变量 .
如果需取回生产机上的 core 信息在实验室分析 , 则需要搜集一些相关信息 . 进程 core 分析一般至少需要依赖应用可执行程序,有时还需要包括一些运行时动态库信息。如果需要收集 core 相关的完整信息,可运行 snapcore <core 路径以及名称 > < 可执行文件以及名称 >,例如 snapcore ./core ./a.out,然后在 /tmp/snapcore 下取下相应的 .pax.Z 文件。
正常的收集过程应该如下 :
# snapcore ./core ./a.out Core file "./core" created by "a.out" pass1() in progress .... Calculating space required . Total space required is 14130 kbytes .. Checking for available space ... Available space is 807572 kbytes pass1 complete. pass2() in progress .... Collecting fileset information . Collecting error report of CORE_DUMP errors .. Creating readme file .. Creating archive file ... Compressing archive file .... pass2 completed. Snapcore completed successfully. Archive created in /tmp/snapcore. # cd /tmp/snapcore # ls snapcore_352276.pax.Z # uncompress snapcore_352276.pax.Z # ls snapcore_352276.pax # pax -r -f snapcore_352276.pax # ls 注意需要保证有类似如下文件 ( 可执行文件,/core/errpt/lslpp/usr 目录等 ): README errpt.out usr a.out lslpp.out core snapcore_352276.pax # |
dbx 是 AIX 下基于命令行界面的源码级调试工具。本文档只提供一些基本的 dbx 分析指令,详细内容请参考“General Programming Concepts: Writing and Debugging Programs”关于 dbx 的描述。
#dbx <program name> core |
示例:
# dbx ./test core Type 'help' for help. warning: The core file is not a fullcore. Some info may not be available. [using memory image in core] reading symbolic information ...warning: no source compiled with -g Segmentation fault in raise at 0xd022e1e4 0xd022e1e4 (raise+0x40) 80410014 lwz r2,0x14(r1) |
显示出 core 发生时,当前进程执行到的位置(-g 编译的情况下能够看到具体的行):
(dbx) where raise(??) at 0xd022e1e4 main(0x1, 0x2ff22d48) at 0x100019c4 |
注意:
如果分析的是异地 core 文件,需要采用 snapcore 收集相关 core 信息。对于依赖链接库的情况,注意需要增加 -p oldpath=newpath:...
重新设置链接库路径(只有所有依赖的库都已经被链接,才能完整的复现 core dump 故障现场),参考 dbx 的帮助文档获取更多信息。
# cd /tmp/snapcore # dbx –p /=./ a.out core Type 'help' for help. [using memory image in core] reading symbolic information ...warning: no source compiled with -g IOT/Abort trap in raise at 0xd01f4f60 0xd01f4f60 (raise+0x40) 80410014 lwz r2,0x14(r1) |
列举源码信息
列举程序源码(list,需要在运行 dbx 命令时使用 -I 指明源码搜索路径,并使用 -g 编译)或者汇编码(listi):
(dbx) listi main 0x10001924 (main) 7c0802a6 mflr r0 0x10001928 (main+0x4) bfa1fff4 stmw r29,-12(r1) 0x1000192c (main+0x8) 90010008 stw r0,0x8(r1) 0x10001930 (main+0xc) 9421ffa0 stwu r1,-96(r1) 0x10001934 (main+0x10) 83e20064 lwz r31,0x64(r2) 0x10001938 (main+0x14) 90610078 stw r3,0x78(r1) 0x1000193c (main+0x18) 9081007c stw r4,0x7c(r1) 0x10001940 (main+0x1c) 83a20068 lwz r29,0x68(r2) |
列举变量内容
示例代码:
#include <iostream> #include <signal.h> int g_test =0; int testfunc(int ¶) { para++; return 0; } int main(int argc, char* argv[]) { struct sigaction s; s.sa_handler = SIG_DFL; s.sa_mask.losigs = 0; s.sa_mask.hisigs = 0; s.sa_flags = SA_FULLDUMP; sigaction(SIGSEGV,&s,(struct sigaction *) NULL); char str[10]; g_test =0; testfunc(g_test); abort(); } # xlC test.C -g |
以全局变量 g_test 举例:
#print g_test 显示 g_test 的取值
#print sizeof(g_test) 显示 g_test 的大小
#whatis g_test 显示 g_test 的类型
#print &g_test 显示 g_test 的地址
#&g_test/16x 显示从 g_test 的地址开始处,连续 16 个 WORD(?byte)的取值
如果没有使用 -g 编译,则不能动态获取 g_test 的类型、大小等信息,但能够得到 g_test 的地址,并查询该地址所在区域存储空间的值。
例如:
# ./a.out IOT/Abort trap(coredump) # dbx ./a.out core Type 'help' for help. [using memory image in core] reading symbolic information ... IOT/Abort trap in raise at 0xd03365bc 0xd03365bc (raise+0x40) 80410014 lwz r2,0x14(r1) (dbx) print g_test 1 (dbx) whatis g_test int g_test; (dbx) print sizeof(g_test) 4 (dbx) print &g_test 0x20000428 (dbx) &g_test/16x 0x20000428: 0000 0001 0000 0000 0000 0000 0000 0000 0x20000438: 0000 0000 0000 0000 0000 0000 0000 0000 |
列举寄存器内容
列举寄存器内容:
(dbx) registers
如下模拟一个简单的 core dump,对 0 地址赋值引发 core dump 的问题:
# dbx ./a.out core Type 'help' for help. warning: The core file is not a fullcore. Some info may not be available. [using memory image in core] reading symbolic information ...warning: no source compiled with -g Segmentation fault in main at 0x10000348 0x10000348 (main+0x18) 90640000 stw r3,0x0(r4) (dbx) where main(0x1, 0x2ff22ccc) at 0x10000348 (dbx) registers $r0:0x00000000 $stkp:0x2ff22bf0 $toc:0x20000414 $r3:0x00000012 $r4:0x00000000 $r5:0x2ff22cd4 $r6:0xdeadbeef $r7:0x2ff22ff8 $r8:0x00000000 $r9:0x04030000 $r10:0xf0577538 $r11:0xdeadbeef $r12:0xdeadbeef $r13:0xdeadbeef $r14:0x00000001 $r15:0x2ff22ccc $r16:0x2ff22cd4 $r17:0x00000000 $r18:0xdeadbeef $r19:0xdeadbeef $r20:0xdeadbeef $r21:0xdeadbeef $r22:0xdeadbeef $r23:0xdeadbeef $r24:0xdeadbeef $r25:0xdeadbeef $r26:0xdeadbeef $r27:0xdeadbeef $r28:0xdeadbeef $r29:0xdeadbeef $r30:0xdeadbeef $r31:0xdeadbeef $iar:0x10000348 $msr:0x0000d0b2 $cr:0x22282489 $link:0x100001b4 $ctr:0xdeadbeef $xer:0x20000020 Condition status = 0:e 1:e 2:e 3:l 4:e 5:g 6:l 7:lo [unset $noflregs to view floating point registers] [unset $novregs to view vector registers] in main at 0x10000348 0x10000348 (main+0x18) 90640000 stw r3,0x0(r4) (dbx) print $r3 0x00000012 (dbx) print $r4 (nil) |
这个例子比较简单,从最后汇编指令“stw r3,0x0(r4)”就可以简单的看到程序 core dump 是因为向 0 地址(0+r4)存入 18(r3 寄存器值)造成。
查看多线程相关信息
如果以下环境变量采用默认的 OFF 值,则系统会完全禁止适当的调试列表,这意味着 dbx 命令将显示不出任何对象:
AIXTHREAD_MUTEX_DEBUG
AIXTHREAD_COND_DEBUG
AIXTHREAD_RWLOCK_DEBUG
可以使用
export AIXTHREAD_MUTEX_DEBUG=ON
打开 AIXTHREAD_MUTEX_DEBUG。
- 查看线程信息
(dbx) print $t1 // 打印 t1 线程的基本信息
(dbx) attribute
(dbx) condition
(dbx) mutex
(dbx) rwlock
(dbx) thread
例如:
(thread_id = 1, state_u = 4, priority = 60, policy = other, attributes = 0x20001078)
- 切换当前线程(默认当前线程为收到 core 触发信号所在线程)
(dbx) thread current [tid]
例如(> 表明 core dump 时的当前线程):
(dbx)thread thread state-k wchan state-u k-tid mode held scope function $t1 wait 0x31bbb558 running 10321 k no pro _ptrgl $t2 wait 0x311fb958 running 6275 k no pro _ptrgl >$t3 run running 6985 k no pro _p_nsleep $t4 wait 0x31bbbb18 running 6571 k no pro _ptrgl $t5 wait 0x311fb9d8 running 7999 k no pro _ptrgl $t6 wait 0x31bf8f98 running 8257 k no pro _ptrgl $t7 wait 0x311fba18 running 8515 k no pro _ptrgl $t8 wait 0x311fb7d8 running 8773 k no pro _ptrgl $t9 wait 0x311fbb18 running 9031 k no pro _ptrgl $t10 wait 0x311fb898 running 9547 k no pro _ptrgl $t11 wait 0x311fb818 running 9805 k no pro _ptrgl $t12 wait 0x311fba58 running 10063 k no pro _ptrgl $t13 wait 0x311fb8d8 running 10579 k no pro _ptrgl (dbx) thread current 3 (dbx) where _p_nsleep(??, ??) at 0xd005f740 raise.nsleep(??, ??) at 0xd022de3c sleep(??) at 0xd0260344 helper(??) at 0x100005ac (dbx) thread current 4 warning: Thread is in kernel mode, not all registers can be accessed. (dbx) where ptrgl._ptrgl() at 0xd020e470 raise.nsleep(??, ??) at 0xd022de3c raise.nsleep(??, ??) at 0xd022de3c sleep(??) at 0xd0260344 helper(??) at 0x100005ac (dbx)
core dump 分析的局限性
不要期待能依赖 core dump 分析解决所有的问题,下面是一个简单的模拟缓冲区溢出的例子,在这个例子中由于缓冲区溢出覆盖了调用栈信息,从而完全丢失了定位依据:
root@/tmp#>xlC test.C -g -o test2 root@/tmp#> root@/tmp#>./test input str! 012345678901234567890123456789 Segmentation fault(coredump) root@/tmp#>dbx ./test2 core Type 'help' for help. [using memory image in core] reading symbolic information ... Segmentation fault in test2. at 0x34353634 0x34353634 (???) warning: Unable to access address 0x34353634 from core (dbx) where warning: Unable to access address 0x34353634 from core warning: Unable to access address 0x34353634 from core warning: Unable to access address 0x34353630 from core warning: Unable to access address 0x34353630 from core warning: Unable to access address 0x34353634 from core warning: Unable to access address 0x34353634 from core warning: Unable to access address 0x34353630 from core warning: Unable to access address 0x34353630 from core warning: Unable to access address 0x34353634 from core warning: Unable to access address 0x36373841 from core test2.() at 0x34353634 warning: Unable to access address 0x36373839 from core warning: Unable to access address 0x36373839 from core (dbx) |
可以通过“sysdumpdev –l”查看系统当前的 dump 配置信息:
root@/#>sysdumpdev -l primary /dev/hd6 secondary /dev/sysdumpnull copy directory /var/adm/ras forced copy flag TRUE always allow dump FALSE dump compression ON |
注意旧版本的 AIX “always allow dump”可能默认为关闭;为方便系统 crash 时问题定位,建议打开,可使用命令 sysdumpdev –K 或者使用 smitty -> System Environments-> Change / Show Characteristics of System Dump 菜单设置。
sysdumpdev –L 获得最近系统产生的 dump 的相关统计信息:
#>sysdumpdev -L 0453-039 Device name: /dev/hd6 Major device number: 10 Minor device number: 2 Size: 18885120 bytes Uncompressed Size: 113724523 bytes Date/Time: Sat Jul 21 14:20:22 BEIST 2007 Dump status: 0 dump completed successfully Dump copy filename: /var/adm/ras/vmcore.2.Z |
为保证系统出现 crash 时,dump device 能够保存下 dump 信息,需要合理的配置 dump device 的大小,可以使用 sysdumpdev –e 估计系统 dump 需要的空间。一般推荐的 dump device 值大小为 sysdumpdev –e 估计值的 1.5 倍。
本文档只提供一些基本的 dump 分析指令,详细内容请参考“KDB kernel debugger and kdb command ”。
初步分析
kdb 对 dump 文件分析需要借助于产生 dump 的内核文件 /unix,一般 snap –ac 会对此文件进行收集。初步命令如下:
#kdb ./dump ./unix
示例:
#kdb ./dump ./unix The specified kernel file is a 64-bit kernel ./dump mapped from @ 700000000000000 to @ 70000007da53bd5 Preserving 1317350 bytes of symbol table First symbol __mulh Component Names: 1) minidump [2 entries] 2) dmp_minimal [9 entries] 3) proc [481 entries] 4) thrd [1539 entries] 5) rasct [1 entries] 6) ldr [2 entries] 7) errlg [3 entries] 8) mtrc [26 entries] 9) lfs [1 entries] 10) bos [2 entries] 11) ipc [7 entries] 12) vmm [13 entries] 13) alloc_kheap [256 entries] 14) alloc_other [26 entries] 15) rtastrc [8 entries] 16) efcdd [20 entries] 17) eidedd [1 entries] 18) sisraid [2 entries] 19) aixpcm [5 entries] 20) scdisk [11 entries] 21) lvm [2 entries] 22) jfs2 [1 entries] 23) tty [4 entries] 24) netstat [10 entries] 25) goent_dd [7 entries] 26) scsidisk [11 entries] 27) efscsi [5 entries] 28) dump_statistics [1 entries] Component Dump Table has 2456 entries START END <name> 0000000000001000 0000000003BBA050 start+000FD8 F00000002FF47600 F00000002FFDC920 __ublock+000000 000000002FF22FF4 000000002FF22FF8 environ+000000 000000002FF22FF8 000000002FF22FFC errno+000000 F100070F00000000 F100070F10000000 pvproc+000000 F100070F10000000 F100070F18000000 pvthread+000000 PFT: PVT: id....................0002 raddr.....0000000000686000 eaddr.....F200800030000000 size..............00040000 align.............00001000 valid..1 ros....0 fixlmb.1 seg....0 wimg...2 Dump analysis on CHRP_SMP_PCI POWER_PC POWER_5 machine with 8 available CPU(s) (64-bit registers) Processing symbol table... .......................done |
分析命令示例
status 查看各个 CPU 在 dump 时正在运行的进程,如:
0)> status CPU TID TSLOT PID PSLOT PROC_NAME 0 2580F5 600 14C0F6 332 cron 1 12025 18 D01A 13 wait 2 1020BB 258 1580C6 344 expr 3 1502B 21 F01E 15 wait |
cpu <id> 命令切换当前 CPU,默认的当前 CPU 为 cpu0:
(0)> cpu 1
(1)>
打印系统的基本状态和相关信息:
(0)> stat
打印系统 dump 时内核栈的情况:
(0)> f
lke 用来列出内核代码对应的相关系统文件信息:
(0)> lke 003DE9CC
显示系统 dump 时最后所在的指令:
(0)> dr iar
显示虚拟存储管理的日志信息;其中 Exception value 若为 0000001C 则表示 pagingspace 耗尽:
(0)> vmlog
显示进程表的信息:
(0)> proc
显示线程表的信息:
(0)> th
显示系统的 errpt 信息:
(0)> errpt
ERRORS NOT READ BY ERRDEMON (ORDERED CHRONOLOGICALLY): Error Record: erec_flags .............. 1 erec_len ................ 54 erec_timestamp .......... 46DCDD9D erec_rec_len ............ 34 erec_dupcount ........... 0 erec_duptime1 ........... 0 erec_duptime2 ........... 0 erec_rec.error_id ....... DD11B4AF erec_rec.resource_name .. SYSPROC 00007FFF FFFFD000 00000000 003DE9CC .............=.. 00000000 00020000 80000000 000290B2 ................ |
本文简单介绍了 core dump 相关的背景知识以及 AIX 上调试 core dump 的一些基本方法。通过阅读这篇文章,希望您能对 AIX 下 core dump 机制有所了解,并能够借助 core dump 定位基本的系统以及应用程序问题。
- AIX Files Reference:这个参考为有经验的 AIX 开发人员提供了对操作系统重要文件的全面的、详细的描述信息。
- General Programming Concepts: Writing and Debugging Programs:本书为开发人员提供了在 AIX 上开发应用程序所需要知道的几乎所有的信息。
- KDB kernel debugger and kdb command:本书介绍了如何使用 KDB 内核调试器以及 kdb 命令来对 AIX 上的程序进行调试。
- AIX and UNIX 专区:developerWorks 的“AIX and UNIX 专区”提供了大量与 AIX 系统管理的所有方面相关的信息,您可以利用它们来扩展自己的 UNIX 技能。
- AIX and UNIX 新手入门:访问“AIX and UNIX 新手入门”页面可了解更多关于 AIX 和 UNIX 的内容。
- AIX and UNIX 专题汇总:AIX and UNIX 专区已经为您推出了很多的技术专题,为您总结了很多热门的知识点。我们在后面还会继续推出很多相关的热门专题给您,为了方便您的访问,我们在这里为你把本专区的所有专题进行汇总,让您更方便的找到你需要的内容。
- AIX Wiki:发现 AIX 相关技术信息的协作环境。