Merge remote-tracking branch 'origin/development' into graph_ogfd_new
Conflicts: src/bridge/bridgemain.cpp src/bridge/bridgemain.h src/gui/Src/BasicView/Disassembly.cpp src/gui/Src/BasicView/Disassembly.h src/gui/Src/Bridge/Bridge.cpp src/gui/Src/Bridge/Bridge.h src/gui/Src/Gui/MainWindow.cpp src/gui/Src/Gui/MainWindow.h src/gui/x64dbg.pro
This commit is contained in:
parent
8e745baac5
commit
4c10421171
|
|
@ -575,6 +575,16 @@ BRIDGE_IMPEXP void DbgSymbolEnum(duint base, CBSYMBOLENUM cbSymbolEnum, void* us
|
|||
_dbg_sendmessage(DBG_SYMBOL_ENUM, &cbInfo, 0);
|
||||
}
|
||||
|
||||
// FIXME all
|
||||
BRIDGE_IMPEXP void DbgSymbolEnumFromCache(duint base, CBSYMBOLENUM cbSymbolEnum, void* user)
|
||||
{
|
||||
SYMBOLCBINFO cbInfo;
|
||||
cbInfo.base = base;
|
||||
cbInfo.cbSymbolEnum = cbSymbolEnum;
|
||||
cbInfo.user = user;
|
||||
_dbg_sendmessage(DBG_SYMBOL_ENUM_FROMCACHE, &cbInfo, 0);
|
||||
}
|
||||
|
||||
BRIDGE_IMPEXP bool DbgAssembleAt(duint addr, const char* instruction)
|
||||
{
|
||||
if(_dbg_sendmessage(DBG_ASSEMBLE_AT, (void*)addr, (void*)instruction))
|
||||
|
|
@ -1028,6 +1038,10 @@ BRIDGE_IMPEXP void GuiReferenceSetProgress(int progress)
|
|||
_gui_sendmessage(GUI_REF_SETPROGRESS, (void*)(duint)progress, 0);
|
||||
}
|
||||
|
||||
BRIDGE_IMPEXP void GuiReferenceSetCurrentTaskProgress(int progress, const char* taskTitle)
|
||||
{
|
||||
_gui_sendmessage(GUI_REF_SETCURRENTTASKPROGRESS, (void*)(duint)progress, (void*)taskTitle);
|
||||
}
|
||||
|
||||
BRIDGE_IMPEXP void GuiReferenceSetSearchStartCol(int col)
|
||||
{
|
||||
|
|
@ -1236,6 +1250,11 @@ BRIDGE_IMPEXP void GuiDumpAtN(duint va, int index)
|
|||
_gui_sendmessage(GUI_DUMP_AT_N, (void*)va, (void*)index);
|
||||
}
|
||||
|
||||
BRIDGE_IMPEXP void GuiDisplayWarning(const char *title, const char *text)
|
||||
{
|
||||
_gui_sendmessage(GUI_DISPLAY_WARNING, (void*)title, (void*)text);
|
||||
}
|
||||
|
||||
BRIDGE_IMPEXP void GuiSetControlFlowInfos(CONTROLFLOWINFOS *ctrlFlow)
|
||||
{
|
||||
_gui_sendmessage(GUI_SET_CONTROLFLOWINFOS, (void*) ctrlFlow, nullptr);
|
||||
|
|
|
|||
|
|
@ -59,6 +59,7 @@ BRIDGE_IMPEXP int BridgeGetDbgVersion();
|
|||
#define MAX_LABEL_SIZE 256
|
||||
#define MAX_COMMENT_SIZE 512
|
||||
#define MAX_MODULE_SIZE 256
|
||||
#define MAX_IMPORT_SIZE 256
|
||||
#define MAX_BREAKPOINT_SIZE 256
|
||||
#define MAX_SCRIPT_LINE_SIZE 2048
|
||||
#define MAX_THREAD_NAME_SIZE 256
|
||||
|
|
@ -66,6 +67,7 @@ BRIDGE_IMPEXP int BridgeGetDbgVersion();
|
|||
#define MAX_ERROR_SIZE 512
|
||||
#define RIGHTS_STRING_SIZE (sizeof("ERWCG") + 1)
|
||||
#define MAX_SECTION_SIZE 10
|
||||
#define MAX_COMMAND_LINE_SIZE 256
|
||||
|
||||
#define TYPE_VALUE 1
|
||||
#define TYPE_MEMORY 2
|
||||
|
|
@ -175,7 +177,8 @@ typedef enum
|
|||
DBG_WIN_EVENT_GLOBAL, // param1=MSG* message, param2=unused
|
||||
DBG_INITIALIZE_LOCKS, // param1=unused, param2=unused
|
||||
DBG_DEINITIALIZE_LOCKS, // param1=unused, param2=unused
|
||||
DBG_GET_TIME_WASTED_COUNTER // param1=unused, param2=unused
|
||||
DBG_GET_TIME_WASTED_COUNTER, // param1=unused, param2=unused
|
||||
DBG_SYMBOL_ENUM_FROMCACHE, // param1=SYMBOLCBINFO* cbInfo, param2=unused
|
||||
} DBGMSG;
|
||||
|
||||
typedef enum
|
||||
|
|
@ -349,6 +352,7 @@ struct SYMBOLINFO_
|
|||
duint addr;
|
||||
char* decoratedSymbol;
|
||||
char* undecoratedSymbol;
|
||||
bool isImported;
|
||||
};
|
||||
|
||||
typedef struct
|
||||
|
|
@ -662,6 +666,7 @@ BRIDGE_IMPEXP SCRIPTLINETYPE DbgScriptGetLineType(int line);
|
|||
BRIDGE_IMPEXP void DbgScriptSetIp(int line);
|
||||
BRIDGE_IMPEXP bool DbgScriptGetBranchInfo(int line, SCRIPTBRANCH* info);
|
||||
BRIDGE_IMPEXP void DbgSymbolEnum(duint base, CBSYMBOLENUM cbSymbolEnum, void* user);
|
||||
BRIDGE_IMPEXP void DbgSymbolEnumFromCache(duint base, CBSYMBOLENUM cbSymbolEnum, void* user);
|
||||
BRIDGE_IMPEXP bool DbgAssembleAt(duint addr, const char* instruction);
|
||||
BRIDGE_IMPEXP duint DbgModBaseFromName(const char* name);
|
||||
BRIDGE_IMPEXP void DbgDisasmAt(duint addr, DISASM_INSTR* instr);
|
||||
|
|
@ -741,7 +746,7 @@ typedef enum
|
|||
GUI_REF_GETCELLCONTENT, // param1=int row, param2=int col
|
||||
GUI_REF_RELOADDATA, // param1=unused, param2=unused
|
||||
GUI_REF_SETSINGLESELECTION, // param1=int index, param2=bool scroll
|
||||
GUI_REF_SETPROGRESS, // param1=int progress, param2=unused
|
||||
GUI_REF_SETPROGRESS, // param1=int progress, param2=unused
|
||||
GUI_REF_SETSEARCHSTARTCOL, // param1=int col param2=unused
|
||||
GUI_STACK_DUMP_AT, // param1=duint addr, param2=duint csp
|
||||
GUI_UPDATE_DUMP_VIEW, // param1=unused, param2=unused
|
||||
|
|
@ -758,7 +763,7 @@ typedef enum
|
|||
GUI_GETLINE_WINDOW, // param1=const char* title, param2=char* text
|
||||
GUI_AUTOCOMPLETE_ADDCMD, // param1=const char* cmd, param2=ununsed
|
||||
GUI_AUTOCOMPLETE_DELCMD, // param1=const char* cmd, param2=ununsed
|
||||
GUI_AUTOCOMPLETE_CLEARALL, // param1=unused, param2=unused
|
||||
GUI_AUTOCOMPLETE_CLEARALL, // param1=unused, param2=unused
|
||||
GUI_SCRIPT_ENABLEHIGHLIGHTING, // param1=bool enable, param2=unused
|
||||
GUI_ADD_MSG_TO_STATUSBAR, // param1=const char* msg, param2=unused
|
||||
GUI_UPDATE_SIDEBAR, // param1=unused, param2=unused
|
||||
|
|
@ -782,7 +787,9 @@ typedef enum
|
|||
GUI_SET_DEBUGGEE_NOTES, // param1=const char* text, param2=unused
|
||||
GUI_GET_DEBUGGEE_NOTES, // param1=char** text, param2=unused
|
||||
GUI_DUMP_AT_N, // param1=int index, param2=duint va
|
||||
GUI_SET_CONTROLFLOWINFOS // param1=duint *infos, param2=unused
|
||||
GUI_SET_CONTROLFLOWINFOS, // param1=duint *infos, param2=unused
|
||||
GUI_DISPLAY_WARNING, // param1=const char *text, param2=unused
|
||||
GUI_REF_SETCURRENTTASKPROGRESS // param1=int progress, param2=const char* taskTitle
|
||||
} GUIMSG;
|
||||
|
||||
//GUI Typedefs
|
||||
|
|
@ -850,6 +857,7 @@ BRIDGE_IMPEXP const char* GuiReferenceGetCellContent(int row, int col);
|
|||
BRIDGE_IMPEXP void GuiReferenceReloadData();
|
||||
BRIDGE_IMPEXP void GuiReferenceSetSingleSelection(int index, bool scroll);
|
||||
BRIDGE_IMPEXP void GuiReferenceSetProgress(int progress);
|
||||
BRIDGE_IMPEXP void GuiReferenceSetCurrentTaskProgress(int progress, const char* taskTitle);
|
||||
BRIDGE_IMPEXP void GuiReferenceSetSearchStartCol(int col);
|
||||
BRIDGE_IMPEXP void GuiStackDumpAt(duint addr, duint csp);
|
||||
BRIDGE_IMPEXP void GuiUpdateDumpView();
|
||||
|
|
@ -887,6 +895,7 @@ BRIDGE_IMPEXP void GuiGetGlobalNotes(char** text);
|
|||
BRIDGE_IMPEXP void GuiSetDebuggeeNotes(const char* text);
|
||||
BRIDGE_IMPEXP void GuiGetDebuggeeNotes(char** text);
|
||||
BRIDGE_IMPEXP void GuiDumpAtN(duint va, int index);
|
||||
BRIDGE_IMPEXP void GuiDisplayWarning(const char *title, const char *text);
|
||||
BRIDGE_IMPEXP void GuiSetControlFlowInfos(CONTROLFLOWINFOS *ctrlFlow);
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
|
|
|||
|
|
@ -154,7 +154,7 @@ void LinearPass::AnalysisWorker(duint Start, duint End, BBlockArray* Blocks)
|
|||
|
||||
for(duint i = Start; i < End;)
|
||||
{
|
||||
if(!disasm.Disassemble(i, TranslateAddress(i)))
|
||||
if(!disasm.Disassemble(i, TranslateAddress(i), End - i))
|
||||
{
|
||||
// Skip instructions that can't be determined
|
||||
i++;
|
||||
|
|
|
|||
|
|
@ -766,6 +766,13 @@ extern "C" DLL_EXPORT duint _dbg_sendmessage(DBGMSG type, void* param1, void* pa
|
|||
}
|
||||
break;
|
||||
|
||||
case DBG_SYMBOL_ENUM_FROMCACHE:
|
||||
{
|
||||
SYMBOLCBINFO* cbInfo = (SYMBOLCBINFO*)param1;
|
||||
SymEnumFromCache(cbInfo->base, cbInfo->cbSymbolEnum, cbInfo->user);
|
||||
}
|
||||
break;
|
||||
|
||||
case DBG_ASSEMBLE_AT:
|
||||
{
|
||||
return assembleat((duint)param1, (const char*)param2, 0, 0, false);
|
||||
|
|
|
|||
|
|
@ -87,5 +87,91 @@ bool apienumexports(duint base, EXPORTENUMCALLBACK cbEnum)
|
|||
cbEnum(base, modname, cur_name, curFunctionRva + base);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool apienumimports(duint base, IMPORTENUMCALLBACK cbEnum)
|
||||
{
|
||||
// Variables
|
||||
bool readSuccess;
|
||||
char importName[MAX_IMPORT_SIZE];
|
||||
char importModuleName[MAX_MODULE_SIZE];
|
||||
duint regionSize, importNameLen;
|
||||
ULONG_PTR importTableRva, importTableSize;
|
||||
MEMORY_BASIC_INFORMATION mbi;
|
||||
PIMAGE_IMPORT_DESCRIPTOR importTableVa;
|
||||
IMAGE_IMPORT_DESCRIPTOR importDescriptor;
|
||||
PIMAGE_THUNK_DATA imageIATVa, imageINTVa;
|
||||
IMAGE_THUNK_DATA imageOftThunkData, imageFtThunkData;
|
||||
PIMAGE_IMPORT_BY_NAME pImageImportByNameVa;
|
||||
|
||||
// Get page size
|
||||
VirtualQueryEx(fdProcessInfo->hProcess, (const void*)base, &mbi, sizeof(mbi));
|
||||
regionSize = mbi.RegionSize;
|
||||
Memory<void* > buffer(regionSize, "apienumimports:buffer");
|
||||
|
||||
// Read first page into buffer
|
||||
if (!MemRead(base, buffer(), regionSize))
|
||||
return false;
|
||||
|
||||
// Import Table address and size
|
||||
importTableRva = GetPE32DataFromMappedFile((duint)buffer(), 0, UE_IMPORTTABLEADDRESS);
|
||||
importTableSize = GetPE32DataFromMappedFile((duint)buffer(), 0, UE_IMPORTTABLESIZE);
|
||||
|
||||
// Return if no imports
|
||||
if (!importTableSize)
|
||||
return false;
|
||||
|
||||
importTableVa = (PIMAGE_IMPORT_DESCRIPTOR)(base + importTableRva);
|
||||
|
||||
readSuccess = MemRead((duint)importTableVa, &importDescriptor, sizeof(importDescriptor));
|
||||
|
||||
// Loop through all dlls
|
||||
while (readSuccess && importDescriptor.FirstThunk)
|
||||
{
|
||||
// Copy module name into importModuleName
|
||||
MemRead((duint)(base + importDescriptor.Name), &importModuleName, MAX_MODULE_SIZE);
|
||||
|
||||
imageIATVa = (PIMAGE_THUNK_DATA)(base + importDescriptor.FirstThunk);
|
||||
imageINTVa = (PIMAGE_THUNK_DATA)(base + importDescriptor.OriginalFirstThunk);
|
||||
|
||||
if (!MemRead((duint)imageIATVa, &imageFtThunkData, sizeof(imageFtThunkData)))
|
||||
return false;
|
||||
|
||||
if (!MemRead((duint)imageINTVa, &imageOftThunkData, sizeof(imageOftThunkData)))
|
||||
return false;
|
||||
|
||||
// Loop through all imported function in this dll
|
||||
while (imageFtThunkData.u1.Function)
|
||||
{
|
||||
pImageImportByNameVa = (PIMAGE_IMPORT_BY_NAME)(base + imageOftThunkData.u1.AddressOfData);
|
||||
|
||||
// Read every IMPORT_BY_NAME.name
|
||||
if (!MemRead((duint)pImageImportByNameVa + sizeof(WORD), buffer(), regionSize))
|
||||
return false;
|
||||
|
||||
// Alloc buffer for name and copy name import name to buffer
|
||||
importNameLen = strlen((char*)buffer());
|
||||
strcpy_s(importName, MAX_IMPORT_SIZE, (char*)buffer());
|
||||
|
||||
// Callback
|
||||
cbEnum(base, imageFtThunkData.u1.Function, importName, importModuleName);
|
||||
|
||||
// Move to next address in the INT
|
||||
imageINTVa++;
|
||||
if(!MemRead((duint)imageINTVa, &imageOftThunkData, sizeof(imageOftThunkData)))
|
||||
return false;
|
||||
|
||||
|
||||
// Move to next address in the IAT and read it into imageFtThunkData
|
||||
imageIATVa++;
|
||||
if (!MemRead((duint)imageIATVa, &imageFtThunkData, sizeof(imageFtThunkData)))
|
||||
return false;
|
||||
}
|
||||
|
||||
importTableVa++;
|
||||
readSuccess = MemRead((duint)importTableVa, &importDescriptor, sizeof(importDescriptor));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
@ -55,7 +55,10 @@ struct DepthModuleRangeCompare
|
|||
|
||||
//typedefs
|
||||
typedef std::function<void (duint base, const char* mod, const char* name, duint addr)> EXPORTENUMCALLBACK;
|
||||
typedef std::function<void (duint base, duint addr, char* name, char* moduleName)> IMPORTENUMCALLBACK;
|
||||
|
||||
|
||||
bool apienumexports(duint base, EXPORTENUMCALLBACK cbEnum);
|
||||
bool apienumimports(duint base, IMPORTENUMCALLBACK cbEnum);
|
||||
|
||||
#endif // _ADDRINFO_H
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@
|
|||
#include "XEDParse\XEDParse.h"
|
||||
#include "value.h"
|
||||
#include "disasm_helper.h"
|
||||
#include "debugger.h"
|
||||
|
||||
static bool cbUnknown(const char* text, ULONGLONG* value)
|
||||
{
|
||||
|
|
@ -67,6 +68,10 @@ bool assembleat(duint addr, const char* instruction, int* size, char* error, boo
|
|||
if(size)
|
||||
*size = destSize;
|
||||
|
||||
// Check if the instruction doesn't set IP to non-executable memory
|
||||
if (isInstructionPointingToExMemory(addr, dest) == NX_MEMORY)
|
||||
GuiDisplayWarning("Non-executable memory region", "Assembled instruction points to non-executable memory region !");
|
||||
|
||||
bool ret = MemPatch(addr, dest, destSize);
|
||||
|
||||
if (ret)
|
||||
|
|
@ -91,3 +96,81 @@ bool assembleat(duint addr, const char* instruction, int* size, char* error, boo
|
|||
|
||||
return ret;
|
||||
}
|
||||
|
||||
INSTR_POINTING_TO isInstructionPointingToExMemory(duint addr, const unsigned char* dest)
|
||||
{
|
||||
MEMMAP wMemMapStruct;
|
||||
DISASM_ARG arg;
|
||||
DISASM_INSTR wDisasInstrStruct;
|
||||
MEMORY_BASIC_INFORMATION *wMbiStruct = NULL;
|
||||
duint instrArgCount;
|
||||
dsint instrMemValues[3] = {0};
|
||||
duint instrMemValuesIndex = 0;
|
||||
dsint mbiBaseAddr, mbiEndAddr;
|
||||
|
||||
disasmget((unsigned char*)dest, 0, &wDisasInstrStruct);
|
||||
|
||||
instrArgCount = wDisasInstrStruct.argcount;
|
||||
if (instrArgCount)
|
||||
{
|
||||
// Loop through all arguements
|
||||
for (int i = 0; i < wDisasInstrStruct.argcount; i++)
|
||||
{
|
||||
arg = wDisasInstrStruct.arg[i];
|
||||
|
||||
// Check if any of the arguments is a memory
|
||||
if (arg.type == arg_memory)
|
||||
{
|
||||
instrMemValues[instrMemValuesIndex] = addr + arg.memvalue; // add current instruction VA for rip-relative addressing
|
||||
instrMemValuesIndex++;
|
||||
}
|
||||
else if (wDisasInstrStruct.type == instr_branch)
|
||||
{
|
||||
instrMemValues[instrMemValuesIndex] = addr + arg.value;
|
||||
instrMemValuesIndex++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// No memory pointer in the instruction, no need to go further
|
||||
if (!instrMemValuesIndex)
|
||||
return NO_POINTER;
|
||||
|
||||
// Get memory map to locate the sections to which the instr memory address belongs to
|
||||
DbgMemMap(&wMemMapStruct);
|
||||
|
||||
// For each memPointerValue
|
||||
for (auto & memValue : instrMemValues)
|
||||
{
|
||||
// Loop through the memMaps
|
||||
for (int i = 0; i < wMemMapStruct.count; i++)
|
||||
{
|
||||
wMbiStruct = &(wMemMapStruct.page)[i].mbi;
|
||||
mbiBaseAddr = (dsint)wMbiStruct->BaseAddress;
|
||||
mbiEndAddr = (dsint)wMbiStruct->BaseAddress + (dsint)wMbiStruct->RegionSize;
|
||||
if (memValue >= mbiBaseAddr && memValue < mbiEndAddr)
|
||||
{
|
||||
if (wMbiStruct->Protect == PAGE_EXECUTE ||
|
||||
wMbiStruct->Protect == PAGE_EXECUTE_READ ||
|
||||
wMbiStruct->Protect == PAGE_EXECUTE_READWRITE ||
|
||||
wMbiStruct->Protect == PAGE_EXECUTE_WRITECOPY)
|
||||
{
|
||||
// Memory region is marked as executable
|
||||
#ifndef _WIN64
|
||||
DWORD lpFlagsDep;
|
||||
BOOL bPermanentDep;
|
||||
|
||||
// DEP is disabled if lpFlagsDep == 0
|
||||
if (GetProcessDEPPolicy(fdProcessInfo->hProcess, &lpFlagsDep, &bPermanentDep) && lpFlagsDep != 0)
|
||||
return EX_MEMORY;
|
||||
#else
|
||||
// DEP enabled on x64
|
||||
return EX_MEMORY;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return NX_MEMORY;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,7 +3,15 @@
|
|||
|
||||
#include "_global.h"
|
||||
|
||||
enum INSTR_POINTING_TO
|
||||
{
|
||||
EX_MEMORY,
|
||||
NX_MEMORY,
|
||||
NO_POINTER
|
||||
};
|
||||
|
||||
bool assemble(duint addr, unsigned char* dest, int* size, const char* instruction, char* error);
|
||||
bool assembleat(duint addr, const char* instruction, int* size, char* error, bool fillnop);
|
||||
INSTR_POINTING_TO isInstructionPointingToExMemory(duint addr, const unsigned char* dest);
|
||||
|
||||
#endif // _ASSEMBLE_H
|
||||
|
|
|
|||
|
|
@ -152,6 +152,13 @@ bool BpEnable(duint Address, BP_TYPE Type, bool Enable)
|
|||
return false;
|
||||
|
||||
bpInfo->enabled = Enable;
|
||||
|
||||
//Re-read oldbytes
|
||||
if (Enable && Type == BPNORMAL)
|
||||
{
|
||||
if (!MemRead(Address, &bpInfo->oldbytes, sizeof(bpInfo->oldbytes)))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,90 @@
|
|||
#include "commandline.h"
|
||||
#include "threading.h"
|
||||
#include "memory.h"
|
||||
#include "debugger.h"
|
||||
#include "debugger_commands.h"
|
||||
|
||||
char commandLine[MAX_COMMAND_LINE_SIZE];
|
||||
|
||||
bool isCmdLineEmpty()
|
||||
{
|
||||
return !strlen(commandLine);
|
||||
}
|
||||
|
||||
char* getCommandLineArgs()
|
||||
{
|
||||
char* commandLineArguments = NULL;
|
||||
char* extensionPtr = strchr(commandLine, '.');
|
||||
|
||||
if (!extensionPtr)
|
||||
return NULL;
|
||||
|
||||
commandLineArguments = strchr(extensionPtr, ' ');
|
||||
|
||||
if (!commandLineArguments)
|
||||
return NULL;
|
||||
|
||||
return (commandLineArguments + 1);
|
||||
|
||||
}
|
||||
|
||||
void CmdLineCacheSave(JSON Root)
|
||||
{
|
||||
EXCLUSIVE_ACQUIRE(LockCmdLine);
|
||||
|
||||
// return if command line is empty
|
||||
if (!strlen(commandLine))
|
||||
return;
|
||||
|
||||
// Create a JSON array to store each sub-object with a breakpoint
|
||||
const JSON jsonCmdLine = json_object();
|
||||
json_object_set_new(jsonCmdLine, "cmdLine", json_string(commandLine));
|
||||
json_object_set(Root, "commandLine", jsonCmdLine);
|
||||
|
||||
// Notify garbage collector
|
||||
json_decref(jsonCmdLine);
|
||||
}
|
||||
|
||||
void CmdLineCacheLoad(JSON Root)
|
||||
{
|
||||
EXCLUSIVE_ACQUIRE(LockCmdLine);
|
||||
|
||||
// Clear command line
|
||||
memset(commandLine, 0, MAX_COMMAND_LINE_SIZE);
|
||||
|
||||
// Get a handle to the root object -> commandLine
|
||||
const JSON jsonCmdLine = json_object_get(Root, "commandLine");
|
||||
|
||||
// Return if there was nothing to load
|
||||
if (!jsonCmdLine)
|
||||
return;
|
||||
|
||||
const char *cmdLine = json_string_value(json_object_get(jsonCmdLine, "cmdLine"));
|
||||
|
||||
strcpy_s(commandLine, cmdLine);
|
||||
|
||||
json_decref(jsonCmdLine);
|
||||
}
|
||||
|
||||
void copyCommandLine(const char* cmdLine)
|
||||
{
|
||||
strcpy_s(commandLine, cmdLine);
|
||||
}
|
||||
|
||||
CMDRESULT SetCommandLine()
|
||||
{
|
||||
cmdline_error_t cmdline_error = { (cmdline_error_type_t)0, 0 };
|
||||
|
||||
if (!dbgsetcmdline(commandLine, &cmdline_error))
|
||||
{
|
||||
showcommandlineerror(&cmdline_error);
|
||||
return STATUS_ERROR;
|
||||
}
|
||||
|
||||
//update the memory map
|
||||
MemUpdateMap();
|
||||
GuiUpdateMemoryView();
|
||||
|
||||
return STATUS_CONTINUE;
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
#pragma once
|
||||
|
||||
#include "_global.h"
|
||||
#include "command.h"
|
||||
|
||||
bool isCmdLineEmpty();
|
||||
char* getCommandLineArgs();
|
||||
void CmdLineCacheSave(JSON Root);
|
||||
void CmdLineCacheLoad(JSON Root);
|
||||
void copyCommandLine(const char* cmdLine);
|
||||
CMDRESULT setCommandLine();
|
||||
|
|
@ -13,6 +13,7 @@
|
|||
#include "bookmark.h"
|
||||
#include "function.h"
|
||||
#include "loop.h"
|
||||
#include "commandline.h"
|
||||
|
||||
/**
|
||||
\brief Directory where program databases are stored (usually in \db). UTF-8 encoding.
|
||||
|
|
@ -24,26 +25,44 @@ char dbbasepath[deflen];
|
|||
*/
|
||||
char dbpath[deflen];
|
||||
|
||||
void DBSave()
|
||||
enum LOAD_SAVE_DB_TYPE
|
||||
{
|
||||
COMMAND_LINE_ONLY,
|
||||
ALL_BUT_COMMAND_LINE,
|
||||
ALL
|
||||
};
|
||||
|
||||
void DBSave(LOAD_SAVE_DB_TYPE saveType)
|
||||
{
|
||||
dprintf("Saving database...");
|
||||
DWORD ticks = GetTickCount();
|
||||
JSON root = json_object();
|
||||
CommentCacheSave(root);
|
||||
LabelCacheSave(root);
|
||||
BookmarkCacheSave(root);
|
||||
FunctionCacheSave(root);
|
||||
LoopCacheSave(root);
|
||||
BpCacheSave(root);
|
||||
//save notes
|
||||
char* text = nullptr;
|
||||
GuiGetDebuggeeNotes(&text);
|
||||
if (text)
|
||||
|
||||
// Save only command line
|
||||
if (saveType == COMMAND_LINE_ONLY || saveType == ALL)
|
||||
{
|
||||
json_object_set_new(root, "notes", json_string(text));
|
||||
BridgeFree(text);
|
||||
CmdLineCacheSave(root);
|
||||
}
|
||||
|
||||
if (saveType == ALL_BUT_COMMAND_LINE || saveType == ALL)
|
||||
{
|
||||
CommentCacheSave(root);
|
||||
LabelCacheSave(root);
|
||||
BookmarkCacheSave(root);
|
||||
FunctionCacheSave(root);
|
||||
LoopCacheSave(root);
|
||||
BpCacheSave(root);
|
||||
|
||||
//save notes
|
||||
char* text = nullptr;
|
||||
GuiGetDebuggeeNotes(&text);
|
||||
if (text)
|
||||
{
|
||||
json_object_set_new(root, "notes", json_string(text));
|
||||
BridgeFree(text);
|
||||
}
|
||||
GuiSetDebuggeeNotes("");
|
||||
}
|
||||
GuiSetDebuggeeNotes("");
|
||||
|
||||
WString wdbpath = StringUtils::Utf8ToUtf16(dbpath);
|
||||
if (json_object_size(root))
|
||||
|
|
@ -76,7 +95,7 @@ void DBSave()
|
|||
json_decref(root); //free root
|
||||
}
|
||||
|
||||
void DBLoad()
|
||||
void DBLoad(LOAD_SAVE_DB_TYPE loadType)
|
||||
{
|
||||
// If the file doesn't exist, there is no DB to load
|
||||
if (!FileExists(dbpath))
|
||||
|
|
@ -139,17 +158,26 @@ void DBLoad()
|
|||
return;
|
||||
}
|
||||
|
||||
// Finally load all structures
|
||||
CommentCacheLoad(root);
|
||||
LabelCacheLoad(root);
|
||||
BookmarkCacheLoad(root);
|
||||
FunctionCacheLoad(root);
|
||||
LoopCacheLoad(root);
|
||||
BpCacheLoad(root);
|
||||
// Load only command line
|
||||
if (loadType == COMMAND_LINE_ONLY || loadType == ALL)
|
||||
{
|
||||
CmdLineCacheLoad(root);
|
||||
}
|
||||
|
||||
// Load notes
|
||||
const char* text = json_string_value(json_object_get(root, "notes"));
|
||||
GuiSetDebuggeeNotes(text);
|
||||
if (loadType == ALL_BUT_COMMAND_LINE || loadType == ALL)
|
||||
{
|
||||
// Finally load all structures
|
||||
CommentCacheLoad(root);
|
||||
LabelCacheLoad(root);
|
||||
BookmarkCacheLoad(root);
|
||||
FunctionCacheLoad(root);
|
||||
LoopCacheLoad(root);
|
||||
BpCacheLoad(root);
|
||||
|
||||
// Load notes
|
||||
const char* text = json_string_value(json_object_get(root, "notes"));
|
||||
GuiSetDebuggeeNotes(text);
|
||||
}
|
||||
|
||||
// Free root
|
||||
json_decref(root);
|
||||
|
|
@ -158,7 +186,7 @@ void DBLoad()
|
|||
|
||||
void DBClose()
|
||||
{
|
||||
DBSave();
|
||||
DBSave(ALL);
|
||||
CommentClear();
|
||||
LabelClear();
|
||||
BookmarkClear();
|
||||
|
|
|
|||
|
|
@ -2,7 +2,14 @@
|
|||
|
||||
#include "_global.h"
|
||||
|
||||
void DBSave();
|
||||
void DBLoad();
|
||||
enum LOAD_SAVE_DB_TYPE
|
||||
{
|
||||
COMMAND_LINE_ONLY,
|
||||
ALL_BUT_COMMAND_LINE,
|
||||
ALL
|
||||
};
|
||||
|
||||
void DBSave(LOAD_SAVE_DB_TYPE saveType);
|
||||
void DBLoad(LOAD_SAVE_DB_TYPE loadType);
|
||||
void DBClose();
|
||||
void DBSetPath(const char *Directory, const char *ModulePath);
|
||||
|
|
@ -20,6 +20,7 @@
|
|||
#include "exception.h"
|
||||
#include "error.h"
|
||||
#include "module.h"
|
||||
#include "commandline.h"
|
||||
|
||||
static PROCESS_INFORMATION g_pi = {0, 0, 0, 0};
|
||||
static char szBaseFileName[MAX_PATH] = "";
|
||||
|
|
@ -33,6 +34,7 @@ static bool isDetachedByUser = false;
|
|||
static bool bIsAttached = false;
|
||||
static bool bSkipExceptions = false;
|
||||
static bool bBreakOnNextDll = false;
|
||||
static bool bFreezeStack = false;
|
||||
static int ecount = 0;
|
||||
static std::vector<ExceptionRange> ignoredExceptionRange;
|
||||
static HANDLE hEvent = 0;
|
||||
|
|
@ -154,6 +156,11 @@ void dbgsetisdetachedbyuser(bool b)
|
|||
isDetachedByUser = b;
|
||||
}
|
||||
|
||||
void dbgsetfreezestack(bool freeze)
|
||||
{
|
||||
bFreezeStack = freeze;
|
||||
}
|
||||
|
||||
void dbgclearignoredexceptions()
|
||||
{
|
||||
ignoredExceptionRange.clear();
|
||||
|
|
@ -214,7 +221,7 @@ void DebugUpdateGui(duint disasm_addr, bool stack)
|
|||
}
|
||||
duint csp = GetContextDataEx(hActiveThread, UE_CSP);
|
||||
if(stack)
|
||||
GuiStackDumpAt(csp, csp);
|
||||
DebugUpdateStack(csp, csp);
|
||||
static duint cacheCsp = 0;
|
||||
if(csp != cacheCsp)
|
||||
{
|
||||
|
|
@ -233,6 +240,17 @@ void DebugUpdateGui(duint disasm_addr, bool stack)
|
|||
GuiUpdateAllViews();
|
||||
}
|
||||
|
||||
void DebugUpdateStack(duint dumpAddr, duint csp, bool forceDump)
|
||||
{
|
||||
if (!forceDump && bFreezeStack)
|
||||
{
|
||||
SELECTIONDATA selection;
|
||||
if (GuiSelectionGet(GUI_STACK, &selection))
|
||||
dumpAddr = selection.start;
|
||||
}
|
||||
GuiStackDumpAt(dumpAddr, csp);
|
||||
}
|
||||
|
||||
void cbUserBreakpoint()
|
||||
{
|
||||
hActiveThread = ThreadGetHandle(((DEBUG_EVENT*)GetDebugData())->dwThreadId);
|
||||
|
|
@ -504,8 +522,22 @@ bool cbSetModuleBreakpoints(const BREAKPOINT* bp)
|
|||
{
|
||||
case BPNORMAL:
|
||||
{
|
||||
if(!SetBPX(bp->addr, bp->titantype, (void*)cbUserBreakpoint))
|
||||
dprintf("Could not set breakpoint " fhex "! (SetBPX)\n", bp->addr);
|
||||
unsigned short oldbytes;
|
||||
if (MemRead(bp->addr, &oldbytes, sizeof(oldbytes)))
|
||||
{
|
||||
if (oldbytes != bp->oldbytes)
|
||||
{
|
||||
dprintf("Breakpoint " fhex " has been disabled because the bytes don't match! Expected: %02X %02X, Found: %02X %02X\n",
|
||||
bp->addr,
|
||||
((unsigned char*)&bp->oldbytes)[0], ((unsigned char*)&bp->oldbytes)[1],
|
||||
((unsigned char*)&oldbytes)[0], ((unsigned char*)&oldbytes)[1]);
|
||||
BpEnable(bp->addr, BPNORMAL, false);
|
||||
}
|
||||
else if (!SetBPX(bp->addr, bp->titantype, (void*)cbUserBreakpoint))
|
||||
dprintf("Could not set breakpoint " fhex "! (SetBPX)\n", bp->addr);
|
||||
}
|
||||
else
|
||||
dprintf("MemRead failed on breakpoint address" fhex "!\n", bp->addr);
|
||||
}
|
||||
break;
|
||||
|
||||
|
|
@ -632,7 +664,7 @@ static void cbCreateProcess(CREATE_PROCESS_DEBUG_INFO* CreateProcessInfo)
|
|||
|
||||
// Init program database
|
||||
DBSetPath(nullptr, szFileName);
|
||||
DBLoad();
|
||||
DBLoad(ALL_BUT_COMMAND_LINE);
|
||||
|
||||
SafeSymSetOptions(SYMOPT_DEBUG | SYMOPT_LOAD_LINES | SYMOPT_ALLOW_ABSOLUTE_SYMBOLS | SYMOPT_FAVOR_COMPRESSED | SYMOPT_IGNORE_NT_SYMPATH);
|
||||
GuiSymbolLogClear();
|
||||
|
|
@ -1116,10 +1148,26 @@ DWORD WINAPI threadDebugLoop(void* lpParameter)
|
|||
bIsAttached = false;
|
||||
bSkipExceptions = false;
|
||||
bBreakOnNextDll = false;
|
||||
bFreezeStack = false;
|
||||
INIT_STRUCT* init = (INIT_STRUCT*)lpParameter;
|
||||
bFileIsDll = IsFileDLLW(StringUtils::Utf8ToUtf16(init->exe).c_str(), 0);
|
||||
pDebuggedEntry = GetPE32DataW(StringUtils::Utf8ToUtf16(init->exe).c_str(), 0, UE_OEP);
|
||||
strcpy_s(szFileName, init->exe);
|
||||
|
||||
// Load command line if it exists in DB
|
||||
DBSetPath(nullptr, szFileName);
|
||||
DBLoad(COMMAND_LINE_ONLY);
|
||||
|
||||
if (!isCmdLineEmpty())
|
||||
{
|
||||
char* commandLineArguments = NULL;
|
||||
commandLineArguments = getCommandLineArgs();
|
||||
|
||||
if (commandLineArguments)
|
||||
init->commandline = commandLineArguments;
|
||||
}
|
||||
|
||||
|
||||
if(bFileIsDll)
|
||||
fdProcessInfo = (PROCESS_INFORMATION*)InitDLLDebugW(StringUtils::Utf8ToUtf16(init->exe).c_str(), false, StringUtils::Utf8ToUtf16(init->commandline).c_str(), StringUtils::Utf8ToUtf16(init->currentfolder).c_str(), 0);
|
||||
else
|
||||
|
|
@ -1195,6 +1243,7 @@ DWORD WINAPI threadDebugLoop(void* lpParameter)
|
|||
DBClose();
|
||||
ModClear();
|
||||
ThreadClear();
|
||||
SymClearMemoryCache();
|
||||
GuiSetDebugState(stopped);
|
||||
dputs("Debugging stopped!");
|
||||
varset("$hp", (duint)0, true);
|
||||
|
|
@ -1409,6 +1458,7 @@ DWORD WINAPI threadAttachLoop(void* lpParameter)
|
|||
lock(WAITID_STOP);
|
||||
bIsAttached = true;
|
||||
bSkipExceptions = false;
|
||||
bFreezeStack = false;
|
||||
DWORD pid = (DWORD)lpParameter;
|
||||
static PROCESS_INFORMATION pi_attached;
|
||||
fdProcessInfo = &pi_attached;
|
||||
|
|
@ -1461,6 +1511,7 @@ DWORD WINAPI threadAttachLoop(void* lpParameter)
|
|||
DBClose();
|
||||
ModClear();
|
||||
ThreadClear();
|
||||
SymClearMemoryCache();
|
||||
GuiSetDebugState(stopped);
|
||||
dputs("debugging stopped!");
|
||||
varset("$hp", (duint)0, true);
|
||||
|
|
@ -1596,7 +1647,7 @@ static bool fixgetcommandlinesbase(duint new_command_line_unicode, duint new_com
|
|||
{
|
||||
duint getcommandline;
|
||||
|
||||
if(!valfromstring("kernelbase:GetCommandLineA", &getcommandline))
|
||||
if(!valfromstring("kernelBase:GetCommandLineA", &getcommandline))
|
||||
{
|
||||
if(!valfromstring("kernel32:GetCommandLineA", &getcommandline))
|
||||
{
|
||||
|
|
@ -1682,6 +1733,9 @@ bool dbgsetcmdline(const char* cmd_line, cmdline_error_t* cmd_line_error)
|
|||
return false;
|
||||
}
|
||||
|
||||
// Copy command line
|
||||
copyCommandLine(cmd_line);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -1723,6 +1777,7 @@ bool dbggetcmdline(char** cmd_line, cmdline_error_t* cmd_line_error)
|
|||
cmd_line_error->type = CMDL_ERR_CONVERTUNICODE;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -67,10 +67,12 @@ bool dbgisrunning();
|
|||
bool dbgisdll();
|
||||
void dbgsetattachevent(HANDLE handle);
|
||||
void DebugUpdateGui(duint disasm_addr, bool stack);
|
||||
void DebugUpdateStack(duint dumpAddr, duint csp, bool forceDump = false);
|
||||
void dbgsetskipexceptions(bool skip);
|
||||
void dbgsetstepping(bool stepping);
|
||||
void dbgsetispausedbyuser(bool b);
|
||||
void dbgsetisdetachedbyuser(bool b);
|
||||
void dbgsetfreezestack(bool freeze);
|
||||
void dbgclearignoredexceptions();
|
||||
void dbgaddignoredexception(ExceptionRange range);
|
||||
bool dbgisignoredexception(unsigned int exception);
|
||||
|
|
|
|||
|
|
@ -1056,7 +1056,7 @@ CMDRESULT cbDebugStackDump(int argc, char* argv[])
|
|||
duint size = 0;
|
||||
duint base = MemFindBaseAddr(csp, &size);
|
||||
if(base && addr >= base && addr < (base + size))
|
||||
GuiStackDumpAt(addr, csp);
|
||||
DebugUpdateStack(addr, csp, true);
|
||||
else
|
||||
dputs("Invalid stack address!");
|
||||
return STATUS_CONTINUE;
|
||||
|
|
@ -2102,3 +2102,16 @@ CMDRESULT cbDebugSkip(int argc, char* argv[])
|
|||
DebugUpdateGui(cip, false); //update GUI
|
||||
return STATUS_CONTINUE;
|
||||
}
|
||||
|
||||
CMDRESULT cbDebugSetfreezestack(int argc, char* argv[])
|
||||
{
|
||||
if (argc < 2)
|
||||
{
|
||||
dputs("Not enough arguments!");
|
||||
return STATUS_ERROR;
|
||||
}
|
||||
bool freeze = *argv[1] != '0';
|
||||
dbgsetfreezestack(freeze);
|
||||
dprintf("Stack is now %s\n", freeze ? "freezed" : "unfreezed");
|
||||
return STATUS_CONTINUE;
|
||||
}
|
||||
|
|
@ -64,6 +64,7 @@ CMDRESULT cbDebugDownloadSymbol(int argc, char* argv[]);
|
|||
CMDRESULT cbDebugGetPageRights(int argc, char* argv[]);
|
||||
CMDRESULT cbDebugSetPageRights(int argc, char* argv[]);
|
||||
CMDRESULT cbDebugSkip(int argc, char* argv[]);
|
||||
CMDRESULT cbDebugSetfreezestack(int argc, char* argv[]);
|
||||
|
||||
//misc
|
||||
void showcommandlineerror(cmdline_error_t* cmdline_error);
|
||||
|
|
|
|||
|
|
@ -416,14 +416,14 @@ CMDRESULT cbInstrBookmarkDel(int argc, char* argv[])
|
|||
|
||||
CMDRESULT cbInstrLoaddb(int argc, char* argv[])
|
||||
{
|
||||
DBLoad();
|
||||
DBLoad(ALL);
|
||||
GuiUpdateAllViews();
|
||||
return STATUS_CONTINUE;
|
||||
}
|
||||
|
||||
CMDRESULT cbInstrSavedb(int argc, char* argv[])
|
||||
{
|
||||
DBSave();
|
||||
DBSave(ALL);
|
||||
return STATUS_CONTINUE;
|
||||
}
|
||||
|
||||
|
|
@ -767,7 +767,7 @@ CMDRESULT cbInstrPush(int argc, char* argv[])
|
|||
}
|
||||
Script::Stack::Push(value);
|
||||
duint csp = GetContextDataEx(hActiveThread, UE_CSP);
|
||||
GuiStackDumpAt(csp, csp);
|
||||
DebugUpdateStack(csp, csp);
|
||||
GuiUpdateRegisterView();
|
||||
return STATUS_CONTINUE;
|
||||
}
|
||||
|
|
@ -776,7 +776,7 @@ CMDRESULT cbInstrPop(int argc, char* argv[])
|
|||
{
|
||||
duint value = Script::Stack::Pop();
|
||||
duint csp = GetContextDataEx(hActiveThread, UE_CSP);
|
||||
GuiStackDumpAt(csp, csp);
|
||||
DebugUpdateStack(csp, csp);
|
||||
GuiUpdateRegisterView();
|
||||
if (argc > 1)
|
||||
{
|
||||
|
|
@ -885,6 +885,8 @@ CMDRESULT cbInstrRefFind(int argc, char* argv[])
|
|||
newCommand += std::string(",") + argv[2];
|
||||
if (argc > 3)
|
||||
newCommand += std::string(",") + argv[3];
|
||||
if (argc > 4)
|
||||
newCommand += std::string(",") + argv[4];
|
||||
return cmddirectexec(newCommand.c_str());
|
||||
}
|
||||
|
||||
|
|
@ -913,7 +915,13 @@ CMDRESULT cbInstrRefFindRange(int argc, char* argv[])
|
|||
sprintf_s(title, "Constant: %" fext "X", range.start);
|
||||
else
|
||||
sprintf_s(title, "Range: %" fext "X-%" fext "X", range.start, range.end);
|
||||
int found = RefFind(addr, size, cbRefFind, &range, false, title);
|
||||
|
||||
duint refFindType = CURRENT_REGION;
|
||||
if (argc >= 6 && valfromstring(argv[5], &refFindType, true))
|
||||
if (refFindType != CURRENT_REGION && refFindType != CURRENT_MODULE && refFindType != ALL_MODULES)
|
||||
refFindType = CURRENT_REGION;
|
||||
|
||||
int found = RefFind(addr, size, cbRefFind, &range, false, title, (REFFINDTYPE)refFindType);
|
||||
dprintf("%u reference(s) in %ums\n", found, GetTickCount() - ticks);
|
||||
varset("$result", found, false);
|
||||
return STATUS_CONTINUE;
|
||||
|
|
@ -970,14 +978,22 @@ bool cbRefStr(Capstone* disasm, BASIC_INSTRUCTION_INFO* basicinfo, REFINFO* refi
|
|||
CMDRESULT cbInstrRefStr(int argc, char* argv[])
|
||||
{
|
||||
duint addr;
|
||||
duint size = 0;
|
||||
|
||||
// If not specified, assume CURRENT_REGION by default
|
||||
if (argc < 2 || !valfromstring(argv[1], &addr, true))
|
||||
addr = GetContextDataEx(hActiveThread, UE_CIP);
|
||||
duint size = 0;
|
||||
if (argc >= 3)
|
||||
if (!valfromstring(argv[2], &size, true))
|
||||
size = 0;
|
||||
|
||||
duint refFindType = CURRENT_REGION;
|
||||
if (argc >= 4 && valfromstring(argv[3], &refFindType, true))
|
||||
if (refFindType != CURRENT_REGION && refFindType != CURRENT_MODULE && refFindType != ALL_MODULES)
|
||||
refFindType = CURRENT_REGION;
|
||||
|
||||
duint ticks = GetTickCount();
|
||||
int found = RefFind(addr, size, cbRefStr, 0, false, "Strings");
|
||||
int found = RefFind(addr, size, cbRefStr, 0, false, "Strings", (REFFINDTYPE)refFindType);
|
||||
dprintf("%u string(s) in %ums\n", found, GetTickCount() - ticks);
|
||||
varset("$result", found, false);
|
||||
return STATUS_CONTINUE;
|
||||
|
|
@ -1399,8 +1415,14 @@ CMDRESULT cbInstrModCallFind(int argc, char* argv[])
|
|||
if (argc >= 3)
|
||||
if (!valfromstring(argv[2], &size, true))
|
||||
size = 0;
|
||||
|
||||
duint refFindType = CURRENT_REGION;
|
||||
if (argc >= 4 && valfromstring(argv[3], &refFindType, true))
|
||||
if (refFindType != CURRENT_REGION && refFindType != CURRENT_MODULE && refFindType != ALL_MODULES)
|
||||
refFindType = CURRENT_REGION;
|
||||
|
||||
duint ticks = GetTickCount();
|
||||
int found = RefFind(addr, size, cbModCallFind, 0, false, "Calls");
|
||||
int found = RefFind(addr, size, cbModCallFind, 0, false, "Calls", (REFFINDTYPE)refFindType);
|
||||
dprintf("%u call(s) in %ums\n", found, GetTickCount() - ticks);
|
||||
varset("$result", found, false);
|
||||
return STATUS_CONTINUE;
|
||||
|
|
@ -1656,6 +1678,11 @@ CMDRESULT cbInstrFindAsm(int argc, char* argv[])
|
|||
if (!valfromstring(argv[3], &size))
|
||||
size = 0;
|
||||
|
||||
duint refFindType = CURRENT_REGION;
|
||||
if (argc >= 5 && valfromstring(argv[4], &refFindType, true))
|
||||
if (refFindType != CURRENT_REGION && refFindType != CURRENT_MODULE && refFindType != ALL_MODULES)
|
||||
refFindType = CURRENT_REGION;
|
||||
|
||||
unsigned char dest[16];
|
||||
int asmsize = 0;
|
||||
char error[MAX_ERROR_SIZE] = "";
|
||||
|
|
@ -1671,7 +1698,7 @@ CMDRESULT cbInstrFindAsm(int argc, char* argv[])
|
|||
duint ticks = GetTickCount();
|
||||
char title[256] = "";
|
||||
sprintf_s(title, "Command: \"%s\"", basicinfo.instruction);
|
||||
int found = RefFind(addr, size, cbFindAsm, (void*)&basicinfo.instruction[0], false, title);
|
||||
int found = RefFind(addr, size, cbFindAsm, (void*)&basicinfo.instruction[0], false, title, (REFFINDTYPE)refFindType);
|
||||
dprintf("%u result(s) in %ums\n", found, GetTickCount() - ticks);
|
||||
varset("$result", found, false);
|
||||
return STATUS_CONTINUE;
|
||||
|
|
|
|||
|
|
@ -497,6 +497,9 @@ bool MemPageRightsToString(DWORD Protect, char* Rights)
|
|||
case PAGE_EXECUTE_WRITECOPY:
|
||||
strcpy_s(Rights, RIGHTS_STRING_SIZE, "ERWC");
|
||||
break;
|
||||
default:
|
||||
memset(Rights, 0, RIGHTS_STRING_SIZE);
|
||||
break;
|
||||
}
|
||||
|
||||
strcat_s(Rights, RIGHTS_STRING_SIZE, ((Protect & PAGE_GUARD) == PAGE_GUARD) ? "G" : "-");
|
||||
|
|
|
|||
|
|
@ -45,6 +45,9 @@ void GetModuleInfo(MODINFO & Info, ULONG_PTR FileMapVA)
|
|||
// Add entry to the vector
|
||||
Info.sections.push_back(curSection);
|
||||
}
|
||||
|
||||
// Clear imports by default
|
||||
Info.imports.clear();
|
||||
}
|
||||
|
||||
bool ModLoad(duint Base, duint Size, const char* FullPath)
|
||||
|
|
@ -292,6 +295,20 @@ bool ModSectionsFromAddr(duint Address, std::vector<MODSECTIONINFO>* Sections)
|
|||
return true;
|
||||
}
|
||||
|
||||
bool ModImportsFromAddr(duint Address, std::vector<MODIMPORTINFO>* Imports)
|
||||
{
|
||||
SHARED_ACQUIRE(LockModules);
|
||||
|
||||
auto module = ModInfoFromAddr(Address);
|
||||
|
||||
if (!module)
|
||||
return false;
|
||||
|
||||
// Copy vector <-> vector
|
||||
*Imports = module->imports;
|
||||
return true;
|
||||
}
|
||||
|
||||
duint ModEntryFromAddr(duint Address)
|
||||
{
|
||||
SHARED_ACQUIRE(LockModules);
|
||||
|
|
@ -328,4 +345,33 @@ void ModGetList(std::vector<MODINFO> & list)
|
|||
list.clear();
|
||||
for(const auto & mod : modinfo)
|
||||
list.push_back(mod.second);
|
||||
}
|
||||
|
||||
bool ModAddImportToModule(duint Base, MODIMPORTINFO importInfo)
|
||||
{
|
||||
SHARED_ACQUIRE(LockModules);
|
||||
|
||||
if (!Base || !importInfo.addr)
|
||||
return false;
|
||||
|
||||
auto module = ModInfoFromAddr(Base);
|
||||
|
||||
if (!module)
|
||||
return false;
|
||||
|
||||
// Search in Import Vector
|
||||
std::vector<MODIMPORTINFO> *pImports = &(module->imports);
|
||||
auto it = std::find_if(pImports->begin(), pImports->end(), [&importInfo](MODIMPORTINFO currentImportInfo)->bool
|
||||
{
|
||||
return (importInfo.addr == currentImportInfo.addr);
|
||||
});
|
||||
|
||||
// Import in the list already
|
||||
if (it != pImports->end())
|
||||
return false;
|
||||
|
||||
// Add import to imports vector
|
||||
pImports->push_back(importInfo);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
@ -9,6 +9,13 @@ struct MODSECTIONINFO
|
|||
char name[MAX_SECTION_SIZE * 5]; // Escaped section name
|
||||
};
|
||||
|
||||
struct MODIMPORTINFO
|
||||
{
|
||||
duint addr; // Virtual address
|
||||
char name[MAX_IMPORT_SIZE];
|
||||
char moduleName[MAX_MODULE_SIZE];
|
||||
};
|
||||
|
||||
struct MODINFO
|
||||
{
|
||||
duint base; // Module base
|
||||
|
|
@ -21,6 +28,7 @@ struct MODINFO
|
|||
char path[MAX_PATH]; // File path (in UTF8)
|
||||
|
||||
std::vector<MODSECTIONINFO> sections;
|
||||
std::vector<MODIMPORTINFO> imports;
|
||||
};
|
||||
|
||||
bool ModLoad(duint Base, duint Size, const char* FullPath);
|
||||
|
|
@ -34,7 +42,9 @@ duint ModHashFromName(const char* Module);
|
|||
duint ModBaseFromName(const char* Module);
|
||||
duint ModSizeFromAddr(duint Address);
|
||||
bool ModSectionsFromAddr(duint Address, std::vector<MODSECTIONINFO>* Sections);
|
||||
bool ModImportsFromAddr(duint Address, std::vector<MODIMPORTINFO>* Imports);
|
||||
duint ModEntryFromAddr(duint Address);
|
||||
int ModPathFromAddr(duint Address, char* Path, int Size);
|
||||
int ModPathFromName(const char* Module, char* Path, int Size);
|
||||
void ModGetList(std::vector<MODINFO> & list);
|
||||
void ModGetList(std::vector<MODINFO> & list);
|
||||
bool ModAddImportToModule(duint Base, MODIMPORTINFO importInfo);
|
||||
|
|
|
|||
|
|
@ -9,34 +9,182 @@
|
|||
#include "console.h"
|
||||
#include "module.h"
|
||||
|
||||
int RefFind(duint Address, duint Size, CBREF Callback, void* UserData, bool Silent, const char* Name)
|
||||
int RefFind(duint Address, duint Size, CBREF Callback, void* UserData, bool Silent, const char* Name, REFFINDTYPE type)
|
||||
{
|
||||
duint regionSize = 0;
|
||||
duint regionBase = MemFindBaseAddr(Address, ®ionSize, true);
|
||||
char fullName[deflen];
|
||||
char moduleName[MAX_MODULE_SIZE];
|
||||
int refFindInRangeRet;
|
||||
duint scanStart, scanSize;
|
||||
REFINFO refInfo;
|
||||
|
||||
// If the memory page wasn't found, fail
|
||||
if(!regionBase || !regionSize)
|
||||
// Search in current Region
|
||||
if (type == CURRENT_REGION)
|
||||
{
|
||||
if(!Silent)
|
||||
dprintf("Invalid memory page 0x%p\n", Address);
|
||||
duint regionSize = 0;
|
||||
duint regionBase = MemFindBaseAddr(Address, ®ionSize, true);
|
||||
|
||||
return 0;
|
||||
// If the memory page wasn't found, fail
|
||||
if (!regionBase || !regionSize)
|
||||
{
|
||||
if (!Silent)
|
||||
dprintf("Invalid memory page 0x%p\n", Address);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Assume the entire range is used
|
||||
scanStart = regionBase;
|
||||
scanSize = regionSize;
|
||||
|
||||
// Otherwise use custom boundaries if size was supplied
|
||||
if(Size)
|
||||
{
|
||||
duint maxsize = Size - (Address - regionBase);
|
||||
|
||||
// Make sure the size fits in one page
|
||||
scanStart = Address;
|
||||
scanSize = min(Size, maxsize);
|
||||
}
|
||||
|
||||
// Determine the full module name
|
||||
if (ModNameFromAddr(scanStart, moduleName, true))
|
||||
sprintf_s(fullName, "%s (Region %s)", Name, moduleName);
|
||||
else
|
||||
sprintf_s(fullName, "%s (Region %p)", Name, scanStart);
|
||||
|
||||
// Initialize disassembler
|
||||
Capstone cp;
|
||||
|
||||
// Allow an "initialization" notice
|
||||
refInfo.refcount = 0;
|
||||
refInfo.userinfo = UserData;
|
||||
refInfo.name = fullName;
|
||||
|
||||
|
||||
refFindInRangeRet = RefFindInRange(scanStart, scanSize, Callback, UserData, Silent, refInfo, cp, true, [](int percent)
|
||||
{
|
||||
GuiReferenceSetCurrentTaskProgress(percent, "Region Search");
|
||||
GuiReferenceSetProgress(percent);
|
||||
});
|
||||
|
||||
GuiReferenceReloadData();
|
||||
|
||||
if (!refFindInRangeRet)
|
||||
return refFindInRangeRet;
|
||||
|
||||
refInfo.refcount += refFindInRangeRet;
|
||||
}
|
||||
|
||||
// Assume the entire range is used
|
||||
duint scanStart = regionBase;
|
||||
duint scanSize = regionSize;
|
||||
|
||||
// Otherwise use custom boundaries if size was supplied
|
||||
if(Size)
|
||||
// Search in current Module
|
||||
else if (type == CURRENT_MODULE)
|
||||
{
|
||||
duint maxsize = Size - (Address - regionBase);
|
||||
MODINFO *modInfo = ModInfoFromAddr(Address);
|
||||
|
||||
// Make sure the size fits in one page
|
||||
scanStart = Address;
|
||||
scanSize = min(Size, maxsize);
|
||||
if (!modInfo)
|
||||
{
|
||||
if (!Silent)
|
||||
dprintf("Couldn't locate module for 0x%p\n", Address);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
duint modBase = modInfo->base;
|
||||
duint modSize = modInfo->size;
|
||||
|
||||
scanStart = modBase;
|
||||
scanSize = modSize;
|
||||
|
||||
// Determine the full module name
|
||||
if (ModNameFromAddr(scanStart, moduleName, true))
|
||||
sprintf_s(fullName, "%s (%s)", Name, moduleName);
|
||||
else
|
||||
sprintf_s(fullName, "%s (%p)", Name, scanStart);
|
||||
|
||||
// Initialize disassembler
|
||||
Capstone cp;
|
||||
|
||||
// Allow an "initialization" notice
|
||||
refInfo.refcount = 0;
|
||||
refInfo.userinfo = UserData;
|
||||
refInfo.name = fullName;
|
||||
|
||||
refFindInRangeRet = RefFindInRange(scanStart, scanSize, Callback, UserData, Silent, refInfo, cp, true, [](int percent)
|
||||
{
|
||||
GuiReferenceSetCurrentTaskProgress(percent, "Module Search");
|
||||
GuiReferenceSetProgress(percent);
|
||||
});
|
||||
|
||||
|
||||
if (!refFindInRangeRet)
|
||||
return refFindInRangeRet;
|
||||
|
||||
GuiReferenceReloadData();
|
||||
}
|
||||
|
||||
// Search in all Modules
|
||||
else if (type == ALL_MODULES)
|
||||
{
|
||||
bool initCallBack = true;
|
||||
std::vector<MODINFO > modList;
|
||||
ModGetList(modList);
|
||||
|
||||
if (!modList.size())
|
||||
{
|
||||
if (!Silent)
|
||||
dprintf("Couldn't get module list");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Initialize disassembler
|
||||
Capstone cp;
|
||||
|
||||
// Determine the full module
|
||||
sprintf_s(fullName, "All Modules (%s)", Name);
|
||||
|
||||
// Allow an "initialization" notice
|
||||
refInfo.refcount = 0;
|
||||
refInfo.userinfo = UserData;
|
||||
refInfo.name = fullName;
|
||||
|
||||
for (duint i = 0; i < modList.size(); i++)
|
||||
{
|
||||
scanStart = modList[i].base;
|
||||
scanSize = modList[i].size;
|
||||
|
||||
if (i != 0)
|
||||
initCallBack = false;
|
||||
|
||||
refFindInRangeRet = RefFindInRange(scanStart, scanSize, Callback, UserData, Silent, refInfo, cp, initCallBack, [&i, &modList](int percent)
|
||||
{
|
||||
float fPercent = (float)percent / 100.f;
|
||||
float fTotalPercent = ((float)i + fPercent) / (float)modList.size();
|
||||
|
||||
int totalPercent = (int)floor(fTotalPercent * 100.f);
|
||||
|
||||
char tst[256];
|
||||
strcpy_s(tst, modList[i].name);
|
||||
|
||||
GuiReferenceSetCurrentTaskProgress(percent, modList[i].name);
|
||||
GuiReferenceSetProgress(totalPercent);
|
||||
});
|
||||
|
||||
|
||||
if (!refFindInRangeRet)
|
||||
return refFindInRangeRet;
|
||||
|
||||
GuiReferenceReloadData();
|
||||
}
|
||||
}
|
||||
|
||||
GuiReferenceSetProgress(100);
|
||||
GuiReferenceReloadData();
|
||||
return refInfo.refcount;
|
||||
}
|
||||
|
||||
|
||||
int RefFindInRange(duint scanStart, duint scanSize, CBREF Callback, void* UserData, bool Silent, REFINFO &refInfo, Capstone &cp, bool initCallBack, CBPROGRESS cbUpdateProgress)
|
||||
{
|
||||
// Allocate and read a buffer from the remote process
|
||||
Memory<unsigned char*> data(scanSize, "reffind:data");
|
||||
|
||||
|
|
@ -48,25 +196,8 @@ int RefFind(duint Address, duint Size, CBREF Callback, void* UserData, bool Sile
|
|||
return 0;
|
||||
}
|
||||
|
||||
// Determine the full module name
|
||||
char fullName[deflen];
|
||||
char moduleName[MAX_MODULE_SIZE];
|
||||
|
||||
if(ModNameFromAddr(scanStart, moduleName, true))
|
||||
sprintf_s(fullName, "%s (%s)", Name, moduleName);
|
||||
else
|
||||
sprintf_s(fullName, "%s (%p)", Name, scanStart);
|
||||
|
||||
// Initialize disassembler
|
||||
Capstone cp;
|
||||
|
||||
// Allow an "initialization" notice
|
||||
REFINFO refInfo;
|
||||
refInfo.refcount = 0;
|
||||
refInfo.userinfo = UserData;
|
||||
refInfo.name = fullName;
|
||||
|
||||
Callback(0, 0, &refInfo);
|
||||
if(initCallBack)
|
||||
Callback(0, 0, &refInfo);
|
||||
|
||||
//concurrency::parallel_for(duint (0), scanSize, [&](duint i)
|
||||
for(duint i = 0; i < scanSize;)
|
||||
|
|
@ -78,7 +209,7 @@ int RefFind(duint Address, duint Size, CBREF Callback, void* UserData, bool Sile
|
|||
// Integer = floor(percent)
|
||||
int percent = (int)floor(((float)i / (float)scanSize) * 100.0f);
|
||||
|
||||
GuiReferenceSetProgress(percent);
|
||||
cbUpdateProgress(percent);
|
||||
}
|
||||
|
||||
// Disassemble the instruction
|
||||
|
|
@ -104,7 +235,6 @@ int RefFind(duint Address, duint Size, CBREF Callback, void* UserData, bool Sile
|
|||
i += disasmLen;
|
||||
}
|
||||
|
||||
GuiReferenceSetProgress(100);
|
||||
GuiReferenceReloadData();
|
||||
cbUpdateProgress(100);
|
||||
return refInfo.refcount;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
#include "_global.h"
|
||||
#include "disasm_fast.h"
|
||||
#include <functional>
|
||||
|
||||
struct REFINFO
|
||||
{
|
||||
|
|
@ -10,7 +11,16 @@ struct REFINFO
|
|||
const char* name;
|
||||
};
|
||||
|
||||
typedef enum
|
||||
{
|
||||
CURRENT_REGION,
|
||||
CURRENT_MODULE,
|
||||
ALL_MODULES
|
||||
} REFFINDTYPE;
|
||||
|
||||
// Reference callback typedef
|
||||
typedef bool (*CBREF)(Capstone* disasm, BASIC_INSTRUCTION_INFO* basicinfo, REFINFO* refinfo);
|
||||
typedef std::function<void(int) > CBPROGRESS;
|
||||
|
||||
int RefFind(duint Address, duint Size, CBREF Callback, void* UserData, bool Silent, const char* Name);
|
||||
int RefFind(duint Address, duint Size, CBREF Callback, void* UserData, bool Silent, const char* Name, REFFINDTYPE type);
|
||||
int RefFindInRange(duint scanStart, duint scanSize, CBREF Callback, void* UserData, bool Silent, REFINFO &refInfo, Capstone &cp, bool initCallBack, CBPROGRESS cbUpdateProgress);
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@
|
|||
#include "console.h"
|
||||
#include "module.h"
|
||||
#include "label.h"
|
||||
#include "addrinfo.h"
|
||||
|
||||
struct SYMBOLCBDATA
|
||||
{
|
||||
|
|
@ -16,35 +17,25 @@ struct SYMBOLCBDATA
|
|||
void* user;
|
||||
};
|
||||
|
||||
typedef std::vector<SYMBOLINFO> SYMBOLINFOVECTOR;
|
||||
typedef std::map<ULONG64, SYMBOLINFOVECTOR> SYMBOLINFOMAP;
|
||||
SYMBOLINFOMAP modulesCacheList;
|
||||
|
||||
|
||||
BOOL CALLBACK EnumSymbols(PSYMBOL_INFO SymInfo, ULONG SymbolSize, PVOID UserContext)
|
||||
{
|
||||
bool returnValue;
|
||||
SYMBOLINFO curSymbol;
|
||||
memset(&curSymbol, 0, sizeof(SYMBOLINFO));
|
||||
|
||||
curSymbol.addr = (duint)SymInfo->Address;
|
||||
curSymbol.decoratedSymbol = (char*)BridgeAlloc(strlen(SymInfo->Name) + 1);
|
||||
curSymbol.undecoratedSymbol = (char*)BridgeAlloc(MAX_SYM_NAME);
|
||||
strcpy_s(curSymbol.decoratedSymbol, strlen(SymInfo->Name) + 1, SymInfo->Name);
|
||||
// Convert from SYMBOL_INFO to SYMBOLINFO
|
||||
returnValue = SymGetSymbolInfo(SymInfo, &curSymbol, false);
|
||||
|
||||
// Skip bad ordinals
|
||||
if(strstr(SymInfo->Name, "Ordinal"))
|
||||
{
|
||||
// Does the symbol point to the module base?
|
||||
if(SymInfo->Address == SymInfo->ModBase)
|
||||
return TRUE;
|
||||
}
|
||||
if (!returnValue)
|
||||
return false;
|
||||
|
||||
// Convert a mangled/decorated C++ name to a readable format
|
||||
if(!SafeUnDecorateSymbolName(SymInfo->Name, curSymbol.undecoratedSymbol, MAX_SYM_NAME, UNDNAME_COMPLETE))
|
||||
{
|
||||
BridgeFree(curSymbol.undecoratedSymbol);
|
||||
curSymbol.undecoratedSymbol = nullptr;
|
||||
}
|
||||
else if(!strcmp(curSymbol.decoratedSymbol, curSymbol.undecoratedSymbol))
|
||||
{
|
||||
BridgeFree(curSymbol.undecoratedSymbol);
|
||||
curSymbol.undecoratedSymbol = nullptr;
|
||||
}
|
||||
// Add to the cache
|
||||
modulesCacheList[SymInfo->ModBase].push_back(curSymbol);
|
||||
|
||||
SYMBOLCBDATA* cbData = (SYMBOLCBDATA*)UserContext;
|
||||
cbData->cbSymbolEnum(&curSymbol, cbData->user);
|
||||
|
|
@ -57,11 +48,35 @@ void SymEnum(duint Base, CBSYMBOLENUM EnumCallback, void* UserData)
|
|||
symbolCbData.cbSymbolEnum = EnumCallback;
|
||||
symbolCbData.user = UserData;
|
||||
|
||||
SymEnumImports(Base, &symbolCbData);
|
||||
|
||||
// Enumerate every single symbol for the module in 'base'
|
||||
if(!SafeSymEnumSymbols(fdProcessInfo->hProcess, Base, "*", EnumSymbols, &symbolCbData))
|
||||
dputs("SymEnumSymbols failed!");
|
||||
}
|
||||
|
||||
void SymEnumFromCache(duint Base, CBSYMBOLENUM EnumCallback, void* UserData)
|
||||
{
|
||||
SYMBOLCBDATA symbolCbData;
|
||||
symbolCbData.cbSymbolEnum = EnumCallback;
|
||||
symbolCbData.user = UserData;
|
||||
|
||||
// Check if this module is cached in the list
|
||||
if (modulesCacheList.find(Base) != modulesCacheList.end())
|
||||
{
|
||||
SymEnumImports(Base, &symbolCbData);
|
||||
|
||||
// Callback
|
||||
for (duint i = 0; i < modulesCacheList[Base].size(); i++)
|
||||
symbolCbData.cbSymbolEnum(&modulesCacheList[Base].at(i), symbolCbData.user);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Then get the symbols and cache them
|
||||
SymEnum(Base, EnumCallback, UserData);
|
||||
}
|
||||
}
|
||||
|
||||
bool SymGetModuleList(std::vector<SYMBOLMODULEINFO>* List)
|
||||
{
|
||||
//
|
||||
|
|
@ -301,4 +316,147 @@ bool SymGetSourceLine(duint Cip, char* FileName, int* Line)
|
|||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void SymClearMemoryCache()
|
||||
{
|
||||
for (auto& itr : modulesCacheList)
|
||||
{
|
||||
SYMBOLINFOVECTOR* pModuleVector = &itr.second;
|
||||
|
||||
// Free up previously allocated memory
|
||||
for (duint i = 0; i < pModuleVector->size(); i++)
|
||||
{
|
||||
BridgeFree(pModuleVector->at(i).decoratedSymbol);
|
||||
BridgeFree(pModuleVector->at(i).undecoratedSymbol);
|
||||
}
|
||||
}
|
||||
|
||||
// Clear the whole map
|
||||
modulesCacheList.clear();
|
||||
}
|
||||
|
||||
bool SymGetSymbolInfo(PSYMBOL_INFO SymInfo, SYMBOLINFO* curSymbol, bool isImported)
|
||||
{
|
||||
// SYMBOL_INFO is a structure used by Sym* functions
|
||||
// SYMBOLINFO is the custom structure used by the debugger
|
||||
// This functions fills SYMBOLINFO fields from SYMBOL_INFO data
|
||||
|
||||
curSymbol->addr = (duint)SymInfo->Address;
|
||||
curSymbol->decoratedSymbol = (char*)BridgeAlloc(strlen(SymInfo->Name) + 1);
|
||||
curSymbol->undecoratedSymbol = (char*)BridgeAlloc(MAX_SYM_NAME);
|
||||
strcpy_s(curSymbol->decoratedSymbol, strlen(SymInfo->Name) + 1, SymInfo->Name);
|
||||
|
||||
// Skip bad ordinals
|
||||
if (strstr(SymInfo->Name, "Ordinal"))
|
||||
{
|
||||
// Does the symbol point to the module base?
|
||||
if (SymInfo->Address == SymInfo->ModBase)
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// Convert a mangled/decorated C++ name to a readable format
|
||||
if (!SafeUnDecorateSymbolName(SymInfo->Name, curSymbol->undecoratedSymbol, MAX_SYM_NAME, UNDNAME_COMPLETE))
|
||||
{
|
||||
BridgeFree(curSymbol->undecoratedSymbol);
|
||||
curSymbol->undecoratedSymbol = nullptr;
|
||||
}
|
||||
else if (!strcmp(curSymbol->decoratedSymbol, curSymbol->undecoratedSymbol))
|
||||
{
|
||||
BridgeFree(curSymbol->undecoratedSymbol);
|
||||
curSymbol->undecoratedSymbol = nullptr;
|
||||
}
|
||||
|
||||
// Symbol is exported
|
||||
curSymbol->isImported = isImported;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void SymEnumImports(duint Base, SYMBOLCBDATA* pSymbolCbData)
|
||||
{
|
||||
char modImportString[MAX_IMPORT_SIZE];
|
||||
char buffer[sizeof(SYMBOL_INFO) + MAX_SYM_NAME]; // Reserve enough space for symbol name, see msdn for this
|
||||
SYMBOLINFO curSymbol;
|
||||
PSYMBOL_INFO pSymInfo;
|
||||
std::vector<MODIMPORTINFO> imports;
|
||||
|
||||
// SizeOfStruct and MaxNameLen need to be set or SymFromAddr() returns INVALID_PARAMETER
|
||||
pSymInfo = (PSYMBOL_INFO)buffer;
|
||||
pSymInfo->SizeOfStruct = sizeof(SYMBOL_INFO);
|
||||
pSymInfo->MaxNameLen = MAX_SYM_NAME;
|
||||
|
||||
// Enum imports if none found
|
||||
if (ModImportsFromAddr(Base, &imports) && !imports.size())
|
||||
{
|
||||
// Enum imports from current module
|
||||
apienumimports(Base, [](duint Base, duint Address, char* name, char* moduleName)
|
||||
{
|
||||
MODIMPORTINFO importInfo;
|
||||
importInfo.addr = Address;
|
||||
strcpy_s(importInfo.name, MAX_IMPORT_SIZE, name);
|
||||
strcpy_s(importInfo.moduleName, MAX_MODULE_SIZE, moduleName);
|
||||
|
||||
// Add import to the module structure
|
||||
ModAddImportToModule(Base, importInfo);
|
||||
});
|
||||
}
|
||||
|
||||
// Get imports
|
||||
if (ModImportsFromAddr(Base, &imports) && imports.size())
|
||||
{
|
||||
for (duint i = 0; i < imports.size(); i++)
|
||||
{
|
||||
// Can we get symbol for the import address?
|
||||
if (SafeSymFromAddr(fdProcessInfo->hProcess, (duint)imports[i].addr, 0, pSymInfo))
|
||||
{
|
||||
// Does the symbol point to the module base?
|
||||
if (!SymGetSymbolInfo(pSymInfo, &curSymbol, true))
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Otherwise just use import info from module itself
|
||||
curSymbol.addr = imports[i].addr;
|
||||
curSymbol.isImported = true;
|
||||
curSymbol.undecoratedSymbol = nullptr;
|
||||
curSymbol.decoratedSymbol = imports[i].name;
|
||||
}
|
||||
|
||||
// Format so that we get: moduleName.importSymbol
|
||||
strcpy_s(modImportString, imports[i].moduleName);
|
||||
|
||||
// Trim the extension if present
|
||||
char *modExt = strrchr(modImportString, '.');
|
||||
|
||||
if (modExt)
|
||||
*modExt = '\0';
|
||||
|
||||
// Buffers to hold the decorated and undecorated strings. Must be declared
|
||||
// outside of the if() scope.
|
||||
char undecBuf[MAX_IMPORT_SIZE];
|
||||
char decBuf[MAX_IMPORT_SIZE];
|
||||
|
||||
if (curSymbol.undecoratedSymbol)
|
||||
{
|
||||
// module.undecorated
|
||||
strcpy_s(undecBuf, modImportString);
|
||||
strncpy_s(undecBuf, curSymbol.undecoratedSymbol, _TRUNCATE);
|
||||
|
||||
curSymbol.undecoratedSymbol = undecBuf;
|
||||
}
|
||||
|
||||
if (curSymbol.decoratedSymbol)
|
||||
{
|
||||
// module.decorated
|
||||
strcpy_s(decBuf, modImportString);
|
||||
strncpy_s(decBuf, curSymbol.decoratedSymbol, _TRUNCATE);
|
||||
|
||||
curSymbol.decoratedSymbol = decBuf;
|
||||
}
|
||||
|
||||
// Callback
|
||||
pSymbolCbData->cbSymbolEnum(&curSymbol, pSymbolCbData->user);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -2,12 +2,18 @@
|
|||
|
||||
#include "_global.h"
|
||||
|
||||
struct SYMBOLCBDATA;
|
||||
|
||||
void SymEnum(duint Base, CBSYMBOLENUM EnumCallback, void* UserData);
|
||||
void SymEnumFromCache(duint Base, CBSYMBOLENUM EnumCallback, void* UserData);
|
||||
bool SymGetModuleList(std::vector<SYMBOLMODULEINFO>* List);
|
||||
void SymUpdateModuleList();
|
||||
void SymDownloadAllSymbols(const char* SymbolStore);
|
||||
bool SymAddrFromName(const char* Name, duint* Address);
|
||||
const char* SymGetSymbolicName(duint Address);
|
||||
void SymClearMemoryCache();
|
||||
bool SymGetSymbolInfo(PSYMBOL_INFO SymInfo, SYMBOLINFO* curSymbol, bool isImported);
|
||||
void SymEnumImports(duint Base, SYMBOLCBDATA* pSymbolCbData);
|
||||
|
||||
/**
|
||||
\brief Gets the source code file name and line from an address.
|
||||
|
|
|
|||
|
|
@ -50,7 +50,11 @@ enum SectionLock
|
|||
LockPluginCallbackList,
|
||||
LockPluginCommandList,
|
||||
LockPluginMenuList,
|
||||
LockLast,
|
||||
LockCmdLine,
|
||||
|
||||
// Number of elements in this enumeration. Must always be the last
|
||||
// index.
|
||||
LockLast
|
||||
};
|
||||
|
||||
class SectionLockerGlobal
|
||||
|
|
|
|||
|
|
@ -2187,7 +2187,7 @@ bool valtostring(const char* string, duint value, bool silent)
|
|||
else if(strstr(regName(), "sp")) //update stack
|
||||
{
|
||||
duint csp = GetContextDataEx(hActiveThread, UE_CSP);
|
||||
GuiStackDumpAt(csp, csp);
|
||||
DebugUpdateStack(csp, csp);
|
||||
GuiUpdateRegisterView();
|
||||
}
|
||||
else
|
||||
|
|
|
|||
|
|
@ -94,6 +94,7 @@ static void registercommands()
|
|||
dbgcmdnew("setcmdline\1setcommandline", cbDebugSetCmdline, true); //Set CmdLine
|
||||
dbgcmdnew("loadlib", cbDebugLoadLib, true); //Load DLL
|
||||
dbgcmdnew("skip", cbDebugSkip, true); //skip one instruction
|
||||
dbgcmdnew("setfreezestack", cbDebugSetfreezestack, false); //freeze the stack from auto updates
|
||||
|
||||
//breakpoints
|
||||
dbgcmdnew("bplist", cbDebugBplist, true); //breakpoint list
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@
|
|||
<ClCompile Include="breakpoint.cpp" />
|
||||
<ClCompile Include="CodeFollowPass.cpp" />
|
||||
<ClCompile Include="command.cpp" />
|
||||
<ClCompile Include="commandline.cpp" />
|
||||
<ClCompile Include="commandparser.cpp" />
|
||||
<ClCompile Include="comment.cpp" />
|
||||
<ClCompile Include="console.cpp" />
|
||||
|
|
@ -106,6 +107,7 @@
|
|||
<ClInclude Include="capstone\xcore.h" />
|
||||
<ClInclude Include="CodeFollowPass.h" />
|
||||
<ClInclude Include="command.h" />
|
||||
<ClInclude Include="commandline.h" />
|
||||
<ClInclude Include="commandparser.h" />
|
||||
<ClInclude Include="comment.h" />
|
||||
<ClInclude Include="console.h" />
|
||||
|
|
|
|||
|
|
@ -278,6 +278,9 @@
|
|||
<ClCompile Include="jit.cpp">
|
||||
<Filter>Source Files\Debugger Core</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="commandline.cpp">
|
||||
<Filter>Source Files\Information</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="x64_dbg.h">
|
||||
|
|
@ -646,5 +649,8 @@
|
|||
<ClInclude Include="yara\yara\stream.h">
|
||||
<Filter>Header Files\Third Party\yara\yara</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="commandline.h">
|
||||
<Filter>Header Files\Information</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
|
@ -1,6 +1,7 @@
|
|||
#include <windows.h>
|
||||
#include <dbghelp.h>
|
||||
#include <stdio.h>
|
||||
#include <exception>
|
||||
#include "crashdump.h"
|
||||
|
||||
BOOL
|
||||
|
|
@ -25,6 +26,15 @@ void CrashDumpInitialize()
|
|||
|
||||
if(MiniDumpWriteDumpPtr)
|
||||
AddVectoredExceptionHandler(0, CrashDumpVectoredHandler);
|
||||
|
||||
// If building for release mode only
|
||||
#ifndef _DEBUG
|
||||
// CRT invalid parameter callback
|
||||
_set_invalid_parameter_handler(InvalidParameterHandler);
|
||||
|
||||
// CRT terminate() callback
|
||||
set_terminate(TerminateHandler);
|
||||
#endif // _DEBUG
|
||||
}
|
||||
|
||||
void CrashDumpFatal(const char* Format, ...)
|
||||
|
|
@ -97,12 +107,12 @@ LONG CALLBACK CrashDumpVectoredHandler(EXCEPTION_POINTERS* ExceptionInfo)
|
|||
// Any "exception" under 0x1000 is usually just a failed RPC call
|
||||
if(ExceptionInfo && ExceptionInfo->ExceptionRecord->ExceptionCode > 0x00001000)
|
||||
{
|
||||
// Skip OutputDebugString(A/W) and invalid handles from TitanEngine
|
||||
switch(ExceptionInfo->ExceptionRecord->ExceptionCode)
|
||||
{
|
||||
case DBG_PRINTEXCEPTION_C:
|
||||
case 0x4001000A:
|
||||
case STATUS_INVALID_HANDLE:
|
||||
case DBG_PRINTEXCEPTION_C: // OutputDebugStringA
|
||||
case 0x4001000A: // OutputDebugStringW
|
||||
case STATUS_INVALID_HANDLE: // Invalid TitanEngine handle
|
||||
case 0x406D1388: // SetThreadName
|
||||
return EXCEPTION_CONTINUE_SEARCH;
|
||||
}
|
||||
|
||||
|
|
@ -110,4 +120,25 @@ LONG CALLBACK CrashDumpVectoredHandler(EXCEPTION_POINTERS* ExceptionInfo)
|
|||
}
|
||||
|
||||
return EXCEPTION_CONTINUE_SEARCH;
|
||||
}
|
||||
|
||||
void InvalidParameterHandler(const wchar_t* Expression, const wchar_t* Function, const wchar_t* File, unsigned int Line, uintptr_t Reserved)
|
||||
{
|
||||
// Notify user
|
||||
CrashDumpFatal("Invalid parameter passed to CRT function! Program will now crash.\n\nFile: %ws\nFunction: %ws\nExpression: %ws",
|
||||
Function ? Function : L"???",
|
||||
File ? File : L"???",
|
||||
Expression ? Expression : L"???");
|
||||
|
||||
// Generate exception
|
||||
throw;
|
||||
}
|
||||
|
||||
void TerminateHandler()
|
||||
{
|
||||
// Notify user
|
||||
CrashDumpFatal("Process termination was requested in an unusual way. Program will now crash.");
|
||||
|
||||
// Generate exception
|
||||
throw;
|
||||
}
|
||||
|
|
@ -1,4 +1,6 @@
|
|||
#pragma once
|
||||
|
||||
void CrashDumpInitialize();
|
||||
LONG CALLBACK CrashDumpVectoredHandler(EXCEPTION_POINTERS* ExceptionInfo);
|
||||
LONG CALLBACK CrashDumpVectoredHandler(EXCEPTION_POINTERS* ExceptionInfo);
|
||||
void InvalidParameterHandler(const wchar_t* Expression, const wchar_t* Function, const wchar_t* File, unsigned int Line, uintptr_t Reserved);
|
||||
void TerminateHandler();
|
||||
|
|
@ -964,10 +964,16 @@ dsint AbstractTableView::getTableOffset()
|
|||
void AbstractTableView::setTableOffset(dsint val)
|
||||
{
|
||||
dsint wMaxOffset = getRowCount() - getViewableRowsCount() + 1;
|
||||
wMaxOffset = wMaxOffset > 0 ? wMaxOffset : 0;
|
||||
wMaxOffset = wMaxOffset > 0 ? getRowCount() : 0;
|
||||
if(val > wMaxOffset)
|
||||
return;
|
||||
mTableOffset = val;
|
||||
|
||||
// If val is within the last ViewableRows, then set RVA to rowCount - ViewableRows + 1
|
||||
if(wMaxOffset && val >= (getRowCount() - getViewableRowsCount() + 1))
|
||||
mTableOffset = (getRowCount() - getViewableRowsCount()) + 1;
|
||||
else
|
||||
mTableOffset = val;
|
||||
|
||||
emit tableOffsetChanged(val);
|
||||
|
||||
#ifdef _WIN64
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
#include "Disassembly.h"
|
||||
#include "Configuration.h"
|
||||
#include "Bridge.h"
|
||||
#include "MainWindow.h"
|
||||
#include "GraphView.h"
|
||||
|
||||
Disassembly::Disassembly(QWidget* parent) : AbstractTableView(parent)
|
||||
|
|
@ -1272,6 +1273,7 @@ void Disassembly::disassembleAt(dsint parVA, dsint parCIP, bool history, dsint n
|
|||
{
|
||||
dsint wBase = DbgMemFindBaseAddr(parVA, 0);
|
||||
dsint wSize = DbgMemGetPageSize(wBase);
|
||||
|
||||
if(!wBase || !wSize)
|
||||
return;
|
||||
dsint wRVA = parVA - wBase;
|
||||
|
|
@ -1301,6 +1303,7 @@ void Disassembly::disassembleAt(dsint parVA, dsint parCIP, bool history, dsint n
|
|||
mCurrentVa++;
|
||||
newHistory.va = selectionVA;
|
||||
newHistory.tableOffset = selectionTableOffset;
|
||||
newHistory.windowTitle = MainWindow::windowTitle;
|
||||
mVaHistory.push_back(newHistory);
|
||||
}
|
||||
}
|
||||
|
|
@ -1361,6 +1364,7 @@ void Disassembly::disassembleAt(dsint parVA, dsint parCIP, bool history, dsint n
|
|||
//new disassembled address
|
||||
newHistory.va = parVA;
|
||||
newHistory.tableOffset = getTableOffset();
|
||||
newHistory.windowTitle = MainWindow::windowTitle;
|
||||
if(mVaHistory.size())
|
||||
{
|
||||
if(mVaHistory.last().va != parVA) //not 2x the same va in history
|
||||
|
|
@ -1471,6 +1475,9 @@ void Disassembly::historyPrevious()
|
|||
return;
|
||||
mCurrentVa--;
|
||||
disassembleAt(mVaHistory.at(mCurrentVa).va, rvaToVa(mCipRva), false, mVaHistory.at(mCurrentVa).tableOffset);
|
||||
|
||||
// Update window title
|
||||
emit updateWindowTitle(mVaHistory.at(mCurrentVa).windowTitle);
|
||||
}
|
||||
|
||||
void Disassembly::historyNext()
|
||||
|
|
@ -1480,6 +1487,9 @@ void Disassembly::historyNext()
|
|||
return;
|
||||
mCurrentVa++;
|
||||
disassembleAt(mVaHistory.at(mCurrentVa).va, rvaToVa(mCipRva), false, mVaHistory.at(mCurrentVa).tableOffset);
|
||||
|
||||
// Update window title
|
||||
emit updateWindowTitle(mVaHistory.at(mCurrentVa).windowTitle);
|
||||
}
|
||||
|
||||
bool Disassembly::historyHasPrevious()
|
||||
|
|
|
|||
|
|
@ -98,6 +98,7 @@ public:
|
|||
signals:
|
||||
void selectionChanged(dsint parVA);
|
||||
void disassembledAt(dsint parVA, dsint parCIP, bool history, dsint newTableOffset);
|
||||
void updateWindowTitle(QString title);
|
||||
void drawGraphAtAddress(dsint va);
|
||||
|
||||
public slots:
|
||||
|
|
@ -132,6 +133,7 @@ private:
|
|||
{
|
||||
dsint va;
|
||||
dsint tableOffset;
|
||||
QString windowTitle;
|
||||
} HistoryData_t;
|
||||
|
||||
QList<HistoryData_t> mVaHistory;
|
||||
|
|
|
|||
|
|
@ -10,25 +10,41 @@ ReferenceView::ReferenceView()
|
|||
mSearchStartCol = 1;
|
||||
mFollowDumpDefault = false;
|
||||
|
||||
QHBoxLayout* layout = new QHBoxLayout();
|
||||
QHBoxLayout* layoutTotalProgress = new QHBoxLayout();
|
||||
QHBoxLayout* layoutCurrentTaskProgress = new QHBoxLayout();
|
||||
|
||||
// Create search progress bar
|
||||
mSearchProgress = new QProgressBar();
|
||||
mSearchProgress->setRange(0, 100);
|
||||
mSearchProgress->setTextVisible(false);
|
||||
mSearchProgress->setMaximumHeight(15);
|
||||
layout->addWidget(mSearchProgress);
|
||||
// Create current task search progress bar
|
||||
mSearchCurrentTaskProgress = new QProgressBar();
|
||||
mSearchCurrentTaskProgress->setRange(0, 100);
|
||||
mSearchCurrentTaskProgress->setTextVisible(true);
|
||||
mSearchCurrentTaskProgress->setMaximumHeight(15);
|
||||
layoutCurrentTaskProgress->addWidget(mSearchCurrentTaskProgress);
|
||||
|
||||
// Create total search progress bar
|
||||
mSearchTotalProgress = new QProgressBar();
|
||||
mSearchTotalProgress->setRange(0, 100);
|
||||
mSearchTotalProgress->setTextVisible(true);
|
||||
mSearchTotalProgress->setMaximumHeight(15);
|
||||
layoutTotalProgress->addWidget(mSearchTotalProgress);
|
||||
|
||||
// Label for the number of references
|
||||
mCountLabel = new QLabel("tst");
|
||||
mCountLabel->setAlignment(Qt::AlignCenter);
|
||||
mCountLabel->setMaximumHeight(16);
|
||||
mCountLabel->setMinimumWidth(40);
|
||||
mCountLabel->setContentsMargins(2, 0, 5, 0);
|
||||
layout->addWidget(mCountLabel);
|
||||
mCountTotalLabel = new QLabel("tst");
|
||||
mCountTotalLabel->setAlignment(Qt::AlignCenter);
|
||||
mCountTotalLabel->setMaximumHeight(16);
|
||||
mCountTotalLabel->setMinimumWidth(40);
|
||||
mCountTotalLabel->setContentsMargins(2, 0, 5, 0);
|
||||
layoutTotalProgress->addWidget(mCountTotalLabel);
|
||||
|
||||
mCountCurrentTaskLabel = new QLabel("");
|
||||
mCountCurrentTaskLabel->setAlignment(Qt::AlignCenter);
|
||||
mCountCurrentTaskLabel->setMaximumHeight(16);
|
||||
mCountCurrentTaskLabel->setMinimumWidth(40);
|
||||
mCountCurrentTaskLabel->setContentsMargins(2, 0, 5, 0);
|
||||
layoutCurrentTaskProgress->addWidget(mCountCurrentTaskLabel);
|
||||
|
||||
// Add the progress bar and label to the main layout
|
||||
mMainLayout->addLayout(layout);
|
||||
mMainLayout->addLayout(layoutCurrentTaskProgress);
|
||||
mMainLayout->addLayout(layoutTotalProgress);
|
||||
|
||||
// Setup signals
|
||||
connect(Bridge::getBridge(), SIGNAL(referenceAddColumnAt(int, QString)), this, SLOT(addColumnAt(int, QString)));
|
||||
|
|
@ -36,7 +52,8 @@ ReferenceView::ReferenceView()
|
|||
connect(Bridge::getBridge(), SIGNAL(referenceSetCellContent(int, int, QString)), this, SLOT(setCellContent(int, int, QString)));
|
||||
connect(Bridge::getBridge(), SIGNAL(referenceReloadData()), this, SLOT(reloadData()));
|
||||
connect(Bridge::getBridge(), SIGNAL(referenceSetSingleSelection(int, bool)), this, SLOT(setSingleSelection(int, bool)));
|
||||
connect(Bridge::getBridge(), SIGNAL(referenceSetProgress(int)), mSearchProgress, SLOT(setValue(int)));
|
||||
connect(Bridge::getBridge(), SIGNAL(referenceSetProgress(int)), this, SLOT(referenceSetProgressSlot(int)));
|
||||
connect(Bridge::getBridge(), SIGNAL(referenceSetCurrentTaskProgress(int,QString)), this, SLOT(referenceSetCurrentTaskProgressSlot(int,QString)));
|
||||
connect(Bridge::getBridge(), SIGNAL(referenceSetSearchStartCol(int)), this, SLOT(setSearchStartCol(int)));
|
||||
connect(this, SIGNAL(listContextMenuSignal(QMenu*)), this, SLOT(referenceContextMenu(QMenu*)));
|
||||
connect(this, SIGNAL(enterPressedSignal()), this, SLOT(followGenericAddress()));
|
||||
|
|
@ -80,7 +97,7 @@ void ReferenceView::disconnectBridge()
|
|||
disconnect(Bridge::getBridge(), SIGNAL(referenceSetCellContent(int, int, QString)), this, SLOT(setCellContent(int, int, QString)));
|
||||
disconnect(Bridge::getBridge(), SIGNAL(referenceReloadData()), this, SLOT(reloadData()));
|
||||
disconnect(Bridge::getBridge(), SIGNAL(referenceSetSingleSelection(int, bool)), this, SLOT(setSingleSelection(int, bool)));
|
||||
disconnect(Bridge::getBridge(), SIGNAL(referenceSetProgress(int)), mSearchProgress, SLOT(setValue(int)));
|
||||
disconnect(Bridge::getBridge(), SIGNAL(referenceSetProgress(int)), mSearchTotalProgress, SLOT(setValue(int)));
|
||||
disconnect(Bridge::getBridge(), SIGNAL(referenceSetSearchStartCol(int)), this, SLOT(setSearchStartCol(int)));
|
||||
}
|
||||
|
||||
|
|
@ -90,6 +107,20 @@ void ReferenceView::refreshShortcutsSlot()
|
|||
mToggleBookmark->setShortcut(ConfigShortcut("ActionToggleBookmark"));
|
||||
}
|
||||
|
||||
void ReferenceView::referenceSetProgressSlot(int progress)
|
||||
{
|
||||
mSearchTotalProgress->setValue(progress);
|
||||
mSearchTotalProgress->setAlignment(Qt::AlignCenter);
|
||||
mSearchTotalProgress->setFormat("Total Progress " + QString::number(progress) + "%");
|
||||
}
|
||||
|
||||
void ReferenceView::referenceSetCurrentTaskProgressSlot(int progress, QString taskTitle)
|
||||
{
|
||||
mSearchCurrentTaskProgress->setValue(progress);
|
||||
mSearchCurrentTaskProgress->setAlignment(Qt::AlignCenter);
|
||||
mSearchCurrentTaskProgress->setFormat(taskTitle + " " + QString::number(progress) + "%");
|
||||
}
|
||||
|
||||
void ReferenceView::addColumnAt(int width, QString title)
|
||||
{
|
||||
int charwidth = mList->getCharWidth();
|
||||
|
|
@ -109,7 +140,7 @@ void ReferenceView::addColumnAt(int width, QString title)
|
|||
|
||||
void ReferenceView::setRowCount(dsint count)
|
||||
{
|
||||
emit mCountLabel->setText(QString("%1").arg(count));
|
||||
emit mCountTotalLabel->setText(QString("%1").arg(count));
|
||||
mSearchBox->setText("");
|
||||
mList->setRowCount(count);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -29,19 +29,23 @@ private slots:
|
|||
void toggleBreakpoint();
|
||||
void toggleBookmark();
|
||||
void refreshShortcutsSlot();
|
||||
void referenceSetProgressSlot(int progress);
|
||||
void referenceSetCurrentTaskProgressSlot(int progress, QString taskTitle);
|
||||
|
||||
signals:
|
||||
void showCpu();
|
||||
|
||||
private:
|
||||
QProgressBar* mSearchProgress;
|
||||
QProgressBar* mSearchTotalProgress;
|
||||
QProgressBar* mSearchCurrentTaskProgress;
|
||||
QAction* mFollowAddress;
|
||||
QAction* mFollowDumpAddress;
|
||||
QAction* mFollowApiAddress;
|
||||
QAction* mToggleBreakpoint;
|
||||
QAction* mToggleBookmark;
|
||||
bool mFollowDumpDefault;
|
||||
QLabel* mCountLabel;
|
||||
QLabel* mCountTotalLabel;
|
||||
QLabel* mCountCurrentTaskLabel;
|
||||
|
||||
dsint apiAddressFromString(const QString & s);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -2,6 +2,8 @@
|
|||
#include "ui_SearchListView.h"
|
||||
#include "FlickerThread.h"
|
||||
|
||||
#include <QMessageBox>
|
||||
|
||||
SearchListView::SearchListView(QWidget* parent) :
|
||||
QWidget(parent),
|
||||
ui(new Ui::SearchListView)
|
||||
|
|
@ -9,7 +11,7 @@ SearchListView::SearchListView(QWidget* parent) :
|
|||
ui->setupUi(this);
|
||||
|
||||
setContextMenuPolicy(Qt::CustomContextMenu);
|
||||
|
||||
mCursorPosition = 0;
|
||||
// Create the reference list
|
||||
mList = new SearchListViewTable();
|
||||
|
||||
|
|
@ -50,15 +52,20 @@ SearchListView::SearchListView(QWidget* parent) :
|
|||
for(int i = 0; i < ui->mainSplitter->count(); i++)
|
||||
ui->mainSplitter->handle(i)->setEnabled(false);
|
||||
|
||||
// Install eventFilter
|
||||
mList->installEventFilter(this);
|
||||
mSearchList->installEventFilter(this);
|
||||
mSearchBox->installEventFilter(this);
|
||||
|
||||
// Setup search menu action
|
||||
mSearchAction = new QAction("Search...", this);
|
||||
connect(mSearchAction, SIGNAL(triggered()), this, SLOT(searchSlot()));
|
||||
|
||||
// Slots
|
||||
connect(mList, SIGNAL(keyPressedSignal(QKeyEvent*)), this, SLOT(listKeyPressed(QKeyEvent*)));
|
||||
// connect(mList, SIGNAL(keyPressedSignal(QKeyEvent*)), this, SLOT(listKeyPressed(QKeyEvent*)));
|
||||
connect(mList, SIGNAL(contextMenuSignal(QPoint)), this, SLOT(listContextMenu(QPoint)));
|
||||
connect(mList, SIGNAL(doubleClickedSignal()), this, SLOT(doubleClickedSlot()));
|
||||
connect(mSearchList, SIGNAL(keyPressedSignal(QKeyEvent*)), this, SLOT(listKeyPressed(QKeyEvent*)));
|
||||
// connect(mSearchList, SIGNAL(keyPressedSignal(QKeyEvent*)), this, SLOT(listKeyPressed(QKeyEvent*)));
|
||||
connect(mSearchList, SIGNAL(contextMenuSignal(QPoint)), this, SLOT(listContextMenu(QPoint)));
|
||||
connect(mSearchList, SIGNAL(doubleClickedSignal()), this, SLOT(doubleClickedSlot()));
|
||||
connect(mSearchBox, SIGNAL(textChanged(QString)), this, SLOT(searchTextChanged(QString)));
|
||||
|
|
@ -69,29 +76,6 @@ SearchListView::~SearchListView()
|
|||
delete ui;
|
||||
}
|
||||
|
||||
void SearchListView::listKeyPressed(QKeyEvent* event)
|
||||
{
|
||||
char ch = event->text().toUtf8().constData()[0];
|
||||
if(isprint(ch)) //add a char to the search box
|
||||
mSearchBox->setText(mSearchBox->text().insert(mSearchBox->cursorPosition(), QString(QChar(ch))));
|
||||
else if(event->key() == Qt::Key_Backspace) //remove a char from the search box
|
||||
{
|
||||
QString newText;
|
||||
if(event->modifiers() == Qt::ControlModifier) //clear the search box
|
||||
newText = "";
|
||||
else
|
||||
{
|
||||
newText = mSearchBox->text();
|
||||
newText.chop(1);
|
||||
}
|
||||
mSearchBox->setText(newText);
|
||||
}
|
||||
else if((event->key() == Qt::Key_Return || event->key() == Qt::Key_Enter)) //user pressed enter
|
||||
emit enterPressedSignal();
|
||||
else if(event->key() == Qt::Key_Escape) // Press escape, clears the search box
|
||||
mSearchBox->clear();
|
||||
}
|
||||
|
||||
bool SearchListView::findTextInList(SearchListViewTable* list, QString text, int row, int startcol, bool startswith)
|
||||
{
|
||||
int count = list->getColumnCount();
|
||||
|
|
@ -168,6 +152,10 @@ void SearchListView::searchTextChanged(const QString & arg1)
|
|||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(rows == 0)
|
||||
emit emptySearchResult();
|
||||
|
||||
if(ui->checkBoxRegex->checkState() != Qt::Checked) //do not highlight with regex
|
||||
mSearchList->highlightText = arg1;
|
||||
mSearchList->reloadData();
|
||||
|
|
@ -199,6 +187,69 @@ void SearchListView::on_checkBoxRegex_toggled(bool checked)
|
|||
searchTextChanged(ui->searchBox->text());
|
||||
}
|
||||
|
||||
bool SearchListView::eventFilter(QObject *obj, QEvent *event)
|
||||
{
|
||||
// Click in searchBox
|
||||
if(obj == mSearchBox && event->type() == QEvent::MouseButtonPress)
|
||||
{
|
||||
QMouseEvent *mouseEvent = static_cast<QMouseEvent* >(event);
|
||||
QLineEdit *lineEdit = static_cast<QLineEdit* >(obj);
|
||||
|
||||
mCursorPosition = lineEdit->cursorPositionAt(mouseEvent->pos());
|
||||
lineEdit->setFocusPolicy(Qt::NoFocus);
|
||||
|
||||
return QObject::eventFilter(obj, event);
|
||||
}
|
||||
// KeyPress in List
|
||||
else if((obj == mList || obj == mSearchList) && event->type() == QEvent::KeyPress)
|
||||
{
|
||||
QKeyEvent *keyEvent = static_cast<QKeyEvent* >(event);
|
||||
char ch = keyEvent->text().toUtf8().constData()[0];
|
||||
|
||||
if(isprint(ch)) //add a char to the search box
|
||||
{
|
||||
mSearchBox->setText(mSearchBox->text().insert(mSearchBox->cursorPosition(), QString(QChar(ch))));
|
||||
mCursorPosition++;
|
||||
}
|
||||
else if(keyEvent->key() == Qt::Key_Backspace) //remove a char from the search box
|
||||
{
|
||||
QString newText;
|
||||
if(keyEvent->modifiers() == Qt::ControlModifier) //clear the search box
|
||||
{
|
||||
newText = "";
|
||||
mCursorPosition = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
newText = mSearchBox->text();
|
||||
|
||||
if(mCursorPosition > 0)
|
||||
newText.remove(mCursorPosition-1, 1);
|
||||
|
||||
((mCursorPosition - 1) < 0) ? mCursorPosition = 0 : mCursorPosition--;
|
||||
}
|
||||
mSearchBox->setText(newText);
|
||||
}
|
||||
else if((keyEvent->key() == Qt::Key_Return || keyEvent->key() == Qt::Key_Enter)) //user pressed enter
|
||||
{
|
||||
if(mCurList->getCellContent(mCurList->getInitialSelection(), 0).length())
|
||||
emit enterPressedSignal();
|
||||
}
|
||||
else if(keyEvent->key() == Qt::Key_Escape) // Press escape, clears the search box
|
||||
{
|
||||
mSearchBox->clear();
|
||||
mCursorPosition = 0;
|
||||
}
|
||||
|
||||
// Update cursorPosition to avoid a weird bug
|
||||
mSearchBox->setCursorPosition(mCursorPosition);
|
||||
|
||||
return true;
|
||||
}
|
||||
else
|
||||
return QObject::eventFilter(obj, event);
|
||||
}
|
||||
|
||||
void SearchListView::searchSlot()
|
||||
{
|
||||
FlickerThread* thread = new FlickerThread(ui->searchBox, this);
|
||||
|
|
|
|||
|
|
@ -31,7 +31,6 @@ public:
|
|||
|
||||
private slots:
|
||||
void searchTextChanged(const QString & arg1);
|
||||
void listKeyPressed(QKeyEvent* event);
|
||||
void listContextMenu(const QPoint & pos);
|
||||
void doubleClickedSlot();
|
||||
void searchSlot();
|
||||
|
|
@ -40,12 +39,17 @@ private slots:
|
|||
signals:
|
||||
void enterPressedSignal();
|
||||
void listContextMenuSignal(QMenu* wMenu);
|
||||
void emptySearchResult();
|
||||
|
||||
private:
|
||||
Ui::SearchListView* ui;
|
||||
QVBoxLayout* mListLayout;
|
||||
QWidget* mListPlaceHolder;
|
||||
QAction* mSearchAction;
|
||||
int mCursorPosition;
|
||||
|
||||
protected:
|
||||
bool eventFilter(QObject *obj, QEvent *event);
|
||||
};
|
||||
|
||||
#endif // SEARCHLISTVIEW_H
|
||||
|
|
|
|||
|
|
@ -228,6 +228,10 @@ void* Bridge::processMessage(GUIMSG type, void* param1, void* param2)
|
|||
emit referenceSetProgress((int)param1);
|
||||
break;
|
||||
|
||||
case GUI_REF_SETCURRENTTASKPROGRESS:
|
||||
emit referenceSetCurrentTaskProgress((int)param1, QString((const char*)param2));
|
||||
break;
|
||||
|
||||
case GUI_REF_SETSEARCHSTARTCOL:
|
||||
emit referenceSetSearchStartCol((int)param1);
|
||||
break;
|
||||
|
|
@ -524,6 +528,14 @@ void* Bridge::processMessage(GUIMSG type, void* param1, void* param2)
|
|||
emit dumpAtN((duint)param1, (int)param2);
|
||||
}
|
||||
break;
|
||||
|
||||
case GUI_DISPLAY_WARNING:
|
||||
{
|
||||
QString title = QString((const char*)param1);
|
||||
QString text = QString((const char*)param2);
|
||||
emit displayWarning(title, text);
|
||||
}
|
||||
break;
|
||||
case GUI_SET_CONTROLFLOWINFOS:
|
||||
{
|
||||
emit setControlFlowInfos((duint*)param1);
|
||||
|
|
|
|||
|
|
@ -70,6 +70,7 @@ signals:
|
|||
void referenceReloadData();
|
||||
void referenceSetSingleSelection(int index, bool scroll);
|
||||
void referenceSetProgress(int progress);
|
||||
void referenceSetCurrentTaskProgress(int progress, QString taskTitle);
|
||||
void referenceSetSearchStartCol(int col);
|
||||
void referenceInitialize(QString name);
|
||||
void stackDumpAt(duint va, duint csp);
|
||||
|
|
@ -114,6 +115,7 @@ signals:
|
|||
void setDebuggeeNotes(const QString text);
|
||||
void getDebuggeeNotes(void* text);
|
||||
void dumpAtN(duint va, int index);
|
||||
void displayWarning(QString title, QString text);
|
||||
void setControlFlowInfos(duint *controlFlowInfos);
|
||||
|
||||
private:
|
||||
|
|
|
|||
|
|
@ -0,0 +1,193 @@
|
|||
#include "AssembleDialog.h"
|
||||
#include "ui_AssembleDialog.h"
|
||||
#include <QMessageBox>
|
||||
|
||||
bool AssembleDialog::bWarningShowedOnce = false;
|
||||
|
||||
AssembleDialog::AssembleDialog(QWidget *parent) :
|
||||
QDialog(parent),
|
||||
ui(new Ui::AssembleDialog)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
setModal(true);
|
||||
setFixedSize(this->size()); //fixed size
|
||||
|
||||
#if QT_VERSION < QT_VERSION_CHECK(5,0,0)
|
||||
setWindowFlags(Qt::Dialog | Qt::WindowSystemMenuHint | Qt::WindowTitleHint | Qt::MSWindowsFixedSizeDialogHint);
|
||||
#endif
|
||||
|
||||
mSelectedInstrVa = 0;
|
||||
bKeepSizeChecked = false;
|
||||
bFillWithNopsChecked = false;
|
||||
|
||||
mValidateThread = new ValidateExpressionThread(this);
|
||||
mValidateThread->setOnExpressionChangedCallback(std::bind(&AssembleDialog::validateInstruction, this, std::placeholders::_1));
|
||||
|
||||
connect(ui->lineEdit, SIGNAL(textEdited(QString)), this, SLOT(textChangedSlot(QString)));
|
||||
connect(mValidateThread, SIGNAL(instructionChanged(dsint,QString)), this, SLOT(instructionChangedSlot(dsint, QString)));
|
||||
}
|
||||
|
||||
AssembleDialog::~AssembleDialog()
|
||||
{
|
||||
delete ui;
|
||||
}
|
||||
|
||||
void AssembleDialog::setTextEditValue(const QString &text)
|
||||
{
|
||||
ui->lineEdit->setText(text);
|
||||
}
|
||||
|
||||
void AssembleDialog::setKeepSizeChecked(bool checked)
|
||||
{
|
||||
ui->checkBoxKeepSize->setChecked(checked);
|
||||
bKeepSizeChecked = checked;
|
||||
}
|
||||
|
||||
void AssembleDialog::setKeepSizeLabel(const QString &text)
|
||||
{
|
||||
ui->labelKeepSize->setText(text);
|
||||
}
|
||||
|
||||
void AssembleDialog::setFillWithNopsChecked(bool checked)
|
||||
{
|
||||
ui->checkBoxFillWithNops->setChecked(checked);
|
||||
bFillWithNopsChecked = checked;
|
||||
}
|
||||
|
||||
void AssembleDialog::setFillWithNopsLabel(const QString &text)
|
||||
{
|
||||
ui->labelFillWithNops->setText(text);
|
||||
}
|
||||
|
||||
void AssembleDialog::setSelectedInstrVa(const duint va)
|
||||
{
|
||||
this->mSelectedInstrVa = va;
|
||||
}
|
||||
|
||||
|
||||
void AssembleDialog::setOkButtonEnabled(bool enabled)
|
||||
{
|
||||
ui->pushButtonOk->setEnabled(enabled);
|
||||
}
|
||||
|
||||
void AssembleDialog::validateInstruction(QString expression)
|
||||
{
|
||||
//void instructionChanged(bool validInstruction, dsint sizeDifference, QString error)
|
||||
dsint sizeDifference = 0;
|
||||
int typedInstructionSize = 0;
|
||||
int selectedInstructionSize = 0;
|
||||
bool validInstruction = false;
|
||||
QByteArray error(MAX_ERROR_SIZE, 0);
|
||||
BASIC_INSTRUCTION_INFO basicInstrInfo;
|
||||
|
||||
// Get selected instruction info (size here)
|
||||
DbgDisasmFastAt(mSelectedInstrVa, &basicInstrInfo);
|
||||
selectedInstructionSize = basicInstrInfo.size;
|
||||
|
||||
// Get typed in instruction size
|
||||
if(!DbgFunctions()->Assemble(this->mSelectedInstrVa, NULL, &typedInstructionSize, editText.toUtf8().constData(), error.data()) || selectedInstructionSize == 0)
|
||||
{
|
||||
emit mValidateThread->emitInstructionChanged(0, QString(error));
|
||||
return;
|
||||
}
|
||||
|
||||
// Valid instruction
|
||||
validInstruction = true;
|
||||
|
||||
sizeDifference = typedInstructionSize - selectedInstructionSize;
|
||||
|
||||
emit mValidateThread->emitInstructionChanged(sizeDifference, "");
|
||||
}
|
||||
|
||||
void AssembleDialog::hideEvent(QHideEvent *event)
|
||||
{
|
||||
Q_UNUSED(event);
|
||||
mValidateThread->stop();
|
||||
mValidateThread->wait();
|
||||
}
|
||||
|
||||
void AssembleDialog::textChangedSlot(QString text)
|
||||
{
|
||||
if(ui->checkBoxKeepSize->isChecked())
|
||||
mValidateThread->textChanged(text);
|
||||
}
|
||||
|
||||
void AssembleDialog::instructionChangedSlot(dsint sizeDifference, QString error)
|
||||
{
|
||||
if(ui->checkBoxKeepSize->isChecked())
|
||||
{
|
||||
// If there was an error
|
||||
if(error.length())
|
||||
{
|
||||
this->setKeepSizeLabel("<font color='orange'><b>Instruction decoding error : " + error + "</b></font>");
|
||||
return;
|
||||
}
|
||||
// No error
|
||||
else
|
||||
{
|
||||
|
||||
// SizeDifference > 0 <=> Typed instruction is bigger
|
||||
if(sizeDifference > 0)
|
||||
{
|
||||
QString message = "<font color='red'><b>Instruction bigger by " + QString::number(sizeDifference);
|
||||
if(sizeDifference == 1)
|
||||
message += QString(" byte</b></font>");
|
||||
else
|
||||
message += QString(" bytes</b></font>");
|
||||
|
||||
this->setKeepSizeLabel(message);
|
||||
this->setOkButtonEnabled(false);
|
||||
}
|
||||
// SizeDifference < 0 <=> Typed instruction is smaller
|
||||
else if(sizeDifference < 0)
|
||||
{
|
||||
QString message = "<font color='#00cc00'><b>Instruction smaller by " + QString::number(sizeDifference);
|
||||
if(sizeDifference == -1)
|
||||
message += QString(" byte</b></font>");
|
||||
else
|
||||
message += QString(" bytes</b></font>");
|
||||
|
||||
this->setKeepSizeLabel(message);
|
||||
this->setOkButtonEnabled(true);
|
||||
}
|
||||
// SizeDifference == 0 <=> Both instruction have same size
|
||||
else
|
||||
{
|
||||
QString message = "<font color='#00cc00'><b>Instruction is same size</b></font>";
|
||||
|
||||
this->setKeepSizeLabel(message);
|
||||
this->setOkButtonEnabled(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AssembleDialog::on_lineEdit_textChanged(const QString &arg1)
|
||||
{
|
||||
editText = arg1;
|
||||
|
||||
if(ui->checkBoxKeepSize->isChecked() && editText.size())
|
||||
mValidateThread->start(editText);
|
||||
}
|
||||
|
||||
void AssembleDialog::on_checkBoxKeepSize_clicked(bool checked)
|
||||
{
|
||||
if(checked && editText.size())
|
||||
{
|
||||
mValidateThread->start();
|
||||
mValidateThread->textChanged(ui->lineEdit->text()); // Have to add this or textChanged isn't called inside start()
|
||||
}
|
||||
else
|
||||
{
|
||||
mValidateThread->stop();
|
||||
mValidateThread->wait();
|
||||
ui->labelKeepSize->setText("");
|
||||
ui->pushButtonOk->setEnabled(true);
|
||||
}
|
||||
bKeepSizeChecked = checked;
|
||||
}
|
||||
|
||||
void AssembleDialog::on_checkBoxFillWithNops_clicked(bool checked)
|
||||
{
|
||||
bFillWithNopsChecked = checked;
|
||||
}
|
||||
|
|
@ -0,0 +1,53 @@
|
|||
#ifndef ASSEMBLEDIALOG_H
|
||||
#define ASSEMBLEDIALOG_H
|
||||
|
||||
#include <QDialog>
|
||||
#include <functional>
|
||||
#include "Bridge.h"
|
||||
#include "ValidateExpressionThread.h"
|
||||
|
||||
namespace Ui
|
||||
{
|
||||
class AssembleDialog;
|
||||
}
|
||||
|
||||
class AssembleDialog : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit AssembleDialog(QWidget *parent = 0);
|
||||
~AssembleDialog();
|
||||
QString editText;
|
||||
static bool bWarningShowedOnce;
|
||||
void setTextEditValue(const QString & text);
|
||||
|
||||
bool bKeepSizeChecked;
|
||||
void setKeepSizeChecked(bool checked);
|
||||
void setKeepSizeLabel(const QString & text);
|
||||
|
||||
bool bFillWithNopsChecked;
|
||||
void setFillWithNopsChecked(bool checked);
|
||||
void setFillWithNopsLabel(const QString & text);
|
||||
|
||||
void setSelectedInstrVa(const duint va);
|
||||
void setOkButtonEnabled(bool enabled);
|
||||
|
||||
void validateInstruction(QString expression);
|
||||
void hideEvent(QHideEvent *event);
|
||||
|
||||
private slots:
|
||||
void textChangedSlot(QString text);
|
||||
void instructionChangedSlot(dsint sizeDifference, QString error);
|
||||
void on_lineEdit_textChanged(const QString &arg1);
|
||||
void on_checkBoxKeepSize_clicked(bool checked);
|
||||
void on_checkBoxFillWithNops_clicked(bool checked);
|
||||
|
||||
private:
|
||||
Ui::AssembleDialog *ui;
|
||||
duint mSelectedInstrVa;
|
||||
ValidateExpressionThread *mValidateThread;
|
||||
|
||||
};
|
||||
|
||||
#endif // ASSEMBLEDIALOG_H
|
||||
|
|
@ -0,0 +1,160 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>AssembleDialog</class>
|
||||
<widget class="QDialog" name="AssembleDialog">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>433</width>
|
||||
<height>114</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>0</string>
|
||||
</property>
|
||||
<property name="windowIcon">
|
||||
<iconset resource="../../resource.qrc">
|
||||
<normaloff>:/icons/images/ui-combo-box-edit.png</normaloff>:/icons/images/ui-combo-box-edit.png</iconset>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_2">
|
||||
<item row="1" column="0">
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<property name="spacing">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QLineEdit" name="lineEdit">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>24</height>
|
||||
</size>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||
<item>
|
||||
<widget class="QCheckBox" name="checkBoxKeepSize">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Maximum">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Keep Size</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="labelKeepSize">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<widget class="QCheckBox" name="checkBoxFillWithNops">
|
||||
<property name="text">
|
||||
<string>Fill with NOP's</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="labelFillWithNops">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="pushButtonOk">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>OK</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="pushButtonCancel">
|
||||
<property name="text">
|
||||
<string>Cancel</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources>
|
||||
<include location="../../resource.qrc"/>
|
||||
</resources>
|
||||
<connections>
|
||||
<connection>
|
||||
<sender>pushButtonOk</sender>
|
||||
<signal>clicked()</signal>
|
||||
<receiver>AssembleDialog</receiver>
|
||||
<slot>accept()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>265</x>
|
||||
<y>77</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>217</x>
|
||||
<y>49</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>pushButtonCancel</sender>
|
||||
<signal>clicked()</signal>
|
||||
<receiver>AssembleDialog</receiver>
|
||||
<slot>close()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>373</x>
|
||||
<y>77</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>217</x>
|
||||
<y>49</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
</connections>
|
||||
</ui>
|
||||
|
|
@ -8,6 +8,7 @@
|
|||
#include "WordEditDialog.h"
|
||||
#include "HexEditDialog.h"
|
||||
#include "YaraRuleSelectionDialog.h"
|
||||
#include "AssembleDialog.h"
|
||||
|
||||
CPUDisassembly::CPUDisassembly(CPUWidget* parent) : Disassembly(parent)
|
||||
{
|
||||
|
|
@ -23,6 +24,7 @@ CPUDisassembly::CPUDisassembly(CPUWidget* parent) : Disassembly(parent)
|
|||
connect(Bridge::getBridge(), SIGNAL(dbgStateChanged(DBGSTATE)), this, SLOT(debugStateChangedSlot(DBGSTATE)));
|
||||
connect(Bridge::getBridge(), SIGNAL(selectionDisasmGet(SELECTIONDATA*)), this, SLOT(selectionGetSlot(SELECTIONDATA*)));
|
||||
connect(Bridge::getBridge(), SIGNAL(selectionDisasmSet(const SELECTIONDATA*)), this, SLOT(selectionSetSlot(const SELECTIONDATA*)));
|
||||
connect(Bridge::getBridge(), SIGNAL(displayWarning(QString, QString)), this, SLOT(displayWarningSlot(QString, QString)));
|
||||
|
||||
Initialize();
|
||||
}
|
||||
|
|
@ -301,7 +303,22 @@ void CPUDisassembly::setupRightClickContextMenu()
|
|||
mMenuBuilder->addAction(makeShortcutAction(QIcon(":/icons/images/highlight.png"), "&Highlighting mode", SLOT(enableHighlightingModeSlot()), "ActionHighlightingMode"));
|
||||
mMenuBuilder->addSeparator();
|
||||
|
||||
mMenuBuilder->addAction(makeShortcutAction(QIcon(":/icons/images/label.png"), "Label", SLOT(setLabelSlot()), "ActionSetLabel"));
|
||||
MenuBuilder* labelMenu = new MenuBuilder(this);
|
||||
labelMenu->addAction(makeShortcutAction("Label Current Address", SLOT(setLabelSlot()), "ActionSetLabel"));
|
||||
QAction* labelAddress = makeAction("Label", SLOT(setLabelAddressSlot()));
|
||||
labelMenu->addAction(labelAddress, [this, labelAddress](QMenu*)
|
||||
{
|
||||
BASIC_INSTRUCTION_INFO instr_info;
|
||||
duint wVA = rvaToVa(getInitialSelection());
|
||||
|
||||
DbgDisasmFastAt(wVA, &instr_info);
|
||||
QString targetAddress = "0x" + QString::number(instr_info.addr, 16).toUpper();
|
||||
labelAddress->setText("Label " + targetAddress);
|
||||
|
||||
return (instr_info.branch || instr_info.call);
|
||||
});
|
||||
mMenuBuilder->addMenu(makeMenu(QIcon(":/icons/images/label.png"), "Label"), labelMenu);
|
||||
|
||||
mMenuBuilder->addAction(makeShortcutAction(QIcon(":/icons/images/comment.png"), "Comment", SLOT(setCommentSlot()), "ActionSetComment"));
|
||||
mMenuBuilder->addAction(makeShortcutAction(QIcon(":/icons/images/bookmark.png"), "Bookmark", SLOT(setBookmarkSlot()), "ActionToggleBookmark"));
|
||||
QAction* toggleFunctionAction = makeShortcutAction(QIcon(":/icons/images/functions.png"), "Function", SLOT(toggleFunctionSlot()), "ActionToggleFunction");
|
||||
|
|
@ -342,11 +359,45 @@ void CPUDisassembly::setupRightClickContextMenu()
|
|||
mMenuBuilder->addSeparator();
|
||||
|
||||
MenuBuilder* searchMenu = new MenuBuilder(this);
|
||||
searchMenu->addAction(makeShortcutAction("C&ommand", SLOT(findCommandSlot()), "ActionFind"));
|
||||
searchMenu->addAction(makeAction("&Constant", SLOT(findConstantSlot())));
|
||||
searchMenu->addAction(makeAction("&String references", SLOT(findStringsSlot())));
|
||||
searchMenu->addAction(makeAction("&Intermodular calls", SLOT(findCallsSlot())));
|
||||
searchMenu->addAction(makeShortcutAction("&Pattern", SLOT(findPatternSlot()), "ActionFindPattern"));
|
||||
MenuBuilder* mSearchRegionMenu = new MenuBuilder(this);
|
||||
MenuBuilder* mSearchModuleMenu = new MenuBuilder(this);
|
||||
MenuBuilder* mSearchAllMenu = new MenuBuilder(this);
|
||||
|
||||
// Search in Current Region menu
|
||||
mFindCommandRegion = makeShortcutAction("C&ommand", SLOT(findCommandSlot()), "ActionFind");
|
||||
mFindConstantRegion = makeAction("&Constant", SLOT(findConstantSlot()));
|
||||
mFindStringsRegion = makeAction("&String references", SLOT(findStringsSlot()));
|
||||
mFindCallsRegion = makeAction("&Intermodular calls", SLOT(findCallsSlot()));
|
||||
mSearchRegionMenu->addAction(mFindCommandRegion);
|
||||
mSearchRegionMenu->addAction(mFindConstantRegion);
|
||||
mSearchRegionMenu->addAction(mFindStringsRegion);
|
||||
mSearchRegionMenu->addAction(mFindCallsRegion);
|
||||
mSearchRegionMenu->addAction(makeShortcutAction("&Pattern", SLOT(findPatternSlot()), "ActionFindPattern"));
|
||||
|
||||
// Search in Current Module menu
|
||||
mFindCommandModule = makeShortcutAction("C&ommand", SLOT(findCommandSlot()), "ActionFind");
|
||||
mFindConstantModule = makeAction("&Constant", SLOT(findConstantSlot()));
|
||||
mFindStringsModule = makeAction("&String references", SLOT(findStringsSlot()));
|
||||
mFindCallsModule = makeAction("&Intermodular calls", SLOT(findCallsSlot()));
|
||||
mSearchModuleMenu->addAction(mFindCommandModule);
|
||||
mSearchModuleMenu->addAction(mFindConstantModule);
|
||||
mSearchModuleMenu->addAction(mFindStringsModule);
|
||||
mSearchModuleMenu->addAction(mFindCallsModule);
|
||||
|
||||
|
||||
// Search in All Modules menu
|
||||
mFindCommandAll = makeShortcutAction("C&ommand", SLOT(findCommandSlot()), "ActionFind");
|
||||
mFindConstantAll = makeAction("&Constant", SLOT(findConstantSlot()));
|
||||
mFindStringsAll = makeAction("&String references", SLOT(findStringsSlot()));
|
||||
mFindCallsAll = makeAction("&Intermodular calls", SLOT(findCallsSlot()));
|
||||
mSearchAllMenu->addAction(mFindCommandAll);
|
||||
mSearchAllMenu->addAction(mFindConstantAll);
|
||||
mSearchAllMenu->addAction(mFindStringsAll);
|
||||
mSearchAllMenu->addAction(mFindCallsAll);
|
||||
|
||||
searchMenu->addMenu(makeMenu("Current Region"), mSearchRegionMenu);
|
||||
searchMenu->addMenu(makeMenu("Current Module"), mSearchModuleMenu);
|
||||
searchMenu->addMenu(makeMenu("All Modules"), mSearchAllMenu);
|
||||
mMenuBuilder->addMenu(makeMenu(QIcon(":/icons/images/search-for.png"), "&Search for"), searchMenu);
|
||||
|
||||
mReferenceSelectedAddressAction = makeShortcutAction("&Selected Address(es)", SLOT(findReferencesSlot()), "ActionFindReferencesToSelectedAddress");
|
||||
|
|
@ -510,6 +561,35 @@ void CPUDisassembly::setLabelSlot()
|
|||
GuiUpdateAllViews();
|
||||
}
|
||||
|
||||
void CPUDisassembly::setLabelAddressSlot()
|
||||
{
|
||||
if(!DbgIsDebugging())
|
||||
return;
|
||||
BASIC_INSTRUCTION_INFO instr_info;
|
||||
duint wVA = rvaToVa(getInitialSelection());
|
||||
|
||||
DbgDisasmFastAt(wVA, &instr_info);
|
||||
wVA = instr_info.addr;
|
||||
|
||||
LineEditDialog mLineEdit(this);
|
||||
QString addr_text = QString("%1").arg(wVA, sizeof(dsint) * 2, 16, QChar('0')).toUpper();
|
||||
char label_text[MAX_COMMENT_SIZE] = "";
|
||||
if(DbgGetLabelAt((duint)wVA, SEG_DEFAULT, label_text))
|
||||
mLineEdit.setText(QString(label_text));
|
||||
mLineEdit.setWindowTitle("Add label at " + addr_text);
|
||||
if(mLineEdit.exec() != QDialog::Accepted)
|
||||
return;
|
||||
if(!DbgSetLabelAt(wVA, mLineEdit.editText.toUtf8().constData()))
|
||||
{
|
||||
QMessageBox msg(QMessageBox::Critical, "Error!", "DbgSetLabelAt failed!");
|
||||
msg.setWindowIcon(QIcon(":/icons/images/compile-error.png"));
|
||||
msg.setParent(this, Qt::Dialog);
|
||||
msg.setWindowFlags(msg.windowFlags() & (~Qt::WindowContextHelpButtonHint));
|
||||
msg.exec();
|
||||
}
|
||||
GuiUpdateAllViews();
|
||||
}
|
||||
|
||||
void CPUDisassembly::setCommentSlot()
|
||||
{
|
||||
if(!DbgIsDebugging())
|
||||
|
|
@ -617,62 +697,49 @@ void CPUDisassembly::assembleSlot()
|
|||
if(!DbgIsDebugging())
|
||||
return;
|
||||
|
||||
AssembleDialog assembleDialog;
|
||||
|
||||
do
|
||||
{
|
||||
dsint wRVA = getInitialSelection();
|
||||
duint wVA = rvaToVa(wRVA);
|
||||
QString addr_text = QString("%1").arg(wVA, sizeof(dsint) * 2, 16, QChar('0')).toUpper();
|
||||
|
||||
QByteArray wBuffer;
|
||||
|
||||
dsint wMaxByteCountToRead = 16 * 2;
|
||||
|
||||
//TODO: fix size problems
|
||||
dsint size = getSize();
|
||||
if(!size)
|
||||
size = wRVA;
|
||||
|
||||
// Bounding
|
||||
wMaxByteCountToRead = wMaxByteCountToRead > (size - wRVA) ? (size - wRVA) : wMaxByteCountToRead;
|
||||
|
||||
wBuffer.resize(wMaxByteCountToRead);
|
||||
|
||||
mMemPage->read(reinterpret_cast<byte_t*>(wBuffer.data()), wRVA, wMaxByteCountToRead);
|
||||
|
||||
QBeaEngine disasm(-1);
|
||||
Instruction_t instr = disasm.DisassembleAt(reinterpret_cast<byte_t*>(wBuffer.data()), wMaxByteCountToRead, 0, 0, wVA);
|
||||
Instruction_t instr = this->DisassembleAt(wRVA);
|
||||
|
||||
QString actual_inst = instr.instStr;
|
||||
|
||||
bool assembly_error;
|
||||
do
|
||||
{
|
||||
char error[MAX_ERROR_SIZE] = "";
|
||||
|
||||
assembly_error = false;
|
||||
|
||||
LineEditDialog mLineEdit(this);
|
||||
mLineEdit.setText(actual_inst);
|
||||
mLineEdit.setWindowTitle("Assemble at " + addr_text);
|
||||
mLineEdit.setCheckBoxText("&Fill with NOPs");
|
||||
mLineEdit.enableCheckBox(true);
|
||||
mLineEdit.setCheckBox(ConfigBool("Disassembler", "FillNOPs"));
|
||||
if(mLineEdit.exec() != QDialog::Accepted)
|
||||
assembleDialog.setSelectedInstrVa(wVA);
|
||||
assembleDialog.setTextEditValue(actual_inst);
|
||||
assembleDialog.setWindowTitle("Assemble at " + addr_text);
|
||||
assembleDialog.setFillWithNopsChecked(ConfigBool("Disassembler", "FillNOPs"));
|
||||
assembleDialog.setKeepSizeChecked(ConfigBool("Disassembler", "KeepSize"));
|
||||
|
||||
if(assembleDialog.exec() != QDialog::Accepted)
|
||||
return;
|
||||
|
||||
//if the instruction its unkown or is the old instruction or empty (easy way to skip from GUI) skipping
|
||||
if(mLineEdit.editText == QString("???") || mLineEdit.editText.toLower() == instr.instStr.toLower() || mLineEdit.editText == QString(""))
|
||||
//if the instruction its unknown or is the old instruction or empty (easy way to skip from GUI) skipping
|
||||
if(assembleDialog.editText == QString("???") || assembleDialog.editText.toLower() == instr.instStr.toLower() || assembleDialog.editText == QString(""))
|
||||
break;
|
||||
|
||||
Config()->setBool("Disassembler", "FillNOPs", mLineEdit.bChecked);
|
||||
Config()->setBool("Disassembler", "FillNOPs", assembleDialog.bFillWithNopsChecked);
|
||||
Config()->setBool("Disassembler", "KeepSize", assembleDialog.bKeepSizeChecked);
|
||||
|
||||
char error[MAX_ERROR_SIZE] = "";
|
||||
if(!DbgFunctions()->AssembleAtEx(wVA, mLineEdit.editText.toUtf8().constData(), error, mLineEdit.bChecked))
|
||||
if(!DbgFunctions()->AssembleAtEx(wVA, assembleDialog.editText.toUtf8().constData(), error, assembleDialog.bFillWithNopsChecked))
|
||||
{
|
||||
QMessageBox msg(QMessageBox::Critical, "Error!", "Failed to assemble instruction \"" + mLineEdit.editText + "\" (" + error + ")");
|
||||
QMessageBox msg(QMessageBox::Critical, "Error!", "Failed to assemble instruction \"" + assembleDialog.editText + "\" (" + error + ")");
|
||||
msg.setWindowIcon(QIcon(":/icons/images/compile-error.png"));
|
||||
msg.setParent(this, Qt::Dialog);
|
||||
msg.setWindowFlags(msg.windowFlags() & (~Qt::WindowContextHelpButtonHint));
|
||||
msg.exec();
|
||||
actual_inst = mLineEdit.editText;
|
||||
actual_inst = assembleDialog.editText;
|
||||
assembly_error = true;
|
||||
}
|
||||
}
|
||||
|
|
@ -782,27 +849,52 @@ void CPUDisassembly::findReferencesSlot()
|
|||
|
||||
void CPUDisassembly::findConstantSlot()
|
||||
{
|
||||
int refFindType = 0;
|
||||
if(sender() == mFindConstantRegion)
|
||||
refFindType = 0;
|
||||
else if(sender() == mFindConstantModule)
|
||||
refFindType = 1;
|
||||
else if(sender() == mFindConstantAll)
|
||||
refFindType = 2;
|
||||
|
||||
WordEditDialog wordEdit(this);
|
||||
wordEdit.setup("Enter Constant", 0, sizeof(dsint));
|
||||
if(wordEdit.exec() != QDialog::Accepted) //cancel pressed
|
||||
return;
|
||||
QString addrText = QString("%1").arg(rvaToVa(getInitialSelection()), sizeof(dsint) * 2, 16, QChar('0')).toUpper();
|
||||
QString constText = QString("%1").arg(wordEdit.getVal(), sizeof(dsint) * 2, 16, QChar('0')).toUpper();
|
||||
DbgCmdExec(QString("findref " + constText + ", " + addrText).toUtf8().constData());
|
||||
DbgCmdExec(QString("findref " + constText + ", " + addrText + ", 0, %1").arg(refFindType).toUtf8().constData());
|
||||
emit displayReferencesWidget();
|
||||
}
|
||||
|
||||
void CPUDisassembly::findStringsSlot()
|
||||
{
|
||||
int refFindType = 0;
|
||||
if(sender() == mFindStringsRegion)
|
||||
refFindType = 0;
|
||||
else if(sender() == mFindStringsModule)
|
||||
refFindType = 1;
|
||||
else if(sender() == mFindStringsAll)
|
||||
refFindType = 2;
|
||||
|
||||
QString addrText = QString("%1").arg(rvaToVa(getInitialSelection()), sizeof(dsint) * 2, 16, QChar('0')).toUpper();
|
||||
DbgCmdExec(QString("strref " + addrText).toUtf8().constData());
|
||||
DbgCmdExec(QString("strref " + addrText + ", 0, %1").arg(refFindType).toUtf8().constData());
|
||||
emit displayReferencesWidget();
|
||||
}
|
||||
|
||||
|
||||
void CPUDisassembly::findCallsSlot()
|
||||
{
|
||||
int refFindType = 0;
|
||||
if(sender() == mFindCallsRegion)
|
||||
refFindType = 0;
|
||||
else if(sender() == mFindCallsModule)
|
||||
refFindType = 1;
|
||||
else if(sender() == mFindCallsAll)
|
||||
refFindType = 2;
|
||||
|
||||
QString addrText = QString("%1").arg(rvaToVa(getInitialSelection()), sizeof(dsint) * 2, 16, QChar('0')).toUpper();
|
||||
DbgCmdExec(QString("modcallfind " + addrText).toUtf8().constData());
|
||||
DbgCmdExec(QString("modcallfind " + addrText + ", 0, 0").toUtf8().constData());
|
||||
emit displayReferencesWidget();
|
||||
}
|
||||
|
||||
|
|
@ -1072,10 +1164,18 @@ void CPUDisassembly::findCommandSlot()
|
|||
if(!DbgIsDebugging())
|
||||
return;
|
||||
|
||||
int refFindType = 0;
|
||||
if(sender() == mFindCommandRegion)
|
||||
refFindType = 0;
|
||||
else if(sender() == mFindCommandModule)
|
||||
refFindType = 1;
|
||||
else if(sender() == mFindCommandAll)
|
||||
refFindType = 2;
|
||||
|
||||
LineEditDialog mLineEdit(this);
|
||||
mLineEdit.enableCheckBox(true);
|
||||
mLineEdit.setCheckBoxText("Entire &Block");
|
||||
mLineEdit.setCheckBox(ConfigBool("Disassembler", "FindCommandEntireBlock"));
|
||||
mLineEdit.enableCheckBox(false);
|
||||
// mLineEdit.setCheckBoxText("Entire &Block");
|
||||
// mLineEdit.setCheckBox(ConfigBool("Disassembler", "FindCommandEntireBlock"));
|
||||
mLineEdit.setWindowTitle("Find Command");
|
||||
if(mLineEdit.exec() != QDialog::Accepted)
|
||||
return;
|
||||
|
|
@ -1098,13 +1198,8 @@ void CPUDisassembly::findCommandSlot()
|
|||
|
||||
QString addr_text = QString("%1").arg(va, sizeof(dsint) * 2, 16, QChar('0')).toUpper();
|
||||
|
||||
if(!mLineEdit.bChecked)
|
||||
{
|
||||
dsint size = mMemPage->getSize();
|
||||
DbgCmdExec(QString("findasm \"%1\", %2, .%3").arg(mLineEdit.editText).arg(addr_text).arg(size).toUtf8().constData());
|
||||
}
|
||||
else
|
||||
DbgCmdExec(QString("findasm \"%1\", %2").arg(mLineEdit.editText).arg(addr_text).toUtf8().constData());
|
||||
dsint size = mMemPage->getSize();
|
||||
DbgCmdExec(QString("findasm \"%1\", %2, .%3, %4").arg(mLineEdit.editText).arg(addr_text).arg(size).arg(refFindType).toUtf8().constData());
|
||||
|
||||
emit displayReferencesWidget();
|
||||
}
|
||||
|
|
@ -1140,6 +1235,11 @@ void CPUDisassembly::decompileFunctionSlot()
|
|||
}
|
||||
}
|
||||
|
||||
void CPUDisassembly::displayWarningSlot(QString title, QString text)
|
||||
{
|
||||
QMessageBox::QMessageBox(QMessageBox::Information, title, text, QMessageBox::Ok).exec();
|
||||
}
|
||||
|
||||
void CPUDisassembly::paintEvent(QPaintEvent* event)
|
||||
{
|
||||
// Hook/hack to update the sidebar at the same time as this widget.
|
||||
|
|
|
|||
|
|
@ -45,6 +45,7 @@ public slots:
|
|||
void setNewOriginHereActionSlot();
|
||||
void gotoOriginSlot();
|
||||
void setLabelSlot();
|
||||
void setLabelAddressSlot();
|
||||
void setCommentSlot();
|
||||
void setBookmarkSlot();
|
||||
void toggleFunctionSlot();
|
||||
|
|
@ -82,6 +83,7 @@ public slots:
|
|||
void openSourceSlot();
|
||||
void decompileSelectionSlot();
|
||||
void decompileFunctionSlot();
|
||||
void displayWarningSlot(QString title, QString text);
|
||||
|
||||
protected:
|
||||
void paintEvent(QPaintEvent* event);
|
||||
|
|
@ -93,6 +95,21 @@ private:
|
|||
|
||||
// Actions
|
||||
QAction* mReferenceSelectedAddressAction;
|
||||
QAction* mFindCommandRegion;
|
||||
QAction* mFindConstantRegion;
|
||||
QAction* mFindStringsRegion;
|
||||
QAction* mFindCallsRegion;
|
||||
|
||||
QAction* mFindCommandModule;
|
||||
QAction* mFindConstantModule;
|
||||
QAction* mFindStringsModule;
|
||||
QAction* mFindCallsModule;
|
||||
|
||||
QAction* mFindCommandAll;
|
||||
QAction* mFindConstantAll;
|
||||
QAction* mFindStringsAll;
|
||||
QAction* mFindCallsAll;
|
||||
|
||||
|
||||
// Goto dialog specific
|
||||
GotoDialog* mGoto;
|
||||
|
|
@ -101,6 +118,7 @@ private:
|
|||
CPUWidget *mParentCPUWindow;
|
||||
|
||||
MenuBuilder* mMenuBuilder;
|
||||
|
||||
};
|
||||
|
||||
#endif // CPUDISASSEMBLY_H
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
#include "CPUDump.h"
|
||||
#include <QMessageBox>
|
||||
#include <QClipboard>
|
||||
#include <QFileDialog>
|
||||
#include "Configuration.h"
|
||||
#include "Bridge.h"
|
||||
#include "LineEditDialog.h"
|
||||
|
|
@ -9,6 +10,7 @@
|
|||
#include "DataCopyDialog.h"
|
||||
#include "EntropyDialog.h"
|
||||
#include "CPUMultiDump.h"
|
||||
#include <QToolTip>
|
||||
|
||||
CPUDump::CPUDump(CPUDisassembly* disas, CPUMultiDump* multiDump, QWidget* parent) : HexDump(parent)
|
||||
{
|
||||
|
|
@ -131,6 +133,14 @@ void CPUDump::setupContextMenu()
|
|||
connect(mBinaryPasteIgnoreSizeAction, SIGNAL(triggered()), this, SLOT(binaryPasteIgnoreSizeSlot()));
|
||||
mBinaryMenu->addAction(mBinaryPasteIgnoreSizeAction);
|
||||
|
||||
//Binary->Save To a File
|
||||
mBinarySaveToFile = new QAction("Save To a File", this);
|
||||
mBinarySaveToFile->setShortcutContext(Qt::WidgetShortcut);
|
||||
this->addAction(mBinarySaveToFile);
|
||||
connect(mBinarySaveToFile, SIGNAL(triggered()), this, SLOT(binarySaveToFileSlot()));
|
||||
mBinaryMenu->addAction(mBinarySaveToFile);
|
||||
|
||||
|
||||
// Restore Selection
|
||||
mUndoSelection = new QAction("&Restore selection", this);
|
||||
mUndoSelection->setShortcutContext(Qt::WidgetShortcut);
|
||||
|
|
@ -241,7 +251,7 @@ void CPUDump::setupContextMenu()
|
|||
mMemoryAccessSingleshoot = new QAction("&Singleshoot", this);
|
||||
connect(mMemoryAccessSingleshoot, SIGNAL(triggered()), this, SLOT(memoryAccessSingleshootSlot()));
|
||||
mMemoryAccessMenu->addAction(mMemoryAccessSingleshoot);
|
||||
mMemoryAccessRestore = new QAction("&Restore", this);
|
||||
mMemoryAccessRestore = new QAction("&Restore on hit", this);
|
||||
connect(mMemoryAccessRestore, SIGNAL(triggered()), this, SLOT(memoryAccessRestoreSlot()));
|
||||
mMemoryAccessMenu->addAction(mMemoryAccessRestore);
|
||||
mBreakpointMenu->addMenu(mMemoryAccessMenu);
|
||||
|
|
@ -251,7 +261,7 @@ void CPUDump::setupContextMenu()
|
|||
mMemoryWriteSingleshoot = new QAction("&Singleshoot", this);
|
||||
connect(mMemoryWriteSingleshoot, SIGNAL(triggered()), this, SLOT(memoryWriteSingleshootSlot()));
|
||||
mMemoryWriteMenu->addAction(mMemoryWriteSingleshoot);
|
||||
mMemoryWriteRestore = new QAction("&Restore", this);
|
||||
mMemoryWriteRestore = new QAction("&Restore on hit", this);
|
||||
connect(mMemoryWriteRestore, SIGNAL(triggered()), this, SLOT(memoryWriteRestoreSlot()));
|
||||
mMemoryWriteMenu->addAction(mMemoryWriteRestore);
|
||||
mBreakpointMenu->addMenu(mMemoryWriteMenu);
|
||||
|
|
@ -261,7 +271,7 @@ void CPUDump::setupContextMenu()
|
|||
mMemoryExecuteSingleshoot = new QAction("&Singleshoot", this);
|
||||
connect(mMemoryExecuteSingleshoot, SIGNAL(triggered()), this, SLOT(memoryExecuteSingleshootSlot()));
|
||||
mMemoryExecuteMenu->addAction(mMemoryExecuteSingleshoot);
|
||||
mMemoryExecuteRestore = new QAction("&Restore", this);
|
||||
mMemoryExecuteRestore = new QAction("&Restore on hit", this);
|
||||
connect(mMemoryExecuteRestore, SIGNAL(triggered()), this, SLOT(memoryExecuteRestoreSlot()));
|
||||
mMemoryExecuteMenu->addAction(mMemoryExecuteRestore);
|
||||
mBreakpointMenu->addMenu(mMemoryExecuteMenu);
|
||||
|
|
@ -449,6 +459,7 @@ void CPUDump::setupContextMenu()
|
|||
connect(mCopyRva, SIGNAL(triggered()), this, SLOT(copyRvaSlot()));
|
||||
mCopyMenu->addAction(mCopyRva);
|
||||
|
||||
|
||||
refreshShortcutsSlot();
|
||||
connect(Config(), SIGNAL(shortcutsUpdated()), this, SLOT(refreshShortcutsSlot()));
|
||||
}
|
||||
|
|
@ -686,6 +697,47 @@ void CPUDump::mouseDoubleClickEvent(QMouseEvent* event)
|
|||
}
|
||||
}
|
||||
|
||||
void CPUDump::mouseMoveEvent(QMouseEvent *event)
|
||||
{
|
||||
dsint ptr = 0, ptrValue = 0;
|
||||
|
||||
// Get mouse pointer relative position
|
||||
int x = event->x();
|
||||
int y = event->y();
|
||||
|
||||
// Get HexDump own RVA address, then VA in memory
|
||||
int rva = getItemStartingAddress(x, y);
|
||||
int va = rvaToVa(rva);
|
||||
|
||||
// Read VA
|
||||
DbgMemRead(va, (unsigned char*)&ptr, sizeof(dsint));
|
||||
|
||||
// Check if its a pointer
|
||||
if(DbgMemIsValidReadPtr(ptr))
|
||||
{
|
||||
// Get the value at the address pointed by the ptr
|
||||
DbgMemRead(ptr, (unsigned char*)&ptrValue, sizeof(dsint));
|
||||
|
||||
// Format text like this : [ptr] = ptrValue
|
||||
QString strPtrValue;
|
||||
#ifdef _WIN64
|
||||
strPtrValue.sprintf("[0x%016X] = 0x%016X", ptr, ptrValue);
|
||||
#else
|
||||
strPtrValue.sprintf("[0x%08X] = 0x%08X", ptr, ptrValue);
|
||||
#endif
|
||||
|
||||
// Show tooltip
|
||||
QToolTip::showText(event->globalPos(), strPtrValue);
|
||||
}
|
||||
// If not a pointer, hide tooltips
|
||||
else
|
||||
{
|
||||
QToolTip::hideText();
|
||||
}
|
||||
|
||||
HexDump::mouseMoveEvent(event);
|
||||
}
|
||||
|
||||
void CPUDump::addVaToHistory(dsint parVa)
|
||||
{
|
||||
mVaHistory.push_back(parVa);
|
||||
|
|
@ -1489,6 +1541,22 @@ void CPUDump::binaryPasteIgnoreSizeSlot()
|
|||
GuiUpdateAllViews();
|
||||
}
|
||||
|
||||
void CPUDump::binarySaveToFileSlot()
|
||||
{
|
||||
QString fileName = QFileDialog::getSaveFileName(this, "Save to file", QDir::currentPath(), tr("All files (*.*)"));
|
||||
if(fileName.length())
|
||||
{
|
||||
// Get starting selection and selection size, then convert selStart to VA
|
||||
dsint rvaSelStart = getSelectionStart();
|
||||
dsint selSize = getSelectionEnd() - rvaSelStart + 1;
|
||||
dsint vaSelStart = rvaToVa(rvaSelStart);
|
||||
|
||||
// Prepare command
|
||||
QString cmd = QString("savedata %1,%2,%3").arg(fileName, QString::number(vaSelStart, 16), QString::number(selSize));
|
||||
DbgCmdExec(cmd.toUtf8().constData());
|
||||
}
|
||||
}
|
||||
|
||||
void CPUDump::findPattern()
|
||||
{
|
||||
HexEditDialog hexEdit(this);
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ public:
|
|||
void setupContextMenu();
|
||||
void contextMenuEvent(QContextMenuEvent* event);
|
||||
void mouseDoubleClickEvent(QMouseEvent* event);
|
||||
void mouseMoveEvent(QMouseEvent* event);
|
||||
void addVaToHistory(dsint parVa);
|
||||
bool historyHasPrev();
|
||||
bool historyHasNext();
|
||||
|
|
@ -25,6 +26,7 @@ public:
|
|||
void historyClear();
|
||||
|
||||
|
||||
|
||||
signals:
|
||||
void displayReferencesWidget();
|
||||
|
||||
|
|
@ -85,6 +87,7 @@ public slots:
|
|||
void binaryCopySlot();
|
||||
void binaryPasteSlot();
|
||||
void binaryPasteIgnoreSizeSlot();
|
||||
void binarySaveToFileSlot();
|
||||
void findPattern();
|
||||
void undoSelectionSlot();
|
||||
void followStackSlot();
|
||||
|
|
@ -187,6 +190,7 @@ private:
|
|||
QAction* mBinaryCopyAction;
|
||||
QAction* mBinaryPasteAction;
|
||||
QAction* mBinaryPasteIgnoreSizeAction;
|
||||
QAction* mBinarySaveToFile;
|
||||
QAction* mFindPatternAction;
|
||||
QAction* mFindReferencesAction;
|
||||
QAction* mYaraAction;
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ CPUStack::CPUStack(QWidget* parent) : HexDump(parent)
|
|||
int charwidth = getCharWidth();
|
||||
ColumnDescriptor_t wColDesc;
|
||||
DataDescriptor_t dDesc;
|
||||
bStackFrozen = false;
|
||||
|
||||
mForceColumn = 1;
|
||||
|
||||
|
|
@ -42,6 +43,8 @@ CPUStack::CPUStack(QWidget* parent) : HexDump(parent)
|
|||
connect(Bridge::getBridge(), SIGNAL(stackDumpAt(duint, duint)), this, SLOT(stackDumpAt(duint, duint)));
|
||||
connect(Bridge::getBridge(), SIGNAL(selectionStackGet(SELECTIONDATA*)), this, SLOT(selectionGet(SELECTIONDATA*)));
|
||||
connect(Bridge::getBridge(), SIGNAL(selectionStackSet(const SELECTIONDATA*)), this, SLOT(selectionSet(const SELECTIONDATA*)));
|
||||
connect(Bridge::getBridge(), SIGNAL(dbgStateChanged(DBGSTATE)), this, SLOT(dbgStateChangedSlot(DBGSTATE)));
|
||||
|
||||
|
||||
Initialize();
|
||||
}
|
||||
|
|
@ -125,6 +128,10 @@ void CPUStack::setupContextMenu()
|
|||
connect(mGotoSp, SIGNAL(triggered()), this, SLOT(gotoSpSlot()));
|
||||
connect(mGotoBp, SIGNAL(triggered()), this, SLOT(gotoBpSlot()));
|
||||
|
||||
mFreezeStack = new QAction("Freeze stack", this);
|
||||
this->addAction(mFreezeStack);
|
||||
connect(mFreezeStack, SIGNAL(triggered()), this, SLOT(freezeStackSlot()));
|
||||
|
||||
//Find Pattern
|
||||
mFindPatternAction = new QAction("&Find Pattern...", this);
|
||||
mFindPatternAction->setShortcutContext(Qt::WidgetShortcut);
|
||||
|
|
@ -156,6 +163,24 @@ void CPUStack::setupContextMenu()
|
|||
connect(Config(), SIGNAL(shortcutsUpdated()), this, SLOT(refreshShortcutsSlot()));
|
||||
}
|
||||
|
||||
void CPUStack::updateFreezeStackAction()
|
||||
{
|
||||
QFont font = mFreezeStack->font();
|
||||
|
||||
if(bStackFrozen)
|
||||
{
|
||||
font.setBold(true);
|
||||
mFreezeStack->setFont(font);
|
||||
mFreezeStack->setText("Unfreeze the stack");
|
||||
}
|
||||
else
|
||||
{
|
||||
font.setBold(false);
|
||||
mFreezeStack->setFont(font);
|
||||
mFreezeStack->setText("Freeze the stack");
|
||||
}
|
||||
}
|
||||
|
||||
void CPUStack::refreshShortcutsSlot()
|
||||
{
|
||||
mBinaryEditAction->setShortcut(ConfigShortcut("ActionBinaryEdit"));
|
||||
|
|
@ -180,6 +205,10 @@ QString CPUStack::paintContent(QPainter* painter, dsint rowBase, int rowOffset,
|
|||
dsint wRva = (rowBase + rowOffset) * wBytePerRowCount - mByteOffset;
|
||||
duint wVa = rvaToVa(wRva);
|
||||
|
||||
// This sets the first visible row to be selected when stack is frozen, so that we can scroll the stack without it being reset to first selection
|
||||
if(bStackFrozen && rowOffset == 0)
|
||||
setSingleSelection(wRva);
|
||||
|
||||
bool wIsSelected = isSelected(wRva);
|
||||
if(wIsSelected) //highlight if selected
|
||||
painter->fillRect(QRect(x, y, w, h), QBrush(selectionColor));
|
||||
|
|
@ -320,6 +349,7 @@ void CPUStack::contextMenuEvent(QContextMenuEvent* event)
|
|||
wMenu->addAction(mFindPatternAction);
|
||||
wMenu->addAction(mGotoSp);
|
||||
wMenu->addAction(mGotoBp);
|
||||
wMenu->addAction(mFreezeStack);
|
||||
wMenu->addAction(mGotoExpression);
|
||||
|
||||
duint selectedData;
|
||||
|
|
@ -596,3 +626,23 @@ void CPUStack::modifySlot()
|
|||
mMemPage->write(&value, addr, sizeof(dsint));
|
||||
reloadData();
|
||||
}
|
||||
|
||||
void CPUStack::freezeStackSlot()
|
||||
{
|
||||
if(bStackFrozen)
|
||||
DbgCmdExec(QString("setfreezestack 0").toUtf8().constData());
|
||||
else
|
||||
DbgCmdExec(QString("setfreezestack 1").toUtf8().constData());
|
||||
|
||||
bStackFrozen = !bStackFrozen;
|
||||
|
||||
updateFreezeStackAction();
|
||||
}
|
||||
|
||||
void CPUStack::dbgStateChangedSlot(DBGSTATE state)
|
||||
{
|
||||
if(state == initialized)
|
||||
bStackFrozen = false;
|
||||
|
||||
updateFreezeStackAction();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ public:
|
|||
void contextMenuEvent(QContextMenuEvent* event);
|
||||
void mouseDoubleClickEvent(QMouseEvent* event);
|
||||
void setupContextMenu();
|
||||
void updateFreezeStackAction();
|
||||
|
||||
signals:
|
||||
void displayReferencesWidget();
|
||||
|
|
@ -41,9 +42,12 @@ public slots:
|
|||
void binaryPasteIgnoreSizeSlot();
|
||||
void undoSelectionSlot();
|
||||
void modifySlot();
|
||||
void freezeStackSlot();
|
||||
void dbgStateChangedSlot(DBGSTATE state);
|
||||
|
||||
private:
|
||||
duint mCsp;
|
||||
bool bStackFrozen;
|
||||
|
||||
QMenu* mBinaryMenu;
|
||||
QAction* mBinaryEditAction;
|
||||
|
|
@ -55,6 +59,7 @@ private:
|
|||
QAction* mUndoSelection;
|
||||
QAction* mGotoSp;
|
||||
QAction* mGotoBp;
|
||||
QAction* mFreezeStack;
|
||||
QAction* mGotoExpression;
|
||||
QAction* mFindPatternAction;
|
||||
QAction* mFollowDisasm;
|
||||
|
|
|
|||
|
|
@ -17,6 +17,63 @@ CommandLineEdit::CommandLineEdit(QWidget* parent) : HistoryLineEdit(parent)
|
|||
connect(Bridge::getBridge(), SIGNAL(autoCompleteClearAll()), this, SLOT(autoCompleteClearAll()));
|
||||
}
|
||||
|
||||
void CommandLineEdit::keyPressEvent(QKeyEvent *event)
|
||||
{
|
||||
if(event->type() == QEvent::KeyPress)
|
||||
{
|
||||
QKeyEvent *keyEvent = static_cast<QKeyEvent*>(event);
|
||||
if(keyEvent->key() == Qt::Key_Tab)
|
||||
{
|
||||
QStringListModel *strListModel = (QStringListModel*)(mCompleter->model());
|
||||
QStringList stringList = strListModel->stringList();
|
||||
|
||||
if(stringList.size())
|
||||
{
|
||||
QModelIndex currentModelIndex = mCompleter->popup()->currentIndex();
|
||||
|
||||
// If not item selected, select first one in the list
|
||||
if(currentModelIndex.row() < 0)
|
||||
currentModelIndex = mCompleter->currentIndex();
|
||||
|
||||
|
||||
// If popup list is not visible, selected next suggested command
|
||||
if(!mCompleter->popup()->isVisible())
|
||||
{
|
||||
for(int row=0; row < mCompleter->popup()->model()->rowCount(); row++)
|
||||
{
|
||||
QModelIndex modelIndex = mCompleter->popup()->model()->index(row, 0);
|
||||
|
||||
// If the lineedit contains a suggested command, get the next suggested one
|
||||
if(mCompleter->popup()->model()->data(modelIndex) == this->text())
|
||||
{
|
||||
int nextModelIndexRow = (currentModelIndex.row() + 1) % mCompleter->popup()->model()->rowCount();
|
||||
currentModelIndex = mCompleter->popup()->model()->index(nextModelIndexRow, 0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mCompleter->popup()->setCurrentIndex(currentModelIndex);
|
||||
mCompleter->popup()->hide();
|
||||
|
||||
int currentRow = mCompleter->currentRow();
|
||||
mCompleter->setCurrentRow(currentRow);
|
||||
}
|
||||
}
|
||||
else
|
||||
HistoryLineEdit::keyPressEvent(event);
|
||||
}
|
||||
else
|
||||
HistoryLineEdit::keyPressEvent(event);
|
||||
}
|
||||
|
||||
// Disables moving to Prev/Next child when pressing tab
|
||||
bool CommandLineEdit::focusNextPrevChild(bool next)
|
||||
{
|
||||
Q_UNUSED(next);
|
||||
return false;
|
||||
}
|
||||
|
||||
void CommandLineEdit::autoCompleteAddCmd(const QString cmd)
|
||||
{
|
||||
QStringListModel* model = (QStringListModel*)(mCompleter->model());
|
||||
|
|
|
|||
|
|
@ -10,6 +10,8 @@ class CommandLineEdit : public HistoryLineEdit
|
|||
|
||||
public:
|
||||
explicit CommandLineEdit(QWidget* parent = 0);
|
||||
void keyPressEvent(QKeyEvent *event);
|
||||
bool focusNextPrevChild(bool next);
|
||||
|
||||
public slots:
|
||||
void autoCompleteAddCmd(const QString cmd);
|
||||
|
|
|
|||
|
|
@ -21,6 +21,8 @@ GotoDialog::GotoDialog(QWidget* parent) : QDialog(parent), ui(new Ui::GotoDialog
|
|||
validRangeEnd = 0;
|
||||
fileOffset = false;
|
||||
mValidateThread = new ValidateExpressionThread(this);
|
||||
mValidateThread->setOnExpressionChangedCallback(std::bind(&GotoDialog::validateExpression, this, std::placeholders::_1));
|
||||
|
||||
connect(mValidateThread, SIGNAL(expressionChanged(bool, bool, dsint)), this, SLOT(expressionChanged(bool, bool, dsint)));
|
||||
connect(ui->editExpression, SIGNAL(textChanged(QString)), mValidateThread, SLOT(textChanged(QString)));
|
||||
connect(this, SIGNAL(finished(int)), this, SLOT(finishedSlot(int)));
|
||||
|
|
@ -44,6 +46,14 @@ void GotoDialog::hideEvent(QHideEvent* event)
|
|||
mValidateThread->wait();
|
||||
}
|
||||
|
||||
void GotoDialog::validateExpression(QString expression)
|
||||
{
|
||||
duint value;
|
||||
bool validExpression = DbgFunctions()->ValFromString(expression.toUtf8().constData(), &value);
|
||||
bool validPointer = validExpression && DbgMemIsValidReadPtr(value);
|
||||
this->mValidateThread->emitExpressionChanged(validExpression, validPointer, value);
|
||||
}
|
||||
|
||||
void GotoDialog::expressionChanged(bool validExpression, bool validPointer, dsint value)
|
||||
{
|
||||
QString expression = ui->editExpression->text();
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@ public:
|
|||
QString modName;
|
||||
void showEvent(QShowEvent* event);
|
||||
void hideEvent(QHideEvent* event);
|
||||
void validateExpression(QString expression);
|
||||
|
||||
private slots:
|
||||
void expressionChanged(bool validExpression, bool validPointer, dsint value);
|
||||
|
|
|
|||
|
|
@ -13,6 +13,8 @@
|
|||
#include "AttachDialog.h"
|
||||
#include "LineEditDialog.h"
|
||||
|
||||
QString MainWindow::windowTitle = "";
|
||||
|
||||
MainWindow::MainWindow(QWidget* parent) : QMainWindow(parent), ui(new Ui::MainWindow)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
|
|
@ -150,20 +152,26 @@ MainWindow::MainWindow(QWidget* parent) : QMainWindow(parent), ui(new Ui::MainWi
|
|||
// Create the tab widget
|
||||
mTabWidget = new MHTabWidget(NULL);
|
||||
|
||||
// Setup tabs
|
||||
addQWidgetTab(mCpuWidget);
|
||||
addQWidgetTab(mLogView);
|
||||
addQWidgetTab(mNotesManager);
|
||||
addQWidgetTab(mBreakpointsView);
|
||||
addQWidgetTab(mMemMapView);
|
||||
addQWidgetTab(mCallStackView);
|
||||
addQWidgetTab(mScriptView);
|
||||
addQWidgetTab(mSymbolView);
|
||||
addQWidgetTab(mSourceViewManager);
|
||||
addQWidgetTab(mReferenceManager);
|
||||
addQWidgetTab(mThreadView);
|
||||
addQWidgetTab(mSnowmanView);
|
||||
addQWidgetTab(mGraphView);
|
||||
// Add all widgets to the list
|
||||
mWidgetList.push_back(mCpuWidget);
|
||||
mWidgetList.push_back(mLogView);
|
||||
mWidgetList.push_back(mNotesManager);
|
||||
mWidgetList.push_back(mBreakpointsView);
|
||||
mWidgetList.push_back(mMemMapView);
|
||||
mWidgetList.push_back(mCallStackView);
|
||||
mWidgetList.push_back(mScriptView);
|
||||
mWidgetList.push_back(mSymbolView);
|
||||
mWidgetList.push_back(mSourceViewManager);
|
||||
mWidgetList.push_back(mReferenceManager);
|
||||
mWidgetList.push_back(mThreadView);
|
||||
mWidgetList.push_back(mSnowmanView);
|
||||
mWidgetList.push_back(mGraphView);
|
||||
|
||||
// If LoadSaveTabOrder disabled, load tabs in default order
|
||||
if(!ConfigBool("Miscellaneous", "LoadSaveTabOrder"))
|
||||
loadTabDefaultOrder();
|
||||
else
|
||||
loadTabSavedOrder();
|
||||
|
||||
setCentralWidget(mTabWidget);
|
||||
|
||||
|
|
@ -240,6 +248,7 @@ MainWindow::MainWindow(QWidget* parent) : QMainWindow(parent), ui(new Ui::MainWi
|
|||
connect(ui->actionChangeCommandLine, SIGNAL(triggered()), this, SLOT(changeCommandLine()));
|
||||
connect(ui->actionManual, SIGNAL(triggered()), this, SLOT(displayManual()));
|
||||
|
||||
connect(mCpuWidget->getDisasmWidget(), SIGNAL(updateWindowTitle(QString)), this, SLOT(updateWindowTitleSlot(QString)));
|
||||
connect(mCpuWidget->getDisasmWidget(), SIGNAL(displayReferencesWidget()), this, SLOT(displayReferencesWidget()));
|
||||
connect(mCpuWidget->getDisasmWidget(), SIGNAL(displaySourceManagerWidget()), this, SLOT(displaySourceViewWidget()));
|
||||
connect(mCpuWidget->getDisasmWidget(), SIGNAL(displaySnowmanWidget()), this, SLOT(displaySnowmanWidget()));
|
||||
|
|
@ -247,13 +256,16 @@ MainWindow::MainWindow(QWidget* parent) : QMainWindow(parent), ui(new Ui::MainWi
|
|||
connect(mCpuWidget->getDisasmWidget(), SIGNAL(decompileAt(dsint, dsint)), this, SLOT(decompileAt(dsint, dsint)));
|
||||
connect(mCpuWidget->getDumpWidget(), SIGNAL(displayReferencesWidget()), this, SLOT(displayReferencesWidget()));
|
||||
connect(mCpuWidget->getStackWidget(), SIGNAL(displayReferencesWidget()), this, SLOT(displayReferencesWidget()));
|
||||
connect(mTabWidget, SIGNAL(tabMovedTabWidget(int,int)), this, SLOT(tabMovedSlot(int, int)));
|
||||
connect(Config(), SIGNAL(shortcutsUpdated()), this, SLOT(refreshShortcuts()));
|
||||
|
||||
|
||||
// Set default setttings (when not set)
|
||||
SettingsDialog defaultSettings;
|
||||
lastException = 0;
|
||||
defaultSettings.SaveSettings();
|
||||
|
||||
|
||||
// Create updatechecker
|
||||
mUpdateChecker = new UpdateChecker(this);
|
||||
|
||||
|
|
@ -309,6 +321,49 @@ void MainWindow::setTab(QWidget* widget)
|
|||
}
|
||||
}
|
||||
|
||||
void MainWindow::loadTabDefaultOrder()
|
||||
{
|
||||
clearTabWidget();
|
||||
|
||||
// Setup tabs
|
||||
for(int i=0; i < mWidgetList.size(); i++)
|
||||
addQWidgetTab(mWidgetList[i]);
|
||||
}
|
||||
|
||||
void MainWindow::loadTabSavedOrder()
|
||||
{
|
||||
clearTabWidget();
|
||||
|
||||
QMap<duint, QWidget* > tabIndexToWidget;
|
||||
|
||||
// Get tabIndex for each widget and add them to tabIndexToWidget
|
||||
for(int i=0; i < mWidgetList.size(); i++)
|
||||
{
|
||||
QString tabName = mWidgetList[i]->windowTitle();
|
||||
tabName = tabName.replace(" ", "") + "Tab";
|
||||
duint tabIndex = Config()->getUint("TabOrder", tabName);
|
||||
tabIndexToWidget.insert(tabIndex, mWidgetList[i]);
|
||||
}
|
||||
|
||||
// Setup tabs
|
||||
QMap<duint, QWidget* >::iterator it = tabIndexToWidget.begin();
|
||||
for(it; it != tabIndexToWidget.end(); it++)
|
||||
{
|
||||
addQWidgetTab(it.value());
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::clearTabWidget()
|
||||
{
|
||||
if(!mTabWidget->count())
|
||||
return;
|
||||
|
||||
for(int i=mTabWidget->count()-1; i >= 0; i--)
|
||||
{
|
||||
mTabWidget->removeTab(i);
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::setGlobalShortcut(QAction* action, const QKeySequence & key)
|
||||
{
|
||||
action->setShortcut(key);
|
||||
|
|
@ -649,9 +704,15 @@ void MainWindow::dropEvent(QDropEvent* pEvent)
|
|||
void MainWindow::updateWindowTitleSlot(QString filename)
|
||||
{
|
||||
if(filename.length())
|
||||
{
|
||||
setWindowTitle(QString(mWindowMainTitle) + QString(" - ") + filename);
|
||||
windowTitle = filename;
|
||||
}
|
||||
else
|
||||
{
|
||||
setWindowTitle(QString(mWindowMainTitle));
|
||||
windowTitle = QString(mWindowMainTitle);
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::execeStepOver()
|
||||
|
|
@ -710,9 +771,10 @@ void MainWindow::displaySnowmanWidget()
|
|||
|
||||
void MainWindow::openSettings()
|
||||
{
|
||||
SettingsDialog settings(this);
|
||||
settings.lastException = lastException;
|
||||
settings.exec();
|
||||
SettingsDialog *settings = new SettingsDialog(this);
|
||||
connect(settings, SIGNAL(chkSaveLoadTabOrderStateChanged(bool)), this, SLOT(chkSaveloadTabSavedOrderStateChangedSlot(bool)));
|
||||
settings->lastException = lastException;
|
||||
settings->exec();
|
||||
}
|
||||
|
||||
void MainWindow::openAppearance()
|
||||
|
|
@ -1162,3 +1224,21 @@ void MainWindow::drawGraphAtAddressSlot(dsint va)
|
|||
{
|
||||
mGraphView->drawGraphAtSlot(va);
|
||||
}
|
||||
|
||||
void MainWindow::tabMovedSlot(int from, int to)
|
||||
{
|
||||
for(int i=0; i < mTabWidget->count(); i++)
|
||||
{
|
||||
// Remove space in widget name and append Tab to get config settings (CPUTab, MemoryMapTab, etc...)
|
||||
QString tabName = mTabWidget->tabText(i).replace(" ", "") + "Tab";
|
||||
Config()->setUint("TabOrder", tabName, i);
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::chkSaveloadTabSavedOrderStateChangedSlot(bool state)
|
||||
{
|
||||
if(state)
|
||||
loadTabSavedOrder();
|
||||
else
|
||||
loadTabDefaultOrder();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@
|
|||
#include "MainWindowCloseThread.h"
|
||||
#include "TimeWastedCounter.h"
|
||||
#include "NotesManager.h"
|
||||
#include "SettingsDialog.h"
|
||||
#include "GraphView.h"
|
||||
|
||||
namespace Ui
|
||||
|
|
@ -41,6 +42,9 @@ public:
|
|||
static DWORD WINAPI closeThread(void* ptr);
|
||||
void closeEvent(QCloseEvent* event);
|
||||
void setTab(QWidget* widget);
|
||||
void loadTabDefaultOrder();
|
||||
void loadTabSavedOrder();
|
||||
void clearTabWidget();
|
||||
|
||||
public slots:
|
||||
void executeCommand();
|
||||
|
|
@ -112,7 +116,9 @@ public slots:
|
|||
void showQWidgetTab(QWidget* qWidget);
|
||||
void closeQWidgetTab(QWidget* qWidget);
|
||||
void executeOnGuiThread(void* cbGuiThread);
|
||||
void tabMovedSlot(int from, int to);
|
||||
void drawGraphAtAddressSlot(dsint va);
|
||||
void chkSaveloadTabSavedOrderStateChangedSlot(bool state);
|
||||
|
||||
private:
|
||||
Ui::MainWindow* ui;
|
||||
|
|
@ -189,10 +195,14 @@ private:
|
|||
|
||||
bool bCanClose;
|
||||
MainWindowCloseThread* mCloseThread;
|
||||
QVector<QWidget* > mWidgetList;
|
||||
|
||||
protected:
|
||||
void dragEnterEvent(QDragEnterEvent* pEvent);
|
||||
void dropEvent(QDropEvent* pEvent);
|
||||
|
||||
public:
|
||||
static QString windowTitle;
|
||||
};
|
||||
|
||||
#endif // MAINWINDOW_H
|
||||
|
|
|
|||
|
|
@ -231,6 +231,9 @@ void SettingsDialog::LoadSettings()
|
|||
|
||||
bJitOld = settings.miscSetJIT;
|
||||
bJitAutoOld = settings.miscSetJITAuto;
|
||||
|
||||
GetSettingBool("Miscellaneous", "LoadSaveTabOrder", &settings.miscLoadSaveTabOrder);
|
||||
ui->chkSaveLoadTabOrder->setChecked(settings.miscLoadSaveTabOrder);
|
||||
}
|
||||
|
||||
void SettingsDialog::SaveSettings()
|
||||
|
|
@ -298,6 +301,8 @@ void SettingsDialog::SaveSettings()
|
|||
if(settings.miscSymbolCache)
|
||||
BridgeSettingSet("Symbols", "CachePath", ui->editSymbolCache->text().toUtf8().constData());
|
||||
|
||||
BridgeSettingSetUint("Miscellaneous", "LoadSaveTabOrder", settings.miscLoadSaveTabOrder);
|
||||
|
||||
BridgeSettingFlush();
|
||||
Config()->load();
|
||||
DbgSettingsUpdated();
|
||||
|
|
@ -625,3 +630,13 @@ void SettingsDialog::on_editSymbolCache_textEdited(const QString & arg1)
|
|||
Q_UNUSED(arg1);
|
||||
settings.miscSymbolCache = true;
|
||||
}
|
||||
|
||||
void SettingsDialog::on_chkSaveLoadTabOrder_stateChanged(int arg1)
|
||||
{
|
||||
if(arg1 == Qt::Unchecked)
|
||||
settings.miscLoadSaveTabOrder = false;
|
||||
else
|
||||
settings.miscLoadSaveTabOrder = true;
|
||||
|
||||
emit chkSaveLoadTabOrderStateChanged((bool)arg1);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,6 +18,9 @@ public:
|
|||
void SaveSettings();
|
||||
unsigned int lastException;
|
||||
|
||||
signals:
|
||||
void chkSaveLoadTabOrderStateChanged(bool state);
|
||||
|
||||
private slots:
|
||||
//Manual slots
|
||||
void setLastException(unsigned int exceptionCode);
|
||||
|
|
@ -62,6 +65,8 @@ private slots:
|
|||
void on_editSymbolStore_textEdited(const QString & arg1);
|
||||
void on_editSymbolCache_textEdited(const QString & arg1);
|
||||
|
||||
void on_chkSaveLoadTabOrder_stateChanged(int arg1);
|
||||
|
||||
private:
|
||||
//enums
|
||||
enum CalcType
|
||||
|
|
@ -127,6 +132,7 @@ private:
|
|||
bool miscSetJITAuto;
|
||||
bool miscSymbolStore;
|
||||
bool miscSymbolCache;
|
||||
bool miscLoadSaveTabOrder;
|
||||
};
|
||||
|
||||
//variables
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@
|
|||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>383</width>
|
||||
<height>307</height>
|
||||
<height>365</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
|
|
@ -432,7 +432,7 @@
|
|||
<x>11</x>
|
||||
<y>13</y>
|
||||
<width>341</width>
|
||||
<height>145</height>
|
||||
<height>168</height>
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_9">
|
||||
|
|
@ -507,6 +507,13 @@
|
|||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="chkSaveLoadTabOrder">
|
||||
<property name="text">
|
||||
<string>Enable Load/Save Tab Order</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</widget>
|
||||
|
|
|
|||
|
|
@ -31,11 +31,13 @@ SymbolView::SymbolView(QWidget* parent) : QWidget(parent), ui(new Ui::SymbolView
|
|||
|
||||
// Setup symbol list
|
||||
mSearchListView->mList->addColumnAt(charwidth * 2 * sizeof(dsint) + 8, "Address", true);
|
||||
mSearchListView->mList->addColumnAt(charwidth * 2 * sizeof(dsint) + 8, "Type", true);
|
||||
mSearchListView->mList->addColumnAt(charwidth * 80, "Symbol", true);
|
||||
mSearchListView->mList->addColumnAt(2000, "Symbol (undecorated)", true);
|
||||
|
||||
// Setup search list
|
||||
mSearchListView->mSearchList->addColumnAt(charwidth * 2 * sizeof(dsint) + 8, "Address", true);
|
||||
mSearchListView->mSearchList->addColumnAt(charwidth * 2 * sizeof(dsint) + 8, "Type", true);
|
||||
mSearchListView->mSearchList->addColumnAt(charwidth * 80, "Symbol", true);
|
||||
mSearchListView->mSearchList->addColumnAt(2000, "Symbol (undecorated)", true);
|
||||
|
||||
|
|
@ -71,6 +73,7 @@ SymbolView::SymbolView(QWidget* parent) : QWidget(parent), ui(new Ui::SymbolView
|
|||
connect(Bridge::getBridge(), SIGNAL(clearSymbolLog()), this, SLOT(clearSymbolLogSlot()));
|
||||
connect(mModuleList->mList, SIGNAL(selectionChangedSignal(int)), this, SLOT(moduleSelectionChanged(int)));
|
||||
connect(mModuleList->mSearchList, SIGNAL(selectionChangedSignal(int)), this, SLOT(moduleSelectionChanged(int)));
|
||||
connect(mModuleList, SIGNAL(emptySearchResult()), this, SLOT(emptySearchResultSlot()));
|
||||
connect(mModuleList, SIGNAL(listContextMenuSignal(QMenu*)), this, SLOT(moduleContextMenu(QMenu*)));
|
||||
connect(mModuleList, SIGNAL(enterPressedSignal()), this, SLOT(moduleFollow()));
|
||||
connect(Bridge::getBridge(), SIGNAL(updateSymbolList(int, SYMBOLMODULEINFO*)), this, SLOT(updateSymbolList(int, SYMBOLMODULEINFO*)));
|
||||
|
|
@ -172,13 +175,20 @@ void SymbolView::cbSymbolEnum(SYMBOLINFO* symbol, void* user)
|
|||
symbolList->setCellContent(index, 0, QString("%1").arg(symbol->addr, sizeof(dsint) * 2, 16, QChar('0')).toUpper());
|
||||
if(symbol->decoratedSymbol)
|
||||
{
|
||||
symbolList->setCellContent(index, 1, symbol->decoratedSymbol);
|
||||
BridgeFree(symbol->decoratedSymbol);
|
||||
symbolList->setCellContent(index, 2, symbol->decoratedSymbol);
|
||||
}
|
||||
if(symbol->undecoratedSymbol)
|
||||
{
|
||||
symbolList->setCellContent(index, 2, symbol->undecoratedSymbol);
|
||||
BridgeFree(symbol->undecoratedSymbol);
|
||||
symbolList->setCellContent(index, 3, symbol->undecoratedSymbol);
|
||||
}
|
||||
|
||||
if(symbol->isImported)
|
||||
{
|
||||
symbolList->setCellContent(index, 1, "Import");
|
||||
}
|
||||
else
|
||||
{
|
||||
symbolList->setCellContent(index, 1, "Export");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -188,7 +198,7 @@ void SymbolView::moduleSelectionChanged(int index)
|
|||
if(!mModuleBaseList.count(mod))
|
||||
return;
|
||||
mSearchListView->mList->setRowCount(0);
|
||||
DbgSymbolEnum(mModuleBaseList[mod], cbSymbolEnum, mSearchListView->mList);
|
||||
DbgSymbolEnumFromCache(mModuleBaseList[mod], cbSymbolEnum, mSearchListView->mList);
|
||||
mSearchListView->mList->reloadData();
|
||||
mSearchListView->mList->setSingleSelection(0);
|
||||
mSearchListView->mList->setTableOffset(0);
|
||||
|
|
@ -204,7 +214,7 @@ void SymbolView::updateSymbolList(int module_count, SYMBOLMODULEINFO* modules)
|
|||
mSearchListView->mList->setSingleSelection(0);
|
||||
mModuleList->mList->setSingleSelection(0);
|
||||
}
|
||||
mModuleList->mList->setFocus();
|
||||
|
||||
mModuleBaseList.clear();
|
||||
for(int i = 0; i < module_count; i++)
|
||||
{
|
||||
|
|
@ -395,3 +405,9 @@ void SymbolView::moduleEntropy()
|
|||
entropyDialog.exec();
|
||||
}
|
||||
}
|
||||
|
||||
void SymbolView::emptySearchResultSlot()
|
||||
{
|
||||
// No result after search
|
||||
mSearchListView->mCurList->setRowCount(0);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -40,6 +40,7 @@ private slots:
|
|||
void toggleBookmark();
|
||||
void refreshShortcutsSlot();
|
||||
void moduleEntropy();
|
||||
void emptySearchResultSlot();
|
||||
|
||||
signals:
|
||||
void showCpu();
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ MHTabWidget::MHTabWidget(QWidget* parent, bool allowDetach, bool allowDelete) :
|
|||
connect(m_tabBar, SIGNAL(OnDetachTab(int, QPoint &)), this, SLOT(DetachTab(int, QPoint &)));
|
||||
connect(m_tabBar, SIGNAL(OnMoveTab(int, int)), this, SLOT(MoveTab(int, int)));
|
||||
connect(m_tabBar, SIGNAL(OnDeleteTab(int)), this, SLOT(DeleteTab(int)));
|
||||
connect(m_tabBar, SIGNAL(tabMoved(int,int)), this, SLOT(tabMoved(int, int)));
|
||||
|
||||
setTabBar(m_tabBar);
|
||||
setMovable(true);
|
||||
|
|
@ -132,6 +133,11 @@ void MHTabWidget::DeleteTab(int index)
|
|||
removeTab(index);
|
||||
}
|
||||
|
||||
void MHTabWidget::tabMoved(int from, int to)
|
||||
{
|
||||
emit tabMovedTabWidget(from, to);
|
||||
}
|
||||
|
||||
void MHTabWidget::setCurrentIndex(int index)
|
||||
{
|
||||
// Check if it's just a normal tab
|
||||
|
|
|
|||
|
|
@ -30,11 +30,15 @@ public:
|
|||
int count() const;
|
||||
QList<QWidget*> windows();
|
||||
|
||||
signals:
|
||||
void tabMovedTabWidget(int from, int to);
|
||||
|
||||
public slots:
|
||||
void AttachTab(QWidget* parent);
|
||||
void DetachTab(int index, QPoint &);
|
||||
void MoveTab(int fromIndex, int toIndex);
|
||||
void DeleteTab(int index);
|
||||
void tabMoved(int from, int to);
|
||||
|
||||
public Q_SLOTS:
|
||||
void setCurrentIndex(int index);
|
||||
|
|
|
|||
|
|
@ -159,6 +159,7 @@ Configuration::Configuration() : QObject()
|
|||
QMap<QString, bool> disassemblyBool;
|
||||
disassemblyBool.insert("ArgumentSpaces", false);
|
||||
disassemblyBool.insert("MemorySpaces", false);
|
||||
disassemblyBool.insert("KeepSize", false);
|
||||
disassemblyBool.insert("FillNOPs", false);
|
||||
disassemblyBool.insert("Uppercase", false);
|
||||
disassemblyBool.insert("FindCommandEntireBlock", false);
|
||||
|
|
@ -170,6 +171,10 @@ Configuration::Configuration() : QObject()
|
|||
engineBool.insert("ListAllPages", false);
|
||||
defaultBools.insert("Engine", engineBool);
|
||||
|
||||
QMap<QString, bool> miscellaneousBool;
|
||||
miscellaneousBool.insert("LoadSaveTabOrder", false);
|
||||
defaultBools.insert("Miscellaneous", miscellaneousBool);
|
||||
|
||||
//uint settings
|
||||
QMap<QString, duint> hexdumpUint;
|
||||
hexdumpUint.insert("DefaultView", 0);
|
||||
|
|
@ -177,6 +182,20 @@ Configuration::Configuration() : QObject()
|
|||
QMap<QString, duint> disasmUint;
|
||||
disasmUint.insert("MaxModuleSize", -1);
|
||||
defaultUints.insert("Disassembler", disasmUint);
|
||||
QMap<QString, duint> tabOrderUint;
|
||||
tabOrderUint.insert("CPUTab", 0);
|
||||
tabOrderUint.insert("LogTab", 1);
|
||||
tabOrderUint.insert("NotesTab", 2);
|
||||
tabOrderUint.insert("BreakpointsTab", 3);
|
||||
tabOrderUint.insert("MemoryMapTab", 4);
|
||||
tabOrderUint.insert("CallStackTab", 5);
|
||||
tabOrderUint.insert("ScriptTab", 6);
|
||||
tabOrderUint.insert("SymbolsTab", 7);
|
||||
tabOrderUint.insert("SourceTab", 8);
|
||||
tabOrderUint.insert("ReferencesTab", 9);
|
||||
tabOrderUint.insert("ThreadsTab", 10);
|
||||
tabOrderUint.insert("SnowmanTab", 11);
|
||||
defaultUints.insert("TabOrder", tabOrderUint);
|
||||
|
||||
//font settings
|
||||
QFont font("Lucida Console", 8, QFont::Normal, false);
|
||||
|
|
@ -398,6 +417,9 @@ void Configuration::readUints()
|
|||
|
||||
void Configuration::writeUints()
|
||||
{
|
||||
duint setting;
|
||||
bool bSaveLoadTabOrder = ConfigBool("Miscellaneous", "LoadSaveTabOrder");
|
||||
|
||||
//write config
|
||||
for(int i = 0; i < Uints.size(); i++)
|
||||
{
|
||||
|
|
@ -406,6 +428,11 @@ void Configuration::writeUints()
|
|||
for(int j = 0; j < currentUint->size(); j++)
|
||||
{
|
||||
QString id = (*currentUint).keys().at(j);
|
||||
|
||||
// Do not save settings to file if saveLoadTabOrder checkbox is Unchecked
|
||||
if(!bSaveLoadTabOrder && category == "TabOrder" && BridgeSettingGetUint(category.toUtf8().constData(), id.toUtf8().constData(), &setting))
|
||||
continue;
|
||||
|
||||
uintToConfig(category, id, (*currentUint)[id]);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
ValidateExpressionThread::ValidateExpressionThread(QObject* parent) : QThread(parent), mExpressionChanged(false), mStopThread(false)
|
||||
{
|
||||
this->mOnExpressionChangedCallback = nullptr;
|
||||
}
|
||||
|
||||
void ValidateExpressionThread::start(QString initialValue)
|
||||
|
|
@ -16,6 +17,16 @@ void ValidateExpressionThread::stop()
|
|||
mStopThread = true;
|
||||
}
|
||||
|
||||
void ValidateExpressionThread::emitExpressionChanged(bool validExpression, bool validPointer, dsint value)
|
||||
{
|
||||
emit expressionChanged(validExpression, validPointer, value);
|
||||
}
|
||||
|
||||
void ValidateExpressionThread::emitInstructionChanged(dsint sizeDifference, QString error)
|
||||
{
|
||||
emit instructionChanged(sizeDifference, error);
|
||||
}
|
||||
|
||||
void ValidateExpressionThread::textChanged(QString text)
|
||||
{
|
||||
mExpressionMutex.lock();
|
||||
|
|
@ -27,6 +38,11 @@ void ValidateExpressionThread::textChanged(QString text)
|
|||
mExpressionMutex.unlock();
|
||||
}
|
||||
|
||||
void ValidateExpressionThread::setOnExpressionChangedCallback(EXPRESSIONCHANGEDCB callback)
|
||||
{
|
||||
mOnExpressionChangedCallback = callback;
|
||||
}
|
||||
|
||||
void ValidateExpressionThread::run()
|
||||
{
|
||||
while(!mStopThread)
|
||||
|
|
@ -36,12 +52,9 @@ void ValidateExpressionThread::run()
|
|||
bool changed = mExpressionChanged;
|
||||
mExpressionChanged = false;
|
||||
mExpressionMutex.unlock();
|
||||
if(changed)
|
||||
if(changed && mOnExpressionChangedCallback != nullptr)
|
||||
{
|
||||
duint value;
|
||||
bool validExpression = DbgFunctions()->ValFromString(expression.toUtf8().constData(), &value);
|
||||
bool validPointer = validExpression && DbgMemIsValidReadPtr(value);
|
||||
emit expressionChanged(validExpression, validPointer, value);
|
||||
mOnExpressionChangedCallback(expression);
|
||||
}
|
||||
Sleep(50);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,8 +3,11 @@
|
|||
|
||||
#include <QThread>
|
||||
#include <QMutex>
|
||||
#include <functional>
|
||||
#include "Imports.h"
|
||||
|
||||
typedef std::function<void(QString expression) > EXPRESSIONCHANGEDCB;
|
||||
|
||||
class ValidateExpressionThread : public QThread
|
||||
{
|
||||
Q_OBJECT
|
||||
|
|
@ -12,18 +15,23 @@ public:
|
|||
ValidateExpressionThread(QObject* parent = 0);
|
||||
void start(QString initialValue = QString());
|
||||
void stop();
|
||||
void emitExpressionChanged(bool validExpression, bool validPointer, dsint value);
|
||||
void emitInstructionChanged(dsint sizeDifference, QString error);
|
||||
|
||||
signals:
|
||||
void expressionChanged(bool validExpression, bool validPointer, dsint value);
|
||||
void instructionChanged(dsint sizeDifference, QString error);
|
||||
|
||||
public slots:
|
||||
void textChanged(QString text);
|
||||
void setOnExpressionChangedCallback(EXPRESSIONCHANGEDCB callback);
|
||||
|
||||
private:
|
||||
QMutex mExpressionMutex;
|
||||
QString mExpressionText;
|
||||
bool mExpressionChanged;
|
||||
volatile bool mStopThread;
|
||||
EXPRESSIONCHANGEDCB mOnExpressionChangedCallback;
|
||||
|
||||
void run();
|
||||
};
|
||||
|
|
|
|||
|
|
@ -146,9 +146,10 @@ SOURCES += \
|
|||
Src/Gui/NotesManager.cpp \
|
||||
Src/Gui/NotepadView.cpp \
|
||||
Src/Gui/CPUMultiDump.cpp \
|
||||
Src/Gui/AssembleDialog.cpp \
|
||||
Src/Gui/GraphView.cpp \
|
||||
Src/Graph/QGraphScene.cpp \
|
||||
Src/QGraphView.cpp \
|
||||
Src/Graph/QGraphView.cpp \
|
||||
Src/Graph/GraphEdge.cpp \
|
||||
Src/Graph/GraphNode.cpp
|
||||
|
||||
|
|
@ -232,6 +233,7 @@ HEADERS += \
|
|||
Src/Utils/MenuBuilder.h \
|
||||
Src/Utils/QActionLambda.h \
|
||||
Src/Gui/CPUMultiDump.h \
|
||||
Src/Gui/AssembleDialog.h \
|
||||
Src/BasicView/HeaderButton.h \
|
||||
Src/ThirdPartyLibs/snowman/SnowmanView.h \
|
||||
Src/Graph/GraphEdge.h \
|
||||
|
|
@ -240,7 +242,7 @@ HEADERS += \
|
|||
Src/Graph/Tree.h \
|
||||
Src/Gui/GraphView.h \
|
||||
Src/Graph/QGraphScene.h \
|
||||
Src/QGraphView.h
|
||||
Src/Graph/QGraphView.h
|
||||
|
||||
FORMS += \
|
||||
Src/Gui/MainWindow.ui \
|
||||
|
|
@ -266,6 +268,7 @@ FORMS += \
|
|||
Src/Gui/YaraRuleSelectionDialog.ui \
|
||||
Src/Gui/DataCopyDialog.ui \
|
||||
Src/Gui/EntropyDialog.ui \
|
||||
Src/Gui/AssembleDialog.ui \
|
||||
Src/Gui/GraphView.ui
|
||||
|
||||
##
|
||||
|
|
|
|||
Loading…
Reference in New Issue