对于基本的转储分析,本文最关注的是转储映像。 在这里,我们介绍了如何从snap包中提取适当的文件,然后说明了一种有条理的方法来检查转储,并找出导致系统崩溃的根本原因。 转储文件和UNIX®文件位于snap软件包的转储子目录中。
尽管我们主要关注转储映像,但需要注意的是,当与适当的选项一起使用时,快照可以为您提供有用的信息。 有关其他信息,请参见本文的“ 常规”和“ 内核”小节。
一般
该常规目录包含有关系统运行时环境的信息,例如:
- ODM数据的副本。
- 所有环境变量(例如PATH和TZ)。
- 数据收集的日期和时间。
- 系统上的实际内存量(bootinfo -r)。
- 列出所有已定义的调页空间。
- 列出所有已安装的文件集及其级别。
- 列出所有已安装的APAR。
- 设备属性(lsattr -El)。
- 系统VPD信息(lscfg -pv)。
- 上次转储的状态(sysdumpdev -L)。
核心
内核子目录包含有用的内核信息(进程和内存数据)。
- 数据收集的日期和时间
- Vmstat输出
- VMM可调信息(vmo -L)。
- 调度可调信息(schedo -L)。
- 与I / O相关的可调信息(ioo -L)。
- 环境变量。
- SRC信息(lssrc -a)。
- 进程信息(ps -ef和ps -leaf)。
- 设备驱动程序和方法的校验和。
提取快照包
pax命令用于从快照包中提取文件。
- 要查看快照包的内容,请键入:
# zcat snap.pax.Z | pax -v
- 要提取包的全部内容,请输入:
# zcat snap.pax.Z | pax -r
- 要仅提取转储,常规和内核子目录,请输入:
#uncompress snap.pax.Z #zcat snap.pax.Z | pax -r ./dump ./general ./kernel
什么是kdb?
kdb实用程序检查当前正在运行的系统的操作系统映像,并与IBM®AIX®内核紧密结合。 这是因为它需要了解内核使用的结构,以正确格式化系统转储映像中包含的信息。 kdb命令具有许多用于查看和格式化数据结构的子命令。
KDB-内核调试器
kdb是一个交互式内核调试器。 kdb允许用户控制内核代码(包括内核扩展和设备驱动程序)的执行,并观察和修改变量并注册。 它必须由特殊的启动映像来调用。
kdb是用于分析系统转储的工具/命令。 它用于系统转储的事后分析或监视正在运行的内核。
调用kdb
检查系统转储时,使用两个参数调用kdb。 第一个指定转储映像,第二个指定转储时系统上正在运行的内核的UNIX文件。 UNIX文件必须与转储映像匹配(即,是崩溃时正在运行的映像)。 如果不是,则kdb显示错误消息并退出。
# kdb [dump] [unix]
不带任何参数调用时,kdb会检查当前正在运行的系统的映像。
# kdb
获取转储状态
在转储映像上调用kdb时,首先要使用stat子命令检索基本转储状态:
图1.统计输出
kdb的stat子命令提供了有关我们正在查看的转储的信息。 除了日期,时间,版本和发行信息之外,我们还找到转储原因代码。
转储原因码
如果由于系统检测到问题而启动了转储,则stat子命令的输出将包含标题为CRASH INFORMATION的部分。
- 本部分输出的第一行列出了检测到导致转储例程被调用的问题的CPU(上一示例中的CPU 0)。
- 转储原因代码是显示在text:LED的错误代码旁边的数字的前三位。 在前面的示例中,“ CRASH INFORMATION”部分的第一行包含以下文本
error code for LEDs: 30000000
这意味着转储原因代码为300,表示DSI(数据存储中断)。
转储原因代码指示崩溃的根本原因。 崩溃最常显示原因码300、400和700。
原因码 | 描述 |
---|---|
2nn | 机器检查 |
3nn | 数据存储中断 |
400 | 指令存储中断 |
5nn | 外部中断 |
700 | 程序中断 |
800 | 浮动数据不可用 |
- 2nn机器检查。
机器检查原因码通常指示硬件问题(例如,内存不足)。
- 3nn数据存储中断(DSI)。
只要引用物理内存中当前未加载的虚拟地址,就会发生DSI(这是页面错误)。 页面错误始终发生。 它们通常由VMM处理,通常不会导致系统崩溃。 但是,如果在内核模式下无法解决页面错误,或者在禁用中断时发生页面错误,则DSI将导致系统崩溃。 根本原因通常是软件,但有时可能与硬件有关。
- 400指令存储中断(ISI)。
指令存储中断是指令提取时的页面错误。 这通常由VMM解决,并且通常不会导致系统崩溃。 如果VMM无法解决它,或者在禁用中断时发生页面错误,则系统将崩溃。
- 5nn-外部中断。
崩溃是由外部设备(例如I / O总线控制器)的中断引起的。
- 700个程序中断。
当内核例程调用陷阱指令时,会导致这种崩溃。 通常,这是从对紧急内核服务的调用或从失败的断言引起的。 当内核例程遇到无法解决的问题时,它将调用panic。 最终原因经常是软件,但也可能与硬件有关。
- 800浮点数不可用。
当MSR(机器状态寄存器)中的浮点可用位被禁用时,试图执行浮点指令。
初始CPU上下文
kdb总是在运行崩溃线程的CPU上下文中启动。 当我们调用kdb时,提示显示为: (n)>>
,其中n是指示当前CPU上下文的数字。
但是,要将上下文更改为另一个CPU,请使用cpu子命令:
(0)>> cpu 1
(1)>>
MST(机器状态保存区域)
机器状态保存区或MST包含CPU进程上下文的已保存映像。 进程上下文包括通用寄存器,浮点寄存器,专用寄存器以及在分派线程时重新启动线程所需的其他信息。 CPU上的每个处理器都有自己的CSA(当前保存区域)指针,该指针指向由于上下文切换而中断或交换线程或中断处理程序时要使用的MST。 当线程处于活动状态时,运行该线程的处理器的CSA将指向当前活动线程的MST。
- MST中的字段之一是指向以前的MST(kdb中的prev)的指针。 该字段仅在中断上下文中填写。
图2. MST结构链表示中断历史
- mst子命令:
mst [ thread_slot | thread_table_address ]
提供指定线程的MST格式显示。 如果未指定地址,则显示当前处理器的MST区域。
图3. 64位内核上的mst子命令的输出
图4. 32位内核上的mst子命令的输出
mst子命令输出中的数据字段
- iar-指令地址寄存器。
包含故障指令的位置(用于故障MST)。 它是崩溃期间已执行的当前指令。
- 链接寄存器的lr值。
包含函数的返回地址。
- 例外-显示异常结构。
提供有关崩溃性质的信息。
- r0-r31显示通用寄存器的内容。
- intpri-指示中断优先级。
指示处理器是否在禁用中断的情况下运行。
- prev-如果值为零。
MST代表在处理器上运行的基本级线程。 如果该值不为零,则说明处理器正在处理中断。 上一个字段指向链中下一个MST结构。
prev和intpri字段中的值有助于确定处理器是运行线程还是中断处理程序。
当CPU运行线程时,该线程可以在进程上下文中或在中断上下文中。 中断处理程序始终在中断上下文中运行。
图5.进程中断上下文
进程环境和中断环境之间的主要区别在于,在中断环境中不允许出现页面错误。
机器状态寄存器(MSR)
每个CPU都有自己的MSR,它指示处理器的状态。
dr msr / * dr cmd用于转储任何寄存器的内容* /
(0)> dr msr
msr : 0000F0B2 bit set : EE PR FP ME IR DR RI
图6. MST寄存器
评估MSR数据
在检查系统转储时,我们只对引起崩溃的CPU上运行的内容感兴趣。
如果MSR中的PR位置1(问题状态),则说明CPU在用户模式下运行,不太可能成为崩溃的原因。 这是因为用户模式指令没有足够的特权导致系统崩溃。
对于转储原因代码为300或400的转储,我们必须评估异常结构。
图7.异常结构
- dar(数据地址寄存器)包含处理器尝试访问的地址,然后导致页面错误。
- dsisr(数据存储中断状态寄存器)指示为什么无法解决页面错误。
图8. DSISR位描述
- dsirr(数据存储中断原因寄存器)指示发生的页面错误的类型。 通过将十六进制值转换为十进制来完成对dsirr的解码。
在1到127之间的值是错误号(显示在/usr/include/sys/errno.h中),而在128到512之间的值是异常(显示在/usr/include/sys/m_except.h中)。
我们必须评估mst输出中显示的IAR值。 特别是,我们将检查IAR引用的指令,以确认它可能导致stat子命令报告的崩溃类型
VMM错误日志
图9. Vmlog输出
当崩溃原因来自VMM时,vmlog子命令将提供其他信息。 在代码300转储的情况下显示的错误ID是DSI_PROC,在代码400转储的情况下显示的是ISI_PROC。 异常DSISR / ISISR,srval,virt addr将包含与异常结构中所示相同的信息。 Exception值是内部VMM错误代码。
堆栈跟踪
f [threadtableslot | threadtableaddress]
它显示线程的内核模式堆栈跟踪。
如果不指定任何参数,则显示当前CPU上下文的堆栈跟踪。
图10.跟踪输出
图11. DSI示例
上图显示了stat命令的输出。 输出指示的错误代码为300,这意味着这是DSI崩溃。
图12. DSI跟踪
上面显示的堆栈跟踪描述了当在CPU 0上运行的线程运行函数__memmove时,似乎已经发生了问题。
数字。 13. mst命令输出
mst子命令的输出显示线程正在运行(由prev = 0指示),并且所有中断均已使能(由intpri = 0B指示)。 换句话说,线程正在流程环境中运行。
异常结构的dsisr字段具有两位集DSISR_PROT和DSISR_ST.DSISR_PROT字段指示存在保护冲突。 DSISR_ST位指示存储操作存在问题。 导致页面错误问题的数据地址为0x00(dar 0000000000000000)。
异常结构的dsisr字段中的DSISR_ST位指示问题是存储操作。 我们希望IAR引用某种形式的存储指令。
0)> dc @iar
___memmove64+000058 std r7,8(r3)
r7的当前内容将存储在通过将0x08加到r3的当前值而计算出的存储地址中。 从mst子命令的输出中,我们可以看到r3的当前值为FFFFFFFFFFFFFFFFF8,因此通过将0x08添加到FFFFFFFFFFFFFFFFF8,我们可以得出:
(0)> hcal FFFFFFFFFFFFFFF8+0x08
Value hexa: 00000000 Value decimal: 0
因此这意味着r7的当前内容将存储在地址0X00中,这与异常结构的dar字段中显示的值匹配。
内核地址空间中虚拟内存的第一页可以由内核代码访问,但是被标记为只读。 尝试写入该存储范围将导致保护冲突。
进程和线程
proc子命令
当使用星号(*)调用时,proc子命令将在进程表中显示每个活动进程的一行摘要。
当使用过程表地址或插槽号调用时,proc子命令显示指定地址或插槽的详细格式化过程信息。 (如果不带任何参数调用proc子命令,它将显示当前进程的详细格式化的进程信息。)
图14. proc命令输出
图15. pid输出
线程子命令
当使用星号(*)调用时,thread子命令显示线程表中每个活动线程的单行摘要。
当使用线程表地址或插槽号调用该线程时,thread子命令将显示指定线程的详细格式化线程信息。 (如果不带任何参数调用线程sudcommand,它将显示当前线程的详细格式化线程信息。)
图16.线程命令输出
图17. tid输出
当前线程和进程
status子命令列出了所有CPU的当前线程和进程信息。
图18. status命令输出
其他kdb子命令
- 默认情况下,kdb在符号模式下工作,并且地址大部分在输出中显示为符号+偏移量。
图19. kdb输出
这里pvproc + 000000是Symbol + Offset格式。
使用ns或设置no_symbol,我们可以更改以上格式:
图20. ns命令输出
- 使用nm子命令获取符号的地址以及包含符号的可执行模块的目录(TOC)部分。
图21. nm命令输出
- 不带参数的lke子命令列出了当前加载的扩展
- ts子命令将地址转换为符号表示
- 计算器-将hcal用于十六进制,将dcal用于十进制计算
- 记录kdb会话-(0)>设置日志文件文件名。
(0)> set loglevel 2
日志级别可以设置为0、1或2。这确定了将记录在日志文件中的信息类型。 值0禁用登录到日志文件。 值1仅记录在提示符下键入的kdb命令。 值2记录kdb会话的输入和输出。
结论
因为找到系统崩溃问题的根本原因可能是一个乏味的过程,所以了解kdb如何提供一种分析崩溃问题的方法方法将很有帮助。 使用kdb,您将能够快速找到系统崩溃问题。 此外,您将获得一项宝贵的技能,该技能不仅可以从调试的角度节省大量时间,而且还可以提供有关哪些编码实践可以避免将来系统崩溃的见解。 最后但并非最不重要的一点是,该方法将提供一种方法论方法来非常快速地解决崩溃问题,从而获得客户的信任。
翻译自: https://www.ibm.com/developerworks/aix/library/au-kdbsteps/index.html