void IntraAnalysisResultsToDotFiles::runAnalysis() { set<FunctionState*> allFuncs = FunctionState::getAllDefinedFuncs(); // Go through functions one by one, call an intra-procedural analysis on each of them // iterate over all functions with bodies for(set<FunctionState*>::iterator it=allFuncs.begin(); it!=allFuncs.end(); it++) { FunctionState* fState = *it; // compose the output file name as filename_mangled_function_name.dot Function *func = & (fState->getFunc()); assert (func != NULL); SgFunctionDefinition* proc = func->get_definition(); string file_name = StringUtility::stripPathFromFileName(proc->get_file_info()->get_filename()); string file_func_name= file_name+ "_"+proc->get_mangled_name().getString(); string full_output = file_func_name +"_cfg.dot"; std::ofstream ostr(full_output.c_str()); ostr << "digraph " << "mygraph" << " {\n"; analysisStatesToDOT* dot_analysis = dynamic_cast <analysisStatesToDOT*> ( intraAnalysis); assert (dot_analysis != NULL); dot_analysis->ostr = &ostr; dot_analysis->runAnalysis(fState->func, &(fState->state)); ostr << "}\n"; } }
bool gmCodeGenPrivate::GenStmtForEach(const gmCodeTreeNode * a_node, gmByteCodeGen * a_byteCode) { unsigned int breakAddress, continueAddress, loc1, loc2; // Generate table if(!Generate(a_node->m_children[0], a_byteCode)) { return false; } PushLoop(); // Push the first iterator a_byteCode->Emit(BC_PUSHINT, (gmuint32) -2); // first iterator value. continueAddress = a_byteCode->Tell(); // Generate call const char * keyVar = s_tempVarName1; if(a_node->m_children[2]) keyVar = a_node->m_children[2]->m_data.m_string; const char * valueVar = a_node->m_children[1]->m_data.m_string; gmuint16 keyOffset = (gmuint16) m_currentFunction->SetVariableType(keyVar, CTVT_LOCAL); gmuint16 valueOffset = (gmuint16) m_currentFunction->SetVariableType(valueVar, CTVT_LOCAL); gmuint32 opcode = (keyOffset << 16) | (valueOffset & 0xffff); loc1 = a_byteCode->Tell(); a_byteCode->Emit(BC_FOREACH, opcode); // Skip space for jump loc2 = a_byteCode->Skip(SIZEOF_BC_BRA); // Generate body if(!Generate(a_node->m_children[3], a_byteCode)) { PopLoop(); return false; } a_byteCode->EmitPtr(BC_BRA, (gmuint32) loc1); breakAddress = a_byteCode->Seek(loc2); a_byteCode->EmitPtr(BC_BRZ, breakAddress); a_byteCode->Seek(breakAddress); // pop table and iterator a_byteCode->Emit(BC_POP2); ApplyPatches(m_loopStack[m_currentLoop].m_breaks, a_byteCode, breakAddress); ApplyPatches(m_loopStack[m_currentLoop].m_continues, a_byteCode, continueAddress); PopLoop(); return true; }
bool gmCodeGenPrivate::GenStmtFork(const gmCodeTreeNode * a_node, gmByteCodeGen * a_byteCode) { GM_ASSERT(a_node->m_type == CTNT_STATEMENT && a_node->m_subType == CTNST_FORK ); gmuint32 loc1,loc2; // create the var for the thread id const char * valname = 0; gmuint32 valref = 0; if ( a_node->m_children[1]) { valname = a_node->m_children[1]->m_data.m_string; valref = m_currentFunction->SetVariableType( valname, CTVT_LOCAL ); } loc1 = a_byteCode->Skip( SIZEOF_BC_BRA ); if (!valname) a_byteCode->Emit( BC_POP ); // if not specified then just pop else a_byteCode->Emit( BC_SETLOCAL, valref ); // store the thread id if (!Generate(a_node->m_children[0], a_byteCode )) return false; a_byteCode->Emit( BC_RET ); loc2 = a_byteCode->Seek( loc1 ); a_byteCode->Emit( BC_FORK, loc2 ); a_byteCode->Seek( loc2 ); if (!valname) a_byteCode->Emit( BC_POP ); // if not specified then just pop else a_byteCode->Emit( BC_SETLOCAL, valref ); // store the thread id return true; }
bool gmCodeGenPrivate::GenDeclVariable(const gmCodeTreeNode * a_node, gmByteCodeGen * a_byteCode) { GM_ASSERT(a_node->m_type == CTNT_DECLARATION && a_node->m_subType == CTNDT_VARIABLE); GM_ASSERT(m_currentFunction); m_currentFunction->SetVariableType(a_node->m_children[0]->m_data.m_string, (gmCodeTreeVariableType) a_node->m_subTypeType); return true; }
gmCodeGenPrivate::FunctionState * gmCodeGenPrivate::PopFunction() { if(m_currentFunction) { m_currentFunction->Reset(); m_currentFunction = m_functionStack.GetPrev(m_currentFunction); if(!m_functionStack.IsValid(m_currentFunction)) { m_currentFunction = NULL; } } return m_currentFunction; }
void InterpreterThread::setState(ByteInputStream& stream) { functionStackLimit = stream.getUInt32(); uint64_t stackSize = stream.getUInt64(); for (std::uint64_t i = 0; i < stackSize; i++) { FunctionState functionState; functionState.setState(stream); } uint64_t instructionStackSize = stream.getUInt64(); instructionStack_.resize(instructionStackSize); for (uint64_t i = 0; i < instructionStackSize; i++) { instructionStack_.at(i).setThread(*this); instructionStack_.at(i).setState(stream, env_); } uint64_t numberOfHeaps = stream.getUInt64(); for (uint64_t i = 0; i < numberOfHeaps; i++) { std::string moduleName = stream.getString(); Heap& heap = heapsByModuleName_[moduleName] = Heap(); heap.setState(stream); } }
gmCodeGenPrivate::FunctionState * gmCodeGenPrivate::PushFunction() { if(m_currentFunction) { if(m_currentFunction != m_functionStack.GetLast()) { m_currentFunction = m_functionStack.GetNext(m_currentFunction); } else { m_currentFunction = GM_NEW( FunctionState() ); m_functionStack.InsertLast(m_currentFunction); } } else { if(m_functionStack.IsEmpty()) { m_currentFunction = GM_NEW( FunctionState() ); m_functionStack.InsertLast(m_currentFunction); } else { m_currentFunction = m_functionStack.GetFirst(); } } m_currentFunction->Reset(); m_currentFunction->m_byteCode.SetSwapEndianOnWrite(m_hooks->SwapEndian()); // if we are debugging, set up some line number debugging. if(m_debug) { m_currentFunction->m_byteCode.m_emitCallback = gmLineNumberCallback; } return m_currentFunction; }
bool gmCodeGenPrivate::GenExprIdentifier(const gmCodeTreeNode * a_node, gmByteCodeGen * a_byteCode) { GM_ASSERT(a_node->m_type == CTNT_EXPRESSION && a_node->m_subType == CTNET_IDENTIFIER); // if local, get local regardless // if member, get this // if global, get global // get global if((a_node->m_flags & gmCodeTreeNode::CTN_MEMBER) > 0) { return a_byteCode->EmitPtr(BC_GETTHIS, m_hooks->GetSymbolId(a_node->m_data.m_string)); } gmCodeTreeVariableType type; int offset = m_currentFunction->GetVariableOffset(a_node->m_data.m_string, type); if(offset >= 0 && type == CTVT_LOCAL) { return a_byteCode->Emit(BC_GETLOCAL, (gmuint32) offset); } else if(offset != -2) { if(type == CTVT_MEMBER) { return a_byteCode->EmitPtr(BC_GETTHIS, m_hooks->GetSymbolId(a_node->m_data.m_string)); } else if(type == CTVT_GLOBAL) { return a_byteCode->EmitPtr(BC_GETGLOBAL, m_hooks->GetSymbolId(a_node->m_data.m_string)); } if(m_log) m_log->LogEntry("internal error"); return false; } return a_byteCode->EmitPtr(BC_GETGLOBAL, m_hooks->GetSymbolId(a_node->m_data.m_string)); }
bool gmCodeGenPrivate::GenExprFunction(const gmCodeTreeNode * a_node, gmByteCodeGen * a_byteCode) { GM_ASSERT(a_node->m_type == CTNT_EXPRESSION && a_node->m_subType == CTNET_FUNCTION); gmptr id = m_hooks->GetFunctionId(); a_byteCode->EmitPtr(BC_PUSHFN, id); // Create the function PushFunction(); // Get a debug function name as the name of the variable the function is assigned to if(m_debug && a_node->m_parent && a_node->m_parent->m_type == CTNT_EXPRESSION && a_node->m_parent->m_subType == CTNET_OPERATION && (a_node->m_parent->m_subTypeType == CTNOT_ASSIGN || a_node->m_parent->m_subTypeType == CTNOT_ASSIGN_FIELD) && a_node->m_parent->m_children[1] == a_node) { const gmCodeTreeNode * debugName = a_node->m_parent->m_children[0]; if(debugName && debugName->m_type == CTNT_EXPRESSION && debugName->m_subType == CTNET_IDENTIFIER) { } else if(debugName->m_type == CTNT_EXPRESSION && debugName->m_subType == CTNET_OPERATION && debugName->m_subTypeType == CTNOT_DOT) { debugName = debugName->m_children[1]; } else { debugName = NULL; } if(debugName) { GM_ASSERT(debugName->m_type == CTNT_EXPRESSION && debugName->m_subType == CTNET_IDENTIFIER); m_currentFunction->m_debugName = debugName->m_data.m_string; } } // Parameters const gmCodeTreeNode * params = a_node->m_children[0]; int numParams = 0; while(params) { const gmCodeTreeNode * param = params->m_children[0]; GM_ASSERT(param->m_type == CTNT_EXPRESSION && param->m_subType == CTNET_IDENTIFIER); if(m_currentFunction->SetVariableType(param->m_data.m_string, CTVT_LOCAL) != numParams) { if(m_log) m_log->LogEntry("error (%d) parameter %s already declared", param->m_lineNumber, param->m_data.m_string); PopFunction(); return false; } ++numParams; params = params->m_sibling; } // Generate the code bool res = Generate(a_node->m_children[1], &m_currentFunction->m_byteCode); // Generate a return incase the function didnt have one. m_currentFunction->m_byteCode.Emit(BC_RET); if(res) { // Create a locals table const char ** locals = NULL; if(m_debug) { locals = (const char **) alloca(sizeof(const char *) * m_currentFunction->m_numLocals); memset(locals, 0, sizeof(const char *) * m_currentFunction->m_numLocals); for(gmuint v = 0; v < m_currentFunction->m_variables.Count(); ++v) { Variable &variable = m_currentFunction->m_variables[v]; if(variable.m_offset != -1) { locals[variable.m_offset] = variable.m_symbol; } } } // Add the function to the hooks. gmSortDebugLines(m_currentFunction->m_lineInfo); gmFunctionInfo info; info.m_id = id; info.m_root = false; info.m_byteCode = m_currentFunction->m_byteCode.GetData(); info.m_byteCodeLength = m_currentFunction->m_byteCode.Tell(); info.m_numParams = numParams; info.m_numLocals = m_currentFunction->m_numLocals - numParams; info.m_symbols = locals; info.m_maxStackSize = m_currentFunction->m_byteCode.GetMaxTos(); info.m_lineInfoCount = m_currentFunction->m_lineInfo.Count(); info.m_lineInfo = m_currentFunction->m_lineInfo.GetData(); info.m_debugName = m_currentFunction->m_debugName; m_hooks->AddFunction(info); //gmByteCodePrint(stdout, info.m_byteCode, info.m_byteCodeLength); } PopFunction(); return res; }
bool gmCodeGenPrivate::GenExprCall(const gmCodeTreeNode * a_node, gmByteCodeGen * a_byteCode) { GM_ASSERT(a_node->m_type == CTNT_EXPRESSION && a_node->m_subType == CTNET_CALL); // mark the stack. int stackLevel = a_byteCode->GetTos(); // if callee is a dot function, push left side of dot as 'this' const gmCodeTreeNode * callee = a_node->m_children[0]; if(callee->m_type == CTNT_EXPRESSION && callee->m_subType == CTNET_OPERATION && callee->m_subTypeType == CTNOT_DOT) { if(!Generate(callee->m_children[0], a_byteCode)) return false; a_byteCode->Emit(BC_DUP); a_byteCode->EmitPtr(BC_GETDOT, m_hooks->GetSymbolId(callee->m_children[1]->m_data.m_string)); } else { if(a_node->m_children[2]) { if(!Generate(a_node->m_children[2], a_byteCode)) return false; } else { #if GM_COMPILE_PASS_THIS_ALWAYS a_byteCode->Emit(BC_PUSHTHIS); #else // !GM_COMPILE_PASS_THIS_ALWAYS // if the lvalue is a member, pass 'this', otherwise pass 'null' bool pushed = false; if(callee->m_type == CTNT_EXPRESSION && callee->m_subType == CTNET_IDENTIFIER) { gmCodeTreeVariableType vtype; int offset = m_currentFunction->GetVariableOffset(callee->m_data.m_string, vtype); if(((callee->m_flags & gmCodeTreeNode::CTN_MEMBER) > 0) || (offset == -1 && vtype == CTVT_MEMBER)) { a_byteCode->Emit(BC_PUSHTHIS); pushed = true; } } if(!pushed) { a_byteCode->Emit(BC_PUSHNULL); } #endif // !GM_COMPILE_PASS_THIS_ALWAYS } if(!Generate(callee, a_byteCode)) return false; } // push parameters, count the number of parameters gmuint32 numParams = 0; const gmCodeTreeNode * params = a_node->m_children[1]; while(params) { ++numParams; if(!Generate(params, a_byteCode, false)) return false; params = params->m_sibling; } // call a_byteCode->Emit(BC_CALL, (gmuint32) numParams); // restore the stack level. a_byteCode->SetTos(stackLevel + 1); return true; }
bool gmCodeGenPrivate::GenExprOpAssign(const gmCodeTreeNode * a_node, gmByteCodeGen * a_byteCode) { GM_ASSERT(a_node->m_type == CTNT_EXPRESSION && a_node->m_subType == CTNET_OPERATION); // value on left hand side must be an l-value... ie, a dot, array or identifier. const gmCodeTreeNode * lValue = a_node->m_children[0]; int type = 0; if(lValue->m_type == CTNT_EXPRESSION && lValue->m_subType == CTNET_OPERATION && lValue->m_subTypeType == CTNOT_DOT) { // Generate half l-value if(!Generate(lValue->m_children[0], a_byteCode)) return false; type = 0; } else if(lValue->m_type == CTNT_EXPRESSION && lValue->m_subType == CTNET_OPERATION && lValue->m_subTypeType == CTNOT_ARRAY_INDEX) { // Generate half l-value if(!Generate(lValue->m_children[0], a_byteCode)) return false; if(!Generate(lValue->m_children[1], a_byteCode)) return false; type = 1; } else if(lValue->m_type == CTNT_EXPRESSION && lValue->m_subType == CTNET_IDENTIFIER) { type = 2; } else { if(m_log) m_log->LogEntry("error (%d) illegal l-value for '=' operator", a_node->m_lineNumber); return false; } // Generate r-value if(!Generate(a_node->m_children[1], a_byteCode)) return false; // complete assignment if(type == 0) { a_byteCode->EmitPtr(BC_SETDOT, m_hooks->GetSymbolId(lValue->m_children[1]->m_data.m_string)); } else if(type == 1) { a_byteCode->Emit(BC_SETIND); } else if(type == 2) { gmCodeTreeVariableType vtype; int offset = m_currentFunction->GetVariableOffset(lValue->m_data.m_string, vtype); // if local, set local regardless // if member set this // if global, set global // set and add local if((lValue->m_flags & gmCodeTreeNode::CTN_MEMBER) > 0) { return a_byteCode->EmitPtr(BC_SETTHIS, m_hooks->GetSymbolId(lValue->m_data.m_string)); } if(offset >= 0 && vtype == CTVT_LOCAL) { return a_byteCode->Emit(BC_SETLOCAL, (gmuint32) offset); } else if(offset == -1) { if(vtype == CTVT_MEMBER) { return a_byteCode->EmitPtr(BC_SETTHIS, m_hooks->GetSymbolId(lValue->m_data.m_string)); } else if(vtype == CTVT_GLOBAL) { return a_byteCode->EmitPtr(BC_SETGLOBAL, m_hooks->GetSymbolId(lValue->m_data.m_string)); } if(m_log) m_log->LogEntry("internal error"); return false; } offset = m_currentFunction->SetVariableType(lValue->m_data.m_string, CTVT_LOCAL); return a_byteCode->Emit(BC_SETLOCAL, (gmuint32) offset); } else { // paranoia if(m_log) m_log->LogEntry("internal error"); return false; } return true; }
bool gmCodeGenPrivate::GenExprOpPreIncDec(const gmCodeTreeNode * a_node, gmByteCodeGen * a_byteCode) { GM_ASSERT(a_node->m_type == CTNT_EXPRESSION && a_node->m_subType == CTNET_OPERATION); // Make sure child 0 is an l-value const gmCodeTreeNode * lValue = a_node->m_children[0]; int type = 0; if(lValue->m_type == CTNT_EXPRESSION && lValue->m_subType == CTNET_OPERATION && lValue->m_subTypeType == CTNOT_DOT) { // Generate half l-value if(!Generate(lValue->m_children[0], a_byteCode)) return false; a_byteCode->Emit(BC_DUP); a_byteCode->EmitPtr(BC_GETDOT, m_hooks->GetSymbolId(lValue->m_children[1]->m_data.m_string)); type = 0; } else if(lValue->m_type == CTNT_EXPRESSION && lValue->m_subType == CTNET_OPERATION && lValue->m_subTypeType == CTNOT_ARRAY_INDEX) { // Generate half l-value if(!Generate(lValue->m_children[0], a_byteCode)) return false; if(!Generate(lValue->m_children[1], a_byteCode)) return false; a_byteCode->Emit(BC_DUP2); a_byteCode->Emit(BC_GETIND); type = 1; } else if(lValue->m_type == CTNT_EXPRESSION && lValue->m_subType == CTNET_IDENTIFIER) { if(!Generate(lValue, a_byteCode)) return false; type = 2; } else { if(m_log) m_log->LogEntry("illegal l-value for '++/--' operator, line %d", a_node->m_lineNumber); return false; } // Perform inc/dec switch(a_node->m_subTypeType) { case CTNOT_PRE_INC : a_byteCode->Emit(BC_OP_INC); break; case CTNOT_PRE_DEC : a_byteCode->Emit(BC_OP_DEC); break; default : { if(m_log) m_log->LogEntry("unkown operator"); return false; } } // Write back the value if(type == 0) { int offset = m_currentFunction->SetVariableType(s_tempVarName0, CTVT_LOCAL); a_byteCode->Emit(BC_DUP); a_byteCode->Emit(BC_SETLOCAL, (gmuint32) offset); a_byteCode->EmitPtr(BC_SETDOT, m_hooks->GetSymbolId(lValue->m_children[1]->m_data.m_string)); a_byteCode->Emit(BC_GETLOCAL, (gmuint32) offset); } else if(type == 1) { int offset = m_currentFunction->SetVariableType(s_tempVarName0, CTVT_LOCAL); a_byteCode->Emit(BC_DUP); a_byteCode->Emit(BC_SETLOCAL, (gmuint32) offset); a_byteCode->Emit(BC_SETIND); a_byteCode->Emit(BC_GETLOCAL, (gmuint32) offset); } else if(type == 2) { a_byteCode->Emit(BC_DUP); gmCodeTreeVariableType vtype; int offset = m_currentFunction->GetVariableOffset(lValue->m_data.m_string, vtype); // if local, set local regardless // if member set this // if global, set global // set and add local if((lValue->m_flags & gmCodeTreeNode::CTN_MEMBER) > 0) { return a_byteCode->EmitPtr(BC_SETTHIS, m_hooks->GetSymbolId(lValue->m_data.m_string)); } if(offset >= 0 && vtype == CTVT_LOCAL) { return a_byteCode->Emit(BC_SETLOCAL, (gmuint32) offset); } else if(offset == -1) { if(vtype == CTVT_MEMBER) { return a_byteCode->EmitPtr(BC_SETTHIS, m_hooks->GetSymbolId(lValue->m_data.m_string)); } else if(vtype == CTVT_GLOBAL) { return a_byteCode->EmitPtr(BC_SETGLOBAL, m_hooks->GetSymbolId(lValue->m_data.m_string)); } if(m_log) m_log->LogEntry("internal error"); return false; } offset = m_currentFunction->SetVariableType(lValue->m_data.m_string, CTVT_LOCAL); return a_byteCode->Emit(BC_SETLOCAL, (gmuint32) offset); } else { // paranoia if(m_log) m_log->LogEntry("internal error"); return false; } return true; }
void printComparable(llvm::raw_ostream &Out, FunctionState const &State) { Out << " Function [Index=" << State.getIndex() << "]\n"; Out << " Allocas:\n"; for (auto const &Alloca : State.getAllocas()) { Out << " " << Alloca.getInstructionIndex() << " =[" << Alloca.getElementCount() << "x" << Alloca.getElementSize() << "]\n"; } Out << " Instruction values [Active="; if (State.getActiveInstructionIndex().assigned(0)) Out << State.getActiveInstructionIndex().get<0>(); else Out << "unassigned"; Out << "]:\n"; auto const InstructionCount = State.getInstructionCount(); for (std::size_t i = 0; i < InstructionCount; ++i) { auto const Instruction = State.getInstruction(i); auto const Type = Instruction->getType(); if (llvm::isa<llvm::IntegerType>(Type)) { auto const UValue = State.getValueUInt64(Instruction); if (UValue.assigned<uint64_t>()) { auto const SValue = State.getValueInt64(Instruction); assert(SValue.assigned<int64_t>()); Out << " " << i << " = (int64_t)" << SValue.get< int64_t>() << ", (uint64_t)" << UValue.get<uint64_t>() << "\n"; } } else if (Type->isPointerTy()) { auto const Value = State.getValuePtr(Instruction); if (Value.assigned<stateptr_ty>()) { Out << " " << i << " = \n"; // TODO: a comparable pointer representation (this requires us to // determine the allocation that a pointer references, and then // display the pointer value relative to that allocation). } } else if (Type->isFloatTy()) { auto const Value = State.getValueFloat(Instruction); if (Value.assigned<float>()) { Out << " " << i << " = (float)" << Value.get<float>() << "\n"; } } else if (Type->isDoubleTy()) { auto const Value = State.getValueDouble(Instruction); if (Value.assigned<double>()) { Out << " " << i << " = (double)" << Value.get<double>() << "\n"; } } else if (Type->isX86_FP80Ty() || Type->isFP128Ty() || Type->isPPC_FP128Ty()) { auto const Value = State.getValueAPFloat(Instruction); if (Value.assigned<llvm::APFloat>()) { llvm::SmallString<32> Buffer; Value.get<llvm::APFloat>().toString(Buffer); Out << " " << i << " = (long double)" << Buffer << "\n"; } } } }