// accessors bool lookup(const std::string& name, Symbol& symbol) const { auto it = symbols.find(name); if (it == symbols.end()) { if (outer) { return outer->lookup(name, symbol); } else { return false; } } else { symbol = it->second; return true; } }
static void set(SymMap &symbols, const llvm::BasicBlock::iterator &it, Val v) { if (VERBOSITY() >= 2) { printf("Setting to %lx / %f: ", v.n, v.d); fflush(stdout); it->dump(); } SymMap::iterator f = symbols.find(it); if (f != symbols.end()) f->second = v; else symbols.insert(std::make_pair(static_cast<llvm::Value*>(&(*it)), v)); //#define SET(v) symbols.insert(std::make_pair(static_cast<llvm::Value*>(&(*it)), Val(v))) }
void init_symbol_map() { map.clear(); // On Windows, you cannot lookup these symbols ... <_< struct mapper { const char* sym; retro_proc_address_t proc; }; #define _D(sym) { #sym, reinterpret_cast<retro_proc_address_t>(sym) } static const mapper bind_map[] = { _D(glEnable), _D(glDisable), _D(glBlendFunc), _D(glClearColor), _D(glTexImage2D), _D(glViewport), _D(glClear), _D(glTexParameteri), _D(glDeleteTextures), _D(glGenTextures), _D(glBindTexture), _D(glDrawArrays), _D(glGetError), _D(glFrontFace), #if defined(__APPLE__) && !defined(IOS) _D(glActiveTexture), _D(glCreateProgram), _D(glCreateShader), _D(glShaderSource), _D(glCompileShader), _D(glGetShaderiv), _D(glAttachShader), _D(glLinkProgram), _D(glGetProgramiv), _D(glGenerateMipmap), _D(glGetIntegerv), _D(glGenBuffers), _D(glBindBuffer), _D(glBufferData), _D(glBindFramebuffer), _D(glUseProgram), _D(glUniform1i), _D(glGetUniformLocation), _D(glUniformMatrix4fv), _D(glUniform3fv), _D(glUniform1f), _D(glGetAttribLocation), _D(glEnableVertexAttribArray), _D(glVertexAttribPointer), _D(glDisableVertexAttribArray), #endif }; #undef _D for (unsigned i = 0; i < sizeof(bind_map) / sizeof(bind_map[0]); i++) map[bind_map[i].sym] = bind_map[i].proc; }
void StreamChecker::checkEndPath(CheckerContext &Ctx) const { const ProgramState *state = Ctx.getState(); typedef llvm::ImmutableMap<SymbolRef, StreamState> SymMap; SymMap M = state->get<StreamState>(); for (SymMap::iterator I = M.begin(), E = M.end(); I != E; ++I) { StreamState SS = I->second; if (SS.isOpened()) { ExplodedNode *N = Ctx.addTransition(state); if (N) { if (!BT_ResourceLeak) BT_ResourceLeak.reset(new BuiltinBug("Resource Leak", "Opened File never closed. Potential Resource leak.")); BugReport *R = new BugReport(*BT_ResourceLeak, BT_ResourceLeak->getDescription(), N); Ctx.EmitReport(R); } } } }
void StreamChecker::checkEndPath(EndOfFunctionNodeBuilder &B, ExprEngine &Eng) const { const GRState *state = B.getState(); typedef llvm::ImmutableMap<SymbolRef, StreamState> SymMap; SymMap M = state->get<StreamState>(); for (SymMap::iterator I = M.begin(), E = M.end(); I != E; ++I) { StreamState SS = I->second; if (SS.isOpened()) { ExplodedNode *N = B.generateNode(state); if (N) { if (!BT_ResourceLeak) BT_ResourceLeak.reset(new BuiltinBug("Resource Leak", "Opened File never closed. Potential Resource leak.")); BugReport *R = new BugReport(*BT_ResourceLeak, BT_ResourceLeak->getDescription(), N); Eng.getBugReporter().EmitReport(R); } } } }
Box* interpretFunction(llvm::Function *f, int nargs, Box* arg1, Box* arg2, Box* arg3, Box* *args) { assert(f); #ifdef TIME_INTERPRETS Timer _t("to interpret", 1000000); long this_us = 0; #endif static StatCounter interpreted_runs("interpreted_runs"); interpreted_runs.log(); llvm::DataLayout dl(f->getParent()); //f->dump(); //assert(nargs == f->getArgumentList().size()); SymMap symbols; void* frame_ptr = __builtin_frame_address(0); interpreter_roots[frame_ptr] = &symbols; UnregisterHelper helper(frame_ptr); int arg_num = -1; for (llvm::Argument& arg : f->args()) { arg_num++; if (arg_num == 0) symbols.insert(std::make_pair(static_cast<llvm::Value*>(&arg), Val(arg1))); else if (arg_num == 1) symbols.insert(std::make_pair(static_cast<llvm::Value*>(&arg), Val(arg2))); else if (arg_num == 2) symbols.insert(std::make_pair(static_cast<llvm::Value*>(&arg), Val(arg3))); else { assert(arg_num == 3); assert(f->getArgumentList().size() == 4); assert(f->getArgumentList().back().getType() == g.llvm_value_type_ptr->getPointerTo()); symbols.insert(std::make_pair(static_cast<llvm::Value*>(&arg), Val((int64_t)args))); //printf("loading %%4 with %p\n", (void*)args); break; } } llvm::BasicBlock *prevblock = NULL; llvm::BasicBlock *curblock = &f->getEntryBlock(); while (true) { for (llvm::Instruction &_inst : *curblock) { llvm::Instruction *inst = &_inst; if (VERBOSITY("interpreter") >= 2) { printf("executing in %s: ", f->getName().data()); fflush(stdout); inst->dump(); //f->dump(); } #define SET(v) set(symbols, inst, (v)) if (llvm::LoadInst *li = llvm::dyn_cast<llvm::LoadInst>(inst)) { llvm::Value *ptr = li->getOperand(0); Val v = fetch(ptr, dl, symbols); //printf("loading from %p\n", v.o); if (width(li, dl) == 1) { Val r = Val(*(bool*)v.o); SET(r); continue; } else if (width(li, dl) == 8) { Val r = Val(*(int64_t*)v.o); SET(r); continue; } else { li->dump(); RELEASE_ASSERT(0, ""); } } else if (llvm::StoreInst *si = llvm::dyn_cast<llvm::StoreInst>(inst)) { llvm::Value *val = si->getOperand(0); llvm::Value *ptr = si->getOperand(1); Val v = fetch(val, dl, symbols); Val p = fetch(ptr, dl, symbols); //printf("storing %lx at %lx\n", v.n, p.n); if (width(val, dl) == 1) { *(bool*)p.o = v.b; continue; } else if (width(val, dl) == 8) { *(int64_t*)p.o = v.n; continue; } else { si->dump(); RELEASE_ASSERT(0, ""); } } else if (llvm::CmpInst *ci = llvm::dyn_cast<llvm::CmpInst>(inst)) { assert(ci->getType() == g.i1); Val a0 = fetch(ci->getOperand(0), dl, symbols); Val a1 = fetch(ci->getOperand(1), dl, symbols); llvm::CmpInst::Predicate pred = ci->getPredicate(); switch (pred) { case llvm::CmpInst::ICMP_EQ: SET(a0.n == a1.n); continue; case llvm::CmpInst::ICMP_NE: SET(a0.n != a1.n); continue; case llvm::CmpInst::ICMP_SLT: SET(a0.n < a1.n); continue; case llvm::CmpInst::ICMP_SLE: SET(a0.n <= a1.n); continue; case llvm::CmpInst::ICMP_SGT: SET(a0.n > a1.n); continue; case llvm::CmpInst::ICMP_SGE: SET(a0.n >= a1.n); continue; case llvm::CmpInst::FCMP_OEQ: SET(a0.d == a1.d); continue; case llvm::CmpInst::FCMP_UNE: SET(a0.d != a1.d); continue; case llvm::CmpInst::FCMP_OLT: SET(a0.d < a1.d); continue; case llvm::CmpInst::FCMP_OLE: SET(a0.d <= a1.d); continue; case llvm::CmpInst::FCMP_OGT: SET(a0.d > a1.d); continue; case llvm::CmpInst::FCMP_OGE: SET(a0.d >= a1.d); continue; default: ci->dump(); RELEASE_ASSERT(0, ""); } continue; } else if (llvm::BinaryOperator *bo = llvm::dyn_cast<llvm::BinaryOperator>(inst)) { if (bo->getOperand(0)->getType() == g.i64 || bo->getOperand(0)->getType() == g.i1) { //assert(bo->getOperand(0)->getType() == g.i64); //assert(bo->getOperand(1)->getType() == g.i64); Val a0 = fetch(bo->getOperand(0), dl, symbols); Val a1 = fetch(bo->getOperand(1), dl, symbols); llvm::Instruction::BinaryOps opcode = bo->getOpcode(); switch (opcode) { case llvm::Instruction::Add: SET(a0.n + a1.n); continue; case llvm::Instruction::And: SET(a0.n & a1.n); continue; case llvm::Instruction::AShr: SET(a0.n >> a1.n); continue; case llvm::Instruction::Mul: SET(a0.n * a1.n); continue; case llvm::Instruction::Or: SET(a0.n | a1.n); continue; case llvm::Instruction::Shl: SET(a0.n << a1.n); continue; case llvm::Instruction::Sub: SET(a0.n - a1.n); continue; case llvm::Instruction::Xor: SET(a0.n ^ a1.n); continue; default: bo->dump(); RELEASE_ASSERT(0, ""); } continue; } else if (bo->getOperand(0)->getType() == g.double_) { //assert(bo->getOperand(0)->getType() == g.i64); //assert(bo->getOperand(1)->getType() == g.i64); double lhs = fetch(bo->getOperand(0), dl, symbols).d; double rhs = fetch(bo->getOperand(1), dl, symbols).d; llvm::Instruction::BinaryOps opcode = bo->getOpcode(); switch (opcode) { case llvm::Instruction::FAdd: SET(lhs + rhs); continue; case llvm::Instruction::FMul: SET(lhs * rhs); continue; case llvm::Instruction::FSub: SET(lhs - rhs); continue; default: bo->dump(); RELEASE_ASSERT(0, ""); } continue; } else { bo->dump(); RELEASE_ASSERT(0, ""); } } else if (llvm::GetElementPtrInst *gep = llvm::dyn_cast<llvm::GetElementPtrInst>(inst)) {
// mutators bool insert(const Symbol& symbol) { auto result = symbols.insert(SymMap::value_type(symbol.get_name(), symbol)); return result.second; }
Box* interpretFunction(llvm::Function* f, int nargs, Box* closure, Box* generator, Box* arg1, Box* arg2, Box* arg3, Box** args) { assert(f); #ifdef TIME_INTERPRETS Timer _t("to interpret", 1000000); long this_us = 0; #endif static StatCounter interpreted_runs("interpreted_runs"); interpreted_runs.log(); llvm::DataLayout dl(f->getParent()); // f->dump(); // assert(nargs == f->getArgumentList().size()); SymMap symbols; void* frame_ptr = __builtin_frame_address(0); root_stack_set.get()->push_back(&symbols); UnregisterHelper helper(frame_ptr); int arg_num = -1; int closure_indicator = closure ? 1 : 0; int generator_indicator = generator ? 1 : 0; int arg_offset = closure_indicator + generator_indicator; for (llvm::Argument& arg : f->args()) { arg_num++; if (arg_num == 0 && closure) symbols.insert(std::make_pair(static_cast<llvm::Value*>(&arg), Val(closure))); else if ((arg_num == 0 || (arg_num == 1 && closure)) && generator) symbols.insert(std::make_pair(static_cast<llvm::Value*>(&arg), Val(generator))); else if (arg_num == 0 + arg_offset) symbols.insert(std::make_pair(static_cast<llvm::Value*>(&arg), Val(arg1))); else if (arg_num == 1 + arg_offset) symbols.insert(std::make_pair(static_cast<llvm::Value*>(&arg), Val(arg2))); else if (arg_num == 2 + arg_offset) symbols.insert(std::make_pair(static_cast<llvm::Value*>(&arg), Val(arg3))); else { assert(arg_num == 3 + arg_offset); assert(f->getArgumentList().size() == 4 + arg_offset); assert(f->getArgumentList().back().getType() == g.llvm_value_type_ptr->getPointerTo()); symbols.insert(std::make_pair(static_cast<llvm::Value*>(&arg), Val((int64_t)args))); // printf("loading %%4 with %p\n", (void*)args); break; } } llvm::BasicBlock* prevblock = NULL; llvm::BasicBlock* curblock = &f->getEntryBlock(); // The symbol table at the end of the previous BB // This is important for the following case: // %a = phi [0, %l1], [1, %l2] // %b = phi [0, %l1], [%a, %l2] // The reference to %a in the definition of %b resolves to the *previous* value of %a, // not the value of %a that we just set in the phi. SymMap prev_symbols; struct { Box* exc_obj; int64_t exc_selector; } landingpad_value; while (true) { for (llvm::Instruction& _inst : *curblock) { llvm::Instruction* inst = &_inst; cur_instruction_map[frame_ptr] = inst; if (VERBOSITY("interpreter") >= 2) { printf("executing in %s: ", f->getName().data()); fflush(stdout); inst->dump(); // f->dump(); } #define SET(v) set(symbols, inst, (v)) if (llvm::LandingPadInst* lpad = llvm::dyn_cast<llvm::LandingPadInst>(inst)) { SET((intptr_t)&landingpad_value); continue; } else if (llvm::ExtractValueInst* ev = llvm::dyn_cast<llvm::ExtractValueInst>(inst)) { Val r = fetch(ev->getAggregateOperand(), dl, symbols); llvm::ArrayRef<unsigned> indexes = ev->getIndices(); #ifndef NDEBUG assert(indexes.size() == 1); llvm::Type* t = llvm::ExtractValueInst::getIndexedType(ev->getAggregateOperand()->getType(), indexes); assert(width(t, dl) == 8); #endif int64_t* ptr = (int64_t*)r.n; int64_t val = ptr[indexes[0]]; SET(val); continue; } else if (llvm::LoadInst* li = llvm::dyn_cast<llvm::LoadInst>(inst)) { llvm::Value* ptr = li->getOperand(0); Val v = fetch(ptr, dl, symbols); // printf("loading from %p\n", v.o); if (width(li, dl) == 1) { Val r = Val(*(bool*)v.o); SET(r); continue; } else if (width(li, dl) == 8) { Val r = Val(*(int64_t*)v.o); SET(r); continue; } else { li->dump(); RELEASE_ASSERT(0, ""); } } else if (llvm::StoreInst* si = llvm::dyn_cast<llvm::StoreInst>(inst)) { llvm::Value* val = si->getOperand(0); llvm::Value* ptr = si->getOperand(1); Val v = fetch(val, dl, symbols); Val p = fetch(ptr, dl, symbols); // printf("storing %lx at %lx\n", v.n, p.n); if (width(val, dl) == 1) { *(bool*)p.o = v.b; continue; } else if (width(val, dl) == 8) { *(int64_t*)p.o = v.n; continue; } else { si->dump(); RELEASE_ASSERT(0, ""); } } else if (llvm::CmpInst* ci = llvm::dyn_cast<llvm::CmpInst>(inst)) { assert(ci->getType() == g.i1); Val a0 = fetch(ci->getOperand(0), dl, symbols); Val a1 = fetch(ci->getOperand(1), dl, symbols); llvm::CmpInst::Predicate pred = ci->getPredicate(); switch (pred) { case llvm::CmpInst::ICMP_EQ: SET(a0.n == a1.n); continue; case llvm::CmpInst::ICMP_NE: SET(a0.n != a1.n); continue; case llvm::CmpInst::ICMP_SLT: SET(a0.n < a1.n); continue; case llvm::CmpInst::ICMP_SLE: SET(a0.n <= a1.n); continue; case llvm::CmpInst::ICMP_SGT: SET(a0.n > a1.n); continue; case llvm::CmpInst::ICMP_SGE: SET(a0.n >= a1.n); continue; case llvm::CmpInst::FCMP_OEQ: SET(a0.d == a1.d); continue; case llvm::CmpInst::FCMP_UNE: SET(a0.d != a1.d); continue; case llvm::CmpInst::FCMP_OLT: SET(a0.d < a1.d); continue; case llvm::CmpInst::FCMP_OLE: SET(a0.d <= a1.d); continue; case llvm::CmpInst::FCMP_OGT: SET(a0.d > a1.d); continue; case llvm::CmpInst::FCMP_OGE: SET(a0.d >= a1.d); continue; default: ci->dump(); RELEASE_ASSERT(0, ""); } continue; } else if (llvm::BinaryOperator* bo = llvm::dyn_cast<llvm::BinaryOperator>(inst)) { if (bo->getOperand(0)->getType() == g.i64 || bo->getOperand(0)->getType() == g.i1) { // assert(bo->getOperand(0)->getType() == g.i64); // assert(bo->getOperand(1)->getType() == g.i64); Val a0 = fetch(bo->getOperand(0), dl, symbols); Val a1 = fetch(bo->getOperand(1), dl, symbols); llvm::Instruction::BinaryOps opcode = bo->getOpcode(); switch (opcode) { case llvm::Instruction::Add: SET(a0.n + a1.n); continue; case llvm::Instruction::And: SET(a0.n & a1.n); continue; case llvm::Instruction::AShr: SET(a0.n >> a1.n); continue; case llvm::Instruction::Mul: SET(a0.n * a1.n); continue; case llvm::Instruction::Or: SET(a0.n | a1.n); continue; case llvm::Instruction::Shl: SET(a0.n << a1.n); continue; case llvm::Instruction::Sub: SET(a0.n - a1.n); continue; case llvm::Instruction::Xor: SET(a0.n ^ a1.n); continue; default: bo->dump(); RELEASE_ASSERT(0, ""); } continue; } else if (bo->getOperand(0)->getType() == g.double_) { // assert(bo->getOperand(0)->getType() == g.i64); // assert(bo->getOperand(1)->getType() == g.i64); double lhs = fetch(bo->getOperand(0), dl, symbols).d; double rhs = fetch(bo->getOperand(1), dl, symbols).d; llvm::Instruction::BinaryOps opcode = bo->getOpcode(); switch (opcode) { case llvm::Instruction::FAdd: SET(lhs + rhs); continue; case llvm::Instruction::FMul: SET(lhs * rhs); continue; case llvm::Instruction::FSub: SET(lhs - rhs); continue; default: bo->dump(); RELEASE_ASSERT(0, ""); } continue; } else { bo->dump(); RELEASE_ASSERT(0, ""); } } else if (llvm::GetElementPtrInst* gep = llvm::dyn_cast<llvm::GetElementPtrInst>(inst)) {