15.2.2. Dyninst をスタンドアロンライブラリーとして使用
Dyninst ライブラリーをアプリケーションの一部として使用する前に、DYNINSTAPI_RT_LIB
環境変数の値をランタイムライブラリーファイルへのパスに設定します。
$ export DYNINSTAPI_RT_LIB=/opt/rh/devtoolset-10/root/usr/lib64/dyninst/libdyninstAPI_RT.so
これにより、現在のシェルセッションで DYNINSTAPI_RT_LIB
環境変数が設定されます。
例15.2「Dyninst をスタンドアロンアプリケーションとして使用する」 は、ユーザー空間プロセスの実行を監視するプログラムを作成およびビルドする方法を示しています。Dyninst の使用方法に関する詳細は、「関連資料」 に記載されているリソースを参照してください。
例15.2 Dyninst をスタンドアロンアプリケーションとして使用する
例15.1「SystemTap での Dyninst の使用」 の exercise.C
ソースファイルを考慮します。このプログラムにより、ユーザーは開始番号を入力し、1 までカウントして各反復の print_iteration()
関数をカウントし、標準出力に番号を出力します。
ここ cout.C
で、以下の内容を含む別のソースファイルを考慮します。
#include <stdio.h> #include <fcntl.h> #include "BPatch.h" #include "BPatch_process.h" #include "BPatch_function.h" #include "BPatch_Vector.h" #include "BPatch_thread.h" #include "BPatch_point.h" void usage() { fprintf(stderr, "Usage: count <process_id> <function>\n"); } // Global information for counter BPatch_variableExpr *counter = NULL; void createCounter(BPatch_process *app, BPatch_image *appImage) { int zero = 0; counter = app->malloc(*appImage->findType("int")); counter->writeValue(&zero); } bool interceptfunc(BPatch_process *app, BPatch_image *appImage, char *funcName) { BPatch_Vector<BPatch_function *> func; appImage->findFunction(funcName, func); if(func.size() == 0) { fprintf(stderr, "Unable to find function to instrument()\n"); exit (-1); } BPatch_Vector<BPatch_snippet *> incCount; BPatch_Vector<BPatch_point *> *points; points = func[0]->findPoint(BPatch_entry); if ((*points).size() == 0) { exit (-1); } BPatch_arithExpr counterPlusOne(BPatch_plus, *counter, BPatch_constExpr(1)); BPatch_arithExpr addCounter(BPatch_assign, *counter, counterPlusOne); return app->insertSnippet(addCounter, *points); } void printCount(BPatch_thread *thread, BPatch_exitType) { int val = 0; counter->readValue(&val, sizeof(int)); fprintf(stderr, "Function executed %d times.\n", val); } int main(int argc, char *argv[]) { int pid; BPatch bpatch; if (argc != 3) { usage(); exit(1); } pid = atoi(argv[1]); BPatch_process *app = bpatch.processAttach(NULL, pid); if (!app) exit (-1); BPatch_image *appImage = app->getImage(); createCounter(app, appImage); fprintf(stderr, "Finding function %s(): ", argv[2]); BPatch_Vector<BPatch_function*> countFuncs; fprintf(stderr, "OK\nInstrumenting function %s(): ", argv[2]); interceptfunc(app, appImage, argv[2]); bpatch.registerExitCallback(printCount); fprintf(stderr, "OK\nWaiting for process %d to exit...\n", pid); app->continueExecution(); while (!app->isTerminated()) bpatch.waitForStatusChange(); return 0; }
Dyninst ライブラリーのデストラクターが呼び出される前に、クライアントアプリケーションがすべての Bpatch
オブジェクトを破棄することが期待されることに注意してください。それ以外の場合は、セグメンテーションフォールトでミューターが突然終了する可能性があります。この問題を回避するには、main()
関数で mutator の BPatch
オブジェクトをローカル変数として設定します。または、グローバル変数として BPatch
使用する必要がある場合は、ミューテーターの終了前にすべての変更プロセスを手作業でデタッチします。
このプログラムは、プロセス ID および関数名をコマンドライン引数として受け入れ、プロセスの実行中に呼び出された関数の合計回数を出力します。これらの 2 つのファイル Makefile
を構築するには、以下を使用します。
DTS = /opt/rh/devtoolset-10/root CXXFLAGS = -g -I$(DTS)/usr/include/dyninst LBITS := $(shell getconf LONG_BIT) ifeq ($(LBITS),64) DYNINSTLIBS = $(DTS)/usr/lib64/dyninst else DYNINSTLIBS = $(DTS)/usr/lib/dyninst endif .PHONY: all all: count exercise count: count.C g++ $(CXXFLAGS) count.C -I /usr/include/dyninst -c g++ $(CXXFLAGS) count.o -L $(DYNINSTLIBS) -ldyninstAPI -o count exercise: exercise.C g++ $(CXXFLAGS) exercise.C -o exercise .PHONY: clean clean: rm -rf *~ *.o count exercise
Red Hat Developer Toolset の g++
コンパイラーを使用してコマンドラインで 2 つのプログラムをコンパイルするには、make
ユーティリティーを実行します。
$ scl enable devtoolset-10 make
g++ -g -I/opt/rh/devtoolset-10/root/usr/include/dyninst count.C -c
g++ -g -I/opt/rh/devtoolset-10/root/usr/include/dyninst count.o -L /opt/rh/devtoolset-10/root/usr/lib64/dyninst -ldyninstAPI -o count
g++ -g -I/opt/rh/devtoolset-10/root/usr/include/dyninst exercise.C -o exercise
これにより、exercise
と count
という名前のバイナリーファイルが、現在の作業ディレクトリーに作成されます。
あるシェルセッションで、以下のように exercise
バイナリーファイルを実行し、開始番号の入力を求めるプロンプトを待ちます。
$ ./exercise
Enter the starting number:
この番号は入力しないでください。代わりに別のシェルセッションを開始し、プロンプトに以下のコマンドを入力します。 DYNINSTAPI_RT_LIB
環境変数を設定して、count
バイナリーファイルを実行します。
$export DYNINSTAPI_RT_LIB=/opt/rh/devtoolset-10/root/usr/lib64/dyninst/libdyninstAPI_RT.so
$./count `pidof exercise` print_iteration
Finding function print_iteration(): OK Instrumenting function print_iteration(): OK Waiting for process 8607 to exit...
最初のシェルセッションに切り替え、exercise
プログラムで要求される開始番号を入力します。以下に例を示します。
Enter the starting number: 5
Iteration number 5
Iteration number 4
Iteration number 3
Iteration number 2
Iteration number 1
exercise
プログラムが終了すると、count
プログラムにより、print_iteration()
関数の実行回数が表示されます。
Function executed 5 times.