DBG+GUI: Various analysis and function drawing code fixes
This commit is contained in:
parent
ae2e3dabfb
commit
2de45d6087
|
@ -469,7 +469,7 @@ BRIDGE_IMPEXP FUNCTYPE DbgGetFunctionTypeAt(duint addr)
|
|||
return FUNC_NONE;
|
||||
duint start = info.function.start;
|
||||
duint end = info.function.end;
|
||||
if(start == end)
|
||||
if(start == end || info.function.instrcount == 1)
|
||||
return FUNC_SINGLE;
|
||||
else if(addr == start)
|
||||
return FUNC_BEGIN;
|
||||
|
|
|
@ -323,6 +323,7 @@ typedef struct
|
|||
{
|
||||
duint start; //OUT
|
||||
duint end; //OUT
|
||||
duint instrcount; //OUT
|
||||
} FUNCTION;
|
||||
|
||||
typedef struct
|
||||
|
|
|
@ -21,7 +21,7 @@ protected:
|
|||
|
||||
inline unsigned char* AnalysisPass::TranslateAddress(duint Address)
|
||||
{
|
||||
assert(ValidateAddress(Address));
|
||||
ASSERT_TRUE(ValidateAddress(Address));
|
||||
|
||||
return &m_Data[Address - m_VirtualStart];
|
||||
}
|
||||
|
|
|
@ -7,7 +7,6 @@ enum BasicBlockFlags : duint
|
|||
BASIC_BLOCK_FLAG_NONE = 0, // No flag
|
||||
|
||||
BASIC_BLOCK_FLAG_FUNCTION = (1 << 1), // Scanned; also part of a known function
|
||||
BASIC_BLOCK_FLAG_ORPHANED = (1 << 2), // No targets ever reach this block
|
||||
BASIC_BLOCK_FLAG_CUTOFF = (1 << 3), // Ends prematurely because of another JMP to location
|
||||
BASIC_BLOCK_FLAG_DELETE = (1 << 4), // Delete element at the next possible time
|
||||
|
||||
|
@ -28,6 +27,8 @@ struct BasicBlock
|
|||
duint Flags;
|
||||
duint Target;
|
||||
|
||||
duint InstrCount; // Number of instructions in block
|
||||
|
||||
__forceinline bool GetFlag(duint Flag)
|
||||
{
|
||||
return (Flags & Flag) == Flag;
|
||||
|
@ -62,6 +63,8 @@ struct FunctionDef
|
|||
duint BBlockStart; // Index of first basic block
|
||||
duint BBlockEnd; // Index of last basic block
|
||||
|
||||
duint InstrCount; // Number of instructions in function
|
||||
|
||||
bool operator< (const FunctionDef & b) const
|
||||
{
|
||||
if(VirtualStart == b.VirtualStart)
|
||||
|
|
|
@ -77,20 +77,20 @@ bool FunctionPass::Analyse()
|
|||
|
||||
concurrency::parallel_for(duint (0), IdealThreadCount(), [&](duint i)
|
||||
{
|
||||
duint threadWorkStart = (workAmount * i);
|
||||
duint threadWorkStop = min((threadWorkStart + workAmount), m_MainBlocks.size());
|
||||
|
||||
// Memory allocation optimization
|
||||
// TODO: Option to conserve memory
|
||||
threadFunctions[i].reserve(30000);
|
||||
|
||||
// Execute
|
||||
duint threadWorkStart = (workAmount * i);
|
||||
duint threadWorkStop = min((threadWorkStart + workAmount), m_MainBlocks.size());
|
||||
|
||||
AnalysisWorker(threadWorkStart, threadWorkStop, &threadFunctions[i]);
|
||||
});
|
||||
|
||||
// Merge thread vectors into single local
|
||||
std::vector<FunctionDef> funcs;
|
||||
|
||||
// Merge thread vectors into single local
|
||||
for(duint i = 0; i < IdealThreadCount(); i++)
|
||||
std::move(threadFunctions[i].begin(), threadFunctions[i].end(), std::back_inserter(funcs));
|
||||
|
||||
|
@ -103,7 +103,7 @@ bool FunctionPass::Analyse()
|
|||
FunctionClear();
|
||||
for(auto & func : funcs)
|
||||
{
|
||||
FunctionAdd(func.VirtualStart, func.VirtualEnd - 1, true);
|
||||
FunctionAdd(func.VirtualStart, func.VirtualEnd - 1, true, func.InstrCount);
|
||||
}
|
||||
GuiUpdateAllViews();
|
||||
|
||||
|
@ -149,12 +149,7 @@ void FunctionPass::AnalysisWorker(duint Start, duint End, std::vector<FunctionDe
|
|||
if(!ValidateAddress(destination))
|
||||
continue;
|
||||
|
||||
FunctionDef def;
|
||||
def.VirtualStart = destination;
|
||||
def.VirtualEnd = 0;
|
||||
def.BBlockStart = 0;
|
||||
def.BBlockEnd = 0;
|
||||
Blocks->push_back(def);
|
||||
Blocks->push_back({ destination, 0, 0, 0, 0 });
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -169,8 +164,6 @@ void FunctionPass::AnalysisWorker(duint Start, duint End, std::vector<FunctionDe
|
|||
//
|
||||
FindFunctionWorker(Blocks);
|
||||
|
||||
dprintf("PRE: Total detected functions: %d\n", Blocks->size());
|
||||
|
||||
//
|
||||
// Step 5: Find all orphaned blocks and repeat analysis process
|
||||
//
|
||||
|
@ -195,11 +188,7 @@ void FunctionPass::AnalysisWorker(duint Start, duint End, std::vector<FunctionDe
|
|||
continue;
|
||||
|
||||
// Try to define a function
|
||||
FunctionDef def;
|
||||
def.VirtualStart = blockItr->VirtualStart;
|
||||
def.VirtualEnd = 0;
|
||||
def.BBlockStart = 0;
|
||||
def.BBlockEnd = 0;
|
||||
FunctionDef def { blockItr->VirtualStart, 0, 0, 0, 0 };
|
||||
|
||||
if (ResolveFunctionEnd(&def, finalBlock))
|
||||
{
|
||||
|
@ -207,8 +196,6 @@ void FunctionPass::AnalysisWorker(duint Start, duint End, std::vector<FunctionDe
|
|||
virtEnd = def.VirtualEnd;
|
||||
}
|
||||
}
|
||||
|
||||
dprintf("POST: Total detected functions: %d\n", Blocks->size());
|
||||
}
|
||||
|
||||
void FunctionPass::FindFunctionWorkerPrepass(duint Start, duint End, std::vector<FunctionDef>* Blocks)
|
||||
|
@ -227,13 +214,8 @@ void FunctionPass::FindFunctionWorkerPrepass(duint Start, duint End, std::vector
|
|||
// If within limits...
|
||||
if(funcAddr >= minFunc && funcAddr < maxFunc)
|
||||
{
|
||||
// Add the descriptor
|
||||
FunctionDef def;
|
||||
def.VirtualStart = funcAddr;
|
||||
def.VirtualEnd = funcEnd;
|
||||
def.BBlockStart = 0;
|
||||
def.BBlockEnd = 0;
|
||||
Blocks->push_back(def);
|
||||
// Add the descriptor (virtual start/end)
|
||||
Blocks->push_back({ funcAddr, funcEnd, 0, 0, 0 });
|
||||
}
|
||||
|
||||
return true;
|
||||
|
@ -246,13 +228,8 @@ void FunctionPass::FindFunctionWorkerPrepass(duint Start, duint End, std::vector
|
|||
// If within limits...
|
||||
if(Address >= minFunc && Address < maxFunc)
|
||||
{
|
||||
// Add the descriptor
|
||||
FunctionDef def;
|
||||
def.VirtualStart = Address;
|
||||
def.VirtualEnd = 0;
|
||||
def.BBlockStart = 0;
|
||||
def.BBlockEnd = 0;
|
||||
Blocks->push_back(def);
|
||||
// Add the descriptor (virtual start)
|
||||
Blocks->push_back({ Address, 0, 0, 0, 0 });
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -265,8 +242,7 @@ void FunctionPass::FindFunctionWorker(std::vector<FunctionDef>* Blocks)
|
|||
// Enumerate all function entries for this thread
|
||||
for(auto & block : *Blocks)
|
||||
{
|
||||
// Sometimes the ending address is already supplied, so
|
||||
// check first
|
||||
// Sometimes the ending address is already supplied, so check first
|
||||
if(block.VirtualEnd != 0)
|
||||
{
|
||||
if(ResolveKnownFunctionEnd(&block))
|
||||
|
@ -292,9 +268,15 @@ bool FunctionPass::ResolveKnownFunctionEnd(FunctionDef* Function)
|
|||
Function->BBlockEnd = FindBBlockIndex(endBlock);
|
||||
|
||||
// Set the flag for blocks that have been scanned
|
||||
for(BasicBlock* block = startBlock; (duint)block <= (duint)endBlock; block++)
|
||||
for (BasicBlock* block = startBlock; (duint)block <= (duint)endBlock; block++)
|
||||
{
|
||||
// Block now in use
|
||||
block->SetFlag(BASIC_BLOCK_FLAG_FUNCTION);
|
||||
|
||||
// Counter
|
||||
Function->InstrCount += block->InstrCount;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -322,6 +304,9 @@ bool FunctionPass::ResolveFunctionEnd(FunctionDef* Function, BasicBlock* LastBlo
|
|||
// Block is now in use
|
||||
block->SetFlag(BASIC_BLOCK_FLAG_FUNCTION);
|
||||
|
||||
// Increment instruction count
|
||||
Function->InstrCount += block->InstrCount;
|
||||
|
||||
// Calculate max from just linear instructions
|
||||
maximumAddr = max(maximumAddr, block->VirtualEnd - 1);
|
||||
|
||||
|
@ -391,10 +376,10 @@ void FunctionPass::EnumerateFunctionRuntimeEntries64(std::function<bool (PRUNTIM
|
|||
|
||||
// Get the table pointer and size
|
||||
auto functionTable = (PRUNTIME_FUNCTION)m_FunctionInfo;
|
||||
ULONG totalCount = (m_FunctionInfoSize / sizeof(RUNTIME_FUNCTION));
|
||||
size_t totalCount = (m_FunctionInfoSize / sizeof(RUNTIME_FUNCTION));
|
||||
|
||||
// Enumerate each entry
|
||||
for(ULONG i = 0; i < totalCount; i++)
|
||||
for (size_t i = 0; i < totalCount; i++)
|
||||
{
|
||||
if(!Callback(&functionTable[i]))
|
||||
break;
|
||||
|
|
|
@ -145,10 +145,13 @@ void LinearPass::AnalysisWorker(duint Start, duint End, BBlockArray* Blocks)
|
|||
Capstone disasm;
|
||||
|
||||
duint blockBegin = Start; // BBlock starting virtual address
|
||||
duint blockEnd; // BBlock ending virtual address
|
||||
duint blockEnd = 0; // BBlock ending virtual address
|
||||
|
||||
bool blockPrevPad = false; // Indicator if the last instruction was padding
|
||||
BasicBlock* lastBlock = nullptr; // Avoid an expensive call to std::vector::back()
|
||||
|
||||
int insnCount = 0; // Temporary number of instructions counted for a block
|
||||
|
||||
for(duint i = Start; i < End;)
|
||||
{
|
||||
if(!disasm.Disassemble(i, TranslateAddress(i)))
|
||||
|
@ -158,9 +161,10 @@ void LinearPass::AnalysisWorker(duint Start, duint End, BBlockArray* Blocks)
|
|||
continue;
|
||||
}
|
||||
|
||||
// Increment counter
|
||||
// Increment counters
|
||||
i += disasm.Size();
|
||||
blockEnd = i;
|
||||
insnCount++;
|
||||
|
||||
// The basic block ends here if it is a branch
|
||||
bool call = disasm.InGroup(CS_GRP_CALL); // CALL
|
||||
|
@ -182,6 +186,8 @@ void LinearPass::AnalysisWorker(duint Start, duint End, BBlockArray* Blocks)
|
|||
lastBlock->SetFlag(BASIC_BLOCK_FLAG_PREPAD);
|
||||
|
||||
blockBegin = realBlockEnd;
|
||||
lastBlock->InstrCount = insnCount;
|
||||
insnCount = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -198,30 +204,39 @@ void LinearPass::AnalysisWorker(duint Start, duint End, BBlockArray* Blocks)
|
|||
// Otherwise use the default route: create a new entry
|
||||
auto block = lastBlock = CreateBlockWorker(Blocks, blockBegin, blockEnd, call, jmp, ret, padding);
|
||||
|
||||
// Figure out the operand type
|
||||
auto operand = disasm.x86().operands[0];
|
||||
// Counters
|
||||
lastBlock->InstrCount = insnCount;
|
||||
insnCount = 0;
|
||||
|
||||
if(operand.type == X86_OP_IMM)
|
||||
if (!padding)
|
||||
{
|
||||
// Branch target immediate
|
||||
block->Target = (duint)operand.imm;
|
||||
|
||||
// Check if absolute jump
|
||||
if(disasm.GetId() == X86_INS_JMP)
|
||||
// Check if absolute jump, regardless of operand
|
||||
if (disasm.GetId() == X86_INS_JMP)
|
||||
block->SetFlag(BASIC_BLOCK_FLAG_ABSJMP);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Indirects
|
||||
block->SetFlag(BASIC_BLOCK_FLAG_INDIRECT);
|
||||
|
||||
if(operand.type == X86_OP_MEM &&
|
||||
operand.mem.base == X86_REG_INVALID &&
|
||||
operand.mem.index == X86_REG_INVALID &&
|
||||
operand.mem.scale == 1)
|
||||
// Figure out the operand type(s)
|
||||
const auto& operand = disasm.x86().operands[0];
|
||||
|
||||
if (operand.type == X86_OP_IMM)
|
||||
{
|
||||
block->SetFlag(BASIC_BLOCK_FLAG_INDIRPTR);
|
||||
block->Target = (duint)operand.mem.disp;
|
||||
// Branch target immediate
|
||||
block->Target = (duint)operand.imm;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Indirects (no operand, register, or memory)
|
||||
block->SetFlag(BASIC_BLOCK_FLAG_INDIRECT);
|
||||
|
||||
if (operand.type == X86_OP_MEM &&
|
||||
operand.mem.base == X86_REG_RIP &&
|
||||
operand.mem.index == X86_REG_INVALID &&
|
||||
operand.mem.scale == 1)
|
||||
{
|
||||
/*
|
||||
block->SetFlag(BASIC_BLOCK_FLAG_INDIRPTR);
|
||||
block->Target = (duint)operand.mem.disp;
|
||||
*/
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -284,14 +299,16 @@ void LinearPass::AnalysisOverlapWorker(duint Start, duint End, BBlockArray* Inse
|
|||
block1.VirtualStart = removal->VirtualStart;
|
||||
block1.VirtualEnd = curr->Target;
|
||||
block1.Target = 0;
|
||||
block1.Flags = removal->Flags;
|
||||
block1.Flags = BASIC_BLOCK_FLAG_CUTOFF; // Attributes of the top half
|
||||
block1.InstrCount = removal->InstrCount;
|
||||
|
||||
// Block part 2
|
||||
BasicBlock block2;
|
||||
block2.VirtualStart = curr->Target;
|
||||
block2.VirtualEnd = removal->VirtualEnd;
|
||||
block2.Target = removal->Target;
|
||||
block2.Flags = BASIC_BLOCK_FLAG_CUTOFF;
|
||||
block2.Flags = removal->Flags; // Attributes of the bottom half (taken from original block)
|
||||
block2.InstrCount = removal->InstrCount;
|
||||
|
||||
Insertions->push_back(block1);
|
||||
Insertions->push_back(block2);
|
||||
|
@ -302,11 +319,7 @@ void LinearPass::AnalysisOverlapWorker(duint Start, duint End, BBlockArray* Inse
|
|||
|
||||
BasicBlock* LinearPass::CreateBlockWorker(std::vector<BasicBlock>* Blocks, duint Start, duint End, bool Call, bool Jmp, bool Ret, bool Pad)
|
||||
{
|
||||
BasicBlock block;
|
||||
block.VirtualStart = Start;
|
||||
block.VirtualEnd = End;
|
||||
block.Flags = 0;
|
||||
block.Target = 0;
|
||||
BasicBlock block { Start, End, 0, 0, 0 };
|
||||
|
||||
// Check for calls
|
||||
if(Call)
|
||||
|
|
|
@ -193,7 +193,7 @@ extern "C" DLL_EXPORT bool _dbg_addrinfoget(duint addr, SEGMENTREG segment, ADDR
|
|||
}
|
||||
if(addrinfo->flags & flagfunction)
|
||||
{
|
||||
if(FunctionGet(addr, &addrinfo->function.start, &addrinfo->function.end))
|
||||
if (FunctionGet(addr, &addrinfo->function.start, &addrinfo->function.end, &addrinfo->function.instrcount))
|
||||
retval = true;
|
||||
}
|
||||
if(addrinfo->flags & flagloop)
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
|
||||
std::map<ModuleRange, FUNCTIONSINFO, ModuleRangeCompare> functions;
|
||||
|
||||
bool FunctionAdd(duint Start, duint End, bool Manual)
|
||||
bool FunctionAdd(duint Start, duint End, bool Manual, int InstructionCount)
|
||||
{
|
||||
ASSERT_DEBUGGING("Export call");
|
||||
|
||||
|
@ -28,6 +28,7 @@ bool FunctionAdd(duint Start, duint End, bool Manual)
|
|||
function.start = Start - moduleBase;
|
||||
function.end = End - moduleBase;
|
||||
function.manual = Manual;
|
||||
function.instructioncount = InstructionCount;
|
||||
|
||||
// Insert to global table
|
||||
EXCLUSIVE_ACQUIRE(LockFunctions);
|
||||
|
@ -36,7 +37,7 @@ bool FunctionAdd(duint Start, duint End, bool Manual)
|
|||
return true;
|
||||
}
|
||||
|
||||
bool FunctionGet(duint Address, duint* Start, duint* End)
|
||||
bool FunctionGet(duint Address, duint* Start, duint* End, duint* InstrCount)
|
||||
{
|
||||
ASSERT_DEBUGGING("Export call");
|
||||
|
||||
|
@ -57,6 +58,9 @@ bool FunctionGet(duint Address, duint* Start, duint* End)
|
|||
if(End)
|
||||
*End = found->second.end + moduleBase;
|
||||
|
||||
if(InstrCount)
|
||||
*InstrCount = found->second.instructioncount;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -142,6 +146,7 @@ void FunctionCacheSave(JSON Root)
|
|||
json_object_set_new(currentFunction, "module", json_string(i.second.mod));
|
||||
json_object_set_new(currentFunction, "start", json_hex(i.second.start));
|
||||
json_object_set_new(currentFunction, "end", json_hex(i.second.end));
|
||||
json_object_set_new(currentFunction, "icount", json_hex(i.second.instructioncount));
|
||||
|
||||
if(i.second.manual)
|
||||
json_array_append_new(jsonFunctions, currentFunction);
|
||||
|
@ -187,6 +192,7 @@ void FunctionCacheLoad(JSON Root)
|
|||
functionInfo.start = (duint)json_hex_value(json_object_get(value, "start"));
|
||||
functionInfo.end = (duint)json_hex_value(json_object_get(value, "end"));
|
||||
functionInfo.manual = Manual;
|
||||
functionInfo.instructioncount = (duint)json_hex_value(json_object_get(value, "icount"));
|
||||
|
||||
// Sanity check
|
||||
if(functionInfo.end < functionInfo.start)
|
||||
|
|
|
@ -8,10 +8,11 @@ struct FUNCTIONSINFO
|
|||
duint start;
|
||||
duint end;
|
||||
bool manual;
|
||||
int instructioncount;
|
||||
};
|
||||
|
||||
bool FunctionAdd(duint Start, duint End, bool Manual);
|
||||
bool FunctionGet(duint Address, duint* Start, duint* End);
|
||||
bool FunctionAdd(duint Start, duint End, bool Manual, int InstructionCount = 0);
|
||||
bool FunctionGet(duint Address, duint* Start = nullptr, duint* End = nullptr, duint* InstrCount = nullptr);
|
||||
bool FunctionOverlaps(duint Start, duint End);
|
||||
bool FunctionDelete(duint Address);
|
||||
void FunctionDelRange(duint Start, duint End);
|
||||
|
|
Loading…
Reference in New Issue