LLVM Hello pass: inserts printf statement in main() method.
This commit is contained in:
parent
5ba302fdea
commit
dd85959391
7 changed files with 404 additions and 2 deletions
|
@ -63,3 +63,5 @@ cp ${OBJ_LLVM}/./Release+Asserts/bin/llvm-* ${CROSS_TOOLS}
|
|||
cd ${NETBSDSRCDIR}/minix/llvm/passes/WeakAliasModuleOverride
|
||||
make LLVMPREFIX=${OBJ_LLVM}/./Release+Asserts/ install
|
||||
|
||||
cd ${NETBSDSRCDIR}/minix/llvm/passes/hello
|
||||
make LLVMPREFIX=${OBJ_LLVM}/./Release+Asserts/ install
|
||||
|
|
|
@ -2,7 +2,7 @@ QUIET=@
|
|||
ECHO=echo
|
||||
CP=cp
|
||||
|
||||
PASSLIBNAME:= weak-alias-module-override
|
||||
PASSLIBNAME:= weak-alias-module-override.so
|
||||
|
||||
LLVM_VERSION = $($LLVMPREFIX/bin/llvm-config --version | sed "s/[^0-9]//g")
|
||||
CFLAGS += -Wno-long-long -Wall -W -Wno-unused-parameter -Wwrite-strings -DHAVE_EXCEPTIONS=0
|
||||
|
|
26
minix/llvm/passes/hello/Makefile
Normal file
26
minix/llvm/passes/hello/Makefile
Normal file
|
@ -0,0 +1,26 @@
|
|||
QUIET=@
|
||||
ECHO=echo
|
||||
CP=cp
|
||||
|
||||
PASSLIBNAME:= hello.so
|
||||
|
||||
LLVM_VERSION=$(shell ($(LLVMPREFIX)/bin/llvm-config --version | sed "s/[^0-9]//g"))
|
||||
CFLAGS += -Wno-long-long -Wall -W -Wno-unused-parameter -Wwrite-strings -DHAVE_EXCEPTIONS=0
|
||||
CFLAGS += $(shell $(LLVMPREFIX)/bin/llvm-config --cxxflags) -g -DLLVM_VERSION=$(LLVM_VERSION)
|
||||
LDFLAGS += $(shell $(LLVMPREFIX)/bin/llvm-config --ldflags)
|
||||
OBJS= hello.o
|
||||
|
||||
$(PASSLIBNAME): $(OBJS)
|
||||
$(QUIET) $(ECHO) " [LINK] $@"
|
||||
$(QUIET) $(CXX) $(CFLAGS) -shared -o $@ $(CPPS) $(OBJS) $(LDFLAGS) $(LIBS)
|
||||
|
||||
%.o: %.cpp $(HEADERS)
|
||||
$(QUIET) $(ECHO) " [C++] $<"
|
||||
$(QUIET) $(CXX) $(CFLAGS) -c -o $@ $<
|
||||
|
||||
install: $(PASSLIBNAME)
|
||||
$(QUIET) -mkdir -p ../../bin
|
||||
$(QUIET) $(CP) $(PASSLIBNAME) ../../bin/$(PASSLIBNAME)
|
||||
|
||||
clean:
|
||||
-rm -f *.o *.so
|
114
minix/llvm/passes/hello/hello.cpp
Normal file
114
minix/llvm/passes/hello/hello.cpp
Normal file
|
@ -0,0 +1,114 @@
|
|||
#include "pass_hello.h"
|
||||
#include <stdlib.h>
|
||||
|
||||
using namespace llvm;
|
||||
|
||||
#define DBG(M) M
|
||||
#define helloPassLog(M) DBG(errs() << "HelloPass: " << M << "\n")
|
||||
#define MSG "Hello world!"
|
||||
#define ERROR_FAILURE 1
|
||||
|
||||
namespace {
|
||||
|
||||
class HelloPass : public ModulePass {
|
||||
|
||||
public:
|
||||
static char ID;
|
||||
|
||||
|
||||
HelloPass() : ModulePass(ID) { }
|
||||
|
||||
|
||||
virtual bool runOnModule(Module &M) {
|
||||
|
||||
Function* printfFunction = NULL;
|
||||
Function* mainFunction = NULL;
|
||||
|
||||
mainFunction = M.getFunction("main");
|
||||
if (NULL == mainFunction)
|
||||
{
|
||||
helloPassLog("Info: main() not found. Skipping instrumentation.");
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Prepare the string arguments for printf */
|
||||
std::string printFuncName = "printf" ;
|
||||
const std::string msg = MSG;
|
||||
const std::string fmt = "%s\n";
|
||||
Constant* strConstMsg = NULL;
|
||||
Constant* strConstFmt = NULL;
|
||||
std::vector<Value*> args(0);
|
||||
Instruction *I = NULL;
|
||||
|
||||
PassUtil::getStringGlobalVariable(M, fmt, ".fmtStr", "", &strConstFmt, false);
|
||||
PassUtil::getStringGlobalVariable(M, msg, ".helloworld", "", &strConstMsg, false);
|
||||
|
||||
if (NULL == strConstFmt || NULL == strConstMsg)
|
||||
{
|
||||
helloPassLog("Error: Prepared string contants point to NULL");
|
||||
exitOnError(ERROR_FAILURE);
|
||||
}
|
||||
|
||||
args.push_back(strConstFmt);
|
||||
args.push_back(strConstMsg);
|
||||
|
||||
/* Look for printf declaration */
|
||||
std::vector<TYPECONST Type*> functionTyArgs;
|
||||
FunctionType* printfFuncType;
|
||||
|
||||
functionTyArgs.push_back(PointerType::get(IntegerType::get(M.getContext(), 8), 0));
|
||||
|
||||
printfFuncType = PassUtil::getFunctionType(IntegerType::get(M.getContext(), 32), functionTyArgs, true);
|
||||
if (NULL == printfFuncType)
|
||||
{
|
||||
helloPassLog("Error: Couldn't make function-type for printf.");
|
||||
exitOnError(ERROR_FAILURE);
|
||||
}
|
||||
|
||||
printfFunction = (Function *) M.getOrInsertFunction(printFuncName, printfFuncType);
|
||||
if (NULL == printfFunction)
|
||||
{
|
||||
helloPassLog("Error: Couldnt find printf function declaration.");
|
||||
exitOnError(ERROR_FAILURE);
|
||||
}
|
||||
|
||||
/* Insert call instruction in main() to call printf */
|
||||
I = mainFunction->getBasicBlockList().begin()->begin();
|
||||
if (NULL != I)
|
||||
{
|
||||
if (args.empty())
|
||||
{
|
||||
helloPassLog("Warning: args to printf is empty.");
|
||||
}
|
||||
|
||||
helloPassLog("Info: Inserting printf call instruction");
|
||||
|
||||
CallInst* callInst = PassUtil::createCallInstruction(printfFunction, args, "", I);
|
||||
|
||||
if (NULL == callInst )
|
||||
{
|
||||
helloPassLog("Error: callInstr is null.");
|
||||
exitOnError(ERROR_FAILURE);
|
||||
}
|
||||
|
||||
helloPassLog("Info: Inserting call instruction successful.");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private:
|
||||
void exitOnError(int errCode)
|
||||
{
|
||||
helloPassLog("Aborting instrumentation.");
|
||||
exit(errCode);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
char HelloPass::ID = 0;
|
||||
RegisterPass<HelloPass> HP("hello", "Hello Pass", false, false);
|
35
minix/llvm/passes/hello/pass.h
Normal file
35
minix/llvm/passes/hello/pass.h
Normal file
|
@ -0,0 +1,35 @@
|
|||
|
||||
#ifndef _PASS_H
|
||||
#define _PASS_H
|
||||
|
||||
#import <set>
|
||||
#import <map>
|
||||
|
||||
#include <llvm/Pass.h>
|
||||
#include <llvm/Support/raw_ostream.h>
|
||||
#include <llvm/Analysis/AliasAnalysis.h>
|
||||
|
||||
#include <llvm/Support/Debug.h>
|
||||
#include <llvm/Transforms/Utils/Cloning.h>
|
||||
#include <llvm/ADT/Statistic.h>
|
||||
|
||||
#include <llvm/Support/Regex.h>
|
||||
#include <llvm/Assembly/Writer.h>
|
||||
#include <llvm/Support/CallSite.h>
|
||||
#include <llvm/Support/CommandLine.h>
|
||||
#include <llvm/Analysis/LoopInfo.h>
|
||||
|
||||
#include <llvm/Support/InstIterator.h>
|
||||
#include <llvm/Transforms/Utils/Local.h>
|
||||
|
||||
#include <llvm/Transforms/Scalar.h>
|
||||
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
|
||||
#include <common/pass_common.h>
|
||||
|
||||
#endif /* _PASS_H */
|
224
minix/llvm/passes/hello/pass_hello.h
Normal file
224
minix/llvm/passes/hello/pass_hello.h
Normal file
|
@ -0,0 +1,224 @@
|
|||
#ifndef _PASS_HELLO_H
|
||||
#define _PASS_HELLO_H
|
||||
|
||||
#if LLVM_VERSION >= 33
|
||||
#define ATTRIBUTE_SET_TY AttributeSet
|
||||
#include <llvm/IR/Function.h>
|
||||
#include <llvm/IR/Module.h>
|
||||
#include <llvm/IR/Instructions.h>
|
||||
#include <llvm/IR/Type.h>
|
||||
#include <llvm/IR/Constants.h>
|
||||
#include <llvm/IR/Intrinsics.h>
|
||||
#include <llvm/IR/DerivedTypes.h>
|
||||
#include <llvm/IR/LLVMContext.h>
|
||||
#include <llvm/IR/IntrinsicInst.h>
|
||||
#include <llvm/IR/DataLayout.h>
|
||||
#include <llvm/IR/IRBuilder.h>
|
||||
#include <llvm/Support/raw_ostream.h>
|
||||
#else /* LLVM_VERSION < 33 */
|
||||
#define ATTRIBUTE_SET_TY AttrListPtr
|
||||
#include <llvm/Function.h>
|
||||
#include <llvm/Module.h>
|
||||
#include <llvm/Instructions.h>
|
||||
#include <llvm/Type.h>
|
||||
#include <llvm/Constants.h>
|
||||
#include <llvm/Intrinsics.h>
|
||||
#include <llvm/DerivedTypes.h>
|
||||
#include <llvm/LLVMContext.h>
|
||||
#include <llvm/IntrinsicInst.h>
|
||||
#endif /* LLVM_VERSION >= 33 */
|
||||
|
||||
#if LLVM_VERSION >= 32
|
||||
#define DATA_LAYOUT_TY DataLayout
|
||||
#define ATTRIBUTE_SET_RET_IDX ATTRIBUTE_SET_TY::ReturnIndex
|
||||
#define ATTRIBUTE_SET_FN_IDX ATTRIBUTE_SET_TY::FunctionIndex
|
||||
#include <llvm/DebugInfo.h>
|
||||
#if LLVM_VERSION == 32
|
||||
#include <llvm/DataLayout.h>
|
||||
#include <llvm/IRBuilder.h>
|
||||
#endif
|
||||
#else /* LLVM_VERSION < 32 */
|
||||
#define DATA_LAYOUT_TY TargetData
|
||||
#define ATTRIBUTE_SET_RET_IDX 0
|
||||
#define ATTRIBUTE_SET_FN_IDX (~0U)
|
||||
#include <llvm/Target/TargetData.h>
|
||||
#include <llvm/Analysis/DebugInfo.h>
|
||||
#include <llvm/Support/IRBuilder.h>
|
||||
#endif /* LLVM_VERSION >= 32 */
|
||||
|
||||
#if LLVM_VERSION >= 31
|
||||
/* XXX Check. */
|
||||
#define CONSTANT_ARRAY_INITIALIZER_TY ConstantDataArray
|
||||
|
||||
#else /* LLVM_VERSION < 31 */
|
||||
#define CONSTANT_ARRAY_INITIALIZER_TY ConstantArray
|
||||
#endif /* LLVM_VERSION >= 31 */
|
||||
|
||||
#if LLVM_VERSION >= 30
|
||||
#define BASE_PARSER parser
|
||||
|
||||
#define TYPECONST
|
||||
#else /* LLVM_VERSION < 30 */
|
||||
#define BASE_PARSER basic_parser
|
||||
|
||||
#define TYPECONST const
|
||||
#endif /* LLVM_VERSION >= 30 */
|
||||
|
||||
#if LLVM_VERSION >= 29
|
||||
#define VALUE_TO_VALUE_MAP_TY ValueToValueMapTy
|
||||
#else /* LLVM_VERSION < 29 */
|
||||
#define VALUE_TO_VALUE_MAP_TY ValueMap<const Value*, Value*>
|
||||
#endif /* LLVM_VERSION >= 29 */
|
||||
|
||||
#define ZERO_CONSTANT_INT(M) ConstantInt::get((M).getContext(), APInt(32, 0, 10))
|
||||
#define VOID_PTR_TY(M) PointerType::get(IntegerType::get((M).getContext(), 8), 0)
|
||||
#define VOID_PTR_PTR_TY(M) PointerType::get(PointerType::get(IntegerType::get((M).getContext(), 8), 0), 0)
|
||||
|
||||
#define DEBUG_LLVM_DEBUG_API 0
|
||||
|
||||
typedef enum PassUtilLinkageTypeE {
|
||||
PASS_UTIL_LINKAGE_NONE = 0,
|
||||
PASS_UTIL_LINKAGE_WEAK,
|
||||
PASS_UTIL_LINKAGE_COMMON,
|
||||
PASS_UTIL_LINKAGE_EXTERNAL,
|
||||
PASS_UTIL_LINKAGE_EXTERNAL_WEAK,
|
||||
PASS_UTIL_LINKAGE_WEAK_POINTER,
|
||||
PASS_UTIL_LINKAGE_PRIVATE,
|
||||
__NUM_PASS_UTIL_LINKAGE_TYPES
|
||||
/* Values here should only be appended at the end, external components (e.g., scripts) may be relying on them.*/
|
||||
} PassUtilLinkageType;
|
||||
|
||||
#define PASS_UTIL_LINKAGE_TYPE_STRINGS \
|
||||
"NONE", \
|
||||
"WEAK", \
|
||||
"COMMON", \
|
||||
"EXTERNAL", \
|
||||
"EXTERNAL_WEAK", \
|
||||
"WEAK_POINTER", \
|
||||
"PRIVATE"
|
||||
|
||||
typedef enum PassUtilPropE {
|
||||
PASS_UTIL_PROP_NONE,
|
||||
PASS_UTIL_PROP_NOINLINE,
|
||||
PASS_UTIL_PROP_USED,
|
||||
PASS_UTIL_PROP_PRESERVE,
|
||||
__NUM_PASS_UTIL_PROPS
|
||||
} PassUtilProp;
|
||||
|
||||
#define PASS_UTIL_FLAG(F) (1 << F)
|
||||
|
||||
#define PASS_COMMON_INIT_ONCE() \
|
||||
Module *PassUtil::M = NULL; \
|
||||
|
||||
using namespace llvm;
|
||||
|
||||
namespace llvm {
|
||||
|
||||
class PassUtil {
|
||||
public:
|
||||
static Constant* getGetElementPtrConstant(Constant *constant, std::vector<Value*> &indexes);
|
||||
static CallInst* createCallInstruction(Value *F, std::vector<Value*> &args, const Twine &NameStr="", Instruction *InsertBefore=0);
|
||||
static CallInst* createCallInstruction(Value *F, std::vector<Value*> &args, const Twine &NameStr="", BasicBlock *InsertAtEnd=0);
|
||||
static FunctionType* getFunctionType(TYPECONST Type* Result, std::vector<TYPECONST Type*> &argsTy, bool isVarArg=false);
|
||||
static Constant* getStringConstantArray(Module &M, const std::string &string);
|
||||
static GlobalVariable* getStringGlobalVariable(Module &M, const std::string &string, const std::string &varName, const std::string &varSection = "", Constant **getElementPtrExpr=NULL, bool cacheable=false);
|
||||
private:
|
||||
static Module *M;
|
||||
};
|
||||
|
||||
inline Constant* PassUtil::getGetElementPtrConstant(Constant *constant, std::vector<Value*> &indexes) {
|
||||
#if LLVM_VERSION >= 30
|
||||
ArrayRef<Value*> ref(indexes);
|
||||
return ConstantExpr::getGetElementPtr(constant, ref);
|
||||
#else
|
||||
return ConstantExpr::getGetElementPtr(constant, &indexes[0], indexes.size());
|
||||
#endif
|
||||
}
|
||||
|
||||
inline CallInst* PassUtil::createCallInstruction(Value *F, std::vector<Value*> &args, const Twine &NameStr, Instruction *InsertBefore) {
|
||||
#if LLVM_VERSION >= 30
|
||||
ArrayRef<Value*> ref(args);
|
||||
return CallInst::Create(F, ref, NameStr, InsertBefore);
|
||||
#else
|
||||
return CallInst::Create(F, args.begin(), args.end(), NameStr, InsertBefore);
|
||||
#endif
|
||||
}
|
||||
|
||||
inline CallInst* PassUtil::createCallInstruction(Value *F, std::vector<Value*> &args, const Twine &NameStr, BasicBlock *InsertAtEnd) {
|
||||
#if LLVM_VERSION >= 30
|
||||
ArrayRef<Value*> ref(args);
|
||||
return CallInst::Create(F, ref, NameStr, InsertAtEnd);
|
||||
#else
|
||||
return CallInst::Create(F, args.begin(), args.end(), NameStr, InsertAtEnd);
|
||||
#endif
|
||||
}
|
||||
|
||||
inline FunctionType* PassUtil::getFunctionType(TYPECONST Type* Result, std::vector<TYPECONST Type*> &argsTy, bool isVarArg)
|
||||
{
|
||||
#if LLVM_VERSION >= 30
|
||||
ArrayRef<TYPECONST Type*> ref(argsTy);
|
||||
return FunctionType::get(Result, ref, isVarArg);
|
||||
#else
|
||||
return FunctionType::get(Result, argsTy, isVarArg);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
inline Constant* PassUtil::getStringConstantArray(Module &M, const std::string &string)
|
||||
{
|
||||
std::vector<Constant*> elements;
|
||||
elements.reserve(string.size() + 1);
|
||||
for (unsigned i = 0; i < string.size(); ++i)
|
||||
elements.push_back(ConstantInt::get(Type::getInt8Ty(M.getContext()), string[i]));
|
||||
|
||||
// Add a null terminator to the string...
|
||||
elements.push_back(ConstantInt::get(Type::getInt8Ty(M.getContext()), 0));
|
||||
|
||||
ArrayType *ATy = ArrayType::get(Type::getInt8Ty(M.getContext()), elements.size());
|
||||
return ConstantArray::get(ATy, elements);
|
||||
}
|
||||
|
||||
inline GlobalVariable* PassUtil::getStringGlobalVariable(Module &M, const std::string &string, const std::string &varName, const std::string &varSection, Constant **getElementPtrExpr, bool cacheable)
|
||||
{
|
||||
static std::map<std::string, GlobalVariable*> stringCache;
|
||||
std::map<std::string, GlobalVariable*>::iterator stringCacheIt;
|
||||
std::string stringCacheKey;
|
||||
GlobalVariable *strGV = NULL;
|
||||
|
||||
if (cacheable) {
|
||||
stringCacheKey = string + "~!~!" + varName + "~!~!" + varSection;
|
||||
stringCacheIt = stringCache.find(stringCacheKey);
|
||||
if (stringCacheIt != stringCache.end()) {
|
||||
strGV = stringCacheIt->second;
|
||||
cacheable = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (!strGV) {
|
||||
//create a constant internal string reference
|
||||
Constant *stringValue = PassUtil::getStringConstantArray(M, string);
|
||||
|
||||
//create the global variable, cache it, and record it in the module
|
||||
strGV = new GlobalVariable(M, stringValue->getType(), true,
|
||||
GlobalValue::InternalLinkage, stringValue, varName);
|
||||
if (varSection.compare("")) {
|
||||
strGV->setSection(varSection);
|
||||
}
|
||||
}
|
||||
if (getElementPtrExpr) {
|
||||
std::vector<Value*> strConstantIndices;
|
||||
strConstantIndices.push_back(ZERO_CONSTANT_INT(M));
|
||||
strConstantIndices.push_back(ZERO_CONSTANT_INT(M));
|
||||
*getElementPtrExpr = PassUtil::getGetElementPtrConstant(strGV, strConstantIndices);
|
||||
}
|
||||
|
||||
if (cacheable) {
|
||||
stringCache.insert(std::pair<std::string, GlobalVariable*>(stringCacheKey, strGV));
|
||||
}
|
||||
|
||||
return strGV;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif /* _PASS_HELLO_H */
|
|
@ -61,7 +61,7 @@ MKRUMP:= no
|
|||
MKSKEY:= no
|
||||
MKYP:= no
|
||||
|
||||
WEAKALIASOVERRIDEPASS?=${NETBSDSRCDIR}/minix/llvm/bin/weak-alias-module-override
|
||||
WEAKALIASOVERRIDEPASS?=${NETBSDSRCDIR}/minix/llvm/bin/weak-alias-module-override.so
|
||||
GOLD_PLUGIN?=${NETBSDSRCDIR}/minix/llvm/bin/LLVMgold.so
|
||||
|
||||
# By default when running LLVM passes:
|
||||
|
@ -69,6 +69,7 @@ GOLD_PLUGIN?=${NETBSDSRCDIR}/minix/llvm/bin/LLVMgold.so
|
|||
# - run the passe which allows assembly weak symbols to be
|
||||
# overriden by bitcode functions
|
||||
OPTFLAGS?= -disable-opt \
|
||||
-disable-internalize -disable-inlining \
|
||||
-load ${WEAKALIASOVERRIDEPASS} -weak-alias-module-override
|
||||
|
||||
# Whitout -Wl,--no-ctors-in-init-array, golds moves the constructors out of
|
||||
|
|
Loading…
Reference in a new issue