kdb 是专门用于执行系统转储映像分析的实用工具。本文将将介绍系统转储分析的基本步骤。

Divya Vikas, 软件工程师, WSO2 Inc

http://www.ibm.com/developerworks/i/p-dvikas.jpgDivya Vikas 是 SMBFS 和 Fast Connect 软件的 AIX 支持专家。她是 IBM 软件实验室 IBM System and Technology 小组的成员。Divya 为全球范围内的 SMBFS 和 Fast Connect 客户提供积极的支持。



Vabhav Sharma, 软件工程师, WSO2 Inc

/developerworks/i/p-vasharma.jpgVabhav Sharma 是 SMBFS 和 FastConnect 软件的 AIX 开发支持专家。他是印度软件实验室 IBM Systems and Technology 小组的成员。他为全球范围内的 SMBFS 和 Fast Connect 客户提供积极的支持。



2008 年 12 月 24 日

简介

对于基本的转储分析,本文主要解释转储映像。我们将介绍如何从 snap 包中提取相应的文件,接着介绍一种检查转储的系统方法,然后探查引起系统崩溃的根本原因。转储文件和 UNIX ® 文件位于 snap 包的 dump 子目录中。

虽然我们考察的重点是转储映像,但是适当地使用 snap 选项还可以获得有用的信息,这点很重要。更多信息请阅读本文的 GeneralKernel 小节。

General

general 目录包括有关系统运行时环境的信息,例如:

  • ODM 数据拷贝。
  • 所有环境变量(例如 PATH 和 TZ)。
  • 数据收集的日期和时间。
  • 系统的实际内存量(bootinfo -r)。
  • 所有已定义页面空间的列表。
  • 所有已安装文件集及其级别的列表。
  • 所有已安装 APAR 的列表。
  • 设备属性(lsattr -El)。
  • 系统 VPD 信息(lscfg -pv)。
  • 上一次转储的状态(sysdumpdev -L)。

Kernel

kernel 子目录包含了有用的内核信息(进程和内存数据)。

  • 数据收集的日期和时间。
  • vmstat 输出。
  • VMM 可调信息(vmo -L)。
  • 调度可调信息(schedo -L)。
  • 与 I/O 有关的可调信息(ioo -L)。
  • 环境变量。
  • SRC 信息(lssrc -a)。
  • 进程信息(ps -ef 和 ps -leaf)。
  • 设备驱动器和方法的校验和。

提取 snap 包

使用 pax 命令从 snap 包中提取文件。

  • 要查看 snap 文件的内容,输入以下命令:
    # zcat snap.pax.Z | pax -v
  • 要提取该包的所有内容,输入以下命令:
     # zcat snap.pax.Z | pax -r
  • 要仅提取 dump、general 和 kernel 子目录,输入:
     #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. Stat 输出
Stat 输出

kdb 的 stat 子命令提供了正在查看的转储的信息。除了包含日期、时间、版本和发布信息外,还包含转储原因代码。

转储原因代码

如果由于系统检测到问题而发起转储,那么 stat 子命令的输出将包含标题为 CRASH INFORMATION 的部分。

  • 该部分中,输出的第一行列出了检测到问题的 CPU,这些问题造成转储例程被调用(在前面的示例中 CPU 为 0)。
  • 转储原因代码指文本 “error code for LEDs” 旁边显示的数字的前三位。在前面的示例中,CRASH INFORMATION 部分的前三位包含以下文本:
    error code for LEDs: 30000000

这意味着转储原因代码为 300,即 DSI(DATA STORAGE INTERRUPT)。

转储原因代码表示造成崩溃的基本原因。大多数崩溃通常显示的原因代码为 300、400 和 700。

原因代码说明
2nn机器检查
3nn数据存储中断
400指令存储中断
5nn外部中断
700程序中断
800浮点数据不可用
  • 2nn-机器检查。

    机器检查原因代码通常表示硬件问题(比如,内存损坏)。

  • 3nn-数据存储中断(DSI)。

    如果对当前不在物理内存中加载的虚拟地址进行引用(这是一个页面错误),则会出现 DSI 错误。页面错误是经常发生的错误。通常由 VMM 处理,并且不会导致系统崩溃。然而,如果页面错误不能够在内核模式下解决,或者在禁用中断情况下出现页面错误,那么 DIS 将造成系统崩溃。这个问题通常由软件引起,但是偶尔也和硬件有关。

  • 400-指令存储中断(ISI)。

    指令存储中断通常是指在取出指令时发生页面错误。这种错误通常通过 VMM 解决,并且一般不会造成系统崩溃。如果不能够通过 VMM 解决,或者在禁用中断的情况下发生页面错误,那么将造成系统崩溃。

  • 5nn-外部中断。

    引起崩溃的原因是外部设备出现中断,比如 I/O 总线控制器。

  • 700-程序中断。

    这种类型的中断是由内核例程调用了 trap 指令引起的。这通常是调用 panic 内核服务或断言失败造成的。内核例程在遇到无法解决的问题时就会调用 panic 服务。这种问题通常和软件有关,但也可能和硬件也有关。

  • 800-浮点不可用。

    如果在 MSR(机器状态寄存器)中可用的浮点位被禁用,将尝试执行一个浮点指令。


初始 CPU 上下文

kdb 永远在运行崩溃线程的 CPU 上下文中启动。当调用 kdb 时,显示以下提示:(n)>>,其中的 n 表示当前的 CPU 上下文。

然而,要切换到另一个 CPU 上下文,可以使用 cpu 子命令:

(0)>> cpu 1
(1)>>

MST (MACHINE STATE SAVE AREA)

Machine State save area(MST)包含已保存的 CPU 进程上下文的映像。进程上下文包含通用寄存器、浮点寄存器、特殊用途的寄存器和其他有关重启线程所需的信息。CPU 上的每个处理器都拥有自己的 CSA(当前保存区)指针,指向当线程或中断处理程序由于上下文切换而被中断或交换时使用的 MST。虽然线程是活动的,但是运行线程的处理器的 CSA 将指向当前活动线程的 MST。

  • MST 中的其中一个字段是指向前一个 MST 的指针(kdb 中的上一个 MST)。该字段只能在中断上下文中被填充。
    图 2. 表示中断历史的 MST 结构链
    MST 链
  • mst 子命令:
    mst [ thread_slot | thread_table_address ]

    为指定的线程提供一个格式化的 MST 显示。如果没有指定任何地址,将显示当前处理器的 MST 区域。

图 3. mst 子命令在 64 位内核中的输出
mst 子命令在 64 位内核中的输出
图 4. mst 子命令在 32 位内核中的输出
mst 子命令在 32 位内核中的输出

mst 子命令输出中的数据字段

  • iar-指令地址寄存器。

    包含错误指令的位置(错误的 MST)。这是在崩溃期间执行的当前指令。

  • lr-链接寄存器的值。

    包含函数的返回地址。

  • Except-显示异常结构。

    提供有关崩溃特征的信息。

  • r0-r31 显示通用寄存器的内容。
  • intpri-表示中断优先级别。

    表示处理器是否在中断禁用的情况下运行。

  • prev-值是否为 0。

    MST 表示处理器中运行的基本级别的线程。如果值为非 0 的值,则处理器正在处理中断。prev 字段指向链中的下一个 MST 结构。

prev 和 intpri 字段中的值帮助判断处理器是在运行线程还是在运行中断处理程序。

如果 CPU 正在运行一个线程,该线程可以位于处理上下文或中断上下文中。中断处理程序始终在中断上下文中运行。

图 5. 处理-中断上下文
处理-中断上下文

处理环境与中断环境之间的主要差别是:当处于中断环境中时,不允许出现任何页面错误。

Machine State Register (MSR)

每个 CPU 都有自己的 MSR,它表示处理器的状态。

dr msr /* dr cmd 用于转储任何寄存器 */ 的内容

    (0)> dr msr
	 msr  : 0000F0B2   bit set : EE PR FP ME IR DR RI
图 6. MST 寄存器
MST 寄存器

分析 MSR 数据

在讨论系统转储时,我们只关注在 CPU 中运行的引起系统崩溃的东西。

如果在 MSR 中设置了 PR 位(问题状态),那么 CPU 在用户模式下运行,并且不可能引起系统崩溃。因为用户模式指令没有引起系统崩溃的足够权限。

如果转储原因代码为 300 或 400,我们必须对异常结构进行分析。

图 7. 异常结构
异常结构
  • dar(数据地址寄存器)包含处理器尝试访问的地址,这一行为将引发页面错误。
  • dsisr(数据存储中断状态寄存器)表示页面错误无法解决的原因。
    图 8. DSISR 位描述
    DSISR 位描述
  • dsirr(数据存储中断原因寄存器)表示发生的页面错误的类型。通过将十六进制值转换为十进制值来对 dsirr 进行解码。

    1 到 127 之间的值是错误编码(在 /usr/include/sys/errno.h 中显示),而 128 到 512 之间的值属于异常(在 /usr/include/sys/m_except.h 中显示)。

我们必须对 mst 输出中的值进行分析。特别要检查 IAR 引用的指令,证实它引起的崩溃类型是 stat 子命令报告的类型。

VMM 错误日志

图 9. Vmlog 输出
Vmlog 输出

在 VMM 提供崩溃原因时,vmlog 子命令提供额外的信息。代码 300 转储中显示的 Error ID 是 DSI_PROC,而在代码 400 转储中为 ISI_PROC。Exception DSISR/ISISR,srval,virt addr 包含异常结构中显示的信息。Exception 值是一个内部 VMM 错误代码。

栈跟踪
f  [threadtableslot | threadtableaddress]

它显示线程的内核模式栈跟踪。

如果没有提供任何参数,则显示当前 CPU 上下文的栈跟踪。

图 10. 跟踪输出
跟踪输出
图 11. DSI 示例
DSI 示例

上图显示了 stat 命令的输出。输出显示错误代码为 300,表明这是一个 DSI 崩溃。

图 12. DSI 跟踪
DSI 跟踪

上图显示的栈跟踪描述了当 CPU 0 上的某个线程运行 function __memmove 时出现的问题。

图 13. mst 命令输出
mst 命令输出

mst 子命令的输出表示线程(表示为 prev =0)在启用了所有中断的情况下运行(表示为 intpri =0B)。换句话说,线程正在进程环境中运行。

异常结构的 dsisr 字段由两项组成,DSISR_PROT 和 DSISR_ST。DSISR_PROT 字段表示出现保护违反(protection violation)。DSISR_ST 表示问题与存储操作有关。引起页面错误的数据地址为 0x00(dar 0000000000000000)。

异常结构 dsisr 字段的 DSISR_ST 表示存储操作出了问题。我们希望 IAR 引用某种形式的存储指令。

0)> dc @iar 
___memmove64+000058        std    r7,8(r3)

r7 的当前内容将被存储到内存地址中(向 r3 的当前值加 0x08 得出该地址)。从 mst 子命令的输出可以看到,r3 的当前值是 FFFFFFFFFFFFFFF8,因此向 FFFFFFFFFFFFFFF8 加 0x08 将得到:

(0)> hcal FFFFFFFFFFFFFFF8+0x08
Value hexa: 00000000          Value decimal: 0

这意味着 r7 的当前内容将被保存到地址 0X00。它匹配异常结构中 dar 字段显示的值。

内核地址空间中的第一页虚拟内存可通过内核代码访问,但是被标记为只读。任何对该内存范围执行写操作的尝试将导致保护违反。


进程和线程

proc 子命令

在使用 asterix (*) 调用 proc 子命令时,它将以一行摘要显示进程表中的所有活动进程。

当使用进程表地址或 slot 编号调用 proc 子命令时,它将详细显示指定地址或 slot 的格式化进程信息(如果在未使用参数的情况下调用 proc 子命令,它将详细显示当前进程的格式化进程信息)。

图 14. proc 命令输出
proc 命令输出
图 15. pid 输出
pid 输出

thread 子命令

当使用 asterix (*) 调用 thread 子命令时,它将以一行摘要显示线程表中的所有活动线程。

当使用线程表地址或 slot 编号调用 thread 子命令时,它将详细显示指定线程的格式化线程信息(如果在未使用参数的情况下调用 thread 子命令,它将详细显示当前线程的格式化线程信息)。

图 16. thread 命令输出
thread 命令输出
图 17. tid 输出
tid 输出

当前线程和进程

status 子命令列出了所有 CPU 的当前线程和进程的信息。

图 18. status 命令输出
status 命令输出

其他 kdb 子命令

  • 默认情况下,kdb 在 symbolic 模式下工作,并且大部分地址在输出中显示为 symbol + 偏移量。
    图 19. kdb 输出
    kdb 输出

    pvproc+000000 在这里使用 Symbol+偏移量格式。

    使用 ns 或设置 no_symbol,我们可以修改以上的格式:

    图 20. ns 命令输出
    ns 命令输出
  • 使用 nm 子命令获得符号的地址以及包含符号的可执行模块的 Table Of Contents (TOC) 部分。
    图 21. nm 命令输出
    nm 命令输出
  • 无参数 lke 子命令列出当前加载的扩展。
  • ts 子命令将地址转换为符号表示。
  • CALCULATORS-Use hcal 用于十六进制计算,dcal 用于十进制计算。
  • 记录 kdb session-(0)>set 日志文件的文件名。
    (0)> set loglevel 2

日志级别可设为 0、1 或 2。这决定将哪种信息记录到日志文件中。值 0 表示禁止记录到日志文件中。值 1 表示只记录在提示时输入的 kdb 命令。值 2 记录 kdb 会话的输入和输出。


结束语

查找系统崩溃的根本原因是一个单调乏味的过程,因此了解 kdb 非常有用,它供一种分析系统崩溃的系统方法。通过 kdb,您将能够迅速跟踪导致系统崩溃问题。此外,您还学习到一种很有价值技能,借助它不仅能够节省大量调试时间,还可以了解可以避免系统崩溃的编程实践。最后这点也很重要,这是一种可以快速解决崩溃问题的系统性方法,它将帮助您赢得客户信任。

参考资料

学习

  • KDB 内核调试器和 kdb 命令
  • 您可以参阅本文在 developerWorks 全球站点上的 英文原文
  • AIX and UNIX 专区:developerWorks 的“AIX and UNIX 专区”提供了大量与 AIX 系统管理的所有方面相关的信息,您可以利用它们来扩展自己的 UNIX 技能。
  • AIX and UNIX 新手入门:访问“AIX and UNIX 新手入门”页面可了解更多关于 AIX 和 UNIX 的内容。
  • AIX and UNIX 专题汇总:AIX and UNIX 专区已经为您推出了很多的技术专题,为您总结了很多热门的知识点。我们在后面还会继续推出很多相关的热门专题给您,为了方便您的访问,我们在这里为您把本专区的所有专题进行汇总,让您更方便的找到您需要的内容。
  • developerWorks 的架构专区 中,获得提高在架构领域的技能所需的参考资料。
  • 浏览 技术书店,阅读有关这些主题和其他技术主题的图书。

获得产品和技术

  • 下载 IBM 产品评估版 并开始使用来自 DB2®、Lotus®、Rational®、Tivoli® 和 WebSphere® 的应用程序开发工具和中间件产品。

讨论

条评论

developerWorks: 登录

标有星(*)号的字段是必填字段。


需要一个 IBM ID?
忘记 IBM ID?


忘记密码?
更改您的密码

单击提交则表示您同意developerWorks 的条款和条件。 查看条款和条件

 


在您首次登录 developerWorks 时,会为您创建一份个人概要。您的个人概要中的信息(您的姓名、国家/地区,以及公司名称)是公开显示的,而且会随着您发布的任何内容一起显示,除非您选择隐藏您的公司名称。您可以随时更新您的 IBM 帐户。

所有提交的信息确保安全。

选择您的昵称



当您初次登录到 developerWorks 时,将会为您创建一份概要信息,您需要指定一个昵称。您的昵称将和您在 developerWorks 发布的内容显示在一起。

昵称长度在 3 至 31 个字符之间。 您的昵称在 developerWorks 社区中必须是唯一的,并且出于隐私保护的原因,不能是您的电子邮件地址。

标有星(*)号的字段是必填字段。

(昵称长度在 3 至 31 个字符之间)

单击提交则表示您同意developerWorks 的条款和条件。 查看条款和条件.

 


所有提交的信息确保安全。


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=10
Zone=AIX and UNIX
ArticleID=361025
ArticleTitle=kdb 入门
publish-date=12242008