プログラミングインタフェース

Solaris ABI ツール

Solaris インタフェースを使用するアプリケーションが Solaris ABI に準拠しているかどうかを確認するために、Solaris オペレーティングシステムは 2 つのツールを提供します。appcert ユーティリティーは、ELF バイナリが使用している Solaris ライブラリインタフェースの非公開インタフェースの使用状況のインスタンスについて静的な調査を行います。次に、appcert ユーティリティーは潜在的なバイナリ安定性の問題について、要約レポートと詳細レポートを生成します。apptrace ツールは実行時リンカーのリンク監視機能を使用して、アプリケーションを実行しながら動的に Solaris ライブラリルーチン呼び出しをトレースします。この機能によって、開発者は、アプリケーションが Solaris システムインタフェースを使用しているかどうかを調査できます。

ABI ツールを使用すると、特定の Solaris リリースで互換性の問題が存在するバイナリをすばやく簡単に識別できます。バイナリ安定性を確認するには、次のようにします。

appcert ユーティリティー

appcert ユーティリティーは、ELF バイナリを静的に調査して、使用されているライブラリシンボルを特定の Solaris リリースにおける公開インタフェースまたは非公開インタフェースのモデルに対して比較する Perl スクリプトです。このユーティリティーは SPARC または Intel のどちらのプラットフォーム上でも動作します。SPARC と Intel の 32 ビットインタフェースだけでなく、SPARC の 64 ビットインタフェースの使用状況も確認できます。appcert ユーティリティーは C 言語インタフェースだけを調査することに注意してください。

新しい Solaris リリースが入手可能になると、いくつかのライブラリインタフェースは動作が変わったり、完全になくなったりします。すると、このようなインタフェースに依存するアプリケーションの性能に影響を与えることがあります。Solaris ABI は、アプリケーションが安全かつ安定して使用できる実行時ライブラリインタフェースを定義します。appcert ユーティリティーは、アプリケーションが Solaris ABI に準拠していることを開発者が確認できるように設計されています。

appcert の確認項目

アプリケーションを調査するとき、appcert ユーティリティーは次のことを確認します。

非公開シンボルの使用

非公開シンボルとは、Solaris ライブラリがお互いを呼び出すときに使用する関数またはデータのことです。非公開シンボルの意味論的な動作は変更されることがあり、ときには、削除されることもあります。このようなシンボルのことを「降格シンボル」と呼びます。非公開シンボルは変更されやすいので、非公開シンボルに依存しているアプリケーションには潜在的に安定性に問題があります。

静的なリンク

Solaris ライブラリ間で非公開シンボルを呼び出すとき、その意味論はリリースごとに変わる可能性があります。したがって、アーカイブに静的にリンクすると、アプリケーションのバイナリ安定性が低下します。この問題を回避するためには、このようなアーカイブに対応する共有オブジェクトファイルに動的にリンクすることが必要です。

非結合シンボル

アプリケーションを調査するとき、appcert ユーティリティーは動的リンカーを使用してアプリケーションが使用するライブラリシンボルを解決します。このとき、動的リンカーが解決できないシンボルのことを「非結合シンボル」と呼びます。非結合シンボルの原因には、LD_LIBRARY_PATH 環境変数が正しく設定されていないなどの環境の問題があります。非結合シンボルの原因にはまた、コンパイル時に -llib または -z のスイッチの定義を省略したなどの構築時の問題もあります。ただしこのような例はまれで、多くの場合 appcert が非結合シンボルを報告するときは、存在しない非公開シンボルに依存しているなど、より深刻な問題が発生していることになります。

appcert の非確認項目

appcert ユーティリティーで調査しているオブジェクトファイルがライブラリに依存する場合、このような依存関係をオブジェクトに記録しておく必要があります。このような依存関係をオブジェクトに記録するには、コードをコンパイルするときに、コンパイラの -l スイッチを使用します。オブジェクトファイルがほかの共有ライブラリに依存する場合、appcert ユーティリティーを実行するときに、このような共有ライブラリには LD_LIBRARY_PATH または RPATH 経由でアクセスできる必要があります。

マシンが 64 ビットの Solaris カーネルを実行していなければ、appcert ユーティリティーは 64 ビットアプリケーションを確認できません。Solaris では 64 ビットの静的ライブラリが提供されていないため、appcert は 64 ビットアプリケーションの静的リンクを確認しません。

appcert は次のことを確認できません。

appcert の使用法

appcert を使用して、利用しているアプリケーションを確認するには、次のように入力します。


appcert object|directory

object|directory は次のどちらかです。


注 –

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 の動作を変更できます。次のオプションは、コマンド行において appcert コマンドから object|directory オペランドの間のどこにでも入力できます。

-B

appcert ユーティリティーをバッチモードで実行します。

バッチモードでは、appcert は確認するバイナリごとに 1 行をレポートに書き込みます。

PASS で始まる行は、その行が示すバイナリには appcert の警告が発行されなかったことを意味します。

FAIL で始まる行は、その行が示すバイナリに問題が見つかったことを意味します。

INC で始まる行は、その行が示すバイナリが完全には確認できなかったことを意味します。

-f infile

ファイル infile には、確認すべきファイルの一覧がファイル名ごとに 1 行ずつ書き込まれている必要があります。このファイルで指定されたファイルは、コマンド行に指定されたファイルに追加されます。このスイッチを使用する場合、オブジェクトまたはディレクトリをコマンド行に指定する必要はありません。

-h

appcert の使用法を出力します。

-L

デフォルトでは、appcert はアプリケーション内にあるすべての共有オブジェクトを記して、このような共有オブジェクトが入っているディレクトリを LD_LIBRARY_PATH に追加しますが、-L スイッチはこの動作を無効にします。

-n

デフォルトでは、ディレクトリを検索して確認すべきバイナリを探すとき、appcert はシンボリックリンクに従います。-n スイッチはこの動作を無効にします。

-S

Solaris ライブラリディレクトリ /usr/openwin/lib および /usr/dt/libLD_LIBRARY_PATH に追加します。

-w working_dir

ライブラリ構成要素を実行するディレクトリを指定します。このスイッチを指定した場合、appcert は一時ファイルをこのディレクトリに作成します。このスイッチを指定しない場合、appcert は一時ファイルを /tmp ディレクトリに作成します。

appcert によるアプリケーションの選択

appcert を使用すると、指定されたセットの中でどのアプリケーションが潜在的に安定性の問題を抱えているかをすばやく簡単に識別できます。appcert が何も安定性の問題を報告しなかった場合、そのアプリケーションは、以降の Solaris リリースでもバイナリ安定性の問題が報告されることは起こりにくいと考えられます。次の表に、よくあるバイナリ安定性問題の一覧を示します。

表 13–1 よくあるバイナリ安定性問題

問題 

回避方法 

ある非公開シンボルを使用しているが、変更されることがわかっている 

このようなシンボルの使用をすぐに停止する 

ある非公開シンボルを使用しているが、まだ変更されていない 

今のところアプリケーションは動作しているが、このようなシンボルの使用をできるだけ早く停止する 

あるライブラリに静的にリンクしているが、同等な共有オブジェクトを入手できる 

代わりに、同等な共有オブジェクトを使用する 

あるライブラリに静的に共有しているが、同等な共有オブジェクトを入手できない 

可能であれば、ld -z allextract を使用して、.a ファイルを .so ファイルに変換する。変換できない場合、共有オブジェクトが利用できるようになるまで、静的なライブラリを使用し続ける

ある非公開シンボルを使用しているが、同等な公開シンボルを入手できない 

Sun に連絡して、公開インタフェースを要求する 

あるシンボルを使用しているが、評判が悪いか、削除されることが計画されている 

今のところアプリケーションは動作しているが、このようなシンボルの使用をできるだけ早く停止する 

ある公開シンボルを使用しているが、すでに変更されている 

コンパイルし直す 

リリースによっては、非公開インタフェースを使用することによる潜在的な安定性の問題が発生しないこともあります。なぜなら、リリースが変わっても、非公開インタフェースの動作が変更されるとは限らないためです。ターゲットリリースで非公開インタフェースの動作が変更されているかどうかを確認するには、apptrace を使用します。apptrace の使用法については、apptrace によるアプリケーションの確認」を参照してください。

appcert の結果

appcert ユーティリティーがアプリケーションのオブジェクトファイルを解析した結果は、appcert ユーティリティーの作業用ディレクトリ (通常は /tmp) にあるいくつかのファイルに書き込まれます。作業用ディレクトリの下にあるメインサブディレクトリは appcert.pid です。このとき、pidappcert の当該インスタンスのプロセス ID です。appcert ユーティリティーの結果は、次のファイルに書き込まれます。

Index

確認されたバイナリ間のマッピングと、当該バイナリに固有な appcert の出力が格納されているサブディレクトリ名が書き込まれる

Report

appcert を実行したときに stdout に出力されたレポートのコピーが書き込まれる

Skipped

appcert が確認しようとしたが強制的にスキップされたバイナリの一覧と、各バイナリがスキップされた理由が書き込まれる。スキップされる理由には次のようなものが挙げられる

  • ファイルがバイナリオブジェクトではない

  • 当該ユーザーではファイルを読み取ることができない

  • ファイル名にメタキャラクタが含まれている

  • ファイルの実行ビットが設定されていない

objects/object_name

objects サブディレクトリの下には、appcert が確認するオブジェクトごとのサブディレクトリが作成される。サブディレクトリごとに、次のようなファイルが格納される

check.demoted.symbols

Solaris 降格シンボルであると appcert が疑っているシンボルの一覧

check.dynamic.private

オブジェクトが直接バインドされている Solaris 非公開シンボルの一覧

check.dynamic.public

オブジェクトが直接バインドされている Solaris 公開シンボルの一覧

check.dynamic.unbound

ldd -r を実行したときに、動的リンカーによってバインドされなかったシンボルの一覧。ldd が返す行には、「file not found 」も含まれる

summary.dynamic

appcert が調査したオブジェクト内にある動的バインドの要約がプリンタ形式で書き込まれる (各 Solaris ライブラリから使用される公開シンボルと非公開シンボルのテーブルも含まれる)

appcert は終了するときに、次の 4 つのうちの 1 つを返します。

0

appcert はバイナリ安定性問題の潜在的な原因を見つけなかった。

1

appcert は正常に実行されなかった。

2

appcert が確認した一部のオブジェクトにバイナリ安定性問題が見つかった。

3

appcert が確認すべきバイナリオブジェクトが見つからなかった。

appcert が報告した問題の修正

apptrace によるアプリケーションの確認

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 と入力し、次に希望のオプションを入力し、最後に対象となるアプリケーションを実行するコマンド行を入力します。apptrace は実行時リンカーのリンク監査機能を使用して、アプリケーションによる Solaris ライブラリインタフェースへの呼び出しを遮断します。次に、apptrace は呼び出しをトレースして、呼び出しの引数と戻り値についての名前と値を出力します。トレースは単一の行に出力することも、読みやすさのために複数の行に分けて出力することも可能です。公開インタフェースは人が読める形式で出力されます。非公開インタフェースは 16 進数で出力されます。

apptrace は、個々のインタフェースとライブラリの両方のレベルで、トレースする呼び出しを選択できます。たとえば、apptracelibnsl からの printf() の呼び出しをトレースすることができ、特定のライブラリ内のさまざまな呼び出しをトレースすることもできます。apptrace はまた、ユーザーが指定した呼び出しを詳細にトレースできます。apptrace の動作を命令する仕様は、truss(1) の使用法と整合する構文によって制御されます。-f オプションを指定すると、apptrace はフォークされた子プロセスもトレースします。-o オプションを指定すると、apptrace は o に指定されたファイルに結果を出力します。

apptrace がトレースするのはライブラリレベルの呼び出しだけであり、また、実行中のアプリケーションのプロセスにロードされるので、truss よりも性能が上がります。しかし、printf は例外ですが、apptrace は可変引数リストを受け入れたり、スタックまたは呼び出し元の情報を調査する関数への呼び出しをトレースできません (たとえば、setcontextgetcontextsetjmplongjmp、および vfork)。

apptrace 出力の解釈

次は、apptrace で単純な 1 バイナリアプリケーション ls をトレースしたときの出力例です。


例 13–1 デフォルトのトレース動作


% 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 の出力に混合されます。


例 13–2 選択的なトレース


% 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 も含まれる) への呼び出しをトレースします。この結果、apptraceprintf および sprintf への呼び出しだけをトレースします。


例 13–3 詳細なトレース


% 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 への引数が複数の行に出力されています。最後に、apptracels コマンドの出力を表示します。