pkg://PCMCIA-HOWTO.tar.gz:51154/PCMCIA-HOWTO-7.html
downloads
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
<HTML>
<HEAD>
<META NAME="GENERATOR" CONTENT="SGML-Tools 1.0.9">
<TITLE>Linux PCMCIA HOWTO: デバッグのヒントとプログラム情報</TITLE>
<LINK HREF="PCMCIA-HOWTO-8.html" REL=next>
<LINK HREF="PCMCIA-HOWTO-6.html" REL=previous>
<LINK HREF="PCMCIA-HOWTO.html#toc7" REL=contents>
</HEAD>
<BODY>
<A HREF="PCMCIA-HOWTO-8.html">次のページ</A>
<A HREF="PCMCIA-HOWTO-6.html">前のページ</A>
<A HREF="PCMCIA-HOWTO.html#toc7">目次へ</A>
<HR>
<H2><A NAME="s7">7. デバッグのヒントとプログラム情報</A></H2>
<H2><A NAME="ss7.1">7.1 有益なバグレポートの送り方</A>
</H2>
<P>最も好ましいバグレポートの送り方は、Linux PCMCIA 情報サイトにある
HyperNews のメッセージリストを使うことです。この方法なら、現状の問題
(そして、もしあれば修正方法や回避方法)が他の人にも見えるからです。
バグレポートに必須の項目を以下に示します:
<P>
<UL>
<LI>お使いのマシンの品名とモデル</LI>
<LI>お使いの PCMCIA カード</LI>
<LI>Linux のカーネルのバージョン(``<CODE>uname -rv</CODE>'' の実行結果)と
PCMCIA のドライバのバージョン(``<CODE>cardctl -V</CODE>'' の実行結果)</LI>
<LI><CODE>/etc/pcmcia</CODE> にある起動ファイルや PCMCIA 起動スクリプト
に加えて変更全て</LI>
<LI>システムのログファイルに記録された PCMCIA に関わる内容全て。
これは起動メッセージとカードの設定時に出力されたメッセージを含みます。</LI>
</UL>
<P>PCMCIA モジュールと <CODE>cardmgr</CODE> デーモンはステータスメッセージを
システムログに送ります。システムログは普通、
<CODE>/var/log/messages</CODE> や <CODE>/usr/adm/messages</CODE> といった名前
だと思います。問題を調べるときには、このファイルを最初に見るべきです。
バグレポートを送る時にも、このファイルの内容は必ず入れてください。
システムのメッセージが見つからない場合には、<CODE>/etc/syslog.conf</CODE>
を見て、他のクラスのメッセージの出力先を調べてください。
<P>バグレポートを送る前には、最新のドライバを使っていることを必ず確認して
ください。既に直したバグのバグレポートを読むのは嬉しくないことでもない
のですが、これはあまり有効な時間の使い方ではありませんから。
<P>WWW にアクセスできなければ、直接私宛(
<CODE>
<A HREF="mailto:dhinds@pcmcia.sourceforge.org">dhinds@pcmcia.sourceforge.org</A></CODE>)
にメールで送ってくださっても構いません。ただし、できればバグレポートは
他の人にも見せられるように、WWW サイトの方に送って欲しいと思っています。
<P>
<H2><A NAME="ss7.2">7.2 カーネルのトラップ通知の解釈</A>
</H2>
<P>もしカーネル自身がフォールトする(エラーを起す)場合、あなたが問題となる
アドレス、EIP 等から何か意味を読み取れるとしても、レジスタのダンプ情報
しか役に立たないでしょう。最近のバージョンの <CODE>klogd</CODE> はフォールトが
起きたアドレスを、現在のカーネルのシンボルマップに基づいて変換しますが、
フォールトがモジュール内で起こった場合や問題が深刻で <CODE>klogd</CODE> がフォー
ルトの情報をシステムログに書き込めない場合にはこの方法は使えません。
<P>フォールトがカーネル本体で起こっている場合、フォールトが起きたアドレス
は <CODE>System.map</CODE> ファイルに残ります。このファイルは
<CODE>/System.map</CODE> か <CODE>/boot/System.map</CODE> にあると思います。
フォールトがモジュールで起こっている場合には、<CODE>nm</CODE> コマンドを使えば
同じ情報が得られますが、フォールトが起きたアドレスはモジュールがロード
されたアドレスが基準になっています。例えば、カーネルが以下のような
フォールトを起こしたとします:
<P>
<BLOCKQUOTE><CODE>
<PRE>
Unable to handle kernel NULL pointer dereference
current->tss.cr3 = 014c9000, %cr3 = 014c9000
*pde = 00000000
Oops: 0002
CPU: 0
EIP: 0010:[<c2026081>]
EFLAGS: 00010282
</PRE>
</CODE></BLOCKQUOTE>
<P>フォールトが起きたアドレスは 0xc2026081 です。<CODE>System.map</CODE> を見ると、
このアドレスはカーネルの最後のアドレスを越えているが分かるでしょう。つ
まり、フォールトはカーネルモジュールで起きているのです。どのモジュール
でフォールトが起きたのかを調べるために、``<CODE>ksyms -m | sort</CODE>'' の
出力を調べましょう:
<P>
<BLOCKQUOTE><CODE>
<PRE>
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]
</PRE>
</CODE></BLOCKQUOTE>
<P>したがって 0xc2026081 は <CODE>3c574_cs</CODE> モジュールの内部で、モジュール
の先頭からのオフセットが 0x0081 です。<CODE>3c574_cs.o</CODE> 内部のこのオフセット
位置を参照する方法は今のところありません。カーネルがモジュールをロード
した時、カーネルはモジュールをロードしたアドレスの先頭にヘッダを入れる
ので、実際にモジュールが始まる位置は <CODE>ksyms</CODE> が示すアドレスから
オフセットを取った位置となります。ヘッダの大きさはカーネルのバージョン
ごとに異なります。お使いのカーネルでのヘッダの大きさを調べるには、
シンボルをエクスポートしているモジュール(前述の <CODE>pcmcia_core</CODE> 等)を
調べ、シンボルいずれかのアドレスをそのシンボルに対する <CODE>nm</CODE> コマンド
の出力と比較します。この例では、<CODE>register_ss_entry</CODE> は
0xc200d10c - 0xc200d000 = 0x010c というオフセット位置にロードされてい
ます。ここで ``<CODE>nm pcmcia_core.o</CODE>'' は 0x00c0 というオフセットを示
していますから、ヘッダの大きさは 0x010c - 0x00c0 = 0x004c ということに
なります。
<P><CODE>3c574_cs</CODE> の話に戻ると、フォールトが起きたオフセット位置は 0x0081
なので、これからヘッダの大きさである 0x004c を引くと、モジュールの実際
の位置は 0x0035 となります。ここで ``<CODE>nm 3c574_cs.o | sort</CODE>'' を
実行すると以下のような出力となります:
<P>
<BLOCKQUOTE><CODE>
<PRE>
0000002c d if_names
0000002c t tc574_attach
00000040 d mii_preamble_required
00000041 d dev_info
</PRE>
</CODE></BLOCKQUOTE>
<P>したがって、フォールトが起きた位置は <CODE>tc574_attach()</CODE> です。
<P>この例では、フォールトでシステム全体が固まることはないので、フォールト
が起きた後に <CODE>ksyms</CODE> を実行することもできます。場合によっては、
モジュールがロードされた位置を間接的に推測するしかないこともあります。
同じ順序で操作すれば、普通はモジュールも同じ順序で同じ位置にロードされ
ます。特定のカードを挿入した時にフォールトが起こる場合は、そのカードを
挿す直前か、代わりに別のカードを挿した時の <CODE>ksyms</CODE> コマンドの出力を
調べましょう。カードを挿す前に手動で <CODE>insmod</CODE> でカードのドライバ
モジュールをロードし、<CODE>ksyms</CODE> コマンドを実行するという方法もありま
す。
<P>背景を詳しく知りたければ ``<CODE>man insmod</CODE>'', ``<CODE>man ksyms</CODE>'',
``<CODE>man klogd</CODE>'' を見てください。カーネルのソースコードに入っている
<CODE>Documentation/oops-tracing.txt</CODE> も関連があります。カーネルの
デバッグ関連のヒントをいくつか紹介します:
<P>
<UL>
<LI>フォールトの種類によっては、「呼び出しトレース」のアドレスに変換
するのも役立ちます。変換の手順は、普通のフォールトアドレスの場合と同じ
です。</LI>
<LI>何もメッセージを出さずにシステムが固まってしまう場合には、X を使
わない状態で問題を再現してみてください。というのも、テキストコンソール
に送られるカーネルメッセージは X 上では読めないからです。</LI>
<LI><CODE>klogd</CODE> を殺してあると、ほとんどのカーネルメッセージは直接
テキストコンソールに表示されます。この方法は、<CODE>klogd</CODE> からシステム
ログに書き込みができなくなってしまう問題が起きた時に役立ちます。</LI>
<LI>カーネルのバージョンが 2.1 で、かつ
<CODE>/proc/sys/kernel/printk</CODE> が存在するならば、以下の操作で全ての
カーネルメッセージをコンソールに送ることができます:
<BLOCKQUOTE><CODE>
<PRE>
echo 8 > /proc/sys/kernel/printk
</PRE>
</CODE></BLOCKQUOTE>
</LI>
<LI><右Alt><ScrLk> というキーの組合せで、レジスタの
ダンプをコンソールに出力することができます。これはシステムが完全に反応
しない状態でも動作するかもしれません。また、EIP アドレスはカーネルフォー
ルト用のアドレスに変換されます。</LI>
<LI>バージョン 2.1 のカーネルでは[訳注: 2.2 も同様です]、
<CODE>CONFIG_MAGIC_SYSRQ</CODE> を有効に
してあると、特別な <Alt><SysRq> というキーの組合せで様々な
緊急用機能を使うことができます。この機能については、カーネルのソースツリー
に入っている <CODE>Documentation/sysrq.txt</CODE> をご覧ください。</LI>
</UL>
<P>
<H2><A NAME="pcdebug"></A> <A NAME="ss7.3">7.3 PCMCIA の低レベルのデバッグを行うための情報</A>
</H2>
<P>PCMCIA モジュールにはコンパイル時のオプションで決まるデバッグ用コード
がたくさん含まれています。 これらのコードの大部分はプリプロセッサの
<CODE>PCMCIA_DEBUG</CODE> という定義で制御されています。もし
<CODE>PCMCIA_DEBUG</CODE> が未定義ならば、デバッグ用のコードはコンパイルさ
れません。もし 0 に定義されていれば、コードはコンパイルされるものの、
利用されません。この数字を大きくすればデバッグメッセージはより細かくな
ります。<CODE>PCMCIA_DEBUG</CODE> を定義してコンパイルした各モジュールには
整数を値に持つ <CODE>pc_debug</CODE> という変数が設定され、この変数でデバッグ
出力の詳しさを制御できます。この変数はモジュールがロードされる際に設定
できるので、再コンパイルを行わなくてもモジュール別にデバッグ出力を制御
することができます。
<P><CODE>syslogd</CODE> のデフォルトの設定は、カーネルのデバッグメッセージを無視
するようになっているかもしれません。これを確実に記録するためには、
<CODE>/etc/syslog.conf</CODE> を編集して、``<CODE>kern.debug</CODE>'' クラスの
メッセージがどこかに記録されるようにします。詳しくは
``<CODE>man syslog.conf</CODE>'' をご覧ください。
<P>PCMCIA パッケージの <CODE>debug_tools/</CODE> ディレクトリには、デバッグ用
のツールがいくつか入っています。<CODE>dump_tcic</CODE> と
<CODE>dump_i365</CODE> コマンドは PCMCIA コントローラのレジスタを全て
ダンプし、多くのレジスタ情報をデコードします。これらのコントローラ
チップのデータシートを参照できるなら、この情報は非常に有効でしょう。
<CODE>dump_cis</CODE>(バージョン 3.0.2 以前は <CODE>dump_tuples</CODE>)コマンド
は、カードの CIS(Card Information Structure)を出力し、いくつかの重要な
ビットをデコードします。<CODE>dump_cisreg</CODE> コマンドはカードのローカル
な設定レジスタを出力します。
<P>メモリカードドライバである <CODE>pcmem_cs</CODE> も 16 ビット PC カードの
デバッグに役立つことがあります。このドライバはどんな PCMCIA カードに対
しても利用でき、他のドライバと干渉することもありません。このドライバを
使えば、どんなカードの属性メモリや共通メモリにも直接アクセスできます。
CardBus カードの場合も同様で、<CODE>memory_cb</CODE> ドライバはどんな 32 ビッ
トカードに対しても使うことができ、カードのアドレス空間にも直接アクセス
することができます。詳しくはオンラインマニュアルを参照してください。
<P>
<H2><A NAME="ss7.4">7.4 /proc/bus/pccard</A>
</H2>
<P>バージョン 2.1.103 以降のカーネルでは、PCMCIA パッケージはステータス情報
のツリーを <CODE>/proc/bus/pccard</CODE> ディレクトリ以下に作り
ます。この情報の多くは、PCMCIA ホストコントローラのデータシートを使わ
ないと意味が分かりません。この内容はドライバの設定によりますが、以下の
情報の全てあるいは一部を含んでいると思います:
<P>
<DL>
<DT><B><CODE>/proc/bus/pccard/{irq,ioport,memory}</CODE></B><DD><P>これらのファイルがある場合には、カーネルの通常のリソーステーブルを補う
ためのリソースの割り当て情報が書かれています。最近のバージョンの
PCMCIA システムは、(設定がしてあれば)追加のリソース情報をプラグ&プ
レイ BIOS からできます。
<DT><B><CODE>/proc/bus/pccard/drivers</CODE></B><DD><P>最近のリリースでは、このファイルには現在ロードされている PCMCIA クライ
アントドライバが列挙されています。<CODE>/proc/modules</CODE> と異なり、こ
のファイルはカーネル内に静的にリンクされているかもしれないドライバも列
挙します。
<DT><B><CODE>/proc/bus/pccard/*/info</CODE></B><DD><P>それぞれのソケットについて、ソケットのホストコントローラとその機能を示
します。
<DT><B><CODE>/proc/bus/pccard/*/exca</CODE></B><DD><P>このファイルには、コントローラの ``ExCA'' Intel i82365sl 互換レジスタ
セットのダンプが含まれています。
<DT><B><CODE>/proc/bus/pccard/*/{pci,cardbus}</CODE></B><DD><P>CardBus ブリッジについての、ブリッジの PCI 設定空間のダンプと、
ブリッジの CardBus 設定レジスタのダンプが含まれています。
</DL>
<P>
<H2><A NAME="ss7.5">7.5 出たばかりのカード向けに PCMCIA カードサービスのドライバを書くには</A>
</H2>
<P>``Linux PCMCIA Programmer's Guide'' がクライアントドライバインタフェース
に関する最善の文書です。最新版は <CODE>sourceforge.org</CODE> の
<CODE>/pub/pcmcia/doc</CODE> ディレクトリにあります。WWW 上では
<A HREF="http://pcmcia.sourceforge.org">http://pcmcia.sourceforge.org</A>
から入手できます。
<P>使いたいデバイスが普通の ISA デバイスによく似ていれば、既存の Linux 用
のドライバの一部を流用することもできるでしょう。場合によっては、既存の
ドライバを修正してブート後にもデバイスを追加したり外したりできるように
するのがもっとも苦労するところです。今あるドライバの中では、メモリカード
用のドライバが、あらゆる種類の汚れ仕事をするのにカーネルの他の部分を利
用しない、唯一の「自己完結した」ドライバです。
<P>多くの場合、新しい種類のカードをサポートする際の最大の障害は、メーカー
から技術情報を入手することです。誰に頼めばよいかも分かりにくいですし、
どんな情報が必要かを正確に説明するのも困難です。しかし、一部の例外を除
くと、メーカーからの技術情報無しでドライバを書くのは不可能とは行かない
までも非常に困難です。
<P>ドライバがカードサービスシステムとどのように通信するかを説明するために、
多数のコメントを入れたダミーのドライバを用意しています。PCMCIA パッケージ
のソースコードに入っている <CODE>clients/dummy_cs.c</CODE> がそれです。
<P>
<H2><A NAME="ss7.6">7.6 PCMCIA クライアントドライバを書く人のための手引き</A>
</H2>
<P>
<P>私は、全ての PCMCIA クライアントドライバを PCMCIA パッケージの一部とし
て配布するのは本当は適切でないと考えています。新しいドライバが加わるた
びに本家のパッケージも段々メンテナンスしにくくなりますし、ドライバを取
り込むとメンテナンス作業の一部がドライバの作者から私へ移ってくるのも明
らかです。そこで全てのドライバを取り込む代わりに、寄付されたドライバは
ケースバイケースの判断で取り込むかどうかを決めています。判断はユーザの
要望やメンテナンス性に基づいて行っています。本家のパッケージに取り込ま
なかったドライバについては、私はドライバの作者に以下の方法で配布用のド
ライバパッケージを作るようにお願いしています。
<P>ドライバファイルは、PCMCIA のソース配布物で使われているのと同じディレクトリ
配置にしなければなりません。これはドライバを PCMCIA ソースツリーのトップ
ディレクトリで展開できるようにするためです。ドライバには
ソースファイル(<CODE>./modules/</CODE> ディレクトリ内)、
オンラインマニュアル(<CODE>./man/</CODE> ディレクトリ内)、
設定ファイル(<CODE>./etc/</CODE>)が含まれていなければなりません。トップレベル
ディレクトリには README ファイルもなければなりません。
<P>トップレベルディレクトリには makefile が必要で、これは
``<CODE>make -f ...</CODE> all'' でドライバをコンパイルでき、
``<CODE>make -f ... install</CODE>'' で必要なファイルを全てインストールできる
ように設定されていなければなりません。この makefile に <CODE>.mk</CODE> という
拡張子が付いていれば、このファイルはトップレベルの <CODE>Makefile</CODE> から
ターゲット <CODE>all</CODE> と <CODE>install</CODE> について自動的に呼び出されます。
このような makefile の作り方の例を以下に示します:
<P>
<BLOCKQUOTE><CODE>
<PRE>
# Sample Makefile for contributed client driver
FILES = sample_cs.mk README.sample_cs \
modules/sample_cs.c modules/sample_cs.h \
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)
</PRE>
</CODE></BLOCKQUOTE>
<P>この makefile では、バージョン 2.9.10 以降の PCMCIA パッケージで定義さ
れているインストールターゲットを使っています。この makefile には、
ドライバ作者の利便のための ``dist'' ターゲットも入っています。最終的な
パッケージのファイル名にはバージョン番号も入れるとよいでしょう(
<CODE>sample_cs-1.5.tar.gz</CODE> 等)。完成品の配布ファイルの内容は以下のよう
になります:
<P>
<BLOCKQUOTE><CODE>
<PRE>
sample_cs.mk
README.sample_cs
modules/sample_cs.c
modules/sample_cs.h
etc/sample
etc/sample.opts
man/sample_cs.4
</PRE>
</CODE></BLOCKQUOTE>
<P>このファイル配置であれば、寄付されたドライバのパッケージを展開した時に、
実質的に PCMCIA のソースツリーの一部となります。PCMCIA のヘッダファイル
やユーザのシステム設定を調べる仕組みの利用、ファイルの依存関係の自動チェック
を「通常の」クライアントドライバと同じように行うことができます。
<P>私はこの仕様に準拠しているクライアントドライバを受け取れば、
<CODE>sourceforge.org</CODE> の <CODE>/pcmcia/contrib</CODE> ディレクトリに置きま
す。このディレクトリにある README ファイルに、寄付されたドライバの
展開方法が書いてあります。
<P>クライアントドライバのインタフェースは昔からあまり変わっていませんし、
後方互換性はほぼ保たれています。本家のパッケージのマイナーバージョンが
上がっても普通は更新の必要はないでしょう。ドライバの更新が必要となるよ
うな変更があれば、ドライバを寄付してくださった作者の方々にはできるだけ
お知らせするようにします。
<P>
<H2><A NAME="ss7.7">7.7 Linux ディストリビューションのメンテナのための手引き</A>
</H2>
<P>
<P>あなたが作っているディストリビューションのシステム設定ツールを PCMCIA
対応にしようとしているのなら、<CODE>/etc/pcmcia</CODE> にある
<CODE>*.opts</CODE> ファイルを「止め具」として使ってください。これらの
ファイルは、ユーザが新しいバージョンの PCMCIA パッケージのコンパイルと
インストールを行っても変更されません。メインの設定スクリプトを修正する
と、最初からのインストールを行った時にカスタマイズしたスクリプトが黙っ
て上書きされ、設定ツールとの連係が途切れてしまいます。適切なオプション
スクリプトの書き方が分からない場合や、追加の機能が必要な場合は、私に相
談してください。
<P>あなたのディストリビューションとこの文書で説明している PCMCIA パッケージ
の相違点を文書化してくだされば、ユーザにとって(そして私にとっても)役立
つでしょう。特に、起動スクリプトと設定スクリプトに関する変更点はぜひ
文書化してください。適切な情報を私まで送っていただければ、
<A HREF="PCMCIA-HOWTO-2.html#distributions">個別ディストリビューションに関する注意</A>
の節に追加させていただきます。
<P>ディストリビューション用に PCMCIA パッケージを作る際には、寄付された
ドライバ群は本家の PCMCIA パッケージの一部ではない点を覚えていてくださ
い。メンテナンス上の理由により中心となるパッケージのサイズは制限しよう
としており、新しいドライバを追加するのは特に需要が高いと思われるときだ
けです。その他のドライバについては前の章で説明した通り、本家とは別に配
布しています。本家に統合されているドライバと別配布になっているドライバ
の違いにはたいした意味はなく、歴史的経緯もある程度含まれています。また、
品質的な違いがあるわけでは決してありません。
<P>
<HR>
<A HREF="PCMCIA-HOWTO-8.html">次のページ</A>
<A HREF="PCMCIA-HOWTO-6.html">前のページ</A>
<A HREF="PCMCIA-HOWTO.html#toc7">目次へ</A>
</BODY>
</HTML>