BasicBlockCoverage::BasicBlockCoverage(const std::string &basicBlockListFile, const std::string &moduleName) { FILE *fp = fopen(basicBlockListFile.c_str(), "r"); if (!fp) { std::cerr << "Could not open file " << basicBlockListFile << std::endl; return; } char buffer[512]; while (fgets(buffer, sizeof(buffer), fp)) { uint64_t start, end; char name[512]; sscanf(buffer, "0x%"PRIx64" 0x%"PRIx64" %[^\r\t\n]s", &start, &end, name); //std::cout << "Read 0x" << std::hex << start << " 0x" << end << " " << name << std::endl; BasicBlocks &bbs = m_functions[name]; //XXX: the +1 is here to compensate the broken extraction script, which //does not take into account the whole size of the last instruction. bbs.insert(BasicBlock(start, end)); m_allBbs.insert(BasicBlock(start, end)); } Functions::iterator fit; unsigned fcnBbCount = 0; for (fit = m_functions.begin(); fit != m_functions.end() ; ++fit) { fcnBbCount += (*fit).second.size(); } assert(fcnBbCount == m_allBbs.size()); if (m_allBbs.size() == 0) { std::cerr << "No basic blocks found in the list for " << moduleName << ". Check the format of the file." << std::endl; } }
void Function::RegisterBlockEnd(std::vector<uint32_t> next_list, SpvOp branch_instruction) { assert( current_block_ && "RegisterBlockEnd can only be called when parsing a binary in a block"); std::vector<BasicBlock*> next_blocks; next_blocks.reserve(next_list.size()); std::unordered_map<uint32_t, BasicBlock>::iterator inserted_block; bool success; for (uint32_t successor_id : next_list) { tie(inserted_block, success) = blocks_.insert({successor_id, BasicBlock(successor_id)}); if (success) { undefined_blocks_.insert(successor_id); } next_blocks.push_back(&inserted_block->second); } if (current_block_->is_type(kBlockTypeLoop)) { // For each loop header, record the set of its successors, and include // its continue target if the continue target is not the loop header // itself. std::vector<BasicBlock*>& next_blocks_plus_continue_target = loop_header_successors_plus_continue_target_map_[current_block_]; next_blocks_plus_continue_target = next_blocks; auto continue_target = FindConstructForEntryBlock(current_block_, ConstructType::kLoop) .corresponding_constructs() .back() ->entry_block(); if (continue_target != current_block_) { next_blocks_plus_continue_target.push_back(continue_target); } } current_block_->RegisterBranchInstruction(branch_instruction); current_block_->RegisterSuccessors(next_blocks); current_block_ = nullptr; return; }
spv_result_t Function::RegisterBlock(uint32_t block_id, bool is_definition) { assert( declaration_type_ == FunctionDecl::kFunctionDeclDefinition && "RegisterBlocks can only be called after declaration_type_ is defined"); std::unordered_map<uint32_t, BasicBlock>::iterator inserted_block; bool success = false; tie(inserted_block, success) = blocks_.insert({block_id, BasicBlock(block_id)}); if (is_definition) { // new block definition assert(current_block_ == nullptr && "Register Block can only be called when parsing a binary outside of " "a BasicBlock"); undefined_blocks_.erase(block_id); current_block_ = &inserted_block->second; ordered_blocks_.push_back(current_block_); if (IsFirstBlock(block_id)) current_block_->set_reachable(true); } else if (success) { // Block doesn't exsist but this is not a definition undefined_blocks_.insert(block_id); } return SPV_SUCCESS; }
//------------------------------------------------------------------------------ // Name: operator= //------------------------------------------------------------------------------ BasicBlock &BasicBlock::operator=(const BasicBlock &rhs) { BasicBlock(rhs).swap(*this); return *this; }
void ControlFlowAnalysis::BasicBlocks() { for(auto i = _blockStarts.begin(); i != _blockStarts.end(); ++i) { uint start = *i; if(!IsValidAddress(start)) continue; uint nextStart = _base + _size; auto next = std::next(i); if(next != _blockStarts.end()) nextStart = *next; for(uint addr = start, prevaddr = 0; addr < _base + _size;) { prevaddr = addr; if(_cp.Disassemble(addr, TranslateAddress(addr), MAX_DISASM_BUFFER)) { if(_cp.InGroup(CS_GRP_RET) || _cp.GetId() == X86_INS_INT3) { insertBlock(BasicBlock(start, addr, 0, 0)); //leaf block break; } else if(_cp.InGroup(CS_GRP_JUMP) || _cp.IsLoop()) { uint dest1 = GetReferenceOperand(); uint dest2 = _cp.GetId() != X86_INS_JMP ? addr + _cp.Size() : 0; insertBlock(BasicBlock(start, addr, dest1, dest2)); insertParent(dest1, start); insertParent(dest2, start); break; } addr += _cp.Size(); } else addr++; if(addr == nextStart) //special case handling overlapping blocks { insertBlock(BasicBlock(start, prevaddr, 0, nextStart)); insertParent(nextStart, start); break; } } } _blockStarts.clear(); #ifdef _WIN64 int count = 0; EnumerateFunctionRuntimeEntries64([&](PRUNTIME_FUNCTION Function) { const uint funcAddr = _moduleBase + Function->BeginAddress; const uint funcEnd = _moduleBase + Function->EndAddress; // If within limits... if(funcAddr >= _base && funcAddr < _base + _size) _functionStarts.insert(funcAddr); count++; return true; }); dprintf("%u functions from the exception directory...\n", count); #endif // _WIN64 dprintf("%u basic blocks, %u function starts detected...\n", _blocks.size(), _functionStarts.size()); }