Skip to content

Commit

Permalink
Just put SingleOut here.
Browse files Browse the repository at this point in the history
  • Loading branch information
andrewreiter committed Jan 24, 2018
1 parent 050ea3c commit 0d60276
Show file tree
Hide file tree
Showing 11 changed files with 500 additions and 0 deletions.
48 changes: 48 additions & 0 deletions SingleOut/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
LLBIN=/usr/lib/llvm-4.0/bin
LLVM_CONFIG=$(LLBIN)/llvm-config
LDIS=$(LLBIN)/llvm-dis
CPP=$(LLBIN)/clang++
CC=$(LLBIN)/clang
LLC=$(LLBIN)/llc
OPTB=$(LLBIN)/opt

#QUIET:=@
QUIET:=

SRC_DIR?=$(PWD)/src
BOD=build/obj

LDFLAGS+=$(shell $(LLVM_CONFIG) --ldflags)
COMMON_FLAGS=-Wall -Wextra -g
CXXFLAGS+=$(COMMON_FLAGS) $(shell $(LLVM_CONFIG) --cxxflags)
CPPFLAGS+=$(shell $(LLVM_CONFIG) --cppflags) -std=c++11 -I$(SRC_DIR)
LOADABLE_MODULE_OPTIONS=-shared
LIBS=$(shell $(LLVM_CONFIG) --libs)

PASS=libSingleOut.so
PASS_OBJECTS=SingleOutPass.o \
NoCallFunctionSieve.o \
PossiblyCheck.o \
SeahornBodyRock.o

default: prep $(PASS)

prep:
$(QUIET)mkdir -p build/obj
$(QUIET)mkdir -p build/lib

define builditdood
$(QUIET)$(CPP) -o $(BOD)/$(1)/$(@F) -c $(CPPFLAGS) $(CXXFLAGS) $<
endef

%.o: %.cpp
@echo "Compiling $*.cpp"
$(call builditdood,.)

$(PASS) : $(PASS_OBJECTS)
@echo "Linking $@"
$(QUIET)$(CPP) -o build/lib/$@ $(LOADABLE_MODULE_OPTIONS) $(CXXFLAGS) $(LDFLAGS) ${addprefix $(BOD)/,$^}

clean:
$(QUIET)rm -rf build

91 changes: 91 additions & 0 deletions SingleOut/NoCallFunctionSieve.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
/*
* Removes all functions in module with no CallInst or
* InvokeInst instruction.
*
* more lame arr code
*/
#include "llvm/IR/Module.h"
#include "llvm/Pass.h"
#include "llvm/IR/Instructions.h"
#include "llvm/IR/CallSite.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/CommandLine.h"

#include <set>
#include <algorithm>

using namespace llvm;

#include "NoCallFunctionSieve.h"

cl::opt<bool> NCFVerbose("no-call-sieve-verbose", cl::desc("verbose yo"),
cl::init(false));

cl::opt<unsigned> NCCallLevel("no-call-sieve-level", cl::desc("level"),
cl::init(0));

cl::opt<bool> NCGreaterThan("no-call-greater", cl::desc("fns with counts > n"),
cl::init(false));

static inline std::vector<std::string>
do_union(std::vector<std::string> keepDecl, std::vector<std::string> calledSet)
{
std::vector<std::string> d;
std::set_union(keepDecl.begin(), keepDecl.end(), calledSet.begin(),
calledSet.end(), std::back_inserter(d));
return d;
}

bool
NoCallFunctionSievePass::runOnModule(Module &M)
{
std::vector<Function *> removeThese;
bool modified = false;

std::vector<std::string> keepDecl;


for (Function &F : M) {
Function *pF = &F;
std::set<std::string> calledSet;
bool keep = true;

for (BasicBlock &B : F) {
for (Instruction &I : B) {
if (isa<CallInst>(I) || isa<InvokeInst>(I)) {
CallSite cs(&I);
calledSet.insert(cs.getCalledFunction()->getName().str());
}
}
}
if (!((NCGreaterThan == false && calledSet.size() == NCCallLevel) || \
(NCGreaterThan == true && calledSet.size() > NCCallLevel))) {
removeThese.push_back(pF);
continue;
}
std::vector<std::string> calledV;
std::copy(calledSet.begin(), calledSet.end(), std::back_inserter(calledV));
keepDecl = do_union(keepDecl, calledV);
}
for (auto fi = removeThese.begin(); fi != removeThese.end(); ++fi) {
Function *pF = *fi;
std::string remName = pF->getName().str();
bool keepIt = false;
for (auto k = keepDecl.begin(); k != keepDecl.end(); ++k) {
std::string s = *k;
if (remName == s) {
keepIt = true;
break;
}
}
if (keepIt) {
pF->deleteBody();
} else {
pF->eraseFromParent();
}
}
return modified;
}

char NoCallFunctionSievePass::ID = 0;
static RegisterPass<NoCallFunctionSievePass> X("no-call-sieve", "no call sieve");
9 changes: 9 additions & 0 deletions SingleOut/NoCallFunctionSieve.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
#ifndef _NOCALLFUNCTIONSIEVEPASS_H
#define _NOCALLFUNCTIONSIEVEPASS_H

struct NoCallFunctionSievePass : ModulePass {
static char ID;
NoCallFunctionSievePass() : ModulePass(ID) {}
virtual bool runOnModule(Module &);
};
#endif
82 changes: 82 additions & 0 deletions SingleOut/PossiblyAnnotate
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
#!/usr/bin/python

# There are hardcoded paths... sorry :(

# target app dir

import sys
import os
import fnmatch
import json
import subprocess

def main():
# By configuration, os.getcwd() gives us the Module dir
modDir = os.getcwd()

# Find all the android_gradle_build.json files
agb = []
for root, dns, fns in os.walk(modDir):
for fn in fnmatch.filter(fns, 'android_gradle_build.json'):
agb.append(os.path.join(root, fn))

if len(agb) == 0:
print "Failed to find any android_gradle_build.json file to work with."
print "You may need to build your project first, or fix the config of tool"
sys.exit(1)


jpath = agb[0]
with open(jpath, "r") as joh:
job = json.load(joh)
cfext = []
try:
cfext = job["cFileExtensions"]
except:
pass
cppfext = []
try:
cppfext = job["cppFileExtensions"]
except:
pass

firstchain = job["toolchains"].keys()[0]
# clang = job["toolchains"][firstchain]["cCompilerExecutable"]
# clangpp = job["toolchains"][firstchain]["cppCompilerExecutable"]

clang = '/usr/lib/llvm-4.0/bin/clang'
clangpp = '/usr/lib/llvm-4.0/bin/clang++'
opt_bin = '/usr/lib/llvm-4.0/bin/opt'


for libs in job["libraries"].keys():
jf = job["libraries"][libs]["files"]
for fi in jf:
comp = None
if fi["src"].split(".")[-1] in cfext:
comp = clang
elif fi["src"].split(".")[-1] in cppfext:
comp = clangpp
else:
print "Failed to get compiler for {}".format(fi["src"])
sys.exit(1)

args = [comp]
args.extend(fi["flags"].split(" "))
args.append("-emit-llvm")
args.append("-o")
args.append("poschk.bc")
args.append(fi["src"])
subprocess.check_output(args)
subprocess.check_output([opt_bin,
"-load",
"/home/areiter/SingleOut/build/lib/libSingleOut.so",
"-possibly-check",
"-o",
"/dev/null",
os.path.join(modDir, "poschk.bc")])

sys.exit(0)

if __name__ == '__main__':
main()
89 changes: 89 additions & 0 deletions SingleOut/PossiblyCheck.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
/*
* not even prototype front end to finding functions that some static
* analysis thinks should have some assume/assert compile time DbC
* checks.
*
* more lame arr code
*/
#include "llvm/IR/Module.h"
#include "llvm/IR/Instructions.h"
#include "llvm/IR/BasicBlock.h"
#include "llvm/IR/CFG.h"
#include "llvm/Pass.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/CommandLine.h"

#include <set>

using namespace llvm;

#include "PossiblyCheck.h"

bool
PossiblyCheck::scCheckAll(Function *F)
{
return true;
}

bool
PossiblyCheck::scCheckNone(Function *F)
{
return false;
}

bool
PossiblyCheck::scCheckCyclo(Function *F)
{
/*
* For a function in well-formed IR, there should be only
* 1 connected component.
*
* M = E - N + 2C;
*
*/
unsigned nEdges = 0; // E
unsigned nNodes = 0; // N
unsigned nConnectedComponents = 1; // C

nNodes = std::distance(F->begin(), F->end());
for (BasicBlock &BB : *F) {
BasicBlock *b = &BB;
nEdges += std::distance(succ_begin(b), succ_end(b));
}
unsigned v = (nEdges - nNodes + (2 * nConnectedComponents));

/* Make tunable */
#define ARBITRARY_CCBAR 10
if (v > 10) {
return true;
}
return false;
}

bool
PossiblyCheck::runOnModule(Module &M)
{

for (Function &F : M) {
if (F.isIntrinsic() || F.isDeclaration() || F.hasName() == false) {
continue;
}
std::string Fname = F.getName().str();
errs() << Fname << ":\n";
for (auto ci = shouldCheckMap.begin(); ci != shouldCheckMap.end();
++ci) {
std::string scName = ci->first;
errs() << " Running check test: " << scName << " ";
shouldCheck scFunc = ci->second;
if (scFunc(&F) == true) {
errs() << "(SHOULD CHECK)\n";
} else {
errs() << "(NO COMMENT)\n";
}
}
}
return false;
}

char PossiblyCheck::ID = 0;
static RegisterPass<PossiblyCheck> X("possibly-check", "Possibly add DbC checks");
25 changes: 25 additions & 0 deletions SingleOut/PossiblyCheck.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
#ifndef _POSSIBLYCHECK_H
#define _POSSIBLYCHECK_H

#include <map>

typedef bool (*shouldCheck)(llvm::Function *);

struct PossiblyCheck : ModulePass {
static char ID;
PossiblyCheck() : ModulePass(ID) {}
virtual bool runOnModule(Module &);

private:

// Worth breaking out; this is just a hack to make go.
static bool scCheckAll(Function *);
static bool scCheckNone(Function *);
static bool scCheckCyclo(Function *);
std::map<std::string, shouldCheck> shouldCheckMap = {
std::make_pair("check all", scCheckAll),
std::make_pair("check none", scCheckNone),
std::make_pair("check by cyclo-complexity", scCheckCyclo)
};
};
#endif
21 changes: 21 additions & 0 deletions SingleOut/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@

## Toys

Just thinking of ways to insert pre/post condition type stuff into code
after the fact. You'd like to have them in prior to implementation, but
say you want or have to add such annotations on a code base that's already
there. One way to think of going about that process is to look at varying
levels of where functions are defined, depth-wise, by how many unique functions
they call.
So, looking at functions that have 0 call instructions, 1 call instructions,
..., >k call instructions lumped. This may or may not be useful for you
depending on goals.

Aside from the above, these are mostly just for-fun, so not likely worth
your while, but putting here so they are available. They modify the
module instead of trying to create a new module with the stuff in it.

### Couple of issues

- Not yet handling other references to functions (eg, pthread_create(.,.,&function,.))
- Probably just awful in general. Could benefit from lambda
Loading

0 comments on commit 0d60276

Please sign in to comment.