(57)【要約】【課題】ソフトウェアの処理ログを容易に取得でき、かつ、バグの解析のための工数を削減することが可能なログ取得方法を提供する。【解決手段】関数（ＦｕｎｃＡＡ）を備えるプログラム９１において、実行中のログを取得するログ取得方法であって、ロードされた関数（ＦｕｎｃＡＡ）のアドレスを、ログ取得のための関数（９２）のアドレスに書き換える工程を備え、ログ取得のための関数（９２）は、関数（ＦｕｎｃＡＡ）のアドレスを呼び出し（９６）、該所定の処理を実行させ（９７）、受け取った実行結果（９８）をプログラム９１に渡す工程（１０１）と、プログラム９１内の関数定義に、ポインタ・パラメータが所定の定義方法で定義されているか否かを判断する工程と、定義されていた場合、該定義方法に基づいて該ポインタ・パラメータの指すメモリの内容をログとして記録する工程とを備える。【選択図】　図４Ａ
2004038312.tif 000002
【特許請求の範囲】
【請求項１】
所定の処理を行う関数を備えるプログラムの実行中のログを取得するログ取得方法であって、
ロードされた前記所定の処理を行う関数のアドレスを、ログ取得のための関数のアドレスに書き換える工程を備え、
前記ログ取得のための関数は、
前記所定の処理を行う関数を呼び出し、該所定の処理を実行させ、受け取った実行結果を前記プログラムに渡す工程と、
前記プログラム内の関数定義において、ポインタ・パラメータが所定の定義方法で定義されているか否かを判断する工程と、
ポインタ・パラメータが所定の定義方法で定義されていた場合、該定義方法に基づいて該ポインタ・パラメータの指すメモリの内容をログとして記録する工程と
を備えることを特徴とするログ取得方法。
【請求項２】
前記ログ取得のための関数は、前記定義方法に基づいてメモリサイズを算出する工程を更に備え、前記記録する工程は、前記ポインタ・パラメータの指すメモリの内容を、該算出したメモリサイズ分、記録することを特徴とする請求項１に記載のログ取得方法。
【請求項３】
所定の処理を行う関数を備えるプログラムの実行中のログを取得するログ取得方法であって、
ロードされた前記所定の処理を行う関数のアドレスを、ログ取得のための関数のアドレスに書き換える工程を備え、
前記ログ取得のための関数は、
前記所定の処理を行う関数を呼び出し、該所定の処理を実行させ、受け取った実行結果を前記プログラムに渡す工程と、
前記所定の処理を行う関数を呼び出す際の所定の情報と、前記実行結果を受け取った際の所定の情報とを記録する工程と、
前記プログラム内の関数定義に基づいて、エクスポートされていない関数の有無を判断する工程と、
エクスポートされていない関数があった場合、該関数に対応するログ取得のための関数を新たに生成し、該エクスポートされていない関数のアドレスを、該新たに生成された関数のアドレスに書き換える工程と、を備え、
前記新たに生成された関数は、
前記エクスポートされていない関数を呼び出し、該所定の処理を実行させ、受け取った実行結果を前記プログラムに渡す工程と、
前記エクスポートされていない関数を呼び出す際の所定の情報と、前記実行結果を受け取った際の所定の情報とを記録する工程と
を備えることを特徴とするログ取得方法。
【請求項４】
所定の処理を行う関数を備えるプログラムの実行中のログを取得するログ取得方法であって、
ロードされた前記所定の処理を行う関数のアドレスを、ログ取得のための関数のアドレスに書き換える工程を備え、
前記ログ取得のための関数は、
前記所定の処理を行う関数を呼び出し、該所定の処理を実行させ、受け取った実行結果を前記プログラムに渡す工程と、
前記プログラム内の関数定義において、可変長配列としてポインタ・パラメータが定義されているか否かを判断する工程と、
可変長配列としてポインタ・パラメータが定義されていた場合、該ポインタ・パラメータの指すメモリの内容を該指定された配列で記録する工程と
を備えることを特徴とするログ取得方法。
【請求項５】
所定の処理を行う関数を備えるプログラムの実行中のログを取得するログ取得方法であって、
ロードされた前記所定の処理を行う関数のアドレスを、ログ取得のための関数のアドレスに書き換える工程を備え、
前記ログ取得のための関数は、
前記所定の処理を行う関数を呼び出し、該所定の処理を実行させ、受け取った実行結果を前記プログラムに渡す工程と、
前記プログラム内の関数定義に、構造体としてポインタ・パラメータが指定されているか否かを判断する工程と、
構造体としてポインタ・パラメータが指定されていた場合、該ポインタ・パラメータの指すメモリの内容について、前記プログラム内の関数定義において定義された構造体のサイズ分ログとして記録する工程と
を備えることを特徴とするログ取得方法。
【請求項６】
所定の処理を行う関数を備えるプログラムの実行中のログを取得するログ取得方法であって、
ロードされた前記所定の処理を行う関数のアドレスを、ログ取得のための関数のアドレスに書き換える工程を備え、
前記ログ取得のための関数は、
前記所定の処理を行う関数を呼び出し、該所定の処理を実行させ、受け取った実行結果を前記プログラムに渡す工程と、
前記プログラム内の関数定義において、構造体として種類指定がなされたポインタ・パラメータが定義されているか否かを判断する工程と、
構造体として種類指定がなされたポインタ・パラメータが定義されていた場合、該ポインタ・パラメータの指すメモリの内容を、種類指定がなされたデータ型として記録する工程と
を備えることを特徴とするログ取得方法。
【請求項７】
所定の処理を行うメソッドを備えるプログラムの実行中のログを取得するログ取得方法であって、
ロードされた前記所定の処理を行うメソッドのアドレスを、ログ取得のためのメソッドのアドレスに書き換える工程を備え、
前記ログ取得のためのメソッドは、
前記所定の処理を行うメソッドを呼び出し、該所定の処理を実行させ、受け取った実行結果を前記プログラムに渡す工程と、
前記プログラム内の関数定義において、ポインタ・パラメータが所定の定義方法で定義されているか否かを判断する工程と、
ポインタ・パラメータが所定の定義方法で定義されていた場合、該定義方法に基づいて該ポインタ・パラメータの指すメモリの内容をログとして記録する工程と
を備えることを特徴とするログ取得方法。
【請求項８】
前記ログ取得のためのメソッドは、前記定義方法に基づいてメモリサイズを算出する工程を更に備え、前記記録する工程は、前記ポインタ・パラメータの指すメモリの内容を、該算出したメモリサイズ分、記録することを特徴とする請求項７に記載のログ取得方法。
【請求項９】
所定の処理を行うメソッドを備えるプログラムの実行中のログを取得するログ取得方法であって、
ロードされた前記所定の処理を行うメソッドのアドレスを、ログ取得のためのメソッドのアドレスに書き換える工程を備え、
前記ログ取得のためのメソッドは、
前記所定の処理を行うメソッドを呼び出し、該所定の処理を実行させ、受け取った実行結果を前記プログラムに渡す工程と、
前記所定の処理を行うメソッドを呼び出す際の所定の情報と、前記実行結果を受け取った際の所定の情報とを記録する工程と、
前記プログラム内の関数定義に基づいて、エクスポートされていないメソッドの有無を判断する工程と、
エクスポートされていないメソッドがあった場合、該メソッドに対応するログ取得のためのメソッドを新たに生成し、該エクスポートされていないメソッドのアドレスを、該新たに生成されたメソッドのアドレスに書き換える工程と、を備え、
前記新たに生成されたメソッドは、
前記エクスポートされていないメソッドを呼び出し、該所定の処理を実行させ、受け取った実行結果を前記プログラムに渡す工程と、
前記エクスポートされていないメソッドを呼び出す際の所定の情報と、前記実行結果を受け取った際の所定の情報とを記録する工程と
を備えることを特徴とするログ取得方法。
【請求項１０】
所定の処理を行うメソッドを備えるプログラムの実行中のログを取得するログ取得方法であって、
ロードされた前記所定の処理を行うメソッドのアドレスを、ログ取得のためのメソッドのアドレスに書き換える工程を備え、
前記ログ取得のためのメソッドは、
前記所定の処理を行うメソッドを呼び出し、該所定の処理を実行させ、受け取った実行結果を前記プログラムに渡す工程と、
前記プログラム内の関数定義において、可変長配列としてポインタ・パラメータが定義されているか否かを判断する工程と、
可変長配列としてポインタ・パラメータが定義されていた場合、該ポインタ・パラメータの指すメモリの内容を該指定された配列で記録する工程と
を備えることを特徴とするログ取得方法。
【請求項１１】
所定の処理を行うメソッドを備えるプログラムの実行中のログを取得するログ取得方法であって、
ロードされた前記所定の処理を行うメソッドのアドレスを、ログ取得のためのメソッドのアドレスに書き換える工程を備え、
前記ログ取得のためのメソッドは、
前記所定の処理を行うメソッドを呼び出し、該所定の処理を実行させ、受け取った実行結果を前記プログラムに渡す工程と、
前記プログラム内の関数定義に、構造体としてポインタ・パラメータが指定されているか否かを判断する工程と、
構造体としてポインタ・パラメータが指定されていた場合、該ポインタ・パラメータの指すメモリの内容について、前記プログラム内の関数定義において定義された構造体のサイズ分ログとして記録する工程と
を備えることを特徴とするログ取得方法。
【請求項１２】
所定の処理を行うメソッドを備えるプログラムの実行中のログを取得するログ取得方法であって、
ロードされた前記所定の処理を行うメソッドのアドレスを、ログ取得のためのメソッドのアドレスに書き換える工程を備え、
前記ログ取得のためのメソッドは、
前記所定の処理を行うメソッドを呼び出し、該所定の処理を実行させ、受け取った実行結果を前記プログラムに渡す工程と、
前記プログラム内の関数定義において、構造体として種類指定がなされたポインタ・パラメータが定義されているか否かを判断する工程と、
構造体として種類指定がなされたポインタ・パラメータが定義されていた場合、該ポインタ・パラメータの指すメモリの内容を、種類指定がなされたデータ型として記録する工程と
を備えることを特徴とするログ取得方法。
【請求項１３】
請求項１乃至１２のいずれか１つに記載のログ取得方法をコンピュータによって実現させるための制御プログラムを格納した記憶媒体。
【請求項１４】
請求項１乃至１２のいずれか１つに記載のログ取得方法をコンピュータによって実現させるための制御プログラム。
【発明の詳細な説明】
【０００１】
【発明の属する技術分野】
本発明は、複数にモジュール分けされたソフトウェアの処理ログを取得するための技術に関するものである。
【０００２】
【従来の技術】
従来より、再現率の低いソフトウェアの障害に対しては、ソフトウェアの処理ログを取得し、当該処理ログを解析することによって、障害の原因をつきとめ、その対策を講じてきた。
【０００３】
【発明が解決しようとする課題】
しかし、上記従来の処理ログの取得には以下のような問題点がある。
（１）ユーザの動作環境でもログを取得しつづけるためには、ソフトウェアのモジュール自体に手を加え、処理ログ取得ルーチンを追加しなければならず、処理ログ取得のための作業負荷が大きかった。
（２）処理ログ取得はモジュール毎に行うため、生成されたログはモジュール単位のものとなってしまい、ソフトウェア全体の処理を、完全に時間順のログとして取得するのが困難である。このため、全体の処理ログとしての見通しが悪く、ログを解析して障害の原因を発見するまでのプロセスに工数がかかっていた。
【０００４】
本発明は、上記課題を鑑みてなされたものであり、複数にモジュール分けされたソフトウェアの処理ログを容易に取得でき、かつ、ソフトウェアの障害の原因の解析のための工数を削減することが可能なログ取得方法、ならびに該方法をコンピュータによって実現させるためのプログラム、および該プログラムを格納した記憶媒体を提供することを目的とする。
【０００５】
【課題を解決するための手段】
上記の目的を達成するために本発明に係るログ取得方法は以下のような構成を備える。即ち、
所定の処理を行う関数を備えるプログラムの実行中のログを取得するログ取得方法であって、
ロードされた前記所定の処理を行う関数のアドレスを、ログ取得のための関数のアドレスに書き換える工程を備え、
前記ログ取得のための関数は、
前記所定の処理を行う関数を呼び出し、該所定の処理を実行させ、受け取った実行結果を前記プログラムに渡す工程と、
前記プログラム内の関数定義において、ポインタ・パラメータが所定の定義方法で定義されているか否かを判断する工程と、
ポインタ・パラメータが所定の定義方法で定義されていた場合、該定義方法に基づいて該ポインタ・パラメータの指すメモリの内容をログとして記録する工程とを備える。
【０００６】
【発明の実施の形態】
【第１の実施形態】
本実施形態は、あるモジュールから別のモジュール内に存在する関数の呼び出しが行われる際の仕組みである、メモリに保持されたインポート関数アドレス、または仮想関数アドレステーブル（Ｖｉｒｔｕａｌ　Ａｄｄｒｅｓｓ　Ｔａｂｌｅ）を利用して、モジュール間の関数呼び出しをフックしてログに記録することで、ソフトウェアのモジュール自体に手を加えることなく、ソフトウエア全体の処理を、時間順のログとして取得することを可能にするものである。以下に具体的に説明する。
【０００７】
＜システム構成＞
図１は、本発明の各実施形態にかかるログ取得方法を実現するコンピュータ（ソフトウェア評価システム）の構成をあらわす図である。説明を簡略化するために、本実施形態では、本ソフトウェア評価システムが１台のＰＣ内部に構築されるものとするが、本発明のログ取得方法の特徴は１台のＰＣ内部に構築されるか、あるいは複数のＰＣにネットワークシステムとして構築されるかによらず有効である。
【０００８】
本ソフトウェア評価システムを搭載するコンピュータには、ＣＰＵ１、チップセット２、ＲＡＭ３、ハードディスクコントローラ４、ディスプレイコントローラ５、ハードディスクドライブ６、ＣＤ−ＲＯＭドライブ７、ディスプレイ８が搭載されている。また、ＣＰＵとチップセットを繋ぐ信号線１１、チップセット２とＲＡＭ３とを繋ぐ信号線１２、チップセット２と各種周辺機器とを繋ぐ周辺機器バス１３、ハードディスクコントローラ４とハードディスクドライブ６とを繋ぐ信号線１４、ハードディスクコントローラ４とＣＤ−ＲＯＭドライブ７とを繋ぐ信号線１５、ディスプレイコントローラ５とディスプレイ８とを繋ぐ信号線１６が搭載されている。
【０００９】
＜関数処理に対する処理ログ取得＞
本発明の第１の実施形態にかかるログ取得方法を実現するソフトウェア評価システムを説明するために、まず図２によって、複数のモジュールに分かれたソフトウェアが、通常の状態でどのようにメモリにロードされるかを説明する。
【００１０】
通常、複数のモジュールに分かれたソフトウェアは、全体の制御を行う実行ファイルＥＸＥ（２３）と、モジュールとして存在しＥＸＥの補完的な役割を担うダイナミックリンクライブラリＤＬＬ（２７）とに分かれており、メモリにはＥＸＥとＤＬＬの両方がロードされる。ＥＸＥはコードセグメント（２８）とデータセグメント（２９）、そしてインポート関数アドレステーブル（２２）から成っている。更に、インポート関数アドレステーブルは、関数の所属するＤＬＬによって分かれており（２１，　２４）、ＤＬＬごとにそれぞれの関数がロードされたアドレスが書かれている（３０〜３５）。ＤＬＬの関数の実体は、ＤＬＬごとに分かれて（２５，　２６）ロードされ、それぞれの関数は該当するＤＬＬの一部としてロードされる（３６〜４１）。この図では、１本のＥＸＥがＡ．ＤＬＬ及びＢ．ＤＬＬの２つのダイナミックリンクライブラリ内の関数を使用している例を示しており、実際に使用される関数はＦｕｎｃ　ＡＡ，　Ｆｕｎｃ　ＡＢ，　Ｆｕｎｃ　ＡＣ，　Ｆｕｎｃ　ＢＡ，　Ｆｕｎｃ　ＢＢ，　Ｆｕｎｃ　ＢＣの６個となっている。
【００１１】
ＥＸＥのコードセグメント内にあるコードが関数Ｆｕｎｃ　ＡＡを呼び出す場合には、まずインポート関数アドレステーブル内に書かれたＦｕｎｃ　ＡＡのアドレス（３０）が読み込まれる。ここには実際にはＡ．ＤＬＬの一部として読み込まれたＦｕｎｃ　ＡＡコード（３６）のアドレスが書かれており、そのアドレスをコールすることによって、ＥＸＥのコードはＡ．ＤＬＬのＦｕｎｃ　ＡＡを呼び出すことができる。
【００１２】
図３は、本発明の第１の実施形態にかかるログ取得方法を実現するソフトウェア評価システムのメモリ構成をあらわす図であり、図２とは、ログ取得用のコードに対してＩＡＴ　Ｐａｔｃｈ（Ｉｍｐｏｒｔ　Ａｄｄｒｅｓｓ　Ｔａｂｌｅ　Ｐａｔｃｈ）という手法を用いて、関数呼び出しをリダイレクトしているという点で異なっている。
【００１３】
ログ取得が開始されると、メモリ内にはＩＡＴ　Ｐａｔｃｈ用のＤＬＬであるＣ．ＤＬＬ（５８）がロードされる。Ｃ．ＤＬＬはインポート関数アドレステーブル（５２）内に書かれた関数のアドレスを、Ｃ．ＤＬＬ内のログ取得コードであるＦｕｎｃ　ＣＡＡ，　Ｆｕｎｃ　ＣＡＢ，　Ｆｕｎｃ　ＣＡＣ，　Ｆｕｎｃ　ＣＢＡ，Ｆｕｎｃ　ＣＢＢ，　Ｆｕｎｃ　ＣＢＣのアドレスに書き換える（６１〜６６）。Ｃ．ＤＬＬ内のＦｕｎｃ　ＣＡＡ，　Ｆｕｎｃ　ＣＡＢ，　Ｆｕｎｃ　ＣＡＣ，　Ｆｕｎｃ　ＣＢＡ，　Ｆｕｎｃ　ＣＢＢ，　Ｆｕｎｃ　ＣＢＣのコード（７３〜７８）は、ログを記録すると共に、元々の関数呼び出しを受けるべくメモリにロードされている、該当する関数であるＦｕｎｃ　ＡＡ，　Ｆｕｎｃ　ＡＢ，　Ｆｕｎｃ　ＡＣ，　Ｆｕｎｃ　ＢＡ，　Ｆｕｎｃ　ＢＢ，　Ｆｕｎｃ　ＢＣ（６７〜７２）を呼び出す。
【００１４】
図４Ａは、図３におけるＩＡＴ　Ｐａｔｃｈの処理をあらわす図、図４Ｂはログ取得処理の流れを示すフローチャートである。説明を簡略化するために、この図ではＥＸＥがＡ．ＤＬＬ内のＦｕｎｃ　ＡＡを呼び出す際に、ＩＡＴ　Ｐａｔｃｈによるログ取得コードがどのように動作するかの例をあらわしている。
【００１５】
ＥＸＥ（図４Ａの９１）がＦｕｎｃ　ＡＡをコールすると（図４Ａの９４）、Ｃ．ＤＬＬ内にあるログ取得コードがＤＬＬ名／関数名をメモリに保存し（図４ＢのステップＳ４０２）、呼び出し時刻をメモリに保存し、呼び出し時のパラメータをメモリに保存し、呼び出し時のポインタパラメータの指すメモリ内容を、別メモリに保存する（図４Ａの９５、図４ＢのステップＳ４０３）。その後Ｃ．ＤＬＬは本来呼び出されるはずであった、Ａ．ＤＬＬ（図４Ａの９３）内のＦｕｎｃ　ＡＡをコールする（図４Ａの９６、図４ＢのステップＳ４０４）。Ａ．ＤＬＬのＦｕｎｃ　ＡＡ処理（図４Ａの９７）が終了し、Ｃ．ＤＬＬに制御がリターンすると（図４Ａの９８）、Ｃ．ＤＬＬはリターン時の時刻をメモリに保存し、戻り値をメモリに保存し、リターン時にポインタパラメータが指すメモリ内容を、別メモリに保存する（図４Ａの９９）。その後、Ｃ．ＤＬＬは保存したログ情報をファイルに書き込み（図４Ａの１００、図４ＢのステップＳ４０５）、あたかもＡ．ＤＬＬのＦｕｎｃ　ＡＡが通常通りに終了したかのように、ＥＸＥにリターンする（１０１）。
【００１６】
図５は、本発明の第１の実施形態にかかるログ取得方法を実現するソフトウェア評価システムの内部構成をあらわす図である。通常は実行形式のＥＸＥ（１１３）が、ＤＬＬ−１（１１６）やＤＬＬ−２（１１７）内の関数を呼び出すが、ここではＡＰＩトレーサと呼ばれるログ取得コードを埋め込み（１１４）、処理ログを生成している（１１５）。ＡＰＩトレーサは、ＤＬＬ−１やＤＬＬ−２の関数定義を記述したファイル（１１１）と、どのＤＬＬのどの関数のインポート関数テーブルを書き換えてログを取得するかの設定シナリオ（トレースシナリオ１１２）を元に動作する。
【００１７】
＜メソッド処理に対する処理ログ取得＞
次に、本発明の第１の実施形態にかかるログ取得方法を実現するソフトウェア評価システムにおいて、実行ファイルＥＸＥ（１１８）がＣＯＭ（Ｃｏｍｐｏｎｅｎｔ　Ｏｂｊｅｃｔ　Ｍｏｄｅｌ）サーバでエクスポートされているインターフェースのインスタンス作成時に、どのようにメモリにロードされるかを説明するために、まず、図６によって、通常の状態でどのようにメモリにロードされるかを説明する。
【００１８】
通常、インターフェースのインスタンス作成を行うと、ＣＯＭサーバ内で、要求されたインターフェース（１２１，　１２２）と、そのメソッド（：オブジェクト指向プログラミングにおいて、オブジェクトの実行する手続きを記述したプログラム、１３０〜１３５）が作成され、それらは、メモリ上に両方がロードされる。ここで、ｖｉｒｔｕａｌ　ａｄｄｒｅｓｓ　ｔａｂｌｅ（仮想アドレステーブル）は作成された各インターフェース毎に作られ（１１８，　１２０）、作成要求を行ったＥＸＥに渡される。このｖｉｒｔｕａｌ　ａｄｄｒｅｓ　ｔａｂｌｅには各メソッドの作成されたアドレスが書かれている（１２４〜１２９）。ＥＸＥはこれら情報を利用し、各インターフェースに対して呼び出しを行う。この図では、１本のＥＸＥがＩｎｔｅｒｆａｃｅ　Ａ及びＩｎｔｅｒｆａｃｅ　Ｂの２つのインターフェースのインスタンスを作成しており、そのインターフェース内部のメソッドを使用している例を示しており、実際に使用されているメソッドは、Ｍｅｔｈｏｄ　ＡＡ，　Ｍｅｔｈｏｄ　ＡＢ，　Ｍｅｔｈｏｄ　ＡＣ，　Ｍｅｔｈｏｄ　ＢＡ，　Ｍｅｔｈｏｄ　ＢＢ，　Ｍｅｔｈｏｄ　ＢＣとなっている。
【００１９】
ＥＸＥのコードが関数Ｍｅｔｈｏｄ　ＡＡを呼び出す場合には、まずｖｉｒｔｕａｌ　ａｄｄｒｅｓｓ　ｔａｂｌｅ内に書かれたＭｅｔｈｏｄ　ＡＡのアドレス（１２４）が読み込まれる。ここには実際にはＣＯＭサーバのＩｎｔｅｒｆａｃｅ　Ａの一部として作成されたＭｅｔｈｏｄ　ＡＡコード（１３０）のアドレスが書かれており、そのアドレスをコールすることによって、ＥＸＥのコードはＩｎｔｅｒｆａｃｅ　ＡのＭｅｔｈｏｄ　ＡＡを呼び出すことができる。
【００２０】
図７は、本発明の第１の実施形態にかかるログ取得方法を実現するソフトウェア評価システムのメモリ構成をあらわす図であり、図６とは、ログ取得用のコードに対してＶＴａｂｌｅ　Ｐａｔｃｈ（ｖｉｒｔｕａｌ　ａｄｄｒｅｓｓ　ｔａｂｌｅ　Ｐａｔｃｈ）という手法を用いて、メソッド呼び出しをリダイレクトしているという点で異なっている。
【００２１】
ログ取得が開始されると、メモリ内にはＶＴａｂｌｅ　Ｐａｔｃｈ用のＤＬＬ（１４３）がロードされる。このＤＬＬはｖｉｒｔｕａｌ　ａｄｄｒｅｓｓ　ｔａｂｌｅ（１３６，　１３８）内に書かれたメソッドのアドレスを、ＤＬＬ内のログ取得コードであるＭｅｔｈｏｄ　Ａ’Ａ，　Ｍｅｔｈｏｄ　Ａ’Ｂ，　ＭｅｔｈｏｄＡ’Ｃ，　Ｍｅｔｈｏｄ　Ｂ’Ａ，　Ｍｅｔｈｏｄ　Ｂ’Ｂ，　Ｍｅｔｈｏｄ　Ｂ’Ｃのアドレスに書き換える（１４５〜１５０）。ＤＬＬ内のＭｅｔｈｏｄ　Ａ’Ａ，Ｍｅｔｈｏｄ　Ａ’Ｂ，　Ｍｅｔｈｏｄ　Ａ’Ｃ，　Ｍｅｔｈｏｄ　Ｂ’Ａ，　Ｍｅｔｈｏｄ　Ｂ’Ｂ，　Ｍｅｔｈｏｄ　Ｂ’Ｃのコード（１５７〜１６２）は、ログを記録すると共に、元々のメソッド呼び出しを受けるべくメモリにロードされている、該当するメソッドであるＭｅｔｈｏｄ　ＡＡ，　Ｍｅｔｈｏｄ　ＡＢ，　Ｍｅｔｈｏｄ　ＡＣ，　Ｍｅｔｈｏｄ　ＢＡ，　Ｍｅｔｈｏｄ　ＢＢ，　Ｍｅｔｈｏｄ
ＢＣ（１５７〜１６２）を呼び出す。
【００２２】
図８Ａは、図７におけるＶＴａｂｌｅ　Ｐａｔｃｈの処理をあらわす図、図８Ｂはログ取得処理の流れを示すフローチャートである。説明を簡略化するために、この図ではＥＸＥがＣＯＭサーバ内のＩｎｔｅｒｆａｃｅ　ＡのＭｅｔｈｏｄＡＡを呼び出す際に、ＶＴａｂｌｅ　Ｐａｔｃｈによるログ取得コードがどのように動作するかの例をあらわしている。
【００２３】
ＥＸＥ（図８Ａの１６３）がＭｅｔｈｏｄ　ＡＡをコールすると（図８Ａの１６６）、ＤＬＬ内にあるログ取得コードがモジュール名／インターフェース名／メソッド名をメモリに保存し（図８ＢのステップＳ８０２）、呼び出し時刻をメモリに保存し、呼び出し時のパラメータをメモリに保存し、呼び出し時のポインタパラメータの指すメモリ内容を、別メモリに保存する（図８Ａの１６７、図８ＢのステップＳ８０３））。その後ＤＬＬは本来呼び出されるはずであった、ＣＯＭサーバ（図８Ａの１６５）内のＭｅｔｈｏｄ　ＡＡをコールする（図８Ａの１６８、図８ＢのステップＳ８０４））。ＣＯＭサーバのＭｅｔｈｏｄ　ＡＡ処理（図８Ａの１６９）が終了し、ＤＬＬに制御がリターンすると（図８Ａの１７０）、ＤＬＬはリターン時の時刻をメモリに保存し、戻り値をメモリに保存し、リターン時にポインタパラメータが指すメモリ内容を、別メモリに保存する（図８Ａの１７１）。その後、ＤＬＬは保存したログ情報をファイルに書き込み（図８Ａの１７２、図８ＢのステップＳ８０５）、あたかもＣＯＭサーバのＭｅｔｈｏｄ　ＡＡが通常通りに終了したかのように、ＥＸＥにリターンする（図８Ａの１７３）。
【００２４】
図９は、本発明の第１の実施形態にかかるソフトウェア評価システムの内部構成をあらわす図である。通常は実行形式のＥＸＥ（１７６）が、ＣＯＭサーバ１（１７９）やＣＯＭサーバ２（１８０）内のメソッドを呼び出すが、ここではＡＰＩトレーサと呼ばれるログ取得コードを埋め込み（１７７）、処理ログを生成している（１７８）。ＡＰＩトレーサは、ＣＯＭサーバ１（１７９）やＣＯＭサーバ２の関数定義を記述したファイル（１７４）と、どのＣＯＭサーバのどのインターフェースのどのメソッドのｖｉｒｔｕａｌ　ａｄｄｒｅｓｓ　ｔａｂｌｅを書き換えてログを取得するかの設定シナリオ（１７５）を元に動作する。
【００２５】
以上の説明から明らかなように、本実施形態にかかるログ取得方法によれば、複数にモジュール分けされたソフトウエアの処理ログの取得において、モジュール自体に変更を加えることなく、モジュール内に用意された関数／メソッドの呼び出しをログとして記録することが可能となり、処理ログ取得のための作業負荷を低減することが可能となる。また、生成されるログは、時間順のログとして取得することができ、ログの解析が容易となるため、ソフトウェアの障害の原因の解析のための工数を削減することが可能となる。
【００２６】
【第２の実施形態】
本実施形態では、通常では、取得しきれないポインタ・パラメータのデータをバイナリとしてログ取得する場合について述べる。
【００２７】
図１０は、本実施形態にかかるログ取得方法を実現するソフトウェア評価システムの関数定義の一例であり、一般的に広く用いられているＩＤＬにより、記述されている。本実施形態にかかるログ取得方法を実現するソフトウェア評価システムに於いては、このＩＤＬをトークン化したタイプライブラリファイルを関数定義ファイルとして使用する。
【００２８】
図１１は、本実施形態にかかるログ取得方法を実現するソフトウェア評価システムの関数定義に於いて、ポインタ・パラメータに対してバイナリ取得を指定することで、ポインタ・パラメータのデータの実体をログとして取得する為のＩＤＬによる記述である。
【００２９】
ＦｕｎｃＢｉｎｉｄＩｄ関数の定義に於いて、ｌｏｎｇ＊　ｌｐｌＰａｒａｍに対してｃｕｓｔｕｍ（ＰＡＴ＿ＰＡＲＡＭ＿ＡＴＴＲ＿ＩＤ，　”ｂｉｎｉｄ＿ｉｓ（）”）と宣言している（２０１）。ここで、ＰＡＴ＿ＰＡＲＡＭ＿ＡＴＴＲ＿ＩＤ（２００）はＩＤＬの中で本ソフトウェア評価システムが利用するための識別子である。ここで、”ｂｉｎｉｄ＿ｉｓ（）”と定義することにより、このパラメータが指すポインタからパラメータのデータ型サイズ（ここではｌｏｎｇ型）分のデータを、バイナリデータとしてログに保存する。
【００３０】
ＦｕｎｃＳｉｚｅＩｓ関数の定義に於いて、ｉｎｔ＊　ｌｐｌＰａｒａｍに対してｃｕｓｔｕｍ（ＰＡＴ＿ＰＡＲＡＭ＿ＡＴＴＲ＿ＩＤ，　”ｓｉｚｅ＿ｉｓ（ｄｗＣｏｕｎｔ）”）と宣言している（２０２）。ここで、”ｓｉｚｅ＿ｉｓ（ｄｗＣｏｕｎｔ）”と定義することにより、このパラメータは第一パラメータであるｄｗＣｏｕｎｔ個分のデータが有ると扱われる。そして、このパラメータが指すポインタから、（ｄｗＣｏｕｎｔ×パラメータのデータ型サイズ（ここでは、ｉｎｔ型））分のデータをバイナリデータとしてログに保存する。
【００３１】
ＦｕｎｃＬｅｎｇｔｈＩｓ関数の定義に於いて、ｃｈａｒ＊　ｌｐｓｚＰａｒａｍに対してｃｕｓｔｕｍ（ＰＡＴ＿ＰＡＲＡＭ＿ＡＴＴＲ＿ＩＤ，　”ｌｅｎｇｔｈ＿ｉｓ（ｄｗＬｅｎｇｔｈ）”）と宣言している（２０３）。ここで、”ｌｅｎｇｔｈ＿ｉｓ（ｄｗＬｅｎｇｔｈ）”と定義することにより、このパラメータは第一パラメータであるｄｗＬｅｎｇｔｈ個分のデータが有ると扱われる。そして、このパラメータが指すポインタから、（ｄｗＬｅｎｇｔｈ×パラメータのデータ型サイズ（ここではｃｈａｒ型））分のデータをバイナリデータとしてログに保存する。
【００３２】
ＦｕｎｃＢｙｔｅｓＩｓ関数の定義に於いて、ｖｏｉｄ＊　ｌｐＰａｒａｍに対してｃｕｓｔｕｍ（ＰＡＴ＿ＰＡＲＡＭ＿ＡＴＴＲ＿ＩＤ，　”ｂｙｔｅｓ＿ｉｓ（ｄｗＳｉｚｅ）”）と宣言している（２０４）。ここで、”ｂｙｔｅｓ＿ｉｓ（ｄｗＳｉｚｅ）”と定義することにより、このパラメータは第一パラメータであるｄｗＳｉｚｅｓバイト分のデータが有ると扱われる。そして、このパラメータが指すポインタから、ｄｗＳｉｚｅバイト分のデータをバイナリデータとしてログに保存する。
【００３３】
ＦｕｎｃＢｙｔｅｓＩｓ１関数の定義に於いて、ｖｏｉｄ＊　ｌｐＰａｒａｍに対してｃｕｓｔｕｍ（ＰＡＴ＿ＰＡＲＡＭ＿ＡＴＴＲ＿ＩＤ，　”ｂｙｔｅｓ＿ｉｓ（１２）”）と宣言している（２０５）。ここで、”ｂｙｔｅｓ＿ｉｓ（１２）”と定義することにより、このパラメータは指定された１２バイト分のデータが有ると扱われる。そして、このパラメータが指すポインタから、１２バイト分のデータをバイナリデータとしてログに保存する。
【００３４】
図１２は、本実施形態にかかるログ取得方法を実現するソフトウェア評価システムにおいて、図１１の様に関数定義されている時のログを取得する場合の流れを示す図である。
【００３５】
処理が開始されると（ステップＳ１）、ログ取得を開始し、モジュール名、インターフェース名、関数／メソッド名をＨＤＤに保存する（ステップＳ２）。次にログ取得コードは、呼び出し時の時刻、パラメータ及びポインタ・パラメータの指すメモリの内容をＨＤＤに保存する（ステップＳ３）。そして、関数定義にバイナリ取得の設定が存在するか判別し（ステップＳ４）、存在する場合には、保存するメモリサイズを各定義方法（ｂｉｎｉｄ＿ｉｓ，　ｓｉｚｅ＿ｉｓ，　ｌｅｎｇｔｈ＿ｉｓ，　ｂｙｔｅｓ＿ｉｓ）毎に計算し（ステップＳ５）、ポインタ・パラメータの指すメモリの内容を算出したサイズ分ＨＤＤに保存する（ステップＳ６）。続いて、元の関数を呼び出す（ステップＳ７）。関数からリターンすると、ログ取得コードはリターン時の時刻、戻り値及びポインタ・パラメータの指すメモリの内容をＨＤＤに保存する（ステップＳ８）。そして、関数定義にバイナリ取得の設定が存在するか判別し（ステップＳ９）、存在する場合には、保存するメモリサイズを各定義方法（ｂｉｎｉｄ＿ｉｓ，　ｓｉｚｅ＿ｉｓ，ｌｅｎｇｔｈ＿ｉｓ，　ｂｙｔｅｓ＿ｉｓ）毎に計算し（ステップＳ１０）、ポインタ・パラメータの指すメモリの内容を算出したサイズ分ＨＤＤに保存する（ステップＳ１１）。この処理はユーザから終了の命令があると（ステップＳ１２）終了される。
【００３６】
図１３は、本実施形態にかかるログ取得方法を実現するソフトウェア評価システムにおいて、図１１の定義により取得されたログデータの図である。
【００３７】
関数定義により、バイナリ取得の設定がない場合に取得できるログ（２１０）は、ＤａｔａＩＤを除いた部分である。そして、バイナリ取得の設定を行った場合には、ＤａｔａＩＤ及び、バイナリデータのログ（２１１）が取得できる。例えばＦｕｎｃＳｉｚｅＩｓのログを比較すると、バイナリ取得の設定がない場合には、ポインタ・パラメータｌｐＰａｒａｍが指し示すデータをｉｎｔ型で１個分だけは取得可能である。しかし、実際にはこのデータは１０個のｉｎｔ型データの配列を指し示す。そのためバイナリ取得の設定を行った場合には、ｉｎｔ型データのサイズである４バイト×１０個分、計４０バイトのデータを取得可能となる。
【００３８】
以上の説明から明らかなように、本実施形態によれば、サイズとポインタ・パラメータを関連付けることにより、通常では、取得しきれないポインタ・パラメータのデータをバイナリとしてログ取得可能となる。
【００３９】
【第３の実施形態】
本実施形態では、コールバック関数等のエクスポートされていない関数をログとして取得する場合について述べる。
【００４０】
図１４は、本実施形態にかかるログ取得方法を実現するソフトウェア評価システムの関数定義に於いてコールバック関数等のエクスポートされていない関数をログとして取得するためのＩＤＬによる記述である。
【００４１】
ＦｕｎｃＳｅｔＣａｌｌＢａｃｋ関数の定義に於いて、ＤＷＯＲＤ　ｐｆｎＦｕｎｃＣａｌｌＢａｃｋに対してｃｕｓｔｏｍ（ＰＡＴ＿ＰＡＲＡＭ＿ＡＴＴＲ＿ＩＤ，　”ｆｕｎｃｎａｍｅ＿ｉｓ（ＦｕｎｃＣａｌｌＢａｃｋ）”）と宣言している（２２１）。ＦｕｎｃＳｅｔＣａｌｌＢａｃｋ関数は、モジュールに対してコールバック関数を設定する関数であり、ＤＷＯＲＤ　ｐｆｎＦｕｎｃＣａｌｌＢａｃｋは、そのコールバック関数のアドレスを設定するためのパラメータである。ここで、”ｆｕｎｃｎａｍｅ＿ｉｓ（ＦｕｎｃＣａｌｌＢａｃｋ）”と定義することにより、ログ取得処理は、このパラメータに渡された値をＦｕｎｃＣａｌｌＢａｃｋ関数（２２２）のアドレスとして認識し、ログ取得処理のアドレスに置換する。また、ログ取得処理時に本来のコールバック関数を呼ぶためにオリジナルの値を保存する。これにより、エクスポートされていないコールバック関数のログが取得可能となる。
【００４２】
ＧｅｔＦｕｎｃＰｏｉｎｔｅｒ関数の定義に於いて、ＤＷＯＲＤ　ｐｆｎＦｕｎｃＩｎｔｅｒｎａｌに対してｃｕｓｔｏｍ（ＰＡＴ＿ＰＡＲＡＭ＿ＡＴＴＲ＿ＩＤ，　”ｆｕｎｃｎａｍｅ＿ｉｓ（ＦｕｎｃＩｎｔｅｒｎａｌ”）と宣言している（２２３）。ＧｅｔＦｕｎｃＰｏｉｎｔｅｒ関数は、モジュール内部のエクスポートされていない関数のポインタを取得する関数であり、ＤＷＯＲＤ　ｐｆｎＦｕｎｃＩｎｔｅｒｎａｌは、その非エクスポート関数のポインタをを取得するためのパラメータである。ここで、”ｆｕｎｃｎａｍｅ＿ｉｓ（ＦｕｎｃＩｎｔｅｒｎａｌ）”と定義することにより、ログ取得処理は、このパラメータに渡された値をＦｕｎｃＩｎｔｅｒｎａｌ関数（２２４）のアドレスとして認識し、ログ取得処理のアドレスに置換する。また、ログ取得処理時に本来の非エクスポート関数を呼ぶためにオリジナルの値を保存する。これにより、エクスポートされていないモジュール内部の関数のログが取得可能となる。
【００４３】
ＧｅｔＦｕｎｃＰｏｉｎｔｅＡｒｒａｙ関数（２２５）は、モジュール内部のエクスポートされていない関数群のアドレスをＦＵＮＣＰＯＩＮＴＥＲＡＲＲＡＹ構造体（２２０）に取得するための関数である。ここで、ＦＵＮＣＰＯＩＮＴＥＲＡＲＲＡＹの各メンバの定義に対してｃｕｓｔｏｍ（ＰＡＴ＿ＰＡＲＡＭ＿ＡＴＴＲ＿ＩＤ，　”ｆｕｎｃｎａｍｅ＿ｉｓ（ＦｕｎｃＩｎｔｅｒｎａｌ１〜４）”）と宣言している。ここで、”ｆｕｎｃｎａｍｅ＿ｉｓ（ＦｕｎｃＩｎｔｅｒｎａｌ１〜４）”）と定義することにより、この構造体のメンバに渡された値をＦｕｎｃＩｎｔｅｒｎａｌ１〜４関数（２２６）のアドレスとして認識し、ログ取得処理のアドレスに置換する。また、ログ取得処理時に本来の非エクスポート関数を呼ぶためにオリジナルの値を保存する。これにより、エクスポートされていないモジュール内部の関数群のログを取得可能となる。
【００４４】
図１５は、本実施形態にかかるログ取得方法を実現するソフトウェア評価システムのメモリ構成をあらわす図であり、図３とは、隠し関数のログ取得用のコードが追加されている点で異なっている。Ａ．ＤＬＬにある、ＦｕｎｃＡＤ（２３１）は、エクスポートされていない関数であり、そのため、Ｉｍｐｏｒｔ　Ａｄｄｒｅｓｓ　Ｔａｂｌｅ（２３０）にも、存在しない。この時ｆｕｎｃｎａｍｅ＿ｉｓをＦｕｎｃＡＤに対して定義すると、Ｃ．ＤＬＬにログ取得のためのＦｕｎｃＣＡＤ（２３２）が生成され、本来ＦｕｎｃＡＤのアドレスが返されるｆｕｎｃｎａｍｅ＿ｉｓで定義されたパラメータの値を置換する場合に、ＦｕｎｃＣＡＤのアドレスが使用される。
【００４５】
図１６は、本実施形態にかかるログ取得方法を実現するソフトウェア評価システムにおいて、図１４の様に関数が定義されている時のログを取得する場合の流れを示す図である。
【００４６】
処理が開始されると（ステップＳ２１）、ログ取得を開始し、モジュール名、インターフェース名、関数／メソッド名をＨＤＤに保存する（ステップＳ２２）。次にログ取得コードは、呼び出し時の時刻、パラメータ及びポインタ・パラメータの指すメモリの内容をＨＤＤに保存する（ステップＳ２３）。そして、関数定義にｆｕｎｃｎａｍｅ＿ｉｓの設定が存在するか判別し（ステップＳ２４）、存在する場合には、ｆｕｎｃｎａｍｅ＿ｉｓによって定義されている関数定義を関数定義ファイルから取得し、その定義に基づいてログ取得処理用のコードを生成する（ステップＳ２５）。そして、ｆｕｎｃｎａｍｅ＿ｉｓが定義されている値を保存し、生成したログ取得コードのアドレスに置換する（ステップＳ２６）。
【００４７】
続いて、元の関数を呼び出す（ステップＳ２７）。関数からリターンすると、ログ取得コードはリターン時の時刻、戻り値及びポインタ・パラメータの指すメモリの内容をＨＤＤに保存する（ステップＳ２８）。そして、関数定義にｆｕｎｃｎａｍｅ＿ｉｓの設定が存在するか判別し（ステップＳ２９）、存在する場合には、ｆｕｎｃｎａｍｅ＿ｉｓによって定義されている関数の定義を関数定義ファイルから取得し、その定義に基づいてログ取得処理用のコードを生成する（ステップＳ３０）。そして、ｆｕｎｃｎａｍｅ＿ｉｓが定義されている値を保存し、生成したログ取得コードのアドレスに置換する（ステップＳ３１）。この処理はユーザから終了の命令があると（ステップＳ３２）終了される。
【００４８】
ｆｕｎｃｎａｍｅ＿ｉｓで設定されているパラメータが生成されたログ取得コードのアドレスに置換されると、その後そのアドレスを使用して呼び出される元の関数は、通常のログと同様に処理されるようになる（つまり、生成されたログ取得コードは、エクスポートされていない関数を呼び出し、処理を実行させ、受け取った実行結果を渡すとともに、エクスポートされていない関数を呼び出す際の所定の情報と、実行結果を受け取った際の所定の情報とをログとして記録する）。
【００４９】
図１７は、本実施形態にかかるログ取得方法を実現するソフトウェア評価システムにおいて、図１４の定義を行わない場合に取得されたログデータの図である。関数定義ファイルに於いて設定を行わない場合は、コールバック関数、エクスポートされていない内部関数のログは取得できない。
【００５０】
図１８は、本実施形態にかかるログ取得方法を実現するソフトウェア評価システムにおいて、図１４の定義より取得されたログデータの図である。関数定義ファイルに於いて、コールバック関数、エクスポートされていない内部関数を取得するように設定しているので、ＦｕｎｃＣａｌｌＢａｃｋ関数や、ＦｕｎｃＩｎｔｅｒｎａｌ関数、ＦｕｎｃＩｎｔｅｒｎａｌ４関数等の非エクスポート関数のログが取得可能となる。
【００５１】
このように本実施形態によれば、通常の方法では取得できない非エクスポート関数のログを取得可能になるという効果が得られる。
【００５２】
【第４の実施形態】
本実施形態では、通常の方法では取得できない関数のログとして、可変長配列のパラメータのログを取得する場合について述べる。
【００５３】
図１９は、本実施形態にかかるログ取得方法を実現するソフトウェア評価システムの関数定義に於いて可変長配列のパラメータをログとして取得するためのＩＤＬによる記述である。
【００５４】
ＦｕｎｃＡｒｒａｙＩｓ関数の定義に於いて、ｉｎｔ＊　ｌｐｎＰａｒａｍに対してｃｕｓｔｕｍ（ＰＡＴ＿ＰＡＲＡＭ＿ＡＴＴＲ＿ＩＤ，　”ａｒｒａｙ＿ｉｓ（ｄｗＣｏｕｎｔ）”）と宣言している（２４０）。ここで、”　ａｒｒａｙ＿ｉｓ（ｄｗＣｏｕｎｔ）”と定義することにより、このポインタ・パラメータは第一パラメータであるｄｗＣｏｕｎｔ個分のｉｎｔ型配列であると扱われる。そして、このポインタ・パラメータが指すポインタをｉｎｔ型のｄｗＣｏｕｎｔ個の配列とし、データをログに保存する。
【００５５】
図２０は、本実施形態にかかるログ取得方法を実現するソフトウェア評価システムにおいて、図１９の様に関数が定義されている時のログを取得する場合の流れ図である。
【００５６】
処理が開始されると（ステップＳ４１）、ログ取得を開始し、モジュール名、インターフェース名、関数／メソッド名をＨＤＤに保存する（ステップＳ４２）。次に関数定義に可変長配列取得（ａｒｒａｙ＿ｉｓ）の設定が存在するか判別し（ステップＳ４３）、存在する場合には、ポインタ・パラメータで定義されているパラメータを配列の定義として扱い（ステップＳ４４）、呼び出し時の時刻、パラメータ及びポインタ・パラメータの指すメモリの内容をＨＤＤに保存する（ステップＳ４５）。そして、続いて、元の関数を呼び出す（ステップＳ４６）。関数からリターンすると、ログ取得コードは関数定義に可変長配列取得（ａｒｒａｙ＿ｉｓ）の設定が存在するか判別し（Ｓ４７）、存在する場合には、ポインタ・パラメータで定義されているパラメータを配列の定義として扱い（ステップＳ４８）、リターン時の時刻、戻り値及びポインタ・パラメータの指すメモリの内容をＨＤＤに保存する（ステップＳ４９）。この処理はユーザから終了の命令があると（ステップＳ５０）終了される。
【００５７】
図２１は、本実施形態にかかるログ取得方法を実現するソフトウェア評価システムにおいて、図１９の定義を行わない場合に取得されたログデータ（２５０）と、図１９の定義により取得されたログデータ（２５１）の図である。関数定義ファイルに於いて設定を行わない場合は、ポインタ・パラメータは配列としては扱えないので、先頭のデータのみが取得されているが、関数定義ファイルに於いて設定が行われている場合では、ポインタ・パラメータは配列として扱われるため、配列の全データが取得されている。
【００５８】
このように本実施形態によれば、通常の方法では取得できない関数のログとして、可変長配列のパラメータのログが取得可能になるという効果が得られる。
【００５９】
【第５の実施形態】
本実施形態では、通常の関数定義では、パラメータを取得できない関数について、ログを取得する場合について説明する。
【００６０】
図２２は、本実施形態にかかるログ取得方法を実現するソフトウェア評価システムで、通常の関数定義では、パラメータを取得できない関数の例である。
【００６１】
構造体として、ＳＴＲＵＣＴＳＩＺＥ１，　ＳＴＲＵＣＴＳＩＺＥ２，　ＳＴＲＵＣＴＳＩＺＥ３の３種類が定義されており、各構造体のＤＷＯＲＤ　ｄｗＳｉｚｅメンバには、自分自身の構造体のサイズを入れる必要がある。ＦｕｎｃＧｅｔＤａｔａ関数は、第一パラメータｄｗＫｉｎｄと、第二パラメータｌｐＢｕｆに上記３種類のどの構造体のポインタが渡されているかを設定する。ＦｕｎｃＧｅｔＤａｔａ関数は、第一パラメータが１の場合には、ｌｐＢｕｆをＳＴＲＵＣＴＳＩＺＥ１のポインタとして扱って処理を行い、第一パラメータが２の場合には、ｌｐＢｕｆをＳＴＲＵＣＴＳＩＺＥ２のポインタとして扱って処理を行い、第一パラメータが３の場合には、ｌｐＢｕｆをＳＴＲＵＣＴＳＩＺＥ３のポインタとして扱って処理を行う。この場合、通常の関数定義により、ＦｕｎｃＧｅｔＤａｔａを定義すると、ｌｐＢｕｆはｖｏｉｄ型のポインタとなり、データを取得することはできない。
【００６２】
図２３は、図２２に於いて、ＳＴＲＵＣＴＳＩＺＥ１，　ＳＴＲＵＣＴＳＩＺＥ２，　ＳＴＲＵＣＴＳＩＺＥ３の各構造体がどのようにメモリを使用するかのメモリ図である。構造体ＳＴＲＵＣＴＳＩＺＥ１（２６０）の、各メンバは、オフセット０ｘ０００にＤＷＯＲＤ　ｄｗＳｉｚｅ（２６１）、０ｘ０００４にＤＷＯＲＤ　ｄｗＰａｒａｍ１（２６２）、０ｘ０００８にＤＷＯＲＤ　ｄｗＰａｒａｍ２、０ｘ０００ＣにＤＷＯＲＤ　ｄｗＰａｒａｍ３が存在する。構造体ＳＴＲＵＣＴＳＩＺＥ２（２６５）はＤＷＯＲＤ　ｄｗＳｉｚｅ〜ＤＷＯＲＤｄｗＰａｒａｍ３（２６６〜２６９）までは、ＳＴＲＵＣＴＳＩＺＥ１と同様であり、０ｘ００１０にＤＷＯＲＤ　ｄｗＰａｒａｍ４（２７０）が存在する。ＳＴＲＵＣＴＳＩＺＥ３（２７１）はＤＷＯＲＤ　ｄｗＳｉｚｅ〜ＤＷＯＲＤ　ｄｗＰａｒａｍ４（２７２〜２７６）までは、ＳＴＲＵＣＴＳＩＺＥ２と同様であり、０ｘ００１４にＤＷＯＲＤ　ｄｗＰａｒａｍ５（２７７）が存在する。このように、ＳＴＲＵＣＴＳＩＺＥ３のｄｗＳｉｚｅ〜ｄｗＰａｒａｍ４までのメモリ配置は、ＳＴＲＵＣＴＳＩＺＥ２と同様であり、ＳＴＲＵＣＴＳＩＺＥ２のｄｗＳｉｚｅ〜ｄｗＰａｒａｍ３までのメモリ配置は、ＳＴＲＵＣＴＳＩＺＥ１と同様になっている。
【００６３】
図２４は、本実施形態にかかるログ取得方法を実現するソフトウェア評価システムで、図２２の様な関数のパラメータのログを取得するためのＩＤＬによる記述である。
【００６４】
本来の関数では、ＳＴＲＵＣＴＳＩＺＥ１，　ＳＴＲＵＣＴＳＩＺＥ２，　ＳＴＲＵＣＴＳＩＺＥ３と分かれていた構造体をＳＴＲＵＣＴＳＩＺＥという１個の構造体として定義する（２９１）。この定義はＳＴＲＵＣＴＳＩＺＥ３と同様であり、これは、図２３でのメモリ配置から、ＳＴＲＵＣＴＳＩＺＥ３は、ＳＴＲＵＣＴＳＩＺＥ１、ＳＴＲＵＣＴＳＩＺＥ２と同様のメモリ配置部分を持つからである。そして、この構造体のメンバであり、構造体のサイズを表す、ＤＷＯＲＤ　ｄｗＳｉｚｅに対して、［ｃｕｓｔｕｍ（ＰＡＴ＿ＰＡＲＡＭ＿ＩＤ，　”ｓｔｒｕｃｔｓｉｚｅ＿ｉｓ（）”）］を設定する。この事で、ログ取得処理は構造体のデータ解析を行う場合に、構造体のサイズを知ることが可能となる。また、ＦｕｎｃＧｅｔＤａｔａ関数において、第二パラメータのｌｐＢｕｆをＳＴＲＵＣＴＳＩＺＥ型として定義しておく。こうすることで、このパラメータをログとして保存する場合には、ＳＴＲＵＣＴＳＩＺＥ型として処理が行われる。仮に、本手法を用いず、ＳＴＲＵＣＴＳＩＺＥ３のデータを取得するように関数定義ファイルに記述した場合には、ＧｅｔＦｕｎｃＤａｔａがｄｗＫｉｎｄ＝１や２で呼ばれた場合には、ＳＴＲＵＣＴＳＩＺＥ１やＳＴＲＵＣＴＳＩＺＥ２のデータが存在することになり、ｄｗＰａｒａｍ３やｄｗＰａｒａｍ４のデータをログに取得しようとしてしまうために、メモリ例外が発生する。
【００６５】
図２５は、本実施形態にかかるログ取得方法を実現するソフトウェア評価システムで、図の様に関数が定義されている時のログを取得する場合の流れを示す図である。
【００６６】
処理が開始されると（ステップＳ６１）、ログ取得を開始し、モジュール名、インターフェース名、関数／メソッド名をＨＤＤに保存する（ステップＳ６２）。次に関数定義に構造体のサイズ指定（ｓｔｒｕｃｔｓｉｚｅ＿ｉｓ）の設定が存在するか判別し（ステップＳ６３）、存在する場合には、設定されている構造体パラメータのデータをサイズ指定（ｓｔｒｕｃｔｓｉｚｅ＿ｉｓ）の設定で定義されているデータサイズ範囲内で解析する（ステップＳ６４）。そして、呼び出し時の時刻、パラメータ及びポインタ・パラメータの指すメモリの内容をＨＤＤに保存する（ステップＳ６５）。そして、続いて、元の関数を呼び出す（ステップＳ６６）。関数からリターンすると、関数定義に構造体のサイズ指定（ｓｔｒｕｃｔｓｉｚｅ＿ｉｓ）の設定が存在するか判別し（ステップＳ６７）、存在する場合には、設定されている構造体パラメータのデータをサイズ指定（ｓｔｒｕｃｔｓｉｚｅ＿ｉｓ）の設定で定義されているデータサイズ範囲内で解析する（ステップＳ６８）。そして、リターン時の時刻、戻り値及びポインタ・パラメータの指すメモリの内容をＨＤＤに保存する（ステップＳ６９）。この処理はユーザから終了の命令があると（ステップＳ７０）終了される。
【００６７】
図２６は、図２５で行われる構造体パラメータ解析の詳細をメモリ配置を基に表した図である。
【００６８】
実際のプログラムでＧｅｔＦｕｎｃＤａｔａがｄｗＫｉｎｄ＝１で使用された場合には、ＳＴＲＵＣＴＳＩＺＥ１構造体（３００）が使用され、その時の各メンバ（３０１〜３０４）のメモリ使用は、図のようになっている。図２４の様に関数定義がなされている場合には、本ソフトウェア評価システムでは、ＳＴＲＵＣＴＳＩＺＥ構造体（３０５）として認識され、その時の各メンバ（３０６〜３１１）のメモリ使用は図のようになると推測する。そして、サイズ指定（ｓｔｒｕｃｔｓｉｚｅ＿ｉｓ）の設定が存在する場合には、ｄｗＳｉｚｅの値を調べることで、構造体のサイズがｄｗＳｉｚｅバイトであると知ることが可能となり、ＳＴＲＵＣＴＳＩＺＥ構造体のうち、ｄｗＳｉｚｅバイト分（３１２）のデータのみをログとして取得する。
【００６９】
図２７は、本実施形態にかかるログ取得方法を実現するソフトウェア評価システムにおいて、図２４の定義により取得されたログデータの図である。通常の関数定義では、ｖｏｉｄ＊となり、ポインタのみしか取得できない構造体のデータが、使用される構造体の種類により、その構造体のデータがログとして取得されている。
【００７０】
このように、本実施形態によれば、通常の方法では取得できないパラメータのログを取得可能になるという効果が得られる。
【００７１】
【第６の実施形態】
図２８は、本実施形態にかかるログ取得方法を実現するソフトウェア評価システムで、通常の関数定義では、パラメータを取得できない関数の例である。
【００７２】
構造体として、ＳＴＲＵＣＴＫＩＮＤ１，　ＳＴＲＵＣＴＫＩＮＤ２，　ＳＴＲＵＣＴＫＩＮＤ３の３種類が定義されている。ＧｅｔＦｕｎｃＤａｔａ関数は、第一パラメータｄｗＫｉｎｄに第二パラメータｌｐＢｕｆに上記３種類のどの構造体のポインタが渡されているかを設定する。ＦｕｎｃＧｅｔＤａｔａ関数は、第一パラメータが１の場合には、ｌｐＢｕｆをＳＴＲＵＣＴＫＩＮＤ１のポインタとして扱って処理を行い、第一パラメータが２の場合には、ｌｐＢｕｆをＳＴＲＵＣＴＫＩＮＤ２のポインタとして扱って処理を行い、第一パラメータが３の場合には、ｌｐＢｕｆをＳＴＲＵＣＴＫＩＮＤ３のポインタとして扱って処理を行う。この場合、通常の関数定義により、ＦｕｎｃＧｅｔＤａｔａを定義すると、ｌｐＢｕｆはｖｏｉｄ型のポインタとなり、データを取得することはできない。
【００７３】
図２９は、図２８に於いて、ＳＴＲＵＣＴＫＩＮＤ１，　ＳＴＲＵＣＴＫＩＮＤ２，　ＳＴＲＵＣＴＫＩＮＤ３の各構造体がどのようなメモリ配置になるかを示した図である。構造体ＳＴＲＵＣＴＫＩＮＤ１（３３０）の、各メンバは、オフセット０ｘ００００にｃｈａｒ　ｃｈＰａｒａｍ（３３１）、０ｘ０００１にＤＷＯＲＤ　ｄｗＰａｒａｍ（３３２）、０ｘ０００５にｓｈｏｒｔ　ｓｈＰａｒａｍ（３３３）が存在する。構造体ＳＴＲＵＣＴＫＩＮＤ２（３３４）　の、各メンバは、オフセット０ｘ００００にｓｈｏｒｔ　ｓｈＰａｒａｍ（３３５）、０ｘ０００２にＤＷＯＲＤ　ｄｗＰａｒａｍ（３３６）、０ｘ０００６にｃｈａｒ　ｃｈＰａｒａｍ（３３７）が存在する。構造体ＳＴＲＵＣＴＫＩＮＤ３（３３８）　の、各メンバは、オフセット０ｘ００００にｃｈａｒ　ｃｈＰａｒａｍ（３３９）、０ｘ０００１にｓｈｏｒｔ　ｓｈＰａｒａｍ（３４０）、０ｘ０００３にＤＷＯＲＤ　ｄｗＰａｒａｍ（３４１）、０ｘ０００７にｌｏｎｇ　ｌＰａｒａｍ（３４２）、０ｘ０００Ｂにｉｎｔ　ｎＰａｒａｍが存在する。このように、各構造体にサイズの情報が無く、構造体データのメモリ構造も異なるため、第５の実施形態で示した方法は使用できない。
【００７４】
図３０は、本実施形態にかかるログ取得方法を実現するソフトウェア評価システムで、図２８の様な関数のパラメータのログを取得するためのＩＤＬによる記述である。
【００７５】
各構造体は、通常の方法で定義されている。ＦｕｎｃＧｅｔＤａｔａ関数の第二パラメータｖｏｉｄ＊　ｌｐＢｕｆに対して［ｃｕｓｔｕｍ（ＰＡＴ＿ＰＡＲＡＭ＿ＩＤ，　”ｓｔｒｕｃｔｋｉｎｄ＿ｉｓ（ｄｗＫｉｎｄ：１：ＳＴＲＵＣＴＫＩＮＤ１＊，　２：ＳＴＲＵＣＴＫＩＮＤ２＊，　３：ＳＴＲＵＣＴＫＩＮＤ３＊）”）］と設定している。これによりｌｐＢｕｆのデータ型は、第一パラメータｄｗＫｉｎｄの値が１の場合には、ＳＴＲＵＣＴＫＩＮＤ１＊として、２の場合には、ＳＴＲＵＣＴＫＩＮＤ２＊として、３の場合には、ＳＴＲＵＣＴＫＩＮＤ３＊として扱われ、ログとして保存される。
【００７６】
図３１は、本実施形態にかかるログ取得方法を実現するソフトウェア評価システムで、図３０の様に関数が定義されている時のログを取得する場合の流れを示す図である。
【００７７】
処理が開始されると（ステップＳ８１）、ログ取得を開始し、モジュール名、インターフェース名、関数／メソッド名をメモリに保存する（ステップＳ８２）。次に関数定義に構造体の種類指定（ｓｔｒｕｃｔｋｉｎｄ＿ｉｓ）の設定が存在するか判別し（ステップＳ８３）、存在する場合には、設定されている構造体パラメータのデータを種類指定（ｓｔｒｕｃｔｋｉｎｄ＿ｉｓ）の設定で定義されているデータ型として解析する（ステップＳ８４）。そして、呼び出し時の時刻、パラメータ及びポインタ・パラメータの指すメモリの内容をメモリに保存する（ステップＳ８５）。そして、続いて、元の関数を呼び出す（ステップＳ８６）。関数からリターンすると、関数定義に構造体の種類指定（ｓｔｒｕｃｔｋｉｎｄ＿ｉｓ）の設定が存在するか判別し（ステップＳ８７）、存在する場合には、設定されている構造体パラメータのデータを種類指定（ｓｔｒｕｃｔｋｉｎｄ＿ｉｓ）の設定で定義されているデータ型として解析する（ステップＳ８８）。そして、リターン時の時刻、戻り値及びポインタ・パラメータの指すメモリの内容をメモリに保存する（ステップＳ８９）。この処理はユーザから終了の命令があると（ステップＳ９０）終了される。
【００７８】
図３２は、本実施形態にかかるログ取得方法を実現するソフトウェア評価システムにおいて、図３０の定義により取得されたログデータの図である。通常の関数定義では、ｖｏｉｄ＊となり、ポインタのみしか取得できない構造体のデータが、使用される構造体の種類により、その構造体のデータがログとして取得されている。
【００７９】
このように本実施形態によれば、通常の方法では取得できないパラメータのログを取得可能になるという効果が得られる。
【００８０】
【他の実施形態】
なお、本発明は、複数の機器（例えばホストコンピュータ，インタフェイス機器、リーダ、プリンタなど）から構成されるシステムに適用しても、一つの機器からなる装置（例えば、複写機、ファクシミリ装置など）に適用してもよい。
【００８１】
また、本発明の目的は、前述した実施形態の機能を実現するソフトウェアのプログラムコードを記録した記憶媒体を、システムあるいは装置に供給し、そのシステムあるいは装置のコンピュータ（またはＣＰＵやＭＰＵ）が記憶媒体に格納されたプログラムコードを読出し実行することによっても、達成されることは言うまでもない。
【００８２】
この場合、記憶媒体から読出されたプログラムコード自体が前述した実施形態の機能を実現することになり、そのプログラムコードを記憶した記憶媒体は本発明を構成することになる。
【００８３】
プログラムコードを供給するための記憶媒体としては、例えば、フロッピ（登録商標）ディスク、ハードディスク、光ディスク、光磁気ディスク、ＣＤ−ＲＯＭ、ＣＤ−Ｒ、磁気テープ、不揮発性のメモリカード、ＲＯＭなどを用いることができる。
【００８４】
また、コンピュータが読出したプログラムコードを実行することにより、前述した実施形態の機能が実現されるだけでなく、そのプログラムコードの指示に基づき、コンピュータ上で稼働しているＯＳ（オペレーティングシステム）などが実際の処理の一部または全部を行い、その処理によって前述した実施形態の機能が実現される場合も含まれることは言うまでもない。
【００８５】
さらに、記憶媒体から読出されたプログラムコードが、コンピュータに挿入された機能拡張ボードやコンピュータに接続された機能拡張ユニットに備わるメモリに書込まれた後、そのプログラムコードの指示に基づき、その機能拡張ボードや機能拡張ユニットに備わるＣＰＵなどが実際の処理の一部または全部を行い、その処理によって前述した実施形態の機能が実現される場合も含まれることは言うまでもない。
【００８６】
【発明の効果】
以上説明したように本発明によれば、複数にモジュール分けされたソフトウェアの処理ログを容易に取得でき、かつ、ソフトウェアの障害の原因の解析のための工数を削減することが可能となる。
【図面の簡単な説明】
【図１】本発明の第１の実施形態にかかるログ取得方法を実現するコンピュータ（ソフトウェア評価システム）の構成をあらわす図である。
【図２】本発明の第１の実施形態にかかるログ取得方法を説明するためにあらわした、関数ロード時の通常のメモリ構成をあらわす図である。
【図３】本発明の第１の実施形態にかかるログ取得方法を実現するソフトウェア評価システムのＩＡＴ　Ｐａｔｃｈ使用時のメモリ構成をあらわす図である。
【図４Ａ】本発明の第１の実施形態にかかるログ取得方法を実現するソフトウェア評価システムのＩＡＴ　Ｐａｔｃｈを使用時の状態を示す図である。
【図４Ｂ】本発明の第１の実施形態にかかるログ取得方法を実現するソフトウェア評価システムのログ取得処理の流れを示す図である。
【図５】本発明の第１の実施形態にかかるソフトウェア評価システムのＩＡＴ　Ｐａｔｃｈを使用時の内部構成をあらわす図である。
【図６】本発明の第１の実施形態にかかるログ取得方法を説明するためにあらわした、ＣＯＭサーバのインターフェースのインスタンス作成時の通常のメモリ構成をあらわす図である。
【図７】本発明の第１の実施形態にかかるログ取得方法を実現するソフトウェア評価システムのＶＴａｂｌｅ　Ｐａｔｃｈ使用時のメモリ構成をあらわす図である。
【図８Ａ】本発明の第１の実施形態にかかるログ取得方法を実現するソフトウェア評価システムのＶＴａｂｌｅ　Ｐａｔｃｈを使用時の状態を示す図である。
【図８Ｂ】本発明の第１の実施形態にかかるログ取得方法を実現するソフトウェア評価システムのログ取得処理の流れを示す図である。
【図９】本発明の第１の実施形態にかかるログ取得方法を実現するソフトウェア評価システムの、内部構成をあらわす図である。
【図１０】本発明の第２の実施形態にかかるログ取得方法を実現するソフトウェア評価システムの関数定義の一例を示す図である。
【図１１】本発明の第２の実施形態にかかるログ取得方法を実現するソフトウェア評価システムの関数定義に於いて、ポインタ・パラメータに対してバイナリ取得を指定することで、ポインタ・パラメータのデータの実体をログとして取得する為のＩＤＬによる記述を示す図である。
【図１２】本発明の第２の実施形態にかかるログ取得方法を実現するソフトウェア評価システムにおいて、図１１の様に関数が定義されている時のログを取得する場合の流れを示す図である。
【図１３】本発明の第２の実施形態にかかるログ取得方法を実現するソフトウェア評価システムにおいて、図１１の定義により取得されたログデータの図である。
【図１４】本発明の第３の本実施形態にかかるログ取得方法を実現するソフトウェア評価システムの関数定義に於いて、コールバック関数等のエクスポートされていない関数をログとして取得するためのＩＤＬによる記述を示す図である。
【図１５】本発明の第３の実施形態にかかるログ取得方法を実現するソフトウェア評価システムのメモリ構成をあらわす図である。
【図１６】本発明の第３の実施形態にかかるログ取得方法を実現するソフトウェア評価システムにおいて、図１４の様に関数が定義されている時のログを取得する場合の流れを示す図である。
【図１７】本発明の第３の実施形態にかかるログ取得方法を実現するソフトウェア評価システムにおいて、図１４の定義を行わない場合に取得されたログデータの図である。
【図１８】本発明の第３の実施形態にかかるログ取得方法を実現するソフトウェア評価システムにおいて、図１４の定義より取得されたログデータの図である。
【図１９】本発明の第４の実施形態にかかるログ取得方法を実現するソフトウェア評価システムの関数定義に於いて、可変長配列のパラメータをログとして取得するためのＩＤＬによる記述を示す図である。
【図２０】本発明の第４の実施形態にかかるログ取得方法を実現するソフトウェア評価システムにおいて、図１９の様に関数が定義されている時のログを取得する場合の流れを示す図である。
【図２１】本発明の第４の実施形態にかかるログ取得方法を実現するソフトウェア評価システムにおいて、図１９の定義を行わない場合に取得されたログデータ（２５０）と、図１９の定義により取得されたログデータ（２５１）の図である。
【図２２】本発明の第５の実施形態にかかるログ取得方法を実現するソフトウェア評価システムで、通常の関数定義では、パラメータを取得できない関数の例を示す図である。
【図２３】図２２に於いて、ＳＴＲＵＣＴＳＩＺＥ１，　ＳＴＲＵＣＴＳＩＺＥ２，　ＳＴＲＵＣＴＳＩＺＥ３の各構造体がどのようにメモリを使用するかを示す図である。
【図２４】本発明の第５の実施形態にかかるログ取得方法を実現するソフトウェア評価システムで、図２２の様な関数のパラメータのログを取得するためのＩＤＬによる記述を示す図である。
【図２５】本発明の第５の実施形態にかかるログ取得方法を実現するソフトウェア評価システムで、図の様に関数が定義されている時のログを取得する場合の流れを示す図である。
【図２６】図２５で行われる構造体パラメータ解析の詳細をメモリ配置をもとに表した図である。
【図２７】本発明の第５の実施形態にかかるログ取得方法を実現するソフトウェア評価システムにおいて、図２４の定義により取得されたログデータの図である。
【図２８】本発明の第６の実施形態にかかるログ取得方法を実現するソフトウェア評価システムで、通常の関数定義では、パラメータを取得できない関数の例を示す図である。
【図２９】図２８に於いて、ＳＴＲＵＣＴＫＩＮＤ１，　ＳＴＲＵＣＴＫＩＮＤ２，　ＳＴＲＵＣＴＫＩＮＤ３の各構造体がどのようなメモリ配置になるかを示した図である。
【図３０】本発明の第６の実施形態にかかるログ取得方法を実現するソフトウェア評価システムで、図２８の様な関数のパラメータのログを取得するためのＩＤＬによる記述を示す図である。
【図３１】本発明の第６の実施形態にかかるログ取得方法を実現するソフトウェア評価システムで、図３０の様に関数が定義されている時のログを取得する場合の流れを示す図である。
【図３２】本発明の第６の実施形態にかかるログ取得方法を実現するソフトウェア評価システムにおいて、図３０の定義により取得されたログデータの図である。
【符号の説明】
１：ＣＰＵ
２：チップセット
３：ＲＡＭ
４：ハードディスクコントローラ
５：ディスプレイコントローラ
６：ハードディスクドライブ
７：ＣＤ−ＲＯＭドライブ
８：ディスプレイ
１１：ＣＰＵとチップセットを繋ぐ信号線
１２：チップセットとＲＡＭを繋ぐ信号線
１３：チップセットと各種周辺機器とを繋ぐ周辺機器バス
１４：ハードディスクコントローラとハードディスクドライブを繋ぐ信号線
１５：ハードディスクコントローラとＣＤ−ＲＯＭドライブを繋ぐ信号線
１６：ディスプレイコントローラとディスプレイを繋ぐ信号線
【図１】
2004038312.tif 000003
【図２】
2004038312.tif 000004
【図３】
2004038312.tif 000005
【図４Ａ】
2004038312.tif 000006
【図４Ｂ】
2004038312.tif 000007
【図５】
2004038312.tif 000008
【図６】
2004038312.tif 000009
【図７】
2004038312.tif 000010
【図８Ａ】
2004038312.tif 000011
【図８Ｂ】
2004038312.tif 000012
【図９】
2004038312.tif 000013
【図１０】
2004038312.tif 000014
【図１１】
2004038312.tif 000015
【図１２】
2004038312.tif 000016
【図１３】
2004038312.tif 000017
【図１４】
2004038312.tif 000018
【図１５】
2004038312.tif 000019
【図１６】
2004038312.tif 000020
【図１７】
2004038312.tif 000021
【図１８】
2004038312.tif 000022
【図１９】
2004038312.tif 000023
【図２０】
2004038312.tif 000024
【図２１】
2004038312.tif 000025
【図２２】
2004038312.tif 000026
【図２３】
2004038312.tif 000027
【図２４】
2004038312.tif 000028
【図２５】
2004038312.tif 000029
【図２６】
2004038312.tif 000030
【図２７】
2004038312.tif 000031
【図２８】
2004038312.tif 000032
【図２９】
2004038312.tif 000033
【図３０】
2004038312.tif 000034
【図３１】
2004038312.tif 000035
【図３２】
2004038312.tif 000036