2.5 DUMP和DUMP分析
没有完美无缺的系统,AIX和pSeries小型机尽管稳定可靠,系统也不可避免会出现严重的故障,DUMP就是帮助技术人员对系统发生的故障进行分析的专用功能。
2.5.1 DUMP的概念
为了增强故障分析能力,IBM的服务器增加了对设备故障当前环境保存的功能,就是保存一份设备故障时的内存、CPU寄存器、IO等设备的数据和状态信息,如果系统并没有停住,只是某个程序死掉,会产生CORE DUMP,在当前目录下产生一个CORE文件。而如果操作系统死掉,则产生System DUMP或者System Crash,通常会引起机器停机。DUMP将记录如图2-9所示。通过这些信息,开发和维护人员可以分析是什么原因导致的系统故障。当发生系统DUMP的时候,机器将会被宕下来。可能的原因包括:系统在进行内核操作时发生了未知的意外或者不能对其进行正常处理,都会引起DUMP。也可以由系统管理员发出命令,强制系统DUMP。
图2-9 系统和程序DUMP的内容
当系统进行DUMP时,DUMP管理设施自动将内核相关的数据(kernel segment0及其他由内核或者内核扩展程序记录在主DUMP表中的内存块)复制到主DUMP设备。可以把DUMP理解为系统当时的一个快照,供以后进行分析,分析DUMP可以在其他机器上进行,但需要复制一份此机器的内核程序,即unix_mp或unix_mp64。没有对应于DUMP的内核程序(不可以使用其他机器的文件,即使是相同的操作系统版本也不行)是无法进行DUMP分析的。
2.5.2 估计DUMP大小
由于DUMP是内存数据记录,而内存的使用量依据系统运行情况在改变,所以DUMP大小也随时改变。了解当前系统DUMP将会有多大可以通过如下命令:
# smit dump_estimate
或者直接执行命令行命令:
# sysdumpdev -e 0453-041 Estimated dump size in bytes: 850395136
了解了DUMP大小后需要创建足够大的主DUMP设备(一个逻辑卷)用来装载DUMP。在默认情况下,系统已经生成了DUMP设备,则需要查看DUMP空间是否足够:
#mklv -y dumplv -t sysdump rootvg 15 →在 rootvg 上创建 15 个 PP 大小的 DUMP 设备dumplv #sysdumpdev -s /dev/dumplv -P →设置主DUMP设备为/dev/dumplv primary /dev/dumplv secondary /dev/sysdumpnull copy directory /var/adm/ras forced copy flag FALSE always allow dump FALSE dump compression OFF
为了防止在主DUMP设备出问题的时候,无法保存DUMP,DUMP管理设施允许使用第二个DUMP设备:
#mklv -y hd7 -t sysdump rootvg 15 → 创建15个pp大小的DUMP设备,名为hd7 #sysdumpdev -s /dev/hd7 -p → 制定此设备为第二个DUMP设备 primary /dev/dumplv secondary /dev/hd7 copy directory /var/adm/ras forced copy flag FALSE always allow dump FALSE dump compression OFF
DUMP管理设施还允许将DUMP出来的数据在系统下一次启动后,复制到指定目录。默认目录地址是/var/adm/ras/为了防止复制的目录不够大,不能正确复制DUMP,所以要检查目录空间:
#df -k /var Filesystem 1024-blocks Free %Used Iused %Iused Mounted on /dev/hd9var 32768 31268 5% 143 64% /var
在本例里,/var文件系统的空间是32MB,如果想增加文件系统空间,可以执行下面的命令:
# chfs -asize=+240000 /var
设定copy目录:
# sysdumpdev -PD /var/adm/ras
当系统重新启动,在启动脚本文件rc.boot中包含如下内容:
# Mount /var for copycore echo "rc.boot: executing \"fsck -fp var\"" \ →检查var文件系统 >>/../tmp/boot_log fsck -fp /var echo "rc.boot: executing \"mount /var\"" \ >>/../tmp/boot_log mount /var →mount /var文件系统 [ $? -ne 0 ] && loopled 0x518 # retrieve dump echo "rc.boot: executing \"copycore\"" \ >>/../tmp/boot_log copycore →复制DUMP umount /var
当系统重新启动的时候,如果设置了force copy标志为TRUE,可以有提示让你将DUMP复制到外置介质,例如磁带。这样磁盘目录不够的时候,你也有机会保留(往往DUMP设备与系统交换区共用同一逻辑卷,而系统启动后,交换区将被覆盖)一份系统DUMP。
如果设置了另一个“总是允许DUMP”开关(TRUE),当按下服务器reset按钮或者预先设定的DUMP键盘序列的时候,系统自动生成DUMP。下面的命令设置此开关为TRUE:
# sysdumpdev -KP
如果想允许DUMP压缩存放,则用如下命令:
# sysdumpdev -CP
如果想让系统DUMP后自动重新启动(对于管理员远程管理比较有用,否则必须管理员到现场按开关重新启动计算机),可以执行下面命令:
# lsattr -El sys0 →显示是否自动重启动 SW_dist_intr false Enable SW distribution of interrupts autorestart true Automatically REBOOT system after a crash boottype disk N/A conslogin enable System Console Login cpuguard disable CPU Guard frequency 1097312280 System Bus Frequency fullcore false Enable full CORE dump fwversion IBM,2b304_430 Firmware version and revision levels id_to_partition 0X04514535A2CE4701 Partition ID id_to_system 0X04514535A2CE4700 System ID iostat false Continuously maintain DISK I/O history keylock normal State of system keylock at boot time maxbuf 20 Maximum number of pages in block I/O BUFFER maxmbuf 0 Maximum Kbytes of real memory allowed for MB maxpout 0 HIGH water mark for pending write I/Os per file maxuproc 128 Maximum number of PROCESSES allowed per user minpout 0 LOW water mark for pending write I/Os per file modelname IBM,8842-41X Machine name ncargs 6 ARG/ENV list size in 4K byte blocks pre430core false Use pre-430 style CORE dump pre520tune disable Pre-520 tuning compatibility mode realmem 2031616 Amount of usable physical memory in Kbytes rtasversion 1 Open Firmware RTAS version systemid IBM,0399GCA4N Hardware system identifier # smit chgsys 使用smit进行修改 # chdev -l sys0 -a autorestart='true' 使用命令进行修改
2.5.3 系统DUMP码分析
如果系统发生了DUMP,则首先机器会停下来,但是并没有关电源,只是键盘、鼠标、网络、终端(主控台连接的串口终端除外)没有任何反应;其次,在机器的液晶显示屏上不是正常的、没有任何提示(机器正常运行的时候)或者OK(机器关闭电源的时候),而是类似这样的一串数字:888 102 205 0c0。
代码含义简要说明如下。
第一段数字888:以888开头的表示都是DUMP。
第二段数字102:状态码Message Type。
第三段数字:叫做ABEND(原因)代码,一般是硬件故障。
000:用户生成的DUMP或者Surveillance Timeout(STO,看门狗电路监测到超时);
2xx:machine check,参考checkstop名词的介绍;
3xx:数据访问越界中断(DSI,Data Storage Interrupt);
400:指令访问越界中断(ISI,Instruction Storage Interrupt)
5xx:外部中断;
700:程序中断(指令陷阱或非法指令);
800:浮点异常。
第四段数字0cX:DUMP状态码。
Message Type 103,105
通常103,105都是由于硬件故障引起的DUMP,下面是检查103,105故障位置的步骤(如果你遇到102故障,也可以参考)。
(1)出现888-103-xxx-xxx提示后,按Reset钮(电源白色按钮旁边的黄点)记录下6位SRN的头三位。
(2)再次按Reset,记录下SRN的后3位。
(3)以后每次按Reset,会依次显示3位FRU位置代码,当所有的FRU位置代码都记录下后,液晶屏会再次显示888,表示信息结束;而如果显示的数字不是888而是ccc,则需要再次重复以上过程,继续接收信息。
(4)根据FRU显示的位置,按顺序查找此硬件是否有故障。
(5)FRU位置代码可以转换成8位的具体位置(AB-CD-EF-GH,关于位置代码的详细介绍,参考Physical Location Code一节/第四天),每行的每段xx,代表位置代码AB-CD-EF-GH中一位。
A B C D E F G H 8位的故障设备位置码
c01 1xx 2xx 3xx 4xx 5xx 6xx 7xx 8xx 第一可能的故障设备
c02 1xx 2xx 3xx 4xx 5xx 6xx 7xx 8xx 第二可能的故障设备
c03 1xx 2xx 3xx 4xx 5xx 6xx 7xx 8xx 第三可能的故障设备
c04 1xx 2xx 3xx 4xx 5xx 6xx 7xx 8xx 第四可能的故障设备
注意
如果没有按顺序显示c0x,而是ccx(x是2~9的数字),那么这表示是重复上次信息,跟着的位置代码不会是完整的8段,只会包含变化的内容,即只有不同的才会显示。例如:
c01 100 200 300 401 500 601 700 800,下一个FRU是:
cc2 602,则表示下一个FRU位置是:
cc2 100 200 300 401 500 602 700 800.(只有一段601,602不同)
位置代码翻译如表2-3所示。
表2-3 位置代码翻译
(6)如果记录完DUMP/FRU信息,下面要恢复系统,只有一种方法:将系统电源关闭,再重新开启。以后可以根据记录下来的FRU位置信息,进行硬件检查。
ABEND原因码
(1)2xx——Machine check
通常是硬件故障导致(例如内存错误),不过也有可能来自原软件原因(例如内核访问不存在的物理地址)。其中:
200 Machine check because of a memory bus error. 内存总线错误。
201 Machine check because of a memory timeout. 内存访问超时。
202 Machine check because of a memory card failure. 内存卡故障。
203 Machine check because of a out of range address. 内存访问越界(读写不存在的物理地址)。
204 Machine check because of an attempt to write to ROS. 试图写只读的内存地址。
205 Machine check because of an uncorrectable address parity. 不可恢复的地址校验错误(通常2位地址为以上的错误)。
206 Machine check because of an uncorrectable ECC error. 不可恢复ECC校验错误。
207 Machine check because of an unidentified error. 未知错误类型。
208 Machine check due to an L2 uncorrectable ECC. L2缓存不可恢复的ECC错误。
(2)3xx——DSI
当程序访问的虚拟内存并没有在物理内存中的时候,就会产生DSI(Data Storage Interrupt数据存储访问中断),被称为内存页访问失败(page fault),内存页访问失败是正常现象,随时都可能发生。然而如果内存页访问失败不能被解决(从磁盘交换区将此虚拟内存读入物理内存),则会导致DSI System Crash,软件和硬件故障都可能引起DSI Dump。其中:
300 Data storage interrupt from the processor. 更可能是CPU问题
32x Data storage interrupt because of an I/O exception from IOCC.更可能是I/O设备
38x Data storage interrupt because of an I/O exception from SLA.数据地址错误
(3)400——ISI
与DSI类似,如果等待执行的指令不在虚拟内存,则产生ISI(Instruct Storage Interrupt指令存储中断),ISI没能够恢复或者此时禁止了中断(无法产生中断,由此磁盘将交换区数据读入物理内存),则产生ISI Dump。
(4)5xx——外部中断
这种DUMP来自于外部设备的中断,例如I/O总线控制器。
500 External interrupt because of a scrub memory bus error. 内存总线故障。
501 External interrupt because of an unidentified error. 未知错误。
51x External interrupt because of a DMA memory bus error. DMA内存总线错误。
52x External interrupt because of an IOCC channel check. I/O控制通道异常。
53x External interrupt from an IOCC bus timeout; x represents the IOCC number. I/O控制通道使用超时,x位代表I/O控制通道号。
54x External interrupt because of an IOCC keyboard check. 收到I/O控制通道强制检查请求。
558 There is not enough memory to continue the IPL. 启动的时候没有足够内存。
(5)600——Alignment中断
600 Alignment Interrupt, If pre-AIX 4.3.3.3: AIX has crashed because the Portability Assist Layer(PAL)for this machine type has detected a problem. 如果是AIX 433以前版本,可能是由于操作系统不支持此硬件设备,或者是微码问题。
605 AIX has crashed because the Portability Assist Layer (PAL) for this machine type has detected a problem(AIX 4.3.3.3 and above)类似600的故障。
(6)700——程序中断
此类故障的直接原因是当程序进入内核调用执行的时候,遇到不能解决的问题,就调用内核的一个叫做panic的例程。这个例程进行如下处理:
如果内核debug模式打开,并且串口连接了一个字符终端,则系统进入debug状态。否则系统挂起,并产生System DUMP。
内核调用panic例程的同时还会产生panic信息,此信息一方面送给debug终端,另一方面送给errlog,如果系统能成功生成DUMP,panic message还会记录到DUMP中。
(7)800——浮点异常
当MSR(machine status register)标记浮点运算不可用的时候遇到浮点指令。
DUMP状态码
0c0——DUMP成功完成。
0c1——DUMP过程中出现I/O问题(空间无法写入、设备故障等),DUMP失败。
0c2——由用户要求的DUMP正在生成。
0c3——DUMP被禁止。
0c4——DUMP设备空间不够。
0c5——DUMP没有开始或者失败。
0c6——由用户要求,DUMP到第二个DUMP设备。
0c7——DUMP等待从NFS服务器的返回信息(DUMP到NFS服务器)。
0c8——没有DUMP设备。
0c9——DUMP正在进行中。
0cc——DUMP到主设备失败,正在向第二个DUMP设备复制DUMP。
简单DUMP分析
显示最近一次DUMP状态:
# sysdumpdev -L 0453-039 Device name: /dev/dumplv →DUMP设备名 Major device number: 10 Minor device number: 2 Size: 8837632 bytes →压缩后大小 Uncompressed Size: 32900935 bytes →未压缩大小 Date/Time: Fri Sep 22 13:01:41 PDT 2000 →生成时间 Dump status: 0 dump completed successfully →DUMP正常生成 Dump copy filename: /var/adm/ras/vmcore.0.Z →存在DUMP,文件是vmcore.0.Z
解压缩DUMP数据:
# cd /var/adm/ras # uncompress vmcore.0.Z
启动内核debug程序(在同一台机器分析DUMP):
# kdb /var/adm/ras/vmcore.0 The specified kernel file is a UP kernel vmcore.1 mapped from @ 70000000 to @ 71fdba81 Preserving 880793 bytes of symbol table First symbol __mulh KERNEXT FUNCTION NAME CACHE (90112 bytes) allocated KERNEXT COMMANDS SPACE (4096 bytes) allocated Component Names: 1) dmp_minimal [5 entries] . . . . Dump analysis on CHRP_UP_PCI POWER_PC POWER_604 machine with 1 cpu(s) (32-bit registers) Processing symbol table... .......................done (0)>
启动内核debug程序(在不同机器分析DUMP):
# kdb -m dump_file -u /usr/lib/boot/unix The specified kernel file is a 64-bit kernel core mapped from @ 700000000000000 to @ 7000000000120a7 Preserving 884137 bytes of symbol table First symbol __mulh KERNEXT FUNCTION NAME CACHE (90112 bytes) allocated KERNEXT COMMANDS SPACE (8192 bytes) allocated Component Dump Table not found. Kernel not included in this dump. dump core corrupted make sure /usr/lib/boot/unix refers to the running kernel
注意
以上错误的含义是DUMP所在机器的内核与指定的内核程序(/usr/lib/boot/unix)不一致,无法分析。因此为了在其他机器上进行DUMP分析,不但需要DUMP文件,还需要保留此机器内核文件:/unix(因为/unix一般是一个链接文件,要复制其链接的源文件而不是链接)。
(0)> stat → 显示DUMP当时系统状态 SYSTEM_CONFIGURATION: CHRP_UP_PCI POWER_PC POWER_604 machine with 1 cpu(s) (32-bit registers) SYSTEM STATUS: sysname... AIX nodename.. garbagepig release... 1 version... 5 → 操作系统版本 machine... 000931134C00 nid....... 0931134C time of crash: Mon Oct 4 14∶14∶14 2004 →DUMP时间 age of system: 3 min., 11 sec. xmalloc debug: disabled abend code: 300 → DUMP ABEND代码 csa: 0x2ff3b400 exception struct: dar: 0x00000000 dsisr: 0x00000000: srv: 0x00000000 dar2: 0x0000000 dsirr: 0x00000000: (errno) "Error 0" > t -mk →堆栈跟踪命令 Skipping first MST MST STACK TRACE: 0x2ff3b400 (excpt=00000018:0a000000:00000000:00000018:00000106) (intpri=3) IAR: .so_pin_more_stack+3c (000a6808): stw r3,0x18(r4) LR: .so_pin_more_stack+38 (000a6804) 2ff3b220: .soaccept+84 (000d75f8) 2ff3b290: .sodequeue+228 (000d7490) 2ff3b300: .accept1+3a8 (000d6fcc) 2ff3b380: .naccept+14 (000db2c0) 2ff3b3c0: .sys_call_ret+0 (00003a90) 00009032: .nbc_min_cache_init+4c (000c7d10) 00008001: .low+0 (00000000) (0) > cpu →显示可切换的CPU信息 0 1 (0) > cpu 1 →转到第一颗CPU(原来是由第0颗CPU) (1) > status →显示正在执行的线程(2颗CPU,两个线程) CPU TID TSLOT PID PSLOT PROC_NAME 0 205 2 204 2 wait 1 5819 88 2CA0 44 kdb_mp (1) > th * →显示第一颗CPU处理的全部线程 …… (1) > p * →显示第一颗CPU处理的全部进程 …… (1) >p * -s ACTIVE → 显示所有活动进程 SLOT NAME STATE PID PPID ADSPACE CL #THS pvproc+000000 0 swapper ACTIVE 0000000 0000000 0000000000000B00 0 0001 pvproc+000280 1 init ACTIVE 0000001 0000000 000000000000E2FD 0 0001 pvproc+000500 2 wait ACTIVE 0000204 0000000 0000000000001B02 0 0001 pvproc+000780 3 wait ACTIVE 0000306 0000000 0000000000002B04 0 0001 pvproc+000A00 4 lrud ACTIVE 0000408 0000000 0000000000003B06 65 0001 pvproc+000C80 5 xmgc ACTIVE 000050A 0000000 000000000000BB16 65 0001 pvproc+000F00 6 netm ACTIVE 000060C 0000000 000000000000CB18 65 0001 pvproc+001180 7 gil ACTIVE 000070E 0000000 000000000000DB1A 65 0005 (1)> f →显示堆栈跟踪 pvthread+004900 STACK: [00034648].panic_trap+000000 () → 推断原因,系统panic [021DCCC4]Duck+000018 () [021DCCC4]Duck+000018 () [021DCC7C]Daffy+000020 (00000001, 2FF3AB10) [0055E9E8]config_kmod+00016C (??, ??, ??) [0055EDCC]sysconfig+0000F8 (??, ??, ??) [00003A50].sys_call+000000 () →导致系统panic的指令在这个位置 地址 例程 偏移量 [kdb_get_memory] no real storage @ 2FF22B68 (0) > q →退出
如果程序在编译的时候使用了附加源程序信息,则此时显示的内容将会提供详细的例程名,便于查找。但不幸的是几乎所有的程序(包括AIX系统)都不会在编译的时候附加源文件,所以要想进一步查看信息只能凭自己的经验进行反汇编了。
2.5.4 CORE DUMP
CORE DUMP只是某个程序故障,相对比较简单,可以直接用dbx等底层代码调试工具进行分析。下面一个小程序可以简单地对core文件进行分析:
#include <stdio.h> #include <sys/core.h> void main(int argc, char *argv[]) { FILE *corefile; struct core_dumpx c_file; char command[256]; if (argc != 2) { fprintf(stderr, "Usage: %s <corefile>\n", *argv); exit(1); } if ((corefile = fopen(argv[1], "r")) == NULL) { perror(argv[1]); exit(1); } fread(&c_file, sizeof(c_file), 1, corefile); fclose(corefile); sprintf(command, "lquerypv -h %s 6E0 64 | head -1 | awk '{print $6}'", argv[1]); printf("Core created by: \n"); system(command); printf("Signal number and cause of error number: %i\n", c_file. c_signo); printf("Core file type: %i\n", c_file.c_flag); printf("Number of core dump modules: %i\n", c_file.c_entries); printf("Core file format number: %i\n", c_file.c_version); printf("Thread identifier: %i\n", c_file.c_flt.th.ti_tid); printf("Process identifier: %i\n", c_file.c_flt.th.ti_pid); printf("Current effective priority: %i\n", c_file.c_flt.th.ti_pri); printf("Processor Usage: %i\n", c_file.c_flt.th.ti_cpu); printf("Processor bound to: cpu%i\n", c_file.c_flt.th.ti_cpuid); if (c_file.c_flt.th.ti_cpu>1) printf("Last Processor: cpu%i\n", c_file.c_flt.th.ti_affinity); exit(0); }