Merge pull request #453 from Herz3h/Herz3hDev
I didn't check all the code, but I trust you to fix the potential issues you created 😄
			
			
This commit is contained in:
		
						commit
						37b5ea5f2e
					
				|  | @ -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); | ||||
| } | ||||
| 
 | ||||
| BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) | ||||
| { | ||||
|     hInst = hinstDLL; | ||||
|  |  | |||
|  | @ -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 | ||||
|  | @ -143,6 +145,7 @@ typedef enum | |||
|     DBG_SCRIPT_SETIP,               // param1=int line,                  param2=unused
 | ||||
|     DBG_SCRIPT_GETBRANCHINFO,       // param1=int line,                  param2=SCRIPTBRANCH* info
 | ||||
|     DBG_SYMBOL_ENUM,                // param1=SYMBOLCBINFO* cbInfo,      param2=unused
 | ||||
|     DBG_SYMBOL_ENUM_FROMCACHE,      // param1=SYMBOLCBINFO* cbInfo,      param2=unused
 | ||||
|     DBG_ASSEMBLE_AT,                // param1=duint addr,                param2=const char* instruction
 | ||||
|     DBG_MODBASE_FROM_NAME,          // param1=const char* modname,       param2=unused
 | ||||
|     DBG_DISASM_AT,                  // param1=duint addr,                 param2=DISASM_INSTR* instr
 | ||||
|  | @ -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,8 @@ 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_SETCURRENTTASKPROGRESS, // param1=int progress,         param2=const char* taskTitle
 | ||||
|     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 +764,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,6 +788,7 @@ 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_DISPLAY_WARNING             // param1=const char *text,     param2=unused
 | ||||
| } GUIMSG; | ||||
| 
 | ||||
| //GUI Typedefs
 | ||||
|  | @ -843,6 +850,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(); | ||||
|  | @ -880,6 +888,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); | ||||
| 
 | ||||
| #ifdef __cplusplus | ||||
| } | ||||
|  |  | |||
|  | @ -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); | ||||
|  |  | |||
|  | @ -1,7 +1,7 @@ | |||
| #ifndef _GLOBAL_H | ||||
| #define _GLOBAL_H | ||||
| 
 | ||||
| #define _WIN32_WINNT 0x0501 | ||||
| #define _WIN32_WINNT 0x0601 | ||||
| #define WINVER 0x0501 | ||||
| #define _WIN32_IE 0x0500 | ||||
| 
 | ||||
|  |  | |||
|  | @ -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
 | ||||
|  |  | |||
|  | @ -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); | ||||
|  | @ -632,7 +650,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 +1134,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 +1229,7 @@ DWORD WINAPI threadDebugLoop(void* lpParameter) | |||
|     DBClose(); | ||||
|     ModClear(); | ||||
|     ThreadClear(); | ||||
|     SymClearMemoryCache(); | ||||
|     GuiSetDebugState(stopped); | ||||
|     dputs("Debugging stopped!"); | ||||
|     varset("$hp", (duint)0, true); | ||||
|  | @ -1409,6 +1444,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 +1497,7 @@ DWORD WINAPI threadAttachLoop(void* lpParameter) | |||
|     DBClose(); | ||||
|     ModClear(); | ||||
|     ThreadClear(); | ||||
|     SymClearMemoryCache(); | ||||
|     GuiSetDebugState(stopped); | ||||
|     dputs("debugging stopped!"); | ||||
|     varset("$hp", (duint)0, true); | ||||
|  | @ -1596,7 +1633,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 +1719,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 +1763,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; | ||||
|  |  | |||
|  | @ -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,133 @@ bool SymGetSourceLine(duint Cip, char* FileName, int* Line) | |||
|     } | ||||
| 
 | ||||
|     return true; | ||||
| } | ||||
| 
 | ||||
| void SymClearMemoryCache() | ||||
| { | ||||
|     SYMBOLINFOMAP::iterator it = modulesCacheList.begin(); | ||||
|     for (; it != modulesCacheList.end(); it++) | ||||
|     { | ||||
|         SYMBOLINFOVECTOR* pModuleVector = &((*it).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 buf[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; | ||||
|             } | ||||
|             // Otherwise just use import info from module itself
 | ||||
|             else | ||||
|             { | ||||
|                 curSymbol.addr = imports[i].addr; | ||||
|                 curSymbol.isImported = true; | ||||
|                 curSymbol.undecoratedSymbol = nullptr; | ||||
|                 curSymbol.decoratedSymbol = imports[i].name; | ||||
|             } | ||||
| 
 | ||||
|             // Format so that we get : moduleName.importSymbol
 | ||||
|             duint lenWithoutExt = strlen(imports[i].moduleName) - 3; // Remove extension
 | ||||
|             strncpy_s(buf, lenWithoutExt, imports[i].moduleName, _TRUNCATE); | ||||
|             strcat_s(buf , "."); | ||||
| 
 | ||||
|             if (curSymbol.undecoratedSymbol) | ||||
|             { | ||||
|                 strcat(buf, curSymbol.undecoratedSymbol); | ||||
|                 curSymbol.undecoratedSymbol = buf; | ||||
|             } | ||||
| 
 | ||||
|             if (curSymbol.decoratedSymbol) | ||||
|             { | ||||
|                 strcat(buf, curSymbol.decoratedSymbol); | ||||
|                 curSymbol.decoratedSymbol = buf; | ||||
|             } | ||||
| 
 | ||||
|             // 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. | ||||
|  |  | |||
|  | @ -51,6 +51,7 @@ enum SectionLock | |||
|     LockPluginCommandList, | ||||
|     LockPluginMenuList, | ||||
|     LockLast, | ||||
|     LockCmdLine | ||||
| }; | ||||
| 
 | ||||
| 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> | ||||
|  | @ -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" | ||||
| 
 | ||||
| Disassembly::Disassembly(QWidget* parent) : AbstractTableView(parent) | ||||
| { | ||||
|  | @ -1271,6 +1272,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; | ||||
|  | @ -1300,6 +1302,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); | ||||
|         } | ||||
|     } | ||||
|  | @ -1360,6 +1363,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
 | ||||
|  | @ -1469,6 +1473,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() | ||||
|  | @ -1478,6 +1485,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); | ||||
| 
 | ||||
| public slots: | ||||
|     void disassembleAt(dsint parVA, dsint parCIP); | ||||
|  | @ -131,6 +132,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; | ||||
|     } | ||||
|     return nullptr; | ||||
| } | ||||
|  |  | |||
|  | @ -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); | ||||
| 
 | ||||
| private: | ||||
|     QMutex* mBridgeMutex; | ||||
|  |  | |||
|  | @ -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(); | ||||
| } | ||||
|  | @ -1139,6 +1234,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); | ||||
|  | @ -144,19 +146,25 @@ 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); | ||||
|     // 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); | ||||
| 
 | ||||
|     // If LoadSaveTabOrder disabled, load tabs in default order
 | ||||
|     if(!ConfigBool("Miscellaneous", "LoadSaveTabOrder")) | ||||
|         loadTabDefaultOrder(); | ||||
|     else | ||||
|         loadTabSavedOrder(); | ||||
| 
 | ||||
|     setCentralWidget(mTabWidget); | ||||
| 
 | ||||
|  | @ -233,6 +241,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())); | ||||
|  | @ -240,13 +249,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); | ||||
| 
 | ||||
|  | @ -302,6 +314,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); | ||||
|  | @ -642,9 +697,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() | ||||
|  | @ -703,9 +764,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() | ||||
|  | @ -1150,3 +1212,21 @@ void MainWindow::executeOnGuiThread(void* cbGuiThread) | |||
| { | ||||
|     ((GUICALLBACK)cbGuiThread)(); | ||||
| } | ||||
| 
 | ||||
| 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" | ||||
| 
 | ||||
| namespace Ui | ||||
| { | ||||
|  | @ -40,6 +41,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(); | ||||
|  | @ -111,6 +115,8 @@ public slots: | |||
|     void showQWidgetTab(QWidget* qWidget); | ||||
|     void closeQWidgetTab(QWidget* qWidget); | ||||
|     void executeOnGuiThread(void* cbGuiThread); | ||||
|     void tabMovedSlot(int from, int to); | ||||
|     void chkSaveloadTabSavedOrderStateChangedSlot(bool state); | ||||
| 
 | ||||
| private: | ||||
|     Ui::MainWindow* ui; | ||||
|  | @ -186,10 +192,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(); | ||||
| }; | ||||
|  |  | |||
|  | @ -139,7 +139,8 @@ SOURCES += \ | |||
|     Src/Gui/EntropyDialog.cpp \ | ||||
|     Src/Gui/NotesManager.cpp \ | ||||
|     Src/Gui/NotepadView.cpp \ | ||||
|     Src/Gui/CPUMultiDump.cpp | ||||
|     Src/Gui/CPUMultiDump.cpp \ | ||||
|     Src/Gui/AssembleDialog.cpp | ||||
| 
 | ||||
| 
 | ||||
| HEADERS += \ | ||||
|  | @ -220,7 +221,8 @@ HEADERS += \ | |||
|     Src/Gui/NotepadView.h \ | ||||
|     Src/Utils/MenuBuilder.h \ | ||||
|     Src/Utils/QActionLambda.h \ | ||||
|     Src/Gui/CPUMultiDump.h | ||||
|     Src/Gui/CPUMultiDump.h \ | ||||
|     Src/Gui/AssembleDialog.h | ||||
| 
 | ||||
| FORMS += \ | ||||
|     Src/Gui/MainWindow.ui \ | ||||
|  | @ -245,7 +247,8 @@ FORMS += \ | |||
|     Src/Gui/SelectFields.ui \ | ||||
|     Src/Gui/YaraRuleSelectionDialog.ui \ | ||||
|     Src/Gui/DataCopyDialog.ui \ | ||||
|     Src/Gui/EntropyDialog.ui | ||||
|     Src/Gui/EntropyDialog.ui \ | ||||
|     Src/Gui/AssembleDialog.ui | ||||
| 
 | ||||
| ## | ||||
| ## Libraries | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue