control_flow: Correct block breaking algorithm.

This commit is contained in:
Fernando Sahmkow 2019-06-27 09:24:40 -04:00 committed by FernandoS27
parent dc4a93594c
commit e7c6045a03

View file

@ -75,19 +75,17 @@ struct CFGRebuildState {
enum class BlockCollision : u32 { None, Found, Inside };
std::pair<BlockCollision, std::vector<BlockInfo>::iterator> TryGetBlock(CFGRebuildState& state,
u32 address) {
auto it = state.block_info.begin();
while (it != state.block_info.end()) {
if (it->start == address) {
return {BlockCollision::Found, it};
std::pair<BlockCollision, u32> TryGetBlock(CFGRebuildState& state, u32 address) {
const auto& blocks = state.block_info;
for (u32 index = 0; index < blocks.size(); index++) {
if (blocks[index].start == address) {
return {BlockCollision::Found, index};
}
if (it->IsInside(address)) {
return {BlockCollision::Inside, it};
if (blocks[index].IsInside(address)) {
return {BlockCollision::Inside, index};
}
it++;
}
return {BlockCollision::None, it};
return {BlockCollision::None, -1};
}
struct ParseInfo {
@ -318,24 +316,26 @@ bool TryInspectAddress(CFGRebuildState& state) {
if (state.inspect_queries.empty()) {
return false;
}
const u32 address = state.inspect_queries.front();
state.inspect_queries.pop_front();
const auto search_result = TryGetBlock(state, address);
switch (search_result.first) {
const auto [result, block_index] = TryGetBlock(state, address);
switch (result) {
case BlockCollision::Found: {
return true;
}
case BlockCollision::Inside: {
// This case is the tricky one:
// We need to Split the block in 2 sepparate blocks
const auto it = search_result.second;
BlockInfo& block_info = CreateBlockInfo(state, address, it->end);
it->end = address - 1;
block_info.branch = it->branch;
const u32 end = state.block_info[block_index].end;
BlockInfo& new_block = CreateBlockInfo(state, address, end);
BlockInfo& current_block = state.block_info[block_index];
current_block.end = address - 1;
new_block.branch = current_block.branch;
BlockBranchInfo forward_branch{};
forward_branch.address = address;
forward_branch.ignore = true;
it->branch = forward_branch;
current_block.branch = forward_branch;
return true;
}
default: