// unparser for testing purposes void printAssembly(string fileNameA, string fileNameB, SgNode* fileA, SgNode* fileB, bool sourceFile) { // this part writes the file out to an assembly file ----------------------------------- if(is_directory( fileNameA ) == false ) { SgBinaryComposite* binaryA = isSgBinaryComposite(isSgProject(fileA)->get_fileList()[0]); SgAsmGenericFile* file1 = binaryA != NULL ? binaryA->get_binaryFile() : NULL; SgAsmInterpretation* interpA = SageInterface::getMainInterpretation(file1); unparseAsmStatementToFile(fileNameA+".dump2", interpA->get_global_block()); } else if (is_directory( fileNameA ) == true ) { //cerr << " Node : " << fileA->class_name() << endl; SgAsmBlock* block = isSgAsmBlock(fileA); if (block) { // SgProject* proj = new SgProject(); // proj->append_statement(block); //proj->insertStatementInScope(block,false); // SageInterface::appendStatement( // isSgStatement(block),isSgScopeStatement(proj)); //block->set_parent(proj); //fileA=proj; } } if (fileNameB!="") if(is_directory( fileNameB ) == false && sourceFile==false) { SgBinaryComposite* binaryB = isSgBinaryComposite(isSgProject(fileB)->get_fileList()[0]); SgAsmGenericFile* file2 = binaryB != NULL ? binaryB->get_binaryFile() : NULL; SgAsmInterpretation* interpB = SageInterface::getMainInterpretation(file2); unparseAsmStatementToFile(fileNameB+".dump2", interpB->get_global_block()); } }
void visit(SgNode *node) { SgAsmFunction* f = isSgAsmFunction(node); if (f == NULL) return; std :: cout << f->get_name() << std::endl; std :: cout << "====================================" << std :: endl; // create dataflow engine SgAsmInterpretation *interp = SageInterface::getEnclosingNode<SgAsmInterpretation>(node); const RegisterDictionary *regdict = interp->get_registers(); BaseSemantics ::RiscOperatorsPtr symbolicOps = SymbolicSemantics::RiscOperators::instance(regdict); DispatcherX86Ptr cpu = DispatcherX86::instance(symbolicOps); BaseSemantics :: SValuePtr esp_0 = symbolicOps->readRegister(cpu->REG_ESP); TaintedFlow taintAnalysis(cpu); TaintedFlow::Approximation approximation = TaintedFlow :: UNDER_APPROXIMATE; taintAnalysis.approximation(approximation); size_t cfgStartVertex = 0; // build control flow graph CFG cfg; ControlFlow().build_block_cfg_from_ast(node, cfg); /////////////////////// // Taint Analysis // /////////////////////// taintAnalysis.computeFlowGraphs(cfg, cfgStartVertex); TaintedFlow::StatePtr initialState = taintAnalysis.stateInstance(TaintedFlow::BOTTOM); // at this point, we would need to taint different variables initialState->setIfExists(DataFlow::Variable(), TaintedFlow::NOT_TAINTED); // actually run the taint analysis taintAnalysis.runToFixedPoint(cfg, cfgStartVertex, initialState); BOOST_FOREACH(const typename CFG::VertexNode &vertex, cfg.vertices()){ // rose_addr_t lastInsnAddr = // SageInterface::querySubTree<SgAsmInstruction>(vertex.value()).back()->get_address(); TaintedFlow::StatePtr state = taintAnalysis.getFinalState(vertex.id()); std :: cout << *state << std :: endl; } // print 'variables' of function // BOOST_FOREACH(const DataFlow::Variable &variable, taintAnalysis.variables() ) // std :: cout << variable << std :: endl; }
void BinControlFlowAnalysis::run(SgNode* fileA, SgNode* fileB) { instance=NULL; if (!testFlag) instance = QROSE::cbData<BinQGUI *>(); if (isSgProject(fileA)==NULL) { cerr << "This is not a valid file for this analysis!" << endl; if (!testFlag) { QString res = QString("This is not a valid file for this analysis"); instance->analysisResult->append(res); } return; } RoseBin_Graph* graph=NULL; ROSE_ASSERT(isSgProject(fileA)); SgBinaryComposite* binary = isSgBinaryComposite(isSgProject(fileA)->get_fileList()[0]); SgAsmGenericFile* file = binary != NULL ? binary->get_binaryFile() : NULL; ROSE_ASSERT(file); VirtualBinCFG::AuxiliaryInformation* info = new VirtualBinCFG::AuxiliaryInformation(file); // control flow analysis ******************************************************* if (!testFlag) { ROSE_ASSERT(instance); ROSE_ASSERT(instance->analysisTab); instance->analysisTab->setCurrentIndex(1); QString res = QString("Creating control flow graph "); instance->analysisResult->append(res); } string cfgFileName = "cfg.dot"; graph= new RoseBin_DotGraph(); bool dot=true; bool forward=true; bool edges=true; bool mergedEdges=true; if (dot==false) { cfgFileName = "cfg.gml"; graph= new RoseBin_GMLGraph(); } GraphAlgorithms* algo = new GraphAlgorithms(info); SgAsmInterpretation* interp = SageInterface::getMainInterpretation(file); RoseBin_ControlFlowAnalysis* cfganalysis = new RoseBin_ControlFlowAnalysis(interp->get_global_block(), forward, new RoseObj(), edges, algo); ROSE_ASSERT(cfganalysis); cfganalysis->run(graph, cfgFileName, mergedEdges); if (!testFlag) { QString res = QString("nr of nodes visited %1. nr of edges visited %2. ") .arg(cfganalysis->nodesVisited()) .arg(cfganalysis->edgesVisited()); instance->analysisResult->append(res); } }
void visit(SgNode* node) { SgAsmInterpretation *interp = isSgAsmInterpretation(node); if (interp) { const SgAsmGenericHeaderPtrList &headers = interp->get_headers()->get_headers(); bool only_x86 = true; for (size_t i=0; i<headers.size() && only_x86; ++i) only_x86 = 4==headers[i]->get_word_size(); if (only_x86) { ++ninterps; analyze_interp(interp); } } }
/** Returns true if basic block appears to be a function call. If the target address is known and is a single value then it is * stored in the @p target_va argument, otherwise we store the maximum 64-bit address. If the return address for the function * call is known then it is stored in the @p return_va argument, otherwise @p return_va will contain the maximum 64-bit * address. The return address is usually the fall-through address of the basic block. * * Note: Use this function in preference to SgAsmInstruction::is_function_call() because the latter is intended to be used by * the Partitioner before an AST is created and might not be as accurate. */ bool SgAsmBlock::is_function_call(rose_addr_t &target_va, rose_addr_t &return_va) { static const rose_addr_t INVALID_ADDR = (rose_addr_t)(-1); target_va = return_va = INVALID_ADDR;; if (!is_basic_block()) return false; std::vector<SgAsmInstruction*> insns = SageInterface::querySubTree<SgAsmInstruction>(this); assert(!insns.empty()); // basic blocks must have instructions // Check that all the successors point to functions entry addresses (other functions or this block's function). There // might be one edge that points to the fall-through address of this block, and that's ok. SgAsmFunction *func = SageInterface::getEnclosingNode<SgAsmFunction>(this); SgAsmInterpretation *interp = SageInterface::getEnclosingNode<SgAsmInterpretation>(func); std::set<rose_addr_t> callee_vas; if (interp) { const InstructionMap &imap = interp->get_instruction_map(); const SgAsmIntegerValuePtrList &successors = get_successors(); for (SgAsmIntegerValuePtrList::const_iterator si=successors.begin(); si!=successors.end(); ++si) { rose_addr_t successor_va = (*si)->get_absolute_value(); if (SgAsmInstruction *target_insn = imap.get_value_or(successor_va, NULL)) { SgAsmFunction *target_func = SageInterface::getEnclosingNode<SgAsmFunction>(target_insn); if (successor_va==target_func->get_entry_va()) { callee_vas.insert(successor_va); // branches to a function entry point } else if (return_va!=INVALID_ADDR) { target_va = return_va = INVALID_ADDR; return false; // multiple function-local CFG edges that are not this function's entry point } else { return_va = successor_va; // possible return address } } } } // Now for the architecture-dependent determination. This will not update target_va or return_va if they cannot be // determined or are ambiguous; so we must reset them to INVALID_ADDR if we're about to return false. bool retval = insns.front()->is_function_call(insns, &target_va, &return_va); if (!retval) { target_va = return_va = INVALID_ADDR; } else if (INVALID_ADDR==target_va && 1==callee_vas.size()) { target_va = *callee_vas.begin(); } return retval; }
/* class method */ SgAsmGenericFile* BinaryLoader::createAsmAST(SgBinaryComposite* binaryFile, std::string filePath) { ASSERT_forbid(filePath.empty()); SgAsmGenericFile* file = SgAsmExecutableFileFormat::parseBinaryFormat(filePath.c_str()); ASSERT_not_null(file); // TODO do I need to attach here - or can I do after return binaryFile->get_genericFileList()->get_files().push_back(file); file->set_parent(binaryFile->get_genericFileList()); /* Add a new interpretation to the SgBinaryComposite object for each header of the newly parsed * SgAsmGenericFile for which a suitable interpretation does not already exist. */ const SgAsmGenericHeaderPtrList &headers = file->get_headers()->get_headers(); SgAsmInterpretationPtrList &interps = binaryFile->get_interpretations()->get_interpretations(); for (size_t i = 0; i < headers.size(); ++i) { SgAsmGenericHeader* header = headers[i]; SgAsmInterpretation* interp = NULL; for (size_t j = 0; j < interps.size(); ++j) { ASSERT_forbid(interps[j]->get_headers()->get_headers().empty()); SgAsmGenericHeader* interpHeader = interps[j]->get_headers()->get_headers().front(); if (isHeaderSimilar(header, interpHeader)) { interp = interps[j]; break; } } if (!interp) { interp = new SgAsmInterpretation(); interps.push_back(interp); interp->set_parent(binaryFile->get_interpretations()); if (const RegisterDictionary *registers = RegisterDictionary::dictionary_for_isa(header->get_isa())) interp->set_registers(registers); } interp->get_headers()->get_headers().push_back(header); } #if USE_ROSE_DWARF_SUPPORT /* Parse Dwarf info and add it to the SgAsmGenericFile. */ readDwarf(file); #endif return file; }
void InterruptAnalysis::test(SgNode* fileA, SgNode* fileB) { RoseBin_Graph* graph=NULL; ROSE_ASSERT(isSgProject(fileA)); SgBinaryComposite* binary = isSgBinaryComposite(isSgProject(fileA)->get_fileList()[0]); SgAsmGenericFile* file = binary != NULL ? binary->get_binaryFile() : NULL; ROSE_ASSERT(file); // VirtualBinCFG::AuxiliaryInformation* info = new VirtualBinCFG::AuxiliaryInformation(file); // call graph analysis ******************************************************* bool dot=true; bool forward=true; bool edges=true; bool mergedEdges=true; bool interprocedural=false; string dfgFileName = "dfg.dot"; graph= new RoseBin_DotGraph(); if (dot==false) { dfgFileName = "dfg.gml"; graph= new RoseBin_GMLGraph(); } // GraphAlgorithms* algo = new GraphAlgorithms(info); SgAsmInterpretation* interp = SageInterface::getMainInterpretation(file); RoseBin_DataFlowAnalysis* dfanalysis = new RoseBin_DataFlowAnalysis(interp->get_global_block(), forward, new RoseObj(), g_algo); ROSE_ASSERT(dfanalysis); dfanalysis->init(interprocedural, edges); dfanalysis->run(graph, dfgFileName, mergedEdges); vector<SgGraphNode*> rootNodes; dfanalysis->getRootNodes(rootNodes); dfanalysis->init(); init(graph); dfanalysis->traverseGraph(rootNodes, this, interprocedural); }
int main(int argc, char** argv) { if (!containsArgument(argc, argv, "-checkAST") && !containsArgument(argc, argv, "-checkGraph") && !containsArgument(argc, argv, "-printTree") && !containsArgument(argc, argv, "-callgraph") && !containsArgument(argc, argv, "-cfa") && !containsArgument(argc, argv, "-dfa") ) {argc = 1;} if (argc < 2) { fprintf(stderr, "Usage: %s executableName [OPTIONS]\n", argv[0]); cout << "\nOPTIONS: " <<endl; cout << "-checkAST - run all checkers on binary AST. " << endl; cout << "-checkGraph - run all checkers on dataflow graph. " << endl; cout << "-printTree - create dot file of AST. " << endl; cout << "-callgraph - perform callgraph analysis and print callgraph.dot file. " << endl; cout << "-cfa - perform control flow analysis and print cfg.dot file. " << endl; cout << "-dfa - perform dataflow flow analysis and print dfg.dot file. " << endl; cout << "-inter - perform dataflow analysis interprocedurally (default intraprocedural). " << endl; cout << "-backward - perform backward analysis (default forward). " << endl; cout << "-gml - all graphs (except AST) are saved as gml files (default dot). " << endl; cout << "-mergeedges - aggregate edges between same nodes. " << endl; cout << "-noedges - do not print edges into dot or gml file (only nodes). " << endl; return 1; } string execName = argv[1]; lt_dlinit(); // this is our test case input, we will assert on the data from this file test = false; if (execName=="buffer2.bin") { //cerr << "running test case on buffer2.bin !! " << endl << endl; test = true; } // create out folder string filenameDir="out"; mode_t mode = S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH; mkdir(filenameDir.c_str(), mode); std::ofstream myfile; bool interprocedural = false; if (containsArgument(argc, argv, "-inter")) { interprocedural = true; } bool forward = true; if (containsArgument(argc, argv, "-backward")) { forward = false; } bool dot = true; if (containsArgument(argc, argv, "-gml")) { dot = false; } bool mergedEdges = false; if (containsArgument(argc, argv, "-mergeedges")) { mergedEdges = true; } bool edges = true; if (containsArgument(argc, argv, "-noedges")) { edges = false; } RoseBin_Def::RoseAssemblyLanguage = RoseBin_Def::x86; //fprintf(stderr, "Starting binCompass frontend...\n"); SgProject* project = frontend(argc,argv); ROSE_ASSERT (project != NULL); SgBinaryComposite* binary = isSgBinaryComposite(project->get_fileList()[0]); SgAsmGenericFile* file = binary != NULL ? binary->get_binaryFile() : NULL; // const SgAsmInterpretationPtrList& interps = file->get_interpretations(); //ROSE_ASSERT (interps.size() == 1); //SgAsmInterpretation* interp = interps[0]; SgAsmInterpretation* interp = SageInterface::getMainInterpretation(file); if (containsArgument(argc, argv, "-printTree")) { //fprintf(stderr, "Printing AST... _binary_tree.dot\n"); string filename="_binary_tree.dot"; AST_BIN_Traversal* trav = new AST_BIN_Traversal(); trav->run(interp->get_global_block(), filename); if (test) { int instrnr = trav->getNrOfInstructions(); //cerr << " Instructions written to file: " << instrnr << endl; ROSE_ASSERT(instrnr==861); } } RoseBin_Graph* graph; VirtualBinCFG::AuxiliaryInformation* info = new VirtualBinCFG::AuxiliaryInformation(file); std::map<int,std::set<SgAsmFunction*> > components; GraphAlgorithms* algo = new GraphAlgorithms(info); // call graph analysis ******************************************************* if (containsArgument(argc, argv, "-callgraph")) { //cerr << " creating call graph ... " << endl; graph= new RoseBin_DotGraph(); string callFileName = "callgraph.dot"; if (dot==false) { callFileName = "callgraph.gml"; graph= new RoseBin_GMLGraph(); } RoseBin_CallGraphAnalysis* callanalysis = new RoseBin_CallGraphAnalysis(interp->get_global_block(), new RoseObj(), algo); callanalysis->run(graph, callFileName, !mergedEdges); callanalysis->getConnectedComponents(components); if (test) { //cerr << " nr of nodes visited in callanalysis : " << callanalysis->nodesVisited() << endl; ROSE_ASSERT(callanalysis->nodesVisited()==10); //cerr << " nr of edges visited in callanalysis : " << callanalysis->edgesVisited() << endl; ROSE_ASSERT(callanalysis->edgesVisited()==9); } } if (containsArgument(argc, argv, "-printTree")) { //fprintf(stderr, "Printing AST... _binary_tree2.dot\n"); string filename="_binary_tree2.dot"; AST_BIN_Traversal* trav = new AST_BIN_Traversal(); trav->run(interp->get_global_block(), filename); if (test) { int instrnr = trav->getNrOfInstructions(); //cerr << " Instructions written to file: " << instrnr << endl; ROSE_ASSERT(instrnr==861); } } // control flow analysis ******************************************************* if (containsArgument(argc, argv, "-cfa")) { string cfgFileName = "cfg.dot"; graph= new RoseBin_DotGraph(); if (dot==false) { cfgFileName = "cfg.gml"; graph= new RoseBin_GMLGraph(); } RoseBin_ControlFlowAnalysis* cfganalysis = new RoseBin_ControlFlowAnalysis(interp->get_global_block(), forward, new RoseObj(), edges, algo); cfganalysis->run(graph, cfgFileName, mergedEdges); #if 1 std::map<int,std::set<SgAsmFunction*> >::const_iterator comps = components.begin(); //set<std::string> partialCFG; for (;comps!=components.end();++comps) { set<std::string> partialCFG; int nr = comps->first; //cerr << " found the following component " << nr << endl; std::set<SgAsmFunction*> funcs = comps->second; std::set<SgAsmFunction*>::const_iterator it = funcs.begin(); for (;it!=funcs.end();++it) { SgAsmFunction* function = *it; string name = function->get_name(); name.append("_f"); //cerr << " binCompass CALLGRAPH ANALYSIS : found function : " << name << endl; partialCFG.insert(name); } string filename = "thomas"; filename.append(RoseBin_support::ToString(nr)); filename.append(".dot"); //cerr << " binCompass writing to file " << filename << endl; cfganalysis->printGraph(filename,partialCFG); } //cfganalysis->printGraph(filename,partialCFG); #endif #if 0 set<std::string> partialCFG; partialCFG.insert(" 80483c0_f"); partialCFG.insert(" 8048491_f"); partialCFG.insert(" 8048363_f"); partialCFG.insert(" 804828f_f"); cfganalysis->printGraph("thomas.dot",partialCFG); #endif if (test) { //cout << " cfa -- Number of nodes == " << cfganalysis->nodesVisited() << endl; //cout << " cfa -- Number of edges == " << cfganalysis->edgesVisited() << endl; //ROSE_ASSERT(cfganalysis->nodesVisited()==210); //ROSE_ASSERT(cfganalysis->edgesVisited()==234); ROSE_ASSERT(cfganalysis->nodesVisited()==237); ROSE_ASSERT(cfganalysis->edgesVisited()==261); } } if (containsArgument(argc, argv, "-printTree")) { //fprintf(stderr, "Printing AST... _binary_tree3.dot\n"); string filename="_binary_tree3.dot"; AST_BIN_Traversal* trav = new AST_BIN_Traversal(); trav->run(interp->get_global_block(), filename); if (test) { int instrnr = trav->getNrOfInstructions(); //cerr << " Instructions written to file: " << instrnr << endl; ROSE_ASSERT(instrnr==861); } } if (containsArgument(argc, argv, "-dfa")) { //cerr << " creating dataflow graph ... " << endl; string dfgFileName = "dfg.dot"; graph= new RoseBin_DotGraph(); if (dot==false) { dfgFileName = "dfg.gml"; graph= new RoseBin_GMLGraph(); } RoseBin_DataFlowAnalysis* dfanalysis = new RoseBin_DataFlowAnalysis(interp->get_global_block(), forward, new RoseObj(), algo); dfanalysis->init(interprocedural, edges); dfanalysis->run(graph, dfgFileName, mergedEdges); if (test) { #if 0 cout << " dfa -- Number of nodes == " << dfanalysis->nodesVisited() << endl; cout << " dfa -- Number of edges == " << dfanalysis->edgesVisited() << endl; cout << " dfa -- Number of memWrites == " << dfanalysis->nrOfMemoryWrites() << endl; cout << " dfa -- Number of regWrites == " << dfanalysis->nrOfRegisterWrites() << endl; cout << " dfa -- Number of definitions == " << dfanalysis->nrOfDefinitions() << endl; cout << " dfa -- Number of uses == " << dfanalysis->nrOfUses() << endl; #endif if (interprocedural) { ROSE_ASSERT(dfanalysis->nodesVisited()==237); ROSE_ASSERT(dfanalysis->edgesVisited()==284); ROSE_ASSERT(dfanalysis->nrOfMemoryWrites()==12); ROSE_ASSERT(dfanalysis->nrOfRegisterWrites()==36); ROSE_ASSERT(dfanalysis->nrOfDefinitions()==183); ROSE_ASSERT(dfanalysis->nrOfUses()==25); } else { ROSE_ASSERT(dfanalysis->nodesVisited()==237); ROSE_ASSERT(dfanalysis->edgesVisited()==287); ROSE_ASSERT(dfanalysis->nrOfMemoryWrites()==18); ROSE_ASSERT(dfanalysis->nrOfRegisterWrites()==77); ROSE_ASSERT(dfanalysis->nrOfDefinitions()==216); ROSE_ASSERT(dfanalysis->nrOfUses()==31); } } } if (containsArgument(argc, argv, "-checkAST") || containsArgument(argc, argv, "-checkGraph")) { // get a list of all checkers and traverse vector <BC_AnalysisInterface*> checkers; vector <BC_GraphAnalysisInterface*> graph_checkers; loadAnalysisFiles(checkers); vector <BC_AnalysisInterface*>::const_iterator it = checkers.begin(); for (;it!=checkers.end();it++) { BC_AnalysisInterface* asmf = *it; //cout << "\nRunning Binary Checker --- " << asmf->get_name() << endl; string filename = execName+"."+asmf->get_name(); unsigned int pos = filename.find_last_of("/"); if (filename.find_last_of("/")!=string::npos && (pos+1)<filename.length()) filename = filename.substr(pos+1, filename.length()); filename = "out/"+filename+".out"; //cerr << "Writing file : " << filename << endl; myfile.open(filename.c_str()); asmf->init(interp->get_global_block()); asmf->traverse(interp->get_global_block(), preorder); asmf->finish(interp->get_global_block()); string output = asmf->get_output(); myfile << output << " \n"; myfile.close(); } if (containsArgument(argc, argv, "-checkGraph")) { loadGraphAnalysisFiles(graph_checkers); //cerr << "\n ---------------- preparing to run DataFlowAnalysis (-checkGraph)" << endl; string dfgFileName = "dfg.dot"; graph= new RoseBin_DotGraph(); if (dot==false) { dfgFileName = "dfg.gml"; graph= new RoseBin_GMLGraph(); } RoseBin_ControlFlowAnalysis* cfganalysis = new RoseBin_ControlFlowAnalysis(interp->get_global_block(), forward, new RoseObj(), edges, algo); cfganalysis->run(graph, dfgFileName, mergedEdges); if (test) { //cerr << " cfa -- Number of nodes == " << cfganalysis->nodesVisited() << endl; //cerr << " cfa -- Number of edges == " << cfganalysis->edgesVisited() << endl; ROSE_ASSERT(cfganalysis->nodesVisited()==237); ROSE_ASSERT(cfganalysis->edgesVisited()==261); } rose_graph_integer_node_hash_map nodes = graph->get_node_index_to_node_map(); //cerr << "CFG (-checkGraph) finished ----- Graph nr of nodes : " << nodes.size() << endl; ROSE_ASSERT(nodes.size()>0); RoseBin_DataFlowAnalysis* dfanalysis = new RoseBin_DataFlowAnalysis(interp->get_global_block(), forward, new RoseObj(), algo); //dfanalysis->init(interprocedural, edges,graph); dfanalysis->init(interprocedural, edges); dfanalysis->run(graph, dfgFileName, mergedEdges); //cerr << "DFG (-checkGraph) finished ----- Graph nr of nodes : " << nodes.size() << endl; vector<SgGraphNode*> rootNodes; dfanalysis->getRootNodes(rootNodes); //SgGraphNode* root1 = rootNodes[0]; //rootNodes.clear(); //rootNodes.push_back(root1); vector <BC_GraphAnalysisInterface*>::const_iterator it2 = graph_checkers.begin(); #if 0 cerr << "\n ---------------- running graph checkers : " << graph_checkers.size() << " rootNodes size : " << rootNodes.size() << " interprocedural : " << RoseBin_support::resBool(interprocedural) << endl; cout << "\n ---------------- running graph checkers : " << graph_checkers.size() << " rootNodes size : " << rootNodes.size() << " interprocedural : " << RoseBin_support::resBool(interprocedural) << endl; cerr << "Graph : " << nodes.size() << endl; #endif for (;it2!=graph_checkers.end();it2++) { BC_GraphAnalysisInterface* asmf = *it2; ROSE_ASSERT(asmf); //cerr << "\nRunning Binary Graph Checker --- " << asmf->get_name() << " " << " roots : " << // rootNodes.size() << endl; // tps 04/23/08 -- fixme: this code was broken when I added the testcase -- needs to be fixed dfanalysis->init(); asmf->init(graph); dfanalysis->traverseGraph(rootNodes, asmf, interprocedural); } } } unparseAsmStatementToFile("unparsed.s", interp->get_global_block()); lt_dlexit(); return 0; }
virtual void visit(SgNode* astNode) { // Note that the SgAsmInterpretation will be visited before the instructions (functions). SgAsmInterpretation* asmGlobalScope = isSgAsmInterpretation(astNode); if (asmGlobalScope != NULL) { globalScopeAnalysisAttribute = dynamic_cast<GlobalScopeAnalysisAttribute*>(asmGlobalScope->getAttribute("GlobalScopeAnalysisAttribute")); ROSE_ASSERT(globalScopeAnalysisAttribute != NULL); } // Handle functions as they are visited in the AST. // DQ (8/30/2013): This type was renamed and so the original function is not available (changed). // SgAsmFunctionDeclaration* asmFunction = isSgAsmFunctionDeclaration(astNode); SgAsmFunctionDeclaration* asmFunction = isSgAsmFunction(astNode); if (asmFunction != NULL) { // This was initalized from the traversal constructor. ROSE_ASSERT(project != NULL); // This was initalized from earlier in the traversal (preorder traversal is assumed). ROSE_ASSERT(globalScopeAnalysisAttribute != NULL); #if 0 string name = "function_" + StringUtility::numberToString(counter); #else string name = asmFunction->get_name(); if (name == "") { name = "unnamed_function_" + StringUtility::numberToString(counter); } #endif printf ("name = %s kind = %u \n",name.c_str(),asmFunction->get_function_kind()); // Add a collection of predefined comments for common functions addGenericCommentsAboutFunctions(asmFunction); if (globalScopeAnalysisAttribute->isVirtualMemberFunction(asmFunction) == true) { printf ("Found a virtual function = %p \n",(void*)asmFunction->get_address()); // Rename the function. name = "virtual_member_function_" + StringUtility::numberToString(counter); MemberFunctionAnalysisAttribute* functionAnalysisAttribute = new MemberFunctionAnalysisAttribute(name,asmFunction,project); ROSE_ASSERT(functionAnalysisAttribute != NULL); // Add it to the AST (so it can be found later in another pass over the AST) asmFunction->addNewAttribute("FunctionAnalysisAttribute",functionAnalysisAttribute); #if 0 printf ("Exiting as a test! \n"); ROSE_ASSERT(false); #endif } else { FunctionAnalysisAttribute* functionAnalysisAttribute = new FunctionAnalysisAttribute(name,asmFunction,project); ROSE_ASSERT(functionAnalysisAttribute != NULL); // Add it to the AST (so it can be found later in another pass over the AST) asmFunction->addNewAttribute("FunctionAnalysisAttribute",functionAnalysisAttribute); // Add the function to global scope globalScopeAnalysisAttribute->associatedDeclarationList.push_back(asmFunction); } counter++; } }
int main(int argc, char** argv) { SgProject* project = frontend(argc,argv); ROSE_ASSERT (project != NULL); RoseBin_Def::RoseAssemblyLanguage = RoseBin_Def::x86; #if 1 SgBinaryComposite* binary = isSgBinaryComposite(project->get_fileList()[0]); SgAsmGenericFile* file = binary != NULL ? binary->get_binaryFile() : NULL; ROSE_ASSERT (file != NULL); const SgAsmInterpretationPtrList& interps = binary->get_interpretations()->get_interpretations(); ROSE_ASSERT (!interps.empty()); SgAsmInterpretation* interp = interps.back(); SgAsmBlock* global_block = interp->get_global_block(); ROSE_ASSERT (global_block != NULL); // RoseBin_unparse* unparser = new RoseBin_unparse(); // RoseBin_support::setUnparseVisitor(unparser->getVisitor()); // Build the DOT file representing the AST (in color) cout << " writing _binary_tree ... " << endl; string filename="_binary_tree.dot"; AST_BIN_Traversal* trav = new AST_BIN_Traversal(); trav->run(global_block, filename); // control flow analysis ******************************************************* cout << " creating control flow graph ... " << endl; bool forward = true; bool edges = true; bool mergedEdges = false; VirtualBinCFG::AuxiliaryInformation* info = new VirtualBinCFG::AuxiliaryInformation(project); RoseBin_DotGraph* dotGraph = new RoseBin_DotGraph(); RoseBin_GMLGraph* gmlGraph = new RoseBin_GMLGraph(); const char* cfgFileName = "cfg.dot"; GraphAlgorithms* algo = new GraphAlgorithms(info); RoseBin_ControlFlowAnalysis* cfganalysis = new RoseBin_ControlFlowAnalysis(global_block, forward, new RoseObj(), edges, algo); cfganalysis->run(dotGraph, cfgFileName, mergedEdges); // call graph analysis ******************************************************* cout << " creating call graph ... " << endl; const char* callFileName = "callgraph.gml"; forward = true; RoseBin_CallGraphAnalysis* callanalysis = new RoseBin_CallGraphAnalysis(global_block, new RoseObj(), algo); // Building a GML file for the call graph callanalysis->run(gmlGraph, callFileName, !mergedEdges); // Building a DOT file for the call graph // callFileName = "callgraph.dot"; // callanalysis->run(dotGraph, callFileName); // dataflow analysis ******************************************************* cout << " creating dataflow graph ... " << endl; string dfgFileName = "dfg.dot"; forward = true; bool printEdges = true; bool interprocedural = true; RoseBin_DataFlowAnalysis* dfanalysis = new RoseBin_DataFlowAnalysis(global_block, forward, new RoseObj(), algo); dfanalysis->init(interprocedural, printEdges); // Building a DOT file for the data-flow graph dfanalysis->run(dotGraph, dfgFileName, mergedEdges); #endif // Unparse the output to test the unparser... return backend(project); }
void operator()() { // Database connections don't survive over fork() according to SqLite and PostgreSQL documentation, so open it again SqlDatabase::TransactionPtr tx = SqlDatabase::Connection::create(databaseUrl)->transaction(); // Use zero for the number of tests ran so that this child process doesn't try to update the semantic_history table. // If two or more processes try to change the same row (which they will if there's a non-zero number of tests) then // they will deadlock with each other. static const size_t NO_TESTS_RAN = 0; NameSet builtin_function_names; add_builtin_functions(builtin_function_names/*out*/); InputGroup igroup; WorkItem prevWorkItem; SgAsmInterpretation *prev_interp = NULL; MemoryMap ro_map; Disassembler::AddressSet whitelist_exports; // dynamic functions that should be called PointerDetectors pointers; InsnCoverage insn_coverage; DynamicCallGraph dynamic_cg; Tracer tracer; ConsumedInputs consumed_inputs; FuncAnalyses funcinfo; OutputGroups ogroups; // do not load from database (that might take a very long time) time_t last_checkpoint = time(NULL); for (size_t workIdx=0; workIdx<work.size(); ++workIdx) { WorkItem &workItem = work[workIdx]; // Load the input group from the database if necessary. if (workItem.igroup_id!=prevWorkItem.igroup_id) { if (!igroup.load(tx, workItem.igroup_id)) { std::cerr <<argv0 <<": input group " <<workItem.igroup_id <<" is empty or does not exist\n"; exit(1); } } // Find the function to test IdFunctionMap::iterator func_found = functions.find(workItem.func_id); assert(func_found!=functions.end()); SgAsmFunction *func = func_found->second; if (opt.verbosity>=LACONIC) { if (opt.verbosity>=EFFUSIVE) std::cerr <<argv0 <<": " <<std::string(100, '=') <<"\n"; std::cerr <<argv0 <<": processing function " <<function_to_str(func, function_ids) <<"\n"; } SgAsmInterpretation *interp = SageInterface::getEnclosingNode<SgAsmInterpretation>(func); assert(interp!=NULL); // Do per-interpretation stuff if (interp!=prev_interp) { prev_interp = interp; assert(interp->get_map()!=NULL); ro_map = *interp->get_map(); ro_map.require(MemoryMap::READABLE).prohibit(MemoryMap::WRITABLE).keep(); Disassembler::AddressSet whitelist_imports = get_import_addresses(interp, builtin_function_names); whitelist_exports.clear(); // imports are addresses of import table slots; exports are functions overmap_dynlink_addresses(interp, *insns, opt.params.follow_calls, &ro_map, GOTPLT_VALUE, whitelist_imports, whitelist_exports/*out*/); if (opt.verbosity>=EFFUSIVE) { std::cerr <<argv0 <<": memory map for SgAsmInterpretation:\n"; interp->get_map()->dump(std::cerr, argv0+": "); } } // Run the test assert(insns!=NULL); assert(entry2id!=NULL); std::cerr <<"process " <<getpid() <<" about to run test " <<workIdx <<"/" <<work.size() <<" " <<workItem <<"\n"; runOneTest(tx, workItem, pointers, func, function_ids, insn_coverage, dynamic_cg, tracer, consumed_inputs, interp, whitelist_exports, cmd_id, igroup, funcinfo, *insns, &ro_map, *entry2id, ogroups); ++ntests_ran; // Checkpoint if (opt.checkpoint>0 && time(NULL)-last_checkpoint > opt.checkpoint) { if (!opt.dry_run) tx = checkpoint(tx, ogroups, tracer, insn_coverage, dynamic_cg, consumed_inputs, NULL, NO_TESTS_RAN, cmd_id); last_checkpoint = time(NULL); } prevWorkItem = workItem; } std::cerr <<"process " <<getpid() <<" is done testing; now finishing up...\n"; if (!tx->is_terminated()) { SqlDatabase::StatementPtr stmt = tx->statement("insert into semantic_funcpartials" " (func_id, ncalls, nretused, ntests, nvoids) values" " (?, ?, ?, ?, ?)"); for (FuncAnalyses::iterator fi=funcinfo.begin(); fi!=funcinfo.end(); ++fi) { stmt->bind(0, fi->first); stmt->bind(1, fi->second.ncalls); stmt->bind(2, fi->second.nretused); stmt->bind(3, fi->second.ntests); stmt->bind(4, fi->second.nvoids); stmt->execute(); } } // Cleanup if (!tx->is_terminated() && !opt.dry_run) { std::cerr <<"process " <<getpid() <<" is doing the final checkpoint\n"; checkpoint(tx, ogroups, tracer, insn_coverage, dynamic_cg, consumed_inputs, NULL, NO_TESTS_RAN, cmd_id); } tx.reset(); std::cerr <<"process " <<getpid() <<" finished\n"; }
int main(int argc, char *argv[]) { SgProject *project = frontend(argc, argv); SgAsmInterpretation *interp = SageInterface::querySubTree<SgAsmInterpretation>(project).back(); AllInstructions insns(interp); SgAsmGenericHeader *header = interp->get_headers()->get_headers().front(); rose_addr_t start_va = header->get_base_va() + header->get_entry_rva(); #if SEMANTIC_API == OLD_API MyPolicy operators; X86InstructionSemantics<MyPolicy, MyValueType> dispatcher(operators); #else BaseSemantics::RiscOperatorsPtr operators = make_ops(); BaseSemantics::DispatcherPtr dispatcher = DispatcherX86::instance(operators); #endif struct sigaction sa; sa.sa_handler = alarm_handler; sigemptyset(&sa.sa_mask); sa.sa_flags = 0; sigaction(SIGALRM, &sa, NULL); alarm(timeout); struct timeval start_time; std::cout <<"test starting...\n"; gettimeofday(&start_time, NULL); size_t ninsns = 0; while (!had_alarm) { rose_addr_t va = start_va; while (SgAsmInstruction *insn = insns.fetch(va)) { //std::cerr <<unparseInstructionWithAddress(insn) <<"\n"; #if SEMANTIC_API == OLD_API dispatcher.processInstruction(isSgAsmx86Instruction(insn)); ++ninsns; #if SEMANTIC_DOMAIN == MULTI_DOMAIN // multi-semantics ValueType has no is_known() or get_known(). We need to invoke it on a specific subpolicy. PartialSymbolicSemantics::ValueType<32> ip = operators.readRegister<32>("eip") .get_subvalue(MyMultiSemanticsClass::SP0()); #else MyValueType<32> ip = operators.readRegister<32>("eip"); #endif if (!ip.is_known()) break; va = ip.known_value(); #else dispatcher->processInstruction(insn); ++ninsns; BaseSemantics::SValuePtr ip = operators->readRegister(dispatcher->findRegister("eip")); if (!ip->is_number()) break; va = ip->get_number(); #endif if (had_alarm) break; } } #if SEMANTIC_API == OLD_API MyValueType<32> eax = operators.readRegister<32>("eax"); std::cerr <<"eax = " <<eax <<"\n"; #else BaseSemantics::SValuePtr eax = operators->readRegister(dispatcher->findRegister("eax")); #if SEMANTIC_DOMAIN == MULTI_DOMAIN // This is entirely optional, but the output looks better if it has the names of the subdomains. std::cerr <<"eax = " <<(*eax + MultiSemantics::RiscOperators::promote(operators)->get_formatter()) <<"\n"; #else std::cerr <<"eax = " <<*eax <<"\n"; #endif #endif struct timeval stop_time; gettimeofday(&stop_time, NULL); double elapsed = ((double)stop_time.tv_sec-start_time.tv_sec) + 1e-6*((double)stop_time.tv_usec-start_time.tv_usec); if (elapsed < timeout/4.0) std::cout <<"warning: test did not run for a sufficiently long time; output may contain a high degree of error.\n"; std::cout <<"number of instructions: " <<ninsns <<"\n" <<"elapsed time: " <<elapsed <<" seconds\n" <<"semantic execution rate: " <<(ninsns/elapsed) <<" instructions/second\n"; return 0; }
void InterruptAnalysis::run(SgNode* fileA, SgNode* fileB) { BinQGUI *instance = QROSE::cbData<BinQGUI *>(); if (isSgProject(fileA)==NULL) { cerr << "This is not a valid file for this analysis!" << endl; QString res = QString("This is not a valid file for this analysis"); instance->analysisResult->append(res); return; } RoseBin_Graph* graph=NULL; ROSE_ASSERT(isSgProject(fileA)); SgBinaryComposite* binary = isSgBinaryComposite(isSgProject(fileA)->get_fileList()[0]); SgAsmGenericFile* file = binary != NULL ? binary->get_binaryFile() : NULL; ROSE_ASSERT(file); // VirtualBinCFG::AuxiliaryInformation* info = new VirtualBinCFG::AuxiliaryInformation(file); // call graph analysis ******************************************************* instance->analysisTab->setCurrentIndex(1); ROSE_ASSERT(instance->analysisTab); instance->analysisTab->setCurrentIndex(1); QString res = QString("Creating dataflow graph "); instance->analysisResult->append(res); bool dot=true; bool forward=true; bool edges=true; bool mergedEdges=true; bool interprocedural=false; string dfgFileName = "dfg.dot"; graph= new RoseBin_DotGraph(); if (dot==false) { dfgFileName = "dfg.gml"; graph= new RoseBin_GMLGraph(); } // GraphAlgorithms* algo = new GraphAlgorithms(info); SgAsmInterpretation* interp = SageInterface::getMainInterpretation(file); RoseBin_DataFlowAnalysis* dfanalysis = new RoseBin_DataFlowAnalysis(interp->get_global_block(), forward, new RoseObj(), g_algo); ROSE_ASSERT(dfanalysis); dfanalysis->init(interprocedural, edges); dfanalysis->run(graph, dfgFileName, mergedEdges); res = QString("nr of nodes visited %1. nr of edges visited %2. ") .arg(dfanalysis->nodesVisited()) .arg(dfanalysis->edgesVisited()); instance->analysisResult->append(res); res = QString("Running InterruptAnalysis detection... "); instance->analysisResult->append(res); vector<SgGraphNode*> rootNodes; dfanalysis->getRootNodes(rootNodes); res = QString("Graph has Rootnodes : %1 ") .arg(rootNodes.size()); instance->analysisResult->append(res); dfanalysis->init(); res = QString("Initializing ... "); instance->analysisResult->append(res); init(graph); res = QString("Traversing ... "); instance->analysisResult->append(res); dfanalysis->traverseGraph(rootNodes, this, interprocedural); res = QString("Done. "); instance->analysisResult->append(res); }
// see base class bool SgAsmX86Instruction::isFunctionCallSlow(const std::vector<SgAsmInstruction*>& insns, rose_addr_t *target, rose_addr_t *return_va) { if (isFunctionCallFast(insns, target, return_va)) return true; // The following stuff works only if we have a relatively complete AST. static const size_t EXECUTION_LIMIT = 10; // max size of basic blocks for expensive analyses if (insns.empty()) return false; SgAsmX86Instruction *last = isSgAsmX86Instruction(insns.back()); if (!last) return false; SgAsmFunction *func = SageInterface::getEnclosingNode<SgAsmFunction>(last); SgAsmInterpretation *interp = SageInterface::getEnclosingNode<SgAsmInterpretation>(func); // Slow method: Emulate the instructions and then look at the EIP and stack. If the EIP points outside the current // function and the top of the stack holds an address of an instruction within the current function, then this must be a // function call. if (interp && insns.size()<=EXECUTION_LIMIT) { using namespace Rose::BinaryAnalysis; using namespace Rose::BinaryAnalysis::InstructionSemantics2; using namespace Rose::BinaryAnalysis::InstructionSemantics2::SymbolicSemantics; const InstructionMap &imap = interp->get_instruction_map(); const RegisterDictionary *regdict = RegisterDictionary::dictionary_for_isa(interp); SmtSolverPtr solver = SmtSolver::instance(Rose::CommandLine::genericSwitchArgs.smtSolver); BaseSemantics::RiscOperatorsPtr ops = RiscOperators::instance(regdict, solver); ASSERT_not_null(ops); const RegisterDescriptor SP = regdict->findLargestRegister(x86_regclass_gpr, x86_gpr_sp); DispatcherX86Ptr dispatcher = DispatcherX86::instance(ops, SP.get_nbits()); SValuePtr orig_esp = SValue::promote(ops->readRegister(dispatcher->REG_anySP)); try { for (size_t i=0; i<insns.size(); ++i) dispatcher->processInstruction(insns[i]); } catch (const BaseSemantics::Exception &e) { return false; } // If the next instruction address is concrete but does not point to a function entry point, then this is not a call. SValuePtr eip = SValue::promote(ops->readRegister(dispatcher->REG_anyIP)); if (eip->is_number()) { rose_addr_t target_va = eip->get_number(); SgAsmFunction *target_func = SageInterface::getEnclosingNode<SgAsmFunction>(imap.get_value_or(target_va, NULL)); if (!target_func || target_va!=target_func->get_entry_va()) return false; } // If nothing was pushed onto the stack, then this isn't a function call. const size_t spWidth = dispatcher->REG_anySP.get_nbits(); SValuePtr esp = SValue::promote(ops->readRegister(dispatcher->REG_anySP)); SValuePtr stack_delta = SValue::promote(ops->add(esp, ops->negate(orig_esp))); SValuePtr stack_delta_sign = SValue::promote(ops->extract(stack_delta, spWidth-1, spWidth)); if (stack_delta_sign->is_number() && 0==stack_delta_sign->get_number()) return false; // If the top of the stack does not contain a concrete value or the top of the stack does not point to an instruction // in this basic block's function, then this is not a function call. const size_t ipWidth = dispatcher->REG_anyIP.get_nbits(); SValuePtr top = SValue::promote(ops->readMemory(dispatcher->REG_SS, esp, esp->undefined_(ipWidth), esp->boolean_(true))); if (top->is_number()) { rose_addr_t va = top->get_number(); SgAsmFunction *return_func = SageInterface::getEnclosingNode<SgAsmFunction>(imap.get_value_or(va, NULL)); if (!return_func || return_func!=func) { return false; } } else { return false; } // Since EIP might point to a function entry address and since the top of the stack contains a pointer to an // instruction in this function, we assume that this is a function call. if (target && eip->is_number()) *target = eip->get_number(); if (return_va && top->is_number()) *return_va = top->get_number(); return true; } // Similar to the above method, but works when all we have is the basic block (e.g., this case gets hit quite a bit from // the Partitioner). Returns true if, after executing the basic block, the top of the stack contains the fall-through // address of the basic block. We depend on our caller to figure out if EIP is reasonably a function entry address. if (!interp && insns.size()<=EXECUTION_LIMIT) { using namespace Rose::BinaryAnalysis; using namespace Rose::BinaryAnalysis::InstructionSemantics2; using namespace Rose::BinaryAnalysis::InstructionSemantics2::SymbolicSemantics; SmtSolverPtr solver = SmtSolver::instance(Rose::CommandLine::genericSwitchArgs.smtSolver); SgAsmX86Instruction *x86insn = isSgAsmX86Instruction(insns.front()); ASSERT_not_null(x86insn); #if 1 // [Robb P. Matzke 2015-03-03]: FIXME[Robb P. Matzke 2015-03-03]: not ready yet; x86-64 semantics still under construction if (x86insn->get_addressSize() != x86_insnsize_32) return false; #endif const RegisterDictionary *regdict = registersForInstructionSize(x86insn->get_addressSize()); const RegisterDescriptor SP = regdict->findLargestRegister(x86_regclass_gpr, x86_gpr_sp); BaseSemantics::RiscOperatorsPtr ops = RiscOperators::instance(regdict, solver); DispatcherX86Ptr dispatcher = DispatcherX86::instance(ops, SP.get_nbits()); try { for (size_t i=0; i<insns.size(); ++i) dispatcher->processInstruction(insns[i]); } catch (const BaseSemantics::Exception &e) { return false; } // Look at the top of the stack const size_t ipWidth = dispatcher->REG_anyIP.get_nbits(); SValuePtr top = SValue::promote(ops->readMemory(dispatcher->REG_SS, ops->readRegister(SP), ops->protoval()->undefined_(ipWidth), ops->protoval()->boolean_(true))); if (top->is_number() && top->get_number() == last->get_address()+last->get_size()) { if (target) { SValuePtr eip = SValue::promote(ops->readRegister(dispatcher->REG_anyIP)); if (eip->is_number()) *target = eip->get_number(); } if (return_va) *return_va = top->get_number(); return true; } } return false; }
// see base class; don't modify target_va or return_va if they are not known bool SgAsmM68kInstruction::isFunctionCallSlow(const std::vector<SgAsmInstruction*>& insns, rose_addr_t *target_va, rose_addr_t *return_va) { if (isFunctionCallFast(insns, target_va, return_va)) return true; static const size_t EXECUTION_LIMIT = 25; // max size of basic blocks for expensive analyses if (insns.empty()) return false; SgAsmM68kInstruction *last = isSgAsmM68kInstruction(insns.back()); if (!last) return false; SgAsmFunction *func = SageInterface::getEnclosingNode<SgAsmFunction>(last); SgAsmInterpretation *interp = SageInterface::getEnclosingNode<SgAsmInterpretation>(func); // Slow method: Emulate the instructions and then look at the program counter (PC) and stack (A7). If the PC points // outside the current function and the top of the stack holds an address of an instruction within the current function, // then this must be a function call. if (interp && insns.size()<=EXECUTION_LIMIT) { using namespace Rose::BinaryAnalysis; using namespace Rose::BinaryAnalysis::InstructionSemantics2; using namespace Rose::BinaryAnalysis::InstructionSemantics2::SymbolicSemantics; const InstructionMap &imap = interp->get_instruction_map(); const RegisterDictionary *regdict = RegisterDictionary::dictionary_for_isa(interp); SmtSolverPtr solver = SmtSolver::instance(Rose::CommandLine::genericSwitchArgs.smtSolver); BaseSemantics::RiscOperatorsPtr ops = RiscOperators::instance(regdict, solver); DispatcherM68kPtr dispatcher = DispatcherM68k::instance(ops, 32); SValuePtr orig_sp = SValue::promote(ops->readRegister(dispatcher->REG_A[7])); try { for (size_t i=0; i<insns.size(); ++i) dispatcher->processInstruction(insns[i]); } catch (const BaseSemantics::Exception &e) { return false; } // If the next instruction address is concrete but does not point to a function entry point, then this is not a call. SValuePtr ip = SValue::promote(ops->readRegister(dispatcher->REG_PC)); if (ip->is_number()) { rose_addr_t target_va = ip->get_number(); SgAsmFunction *target_func = SageInterface::getEnclosingNode<SgAsmFunction>(imap.get_value_or(target_va, NULL)); if (!target_func || target_va!=target_func->get_entry_va()) return false; } // If nothing was pushed onto the stack, then this isn't a function call. SValuePtr sp = SValue::promote(ops->readRegister(dispatcher->REG_A[7])); SValuePtr stack_delta = SValue::promote(ops->add(sp, ops->negate(orig_sp))); SValuePtr stack_delta_sign = SValue::promote(ops->extract(stack_delta, 31, 32)); if (stack_delta_sign->is_number() && 0==stack_delta_sign->get_number()) return false; // If the top of the stack does not contain a concrete value or the top of the stack does not point to an instruction // in this basic block's function, then this is not a function call. SValuePtr top = SValue::promote(ops->readMemory(RegisterDescriptor(), sp, sp->undefined_(32), sp->boolean_(true))); if (top->is_number()) { rose_addr_t va = top->get_number(); SgAsmFunction *return_func = SageInterface::getEnclosingNode<SgAsmFunction>(imap.get_value_or(va, NULL)); if (!return_func || return_func!=func) { return false; } } else { return false; } // Since the instruction pointer might point to a function entry address and since the top of the stack contains a // pointer to an instruction in this function, we assume that this is a function call. if (target_va && ip->is_number()) *target_va = ip->get_number(); if (return_va && top->is_number()) *return_va = top->get_number(); return true; } // Similar to the above method, but works when all we have is the basic block (e.g., this case gets hit quite a bit from // the Partitioner). Returns true if, after executing the basic block, the top of the stack contains the fall-through // address of the basic block. We depend on our caller to figure out if the instruction pointer is reasonably a function // entry address. if (!interp && insns.size()<=EXECUTION_LIMIT) { using namespace Rose::BinaryAnalysis; using namespace Rose::BinaryAnalysis::InstructionSemantics2; using namespace Rose::BinaryAnalysis::InstructionSemantics2::SymbolicSemantics; const RegisterDictionary *regdict = RegisterDictionary::dictionary_coldfire_emac(); SmtSolverPtr solver = SmtSolver::instance(Rose::CommandLine::genericSwitchArgs.smtSolver); BaseSemantics::RiscOperatorsPtr ops = RiscOperators::instance(regdict, solver); DispatcherM68kPtr dispatcher = DispatcherM68k::instance(ops, 32); try { for (size_t i=0; i<insns.size(); ++i) dispatcher->processInstruction(insns[i]); } catch (const BaseSemantics::Exception &e) { return false; } // Look at the top of the stack SValuePtr top = SValue::promote(ops->readMemory(RegisterDescriptor(), ops->readRegister(dispatcher->REG_A[7]), ops->protoval()->undefined_(32), ops->protoval()->boolean_(true))); if (top->is_number() && top->get_number() == last->get_address()+last->get_size()) { if (target_va) { SValuePtr ip = SValue::promote(ops->readRegister(dispatcher->REG_PC)); if (ip->is_number()) *target_va = ip->get_number(); } if (return_va) *return_va = top->get_number(); return true; } } return false; }