DBG: changes in controlflowanalysis
This commit is contained in:
parent
38683dae38
commit
8ac9f90eeb
|
@ -9,7 +9,7 @@ class Analysis
|
|||
public:
|
||||
explicit Analysis(uint base, uint size);
|
||||
Analysis(const Analysis & that) = delete;
|
||||
~Analysis();
|
||||
virtual ~Analysis();
|
||||
virtual void Analyse() = 0;
|
||||
virtual void SetMarkers() = 0;
|
||||
|
||||
|
|
|
@ -11,9 +11,17 @@ void ControlFlowAnalysis::Analyse()
|
|||
DWORD ticks = GetTickCount();
|
||||
|
||||
BasicBlockStarts();
|
||||
BasicBlocks();
|
||||
dprintf("Basic block starts in %ums!\n", GetTickCount() - ticks);
|
||||
ticks = GetTickCount();
|
||||
|
||||
dprintf("Analysis finished in %ums!\n", GetTickCount() - ticks);
|
||||
BasicBlocks();
|
||||
dprintf("Basick blocks in %ums!\n", GetTickCount() - ticks);
|
||||
ticks = GetTickCount();
|
||||
|
||||
Functions();
|
||||
dprintf("Functions in %ums!\n", GetTickCount() - ticks);
|
||||
|
||||
dprintf("Analysis finished!\n");
|
||||
}
|
||||
|
||||
void ControlFlowAnalysis::SetMarkers()
|
||||
|
@ -21,14 +29,16 @@ void ControlFlowAnalysis::SetMarkers()
|
|||
dprintf("digraph ControlFlow {\n");
|
||||
int i = 0;
|
||||
std::map<uint, int> nodeMap;
|
||||
for(auto block : _blocks)
|
||||
for(const auto & it : _blocks)
|
||||
{
|
||||
const auto & block = it.second;
|
||||
nodeMap.insert({ block.start, i });
|
||||
dprintf(" node%u [label=\"start=%p, end=%p\"];\n", i, block.start, block.end);
|
||||
dprintf(" node%u [label=\"s=%p, e=%p, f=%p\"];\n", i, block.start, block.end, block.function);
|
||||
i++;
|
||||
}
|
||||
for(auto block : _blocks)
|
||||
for(auto it : _blocks)
|
||||
{
|
||||
const auto & block = it.second;
|
||||
int startNode = nodeMap[block.start];
|
||||
if(block.left)
|
||||
{
|
||||
|
@ -65,26 +75,26 @@ void ControlFlowAnalysis::BasicBlockStarts()
|
|||
uint addr = _base + i;
|
||||
if(_cp.Disassemble(addr, TranslateAddress(addr), MAX_DISASM_BUFFER))
|
||||
{
|
||||
if(bSkipFilling) //handle filling skip mode
|
||||
if(bSkipFilling) //handle filling skip mode
|
||||
{
|
||||
if(!_cp.IsFilling()) //do nothing until the filling stopped
|
||||
if(!_cp.IsFilling()) //do nothing until the filling stopped
|
||||
{
|
||||
bSkipFilling = false;
|
||||
_blockStarts.insert(addr);
|
||||
}
|
||||
}
|
||||
else if(_cp.InGroup(CS_GRP_RET) || _cp.InGroup(CS_GRP_INT)) //RET/INT break control flow
|
||||
else if(_cp.InGroup(CS_GRP_RET) || _cp.InGroup(CS_GRP_INT)) //RET/INT break control flow
|
||||
{
|
||||
bSkipFilling = true; //skip INT3/NOP/whatever filling bytes (those are not part of the control flow)
|
||||
}
|
||||
else if(_cp.InGroup(CS_GRP_JUMP) || _cp.IsLoop()) //branches
|
||||
else if(_cp.InGroup(CS_GRP_JUMP) || _cp.IsLoop()) //branches
|
||||
{
|
||||
uint dest1 = GetBranchOperand();
|
||||
uint dest2 = 0;
|
||||
if(_cp.GetId() != X86_INS_JMP) //unconditional jump
|
||||
if(_cp.GetId() != X86_INS_JMP) //unconditional jump
|
||||
dest2 = addr + _cp.Size();
|
||||
|
||||
if(!dest1 && !dest2) //TODO: better code for this (make sure absolutely no filling is inserted)
|
||||
if(!dest1 && !dest2) //TODO: better code for this (make sure absolutely no filling is inserted)
|
||||
bSkipFilling = true;
|
||||
if(dest1)
|
||||
_blockStarts.insert(dest1);
|
||||
|
@ -128,29 +138,153 @@ void ControlFlowAnalysis::BasicBlocks()
|
|||
{
|
||||
if(_cp.InGroup(CS_GRP_RET))
|
||||
{
|
||||
_blocks.push_back(BasicBlock(start, addr, 0, 0)); //leaf block
|
||||
insertBlock(BasicBlock(start, addr, 0, 0)); //leaf block
|
||||
break;
|
||||
}
|
||||
else if(_cp.InGroup(CS_GRP_JUMP) || _cp.IsLoop())
|
||||
{
|
||||
uint dest1 = GetBranchOperand();
|
||||
uint dest2 = _cp.GetId() != X86_INS_JMP ? addr + _cp.Size() : 0;
|
||||
_blocks.push_back(BasicBlock(start, addr, dest1, dest2));
|
||||
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
|
||||
if(addr == nextStart) //special case handling overlapping blocks
|
||||
{
|
||||
_blocks.push_back(BasicBlock(start, prevaddr, 0, nextStart));
|
||||
insertBlock(BasicBlock(start, prevaddr, 0, nextStart));
|
||||
insertParent(nextStart, start);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ControlFlowAnalysis::Functions()
|
||||
{
|
||||
typedef std::pair<BasicBlock*, UintSet*> DelayedBlock;
|
||||
std::vector<DelayedBlock> delayedBlocks;
|
||||
for(auto & it : _blocks)
|
||||
{
|
||||
BasicBlock* block = &it.second;
|
||||
UintSet* parents = findParents(block->start);
|
||||
if(!block->function)
|
||||
{
|
||||
if(!parents) //no parents = function start
|
||||
{
|
||||
uint functionStart = block->start;
|
||||
block->function = functionStart;
|
||||
UintSet functionBlocks;
|
||||
functionBlocks.insert(functionStart);
|
||||
_functions[functionStart] = functionBlocks;
|
||||
}
|
||||
else //in function
|
||||
{
|
||||
uint function = findFunctionStart(block, parents);
|
||||
if(!function) //this happens with loops sometimes
|
||||
delayedBlocks.push_back(DelayedBlock(block, parents));
|
||||
else
|
||||
block->function = function;
|
||||
}
|
||||
}
|
||||
else
|
||||
DebugBreak(); //this should not happen
|
||||
}
|
||||
dprintf("%u/%u delayed blocks...\n", delayedBlocks.size(), _blocks.size());
|
||||
for(auto & delayedBlock : delayedBlocks)
|
||||
{
|
||||
BasicBlock* block = delayedBlock.first;
|
||||
UintSet* parents = delayedBlock.second;
|
||||
uint function = findFunctionStart(block, parents);
|
||||
if(!function)
|
||||
{
|
||||
dprintf("unresolved block %s\n", blockToString(block).c_str());
|
||||
if(parents)
|
||||
{
|
||||
dprintf("parents:\n");
|
||||
for(auto parent : *parents)
|
||||
dprintf(" %s\n", blockToString(findBlock(parent)).c_str());
|
||||
}
|
||||
else
|
||||
dprintf("parents: null");
|
||||
dprintf("left: %s\n", blockToString(findBlock(block->left)).c_str());
|
||||
dprintf("right: %s\n", blockToString(findBlock(block->right)).c_str());
|
||||
return;
|
||||
}
|
||||
block->function = function;
|
||||
}
|
||||
}
|
||||
|
||||
void ControlFlowAnalysis::insertBlock(BasicBlock block)
|
||||
{
|
||||
if(_blocks.find(block.start) != _blocks.end())
|
||||
DebugBreak();
|
||||
_blocks[block.start] = block;
|
||||
}
|
||||
|
||||
ControlFlowAnalysis::BasicBlock* ControlFlowAnalysis::findBlock(uint start)
|
||||
{
|
||||
if(!start)
|
||||
return nullptr;
|
||||
auto found = _blocks.find(start);
|
||||
return found != _blocks.end() ? &found->second : nullptr;
|
||||
}
|
||||
|
||||
void ControlFlowAnalysis::insertParent(uint child, uint parent)
|
||||
{
|
||||
if(!child || !parent)
|
||||
return;
|
||||
auto found = _parentMap.find(child);
|
||||
if(found == _parentMap.end())
|
||||
{
|
||||
UintSet parents;
|
||||
parents.insert(parent);
|
||||
_parentMap[child] = parents;
|
||||
}
|
||||
else
|
||||
found->second.insert(parent);
|
||||
}
|
||||
|
||||
ControlFlowAnalysis::UintSet* ControlFlowAnalysis::findParents(uint child)
|
||||
{
|
||||
if(!child)
|
||||
return nullptr;
|
||||
auto found = _parentMap.find(child);
|
||||
return found != _parentMap.end() ? &found->second : nullptr;
|
||||
}
|
||||
|
||||
uint ControlFlowAnalysis::findFunctionStart(BasicBlock* block, ControlFlowAnalysis::UintSet* parents)
|
||||
{
|
||||
if(!block)
|
||||
return 0;
|
||||
if(block->function)
|
||||
return block->function;
|
||||
BasicBlock* left = findBlock(block->left);
|
||||
if(left && left->function)
|
||||
return left->function;
|
||||
BasicBlock* right = findBlock(block->right);
|
||||
if(right && right->function)
|
||||
return right->function;
|
||||
for(auto start : *parents)
|
||||
{
|
||||
BasicBlock* parent = findBlock(start);
|
||||
if(parent->function)
|
||||
return parent->function;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
String ControlFlowAnalysis::blockToString(BasicBlock* block)
|
||||
{
|
||||
if(!block)
|
||||
return String("null");
|
||||
return block->toString();
|
||||
}
|
||||
|
||||
uint ControlFlowAnalysis::GetBranchOperand()
|
||||
{
|
||||
for(int i = 0; i < _cp.x86().op_count; i++)
|
||||
|
|
|
@ -2,15 +2,15 @@
|
|||
#define _CONTROLFLOWANALYSIS_H
|
||||
|
||||
#include "_global.h"
|
||||
#include "capstone_wrapper.h"
|
||||
#include "analysis.h"
|
||||
#include "addrinfo.h"
|
||||
|
||||
class ControlFlowAnalysis : public Analysis
|
||||
{
|
||||
public:
|
||||
explicit ControlFlowAnalysis(uint base, uint size);
|
||||
void Analyse();
|
||||
void SetMarkers();
|
||||
void Analyse() override;
|
||||
void SetMarkers() override;
|
||||
|
||||
private:
|
||||
struct BasicBlock
|
||||
|
@ -19,6 +19,7 @@ private:
|
|||
uint end;
|
||||
uint left;
|
||||
uint right;
|
||||
uint function;
|
||||
|
||||
BasicBlock()
|
||||
{
|
||||
|
@ -26,6 +27,7 @@ private:
|
|||
this->end = 0;
|
||||
this->left = 0;
|
||||
this->right = 0;
|
||||
this->function = 0;
|
||||
}
|
||||
|
||||
BasicBlock(uint start, uint end, uint left, uint right)
|
||||
|
@ -34,14 +36,31 @@ private:
|
|||
this->end = end;
|
||||
this->left = min(left, right);
|
||||
this->right = max(left, right);
|
||||
this->function = 0;
|
||||
}
|
||||
|
||||
String toString()
|
||||
{
|
||||
return StringUtils::sprintf("start:%p,end:%p,left:%p,right:%p,func:%p", start, end, left, right, function);
|
||||
}
|
||||
};
|
||||
|
||||
std::set<uint> _blockStarts;
|
||||
std::vector<BasicBlock> _blocks;
|
||||
typedef std::set<uint> UintSet;
|
||||
|
||||
UintSet _blockStarts;
|
||||
std::map<uint, BasicBlock> _blocks; //start of block -> block
|
||||
std::map<uint, UintSet> _parentMap; //start child -> parents
|
||||
std::map<uint, UintSet> _functions; //function start -> function block starts
|
||||
|
||||
void BasicBlockStarts();
|
||||
void BasicBlocks();
|
||||
void Functions();
|
||||
void insertBlock(BasicBlock block);
|
||||
BasicBlock* findBlock(uint start);
|
||||
void insertParent(uint child, uint parent);
|
||||
UintSet* findParents(uint child);
|
||||
uint findFunctionStart(BasicBlock* block, UintSet* parents);
|
||||
String blockToString(BasicBlock* block);
|
||||
uint GetBranchOperand();
|
||||
};
|
||||
|
||||
|
|
|
@ -2,15 +2,14 @@
|
|||
#define _FUNCTIONANALYSIS_H
|
||||
|
||||
#include "_global.h"
|
||||
#include "capstone_wrapper.h"
|
||||
#include "analysis.h"
|
||||
|
||||
class FunctionAnalysis : public Analysis
|
||||
{
|
||||
public:
|
||||
explicit FunctionAnalysis(uint base, uint size);
|
||||
void Analyse();
|
||||
void SetMarkers();
|
||||
void Analyse() override;
|
||||
void SetMarkers() override;
|
||||
|
||||
private:
|
||||
struct FunctionInfo
|
||||
|
|
|
@ -1930,7 +1930,7 @@ CMDRESULT cbInstrCfanalyse(int argc, char* argv[])
|
|||
uint base = MemFindBaseAddr(sel.start, &size);
|
||||
ControlFlowAnalysis anal(base, size);
|
||||
anal.Analyse();
|
||||
anal.SetMarkers();
|
||||
//anal.SetMarkers();
|
||||
GuiUpdateAllViews();
|
||||
return STATUS_CONTINUE;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue