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 コマンドの出力を表示します。