(57)【要約】【課題】フックポイントにフックコードを埋め込むフックコード埋め込み方式のトレース技術を用いる場合において、ソースコードに改変せずに、オーバヘッドを抑えたプログラム実行のトレースを実現するコード変換装置及びコード変換方法を提供する。【解決手段】コード変換装置100は、フックポイント検出情報400を出力するフックポイント検出部110と、第２のコード300を生成する第２のコード生成部120と、第２のコード300が配置されるプロセス空間500上のアドレスを特定するアドレス特定部130と、フックポイント検出情報400によって特定されるフックポイントから、アドレスが特定されたコードを第２のコード300へ分岐するために用いられるフックコードとした場合において、置換コードをフックコードに置き換えるコード変換部140と、変換済み第１のコード210、第２のコード300及びフックポイント検出情報400を出力する出力部150とを備える。【選択図】図３
2009237610.tif 000002
【特許請求の範囲】
【請求項１】
入力された第１のコードのプロセス空間上に第２のコードを配置するために、前記第１のコードを変換するコード変換装置であって、
あらかじめ与えられた規則に従い、前記第１のコードから前記第２のコードを呼び出すポイントをフックポイントに設定するとともに、前記フックポイント上のコードを置換コードとした場合において、前記第１のコードの中から前記フックポイントを検出し、前記フックポイントのアドレス及び前記置換コードをフックポイント検出情報として出力するフックポイント検出部と、
前記第２のコードを生成する第２のコード生成部と、
前記第２のコード生成部によって生成された前記第２のコードが配置される前記プロセス空間上のアドレスを特定するアドレス特定部と、
前記フックポイント検出情報によって特定される前記フックポイントから、前記アドレス特定部によって前記アドレスが特定されたコードを前記第２のコードへ分岐するために用いられるフックコードとした場合において、前記置換コードを前記フックコードに置き換えるコード変換部と、
前記コード変換部によって変換された変換済み第１のコード、前記第２のコード及び前記フックポイント検出情報を出力する出力部と
を備え、
前記第２のコード生成部によって生成される前記第２のコードは、
前記第１のコードから前記第２のコードを呼び出す前記フックポイントを特定するフックポイント特定処理と、
前記フックポイント検出情報を参照し、前記フックポイントに対応する前記置換コードを実行する置換コード実行処理と、
コードの実行制御を前記フックポイントへ復帰させる復帰処理と
を含むコード変換装置。
【請求項２】
前記フックポイントは、複数設定されており、
前記第２のコード生成部は、前記第２のコード上に、それぞれの前記フックポイントに対応するエントリポイントを用意し、
前記フックコードは、前記エントリポイントへの分岐命令であり、
前記フックポイント特定処理は、前記エントリポイントに基づいて前記フックポイントを特定する請求項１に記載のコード変換装置。
【請求項３】
前記フックポイント特定処理は、前記置換コードが関数を呼び出す分岐命令であった場合、前記関数の呼び出しに対する返りアドレスを参照することによって前記フックポイントを特定する請求項１に記載のコード変換装置。
【請求項４】
前記アドレス特定部は、前記第１のコードのコード領域と、前記第１のコードのデータ領域との間に未使用のメモリ領域が存在し、かつ前記メモリ領域のサイズが前記第２のコードのサイズより大きい場合、前記メモリ領域に前記第２のコードを配置する請求項１に記載のコード変換装置。
【請求項５】
前記アドレス特定部は、前記第１のコードの実行開始時にローダによる共有ライブラリのロード処理が実行される場合、前記ロード処理の開始前に前記ロード処理をフックし、前記第２のコードを前記共有ライブラリとして前記プロセス空間上に配置する請求項１に記載のコード変換装置。
【請求項６】
前記アドレス特定部は、前記第１のコードと対応する仮想アドレス空間のうち、共有ライブラリとして前記第２のコードを配置可能な配置可能アドレスを特定し、
前記第２のコード生成部は、前記配置可能アドレスをアドレス情報として前記第２のコードに含め、
前記出力部は、前記第１のコードの実行開始時に、前記アドレス情報を前記共有ライブラリのロード処理に提供することによって、前記第２のコードを前記共有ライブラリとして前記プロセス空間上に配置する請求項１に記載のコード変換装置。
【請求項７】
前記コード変換部は、前記フックポイント検出部によって検出された前記フックポイントのうち、前記フックコードを挿入するためのコード変換規則が特定のフックポイントにのみ与えられた場合、前記コード変換規則によって指定された前記フックポイントにのみ、前記フックコードを埋め込む請求項５に記載のコード変換装置。
【請求項８】
前記第２のコード生成部が生成する前記第２のコードは、前記フックポイント特定処理、前記置換コード実行処理、及び前記復帰処理に加え、前記第１のコードの実行終了時に呼び出されて実行される実行後処理を含む請求項１に記載のコード変換装置。
【請求項９】
前記フックポイント検出部は、前記第１のコードの中から最後に実行される前記フックポイントを検出し、
前記コード変換部は、最後に実行される前記フックポイントに、前記第２のコードの前記実行後処理を呼び出す前記フックコードを挿入する請求項８に記載のコード変換装置。
【請求項１０】
入力された第１のコードのプロセス空間上に第２のコードを配置するために、前記第１のコードを変換するコード変換方法であって、
あらかじめ与えられた規則に従い、前記第１のコードから前記第２のコードを呼び出すポイントをフックポイントに設定するとともに、前記フックポイント上のコードを置換コードとした場合において、前記第１のコードの中から前記フックポイントを検出し、前記フックポイントのアドレス及び前記置換コードをフックポイント検出情報として出力するステップと、
前記第２のコードを生成するステップと、
生成された前記第２のコードが配置される前記プロセス空間上のアドレスを特定するステップと、
前記フックポイント検出情報によって特定される前記フックポイントから、前記アドレスが特定されたコードを前記第２のコードへ分岐するために用いられるフックコードとした場合において、前記置換コードを前記フックコードに置き換えるステップと、
前記置き換えるステップにおいて変換された変換済み第１のコード、前記第２のコード及び前記フックポイント検出情報を出力するステップと
を備え、
前記生成するステップにおいて生成される前記第２のコードは、
前記第１のコードから前記第２のコードを呼び出す前記フックポイントを特定し、
前記フックポイント検出情報を参照し、前記フックポイントに対応する前記置換コードを実行し、
コードの実行制御を前記フックポイントへ復帰させる
コード変換方法。
【発明の詳細な説明】
【技術分野】
【０００１】
本発明は、プログラムのトレース方式に関し、特に、プログラムのトレースにおいて、第１のコードのプロセス空間上に第２のコードを配置するために、前記第１のコードを変換するコード変換装置及びコード変換方法に関する。
【背景技術】
【０００２】
プログラムに発生する不具合原因の特定や、プログラムの性能改善を行うため、プログラムの動作をトレースし、トレース結果（以下、トレースログ）を取得する技術がある。トレース技術は、使用用途、トレース手段、或いは取得するトレースログなどによって様々な種類がある。
【０００３】
図１は、プログラムトレースの原理を説明する説明図である。図１に示すように、何れのトレース技術も、基本的には以下のようなステップを実行することによって、ターゲットプログラムのトレースを実現する。
【０００４】
（１）  ターゲットプログラムを追跡するトレースコードを用意する
（２）  ターゲットプログラムからトレースコードを呼び出すフックのアドレス（フックポイント）やタイミングを設定する
（３）  ターゲットプログラムの実行中、フックによりトレースコードが呼び出された際、トレースコードによって、呼び出された時点におけるプログラムの状況をトレースログとして記録する
トレース技術は、上述したような「フック」をいかにして実現するかによって、取得可能なトレースログや使用条件が異なる。トレース技術は、フックの実現手段によって以下のように分類できる。
【０００５】
（１）  サンプリング方式
（２）  フックコード埋め込み方式
・  動的変換型
・  ソース埋め込み型
サンプリング方式は、ターゲットプログラムの実行中に、トレーサが一定間隔でシグナルを発生することによって、ターゲットプログラムの動作を停止させる。プロセスを停止させる性質上、トレーサ自体は、システム上において高い権限を持ったプロセス（親プロセスやカーネル権限プロセス）によって実現される。代表的なサンプリング方式のトレーサには、sysprof（非特許文献1参照）やoprofile（非特許文献2参照）がある。
【０００６】
サンプリング方式は、主にプログラム性能のプロファイリングに用いられる。例えば、プログラムの動作中に一定間隔でプログラムカウンタをサンプリングすることによって、ターゲットプログラムが実行中であるアドレスが取得されていく。このため、ターゲットプログラム中のどのルーチンがより多く実行されているかを把握でき、性能改善のポイントを特定できる。また、サンプリング方式は、動作中の任意のプロセスに対してアタッチできる特徴がある。
【０００７】
サンプリング方式の欠点は、プログラムの特定部分をフックすることができないことである。例えば、トレースログにおける有用なログの一つとして、関数コールの履歴（コールグラフ）が挙げられる。しかし、サンプリング方式は、関数コールのentryやreturn部分を確実にフックできる保証がない。また、極端に実行時間や実行回数が少ない関数については、サンプリング自体が行われない可能性もある。このため、関数の呼び出し履歴、関数間の関係、関数の引数や返り値といったコンテキスト情報を取得することは非常に困難である。
【０００８】
一方、フックコード埋め込み方式は、ターゲットプログラム中に直接フックコードを埋め込む。フックコードは、プロセス空間内をジャンプする分岐命令や、カーネルへ処理を移すソフトウェア割り込みである。
【０００９】
フックコード埋め込み方式は、フックコードやフックコード埋め込み手段によって、さらに動的変換型またはソース埋め込み型に分類される。
【００１０】
動的変換型は、ターゲットプログラム実行時に、当該ターゲットプログラムのコード領域を書き換えることによってフックコードを埋め込む。例えば、GDB（非特許文献3参照）は、ターゲットプログラムを子プロセスとして実行し、ptraceシステムコールを利用することによって子プロセスのコードへフックコードを埋め込む。フックコードが実行されると、親プロセス（GDB）へ制御が戻る。親プロセスに制御が戻った時点での子プロセスのメモリへアクセスすることによって、様々なトレースログを取得可能である。フックコードは、任意のアドレスへ埋め込むことが可能であるため、コールグラフを含め、任意のタイミングでターゲットプログラムからコンテキスト情報を取得可能である。
【００１１】
また、DTrace（非特許文献4参照）は、ターゲットプログラムの動作中に当該プロセスのメモリ空間へ直接アタッチし、フックコードとしてソフトウェアブレイク命令を埋め込む。実際にフックコードが実行されれば、DTrace（カーネルプロセス）へのコンテキストスイッチが行われ、当該時点におけるメモリにアクセスすることによって、様々なトレースログを取得する。
【００１２】
動的変換型の欠点は、実行時の実行時間オーバヘッドである。ターゲットプログラムがフックコードを呼び出すことによって、トレーサへのコンテキストスイッチが発生するためである。また、トレーサがターゲットプログラムのコンテキストを復元する際には、トレーサは、次のフックポイントを探索してフックコードを埋め込む必要があり、プログラムの実行中におけるコードの解析や変換によるオーバヘッドも大きい。
【００１３】
ソース埋め込み型には、gprof（非特許文献5参照）、CTrace（非特許文献6参照）、及びetrace（非特許文献7参照）などがある。gprofは、全ての関数のentryにCのライブラリ関数であるmcount(・)関数を埋め込み、関数呼び出しが発生した時点でのアドレスを記録していく。このため、ターゲットプログラムの実行中に呼び出された全ての関数について、コールグラフを取得できる。
【００１４】
CTraceは、ターゲットプログラムのソースコードに改変を加えることによって、ソースレベルにおいてフックコードとトレースコードとを埋め込む。フックコードは、トレースコード中のルーチンを呼び出すための分岐命令となる。改変されたターゲットプログラムは再コンパイルされ、実行される。このような処理によって、フックコードが実行される毎にトレースコードが実行され、実行時点におけるコンテキスト情報を取得できる。
【００１５】
さらに、フックコードは、プログラムソース中の任意の位置に埋め込むことができるため、ターゲットプログラムを任意のタイミングでフックできる。
【００１６】
etraceは、ターゲットプログラムにトレースコードを埋め込んだのち、GNU C Compiler（gcc）の拡張コンパイルオプションである”-finstruments-functions”を用いて、ターゲットプログラムを再コンパイルする。当該コンパイルオプションは、全ての関数entryとreturnとによって任意のコードを実行させることを可能とする。このため、関数のentryとreturnとによって、埋め込んだトレースコードを呼び出すことができ、コールグラフや引数など、実行時点における様々なコンテキスト情報を取得できる。
【００１７】
ソース埋め込み型の欠点は、ターゲットプログラムのソースが必要となる点である。プログラムの開発中にデバッグ目的で使用するのであれば、ソースコードも入手できるが、ターゲットプログラムがリリースされた後、開発者以外のユーザが当該ターゲットプログラムを用いている場合、ソースコードが入手できない場合も多く利用しにくい。また、フックコードが恒久的にターゲットプログラムに埋め込まれてしまうため、当該ターゲットプログラムについて恒常的なオーバヘッドが発生する。例えば、必要な時にだけトレースログを取得するといった、選択的なトレースを行うことはできない。
【００１８】
表１は、上述したトレース技術（トレーサ）の特徴を示す。
【表１】
2009237610.tif 000003
【非特許文献１】Sysprof、［online］、［平成２０年３月６日検索］、<URL: http://www.daimi.au.dk/~sandmann/sysprof/>
【非特許文献２】Oprofile、［online］、［平成２０年３月６日検索］、<URL: http://oprofile.sourceforge.net/news/>
【非特許文献３】GDB、［online］、［平成２０年３月６日検索］、<URL: http://sourceware.org/gdb/>
【非特許文献４】Dtrace、［online］、［平成２０年３月６日検索］、<URL: http://jp.sun.com/products/software/solaris/10/dtracehowto.html>
【非特許文献５】gprof、［online］、［平成２０年３月６日検索］、<URL: http://www.cs.utah.edu/dept/old/texinfo/as/gprof_toc.html>
【非特許文献６】Ctrace、［online］、［平成２０年３月６日検索］、<URL: http://ctrace.sourceforge.net/>
【発明の開示】
【発明が解決しようとする課題】
【００１９】
しかし、上述した従来のトレース技術には、次のような問題があった。すなわち、リリースされたソフトウェアをユーザが実際に利用する際に、当該ソフトウェアをトレースする場合、上述した従来のトレース技術は必ずしも有用でない問題があった。
【００２０】
例えば、新規に開発されたソフトウェアは、開発時にプログラムに混入したバグによって不具合が発生する可能性が高い。このような場合、当該ソフトウェアをトレースし、トレースコードによって不具合の診断に有用なトレースログを取得すること考えられる。このようなトレースログとして最も広く用いられているのが、ソフトウェアに致命的な障害が発生した場合などに、OSの機能によって出力されるメモリダンプである。
【００２１】
メモリダンプは、強制終了時におけるメモリの内容がそのまま出力されるため、不具合の発生箇所や、スタックトレースによって障害発生直前のコンテキスト情報を取得できる。しかし、メモリダンプには、障害発生直前の情報しか保存されていないため、障害に至るまでのコンテキスト情報を時系列で遡り、根本原因を特定することは困難である。また、強制終了に至らない過渡的な障害に対しては有用でない。
【００２２】
一方、プログラム開発時には、上述したような多数のプロファイラやデバッガによって、メモリダンプ以外のコンテキスト情報（関数のコールグラフや引数、返り値、或いはデータの入出力に関する情報）が用いられる。このようなコンテキスト情報は、メモリダンプの情報と合わせて、バグの発見や不具合の修正に活用されている。
【００２３】
そこで、開発時だけではなく、ソフトウェアのリリース後においても、このようなコンテキスト情報を随時取得しておくことによって、当該ソフトウェアに対する事後のサポートやアップデートに活用できると考えられる。図２は、メモリダンプとコンテキスト情報との関係を示す。
【００２４】
すなわち、上述したような既存のトレース方式は、ソースコードに改変せずに、オーバヘッドを抑えつつプログラムの実行をトレースすることはできない問題があった。つまり、ユーザが用いるソフトウェアのトレース方式として適当ではない問題があった。
【００２５】
そこで、本発明は、このような状況に鑑みてなされたものであり、フックポイントにフックコードを埋め込むフックコード埋め込み方式のトレース技術を用いる場合において、ソースコードに改変せずに、オーバヘッドを抑えたプログラム実行のトレースを実現するコード変換装置及びコード変換方法を提供することを目的とする。
【課題を解決するための手段】
【００２６】
上述した問題を解決するため、本発明は、次のような特徴を有している。まず、本発明の第１の特徴は、入力された第１のコード（第１のコード200）のプロセス空間（プロセス空間500）上に第２のコード（第２のコード300）を配置するために、前記第１のコードを変換するコード変換装置（コード変換装置100）であって、あらかじめ与えられた規則（フックポイント検出規則600）に従い、前記第１のコードから前記第２のコードを呼び出すポイントをフックポイント（フックポイントHP）に設定するとともに、前記フックポイント上のコードを置換コードとした場合において、前記第１のコードの中から前記フックポイントを検出し、前記フックポイントのアドレス及び前記置換コードをフックポイント検出情報（フックポイント検出情報400）として出力するフックポイント検出部（フックポイント検出部110）と、前記第２のコードを生成する第２のコード生成部（第２のコード生成部120）と、前記第２のコード生成部によって生成された前記第２のコードが配置される前記プロセス空間上のアドレスを特定するアドレス特定部（アドレス特定部130）と、前記フックポイント検出情報によって特定される前記フックポイントから、前記アドレス特定部によって前記アドレスが特定されたコードを前記第２のコードへ分岐するために用いられるフックコードとした場合において、前記置換コードを前記フックコードに置き換えるコード変換部（コード変換部140）と、前記コード変換部によって変換された変換済み第１のコード（変換済み第１のコード210）、前記第２のコード及び前記フックポイント検出情報を出力する出力部（出力部150）とを備え、前記第２のコード生成部によって生成される前記第２のコードは、前記第１のコードから前記第２のコードを呼び出す前記フックポイントを特定するフックポイント特定処理と、前記フックポイント検出情報を参照し、前記フックポイントに対応する前記置換コードを実行する置換コード実行処理と、コードの実行制御を前記フックポイントへ復帰させる復帰処理とを含むことを要旨とする。
【００２７】
本発明の第２の特徴は、本発明の第１の特徴に係り、前記フックポイントは、複数設定されており、前記第２のコード生成部は、前記第２のコード上に、それぞれの前記フックポイントに対応するエントリポイントを用意し、前記フックコードは、前記エントリポイントへの分岐命令であり、前記フックポイント特定処理は、前記エントリポイントに基づいて前記フックポイントを特定することを要旨とする。
【００２８】
本発明の第３の特徴は、本発明の第１の特徴に係り、前記フックポイント特定処理は、前記置換コードが関数を呼び出す分岐命令であった場合、前記関数の呼び出しに対する返りアドレスを参照することによって前記フックポイントを特定することを要旨とする。
【００２９】
本発明の第４の特徴は、本発明の第１の特徴に係り、前記アドレス特定部は、前記第１のコードのコード領域と、前記第１のコードのデータ領域との間に未使用のメモリ領域が存在し、かつ前記メモリ領域のサイズが前記第２のコードのサイズより大きい場合、前記メモリ領域に前記第２のコードを配置することを要旨とする。
【００３０】
本発明の第５の特徴は、本発明の第１の特徴に係り、前記アドレス特定部は、前記第１のコードの実行開始時にローダによる共有ライブラリのロード処理が実行される場合、前記ロード処理の開始前に前記ロード処理をフックし、前記第２のコードを前記共有ライブラリとして前記プロセス空間上に配置することを要旨とする。
【００３１】
本発明の第６の特徴は、本発明の第１の特徴に係り、前記アドレス特定部は、前記第１のコードと対応する仮想アドレス空間のうち、共有ライブラリとして前記第２のコードを配置可能な配置可能アドレスを特定し、前記第２のコード生成部は、前記配置可能アドレスをアドレス情報として前記第２のコードに含め、前記出力部は、前記第１のコードの実行開始時に、前記アドレス情報を前記共有ライブラリのロード処理に提供することによって、前記第２のコードを前記共有ライブラリとして前記プロセス空間上に配置することを要旨とする。
【００３２】
本発明の第７の特徴は、本発明の第５の特徴に係り、前記コード変換部は、前記フックポイント検出部によって検出された前記フックポイントのうち、前記フックコードを挿入するためのコード変換規則が特定のフックポイントにのみ与えられた場合、前記コード変換規則によって指定された前記フックポイントにのみ、前記フックコードを埋め込むことを要旨とする。
【００３３】
本発明の第８の特徴は、本発明の第１の特徴に係り、前記第２のコード生成部が生成する前記第２のコードは、前記フックポイント特定処理、前記置換コード実行処理、及び前記復帰処理に加え、前記第１のコードの実行終了時に呼び出されて実行される実行後処理を含むことを要旨とする。
【００３４】
本発明の第９の特徴は、前記フックポイント検出部は、前記第１のコードの中から最後に実行される前記フックポイントを検出し、前記コード変換部は、最後に実行される前記フックポイントに、前記第２のコードの前記実行後処理を呼び出す前記フックコードを挿入することを要旨とする。
【００３５】
本発明の第１０の特徴は、入力された第１のコードのプロセス空間上に第２のコードを配置するために、前記第１のコードを変換するコード変換方法であって、あらかじめ与えられた規則に従い、前記第１のコードから前記第２のコードを呼び出すポイントをフックポイントに設定するとともに、前記フックポイント上のコードを置換コードとした場合において、前記第１のコードの中から前記フックポイントを検出し、前記フックポイントのアドレス及び前記置換コードをフックポイント検出情報として出力するステップと、
前記第２のコードを生成するステップと、生成された前記第２のコードが配置される前記プロセス空間上のアドレスを特定するステップと、前記フックポイント検出情報によって特定される前記フックポイントから、前記アドレスが特定されたコードを前記第２のコードへ分岐するために用いられるフックコードとした場合において、前記置換コードを前記フックコードに置き換えるステップと、前記置き換えるステップにおいて変換された変換済み第１のコード、前記第２のコード及び前記フックポイント検出情報を出力すステップとを備え、前記生成するステップにおいて生成される前記第２のコードは、前記第１のコードから前記第２のコードを呼び出す前記フックポイントを特定し、前記フックポイント検出情報を参照し、前記フックポイントに対応する前記置換コードを実行し、コードの実行制御を前記フックポイントへ復帰させることを要旨とする。
【発明の効果】
【００３６】
本発明の特徴によれば、フックポイントにフックコードを埋め込むフックコード埋め込み方式のトレース技術を用いる場合において、ソースコードに改変せずに、オーバヘッドを抑えたプログラム実行のトレースを実現するコード変換装置及びコード変換方法を提供することができる。
【発明を実施するための最良の形態】
【００３７】
次に、本発明の実施形態について説明する。具体的には、本発明の第１実施形態〜第３実施形態について説明する。
【００３８】
なお、以下の図面の記載において、同一または類似の部分には、同一または類似の符号を付している。ただし、図面は模式的なものであり、各寸法の比率などは現実のものとは異なることに留意すべきである。
【００３９】
したがって、具体的な寸法などは以下の説明を参酌して判断すべきものである。また、図面相互間においても互いの寸法の関係や比率が異なる部分が含まれていることは勿論である。
【００４０】
［第１実施形態］
まず、本発明の第１実施形態について説明する。具体的には、（１）コード変換装置の全体概略構成、（２）各ブロックの機能、（３）コード変換装置の動作、及び（４）作用・効果について説明する。
【００４１】
（１）コード変換装置の全体概略構成
図３は、本実施形態に係るコード変換装置100の全体概略構成図である。図３に示すように、コード変換装置100は、フックポイント検出部110、第２のコード生成部120、アドレス特定部130、コード変換部140及び出力部150を備える。
【００４２】
コード変換装置100は、入力された第１のコード200を変換し、変換済み第１のコード210を出力する。このような変換は、例えば、ターゲットプログラムのバイナリコードを第１のコード200とし、トレースコードを第２のコード300とした場合、第１のコード200を第２のコード300によってトレースするために行われる。
【００４３】
すなわち、コード変換装置100は、入力された第１のコード200のプロセス空間500上に第２のコード300を配置するために、第１のコード200を変換する機能を有する。
【００４４】
本実施形態に係るトレースは、少なくとも３つの特徴を有する。第１の特徴は、第１のコード200中のトレース対象アドレスをフックポイントHP（図３において不図示、図４参照）とすることである。つまり、フックポイントHPにフックコードを埋め込むことによって、第２のコード300を呼び出すフックコード埋め込み方式である。フックコード埋め込み方式は、フックポイントHPにおいて確実に第１のコード200から第２のコード300を呼び出すことができるため、ソフトウェアの不具合診断に用いられるトレースログの取得など、確実に特定のポイントをトレースしたい場合に有用である。
【００４５】
第２の特徴は、ターゲットプログラムのソースを一切改変しないことである。改変しない理由は、特定のソフトウェアがリリースされた後に当該ソフトウェアのプログラムコードをトレースする場合、ソースコードが入手困難であることが想定されるためである。
【００４６】
第３の特徴は、低いオーバヘッドを実現するため、第１のコード200と第２のコード300を同一のプロセス空間500に配置する。さらに、第１のコード200の実行開始後には、第１のコード200に対する動的変換処理、つまり、ターゲットプログラム実行中におけるフックポイントHPの検出やフックコードへの変換及び挿入といった処理を行わない。
【００４７】
なお、第１のコード200中からフックポイントHPをどのように検出するかについては、実際のトレース処理に依存する。本実施形態では、何らかの手段によってトレース対象のポイントは特定可能であるものとする。例えば、関数callグラフをトレースログとして記録する場合、関数呼び出し用の決まったコードを検出すればよい。また、さらにトレースポイントを限定する方法としては、例えば、特開2001-34503号公報に記載されている方法を用いることができる。具体的には、当該公報では、あらかじめ取得したトレース情報を解析することによって、次回解析時のトレースポイントを必要部分に限定する方法が記載されている。
【００４８】
（２）各ブロックの機能
次に、コード変換装置100を構成する各ブロックの機能について説明する。
【００４９】
（２．１）フックポイント検出部110
フックポイント検出部110は、あらかじめ与えられたフックポイント検出規則600に従い、第１のコード200から第２のコード300を呼び出すポイントをフックポイントHPに設定する。また、フックポイント検出部110は、フックポイントHP上のコードを置換コードとした場合において、第１のコード200の中からフックポイントHPを検出し、フックポイントHPのアドレス及び置換コードをフックポイント検出情報400として出力する。
【００５０】
具体的には、フックポイント検出部110は、第１のコード200及びフックポイント検出規則600を入力とし、フックポイント検出規則600に従って、第１のコード200中に存在するフックポイントHPのアドレスを検出する。
【００５１】
また、フックポイント検出部110は、第１のコード200の中から最後に実行されるフックポイントHPを検出することができる。
【００５２】
本実施形態では、第１のコード200は、コンパイル済みの実行可能バイナリである。フックポイント検出部110による処理は、第１のコード200の実行開始前における任意の時点で行うことができる。
【００５３】
例えば、第２のコード300によって関数呼び出しを記録していくようなトレースを考える。このような場合、フックポイントHPは、関数呼び出しの命令が存在するアドレスとなる。フックポイント検出部110は、まず第１のコード200を逆アセンブルし、逆アセンブルの結果を全て探索することによって、関数呼び出しに該当する命令を検出する。このような命令は、第１のコード200がどのようなCPUアーキテクチャ向けにコンパイルされているかにより異なる。例えば、ARM（Acorn RISC Machine）の場合は、次の3つの命令が関数呼び出し命令の可能性がある。つまり、フックポイント検出規則600は、当該3つの命令を検出対象として指定する。
【００５４】
・  bl <address>
・  mov pc <Rd>（pcはプログラムカウンタ、Rdは汎用レジスタを表す）
・  ldr pc <address>（<address>は、適当なアドレス表現を表す）
bl命令は、lrレジスタ（関数呼び出し後の帰還アドレス格納レジスタ）へ現在のアドレスを格納した上で<address>へ分岐する関数呼び出し用分岐命令である。
【００５５】
mov pcやldr pcは、それぞれ汎用レジスタに格納されたアドレス、或いは<address>で示されたアドレスの値をプログラムカウンタにセットすることによって、当該アドレスへ分岐する分岐命令を表す。以下の説明では、これらのフックポイントHP上の命令を置換コードと呼ぶ。
【００５６】
フックポイント検出部110は、これらの命令が存在するアドレスと置換コードとを、フックポイント検出情報400として出力する。表２は、フックポイント検出情報400の例を示す。
【表２】
2009237610.tif 000004
【００５７】
（２．２）第２のコード生成部120
第２のコード生成部120は、第１のコード200から呼び出される第２のコード300を生成する。第２のコード300の生成は、第１のコード200の実行開始前における任意の時点で行うことができる。また、フックポイント検出部110による処理と独立して行うことができる。
【００５８】
上述したように、第２のコード300は、第１のコード200をトレースするトレースコードである。第２のコード生成部120によって生成される第２のコード300は、第１のコード200から呼び出された際にトレース処理を実行する以外に、第１のコード200から第２のコード300を呼び出すフックポイントHPを特定するフックポイント特定処理と、フックポイント検出情報400を参照し、フックポイントHPに対応する置換コードを実行する置換コード実行処理と、コード、具体的には第１のコード200の実行制御をフックポイントHPへ復帰させる第１のコード復帰処理とを有する。以下、図４を参照しながら各処理の内容について説明する。図４は、本実施形態において用いられるコードの概略構成を示す。
【００５９】
（２．２．１）トレース処理
トレース処理は、第２のコード300を用いてどのようなトレースを実現したいかによって内容が異なる。例えば、ARMにおいて関数呼び出しと、当該関数の引数を記録していくような場合、置換コードの分岐先アドレス、及び汎用レジスタのr1からr5を記録する。なぜなら、置換コードは、関数呼び出し分岐命令そのものであり、当該分岐命令の分岐先アドレスは、呼び出される関数のアドレスを示すためである。また、ARMでは、関数呼び出しの際、上位5つの引数については、汎用レジスタのr1からr5に格納される特徴があるためである。
【００６０】
このようなトレースログを二次記憶装置などの低速なデバイスへ随時出力すると、高いオーバヘッドが発生する。そこで、本実施形態では、メモリ容量に余裕がある限り、当該メモリ上の適当なバッファに蓄積していくものとする。
【００６１】
（２．２．２）フックポイント特定処理
フックポイント特定処理は、トレース処理に先んじて呼び出され、第１のコード200上の呼び出し元フックポイントを特定する。後述のように、フックポイントHP上の置換コードは、第２のコード300を呼び出すためのフックコードに置き換えられる。フックコードは、通常の分岐命令であり、分岐先から単純に分岐元のアドレスを特定することができない。
【００６２】
一方、第２のコード300のトレース処理を実行後には、フックコードに置き換えられた置換コードが実行された上で、元のフックポイントHPへ実行制御が復帰し、第１のコード200の実行が再開される必要がある。このため、分岐元のフックポイントHPを特定するフックポイント特定処理が必要となる。
【００６３】
分岐元のフックポイントHPを特定する方法の一つとして、フックポイントHP毎に第２のコード300上にエントリポイントを用意する方法が考えられる。図４に示す例では、ha, hb,…, hzは、フックポイントHPのアドレスである。すなわち、フックポイントHPは、複数設定されている。また、A, B,…, Zは、置換コードである。
【００６４】
この場合、フックポイント検出情報400は、（ha、A）, (hb、B),…といったように、フックポイントHPのアドレスと置換コードとがセットで記録される。各置換コードは、後述するコード変換部140によってフックコードa, b,…, zに置き換えられる。各フックコードは、フックポイントHP特定処理上のエントリポイントa’, b’,…, z’へ分岐する分岐命令である。各エントリポイントとフックポイントHPとが一意に対応するため、フックポイント特定処理は、分岐先のエントリポイントに応じて分岐元のフックポイントHPを特定できる。
【００６５】
すなわち、本実施形態では、第２のコード生成部120は、第２のコード300上に、それぞれのフックポイントHPに対応するエントリポイントを用意する。
【００６６】
なお、上述したような関数呼び出しをトレースする例においては、別の手段でフックポイントHPを特定することが可能である。このような場合、置換コードは関数呼び出し命令であり、置換コードが実行される前には必ず、関数実行後の帰還アドレス（すなわちフックポイントHPのアドレスが専用レジスタに登録される。ARMの場合、lrレジスタが専用レジスタに該当する。
【００６７】
このため、このようなトレースを行う場合に限り、フックポイント特定処理は、当該レジスタを参照することによって、簡単に呼び出し元フックポイントのアドレスを特定できる。つまり、フックポイント特定処理は、置換コードが関数を呼び出す分岐命令であった場合、当該関数の呼び出しに対する帰還アドレス（返りアドレス）を参照することによって呼び出し元フックポイントを特定する。
【００６８】
（２．２．３）置換コード実行処理
置換コード実行処理は、トレース処理実行後に呼び出され、フックコードによって置き換えられた置換コードを実行する。置換コードは、第１のコード200上で元々実行されるはずだった処理であるため、第１のコード200へ実行制御が復帰する前に必ず実行される必要がある。
【００６９】
フックポイントHPが特定できている場合、フックポイント検出情報400に基づいて対応する置換コードが特定できる。例えば、エントリポイントa’が呼び出されていた場合、エントリポイントのアドレスはhaであるため、置換コードはAと特定され、Aが実行される。
【００７０】
（２．２．４）第１のコード復帰処理
第１のコード復帰処理は、第１のコード200のフックポイントHPへ復帰する処理である。第１のコード復帰処理によって、第１のコード200の実行が再開される。
【００７１】
フックポイントHPのアドレスは、フックポイント特定処理によって特定されている。例えば、エントリポイントa’が呼び出されていた場合には、アドレスhaへ復帰する。
【００７２】
なお、上述した関数呼び出しのトレースのように、置換コードが分岐命令である場合には、第１のコード復帰処理は実行されない場合もある。この場合、置換コードが関数呼び出しの分岐命令であるため、置換コード実行処理による置換コードが実行されると、第１のコード200上で実行されるはずであった関数呼び出しが実行され、第１のコード200へ実行制御が復帰するからである。
【００７３】
（２．２．５）実行後処理
図４に示すように、第２のコード生成部120が生成する第２のコード300は、第１のコード200の実行終了時に呼び出されて実行される実行後処理を含むようにしてもよい。
【００７４】
実行後処理は、上述したようなトレースログを取得する場合において必要である。上述したように、関数呼び出し時に取得されていくトレースログは、メモリ上のバッファに一時的に蓄積することが好ましい。
【００７５】
第２のコード300がバッファ領域を取得するためには、heapを利用すればよい。しかし、メモリ上のバッファは、第１のコード200の実行終了時点で消去されてしまうため、第１のコード200の実行終了直前に、バッファに残ったトレースログを全て書き出す必要がある。具体的には、最後に実行されるフックポイントHPのみ、トレース処理実行後に特別な実行後処理を実行すればよい。
【００７６】
例えば、ELFバイナリの場合、プログラムが正常終了する限り、.finiセグメントが必ず最後に実行される。そこで、.finiセグメントに存在するフックポイントHPのうち、最も下位のフックポイントHPから第２のコード300が呼び出された場合にのみ、第２のコード300のトレース処理は、実行後処理を呼び出し、全てのトレースログを二次記憶装置などに書き出す。このような処理によって、第１のコード200が終了するまで取得された全てのトレースログを欠損なく取得できる。
【００７７】
（２．３）アドレス特定部130
アドレス特定部130は、第２のコード生成部120によって生成された第２のコード300が配置されるプロセス空間500上のアドレスを特定する。具体的には、アドレス特定部130は、第２のコード300を入力とし、第２のコード300が配置されるアドレスを特定する。
【００７８】
本実施形態では、第１のコード200から第２のコード300が呼び出される際に、コンテキストスイッチが発生することを抑えるため、両コードは、同一のプロセス空間500に配置される。本実施形態に係るアドレス特定部130は、第２のコード300が配置されるプロセス空間500上のアドレスを特定するだけではなく、第１のコード200中の空き領域に第２のコード300を埋め込む。
【００７９】
具体的には、アドレス特定部130は、第１のコード200のコード領域と、第１のコード200のデータ領域との間に未使用のメモリ領域が存在し、かつ当該メモリ領域のサイズが第２のコード300のサイズより大きい場合、当該メモリ領域に第２のコード300を配置する。当該処理は、第２のコード生成部120による第２のコード300の生成終了後、第１のコード200実行前における任意の時点で行うことができる。第２のコード300は実行可能バイナリであるため、少なくとも第１のコード200の実行可能領域（.textなどの配置領域）に配置される必要がある。図５は、第１のコード200がELFバイナリである場合におけるプログラムヘッダの例を示す。
【００８０】
図５に示すように、PHDRは、プログラムヘッダが配置されるアドレスを示す。INTERPは、共有ライブラリのロード処理など、プログラム実行開始前に呼び出されるインタプリタ処理を示す。
【００８１】
２つ存在するLOADのうち、FlagがRE（読み、実行可能領域）であるLOADは、.textなどの実行可能コードが配置される領域である。一方、FlagがRW（読み、書き可能）であるLOADは、.dataなどのデータが配置される領域である。
【００８２】
仮にFlagがRE（読み、実行可能領域）であるLOADをLOAD1、FlagがRW（読み、書き可能）であるLOADをLOAD2とした場合、第２のコード300は実行可能領域に配置される必要があるため、LOAD1（図中のA1枠部分）に配置される必要がある。
【００８３】
図６は、第２のコード300が配置可能な領域を示す。LOAD1の末尾、かつLOAD2と重複しない領域に配置される必要がある。図６では、アドレス0x8907からアドレス0x1098の領域である。当該領域を超過して第２のコード300が配置された場合、実際に第１のコード200が実行された際に、LOAD2のロードによって第２のコード300が破壊される可能性がある。
【００８４】
なお、全ての関数呼び出しと、引数とを記録する第２のコード300を実装し、第１のコード200としてgzipに対して適用した場合、gzipの空き領域33[KB]に対して、27[KB]の第２のコード300を記述可能であることが確認されている。
【００８５】
（２．４）コード変換部140
コード変換部140は、フックポイント検出情報400400に基づいて、第１のコード200にフックコードを埋め込んでいく処理を実行する。具体的には、コード変換部140は、第２のコード300が配置されるプロセス空間500上のアドレスが特定されたコードを、フックポイント検出情報400によって特定されるフックポイントHPから第２のコード300へ分岐するために用いられるフックコードとする。さらに、コード変換部140は、置換コード、つまり、フックポイントHP上の命令を当該フックコードに置き換える。
【００８６】
フックコードを埋め込むアドレスは、フックポイント検出情報400によって特定される。また、フックコードは分岐命令であるが、分岐先のアドレスは、アドレス特定部130によって特定されている。
【００８７】
コード変換部140は、フックポイント検出情報400によって示されたアドレスに、第２のコード300のアドレスへ分岐する分岐命令を上書きしていく。置換コードは既にフックポイント検出情報400として退避されているため、上書きしていくことで失われる情報はない。また、第２のコード300のフックポイント特定処理がフックポイントHP毎にエントリポイントを用意する場合には、フックコードの分岐先はそれぞれ対応するエントリポイントになる。
【００８８】
コード変換部140は、上述したコード変換を実行後、変換済み第１のコード210を出力部150に出力する。なお、コード変換部140による処理は、フックポイント検出部110またはアドレス特定部130のよる処理終了後、或いは第１のコード200における実行前の任意の時点で行うことができる。
【００８９】
また、コード変換部140は、第１のコード200を実行した結果、最後に実行されるフックポイントHPに、上述した実行後処理を呼び出すフックコードを挿入することができる。
【００９０】
（２．５）出力部150
出力部150は、単純に第２のコード300が配置された変換済み第１のコード210、及びフックポイント検出情報400を出力するのみである。つまり、出力部150は、変換済み第１のコード210、第２のコード300及びフックポイント検出情報400を出力ことができる。
【００９１】
実際に第１のコード200が実行された際には、フックポイントHPから自動的に第２のコード300が呼び出されてトレース処理が実行される。この際、第２のコード300は、フックポイント検出情報400を参照することによって必要な処理を行うことができる。
【００９２】
（３）コード変換装置の動作
次に、コード変換装置100の動作について説明する。図７は、コード変換装置100を構成する各ブロックの動作フローを示す。
【００９３】
図７に示す全ての処理は、第１のコード200の実行前に静的に行うことできる。つまり、動的変換処理に係わるオーバヘッドは一切発生せず、第２のコード300の実行に伴うオーバヘッドが加わるのみである。
【００９４】
ステップＳ１０において、第１のコード200がフックポイント検出部110に入力される。
【００９５】
ステップＳ２０において、フックポイント検出部110は、入力された第１のコード200の内容を解析する。具体的には、フックポイント検出部110は、第１のコード200の中からフックポイントHPを検出する。
【００９６】
ステップＳ３０において、フックポイント検出部110は、検出したフックポイントHPのアドレス及び置換コードを含むフックポイント検出情報400をコード変換部140に出力する。
【００９７】
ステップＳ４０において、第２のコード生成部120は、第２のコード300を生成する。
【００９８】
ステップＳ５０において、第２のコード生成部120は、生成した第２のコード300をアドレス特定部130に出力する。
【００９９】
ステップＳ６０において、アドレス特定部130は、第２のコード生成部120から出力された第２のコード300が配置されるプロセス空間500上のアドレスを特定する。また、アドレス特定部130は、特定したアドレスに第２のコード300を配置する。
【０１００】
ステップＳ７０において、アドレス特定部130は、特定したアドレスに第２のコード300が配置された第１のコード200をコード変換部140に出力する。
【０１０１】
ステップＳ８０において、コード変換部140は、フックポイント検出部110から出力されたフックポイント検出情報400に含まれるフックポイントHP及び置換コードに基づいて、アドレス特定部130から出力された第１のコード200にフックコードを埋め込む。
【０１０２】
ステップＳ９０において、コード変換部140は、フックコードを埋め込むことによって変換された変換済み第１のコード210を出力部150に出力する。
【０１０３】
（４）作用・効果
本実施形態に係るコード変換装置100によれば、フックポイント検出部110は、トレースする内容により特定される規則（フックポイント検出規則600）に従い、第１のコード200からフックポイントHPを検出する。例えば、第１のコード200全ての関数呼び出しをトレースしたい場合には、フックポイントHPは関数呼び出しを実行する分岐命令である。フックポイント検出部110は、第１のコード200から該当する全て分岐命令を検出する。検出したフックポイントHPのアドレスは、フックポイントHPのアドレスとともに、フックポイント検出情報400として、出力する。
【０１０４】
第２のコード生成部120は、第２のコード300、つまり、トレースコードを生成する。第２のコード300の生成は、フックポイント検出部110の処理とは独立に行われる。第２のコード300は、第１のコード200をトレースする以外に、フックポイント特定処理と、置換コード実行処理と、第１のコード復帰処理とを有する。当該３つの処理によって、第２のコード300がフックコードから呼び出されて実行された場合であっても、フックコードに置き換えられた置換コードが実行される。さらに、フックポイントHPへコードの実行制御を復帰させ、フックポイントHPから第１のコード200の実行を再開させることができる。
【０１０５】
アドレス特定部130は、第２のコード300が配置されるアドレスを特定する。第１のコード200から第２のコード300が呼び出される際、両者が同一プロセス空間にない場合には、コンテキストスイッチが発生する。そこで、第２のコード300は、第１のコード200の実行に影響を及ぼさないように、第１のコード200が実行されるプロセス空間500の適当なアドレスに配置される必要がある。アドレス特定部130は、当該アドレスを特定する。
【０１０６】
コード変換部140は、置換コードを、アドレス特定部130によってアドレスが特定された第２のコード300を呼び出すためのフックコードへと置き換える。フックコードによって第１のコード200のフックポイントHPから第２のコード300へと分岐し、第２のコード300が実行されることでトレース処理が行われる。
【０１０７】
出力部150は、フックコードを埋め込むことで変換された変換済み第１のコード210、第２のコード300を出力する。さらに、出力部150は、フックポイントHPと関連付けられた置換コードを出力する。
【０１０８】
このように、変換済み第１のコード210の実行において、コードの実行がフックポイントHPへ到達した際、フックコードが実行されることによって第２のコード300へと実行制御が移り、第２のコード300によるトレース処理が実行される。
【０１０９】
第２のコード300の実行時には、出力部150により出力された置換コードが実行された上で、第１のコード200のフックポイントHPへと実行制御が移る。このため、第２のコード300の実行後には、第１のコード200がフックポイントHPから引き続き実行される。つまり、第１のコード200の実行は、第２のコード300の実行に係わらず、継続して行われる。
【０１１０】
すなわち、コード変換装置100によれば、トレースに際してソースコードが不要であり、さらに動的変換処理を伴わずに第１のコード200のトレース処理ができる。このため、コード変換装置100によれば、フックポイントHPにフックコードを埋め込むフックコード埋め込み方式のトレース技術を用いる場合において、ソースコードに改変せずに、オーバヘッドを抑えたプログラム実行のトレースを実現することができる。
【０１１１】
本実施形態では、各エントリポイントに挿入されるフックコードは、フックポイントHPから対応するエントリポイントへの分岐命令である。また、フックポイント特定処理は、どのエントリポイントへ分岐したかによって、呼び出し元のフックポイントHPを特定する。このため、トレース処理後に実行すべき置換コード、及び復帰すべき第１のコード200のアドレスを特定できる。
【０１１２】
本実施形態では、置換コードが関数呼び出しであった場合、CPUの特定レジスタには、関数実行後の返りアドレスが保存される。返りアドレスは、フックポイントHPのアドレスに等しい。そこで、フックポイント特定処理では、当該特定レジスタを参照することによって、呼び出し元のフックポイントHPを特定する。このため、フックポイントHP毎にエントリポイントを用意することなく、復帰すべき第１のコード200のアドレスを特定できる。
【０１１３】
本実施形態では、仮想アドレス空間のうち、コード領域とデータ領域との間に実行可能かつ未使用なメモリ領域がある場合、第２のコード300が当該領域に配置される。このため、第１のコード200の実行に影響を及ぼすことなく、同一プロセス空間に第１のコード200と第２のコード300とを配置できる。さらに、プログラムの実行開始前にアドレス特定部130の処理が実行されるため、プログラム開始前にコード変換部140による処理も実行できる。つまり、プログラム実行開始時の処理量を削減することができる。
【０１１４】
本実施形態では、第２のコード300は、第１のコード200の実行終了時に呼び出されて実行される実行後処理を有する。このため、例えば、第２のコード300がトレースした結果（トレースログ）がバッファとしてメモリ上に蓄積されていた場合、第１のコード200の実行が終了して当該メモリが解放される前に、当該トレースログを二次記憶装置などに出力することができる。
【０１１５】
なお、このような処理は、フックコードから呼び出された際に実行することは困難である。なぜなら、フックコードから呼び出された時点では、第１のコード200の実行が終了するか否か判定できないからである。また、フックコードから呼び出される度に二次記憶装置などに出力する方法も考えられるが、出力の際に発生するオーバヘッドが大きくなってしまうという問題がある。
【０１１６】
本実施形態では、第１のコード200の中で最後に呼び出されるフックポイントHPから、第２のコード300の後処理を実行するルーチンへ分岐するフックコードが、当該フックポイントHPへ挿入される。プログラムの最後に実行されるコードは、バイナリ形式によって定まっている。例えば、ELFバイナリでは.finiセグメントが最後に実行されるため、当該セグメントの最後のフックポイントHPは、第１のコード200によって確実に最後に実行されるフックポイントHPである。このため、第２のコード300による後処理を確実に実行できる。
【０１１７】
ここで、本実施形態に係るコード変換装置100の特徴について整理する。本実施形態に係るコード変換装置100は、ソフトウェアのトレースに関する以下の要件を満足する。
【０１１８】
（ａ）コンテキスト情報を確実に取得できること
不具合の修正に利用可能となる情報の欠損を避けるため、確実にコンテキスト情報を取得できる必要がある。
【０１１９】
（ｂ）ソースコード無しでトレースできること
ソースコードや、再コンパイルが必要となるトレース技術は、開発者が利用する場合は有用であるが、ソフトウェアリリース後において、ユーザが利用する場合には現実的ではない。ソフトウェアによっては、実行可能バイナリのみが配布され、原理的にソースコードに頼ったトレースが不可能な場合もある。
【０１２０】
（ｃ）低オーバヘッドであること
トレース中であってもユーザは実際にソフトウェアを使用しているため、オーバヘッドはなるべく抑える必要がある。
【０１２１】
ここで、このような要件に基づいて従来のトレース技術について考察する。まず、サンプリング方式は、要件（ａ）を満足しないため適用できない。サンプリング方式では、任意の場所をフックすることは困難であるため、必要となるコンテキスト情報を取得することはできない。
【０１２２】
また、フック埋め込み方式のうち、ソース埋め込み型は、要件（ｂ）を満足しないため適用できない。
【０１２３】
要件（ｃ）については、実際にgprofとDtraceとを例として、ターゲットプログラムの実行に伴って発生する実行時間オーバヘッドを測定した。両者ともトレースログとして、プログラム実行中に呼び出された全ての関数についてコールグラフを記録した。
【０１２４】
表３は、gprofのオーバヘッド測定環境を示す。表４は、DTraceの測定環境を示す。表５は、ターゲットプログラムの実行条件を示す。ターゲットプログラムは、何れも同バージョンのgzip（http://www.gnu.org/software/gzip/参照）、perl（http://www.perl.org/参照）、tar（http://www.gnu.org/software/tar/参照）を同じコンパイルオプションによってコンパイルしたものを用いた。
【表３】
2009237610.tif 000005
【表４】
2009237610.tif 000006
【表５】
2009237610.tif 000007
【０１２５】
各ターゲットプログラムを定められた測定環境の下で、トレース無し及びトレースありの状態で実行し、それぞれの実行時間と各トレーサのオーバヘッドを測定した。表６及び表７は、当該測定結果を示す。
【表６】
2009237610.tif 000008
【表７】
2009237610.tif 000009
【０１２６】
動作環境の違いによってターゲットプログラムの本来の実行時間が異なるため、オーバヘッドで比較する。DTraceのオーバヘッドは、CTraceとは比較にならないほど大きい。これは、関数callのフックによりフックコードの実行が発生する度にコンテキストスイッチが発生するためである。さらに、ターゲットプログラム実行中にフックポイントの検出やフックコードへの変換といった動的変換処理が行われる動的変換型の欠点である。
【０１２７】
このようなオーバヘッドは、ソフトウェア開発者がデバッグ時に用いるのには許容範囲であったとしても、ソフトウェアのリリース後に、ユーザがトレースを実行する際には非現実的である。
【０１２８】
一方、CTraceのように、コンテキストスイッチが発生しないタイプのトレースでは、オーバヘッドは、数%から多くても数十%に収まる。すなわち、ユーザがソフトウェアの実行をトレースするためには、コンテキストスイッチや動的変換処理が発生しないことが必須であると言える。
【０１２９】
上述したように、従来のトレース方式は何れも、ソースコードに改変を加えずにプログラム実行を低いオーバヘッドでトレースすることはできず、ユーザが利用するソフトウェアのトレース方式として適当ではない。本実施形態に係るコード変換装置100は、上述した従来のトレース方式の問題を解決する。
【０１３０】
なお、上述した測定では、オーバヘッドとして時間の観点から比較したが、トレースログを取得していく際のもう一つの問題は、ログのサイズである。トレースログは、正常、異常に係わらず取得されていくため、適当なタイミングでトレースログのローテーションが行われないと、ログのサイズが膨大となる。このようなログは、メモリ上のバッファ、ディスクなどのリソースを圧迫するだけではなく、不要なデータの肥大化による有用なログの埋没を招く。
【０１３１】
このような問題について、例えば、特開2002-215431号公報では、記録するタイムスタンプの情報を減らすなどして、メモリ上のバッファ使用量を抑える技術が開示されている。また、特開2004-30505号公報では、不具合が発生した場合にのみトレースログを二次記憶装置に出力するなどして、蓄積されるログのサイズを抑える技術が開示されている。ログのサイズに関する問題については、コード変換装置100でも、これらの技術を用いて解決すればよい。
【０１３２】
［第２実施形態］
次に、本発明の第２実施形態について説明する。本実施形態ではプロセス空間500への第２のコード300の配置方法が第１実施形態と異なる。なお、以下、上述した第１実施形態と異なる部分について主に説明し、第１実施形態と同様な部分については、その説明を適宜省略する。
【０１３３】
（１）コード変換装置の機能
第１実施形態では、第２のコード300を静的に第１のコード200の空き領域に配置することによって、全ての処理を第１のコード200の実行開始前に静的に行うことが可能であった。しかし、第１のコード200の空き領域が、第２のコード300のサイズより大きいことが条件となる。実験の結果、第２のコード300が関数呼び出しをトレースするような処理であった場合には、当該条件が満たされることを確認した。
【０１３４】
しかし、空き領域のサイズは実行されるプログラムに依存するとともに、第２のコード300のサイズはトレース処理の内容に依存する。このため、上述した条件を満たさない場合も起こり得る。
【０１３５】
そこで、本実施形態では、第２のコード300は、動的リンクライブラリとして第１のコード200のプロセス空間500に配置される。動的リンクライブラリの配置先アドレスは、プログラムの実行開始時にローダによって決定される。
【０１３６】
例えば、第１のコード200が実行される際、ローダは、第２のコード300を含める。また、ローダは、ロードすべき全ての動的リンクライブラリを参照し、動的リンクライブラリのそれぞれが重ならないように配置する。このため、第２のコード300のサイズが第１のコード200の空き領域よりも大きくなる問題は起こらない。本実施形態に係るコード変換装置100は、第２のコード300を第１のコード200の動的リンクライブラリとしてロードする。
【０１３７】
フックポイント検出部110及び第２のコード生成部120の機能は、第１実施形態に係るコード変換装置100とほぼ同様である。
【０１３８】
まず、ソースコードの改変をすることなく、第２のコード300を第１のコード200の動的リンクライブラリとしてプロセス空間500へ配置する方法について説明する。例えば、LinuxやFreeBSDといったUNIX（登録商標）互換OSなどで可能なLD_PRELOAD環境変数を用いる方法がある。
【０１３９】
LD_PRELOADは、プログラムコードによって指定された動的リンクライブラリがロードされる前に、ローダによって優先的に指定したライブラリをロードする仕組みである。図８（ａ）及び（ｂ）は、LD_PRELOADによるライブラリのロードを説明する説明図である。
【０１４０】
例えば、C言語のputs関数を用いるようなプログラム（test.o）では、ローダは、プログラム実行開始時にlibcライブラリをロードする。そこで、以下にように、LD_PRELOADが自作の同名ライブラリ（./libc）をロードすることによって、puts関数を自作の関数（myputs）に置き換えることができる。
【０１４１】
$ LD_PRELOAD=./libc ./test.o
この仕組みを利用することによって、第１のコード200の実行時に、第２のコード300を共有ライブラリとしてロードすれば、上述した問題は解決する。
【０１４２】
しかし、動的リンクライブラリの配置先アドレスは、プログラム実行開始時にローダによって決定されるため、第２のコード300のアドレスを第１のコード200の実行開始前には特定することができない。そこで、アドレス特定部130、コード変換部140及び出力部150の処理は、ローダによる第２のコード300のロードが完了し、プロセス空間500に第２のコード300が配置された後に呼び出されることが要求される。例えば、プログラムローダ（linuxではld.so）に対して拡張実装することによって、このような要求に対応できる。
【０１４３】
アドレス特定部130は、ローダによって配置された第２のコード300を参照することによって、第２のコード300の配置先アドレスを特定する。具体的には、アドレス特定部130は、第１のコード200と対応する仮想アドレス空間のうち、共有ライブラリとして第２のコード300を配置可能なアドレス（配置可能アドレス）を特定する。
【０１４４】
なお、第２のコード生成部120は、アドレス特定部130によって特定された配置可能アドレスをアドレス情報として前記第２のコードに含める。
【０１４５】
コード変換部140は、既にメモリ上にロードされている第１のコード200に対してフックコードを埋め込む。第１のコード200の配置先アドレスは、フックポイント検出部110が解析した時点から変化していないため、フックポイント検出情報400のアドレスを参照することによってフックポイントHPの特定は容易である。
【０１４６】
ただし、フックポイントHPは、コード領域（図５及び図６に示すLOAD1）に存在するため、書き換えは許可されていない。そこで、内容を書き換える際には、一時的に当該アドレスの権限を変更する必要がある。例えば、linuxでは、mprotect()システムコールを利用する。
【０１４７】
出力部150は、ローダの通常処理に制御を渡すだけである。ローダは、第２のコード300以外の動的リンクライブラリを全てロードし、変換済み第１のコード210の実行を開始する。変換済み第１のコード210が実行された際における第２のコード300の処理については、第１実施形態と同様であるため省略する。
【０１４８】
以上説明したように、本実施形態では、第２のコード300に対するサイズ制限が生じない。さらに、本実施形態では、メモリにロードされたコードに対して、ロードの都度コード変換部140による処理が行われるため、第１のコード200を実行する度に、変換対象とするフックポイントHPを柔軟に変更することもできる。
【０１４９】
例えば、関数呼び出しをトレースするような場合において、（ｉ）全ての関数をトレースする場合、（ｉｉ）共有ライブラリ上の関数のみトレースする場合、（ｉｉｉ）ローカル関数のみをトレースする場合など、プログラムの実行毎にトレースの対象を切り替えることができる。
【０１５０】
第１のコード200上の不具合のみを調べる場合には、共有ライブラリ関数の呼び出しまでトレースすることは無意味であるため、ローカル関数のみをトレースすればよい。また、第１のコード200がシステム上のどのようなリソースを参照しているか調べる場合には、共有ライブラリ関数のみをトレースすればよい。
【０１５１】
このように、トレースする目的に応じて、フックコードを挿入するフックポイントHPを柔軟に切り替える方法についてさらに説明する。上述したトレースを例にすると、フックポイント検出部110がフックポイントHPを検出する際、それぞれのフックポイントHPにローカル関数呼び出しであるか、動的リンクライブラリ関数呼び出しであるかを区別するフラグを設定する。ライブラリ関数の呼び出しである場合には、必ずpltセクション経由での呼び出しが発生するため、上述した関数の判別は容易である。
【０１５２】
コード変換部140は、コードの実行時において、どの関数を実行するかを規定するコード変換規則700（図３参照）を入力とし、フックポイント検出情報400に含まれるフックポイントHPのうち、コード変換規則700に合致するフックポイントHPにのみ、フックコードを挿入していけばよい。
【０１５３】
すなわち、コード変換部140は、フックポイント検出部110によって検出されたフックポイントHPのうち、フックコードを挿入するためのコード変換規則700が特定のフックポイントHPにのみ与えられた場合、コード変換規則700によって指定されたフックポイントHPにのみ、フックコードを埋め込む。
【０１５４】
（２）作用・効果
本実施形態では、第１のコード200の実行開始時にローダによって共有ライブラリとのリンク処理が実行される場合、当該処理に割り込むことによって、第２のコード300が共有ライブラリとして第１のコード200にリンクされる。このため、第１のコード200の実行に影響を及ぼすことなく、また、第２のコード300のサイズに係わらず、同一のプロセス空間（プロセス空間500）に第１のコード200と第２のコード300とを配置できる。
【０１５５】
本実施形態では、例えば、第１のコード200を実行する状況によってトレースすべきフックポイントHPが異なるような場合、与えられたコード変換規則700がトレースすべきフックポイントHPを特定する。また、コード変換部140は、選択的にフックポイントHPのコード変換を行うことによって、フックコードを挿入する。このため、必要な部分のみのトレース処理を実行できる。
【０１５６】
［第３実施形態］
次に、本発明の第３実施形態について説明する。本実施形態では、第２実施形態と同様に、第１のコード200の動的リンクライブラリとして、第２のコード300がプロセス空間500へ配置する。ただし、第２実施形態とは異なり、コード変換装置100の全ての動作は、第１のコード200の実行開始前に行われる。このような動作によれば、第２実施形態と異なり、第１のコード200の実行開始時にコード変換装置100の処理によるオーバヘッドが発生することを回避できる。
【０１５７】
（１）コード変換装置の機能
第２実施形態でも記載したとおり、通常、動的リンクライブラリの配置アドレスは、プログラム実行開始時に、ロードされる動的リンクライブラリを参照することによってローダが解決する。このため、実行開始前に当該アドレスを特定することはできない。
【０１５８】
そこで、アドレス特定部130は、第２のコード300をあらかじめ参照することによって、配置可能なアドレスを特定する。このような仕組みは既に実現されており、linuxやFreeBSDなどのUNIX（登録商標）互換OSではprelink（prelink, http://people.redhat.com/jakub/prelink.pdf参照）と呼ばれる。prelinkは、元々、ローダによるプログラム実行開始時のアドレス解決処理を事前に行うことによって、プログラムの処理開始までの時間を短縮するための技術である。
【０１５９】
具体的には、アドレス特定部130は、prelinkする各ライブラリを参照し、配置アドレスを決定する。さらに、アドレス特定部130は、決定した配置アドレスを各ライブラリのプログラムヘッダにあらかじめ書き込む。実際にプログラムが起動される場合、各ライブラリは、プログラムヘッダにより指定されたアドレスに配置されていく。
【０１６０】
図９（ａ）及び（ｂ）は、試作した動的リンクライブラリに対するprelink実行前後のプログラムヘッダを示す。prelink後は、配置先のアドレスが固定されている（図９（ｂ）の園内参照）。
【０１６１】
すなわち、アドレス特定部130は、第１のコード200の実行開始時に、ローダによる共有ライブラリのロード処理が実行される場合、ロード処理の開始前に当該ロード処理をフックし、第２のコード300を共有ライブラリとしてプロセス空間500上に配置する。
【０１６２】
また、出力部150は、第１のコード200の実行開始時に、第２のコード300に含まれるアドレス情報を共有ライブラリのロード処理に提供することによって、第２のコード300が共有ライブラリとしてプロセス空間500上に配置される。
【０１６３】
（２）作用・効果
本実施形態では、第１のコード200の実行開始前に、第２のコード300を共有ライブラリとして配置可能なアドレスが、事前に解決（プレリンク）され、コードの実行時には、当該アドレスへ第２のコード300が配置される。
【０１６４】
このため、第１のコード200の実行に影響を及ぼすことなく、また、第２のコード300のサイズに係わらず、同一のプロセス空間（プロセス空間500）に第１のコード200と第２のコード300とを配置できる。さらに、プログラムの実行開始前にアドレス特定部130の処理が実行されるため、プログラム開始前にコード変換部140による処理も実行できる。つまり、プログラム実行開始時の処理量を削減することができる。
【０１６５】
［その他の実施形態］
上述したように、本発明の第１実施形態〜第３実施形態を通じて本発明の内容を開示したが、この開示の一部をなす論述及び図面は、本発明を限定するものであると理解すべきではない。この開示から当業者には様々な代替実施の形態が明らかとなろう。
【０１６６】
例えば、上述した第１実施形態では、第２のコード300は、第１のコード200の実行終了時に呼び出されて実行される実行後処理を有していたが、第２のコード300は、実行後処理を有していなくても構わない。
【０１６７】
また、上述した第１実施形態では、仮想アドレス空間のうち、コード領域とデータ領域との間に実行可能かつ未使用なメモリ領域がある場合、第２のコード300が当該領域に配置されたが、第２のコード300は、必ずしも当該領域に配置されなくてもよい。
【０１６８】
このように、本発明は、ここでは記載していない様々な実施の形態などを含むことは勿論である。したがって、本発明の技術的範囲は、上述の説明から妥当な特許請求の範囲に係る発明特定事項によってのみ定められるものである。
【図面の簡単な説明】
【０１６９】
【図１】プログラムトレースの原理を説明する説明図である。
【図２】メモリダンプとコンテキスト情報との関係を示す図である。
【図３】本発明の実施形態に係るコード変換装置100の全体概略構成図である。
【図４】本発明の実施形態において用いられるコードの概略構成を示す図である。
【図５】本発明の第１実施形態に係る第１のコード200がELFバイナリである場合におけるプログラムヘッダの例を示す図である。
【図６】本発明の第１実施形態に係る第２のコード300が配置可能な領域を示す図である。
【図７】本発明の第１実施形態に係るコード変換装置100を構成する各ブロックの動作フローを示す図である。
【図８】本発明の第２実施形態に係るLD_PRELOADによるライブラリのロードを説明する説明図である。
【図９】本発明の第３実施形態に係る動的リンクライブラリに対するprelink実行前後のプログラムヘッダを示す図である。
【符号の説明】
【０１７０】
100…コード変換装置、110…フックポイント検出部、120…第２のコード生成部、130…アドレス特定部、140…コード変換部、150…出力部、200…第１のコード、210…変換済み第１のコード、300…第２のコード、400…フックポイント検出情報、500…プロセス空間、600…フックポイント検出規則、700…コード変換規則、HP…フックポイント
【図１】
2009237610.tif 000010
【図２】
2009237610.tif 000011
【図３】
2009237610.tif 000012
【図４】
2009237610.tif 000013
【図５】
2009237610.tif 000014
【図６】
2009237610.tif 000015
【図７】
2009237610.tif 000016
【図８】
2009237610.tif 000017
【図９】
2009237610.tif 000018