diff --git a/.gitattributes b/.gitattributes index 5d6462a718b423ea428c5ac2f52d0233795a4512..ce4a0f652de27bd618199d4973d3f18291e7ec6e 100644 --- a/.gitattributes +++ b/.gitattributes @@ -204,6 +204,7 @@ libIRDB/SConstruct -text libIRDB/include/cfg/BasicBlock.hpp -text libIRDB/include/cfg/CFG.hpp -text libIRDB/include/cfg/callgraph.hpp -text +libIRDB/include/cfg/domgraph.hpp -text libIRDB/include/core/address.hpp -text libIRDB/include/core/archdesc.hpp -text libIRDB/include/core/baseobj.hpp -text diff --git a/libIRDB/include/cfg/BasicBlock.hpp b/libIRDB/include/cfg/BasicBlock.hpp index bd61587db7bc449803d1ec121ec5b6152cb2ef4d..340c9d697dc1e8ce801c5e5641ae2bcedb9b9cb8 100644 --- a/libIRDB/include/cfg/BasicBlock.hpp +++ b/libIRDB/include/cfg/BasicBlock.hpp @@ -36,9 +36,15 @@ class BasicBlock_t BasicBlockSet_t& GetPredecessors() { return predecessors; } BasicBlockSet_t& GetSuccessors() { return successors; } BasicBlockSet_t& GetIndirectTargets() { return indirect_targets; } - BasicBlock_t* GetFallthrough(); BasicBlock_t* GetTarget(); + + // for const correctness if you aren't modifying. + const InstructionVector_t& GetInstructions() const { return instructions; } + const BasicBlockSet_t& GetPredecessors() const { return predecessors; } + const BasicBlockSet_t& GetSuccessors() const { return successors; } + const BasicBlockSet_t& GetIndirectTargets() const { return indirect_targets; } + bool EndsInBranch(); bool EndsInIndirectBranch(); bool EndsInConditionalBranch(); diff --git a/libIRDB/include/cfg/CFG.hpp b/libIRDB/include/cfg/CFG.hpp index afb0e63bb57b1a98487e3ac2c41bf0c89d23596d..532570be5ed3343adc29f77c7ea56f431f163736 100644 --- a/libIRDB/include/cfg/CFG.hpp +++ b/libIRDB/include/cfg/CFG.hpp @@ -42,6 +42,7 @@ class ControlFlowGraph_t public: friend std::ostream& operator<<(std::ostream& os, const ControlFlowGraph_t& cfg); BasicBlockSet_t& GetBlocks() { return blocks; } + const BasicBlockSet_t& GetBlocks() const { return blocks; } }; diff --git a/libIRDB/include/cfg/domgraph.hpp b/libIRDB/include/cfg/domgraph.hpp new file mode 100644 index 0000000000000000000000000000000000000000..d5de10e5ebdc389b40eaebe1520fa0a0dfdd8c59 --- /dev/null +++ b/libIRDB/include/cfg/domgraph.hpp @@ -0,0 +1,50 @@ + + + +typedef std::map<const BasicBlock_t*, BasicBlockSet_t> DominatorMap_t; +typedef std::map<const BasicBlock_t*, BasicBlock_t*> BlockToBlockMap_t; + +class DominatorGraph_t +{ + public: + DominatorGraph_t(const ControlFlowGraph_t* p_cfg, bool needs_postdoms=false, bool needs_idoms=false); + + + // get the (post) dominators for a node + BasicBlockSet_t& GetDominators(const BasicBlock_t* node) { return dom_graph[node]; } + BasicBlockSet_t& GetPostDominators(const BasicBlock_t* node) { return post_dom_graph[node]; } + + const BasicBlockSet_t& GetDominators(const BasicBlock_t* node) const { return dom_graph.at(node); } + const BasicBlockSet_t& GetPostDominators(const BasicBlock_t* node) const { return post_dom_graph.at(node); } + + + // get the immeidate (post) dominators for a node + const BasicBlock_t* GetImmediateDominator(const BasicBlock_t* node) const + { auto it=idom_graph.find(node); return (it!=idom_graph.end()) ? it->second : NULL; } + const BasicBlock_t* GetImmediatePostDominators(const BasicBlock_t* node) const + { auto it=post_idom_graph.find(node); return (it!=post_idom_graph.end()) ? it->second : NULL; } + + + private: + + typedef const BasicBlockSet_t& (*pred_func_ptr_t) (const BasicBlock_t* node); + + DominatorMap_t Dom_Comp(const BasicBlockSet_t& N, pred_func_ptr_t pred_func, BasicBlock_t* r); + BlockToBlockMap_t Idom_Comp(const BasicBlockSet_t& N, const DominatorMap_t &Domin, BasicBlock_t* r); + + + DominatorMap_t dom_graph; + BlockToBlockMap_t idom_graph; + + DominatorMap_t post_dom_graph; + BlockToBlockMap_t post_idom_graph; + + const ControlFlowGraph_t& cfg; // a reference to our cfg. + + friend std::ostream& operator<<(std::ostream& os, const DominatorGraph_t& cfg); + +}; + +std::ostream& operator<<(std::ostream& os, const DominatorGraph_t& cfg); + + diff --git a/libIRDB/include/libIRDB-cfg.hpp b/libIRDB/include/libIRDB-cfg.hpp index 6cfc423dfc66eba3e394fd671d6441cde7eca32e..1a720ec614c5b281ceaef0efe3230d37c8fda04e 100644 --- a/libIRDB/include/libIRDB-cfg.hpp +++ b/libIRDB/include/libIRDB-cfg.hpp @@ -36,6 +36,7 @@ namespace libIRDB #include <cfg/BasicBlock.hpp> #include <cfg/CFG.hpp> #include <cfg/callgraph.hpp> +#include <cfg/domgraph.hpp> }; diff --git a/libIRDB/src/cfg/BasicBlock.cpp b/libIRDB/src/cfg/BasicBlock.cpp index 8cf8350612ee882b15b0095fd915152c3005d582..f45440423294f95c37431c2ba4d05d88934e980f 100644 --- a/libIRDB/src/cfg/BasicBlock.cpp +++ b/libIRDB/src/cfg/BasicBlock.cpp @@ -69,6 +69,35 @@ void BasicBlock_t::BuildBlock successors.insert(target_block); } + /* This is also the end of the block if this is a function exit instruction */ + if(insn->IsFunctionExit()) + { + is_exit_block=true; + } + + // handle fixed-call fallthroughs. + for_each(insn->GetRelocations().begin(), insn->GetRelocations().end(), [this,&insn2block_map](Relocation_t* reloc) + { + /* and has a reloc that's a pcrel with a WRT object */ + if( reloc->GetType()==string("fix_call_fallthrough")) + { + assert(reloc->GetWRT()!=NULL); + Instruction_t* fix_call_fallthrough_insn=dynamic_cast<Instruction_t*>(reloc->GetWRT()); + assert(fix_call_fallthrough_insn); + + // this block has a fallthrough to the return block. + if(is_in_container(insn2block_map,fix_call_fallthrough_insn)) + { + BasicBlock_t* fix_call_fallthrough_blk=find_map_object(insn2block_map,fix_call_fallthrough_insn); + successors.insert(fix_call_fallthrough_blk); + fix_call_fallthrough_blk->GetPredecessors().insert(this); + } + + is_exit_block=false; + } + }); + + /* if there's a fallthrough block, insert it into the appropriate sets */ if(ft_block) { @@ -81,16 +110,34 @@ void BasicBlock_t::BuildBlock break; /* or if there is a fallthrough block already built */ - if(target_insn || ft_block) + if(ft_block) break; - /* This is also the end of the block if this is a function exit instruction */ - if(insn->IsFunctionExit()) + /* check for a fallthrough out of the function */ + if(ft_insn && !is_in_container(func->GetInstructions(),ft_insn)) break; + /* otherwise, move to the fallthrough */ insn=ft_insn; } + + // deal with IB targets for the end of the block + + insn=instructions[instructions.size()-1]; // get last instruction. + assert(insn); + if(insn->GetIBTargets()) + { + for_each(insn->GetIBTargets()->begin(), insn->GetIBTargets()->end(), [this,&insn2block_map,func](Instruction_t* target) + { + if(is_in_container(insn2block_map,target) && target!=func->GetEntryPoint()) // don't link calls to the entry block. + { + BasicBlock_t* target_block=find_map_object(insn2block_map,target); + target_block->GetPredecessors().insert(this); + successors.insert(target_block); + } + }); + } } diff --git a/libIRDB/src/cfg/CFG.cpp b/libIRDB/src/cfg/CFG.cpp index 3203c947c3a6a4c95acf9411e3afd0b95d1c7895..2e1b80c83572229c76146f501659c5a5c3bd7163 100644 --- a/libIRDB/src/cfg/CFG.cpp +++ b/libIRDB/src/cfg/CFG.cpp @@ -139,7 +139,18 @@ void ControlFlowGraph_t::Build(Function_t* func) ostream& libIRDB::operator<<(ostream& os, const ControlFlowGraph_t& cfg) { int i=0; + + map<BasicBlock_t*,int> blk_numbers; + for( + set<BasicBlock_t*>::const_iterator it=cfg.blocks.begin(); + it!=cfg.blocks.end(); + ++it + ) + { + blk_numbers[*it]=i++; + } + for( set<BasicBlock_t*>::const_iterator it=cfg.blocks.begin(); it!=cfg.blocks.end(); @@ -152,11 +163,21 @@ ostream& libIRDB::operator<<(ostream& os, const ControlFlowGraph_t& cfg) os<<"**** Entry "; else os<<"---- NotEntry "; - os<<"block "<<std::dec<<i<<endl; - i++; - + os<<"block "<<std::dec<<blk_numbers[block]<<endl; + os<<"Successors: "; + for_each(block->GetSuccessors().begin(), block->GetSuccessors().end(), [&](BasicBlock_t* succ) + { + os<<blk_numbers[succ]<<", "; + + }); + os<<endl; + os<<"Predecessors: "; + for_each(block->GetPredecessors().begin(), block->GetPredecessors().end(), [&](BasicBlock_t* pred) + { + os<<blk_numbers[pred]<<", "; + }); + os<<endl; os << *block; - } return os; diff --git a/libIRDB/src/cfg/SConscript b/libIRDB/src/cfg/SConscript index ad91f9943222a6955c43e3b83ad6d2d5dfb27d95..572af82762c62dee62e59bec833cdfc485107fbd 100644 --- a/libIRDB/src/cfg/SConscript +++ b/libIRDB/src/cfg/SConscript @@ -8,7 +8,7 @@ myenv.Replace(SECURITY_TRANSFORMS_HOME=os.environ['SECURITY_TRANSFORMS_HOME']) libname="IRDB-cfg" files= ''' - BasicBlock.cpp callgraph.cpp CFG.cpp + BasicBlock.cpp callgraph.cpp CFG.cpp domgraph.cpp ''' cpppath=''' $SECURITY_TRANSFORMS_HOME/include/ @@ -18,6 +18,7 @@ cpppath=''' ''' #myenv.Append(CCFLAGS=" -Wall -W -Wextra -Wconversion ") +myenv.Append(CCFLAGS=" -Wall -W -Wextra -Wconversion -std=c++11") myenv=myenv.Clone(CPPPATH=Split(cpppath)) lib=myenv.Library(libname, Split(files)) diff --git a/libIRDB/test/fix_calls.cpp b/libIRDB/test/fix_calls.cpp index 533dc88891d33aca4d4502d33696a3dd81c78a89..b96895c2e5a54a9722ec1c3a858a17cd5dd765ea 100644 --- a/libIRDB/test/fix_calls.cpp +++ b/libIRDB/test/fix_calls.cpp @@ -677,6 +677,15 @@ void fix_call(Instruction_t* insn, FileIR_t *firp, bool can_unpin) } } + + // mark in the IR what the fallthrough of this insn is. + Relocation_t* fix_call_reloc=new Relocation_t(); + fix_call_reloc->SetOffset(0); + fix_call_reloc->SetType("fix_call_fallthrough"); + fix_call_reloc->SetWRT(newindirtarg); + callinsn->GetRelocations().insert(fix_call_reloc); + firp->GetRelocations().insert(fix_call_reloc); + }