Example #1
0
File: BinQMain.C Project: 8l/rose
// 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());
    }
}
Example #2
0
	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;



	}
Example #3
0
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);  
  }  
}
Example #4
0
 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);
         }
     }
 }
Example #5
0
/** 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;
}
Example #6
0
/* 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;
}
Example #7
0
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);



}
Example #8
0
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);
   }
Example #11
0
    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";
    }
Example #12
0
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;
}
Example #13
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;
}