下一页 上一页 目录

7. 调试技巧和编程信息

7.1 提交有用的问题报告

提交报告的最佳方式是使用在线 pcmcia-cs 论坛或 SourceForge 上的 bug 跟踪器。这样,其他人可以看到当前的问题(以及可用的修复程序或解决方法)。以下是在所有 bug 报告中应包含的一些内容:

所有 PCMCIA 模块和 cardmgr 守护程序都会将状态消息发送到系统日志。这些消息通常会出现在类似 /var/log/messages/var/log/daemon.log 的位置。在追踪问题时,这些文件应该是首先查看的地方。提交 bug 报告时,请务必包含这些文件的相关内容。如果您在查找系统消息时遇到问题,请检查 /etc/syslog.conf 以了解如何处理不同类别的消息。

在提交 bug 报告之前,请检查以确保您正在使用最新版本的驱动程序包。虽然阅读我已经修复的问题的 bug 报告有点令人欣慰,但这并不是对我时间的特别建设性的利用。

如果您无法访问网络,可以将 bug 报告发送给我,地址是 dahinds@users.sourceforge.net。但是,我更希望将 bug 报告发布到 pcmcia-cs SourceForge 站点,以便其他人可以看到它们。

7.2 解释内核陷阱报告

如果您的​​问题涉及内核故障,则故障的寄存器转储只有在您可以将故障地址 EIP 转换为有意义的内容时才有用。最新版本的 klogd 尝试根据当前的内核符号表转换故障地址,但如果故障发生在模块中,或者问题严重到 klogd 无法完成将故障信息写入系统日志,则可能无法正常工作。

如果故障发生在主内核中,则可以在 System.map 文件中查找故障地址。该文件可能安装在 /System.map/boot/System.map 中。如果故障发生在模块中,则 nm 命令提供相同的信息,但是,必须根据模块的加载地址调整故障地址。假设您有以下内核故障

Unable to handle kernel NULL pointer dereference
current->tss.cr3 = 014c9000, %cr3 = 014c9000
*pde = 00000000
Oops: 0002
CPU:    0
EIP:    0010:[<c2026081>]
EFLAGS: 00010282

故障地址为 0xc2026081。查看 System.map,我们看到这超出了内核的末尾,即在内核模块中。要确定是哪个模块,请检查 ``ksyms -m | sort'' 的输出

Address   Symbol                            Defined by
c200d000  (35k)                             [pcmcia_core]
c200d10c  register_ss_entry                 [pcmcia_core]
c200d230  unregister_ss_entry               [pcmcia_core]
          ...
c2026000  (9k)                              [3c574_cs]
c202a000  (4k)                              [serial_cs]

所以,0xc2026081 在 3c574_cs 模块中,并且相对于模块的起始地址偏移 0x0081。我们还不能在 3c574_cs.o 中查找此偏移量:当内核加载模块时,它会在模块加载地址处插入一个标头,因此模块的真实起始地址与 ksyms 中显示的地址偏移。标头的大小随内核版本而异:要找出您的内核的标头大小,请检查导出符号的模块(例如上面的 pcmcia_core),并将符号地址与该符号的 nm 输出进行比较。在本例中,register_ss_entry 加载在偏移量为 0xc200d10c - 0xc200d000 = 0x010c 处,而 ``nm pcmcia_core.o'' 显示偏移量为 0x00c0,因此标头大小为 0x010c - 0x00c0 = 0x004c 字节。

回到 3c574_cs,我们的故障偏移量为 0x0081,减去 0x004c 标头,实际的模块偏移量为 0x0035。现在查看 ``nm 3c574_cs.o | sort'',我们看到

0000002c d if_names
0000002c t tc574_attach
00000040 d mii_preamble_required
00000041 d dev_info

所以,故障位于 tc574_attach() 中。

在本例中,故障没有导致系统完全死锁,因此可以在故障发生后执行 ksyms。在其他情况下,您可能必须间接推断模块加载地址。相同的事件序列通常会以相同的顺序和相同的地址加载模块。如果插入特定卡时发生故障,请在插入卡之前或插入不同的卡时获取 ksyms 输出。您还可以使用 insmod 手动加载卡的驱动程序模块,并在插入卡之前运行 ksyms

有关更多背景信息,请参阅 ``man insmod''、``man ksyms'' 和 ``man klogd''。在内核源代码树中,Documentation/oops-tracing.txt 也相关。以下是一些内核调试提示:

7.3 低级 PCMCIA 调试辅助工具

PCMCIA 模块包含大量有条件编译的调试代码。大多数代码都在 PCMCIA_DEBUG 预处理器定义的控制之下。如果未定义此项,则不会编译调试代码。如果设置为 0,则代码已编译但处于非活动状态。较大的数字指定更高的详细程度。每个使用 PCMCIA_DEBUG 定义构建的模块都将具有一个整数参数 pc_debug,该参数控制其输出的详细程度。这可以在模块加载时进行调整,因此可以在每个模块的基础上控制输出,而无需重新编译。

您的 syslogd 默认配置可能会丢弃内核调试消息。为确保记录这些消息,请编辑 /etc/syslog.conf 以确保将 ``kern.debug'' 消息记录在某个位置。有关详细信息,请参阅 ``man syslog.conf''。

在 PCMCIA 发行版的 debug_tools/ 子目录中,有一些寄存器级调试工具。 dump_tcicdump_i365 实用程序为 ISA 到 PCMCIA 控制器生成寄存器转储。在 3.1.15 及更高版本中,dump_i365dump_exca 取代,后者类似,但也适用于 PCI 到 CardBus 桥接器。3.1.15 中针对 CardBus 桥接器的新工具还有 dump_cardbus 工具,它解释 CardBus 特定的寄存器。如果您可以访问相应控制器芯片的数据手册,这些工具都非常有用。 dump_cis 实用程序(在 3.0.2 之前的发行版中为 dump_tuples)列出卡的 CIS(卡信息结构)的内容,并解码大多数重要位。 dump_cisreg 实用程序显示卡的本地配置寄存器。

memory_cs 存储卡驱动程序有时也用于调试 16 位 PC 卡的问题。它可以绑定到任何卡,并且不干扰其他驱动程序。它可以用于直接访问任何卡的属性内存或公共内存。类似地,对于 CardBus 卡,memory_cb 驱动程序可以绑定到任何 32 位卡,以直接访问该卡的地址空间。有关更多信息,请参阅手册页。

7.4 /proc/bus/pccard

在 2.2 及更高版本的内核上,PCMCIA 包将在 /proc/bus/pccard 下创建一个状态信息树。许多信息只能使用 PCMCIA 主机控制器的数据表来解释。其内容可能取决于驱动程序的配置方式,但可能包括以下全部或部分内容:

/proc/bus/pccard/{irq,ioport,memory}

如果存在,这些文件包含资源分配信息,以补充正常的内核资源表。如果配置为这样做,则最新版本的 PCMCIA 系统可能会从即插即用 BIOS 获取其他资源信息。

/proc/bus/pccard/drivers

在最新版本中,此文件列出所有当前加载的 PCMCIA 客户端驱动程序。与 /proc/modules 不同,它还列出可能静态链接到内核的驱动程序。

/proc/bus/pccard/*/info

对于每个插槽,描述该插槽的主机控制器及其功能。

/proc/bus/pccard/*/exca

这包含控制器 ``ExCA'' Intel i82365sl 兼容寄存器集的转储。

/proc/bus/pccard/*/{pci,cardbus}

对于 CardBus 桥接器,桥接器的 PCI 配置空间的转储以及桥接器的 CardBus 配置寄存器的转储。

7.5 为新卡编写 Card Services 驱动程序

Linux PCMCIA 程序员指南是客户端驱动程序接口的最佳文档。最新版本始终可以从 projects.sourceforge.net/pub/pcmcia-cs/doc 中获得,或在 Web 上访问 http://pcmcia-cs.sourceforge.net

对于与普通 ISA 设备密切相关的设备,您可能可以使用现有 Linux 驱动程序的部分内容。在某些情况下,最大的障碍将是修改现有驱动程序,使其可以处理在启动后添加和删除设备。在当前的驱动程序中,存储卡驱动程序是唯一“独立的”驱动程序,它不依赖于 Linux 内核的其他部分来完成大部分繁重的工作。

在许多情况下,支持新卡类型的最大障碍是从制造商那里获取技术信息。可能很难弄清楚该问谁,或者准确解释需要哪些信息。但是,除了一些例外,如果没有制造商提供的技术信息,就很难(如果不是不可能)为卡实现驱动程序。

我编写了一个带有大量注释的虚拟驱动程序,其中解释了驱动程序如何与 Card Services 通信;您可以在 PCMCIA 源代码发行版的 clients/dummy_cs.c 中找到它。

7.6 PCMCIA 客户端驱动程序作者指南

我已经决定,将所有 PCMCIA 客户端驱动程序作为 PCMCIA 包的一部分分发对我来说实际上是不可行的。每个新的驱动程序都会使主包的维护难度逐渐增加,并且包含驱动程序不可避免地会将一些维护工作从驱动程序作者转移到我身上。相反,我将根据用户需求以及可维护性,逐个案例地决定是否包含贡献的驱动程序。对于未包含在核心包中的驱动程序,我建议驱动程序作者采用以下方案来打包他们的驱动程序以进行分发。

驱动程序文件应以与 PCMCIA 源代码发行版中使用的目录方案相同的目录方案排列,以便可以将驱动程序解压缩到完整的 PCMCIA 源代码树的顶部。驱动程序应包括源文件(在 ./modules/ 中)、手册页(在 ./man/ 中)和配置文件(在 ./etc/ 中)。顶层目录还应包含 README 文件。

顶层目录应包含一个 makefile,设置为使 ``make -f ... all'' 和 ``make -f ... install'' 编译驱动程序并安装所有适当的文件。如果此 makefile 的扩展名为 .mk,则它将自动由顶层 Makefileallinstall 目标调用。以下是如何构建此类 makefile 的示例:

# Sample Makefile for contributed client driver
FILES = sample_cs.mk README.sample_cs \
        modules/sample_cs.c modules/sample_cs.h \
        etc/sample.conf etc/sample etc/sample.opts \
        man/sample_cs.4
all:
        $(MAKE) -C modules MODULES=sample_cs.o
install:
        $(MAKE) -C modules install-modules MODULES=sample_cs.o
        $(MAKE) -C etc install-clients CLIENTS=sample
        $(MAKE) -C man install-man4 MAN4=sample_cs.4
dist:
        tar czvf sample_cs.tar.gz $(FILES)

此 makefile 使用在 2.9.10 及更高版本的 PCMCIA 包中定义的安装目标。此 makefile 还包括一个 ``dist'' 目标,以方便驱动程序作者。您可能需要在最终软件包文件名中添加版本号(例如,sample_cs-1.5.tar.gz)。完整的发行版可能如下所示:

sample_cs.mk
README.sample_cs
modules/sample_cs.c
modules/sample_cs.h
etc/sample.conf
etc/sample
etc/sample.opts
man/sample_cs.4

通过这种安排,当解压缩贡献的驱动程序时,它实际上成为 PCMCIA 源代码树的一部分。它可以利用 PCMCIA 头文件,以及用于检查用户系统配置的机制,以及自动依赖项检查,就像“普通”客户端驱动程序一样。

在本例中,etc/sampleetc/sample.opts 将是新驱动程序的配置文件(如果需要),etc/sample.conf 将包含对 PCMCIA 卡配置文件的任何添加。从 3.1.6 版本开始,cardmgr 将自动处理安装在 /etc/pcmcia 中的任何 *.conf 文件,因此贡献的驱动程序的安装应该不再需要手动编辑配置文件。

我将接受根据此规范准备的客户端驱动程序,并将它们放在 projects.sourceforge.net 上的 /pub/pcmcia-cs/contrib 目录中。此目录中的 README 文件将描述如何解压缩贡献的驱动程序。

客户端驱动程序接口随着时间的推移变化不大,并且几乎始终保持向后兼容性。客户端驱动程序通常不需要为主包中的次要修订进行更新。我将尝试通知贡献的驱动程序的作者需要更新其驱动程序的更改。

7.7 Linux 发行版维护者指南

如果您的发行版具有您希望 PCMCIA 感知的系统配置工具,请使用 /etc/pcmcia 中的 *.opts 文件作为您的“hooks”。如果用户编译并安装新版本的 PCMCIA 包,这些文件将不会被修改。如果您修改主配置文件,则全新安装将静默覆盖您的自定义脚本并断开与您的配置工具的连接。如果您不确定如何编写适当的选项脚本,或者您需要其他功能,请与我联系。

如果您可以记录您的发行版如何偏离本文档中描述的 PCMCIA 包,这对用户(和我)都很有帮助。特别是,请记录对启动脚本和配置脚本的更改。如果您向我发送适当的信息,我将将其包含在关于特定 Linux 发行版的注释中。

为发行版构建 PCMCIA 时,请考虑包含不属于主 PCMCIA 包的贡献驱动程序。出于可维护性的原因,我正在尝试限制核心包的大小,仅在我认为它们具有特别广泛的兴趣时才添加新驱动程序。其他驱动程序将单独分发,如上一节所述。集成驱动程序和单独驱动程序之间的划分在某种程度上是任意的,并且部分是历史原因造成的,不应暗示质量上的差异。


下一页 上一页 目录