JP2010049489A - デバッグ支援装置およびデバッグ支援プログラム - Google Patents
デバッグ支援装置およびデバッグ支援プログラム Download PDFInfo
- Publication number
- JP2010049489A JP2010049489A JP2008213156A JP2008213156A JP2010049489A JP 2010049489 A JP2010049489 A JP 2010049489A JP 2008213156 A JP2008213156 A JP 2008213156A JP 2008213156 A JP2008213156 A JP 2008213156A JP 2010049489 A JP2010049489 A JP 2010049489A
- Authority
- JP
- Japan
- Prior art keywords
- function
- log
- program
- called
- input
- Prior art date
- Legal status (The legal status is an assumption and is not a legal conclusion. Google has not performed a legal analysis and makes no representation as to the accuracy of the status listed.)
- Pending
Links
Images
Landscapes
- Debugging And Monitoring (AREA)
Abstract
【課題】対話的なデバッグ環境を提供するとともにコンテキストを限定させた入出力値をユーザに提示する。
【解決手段】本発明のデバッグ支援装置は、関数型言語のプログラムを実行して、関数の呼び出し毎に前記関数の入力値および出力値を取得し、取得した入力値および出力値を、前記関数の親関数と前記関数との親子関係を識別する情報と関連づけてログを取得する手段と、前記プログラム内で定義された関数毎に、定義された関数および前記定義された関数内で呼び出される子関数間のデータの流れを記述したデータフローグラフを生成する手段と、ユーザに対し、連鎖的に呼び出されるn個の関数の指定を第1のコンテキストとして受け付ける手段と、前記データフローグラフと前記ログとをもとに、前記第1のコンテキストに対応するログを特定する手段と、特定されたログを出力する出力手段と、を備える。
【選択図】図4
【解決手段】本発明のデバッグ支援装置は、関数型言語のプログラムを実行して、関数の呼び出し毎に前記関数の入力値および出力値を取得し、取得した入力値および出力値を、前記関数の親関数と前記関数との親子関係を識別する情報と関連づけてログを取得する手段と、前記プログラム内で定義された関数毎に、定義された関数および前記定義された関数内で呼び出される子関数間のデータの流れを記述したデータフローグラフを生成する手段と、ユーザに対し、連鎖的に呼び出されるn個の関数の指定を第1のコンテキストとして受け付ける手段と、前記データフローグラフと前記ログとをもとに、前記第1のコンテキストに対応するログを特定する手段と、特定されたログを出力する出力手段と、を備える。
【選択図】図4
Description
本発明は、プログラムのデバッグ作業を支援するデバッグ支援装置およびデバッグ支援プログラムに関し、たとえばプログラミング言語のうち関数型言語で記述されたプログラムのデバッグに関する。
プログラミング言語は、C言語やJavaTM言語に代表される手続き型言語と、Haskellといった言語に代表される関数型言語に分類できる。
関数型言語には手続き型言語には無い様々な特徴があるが、その中の一つに、一度変数に値が代入されると、その値を二度と変更できない「単一代入」という特徴がある。関数型言語で記述したプログラムは単一代入という特徴により、変数の値が不変であるため、関数に状態が存在しない。そのため、関数型言語で記述したプログラムの関数は、同じ入力を受け取ると必ず同じ出力を返すという特徴がある。
また、LISPやSCHEMEのような非純粋関数型言語でも、プログラム中で変数の再代入を行わなければ、この特徴は成り立つ。
関数型言語のもうひとつの特徴として、複数の関数を組み合わせてプログラムを作成するプログラミングスタイルが挙げられる。そのため、プログラムの不具合を見つけるためのデバッグを行う際は関数単位で動作チェックを行い、動きのおかしな関数を特定して不具合を検出することが多い。
関数型言語のデバッグ方法の一つとして、関数に渡された値(入力値)と関数が返す値(出力値)を取り出し、入力値と出力値の対応関係をチェックして関数の不具合を見つける方法がある。従来は、関数の入力値、出力値の対応関係を見るために、関数型言語の処理系のトレース機能を用いていた。従来のトレース機能は、実行前にトレース対象の関数を指定してからプログラムの実行を開始し、トレース対象の関数が呼ばれたときに、関数の入力値と出力値を表示していた。プログラマは表示された入力値と出力値の対応関係からトレース対象に指定した関数に不具合があるかどうかを判定していた。
ANSI CommonLisp(ポールグレアム著、ピアソン・エデュケーション)
ANSI CommonLisp(ポールグレアム著、ピアソン・エデュケーション)
従来の手法では、プログラムを実行する前にトレース対象の関数を指定する必要があった。これでは、トレース対象の関数を変更して、違う関数の入出力値を確認したい場合、関数の再指定と再実行が必要となる。そのため、対話的に関数の入出力値を調べるデバッグ環境を提供しようとしても、関数を変更する度に、再指定と再実行が必要になるため対話的なデバッグ環境の提供ができなかった。
これに加え従来の手法では、トレース対象の関数が呼ばれたときは常に入出力値を表示してしまうという問題があった。関数型言語のプログラムのデバッグを行う際、検査対象の関数が、別のある特定の関数から呼ばれたときだけ挙動がおかしいという場合がある。この場合、入出力値の表示を、別のある特定の関数から呼ばれたときだけに限定(これをコンテキストの限定と呼ぶ)して入出力値の表示が抑制できると、不具合を示す入出力のペアを見つけやすくなりデバッグ効率を上げることができる。
しかし、従来の手法では、トレース対象の関数が、どのようなコンテキストで呼ばれていても常に入出力値を表示してしまうので、コンテキストを限定させた入出力値の表示の抑制ができなかった。
本発明は、対話的なデバッグ環境を提供するとともにコンテキストを限定させた入出力値をユーザに提示できるようにしたデバッグ支援装置およびデバッグ支援プログラムを提供する。
本発明の一態様としてのデバッグ支援装置は、
関数型言語で記述されたプログラムを、前記プログラムを記憶するプログラム記憶装置から読み込むプログラム読込手段と、
前記プログラムを実行して、前記プログラムに含まれる関数の呼び出し毎に前記関数の入力値および出力値を取得し、取得した入力値および出力値を、前記関数と前記関数を呼び出した親関数との親子関係の識別情報と関連づけるプログラム実行手段と、
互いに関連づけられた、前記入力値および出力値と前記親子関係の識別情報とからなるログを記憶するログ記憶手段と、
前記プログラム内で定義された関数毎に、定義された関数および前記定義された関数内で呼び出される子関数間のデータの流れを記述したデータフローグラフを生成するデータフローグラフ生成手段と、
ユーザから、連鎖的に呼び出されるn(nは3以上の整数)個の関数を指定した第1のコンテキストを受け付ける指定手段と、
前記第1のコンテキストにおける1番目および2番目で呼ばれる関数の親子関係に対応するログを前記ログ記憶手段において特定する特定手段と、
(A)前記第1のコンテキストにおけるm(mは1以上n−2以下の整数)+1番目で呼び出される関数の入力とm+2番目で呼び出される関数の入力とが同一か否かを前記m+1番目で呼び出される関数に対応するデータフローグラフに基づき判断し、
(B)同一のとき、m+1番目およびm+2番目で呼ばれる関数の親子関係に対応するログから、最新の特定されたログであるターゲットログの入力値と同じ入力値をもつログを特定し、
(C−1)同一でないとき前記m+1番目で呼び出される関数に対応するデータフローグラフを辿り、前記m+1番目で呼び出される関数と同じ入力をもつ関数を特定し、
(C−2)前記m+1番目で呼ばれる関数と特定した関数との親子関係に対応するログにおいて、前記ターゲットログと同じ入力値に対応する出力値を取得し、
(C−3)特定した関数の出力が前記m+2番目で呼ばれる関数の入力に一致するまで、前記データフローグラフを辿って前記特定した関数の出力を入力としてもつ関数を特定し前記m+1番目で呼ばれる関数と当該特定した関数との親子関係に対応するログにおいて最新の取得した出力値と同じ入力値に対応する出力値を取得する処理を行い、一致したら前記m+1番目およびm+2番目で呼ばれる関数の親子関係に対応するログから最新の取得した出力値と同じ入力値をもつログを特定する、
ログ処理手段と、
mを1からn−2まで順次インクリメントして前記ログ処理手段による処理を繰り返し行うことを制御する制御手段と、
前記n−2に対応して前記ログ処理手段により特定された最新のログを出力する出力手段と、
を備える。
関数型言語で記述されたプログラムを、前記プログラムを記憶するプログラム記憶装置から読み込むプログラム読込手段と、
前記プログラムを実行して、前記プログラムに含まれる関数の呼び出し毎に前記関数の入力値および出力値を取得し、取得した入力値および出力値を、前記関数と前記関数を呼び出した親関数との親子関係の識別情報と関連づけるプログラム実行手段と、
互いに関連づけられた、前記入力値および出力値と前記親子関係の識別情報とからなるログを記憶するログ記憶手段と、
前記プログラム内で定義された関数毎に、定義された関数および前記定義された関数内で呼び出される子関数間のデータの流れを記述したデータフローグラフを生成するデータフローグラフ生成手段と、
ユーザから、連鎖的に呼び出されるn(nは3以上の整数)個の関数を指定した第1のコンテキストを受け付ける指定手段と、
前記第1のコンテキストにおける1番目および2番目で呼ばれる関数の親子関係に対応するログを前記ログ記憶手段において特定する特定手段と、
(A)前記第1のコンテキストにおけるm(mは1以上n−2以下の整数)+1番目で呼び出される関数の入力とm+2番目で呼び出される関数の入力とが同一か否かを前記m+1番目で呼び出される関数に対応するデータフローグラフに基づき判断し、
(B)同一のとき、m+1番目およびm+2番目で呼ばれる関数の親子関係に対応するログから、最新の特定されたログであるターゲットログの入力値と同じ入力値をもつログを特定し、
(C−1)同一でないとき前記m+1番目で呼び出される関数に対応するデータフローグラフを辿り、前記m+1番目で呼び出される関数と同じ入力をもつ関数を特定し、
(C−2)前記m+1番目で呼ばれる関数と特定した関数との親子関係に対応するログにおいて、前記ターゲットログと同じ入力値に対応する出力値を取得し、
(C−3)特定した関数の出力が前記m+2番目で呼ばれる関数の入力に一致するまで、前記データフローグラフを辿って前記特定した関数の出力を入力としてもつ関数を特定し前記m+1番目で呼ばれる関数と当該特定した関数との親子関係に対応するログにおいて最新の取得した出力値と同じ入力値に対応する出力値を取得する処理を行い、一致したら前記m+1番目およびm+2番目で呼ばれる関数の親子関係に対応するログから最新の取得した出力値と同じ入力値をもつログを特定する、
ログ処理手段と、
mを1からn−2まで順次インクリメントして前記ログ処理手段による処理を繰り返し行うことを制御する制御手段と、
前記n−2に対応して前記ログ処理手段により特定された最新のログを出力する出力手段と、
を備える。
本発明の一態様としてのデバッグ支援プログラムは、
関数型言語で記述されたプログラムを、前記プログラムを記憶するプログラム記憶装置から読み込むプログラム読込ステップと、
前記プログラムを実行して、前記プログラムに含まれる関数の呼び出し毎に前記関数の入力値および出力値を取得し、取得した入力値および出力値を、前記関数と前記関数を呼び出した親関数との親子関係の識別情報と関連づけるプログラム実行ステップと、
互いに関連づけられた、前記入力値および出力値と前記親子関係の識別情報とからなるログをログ記憶手段に記憶するログ記憶ステップと、
前記プログラム内で定義された関数毎に、定義された関数および前記定義された関数内で呼び出される子関数間のデータの流れを記述したデータフローグラフを生成するデータフローグラフ生成ステップと、
ユーザから、連鎖的に呼び出されるn(nは3以上の整数)個の関数を指定した第1のコンテキストを受け付ける指定ステップと、
前記第1のコンテキストにおける1番目および2番目で呼ばれる関数の親子関係に対応するログを前記ログ記憶手段において特定する特定ステップと、
(A)前記第1のコンテキストにおけるm(mは1以上n−2以下の整数)+1番目で呼び出される関数の入力とm+2番目で呼び出される関数の入力とが同一か否かを前記m+1番目で呼び出される関数に対応するデータフローグラフに基づき判断し、
(B)同一のとき、m+1番目およびm+2番目で呼ばれる関数の親子関係に対応するログから、最新の特定されたログであるターゲットログの入力値と同じ入力値をもつログを特定し、
(C−1)同一でないとき前記m+1番目で呼び出される関数に対応するデータフローグラフを辿り、前記m+1番目で呼び出される関数と同じ入力をもつ関数を特定し、
(C−2)前記m+1番目で呼ばれる関数と特定した関数との親子関係に対応するログにおいて、前記ターゲットログと同じ入力値に対応する出力値を取得し、
(C−3)特定した関数の出力が前記m+2番目で呼ばれる関数の入力に一致するまで、前記データフローグラフを辿って前記特定した関数の出力を入力としてもつ関数を特定し前記m+1番目で呼ばれる関数と当該特定した関数との親子関係に対応するログにおいて最新の取得した出力値と同じ入力値に対応する出力値を取得する処理を行い、一致したら前記m+1番目およびm+2番目で呼ばれる関数の親子関係に対応するログから最新の取得した出力値と同じ入力値をもつログを特定する、
ログ処理ステップと、
mを1からn−2まで順次インクリメントして前記ログ処理ステップを繰り返し行うことを制御する制御ステップと、
前記n−2に対応して前記ログ処理ステップにより特定された最新のログを出力する出力ステップと、
をコンピュータに実行させることを特徴とする。
関数型言語で記述されたプログラムを、前記プログラムを記憶するプログラム記憶装置から読み込むプログラム読込ステップと、
前記プログラムを実行して、前記プログラムに含まれる関数の呼び出し毎に前記関数の入力値および出力値を取得し、取得した入力値および出力値を、前記関数と前記関数を呼び出した親関数との親子関係の識別情報と関連づけるプログラム実行ステップと、
互いに関連づけられた、前記入力値および出力値と前記親子関係の識別情報とからなるログをログ記憶手段に記憶するログ記憶ステップと、
前記プログラム内で定義された関数毎に、定義された関数および前記定義された関数内で呼び出される子関数間のデータの流れを記述したデータフローグラフを生成するデータフローグラフ生成ステップと、
ユーザから、連鎖的に呼び出されるn(nは3以上の整数)個の関数を指定した第1のコンテキストを受け付ける指定ステップと、
前記第1のコンテキストにおける1番目および2番目で呼ばれる関数の親子関係に対応するログを前記ログ記憶手段において特定する特定ステップと、
(A)前記第1のコンテキストにおけるm(mは1以上n−2以下の整数)+1番目で呼び出される関数の入力とm+2番目で呼び出される関数の入力とが同一か否かを前記m+1番目で呼び出される関数に対応するデータフローグラフに基づき判断し、
(B)同一のとき、m+1番目およびm+2番目で呼ばれる関数の親子関係に対応するログから、最新の特定されたログであるターゲットログの入力値と同じ入力値をもつログを特定し、
(C−1)同一でないとき前記m+1番目で呼び出される関数に対応するデータフローグラフを辿り、前記m+1番目で呼び出される関数と同じ入力をもつ関数を特定し、
(C−2)前記m+1番目で呼ばれる関数と特定した関数との親子関係に対応するログにおいて、前記ターゲットログと同じ入力値に対応する出力値を取得し、
(C−3)特定した関数の出力が前記m+2番目で呼ばれる関数の入力に一致するまで、前記データフローグラフを辿って前記特定した関数の出力を入力としてもつ関数を特定し前記m+1番目で呼ばれる関数と当該特定した関数との親子関係に対応するログにおいて最新の取得した出力値と同じ入力値に対応する出力値を取得する処理を行い、一致したら前記m+1番目およびm+2番目で呼ばれる関数の親子関係に対応するログから最新の取得した出力値と同じ入力値をもつログを特定する、
ログ処理ステップと、
mを1からn−2まで順次インクリメントして前記ログ処理ステップを繰り返し行うことを制御する制御ステップと、
前記n−2に対応して前記ログ処理ステップにより特定された最新のログを出力する出力ステップと、
をコンピュータに実行させることを特徴とする。
本発明により、対話的なデバッグ環境を提供するとともにコンテキストを限定させた入出力値をユーザに提示できる。
本発明の実施の形態では、まず関数型言語で記述されたプログラムを実行してすべての関数呼び出しに対して、関数の入力値および出力値を取得し、取得した入力値および出力値を、当該関数と当該関数を呼び出した親関数との親子関係の識別情報と関連づけたログを保存しておく。次いで、ユーザによる関数指定、またはコンテキスト指定(連鎖的に呼び出される2つ以上の関数の指定)を受け付け、ユーザの指定に応じたログを、関数型言語の特徴(関数が同じ入力を得た場合、同じ出力を返すという特徴)を利用して、保存したログから特定して表示する。
なお、以下の記述において、サンプルプログラムをSCHEME言語及びSCHEME言語の1つの処理系であるGaucheで記述しているが、これは説明のためである。このサンプルはSCHEMEで記述しているが、プログラム内で再代入をまったく行っていないため、関数型の特徴を満たしている。
以下、図面を参照しながら、本発明の実施の形態について詳しい説明を行う。
図1は、本発明の実施の形態に従ったデバッグ支援装置の構成を示すブロック図である。
図1のデバッグ支援装置は、トレーサ生成部11、プログラム実行部12、ログビューア部13から成る。
トレーサ生成部11は、関数型言語で記述されたプログラムをプログラム記憶装置から読み込んでトレーサを生成し、プログラムにトレーサを付加したトレーサ付きプログラムを生成する。トレーサ生成部11は、関数型言語で記述されたプログラムを、該プログラムを記憶するプログラム記憶装置から読み込むプログラム読込手段を含む。
ここでトレーサとは、関数呼び出しが行われるすべての箇所に対して挿入されるもので、関数に対する入力値と関数からの出力値を取得し、取得した入力値および出力値を、当該関数と当該関数を呼び出した親関数との親子関係の識別情報と関連づけて保存するコードのことである。トレーサのうち、入力値の保存に係わるコードを「入力値保存コード」、出力値の保存に係わるコードを「出力値保存コード」と呼ぶ。
入力値保存コードは、関数への入力値、すなわち、関数呼び出しの際の実引数の値を一時変数に保存し、一時変数の値をログに書き出す。より詳細には、ログの書き出しにおいては、呼び出されている関数の名と、その関数を呼び出している関数(これを親関数と呼ぶ)の関数名とから識別子を求め、その識別子を割り当てたテーブルの入力項目(入力値を格納する項目)に上記入力値(一時変数の値)を追加する。その識別子をもつテーブルがまだ存在しないときは新たに生成する。テーブルは、関数への入力値の個数分の入力項目と、1つの出力項目(出力値を格納する項目)とを有する。
ここでテーブルの識別子の求め方についてその一例を説明する。
テーブルの識別子は、呼び出されている関数の名と、その関数を呼び出している関数(親関数)とを予約語を挟んで結合することで求める。
たとえば、g関数定義の中でadd関数を呼び出している場合、"add in g"という文字列の識別子が求められる。
もし、ある関数定義の中で同じ関数を複数回呼び出している場合は、各呼び出されている関数名にソースコード上での位置や呼び出し順番などを付加することで、識別子の一意性を失わないようにする。たとえば、g関数の中でadd関数を2回呼び出している場合は、プログラム中で先に現れる方を"add1 in g"、後に現れるほうを"add2 in g"とすることで識別子の一意性を保つ。
出力値保存コードは、関数からの出力値、すなわち、関数からの返り値を一時変数に保存し、一時変数の値をログに書き出す。より詳細に、ログへの書き出しにおいては、入力値保存コードと同様にして、テーブルの識別子を求め、その識別子を持つテーブルの出力項目に書き込む。書き出す際は、入力項目が埋まっており、出力項目が空いているところに書き出す。もし、複数の行にわたって出力項目が空いている場合は、最後に入力値が書き込まれた行に対応する出力項目に書き出しを行う(このようなケースは再帰的に関数が呼び出されている場合に起こる)。
ここで入力値保存コードがログを保存するとき、同じ入力値の行が既に存在する場合は、保存を省略しても良い。そうした場合は、ログの量を圧縮することができる。ただし、ログを保存する際に同じ入力値があるかどうかのチェックが入るために、ログ保存時の計算コストが高くなる。これとは別の方法として、プログラムの実行が終了したあと、すべてのログを走査し、同じ入力値を持つ重複する行を削除することでログの量を圧縮しても良い。
図2は、トレーサ生成部11による処理の手順を示すフローチャートである。
1) プログラムを読み込み、関数呼び出しを行っている箇所を記憶する(S101)。
2) 呼び出されている関数への入力値を取り出すコードと、呼び出されている関数名と親関数名から識別子を生成しその識別子をもつテーブル(ログ)を検索するコードと、取り出した入力値をテーブルに保存するコードとを併せ持った「入力値保存コード」を生成する(S102)。
3) 呼び出されている関数からの出力値を取り出すコードと、呼び出されている関数名と親関数名から識別子を生成しその識別子をもつテーブル(ログ)を検索するコードと、取り出した出力値をテーブルに保存するコードとを併せ持った「出力値保存コード」を生成する(S103)。
4) 入力値保存コードを関数呼び出し直前に実行されるように、また、出力値保存コードを関数呼び出し直後に実行されるように、プログラムに挿入する(S104)。
以上のようにして、関数呼び出しを行っているすべての箇所について入力値保存コードおよび出力値保存コードを生成し挿入することで、トレーサ付きプログラムが生成される。
SCHEME言語で記述されたプログラム内で定義された下記の関数
(define (g x y)
(h (add x y)
(sub x y)))
に対して入力値保存コードおよび出力値保存コードを挿入する例を説明する。
(define (g x y)
(h (add x y)
(sub x y)))
に対して入力値保存コードおよび出力値保存コードを挿入する例を説明する。
このプログラムでは、入力がx, yであるようなg関数が定義されている。g関数の中では、h関数が呼び出され、h関数への入力は、add関数の返り値“(add x y)”と、sub関数の返り値“(sub x y)”である。さらにadd関数への入力はxとyであり、sub関数への入力はxとyである。以上のことから、g関数は入力としてx,yを受取り、それがadd関数、sub関数の入力になる。そして、add関数、sub関数の出力が、次に、h関数の入力になる。最後に、h関数の出力がg関数の出力になる。
上記の関数への入力値保存コードおよび出力値保存コードの挿入後のコードは、それぞれ内部で呼び出している関数の入力値、出力値を一時変数で保持しておき、それをログに書き込み、最後に、g関数の返り値として、h関数の返り値を返す。以下は挿入後のコードの一例である。なお、このコードはSCHEME言語の処理系の1つであるGaucheでの実行を想定している。
(define (g x y)
(let* ((add-in1 x) ; add関数へ入力を保持
(add-in2 y) ; add関数へ入力を保持
(add-out (add add-in1 add-in2)) ;add関数の出力を保持
(sub-in1 x) ; sub関数の入力を保持
(sub-in2 y) ; sub関数の入力を保持
(sub-out (sub sub-in1 sub-in2)) ; sub関数の出力を保持
(h-in1 add-out) ; h関数の入力を保持
(h-in2 sub-out) ; h関数の入力を保持
(h-out (h h-in1 h-in2))) ; h関数の出力を保持
(log-open "./add_in_g.log") ; add関数のログをオープン
(log-format "add-in1: ~s" add-in1) ; add関数の入力をログに書き込む
(log-format "add-in2: ~s" add-in2) ; add関数の入力をログに書き込む
(log-format "add-out: ~s" add-out) ; add関数の出力をログに書き込む
(log-open "./sub_in_g.log") ; sub関数のログをオープン
(log-format "sub-in1: ~s" sub-in1) ; sub関数の入力をログに書き込む
(log-format "sub-in2: ~s" sub-in2) ; sub関数の入力をログに書き込む
(log-format "sub-out: ~s" sub-out) ; sub関数の出力をログに書き込む
(log-open "./h_in_g.log") ; h関数のログをオープン
(log-format "h-in1: ~s" h-in1) ; h関数の入力をログに書き込む
(log-format "h-in2: ~s" h-in2) ; h関数の入力をログに書き込む
(log-format "h-out: ~s" h-out) ; h関数の出力をログに書き込む
h-out)) ; 最後にh関数を出力をg関数の出力として返す
(define (g x y)
(let* ((add-in1 x) ; add関数へ入力を保持
(add-in2 y) ; add関数へ入力を保持
(add-out (add add-in1 add-in2)) ;add関数の出力を保持
(sub-in1 x) ; sub関数の入力を保持
(sub-in2 y) ; sub関数の入力を保持
(sub-out (sub sub-in1 sub-in2)) ; sub関数の出力を保持
(h-in1 add-out) ; h関数の入力を保持
(h-in2 sub-out) ; h関数の入力を保持
(h-out (h h-in1 h-in2))) ; h関数の出力を保持
(log-open "./add_in_g.log") ; add関数のログをオープン
(log-format "add-in1: ~s" add-in1) ; add関数の入力をログに書き込む
(log-format "add-in2: ~s" add-in2) ; add関数の入力をログに書き込む
(log-format "add-out: ~s" add-out) ; add関数の出力をログに書き込む
(log-open "./sub_in_g.log") ; sub関数のログをオープン
(log-format "sub-in1: ~s" sub-in1) ; sub関数の入力をログに書き込む
(log-format "sub-in2: ~s" sub-in2) ; sub関数の入力をログに書き込む
(log-format "sub-out: ~s" sub-out) ; sub関数の出力をログに書き込む
(log-open "./h_in_g.log") ; h関数のログをオープン
(log-format "h-in1: ~s" h-in1) ; h関数の入力をログに書き込む
(log-format "h-in2: ~s" h-in2) ; h関数の入力をログに書き込む
(log-format "h-out: ~s" h-out) ; h関数の出力をログに書き込む
h-out)) ; 最後にh関数を出力をg関数の出力として返す
プログラム実行部12は、トレーサ生成部11により生成されたトレーサ付きプログラムを実行して、ログを出力する。より詳細に、プログラム実行部12は、トレーサ付きプログラムを実行して、関数の呼び出し毎に該関数の入力値および出力値を取得し、取得した入力値および出力値を、該関数の親関数と該関数との親子関係の識別情報と関連づけ、互いに関連づけられた、入力値および出力値と親子関係の識別情報とからなるログを取得する。取得されたログは、ログを記憶するログ記憶手段(図示せず)に記憶される。
次に、ログビューア部13について説明する。
ログビューア部13はユーザから対話的な指示を受け取り、ユーザの指示に応じてログ解析を行い、ユーザの所望するログを取り出して表示する。
図3は、ログビューア部13の詳細構成を示すブロック図である。
ログビューア部13は、データフローグラフ生成部21、関数・コンテキスト指定入力部(指定手段)22、ログ解析部(特定手段、ログ処理手段、制御手段)23、ログ表示部(出力手段)24から成る。
データフローグラフ生成部21は、トレーサ生成部11に与えられたのと同じプログラムを受け取り、プログラム内で定義された各関数のそれぞれについて、データフローグラフを生成する。データフローグラフとは、関数の出力値が別のどの関数の入力値になるかといった関数間の入出力の関係(すなわち定義された関数および該定義された関数内で呼び出される子関数間のデータの流れ)をグラフにより表現したものである。データグラフの一例を図5に示す。
このデータフローグラフは、SCHEME言語で記述されたプログラム内で定義された下記の関数
(define (g x y)
(h (add x y)
(sub x y)))
についてのデータフローグラフである。この関数についての詳細はすでに述べた通りである説明を省略する。このように関数型言語のプログラムでは、入出力に着目することでひとつの関数定義をひとつのデータフローグラフとして表現できる。
(define (g x y)
(h (add x y)
(sub x y)))
についてのデータフローグラフである。この関数についての詳細はすでに述べた通りである説明を省略する。このように関数型言語のプログラムでは、入出力に着目することでひとつの関数定義をひとつのデータフローグラフとして表現できる。
ここでプログラムからデータフローグラフを生成する方法について説明する。
なお、変数が単一代入の場合(一度変数に値が代入されると、その値を二度と変更できない場合)の、データフローグラフの生成手法は、「参考文献:コンパイラの構成と最適化、中田育男著、朝倉出版」に、詳しい説明があるため、ここでは簡単に説明するにとどめる。
(1)最初に関数定義毎にプログラムを分割する。
(2)次に、関数定義から仮引数(上記のg関数の例ではx,y)を取り出し、それを元にデータフローグラフ中の入力値ノードと、一つの出力値ノードを生成する。
(3)次に、関数定義の中で行っている関数呼び出しに対して、呼び出されている関数に対する入力値を示すノード、関数呼び出しを示すノード(上記のg関数の例では“add”、“sub”のノード)、関数からの出力値を示すノード(上記のg関数の例では“出力”のノード)を生成する。
(1)最初に関数定義毎にプログラムを分割する。
(2)次に、関数定義から仮引数(上記のg関数の例ではx,y)を取り出し、それを元にデータフローグラフ中の入力値ノードと、一つの出力値ノードを生成する。
(3)次に、関数定義の中で行っている関数呼び出しに対して、呼び出されている関数に対する入力値を示すノード、関数呼び出しを示すノード(上記のg関数の例では“add”、“sub”のノード)、関数からの出力値を示すノード(上記のg関数の例では“出力”のノード)を生成する。
(3)においては、入力値が定義関数の仮引数と等しい場合は、呼び出されている関数に対する入力値ノードを、定義関数に対する入力値ノードに一致させる。また、入力値が別の関数の出力値と等しい場合は、入力値を示すノードを、当該別の関数の関数呼び出しノードに一致させる。呼び出された関数の出力値が定義関数の出力である場合は、呼び出されている関数の出力値を示すノードを、定義関数の出力値ノードに一致させる。
以上の処理(1)〜(3)を定義関数内のすべての関数呼び出しに対して行うことで、データフローグラフが生成できる。
以上のような処理手順を行うことで、プログラム内で定義された各関数についてデータフローグラフを生成する。
関数・コンテキスト指定入力部22は、ユーザと対話的なやりとりをすることで、ユーザの指示を、受け取る。ユーザの指示は次の3種類に分類できる。
1) 関数指定(すなわち単一の関数の指定)
2) 1階層コンテキスト限定を行った関数指定(すなわち連鎖的に呼び出される2つの関数の連鎖の指定)
3) 2階層以上のコンテキスト限定を行った関数指定(すなわち連鎖的に呼び出される3つ以上の関数の連鎖の指定)
1) 関数指定(すなわち単一の関数の指定)
2) 1階層コンテキスト限定を行った関数指定(すなわち連鎖的に呼び出される2つの関数の連鎖の指定)
3) 2階層以上のコンテキスト限定を行った関数指定(すなわち連鎖的に呼び出される3つ以上の関数の連鎖の指定)
関数・コンテキスト指定入力部22は、1), 2), 3)のいずれかの指定をユーザができるように、画面にプログラムのソースコードを表示し、指定を促す。
1)の関数指定は、ユーザが関数定義を行っている箇所を指定する方法である(これはたとえば本発明における単一の関数の指定を受け付けることに相当する)。ユーザが関数定義を行っている箇所を指定した場合は、関数・コンテキスト指定入力部22はユーザが関数指定を指定したものと認識し、関数の指定情報を、ログ解析部23に入力する(図7(A)参照)。
関数定義を行っている箇所の指定とは、たとえば、SCHEME言語の場合は、関数定義を行っているdefineという文字列や、defineの後ろに並ぶ関数名と引数名のリストを示す文字列や、関数定義全体、すなわち、defineで始まる括弧内全体を選択した場合などである。
2)の1階層のコンテキスト限定は、関数内で関数呼び出しを行っている箇所を指定する方法である(これはたとえば本発明において、連鎖的に呼び出される2個の関数を指定した第2のコンテキストを受け付けることに相当する)。例えば、上記したg関数の中でadd関数を指定したい場合は、g関数内でadd関数呼び出しを行っている箇所を指定すればよい。
g関数内でadd関数を呼び出している箇所の指定とは、たとえば、add関数呼び出しを示すadd文字列を選択した場合などである。こうして得られたコンテキストの限定を表すコンテキスト指定情報をスタックデータとしてログ解析部23に入力する(図7(B)参照)。
3)の2階層以上のコンテキスト限定とは、関数呼び出しを行っている箇所を指定し、更にその関数の呼び出しを持つ関数(親関数)を呼び出している更に上の親関数を指定するというように、関数の呼び出しパターンを2階層以上で指定する方法である(これはたとえば本発明において、連鎖的に呼び出されるn(nは3以上の整数)個の関数を指定した第1のコンテキストを受け付けることに相当する)。
2階層以上のコンテキストを指定するためには、まず、1階層のコンテキスト限定と同じ方法で関数呼び出しを指定する。次に、親関数を呼び出している関数をプログラム全体を検索して検出し、検出した関数を含む一覧を生成し、一覧をユーザに提示する。ユーザはその一覧から一つ関数を指定する。更に上位の親関数の指定(すなわち3階層以上のコンテキストの指定)を行う場合は、同様に呼び出している関数一覧の提示とユーザ選択とを繰り返す。こうして得られたコンテキストの限定をスタックデータとしてコンテキスト指定情報とする(図7(C)参照。図7(C)ではk関数、i関数、g関数経由で、h関数が呼ばれており、kはトップの関数呼び出し、iは2段目の関数呼び出し、gは3段目の関数呼び出し、hは4段目の関数呼び出しに相当する)。
次にログ解析部23を説明する。
図4は、ログ解析部23の処理の手順を示すフローチャートである。
1) ログ解析部23は、関数・コンテキスト指定入力部22から関数またはコンテキストの指定情報を受け取る(S201)。
受け取った指定情報が、関数指定の場合とコンテキスト指定の場合とで処理内容が異なる。関数指定とコンテキスト指定との識別は、関数・コンテキスト指定情報で指定された関数の個数(スタックデータの段数)からわかる。1段であるときは、関数指定である(図7(A)参照)。2段以上である場合は、コンテキスト指定である(図7(B)および図7(C)参照)。
1-1) 関数の指定情報を受けた場合は、指定された関数のログ(テーブル)をすべて取得する。上述したように、ログ(テーブル)の識別子は、呼び出されている関数の名と親関数名から生成される。したがって、識別子が、呼び出されている関数の名を含んでいるすべてのログ(テーブル)を検索することで、指定された関数に関するすべてのログ(テーブル)を取得できる。
1-2) 各識別子に応じて取得されたログ(テーブル)をすべて結合し、ターゲットログとする(S203)。結合する際に、同じ入力値であるような行は一つにまとめれば、冗長な行が削除されるため、より見やすいログとなる。ただし、この場合、処理の負荷が大きくなる。
1-3) ターゲットログを表示する(S204)。
2-1)コンテキストの指定情報を受けた場合、コンテキスト指定情報のトップ(たとえば図7(C)のk)と2段目(たとえば図7(C)のi)の関数呼び出しを取り出し、取り出した関数呼び出しの呼び出し関係に対応するログ(たとえばi in k)を特定する(S205)。最新の特定されたログは「ターゲットログ」と称され、ここではS205で特定されたログが最新であるため、このログがターゲットログに相当する。S205の処理は、たとえば本発明の特定手段の処理に相当する。また、ここでの2段目の関数呼び出し(たとえば図7(C)のi)を説明の便宜上、「前関数呼び出し」と称する。
2-2) コンテキスト指定情報の中に関数呼び出しが残っているかをチェックする(S206)。残っていない場合は(たとえばコンテキスト指定情報が図7(B)の1階層コンテキストのときはこれに該当)、ターゲットログを表示する(S204)。残っている場合(たとえばコンテキスト指定情報が図7(C)の3階層コンテキストのときはこれに該当))は2-3)へ進む。S206の処理は、たとえば本発明の制御手段の処理に相当する。
2-3) コンテキスト指定情報からトップの関数呼び出しを取り出し(たとえば図7(C)のg)、前関数呼び出し(たとえば図7(C)のi)と取り出したトップの関数呼び出しの呼び出し関係に対応するログを取得する(S207)。本ステップS207で取得された最新のログは「フィルタ対象ログ」と称する(S207)。そして、取り出したトップの関数呼び出し(たとえば図7(C)のg)を新たに「前関数呼び出し」と称する(S207)。
2-4) ターゲットログの入力値(たとえばi in kの入力値)を取り出す(S208)。本ステップS208で取り出された入力値および後述するステップS210で取り出された出力値のうち最新の取り出された値はターゲット入力値と称される(S208)。現時点ではS208で取り出された入力値がターゲット入力値に相当する。
2-5) 現在のターゲット入力値が、前関数呼び出し(たとえば図7(C)のg)に対応する関数の入力値かどうかを調べる(S209)。これはたとえばログ処理手段における(A)の処理に相当する。まず、現在のターゲット入力値を表すノードをデータフローグラフから検索する。次に、前関数呼び出しに対応する関数の入力値を表すノードをデータフローグラフから検索する。
これらのノードが同じ値を示している場合は、ターゲット入力値が前関数呼び出しに対応する関数の入力値に一致する。同じ値を示していなければ、ターゲット入力値と、前関数呼び出しに対応する関数の入力値とは異なる。同じ場合は、2-7)へ、違う場合は、2-6)へ進む。
たとえば図6(E)のi関数のデータフローグラフにおいて、現在のターゲット入力値に対応するノードはx,yで、前関数呼び出し(たとえばg)に対応する入力値に対応するノードもx,yであり、したがって、これらのノードが共にx,yで同じである。したがって、この場合、2-7)へ進む。
仮に、図6(C)のg関数のデータフローグラフにおいて、現在のターゲット入力値を表すノードがx,y、前関数呼び出しがhであるとしたときは、hの入力値を表すノードはaddとsubであるため、これらのノードは互いに異なることとなる。したがってこの場合は2-6)へ進むこととなる。
2-6) ターゲット入力値を入力している関数(たとえば図6(C)のadd,sub)の呼び出しのログ(たとえばadd in g, sub in g)を検索する(S210)。検索して得られたログの中で、ターゲット入力値と同じ入力値をもつ行の出力値を取り出す。この取り出した出力値は、新たにターゲット入力値に相当する。この後、2-5)へ進む(S209へ進む)。
2-7) フィルタ対象ログのうち、ターゲット入力値と同じ入力値をもつ行だけを残すようにフィルタリングを行う(S211)。すなわちフィルタ対象ログのうち、ターゲット入力値と同じ入力値をもつ行を含むログを特定する。この特定されたログは新たにターゲットログに相当する。この後、2-2)へ進む(S206へ進む)。
なお、ユーザが指定できる関数・コンテキスト指定情報を関数指定と1階層のコンテキスト指定だけに限定する場合、ログビューア部13の中のデータフローグラフ生成部21は無くてもよい。この場合、図4のフローチャートにおいて、ステップS206の「関数呼び出しの指定が残っているか」の選択項目で必ずNOが選択されることとなる。
以上に示した図4の処理において、S207→S208→S209のYES→S211の流れの処理(S209において一度もNOとならないケース)は、たとえば本発明におけるログ処理手段の(B)の処理に相当する。
また、S207→S208→S209のNO→S210・・・S209のYES→S211の流れの処理(S209において1回以上、NOとなるケース)は、たとえば本発明におけるログ処理手段の(C−1)〜(C−3)の処理に相当する。特に、S209のNO→S210の繰り返しは(C−3)の処理に相当する。
以下、具体例に沿って図1のデバッグ支援装置の各部の動きについて説明する。
下記の[サンプルプログラム]はSCHEME言語で記述したプログラムの一例であるである。以下では、このサンプルプログラムを入力したときに、デバッグ支援装置がどのように動作するかを具体的に説明する。
----------------------------------
[サンプルプログラム]
01: (define (main args)
02: (k 1 2)
03: (l 3 4)
04: (h 5 6)
05: (j 7 8))
06:
07: (define (add x y)
08: (+ x y))
09:
10: (define (sub x y)
11: (- x y))
12:
13: (define (g x y)
14: (h (add x y)
15: (sub x y)))
16:
17: (define (h x y)
18: (* (* x y)
19: (add x y)))
20:
21: (define (i x y)
22: (g x y))
23:
24: (define (j x y)
25: (g x y))
26:
27: (define (k x y)
28: (i (add x 1)
29: y))
30:
31: (define (l x y)
32: (i x y))
----------------------------------
----------------------------------
[サンプルプログラム]
01: (define (main args)
02: (k 1 2)
03: (l 3 4)
04: (h 5 6)
05: (j 7 8))
06:
07: (define (add x y)
08: (+ x y))
09:
10: (define (sub x y)
11: (- x y))
12:
13: (define (g x y)
14: (h (add x y)
15: (sub x y)))
16:
17: (define (h x y)
18: (* (* x y)
19: (add x y)))
20:
21: (define (i x y)
22: (g x y))
23:
24: (define (j x y)
25: (g x y))
26:
27: (define (k x y)
28: (i (add x 1)
29: y))
30:
31: (define (l x y)
32: (i x y))
----------------------------------
[サンプルプログラム]は上から順にmain関数、add関数、sub関数、g関数、h関数、i関数、j関数、k関数、l関数が宣言されており、それぞれの関数内で様々な関数呼び出しが行われている。
トレーサ生成部11は、[サンプルプログラム]を入力として受け取ってトレーサ(入力値保存コードと出力値保存コード)を生成し、生成したトレーサをプログラムに付与する。
トレーサは、以下の関数呼び出しに対して生成され、関数呼び出しの直前に入力値保存コードを、直後に出力値保存コードが実行されるようにプログラム中に挿入される。
main関数の中では、
k関数呼び出し
l関数呼び出し
h関数呼び出し
j関数呼び出し
に対して作成される。
add関数の中では、
+関数呼び出し
に対して作成される。
sub関数の中では、
-関数呼び出し
に対して作成される。
g関数の中では、
h関数呼び出し
add関数呼び出し
sub関数呼び出し
に対して作成される。
h関数の中では、
一つ目の*関数呼び出し
二つ目の*関数呼び出し
add関数呼び出し
に対して作成される。なお*は乗算を表す。
i関数の中では
g関数呼び出し
に対して作成される。
j関数の中では
g関数呼び出し
に対して作成される。
k関数の中では
i関数呼び出し
add関数呼び出し
に対して作成される。
l関数の中では
i関数呼び出し
に対して作成される。
main関数の中では、
k関数呼び出し
l関数呼び出し
h関数呼び出し
j関数呼び出し
に対して作成される。
add関数の中では、
+関数呼び出し
に対して作成される。
sub関数の中では、
-関数呼び出し
に対して作成される。
g関数の中では、
h関数呼び出し
add関数呼び出し
sub関数呼び出し
に対して作成される。
h関数の中では、
一つ目の*関数呼び出し
二つ目の*関数呼び出し
add関数呼び出し
に対して作成される。なお*は乗算を表す。
i関数の中では
g関数呼び出し
に対して作成される。
j関数の中では
g関数呼び出し
に対して作成される。
k関数の中では
i関数呼び出し
add関数呼び出し
に対して作成される。
l関数の中では
i関数呼び出し
に対して作成される。
こうして生成されたトレーサ付きプログラムは、プログラム実行部12により実行されることで、以下のログが生成される。
[カッコ]内で記述しているのが、ログ(テーブル)の識別子であり、入力項目には、関数に対する入力値が、出力項目には、出力値がそれぞれ書き込まれる。ただし、記述を簡略化するために、組み込み関数の呼び出し、すなわち+関数呼び出し、-関数呼び出し、*関数の呼び出しについてはログの表示を省略している(本来は、組み込み関数呼び出しに対する入出力値も保存される)。
次に、[サンプルプログラム]をログビューア部13が読み込んだときの動きについて説明する。
データフローグラフ生成部21は、[サンプルプログラム]を入力して、図6(A)〜図6(H)に示すようなデータフローグラフを生成する。
関数・コンテキスト指定入力部22は、[サンプルプログラム]を読み込むと、これを表示して、関数またはコンテキストの指定をユーザに促す。以下、(1)関数指定を行う場合、(2)1階層のコンテキスト指定を行う場合、(3)2階層以上のコンテキスト指定を行う場合に分けて、詳細を説明する。
(1)関数指定を行う場合は、関数定義を識別する方法でユーザは指定を行う。
例えば、add関数を指定する場合は、addを定義している7行目のdefineの文字列を選択する。もしくは、addを定義しているdefineをくくっている括弧全体、すなわち、7~8行目を選択する。これを受け関数・コンテキスト指定入力部22は、図7(A)に示すような、内部に関数名を保持する、関数の指定情報を生成する。
(2)1階層のコンテキスト指定を行う場合は、関数の呼び出し箇所を選択する。
例えば、g関数経由で呼ばれているaddを選択するには、14行目のadd文字列を選択する。これを受け、関数・コンテキスト指定入力部22は、図7(B)に示すようにg、addとがスタック状に並んだ、1階層のコンテキストの指定情報を生成する。
(3)2階層以上のコンテキスト指定を行う場合は、関数の呼び出し箇所を選択したのちに、その関数の親関数の呼び出しを行っている関数の指定をユーザが行う。
例えば、ユーザがk関数、i関数、g関数経由で呼ばれたh関数のログを見たいとする。その場合は、ユーザは、まず、13行目のg関数内のh関数呼び出しを指定する。次に、ユーザは、更に上位の親関数の呼び出しの指定を行うことを指示する。関数・コンテキスト指定入力部22は、この指示を受け、g関数呼び出しを内部に持つ関数の一覧を検索する。g関数呼び出しは、22行目、25行目で行われている。したがって、g関数呼び出しを内部に持つ関数は、
i関数
j関数
である。
i関数
j関数
である。
そのため、関数・コンテキスト指定入力部22はi関数とj関数を提示し、ユーザに選択を促す。ユーザはここで、i関数を指定し、更に上位の親関数の呼び出しの指定を指示する。これを受け、関数・コンテキスト指定入力部22は、i関数の呼び出しを行っている関数を検索する。
i関数の呼び出しを行っているのは、28行目、32行目である。したがって、i関数の呼び出しを行っているのは
k関数、
l関数
である。
k関数、
l関数
である。
関数・コンテキスト指定入力部22は、k関数とl関数とを提示し、ユーザに選択を促す。ユーザは、ここでk関数を指定し、コンテキスト指定の終了を指示する。
以上の処理から、関数・コンテキスト指定入力部22は、図7(C)に示すようにk、i、g、hがスタック状に並んだ、2階層以上のコンテキストの指定情報を生成する。
次にログ解析部23の動きの具体例について説明する。
ログ解析部23はデータフローグラフと、ログと、関数またはコンテキストの指定情報とを読み込んで処理を行う。以下、ログ解析部23の処理の具体例を、
(1)add関数が指定された場合
(2)g関数経由でのadd関数の呼び出しが指定された場合
(3)k関数、i関数、g関数経由でのh関数の呼び出しが指定された場合
に分けて説明する。
(1)add関数が指定された場合
(2)g関数経由でのadd関数の呼び出しが指定された場合
(3)k関数、i関数、g関数経由でのh関数の呼び出しが指定された場合
に分けて説明する。
(1)最初に、関数・コンテキスト指定情報がadd関数を指定した場合について説明する。
ログ解析部23は、add関数を呼び出しているログ(テーブル)をすべて取得する。
ログには、関数名がわかるような識別子が付加されているため、簡単に取得できる。
先に示した[ログの例]の中からaddを呼び出しているログは、
- [add in g]
- [add in h]
- [add in k]
の三つである。
- [add in g]
- [add in h]
- [add in k]
の三つである。
(2)次に1階層のコンテキストを指定する例として、g関数経由でadd関数が呼び出された場合(コンテキスト指定情報がadd,gのスタックデータの場合)について説明する。
g関数経由でadd関数が呼び出された場合は、トップの関数呼び出しがg関数で、二段目がadd関数であることから、g関数内のadd関数呼び出しのログである [add in g]ログを取り出し、以下のようなターゲットログを表示して終了する。
(3)次に2階層以上のコンテキストを指定する例として、k関数、i関数、g関数経由でh関数が呼び出された場合(コンテキスト指定情報がh,g,i,kのスタックデータの場合)について説明する。
コンテキスト指定情報のトップと2段目の関数呼び出しからk関数内のi関数呼び出しに対応するログ [i in k]を特定する。この特定されたログはターゲットログに相当し、i関数は前関数呼び出しに相当する。
コンテキスト指定情報には、g, h が残っているため、トップのg関数を取り出す。
ターゲット入力値が前関数呼び出し、すなわちg関数の入力になっているかをチェックする。ターゲット入力値はk関数内でのi関数呼び出しの入力値である。i関数のデータフローグラフ(図6(E)参照)から、i関数の入力値はg関数の入力値であることがわかる。そのため、ターゲット入力値が、次の前関数呼び出しの入力値であることがわかる。
次に、ターゲット入力値でフィルタ対象ログをフィルタリングする。
次に、コンテキスト指定情報にh関数が残っているため、h関数を取り出し、前関数呼び出しであるg関数と、取り出したh関数から、[h in g]関数呼び出しのログを取り出す。このログは、新たにフィルタリング対象ログに相当し、h関数は新たに前関数呼び出しに相当する。
ターゲット入力値が、前関数呼び出しであるh関数の入力値であるかをチェックする。
ターゲット入力値は、g関数の入力値であるため、図6(C)に示すg関数のデータフローグラフを参照する。
g関数のデータフローグラフから、ターゲット入力値であるg関数の入力値は、h関数の入力値でないことがわかる。g関数のデータフローグラフから、h関数の入力値を求めるには、add関数の出力値とsub関数の出力値を求めればよいことがわかる。
このログとターゲット入力値からadd関数呼び出しの出力値が4であることがわかる。
求めたターゲット入力値はadd関数呼び出しの出力とsub関数の出力であるため、g関数のデータフローグラフから、前関数呼び出しであるh関数の入力値であることがわかる。
そのため、ターゲット入力値でフィルタリング対象のログをフィルタリングする。すなわち、フィルタリング対象ログから、ターゲット入力値と同じ入力値を持つ行のみを特定する。
コンテキスト指定情報には、関数呼び出しの指定が残っていないため、このターゲットログを表示して処理は終了する。
このようにコンテキストを限定することにより、従来では、h関数呼び出しのログ
が表示されていたが、本実施の形態では、k関数, i関数、g関数、h関数とコンテキストの限定ができることで、コンテキストを限定したログ
を表示できる。これにより、表示量が抑制されるとともに、不具合を含む、入力および出力間の対応関係が見つけやすくなり、結果としてデバッグ効率を上げることができる。
以上のように、本実施の形態によれば、事前にすべてのログを保存しておくため、トレース関数の再指定とプログラムの再実行が不要になり、対話的なデバッグ環境が提供できる。
また、実行時の関数の入出力値の表示を行う際に、関数呼び出しのコンテキストを限定した表示が可能になる。そのため、不具合が、あるコンテキストに限定されて生じる場合、不具合を示す入出力のペアを効率的に見つけることが可能になる。
11:トレーサ生成部
12:プログラム実行部
13:ログビューア
21:データフローグラフ生成部
22:関数・コンテキスト指定入力部(指定手段)
23:ログ解析部(特定手段、ログ処理手段、制御手段)
24:ログ表示部(出力手段)
12:プログラム実行部
13:ログビューア
21:データフローグラフ生成部
22:関数・コンテキスト指定入力部(指定手段)
23:ログ解析部(特定手段、ログ処理手段、制御手段)
24:ログ表示部(出力手段)
Claims (8)
- 関数型言語で記述されたプログラムを、前記プログラムを記憶するプログラム記憶装置から読み込むプログラム読込手段と、
前記プログラムを実行して前記プログラムに含まれる関数の呼び出し毎に前記関数の入力値および出力値を取得し、取得した入力値および出力値を、前記関数と前記関数を呼び出した親関数との親子関係の識別情報と関連づけるプログラム実行手段と、
互いに関連づけられた、前記入力値および出力値と前記親子関係の識別情報とからなるログを記憶するログ記憶手段と、
前記プログラム内で定義された関数毎に、定義された関数および前記定義された関数内で呼び出される子関数間のデータの流れを記述したデータフローグラフを生成するデータフローグラフ生成手段と、
ユーザから、連鎖的に呼び出されるn(nは3以上の整数)個の関数を指定した第1のコンテキストを受け付ける指定手段と、
前記第1のコンテキストにおける1番目および2番目で呼ばれる関数の親子関係に対応するログを前記ログ記憶手段において特定する特定手段と、
(A)前記第1のコンテキストにおけるm(mは1以上n−2以下の整数)+1番目で呼び出される関数の入力とm+2番目で呼び出される関数の入力とが同一か否かを前記m+1番目で呼び出される関数に対応するデータフローグラフに基づき判断し、
(B)同一のとき、m+1番目およびm+2番目で呼ばれる関数の親子関係に対応するログから、最新の特定されたログであるターゲットログの入力値と同じ入力値をもつログを特定し、
(C−1)同一でないとき前記m+1番目で呼び出される関数に対応するデータフローグラフを辿り、前記m+1番目で呼び出される関数と同じ入力をもつ関数を特定し、
(C−2)前記m+1番目で呼ばれる関数と特定した関数との親子関係に対応するログにおいて、前記ターゲットログと同じ入力値に対応する出力値を取得し、
(C−3)特定した関数の出力が前記m+2番目で呼ばれる関数の入力に一致するまで、前記データフローグラフを辿って前記特定した関数の出力を入力としてもつ関数を特定し前記m+1番目で呼ばれる関数と当該特定した関数との親子関係に対応するログにおいて最新の取得した出力値と同じ入力値に対応する出力値を取得する処理を行い、一致したら前記m+1番目およびm+2番目で呼ばれる関数の親子関係に対応するログから最新の取得した出力値と同じ入力値をもつログを特定する、
ログ処理手段と、
mを1からn−2まで順次インクリメントして前記ログ処理手段による処理を繰り返し行うことを制御する制御手段と、
前記n−2に対応して前記ログ処理手段により特定された最新のログを出力する出力手段と、
を備えたデバッグ支援装置。 - 前記指定手段は、前記ユーザから、連鎖的に呼び出される2個の関数を指定した第2のコンテキストを受け付け、
前記ログ処理手段は、前記指定手段で前記第2のコンテキストを受け付けたとき、前記第2のコンテキストで指定される2個の関数の親子関係に対応するログを前記ログ記憶手段から検出し、
前記出力手段は、検出されたログを出力する
ことを特徴とする請求項1に記載のデバッグ支援装置。 - 前記指定手段は、前記ユーザから単一の関数の指定を受け付け、
前記ログ処理手段は、前記指定手段で前記単一の関数の指定を受け付けたとき、前記単一の関数を子関数として識別する前記識別情報を含むログを前記ログ記憶手段から検出し、
前記出力手段は、検出されたログを出力する
ことを特徴とする請求項1に記載のデバッグ支援装置。 - 前記プログラムに含まれる関数の呼び出し毎に、前記関数の入力値および出力値を前記親子関係の識別情報と関連づける命令コードを前記プログラムに追加してトレーサプログラムを生成するトレーサ生成手段をさらに備え、
前記プログラム実行手段は、前記トレーサプログラムを実行する
ことを特徴とする請求項1ないし3のいずれか一項に記載のデバッグ支援装置。 - 関数型言語で記述されたプログラムを、前記プログラムを記憶するプログラム記憶装置から読み込むプログラム読込ステップと、
前記プログラムを実行して前記プログラムに含まれる関数の呼び出し毎に前記関数の入力値および出力値を取得し、取得した入力値および出力値を、前記関数と前記関数を呼び出した親関数との親子関係の識別情報と関連づけるプログラム実行ステップと、
互いに関連づけられた、前記入力値および出力値と前記親子関係の識別情報とからなるログをログ記憶手段に記憶するログ記憶ステップと、
前記プログラム内で定義された関数毎に、定義された関数および前記定義された関数内で呼び出される子関数間のデータの流れを記述したデータフローグラフを生成するデータフローグラフ生成ステップと、
ユーザから、連鎖的に呼び出されるn(nは3以上の整数)個の関数を指定した第1のコンテキストを受け付ける指定ステップと、
前記第1のコンテキストにおける1番目および2番目で呼ばれる関数の親子関係に対応するログを前記ログ記憶手段において特定する特定ステップと、
(A)前記第1のコンテキストにおけるm(mは1以上n−2以下の整数)+1番目で呼び出される関数の入力とm+2番目で呼び出される関数の入力とが同一か否かを前記m+1番目で呼び出される関数に対応するデータフローグラフに基づき判断し、
(B)同一のとき、m+1番目およびm+2番目で呼ばれる関数の親子関係に対応するログから、最新の特定されたログであるターゲットログの入力値と同じ入力値をもつログを特定し、
(C−1)同一でないとき前記m+1番目で呼び出される関数に対応するデータフローグラフを辿り、前記m+1番目で呼び出される関数と同じ入力をもつ関数を特定し、
(C−2)前記m+1番目で呼ばれる関数と特定した関数との親子関係に対応するログにおいて、前記ターゲットログと同じ入力値に対応する出力値を取得し、
(C−3)特定した関数の出力が前記m+2番目で呼ばれる関数の入力に一致するまで、前記データフローグラフを辿って前記特定した関数の出力を入力としてもつ関数を特定し前記m+1番目で呼ばれる関数と当該特定した関数との親子関係に対応するログにおいて最新の取得した出力値と同じ入力値に対応する出力値を取得する処理を行い、一致したら前記m+1番目およびm+2番目で呼ばれる関数の親子関係に対応するログから最新の取得した出力値と同じ入力値をもつログを特定する、
ログ処理ステップと、
mを1からn−2まで順次インクリメントして前記ログ処理ステップを繰り返し行うことを制御する制御ステップと、
前記n−2に対応して前記ログ処理ステップに特定された最新のログを出力する出力ステップと、
をコンピュータに実行させるためのデバッグ支援プログラム。 - 前記指定ステップは、前記ユーザから、連鎖的に呼び出される2個の関数を指定した第2のコンテキストを受け付け、
前記ログ処理ステップは、前記指定ステップで前記第2のコンテキストを受け付けたとき、前記第2のコンテキストで指定される2個の関数の親子関係に対応するログを前記ログ記憶手段から検出し、
前記出力ステップは、検出されたログを出力する
ことを特徴とする請求項5に記載のデバッグ支援プログラム。 - 前記指定ステップは、前記ユーザから単一の関数の指定を受け付け、
前記ログ処理ステップは、前記指定ステップで前記単一の関数の指定を受け付けたとき、前記単一の関数を子関数として識別する前記識別情報を含むログを前記ログ記憶手段から検出し、
前記出力ステップは、検出されたログを出力する
ことを特徴とする請求項5に記載のデバッグ支援プログラム。 - 前記プログラムに含まれる関数の呼び出し毎に、前記関数の入力値および出力値を前記親子関係の識別情報と関連づける命令コードを前記プログラムに追加してトレーサプログラムを生成するトレーサ生成ステップをさらに前記コンピュータに実行させ、
前記プログラム実行ステップは、前記トレーサプログラムを実行する
ことを特徴とする請求項5ないし7のいずれか一項に記載のデバッグ支援プログラム。
Priority Applications (1)
Application Number | Priority Date | Filing Date | Title |
---|---|---|---|
JP2008213156A JP2010049489A (ja) | 2008-08-21 | 2008-08-21 | デバッグ支援装置およびデバッグ支援プログラム |
Applications Claiming Priority (1)
Application Number | Priority Date | Filing Date | Title |
---|---|---|---|
JP2008213156A JP2010049489A (ja) | 2008-08-21 | 2008-08-21 | デバッグ支援装置およびデバッグ支援プログラム |
Publications (1)
Publication Number | Publication Date |
---|---|
JP2010049489A true JP2010049489A (ja) | 2010-03-04 |
Family
ID=42066526
Family Applications (1)
Application Number | Title | Priority Date | Filing Date |
---|---|---|---|
JP2008213156A Pending JP2010049489A (ja) | 2008-08-21 | 2008-08-21 | デバッグ支援装置およびデバッグ支援プログラム |
Country Status (1)
Country | Link |
---|---|
JP (1) | JP2010049489A (ja) |
Cited By (5)
Publication number | Priority date | Publication date | Assignee | Title |
---|---|---|---|---|
JP2012155680A (ja) * | 2011-01-28 | 2012-08-16 | Fujitsu Ltd | コンピュータプログラム、プログラム解析方法及びプログラム解析装置 |
JP2020119348A (ja) * | 2019-01-25 | 2020-08-06 | 富士通株式会社 | 解析プログラム、解析方法および解析装置 |
US11086604B2 (en) | 2017-11-21 | 2021-08-10 | Mitsubishi Electric Corporation | Source code splitting device, source code analyzing device, source code splitting method, and computer readable medium |
WO2023246128A1 (zh) * | 2022-06-24 | 2023-12-28 | 比亚迪股份有限公司 | 软件模型架构、电池管理系统控制器和车辆 |
JP7568934B2 (ja) | 2021-03-30 | 2024-10-17 | 富士通株式会社 | 不正箇所特定プログラム、不正箇所特定装置、及び不正箇所特定方法 |
-
2008
- 2008-08-21 JP JP2008213156A patent/JP2010049489A/ja active Pending
Cited By (6)
Publication number | Priority date | Publication date | Assignee | Title |
---|---|---|---|---|
JP2012155680A (ja) * | 2011-01-28 | 2012-08-16 | Fujitsu Ltd | コンピュータプログラム、プログラム解析方法及びプログラム解析装置 |
US11086604B2 (en) | 2017-11-21 | 2021-08-10 | Mitsubishi Electric Corporation | Source code splitting device, source code analyzing device, source code splitting method, and computer readable medium |
JP2020119348A (ja) * | 2019-01-25 | 2020-08-06 | 富士通株式会社 | 解析プログラム、解析方法および解析装置 |
JP7148802B2 (ja) | 2019-01-25 | 2022-10-06 | 富士通株式会社 | 解析プログラム、解析方法および解析装置 |
JP7568934B2 (ja) | 2021-03-30 | 2024-10-17 | 富士通株式会社 | 不正箇所特定プログラム、不正箇所特定装置、及び不正箇所特定方法 |
WO2023246128A1 (zh) * | 2022-06-24 | 2023-12-28 | 比亚迪股份有限公司 | 软件模型架构、电池管理系统控制器和车辆 |
Similar Documents
Publication | Publication Date | Title |
---|---|---|
JP5102828B2 (ja) | アプリケーション・データ・エディタを生成するための方法及びシステム | |
US9021440B1 (en) | System and method for automated test script generation | |
US7644370B2 (en) | Method of componentisation of a graphically defined formula | |
CN103597469B (zh) | 集成开发环境中的实况浏览器工具 | |
US8006229B2 (en) | Program maintenance support device and program for the same | |
KR100860963B1 (ko) | 컴포넌트 기반의 소프트웨어 개발을 위한 장치 및 방법 | |
JP2012059026A (ja) | ソースコード変換方法およびソースコード変換プログラム | |
CN105743736B (zh) | 自动化测试方法及系统 | |
US5130932A (en) | Generating device for production system simulator | |
JP2010049489A (ja) | デバッグ支援装置およびデバッグ支援プログラム | |
JP2015230582A (ja) | プログラム可視化装置、プログラム可視化方法、及びプログラム可視化プログラム | |
JP6092686B2 (ja) | 運用作業フロー作成支援方法および運用作業フロー作成支援システム | |
CN112905441A (zh) | 测试用例生成方法、测试方法、装置及设备 | |
JP4366605B2 (ja) | 開発支援装置およびプログラムならびに処理方法 | |
JP6866270B2 (ja) | Sql文抽出装置、sql文抽出方法及びプログラム | |
CN117785168A (zh) | 变量赋值方法、介质、装置及计算设备 | |
CN110222050B (zh) | 用于核电厂三维数据库仪表关联物项的调取方法和系统 | |
Boucher et al. | Transforming workflow models into automated end-to-end acceptance test cases | |
JP2013029999A (ja) | テストコード生成装置、テストコード生成方法及びテストコード生成プログラム | |
CN109019217B (zh) | 一种电梯控制软件现场调试系统 | |
JPH08314752A (ja) | オブジェクト指向システムの開発支援装置 | |
JP3395347B2 (ja) | 文書処理装置 | |
US20090083718A1 (en) | Using a command interpreter at design time | |
JPH1153391A (ja) | データベースアクセス方法 | |
JP7073431B2 (ja) | ソースコード解析システムおよびソースコード解析方法 |