/****************************************************
 * traverse the binary AST
 ****************************************************/
void
RoseBin_FlowAnalysis::visit(SgNode* node) {

  //  cerr << " traversing node " << node->class_name() << endl;

  if (isSgAsmFunction(node) ) {
    SgAsmFunction* binDecl = isSgAsmFunction(node);
    string name = binDecl->get_name();
    ostringstream addrhex;
    addrhex << hex << setw(8) << binDecl->get_address() ;
    if (name=="") {
      name=addrhex.str();
      binDecl->set_name(name);
    }
    SgAsmStatement* stat = NULL;
    //    SgAsmStatementPtrList& list = binDecl->get_statementList();

    vector<SgAsmInstruction*> list;
    FindInstructionsVisitor vis;
    AstQueryNamespace::querySubTree(binDecl, std::bind2nd( vis, &list ));

    int sizeList = list.size();
    if (sizeList==0) {
      //cerr << " this function is empty!! " << endl;
      return;
    }

    //if ((func_nr % 1)==0)
    //  if (RoseBin_support::DEBUG_MODE())
    //    cout  << analysisName << " Func Nr: " << (++func_nr) << "  blocks:" <<
    //     sizeList << "  ***************** checking function : " << name << endl;

    if (forward_analysis) {
      stat = list.front();
    } else {
      // get the last instruction in a function (backward control flow)
      stat = list.back();
    }
    ROSE_ASSERT(stat);

    //   if (RoseBin_support::DEBUG_MODE())
    //cout << ">>>>>>>>>>>>>. checking statement in function : " << name << " .. " << stat->class_name() << endl;
    if (isSgAsmInstruction(stat)) {
      SgAsmInstruction* inst = isSgAsmInstruction(stat);
      ROSE_ASSERT(inst);
      // check the control flow of the first instruction in a function
      string typeFunction ="function";
      SgGraphNode* src=NULL;
      if (analysisName=="callgraph") {
        //      src = vizzGraph->createNode (name, typeFunction, binDecl->get_address(), vizzGraph->graph->get_graph_id(), false, binDecl);
        src = addCFNode (name, typeFunction, binDecl->get_address(), false, binDecl);
      } else {
        //src = vizzGraph->createNode (name, typeFunction, binDecl->get_address(), vizzGraph->graph->get_graph_id(), true, binDecl);
        //cerr << ">> adding node (f) src: " << RoseBin_support::HexToString(binDecl->get_address()) << endl;
        src = addCFNode (name, typeFunction, binDecl->get_address(), true, binDecl);
        string mnemonic=inst->get_mnemonic();
        //SgGraphNode* trg = vizzGraph->createNode (mnemonic, typeNode, inst->get_address(), vizzGraph->graph->get_graph_id(),false, inst);
        //cerr << ">> adding node (first) trg: " << RoseBin_support::HexToString(inst->get_address()) << endl;
        SgGraphNode* trg = addCFNode (mnemonic, typeNode, inst->get_address(), false, inst);
        string unp_name = unparseInstructionWithAddress(inst);
        trg->append_properties(SgGraph::name,unp_name);
        if (analysisName=="dfa")
          trg->append_properties(SgGraph::dfa_standard,unp_name);
        //cerr << "Create edge " << endl;
        //      SgDirectedGraphEdge* edge = vizzGraph->createEdge ( typeFunction, vizzGraph->graph->get_graph_id(), src, binDecl->get_address(), trg, inst->get_address());
        SgDirectedGraphEdge* edge = vizzGraph->addDirectedEdge ( src, trg, typeFunction);
        vizzGraph->setProperty(SgGraph::type, edge, RoseBin_support::ToString(SgGraph::cfg));
      }

      local_visited.clear();
      worklist_forthisfunction.push(inst);

      funcDecl = binDecl;
      funcDeclNode = src;
      checkControlFlow(inst, sizeList, sizeList, name, func_nr);
    } else {
    if (RoseBin_support::DEBUG_MODE())
      cerr << "This is not an Instruction " << endl;
    }
  }
}
/****************************************************
 * process all functions in the DB
 ****************************************************/
void RoseBin_DB_IDAPRO::process_functions_query(MYSQL* conn, MYSQL_RES* res_set,
                                                SgAsmBlock* globalBlock,
                                                list<string> functionFilter) {
  // get the functions
  rememberFunctions.clear();
  //int counter=0;

  char* q = (char*)"SELECT * FROM functions_1 order by address";
  if (RoseBin_support::DEBUG_MODE())
    cout << "\n>> QUERY:: " << q << "\n" << endl;
  res_set = process_query(conn,q);
  if (res_set == NULL) {
    print_problemWithResults(conn);
  } else {
    
    MYSQL_ROW row;
    long address=0;
    string name = (char*)"";
    int type=-1;
    string name_md5 =(char*)"";

    while ((row = mysql_fetch_row(res_set))!=NULL) {
      for (unsigned int i=0; i<mysql_num_fields(res_set);i++) {
        char* ret=(char*)"";
        if (row[i] ==NULL) {
          ret = (char*)"<NULL>";
          if (i==0) address = -1;
          if (i==1) name = ret;
          if (i==2) type= -1;
          if (i==3) name_md5= ret;
        } else {
          ret= row[i];
          if (i==0) address = atoi(ret);
          if (i==1) name = ret;
          if (i==2) type= atoi(ret);
          if (i==3) name_md5= ret;
        }
      }

      // demangling *****************************************************
      // we need to demangle this function name, so
      // we can correspond it with the source name
      char *newName;// = new char[size*2];
      int status;
      size_t length;
      newName = abi::__cxa_demangle(name.c_str(), 0, 
                                    &length,&status);

      //      cerr << "converting name : " << name <<  "   status: " << status <<endl;

      if (status==0) {
        name =(char*)"";
        bool found_bracket=false;
        for (unsigned int i=0; i<length;i++) {
          if (newName[i]=='(')
            found_bracket=true;
          if (found_bracket==false)
            name += newName[i];
        }
        if (RoseBin_support::DEBUG_MODE())
          cout << " demangling name to " << name << endl;
      }
      name = getName(name);
      RoseBin_support::checkText(name);
      //cerr << " checking for function : " << name << endl;

      // demangling *****************************************************

      // filter : we filter away all kind of functions that are not
      // relevant == slicing of binaries, relevant = source AST functions
      // if (functionFilter.size()>0) {
      // list<string>::iterator filterMe = functionFilter.begin();
      // bool skip=true;
      if (!functionFilter.empty() && std::find(functionFilter.begin(), functionFilter.end(), name) == functionFilter.end()) {
        continue;
      }
#if 0
      for (filterMe;filterMe!=functionFilter.end();++filterMe) {
        string name_list = *filterMe;
        //          cerr << " comparing strings : " << name_list << " and " << name << endl;
        if (name_list==name) {
          
          //  if (name.find(name_list)!=string::npos)
          skip=false;
        }
      }
      if (skip)
        continue;
#endif
      // }
      //make sure we dont get too many nodes, so the visualization works for testing
      // find me : counter
      //counter++;
      //if (counter>50)
      //        break;
      // --------------------------------------------------------------------------
      if (RoseBin_support::DEBUG_MODE()) {
        ostringstream addrhex;
        addrhex << hex << setw(8) << address ;
        cout << ">> creating function : " << address << " " << addrhex.str() << " - " << name << " - " << type << endl;
      }
      SgAsmFunction* fd = new SgAsmFunction();
      fd->set_address(address);
      fd->set_name(name);
      globalBlock->append_statement(fd);
      fd->set_parent(globalBlock);

      // added a block between function and instruction to conform to jeremiahs code
      //SgAsmBlock* block = new SgAsmBlock();
      //fd->append_statement(block);
      //block->set_parent(fd);

      rememberFunctions[address]= fd ;
    } // while
  } // if (res_set==NULL)
  checkError(conn,res_set);
}
SgAsmInstruction*
RoseBin_FlowAnalysis::process_jumps_get_target(SgAsmx86Instruction* inst) {
  if (inst && x86InstructionIsControlTransfer(inst)) {
    //cerr << " ..................... processing jmp " << endl;
    ostringstream addrhex3;
    int addrsource = inst->get_address();
    addrhex3 << hex << setw(8) << addrsource ;
    string funcName ="";

    // get the operand and the destination address
    SgAsmOperandList* opList = inst->get_operandList();
    ROSE_ASSERT(opList);
    SgAsmExpressionPtrList ptrList = opList->get_operands();

    std::vector<SgAsmExpression*>::iterator itList= ptrList.begin();
    for (;itList!=ptrList.end();++itList) {
      SgAsmExpression* exp = *itList;
      ROSE_ASSERT(exp);
      SgAsmRegisterReferenceExpression* regRef = isSgAsmRegisterReferenceExpression(exp);

      //if (RoseBin_support::DEBUG_MODE())
      //        cout << " inst (jmp):: " << inst->get_mnemonic() << "  addr : " << addrhex3.str() << endl;
      SgAsmValueExpression* valExpr = isSgAsmValueExpression(exp);
      SgAsmMemoryReferenceExpression* memExpr = isSgAsmMemoryReferenceExpression(exp);
      string valStr = "";
      if (valExpr) {
        uint8_t byte_val=0xF;
        uint16_t word_val=0xFF;
        uint32_t double_word_val=0xFFFF;
        uint64_t quad_word_val=0xFFFFFFFFU;

        valStr =
          RoseBin_support::resolveValue(valExpr, true,
                                        byte_val,
                                        word_val,
                                        double_word_val,
                                        quad_word_val);

        //if (RoseBin_support::DEBUG_MODE())
        //cout << "   found value ....... :: " << valStr << endl;
        funcName = valExpr->get_replacement();
        //if (funcName=="")
        //  funcName="noName";
      }
      if (memExpr) {
        continue;
        // this is a jump to data ... do not handle right now!!
      }

      // convert val string to long
      uint64_t val=0;
      if(from_string<uint64_t>(val, valStr, std::hex)) {
        ostringstream addrhex2;
        addrhex2 << hex << setw(8) << val ;
        //if (RoseBin_support::DEBUG_MODE())
        //cerr << "    looking for value ("<<valStr << " ) in InstrSet: "
        //     << val << "  " << addrhex2.str() << endl;
        rose_hash::unordered_map <uint64_t, SgAsmInstruction* >::const_iterator itc =
          rememberInstructions.find(val);
        if (itc!=rememberInstructions.end()) {
          SgAsmInstruction* target = itc->second;

          // we set the target (jump to for each control instruction)
          ROSE_ASSERT(target);


          //if (RoseBin_support::DEBUG_MODE())
          //cout << "    >>> target found! " << target << "     funcName " << funcName << endl;
          if (funcName!="") {
            SgAsmNode* block = target;
            if (!db)
              block = isSgAsmNode(target->get_parent());
            ROSE_ASSERT(block);
            SgAsmFunction* func = isSgAsmFunction(block->get_parent());

            if (func) {
              string fname = func->get_name();
              uint64_t val_f=0;
              if(from_string<uint64_t>(val_f, fname, std::hex)) {
                // func name is a hex number
                func->set_name(funcName);
                //              inst->set_comment(funcName);
              } else {
                // its a name
              }
            }
          }
          return target;
        } else {
          //if (RoseBin_support::DEBUG_MODE())
          //  cerr << "    >>>>>>>>>>>>>>> !!! OPS :: Target not found ...  \n" << endl;
        }
      }
      else{
        //      std::cerr << "FlowAnalysis ::  from_string failed .. " << std::endl;
        if (valStr!="")
          if (RoseBin_support::DEBUG_MODE())
          cerr << " WARNING: Cant convert string to long - in process_jump  :: " << regRef->class_name() <<
            " inst :: " << inst->get_mnemonic() << "  addr : " << addrhex3.str() << " target : " << valStr << endl;
      }
    }

  }
  return NULL;
}