minix/minix/llvm/passes/include/magic/support/MagicDebugFunction.h
David van Moolenbroek 3e457fe321 Import magic pass from llvm-apps
Change-Id: I19535b913b50f2ff24aeb80ddefc92e305c31fe8
2015-09-17 13:57:53 +00:00

231 lines
8.2 KiB
C++

#ifndef MAGIC_DEBUG_FUNCTION_H_
#define MAGIC_DEBUG_FUNCTION_H_
#include <pass.h>
#define NUM_DEBUG_ARGS 1
using namespace llvm;
namespace llvm {
class MagicDebugFunction {
public:
MagicDebugFunction(Function *function);
Function* getFunction() const;
void addHooks(std::pair<Function*, Function*> hooks, unsigned flags, std::vector<unsigned> argsMapping, std::vector<Value*> trailingArgs);
void fixCalls(Module &M, const std::string &baseDir="");
void print(raw_ostream &OS) const;
void printDescription(raw_ostream &OS) const;
const std::string getDescription() const;
static bool inlineHookCalls(Function* function, std::pair<Function*, Function*> hooks, unsigned flags, std::vector<unsigned> argsMapping,
std::vector<Value*> trailingArgs);
Function* getDebugFunction(Module &M);
private:
Function *function;
std::pair<Function*, Function*> hooks;
unsigned flags;
std::vector<unsigned> argsMapping;
std::vector<Value*> trailingArgs;
Function* getDebugClone(Function* function, const Twine wrapperName, TYPECONST Type* debugArgType);
};
inline raw_ostream &operator<<(raw_ostream &OS, const MagicDebugFunction &aMagicDebugFunction) {
aMagicDebugFunction.print(OS);
return OS;
}
inline void MagicDebugFunction::print(raw_ostream &OS) const {
OS << getDescription();
}
inline void MagicDebugFunction::printDescription(raw_ostream &OS) const {
OS << "[ function = ";
OS << function->getName() << "(" << TypeUtil::getDescription(function->getFunctionType()) << ") ]";
}
inline const std::string MagicDebugFunction::getDescription() const {
std::string string;
raw_string_ostream ostream(string);
printDescription(ostream);
ostream.flush();
return string;
}
inline Function* MagicDebugFunction::getDebugClone(Function* function, const Twine wrapperName, TYPECONST Type* debugArgType) {
Function* wrapper;
std::vector<TYPECONST Type*> ArgTypes;
VALUE_TO_VALUE_MAP_TY VMap;
// Build arg types for wrapper
ArgTypes.push_back(debugArgType);
Function::const_arg_iterator E = function->arg_end();
for (Function::const_arg_iterator I = function->arg_begin(); I != E; ++I)
ArgTypes.push_back(I->getType());
// Create a new function type...
FunctionType *FTy = FunctionType::get(function->getFunctionType()->getReturnType(), ArgTypes, function->getFunctionType()->isVarArg());
// Create the wrapper
wrapper = Function::Create(FTy, function->getLinkage(), wrapperName, function->getParent());
// Loop over the arguments, copying the names of the mapped arguments over...
Function::arg_iterator DestI = wrapper->arg_begin();
Value *magicTypeValue = DestI;
magicTypeValue->setName("cs_info");
DestI++;
for (Function::const_arg_iterator I = function->arg_begin(), E = function->arg_end(); I != E; ++I) {
DestI->setName(I->getName());
VMap[I] = DestI++;
}
SmallVector<ReturnInst*, 8> Returns; // Ignore returns cloned...
CloneFunctionInto(wrapper, function, VMap, false, Returns, "", NULL);
return wrapper;
}
inline MagicDebugFunction::MagicDebugFunction(Function *function) {
this->function = function;
}
inline void MagicDebugFunction::addHooks(std::pair<Function*, Function*> aHooks, unsigned aFlags, std::vector<unsigned> aArgsMapping,
std::vector<Value*> aTrailingArgs) {
hooks = aHooks;
flags = aFlags;
trailingArgs = aTrailingArgs;
argsMapping = aArgsMapping;
}
inline Function* MagicDebugFunction::getFunction() const {
return function;
}
inline Function* MagicDebugFunction::getDebugFunction(Module &M) {
PointerType* PointerTy = PointerType::get(IntegerType::get((&M)->getContext(), 8), 0);
Function* debugFunction = MagicDebugFunction::getDebugClone(function, "debug_magic_" + function->getName(), PointerTy);
bool ret = MagicDebugFunction::inlineHookCalls(debugFunction, hooks, flags, argsMapping, trailingArgs);
if (ret) {
return debugFunction;
} else {
return NULL;
}
}
inline void MagicDebugFunction::fixCalls(Module &M, const std::string &baseDir) {
PointerType* PointerTy = PointerType::get(IntegerType::get((&M)->getContext(), 8), 0);
Function* debugFunction = MagicDebugFunction::getDebugClone(function, "debug_magic_" + function->getName(), PointerTy);
bool ret = MagicDebugFunction::inlineHookCalls(debugFunction, hooks, flags, argsMapping, trailingArgs);
assert(ret && "Unable to inline the calls to the hook functions.");
std::vector<User*> Users(function->use_begin(), function->use_end());
std::vector<Value*> EqPointers;
while (!Users.empty()) {
User *U = Users.back();
Users.pop_back();
if (Instruction * I = dyn_cast<Instruction>(U)) {
CallSite CS = MagicUtil::getCallSiteFromInstruction(I);
if (CS.getInstruction()
&& (MagicUtil::getCalledFunctionFromCS(CS) == function
|| std::find(EqPointers.begin(), EqPointers.end(), CS.getCalledValue()) != EqPointers.end())) {
Function *parentFunction = CS.getInstruction()->getParent()->getParent();
StringRef callParentName = MagicUtil::getFunctionSourceName(M, parentFunction, NULL, baseDir);
//extend function name with debug information
if (MDNode *N = I->getMetadata("dbg")) {
DILocation Loc(N);
std::string string;
raw_string_ostream ostream(string);
ostream << callParentName << MAGIC_ALLOC_NAME_SEP << Loc.getFilename() << MAGIC_ALLOC_NAME_SEP << Loc.getLineNumber();
ostream.flush();
callParentName = string;
}
Value* callParentNameValue = MagicUtil::getArrayPtr(M, MagicUtil::getStringRef(M, callParentName));
std::vector<Value*> debugArgs;
debugArgs.push_back(callParentNameValue);
debugArgs.insert(debugArgs.end(), CS.arg_begin(), CS.arg_end());
CallInst* newInst = MagicUtil::createCallInstruction(debugFunction, debugArgs, "", I);
newInst->takeName(I);
MagicUtil::replaceCallInst(I, newInst, 1);
}
} else if (GlobalValue * GV = dyn_cast<GlobalValue>(U)) {
Users.insert(Users.end(), GV->use_begin(), GV->use_end());
EqPointers.push_back(GV);
} else if (ConstantExpr * CE = dyn_cast<ConstantExpr>(U)) {
if (CE->isCast()) {
Users.insert(Users.end(), CE->use_begin(), CE->use_end());
EqPointers.push_back(CE);
}
}
}
}
}
// inlines calls to the pre and post hooks and returns true if the inlining succeeded, false otherwise
inline bool MagicDebugFunction::inlineHookCalls(Function* function, std::pair<Function*, Function*> hooks, unsigned flags,
std::vector<unsigned> argsMapping, std::vector<Value*> trailingArgs) {
std::vector<Value*> emptyArgs;
std::vector<unsigned> emptyMapping;
std::vector<unsigned> debugEmptyMapping;
std::vector<unsigned> debugArgsMapping;
// debug version of the function, argument mapping has to be adjusted
if (flags & MAGIC_HOOK_DEBUG_MASK) {
// re-adjusted the index of the arguments (do not re-adjust return value)
for (unsigned i = 0; i < argsMapping.size(); i++) {
if (argsMapping[i] > 0) {
argsMapping[i] += NUM_DEBUG_ARGS;
}
}
// first come the debug argument
for (unsigned i = 1; i <= NUM_DEBUG_ARGS; i++) {
debugEmptyMapping.push_back(i);
debugArgsMapping.push_back(i);
}
debugArgsMapping.insert(debugArgsMapping.end(), argsMapping.begin(), argsMapping.end());
}
if (hooks.first != NULL) {
// inline first hook call at the beginning of the function, according to the flag
switch (flags & MAGIC_PRE_HOOK_FLAGS_MASK) {
case MAGIC_PRE_HOOK_SIMPLE_CALL:
MagicUtil::inlinePreHookForwardingCall(function, hooks.first, (flags & MAGIC_PRE_HOOK_DEBUG) ? debugEmptyMapping : emptyMapping,
emptyArgs);
break;
case MAGIC_PRE_HOOK_FORWARDING_CALL:
MagicUtil::inlinePreHookForwardingCall(function, hooks.first, (flags & MAGIC_PRE_HOOK_DEBUG) ? debugArgsMapping : argsMapping,
trailingArgs);
break;
default:
// unknown flag
return false;
}
}
if (hooks.second != NULL) {
// inline the second wrapper call at the end of the function, according to the flag
switch (flags & MAGIC_POST_HOOK_FLAGS_MASK) {
case MAGIC_POST_HOOK_SIMPLE_CALL:
MagicUtil::inlinePostHookForwardingCall(function, hooks.second, (flags & MAGIC_POST_HOOK_DEBUG) ? debugEmptyMapping : emptyMapping,
emptyArgs);
break;
case MAGIC_POST_HOOK_FORWARDING_CALL:
MagicUtil::inlinePostHookForwardingCall(function, hooks.second, (flags & MAGIC_POST_HOOK_DEBUG) ? debugArgsMapping : argsMapping,
trailingArgs);
break;
default:
// unknown flag
return false;
}
}
return true;
}
#endif /* MAGIC_DEBUG_FUNCTION_H_ */