[DynInst_API:] Question about using Dyninst for static instrumentation


Date: Wed, 16 Apr 2014 12:03:56 +0900
From: êíí <kimpooh2@xxxxxxxxx>
Subject: [DynInst_API:] Question about using Dyninst for static instrumentation
Hello, I'm Taehwan Kim, a Ph.D student at Hongik University in South Korea. I read PASTE '11 article about Dyninst, that is so impressive for me.

I want to do various tests using Dyninst. Dyninst seems to be a very useful instrumentation tool, but I have several problems while I using this tool.

I would like to know the destination address of indirect branch instructions during run-time. So, I'm trying to instrument a short snippet code at the points targeting indirect branch instructions. I used static instrumentation methods, but it didn't normally work. Mutator cannot convert a sample binary to mutatee.

I saw the error message of function assert(), however, it is difficult to know exactly what it mean. So, I would like to know your opinion about my code.

Best regards.

- Kim
#include <stdio.h>

void TargetCall(void *addr) {
	printf("[CALL - Target] : %p\n", (unsigned long *)addr);
}

void TargetJmp(void *addr) {
	printf("[JMP - Target] : %p\n", (unsigned long *)addr);
}

void TargetRet(void *addr) {
	printf("[RET - Target] : %p\n", (unsigned long *)addr);
}
#include "BPatch.h"
#include "BPatch_addressSpace.h"
#include "BPatch_process.h"
#include "BPatch_image.h"
#include "BPatch_binaryEdit.h"
#include "BPatch_function.h"
#include "BPatch_point.h"
#include "BPatch_flowGraph.h"

#include <cstdio>
#include <fstream>
#include <iostream>
#include <set>
#include <string>

using namespace std;

int main(int argc, const char * argv[]) {
	ofstream outFile;
	outFile.open("/home/kim/test/dyninst/log/test.out");

	BPatch * bpatch = new BPatch;
	BPatch_addressSpace * addSpace;
	enum {binary_rewriter, attach, create} runmode;
	switch(argv[1][1]) {
		case 'b':	runmode = binary_rewriter;	break;
		case 'c':	runmode = create;		break;
		case 'a':	runmode = attach;		break;
	}
	const char * mutatee = argv[2];

	if(runmode == binary_rewriter)
		addSpace = bpatch->openBinary(mutatee, false);
	else if(runmode == attach)
		addSpace = bpatch->processAttach(mutatee, atoi(argv[3]));
	else if(runmode == create)
		addSpace = bpatch->processCreate(mutatee, argv+3);

	// image loading
	BPatch_image *appImage = addSpace->getImage();

	// library setting
	addSpace->loadLibrary("libTargetBranchInstruction.so");
	
	set<string> skipLibraries;
	skipLibraries.insert("libTargetBranchInstruction.so");

	// snippet setting
	vector<BPatch_snippet *> args;
	args.push_back(new BPatch_dynamicTargetExpr());
	vector<BPatch_function *> IBFuncs;
	appImage->findFunction("TargetCall", IBFuncs);
	appImage->findFunction("TargetJmp", IBFuncs);
	appImage->findFunction("TargetRet", IBFuncs);
	
	BPatch_function *callFunc = IBFuncs[0];
	BPatch_function *jmpFunc = IBFuncs[1];
	BPatch_function *retFunc = IBFuncs[2];
	BPatch_funcCallExpr TargetCall(*callFunc, args);
	BPatch_funcCallExpr TargetJmp(*jmpFunc, args);
	BPatch_funcCallExpr TargetRet(*retFunc, args);


	// inserting snippet point vector
	vector<BPatch_point *> call_Points;
	vector<BPatch_point *> jmp_Points;
	vector<BPatch_point *> ret_Points;

	// module loading
	vector<BPatch_module *> * modules = appImage->getModules();
	vector<BPatch_module *>::iterator module_iter;
	for(module_iter = modules->begin(); module_iter != modules->end(); ++module_iter) {
		char moduleName[1024];
		(*module_iter)->getName(moduleName, 1024);

		if((*module_iter)->isSharedLib() && skipLibraries.find(moduleName) != skipLibraries.end())
			continue;

		outFile << "-- Module : " << moduleName << " --" << endl;

		// function loading
		vector<BPatch_function *> * funcs = (*module_iter)->getProcedures();
		vector<BPatch_function *>::iterator func_iter;
		for(func_iter = funcs->begin(); func_iter != funcs->end(); ++func_iter) {
			char functionName[1024];
			(*func_iter)->getName(functionName, 1024);
			outFile << "-- Function : " << functionName << " --" << endl;
			
			// basic block loading
			set<BPatch_basicBlock *> blocks;
			BPatch_flowGraph * fg = (*func_iter)->getCFG();
			if(!fg) {
					cerr << "Failed to find CFG for function " << functionName << endl;
					exit(1);
			}
			if(!fg->getAllBasicBlocks(blocks)) {
					cerr << "Failed to find basic blocks for function " << functionName << endl;
					exit(1);
			}
			else if(blocks.size() == 0) {
					cerr << "No basic blocks for function " << functionName << endl;
					exit(1);
			}

			unsigned int bb_count = 0;
			set<BPatch_basicBlock *>::iterator bb_iter;
			for(bb_iter = blocks.begin(); bb_iter != blocks.end(); ++bb_iter) {
				BPatch_basicBlock * block = *bb_iter;
				vector<pair<Dyninst::InstructionAPI::Instruction::Ptr, Dyninst::Address>> insns;
				block->getInstructions(insns);
				outFile << endl << "-- Basic Block : " << dec << bb_count++ << endl;

				/*
				vector<BPatch_edge *> outgoingEdge;
				(*bb_iter)->getOutgoingEdges(outgoingEdge);

				vector<BPatch_edge *>::iterator edge_iter;
				for(edge_iter = outgoingEdge.begin(); edge_iter != outgoingEdge.end(); ++edge_iter) {
					temp_points.push_back((*edge_iter)->getPoint());


				}
				*/

				// instruction loading
				vector<pair<Dyninst::InstructionAPI::Instruction::Ptr, Dyninst::Address>>::iterator insn_iter;
				for(insn_iter = insns.begin(); insn_iter != insns.end(); ++insn_iter) {
					Dyninst::InstructionAPI::Instruction::Ptr insn = insn_iter->first;
					Dyninst::Address addr = insn_iter->second;
					Dyninst::InstructionAPI::Operation op = insn->getOperation();
					Dyninst::InstructionAPI::InsnCategory category = insn->getCategory();
					Dyninst::InstructionAPI::Expression::Ptr exp = insn->getControlFlowTarget();
					
					
					bool isAccess = false;
					if(exp && insn->isRead(exp)) {
						outFile << "==== Expr: " << exp->format() << endl;
						outFile << "==== Value: " << exp->eval().format() << endl;
					
						isAccess = true;
					}

					
					for(Dyninst::InstructionAPI::Instruction::cftConstIter iter = insn->cft_begin(); iter != insn->cft_end(); ++iter) {
							if(iter->isIndirect) {
								outFile << "Instrumenting Point(Opcode : " << op.format() << ") at 0x" << hex << addr << " of " << functionName << endl;
								
								if(category == Dyninst::InstructionAPI::c_CallInsn) {
									vector<BPatch_point *> callPoints;
									appImage->findPoints(addr, callPoints);

									vector<BPatch_point *>::iterator callPt_iter;
									for(callPt_iter = callPoints.begin(); callPt_iter != callPoints.end(); ++callPt_iter) {
										call_Points.push_back(*callPt_iter);
									}
								}
								
								else if(category == Dyninst::InstructionAPI::c_BranchInsn) {
									vector<BPatch_point *> jmpPoints;
									appImage->findPoints(addr, jmpPoints);

									vector<BPatch_point *>::iterator jmpPt_iter;
									for(jmpPt_iter = jmpPoints.begin(); jmpPt_iter != jmpPoints.end(); ++jmpPt_iter) {
										jmp_Points.push_back(*jmpPt_iter);
									}
								}
								
								else if(category == Dyninst::InstructionAPI::c_ReturnInsn) {
									vector<BPatch_point *> retPoints;
									appImage->findPoints(addr, retPoints);

									vector<BPatch_point *>::iterator retPt_iter;
									for(retPt_iter = retPoints.begin(); retPt_iter != retPoints.end(); ++retPt_iter) {
										ret_Points.push_back(*retPt_iter);
									}
								}
							}
					}
					

					/*
					if(category == Dyninst::InstructionAPI::c_CallInsn && isAccess) {
						outFile << "Instrumenting Point(Opcode : " << op.format() << ") at 0x" << hex << addr << " of " << functionName << endl;

						vector<BPatch_point *> callPoints;
						appImage->findPoints(addr, callPoints);

						vector<BPatch_point *>::iterator callPt_iter;
						for(callPt_iter = callPoints.begin(); callPt_iter != callPoints.end(); ++callPt_iter) {
							points.push_back(*callPt_iter);
						}
					}
					*/

					/*
					if(category == Dyninst::InstructionAPI::c_ReturnInsn) {
						outFile << "Instrumenting Point(Opcode : " << op.format() << ") at 0x" << hex << addr << " of " << functionName << endl;

						vector<BPatch_point *> returnPoints;
						appImage->findPoints(addr, returnPoints);

						vector<BPatch_point *>::iterator returnPt_iter;
						for(returnPt_iter = returnPoints.begin(); returnPt_iter != returnPoints.end(); ++returnPt_iter) {
							points.push_back(*returnPt_iter);
						}
					}
					*/

					/*
					if(category == Dyninst::InstructionAPI::c_BranchInsn && isAccess) {
						outFile << "Instrumenting Point(Opcode : " << op.format() << ") at 0x" << hex << addr << " of " << functionName << endl;

						vector<BPatch_point *> branchPoints;
						appImage->findPoints(addr, branchPoints);

						vector<BPatch_point *>::iterator branchPt_iter;
						for(branchPt_iter = branchPoints.begin(); branchPt_iter != branchPoints.end(); ++branchPt_iter) {
							points.push_back(*branchPt_iter);
						}
					}
					*/

				}
				outFile << "-- END of Basic Block --" << endl << endl;
			}
		}
	}

	outFile << "Point Size : " << dec << call_Points.size() + jmp_Points.size() + ret_Points.size() << endl;

	BPatchSnippetHandle * handle;
	handle = addSpace->insertSnippet(TargetCall, call_Points);
	if(call_Points.size() && !handle) {
		cerr << "Failed to insert instrumentation - call_Points" << endl;
		exit(1);
	}

	handle = addSpace->insertSnippet(TargetJmp, jmp_Points);
	if(jmp_Points.size() && !handle) {
		cerr << "Failed to insert instrumentation - jmp_Points" << endl;
		exit(1);
	}

	handle = addSpace->insertSnippet(TargetRet, ret_Points);
	if(ret_Points.size() && !handle) {
		cerr << "Failed to insert instrumentation - ret_Points" << endl;
		exit(1);
	}

	if(runmode == binary_rewriter) {
		if(!dynamic_cast<BPatch_binaryEdit *>(addSpace)->writeFile(argv[3])) {
			cerr << "Failed to write output file: " << argv[3] << endl;
			exit(1);
		}
	}
	else {
		dynamic_cast<BPatch_process *>(addSpace)->continueExecution();
		while (!dynamic_cast<BPatch_process *>(addSpace)->isTerminated())
			bpatch->waitForStatusChange();
	}

	outFile.close();

	return 0;
}
[← Prev in Thread] Current Thread [Next in Thread→]