xref: /minix3/minix/llvm/passes/include/magic/support/MagicDebugFunction.h (revision bdb565187c0f1a04513dd488df843317b27f86c8)
13e457fe3SDavid van Moolenbroek #ifndef MAGIC_DEBUG_FUNCTION_H_
23e457fe3SDavid van Moolenbroek #define MAGIC_DEBUG_FUNCTION_H_
33e457fe3SDavid van Moolenbroek 
43e457fe3SDavid van Moolenbroek #include <pass.h>
53e457fe3SDavid van Moolenbroek 
63e457fe3SDavid van Moolenbroek #define NUM_DEBUG_ARGS 1
73e457fe3SDavid van Moolenbroek 
83e457fe3SDavid van Moolenbroek using namespace llvm;
93e457fe3SDavid van Moolenbroek 
103e457fe3SDavid van Moolenbroek namespace llvm {
113e457fe3SDavid van Moolenbroek 
123e457fe3SDavid van Moolenbroek class MagicDebugFunction {
133e457fe3SDavid van Moolenbroek public:
143e457fe3SDavid van Moolenbroek 	MagicDebugFunction(Function *function);
153e457fe3SDavid van Moolenbroek 
163e457fe3SDavid van Moolenbroek 	Function* getFunction() const;
173e457fe3SDavid van Moolenbroek 	void addHooks(std::pair<Function*, Function*> hooks, unsigned flags, std::vector<unsigned> argsMapping, std::vector<Value*> trailingArgs);
183e457fe3SDavid van Moolenbroek 	void fixCalls(Module &M, const std::string &baseDir="");
193e457fe3SDavid van Moolenbroek 
203e457fe3SDavid van Moolenbroek 	void print(raw_ostream &OS) const;
213e457fe3SDavid van Moolenbroek 	void printDescription(raw_ostream &OS) const;
223e457fe3SDavid van Moolenbroek 	const std::string getDescription() const;
233e457fe3SDavid van Moolenbroek 	static bool inlineHookCalls(Function* function, std::pair<Function*, Function*> hooks, unsigned flags, std::vector<unsigned> argsMapping,
243e457fe3SDavid van Moolenbroek 			std::vector<Value*> trailingArgs);
253e457fe3SDavid van Moolenbroek 	Function* getDebugFunction(Module &M);
263e457fe3SDavid van Moolenbroek 
273e457fe3SDavid van Moolenbroek private:
283e457fe3SDavid van Moolenbroek 	Function *function;
293e457fe3SDavid van Moolenbroek 
303e457fe3SDavid van Moolenbroek 	std::pair<Function*, Function*> hooks;
313e457fe3SDavid van Moolenbroek 	unsigned flags;
323e457fe3SDavid van Moolenbroek 	std::vector<unsigned> argsMapping;
333e457fe3SDavid van Moolenbroek 	std::vector<Value*> trailingArgs;
343e457fe3SDavid van Moolenbroek 
353e457fe3SDavid van Moolenbroek 	Function* getDebugClone(Function* function, const Twine wrapperName, TYPECONST Type* debugArgType);
363e457fe3SDavid van Moolenbroek };
373e457fe3SDavid van Moolenbroek 
383e457fe3SDavid van Moolenbroek inline raw_ostream &operator<<(raw_ostream &OS, const MagicDebugFunction &aMagicDebugFunction) {
393e457fe3SDavid van Moolenbroek 	aMagicDebugFunction.print(OS);
403e457fe3SDavid van Moolenbroek 	return OS;
413e457fe3SDavid van Moolenbroek }
423e457fe3SDavid van Moolenbroek 
print(raw_ostream & OS)433e457fe3SDavid van Moolenbroek inline void MagicDebugFunction::print(raw_ostream &OS) const {
443e457fe3SDavid van Moolenbroek 	OS << getDescription();
453e457fe3SDavid van Moolenbroek }
463e457fe3SDavid van Moolenbroek 
printDescription(raw_ostream & OS)473e457fe3SDavid van Moolenbroek inline void MagicDebugFunction::printDescription(raw_ostream &OS) const {
483e457fe3SDavid van Moolenbroek 	OS << "[ function = ";
493e457fe3SDavid van Moolenbroek 	OS << function->getName() << "(" << TypeUtil::getDescription(function->getFunctionType()) << ") ]";
503e457fe3SDavid van Moolenbroek }
513e457fe3SDavid van Moolenbroek 
getDescription()523e457fe3SDavid van Moolenbroek inline const std::string MagicDebugFunction::getDescription() const {
533e457fe3SDavid van Moolenbroek 	std::string string;
543e457fe3SDavid van Moolenbroek 	raw_string_ostream ostream(string);
553e457fe3SDavid van Moolenbroek 	printDescription(ostream);
563e457fe3SDavid van Moolenbroek 	ostream.flush();
573e457fe3SDavid van Moolenbroek 	return string;
583e457fe3SDavid van Moolenbroek }
593e457fe3SDavid van Moolenbroek 
getDebugClone(Function * function,const Twine wrapperName,TYPECONST Type * debugArgType)603e457fe3SDavid van Moolenbroek inline Function* MagicDebugFunction::getDebugClone(Function* function, const Twine wrapperName, TYPECONST Type* debugArgType) {
613e457fe3SDavid van Moolenbroek 	Function* wrapper;
623e457fe3SDavid van Moolenbroek 	std::vector<TYPECONST Type*> ArgTypes;
633e457fe3SDavid van Moolenbroek 	VALUE_TO_VALUE_MAP_TY VMap;
643e457fe3SDavid van Moolenbroek 
653e457fe3SDavid van Moolenbroek 	// Build arg types for wrapper
663e457fe3SDavid van Moolenbroek 	ArgTypes.push_back(debugArgType);
673e457fe3SDavid van Moolenbroek 	Function::const_arg_iterator E = function->arg_end();
683e457fe3SDavid van Moolenbroek 	for (Function::const_arg_iterator I = function->arg_begin(); I != E; ++I)
693e457fe3SDavid van Moolenbroek 		ArgTypes.push_back(I->getType());
703e457fe3SDavid van Moolenbroek 
713e457fe3SDavid van Moolenbroek 	// Create a new function type...
723e457fe3SDavid van Moolenbroek 	FunctionType *FTy = FunctionType::get(function->getFunctionType()->getReturnType(), ArgTypes, function->getFunctionType()->isVarArg());
733e457fe3SDavid van Moolenbroek 
743e457fe3SDavid van Moolenbroek 	// Create the wrapper
753e457fe3SDavid van Moolenbroek 	wrapper = Function::Create(FTy, function->getLinkage(), wrapperName, function->getParent());
763e457fe3SDavid van Moolenbroek 
773e457fe3SDavid van Moolenbroek 	// Loop over the arguments, copying the names of the mapped arguments over...
783e457fe3SDavid van Moolenbroek 	Function::arg_iterator DestI = wrapper->arg_begin();
793e457fe3SDavid van Moolenbroek 	Value *magicTypeValue = DestI;
803e457fe3SDavid van Moolenbroek 	magicTypeValue->setName("cs_info");
813e457fe3SDavid van Moolenbroek 	DestI++;
823e457fe3SDavid van Moolenbroek 	for (Function::const_arg_iterator I = function->arg_begin(), E = function->arg_end(); I != E; ++I) {
833e457fe3SDavid van Moolenbroek 		DestI->setName(I->getName());
843e457fe3SDavid van Moolenbroek 		VMap[I] = DestI++;
853e457fe3SDavid van Moolenbroek 	}
863e457fe3SDavid van Moolenbroek 
873e457fe3SDavid van Moolenbroek 	SmallVector<ReturnInst*, 8> Returns; // Ignore returns cloned...
883e457fe3SDavid van Moolenbroek 	CloneFunctionInto(wrapper, function, VMap, false, Returns, "", NULL);
893e457fe3SDavid van Moolenbroek 	return wrapper;
903e457fe3SDavid van Moolenbroek }
913e457fe3SDavid van Moolenbroek 
MagicDebugFunction(Function * function)923e457fe3SDavid van Moolenbroek inline MagicDebugFunction::MagicDebugFunction(Function *function) {
933e457fe3SDavid van Moolenbroek 	this->function = function;
943e457fe3SDavid van Moolenbroek }
953e457fe3SDavid van Moolenbroek 
addHooks(std::pair<Function *,Function * > aHooks,unsigned aFlags,std::vector<unsigned> aArgsMapping,std::vector<Value * > aTrailingArgs)963e457fe3SDavid van Moolenbroek inline void MagicDebugFunction::addHooks(std::pair<Function*, Function*> aHooks, unsigned aFlags, std::vector<unsigned> aArgsMapping,
973e457fe3SDavid van Moolenbroek 		std::vector<Value*> aTrailingArgs) {
983e457fe3SDavid van Moolenbroek 	hooks = aHooks;
993e457fe3SDavid van Moolenbroek 	flags = aFlags;
1003e457fe3SDavid van Moolenbroek 	trailingArgs = aTrailingArgs;
1013e457fe3SDavid van Moolenbroek 	argsMapping = aArgsMapping;
1023e457fe3SDavid van Moolenbroek }
1033e457fe3SDavid van Moolenbroek 
getFunction()1043e457fe3SDavid van Moolenbroek inline Function* MagicDebugFunction::getFunction() const {
1053e457fe3SDavid van Moolenbroek 	return function;
1063e457fe3SDavid van Moolenbroek }
1073e457fe3SDavid van Moolenbroek 
getDebugFunction(Module & M)1083e457fe3SDavid van Moolenbroek inline Function* MagicDebugFunction::getDebugFunction(Module &M) {
1093e457fe3SDavid van Moolenbroek 	PointerType* PointerTy = PointerType::get(IntegerType::get((&M)->getContext(), 8), 0);
1103e457fe3SDavid van Moolenbroek 	Function* debugFunction = MagicDebugFunction::getDebugClone(function, "debug_magic_" + function->getName(), PointerTy);
1113e457fe3SDavid van Moolenbroek 	bool ret = MagicDebugFunction::inlineHookCalls(debugFunction, hooks, flags, argsMapping, trailingArgs);
1123e457fe3SDavid van Moolenbroek 	if (ret) {
1133e457fe3SDavid van Moolenbroek 		return debugFunction;
1143e457fe3SDavid van Moolenbroek 	} else {
1153e457fe3SDavid van Moolenbroek 		return NULL;
1163e457fe3SDavid van Moolenbroek 	}
1173e457fe3SDavid van Moolenbroek }
1183e457fe3SDavid van Moolenbroek 
fixCalls(Module & M,const std::string & baseDir)1193e457fe3SDavid van Moolenbroek inline void MagicDebugFunction::fixCalls(Module &M, const std::string &baseDir) {
1203e457fe3SDavid van Moolenbroek 	PointerType* PointerTy = PointerType::get(IntegerType::get((&M)->getContext(), 8), 0);
1213e457fe3SDavid van Moolenbroek 	Function* debugFunction = MagicDebugFunction::getDebugClone(function, "debug_magic_" + function->getName(), PointerTy);
1223e457fe3SDavid van Moolenbroek 	bool ret = MagicDebugFunction::inlineHookCalls(debugFunction, hooks, flags, argsMapping, trailingArgs);
1233e457fe3SDavid van Moolenbroek 	assert(ret && "Unable to inline the calls to the hook functions.");
1243e457fe3SDavid van Moolenbroek 
125*bdb56518SDavid van Moolenbroek 	std::vector<User*> Users(function->user_begin(), function->user_end());
1263e457fe3SDavid van Moolenbroek 	std::vector<Value*> EqPointers;
1273e457fe3SDavid van Moolenbroek 	while (!Users.empty()) {
1283e457fe3SDavid van Moolenbroek 		User *U = Users.back();
1293e457fe3SDavid van Moolenbroek 		Users.pop_back();
1303e457fe3SDavid van Moolenbroek 
1313e457fe3SDavid van Moolenbroek 		if (Instruction * I = dyn_cast<Instruction>(U)) {
1323e457fe3SDavid van Moolenbroek 			CallSite CS = MagicUtil::getCallSiteFromInstruction(I);
1333e457fe3SDavid van Moolenbroek 			if (CS.getInstruction()
1343e457fe3SDavid van Moolenbroek 					&& (MagicUtil::getCalledFunctionFromCS(CS) == function
1353e457fe3SDavid van Moolenbroek 							|| std::find(EqPointers.begin(), EqPointers.end(), CS.getCalledValue()) != EqPointers.end())) {
1363e457fe3SDavid van Moolenbroek 				Function *parentFunction = CS.getInstruction()->getParent()->getParent();
1373e457fe3SDavid van Moolenbroek 				StringRef callParentName = MagicUtil::getFunctionSourceName(M, parentFunction, NULL, baseDir);
1383e457fe3SDavid van Moolenbroek 				//extend function name with debug information
1393e457fe3SDavid van Moolenbroek 				if (MDNode *N = I->getMetadata("dbg")) {
1403e457fe3SDavid van Moolenbroek 					DILocation Loc(N);
1413e457fe3SDavid van Moolenbroek 					std::string string;
1423e457fe3SDavid van Moolenbroek 					raw_string_ostream ostream(string);
1433e457fe3SDavid van Moolenbroek 					ostream << callParentName << MAGIC_ALLOC_NAME_SEP << Loc.getFilename() << MAGIC_ALLOC_NAME_SEP << Loc.getLineNumber();
1443e457fe3SDavid van Moolenbroek 					ostream.flush();
1453e457fe3SDavid van Moolenbroek 					callParentName = string;
1463e457fe3SDavid van Moolenbroek 				}
1473e457fe3SDavid van Moolenbroek 				Value* callParentNameValue = MagicUtil::getArrayPtr(M, MagicUtil::getStringRef(M, callParentName));
1483e457fe3SDavid van Moolenbroek 				std::vector<Value*> debugArgs;
1493e457fe3SDavid van Moolenbroek 				debugArgs.push_back(callParentNameValue);
1503e457fe3SDavid van Moolenbroek 				debugArgs.insert(debugArgs.end(), CS.arg_begin(), CS.arg_end());
1513e457fe3SDavid van Moolenbroek 				CallInst* newInst = MagicUtil::createCallInstruction(debugFunction, debugArgs, "", I);
1523e457fe3SDavid van Moolenbroek 				newInst->takeName(I);
1533e457fe3SDavid van Moolenbroek 				MagicUtil::replaceCallInst(I, newInst, 1);
1543e457fe3SDavid van Moolenbroek 			}
1553e457fe3SDavid van Moolenbroek 		} else if (GlobalValue * GV = dyn_cast<GlobalValue>(U)) {
156*bdb56518SDavid van Moolenbroek 			Users.insert(Users.end(), GV->user_begin(), GV->user_end());
1573e457fe3SDavid van Moolenbroek 			EqPointers.push_back(GV);
1583e457fe3SDavid van Moolenbroek 		} else if (ConstantExpr * CE = dyn_cast<ConstantExpr>(U)) {
1593e457fe3SDavid van Moolenbroek 			if (CE->isCast()) {
160*bdb56518SDavid van Moolenbroek 				Users.insert(Users.end(), CE->user_begin(), CE->user_end());
1613e457fe3SDavid van Moolenbroek 				EqPointers.push_back(CE);
1623e457fe3SDavid van Moolenbroek 			}
1633e457fe3SDavid van Moolenbroek 		}
1643e457fe3SDavid van Moolenbroek 	}
1653e457fe3SDavid van Moolenbroek }
1663e457fe3SDavid van Moolenbroek 
1673e457fe3SDavid van Moolenbroek }
1683e457fe3SDavid van Moolenbroek 
1693e457fe3SDavid van Moolenbroek // inlines calls to the pre and post hooks and returns true if the inlining succeeded, false otherwise
inlineHookCalls(Function * function,std::pair<Function *,Function * > hooks,unsigned flags,std::vector<unsigned> argsMapping,std::vector<Value * > trailingArgs)1703e457fe3SDavid van Moolenbroek inline bool MagicDebugFunction::inlineHookCalls(Function* function, std::pair<Function*, Function*> hooks, unsigned flags,
1713e457fe3SDavid van Moolenbroek 		std::vector<unsigned> argsMapping, std::vector<Value*> trailingArgs) {
1723e457fe3SDavid van Moolenbroek 	std::vector<Value*> emptyArgs;
1733e457fe3SDavid van Moolenbroek 	std::vector<unsigned> emptyMapping;
1743e457fe3SDavid van Moolenbroek 	std::vector<unsigned> debugEmptyMapping;
1753e457fe3SDavid van Moolenbroek 	std::vector<unsigned> debugArgsMapping;
1763e457fe3SDavid van Moolenbroek 
1773e457fe3SDavid van Moolenbroek 	// debug version of the function, argument mapping has to be adjusted
1783e457fe3SDavid van Moolenbroek 	if (flags & MAGIC_HOOK_DEBUG_MASK) {
1793e457fe3SDavid van Moolenbroek 		// re-adjusted the index of the arguments (do not re-adjust return value)
1803e457fe3SDavid van Moolenbroek 		for (unsigned i = 0; i < argsMapping.size(); i++) {
1813e457fe3SDavid van Moolenbroek 			if (argsMapping[i] > 0) {
1823e457fe3SDavid van Moolenbroek 				argsMapping[i] += NUM_DEBUG_ARGS;
1833e457fe3SDavid van Moolenbroek 			}
1843e457fe3SDavid van Moolenbroek 		}
1853e457fe3SDavid van Moolenbroek 		// first come the debug argument
1863e457fe3SDavid van Moolenbroek 		for (unsigned i = 1; i <= NUM_DEBUG_ARGS; i++) {
1873e457fe3SDavid van Moolenbroek 			debugEmptyMapping.push_back(i);
1883e457fe3SDavid van Moolenbroek 			debugArgsMapping.push_back(i);
1893e457fe3SDavid van Moolenbroek 		}
1903e457fe3SDavid van Moolenbroek 		debugArgsMapping.insert(debugArgsMapping.end(), argsMapping.begin(), argsMapping.end());
1913e457fe3SDavid van Moolenbroek 	}
1923e457fe3SDavid van Moolenbroek 
1933e457fe3SDavid van Moolenbroek 	if (hooks.first != NULL) {
1943e457fe3SDavid van Moolenbroek 		// inline first hook call at the beginning of the function, according to the flag
1953e457fe3SDavid van Moolenbroek 		switch (flags & MAGIC_PRE_HOOK_FLAGS_MASK) {
1963e457fe3SDavid van Moolenbroek 		case MAGIC_PRE_HOOK_SIMPLE_CALL:
1973e457fe3SDavid van Moolenbroek 			MagicUtil::inlinePreHookForwardingCall(function, hooks.first, (flags & MAGIC_PRE_HOOK_DEBUG) ? debugEmptyMapping : emptyMapping,
1983e457fe3SDavid van Moolenbroek 					emptyArgs);
1993e457fe3SDavid van Moolenbroek 			break;
2003e457fe3SDavid van Moolenbroek 		case MAGIC_PRE_HOOK_FORWARDING_CALL:
2013e457fe3SDavid van Moolenbroek 			MagicUtil::inlinePreHookForwardingCall(function, hooks.first, (flags & MAGIC_PRE_HOOK_DEBUG) ? debugArgsMapping : argsMapping,
2023e457fe3SDavid van Moolenbroek 					trailingArgs);
2033e457fe3SDavid van Moolenbroek 			break;
2043e457fe3SDavid van Moolenbroek 		default:
2053e457fe3SDavid van Moolenbroek 			// unknown flag
2063e457fe3SDavid van Moolenbroek 			return false;
2073e457fe3SDavid van Moolenbroek 		}
2083e457fe3SDavid van Moolenbroek 	}
2093e457fe3SDavid van Moolenbroek 
2103e457fe3SDavid van Moolenbroek 	if (hooks.second != NULL) {
2113e457fe3SDavid van Moolenbroek 		// inline the second wrapper call at the end of the function, according to the flag
2123e457fe3SDavid van Moolenbroek 		switch (flags & MAGIC_POST_HOOK_FLAGS_MASK) {
2133e457fe3SDavid van Moolenbroek 		case MAGIC_POST_HOOK_SIMPLE_CALL:
2143e457fe3SDavid van Moolenbroek 			MagicUtil::inlinePostHookForwardingCall(function, hooks.second, (flags & MAGIC_POST_HOOK_DEBUG) ? debugEmptyMapping : emptyMapping,
2153e457fe3SDavid van Moolenbroek 					emptyArgs);
2163e457fe3SDavid van Moolenbroek 			break;
2173e457fe3SDavid van Moolenbroek 		case MAGIC_POST_HOOK_FORWARDING_CALL:
2183e457fe3SDavid van Moolenbroek 			MagicUtil::inlinePostHookForwardingCall(function, hooks.second, (flags & MAGIC_POST_HOOK_DEBUG) ? debugArgsMapping : argsMapping,
2193e457fe3SDavid van Moolenbroek 					trailingArgs);
2203e457fe3SDavid van Moolenbroek 			break;
2213e457fe3SDavid van Moolenbroek 		default:
2223e457fe3SDavid van Moolenbroek 			// unknown flag
2233e457fe3SDavid van Moolenbroek 			return false;
2243e457fe3SDavid van Moolenbroek 		}
2253e457fe3SDavid van Moolenbroek 	}
2263e457fe3SDavid van Moolenbroek 
2273e457fe3SDavid van Moolenbroek 	return true;
2283e457fe3SDavid van Moolenbroek }
2293e457fe3SDavid van Moolenbroek 
2303e457fe3SDavid van Moolenbroek #endif /* MAGIC_DEBUG_FUNCTION_H_ */
231