2007-12-06 23:05:38 +00:00
|
|
|
#include "MipsExecutor.h"
|
|
|
|
|
2015-06-07 23:44:46 -04:00
|
|
|
static bool IsInsideRange(uint32 address, uint32 start, uint32 end)
|
|
|
|
{
|
|
|
|
return (address >= start) && (address <= end);
|
|
|
|
}
|
|
|
|
|
2017-06-25 11:45:08 -04:00
|
|
|
#define SUBTABLE_BITS 16
|
|
|
|
#define SUBTABLE_SIZE (1 << SUBTABLE_BITS)
|
|
|
|
#define SUBTABLE_MASK (SUBTABLE_SIZE - 1)
|
|
|
|
|
2012-03-13 06:16:33 +00:00
|
|
|
CMipsExecutor::CMipsExecutor(CMIPS& context, uint32 maxAddress)
|
|
|
|
: m_context(context)
|
2017-06-24 20:27:05 -04:00
|
|
|
, m_maxAddress(maxAddress)
|
2007-12-06 23:05:38 +00:00
|
|
|
{
|
2017-06-25 11:45:08 -04:00
|
|
|
m_subTableCount = (m_maxAddress + SUBTABLE_MASK) / SUBTABLE_SIZE;
|
2017-06-24 20:27:05 -04:00
|
|
|
assert(m_subTableCount != 0);
|
2012-03-13 06:16:33 +00:00
|
|
|
m_blockTable = new CBasicBlock**[m_subTableCount];
|
|
|
|
memset(m_blockTable, 0, sizeof(CBasicBlock**) * m_subTableCount);
|
2007-12-06 23:05:38 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
CMipsExecutor::~CMipsExecutor()
|
|
|
|
{
|
2012-03-13 06:16:33 +00:00
|
|
|
for(unsigned int i = 0; i < m_subTableCount; i++)
|
|
|
|
{
|
|
|
|
CBasicBlock** subTable = m_blockTable[i];
|
|
|
|
if(subTable != NULL)
|
|
|
|
{
|
|
|
|
delete [] subTable;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
delete [] m_blockTable;
|
2010-11-17 03:59:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void CMipsExecutor::Reset()
|
|
|
|
{
|
|
|
|
ClearActiveBlocks();
|
2007-12-17 04:08:46 +00:00
|
|
|
}
|
2007-12-06 23:05:38 +00:00
|
|
|
|
2010-11-17 03:59:29 +00:00
|
|
|
void CMipsExecutor::ClearActiveBlocks()
|
2007-12-17 04:08:46 +00:00
|
|
|
{
|
2012-03-13 06:16:33 +00:00
|
|
|
for(unsigned int i = 0; i < m_subTableCount; i++)
|
|
|
|
{
|
|
|
|
CBasicBlock** subTable = m_blockTable[i];
|
|
|
|
if(subTable != NULL)
|
|
|
|
{
|
|
|
|
delete [] subTable;
|
|
|
|
m_blockTable[i] = NULL;
|
|
|
|
}
|
|
|
|
}
|
2010-11-17 03:59:29 +00:00
|
|
|
|
|
|
|
m_blocks.clear();
|
2007-12-06 23:05:38 +00:00
|
|
|
}
|
|
|
|
|
2013-03-10 05:11:53 +00:00
|
|
|
void CMipsExecutor::ClearActiveBlocksInRange(uint32 start, uint32 end)
|
2015-06-07 23:44:46 -04:00
|
|
|
{
|
|
|
|
ClearActiveBlocksInRangeInternal(start, end, nullptr);
|
|
|
|
}
|
|
|
|
|
|
|
|
void CMipsExecutor::ClearActiveBlocksInRangeInternal(uint32 start, uint32 end, CBasicBlock* protectedBlock)
|
2013-03-10 05:11:53 +00:00
|
|
|
{
|
2017-06-25 11:45:08 -04:00
|
|
|
uint32 hiStart = start >> SUBTABLE_BITS;
|
|
|
|
uint32 hiEnd = end >> SUBTABLE_BITS;
|
2013-03-10 05:11:53 +00:00
|
|
|
|
2015-06-07 23:44:46 -04:00
|
|
|
//We need to increase the range to make sure we catch any
|
|
|
|
//block that are straddling table boundaries
|
|
|
|
if(hiStart != 0) hiStart--;
|
|
|
|
if(hiEnd != (m_subTableCount - 1)) hiEnd++;
|
|
|
|
|
2013-03-10 05:11:53 +00:00
|
|
|
std::set<CBasicBlock*> blocksToDelete;
|
|
|
|
|
|
|
|
for(uint32 hi = hiStart; hi <= hiEnd; hi++)
|
|
|
|
{
|
2017-06-25 12:08:06 -04:00
|
|
|
auto table = m_blockTable[hi];
|
|
|
|
if(!table) continue;
|
2013-03-10 05:11:53 +00:00
|
|
|
|
2017-06-25 11:45:08 -04:00
|
|
|
for(uint32 lo = 0; lo < SUBTABLE_SIZE; lo += 4)
|
2013-03-10 05:11:53 +00:00
|
|
|
{
|
2017-06-25 11:45:08 -04:00
|
|
|
uint32 tableAddress = (hi << SUBTABLE_BITS) | lo;
|
2015-06-07 23:44:46 -04:00
|
|
|
auto block = table[lo / 4];
|
2013-03-10 05:11:53 +00:00
|
|
|
if(block == nullptr) continue;
|
2015-06-07 23:44:46 -04:00
|
|
|
if(block == protectedBlock) continue;
|
|
|
|
if(!IsInsideRange(block->GetBeginAddress(), start, end)
|
|
|
|
&& !IsInsideRange(block->GetEndAddress(), start, end)) continue;
|
2013-03-10 05:11:53 +00:00
|
|
|
table[lo / 4] = nullptr;
|
|
|
|
blocksToDelete.insert(block);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if(!blocksToDelete.empty())
|
|
|
|
{
|
|
|
|
m_blocks.remove_if([&] (const BasicBlockPtr& block) { return blocksToDelete.find(block.get()) != std::end(blocksToDelete); });
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-09-29 01:28:23 +00:00
|
|
|
#ifdef DEBUGGER_INCLUDED
|
|
|
|
|
2009-06-06 15:38:03 +00:00
|
|
|
bool CMipsExecutor::MustBreak() const
|
2007-12-06 23:05:38 +00:00
|
|
|
{
|
2012-04-16 02:34:36 +00:00
|
|
|
uint32 currentPc = m_context.m_pAddrTranslator(&m_context, m_context.m_State.nPC);
|
2012-04-15 22:10:11 +00:00
|
|
|
CBasicBlock* block = FindBlockAt(currentPc);
|
2017-05-08 19:11:51 +01:00
|
|
|
for(auto breakPointAddress : m_context.m_breakpoints)
|
2012-03-13 06:16:33 +00:00
|
|
|
{
|
|
|
|
if(currentPc == breakPointAddress) return true;
|
|
|
|
if(block != NULL)
|
|
|
|
{
|
|
|
|
if(breakPointAddress >= block->GetBeginAddress() && breakPointAddress <= block->GetEndAddress()) return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false;
|
2007-12-06 23:05:38 +00:00
|
|
|
}
|
|
|
|
|
2012-09-29 01:28:23 +00:00
|
|
|
void CMipsExecutor::DisableBreakpointsOnce()
|
|
|
|
{
|
|
|
|
m_breakpointsDisabledOnce = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
2012-03-13 06:16:33 +00:00
|
|
|
CBasicBlock* CMipsExecutor::FindBlockAt(uint32 address) const
|
2007-12-06 23:05:38 +00:00
|
|
|
{
|
2017-06-25 11:45:08 -04:00
|
|
|
uint32 hiAddress = address >> SUBTABLE_BITS;
|
|
|
|
uint32 loAddress = address & SUBTABLE_MASK;
|
2012-03-13 06:16:33 +00:00
|
|
|
assert(hiAddress < m_subTableCount);
|
2017-06-25 12:08:06 -04:00
|
|
|
auto& subTable = m_blockTable[hiAddress];
|
|
|
|
if(!subTable) return nullptr;
|
|
|
|
auto result = subTable[loAddress / 4];
|
2012-03-13 06:16:33 +00:00
|
|
|
return result;
|
2007-12-06 23:05:38 +00:00
|
|
|
}
|
|
|
|
|
2012-03-13 06:16:33 +00:00
|
|
|
CBasicBlock* CMipsExecutor::FindBlockStartingAt(uint32 address) const
|
2007-12-06 23:05:38 +00:00
|
|
|
{
|
2017-06-25 11:45:08 -04:00
|
|
|
uint32 hiAddress = address >> SUBTABLE_BITS;
|
|
|
|
uint32 loAddress = address & SUBTABLE_MASK;
|
2012-03-13 06:16:33 +00:00
|
|
|
assert(hiAddress < m_subTableCount);
|
2017-06-25 12:08:06 -04:00
|
|
|
auto& subTable = m_blockTable[hiAddress];
|
|
|
|
if(!subTable) return nullptr;
|
|
|
|
auto result = subTable[loAddress / 4];
|
2012-03-13 06:16:33 +00:00
|
|
|
if((address != 0) && (FindBlockAt(address - 4) == result))
|
|
|
|
{
|
2017-06-25 12:08:06 -04:00
|
|
|
return nullptr;
|
2012-03-13 06:16:33 +00:00
|
|
|
}
|
|
|
|
return result;
|
2007-12-06 23:05:38 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void CMipsExecutor::CreateBlock(uint32 start, uint32 end)
|
|
|
|
{
|
2012-03-13 06:16:33 +00:00
|
|
|
{
|
2017-06-25 12:08:06 -04:00
|
|
|
auto block = FindBlockAt(start);
|
2012-03-13 06:16:33 +00:00
|
|
|
if(block)
|
|
|
|
{
|
|
|
|
//If the block starts and ends at the same place, block already exists and doesn't need
|
|
|
|
//to be re-created
|
|
|
|
uint32 otherBegin = block->GetBeginAddress();
|
|
|
|
uint32 otherEnd = block->GetEndAddress();
|
|
|
|
if((otherBegin == start) && (otherEnd == end))
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if(otherEnd == end)
|
|
|
|
{
|
|
|
|
//Repartition the existing block if end of both blocks are the same
|
|
|
|
DeleteBlock(block);
|
|
|
|
CreateBlock(otherBegin, start - 4);
|
2017-06-25 12:08:06 -04:00
|
|
|
assert(!FindBlockAt(start));
|
2012-03-13 06:16:33 +00:00
|
|
|
}
|
|
|
|
else if(otherBegin == start)
|
|
|
|
{
|
|
|
|
DeleteBlock(block);
|
|
|
|
CreateBlock(end + 4, otherEnd);
|
2017-06-25 12:08:06 -04:00
|
|
|
assert(!FindBlockAt(end));
|
2012-03-13 06:16:33 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
//Delete the currently existing block otherwise
|
2017-05-29 06:01:32 +01:00
|
|
|
printf("MipsExecutor: Warning. Deleting block at %08X.\r\n", block->GetEndAddress());
|
2012-03-13 06:16:33 +00:00
|
|
|
DeleteBlock(block);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2017-06-25 12:08:06 -04:00
|
|
|
assert(!FindBlockAt(end));
|
2012-03-13 06:16:33 +00:00
|
|
|
{
|
2017-06-24 20:25:57 -04:00
|
|
|
auto block = BlockFactory(m_context, start, end);
|
2012-03-13 06:16:33 +00:00
|
|
|
for(uint32 address = block->GetBeginAddress(); address <= block->GetEndAddress(); address += 4)
|
|
|
|
{
|
2017-06-25 11:45:08 -04:00
|
|
|
uint32 hiAddress = address >> SUBTABLE_BITS;
|
|
|
|
uint32 loAddress = address & SUBTABLE_MASK;
|
2012-03-13 06:16:33 +00:00
|
|
|
assert(hiAddress < m_subTableCount);
|
2017-06-25 12:08:06 -04:00
|
|
|
auto& subTable = m_blockTable[hiAddress];
|
|
|
|
if(!subTable)
|
2012-03-13 06:16:33 +00:00
|
|
|
{
|
2017-06-25 11:45:08 -04:00
|
|
|
const uint32 subTableSize = SUBTABLE_SIZE / 4;
|
2012-03-13 06:16:33 +00:00
|
|
|
subTable = new CBasicBlock*[subTableSize];
|
|
|
|
memset(subTable, 0, sizeof(CBasicBlock*) * subTableSize);
|
|
|
|
}
|
2017-06-25 12:08:06 -04:00
|
|
|
assert(!subTable[loAddress / 4]);
|
2012-03-13 06:16:33 +00:00
|
|
|
subTable[loAddress / 4] = block.get();
|
|
|
|
}
|
2013-04-12 02:35:55 +00:00
|
|
|
m_blocks.push_back(std::move(block));
|
2012-03-13 06:16:33 +00:00
|
|
|
}
|
2007-12-06 23:05:38 +00:00
|
|
|
}
|
|
|
|
|
2012-03-13 06:16:33 +00:00
|
|
|
void CMipsExecutor::DeleteBlock(CBasicBlock* block)
|
2008-01-03 07:42:54 +00:00
|
|
|
{
|
2012-03-13 06:16:33 +00:00
|
|
|
for(uint32 address = block->GetBeginAddress(); address <= block->GetEndAddress(); address += 4)
|
|
|
|
{
|
2017-06-25 11:45:08 -04:00
|
|
|
uint32 hiAddress = address >> SUBTABLE_BITS;
|
|
|
|
uint32 loAddress = address & SUBTABLE_MASK;
|
2012-03-13 06:16:33 +00:00
|
|
|
assert(hiAddress < m_subTableCount);
|
2017-06-25 12:08:06 -04:00
|
|
|
auto& subTable = m_blockTable[hiAddress];
|
|
|
|
assert(subTable);
|
|
|
|
assert(subTable[loAddress / 4]);
|
|
|
|
subTable[loAddress / 4] = nullptr;
|
2012-03-13 06:16:33 +00:00
|
|
|
}
|
2008-08-24 21:28:42 +00:00
|
|
|
|
2012-03-13 06:16:33 +00:00
|
|
|
//Remove block from our lists
|
2013-04-12 02:35:55 +00:00
|
|
|
auto blockIterator = std::find_if(std::begin(m_blocks), std::end(m_blocks), [&] (const BasicBlockPtr& blockPtr) { return blockPtr.get() == block; });
|
|
|
|
assert(blockIterator != std::end(m_blocks));
|
|
|
|
m_blocks.erase(blockIterator);
|
2008-01-03 07:42:54 +00:00
|
|
|
}
|
|
|
|
|
2013-04-12 02:35:55 +00:00
|
|
|
CMipsExecutor::BasicBlockPtr CMipsExecutor::BlockFactory(CMIPS& context, uint32 start, uint32 end)
|
2009-06-06 15:38:03 +00:00
|
|
|
{
|
2017-06-25 12:28:29 -04:00
|
|
|
auto result = std::make_shared<CBasicBlock>(context, start, end);
|
|
|
|
result->Compile();
|
|
|
|
return result;
|
2009-06-06 15:38:03 +00:00
|
|
|
}
|
|
|
|
|
2007-12-06 23:05:38 +00:00
|
|
|
void CMipsExecutor::PartitionFunction(uint32 functionAddress)
|
|
|
|
{
|
2012-03-13 06:16:33 +00:00
|
|
|
typedef std::set<uint32> PartitionPointSet;
|
|
|
|
uint32 endAddress = 0;
|
|
|
|
PartitionPointSet partitionPoints;
|
2007-12-06 23:05:38 +00:00
|
|
|
|
2012-03-13 06:16:33 +00:00
|
|
|
//Insert begin point
|
|
|
|
partitionPoints.insert(functionAddress);
|
2007-12-06 23:05:38 +00:00
|
|
|
|
2012-03-13 06:16:33 +00:00
|
|
|
//Find the end
|
|
|
|
for(uint32 address = functionAddress; ; address += 4)
|
|
|
|
{
|
|
|
|
//Probably going too far...
|
|
|
|
if((address - functionAddress) > 0x10000)
|
|
|
|
{
|
|
|
|
printf("MipsExecutor: Warning. Found no JR after a big distance.\r\n");
|
|
|
|
endAddress = address;
|
|
|
|
partitionPoints.insert(endAddress);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
uint32 opcode = m_context.m_pMemoryMap->GetInstruction(address);
|
|
|
|
if(opcode == 0x03E00008)
|
|
|
|
{
|
|
|
|
//+4 for delay slot
|
|
|
|
endAddress = address + 4;
|
|
|
|
partitionPoints.insert(endAddress + 4);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2007-12-06 23:05:38 +00:00
|
|
|
|
2012-03-13 06:16:33 +00:00
|
|
|
//Find partition points within the function
|
|
|
|
for(uint32 address = functionAddress; address <= endAddress; address += 4)
|
|
|
|
{
|
|
|
|
uint32 opcode = m_context.m_pMemoryMap->GetInstruction(address);
|
2011-12-10 20:49:50 +00:00
|
|
|
MIPS_BRANCH_TYPE branchType = m_context.m_pArch->IsInstructionBranch(&m_context, address, opcode);
|
2012-03-13 06:16:33 +00:00
|
|
|
if(branchType == MIPS_BRANCH_NORMAL)
|
|
|
|
{
|
|
|
|
partitionPoints.insert(address + 8);
|
|
|
|
uint32 target = m_context.m_pArch->GetInstructionEffectiveAddress(&m_context, address, opcode);
|
|
|
|
if(target > functionAddress && target < endAddress)
|
|
|
|
{
|
|
|
|
partitionPoints.insert(target);
|
|
|
|
}
|
|
|
|
}
|
2011-12-10 20:49:50 +00:00
|
|
|
else if(branchType == MIPS_BRANCH_NODELAY)
|
|
|
|
{
|
|
|
|
partitionPoints.insert(address + 4);
|
|
|
|
}
|
2012-03-13 06:16:33 +00:00
|
|
|
//Check if there's a block already exising that this address
|
|
|
|
if(address != endAddress)
|
|
|
|
{
|
2012-04-15 22:10:11 +00:00
|
|
|
CBasicBlock* possibleBlock = FindBlockStartingAt(address);
|
2012-03-13 06:16:33 +00:00
|
|
|
if(possibleBlock)
|
|
|
|
{
|
|
|
|
//assert(possibleBlock->GetEndAddress() <= endAddress);
|
|
|
|
//Add its beginning and end in the partition points
|
|
|
|
partitionPoints.insert(possibleBlock->GetBeginAddress());
|
|
|
|
partitionPoints.insert(possibleBlock->GetEndAddress() + 4);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2007-12-06 23:05:38 +00:00
|
|
|
|
2011-12-10 20:49:50 +00:00
|
|
|
//Check if blocks are too big
|
|
|
|
{
|
|
|
|
uint32 currentPoint = -1;
|
|
|
|
for(PartitionPointSet::const_iterator pointIterator(partitionPoints.begin());
|
2017-05-08 19:11:51 +01:00
|
|
|
pointIterator != partitionPoints.end(); ++pointIterator)
|
2011-12-10 20:49:50 +00:00
|
|
|
{
|
|
|
|
if(currentPoint != -1)
|
|
|
|
{
|
|
|
|
uint32 startPos = currentPoint;
|
|
|
|
uint32 endPos = *pointIterator;
|
|
|
|
uint32 distance = (endPos - startPos);
|
|
|
|
if(distance > 0x400)
|
|
|
|
{
|
|
|
|
uint32 middlePos = ((endPos + startPos) / 2) & ~0x03;
|
|
|
|
pointIterator = partitionPoints.insert(middlePos).first;
|
2017-05-08 19:11:51 +01:00
|
|
|
--pointIterator;
|
2011-12-10 20:49:50 +00:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
currentPoint = *pointIterator;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//Create blocks
|
|
|
|
{
|
|
|
|
uint32 currentPoint = -1;
|
2017-05-08 19:11:51 +01:00
|
|
|
for(auto partitionPoint : partitionPoints)
|
2011-12-10 20:49:50 +00:00
|
|
|
{
|
|
|
|
if(currentPoint != -1)
|
|
|
|
{
|
2017-05-08 19:11:51 +01:00
|
|
|
CreateBlock(currentPoint, partitionPoint - 4);
|
2011-12-10 20:49:50 +00:00
|
|
|
}
|
2017-05-08 19:11:51 +01:00
|
|
|
currentPoint = partitionPoint;
|
2011-12-10 20:49:50 +00:00
|
|
|
}
|
|
|
|
}
|
2007-12-06 23:05:38 +00:00
|
|
|
}
|