Merge branch 'patch-1' of https://github.com/torusrxxx/x64dbg into torusrxxx-patch-1
Conflicts: src/dbg/_dbgfunctions.cpp src/dbg/_dbgfunctions.h src/dbg/threading.h src/dbg/x64_dbg_dbg.vcxproj.filters src/gui/Src/Gui/CPUDisassembly.cpp src/gui/Src/Gui/CPUDisassembly.h
This commit is contained in:
commit
ffac42d16d
|
|
@ -106,7 +106,7 @@ BRIDGE_IMPEXP void* BridgeAlloc(size_t size)
|
|||
unsigned char* ptr = (unsigned char*)GlobalAlloc(GMEM_FIXED, size);
|
||||
if(!ptr)
|
||||
{
|
||||
MessageBoxA(0, "Could not allocate memory", "Error", MB_ICONERROR);
|
||||
MessageBoxW(0, L"Could not allocate memory", L"Error", MB_ICONERROR);
|
||||
ExitProcess(1);
|
||||
}
|
||||
memset(ptr, 0, size);
|
||||
|
|
|
|||
|
|
@ -0,0 +1,447 @@
|
|||
#include "TraceRecord.h"
|
||||
#include "capstone_wrapper.h"
|
||||
#include "module.h"
|
||||
#include "memory.h"
|
||||
#include "threading.h"
|
||||
#include "console.h"
|
||||
#include <algorithm>
|
||||
|
||||
TraceRecordManager TraceRecord;
|
||||
|
||||
TraceRecordManager::TraceRecordManager() : instructionCounter(0)
|
||||
{
|
||||
ModuleNames.emplace_back("");
|
||||
}
|
||||
|
||||
TraceRecordManager::~TraceRecordManager()
|
||||
{
|
||||
clear();
|
||||
}
|
||||
|
||||
void TraceRecordManager::clear()
|
||||
{
|
||||
EXCLUSIVE_ACQUIRE(LockTraceRecord);
|
||||
for(auto i = TraceRecord.begin(); i != TraceRecord.end(); i++)
|
||||
efree(i->second.rawPtr, "TraceRecordManager");
|
||||
TraceRecord.clear();
|
||||
ModuleNames.clear();
|
||||
ModuleNames.emplace_back("");
|
||||
}
|
||||
|
||||
bool TraceRecordManager::setTraceRecordType(duint pageAddress, TraceRecordType type)
|
||||
{
|
||||
EXCLUSIVE_ACQUIRE(LockTraceRecord);
|
||||
pageAddress &= ~((duint)4096 - 1);
|
||||
auto pageInfo = TraceRecord.find(ModHashFromAddr(pageAddress));
|
||||
if(pageInfo == TraceRecord.end())
|
||||
{
|
||||
if(type != TraceRecordType::TraceRecordNone)
|
||||
{
|
||||
TraceRecordPage newPage;
|
||||
char modName[MAX_MODULE_SIZE];
|
||||
switch(type)
|
||||
{
|
||||
case TraceRecordBitExec:
|
||||
newPage.rawPtr = emalloc(4096 / 8, "TraceRecordManager");
|
||||
memset(newPage.rawPtr, 0, 4096 / 8);
|
||||
break;
|
||||
case TraceRecordByteWithExecTypeAndCounter:
|
||||
newPage.rawPtr = emalloc(4096, "TraceRecordManager");
|
||||
memset(newPage.rawPtr, 0, 4096);
|
||||
break;
|
||||
case TraceRecordWordWithExecTypeAndCounter:
|
||||
newPage.rawPtr = emalloc(4096 * 2, "TraceRecordManager");
|
||||
memset(newPage.rawPtr, 0, 4096 * 2);
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
newPage.dataType = type;
|
||||
if(ModNameFromAddr(pageAddress, modName, true))
|
||||
{
|
||||
newPage.rva = pageAddress - ModBaseFromAddr(pageAddress);
|
||||
newPage.moduleIndex = getModuleIndex(std::string(modName));
|
||||
}
|
||||
else
|
||||
newPage.moduleIndex = ~0;
|
||||
|
||||
auto inserted = TraceRecord.insert(std::make_pair(ModHashFromAddr(pageAddress), newPage));
|
||||
if(inserted.second == false) // we failed to insert new page into the map
|
||||
{
|
||||
free(newPage.rawPtr);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
else
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(type == TraceRecordType::TraceRecordNone)
|
||||
{
|
||||
if(pageInfo != TraceRecord.end())
|
||||
{
|
||||
efree(pageInfo->second.rawPtr, "TraceRecordManager");
|
||||
TraceRecord.erase(pageInfo);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
else
|
||||
return pageInfo->second.dataType == type; //Can't covert between data types
|
||||
}
|
||||
}
|
||||
|
||||
TraceRecordManager::TraceRecordType TraceRecordManager::getTraceRecordType(duint pageAddress)
|
||||
{
|
||||
SHARED_ACQUIRE(LockTraceRecord);
|
||||
pageAddress &= ~((duint)4096 - 1);
|
||||
auto pageInfo = TraceRecord.find(ModHashFromAddr(pageAddress));
|
||||
if(pageInfo == TraceRecord.end())
|
||||
return TraceRecordNone;
|
||||
else
|
||||
return pageInfo->second.dataType;
|
||||
}
|
||||
|
||||
void TraceRecordManager::TraceExecute(duint address, duint size)
|
||||
{
|
||||
SHARED_ACQUIRE(LockTraceRecord);
|
||||
if(size == 0)
|
||||
return;
|
||||
duint base = address & ~((duint)4096 - 1);
|
||||
auto pageInfoIterator = TraceRecord.find(ModHashFromAddr(base));
|
||||
if(pageInfoIterator == TraceRecord.end())
|
||||
return;
|
||||
TraceRecordPage pageInfo;
|
||||
pageInfo = pageInfoIterator->second;
|
||||
duint offset = address - base;
|
||||
bool isMixed;
|
||||
if((offset + size) > 4096) // execution crossed page boundary, splitting into 2 sub calls. Noting that byte type may be mislabelled.
|
||||
{
|
||||
SHARED_RELEASE();
|
||||
TraceExecute(address, 4096 - offset);
|
||||
TraceExecute(base + 4096, size + offset - 4096);
|
||||
return;
|
||||
}
|
||||
isMixed = false;
|
||||
switch(pageInfo.dataType)
|
||||
{
|
||||
case TraceRecordType::TraceRecordBitExec:
|
||||
for(unsigned char i = 0; i < size; i++)
|
||||
*((char*)pageInfo.rawPtr + (i + offset) / 8) |= 1 << ((i + offset) % 8);
|
||||
break;
|
||||
|
||||
case TraceRecordType::TraceRecordByteWithExecTypeAndCounter:
|
||||
for(unsigned char i = 0; i < size; i++)
|
||||
{
|
||||
TraceRecordByteType_2bit currentByteType;
|
||||
if(isMixed)
|
||||
currentByteType = TraceRecordByteType_2bit::_InstructionOverlapped;
|
||||
else if(i == 0)
|
||||
currentByteType = TraceRecordByteType_2bit::_InstructionHeading;
|
||||
else if(i == size - 1)
|
||||
currentByteType = TraceRecordByteType_2bit::_InstructionTailing;
|
||||
else
|
||||
currentByteType = TraceRecordByteType_2bit::_InstructionBody;
|
||||
|
||||
char* data = (char*)pageInfo.rawPtr + offset + i;
|
||||
if(*data == 0)
|
||||
{
|
||||
*data = (char)currentByteType << 6 | 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
isMixed |= (*data & 0xC0) >> 6 == currentByteType;
|
||||
*data = ((char)currentByteType << 6) | ((*data & 0x3F) == 0x3F ? 0x3F : (*data & 0x3F) + 1);
|
||||
}
|
||||
}
|
||||
if(isMixed)
|
||||
for(unsigned char i = 0; i < size; i++)
|
||||
*((char*)pageInfo.rawPtr + i + offset) |= 0xC0;
|
||||
break;
|
||||
|
||||
case TraceRecordType::TraceRecordWordWithExecTypeAndCounter:
|
||||
for(unsigned char i = 0; i < size; i++)
|
||||
{
|
||||
TraceRecordByteType_2bit currentByteType;
|
||||
if(isMixed)
|
||||
currentByteType = TraceRecordByteType_2bit::_InstructionOverlapped;
|
||||
else if(i == 0)
|
||||
currentByteType = TraceRecordByteType_2bit::_InstructionHeading;
|
||||
else if(i == size - 1)
|
||||
currentByteType = TraceRecordByteType_2bit::_InstructionTailing;
|
||||
else
|
||||
currentByteType = TraceRecordByteType_2bit::_InstructionBody;
|
||||
|
||||
short* data = (short*)pageInfo.rawPtr + offset + i;
|
||||
if(*data == 0)
|
||||
{
|
||||
*data = (char)currentByteType << 14 | 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
isMixed |= (*data & 0xC0) >> 6 == currentByteType;
|
||||
*data = ((char)currentByteType << 14) | ((*data & 0x3FFF) == 0x3FFF ? 0x3FFF : (*data & 0x3FFF) + 1);
|
||||
}
|
||||
}
|
||||
if(isMixed)
|
||||
for(unsigned char i = 0; i < size; i++)
|
||||
*((short*)pageInfo.rawPtr + i + offset) |= 0xC000;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
unsigned int TraceRecordManager::getHitCount(duint address)
|
||||
{
|
||||
SHARED_ACQUIRE(LockTraceRecord);
|
||||
duint base = address & ~((duint)4096 - 1);
|
||||
auto pageInfoIterator = TraceRecord.find(ModHashFromAddr(base));
|
||||
if(pageInfoIterator == TraceRecord.end())
|
||||
return 0;
|
||||
else
|
||||
{
|
||||
TraceRecordPage pageInfo = pageInfoIterator->second;
|
||||
duint offset = address - base;
|
||||
switch(pageInfo.dataType)
|
||||
{
|
||||
case TraceRecordType::TraceRecordBitExec:
|
||||
return ((char*)pageInfo.rawPtr)[offset / 8] & (1 << (offset % 8)) ? 1 : 0;
|
||||
case TraceRecordType::TraceRecordByteWithExecTypeAndCounter:
|
||||
return ((char*)pageInfo.rawPtr)[offset] & 0x3F;
|
||||
case TraceRecordType::TraceRecordWordWithExecTypeAndCounter:
|
||||
return ((short*)pageInfo.rawPtr)[offset] & 0x3FFF;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TraceRecordManager::TraceRecordByteType TraceRecordManager::getByteType(duint address)
|
||||
{
|
||||
SHARED_ACQUIRE(LockTraceRecord);
|
||||
duint base = address & ~((duint)4096 - 1);
|
||||
auto pageInfoIterator = TraceRecord.find(ModHashFromAddr(base));
|
||||
if(pageInfoIterator == TraceRecord.end())
|
||||
return TraceRecordByteType::InstructionHeading;
|
||||
else
|
||||
{
|
||||
TraceRecordPage pageInfo = pageInfoIterator->second;
|
||||
duint offset = address - base;
|
||||
switch(pageInfo.dataType)
|
||||
{
|
||||
case TraceRecordType::TraceRecordBitExec:
|
||||
default:
|
||||
return TraceRecordByteType::InstructionHeading;
|
||||
case TraceRecordType::TraceRecordByteWithExecTypeAndCounter:
|
||||
return (TraceRecordByteType)((((char*)pageInfo.rawPtr)[offset] & 0xC0) >> 6);
|
||||
case TraceRecordType::TraceRecordWordWithExecTypeAndCounter:
|
||||
return (TraceRecordByteType)((((short*)pageInfo.rawPtr)[offset] & 0xC000) >> 14);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void TraceRecordManager::increaseInstructionCounter()
|
||||
{
|
||||
InterlockedIncrement(&instructionCounter);
|
||||
}
|
||||
|
||||
|
||||
void TraceRecordManager::saveToDb(JSON root)
|
||||
{
|
||||
EXCLUSIVE_ACQUIRE(LockTraceRecord);
|
||||
const JSON jsonTraceRecords = json_array();
|
||||
const char* byteToHex = "0123456789ABCDEF";
|
||||
for(auto i : TraceRecord)
|
||||
{
|
||||
JSON jsonObj = json_object();
|
||||
duint j;
|
||||
json_object_set_new(jsonObj, "idx", json_hex(i.first));
|
||||
if(i.second.moduleIndex != ~0)
|
||||
{
|
||||
json_object_set_new(jsonObj, "module", json_string(ModuleNames[i.second.moduleIndex].c_str()));
|
||||
json_object_set_new(jsonObj, "rva", json_hex(i.second.rva));
|
||||
}
|
||||
else
|
||||
{
|
||||
json_object_set_new(jsonObj, "module", json_string(""));
|
||||
json_object_set_new(jsonObj, "rva", json_hex(i.first));
|
||||
}
|
||||
json_object_set_new(jsonObj, "type", json_hex((duint)i.second.dataType));
|
||||
char* ptr = (char*)i.second.rawPtr;
|
||||
duint size = 0;
|
||||
char* temp;
|
||||
switch(i.second.dataType)
|
||||
{
|
||||
case TraceRecordType::TraceRecordBitExec:
|
||||
size = 4096 / 8;
|
||||
break;
|
||||
case TraceRecordType::TraceRecordByteWithExecTypeAndCounter:
|
||||
size = 4096;
|
||||
break;
|
||||
case TraceRecordType::TraceRecordWordWithExecTypeAndCounter:
|
||||
size = 4096 * 2;
|
||||
break;
|
||||
default:
|
||||
__debugbreak(); // We have encountered an error condition.
|
||||
}
|
||||
temp = (char*)emalloc(size * 2 + 1, "TraceRecordManager::saveToDb");
|
||||
for(j = 0; j < size; j++)
|
||||
{
|
||||
temp[j * 2 + 1] = byteToHex[ptr[j] & 0xF];
|
||||
temp[j * 2] = byteToHex[(ptr[j] & 0xF0) >> 4];
|
||||
}
|
||||
temp[size * 2] = 0;
|
||||
json_object_set_new(jsonObj, "data", json_string(temp));
|
||||
efree(temp, "TraceRecordManager::saveToDb");
|
||||
json_array_append_new(jsonTraceRecords, jsonObj);
|
||||
}
|
||||
json_object_set_new(root, "tracerecord", jsonTraceRecords);
|
||||
}
|
||||
|
||||
void TraceRecordManager::loadFromDb(JSON root)
|
||||
{
|
||||
clear();
|
||||
EXCLUSIVE_ACQUIRE(LockTraceRecord);
|
||||
// get the root object
|
||||
const JSON tracerecord = json_object_get(root, "tracerecord");
|
||||
|
||||
// return if nothing found
|
||||
if(!tracerecord)
|
||||
return;
|
||||
|
||||
size_t i;
|
||||
JSON value;
|
||||
json_array_foreach(tracerecord, i, value)
|
||||
{
|
||||
TraceRecordPage currentPage;
|
||||
size_t size;
|
||||
currentPage.dataType = (TraceRecordType)json_hex_value(json_object_get(value, "type"));
|
||||
currentPage.rva = json_hex_value(json_object_get(value, "rva"));
|
||||
switch(currentPage.dataType)
|
||||
{
|
||||
case TraceRecordType::TraceRecordBitExec:
|
||||
size = 4096 / 8;
|
||||
break;
|
||||
case TraceRecordType::TraceRecordByteWithExecTypeAndCounter:
|
||||
size = 4096;
|
||||
break;
|
||||
case TraceRecordType::TraceRecordWordWithExecTypeAndCounter:
|
||||
size = 4096 * 2;
|
||||
break;
|
||||
default:
|
||||
size = 0;
|
||||
break;
|
||||
}
|
||||
if(size != 0)
|
||||
{
|
||||
currentPage.rawPtr = emalloc(size, "TraceRecordManager");
|
||||
const char* p = json_string_value(json_object_get(value, "data"));
|
||||
char* read_ptr = (char*)currentPage.rawPtr;
|
||||
const char* c;
|
||||
for(c = p; c < p + size * 2 && *c != '\0'; c += 2, read_ptr++)
|
||||
{
|
||||
if(c[1] >= '0' && c[1] <= '9')
|
||||
*read_ptr = c[1] - '0';
|
||||
else if(c[1] >= 'A' && c[0] <= 'F')
|
||||
*read_ptr = c[1] - 'A' + 10;
|
||||
else
|
||||
break;
|
||||
if(c[0] >= '0' && c[0] <= '9')
|
||||
*read_ptr |= (c[0] - '0') << 4;
|
||||
else if(c[0] >= 'A' && c[0] <= 'F')
|
||||
*read_ptr |= (c[0] - 'A' + 10) << 4;
|
||||
else
|
||||
break;
|
||||
}
|
||||
if(c != p + size * 2)
|
||||
{
|
||||
efree(currentPage.rawPtr, "TraceRecordManager");
|
||||
}
|
||||
else
|
||||
{
|
||||
const char* moduleName = json_string_value(json_object_get(value, "module"));
|
||||
duint key;
|
||||
dprintf("%s\n", moduleName);
|
||||
if(*moduleName)
|
||||
{
|
||||
currentPage.moduleIndex = getModuleIndex(std::string(moduleName));
|
||||
key = currentPage.rva + ModHashFromName(moduleName);
|
||||
}
|
||||
else
|
||||
{
|
||||
currentPage.moduleIndex = ~0;
|
||||
key = currentPage.rva;
|
||||
}
|
||||
TraceRecord.insert(std::make_pair(key, currentPage));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
unsigned int TraceRecordManager::getModuleIndex(std::string moduleName)
|
||||
{
|
||||
auto iterator = std::find(ModuleNames.begin(), ModuleNames.end(), moduleName);
|
||||
if(iterator != ModuleNames.end())
|
||||
return iterator - ModuleNames.begin(); //TODO: warning
|
||||
else
|
||||
{
|
||||
ModuleNames.push_back(moduleName);
|
||||
return ModuleNames.size() - 1; //TODO: warning
|
||||
}
|
||||
}
|
||||
|
||||
void _dbg_dbgtraceexecute(duint CIP)
|
||||
{
|
||||
if(TraceRecord.getTraceRecordType(CIP) != TraceRecordManager::TraceRecordType::TraceRecordNone)
|
||||
{
|
||||
Capstone disassembler;
|
||||
unsigned char buffer[16];
|
||||
duint size;
|
||||
if(MemRead(CIP, buffer, 16))
|
||||
{
|
||||
TraceRecord.increaseInstructionCounter();
|
||||
disassembler.Disassemble(CIP, buffer);
|
||||
size = disassembler.Success() ? disassembler.Size() : 1;
|
||||
TraceRecord.TraceExecute(CIP, size);
|
||||
}
|
||||
else
|
||||
{
|
||||
duint base = MemFindBaseAddr(CIP, &size);
|
||||
if(CIP - base + 16 > size) // Corner case where CIP is near the end of the page
|
||||
{
|
||||
size = base + size - CIP;
|
||||
if(MemRead(CIP, buffer, size))
|
||||
{
|
||||
TraceRecord.increaseInstructionCounter();
|
||||
disassembler.Disassemble(CIP, buffer, size); //TODO: warning
|
||||
size = disassembler.Success() ? disassembler.Size() : 1;
|
||||
TraceRecord.TraceExecute(CIP, size);
|
||||
return;
|
||||
}
|
||||
}
|
||||
// if we reaches here, then the executable had executed an invalid address. Don't trace it.
|
||||
}
|
||||
}
|
||||
else
|
||||
TraceRecord.increaseInstructionCounter();
|
||||
}
|
||||
|
||||
unsigned int _dbg_dbggetTraceRecordHitCount(duint address)
|
||||
{
|
||||
return TraceRecord.getHitCount(address);
|
||||
}
|
||||
TRACERECORDBYTETYPE _dbg_dbggetTraceRecordByteType(duint address)
|
||||
{
|
||||
return (TRACERECORDBYTETYPE)TraceRecord.getByteType(address);
|
||||
}
|
||||
bool _dbg_dbgsetTraceRecordType(duint pageAddress, TRACERECORDTYPE type)
|
||||
{
|
||||
return TraceRecord.setTraceRecordType(pageAddress, (TraceRecordManager::TraceRecordType)type);
|
||||
}
|
||||
TRACERECORDTYPE _dbg_dbggetTraceRecordType(duint pageAddress)
|
||||
{
|
||||
return (TRACERECORDTYPE)TraceRecord.getTraceRecordType(pageAddress);
|
||||
}
|
||||
|
|
@ -0,0 +1,93 @@
|
|||
#ifndef TRACERECORD_H
|
||||
#define TRACERECORD_H
|
||||
#include "_global.h"
|
||||
#include "_dbgfunctions.h"
|
||||
|
||||
class TraceRecordManager
|
||||
{
|
||||
public:
|
||||
enum TraceRecordByteType
|
||||
{
|
||||
InstructionBody = 0,
|
||||
InstructionHeading = 1,
|
||||
InstructionTailing = 2,
|
||||
InstructionOverlapped = 3, // The byte was executed with differing instruction base addresses
|
||||
DataByte, // This and the following is not implemented yet.
|
||||
DataWord,
|
||||
DataDWord,
|
||||
DataQWord,
|
||||
DataFloat,
|
||||
DataDouble,
|
||||
DataLongDouble,
|
||||
DataXMM,
|
||||
DataYMM,
|
||||
DataMMX,
|
||||
DataMixed, //the byte is accessed in multiple ways
|
||||
InstructionDataMixed //the byte is both executed and written
|
||||
};
|
||||
|
||||
/***************************************************************
|
||||
* Trace record data layout
|
||||
* TraceRecordNonoe: disable trace record
|
||||
* TraceRecordBitExec: single-bit, executed.
|
||||
* TraceRecordByteWithExecTypeAndCounter: 8-bit, YYXXXXXX YY:=TraceRecordByteType_2bit, XXXXXX:=Hit count(6bit)
|
||||
* TraceRecordWordWithExecTypeAndCounter: 16-bit, YYXXXXXX XXXXXXXX YY:=TraceRecordByteType_2bit, XX:=Hit count(14bit)
|
||||
* Other: reserved for future expanding
|
||||
**************************************************************/
|
||||
enum TraceRecordType
|
||||
{
|
||||
TraceRecordNone,
|
||||
TraceRecordBitExec,
|
||||
TraceRecordByteWithExecTypeAndCounter,
|
||||
TraceRecordWordWithExecTypeAndCounter
|
||||
};
|
||||
|
||||
TraceRecordManager();
|
||||
~TraceRecordManager();
|
||||
void clear();
|
||||
|
||||
bool setTraceRecordType(duint pageAddress, TraceRecordType type);
|
||||
TraceRecordType getTraceRecordType(duint pageAddress);
|
||||
|
||||
void TraceExecute(duint address, duint size);
|
||||
//void TraceAccess(duint address, unsigned char size, TraceRecordByteType accessType);
|
||||
|
||||
unsigned int getHitCount(duint address);
|
||||
TraceRecordByteType getByteType(duint address);
|
||||
void increaseInstructionCounter();
|
||||
|
||||
void saveToDb(JSON root);
|
||||
void loadFromDb(JSON root);
|
||||
private:
|
||||
enum TraceRecordByteType_2bit
|
||||
{
|
||||
_InstructionBody = 0,
|
||||
_InstructionHeading = 1,
|
||||
_InstructionTailing = 2,
|
||||
_InstructionOverlapped = 3
|
||||
};
|
||||
|
||||
struct TraceRecordPage
|
||||
{
|
||||
void* rawPtr;
|
||||
duint rva;
|
||||
TraceRecordType dataType;
|
||||
unsigned int moduleIndex;
|
||||
};
|
||||
|
||||
//Key := page base, value := trace record raw data
|
||||
std::map<duint, TraceRecordPage> TraceRecord;
|
||||
std::vector<std::string> ModuleNames;
|
||||
unsigned int getModuleIndex(std::string moduleName);
|
||||
unsigned int instructionCounter;
|
||||
};
|
||||
|
||||
extern TraceRecordManager TraceRecord;
|
||||
void _dbg_dbgtraceexecute(duint CIP);
|
||||
//exported to bridge
|
||||
unsigned int _dbg_dbggetTraceRecordHitCount(duint address);
|
||||
TRACERECORDBYTETYPE _dbg_dbggetTraceRecordByteType(duint address);
|
||||
bool _dbg_dbgsetTraceRecordType(duint pageAddress, TRACERECORDTYPE type);
|
||||
TRACERECORDTYPE _dbg_dbggetTraceRecordType(duint pageAddress);
|
||||
|
||||
#endif // TRACERECORD_H
|
||||
|
|
@ -19,6 +19,7 @@
|
|||
#include "breakpoint.h"
|
||||
#include "threading.h"
|
||||
#include "stringformat.h"
|
||||
#include "TraceRecord.h"
|
||||
#include "mnemonichelp.h"
|
||||
|
||||
static DBGFUNCTIONS _dbgfunctions;
|
||||
|
|
@ -293,4 +294,8 @@ void dbgfunctionsinit()
|
|||
_dbgfunctions.GetBridgeBp = _getbridgebp;
|
||||
_dbgfunctions.StringFormatInline = _stringformatinline;
|
||||
_dbgfunctions.GetMnemonicBrief = _getmnemonicbrief;
|
||||
_dbgfunctions.GetTraceRecordHitCount = _dbg_dbggetTraceRecordHitCount;
|
||||
_dbgfunctions.GetTraceRecordByteType = _dbg_dbggetTraceRecordByteType;
|
||||
_dbgfunctions.SetTraceRecordType = _dbg_dbgsetTraceRecordType;
|
||||
_dbgfunctions.GetTraceRecordType = _dbg_dbggetTraceRecordType;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -45,6 +45,35 @@ typedef struct
|
|||
char szExeFile[MAX_PATH];
|
||||
} DBGPROCESSINFO;
|
||||
|
||||
|
||||
enum TRACERECORDBYTETYPE
|
||||
{
|
||||
InstructionBody = 0,
|
||||
InstructionHeading = 1,
|
||||
InstructionTailing = 2,
|
||||
InstructionOverlapped = 3, // The byte was executed with differing instruction base addresses
|
||||
DataByte, // This and the following is not implemented yet.
|
||||
DataWord,
|
||||
DataDWord,
|
||||
DataQWord,
|
||||
DataFloat,
|
||||
DataDouble,
|
||||
DataLongDouble,
|
||||
DataXMM,
|
||||
DataYMM,
|
||||
DataMMX,
|
||||
DataMixed, //the byte is accessed in multiple ways
|
||||
InstructionDataMixed //the byte is both executed and written
|
||||
};
|
||||
|
||||
enum TRACERECORDTYPE
|
||||
{
|
||||
TraceRecordNone,
|
||||
TraceRecordBitExec,
|
||||
TraceRecordByteWithExecTypeAndCounter,
|
||||
TraceRecordWordWithExecTypeAndCounter
|
||||
};
|
||||
|
||||
typedef bool (*ASSEMBLEATEX)(duint addr, const char* instruction, char* error, bool fillnop);
|
||||
typedef bool (*SECTIONFROMADDR)(duint addr, char* section);
|
||||
typedef bool (*MODNAMEFROMADDR)(duint addr, char* modname, bool extension);
|
||||
|
|
@ -85,6 +114,10 @@ typedef bool (*PATCHGETEX)(duint addr, DBGPATCHINFO* info);
|
|||
typedef bool(*GETBRIDGEBP)(BPXTYPE type, duint addr, BRIDGEBP* bp);
|
||||
typedef bool(*STRINGFORMATINLINE)(const char* format, size_t resultSize, char* result);
|
||||
typedef void(*GETMNEMONICBRIEF)(const char* mnem, size_t resultSize, char* result);
|
||||
typedef unsigned int (*GETTRACERECORDHITCOUNT)(duint address);
|
||||
typedef TRACERECORDBYTETYPE(*GETTRACERECORDBYTETYPE)(duint address);
|
||||
typedef bool (*SETTRACERECORDTYPE)(duint pageAddress, TRACERECORDTYPE type);
|
||||
typedef TRACERECORDTYPE(*GETTRACERECORDTYPE)(duint pageAddress);
|
||||
|
||||
typedef struct DBGFUNCTIONS_
|
||||
{
|
||||
|
|
@ -128,6 +161,10 @@ typedef struct DBGFUNCTIONS_
|
|||
GETBRIDGEBP GetBridgeBp;
|
||||
STRINGFORMATINLINE StringFormatInline;
|
||||
GETMNEMONICBRIEF GetMnemonicBrief;
|
||||
GETTRACERECORDHITCOUNT GetTraceRecordHitCount;
|
||||
GETTRACERECORDBYTETYPE GetTraceRecordByteType;
|
||||
SETTRACERECORDTYPE SetTraceRecordType;
|
||||
GETTRACERECORDTYPE GetTraceRecordType;
|
||||
} DBGFUNCTIONS;
|
||||
|
||||
#ifdef BUILD_DBG
|
||||
|
|
|
|||
|
|
@ -35,7 +35,7 @@ void* emalloc(size_t size, const char* reason)
|
|||
unsigned char* a = (unsigned char*)GlobalAlloc(GMEM_FIXED, size);
|
||||
if(!a)
|
||||
{
|
||||
MessageBoxA(0, "Could not allocate memory", "Error", MB_ICONERROR);
|
||||
MessageBoxW(0, L"Could not allocate memory", L"Error", MB_ICONERROR);
|
||||
ExitProcess(1);
|
||||
}
|
||||
memset(a, 0, size);
|
||||
|
|
@ -61,7 +61,7 @@ void* erealloc(void* ptr, size_t size, const char* reason)
|
|||
|
||||
// Free the memory if the pointer was set (as per documentation).
|
||||
if(ptr)
|
||||
efree(ptr);
|
||||
efree(ptr, reason);
|
||||
|
||||
return emalloc(size, reason);
|
||||
}
|
||||
|
|
@ -345,4 +345,4 @@ void WaitForThreadTermination(HANDLE hThread)
|
|||
{
|
||||
WaitForSingleObject(hThread, INFINITE);
|
||||
CloseHandle(hThread);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@
|
|||
#include "database.h"
|
||||
#include "threading.h"
|
||||
#include "filehelper.h"
|
||||
#include "TraceRecord.h"
|
||||
|
||||
/**
|
||||
\brief Directory where program databases are stored (usually in \db). UTF-8 encoding.
|
||||
|
|
@ -49,6 +50,7 @@ void DbSave(DbLoadSaveType saveType)
|
|||
BookmarkCacheSave(root);
|
||||
FunctionCacheSave(root);
|
||||
LoopCacheSave(root);
|
||||
TraceRecord.saveToDb(root);
|
||||
BpCacheSave(root);
|
||||
|
||||
//save notes
|
||||
|
|
@ -158,6 +160,7 @@ void DbLoad(DbLoadSaveType loadType)
|
|||
BookmarkCacheLoad(root);
|
||||
FunctionCacheLoad(root);
|
||||
LoopCacheLoad(root);
|
||||
TraceRecord.loadFromDb(root);
|
||||
BpCacheLoad(root);
|
||||
|
||||
// Load notes
|
||||
|
|
@ -251,4 +254,4 @@ void DbSetPath(const char* Directory, const char* ModulePath)
|
|||
|
||||
dprintf("Database file: %s\n", dbpath);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@
|
|||
#include "commandline.h"
|
||||
#include "stackinfo.h"
|
||||
#include "stringformat.h"
|
||||
#include "TraceRecord.h"
|
||||
|
||||
static PROCESS_INFORMATION g_pi = {0, 0, 0, 0};
|
||||
static char szBaseFileName[MAX_PATH] = "";
|
||||
|
|
@ -395,51 +396,6 @@ static bool getConditionValue(const char* expression)
|
|||
return true;
|
||||
}
|
||||
|
||||
static void BreakpointProlog(BREAKPOINT & bp, bool breakCondition, bool logCondition, bool commandCondition)
|
||||
{
|
||||
// update GUI
|
||||
if(breakCondition)
|
||||
{
|
||||
GuiSetDebugState(paused);
|
||||
DebugUpdateGui(GetContextDataEx(hActiveThread, UE_CIP), true);
|
||||
}
|
||||
|
||||
// plugin interaction
|
||||
lock(WAITID_RUN);
|
||||
if(breakCondition)
|
||||
{
|
||||
PLUG_CB_PAUSEDEBUG pauseInfo;
|
||||
pauseInfo.reserved = nullptr;
|
||||
plugincbcall(CB_PAUSEDEBUG, &pauseInfo);
|
||||
}
|
||||
PLUG_CB_BREAKPOINT bpInfo;
|
||||
BRIDGEBP bridgebp;
|
||||
bpInfo.breakpoint = &bridgebp;
|
||||
memset(&bpInfo, 0, sizeof(bpInfo));
|
||||
BpToBridge(&bp, &bridgebp);
|
||||
plugincbcall(CB_BREAKPOINT, &bpInfo);
|
||||
|
||||
if(*bp.logText && logCondition) //log
|
||||
{
|
||||
dprintf("%s\n", stringformatinline(bp.logText).c_str());
|
||||
}
|
||||
if(*bp.commandText && commandCondition) //command
|
||||
{
|
||||
//TODO: commands like run/step etc will fuck up your shit
|
||||
DbgCmdExec(bp.commandText);
|
||||
}
|
||||
if(breakCondition) //break the debugger
|
||||
{
|
||||
SetForegroundWindow(GuiGetWindowHandle());
|
||||
bSkipExceptions = false;
|
||||
}
|
||||
else //resume immediately
|
||||
unlock(WAITID_RUN);
|
||||
|
||||
//wait until the user resumes
|
||||
wait(WAITID_RUN);
|
||||
}
|
||||
|
||||
static void cbGenericBreakpoint(BP_TYPE bptype, void* ExceptionAddress = nullptr)
|
||||
{
|
||||
hActiveThread = ThreadGetHandle(((DEBUG_EVENT*)GetDebugData())->dwThreadId);
|
||||
|
|
@ -503,6 +459,7 @@ static void cbGenericBreakpoint(BP_TYPE bptype, void* ExceptionAddress = nullptr
|
|||
else
|
||||
commandCondition = breakCondition; //if no condition is set, execute the command when the debugger would break
|
||||
|
||||
lock(WAITID_RUN);
|
||||
if(breakCondition)
|
||||
{
|
||||
if(bp.singleshoot)
|
||||
|
|
@ -521,9 +478,46 @@ static void cbGenericBreakpoint(BP_TYPE bptype, void* ExceptionAddress = nullptr
|
|||
default:
|
||||
break;
|
||||
}
|
||||
GuiSetDebugState(paused);
|
||||
DebugUpdateGui(CIP, true);
|
||||
}
|
||||
|
||||
BreakpointProlog(bp, breakCondition, logCondition, commandCondition);
|
||||
// plugin interaction
|
||||
if(breakCondition)
|
||||
{
|
||||
PLUG_CB_PAUSEDEBUG pauseInfo;
|
||||
pauseInfo.reserved = nullptr;
|
||||
plugincbcall(CB_PAUSEDEBUG, &pauseInfo);
|
||||
}
|
||||
PLUG_CB_BREAKPOINT bpInfo;
|
||||
BRIDGEBP bridgebp;
|
||||
bpInfo.breakpoint = &bridgebp;
|
||||
memset(&bpInfo, 0, sizeof(bpInfo));
|
||||
BpToBridge(&bp, &bridgebp);
|
||||
plugincbcall(CB_BREAKPOINT, &bpInfo);
|
||||
|
||||
// Trace record
|
||||
_dbg_dbgtraceexecute(CIP);
|
||||
|
||||
if(*bp.logText && logCondition) //log
|
||||
{
|
||||
dprintf("%s\n", stringformatinline(bp.logText).c_str());
|
||||
}
|
||||
if(*bp.commandText && commandCondition) //command
|
||||
{
|
||||
//TODO: commands like run/step etc will fuck up your shit
|
||||
DbgCmdExec(bp.commandText);
|
||||
}
|
||||
if(breakCondition) //break the debugger
|
||||
{
|
||||
SetForegroundWindow(GuiGetWindowHandle());
|
||||
bSkipExceptions = false;
|
||||
}
|
||||
else //resume immediately
|
||||
unlock(WAITID_RUN);
|
||||
|
||||
//wait until the user resumes
|
||||
wait(WAITID_RUN);
|
||||
}
|
||||
|
||||
void cbUserBreakpoint()
|
||||
|
|
@ -706,7 +700,11 @@ void cbStep()
|
|||
hActiveThread = ThreadGetHandle(((DEBUG_EVENT*)GetDebugData())->dwThreadId);
|
||||
isStepping = false;
|
||||
GuiSetDebugState(paused);
|
||||
DebugUpdateGui(GetContextDataEx(hActiveThread, UE_CIP), true);
|
||||
duint CIP = GetContextDataEx(hActiveThread, UE_CIP);
|
||||
DebugUpdateGui(CIP, true);
|
||||
// Trace record
|
||||
_dbg_dbgtraceexecute(CIP);
|
||||
// Plugin interaction
|
||||
PLUG_CB_STEPPED stepInfo;
|
||||
stepInfo.reserved = 0;
|
||||
//lock
|
||||
|
|
@ -724,7 +722,10 @@ static void cbRtrFinalStep()
|
|||
{
|
||||
hActiveThread = ThreadGetHandle(((DEBUG_EVENT*)GetDebugData())->dwThreadId);
|
||||
GuiSetDebugState(paused);
|
||||
DebugUpdateGui(GetContextDataEx(hActiveThread, UE_CIP), true);
|
||||
duint CIP = GetContextDataEx(hActiveThread, UE_CIP);
|
||||
DebugUpdateGui(CIP, true);
|
||||
// Trace record
|
||||
_dbg_dbgtraceexecute(CIP);
|
||||
//lock
|
||||
lock(WAITID_RUN);
|
||||
SetForegroundWindow(GuiGetWindowHandle());
|
||||
|
|
@ -883,7 +884,7 @@ static void cbExitProcess(EXIT_PROCESS_DEBUG_INFO* ExitProcess)
|
|||
plugincbcall(CB_EXITPROCESS, &callbackInfo);
|
||||
//unload main module
|
||||
SafeSymUnloadModule64(fdProcessInfo->hProcess, pCreateProcessBase);
|
||||
ModUnload(pCreateProcessBase);
|
||||
ModClear(); //clear all modules
|
||||
}
|
||||
|
||||
static void cbCreateThread(CREATE_THREAD_DEBUG_INFO* CreateThread)
|
||||
|
|
@ -1530,9 +1531,7 @@ bool dbglistprocesses(std::vector<PROCESSENTRY32>* list)
|
|||
{
|
||||
if(pe32.th32ProcessID == GetCurrentProcessId())
|
||||
continue;
|
||||
if(!_stricmp(pe32.szExeFile, "System"))
|
||||
continue;
|
||||
if(!_stricmp(pe32.szExeFile, "[System Process]"))
|
||||
if(pe32.th32ProcessID == 0 || pe32.th32ProcessID == 4) // System process and Idle process have special PID.
|
||||
continue;
|
||||
Handle hProcess = TitanOpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, false, pe32.th32ProcessID);
|
||||
if(!hProcess)
|
||||
|
|
@ -1928,6 +1927,7 @@ static void debugLoopFunction(void* lpParameter, bool attach)
|
|||
DbClose();
|
||||
ModClear();
|
||||
ThreadClear();
|
||||
TraceRecord.clear();
|
||||
GuiSetDebugState(stopped);
|
||||
GuiUpdateAllViews();
|
||||
dputs("Debugging stopped!");
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ bool waitislocked(WAIT_ID id)
|
|||
void waitinitialize()
|
||||
{
|
||||
for(int i = 0; i < WAITID_LAST; i++)
|
||||
waitArray[i] = CreateEventA(NULL, TRUE, TRUE, NULL);
|
||||
waitArray[i] = CreateEventW(NULL, TRUE, TRUE, NULL);
|
||||
}
|
||||
|
||||
void waitdeinitialize()
|
||||
|
|
@ -126,4 +126,4 @@ void SectionLockerGlobal::Deinitialize()
|
|||
}
|
||||
|
||||
m_Initialized = false;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -55,6 +55,7 @@ enum SectionLock
|
|||
LockPluginMenuList,
|
||||
LockSehCache,
|
||||
LockMnemonicHelp,
|
||||
LockTraceRecord,
|
||||
|
||||
// Number of elements in this enumeration. Must always be the last
|
||||
// index.
|
||||
|
|
@ -153,4 +154,4 @@ private:
|
|||
using Internal = SectionLockerGlobal;
|
||||
};
|
||||
|
||||
#endif // _THREADING_H
|
||||
#endif // _THREADING_H
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|Win32">
|
||||
|
|
@ -70,6 +70,7 @@
|
|||
<ClCompile Include="symbolinfo.cpp" />
|
||||
<ClCompile Include="thread.cpp" />
|
||||
<ClCompile Include="threading.cpp" />
|
||||
<ClCompile Include="TraceRecord.cpp" />
|
||||
<ClCompile Include="value.cpp" />
|
||||
<ClCompile Include="variable.cpp" />
|
||||
<ClCompile Include="x64_dbg.cpp" />
|
||||
|
|
@ -148,6 +149,7 @@
|
|||
<ClInclude Include="patternfind.h" />
|
||||
<ClInclude Include="plugin_loader.h" />
|
||||
<ClInclude Include="reference.h" />
|
||||
<ClInclude Include="TraceRecord.h" />
|
||||
<ClInclude Include="yara\yara\stream.h" />
|
||||
<ClInclude Include="_scriptapi.h" />
|
||||
<ClInclude Include="simplescript.h" />
|
||||
|
|
@ -381,4 +383,4 @@
|
|||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
</Project>
|
||||
</Project>
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<Filter Include="Source Files">
|
||||
|
|
@ -296,6 +296,9 @@
|
|||
<ClCompile Include="exhandlerinfo.cpp">
|
||||
<Filter>Source Files\Information</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="TraceRecord.cpp">
|
||||
<Filter>Source Files\Information</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="mnemonichelp.cpp">
|
||||
<Filter>Source Files\Information</Filter>
|
||||
</ClCompile>
|
||||
|
|
@ -658,5 +661,8 @@
|
|||
<ClInclude Include="mnemonichelp.h">
|
||||
<Filter>Header Files\Information</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="TraceRecord.h">
|
||||
<Filter>Header Files\Information</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
</Project>
|
||||
|
|
|
|||
|
|
@ -78,6 +78,7 @@ void Disassembly::updateColors()
|
|||
mLabelColor = ConfigColor("DisassemblyLabelColor");
|
||||
mLabelBackgroundColor = ConfigColor("DisassemblyLabelBackgroundColor");
|
||||
mSelectedAddressBackgroundColor = ConfigColor("DisassemblySelectedAddressBackgroundColor");
|
||||
mTracedAddressBackgroundColor = ConfigColor("DisassemblyTracedBackgroundColor");
|
||||
mSelectedAddressColor = ConfigColor("DisassemblySelectedAddressColor");
|
||||
mAddressBackgroundColor = ConfigColor("DisassemblyAddressBackgroundColor");
|
||||
mAddressColor = ConfigColor("DisassemblyAddressColor");
|
||||
|
|
@ -133,6 +134,8 @@ QString Disassembly::paintContent(QPainter* painter, dsint rowBase, int rowOffse
|
|||
{
|
||||
Q_UNUSED(rowBase);
|
||||
|
||||
const DBGFUNCTIONS* dbgFuncs = DbgFunctions();
|
||||
bool isTraced;
|
||||
if(mHighlightingMode)
|
||||
{
|
||||
QPen pen(mInstructionHighlightColor);
|
||||
|
|
@ -144,17 +147,20 @@ QString Disassembly::paintContent(QPainter* painter, dsint rowBase, int rowOffse
|
|||
}
|
||||
dsint wRVA = mInstBuffer.at(rowOffset).rva;
|
||||
bool wIsSelected = isSelected(&mInstBuffer, rowOffset);
|
||||
dsint cur_addr = rvaToVa(mInstBuffer.at(rowOffset).rva);
|
||||
isTraced = dbgFuncs->GetTraceRecordHitCount(cur_addr) != 0;
|
||||
|
||||
// Highlight if selected
|
||||
if(wIsSelected)
|
||||
painter->fillRect(QRect(x, y, w, h), QBrush(mSelectionColor));
|
||||
else if(isTraced)
|
||||
painter->fillRect(QRect(x, y, w, h), QBrush(mTracedAddressBackgroundColor));
|
||||
|
||||
switch(col)
|
||||
{
|
||||
case 0: // Draw address (+ label)
|
||||
{
|
||||
char label[MAX_LABEL_SIZE] = "";
|
||||
dsint cur_addr = rvaToVa(mInstBuffer.at(rowOffset).rva);
|
||||
QString addrText = getAddrText(cur_addr, label);
|
||||
BPXTYPE bpxtype = DbgGetBpxTypeAt(cur_addr);
|
||||
bool isbookmark = DbgGetBookmarkAt(cur_addr);
|
||||
|
|
@ -202,12 +208,12 @@ QString Disassembly::paintContent(QPainter* painter, dsint rowBase, int rowOffse
|
|||
{
|
||||
if(*label) //label
|
||||
{
|
||||
if(bpxtype == bp_none) //label only
|
||||
if(bpxtype == bp_none) //label only : fill label background
|
||||
{
|
||||
painter->setPen(mLabelColor); //red -> address + label text
|
||||
painter->fillRect(QRect(x, y, w, h), QBrush(mLabelBackgroundColor)); //fill label background
|
||||
}
|
||||
else //label+breakpoint
|
||||
else //label + breakpoint
|
||||
{
|
||||
if(bpxtype & bp_normal) //label + normal breakpoint
|
||||
{
|
||||
|
|
@ -284,7 +290,7 @@ QString Disassembly::paintContent(QPainter* painter, dsint rowBase, int rowOffse
|
|||
painter->setPen(mLabelColor); //red -> address + label text
|
||||
painter->fillRect(QRect(x, y, w, h), QBrush(mBookmarkBackgroundColor)); //fill label background
|
||||
}
|
||||
else //label+breakpoint+bookmark
|
||||
else //label + breakpoint + bookmark
|
||||
{
|
||||
QColor color = mBookmarkBackgroundColor;
|
||||
if(!color.alpha()) //we don't want transparent text
|
||||
|
|
@ -337,7 +343,6 @@ QString Disassembly::paintContent(QPainter* painter, dsint rowBase, int rowOffse
|
|||
case 1: //draw bytes (TODO: some spaces between bytes)
|
||||
{
|
||||
//draw functions
|
||||
dsint cur_addr = rvaToVa(mInstBuffer.at(rowOffset).rva);
|
||||
Function_t funcType;
|
||||
FUNCTYPE funcFirst = DbgGetFunctionTypeAt(cur_addr);
|
||||
FUNCTYPE funcLast = DbgGetFunctionTypeAt(cur_addr + mInstBuffer.at(rowOffset).length - 1);
|
||||
|
|
@ -395,7 +400,6 @@ QString Disassembly::paintContent(QPainter* painter, dsint rowBase, int rowOffse
|
|||
|
||||
case 2: //draw disassembly (with colours needed)
|
||||
{
|
||||
dsint cur_addr = rvaToVa(mInstBuffer.at(rowOffset).rva);
|
||||
int loopsize = 0;
|
||||
int depth = 0;
|
||||
|
||||
|
|
@ -442,7 +446,6 @@ QString Disassembly::paintContent(QPainter* painter, dsint rowBase, int rowOffse
|
|||
case 3: //draw comments
|
||||
{
|
||||
int argsize = 0;
|
||||
duint cur_addr = rvaToVa(mInstBuffer.at(rowOffset).rva);
|
||||
|
||||
ARGTYPE argType = DbgGetArgTypeAt(cur_addr);
|
||||
if(argType != ARG_NONE)
|
||||
|
|
|
|||
|
|
@ -161,6 +161,7 @@ protected:
|
|||
QColor mLabelBackgroundColor;
|
||||
|
||||
QColor mSelectedAddressBackgroundColor;
|
||||
QColor mTracedAddressBackgroundColor;
|
||||
QColor mSelectedAddressColor;
|
||||
QColor mAddressBackgroundColor;
|
||||
QColor mAddressColor;
|
||||
|
|
|
|||
|
|
@ -438,6 +438,7 @@ void AppearanceDialog::colorInfoListInit()
|
|||
colorInfoListAppend("Conditional Jump Lines (jump)", "DisassemblyConditionalJumpLineTrueColor", "");
|
||||
colorInfoListAppend("Conditional Jump Lines (no jump)", "DisassemblyConditionalJumpLineFalseColor", "");
|
||||
colorInfoListAppend("Unconditional Jump Lines", "DisassemblyUnconditionalJumpLineColor", "");
|
||||
colorInfoListAppend(tr("Traced line"), "DisassemblyTracedBackgroundColor", "");
|
||||
colorInfoListAppend("Function Lines", "DisassemblyFunctionColor", "");
|
||||
colorInfoListAppend("Loop Lines", "DisassemblyLoopColor", "");
|
||||
|
||||
|
|
|
|||
|
|
@ -237,7 +237,7 @@ void CPUDisassembly::setupRightClickContextMenu()
|
|||
QAction* setHwBreakpointAction = makeAction(tr("Set Hardware on Execution"), SLOT(toggleHwBpActionSlot()));
|
||||
QAction* removeHwBreakpointAction = makeAction(tr("Remove Hardware"), SLOT(toggleHwBpActionSlot()));
|
||||
|
||||
QMenu* replaceSlotMenu = makeMenu("Set Hardware on Execution");
|
||||
QMenu* replaceSlotMenu = makeMenu(tr("Set Hardware on Execution"));
|
||||
QAction* replaceSlot0Action = makeMenuAction(replaceSlotMenu, tr("Replace Slot 0 (Free)"), SLOT(setHwBpOnSlot0ActionSlot()));
|
||||
QAction* replaceSlot1Action = makeMenuAction(replaceSlotMenu, tr("Replace Slot 1 (Free)"), SLOT(setHwBpOnSlot1ActionSlot()));
|
||||
QAction* replaceSlot2Action = makeMenuAction(replaceSlotMenu, tr("Replace Slot 2 (Free)"), SLOT(setHwBpOnSlot2ActionSlot()));
|
||||
|
|
@ -373,6 +373,24 @@ void CPUDisassembly::setupRightClickContextMenu()
|
|||
});
|
||||
mMenuBuilder->addMenu(makeMenu(QIcon(":/icons/images/label.png"), tr("Label")), labelMenu);
|
||||
|
||||
QAction* traceRecordDisable = makeAction(tr("Disable"), SLOT(ActionTraceRecordDisableSlot()));
|
||||
QAction* traceRecordEnableBit = makeAction(tr("Bit"), SLOT(ActionTraceRecordBitSlot()));
|
||||
QAction* traceRecordEnableByte = makeAction(tr("Byte"), SLOT(ActionTraceRecordByteSlot()));
|
||||
QAction* traceRecordEnableWord = makeAction(tr("Word"), SLOT(ActionTraceRecordWordSlot()));
|
||||
//TODO: I can't get mMenuBuilder work without an icon. Please add an icon for trace record. --torusrxxx
|
||||
mMenuBuilder->addMenu(makeMenu(QIcon(":/icons/images/breakpoint.png"), tr("Trace record")), [ = ](QMenu * menu)
|
||||
{
|
||||
if(DbgFunctions()->GetTraceRecordType(rvaToVa(getInitialSelection())) == TRACERECORDTYPE::TraceRecordNone)
|
||||
{
|
||||
menu->addAction(traceRecordEnableBit);
|
||||
menu->addAction(traceRecordEnableByte);
|
||||
menu->addAction(traceRecordEnableWord);
|
||||
}
|
||||
else
|
||||
menu->addAction(traceRecordDisable);
|
||||
return true;
|
||||
});
|
||||
|
||||
mMenuBuilder->addAction(makeShortcutAction(QIcon(":/icons/images/comment.png"), tr("Comment"), SLOT(setCommentSlot()), "ActionSetComment"));
|
||||
mMenuBuilder->addAction(makeShortcutAction(QIcon(":/icons/images/bookmark.png"), tr("Bookmark"), SLOT(setBookmarkSlot()), "ActionToggleBookmark"));
|
||||
QAction* toggleFunctionAction = makeShortcutAction(QIcon(":/icons/images/functions.png"), tr("Function"), SLOT(toggleFunctionSlot()), "ActionToggleFunction");
|
||||
|
|
@ -438,7 +456,6 @@ void CPUDisassembly::setupRightClickContextMenu()
|
|||
mSearchModuleMenu->addAction(mFindStringsModule);
|
||||
mSearchModuleMenu->addAction(mFindCallsModule);
|
||||
|
||||
|
||||
// Search in All Modules menu
|
||||
mFindCommandAll = makeAction(tr("C&ommand"), SLOT(findCommandSlot()));
|
||||
mFindConstantAll = makeAction(tr("&Constant"), SLOT(findConstantSlot()));
|
||||
|
|
@ -1373,6 +1390,36 @@ void CPUDisassembly::editSoftBpActionSlot()
|
|||
Breakpoints::editBP(bp_normal, ToHexString(rvaToVa(getInitialSelection())), this);
|
||||
}
|
||||
|
||||
void CPUDisassembly::ActionTraceRecordBitSlot()
|
||||
{
|
||||
if(!(DbgFunctions()->SetTraceRecordType(rvaToVa(getInitialSelection()), TRACERECORDTYPE::TraceRecordBitExec)))
|
||||
GuiAddLogMessage("Failed to set trace record.\n");
|
||||
}
|
||||
|
||||
void CPUDisassembly::ActionTraceRecordByteSlot()
|
||||
{
|
||||
if(!(DbgFunctions()->SetTraceRecordType(rvaToVa(getInitialSelection()), TRACERECORDTYPE::TraceRecordByteWithExecTypeAndCounter)))
|
||||
GuiAddLogMessage("Failed to set trace record.\n");
|
||||
}
|
||||
|
||||
void CPUDisassembly::ActionTraceRecordWordSlot()
|
||||
{
|
||||
if(!(DbgFunctions()->SetTraceRecordType(rvaToVa(getInitialSelection()), TRACERECORDTYPE::TraceRecordWordWithExecTypeAndCounter)))
|
||||
GuiAddLogMessage("Failed to set trace record.\n");
|
||||
}
|
||||
|
||||
void CPUDisassembly::ActionTraceRecordDisableSlot()
|
||||
{
|
||||
if(!(DbgFunctions()->SetTraceRecordType(rvaToVa(getInitialSelection()), TRACERECORDTYPE::TraceRecordNone)))
|
||||
GuiAddLogMessage("Failed to set trace record.\n");
|
||||
}
|
||||
|
||||
void CPUDisassembly::mnemonicBriefSlot()
|
||||
{
|
||||
mShowMnemonicBrief = !mShowMnemonicBrief;
|
||||
reloadData();
|
||||
}
|
||||
|
||||
void CPUDisassembly::mnemonicHelpSlot()
|
||||
{
|
||||
BASIC_INSTRUCTION_INFO disasm;
|
||||
|
|
@ -1385,9 +1432,3 @@ void CPUDisassembly::mnemonicHelpSlot()
|
|||
DbgCmdExecDirect(QString("mnemonichelp %1").arg(disasm.instruction).toUtf8().constData());
|
||||
emit displayLogWidget();
|
||||
}
|
||||
|
||||
void CPUDisassembly::mnemonicBriefSlot()
|
||||
{
|
||||
mShowMnemonicBrief = !mShowMnemonicBrief;
|
||||
reloadData();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -89,6 +89,10 @@ public slots:
|
|||
void editSoftBpActionSlot();
|
||||
void mnemonicHelpSlot();
|
||||
void mnemonicBriefSlot();
|
||||
void ActionTraceRecordBitSlot();
|
||||
void ActionTraceRecordByteSlot();
|
||||
void ActionTraceRecordWordSlot();
|
||||
void ActionTraceRecordDisableSlot();
|
||||
|
||||
protected:
|
||||
void paintEvent(QPaintEvent* event);
|
||||
|
|
|
|||
|
|
@ -63,8 +63,8 @@ MainWindow::MainWindow(QWidget* parent)
|
|||
setWindowTitle(QString(mWindowMainTitle));
|
||||
|
||||
// Load application icon
|
||||
HICON hIcon = LoadIcon(GetModuleHandleA(0), MAKEINTRESOURCE(100));
|
||||
SendMessageA((HWND)MainWindow::winId(), WM_SETICON, ICON_BIG, (LPARAM)hIcon);
|
||||
HICON hIcon = LoadIcon(GetModuleHandleW(0), MAKEINTRESOURCE(100));
|
||||
SendMessageW((HWND)MainWindow::winId(), WM_SETICON, ICON_BIG, (LPARAM)hIcon);
|
||||
DestroyIcon(hIcon);
|
||||
|
||||
// Load recent files
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@ Configuration::Configuration() : QObject(), noMoreMsgbox(false)
|
|||
defaultColors.insert("DisassemblyLabelBackgroundColor", Qt::transparent);
|
||||
defaultColors.insert("DisassemblyBackgroundColor", QColor("#FFF8F0"));
|
||||
defaultColors.insert("DisassemblySelectionColor", QColor("#C0C0C0"));
|
||||
defaultColors.insert("DisassemblyTracedBackgroundColor", QColor("#C0FFC0"));
|
||||
defaultColors.insert("DisassemblyAddressColor", QColor("#808080"));
|
||||
defaultColors.insert("DisassemblyAddressBackgroundColor", Qt::transparent);
|
||||
defaultColors.insert("DisassemblySelectedAddressColor", QColor("#000000"));
|
||||
|
|
|
|||
Loading…
Reference in New Issue