1
0
Fork 0

DBG+GUI: Various analysis and function drawing code fixes

This commit is contained in:
Nukem 2015-11-26 00:56:43 -05:00
parent ae2e3dabfb
commit 2de45d6087
9 changed files with 84 additions and 75 deletions

View File

@ -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;

View File

@ -323,6 +323,7 @@ typedef struct
{
duint start; //OUT
duint end; //OUT
duint instrcount; //OUT
} FUNCTION;
typedef struct

View File

@ -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];
}

View File

@ -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)

View File

@ -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;

View File

@ -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)

View File

@ -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)

View File

@ -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)

View File

@ -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);