From 94288613a0a0293f1d0bde4543ef4ff0641dd399 Mon Sep 17 00:00:00 2001 From: fundamental Date: Fri, 8 Aug 2014 22:52:46 -0400 Subject: [PATCH] Initial Rewrite --- README.adoc | 31 ++++ run.rb | 207 +++++++++++++++++++++++++++ src/pass1.cpp | 101 +++++++++++++ test/cpp-new-detection.cpp | 5 + test/function-pointer-call.cpp | 31 ++++ test/function-pointer-resolution.cpp | 8 ++ test/function-pointer.c | 28 ++++ test/implicit-methods.cpp | 21 +++ test/lambda-call.cpp | 23 +++ test/malloc-blacklist.c | 9 ++ test/math-safety.cpp | 15 ++ test/test-input.c | 28 ++++ test/test-input.cpp | 12 ++ test/test-input2.cpp | 19 +++ test/test-input3.c | 12 ++ test/virtual-methods.cpp | 34 +++++ 16 files changed, 584 insertions(+) create mode 100644 README.adoc create mode 100644 run.rb create mode 100644 src/pass1.cpp create mode 100644 test/cpp-new-detection.cpp create mode 100644 test/function-pointer-call.cpp create mode 100644 test/function-pointer-resolution.cpp create mode 100644 test/function-pointer.c create mode 100644 test/implicit-methods.cpp create mode 100644 test/lambda-call.cpp create mode 100644 test/malloc-blacklist.c create mode 100644 test/math-safety.cpp create mode 100644 test/test-input.c create mode 100644 test/test-input.cpp create mode 100644 test/test-input2.cpp create mode 100644 test/test-input3.c create mode 100644 test/virtual-methods.cpp diff --git a/README.adoc b/README.adoc new file mode 100644 index 0000000..e23398a --- /dev/null +++ b/README.adoc @@ -0,0 +1,31 @@ +Realtime Function Static Analysis +--------------------------------- + +Pass 1 +~~~~~~ + +Generate Function List and Annotations +Perhaps annotate rtosc ports somehow + +Code 1.5 +~~~~~~~~ + +Merge in blacklist/whitelist information + +Pass 2 +~~~~~~ + +Populate the MultiGraph + +Function->Function +:source location with source function + +Code 2.5 +~~~~~~~~ + +Perform same graph operations to determine problematic sequences + +Pass 3 +~~~~~~ + +Gather more information about source if needed diff --git a/run.rb b/run.rb new file mode 100644 index 0000000..3d30978 --- /dev/null +++ b/run.rb @@ -0,0 +1,207 @@ +require 'optparse' +require 'ostruct' +require 'set' +require 'yaml' +require 'pp' + + +#Modifies mapa s.t. it includes the mapb info +def merge_maps(mapa, mapb) + mapb.each do |key, val| + if(mapa.has_key? key) + mapa[key].concat val + else + mapa[key] = val + end + end +end + + +options = OpenStruct.new +options.whitelist = [] +options.blacklist = [] +options.unmangled = OpenStruct.new +options.unmangled.whitelist = [] +options.unmangled.blacklist = [] +options.root = "./" +options.dir = [] +options.recursive = false + +OptionParser.new do |opts| + opts.banner = "Usage: example.rb [options] FILE" + + opts.on("-w", "--whitelist FILE", + "Define a Mangled Whitelist File") do |list| + options.whitelist << list + end + + opts.on("-b", "--blacklist FILE", + "Define a Mangled Blacklist File") do |list| + options.blacklist << list + end + + #opts.on("-W", "--unmangled-whitelist FILE", + # "Define an Unmangled Whitelist File") do |list| + # options.unmangled.whitelist << list + #end + + #opts.on("-B", "--unmangled-blacklist FILE", + # "Define an Unmangled Blacklist File") do |list| + # options.unmangled.blacklist << list + #end + + #opts.on("-s", "--search DIR", + # "Search Within the Defined Directory") do |dir| + # options.dirs << dir + #end + + opts.on("-r", "--recursive DIR", + "Enable Recursive Search Mode") do |dir| + options.recursive = true + options.root = dir + end +end.parse! + +#If there are unmangled files, then mangle them and add them to the end of the +#mangled lists + +#For each one of the bitcode files, run the pass based preprocessor +if(!options.recursive) + $stderr.puts "This Program Must Process Input Recursively At this time" + exit 1 +end +files = `find #{options.root} -type f | grep -e "\\.bc$"`.split +#p files +callgraph = Hash.new +function_props = Hash.new + +files.each do |f| + p "running #{f} file..." + `opt -load ./src/libfoo.so --dummy1 < #{f} > /dev/null 2> sfpv_output.txt` + #puts File.read("sfpv_output.txt") + ncallgraph = YAML.load_file "sfpv_output.txt" + + + `opt -load ./src/libfoo.so --dummy2 < #{f} > /dev/null 2> sfpv_output.txt` + #puts File.read("sfpv_output.txt") + nfunc = YAML.load_file "sfpv_output.txt" + + if(ncallgraph) + merge_maps(callgraph, ncallgraph) + end + if(nfunc) + merge_maps(function_props, nfunc) + end +end + +symbol_list = Set.new +callgraph.each do |key,val| + symbol_list << key + val.each do |x| + symbol_list << x + end +end + +demangled_symbols = Hash.new +symbol_list.each do |x| + demangled_symbols[x] = `echo '#{x}' | c++filt` +end +pp demangled_symbols + + +reason_user_w = "The Function Was Declared Realtime By A Whitelist" +reason_user_b = "The Function Was Declared NonRealtime By A Blacklist" +reason_code_w = "The Function Was Declared Realtime By A Code Annotation" +reason_code_b = "The Function Was Declared NonRealtime By A Code Annotation" +reason_deduced = "The Function Was Deduced To Need To Be RealTime As It Was Called By A Realtime Function" +reason_none = "No Deduction has occured" +reason_nocode = "No Code Or Annotations, So The Function is Assumed Unsafe" + +class DeductionChain + attr_accessor :deduction_source, :reason, :realtime_p, :non_realtime_p, :has_body_p, :contradicted_p, :contradicted_by + + def initialize + @deduction_source = nil + @reason = "No Deduction has occured" + @realtime_p = false + @non_realtime_p = false + @has_body_p = false + @contradicted_p = false + @contradicted_by = Set.new + end +end + +property_list = Hash.new +symbol_list.each do |x| + property_list[x] = DeductionChain.new +end + +#Add information about finding source +callgraph.each do |key,value| + property_list[key].has_body_p = true +end + +#Add Anything That's On the function_props list +function_props.each do |key, value| + if(property_list.include? key) + if(value.include? 'realtime') + property_list[key].realtime_p = true + property_list[key].reason = reason_code_w + elsif(value.include? 'non-realtime') + property_list[key].non_realtime_p = true + property_list[key].reason = reason_code_b + end + end +end + +#Add no source stuff +property_list.each do |key, value| + if(!value.has_body_p && !value.realtime_p && !value.non_realtime_p) + value.non_realtime_p = true + value.reason = reason_nocode + end +end + +#Perform Deductions +do_stuff = true +while do_stuff + do_stuff = false + property_list.each do |key, value| + if(!value.contradicted_p) + if(value.realtime_p() && callgraph.include?(key)) + callgraph[key].each do |x| + if(property_list[x].non_realtime_p) + value.contradicted_p = true + value.contradicted_by << x + do_stuff = true + elsif(!property_list[x].realtime_p) + property_list[x].realtime_p = true + property_list[x].deduction_source = key + property_list[x].reason = reason_deduced + do_stuff = true + end + end + end + end + end +end + + + +#pp symbol_list +#pp callgraph +#puts "\n\n\n\n\n" +#pp function_props +#pp property_list + +property_list.each do |key, value| + if(value.contradicted_p) + pp key + pp value + puts "\n\n\n" + end +end + + +#p options +#p ARGV diff --git a/src/pass1.cpp b/src/pass1.cpp new file mode 100644 index 0000000..eb2ac04 --- /dev/null +++ b/src/pass1.cpp @@ -0,0 +1,101 @@ +#include +#include +#include +#include +#include +#include + +using namespace llvm; +using std::string; + +namespace { +struct DummyPass : public FunctionPass { + static char ID; // Pass ID, replacement for typeid + DummyPass() : FunctionPass(ID) {} + + void getAnalysisUsage(AnalysisUsage &AU) const override { + AU.setPreservesAll(); + } + + bool runOnFunction(Function &Fn) override { + //Fn.dump(); + //auto attr = Fn.getAttributes(); + //attr.dump(); + std::vector v; + //Fn.dump(); + for(auto &bb:Fn) { + for(auto &i:bb) { + if(i.getOpcode() == Instruction::Call) { + auto call = dyn_cast(&i); + auto fn2 = call->getCalledFunction(); + if(!fn2) + continue; + auto s = fn2->getName().str(); + if(s == "llvm.dbg.value") + continue; + if(fn2) + v.push_back(s); + } + } + } + if(!v.empty()) { + fprintf(stderr, "%s :\n", Fn.getName().str().c_str()); + for(auto x:v) + fprintf(stderr, " - %s\n", x.c_str()); + } + return false; + } +}; + +struct DummyPass2 : public ModulePass { + static char ID; // Pass ID, replacement for typeid + DummyPass2() : ModulePass(ID) {} + + void getAnalysisUsage(AnalysisUsage &AU) const override { + AU.setPreservesAll(); + } + + void handleNested(Value *v) + { + if(auto o = dyn_cast(v)) + { + fprintf(stderr, "%s :\n", o->getName().str().c_str()); + } else if(auto s = dyn_cast(v)) { + fprintf(stderr, " - %s\n", dyn_cast(s->getOperand(0))->getAsString().str().c_str()); + } else + fprintf(stderr, "We have a dinosaur\n"); + + + } + + bool runOnModule(Module &m) override { + auto g = m.getNamedGlobal("llvm.global.annotations"); + if(g) { + auto gg = dyn_cast(g->getOperand(0)); + auto ggg = gg->getOperand(0); + unsigned ops = ggg->getNumOperands(); + if(ops > 2) + ops = 2; + for(unsigned i=0; igetOperand(i); + if(auto o = dyn_cast(op)) + { + //fprintf(stderr, "Case 1["); + //o->getOperand(0)->dump();; + //fprintf(stderr, "]\n"); + handleNested(o->getOperand(0)); + + } + //fprintf(stderr,"\n"); + } + //fprintf(stderr, "I found it\n"); + } + return false; + } +}; +} + +char DummyPass::ID = 0; +char DummyPass2::ID = 0; +static RegisterPass P1("dummy1", "do nothin"); +static RegisterPass P2("dummy2", "do nothin"); diff --git a/test/cpp-new-detection.cpp b/test/cpp-new-detection.cpp new file mode 100644 index 0000000..a1d9145 --- /dev/null +++ b/test/cpp-new-detection.cpp @@ -0,0 +1,5 @@ +void foo() +{ + int *x = new int; + delete x; +} diff --git a/test/function-pointer-call.cpp b/test/function-pointer-call.cpp new file mode 100644 index 0000000..c9ca126 --- /dev/null +++ b/test/function-pointer-call.cpp @@ -0,0 +1,31 @@ +#define REALTIME __attribute__((annotate("realtime"))) +#define NREALTIME __attribute__((annotate("!realtime"))) + +typedef int (*callback_t)(int, void*); + +void make_realtime(callback_t REALTIME call, void*) +{ +} + +void NREALTIME malloc_of_doooooooooom(); + +class Runner +{ + public: + int process(int, void*) + { + malloc_of_doooooooooom(); + return 1; + } + + static int _process(int i, void* data) + { + Runner *ptr = (Runner*)(data); + return ptr->process(i,data); + } +}; + +int main() +{ + make_realtime(Runner::_process, new Runner); +} diff --git a/test/function-pointer-resolution.cpp b/test/function-pointer-resolution.cpp new file mode 100644 index 0000000..443992e --- /dev/null +++ b/test/function-pointer-resolution.cpp @@ -0,0 +1,8 @@ +int x(); + + + +int main() +{ + return 0; +} diff --git a/test/function-pointer.c b/test/function-pointer.c new file mode 100644 index 0000000..7f3be12 --- /dev/null +++ b/test/function-pointer.c @@ -0,0 +1,28 @@ +#define REALTIME __attribute__((annotate("realtime"))) +#define NREALTIME __attribute__((annotate("!realtime"))) + +typedef void (*rt_callback_t)(void); + +void REALTIME function(void) +{} + +void NREALTIME bad_function(void) +{} + +int REALTIME main() +{ + const char *not_a_function_pointer; + int me_neither; + void *hey_look_some_function_pointers_are_below; + + not_a_function_pointer = "string"; + me_neither = 2; + hey_look_some_function_pointers_are_below = &me_neither; + + + rt_callback_t fn; + fn = function; + fn = bad_function; + fn(); + void (*func)(void) = bad_function; +} diff --git a/test/implicit-methods.cpp b/test/implicit-methods.cpp new file mode 100644 index 0000000..fdbd159 --- /dev/null +++ b/test/implicit-methods.cpp @@ -0,0 +1,21 @@ + +class bar +{ + public: + ~bar(void) + { + new int; + } +}; + +class foo +{ + public: + bar boo; +}; + +int blam(void) __attribute__((annotate("realtime"))) +{ + foo fooo; + return 0; +} diff --git a/test/lambda-call.cpp b/test/lambda-call.cpp new file mode 100644 index 0000000..57d340f --- /dev/null +++ b/test/lambda-call.cpp @@ -0,0 +1,23 @@ +#include +#define REALTIME __attribute__((annotate("realtime"))) +#define NREALTIME __attribute__((annotate("!realtime"))) + +typedef int (*callback_t)(int, void*); + +void REALTIME make_realtime(std::function cb, void*) +{ + cb(0, ((void*)0)); +} + +void NREALTIME malloc_of_doooooooooom(); + +void REALTIME tmp(void) +{ + ([](void){malloc_of_doooooooooom();})(); +} + +int main() +{ + std::function foobar = [](int, void*){malloc_of_doooooooooom();return 1;}; + make_realtime(foobar, 0); +} diff --git a/test/malloc-blacklist.c b/test/malloc-blacklist.c new file mode 100644 index 0000000..ae18128 --- /dev/null +++ b/test/malloc-blacklist.c @@ -0,0 +1,9 @@ +#include +#define REALTIME __attribute__((annotate("realtime"))) +#define NREALTIME __attribute__((annotate("!realtime"))) + +int REALTIME main() +{ + malloc(123); + return 0; +} diff --git a/test/math-safety.cpp b/test/math-safety.cpp new file mode 100644 index 0000000..d32f4fa --- /dev/null +++ b/test/math-safety.cpp @@ -0,0 +1,15 @@ +#include +#define REALTIME __attribute__((annotate("realtime"))) +#define NREALTIME __attribute__((annotate("!realtime"))) + +void REALTIME test_functions() +{ + float f = 23.3; + sinf(f); + cosf(f); + powf(f,f); +} + +int main() +{ +} diff --git a/test/test-input.c b/test/test-input.c new file mode 100644 index 0000000..2ff8e05 --- /dev/null +++ b/test/test-input.c @@ -0,0 +1,28 @@ +#define REALTIME __attribute__((annotate("realtime"))) +#define NREALTIME __attribute__((annotate("!realtime"))) + +void undefined_function(void); + +void bar(void) +{} + +void REALTIME foo(int x) +{ + (void) x; + bar(); + undefined_function(); +} + + +void NREALTIME baz(void) +{} + +int tall_number; + +int REALTIME main() +{ + int barbar; + foo(barbar); + baz(); + return 0; +} diff --git a/test/test-input.cpp b/test/test-input.cpp new file mode 100644 index 0000000..54477d7 --- /dev/null +++ b/test/test-input.cpp @@ -0,0 +1,12 @@ +#define REALTIME __attribute__((annotate("realtime"))) +#define NREALTIME __attribute__((annotate("!realtime"))) +#include "test-input2.h" + +class TestClass +{ + void bar(void) {other_thing();}; + void REALTIME foo(void) {bar();}; + void REALTIME entry(void) { foo(); baz(); } + void NREALTIME baz(void) {}; +}; + diff --git a/test/test-input2.cpp b/test/test-input2.cpp new file mode 100644 index 0000000..5935dec --- /dev/null +++ b/test/test-input2.cpp @@ -0,0 +1,19 @@ +#define REALTIME __attribute__((annotate("realtime"))) +#define NREALTIME __attribute__((annotate("!realtime"))) +static int stuffy_stuff(int i) +{ + return i; +} + +static void undefined_and_unused(void); +void undefined_and_used(void); +static void unused(void) +{ +} + +void REALTIME other_thing(void) +{ + int i = 32; + stuffy_stuff(i); + undefined_and_used(); +} diff --git a/test/test-input3.c b/test/test-input3.c new file mode 100644 index 0000000..8275797 --- /dev/null +++ b/test/test-input3.c @@ -0,0 +1,12 @@ + +//Function prototype (eg from a header) +void prototype_only(void); + +void trivial_function(void) +{} + +void calling_function(void) +{ + prototype_only(); + trivial_function(); +} diff --git a/test/virtual-methods.cpp b/test/virtual-methods.cpp new file mode 100644 index 0000000..11d5ecb --- /dev/null +++ b/test/virtual-methods.cpp @@ -0,0 +1,34 @@ +#define RT __attribute__((annotate("realtime"))) +#define nRT __attribute__((annotate("!realtime"))) + +class A +{ + public: + virtual void method(void) = 0; +}; + +class B : public A +{ + public: +}; + +class C : public B +{ + public: + virtual void method(void){}; + void other(void); +}; + +class D : public virtual C +{ + public: + virtual void RT method(void) {}; +}; + + +int RT main() +{ + D d; + A *a = &d; + a->method(); +}