使用 /etc 目录中的 system(4) 文件可在引导时设置内核变量的值。使用内核变量,可在驱动程序中切换不同的行为,并利用内核提供的调试功能。内核变量 moddebug 和 kmem_flags 在调试中非常有用,本节稍后将对其进行讨论。另请参见启用 Deadman 功能以避免硬挂起。
由于仅在内核引导时读取 /etc/system 一次,因此引导后对内核变量所做的更改不可靠。修改此文件后,必须重新引导系统,更改才能生效。如果文件中的更改导致系统无法工作,请使用询问功能 (-a) 选项进行引导。然后,将 /dev/null 指定为系统文件。
后续发行版中不一定存在内核变量。
set 命令可以更改模块变量或内核变量的值。要设置模块变量,请指定模块名称和变量:
set module_name:variable=value |
例如,要在名为 myTest 的驱动程序中设置变量 test_debug,请按如下方式使用 set:
% set myTest:test_debug=1 |
要设置由内核自身导出的变量,可忽略模块名称。
还可以使用按位 OR 运算设置值,例如:
% set moddebug | 0x80000000 |
使用命令 modload(1M)、modunload(1M) 和 modinfo(1M) 可以添加测试模块,在对驱动程序进行调试和压力测试时,这是一种非常有用的方法。正常操作中通常不需要这些命令,因为内核会自动装入需要的模块并卸载未使用的模块。moddebug 内核变量可与这些命令一起使用,以提供信息并设置控制。
使用 modload(1M) 可将模块强制装入内存。modload 命令可验证装入驱动程序时该驱动程序是否具有未解析的引用。装入驱动程序并不表明该驱动程序一定可以连接。驱动程序成功装入时,将调用该驱动程序的 _info(9E) 入口点,但不一定调用 attach() 入口点。
使用 modinfo(1M) 可以确认驱动程序已装入。
$ modinfo Id Loadaddr Size Info Rev Module Name 6 101b6000 732 - 1 obpsym (OBP symbol callbacks) 7 101b65bd 1acd0 226 1 rpcmod (RPC syscall) 7 101b65bd 1acd0 226 1 rpcmod (32-bit RPC syscall) 7 101b65bd 1acd0 1 1 rpcmod (rpc interface str mod) 8 101ce8dd 74600 0 1 ip (IP STREAMS module) 8 101ce8dd 74600 3 1 ip (IP STREAMS device) ... $ modinfo | grep mydriver 169 781a8d78 13fb 0 1 mydriver (Test Driver 1.5) |
info 字段中的数字是为驱动程序选择的主设备号。如果提供了模块 ID,则可使用 modunload(1M) 命令来卸载模块。模块 ID 位于 modinfo 输出的左列中。
有时,发出 modunload 后驱动程序不会按预期卸载,因为该驱动程序被确定处于忙状态。由于驱动程序确实繁忙或 detach 入口点未正确实现而导致驱动程序无法执行 detach(9E) 时,会出现上述情况。
要从内存中删除所有当前未使用的模块,请使用模块 ID 0 运行 modunload(1M):
# modunload -i 0 |
moddebug 内核变量可控制模块装入过程。moddebug 的可能值包括:
装入或卸载模块时向控制台列显消息。
提供更详细的错误消息。
装入或卸载时列显更多详细信息,如包含地址和大小。
不自动卸载驱动程序。系统资源变少时,系统不尝试卸载设备驱动程序。
不自动卸载流。系统资源变少时,系统不尝试卸载 STREAMS 模块。
不自动卸载任何类型的内核模块。
如果与 kmdb 一起运行,moddebug 会导致执行断点,并在调用每个模块的 _init() 例程之前立即返回到 kmdb。此设置还会在执行模块的 _info() 和 _fini() 例程时生成其他调试消息。
kmem_flags 内核变量用于启用内核的内存分配器中的调试功能。将 kmem_flags 设置为 0xf 即启用分配器的调试功能。这些功能包括运行时检查,以找出以下代码条件:
释放缓冲区后向缓冲区写入
初始化内存之前使用内存
写入时已过缓冲区结尾
《Solaris 模块调试器指南》介绍了如何使用内核内存分配器来分析此类问题。
在将 kmem_flags 设置为 0xf 的情况下进行测试和开发有助于检测潜在的内存损坏错误。由于将 kmem_flags 设置为 0xf 会更改内核内存分配器的内部行为,因此最好应不使用 kmem_flags 而执行全面测试。