Solaris インタフェースを使用するアプリケーションが Solaris ABI に準拠しているかどうかを確認するために、Solaris オペレーティングシステムは 2 つのツールを提供します。appcert ユーティリティーは、ELF バイナリが使用している Solaris ライブラリインタフェースの非公開インタフェースの使用状況のインスタンスについて静的な調査を行います。次に、appcert ユーティリティーは潜在的なバイナリ安定性の問題について、要約レポートと詳細レポートを生成します。apptrace ツールは実行時リンカーのリンク監視機能を使用して、アプリケーションを実行しながら動的に Solaris ライブラリルーチン呼び出しをトレースします。この機能によって、開発者は、アプリケーションが Solaris システムインタフェースを使用しているかどうかを調査できます。
ABI ツールを使用すると、特定の Solaris リリースで互換性の問題が存在するバイナリをすばやく簡単に識別できます。バイナリ安定性を確認するには、次のようにします。
現在の Solaris リリース上で appcert を使用して、問題のあるバイナリを選別します。どのバイナリが問題のあるインタフェースを使用しているか否かを識別します。
ターゲットの Solaris リリース上で apptrace を使用して、問題が存在するかどうかを確認します。インタフェースを使用しながら動的に観察することによって、インタフェース互換性の問題が存在するかどうかを確認できます。
appcert ユーティリティーは、ELF バイナリを静的に調査して、使用されているライブラリシンボルを特定の Solaris リリースにおける公開インタフェースまたは非公開インタフェースのモデルに対して比較する Perl スクリプトです。このユーティリティーは SPARC または Intel のどちらのプラットフォーム上でも動作します。SPARC と Intel の 32 ビットインタフェースだけでなく、SPARC の 64 ビットインタフェースの使用状況も確認できます。appcert ユーティリティーは C 言語インタフェースだけを調査することに注意してください。
新しい Solaris リリースが入手可能になると、いくつかのライブラリインタフェースは動作が変わったり、完全になくなったりします。すると、このようなインタフェースに依存するアプリケーションの性能に影響を与えることがあります。Solaris ABI は、アプリケーションが安全かつ安定して使用できる実行時ライブラリインタフェースを定義します。appcert ユーティリティーは、アプリケーションが Solaris ABI に準拠していることを開発者が確認できるように設計されています。
アプリケーションを調査するとき、appcert ユーティリティーは次のことを確認します。
非公開シンボルの使用
静的なリンク
非結合シンボル
非公開シンボルとは、Solaris ライブラリがお互いを呼び出すときに使用する関数またはデータのことです。非公開シンボルの意味論的な動作は変更されることがあり、ときには、削除されることもあります。このようなシンボルのことを「降格シンボル」と呼びます。非公開シンボルは変更されやすいので、非公開シンボルに依存しているアプリケーションには潜在的に安定性に問題があります。
Solaris ライブラリ間で非公開シンボルを呼び出すとき、その意味論はリリースごとに変わる可能性があります。したがって、アーカイブに静的にリンクすると、アプリケーションのバイナリ安定性が低下します。この問題を回避するためには、このようなアーカイブに対応する共有オブジェクトファイルに動的にリンクすることが必要です。
アプリケーションを調査するとき、appcert ユーティリティーは動的リンカーを使用してアプリケーションが使用するライブラリシンボルを解決します。このとき、動的リンカーが解決できないシンボルのことを「非結合シンボル」と呼びます。非結合シンボルの原因には、LD_LIBRARY_PATH 環境変数が正しく設定されていないなどの環境の問題があります。非結合シンボルの原因にはまた、コンパイル時に -llib または -z のスイッチの定義を省略したなどの構築時の問題もあります。ただしこのような例はまれで、多くの場合 appcert が非結合シンボルを報告するときは、存在しない非公開シンボルに依存しているなど、より深刻な問題が発生していることになります。
appcert ユーティリティーで調査しているオブジェクトファイルがライブラリに依存する場合、このような依存関係をオブジェクトに記録しておく必要があります。このような依存関係をオブジェクトに記録するには、コードをコンパイルするときに、コンパイラの -l スイッチを使用します。オブジェクトファイルがほかの共有ライブラリに依存する場合、appcert ユーティリティーを実行するときに、このような共有ライブラリには LD_LIBRARY_PATH または RPATH 経由でアクセスできる必要があります。
マシンが 64 ビットの Solaris カーネルを実行していなければ、appcert ユーティリティーは 64 ビットアプリケーションを確認できません。Solaris では 64 ビットの静的ライブラリが提供されていないため、appcert は 64 ビットアプリケーションの静的リンクを確認しません。
appcert は次のことを確認できません。
完全または部分的に静的にリンクされているオブジェクトファイル。完全に静的にリンクされているオブジェクトは「unstable (安定していない)」と報告される
実行権が設定されていない実行可能ファイル。appcert ユーティリティーはこのような実行可能ファイルをスキップする。実行権が設定されていない共有オブジェクトは通常どおりに確認する
ユーザー ID が root に設定されているオブジェクトファイル
ELF 以外の実行可能ファイル (シェルスクリプトなど)
C 言語以外の言語の Solaris インタフェース。コードは C 言語である必要はないが、Solaris ライブラリへの呼び出しは C 言語を使う必要がある
appcert を使用して、利用しているアプリケーションを確認するには、次のように入力します。
appcert object|directory |
object|directory は次のどちらかです。
appcert で調査したいオブジェクトの完全な一覧
このようなオブジェクトが格納されているディレクトリの完全な一覧
appcert ユーティリティーは、アプリケーションを実行する環境とは異なる環境で実行する場合もあります。このような環境では、appcert ユーティリティーは Solaris ライブラリインタフェースへの参照を正しく解決できないことがあります。
appcert は Solaris 実行時リンカーを使用して、実行可能ファイルまたは共有オブジェクトファイルごとにインタフェース依存関係のプロファイルを構築します。このプロファイルを使用すると、アプリケーションが依存している Solaris システムインタフェースを判断できます。このプロファイルに記述されている依存関係を Solaris ABI と比較すると、Solaris ABI への準拠を確認できます。このプロファイルには、非公開インタフェースが見つかってはなりません。
appcert はディレクトリを再帰的に検索して、ELF 以外を無視しながら、オブジェクトファイルを探します。アプリケーションの確認が終了すると、appcert は検索結果レポートを標準出力 (通常は画面) に出力します。このレポートは、作業用ディレク トリ (通常は /tmp/appcert.pid) の Report という名前のファイルに書き込まれます。このサブディレクトリ名の pid は 1 から 6 桁の数字であり、appcert の当該インスタンスのプロセス ID を示します。appcert が出力ファイルに書き込むディレクトリ構造の詳細については、「appcert の結果」を参照してください。
次のオプションで、appcert の動作を変更できます。次のオプションは、コマンド行において appcert コマンドから object|directory オペランドの間のどこにでも入力できます。
appcert ユーティリティーをバッチモードで実行します。
バッチモードでは、appcert は確認するバイナリごとに 1 行をレポートに書き込みます。
PASS で始まる行は、その行が示すバイナリには appcert の警告が発行されなかったことを意味します。
FAIL で始まる行は、その行が示すバイナリに問題が見つかったことを意味します。
INC で始まる行は、その行が示すバイナリが完全には確認できなかったことを意味します。
ファイル infile には、確認すべきファイルの一覧がファイル名ごとに 1 行ずつ書き込まれている必要があります。このファイルで指定されたファイルは、コマンド行に指定されたファイルに追加されます。このスイッチを使用する場合、オブジェクトまたはディレクトリをコマンド行に指定する必要はありません。
appcert の使用法を出力します。
デフォルトでは、appcert はアプリケーション内にあるすべての共有オブジェクトを記して、このような共有オブジェクトが入っているディレクトリを LD_LIBRARY_PATH に追加しますが、-L スイッチはこの動作を無効にします。
デフォルトでは、ディレクトリを検索して確認すべきバイナリを探すとき、appcert はシンボリックリンクに従います。-n スイッチはこの動作を無効にします。
Solaris ライブラリディレクトリ /usr/openwin/lib および /usr/dt/lib を LD_LIBRARY_PATH に追加します。
ライブラリ構成要素を実行するディレクトリを指定します。このスイッチを指定した場合、appcert は一時ファイルをこのディレクトリに作成します。このスイッチを指定しない場合、appcert は一時ファイルを /tmp ディレクトリに作成します。
appcert を使用すると、指定されたセットの中でどのアプリケーションが潜在的に安定性の問題を抱えているかをすばやく簡単に識別できます。appcert が何も安定性の問題を報告しなかった場合、そのアプリケーションは、以降の Solaris リリースでもバイナリ安定性の問題が報告されることは起こりにくいと考えられます。次の表に、よくあるバイナリ安定性問題の一覧を示します。
表 13–1 よくあるバイナリ安定性問題
問題 |
回避方法 |
---|---|
ある非公開シンボルを使用しているが、変更されることがわかっている |
このようなシンボルの使用をすぐに停止する |
ある非公開シンボルを使用しているが、まだ変更されていない |
今のところアプリケーションは動作しているが、このようなシンボルの使用をできるだけ早く停止する |
あるライブラリに静的にリンクしているが、同等な共有オブジェクトを入手できる |
代わりに、同等な共有オブジェクトを使用する |
あるライブラリに静的に共有しているが、同等な共有オブジェクトを入手できない |
可能であれば、ld -z allextract を使用して、.a ファイルを .so ファイルに変換する。変換できない場合、共有オブジェクトが利用できるようになるまで、静的なライブラリを使用し続ける |
ある非公開シンボルを使用しているが、同等な公開シンボルを入手できない |
Sun に連絡して、公開インタフェースを要求する |
あるシンボルを使用しているが、評判が悪いか、削除されることが計画されている |
今のところアプリケーションは動作しているが、このようなシンボルの使用をできるだけ早く停止する |
ある公開シンボルを使用しているが、すでに変更されている |
コンパイルし直す |
リリースによっては、非公開インタフェースを使用することによる潜在的な安定性の問題が発生しないこともあります。なぜなら、リリースが変わっても、非公開インタフェースの動作が変更されるとは限らないためです。ターゲットリリースで非公開インタフェースの動作が変更されているかどうかを確認するには、apptrace を使用します。apptrace の使用法については、「apptrace によるアプリケーションの確認」を参照してください。
appcert ユーティリティーがアプリケーションのオブジェクトファイルを解析した結果は、appcert ユーティリティーの作業用ディレクトリ (通常は /tmp) にあるいくつかのファイルに書き込まれます。作業用ディレクトリの下にあるメインサブディレクトリは appcert.pid です。このとき、pid は appcert の当該インスタンスのプロセス ID です。appcert ユーティリティーの結果は、次のファイルに書き込まれます。
確認されたバイナリ間のマッピングと、当該バイナリに固有な appcert の出力が格納されているサブディレクトリ名が書き込まれる
appcert を実行したときに stdout に出力されたレポートのコピーが書き込まれる
appcert が確認しようとしたが強制的にスキップされたバイナリの一覧と、各バイナリがスキップされた理由が書き込まれる。スキップされる理由には次のようなものが挙げられる
ファイルがバイナリオブジェクトではない
当該ユーザーではファイルを読み取ることができない
ファイル名にメタキャラクタが含まれている
ファイルの実行ビットが設定されていない
objects サブディレクトリの下には、appcert が確認するオブジェクトごとのサブディレクトリが作成される。サブディレクトリごとに、次のようなファイルが格納される
Solaris 降格シンボルであると appcert が疑っているシンボルの一覧
オブジェクトが直接バインドされている Solaris 非公開シンボルの一覧
オブジェクトが直接バインドされている Solaris 公開シンボルの一覧
ldd -r を実行したときに、動的リンカーによってバインドされなかったシンボルの一覧。ldd が返す行には、「file not found 」も含まれる
appcert が調査したオブジェクト内にある動的バインドの要約がプリンタ形式で書き込まれる (各 Solaris ライブラリから使用される公開シンボルと非公開シンボルのテーブルも含まれる)
appcert は終了するときに、次の 4 つのうちの 1 つを返します。
appcert はバイナリ安定性問題の潜在的な原因を見つけなかった。
appcert は正常に実行されなかった。
appcert が確認した一部のオブジェクトにバイナリ安定性問題が見つかった。
appcert が確認すべきバイナリオブジェクトが見つからなかった。
非公開シンボルの使用 – 開発したときの Solaris リリースとは異なる Solaris リリース上で実行しようとすると、非公開シンボルに依存するアプリケーションは動作しない可能性があります。これは、非公開シンボルは Solaris リリース間で変更または削除される可能性があるためです。アプリケーション内で非公開シンボルが使用されていることを appcert が報告した場合は、非公開シンボルを使用しないようにアプリケーションを再作成してください。
降格シンボル – 降格シンボルとは、あとの Solaris リリースにおいて削除された、あるいは、有効範囲がローカルに制限された Solaris ライブラリの関数またはデータ変数のことです。このようなシンボルを直接呼び出すアプリケーションは、ライブラリが当該シンボルをエクスポートしないリリース上では動作できません。
非結合シンボル – 非結合シンボルとは、アプリケーションが参照するライブラリシンボルのうち、appcert によって呼び出されたときに動的リンカーが解決できなかったライブラリシンボルのことです。非結合シンボルは必ずしも常にバイナリ安定性が低いことを示す指標ではありませんが、降格シンボルへの依存関係など、より深刻な問題が発生していることを示す場合もあります。
廃止ライブラリ – 廃止ライブラリとは、将来のリリースで Solaris オペレーティング環境から削除される可能性があるライブラリのことです。appcert ユーティリティーは廃止ライブラリのすべての使用に対して警告を発します。廃止ライブラリに依存するアプリケーションは、将来のリリースでサポートされなくなり、機能しなくなる可能性があります。廃止ライブラリのインタフェースを使用しないでください。
sys_errlist または sys_nerr の使用 – sys_errlist シンボルおよび sys_nerr シンボルを使用すると、バイナリ安定性が低下することがあります。これは、sys_errlist 配列の終わりを越えた参照が行われる可能性があるためです。代わりに strerror を使用してください。
強いシンボルと弱いシンボルの使用 – 将来の Solaris リリースで動作が変更される可能性があるので、弱いシンボルに関連付けられた強いシンボルは非公開シンボルとして予約されます。アプリケーションは弱いシンボルに直接参照する必要があります。強いシンボルの例としては、弱いシンボル socket に関連付けられた _socket があります。
apptrace は、アプリケーションを実行しながら動的に Solaris ライブラリルーチンへの呼び出しをトレースする C 言語のプログラムです。apptrace ユーティリティーは SPARC または Intel のどちらのプラットフォーム上でも動作します。apptrace ユーティリティーは、SPARC と Intel の 32 ビットインタフェースだけではなく、SPARC の 64 ビットインタフェースへのインタフェース呼び出しをトレースできます。ただし appcert と同様に、apptrace が調査するのは C 言語のインタフェースだけです。
appcert を使用してアプリケーションのバイナリ安定性低下の危険性を判断した後は、apptrace を使用して各ケースの危険度を評価します。apptrace を使用すると、アプリケーションが各インタフェースを正しく使用しているかどうかを確認し、特定のリリースとのバイナリ互換性を判断できます。
apptrace を用いると、アプリケーションが公開インタフェースを正しく使用しているかどうかを確認できます。たとえば、システム管理ファイル /etc/passwd を開くとき、アプリケーションは open() を使用するのではなく、適切なプログラマティックインタフェースを使用する必要があります。このような Solaris ABI を正しく使用しているかどうかを検査できる機能を使用すると、潜在的なインタフェースの問題をすばやく簡単に識別できます。
apptrace を実行するとき、トレースするアプリケーションは何も変更する必要がありません。apptrace を使用するには、まず apptrace と入力し、次に希望のオプションを入力し、最後に対象となるアプリケーションを実行するコマンド行を入力します。apptrace は実行時リンカーのリンク監査機能を使用して、アプリケーションによる Solaris ライブラリインタフェースへの呼び出しを遮断します。次に、apptrace は呼び出しをトレースして、呼び出しの引数と戻り値についての名前と値を出力します。トレースは単一の行に出力することも、読みやすさのために複数の行に分けて出力することも可能です。公開インタフェースは人が読める形式で出力されます。非公開インタフェースは 16 進数で出力されます。
apptrace は、個々のインタフェースとライブラリの両方のレベルで、トレースする呼び出しを選択できます。たとえば、apptrace は libnsl からの printf() の呼び出しをトレースすることができ、特定のライブラリ内のさまざまな呼び出しをトレースすることもできます。apptrace はまた、ユーザーが指定した呼び出しを詳細にトレースできます。apptrace の動作を命令する仕様は、truss(1) の使用法と整合する構文によって制御されます。-f オプションを指定すると、apptrace はフォークされた子プロセスもトレースします。-o オプションを指定すると、apptrace は o に指定されたファイルに結果を出力します。
apptrace がトレースするのはライブラリレベルの呼び出しだけであり、また、実行中のアプリケーションのプロセスにロードされるので、truss よりも性能が上がります。しかし、printf は例外ですが、apptrace は可変引数リストを受け入れたり、スタックまたは呼び出し元の情報を調査する関数への呼び出しをトレースできません (たとえば、setcontext、getcontext、setjmp、longjmp、および vfork)。
次は、apptrace で単純な 1 バイナリアプリケーション ls をトレースしたときの出力例です。
% apptrace ls /etc/passwd ls -> libc.so.1:atexit(func = 0xff3cb8f0) = 0x0 ls -> libc.so.1:atexit(func = 0x129a4) = 0x0 ls -> libc.so.1:getuid() = 0x32c3 ls -> libc.so.1:time(tloc = 0x23918) = 0x3b2fe4ef ls -> libc.so.1:isatty(fildes = 0x1) = 0x1 ls -> libc.so.1:ioctl(0x1, 0x540d, 0xffbff7ac) ls -> libc.so.1:ioctl(0x1, 0x5468, 0x23908) ls -> libc.so.1:setlocale(category = 0x6, locale = "") = "C" ls -> libc.so.1:calloc(nelem = 0x1, elsize = 0x40) = 0x23cd0 ls -> libc.so.1:lstat64(path = "/etc/passwd", buf = 0xffbff6b0) = 0x0 ls -> libc.so.1:acl(pathp = "/etc/passwd", cmd = 0x3, nentries = 0x0, aclbufp = 0x0) = 0x4 ls -> libc.so.1:qsort(base = 0x23cd0, nel = 0x1, width = 0x40, compar = 0x12038) ls -> libc.so.1:sprintf(buf = 0x233d0, format = 0x12af8, ...) = 0 ls -> libc.so.1:strlen(s = "") = 0x0 ls -> libc.so.1:strlen(s = "/etc/passwd") = 0xb ls -> libc.so.1:sprintf(buf = 0x233d0, format = 0x12af8, ...) = 0 ls -> libc.so.1:strlen(s = "") = 0x0 ls -> libc.so.1:printf(format = 0x12ab8, ...) = 11 ls -> libc.so.1:printf(/etc/passwd format = 0x12abc, ...) = 1 ls -> libc.so.1:exit(status = 0) |
上記例は、ls /etc/passwd というコマンド上で、すべてのライブラリ呼び出しをトレースしたときのデフォルトのトレース動作を示しています。apptrace はシステムコールごとに、次のような情報を含む 1 行を出力します。
システムコールの名前
システムコールが属するライブラリ
システムコールの引数と戻り値
ls の出力は apptrace の出力に混合されます。
% apptrace -t \*printf ls /etc/passwd ls -> libc.so.1:sprintf(buf = 0x233d0, format = 0x12af8, ...) = 0 ls -> libc.so.1:sprintf(buf = 0x233d0, format = 0x12af8, ...) = 0 ls -> libc.so.1:printf(format = 0x12ab8, ...) = 11 ls -> libc.so.1:printf(/etc/passwd format = 0x12abc, ...) = 1 |
上記例は、正規表現を使用することによって、apptrace がトレースする呼び出しを選択する方法を示しています。この例では、前の例と同じ ls コマンド上で、printf で終わるインタフェース (sprintf も含まれる) への呼び出しをトレースします。この結果、apptrace は printf および sprintf への呼び出しだけをトレースします。
% apptrace -v sprintf ls /etc/passwd ls -> libc.so.1:sprintf(buf = 0x233d0, format = 0x12af8, ...) = 0 buf = (char *) 0x233d0 "" format = (char *) 0x12af8 "%s%s%s" ls -> libc.so.1:sprintf(buf = 0x233d0, format = 0x12af8, ...) = 0 buf = (char *) 0x233d0 "" format = (char *) 0x12af8 "%s%s%s" /etc/passwd |
上記例は、詳細トレースモードを示しており、読みやすさのために、sprintf への引数が複数の行に出力されています。最後に、apptrace は ls コマンドの出力を表示します。