使用 kmdb 和 mdb 执行的有用调试任务

http://download.oracle.com/docs/cd/E19253-01/819-7057/euxdg/index.html

使用 kmdbmdb 执行的有用调试任务

本节提供了有用的调试任务示例。除非特别说明,否则本节中的任务均可使用 mdbkmdb 来执行。本节假定您已了解 kmdbmdb 的基本使用知识。请注意,此处提供的信息取决于所使用系统的类型。这些示例是使用运行 64 位内核的 Sun Blade 100 工作站生成的。


注意 – 注意 –

由于修改内核结构中的数据会导致无法恢复的数据损毁,因此务必要格外谨慎。请勿修改或依赖于不属于 Solaris DDI 结构中的数据。有关属于 Solaris DDI 的结构的信息,请参见 Intro(9S) 手册页。


使用 kmdb 查找系统寄存器

kmdb 调试程序可按组或单独显示计算机寄存器。要按组显示所有寄存器,请按以下示例所示使用 $r


示例 22–11 使用 kmdb 读取 SPARC 处理器中的所有寄存器


[0]: $r



g0    0                                 l0      0

g1    100130a4      debug_enter         l1      edd00028

g2    10411c00      tsbmiss_area+0xe00  l2      10449c90

g3    10442000      ti_statetbl+0x1ba   l3      1b

g4    3000061a004                       l4      10474400     ecc_syndrome_tab+0x80

g5    0                                 l5      3b9aca00

g6    0                                 l6      0

g7    2a10001fd40                       l7      0

o0    0                                 i0      0

o1    c                                 i1      10449e50

o2    20                                i2      0

o3    300006b2d08                       i3      10

o4    0                                 i4      0

o5    0                                 i5      b0

sp    2a10001b451                       fp      2a10001b521

o7    1001311c      debug_enter+0x78    i7      1034bb24     zsa_xsint+0x2c4

y     0

tstate: 1604  (ccr=0x0, asi=0x0, pstate=0x16, cwp=0x4)

pstate: ag:0 ie:1 priv:1 am:0 pef:1 mm:0 tle:0 cle:0 mg:0 ig:0

winreg: cur:4 other:0 clean:7 cansave:1 canrest:5 wstate:14

tba   0x10000000

pc    edd000d8 edd000d8:        ta      %icc,%g0 + 125

npc   edd000dc edd000dc:        nop

调试程序会将每个寄存器值导出到与寄存器同名的一个变量中。如果读取该变量,则返回对应寄存器的当前值。如果写入该变量,则会更改关联的计算机寄存器值。以下示例将一台 x86 计算机上 %o0 寄存器的值由 0 更改为 1。


示例 22–12 使用 kmdb 读/写 x86 计算机中的寄存器


[0]> <eax=K

        c1e6e0f0

[0]> 0>eax

[0]> <eax=K

        0

[0]>  c1e6e0f0>eax


如果需要检查不同处理器的寄存器,则可使用 ::cpuregs dcmd。要检查的处理器的 ID 可以作为 dcmd 的地址或 -c 选项的值来提供,如以下示例所示。


示例 22–13 检查不同处理器的寄存器


[0]> 0::cpuregs

   %cs = 0x0158            %eax = 0xc1e6e0f0 kmdbmod`kaif_dvec

   %ds = 0x0160            %ebx = 0x00000000

以下示例从 SPARC 计算机上的处理器 0 切换到处理器 3。检查了寄存器 %g3,然后将其清除。为确认新值,再次读取 %g3


示例 22–14 从指定的处理器中检索单个寄存器值


[0]> 3::switch

[3]> <g3=K

        24

[3]> 0>g3

[3]> <g3

        0

检测内核内存泄漏

::findleaks dcmd 可对内核崩溃转储中的内存泄漏提供强大、有效的检测。必须启用一整套内核内存调试功能,::findleaks 才会有效。有关更多信息,请参见设置 kmem_flags 调试标志。在驱动程序开发和测试期间运行 ::findleaks,以检测泄漏内存从而浪费内核资源的代码。有关 ::findleaks 的完整讨论,请参见《Solaris 模块调试器指南》中的第 9  章 “使用内核内存分配器进行调试”


注 –

泄漏内核内存的代码会使系统容易受到拒绝服务攻击。


使用 mdb 编写调试程序命令

mdb 调试程序提供了一个功能强大的 API,用于实现为调试驱动程序而自定义的调试程序功能。《Solaris 模块调试器指南》详细介绍了该编程 API。

SUNWmdbdm 软件包将 mdb 源代码示例安装在目录 /usr/demo/mdb 中。可以使用 mdb 来自动完成冗长的调试日常事务,或帮助验证驱动程序是否正常工作。还可以将 mdb 调试模块与驱动程序产品一起打包。通过打包,服务人员可在客户站点处使用这些功能。

获取内核数据结构信息

Solaris 内核在可用 kmdbmdb 检查的结构中提供数据类型信息。


注 –

kmdbmdb dcmd 只能用于包含设计用于 mdb 的压缩符号调试信息的对象。此信息当前只能用于某些 Solaris 内核模块。必须安装 SUNWzlib 软件包,才能处理符号调试信息。


以下示例说明如何显示 scsi_pkt 结构中的数据。


示例 22–15 使用调试程序显示内核数据结构


> 7079ceb0::print -t 'struct scsi_pkt'

{

    opaque_t pkt_ha_private = 0x7079ce20

    struct scsi_address pkt_address = {

        struct scsi_hba_tran *a_hba_tran = 0x70175e68

        ushort_t a_target = 0x6

        uchar_t a_lun = 0

        uchar_t a_sublun = 0

    }

    opaque_t pkt_private = 0x708db4d0

    int (*)() *pkt_comp = sd_intr

    uint_t pkt_flags = 0

    int pkt_time = 0x78

    uchar_t *pkt_scbp = 0x7079ce74

    uchar_t *pkt_cdbp = 0x7079ce64

    ssize_t pkt_resid = 0

    uint_t pkt_state = 0x37

    uint_t pkt_statistics = 0

    uchar_t pkt_reason = 0

}

数据结构的大小在调试中很有用。使用 ::sizeof dcmd 可获取结构的大小,如以下示例所示。


示例 22–16 显示内核数据结构的大小


> ::sizeof struct scsi_pkt

sizeof (struct scsi_pkt) = 0x58

结构中特定成员的地址在调试中也很有用。有几种方法可用来确定成员的地址。

使用 ::offsetof dcmd 可以获取结构中给定成员的偏移,如以下示例所示。


示例 22–17 显示内核数据结构的偏移


> ::offsetof struct scsi_pkt pkt_state

offsetof (struct pkt_state) = 0x48

使用带 -a 选项的 ::print dcmd 可以显示结构中所有成员的地址,如以下示例所示。


示例 22–18 显示内核数据结构的相对地址


> ::print -a struct scsi_pkt

{

    0 pkt_ha_private

    8 pkt_address {

    ...

    }

    18 pkt_private

    ...

}

如果结合使用 ::print-a 选项来指定地址,则会显示每个成员的绝对地址。


示例 22–19 显示内核数据结构的绝对地址


> 10000000::print -a struct scsi_pkt

{

    10000000 pkt_ha_private

    10000008 pkt_address {

    ...

    }

    10000018 pkt_private

    ...

}

使用 ::print::sizeof::offsetof dcmd,可在驱动程序与 Solaris 内核交互时调试问题。


注意 – 注意 –

通过此功能可访问原始内核数据结构。您可以检查任何结构,无论该结构是否显示为 DDI 的一部分。因此,应避免依赖于未显式构成 DDI 的任何数据结构。



注 –

这些 dcmd 只能用于包含设计用于 mdb 的压缩符号调试信息的对象。符号调试信息当前只能用于某些 Solaris 内核模块。必须安装 SUNWzlib(32 位)或 SUNWzlibx(64 位)解压缩软件,才能处理符号调试信息。无论是否包含 SUNWzlibSUNWzlibx 软件包,kmdb 调试程序均可处理符号类型数据。


获取设备树信息

mdb 调试程序提供了用于显示内核设备树的 ::prtconf dcmd。::prtconf dcmd 的输出与 prtconf(1M) 命令的输出相似。


示例 22–20 使用 ::prtconf Dcmd


> ::prtconf

300015d3e08      SUNW,Sun-Blade-100

    300015d3c28      packages (driver not attached)

        300015d3868      SUNW,builtin-drivers (driver not attached)

        300015d3688      deblocker (driver not attached)

        300015d34a8      disk-label (driver not attached)

        300015d32c8      terminal-emulator (driver not attached)

        300015d30e8      obp-tftp (driver not attached)

        300015d2f08      dropins (driver not attached)

        300015d2d28      kbd-translator (driver not attached)

        300015d2b48      ufs-file-system (driver not attached)

    300015d3a48      chosen (driver not attached)

    300015d2968      openprom (driver not attached)

可以使用宏(如 ::devinfo dcmd)来显示节点,如以下示例所示。


示例 22–21 显示单个节点的设备信息


> 300015d3e08::devinfo

300015d3e08      SUNW,Sun-Blade-100

        System properties at 0x300015abdc0:

            name='relative-addressing' type=int items=1

                value=00000001

            name='MMU_PAGEOFFSET' type=int items=1

                value=00001fff

            name='MMU_PAGESIZE' type=int items=1

                value=00002000

            name='PAGESIZE' type=int items=1

                value=00002000

        Driver properties at 0x300015abe00:

            name='pm-hardware-state' type=string items=1

                value='no-suspend-resume'

使用 ::prtconf 可以查看驱动程序在设备树中连接的位置,以及显示设备属性。还可以为 ::prtconf 指定详细 (-v) 标志,以显示每个设备节点的属性,如下所示。


示例 22–22 在详细模式下使用 ::prtconf Dcmd


> ::prtconf -v

DEVINFO          NAME

300015d3e08      SUNW,Sun-Blade-100

        System properties at 0x300015abdc0:

            name='relative-addressing' type=int items=1

                value=00000001

            name='MMU_PAGEOFFSET' type=int items=1

                value=00001fff

            name='MMU_PAGESIZE' type=int items=1

                value=00002000

            name='PAGESIZE' type=int items=1

                value=00002000

        Driver properties at 0x300015abe00:

            name='pm-hardware-state' type=string items=1

                value='no-suspend-resume'

        ...

        300015ce798      pci10b9,5229, instance #0

                Driver properties at 0x300015ab980:

                    name='target2-dcd-options' type=any items=4

                        value=00.00.00.a4

                    name='target1-dcd-options' type=any items=4

                        value=00.00.00.a2

                    name='target0-dcd-options' type=any items=4

                        value=00.00.00.a4

另一种查找驱动程序实例的方法是使用 ::devbindings dcmd。在给定驱动程序名称的情况下,该命令会显示指定驱动程序的所有实例的列表,如以下示例所示。


示例 22–23 使用 ::devbindings Dcmd 查找驱动程序实例


> ::devbindings dad

300015ce3d8      ide-disk (driver not attached)

300015c9a60      dad, instance #0

        System properties at 0x300015ab400:

            name='lun' type=int items=1

                value=00000000

            name='target' type=int items=1

                value=00000000

            name='class_prop' type=string items=1

                value='ata'

            name='type' type=string items=1

                value='ata'

            name='class' type=string items=1

                value='dada'

...

300015c9880      dad, instance #1

        System properties at 0x300015ab080:

            name='lun' type=int items=1

                value=00000000

            name='target' type=int items=1

                value=00000002

            name='class_prop' type=string items=1

                value='ata'

            name='type' type=string items=1

                value='ata'

            name='class' type=string items=1

                value='dada'

检索驱动程序软状态信息

调试驱动程序的常见问题是检索特定驱动程序实例的软状态。软状态使用 ddi_soft_state_zalloc(9F) 例程来分配。驱动程序可以通过 ddi_get_soft_state(9F) 获取软状态。软状态指针的名称是 ddi_soft_state_init (9F) 的第一个参数。根据名称,可以使用 mdb 通过 ::softstate dcmd 检索特定驱动程序实例的软状态:


> *bst_state::softstate 0x3

702b7578

在此示例中,::softstate 用来获取 bst 示例驱动程序的实例 3 的软状态。此指针引用由驱动程序使用的 bst_soft 结构,以便跟踪该实例的状态。

修改内核变量

可以使用 kmdbmdb 来修改内核变量或其他内核状态。使用 mdb 修改内核状态时要格外谨慎,因为 mdb 在进行修改前不会停止内核。使用 kmdb 可以原子方式进行成组修改,因为 kmdb 会在允许用户访问之前停止内核。mdb 调试程序只能进行单个原子修改。

务必要使用正确的格式指示符来进行修改。格式可以为:

  • w-将每个表达式值的最低 2 个字节写入从点所指定的位置开始的目标位置

  • W-将每个表达式值的最低 4 个字节写入从点所指定的位置开始的目标位置

  • Z-将每个表达式值的全部 8 个字节写入从点所指定的位置开始的目标位置

使用 ::sizeof dcmd 可以确定要修改的变量的大小。

以下示例使用值 0x80000000 覆写 moddebug 的值。


示例 22–24 使用调试程序修改内核变量


> moddebug/W 0x80000000

    moddebug:       0 = 0x80000000

你可能感兴趣的:(DB)