1
0
Fork 0

Compare commits

...

89 Commits

Author SHA1 Message Date
Duncan Ogilvie caa578a029 Add more descriptive error messages in the trace browser 2024-02-19 03:10:42 +01:00
Duncan Ogilvie d08913bc54 Support copying in the StdTable with multiple items selected 2024-02-19 03:10:17 +01:00
Duncan Ogilvie da43aca116 Fix a few compilation warnings in the GUI 2024-02-19 03:09:53 +01:00
Duncan Ogilvie 7a3851a607 Fix a bug in the vardel command 2024-02-19 03:08:45 +01:00
Duncan Ogilvie a5f73b479f Also implement the syscall.id expression function 2024-02-19 03:08:29 +01:00
Duncan Ogilvie 9e4c1a4d26 Add a syscall.name expression function 2024-02-19 02:29:08 +01:00
Duncan Ogilvie 517a855e9a Refresh the table after reordering the columns 2024-01-07 18:19:59 +01:00
Duncan Ogilvie f3cb3443d1 Print NTSTATUS value in info box 2024-01-06 21:23:08 +01:00
Duncan Ogilvie c3642c35be Fix a bug in zydis_wrapper
Introduced in #3192
2024-01-06 21:21:56 +01:00
Duncan Ogilvie 399b19f847 Keep loaddll running after the DLL is loaded
See #3294
2024-01-06 20:07:18 +01:00
Duncan Ogilvie 9c07d82dc8 Replace broken line breaking in goto dialog with tooltip 2024-01-06 01:31:19 +01:00
Duncan Ogilvie a6e448b598 Truncate first line of disassembly popup to 100 characters 2024-01-06 01:30:36 +01:00
Duncan Ogilvie ec9a2a2af1
Merge pull request #3300 from torusrxxx/patch000000fe
Save module party
2024-01-05 22:25:17 +01:00
Duncan Ogilvie 9f6d396c4e
Merge pull request #3298 from torusrxxx/patch000000fd
Add symbol online search to symbol view
2024-01-05 22:23:01 +01:00
torusrxxx a006d75ee5
fix VS2013 2023-12-30 11:23:07 +08:00
torusrxxx e30a70ad4d
Save module party 2023-12-29 20:36:50 +08:00
torusrxxx 8cb5459629
Add symbol online search to symbol view 2023-12-29 16:26:48 +08:00
Duncan Ogilvie b683fc6a59
Merge pull request #3278 from foralost/3051_Switch__to_thread_handles
#3051: Follow a thread from handles window
2023-12-21 21:33:38 +01:00
Duncan Ogilvie 62129b426e
Merge pull request #3292 from foralost/3134_Highlight_mode_NOP
#3134: Avoiding having space in MnemonicNop instruction
2023-12-21 21:31:23 +01:00
foralost 9ed6033fb6 Avoiding having space in MnemonicNop instruction 2023-12-18 12:25:30 +01:00
Duncan Ogilvie afb5ac45c5 Simplify the showthreadid command 2023-12-18 00:44:24 +01:00
foralost ab9c28549a Switch to Thread from Handles: getCellUserdata fix 2023-12-17 00:03:29 +01:00
foralost 0853cafadc
Merge branch 'x64dbg:development' into 3051_Switch__to_thread_handles 2023-12-16 15:51:39 +01:00
Duncan Ogilvie 81bc337e52 Implement getCellUserdata 2023-12-15 20:32:47 +01:00
Duncan Ogilvie ee13290541 Add support for getCellUserdata in StdSearchListView 2023-12-15 20:32:47 +01:00
Duncan Ogilvie 04c5050015
Merge pull request #3285 from x64dbg/ui-lagging
Fix UI lagging
2023-12-04 17:45:57 +01:00
Duncan Ogilvie e2093d2d89
Merge pull request #3283 from torusrxxx/patch000000fc
Double click to follow wndproc
2023-11-28 08:37:19 +01:00
Duncan Ogilvie 3eb2070c3a Remove some performance bottlenecks from the memory map update
Thanks to @AnthonyPrintup for bringing this to my attention
2023-11-27 23:11:12 +01:00
Duncan Ogilvie f56fa5ce23 Delay at least 100ms between individual UI updates
Thanks to @JustasMasiulis for the help!
2023-11-27 23:09:19 +01:00
torusrxxx aa85488fe5
double click to follow window proc 2023-11-27 11:33:34 +08:00
foralost 911329e8e6 Keeping the style (nice icons) for the CallStackView 2023-11-26 18:16:02 +01:00
foralost 03baaa1ae3 Adding Follow in Threads option and setting the Thread ID 2023-11-26 18:15:45 +01:00
Duncan Ogilvie b17fc86af7
Merge pull request #3281 from foralost/3238_File_does_not_exists_bracket
#3238: Escaping { from any command argument
2023-11-26 17:16:12 +01:00
Duncan Ogilvie 93ac4548f7
Merge pull request #3275 from torusrxxx/patch000000fb
fix No such signal in graph view
2023-11-26 17:13:17 +01:00
Duncan Ogilvie 03c6f3b6a5
Merge pull request #3277 from ZehMatt/optimize-pagerights
Optimize Page Rights UI
2023-11-26 17:12:35 +01:00
foralost 16fccbd2d4 God forgive me: Escaping { from file path for init 2023-11-26 11:02:05 +01:00
ζeh Matt 050c989dc3
Improve performance for deselection a large amount 2023-11-24 17:52:15 +02:00
ζeh Matt 218d784a7e
Optimize select all for the PageMemoryRights UI 2023-11-24 17:52:12 +02:00
torusrxxx f8567b59f5
Modify various functions in graph view with const 2023-11-21 15:51:54 +08:00
torusrxxx eff762460f
fix No such signal 2023-11-21 15:42:14 +08:00
Duncan Ogilvie 570aaea06d
Merge pull request #3272 from GermanAizek/fix-numa
Fixed get count threads for multi-cpu system with NUMA architecture
2023-11-18 19:38:30 +01:00
Duncan Ogilvie d2f6ba72cc Clean up GetThreadCount for XP 2023-11-18 17:47:21 +01:00
Duncan Ogilvie 61814b2da7
Merge pull request #3271 from torusrxxx/patch000000fa
Auto switch thread when following callstack
2023-11-18 02:22:40 +01:00
torusrxxx 715831637a Auto switch thread when following callstack 2023-11-18 02:22:17 +01:00
Duncan Ogilvie 01c239534a
Merge pull request #3260 from foralost/3163-Long_symbol_name
#3163: Long symbol name
2023-11-18 02:16:47 +01:00
Duncan Ogilvie 2747f72f38
Merge pull request #3264 from leetfin/development
Use gender neutral language
2023-11-18 02:15:38 +01:00
Duncan Ogilvie 4193000159
Merge pull request #3263 from habipakyol/patch-1
Fix typo in CPUMultiDump.cpp
2023-11-18 02:15:01 +01:00
Duncan Ogilvie a320227378
Merge pull request #3262 from foralost/3232-follow_rename_thread_callstack
#3232: Providing Rename Thread and etc. for CallStack View
2023-11-18 02:14:25 +01:00
Duncan Ogilvie 7c2276681a Clean up the thread renaming a bit 2023-11-18 02:13:51 +01:00
Duncan Ogilvie b2b104b79f Introduce DbgCmdEscape 2023-11-18 02:13:51 +01:00
Duncan Ogilvie 95b790eab1 Rename addr_text to addrText 2023-11-18 02:13:47 +01:00
German Semenov eeab4c47ed Fixed get count threads for multi-cpu system with NUMA architecture 2023-11-14 17:20:32 +03:00
Duncan Ogilvie 373b3a538f Disable core.autocrlf for all files 2023-11-14 12:50:42 +01:00
Duncan Ogilvie 44c3d39165 Allow strings in the ternary expression function 2023-11-13 01:30:36 +01:00
Duncan Ogilvie 923b894df2 Fix wraparound in disassembly (thanks @shocoman)
Closes #3228
2023-11-12 23:04:19 +01:00
foralost c9d80e5c99 Introducing showthreadid command
Additional options in CallStackView
2023-11-08 18:04:50 +01:00
Duncan Ogilvie 65d57bfd2e Quote the result of a string expression function in the log 2023-11-07 18:18:58 +01:00
Duncan Ogilvie 2e1fd1f289 Add optional count argument to the string expression functions 2023-11-07 18:18:58 +01:00
Duncan Ogilvie b84c293f15 Implement optional arguments for expression functions 2023-11-07 18:18:58 +01:00
Duncan Ogilvie 50d7d988f6 Store the number of expression function arguments in the token 2023-11-07 18:18:58 +01:00
Duncan Ogilvie 735d3ca5f9 Escape logged strings returned from expression functions 2023-11-07 18:18:58 +01:00
Duncan Ogilvie dfda450b41 Allow printing empty strings using the "{s:addr}" format 2023-11-07 18:18:58 +01:00
Duncan Ogilvie 49f9487a59 Allow zero-sized string for utf16/utf8 format type 2023-11-07 18:18:56 +01:00
Duncan Ogilvie 7f9dc7fc04 Allow reading/writing 0 bytes of memory 2023-11-07 18:16:16 +01:00
Duncan Ogilvie 50fc52b0d2 Fix a bug where setTableOffset(0) did nothing
Closes #3254
2023-11-02 17:24:45 +01:00
Duncan Ogilvie 61f99ae5c9 Clean up the code in SearchListView 2023-11-02 17:24:11 +01:00
Duncan Ogilvie e3e6a8a9fa Fix signal connection issues in ReferenceView
Leftovers from the refactor of int -> duint
2023-11-02 17:23:48 +01:00
Duncan Ogilvie 8ae5982502 Delete unused ZydisExportConfig.h 2023-11-02 00:34:20 +01:00
Leet f4821ce331 fix weird character problem 2023-10-31 15:51:32 +00:00
Leet de527241cd
Merge branch 'x64dbg:development' into development 2023-10-31 15:49:53 +00:00
Habip Akyol a2594cf1f9
Fix typo in CPUMultiDump.cpp 2023-10-31 13:30:37 +03:00
Duncan Ogilvie 0f54d5ebcd
Merge pull request #3261 from ruslangaripov/fix_a_typo
Fix a typo
2023-10-30 18:20:49 +01:00
Ruslan Garipov d52466f981
Fix a typo
Signed-off-by: Ruslan Garipov <ruslanngaripov@gmail.com>
2023-10-30 22:00:03 +05:00
Marek Szwajka 4945c36e85 Formatting 2023-10-30 11:18:25 +01:00
foralost 0f39191c9d
Fixing character skipping 2023-10-30 10:54:33 +01:00
foralost 81d72252a8 Formatting 2023-10-29 23:39:57 +01:00
foralost c122eb9e1d Limited window size and dynamic height of errorLabel 2023-10-29 23:26:57 +01:00
Duncan Ogilvie b0392eda1c
Merge pull request #3240 from HayFieldLaps/find-pattern-ranges
Find Pattern searches now begin at start of current region
2023-10-28 15:17:38 +02:00
Duncan Ogilvie d0fb3a0b88
Merge pull request #3250 from shocoman/fix-edit-bp-dialog-bug
Fixed a bug in the Edit Breakpoint dialog that might erase double quotes
2023-10-28 15:17:21 +02:00
Duncan Ogilvie cb31cbd83b
Merge pull request #3251 from lhmouse/development
Make error messages clearer if x96dbg fails to open a file
2023-10-28 15:16:55 +02:00
Duncan Ogilvie 99f5e93592
Merge pull request #3239 from stdust/patch-1
Update HexEditDialog.ui
2023-10-28 15:16:28 +02:00
LIU Hao e9dfe3020e
Make error messages clearer if x96dbg fails to open a file
When x96dbg failed to open a file, it displayed a message box with the path as the message and a reason string as the caption. This looks weird, as the caption conveys useful information but it can usually be truncated.

We should display the reason string as the message, and the path as the caption instead.
2023-10-27 00:17:32 +08:00
shocoman 98d08ce826 Make the Edit Breakpoint dialog resizable horizontally 2023-10-26 02:08:23 +07:00
shocoman 17bd183de2 Fixed a bug in the Edit Breakpoint dialog that might erase double quotes
#3248
2023-10-26 02:08:07 +07:00
Leet 89aee8ad5b Use gender neutral language 2023-10-24 15:59:18 +00:00
dad 7dade58481 Add Start from Selection 2023-10-23 11:10:59 -06:00
dad ca637fad33 Find Pattern searches now begin at start of current region 2023-10-12 10:37:51 -06:00
stdust e5dba0ad63
Update HexEditDialog.ui 2023-10-11 15:43:04 +09:00
stdust 3409444e33
Update HexEditDialog.u
HexEditDialog's tab orders have been assigned to code for less frequently used codepages and to keep size, etc
so unnecessary tab orders should be deleted
2023-10-11 15:25:03 +09:00
100 changed files with 1730 additions and 792 deletions

2
.gitattributes vendored Normal file
View File

@ -0,0 +1,2 @@
# Disable core.autocrlf (https://stackoverflow.com/a/52996849/1806760)
* -text

View File

@ -1779,6 +1779,12 @@ BRIDGE_IMPEXP void GuiMenuSetEntryHotkey(int hEntry, const char* hack)
_gui_sendmessage(GUI_MENU_SET_ENTRY_HOTKEY, (void*)hEntry, (void*)hack);
}
BRIDGE_IMPEXP void GuiShowThreads()
{
_gui_sendmessage(GUI_SHOW_THREADS, 0, 0);
}
BRIDGE_IMPEXP void GuiShowCpu()
{
_gui_sendmessage(GUI_SHOW_CPU, 0, 0);

View File

@ -1152,6 +1152,7 @@ typedef enum
GUI_GRAPH,
GUI_MEMMAP,
GUI_SYMMOD,
GUI_THREADS,
} GUISELECTIONTYPE;
#define GUI_MAX_LINE_SIZE 65536
@ -1281,6 +1282,7 @@ typedef enum
GUI_SAVE_LOG, // param1=const char* file name,param2=unused
GUI_REDIRECT_LOG, // param1=const char* file name,param2=unused
GUI_STOP_REDIRECT_LOG, // param1=unused, param2=unused
GUI_SHOW_THREADS, // param1=unused, param2=unused
} GUIMSG;
//GUI Typedefs
@ -1423,6 +1425,7 @@ BRIDGE_IMPEXP void GuiMenuSetName(int hMenu, const char* name);
BRIDGE_IMPEXP void GuiMenuSetEntryName(int hEntry, const char* name);
BRIDGE_IMPEXP void GuiMenuSetEntryHotkey(int hEntry, const char* hack);
BRIDGE_IMPEXP void GuiShowCpu();
BRIDGE_IMPEXP void GuiShowThreads();
BRIDGE_IMPEXP void GuiAddQWidgetTab(void* qWidget);
BRIDGE_IMPEXP void GuiShowQWidgetTab(void* qWidget);
BRIDGE_IMPEXP void GuiCloseQWidgetTab(void* qWidget);

View File

@ -1513,7 +1513,7 @@ extern "C" DLL_EXPORT duint _dbg_sendmessage(DBGMSG type, void* param1, void* pa
case DBG_GET_STRING_AT:
{
return disasmgetstringatwrapper(duint(param1), (char*)param2);
return disasmgetstringatwrapper(duint(param1), (char*)param2, true);
}
break;

View File

@ -3,10 +3,12 @@
\brief Implements the global class.
*/
#include <windows.h>
#include "_global.h"
#include <objbase.h>
#include <shlobj.h>
#include <psapi.h>
#include <thread>
#include "DeviceNameResolver/DeviceNameResolver.h"
/**
@ -393,3 +395,53 @@ void WaitForMultipleThreadsTermination(const HANDLE* hThread, int count, DWORD t
for(int i = 0; i < count; i++)
CloseHandle(hThread[i]);
}
// This implementation supports both conventional single-cpu PC configurations
// and multi-cpu system on NUMA (Non-uniform_memory_access) architecture
// Original code from here: https://developercommunity.visualstudio.com/t/hardware-concurrency-returns-an-incorrect-result/350854
duint GetThreadCount()
{
duint threadCount = std::thread::hardware_concurrency();
typedef BOOL(*WINAPI GetLogicalProcessorInformationEx_t)(
LOGICAL_PROCESSOR_RELATIONSHIP,
PSYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX,
PDWORD
);
static auto p_GetLogicalProcessorInformationEx = (GetLogicalProcessorInformationEx_t)GetProcAddress(GetModuleHandleW(L"kernel32.dll"), "GetLogicalProcessorInformationEx");
if(p_GetLogicalProcessorInformationEx == nullptr)
{
return threadCount;
}
DWORD length = 0;
if(p_GetLogicalProcessorInformationEx(RelationAll, nullptr, &length) || GetLastError() != ERROR_INSUFFICIENT_BUFFER)
{
return threadCount;
}
std::vector<uint8_t> buffer(length);
if(!p_GetLogicalProcessorInformationEx(RelationAll, (PSYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX)buffer.data(), &length))
{
return threadCount;
}
threadCount = 0;
for(DWORD offset = 0; offset < length;)
{
auto info = (PSYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX)(buffer.data() + offset);
if(info->Relationship == RelationProcessorCore)
{
for(WORD group = 0; group < info->Processor.GroupCount; ++group)
{
for(KAFFINITY mask = info->Processor.GroupMask[group].Mask; mask != 0; mask >>= 1)
{
threadCount += mask & 1;
}
}
}
offset += info->Size;
}
return threadCount;
}

View File

@ -65,6 +65,7 @@ bool IsWow64();
bool ResolveShortcut(HWND hwnd, const wchar_t* szShortcutPath, std::wstring & executable, std::wstring & arguments, std::wstring & workingDir);
void WaitForThreadTermination(HANDLE hThread, DWORD timeout = INFINITE);
void WaitForMultipleThreadsTermination(const HANDLE* hThread, int count, DWORD timeout = INFINITE);
duint GetThreadCount();
#ifdef _WIN64
#define ArchValue(x32value, x64value) x64value

View File

@ -240,7 +240,11 @@ typedef enum
{
ValueTypeNumber,
ValueTypeString,
ValueTypeAny, // Cannot be used for values, only for argTypes (to accept any type)
// Types below cannot be used for values, only for registration
ValueTypeAny,
ValueTypeOptionalNumber,
ValueTypeOptionalString,
ValueTypeOptionalAny,
} ValueType;
typedef struct

View File

@ -77,7 +77,7 @@ duint AnalysisPass::IdealThreadCount()
if(m_InternalMaxThreads == 0)
{
// Determine the maximum hardware thread count at once
duint maximumThreads = max(std::thread::hardware_concurrency(), 1);
duint maximumThreads = max(GetThreadCount(), 1);
// Don't consume 100% of the CPU, adjust accordingly
if(maximumThreads > 1)

View File

@ -8,6 +8,26 @@
#include "value.h"
#include "variable.h"
bool cbShowThreadId(int argc, char* argv[])
{
if(argc > 1)
{
duint threadId = 0;
if(!valfromstring(argv[1], &threadId, false))
return false;
SELECTIONDATA newSelection = { threadId, threadId };
if(!GuiSelectionSet(GUI_THREADS, &newSelection))
{
dprintf(QT_TRANSLATE_NOOP("DBG", "Invalid thread %s\n"), formatpidtid((DWORD)threadId).c_str());
return false;
}
}
GuiShowThreads();
return true;
}
bool cbDebugDisasm(int argc, char* argv[])
{
duint addr = 0;

View File

@ -2,6 +2,7 @@
#include "command.h"
bool cbShowThreadId(int argc, char* argv[]);
bool cbDebugDisasm(int argc, char* argv[]);
bool cbDebugDump(int argc, char* argv[]);
bool cbDebugStackDump(int argc, char* argv[]);

View File

@ -29,7 +29,8 @@ bool cbBadCmd(int argc, char* argv[])
{
if(evalue.isString)
{
dputs_untranslated(StringUtils::Escape(evalue.data).c_str());
varset("$ans", evalue.data.c_str(), true);
dprintf_untranslated("\"%s\"\n", StringUtils::Escape(evalue.data).c_str());
}
else if(evalue.DoEvaluate(value, silent, baseonly, &valsize, &isvar, &hexonly))
{

View File

@ -51,7 +51,7 @@ bool cbInstrVarDel(int argc, char* argv[])
{
if(IsArgumentsLessThan(argc, 2))
return false;
if(!vardel(argv[1], false))
if(vardel(argv[1], false) != 0)
dprintf(QT_TRANSLATE_NOOP("DBG", "Could not delete variable \"%s\"\n"), argv[1]);
else
dprintf(QT_TRANSLATE_NOOP("DBG", "Deleted variable \"%s\"\n"), argv[1]);

View File

@ -71,6 +71,7 @@ void DbSave(DbLoadSaveType saveType, const char* dbfile, bool disablecompression
EncodeMapCacheSave(root);
TraceRecord.saveToDb(root);
BpCacheSave(root);
ModCacheSave(root);
WatchCacheSave(root);
//save notes
@ -91,7 +92,7 @@ void DbSave(DbLoadSaveType saveType, const char* dbfile, bool disablecompression
//plugin data
PLUG_CB_LOADSAVEDB pluginSaveDb;
// Some plugins may wish to change this value so that all plugins after his or her plugin will save data into plugin-supplied storage instead of the system's.
// Some plugins may wish to change this value so that all plugins after their plugin will save data into plugin-supplied storage instead of the system's.
// We back up this value so that the debugger is not fooled by such plugins.
JSON pluginRoot = json_object();
pluginSaveDb.root = pluginRoot;
@ -283,6 +284,7 @@ void DbLoad(DbLoadSaveType loadType, const char* dbfile)
EncodeMapCacheLoad(root);
TraceRecord.loadFromDb(root);
BpCacheLoad(root, migrateBreakpoints);
ModCacheLoad(root);
WatchCacheLoad(root);
// Load notes
@ -340,6 +342,7 @@ void DbClear(bool terminating)
EncodeMapClear();
TraceRecord.clear();
BpClear();
ModCacheClear();
WatchClear();
GuiSetDebuggeeNotes("");

View File

@ -13,7 +13,7 @@ void disasmget(unsigned char* buffer, duint addr, DISASM_INSTR* instr, bool getr
void disasmget(duint addr, DISASM_INSTR* instr, bool getregs = true);
bool disasmispossiblestring(duint addr, STRING_TYPE* type = nullptr);
bool disasmgetstringat(duint addr, STRING_TYPE* type, char* ascii, char* unicode, int maxlen);
bool disasmgetstringatwrapper(duint addr, char* text, bool cache = true);
bool disasmgetstringatwrapper(duint addr, char* text, bool cache);
int disasmgetsize(duint addr, unsigned char* data);
int disasmgetsize(duint addr);

View File

@ -13,6 +13,7 @@ static std::unordered_map<unsigned int, String> NtStatusNames;
static std::unordered_map<unsigned int, String> ErrorNames;
static std::unordered_map<String, unsigned int> Constants;
static std::unordered_map<unsigned int, String> SyscallIndices;
static std::unordered_map<String, unsigned int> SyscallNames;
static bool UniversalCodeInit(const String & file, std::unordered_map<unsigned int, String> & names, unsigned char radix)
{
@ -253,12 +254,43 @@ bool SyscallInit()
SyscallIndices.insert({ index, syscall.Name });
}
}
ModClear(false);
// Populate the name map
for(const auto & itr : SyscallIndices)
{
SyscallNames.emplace(itr.second, itr.first);
}
// Also allow lookup with only the least significant 14 bits
// Reference: https://alice.climent-pommeret.red/posts/a-syscall-journey-in-the-windows-kernel/
for(const auto & itr : SyscallIndices)
{
auto truncated = itr.first & 0x3FFF;
if(truncated != itr.first)
{
SyscallIndices.emplace(truncated, itr.second);
}
}
// Clear the GUI
ModClear(true);
return result;
}
const String & SyscallToName(unsigned int index)
{
auto found = SyscallIndices.find(index);
auto found = SyscallIndices.find(index & 0x3FFF);
return found != SyscallIndices.end() ? found->second : emptyString;
}
}
unsigned int SyscallToId(const String & name)
{
if(name.find("Zw") == 0)
{
return SyscallToId("Nt" + name.substr(2));
}
auto found = SyscallNames.find(name);
return found != SyscallNames.end() ? found->second : -1;
}

View File

@ -22,5 +22,6 @@ std::vector<CONSTANTINFO> ConstantList();
// To use this function, use EXCLUSIVE_ACQUIRE(LockModules)
bool SyscallInit();
const String & SyscallToName(unsigned int index);
unsigned int SyscallToId(const String & name);
#endif // _EXCEPTION_H

View File

@ -71,7 +71,7 @@ void ExpressionFunctions::Init()
RegisterEasy("mod.offset,mod.fileoffset", valvatofileoffset);
RegisterEasy("mod.headerva", modheaderva);
RegisterEasy("mod.isexport", modisexport);
ExpressionFunctions::Register("mod.fromname", ValueTypeNumber, { ValueTypeString }, Exprfunc::modbasefromname, nullptr);
ExpressionFunctions::Register("mod.fromname", ValueTypeNumber, { ValueTypeString }, Exprfunc::modbasefromname);
//Process information
RegisterEasy("peb,PEB", peb);
@ -81,7 +81,7 @@ void ExpressionFunctions::Init()
//General purpose
RegisterEasy("bswap", bswap);
RegisterEasy("ternary,tern", ternary);
ExpressionFunctions::Register("ternary,tern", ValueTypeAny, { ValueTypeNumber, ValueTypeAny, ValueTypeAny }, ternary);
RegisterEasy("GetTickCount,gettickcount", gettickcount);
RegisterEasy("rdtsc", rdtsc);
@ -110,9 +110,9 @@ void ExpressionFunctions::Init()
RegisterEasy("dis.next", disnext);
RegisterEasy("dis.prev", disprev);
RegisterEasy("dis.iscallsystem", disiscallsystem);
ExpressionFunctions::Register("dis.mnemonic", ValueTypeString, { ValueTypeNumber }, Exprfunc::dismnemonic, nullptr);
ExpressionFunctions::Register("dis.text", ValueTypeString, { ValueTypeNumber }, Exprfunc::distext, nullptr);
ExpressionFunctions::Register("dis.match", ValueTypeNumber, { ValueTypeNumber, ValueTypeString }, Exprfunc::dismatch, nullptr);
ExpressionFunctions::Register("dis.mnemonic", ValueTypeString, { ValueTypeNumber }, dismnemonic);
ExpressionFunctions::Register("dis.text", ValueTypeString, { ValueTypeNumber }, distext);
ExpressionFunctions::Register("dis.match", ValueTypeNumber, { ValueTypeNumber, ValueTypeString }, dismatch);
//Trace record
RegisterEasy("tr.enabled", trenabled);
@ -158,17 +158,20 @@ void ExpressionFunctions::Init()
RegisterEasy("isdebuggeefocused", isdebuggeefocused);
// Strings
ExpressionFunctions::Register("ansi", ValueTypeString, { ValueTypeNumber }, Exprfunc::ansi, nullptr);
ExpressionFunctions::Register("ansi.strict", ValueTypeString, { ValueTypeNumber }, Exprfunc::ansi_strict, nullptr);
ExpressionFunctions::Register("utf8", ValueTypeString, { ValueTypeNumber }, Exprfunc::utf8, nullptr);
ExpressionFunctions::Register("utf8.strict", ValueTypeString, { ValueTypeNumber }, Exprfunc::utf8_strict, nullptr);
ExpressionFunctions::Register("utf16", ValueTypeString, { ValueTypeNumber }, Exprfunc::utf16, nullptr);
ExpressionFunctions::Register("utf16.strict", ValueTypeString, { ValueTypeNumber }, Exprfunc::utf16_strict, nullptr);
ExpressionFunctions::Register("strstr", ValueTypeNumber, { ValueTypeString, ValueTypeString }, Exprfunc::strstr, nullptr);
ExpressionFunctions::Register("stristr", ValueTypeNumber, { ValueTypeString, ValueTypeString }, Exprfunc::stristr, nullptr);
ExpressionFunctions::Register("streq", ValueTypeNumber, { ValueTypeString, ValueTypeString }, Exprfunc::streq, nullptr);
ExpressionFunctions::Register("strieq", ValueTypeNumber, { ValueTypeString, ValueTypeString }, Exprfunc::strieq, nullptr);
ExpressionFunctions::Register("strlen", ValueTypeNumber, { ValueTypeString }, Exprfunc::strlen, nullptr);
ExpressionFunctions::Register("ansi", ValueTypeString, { ValueTypeNumber, ValueTypeOptionalNumber }, Exprfunc::ansi);
ExpressionFunctions::Register("ansi.strict", ValueTypeString, { ValueTypeNumber, ValueTypeOptionalNumber }, Exprfunc::ansi_strict);
ExpressionFunctions::Register("utf8", ValueTypeString, { ValueTypeNumber, ValueTypeOptionalNumber }, Exprfunc::utf8);
ExpressionFunctions::Register("utf8.strict", ValueTypeString, { ValueTypeNumber, ValueTypeOptionalNumber }, Exprfunc::utf8_strict);
ExpressionFunctions::Register("utf16", ValueTypeString, { ValueTypeNumber, ValueTypeOptionalNumber }, Exprfunc::utf16);
ExpressionFunctions::Register("utf16.strict", ValueTypeString, { ValueTypeNumber, ValueTypeOptionalNumber }, Exprfunc::utf16_strict);
ExpressionFunctions::Register("strstr", ValueTypeNumber, { ValueTypeString, ValueTypeString }, Exprfunc::strstr);
ExpressionFunctions::Register("stristr", ValueTypeNumber, { ValueTypeString, ValueTypeString }, Exprfunc::stristr);
ExpressionFunctions::Register("streq", ValueTypeNumber, { ValueTypeString, ValueTypeString }, Exprfunc::streq);
ExpressionFunctions::Register("strieq", ValueTypeNumber, { ValueTypeString, ValueTypeString }, Exprfunc::strieq);
ExpressionFunctions::Register("strlen", ValueTypeNumber, { ValueTypeString }, Exprfunc::strlen);
ExpressionFunctions::Register("syscall.name", ValueTypeString, { ValueTypeNumber }, Exprfunc::syscall_name);
ExpressionFunctions::Register("syscall.id", ValueTypeNumber, { ValueTypeString }, Exprfunc::syscall_id);
}
bool ExpressionFunctions::Register(const String & name, const ValueType & returnType, const std::vector<ValueType> & argTypes, const CBEXPRESSIONFUNCTION & cbFunction, void* userdata)
@ -180,10 +183,39 @@ bool ExpressionFunctions::Register(const String & name, const ValueType & return
if(mFunctions.count(aliases[0]))
return false;
// Return type cannot be optional
switch(returnType)
{
case ValueTypeOptionalNumber:
case ValueTypeOptionalString:
case ValueTypeOptionalAny:
return false;
default:
break;
}
// Make sure optional arguments are at the end
bool seenOptional = false;
for(const auto & argType : argTypes)
{
switch(argType)
{
case ValueTypeOptionalNumber:
case ValueTypeOptionalString:
case ValueTypeOptionalAny:
seenOptional = true;
break;
default:
if(seenOptional)
return false;
break;
}
}
Function f;
f.name = aliases[0];
f.argTypes = argTypes;
f.returnType = returnType;
f.argTypes = argTypes;
f.cbFunction = cbFunction;
f.userdata = userdata;
mFunctions[aliases[0]] = f;
@ -228,13 +260,6 @@ bool ExpressionFunctions::Call(const String & name, ExpressionValue & result, st
if(found == mFunctions.end())
return false;
const auto & f = found->second;
if(f.argTypes.size() != int(argv.size()))
return false;
for(size_t i = 0; i < argv.size(); i++)
{
if(argv[i].type != f.argTypes[i] && f.argTypes[i] != ValueTypeAny)
return false;
}
return f.cbFunction(&result, (int)argv.size(), argv.data(), f.userdata);
}

View File

@ -141,6 +141,15 @@ ExpressionParser::ExpressionParser(const String & expression)
mTokens.reserve(r);
mCurToken.reserve(r);
tokenize();
#if 0
// Print the tokens for debugging
dprintf_untranslated("'%s':\n", expression.c_str());
for(const auto & token : mTokens)
{
dprintf_untranslated(" % 2d '%s'\n", token.type(), token.data().c_str());
}
dprintf_untranslated("\n");
#endif
shuntingYard();
}
@ -215,10 +224,10 @@ void ExpressionParser::tokenize()
addOperatorToken(ch, Token::Type::Comma);
break;
case '(':
addOperatorToken(ch, Token::Type::OpenBracket);
addOperatorToken(ch, Token::Type::OpenParen);
break;
case ')':
addOperatorToken(ch, Token::Type::CloseBracket);
addOperatorToken(ch, Token::Type::CloseParen);
break;
case '~':
addOperatorToken(ch, Token::Type::OperatorNot);
@ -367,7 +376,14 @@ void ExpressionParser::addOperatorToken(const String & data, Token::Type type)
{
if(mCurToken.length()) //add a new data token when there is data in the buffer
{
mTokens.push_back(Token(mCurToken, type == Token::Type::OpenBracket ? Token::Type::Function : resolveQuotedData()));
if(type == Token::Type::OpenParen)
{
mTokens.push_back(Token(mCurToken, Token::Type::Function));
}
else
{
mTokens.push_back(Token(mCurToken, resolveQuotedData()));
}
mCurToken.clear();
mCurTokenQuoted.clear();
}
@ -388,7 +404,7 @@ bool ExpressionParser::isUnaryOperator() const
return true;
auto lastType = mTokens.back().type();
//if the previous token is not data or a close bracket, this operator is a unary operator
return lastType != Token::Type::Data && lastType != Token::Type::QuotedData && lastType != Token::Type::CloseBracket;
return lastType != Token::Type::Data && lastType != Token::Type::QuotedData && lastType != Token::Type::CloseParen;
}
void ExpressionParser::shuntingYard()
@ -396,6 +412,7 @@ void ExpressionParser::shuntingYard()
//Implementation of Dijkstra's Shunting-yard algorithm (https://en.wikipedia.org/wiki/Shunting-yard_algorithm)
std::vector<Token> queue;
std::vector<Token> stack;
std::vector<duint> argCount;
auto len = mTokens.size();
queue.reserve(len);
stack.reserve(len);
@ -410,9 +427,18 @@ void ExpressionParser::shuntingYard()
queue.push_back(token);
break;
case Token::Type::Function: //If the token is a function token, then push it onto the stack.
{
stack.push_back(token);
break;
// Unless the syntax is 'fn()' there is always at least one argument
if(i + 2 < mTokens.size() && mTokens[i + 1].type() == Token::Type::OpenParen && mTokens[i + 2].type() == Token::Type::CloseParen)
argCount.push_back(0);
else
argCount.push_back(1);
}
break;
case Token::Type::Comma: //If the token is a function argument separator (e.g., a comma):
{
while(true) //Until the token at the top of the stack is a left parenthesis, pop operators off the stack onto the output queue.
{
if(stack.empty()) //If no left parentheses are encountered, either the separator was misplaced or parentheses were mismatched.
@ -421,16 +447,20 @@ void ExpressionParser::shuntingYard()
return;
}
const auto & curToken = stack.back();
if(curToken.type() == Token::Type::OpenBracket)
if(curToken.type() == Token::Type::OpenParen)
break;
queue.push_back(curToken);
stack.pop_back();
}
break;
case Token::Type::OpenBracket: //If the token is a left parenthesis (i.e. "("), then push it onto the stack.
if(!argCount.empty()) // A comma increases the argument count
argCount.back()++;
}
break;
case Token::Type::OpenParen: //If the token is a left parenthesis (i.e. "("), then push it onto the stack.
stack.push_back(token);
break;
case Token::Type::CloseBracket: //If the token is a right parenthesis (i.e. ")"):
case Token::Type::CloseParen: //If the token is a right parenthesis (i.e. ")"):
{
while(true) //Until the token at the top of the stack is a left parenthesis, pop operators off the stack onto the output queue.
{
@ -441,14 +471,16 @@ void ExpressionParser::shuntingYard()
}
auto curToken = stack.back();
stack.pop_back(); //Pop the left parenthesis from the stack, but not onto the output queue.
if(curToken.type() == Token::Type::OpenBracket) //the bracket is already popped here
if(curToken.type() == Token::Type::OpenParen) //the bracket is already popped here
break;
queue.push_back(curToken);
}
auto size = stack.size();
if(size && stack[size - 1].type() == Token::Type::Function) //If the token at the top of the stack is a function token, pop it onto the output queue.
if(!stack.empty() && stack.back().type() == Token::Type::Function) //If the token at the top of the stack is a function token, pop it onto the output queue.
{
queue.push_back(stack[size - 1]);
// Propagate the argument count as extra information
stack.back().setInfo(argCount.back());
argCount.pop_back();
queue.push_back(stack.back());
stack.pop_back();
}
}
@ -476,7 +508,7 @@ void ExpressionParser::shuntingYard()
while(!stack.empty()) //While there are still operator tokens in the stack:
{
const auto & curToken = stack.back();
if(curToken.type() == Token::Type::OpenBracket || curToken.type() == Token::Type::CloseBracket) //If the operator token on the top of the stack is a parenthesis, then there are mismatched parentheses.
if(curToken.type() == Token::Type::OpenParen || curToken.type() == Token::Type::CloseParen) //If the operator token on the top of the stack is a parenthesis, then there are mismatched parentheses.
{
mIsValidExpression = false;
return;
@ -907,108 +939,203 @@ bool ExpressionParser::Calculate(EvalValue & value, bool signedcalc, bool allowa
else if(token.type() == Token::Type::Function)
{
const auto & name = token.data();
const auto argCount = token.info();
ValueType returnType;
std::vector<ValueType> argTypes;
if(!ExpressionFunctions::GetType(name, returnType, argTypes))
return false;
if(int(stack.size()) < argTypes.size())
return false;
std::vector<ExpressionValue> argv;
argv.resize(argTypes.size());
for(size_t i = 0; i < argTypes.size(); i++)
{
const auto & argType = argTypes[argTypes.size() - i - 1];
auto & top = stack[stack.size() - i - 1];
ExpressionValue arg;
if(top.isString)
if(!silent)
dprintf(QT_TRANSLATE_NOOP("DBG", "No such expression function '%s'\n"), name.c_str());
return false;
}
size_t requiredArguments = 0;
for(const auto & argType : argTypes)
{
switch(argType)
{
arg = { ValueTypeString, 0, StringValue{ top.data.c_str(), false } };
case ValueTypeOptionalNumber:
case ValueTypeOptionalString:
case ValueTypeOptionalAny:
break;
default:
requiredArguments++;
break;
}
else if(top.evaluated)
}
auto typeName = [](ValueType t) -> String
{
switch(t)
{
arg = { ValueTypeNumber, top.value };
case ValueTypeOptionalNumber:
case ValueTypeNumber:
return GuiTranslateText(QT_TRANSLATE_NOOP("DBG", "number"));
case ValueTypeOptionalString:
case ValueTypeString:
return GuiTranslateText(QT_TRANSLATE_NOOP("DBG", "string"));
case ValueTypeOptionalAny:
case ValueTypeAny:
return GuiTranslateText(QT_TRANSLATE_NOOP("DBG", "any"));
}
return GuiTranslateText(QT_TRANSLATE_NOOP("DBG", "invalid"));
};
auto makeSignature = [&]()
{
String signature = name;
signature += "(";
for(size_t j = 0; j < argTypes.size(); j++)
{
if(j == requiredArguments)
{
signature += "[";
}
if(j > 0)
{
signature += ", ";
}
signature += typeName(argTypes[j]);
}
if(requiredArguments < argTypes.size())
{
signature += "]";
}
signature += ")";
return signature;
};
if(stack.size() < requiredArguments || argCount > argTypes.size())
{
if(!silent)
{
std::string expected;
if(requiredArguments == argTypes.size())
expected = StringUtils::sprintf("%d", (int)requiredArguments);
else
expected = StringUtils::sprintf("%d-%d", (int)requiredArguments, (int)argTypes.size());
dprintf(QT_TRANSLATE_NOOP("DBG", "Bad argument count for expression function %s (expected %s, got %d)!\n"),
makeSignature().c_str(),
expected.c_str(),
(int)argCount
);
}
return false;
}
std::vector<ExpressionValue> argv;
argv.resize(argCount);
for(size_t i = 0; i < argCount; i++)
{
// Get the expected (concrete) argument type
auto argType = argTypes[i];
switch(argType)
{
case ValueTypeOptionalNumber:
argType = ValueTypeNumber;
break;
case ValueTypeOptionalString:
argType = ValueTypeString;
break;
case ValueTypeOptionalAny:
argType = ValueTypeAny;
break;
default:
break;
}
auto & argEval = stack[stack.size() - argCount + i];
ExpressionValue argValue;
if(argEval.isString)
{
argValue = { ValueTypeString, 0, StringValue{ argEval.data.c_str(), false } };
}
else if(argEval.evaluated)
{
argValue = { ValueTypeNumber, argEval.value };
}
else
{
duint result;
if(!top.DoEvaluate(result, silent, baseonly, value_size, isvar, hexonly))
if(!argEval.DoEvaluate(result, silent, baseonly, value_size, isvar, hexonly))
return false;
arg = { ValueTypeNumber, result };
argValue = { ValueTypeNumber, result };
}
if(arg.type != argType && argType != ValueTypeAny)
if(argValue.type != argType && argType != ValueTypeAny)
{
if(!silent)
{
auto typeName = [](ValueType t) -> String
{
switch(t)
{
case ValueTypeNumber:
return GuiTranslateText(QT_TRANSLATE_NOOP("DBG", "number"));
case ValueTypeString:
return GuiTranslateText(QT_TRANSLATE_NOOP("DBG", "string"));
}
return GuiTranslateText(QT_TRANSLATE_NOOP("DBG", "invalid"));
};
String argValueStr;
if(arg.type == ValueTypeNumber)
if(argValue.type == ValueTypeNumber)
{
argValueStr = StringUtils::sprintf("0x%p", arg.number);
argValueStr = StringUtils::sprintf("0x%p", argValue.number);
}
else if(arg.type == ValueTypeString)
else if(argValue.type == ValueTypeString)
{
argValueStr = "\"" + StringUtils::Escape(arg.string.ptr) + "\"";
argValueStr = "\"" + StringUtils::Escape(argValue.string.ptr) + "\"";
}
else
{
argValueStr = "???";
}
String signature = name;
signature += "(";
for(size_t j = 0; j < argTypes.size(); j++)
{
if(j > 0)
{
signature += ", ";
}
signature += typeName(argTypes[j]);
}
signature += ")";
dprintf(QT_TRANSLATE_NOOP("DBG", "Expression function %s argument %d/%d (%s) type mismatch (expected %s, got %s)!\n"),
signature.c_str(),
argTypes.size() - i,
makeSignature().c_str(),
i + 1,
argTypes.size(),
argValueStr.c_str(),
typeName(argType).c_str(),
typeName(arg.type).c_str()
typeName(argValue.type).c_str()
);
}
return false;
}
argv[argTypes.size() - i - 1] = arg;
argv[i] = argValue;
}
ExpressionValue result = { ValueTypeNumber, 0 };
if(!ExpressionFunctions::Call(name, result, argv))
{
if(!silent)
dprintf(QT_TRANSLATE_NOOP("DBG", "Expression function %s errored!\n"),
makeSignature().c_str()
);
return false;
}
if(result.type == ValueTypeAny)
// Check the return type
switch(result.type)
{
case ValueTypeNumber:
case ValueTypeString:
break;
default:
if(!silent)
dprintf(QT_TRANSLATE_NOOP("DBG", "Expression function %s returned an invalid value!\n"),
makeSignature().c_str()
);
return false;
}
// Pop the arguments off the stack
// NOTE: Do not move, the string pointers are needed during the call
for(size_t i = 0; i < argv.size(); i++)
{
stack.pop_back();
}
// Push the result on the stack
if(result.type == ValueTypeString)
{
stack.push_back(EvalValue(result.string.ptr, true));
stack.emplace_back(result.string.ptr, true);
// We can free the string since it was copied into the EvalValue
if(result.string.isOwner)
BridgeFree((void*)result.string.ptr);
}
else
stack.push_back(EvalValue(result.number));
stack.emplace_back(result.number);
}
else
stack.push_back(EvalValue(token.data(), token.type() == Token::Type::QuotedData));

View File

@ -17,7 +17,7 @@ public:
explicit EvalValue(duint value)
: evaluated(true), value(value) {}
explicit EvalValue(const String & data, bool isString)
EvalValue(const String & data, bool isString)
: evaluated(false), data(data), isString(isString) {}
bool DoEvaluate(duint & result, bool silent = true, bool baseonly = false, int* value_size = nullptr, bool* isvar = nullptr, bool* hexonly = nullptr) const
@ -61,8 +61,8 @@ public:
QuotedData,
Function,
Comma,
OpenBracket,
CloseBracket,
OpenParen,
CloseParen,
OperatorUnarySub,
OperatorUnaryAdd,
@ -133,6 +133,16 @@ public:
return mType;
}
duint info() const
{
return mInfo;
}
void setInfo(duint info)
{
mInfo = info;
}
Associativity associativity() const;
int precedence() const;
bool isOperator() const;
@ -140,6 +150,7 @@ public:
private:
String mData;
Type mType;
duint mInfo = 0;
};
private:

View File

@ -11,6 +11,7 @@
#include "value.h"
#include "TraceRecord.h"
#include "exhandlerinfo.h"
#include "exception.h"
#include <vector>
#include <regex>
#include <string>
@ -189,9 +190,11 @@ namespace Exprfunc
return result;
}
duint ternary(duint condition, duint value1, duint value2)
bool ternary(ExpressionValue* result, int argc, const ExpressionValue* argv, void* userdata)
{
return condition ? value1 : value2;
*result = argv[0].number ? argv[1] : argv[2];
result->string.isOwner = false;
return true;
}
duint memvalid(duint addr)
@ -690,14 +693,24 @@ namespace Exprfunc
template<bool Strict>
bool ansi(ExpressionValue* result, int argc, const ExpressionValue* argv, void* userdata)
{
assert(argc == 1);
assert(argc >= 1);
assert(argv[0].type == ValueTypeNumber);
duint addr = argv[0].number;
std::vector<char> tempStr(MAX_STRING_SIZE + 1);
duint NumberOfBytesRead = 0;
if(!MemRead(addr, tempStr.data(), tempStr.size() - 1, &NumberOfBytesRead) && NumberOfBytesRead == 0 && Strict)
std::vector<char> tempStr;
if(argc > 1)
{
assert(argv[1].type == ValueTypeNumber);
tempStr.resize(argv[1].number + 1);
}
else
{
tempStr.resize(MAX_STRING_SIZE + 1);
}
duint NumberOfBytesRead = -1;
if(!MemRead(addr, tempStr.data(), tempStr.size() - 1, &NumberOfBytesRead) && NumberOfBytesRead == -1 && Strict)
{
return false;
}
@ -709,14 +722,24 @@ namespace Exprfunc
template<bool Strict>
bool utf8(ExpressionValue* result, int argc, const ExpressionValue* argv, void* userdata)
{
assert(argc == 1);
assert(argc >= 1);
assert(argv[0].type == ValueTypeNumber);
duint addr = argv[0].number;
std::vector<char> tempStr(MAX_STRING_SIZE + 1);
duint NumberOfBytesRead = 0;
if(!MemRead(addr, tempStr.data(), tempStr.size() - 1, &NumberOfBytesRead) && NumberOfBytesRead == 0 && Strict)
std::vector<char> tempStr;
if(argc > 1)
{
assert(argv[1].type == ValueTypeNumber);
tempStr.resize(argv[1].number + 1);
}
else
{
tempStr.resize(MAX_STRING_SIZE + 1);
}
duint NumberOfBytesRead = -1;
if(!MemRead(addr, tempStr.data(), tempStr.size() - 1, &NumberOfBytesRead) && NumberOfBytesRead == -1 && Strict)
{
return false;
}
@ -728,14 +751,24 @@ namespace Exprfunc
template<bool Strict>
bool utf16(ExpressionValue* result, int argc, const ExpressionValue* argv, void* userdata)
{
assert(argc == 1);
assert(argc >= 1);
assert(argv[0].type == ValueTypeNumber);
duint addr = argv[0].number;
std::vector<wchar_t> tempStr(MAX_STRING_SIZE + 1);
duint NumberOfBytesRead = 0;
if(!MemRead(addr, tempStr.data(), sizeof(wchar_t) * (tempStr.size() - 1), &NumberOfBytesRead) && NumberOfBytesRead == 0 && Strict)
std::vector<wchar_t> tempStr;
if(argc > 1)
{
assert(argv[1].type == ValueTypeNumber);
tempStr.resize(argv[1].number + 1);
}
else
{
tempStr.resize(MAX_STRING_SIZE + 1);
}
duint NumberOfBytesRead = -1;
if(!MemRead(addr, tempStr.data(), sizeof(wchar_t) * (tempStr.size() - 1), &NumberOfBytesRead) && NumberOfBytesRead == -1 && Strict)
{
return false;
}
@ -780,4 +813,20 @@ namespace Exprfunc
{
return utf16<true>(result, argc, argv, userdata);
}
bool syscall_name(ExpressionValue* result, int argc, const ExpressionValue* argv, void* userdata)
{
*result = ValueString(SyscallToName(argv[0].number));
return true;
}
bool syscall_id(ExpressionValue* result, int argc, const ExpressionValue* argv, void* userdata)
{
auto id = SyscallToId(argv[0].string.ptr);
if(id == -1)
return false;
*result = ValueNumber(id);
return true;
}
}

View File

@ -26,7 +26,7 @@ namespace Exprfunc
duint kusd();
duint bswap(duint value);
duint ternary(duint condition, duint value1, duint value2);
bool ternary(ExpressionValue* result, int argc, const ExpressionValue* argv, void* userdata);
duint memvalid(duint addr);
duint membase(duint addr);
@ -101,4 +101,7 @@ namespace Exprfunc
bool utf8_strict(ExpressionValue* result, int argc, const ExpressionValue* argv, void* userdata);
bool utf16(ExpressionValue* result, int argc, const ExpressionValue* argv, void* userdata);
bool utf16_strict(ExpressionValue* result, int argc, const ExpressionValue* argv, void* userdata);
bool syscall_name(ExpressionValue* result, int argc, const ExpressionValue* argv, void* userdata);
bool syscall_id(ExpressionValue* result, int argc, const ExpressionValue* argv, void* userdata);
}

View File

@ -61,19 +61,14 @@ static FORMATRESULT memoryFormatter(char* dest, size_t destCount, int argc, char
strcpy_s(dest, destCount, GuiTranslateText(QT_TRANSLATE_NOOP("DBG", "Invalid argument...")));
return FORMAT_ERROR_MESSAGE;
}
if(size == 0)
{
strcpy_s(dest, destCount, GuiTranslateText(QT_TRANSLATE_NOOP("DBG", "Not enough arguments...")));
return FORMAT_ERROR_MESSAGE;
}
if(size > 1024 * 1024 * 10) //10MB max
{
strcpy_s(dest, destCount, GuiTranslateText(QT_TRANSLATE_NOOP("DBG", "Too much data (10MB max)...")));
return FORMAT_ERROR_MESSAGE;
}
std::vector<Char> data(size);
duint read = 0;
if(!MemRead(addr, data.data(), size * sizeof(Char), &read) && read == 0)
duint read = -1;
if(!MemRead(addr, data.data(), size * sizeof(Char), &read) && read == -1)
{
strcpy_s(dest, destCount, GuiTranslateText(QT_TRANSLATE_NOOP("DBG", "Failed to read memory...")));
return FORMAT_ERROR_MESSAGE;

View File

@ -96,7 +96,7 @@ static std::vector<MEMPAGE> QueryMemPages()
else
{
// Otherwise append the page to the last created entry
if(pages.size()) //make sure to not dereference an invalid pointer
if(pages.size()) //make sure to not dereference an invalid pointer
pages.back().mbi.RegionSize += mbi.RegionSize;
}
}
@ -471,7 +471,7 @@ duint MemFindBaseAddr(duint Address, duint* Size, bool Refresh, bool FindReserve
if(found == memoryPages.end())
return 0;
if(!FindReserved && found->second.mbi.State == MEM_RESERVE) //check if the current page is reserved.
if(!FindReserved && found->second.mbi.State == MEM_RESERVE) //check if the current page is reserved.
return 0;
// Return the allocation region size when requested
@ -526,12 +526,13 @@ bool MemRead(duint BaseAddress, void* Buffer, duint Size, duint* NumberOfBytesRe
if(cache && !MemIsValidReadPtr(BaseAddress, true))
return false;
if(!Buffer || !Size)
if(!Buffer)
return false;
duint bytesReadTemp = 0;
if(!NumberOfBytesRead)
NumberOfBytesRead = &bytesReadTemp;
*NumberOfBytesRead = 0;
duint offset = 0;
duint requestedSize = Size;
@ -575,12 +576,13 @@ bool MemReadUnsafe(duint BaseAddress, void* Buffer, duint Size, duint* NumberOfB
if(!MemIsCanonicalAddress(BaseAddress) || BaseAddress < PAGE_SIZE || !DbgIsDebugging())
return false;
if(!Buffer || !Size)
if(!Buffer)
return false;
duint bytesReadTemp = 0;
if(!NumberOfBytesRead)
NumberOfBytesRead = &bytesReadTemp;
*NumberOfBytesRead = 0;
duint offset = 0;
duint requestedSize = Size;
@ -622,12 +624,13 @@ bool MemWrite(duint BaseAddress, const void* Buffer, duint Size, duint* NumberOf
if(!MemIsCanonicalAddress(BaseAddress))
return false;
if(!Buffer || !Size)
if(!Buffer)
return false;
SIZE_T bytesWrittenTemp = 0;
if(!NumberOfBytesWritten)
NumberOfBytesWritten = &bytesWrittenTemp;
*NumberOfBytesWritten = 0;
duint offset = 0;
duint requestedSize = Size;
@ -657,8 +660,8 @@ bool MemWrite(duint BaseAddress, const void* Buffer, duint Size, duint* NumberOf
bool MemPatch(duint BaseAddress, const void* Buffer, duint Size, duint* NumberOfBytesWritten)
{
// Buffer and size must be valid
if(!Buffer || Size <= 0)
// Buffer must be valid
if(!Buffer)
return false;
// Allocate the memory
@ -777,7 +780,7 @@ bool MemGetPageRights(duint Address, char* Rights)
bool MemPageRightsToString(DWORD Protect, char* Rights)
{
if(!Protect) //reserved pages don't have a protection (https://goo.gl/Izkk0c)
if(!Protect) //reserved pages don't have a protection (https://goo.gl/Izkk0c)
{
*Rights = '\0';
return true;
@ -1044,7 +1047,7 @@ bool MemGetProtect(duint Address, bool Reserved, bool Cache, unsigned int* Prote
auto found = memoryPages.find({ Address, Address });
if(found == memoryPages.end())
return false;
if(!Reserved && found->second.mbi.State == MEM_RESERVE) //check if the current page is reserved.
if(!Reserved && found->second.mbi.State == MEM_RESERVE) //check if the current page is reserved.
return false;
*Protect = found->second.mbi.Protect;

View File

@ -701,6 +701,59 @@ static bool GetUnsafeModuleInfoImpl(MODINFO & Info, ULONG_PTR FileMapVA, void(*f
return true;
}
// Determine user/system module based on path, the default method
static MODULEPARTY GetDefaultParty(const MODINFO & Info)
{
if(Info.isVirtual)
return mod_user;
// Determine whether the module is located in system
wchar_t szWindowsDir[MAX_PATH];
GetWindowsDirectoryW(szWindowsDir, _countof(szWindowsDir));
String Utf8Sysdir = StringUtils::Utf16ToUtf8(szWindowsDir);
Utf8Sysdir.append("\\");
if(_memicmp(Utf8Sysdir.c_str(), Info.path, Utf8Sysdir.size()) == 0)
{
return mod_system;
}
else
{
return mod_user;
}
}
// These are used to store party in DB
struct MODULEPARTYINFO : AddrInfo
{
MODULEPARTY party;
};
struct ModuleSerializer : AddrInfoSerializer<MODULEPARTYINFO>
{
bool Save(const MODULEPARTYINFO & value) override
{
setHex("hash", value.modhash);
setInt("party", value.party);
return true;
}
bool Load(MODULEPARTYINFO & value) override
{
value.addr = 0;
value.manual = true;
return getHex("hash", value.modhash) && getInt("party", value.party);
}
};
struct ModulePartyInfo : AddrInfoHashMap<LockModuleHashes, MODULEPARTYINFO, ModuleSerializer>
{
const char* jsonKey() const override
{
return "modules";
}
};
static ModulePartyInfo modulePartyInfo;
void GetModuleInfo(MODINFO & Info, ULONG_PTR FileMapVA)
{
// Get the PE headers
@ -840,23 +893,15 @@ bool ModLoad(duint Base, duint Size, const char* FullPath, bool loadSymbols)
info.fileMap = nullptr;
info.fileMapVA = 0;
// Determine whether the module is located in system
wchar_t szWindowsDir[MAX_PATH];
GetWindowsDirectoryW(szWindowsDir, _countof(szWindowsDir));
String Utf8Sysdir = StringUtils::Utf16ToUtf8(szWindowsDir);
Utf8Sysdir.append("\\");
if(_memicmp(Utf8Sysdir.c_str(), FullPath, Utf8Sysdir.size()) == 0)
{
info.party = mod_system;
}
else
{
info.party = mod_user;
}
// Load module data
info.isVirtual = strstr(FullPath, "virtual:\\") == FullPath;
MODULEPARTYINFO modParty;
if(modulePartyInfo.Get(info.hash, modParty))
info.party = modParty.party;
else
info.party = GetDefaultParty(info);
if(!info.isVirtual)
{
auto wszFullPath = StringUtils::Utf8ToUtf16(FullPath);
@ -1188,6 +1233,34 @@ void ModSetParty(duint Address, MODULEPARTY Party)
return;
module->party = Party;
// DB
MODULEPARTYINFO DBEntry;
if(Party != GetDefaultParty(module[0])) // Save non-default party settings
{
DBEntry.addr = 0;
DBEntry.modhash = module->hash;
DBEntry.party = Party;
DBEntry.manual = true;
modulePartyInfo.Add(DBEntry);
}
else
modulePartyInfo.Delete(module->hash); // Don't need to save the default party
}
void ModCacheSave(JSON root)
{
modulePartyInfo.CacheSave(root);
}
void ModCacheLoad(JSON root)
{
modulePartyInfo.CacheLoad(root);
}
void ModCacheClear()
{
modulePartyInfo.Clear();
}
bool ModRelocationsFromAddr(duint Address, std::vector<MODRELOCATIONINFO> & Relocations)

View File

@ -2,6 +2,7 @@
#define _MODULE_H
#include "_global.h"
#include "jansson/jansson_x64dbg.h" // addrinfo.h and serializablemap.h use functions defined here so can't be included
#include <functional>
#include "symbolsourcebase.h"
@ -173,6 +174,9 @@ void ModEnum(const std::function<void(const MODINFO &)> & cbEnum);
MODULEPARTY ModGetParty(duint Address);
void ModSetParty(duint Address, MODULEPARTY Party);
void ModCacheSave(JSON root);
void ModCacheLoad(JSON root);
void ModCacheClear();
bool ModRelocationsFromAddr(duint Address, std::vector<MODRELOCATIONINFO> & Relocations);
bool ModRelocationAtAddr(duint Address, MODRELOCATIONINFO* Relocation);
bool ModRelocationsInRange(duint Address, duint Size, std::vector<MODRELOCATIONINFO> & Relocations);

View File

@ -2,6 +2,7 @@
#include "value.h"
#include "symbolinfo.h"
#include "module.h"
#include "memory.h"
#include "disasm_fast.h"
#include "disasm_helper.h"
#include "formatfunctions.h"
@ -122,8 +123,13 @@ static String printValue(FormatValueType value, StringValueType type)
if(!parser.Calculate(evalue, valuesignedcalc(), false))
return "???";
if(type == StringValueType::Default && evalue.isString)
return evalue.data;
if(evalue.isString)
{
if(type == StringValueType::Default)
return StringUtils::Escape(evalue.data);
else if(type == StringValueType::String)
return evalue.data; // allow raw string output
}
duint valuint = 0;
if(evalue.isString || !evalue.DoEvaluate(valuint))
@ -151,9 +157,19 @@ static String printValue(FormatValueType value, StringValueType type)
case StringValueType::Pointer:
return StringUtils::sprintf("%p", valuint);
case StringValueType::String:
{
if(disasmgetstringatwrapper(valuint, string, false))
{
return string;
}
else
{
char data;
if(MemRead(valuint, &data, sizeof(data)) && data == '\0')
return "\"\"";
}
break;
}
case StringValueType::AddrInfo:
{
auto symbolic = SymGetSymbolicName(valuint);

View File

@ -415,6 +415,7 @@ static void registercommands()
dbgcmdnew("scriptcmd", cbScriptCmd, false); // execute a script command TODO: undocumented
//gui
dbgcmdnew("showthreadid", cbShowThreadId, false); // show given thread in threads
dbgcmdnew("disasm,dis,d", cbDebugDisasm, true); //doDisasm
dbgcmdnew("dump", cbDebugDump, true); //dump at address
dbgcmdnew("sdump", cbDebugStackDump, true); //dump at stack address

View File

@ -885,8 +885,17 @@ void AbstractStdTable::copyEntrySlot()
if(!action)
return;
int col = action->objectName().toInt();
QString finalText = getCellContent(getInitialSelection(), col);
while(finalText.endsWith(" ")) finalText.chop(1);
QString finalText;
for(int row : getSelection())
{
if(!finalText.isEmpty())
{
finalText += "\n";
}
finalText += getCellContent(row, col);
while(finalText.endsWith(' '))
finalText.chop(1);
}
Bridge::CopyToClipboard(finalText);
}

View File

@ -42,6 +42,7 @@ public:
void deleteAllColumns() override;
virtual QString getCellContent(duint row, duint column) = 0;
virtual duint getCellUserdata(duint row, duint column) = 0;
virtual bool isValidIndex(duint row, duint column) = 0;
virtual void sortRows(duint column, bool ascending) = 0;
@ -138,7 +139,7 @@ protected:
QColor mTracedSelectedAddressBackgroundColor;
bool bCipBase = false;
QString mHighlightText;
int mMinimumHighlightColumn = 0;
duint mMinimumHighlightColumn = 0;
int mAddressColumn = -1;
bool bAddressLabel = true;

View File

@ -210,6 +210,8 @@ void AbstractTableView::paintEvent(QPaintEvent* event)
mShouldReload = false;
}
// TODO: report if mTableOffset is out of view
// Paints background
if(mBackgroundColor.alpha() == 255) // The secret code to allow the user to set a background image in style.css
painter.fillRect(painter.viewport(), QBrush(mBackgroundColor));
@ -1133,6 +1135,8 @@ void AbstractTableView::setRowCount(duint count)
{
updateScrollBarRange(getRowCount());
});
// TODO: report if mTableOffset is out of view
}
void AbstractTableView::deleteAllColumns()
@ -1143,7 +1147,7 @@ void AbstractTableView::deleteAllColumns()
void AbstractTableView::setColTitle(duint col, const QString & title)
{
if(mColumnList.size() > 0 && col < mColumnList.size())
if(mColumnList.size() > 0 && col < (duint)mColumnList.size())
{
Column column = mColumnList.takeAt(col);
column.title = title;
@ -1153,7 +1157,7 @@ void AbstractTableView::setColTitle(duint col, const QString & title)
QString AbstractTableView::getColTitle(duint col) const
{
if(mColumnList.size() > 0 && col < mColumnList.size())
if(mColumnList.size() > 0 && col < (duint)mColumnList.size())
return mColumnList[col].title;
return QString();
}
@ -1304,7 +1308,10 @@ void AbstractTableView::setTableOffset(duint val)
auto rowCount = getRowCount();
auto viewableRows = getViewableRowsCount();
if(rowCount <= viewableRows)
{
mTableOffset = 0;
return;
}
auto maxTableOffset = getMaxTableOffset();
// If val is within the last viewable rows

View File

@ -1416,8 +1416,8 @@ duint Disassembly::getPreviousInstructionRVA(duint rva, duint count)
{
QByteArray buffer;
// TODO: fix sign check
auto bottomByteRealRVA = (dsint)rva - 16 * (count + 3);
// TODO: explicitly bail out early
dsint bottomByteRealRVA = (dsint)rva - 16 * (count + 3);
if(mCodeFoldingManager)
{
if(mCodeFoldingManager->isFolded(rvaToVa(bottomByteRealRVA)))
@ -1502,7 +1502,7 @@ duint Disassembly::getInstructionRVA(duint index, dsint count)
else if(count > 0)
addr = getNextInstructionRVA(index, qAbs(count));
// TODO: fix this sign check
if(addr < 0)
addr = 0;
else if(addr > getRowCount() - 1)

View File

@ -698,7 +698,7 @@ QString HexDump::paintContent(QPainter* painter, duint row, duint col, int x, in
void HexDump::printSelected(QPainter* painter, duint row, duint col, int x, int y, int w, int h)
{
if(col > 0 && col <= mDescriptor.size())
if(col > 0 && col <= (duint)mDescriptor.size())
{
ColumnDescriptor curDescriptor = mDescriptor.at(col - 1);
auto bytePerRowCount = getBytePerRowCount();

View File

@ -107,8 +107,8 @@ void ReferenceView::connectBridge()
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(referenceAddCommand(QString, QString)), this, SLOT(addCommand(QString, QString)));
connect(stdSearchList(), SIGNAL(selectionChanged(duint)), this, SLOT(searchSelectionChanged(int)));
connect(stdList(), SIGNAL(selectionChanged(duint)), this, SLOT(searchSelectionChanged(int)));
connect(stdSearchList(), SIGNAL(selectionChanged(duint)), this, SLOT(searchSelectionChanged(duint)));
connect(stdList(), SIGNAL(selectionChanged(duint)), this, SLOT(searchSelectionChanged(duint)));
}
void ReferenceView::disconnectBridge()
@ -118,8 +118,8 @@ void ReferenceView::disconnectBridge()
disconnect(Bridge::getBridge(), SIGNAL(referenceSetProgress(int)), this, SLOT(referenceSetProgressSlot(int)));
disconnect(Bridge::getBridge(), SIGNAL(referenceSetCurrentTaskProgress(int, QString)), this, SLOT(referenceSetCurrentTaskProgressSlot(int, QString)));
disconnect(Bridge::getBridge(), SIGNAL(referenceAddCommand(QString, QString)), this, SLOT(addCommand(QString, QString)));
disconnect(stdSearchList(), SIGNAL(selectionChanged(int)), this, SLOT(searchSelectionChanged(int)));
disconnect(stdList(), SIGNAL(selectionChanged(int)), this, SLOT(searchSelectionChanged(int)));
disconnect(stdSearchList(), SIGNAL(selectionChanged(duint)), this, SLOT(searchSelectionChanged(duint)));
disconnect(stdList(), SIGNAL(selectionChanged(duint)), this, SLOT(searchSelectionChanged(duint)));
}
int ReferenceView::progress() const
@ -153,7 +153,7 @@ void ReferenceView::referenceSetCurrentTaskProgressSlot(int progress, QString ta
mSearchCurrentTaskProgress->setFormat(taskTitle + " " + QString::number(progress) + "%");
}
void ReferenceView::searchSelectionChanged(int index)
void ReferenceView::searchSelectionChanged(duint index)
{
DbgValToString("$__disasm_refindex", index);
DbgValToString("$__dump_refindex", index);
@ -182,7 +182,7 @@ void ReferenceView::addColumnAtRef(int width, QString title)
StdSearchListView::addColumnAt(width, title, true);
}
void ReferenceView::setRowCount(dsint count)
void ReferenceView::setRowCount(duint count)
{
if(!stdList()->getRowCount() && count) //from zero to N rows
searchSelectionChanged(0);
@ -257,14 +257,14 @@ void ReferenceView::referenceContextMenu(QMenu* menu)
void ReferenceView::followAddress()
{
int index = mCurList->getInitialSelection();
auto index = mCurList->getInitialSelection();
searchSelectionChanged(index);
DbgCmdExecDirect(QString("disasm " + mCurList->getCellContent(index, 0)));
}
void ReferenceView::followDumpAddress()
{
int index = mCurList->getInitialSelection();
auto index = mCurList->getInitialSelection();
searchSelectionChanged(index);
DbgCmdExecDirect(QString("dump " + mCurList->getCellContent(index, 0)));
}

View File

@ -21,7 +21,7 @@ public:
public slots:
void addColumnAtRef(int width, QString title);
void setRowCount(dsint count) override;
void setRowCount(duint count) override;
void setSingleSelection(int index, bool scroll);
void addCommand(QString title, QString command);
@ -39,7 +39,7 @@ public slots:
void refreshShortcutsSlot();
void referenceSetProgressSlot(int progress);
void referenceSetCurrentTaskProgressSlot(int progress, QString taskTitle);
void searchSelectionChanged(int index);
void searchSelectionChanged(duint index);
void reloadDataSlot();
signals:

View File

@ -122,39 +122,11 @@ SearchListView::SearchListView(QWidget* parent, AbstractSearchList* abstractSear
abstractSearchList->list()->setFocusProxy(mSearchBox);
}
bool SearchListView::findTextInList(AbstractStdTable* list, QString text, int row, int startcol, bool startswith)
{
int count = list->getColumnCount();
if(startcol + 1 > count)
return false;
if(startswith)
{
for(int i = startcol; i < count; i++)
if(list->getCellContent(row, i).startsWith(text, Qt::CaseInsensitive))
return true;
}
else
{
for(int i = startcol; i < count; i++)
{
auto state = mRegexCheckbox->checkState();
if(state != Qt::Unchecked)
{
if(list->getCellContent(row, i).contains(QRegExp(text, state == Qt::PartiallyChecked ? Qt::CaseInsensitive : Qt::CaseSensitive)))
return true;
}
else
{
if(list->getCellContent(row, i).contains(text, Qt::CaseInsensitive))
return true;
}
}
}
return false;
}
void SearchListView::filterEntries()
{
// Copy the filter text before entering the critical section
auto filterText = mFilterText;
mAbstractSearchList->lock();
// store the first selection value
@ -166,7 +138,7 @@ void SearchListView::filterEntries()
// get the correct previous list instance
auto mPrevList = mAbstractSearchList->list()->isVisible() ? mAbstractSearchList->list() : mAbstractSearchList->searchList();
if(mFilterText.length())
if(filterText.length())
{
MethodInvoker::invokeMethod([this]()
{
@ -187,7 +159,7 @@ void SearchListView::filterEntries()
filterType = AbstractSearchList::FilterRegexCaseSensitive;
break;
}
mAbstractSearchList->filter(mFilterText, filterType, mSearchStartCol);
mAbstractSearchList->filter(filterText, filterType, mSearchStartCol);
}
else
{
@ -236,9 +208,6 @@ void SearchListView::filterEntries()
else
mAbstractSearchList->searchList()->setHighlightText(QString());
// Reload the search list data
mAbstractSearchList->searchList()->reloadData();
// setup the same layout of the previous list control
if(mPrevList != mCurList)
{
@ -251,6 +220,9 @@ void SearchListView::filterEntries()
}
}
// Reload the search list data
mCurList->reloadData();
mAbstractSearchList->unlock();
}

View File

@ -17,7 +17,6 @@ public:
AbstractStdTable* mCurList = nullptr;
duint mSearchStartCol = 0;
bool findTextInList(AbstractStdTable* list, QString text, int row, int startcol, bool startswith);
void refreshSearchList();
void clearFilter();
bool isSearchBoxLocked();

View File

@ -4,22 +4,22 @@
Data Management
************************************************************************************/
void StdIconTable::setRowIcon(int r, const QIcon & icon)
void StdIconTable::setRowIcon(duint r, const QIcon & icon)
{
mIcon.at(r) = icon;
}
QIcon StdIconTable::getRowIcon(int r) const
QIcon StdIconTable::getRowIcon(duint r) const
{
return mIcon.at(r);
}
void StdIconTable::setIconColumn(int c)
void StdIconTable::setIconColumn(duint c)
{
mIconColumn = c;
}
int StdIconTable::getIconColumn() const
duint StdIconTable::getIconColumn() const
{
return mIconColumn;
}

View File

@ -10,10 +10,10 @@ public:
explicit StdIconTable(QWidget* parent = nullptr) : StdTable(parent), mIconColumn(0) {}
// Data Management
void setRowIcon(int r, const QIcon & icon); // set the icon for a row
QIcon getRowIcon(int r) const;
void setIconColumn(int c); // set in which column the icons appear
int getIconColumn() const;
void setRowIcon(duint r, const QIcon & icon); // set the icon for a row
QIcon getRowIcon(duint r) const;
void setIconColumn(duint c); // set in which column the icons appear
duint getIconColumn() const;
void setRowCount(duint count) override;
void sortRows(duint column, bool ascending) override;
@ -21,5 +21,5 @@ public:
protected:
std::vector<QIcon> mIcon; //listof(row) where row = (listof(col) where col = CellData)
int mIconColumn;
duint mIconColumn;
};

View File

@ -57,16 +57,22 @@ void StdSearchListView::loadColumnFromConfig(const QString & viewName)
stdSearchList()->loadColumnFromConfig(viewName);
}
void StdSearchListView::setRowCount(dsint count)
void StdSearchListView::setRowCount(duint count)
{
//clearFilter();
stdList()->setRowCount(count);
}
void StdSearchListView::setCellContent(int r, int c, QString s)
void StdSearchListView::setCellContent(duint row, duint column, QString s)
{
//clearFilter();
stdList()->setCellContent(r, c, s);
stdList()->setCellContent(row, column, s);
}
void StdSearchListView::setCellUserdata(duint row, duint column, duint userdata)
{
//clearFilter();
stdList()->setCellUserdata(row, column, userdata);
}
void StdSearchListView::reloadData()

View File

@ -18,12 +18,13 @@ public:
void enableMultiSelection(bool enabled);
void setAddressColumn(int col, bool cipBase = false);
void loadColumnFromConfig(const QString & viewName);
virtual void setRowCount(duint count);
void setCellContent(duint row, duint column, QString s);
void setCellUserdata(duint row, duint column, duint userdata);
void setSearchStartCol(duint column);
public slots:
virtual void setRowCount(dsint count);
void setCellContent(int r, int c, QString s);
void reloadData();
void setSearchStartCol(duint col);
private:
StdTableSearchList* mSearchListData;

View File

@ -25,7 +25,7 @@ public:
void setCellContent(duint r, duint c, QString s, duint userdata);
QString getCellContent(duint r, duint c) override;
void setCellUserdata(duint r, duint c, duint userdata);
duint getCellUserdata(duint r, duint c);
duint getCellUserdata(duint r, duint c) override;
bool isValidIndex(duint r, duint c) override;
void sortRows(duint column, bool ascending) override;

View File

@ -6,14 +6,14 @@ void StdTableSearchList::filter(const QString & filter, FilterType type, duint s
StdIconTable* mSearchIconList = qobject_cast<StdIconTable*>(mSearchList);
StdIconTable* mIconList = qobject_cast<StdIconTable*>(mList);
mSearchList->setRowCount(0);
int rows = mList->getRowCount();
int columns = mList->getColumnCount();
for(int i = 0, j = 0; i < rows; i++)
auto rows = mList->getRowCount();
auto columns = mList->getColumnCount();
for(duint i = 0, j = 0; i < rows; i++)
{
if(rowMatchesFilter(filter, type, i, startColumn))
{
mSearchList->setRowCount(j + 1);
for(int k = 0; k < columns; k++)
for(duint k = 0; k < columns; k++)
{
mSearchList->setCellContent(j, k, mList->getCellContent(i, k));
mSearchList->setCellUserdata(j, k, mList->getCellUserdata(i, k));

View File

@ -28,20 +28,188 @@ class BridgeArchitecture : public Architecture
/************************************************************************************
Class Members
************************************************************************************/
static const char* msg2str(GUIMSG msg)
{
switch(msg)
{
case GUI_UPDATE_REGISTER_VIEW:
return "GUI_UPDATE_REGISTER_VIEW";
case GUI_UPDATE_DISASSEMBLY_VIEW:
return "GUI_UPDATE_DISASSEMBLY_VIEW";
case GUI_UPDATE_BREAKPOINTS_VIEW:
return "GUI_UPDATE_BREAKPOINTS_VIEW";
case GUI_UPDATE_DUMP_VIEW:
return "GUI_UPDATE_DUMP_VIEW";
case GUI_UPDATE_THREAD_VIEW:
return "GUI_UPDATE_THREAD_VIEW";
case GUI_UPDATE_MEMORY_VIEW:
return "GUI_UPDATE_MEMORY_VIEW";
case GUI_UPDATE_SIDEBAR:
return "GUI_UPDATE_SIDEBAR";
case GUI_REPAINT_TABLE_VIEW:
return "GUI_REPAINT_TABLE_VIEW";
case GUI_UPDATE_PATCHES:
return "GUI_UPDATE_PATCHES";
case GUI_UPDATE_CALLSTACK:
return "GUI_UPDATE_CALLSTACK";
case GUI_UPDATE_SEHCHAIN:
return "GUI_UPDATE_SEHCHAIN";
case GUI_UPDATE_TIME_WASTED_COUNTER:
return "GUI_UPDATE_TIME_WASTED_COUNTER";
case GUI_UPDATE_ARGUMENT_VIEW:
return "GUI_UPDATE_ARGUMENT_VIEW";
case GUI_UPDATE_WATCH_VIEW:
return "GUI_UPDATE_WATCH_VIEW";
case GUI_UPDATE_GRAPH_VIEW:
return "GUI_UPDATE_GRAPH_VIEW";
case GUI_UPDATE_TYPE_WIDGET:
return "GUI_UPDATE_TYPE_WIDGET";
case GUI_UPDATE_TRACE_BROWSER:
return "GUI_UPDATE_TRACE_BROWSER";
default:
return "<unknown message>";
}
}
void Bridge::throttleUpdateSlot(GUIMSG msg)
{
// NOTE: This is running synchronously on the UI thread
auto lastUpdate = mLastUpdates[msg];
auto now = GetTickCount();
auto elapsed = now - lastUpdate;
const auto interval = 100;
if(lastUpdate > 0 && elapsed < interval)
{
//qDebug() << "Delay update:" << msg2str(msg);
QTimer* timer = mUpdateTimers[msg];
if(timer == nullptr)
{
timer = new QTimer(this);
timer->setSingleShot(true);
connect(timer, &QTimer::timeout, this, [this, msg]
{
doUpdate(msg);
});
mUpdateTimers[msg] = timer;
}
if(!timer->isActive())
{
timer->setInterval(interval - elapsed);
timer->start();
}
}
else
{
//qDebug() << "No delay: " << msg2str(msg);
doUpdate(msg);
}
}
void Bridge::doUpdate(GUIMSG msg)
{
auto start = GetTickCount();
switch(msg)
{
case GUI_UPDATE_REGISTER_VIEW:
updateRegisters();
break;
case GUI_UPDATE_DISASSEMBLY_VIEW:
updateDisassembly();
break;
case GUI_UPDATE_BREAKPOINTS_VIEW:
updateBreakpoints();
break;
case GUI_UPDATE_DUMP_VIEW:
updateDump();
break;
case GUI_UPDATE_THREAD_VIEW:
updateThreads();
break;
case GUI_UPDATE_MEMORY_VIEW:
updateMemory();
break;
case GUI_UPDATE_SIDEBAR:
updateSideBar();
break;
case GUI_REPAINT_TABLE_VIEW:
repaintTableView();
break;
case GUI_UPDATE_PATCHES:
updatePatches();
break;
case GUI_UPDATE_CALLSTACK:
updateCallStack();
break;
case GUI_UPDATE_SEHCHAIN:
updateSEHChain();
break;
case GUI_UPDATE_TIME_WASTED_COUNTER:
updateTimeWastedCounter();
break;
case GUI_UPDATE_ARGUMENT_VIEW:
updateArgumentView();
break;
case GUI_UPDATE_WATCH_VIEW:
updateWatch();
break;
case GUI_UPDATE_GRAPH_VIEW:
updateGraph();
break;
case GUI_UPDATE_TYPE_WIDGET:
typeUpdateWidget();
break;
case GUI_UPDATE_TRACE_BROWSER:
updateTraceBrowser();
break;
default:
__debugbreak();
}
// Log potentially bottlenecked updates
auto now = GetTickCount();
auto elapsed = now - start;
if(elapsed > 5)
qDebug() << msg2str(msg) << elapsed << "ms";
mLastUpdates[msg] = now;
}
Bridge::Bridge(QObject* parent) : QObject(parent)
{
InitializeCriticalSection(&csBridge);
InitializeCriticalSection(&mCsBridge);
for(size_t i = 0; i < BridgeResult::Last; i++)
resultEvents[i] = CreateEventW(nullptr, true, true, nullptr);
dwMainThreadId = GetCurrentThreadId();
mResultEvents[i] = CreateEventW(nullptr, true, true, nullptr);
mMainThreadId = GetCurrentThreadId();
connect(this, &Bridge::throttleUpdate, this, &Bridge::throttleUpdateSlot);
}
Bridge::~Bridge()
{
EnterCriticalSection(&csBridge);
EnterCriticalSection(&mCsBridge);
for(size_t i = 0; i < BridgeResult::Last; i++)
CloseHandle(resultEvents[i]);
DeleteCriticalSection(&csBridge);
CloseHandle(mResultEvents[i]);
DeleteCriticalSection(&mCsBridge);
}
void Bridge::CopyToClipboard(const QString & text)
@ -68,8 +236,8 @@ void Bridge::setResult(BridgeResult::Type type, dsint result)
#ifdef DEBUG
OutputDebugStringA(QString().sprintf("[x64dbg] [%u] Bridge::setResult(%d, %p)\n", GetCurrentThreadId(), type, result).toUtf8().constData());
#endif //DEBUG
bridgeResults[type] = result;
SetEvent(resultEvents[type]);
mBridgeResults[type] = result;
SetEvent(mResultEvents[type]);
}
/************************************************************************************
@ -103,7 +271,7 @@ void Bridge::emitMenuAddToList(QWidget* parent, QMenu* menu, GUIMENUTYPE hMenu,
void Bridge::setDbgStopped()
{
dbgStopped = true;
mDbgStopped = true;
}
/************************************************************************************
@ -112,7 +280,7 @@ void Bridge::setDbgStopped()
void* Bridge::processMessage(GUIMSG type, void* param1, void* param2)
{
if(dbgStopped) //there can be no more messages if the debugger stopped = IGNORE
if(mDbgStopped) //there can be no more messages if the debugger stopped = IGNORE
return nullptr;
switch(type)
{
@ -160,24 +328,12 @@ void* Bridge::processMessage(GUIMSG type, void* param1, void* param2)
emit redirectLogStop();
break;
case GUI_UPDATE_REGISTER_VIEW:
emit updateRegisters();
break;
case GUI_UPDATE_DISASSEMBLY_VIEW:
emit updateDisassembly();
break;
case GUI_UPDATE_BREAKPOINTS_VIEW:
emit updateBreakpoints();
break;
case GUI_UPDATE_WINDOW_TITLE:
emit updateWindowTitle(QString((const char*)param1));
break;
case GUI_GET_WINDOW_HANDLE:
return winId;
return mWinId;
case GUI_DUMP_AT:
emit dumpAt((dsint)param1);
@ -252,25 +408,25 @@ void* Bridge::processMessage(GUIMSG type, void* param1, void* param2)
break;
case GUI_REF_ADDCOLUMN:
if(referenceManager->currentReferenceView())
referenceManager->currentReferenceView()->addColumnAtRef((int)param1, QString((const char*)param2));
if(mReferenceManager->currentReferenceView())
mReferenceManager->currentReferenceView()->addColumnAtRef((int)param1, QString((const char*)param2));
break;
case GUI_REF_SETROWCOUNT:
{
if(referenceManager->currentReferenceView())
referenceManager->currentReferenceView()->setRowCount((dsint)param1);
if(mReferenceManager->currentReferenceView())
mReferenceManager->currentReferenceView()->setRowCount((dsint)param1);
}
break;
case GUI_REF_GETROWCOUNT:
if(referenceManager->currentReferenceView())
return (void*)referenceManager->currentReferenceView()->stdList()->getRowCount();
if(mReferenceManager->currentReferenceView())
return (void*)mReferenceManager->currentReferenceView()->stdList()->getRowCount();
return 0;
case GUI_REF_SEARCH_GETROWCOUNT:
if(referenceManager->currentReferenceView())
return (void*)referenceManager->currentReferenceView()->mCurList->getRowCount();
if(mReferenceManager->currentReferenceView())
return (void*)mReferenceManager->currentReferenceView()->mCurList->getRowCount();
return 0;
case GUI_REF_DELETEALLCOLUMNS:
@ -280,16 +436,16 @@ void* Bridge::processMessage(GUIMSG type, void* param1, void* param2)
case GUI_REF_SETCELLCONTENT:
{
CELLINFO* info = (CELLINFO*)param1;
if(referenceManager->currentReferenceView())
referenceManager->currentReferenceView()->setCellContent(info->row, info->col, QString(info->str));
if(mReferenceManager->currentReferenceView())
mReferenceManager->currentReferenceView()->setCellContent(info->row, info->col, QString(info->str));
}
break;
case GUI_REF_GETCELLCONTENT:
{
QString content;
if(referenceManager->currentReferenceView())
content = referenceManager->currentReferenceView()->stdList()->getCellContent((int)param1, (int)param2);
if(mReferenceManager->currentReferenceView())
content = mReferenceManager->currentReferenceView()->stdList()->getCellContent((int)param1, (int)param2);
auto bytes = content.toUtf8();
auto data = BridgeAlloc(bytes.size() + 1);
memcpy(data, bytes.constData(), bytes.size());
@ -299,8 +455,8 @@ void* Bridge::processMessage(GUIMSG type, void* param1, void* param2)
case GUI_REF_SEARCH_GETCELLCONTENT:
{
QString content;
if(referenceManager->currentReferenceView())
content = referenceManager->currentReferenceView()->mCurList->getCellContent((int)param1, (int)param2);
if(mReferenceManager->currentReferenceView())
content = mReferenceManager->currentReferenceView()->mCurList->getCellContent((int)param1, (int)param2);
auto bytes = content.toUtf8();
auto data = BridgeAlloc(bytes.size() + 1);
memcpy(data, bytes.constData(), bytes.size());
@ -316,26 +472,26 @@ void* Bridge::processMessage(GUIMSG type, void* param1, void* param2)
break;
case GUI_REF_SETPROGRESS:
if(referenceManager->currentReferenceView())
if(mReferenceManager->currentReferenceView())
{
auto newProgress = (int)param1;
if(referenceManager->currentReferenceView()->progress() != newProgress)
if(mReferenceManager->currentReferenceView()->progress() != newProgress)
emit referenceSetProgress(newProgress);
}
break;
case GUI_REF_SETCURRENTTASKPROGRESS:
if(referenceManager->currentReferenceView())
if(mReferenceManager->currentReferenceView())
{
auto newProgress = (int)param1;
if(referenceManager->currentReferenceView()->currentTaskProgress() != newProgress)
if(mReferenceManager->currentReferenceView()->currentTaskProgress() != newProgress)
emit referenceSetCurrentTaskProgress((int)param1, QString((const char*)param2));
}
break;
case GUI_REF_SETSEARCHSTARTCOL:
if(referenceManager->currentReferenceView())
referenceManager->currentReferenceView()->setSearchStartCol((duint)param1);
if(mReferenceManager->currentReferenceView())
mReferenceManager->currentReferenceView()->setSearchStartCol((duint)param1);
break;
case GUI_REF_INITIALIZE:
@ -350,18 +506,6 @@ void* Bridge::processMessage(GUIMSG type, void* param1, void* param2)
emit stackDumpAt((duint)param1, (duint)param2);
break;
case GUI_UPDATE_DUMP_VIEW:
emit updateDump();
break;
case GUI_UPDATE_THREAD_VIEW:
emit updateThreads();
break;
case GUI_UPDATE_MEMORY_VIEW:
emit updateMemory();
break;
case GUI_ADD_RECENT_FILE:
emit addRecentFile(QString((const char*)param1));
break;
@ -544,6 +688,9 @@ void* Bridge::processMessage(GUIMSG type, void* param1, void* param2)
case GUI_SYMMOD:
emit selectionSymmodGet(selection);
break;
case GUI_THREADS:
emit selectionThreadsGet(selection);
break;
default:
return (void*)false;
}
@ -579,6 +726,9 @@ void* Bridge::processMessage(GUIMSG type, void* param1, void* param2)
case GUI_MEMMAP:
emit selectionMemmapSet(selection);
break;
case GUI_THREADS:
emit selectionThreadsSet(selection);
break;
default:
return (void*)false;
}
@ -616,26 +766,6 @@ void* Bridge::processMessage(GUIMSG type, void* param1, void* param2)
emit addMsgToStatusBar(QString((const char*)param1));
break;
case GUI_UPDATE_SIDEBAR:
emit updateSideBar();
break;
case GUI_REPAINT_TABLE_VIEW:
emit repaintTableView();
break;
case GUI_UPDATE_PATCHES:
emit updatePatches();
break;
case GUI_UPDATE_CALLSTACK:
emit updateCallStack();
break;
case GUI_UPDATE_SEHCHAIN:
emit updateSEHChain();
break;
case GUI_SYMBOL_REFRESH_CURRENT:
emit symbolRefreshCurrent();
break;
@ -644,6 +774,10 @@ void* Bridge::processMessage(GUIMSG type, void* param1, void* param2)
emit loadSourceFile(QString((const char*)param1), (duint)param2);
break;
case GUI_SHOW_THREADS:
emit showThreads();
break;
case GUI_SHOW_CPU:
emit showCpu();
break;
@ -662,17 +796,13 @@ void* Bridge::processMessage(GUIMSG type, void* param1, void* param2)
case GUI_EXECUTE_ON_GUI_THREAD:
{
if(GetCurrentThreadId() == dwMainThreadId)
if(GetCurrentThreadId() == mMainThreadId)
((GUICALLBACKEX)param1)(param2);
else
emit executeOnGuiThread(param1, param2);
}
break;
case GUI_UPDATE_TIME_WASTED_COUNTER:
emit updateTimeWastedCounter();
break;
case GUI_SET_GLOBAL_NOTES:
{
QString text = QString((const char*)param1);
@ -727,10 +857,6 @@ void* Bridge::processMessage(GUIMSG type, void* param1, void* param2)
emit unregisterScriptLang((int)param1);
break;
case GUI_UPDATE_ARGUMENT_VIEW:
emit updateArgumentView();
break;
case GUI_FOCUS_VIEW:
{
int hWindow = int(param1);
@ -757,10 +883,6 @@ void* Bridge::processMessage(GUIMSG type, void* param1, void* param2)
}
break;
case GUI_UPDATE_WATCH_VIEW:
emit updateWatch();
break;
case GUI_LOAD_GRAPH:
{
BridgeResult result(BridgeResult::LoadGraph);
@ -777,17 +899,13 @@ void* Bridge::processMessage(GUIMSG type, void* param1, void* param2)
}
break;
case GUI_UPDATE_GRAPH_VIEW:
emit updateGraph();
break;
case GUI_SET_LOG_ENABLED:
loggingEnabled = param1 != 0;
emit setLogEnabled(loggingEnabled);
mLoggingEnabled = param1 != 0;
emit setLogEnabled(mLoggingEnabled);
break;
case GUI_IS_LOG_ENABLED:
return (void*)loggingEnabled;
return (void*)mLoggingEnabled;
case GUI_ADD_FAVOURITE_TOOL:
{
@ -876,10 +994,6 @@ void* Bridge::processMessage(GUIMSG type, void* param1, void* param2)
}
break;
case GUI_UPDATE_TYPE_WIDGET:
emit typeUpdateWidget();
break;
case GUI_CLOSE_APPLICATION:
emit closeApplication();
break;
@ -907,12 +1021,8 @@ void* Bridge::processMessage(GUIMSG type, void* param1, void* param2)
}
break;
case GUI_UPDATE_TRACE_BROWSER:
emit updateTraceBrowser();
break;
case GUI_INVALIDATE_SYMBOL_SOURCE:
symbolView->invalidateSymbolSource(duint(param1));
mSymbolView->invalidateSymbolSource(duint(param1));
break;
case GUI_GET_CURRENT_GRAPH:
@ -940,7 +1050,28 @@ void* Bridge::processMessage(GUIMSG type, void* param1, void* param2)
break;
case GUI_GET_MAIN_THREAD_ID:
return (void*)dwMainThreadId;
return (void*)mMainThreadId;
case GUI_UPDATE_REGISTER_VIEW:
case GUI_UPDATE_DISASSEMBLY_VIEW:
case GUI_UPDATE_BREAKPOINTS_VIEW:
case GUI_UPDATE_DUMP_VIEW:
case GUI_UPDATE_THREAD_VIEW:
case GUI_UPDATE_MEMORY_VIEW:
case GUI_UPDATE_SIDEBAR:
case GUI_REPAINT_TABLE_VIEW:
case GUI_UPDATE_PATCHES:
case GUI_UPDATE_CALLSTACK:
case GUI_UPDATE_SEHCHAIN:
case GUI_UPDATE_TIME_WASTED_COUNTER:
case GUI_UPDATE_ARGUMENT_VIEW:
case GUI_UPDATE_WATCH_VIEW:
case GUI_UPDATE_GRAPH_VIEW:
case GUI_UPDATE_TYPE_WIDGET:
case GUI_UPDATE_TRACE_BROWSER:
// NOTE: this can run on any thread.
emit throttleUpdate(type);
break;
}
return nullptr;

View File

@ -26,6 +26,11 @@ class Bridge : public QObject
friend class BridgeResult;
void doUpdate(GUIMSG msg);
private slots:
void throttleUpdateSlot(GUIMSG msg);
public:
explicit Bridge(QObject* parent = nullptr);
~Bridge();
@ -49,12 +54,12 @@ public:
void setDbgStopped();
//Public variables
void* winId = nullptr;
ReferenceManager* referenceManager = nullptr;
void* mWinId = nullptr;
ReferenceManager* mReferenceManager = nullptr;
bool mIsRunning = false;
duint mLastCip = 0;
SymbolView* symbolView = nullptr;
bool loggingEnabled = true;
SymbolView* mSymbolView = nullptr;
bool mLoggingEnabled = true;
signals:
void disassembleAt(duint va, duint eip);
@ -125,6 +130,8 @@ signals:
void selectionMemmapGet(SELECTIONDATA* selection);
void selectionMemmapSet(const SELECTIONDATA* selection);
void selectionSymmodGet(SELECTIONDATA* selection);
void selectionThreadsGet(SELECTIONDATA* selection);
void selectionThreadsSet(const SELECTIONDATA* selection);
void getStrWindow(const QString title, QString* text);
void autoCompleteAddCmd(const QString cmd);
void autoCompleteDelCmd(const QString cmd);
@ -139,6 +146,7 @@ signals:
void symbolRefreshCurrent();
void loadSourceFile(const QString path, duint addr);
void showCpu();
void showThreads();
void addQWidgetTab(QWidget* qWidget);
void showQWidgetTab(QWidget* qWidget);
void closeQWidgetTab(QWidget* qWidget);
@ -181,11 +189,14 @@ signals:
void showReferences();
void gotoTraceIndex(duint index);
void showTraceBrowser();
void throttleUpdate(GUIMSG msg);
private:
CRITICAL_SECTION csBridge;
HANDLE resultEvents[BridgeResult::Last];
duint bridgeResults[BridgeResult::Last];
DWORD dwMainThreadId = 0;
volatile bool dbgStopped = false;
CRITICAL_SECTION mCsBridge;
HANDLE mResultEvents[BridgeResult::Last];
duint mBridgeResults[BridgeResult::Last];
DWORD mMainThreadId = 0;
volatile bool mDbgStopped = false;
QMap<GUIMSG, DWORD> mLastUpdates;
QMap<GUIMSG, QTimer*> mUpdateTimers;
};

View File

@ -6,11 +6,11 @@ BridgeResult::BridgeResult(Type type)
: mType(type)
{
Bridge* bridge = Bridge::getBridge();
EnterCriticalSection(&bridge->csBridge);
EnterCriticalSection(&bridge->mCsBridge);
#ifdef DEBUG
OutputDebugStringA(QString().sprintf("[x64dbg] [%u] BridgeResult(%d)\n", GetCurrentThreadId(), type).toUtf8().constData());
#endif //DEBUG
ResetEvent(bridge->resultEvents[type]);
ResetEvent(bridge->mResultEvents[type]);
}
BridgeResult::~BridgeResult()
@ -18,7 +18,7 @@ BridgeResult::~BridgeResult()
#ifdef DEBUG
OutputDebugStringA(QString().sprintf("[x64dbg] [%u] ~BridgeResult(%d)\n", GetCurrentThreadId(), mType).toUtf8().constData());
#endif //DEBUG
LeaveCriticalSection(&Bridge::getBridge()->csBridge);
LeaveCriticalSection(&Bridge::getBridge()->mCsBridge);
}
dsint BridgeResult::Wait()
@ -27,9 +27,9 @@ dsint BridgeResult::Wait()
OutputDebugStringA(QString().sprintf("[x64dbg] [%u] BridgeResult::Wait(%d)\n", GetCurrentThreadId(), mType).toUtf8().constData());
#endif //DEBUG
Bridge* bridge = Bridge::getBridge();
HANDLE hResultEvent = bridge->resultEvents[mType];
HANDLE hResultEvent = bridge->mResultEvents[mType];
//Don't freeze when waiting on the main thread (https://github.com/x64dbg/x64dbg/issues/1716)
if(GetCurrentThreadId() == bridge->dwMainThreadId)
if(GetCurrentThreadId() == bridge->mMainThreadId)
while(WaitForSingleObject(hResultEvent, 10) == WAIT_TIMEOUT)
QCoreApplication::processEvents();
else
@ -37,5 +37,5 @@ dsint BridgeResult::Wait()
#ifdef DEBUG
OutputDebugStringA(QString().sprintf("[x64dbg] [%u] BridgeResult::~Wait(%d)\n", GetCurrentThreadId(), mType).toUtf8().constData());
#endif //DEBUG
return bridge->bridgeResults[mType];
return bridge->mBridgeResults[mType];
}

View File

@ -351,21 +351,31 @@ bool ZydisTokenizer::TokenEquals(const SingleToken* a, const SingleToken* b, boo
return tokenTextPoolEquals(a->text, b->text);
}
static bool tokenIsSpace(ZydisTokenizer::TokenType type)
{
return type == ZydisTokenizer::TokenType::Space || type == ZydisTokenizer::TokenType::ArgumentSpace || type == ZydisTokenizer::TokenType::MemoryOperatorSpace;
}
void ZydisTokenizer::addToken(TokenType type, QString text, const TokenValue & value)
{
switch(type)
bool isItSpaceType = tokenIsSpace(type);
if(!isItSpaceType)
{
case TokenType::Space:
case TokenType::ArgumentSpace:
case TokenType::MemoryOperatorSpace:
break;
default:
text = text.trimmed();
break;
}
if(mUppercase && !value.size)
text = text.toUpper();
mInst.tokens.push_back(SingleToken(mIsNop ? TokenType::MnemonicNop : type, text, value));
if(isItSpaceType)
{
mInst.tokens.push_back(SingleToken(type, text, value));
}
else
{
mInst.tokens.push_back(SingleToken(mIsNop ? TokenType::MnemonicNop : type, text, value));
}
}
void ZydisTokenizer::addToken(TokenType type, const QString & text)
@ -568,7 +578,6 @@ bool ZydisTokenizer::tokenizeImmOperand(const ZydisDecodedOperand & op)
auto opsize = mZydis.GetInstr()->info.operand_width;
valueType = TokenType::Value;
value = duint(op.imm.value.u) & (duint(-1) >> (sizeof(duint) * 8 - opsize));
}
auto tokenValue = TokenValue(op.size / 8, value);
addToken(valueType, printValue(tokenValue, true), tokenValue);

View File

@ -813,9 +813,7 @@ void BreakpointsView::addExceptionBreakpointSlot()
static QString escape(QString data)
{
//data = data.replace("\\", "\\\\");
data = data.replace("\"", "\\\"");
return data;
return DbgCmdEscape(std::move(data));
}
void BreakpointsView::copyConditionalBreakpointSlot()

View File

@ -739,11 +739,11 @@ void CPUDisassembly::setLabelSlot()
duint va = rvaToVa(getInitialSelection());
LineEditDialog mLineEdit(this);
mLineEdit.setTextMaxLength(MAX_LABEL_SIZE - 2);
QString addr_text = ToPtrString(va);
QString addrText = ToPtrString(va);
char label_text[MAX_COMMENT_SIZE] = "";
if(DbgGetLabelAt((duint)va, SEG_DEFAULT, label_text))
mLineEdit.setText(QString(label_text));
mLineEdit.setWindowTitle(tr("Add label at ") + addr_text);
mLineEdit.setWindowTitle(tr("Add label at ") + addrText);
restart:
if(mLineEdit.exec() != QDialog::Accepted)
return;
@ -785,11 +785,11 @@ void CPUDisassembly::setLabelAddressSlot()
return;
LineEditDialog mLineEdit(this);
mLineEdit.setTextMaxLength(MAX_LABEL_SIZE - 2);
QString addr_text = ToPtrString(addr);
QString addrText = ToPtrString(addr);
char label_text[MAX_LABEL_SIZE] = "";
if(DbgGetLabelAt(addr, SEG_DEFAULT, label_text))
mLineEdit.setText(QString(label_text));
mLineEdit.setWindowTitle(tr("Add label at ") + addr_text);
mLineEdit.setWindowTitle(tr("Add label at ") + addrText);
restart:
if(mLineEdit.exec() != QDialog::Accepted)
return;
@ -902,7 +902,7 @@ void CPUDisassembly::assembleSlot()
dsint rva = getInitialSelection();
duint va = rvaToVa(rva);
unfold(rva);
QString addr_text = ToPtrString(va);
QString addrText = ToPtrString(va);
Instruction_t instr = this->DisassembleAt(rva);
@ -919,7 +919,7 @@ void CPUDisassembly::assembleSlot()
if(ConfigBool("Disassembler", "Uppercase"))
actual_inst = actual_inst.toUpper().replace(QRegularExpression("0X([0-9A-F]+)"), "0x\\1");
assembleDialog.setTextEditValue(actual_inst);
assembleDialog.setWindowTitle(tr("Assemble at %1").arg(addr_text));
assembleDialog.setWindowTitle(tr("Assemble at %1").arg(addrText));
assembleDialog.setFillWithNopsChecked(ConfigBool("Disassembler", "FillNOPs"));
assembleDialog.setKeepSizeChecked(ConfigBool("Disassembler", "KeepSize"));
@ -1217,20 +1217,23 @@ void CPUDisassembly::findCallsSlot()
void CPUDisassembly::findPatternSlot()
{
HexEditDialog hexEdit(this);
hexEdit.showEntireBlock(true);
hexEdit.isDataCopiable(false);
if(sender() == mFindPatternRegion)
hexEdit.showStartFromSelection(true, ConfigBool("Disassembler", "FindPatternFromSelection"));
hexEdit.mHexEdit->setOverwriteMode(false);
hexEdit.setWindowTitle(tr("Find Pattern..."));
if(hexEdit.exec() != QDialog::Accepted)
return;
dsint addr = rvaToVa(getSelectionStart());
if(hexEdit.entireBlock())
addr = DbgMemFindBaseAddr(addr, 0);
QString command;
if(sender() == mFindPatternRegion)
{
bool startFromSelection = hexEdit.startFromSelection();
Config()->setBool("Disassembler", "FindPatternFromSelection", startFromSelection);
if(!startFromSelection)
addr = DbgMemFindBaseAddr(addr, 0);
command = QString("findall %1, %2").arg(ToHexString(addr), hexEdit.mHexEdit->pattern());
}
else if(sender() == mFindPatternModule)
@ -1775,18 +1778,18 @@ void CPUDisassembly::findCommandSlot()
LineEditDialog mLineEdit(this);
mLineEdit.enableCheckBox(refFindType == 0);
mLineEdit.setCheckBoxText(tr("Entire &Block"));
mLineEdit.setCheckBox(ConfigBool("Disassembler", "FindCommandEntireBlock"));
mLineEdit.setCheckBoxText(tr("Start from &Selection"));
mLineEdit.setCheckBox(ConfigBool("Disassembler", "FindCommandFromSelection"));
mLineEdit.setWindowTitle("Find Command");
if(mLineEdit.exec() != QDialog::Accepted)
return;
Config()->setBool("Disassembler", "FindCommandEntireBlock", mLineEdit.bChecked);
Config()->setBool("Disassembler", "FindCommandFromSelection", mLineEdit.bChecked);
char error[MAX_ERROR_SIZE] = "";
unsigned char dest[16];
int asmsize = 0;
duint va = rvaToVa(getInitialSelection());
if(mLineEdit.bChecked) // entire block
if(!mLineEdit.bChecked) // start search from selection
va = mMemPage->getBase();
if(!DbgFunctions()->Assemble(mMemPage->getBase() + mMemPage->getSize() / 2, dest, &asmsize, mLineEdit.editText.toUtf8().constData(), error))
@ -1795,11 +1798,11 @@ void CPUDisassembly::findCommandSlot()
return;
}
QString addr_text = ToPtrString(va);
QString addrText = ToPtrString(va);
dsint size = mMemPage->getSize();
if(refFindType != -1)
DbgCmdExec(QString("findasm \"%1\", %2, .%3, %4").arg(mLineEdit.editText).arg(addr_text).arg(size).arg(refFindType));
DbgCmdExec(QString("findasm \"%1\", %2, .%3, %4").arg(mLineEdit.editText).arg(addrText).arg(size).arg(refFindType));
else
{
duint start, end;
@ -1880,7 +1883,7 @@ void CPUDisassembly::labelHelpSlot()
QString baseUrl(setting);
QString fullUrl = baseUrl.replace("@topic", topic);
if(fullUrl.startsWith("execute://"))
if(baseUrl.startsWith("execute://"))
{
QString command = fullUrl.right(fullUrl.length() - 10);
QProcess::execute(command);

View File

@ -1443,14 +1443,16 @@ void CPUDump::binarySaveToFileSlot()
void CPUDump::findPattern()
{
HexEditDialog hexEdit(this);
hexEdit.showEntireBlock(true);
hexEdit.isDataCopiable(false);
hexEdit.showStartFromSelection(true, ConfigBool("Gui", "CPUDumpStartFromSelect"));
hexEdit.mHexEdit->setOverwriteMode(false);
hexEdit.setWindowTitle(tr("Find Pattern..."));
if(hexEdit.exec() != QDialog::Accepted)
return;
bool startFromSelection = hexEdit.startFromSelection();
Config()->setBool("Gui", "CPUDumpStartFromSelect", startFromSelection);
dsint addr = rvaToVa(getSelectionStart());
if(hexEdit.entireBlock())
if(!startFromSelection)
addr = DbgMemFindBaseAddr(addr, 0);
QString addrText = ToPtrString(addr);
DbgCmdExec(QString("findall " + addrText + ", " + hexEdit.mHexEdit->pattern() + ", &data&"));

View File

@ -288,20 +288,15 @@ void CPUInfoBox::disasmSelectionChanged(duint parVA)
}
else
{
QString valText;
auto symbolicName = getSymbolicNameStr(arg.value);
if(!symbolicName.contains(valText))
valText = QString("%1 (%2)").arg(symbolicName, valText);
else
valText = symbolicName;
QString valText = getSymbolicNameStr(arg.value);
QString mnemonic(arg.mnemonic);
bool ok;
mnemonic.toULongLong(&ok, 16);
if(ok) //skip certain numbers
{
if(ToHexString(arg.value) == symbolicName)
if(ToHexString(arg.value) == valText)
continue;
setInfoLine(j, symbolicName);
setInfoLine(j, valText);
}
else if(!mnemonic.startsWith("xmm") &&
!mnemonic.startsWith("ymm") &&

View File

@ -254,7 +254,7 @@ void CPUMultiDump::showDisassemblyTabSlot(duint selectionStart, duint selectionE
mExtraDisassembly->disassembleAtSlot(selectionStart, Bridge::getBridge()->mLastCip);
if(clearHistory)
mExtraDisassembly->historyClear();
// Make the address visisble in memory
// Make the address visible in memory
mExtraDisassembly->disassembleAt(selectionStart, true, -1);
// Set selection to match the dump
mExtraDisassembly->setSingleSelection(selectionStart - mExtraDisassembly->getBase());

View File

@ -217,7 +217,7 @@ void CPUSideBar::paintEvent(QPaintEvent* event)
for(duint line = 0; line < mViewableRows; line++)
{
if(line >= mInstrBuffer->size()) //at the end of the page it will crash otherwise
if(line >= (duint)mInstrBuffer->size()) //at the end of the page it will crash otherwise
break;
const Instruction_t & instr = mInstrBuffer->at(line);
@ -817,7 +817,7 @@ void CPUSideBar::AllocateJumpOffsets(std::vector<JumpLine> & jumpLines, std::vec
unsigned int maxJmpOffset = 0;
if(jmp.line < jmp.destLine)
{
for(int j = jmp.line; j <= jmp.destLine && j < mViewableRows; j++)
for(int j = jmp.line; j <= jmp.destLine && (duint)j < mViewableRows; j++)
{
if(numLines[j] > maxJmpOffset)
maxJmpOffset = numLines[j];
@ -834,7 +834,7 @@ void CPUSideBar::AllocateJumpOffsets(std::vector<JumpLine> & jumpLines, std::vec
jmp.jumpOffset = maxJmpOffset + 1;
if(jmp.line < jmp.destLine)
{
for(int j = jmp.line; j <= jmp.destLine && j < mViewableRows; j++)
for(int j = jmp.line; j <= jmp.destLine && (duint)j < mViewableRows; j++)
numLines[j] = jmp.jumpOffset;
}
else
@ -842,9 +842,9 @@ void CPUSideBar::AllocateJumpOffsets(std::vector<JumpLine> & jumpLines, std::vec
for(int j = jmp.line; j >= jmp.destLine && j >= 0; j--)
numLines[j] = jmp.jumpOffset;
}
if(jmp.line >= 0 && jmp.line < mViewableRows)
if(jmp.line >= 0 && (duint)jmp.line < mViewableRows)
numLines[jmp.line + mViewableRows] = jmp.jumpOffset;
if(jmp.destLine >= 0 && jmp.destLine < mViewableRows)
if(jmp.destLine >= 0 && (duint)jmp.destLine < mViewableRows)
numLines[jmp.destLine + mViewableRows] = jmp.jumpOffset;
}
// set label arrows according to jump offsets

View File

@ -865,15 +865,19 @@ void CPUStack::binaryPasteIgnoreSizeSlot()
void CPUStack::findPattern()
{
HexEditDialog hexEdit(this);
hexEdit.showEntireBlock(true);
hexEdit.isDataCopiable(false);
hexEdit.showStartFromSelection(true, ConfigBool("Gui", "CPUStackStartFromSelect"));
hexEdit.mHexEdit->setOverwriteMode(false);
hexEdit.setWindowTitle(tr("Find Pattern..."));
if(hexEdit.exec() != QDialog::Accepted)
return;
dsint addr = rvaToVa(getSelectionStart());
if(hexEdit.entireBlock())
bool startFromSelection = hexEdit.startFromSelection();
Config()->setBool("Gui", "CPUStackStartFromSelect", startFromSelection);
if(!startFromSelection)
addr = DbgMemFindBaseAddr(addr, 0);
QString addrText = ToPtrString(addr);
DbgCmdExec(QString("findall " + addrText + ", " + hexEdit.mHexEdit->pattern() + ", &data&"));
emit displayReferencesWidget();

View File

@ -7,7 +7,7 @@ CallStackView::CallStackView(StdTable* parent) : StdIconTable(parent)
{
int charwidth = getCharWidth();
addColumnAt(8 * charwidth, tr("Thread ID"), false);
addColumnAt(32 * charwidth, tr("Thread ID"), false);
addColumnAt(8 + charwidth * sizeof(dsint) * 2, tr("Address"), false); //address in the stack
addColumnAt(8 + charwidth * sizeof(dsint) * 2, tr("To"), false); //return to
addColumnAt(8 + charwidth * sizeof(dsint) * 2, tr("From"), false); //return from
@ -17,9 +17,9 @@ CallStackView::CallStackView(StdTable* parent) : StdIconTable(parent)
setIconColumn(ColParty);
loadColumnFromConfig("CallStack");
connect(Bridge::getBridge(), SIGNAL(updateCallStack()), this, SLOT(updateCallStack()));
connect(Bridge::getBridge(), SIGNAL(updateCallStack()), this, SLOT(updateCallStackSlot()));
connect(this, SIGNAL(contextMenuSignal(QPoint)), this, SLOT(contextMenuSlot(QPoint)));
connect(this, SIGNAL(doubleClickedSignal()), this, SLOT(followFrom()));
connect(this, SIGNAL(doubleClickedSignal()), this, SLOT(followFromSlot()));
setupContextMenu();
@ -37,26 +37,27 @@ void CallStackView::setupContextMenu()
return getSelectionVa();
});
QIcon icon = DIcon(ArchValue("processor32", "processor64"));
mMenuBuilder->addAction(makeAction(icon, tr("Follow &Address"), SLOT(followAddress())), [this](QMenu*)
mMenuBuilder->addAction(makeAction(icon, tr("Follow &Address"), SLOT(followAddressSlot())), [this](QMenu*)
{
return isSelectionValid();
});
mMenuBuilder->addAction(makeAction(icon, tr("Follow &To"), SLOT(followTo())), [this](QMenu*)
mMenuBuilder->addAction(makeAction(icon, tr("Follow &To"), SLOT(followToSlot())), [this](QMenu*)
{
return isSelectionValid();
});
QAction* mFollowFrom = mMenuBuilder->addAction(makeAction(icon, tr("Follow &From"), SLOT(followFrom())), [this](QMenu*)
QAction* mFollowFrom = mMenuBuilder->addAction(makeAction(icon, tr("Follow &From"), SLOT(followFromSlot())), [this](QMenu*)
{
return !getCellContent(getInitialSelection(), ColFrom).isEmpty() && isSelectionValid();
});
mFollowFrom->setShortcutContext(Qt::WidgetShortcut);
mFollowFrom->setShortcut(QKeySequence("enter"));
connect(this, SIGNAL(enterPressedSignal()), this, SLOT(followFrom()));
connect(this, SIGNAL(enterPressedSignal()), this, SLOT(followFromSlot()));
// Breakpoint menu
// TODO: Is Label/Comment/Bookmark useful?
mCommonActions->build(mMenuBuilder, CommonActions::ActionBreakpoint);
mMenuBuilder->addSeparator();
QAction* showSuspectedCallStack = makeAction(tr("Show Suspected Call Stack Frame"), SLOT(showSuspectedCallStack()));
QAction* showSuspectedCallStack = makeAction(tr("Show Suspected Call Stack Frame"), SLOT(showSuspectedCallStackSlot()));
mMenuBuilder->addAction(showSuspectedCallStack, [showSuspectedCallStack](QMenu*)
{
duint i;
@ -68,6 +69,20 @@ void CallStackView::setupContextMenu()
showSuspectedCallStack->setText(tr("Show Suspected Call Stack Frame"));
return true;
});
mMenuBuilder->addSeparator();
QAction* followInThreads = makeAction(DIcon("arrow-threads"), tr("Follow in Threads"), SLOT(followInThreadsSlot()));
mMenuBuilder->addAction(followInThreads, [this](QMenu*)
{
return isThreadHeaderSelected();
});
QAction* renameThread = makeAction(DIcon("thread-setname"), tr("Rename Thread"), SLOT(renameThreadSlot()));
mMenuBuilder->addAction(renameThread, [this](QMenu*)
{
return isThreadHeaderSelected();
});
MenuBuilder* mCopyMenu = new MenuBuilder(this);
setupCopyMenu(mCopyMenu);
// Column count cannot be zero
@ -121,7 +136,7 @@ QString CallStackView::paintContent(QPainter* painter, duint row, duint col, int
return StdIconTable::paintContent(painter, row, col, x, y, w, h);
}
void CallStackView::updateCallStack()
void CallStackView::updateCallStackSlot()
{
if(!DbgFunctions()->GetCallStackByThread)
return;
@ -130,7 +145,7 @@ void CallStackView::updateCallStack()
memset(&threadList, 0, sizeof(THREADLIST));
DbgGetThreadList(&threadList);
int currentRow = 0;
duint currentRow = 0;
int currentIndexToDraw = 0;
setRowCount(0);
for(int j = 0; j < threadList.count; j++)
@ -146,7 +161,15 @@ void CallStackView::updateCallStack()
memset(&callstack, 0, sizeof(DBGCALLSTACK));
DbgFunctions()->GetCallStackByThread(threadList.list[currentIndexToDraw].BasicInfo.Handle, &callstack);
setRowCount(currentRow + callstack.total + 1);
setCellContent(currentRow, ColThread, ToDecString(threadList.list[currentIndexToDraw].BasicInfo.ThreadId));
auto threadId = threadList.list[currentIndexToDraw].BasicInfo.ThreadId;
QString threadName = threadList.list[currentIndexToDraw].BasicInfo.threadName;
QString colThreadString = ToDecString(threadList.list[currentIndexToDraw].BasicInfo.ThreadId);
if(threadName.size() > 0)
colThreadString += " - " + threadName; // The " - " is crucial here, because later split is happening
setCellContent(currentRow, ColThread, colThreadString);
currentRow++;
@ -161,6 +184,7 @@ void CallStackView::updateCallStack()
addrText = ToPtrString(callstack.entries[i].from);
setCellContent(currentRow, ColFrom, addrText);
}
setCellUserdata(currentRow, ColThread, threadId);
setCellUserdata(currentRow, ColFrom, callstack.entries[i].from);
setCellUserdata(currentRow, ColTo, callstack.entries[i].to);
setCellUserdata(currentRow, ColAddress, callstack.entries[i].addr);
@ -205,25 +229,52 @@ void CallStackView::contextMenuSlot(const QPoint pos)
menu.exec(mapToGlobal(pos)); //execute context menu
}
void CallStackView::followAddress()
void CallStackView::followAddressSlot()
{
QString addrText = getCellContent(getInitialSelection(), ColAddress);
DbgCmdExecDirect(QString("sdump " + addrText));
switchThread();
}
void CallStackView::followTo()
void CallStackView::followToSlot()
{
QString addrText = getCellContent(getInitialSelection(), ColTo);
DbgCmdExecDirect(QString("disasm " + addrText));
switchThread();
}
void CallStackView::followFrom()
void CallStackView::followFromSlot()
{
QString addrText = getCellContent(getInitialSelection(), ColFrom);
DbgCmdExecDirect(QString("disasm " + addrText));
// Double click signal is recieved by this as well, so we must check again.
if(!addrText.isEmpty() && isSelectionValid())
{
DbgCmdExecDirect(QString("disasm " + addrText));
switchThread();
}
}
void CallStackView::showSuspectedCallStack()
void CallStackView::renameThreadSlot()
{
QStringList split = getCellContent(getInitialSelection(), 0).split(" - ", QString::SplitBehavior::SkipEmptyParts);
duint threadId = split[0].toInt();
QString threadName = split.length() > 1 ? split[1] : "";
if(!SimpleInputBox(this, tr("Thread name - %1").arg(threadId), threadName, threadName, QString()))
return;
DbgCmdExec(QString("setthreadname %1, \"%2\"").arg(ToHexString(threadId)).arg(DbgCmdEscape(threadName)));
}
void CallStackView::followInThreadsSlot()
{
QStringList threadIDName = getCellContent(getInitialSelection(), ColThread).split(" - ");
if(threadIDName[0].size() == 0)
return;
DbgCmdExecDirect(QString("showthreadid " + threadIDName[0]));
}
void CallStackView::showSuspectedCallStackSlot()
{
duint i;
if(!BridgeSettingGetUint("Engine", "ShowSuspectedCallStack", &i))
@ -231,10 +282,15 @@ void CallStackView::showSuspectedCallStack()
i = (i == 0) ? 1 : 0;
BridgeSettingSetUint("Engine", "ShowSuspectedCallStack", i);
DbgSettingsUpdated();
updateCallStack();
updateCallStackSlot();
emit Bridge::getBridge()->updateDump();
}
bool CallStackView::isThreadHeaderSelected()
{
return !getCellContent(getInitialSelection(), ColThread).isEmpty();
}
bool CallStackView::isSelectionValid()
{
return getCellContent(getInitialSelection(), ColThread).isEmpty();
@ -248,3 +304,12 @@ duint CallStackView::getSelectionVa()
else
return 0;
}
// Switch to the new thread if it is not the current thread
void CallStackView::switchThread()
{
DWORD currentThread = DbgGetThreadId();
DWORD newThread = getCellUserdata(getInitialSelection(), ColThread);
if(currentThread != newThread)
DbgCmdExecDirect(QString("switchthread %1").arg(ToHexString(newThread)).toUtf8().constData());
}

View File

@ -15,12 +15,14 @@ protected:
QString paintContent(QPainter* painter, duint row, duint col, int x, int y, int w, int h) override;
protected slots:
void updateCallStack();
void updateCallStackSlot();
void contextMenuSlot(const QPoint pos);
void followAddress();
void followTo();
void followFrom();
void showSuspectedCallStack();
void followAddressSlot();
void followToSlot();
void followFromSlot();
void showSuspectedCallStackSlot();
void followInThreadsSlot();
void renameThreadSlot();
private:
enum
@ -37,4 +39,6 @@ private:
MenuBuilder* mMenuBuilder;
CommonActions* mCommonActions;
bool isSelectionValid();
bool CallStackView::isThreadHeaderSelected();
void switchThread();
};

View File

@ -62,6 +62,7 @@ void ColumnReorderDialog::on_okButton_clicked()
mParent->mColumnOrder[i] = col;
mParent->setColumnHidden(col, true);
}
mParent->reloadData();
this->done(QDialog::Accepted);
}

View File

@ -218,7 +218,7 @@ void DisassemblerGraphView::resizeEvent(QResizeEvent* event)
adjustSize(event->size().width(), event->size().height());
}
duint DisassemblerGraphView::get_cursor_pos()
duint DisassemblerGraphView::get_cursor_pos() const
{
if(this->cur_instr == 0)
return this->function;
@ -934,7 +934,7 @@ void DisassemblerGraphView::wheelEvent(QWheelEvent* event)
}
}
bool DisassemblerGraphView::isMouseEventInBlock(QMouseEvent* event)
bool DisassemblerGraphView::isMouseEventInBlock(QMouseEvent* event) const
{
//Convert coordinates to system used in blocks
int xofs = this->horizontalScrollBar()->value();
@ -945,7 +945,7 @@ bool DisassemblerGraphView::isMouseEventInBlock(QMouseEvent* event)
// Check each block for hits
for(auto & blockIt : this->blocks)
{
DisassemblerBlock & block = blockIt.second;
auto & block = blockIt.second;
//Compute coordinate relative to text area in block
int blockx = x - (block.x + (2 * this->charWidth));
int blocky = y - (block.y + (2 * this->charWidth));
@ -959,7 +959,7 @@ bool DisassemblerGraphView::isMouseEventInBlock(QMouseEvent* event)
return false;
}
duint DisassemblerGraphView::getInstrForMouseEvent(QMouseEvent* event)
duint DisassemblerGraphView::getInstrForMouseEvent(QMouseEvent* event) const
{
//Convert coordinates to system used in blocks
int xofs = this->horizontalScrollBar()->value();
@ -970,7 +970,7 @@ duint DisassemblerGraphView::getInstrForMouseEvent(QMouseEvent* event)
//Check each block for hits
for(auto & blockIt : this->blocks)
{
DisassemblerBlock & block = blockIt.second;
auto & block = blockIt.second;
//Compute coordinate relative to text area in block
int blockx = x - (block.x + (2 * this->charWidth));
int blocky = y - (block.y + (2 * this->charWidth));
@ -985,7 +985,7 @@ duint DisassemblerGraphView::getInstrForMouseEvent(QMouseEvent* event)
int cur_row = int(block.block.header_text.lines.size());
if(row < cur_row)
return block.block.entry;
for(Instr & instr : block.block.instrs)
for(auto & instr : block.block.instrs)
{
if(row < cur_row + int(instr.text.lines.size()))
return instr.addr;
@ -995,7 +995,7 @@ duint DisassemblerGraphView::getInstrForMouseEvent(QMouseEvent* event)
return 0;
}
bool DisassemblerGraphView::getTokenForMouseEvent(QMouseEvent* event, ZydisTokenizer::SingleToken & tokenOut)
bool DisassemblerGraphView::getTokenForMouseEvent(QMouseEvent* event, ZydisTokenizer::SingleToken & tokenOut) const
{
//Convert coordinates to system used in blocks
int xofs = this->horizontalScrollBar()->value();
@ -1006,7 +1006,7 @@ bool DisassemblerGraphView::getTokenForMouseEvent(QMouseEvent* event, ZydisToken
//Check each block for hits
for(auto & blockIt : this->blocks)
{
DisassemblerBlock & block = blockIt.second;
auto & block = blockIt.second;
//Compute coordinate relative to text area in block
int blockx = x - (block.x + (2 * this->charWidth));
int blocky = y - (block.y + (2 * this->charWidth));
@ -1064,12 +1064,16 @@ bool DisassemblerGraphView::getTokenForMouseEvent(QMouseEvent* event, ZydisToken
bool DisassemblerGraphView::find_instr(duint addr, Instr & instrOut)
{
for(auto & blockIt : this->blocks)
{
for(Instr & instr : blockIt.second.block.instrs)
{
if(instr.addr == addr)
{
instrOut = instr;
return true;
}
}
}
return false;
}
@ -1358,7 +1362,7 @@ void DisassemblerGraphView::computeGraphLayout(DisassemblerBlock & block)
block.row_count = row_count;
}
bool DisassemblerGraphView::isEdgeMarked(EdgesVector & edges, int row, int col, int index)
bool DisassemblerGraphView::isEdgeMarked(EdgesVector & edges, int row, int col, int index) const
{
if(index >= int(edges[row][col].size()))
return false;
@ -2244,7 +2248,7 @@ void DisassemblerGraphView::setupContextMenu()
* There are several options for how menu will look like. This makes interaction more clear and predictable.
* E.g clicking outside of block (especially at large zoom level) will set breakpoint menu hidden
* as well as any action that needs text to be visible will also be hidden.
* Notice: keyboard shortcuts still work - this implies that user understands what he is doing. */
* Notice: keyboard shortcuts still work - this implies that the user understands what they are doing. */
mMenuBuilder = new MenuBuilder(this, [this](QMenu*)
{
@ -2692,7 +2696,7 @@ void DisassemblerGraphView::copyHighlightedTokenValueSlot()
Bridge::CopyToClipboard(text);
}
bool DisassemblerGraphView::getHighlightedTokenValueText(QString & text)
bool DisassemblerGraphView::getHighlightedTokenValueText(QString & text) const
{
if(mHighlightToken.type <= ZydisTokenizer::TokenType::MnemonicUnusual)
return false;

View File

@ -212,7 +212,7 @@ public:
void initFont();
void adjustSize(int viewportWidth, int viewportHeight, QPoint mousePosition = QPoint(0, 0), bool fitToWindow = false);
void resizeEvent(QResizeEvent* event);
duint get_cursor_pos();
duint get_cursor_pos() const;
void set_cursor_pos(duint addr);
std::tuple<duint, duint> get_selection_range();
void set_selection_range(std::tuple<duint, duint> range);
@ -220,9 +220,9 @@ public:
void paintNormal(QPainter & p, QRect & viewportRect, int xofs, int yofs);
void paintOverview(QPainter & p, QRect & viewportRect, int xofs, int yofs);
void paintEvent(QPaintEvent* event);
bool isMouseEventInBlock(QMouseEvent* event);
duint getInstrForMouseEvent(QMouseEvent* event);
bool getTokenForMouseEvent(QMouseEvent* event, ZydisTokenizer::SingleToken & token);
bool isMouseEventInBlock(QMouseEvent* event) const;
duint getInstrForMouseEvent(QMouseEvent* event) const;
bool getTokenForMouseEvent(QMouseEvent* event, ZydisTokenizer::SingleToken & token) const;
bool find_instr(duint addr, Instr & instr);
void mousePressEvent(QMouseEvent* event);
void mouseMoveEvent(QMouseEvent* event);
@ -236,7 +236,7 @@ public:
template<typename T>
using Matrix = std::vector<std::vector<T>>;
using EdgesVector = Matrix<std::vector<bool>>;
bool isEdgeMarked(EdgesVector & edges, int row, int col, int index);
bool isEdgeMarked(EdgesVector & edges, int row, int col, int index) const;
void markEdge(EdgesVector & edges, int row, int col, int index, bool used = true);
int findHorizEdgeIndex(EdgesVector & edges, int row, int min_col, int max_col);
int findVertEdgeIndex(EdgesVector & edges, int col, int min_row, int max_row);
@ -257,7 +257,7 @@ public:
VaHistory mHistory;
signals:
void selectionChanged(dsint parVA);
void selectionChanged(duint parVA);
void displayLogWidget();
void detachGraph();
@ -392,5 +392,5 @@ private:
XrefBrowseDialog* mXrefDlg = nullptr;
void addReferenceAction(QMenu* menu, duint addr, const QString & description);
bool getHighlightedTokenValueText(QString & text);
bool getHighlightedTokenValueText(QString & text) const;
};

View File

@ -184,6 +184,7 @@ void DisassemblyPopup::setAddress(duint addr)
// Get RVA
duint size;
duint base = DbgMemFindBaseAddr(addr, &size);
// Prepare RVA of every instruction
unsigned int i = 0;
instBuffer.clear();
@ -224,6 +225,7 @@ void DisassemblyPopup::setAddress(duint addr)
i++;
}
while(i < mMaxInstructions);
// Disassemble
for(auto & instruction : instBuffer)
{
@ -236,17 +238,28 @@ void DisassemblyPopup::setAddress(duint addr)
mWidth = std::max(mWidth, currentInstructionWidth);
mDisassemblyToken.push_back(std::make_pair(std::move(richText), DbgFunctions()->GetTraceRecordHitCount(instruction.rva) != 0));
}
// Address
mAddrText = getSymbolicName(addr);
// Comments
GetCommentFormat(addr, mAddrComment, &mAddrCommentAuto);
if(mAddrComment.length())
mAddrText.append(' ');
// Truncate first line to something reasonable
if(mAddrText.length() + mAddrComment.length() > 100)
mAddrComment.clear();
if(mAddrText.length() > 100)
mAddrText = mAddrText.left(100) + " ...";
// Calculate width of address
mWidth = std::max(mWidth, mFontMetrics->width(mAddrText) + mFontMetrics->width(mAddrComment));
mWidth += mCharWidth * 6;
mWidth += 3;
// Resize popup
resize(mWidth + 2, mCharHeight * int(mDisassemblyToken.size() + 1) + 2);
resize(mWidth + 2, mCharHeight * int(mDisassemblyToken.size() + 1) + 4);
}
update();
}

View File

@ -10,7 +10,9 @@ EditBreakpointDialog::EditBreakpointDialog(QWidget* parent, const BRIDGEBP & bp)
mBp(bp)
{
ui->setupUi(this);
setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint | Qt::MSWindowsFixedSizeDialogHint);
setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
setFixedHeight(sizeHint().height()); // resizable only horizontally
switch(bp.type)
{
case bp_dll:
@ -35,6 +37,8 @@ EditBreakpointDialog::EditBreakpointDialog(QWidget* parent, const BRIDGEBP & bp)
setWindowIcon(DIcon("breakpoint"));
loadFromBp();
connect(this, SIGNAL(accepted()), this, SLOT(acceptedSlot()));
Config()->loadWindowGeometry(this);
}
@ -61,58 +65,27 @@ void EditBreakpointDialog::loadFromBp()
template<typename T>
void copyTruncate(T & dest, QString src)
{
src.replace(QChar('\\'), QString("\\\\"));
src.replace(QChar('"'), QString("\\\""));
src = DbgCmdEscape(std::move(src));
strncpy_s(dest, src.toUtf8().constData(), _TRUNCATE);
}
void EditBreakpointDialog::on_editName_textEdited(const QString & arg1)
{
copyTruncate(mBp.name, arg1);
}
void EditBreakpointDialog::on_editBreakCondition_textEdited(const QString & arg1)
{
copyTruncate(mBp.breakCondition, arg1);
}
void EditBreakpointDialog::on_editLogText_textEdited(const QString & arg1)
{
Q_UNUSED(arg1);
ui->checkBoxSilent->setChecked(true);
copyTruncate(mBp.logText, arg1);
}
void EditBreakpointDialog::on_editLogCondition_textEdited(const QString & arg1)
void EditBreakpointDialog::acceptedSlot()
{
copyTruncate(mBp.logCondition, arg1);
}
copyTruncate(mBp.breakCondition, ui->editBreakCondition->text());
copyTruncate(mBp.logText, ui->editLogText->text());
copyTruncate(mBp.logCondition, ui->editLogCondition->text());
copyTruncate(mBp.commandText, ui->editCommandText->text());
copyTruncate(mBp.commandCondition, ui->editCommandCondition->text());
copyTruncate(mBp.name, ui->editName->text());
void EditBreakpointDialog::on_editCommandText_textEdited(const QString & arg1)
{
copyTruncate(mBp.commandText, arg1);
}
void EditBreakpointDialog::on_editCommandCondition_textEdited(const QString & arg1)
{
copyTruncate(mBp.commandCondition, arg1);
}
void EditBreakpointDialog::on_checkBoxFastResume_toggled(bool checked)
{
mBp.fastResume = checked;
}
void EditBreakpointDialog::on_spinHitCount_valueChanged(int arg1)
{
mBp.hitCount = arg1;
}
void EditBreakpointDialog::on_checkBoxSilent_toggled(bool checked)
{
mBp.silent = checked;
}
void EditBreakpointDialog::on_checkBoxSingleshoot_toggled(bool checked)
{
mBp.singleshoot = checked;
mBp.singleshoot = ui->checkBoxSingleshoot->isChecked();
mBp.fastResume = ui->checkBoxFastResume->isChecked();
mBp.hitCount = ui->spinHitCount->value();
mBp.silent = ui->checkBoxSilent->isChecked();
}

View File

@ -21,16 +21,8 @@ public:
}
private slots:
void on_editName_textEdited(const QString & arg1);
void on_editBreakCondition_textEdited(const QString & arg1);
void on_editLogText_textEdited(const QString & arg1);
void on_editLogCondition_textEdited(const QString & arg1);
void on_editCommandText_textEdited(const QString & arg1);
void on_editCommandCondition_textEdited(const QString & arg1);
void on_checkBoxFastResume_toggled(bool checked);
void on_spinHitCount_valueChanged(int arg1);
void on_checkBoxSilent_toggled(bool checked);
void on_checkBoxSingleshoot_toggled(bool checked);
void acceptedSlot();
private:
Ui::EditBreakpointDialog* ui;

View File

@ -46,7 +46,9 @@ GotoDialog::GotoDialog(QWidget* parent, bool allowInvalidExpression, bool allowI
connect(this, SIGNAL(finished(int)), this, SLOT(finishedSlot(int)));
connect(Config(), SIGNAL(disableAutoCompleteUpdated()), this, SLOT(disableAutoCompleteUpdated()));
auto prevSize = size();
Config()->loadWindowGeometry(this);
this->resize(prevSize);
}
GotoDialog::~GotoDialog()
@ -61,6 +63,9 @@ void GotoDialog::showEvent(QShowEvent* event)
{
Q_UNUSED(event);
mValidateThread->start();
// Fix the label width
ui->labelError->setMaximumWidth(ui->labelError->width());
}
void GotoDialog::hideEvent(QHideEvent* event)
@ -167,7 +172,9 @@ void GotoDialog::expressionChanged(bool validExpression, bool validPointer, dsin
addrText = QString(module) + "." + ToPtrString(addr);
else
addrText = ToPtrString(addr);
ui->labelError->setText(tr("<font color='#00DD00'><b>Correct expression! -&gt; </b></font>") + addrText);
ui->labelError->setToolTip(QString("<qt>%1</qt>").arg(addrText.toHtmlEscaped()));
ui->labelError->setText(tr("<font color='#00DD00'><b>Correct expression! -&gt; </b></font>") + addrText.toHtmlEscaped());
setOkEnabled(true);
expressionText = expression;
}

View File

@ -26,10 +26,23 @@
<item>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="HistoryLineEdit" name="editExpression"/>
<widget class="HistoryLineEdit" name="editExpression">
<property name="maximumSize">
<size>
<width>4132</width>
<height>16777215</height>
</size>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="labelError">
<property name="maximumSize">
<size>
<width>4132</width>
<height>16777215</height>
</size>
</property>
<property name="text">
<string/>
</property>
@ -58,7 +71,7 @@
<item>
<widget class="QPushButton" name="buttonOk">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Minimum">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
@ -71,7 +84,7 @@
<item>
<widget class="QPushButton" name="buttonCancel">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Minimum">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>

View File

@ -47,7 +47,7 @@ HandlesView::HandlesView(QWidget* parent) : QWidget(parent)
mWindowsTable->addColumnAt(8 + 16 * charWidth, tr("StyleEx"), true, "", StdTable::SortBy::AsHex);
mWindowsTable->addColumnAt(8 + 8 * charWidth, tr("Parent"), true);
mWindowsTable->addColumnAt(8 + 20 * charWidth, tr("Size"), true);
mWindowsTable->addColumnAt(8 + 6 * charWidth, tr("Enable"), true);
mWindowsTable->addColumnAt(8 + 8 * charWidth, tr("Enable"), true);
mWindowsTable->loadColumnFromConfig("Window");
mWindowsTable->setIconColumn(2);
@ -118,6 +118,8 @@ HandlesView::HandlesView(QWidget* parent) : QWidget(parent)
mActionFollowProc = new QAction(DIcon(ArchValue("processor32", "processor64")), tr("Follow Proc in Disassembler"), this);
connect(mActionFollowProc, SIGNAL(triggered()), this, SLOT(followInDisasmSlot()));
mActionFollowProc->setShortcut(Qt::Key_Return);
mActionFollowThread = new QAction(DIcon("arrow-threads"), tr("Follow in Threads"), this);
connect(mActionFollowThread, SIGNAL(triggered()), this, SLOT(followInThreads()));
mWindowsTable->addAction(mActionFollowProc);
mActionToggleProcBP = new QAction(DIcon("breakpoint_toggle"), tr("Toggle Breakpoint in Proc"), this);
connect(mActionToggleProcBP, SIGNAL(triggered()), this, SLOT(toggleBPSlot()));
@ -127,12 +129,15 @@ HandlesView::HandlesView(QWidget* parent) : QWidget(parent)
connect(mHandlesTable, SIGNAL(listContextMenuSignal(QMenu*)), this, SLOT(handlesTableContextMenuSlot(QMenu*)));
connect(mWindowsTable, SIGNAL(listContextMenuSignal(QMenu*)), this, SLOT(windowsTableContextMenuSlot(QMenu*)));
connect(mWindowsTable, SIGNAL(enterPressedSignal()), this, SLOT(followInDisasmSlot()));
connect(mTcpConnectionsTable, SIGNAL(listContextMenuSignal(QMenu*)), this, SLOT(tcpConnectionsTableContextMenuSlot(QMenu*)));
connect(mPrivilegesTable, SIGNAL(contextMenuSignal(const QPoint &)), this, SLOT(privilegesTableContextMenuSlot(const QPoint &)));
connect(Config(), SIGNAL(shortcutsUpdated()), this, SLOT(refreshShortcuts()));
connect(Bridge::getBridge(), SIGNAL(dbgStateChanged(DBGSTATE)), this, SLOT(dbgStateChanged(DBGSTATE)));
#ifdef _WIN32 // This is only supported on Windows Vista or greater
if(!IsWindowsVistaOrGreater())
#endif //_WIN32
{
mTcpConnectionsTable->setRowCount(1);
mTcpConnectionsTable->setCellContent(0, 0, tr("TCP Connection enumeration is only available on Windows Vista or greater."));
@ -218,6 +223,7 @@ void HandlesView::windowsTableContextMenuSlot(QMenu* menu)
}
menu->addAction(mActionFollowProc);
menu->addAction(mActionFollowThread);
menu->addAction(mActionToggleProcBP);
menu->addAction(mActionMessageProcBP);
}
@ -322,6 +328,12 @@ void HandlesView::followInDisasmSlot()
DbgCmdExec(QString("disasm %1").arg(mWindowsTable->mCurList->getCellContent(mWindowsTable->mCurList->getInitialSelection(), 0)));
}
void HandlesView::followInThreads()
{
auto threadId = mWindowsTable->mCurList->getCellUserdata(mWindowsTable->mCurList->getInitialSelection(), 4);
DbgCmdExec(QString("showthreadid %1").arg(ToHexString(threadId)));
}
void HandlesView::toggleBPSlot()
{
auto & mCurList = *mWindowsTable->mCurList;
@ -395,6 +407,8 @@ void HandlesView::enumHandles()
static QIcon getWindowIcon(HWND hWnd)
{
QIcon result;
#ifdef _WIN32
HICON winIcon;
if(IsWindowUnicode(hWnd))
{
@ -407,12 +421,12 @@ static QIcon getWindowIcon(HWND hWnd)
//if(SendMessageTimeoutA(hWnd, WM_GETICON, 0, 0, SMTO_ABORTIFHUNG | SMTO_BLOCK | SMTO_ERRORONEXIT, 500, (PDWORD)&winIcon) == 0)
winIcon = (HICON)GetClassLongPtrA(hWnd, -14); //GCL_HICON
}
QIcon result;
if(winIcon != 0)
{
result = QIcon(QtWin::fromHICON(winIcon));
DestroyIcon(winIcon);
}
#endif //_WIN32
return result;
}
@ -430,13 +444,13 @@ void HandlesView::enumWindows()
mWindowsTable->setCellContent(i, 1, ToHexString(windows[i].handle));
mWindowsTable->setCellContent(i, 2, QString(windows[i].windowTitle));
mWindowsTable->setCellContent(i, 3, QString(windows[i].windowClass));
char threadname[MAX_THREAD_NAME_SIZE];
if(DbgFunctions()->ThreadGetName(windows[i].threadId, threadname) && *threadname != '\0')
mWindowsTable->setCellContent(i, 4, QString::fromUtf8(threadname));
else if(Config()->getBool("Gui", "PidTidInHex"))
mWindowsTable->setCellContent(i, 4, ToHexString(windows[i].threadId));
auto tidStr = QString().sprintf(Config()->getBool("Gui", "PidTidInHex") ? "%X" : "%u", windows[i].threadId);
char threadName[MAX_THREAD_NAME_SIZE];
if(DbgFunctions()->ThreadGetName(windows[i].threadId, threadName) && *threadName != '\0')
mWindowsTable->setCellContent(i, 4, QString::fromUtf8(threadName) + QString(" (%1)").arg(tidStr));
else
mWindowsTable->setCellContent(i, 4, QString::number(windows[i].threadId));
mWindowsTable->setCellContent(i, 4, tidStr);
mWindowsTable->setCellUserdata(i, 4, windows[i].threadId);
//Style
mWindowsTable->setCellContent(i, 5, ToHexString(windows[i].style));
//StyleEx

View File

@ -35,6 +35,7 @@ public slots:
void enableWindowSlot();
void disableWindowSlot();
void followInDisasmSlot();
void followInThreads();
void toggleBPSlot();
void messagesBPSlot();
@ -56,6 +57,7 @@ private:
QAction* mActionEnableWindow;
QAction* mActionDisableWindow;
QAction* mActionFollowProc;
QAction* mActionFollowThread;
QAction* mActionToggleProcBP;
QAction* mActionMessageProcBP;

View File

@ -28,6 +28,7 @@ HexEditDialog::HexEditDialog(QWidget* parent) : QDialog(parent), ui(new Ui::HexE
ui->chkKeepSize->setChecked(ConfigBool("HexDump", "KeepSize"));
ui->chkKeepSize->hide();
ui->chkEntireBlock->hide();
ui->chkFromSelection->hide();
mDataInitialized = false;
stringEditorLock = false;
@ -112,6 +113,12 @@ void HexEditDialog::showKeepSize(bool show)
ui->chkKeepSize->setVisible(show);
}
void HexEditDialog::showStartFromSelection(bool show, bool checked)
{
ui->chkFromSelection->setVisible(show);
ui->chkFromSelection->setChecked(checked);
}
void HexEditDialog::isDataCopiable(bool copyDataEnabled)
{
if(copyDataEnabled == false)
@ -150,6 +157,11 @@ bool HexEditDialog::entireBlock()
return ui->chkEntireBlock->isChecked();
}
bool HexEditDialog::startFromSelection()
{
return ui->chkFromSelection->isChecked();
}
void HexEditDialog::updateStyle()
{
QString style = QString("QLineEdit { border-style: outset; border-width: 1px; border-color: %1; color: %1; background-color: %2 }").arg(ConfigColor("HexEditTextColor").name(), ConfigColor("HexEditBackgroundColor").name());

View File

@ -18,10 +18,12 @@ public:
void showEntireBlock(bool show, bool checked = false);
void showKeepSize(bool show);
void showStartFromSelection(bool show, bool checked = false);
void isDataCopiable(bool copyDataEnabled);
void updateCodepage();
bool entireBlock();
bool startFromSelection();
QHexEdit* mHexEdit;

View File

@ -20,6 +20,9 @@
<layout class="QVBoxLayout" name="verticalLayout_4">
<item>
<widget class="QTabWidget" name="tabModeSelect">
<property name="focusPolicy">
<enum>Qt::NoFocus</enum>
</property>
<property name="currentIndex">
<number>0</number>
</property>
@ -53,7 +56,7 @@
<string/>
</property>
<property name="pixmap">
<pixmap resource="../../resource.qrc">:/Default/icons/fatal-error.png</pixmap>
<pixmap>:/Default/icons/fatal-error.png</pixmap>
</property>
</widget>
</item>
@ -84,6 +87,9 @@
</item>
<item>
<widget class="HexLineEdit" name="lineEditAscii">
<property name="focusPolicy">
<enum>Qt::StrongFocus</enum>
</property>
<property name="styleSheet">
<string notr="true">QLineEdit {border-style: outset; border-width: 1px; border-color: black}</string>
</property>
@ -165,7 +171,7 @@
<string/>
</property>
<property name="pixmap">
<pixmap resource="../../resource.qrc">:/Default/icons/fatal-error.png</pixmap>
<pixmap>:/Default/icons/fatal-error.png</pixmap>
</property>
</widget>
</item>
@ -206,6 +212,9 @@
<height>16777215</height>
</size>
</property>
<property name="focusPolicy">
<enum>Qt::NoFocus</enum>
</property>
<property name="text">
<string>Code&amp;page...</string>
</property>
@ -239,7 +248,7 @@
<item>
<widget class="QScrollArea" name="scrollArea">
<property name="focusPolicy">
<enum>Qt::NoFocus</enum>
<enum>Qt::StrongFocus</enum>
</property>
<property name="widgetResizable">
<bool>true</bool>
@ -310,6 +319,9 @@
</item>
<item>
<widget class="QPushButton" name="btnCodePage2">
<property name="focusPolicy">
<enum>Qt::NoFocus</enum>
</property>
<property name="text">
<string>Code&amp;page...</string>
</property>
@ -317,6 +329,9 @@
</item>
<item>
<widget class="QCheckBox" name="chkCRLF">
<property name="focusPolicy">
<enum>Qt::NoFocus</enum>
</property>
<property name="toolTip">
<string>Convert to Windows style line ending.</string>
</property>
@ -383,6 +398,9 @@
<layout class="QHBoxLayout" name="horizontalLayout_5">
<item>
<widget class="QPushButton" name="buttonCopy">
<property name="focusPolicy">
<enum>Qt::NoFocus</enum>
</property>
<property name="text">
<string>Copy</string>
</property>
@ -413,6 +431,9 @@
</item>
<item>
<widget class="QSpinBox" name="spinBox">
<property name="focusPolicy">
<enum>Qt::NoFocus</enum>
</property>
<property name="minimum">
<number>1</number>
</property>
@ -433,6 +454,9 @@
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QCheckBox" name="chkKeepSize">
<property name="focusPolicy">
<enum>Qt::NoFocus</enum>
</property>
<property name="text">
<string>&amp;Keep Size</string>
</property>
@ -440,11 +464,21 @@
</item>
<item>
<widget class="QCheckBox" name="chkEntireBlock">
<property name="focusPolicy">
<enum>Qt::NoFocus</enum>
</property>
<property name="text">
<string>&amp;Entire Block</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="chkFromSelection">
<property name="text">
<string>Start from &amp;Selection</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
@ -460,6 +494,9 @@
</item>
<item>
<widget class="QPushButton" name="btnOk">
<property name="focusPolicy">
<enum>Qt::NoFocus</enum>
</property>
<property name="text">
<string>&amp;OK</string>
</property>
@ -470,6 +507,9 @@
</item>
<item>
<widget class="QPushButton" name="btnCancel">
<property name="focusPolicy">
<enum>Qt::NoFocus</enum>
</property>
<property name="text">
<string>&amp;Cancel</string>
</property>
@ -486,6 +526,15 @@
<header>HexLineEdit.h</header>
</customwidget>
</customwidgets>
<tabstops>
<tabstop>lineEditAscii</tabstop>
<tabstop>lineEditUnicode</tabstop>
<tabstop>lineEditCodepage</tabstop>
<tabstop>scrollArea</tabstop>
<tabstop>listType</tabstop>
<tabstop>editCode</tabstop>
<tabstop>stringEditor</tabstop>
</tabstops>
<resources>
<include location="../../resource.qrc"/>
</resources>

View File

@ -91,6 +91,7 @@ MainWindow::MainWindow(QWidget* parent)
connect(Bridge::getBridge(), SIGNAL(getStrWindow(QString, QString*)), this, SLOT(getStrWindow(QString, QString*)));
connect(Bridge::getBridge(), SIGNAL(showCpu()), this, SLOT(displayCpuWidget()));
connect(Bridge::getBridge(), SIGNAL(showReferences()), this, SLOT(displayReferencesWidget()));
connect(Bridge::getBridge(), SIGNAL(showThreads()), this, SLOT(displayThreadsWidget()));
connect(Bridge::getBridge(), SIGNAL(addQWidgetTab(QWidget*)), this, SLOT(addQWidgetTab(QWidget*)));
connect(Bridge::getBridge(), SIGNAL(showQWidgetTab(QWidget*)), this, SLOT(showQWidgetTab(QWidget*)));
connect(Bridge::getBridge(), SIGNAL(closeQWidgetTab(QWidget*)), this, SLOT(closeQWidgetTab(QWidget*)));
@ -153,7 +154,7 @@ MainWindow::MainWindow(QWidget* parent)
// Symbol view
mSymbolView = new SymbolView();
Bridge::getBridge()->symbolView = mSymbolView;
Bridge::getBridge()->mSymbolView = mSymbolView;
mSymbolView->setWindowTitle(tr("Symbols"));
mSymbolView->setWindowIcon(DIcon("pdb"));
mSymbolView->hide();
@ -206,7 +207,7 @@ MainWindow::MainWindow(QWidget* parent)
// Reference manager
mReferenceManager = new ReferenceManager(this);
Bridge::getBridge()->referenceManager = mReferenceManager;
Bridge::getBridge()->mReferenceManager = mReferenceManager;
mReferenceManager->setWindowTitle(tr("References"));
mReferenceManager->setWindowIcon(DIcon("search"));
@ -368,6 +369,7 @@ MainWindow::MainWindow(QWidget* parent)
connect(mCpuWidget->getDisasmWidget(), SIGNAL(displaySourceManagerWidget()), this, SLOT(displaySourceViewWidget()));
connect(mCpuWidget->getDisasmWidget(), SIGNAL(displayLogWidget()), this, SLOT(displayLogWidget()));
connect(mCpuWidget->getDisasmWidget(), SIGNAL(displaySymbolsWidget()), this, SLOT(displaySymbolWidget()));
connect(mThreadView, SIGNAL(displayThreadsView()), this, SLOT(displayThreadsWidget()));
connect(mCpuWidget->getDisasmWidget(), SIGNAL(showPatches()), this, SLOT(patchWindow()));
connect(mCpuWidget->getGraphWidget(), SIGNAL(displayLogWidget()), this, SLOT(displayLogWidget()));
@ -1246,7 +1248,7 @@ void MainWindow::openFileSlot()
void MainWindow::openRecentFileSlot(QString filename)
{
DbgCmdExec(QString().sprintf("init \"%s\"", filename.toUtf8().constData()));
DbgCmdExec(QString().sprintf("init \"%s\"", DbgCmdEscape(filename).toUtf8().constData()));
}
void MainWindow::runSlot()
@ -1261,7 +1263,7 @@ void MainWindow::restartDebugging()
{
auto last = mMRUList->getEntry(0);
if(!last.isEmpty())
DbgCmdExec(QString("init \"%1\"").arg(last));
DbgCmdExec(QString("init \"%1\"").arg(DbgCmdEscape(last)));
}
void MainWindow::displayBreakpointWidget()
@ -1279,10 +1281,11 @@ void MainWindow::dragEnterEvent(QDragEnterEvent* pEvent)
void MainWindow::dropEvent(QDropEvent* pEvent)
{
if(pEvent->mimeData()->hasUrls())
{
QString filename = QDir::toNativeSeparators(pEvent->mimeData()->urls()[0].toLocalFile());
DbgCmdExec(QString().sprintf("init \"%s\"", filename.toUtf8().constData()));
DbgCmdExec(QString().sprintf("init \"%s\"", DbgCmdEscape(filename).toUtf8().constData()));
pEvent->acceptProposedAction();
}
}
@ -1363,6 +1366,11 @@ void MainWindow::displayCpuWidget()
showQWidgetTab(mCpuWidget);
}
void MainWindow::displayThreadsWidget()
{
showQWidgetTab(mThreadView);
}
void MainWindow::displaySymbolWidget()
{
showQWidgetTab(mSymbolView);
@ -1378,11 +1386,6 @@ void MainWindow::displayReferencesWidget()
showQWidgetTab(mReferenceManager);
}
void MainWindow::displayThreadsWidget()
{
showQWidgetTab(mThreadView);
}
void MainWindow::displayGraphWidget()
{
showQWidgetTab(mCpuWidget);

View File

@ -80,12 +80,12 @@ public slots:
void displayBreakpointWidget();
void updateWindowTitleSlot(QString filename);
void runSlot();
void displayThreadsWidget();
void displayCpuWidget();
void displayCpuWidgetShowCpu();
void displaySymbolWidget();
void displaySourceViewWidget();
void displayReferencesWidget();
void displayThreadsWidget();
void displayVariables();
void displayGraphWidget();
void displayTraceWidget();

View File

@ -33,9 +33,9 @@ MemoryMapView::MemoryMapView(StdTable* parent)
loadColumnFromConfig("MemoryMap");
setIconColumn(ColParty);
connect(Bridge::getBridge(), SIGNAL(updateMemory()), this, SLOT(refreshMap()));
connect(Bridge::getBridge(), SIGNAL(updateMemory()), this, SLOT(refreshMapSlot()));
connect(Bridge::getBridge(), SIGNAL(dbgStateChanged(DBGSTATE)), this, SLOT(stateChangedSlot(DBGSTATE)));
connect(Bridge::getBridge(), SIGNAL(selectInMemoryMap(duint)), this, SLOT(selectAddress(duint)));
connect(Bridge::getBridge(), SIGNAL(selectInMemoryMap(duint)), this, SLOT(selectAddressSlot(duint)));
connect(Bridge::getBridge(), SIGNAL(selectionMemmapGet(SELECTIONDATA*)), this, SLOT(selectionGetSlot(SELECTIONDATA*)));
connect(Bridge::getBridge(), SIGNAL(selectionMemmapSet(const SELECTIONDATA*)), this, SLOT(selectionSetSlot(const SELECTIONDATA*)));
connect(Bridge::getBridge(), SIGNAL(disassembleAt(duint, duint)), this, SLOT(disassembleAtSlot(duint, duint)));
@ -63,12 +63,12 @@ void MemoryMapView::setupContextMenu()
//Set PageMemory Rights
mPageMemoryRights = new QAction(DIcon("memmap_set_page_memory_rights"), tr("Set Page Memory Rights"), this);
connect(mPageMemoryRights, SIGNAL(triggered()), this, SLOT(pageMemoryRights()));
connect(mPageMemoryRights, SIGNAL(triggered()), this, SLOT(pageMemoryRightsSlot()));
//Switch View
mSwitchView = new QAction(DIcon("change-view"), "", this);
setSwitchViewName();
connect(mSwitchView, SIGNAL(triggered()), this, SLOT(switchView()));
connect(mSwitchView, SIGNAL(triggered()), this, SLOT(switchViewSlot()));
//Breakpoint menu
mBreakpointMenu = new QMenu(tr("Memory &Breakpoint"), this);
@ -169,11 +169,11 @@ void MemoryMapView::setupContextMenu()
//Dump
//TODO: These two actions should also appear in CPUDump
mDumpMemory = new QAction(DIcon("binary_save"), tr("&Dump Memory to File"), this);
connect(mDumpMemory, SIGNAL(triggered()), this, SLOT(dumpMemory()));
connect(mDumpMemory, SIGNAL(triggered()), this, SLOT(dumpMemorySlot()));
//Load
mLoadMemory = new QAction(DIcon(""), tr("&Overwrite with Data from File"), this);
connect(mLoadMemory, SIGNAL(triggered()), this, SLOT(loadMemory()));
connect(mLoadMemory, SIGNAL(triggered()), this, SLOT(loadMemorySlot()));
//Add virtual module
mAddVirtualMod = new QAction(DIcon("virtual"), tr("Add virtual module"), this);
@ -272,17 +272,6 @@ void MemoryMapView::contextMenuSlot(const QPoint & pos)
menu.exec(mapToGlobal(pos)); //execute context menu
}
static QString getProtectionString(DWORD Protect)
{
#define RIGHTS_STRING (sizeof("ERWCG"))
char rights[RIGHTS_STRING];
if(!DbgFunctions()->PageRightsToString(Protect, rights))
return "bad";
return QString(rights);
}
QString MemoryMapView::paintContent(QPainter* painter, duint row, duint col, int x, int y, int w, int h)
{
if(col == 0) //address
@ -377,14 +366,14 @@ void MemoryMapView::setSwitchViewName()
QAction* MemoryMapView::makeCommandAction(QAction* action, const QString & command)
{
action->setData(QVariant(command));
connect(action, SIGNAL(triggered()), this, SLOT(ExecCommand()));
connect(action, SIGNAL(triggered()), this, SLOT(execCommandSlot()));
return action;
}
/**
* @brief MemoryMapView::ExecCommand execute command slot for menus.
* @brief MemoryMapView::execCommandSlot execute command slot for menus.
*/
void MemoryMapView::ExecCommand()
void MemoryMapView::execCommandSlot()
{
QAction* action = qobject_cast<QAction*>(sender());
if(action)
@ -404,16 +393,52 @@ void MemoryMapView::ExecCommand()
}
}
void MemoryMapView::refreshMap()
static QString getProtectionString(DWORD protect)
{
//reserved pages don't have a protection (https://goo.gl/Izkk0c)
if(protect == 0)
{
return QString();
}
#define meme(prot, str) (prot & PAGE_GUARD) ? QStringLiteral(str QT_UNICODE_LITERAL("G")) : QStringLiteral(str QT_UNICODE_LITERAL("-"))
switch(protect & 0xFF)
{
case PAGE_NOACCESS:
return meme(protect, "----");
case PAGE_READONLY:
return meme(protect, "-R--");
case PAGE_READWRITE:
return meme(protect, "-RW-");
case PAGE_WRITECOPY:
return meme(protect, "-RWC");
case PAGE_EXECUTE:
return meme(protect, "E---");
case PAGE_EXECUTE_READ:
return meme(protect, "ER--");
case PAGE_EXECUTE_READWRITE:
return meme(protect, "ERW-");
case PAGE_EXECUTE_WRITECOPY:
return meme(protect, "ERWC");
default:
return meme(protect, "????");
}
}
void MemoryMapView::refreshMapSlot()
{
MEMMAP memoryMap = {};
DbgMemMap(&memoryMap);
setRowCount(memoryMap.count);
auto strUser = tr("User");
auto strSystem = tr("System");
for(int i = 0; i < memoryMap.count; i++)
{
const auto & mbi = (memoryMap.page)[i].mbi;
const auto & mbi = memoryMap.page[i].mbi;
// Base address
setCellContent(i, ColAddress, ToPtrString((duint)mbi.BaseAddress));
@ -428,11 +453,11 @@ void MemoryMapView::refreshMap()
switch(party)
{
case mod_user:
setCellContent(i, ColParty, tr("User"));
setCellContent(i, ColParty, strUser);
setRowIcon(i, DIcon("markasuser"));
break;
case mod_system:
setCellContent(i, ColParty, tr("System"));
setCellContent(i, ColParty, strSystem);
setRowIcon(i, DIcon("markassystem"));
break;
default:
@ -442,64 +467,62 @@ void MemoryMapView::refreshMap()
}
// Information
auto content = QString((memoryMap.page)[i].info);
setCellContent(i, ColPageInfo, content);
auto info = memoryMap.page[i].info;
setCellContent(i, ColPageInfo, info);
// Content, TODO: proper section content analysis in dbg/memory.cpp:MemUpdateMap
QString content;
char comment_text[MAX_COMMENT_SIZE];
if(DbgFunctions()->GetUserComment((duint)mbi.BaseAddress, comment_text)) // user comment present
content = comment_text;
else if(content.contains(".bss"))
else if(strncmp(info, ".bss", 4) == 0)
content = tr("Uninitialized data");
else if(content.contains(".data"))
else if(strncmp(info, ".data", 5) == 0)
content = tr("Initialized data");
else if(content.contains(".edata"))
else if(strncmp(info, ".edata", 6) == 0)
content = tr("Export tables");
else if(content.contains(".idata"))
else if(strncmp(info, ".idata", 6) == 0)
content = tr("Import tables");
else if(content.contains(".pdata"))
else if(strncmp(info, ".pdata", 6) == 0)
content = tr("Exception information");
else if(content.contains(".rdata"))
else if(strncmp(info, ".rdata", 6) == 0)
content = tr("Read-only initialized data");
else if(content.contains(".reloc"))
else if(strncmp(info, ".reloc", 6) == 0)
content = tr("Base relocations");
else if(content.contains(".rsrc"))
else if(strncmp(info, ".rsrc", 5) == 0)
content = tr("Resources");
else if(content.contains(".text"))
else if(strncmp(info, ".text", 5) == 0)
content = tr("Executable code");
else if(content.contains(".tls"))
else if(strncmp(info, ".tls", 4) == 0)
content = tr("Thread-local storage");
else if(content.contains(".xdata"))
else if(strncmp(info, ".xdata", 6) == 0)
content = tr("Exception information");
else
content = QString("");
setCellContent(i, ColContent, std::move(content));
// Type
const char* type = "";
QString type;
switch(mbi.Type)
{
case MEM_IMAGE:
type = "IMG";
type = QStringLiteral("IMG");
break;
case MEM_MAPPED:
type = "MAP";
type = QStringLiteral("MAP");
break;
case MEM_PRIVATE:
type = "PRV";
type = QStringLiteral("PRV");
break;
default:
type = "N/A";
type = QStringLiteral("N/A");
break;
}
setCellContent(i, ColAllocation, type);
setCellContent(i, ColAllocation, std::move(type));
// current access protection
setCellContent(i, ColCurProtect, getProtectionString(mbi.Protect));
// allocation protection
setCellContent(i, ColAllocProtect, getProtectionString(mbi.AllocationProtect));
}
if(memoryMap.page != 0)
BridgeFree(memoryMap.page);
@ -509,7 +532,7 @@ void MemoryMapView::refreshMap()
void MemoryMapView::stateChangedSlot(DBGSTATE state)
{
if(state == paused)
refreshMap();
refreshMapSlot();
}
void MemoryMapView::followDumpSlot()
@ -545,25 +568,25 @@ void MemoryMapView::memoryExecuteSingleshootToggleSlot()
{
for(int i : getSelection())
{
QString addr_text = getCellContent(i, ColAddress);
QString addrText = getCellContent(i, ColAddress);
duint selectedAddr = getSelectionAddr();
if((DbgGetBpxTypeAt(selectedAddr) & bp_memory) == bp_memory) //memory breakpoint set
DbgCmdExec(QString("bpmc ") + addr_text);
DbgCmdExec(QString("bpmc ") + addrText);
else
DbgCmdExec(QString("bpm %1, 0, x").arg(addr_text));
DbgCmdExec(QString("bpm %1, 0, x").arg(addrText));
}
}
void MemoryMapView::pageMemoryRights()
void MemoryMapView::pageMemoryRightsSlot()
{
PageMemoryRights PageMemoryRightsDialog(this);
connect(&PageMemoryRightsDialog, SIGNAL(refreshMemoryMap()), this, SLOT(refreshMap()));
connect(&PageMemoryRightsDialog, SIGNAL(refreshMemoryMap()), this, SLOT(refreshMapSlot()));
duint addr = getSelectionAddr();
duint size = getCellUserdata(getInitialSelection(), ColSize);
PageMemoryRightsDialog.RunAddrSize(addr, size, getCellContent(getInitialSelection(), ColCurProtect));
}
void MemoryMapView::switchView()
void MemoryMapView::switchViewSlot()
{
Config()->setBool("Engine", "ListAllPages", !ConfigBool("Engine", "ListAllPages"));
Config()->writeBools();
@ -612,16 +635,27 @@ void MemoryMapView::findPatternSlot()
hexEdit.setWindowTitle(tr("Find Pattern..."));
if(hexEdit.exec() != QDialog::Accepted)
return;
duint addr = getSelectionAddr();
entireBlockEnabled = hexEdit.entireBlock();
BridgeSettingSetUint("Gui", "MemoryMapEntireBlock", entireBlockEnabled);
if(entireBlockEnabled)
addr = 0;
DbgCmdExec(QString("findallmem %1, %2, &data&").arg(ToPtrString(addr)).arg(hexEdit.mHexEdit->pattern()));
{
DbgCmdExec(QString("findallmem 0, %2").arg(hexEdit.mHexEdit->pattern()));
}
else
{
QList<duint> selection = getSelection();
if(selection.isEmpty())
return;
duint addrFirst = getCellUserdata(selection.first(), ColAddress);
duint addrLast = getCellUserdata(selection.last(), ColAddress);
duint size = getCellUserdata(selection.last(), ColSize);
DbgCmdExec(QString("findallmem %1, %2, %3").arg(ToPtrString(addrFirst)).arg(hexEdit.mHexEdit->pattern()).arg(ToHexString(addrLast - addrFirst + size)));
}
emit showReferences();
}
void MemoryMapView::dumpMemory()
void MemoryMapView::dumpMemorySlot()
{
duint start = 0;
duint end = 0;
@ -654,7 +688,7 @@ void MemoryMapView::dumpMemory()
}
}
void MemoryMapView::loadMemory()
void MemoryMapView::loadMemorySlot()
{
auto modname = mainModuleName();
if(!modname.isEmpty())
@ -671,7 +705,7 @@ void MemoryMapView::loadMemory()
}
}
void MemoryMapView::selectAddress(duint va)
void MemoryMapView::selectAddressSlot(duint va)
{
auto base = DbgMemFindBaseAddr(va, nullptr);
if(base)
@ -692,7 +726,7 @@ void MemoryMapView::selectAddress(duint va)
void MemoryMapView::gotoOriginSlot()
{
selectAddress(mCipBase);
selectAddressSlot(mCipBase);
}
void MemoryMapView::gotoExpressionSlot()
@ -703,7 +737,7 @@ void MemoryMapView::gotoExpressionSlot()
mGoto->setInitialExpression(ToPtrString(getSelectionAddr()));
if(mGoto->exec() == QDialog::Accepted)
{
selectAddress(DbgValFromString(mGoto->expressionText.toUtf8().constData()));
selectAddressSlot(DbgValFromString(mGoto->expressionText.toUtf8().constData()));
}
}
@ -788,7 +822,7 @@ void MemoryMapView::commentSlot()
{
duint va = getSelectionAddr();
LineEditDialog mLineEdit(this);
QString addr_text = ToPtrString(va);
QString addrText = ToPtrString(va);
char comment_text[MAX_COMMENT_SIZE] = "";
if(DbgGetCommentAt((duint)va, comment_text))
{
@ -797,7 +831,7 @@ void MemoryMapView::commentSlot()
else
mLineEdit.setText(QString(comment_text));
}
mLineEdit.setWindowTitle(tr("Add comment at ") + addr_text);
mLineEdit.setWindowTitle(tr("Add comment at ") + addrText);
if(mLineEdit.exec() != QDialog::Accepted)
return;
if(!DbgSetCommentAt(va, mLineEdit.editText.replace('\r', "").replace('\n', "").toUtf8().constData()))

View File

@ -24,16 +24,16 @@ public slots:
void doubleClickedSlot();
void memoryExecuteSingleshootToggleSlot();
void memoryAllocateSlot();
void ExecCommand();
void execCommandSlot();
void contextMenuSlot(const QPoint & pos);
void switchView();
void pageMemoryRights();
void refreshMap();
void switchViewSlot();
void pageMemoryRightsSlot();
void refreshMapSlot();
void findPatternSlot();
void dumpMemory();
void loadMemory();
void dumpMemorySlot();
void loadMemorySlot();
void commentSlot();
void selectAddress(duint va);
void selectAddressSlot(duint va);
void gotoOriginSlot();
void gotoExpressionSlot();
void addVirtualModSlot();

View File

@ -55,24 +55,27 @@ void PageMemoryRights::RunAddrSize(duint addrin, duint sizein, QString pagetypei
void PageMemoryRights::on_btnSelectall_clicked()
{
for(int i = 0; i < ui->pagetableWidget->rowCount(); i++)
{
for(int j = 0; j < ui->pagetableWidget->columnCount(); j++)
{
QModelIndex idx = (ui->pagetableWidget->model()->index(i, j));
ui->pagetableWidget->selectionModel()->select(idx, QItemSelectionModel::Select);
}
}
const auto rowCount = ui->pagetableWidget->rowCount();
const auto columnCount = ui->pagetableWidget->columnCount();
QModelIndex topLeft = ui->pagetableWidget->model()->index(0, 0);
QModelIndex bottomRight = ui->pagetableWidget->model()->index(rowCount - 1, columnCount - 1);
QItemSelection selection(topLeft, bottomRight);
ui->pagetableWidget->selectionModel()->select(selection, QItemSelectionModel::Select);
}
void PageMemoryRights::on_btnDeselectall_clicked()
{
QModelIndexList indexList = ui->pagetableWidget->selectionModel()->selectedIndexes();
foreach(QModelIndex index, indexList)
{
ui->pagetableWidget->selectionModel()->select(index, QItemSelectionModel::Deselect);
QModelIndexList selectedIndexes = ui->pagetableWidget->selectionModel()->selectedIndexes();
if(selectedIndexes.isEmpty())
return;
}
QModelIndex topLeft = selectedIndexes.first();
QModelIndex bottomRight = selectedIndexes.last();
QItemSelection selection(topLeft, bottomRight);
ui->pagetableWidget->selectionModel()->select(selection, QItemSelectionModel::Deselect);
}
void PageMemoryRights::on_btnSetrights_clicked()

View File

@ -1332,7 +1332,7 @@ QString RegistersView::helpRegister(REGISTER_NAME reg)
"</table>").arg(headerRow).arg(bodyRows);
}
case CF:
return tr("CF (bit 0) : Carry flag - Set if an arithmetic operation generates a carry or a borrow out of the mostsignificant bit of the result; cleared otherwise.\n"
return tr("CF (bit 0) : Carry flag - Set if an arithmetic operation generates a carry or a borrow out of the most-significant bit of the result; cleared otherwise.\n"
"This flag indicates an overflow condition for unsigned-integer arithmetic. It is also used in multiple-precision arithmetic.");
case PF:
return tr("PF (bit 2) : Parity flag - Set if the least-significant byte of the result contains an even number of 1 bits; cleared otherwise.");

View File

@ -682,13 +682,13 @@ void SettingsDialog::on_chkSetJIT_stateChanged(int arg1)
if((DbgFunctions()->GetJit(NULL, true) == false) && (ui->editJIT->text() == qsjit_def_entry))
{
/*
* Only do this when the user wants uncheck the JIT and there are not an OLD JIT Stored
* and the JIT in Windows registry its this debugger.
* Scenario 1: the JIT in Windows registry its this debugger, if the database of the
* debugger was removed and the user wants uncheck the JIT: he cant (this block its executed then)
* Only do this when the user wants to uncheck the JIT and there is not an OLD JIT Stored
* and the JIT in Windows registry is this debugger.
* Scenario 1: the JIT in Windows registry is this debugger, if the database of the
* debugger was removed and the user wants uncheck the JIT: they can't (this block its executed then)
* -
* Scenario 2: the JIT in Windows registry its NOT this debugger, if the database of the debugger
* was removed and the user in MISC tab wants check and uncheck the JIT checkbox: he can (this block its NOT executed then).
* Scenario 2: the JIT in Windows registry is NOT this debugger, if the database of the debugger
* was removed and the user in MISC tab wants check and uncheck the JIT checkbox: they can (this block its NOT executed then).
*/
SimpleWarningBox(this, tr("ERROR NOT FOUND OLD JIT"), tr("NOT FOUND OLD JIT ENTRY STORED, USE SETJIT COMMAND"));
settings.miscSetJIT = true;

View File

@ -35,9 +35,7 @@ void SimpleTraceDialog::setTraceCommand(const QString & command)
static QString escapeText(QString str)
{
str.replace(QChar('\\'), QString("\\\\"));
str.replace(QChar('"'), QString("\\\""));
return str;
return DbgCmdEscape(std::move(str));
}
void SimpleTraceDialog::on_btnOk_clicked()

View File

@ -41,12 +41,12 @@ SourceView::~SourceView()
clear();
}
QString SourceView::getCellContent(duint r, duint c)
QString SourceView::getCellContent(duint row, duint column)
{
if(!isValidIndex(r, c))
if(!isValidIndex(row, column))
return QString();
LineData & line = mLines.at(r - mPrepareTableOffset);
switch(c)
LineData & line = mLines.at(row - mPrepareTableOffset);
switch(column)
{
case ColAddr:
return line.addr ? ToPtrString(line.addr) : QString();
@ -59,13 +59,29 @@ QString SourceView::getCellContent(duint r, duint c)
return "INVALID";
}
bool SourceView::isValidIndex(duint r, duint c)
duint SourceView::getCellUserdata(duint row, duint column)
{
if(!isValidIndex(row, column))
return 0;
LineData & line = mLines.at(row - mPrepareTableOffset);
switch(column)
{
case ColAddr:
return line.addr;
case ColLine:
return line.index + 1;
default:
return 0;
}
}
bool SourceView::isValidIndex(duint row, duint column)
{
if(!mFileLines)
return false;
if(c < ColAddr || c > ColCode)
if(column < ColAddr || column > ColCode)
return false;
return r >= 0 && size_t(r) < mFileLines->size();
return row >= 0 && size_t(row) < mFileLines->size();
}
void SourceView::sortRows(duint column, bool ascending)

View File

@ -13,8 +13,9 @@ public:
SourceView(QString path, duint addr, QWidget* parent = nullptr);
~SourceView();
QString getCellContent(duint r, duint c) override;
bool isValidIndex(duint r, duint c) override;
QString getCellContent(duint row, duint column) override;
duint getCellUserdata(duint row, duint column) override;
bool isValidIndex(duint row, duint column) override;
void sortRows(duint column, bool ascending) override;
void prepareData() override;

View File

@ -7,7 +7,7 @@
#include "StdIconSearchListView.h"
#include "ZehSymbolTable.h"
#include "DisassemblyPopup.h"
#include <QDesktopServices>
#include <QVBoxLayout>
#include <QProcess>
#include <QFileDialog>
@ -321,6 +321,9 @@ void SymbolView::setupContextMenu()
mSymbolSearchList->addAction(mToggleBookmark);
connect(mToggleBookmark, SIGNAL(triggered()), this, SLOT(toggleBookmark()));
mLabelHelp = new QAction(DIcon("help"), tr("Help on Symbolic Name"), this);
connect(mLabelHelp, SIGNAL(triggered()), this, SLOT(labelHelpSlot()));
//Modules
mFollowModuleAction = new QAction(disassembler, tr("&Follow in Disassembler"), this);
mFollowModuleAction->setShortcutContext(Qt::WidgetWithChildrenShortcut);
@ -529,6 +532,7 @@ void SymbolView::symbolContextMenu(QMenu* menu)
menu->addAction(mFollowSymbolDumpAction);
if(mSymbolList->mCurList->getCellContent(mSymbolList->mCurList->getInitialSelection(), 1) == tr("Import"))
menu->addAction(mFollowSymbolImportAction);
menu->addAction(mLabelHelp);
menu->addSeparator();
menu->addAction(mToggleBreakpoint);
menu->addAction(mToggleBookmark);
@ -580,6 +584,34 @@ void SymbolView::symbolSelectModule(duint base)
}
}
void SymbolView::labelHelpSlot()
{
QString topic = mSymbolList->mCurList->getCellContent(mSymbolList->mCurList->getInitialSelection(), ZehSymbolTable::ColUndecorated);
if(topic.isEmpty())
topic = mSymbolList->mCurList->getCellContent(mSymbolList->mCurList->getInitialSelection(), ZehSymbolTable::ColDecorated);
if(topic.isEmpty())
return;
char setting[MAX_SETTING_SIZE] = "";
if(!BridgeSettingGet("Misc", "HelpOnSymbolicNameUrl", setting))
{
//"execute://winhlp32.exe -k@topic ..\\win32.hlp";
strcpy_s(setting, "https://www.google.com/search?q=@topic");
BridgeSettingSet("Misc", "HelpOnSymbolicNameUrl", setting);
}
QString baseUrl(setting);
QString fullUrl = baseUrl.replace("@topic", topic);
if(baseUrl.startsWith("execute://"))
{
QString command = fullUrl.right(fullUrl.length() - 10);
QProcess::execute(command);
}
else
{
QDesktopServices::openUrl(QUrl(fullUrl));
}
}
void SymbolView::enterPressedSlot()
{
auto addr = DbgValFromString(mSymbolList->mCurList->getCellContent(mSymbolList->mCurList->getInitialSelection(), 0).toUtf8().constData());
@ -701,7 +733,7 @@ void SymbolView::moduleLoad()
if(browse.exec() != QDialog::Accepted && browse.path.length())
return;
auto fileName = browse.path;
DbgCmdExec(QString("loadlib \"%1\"").arg(fileName.replace("\\", "\\\\")));
DbgCmdExec(QString("loadlib \"%1\"").arg(DbgCmdEscape(fileName)));
}
void SymbolView::moduleFree()

View File

@ -42,6 +42,7 @@ private slots:
void enterPressedSlot();
void symbolContextMenu(QMenu* menu);
void symbolRefreshCurrent();
void labelHelpSlot();
void moduleContextMenu(QMenu* menu);
void moduleFollow();
void moduleEntryFollow();
@ -90,6 +91,7 @@ private:
QAction* mFollowInMemMap;
QAction* mLoadLib;
QAction* mFreeLib;
QAction* mLabelHelp;
QMenu* mPluginMenu;
static void cbSymbolEnum(SYMBOLINFO* symbol, void* user);

View File

@ -15,33 +15,27 @@ void ThreadView::contextMenuSlot(const QPoint & pos)
menu.exec(mapToGlobal(pos)); //execute context menu
}
void ThreadView::GoToThreadEntry()
void ThreadView::gotoThreadEntrySlot()
{
QString addr_text = getCellContent(getInitialSelection(), 2);
DbgCmdExecDirect(QString("disasm " + addr_text));
QString addrText = getCellContent(getInitialSelection(), ColEntry);
DbgCmdExecDirect(QString("disasm " + addrText));
}
void ThreadView::setupContextMenu()
{
mMenuBuilder = new MenuBuilder(this);
//Switch thread menu
mMenuBuilder->addAction(makeCommandAction(new QAction(DIcon("thread-switch"), tr("Switch Thread"), this), "switchthread $"));
//Suspend thread menu
mMenuBuilder->addAction(makeCommandAction(new QAction(DIcon("thread-pause"), tr("Suspend Thread"), this), "suspendthread $"));
//Resume thread menu
mMenuBuilder->addAction(makeCommandAction(new QAction(DIcon("thread-resume"), tr("Resume Thread"), this), "resumethread $"));
mMenuBuilder->addAction(makeCommandAction(new QAction(DIcon("thread-pause"), tr("Suspend All Threads"), this), "suspendallthreads"));
mMenuBuilder->addAction(makeCommandAction(new QAction(DIcon("thread-resume"), tr("Resume All Threads"), this), "resumeallthreads"));
//Kill thread menu
mMenuBuilder->addAction(makeCommandAction(new QAction(DIcon("thread-kill"), tr("Kill Thread"), this), "killthread $"));
mMenuBuilder->addSeparator();
// Set name
mMenuBuilder->addAction(makeAction(DIcon("thread-setname"), tr("Set Name"), SLOT(SetNameSlot())));
mMenuBuilder->addAction(makeAction(DIcon("thread-setname"), tr("Set Name"), SLOT(setNameSlot())));
// Set priority
QAction* mSetPriorityIdle = makeCommandAction(new QAction(DIcon("thread-priority-idle"), tr("Idle"), this), "setprioritythread $, Idle");
QAction* mSetPriorityAboveNormal = makeCommandAction(new QAction(DIcon("thread-priority-above-normal"), tr("Above Normal"), this), "setprioritythread $, AboveNormal");
@ -94,9 +88,7 @@ void ThreadView::setupContextMenu()
mSetPriority->addAction(mSetPriorityLowest);
mSetPriority->addAction(mSetPriorityIdle);
mMenuBuilder->addMenu(makeMenu(DIcon("thread-setpriority_alt"), tr("Set Priority")), mSetPriority);
// GoToThreadEntry
mMenuBuilder->addAction(makeAction(DIcon("thread-entry"), tr("Go to Thread Entry"), SLOT(GoToThreadEntry())), [this](QMenu * menu)
mMenuBuilder->addAction(makeAction(DIcon("thread-entry"), tr("Go to Thread Entry"), SLOT(gotoThreadEntrySlot())), [this](QMenu * menu)
{
bool ok;
ULONGLONG entry = getCellContent(getInitialSelection(), 2).toULongLong(&ok, 16);
@ -126,14 +118,14 @@ void ThreadView::setupContextMenu()
QAction* ThreadView::makeCommandAction(QAction* action, const QString & command)
{
action->setData(QVariant(command));
connect(action, SIGNAL(triggered()), this, SLOT(ExecCommand()));
connect(action, SIGNAL(triggered()), this, SLOT(execCommandSlot()));
return action;
}
/**
* @brief ThreadView::ExecCommand execute command slot for menus. Only used by command that reference thread id.
* @brief ThreadView::execCommandSlot execute command slot for menus. Only used by command that reference thread id.
*/
void ThreadView::ExecCommand()
void ThreadView::execCommandSlot()
{
QAction* action = qobject_cast<QAction*>(sender());
if(action)
@ -174,8 +166,9 @@ ThreadView::ThreadView(StdTable* parent) : StdTable(parent)
loadColumnFromConfig("Thread");
//setCopyMenuOnly(true);
connect(Bridge::getBridge(), SIGNAL(updateThreads()), this, SLOT(updateThreadList()));
connect(Bridge::getBridge(), SIGNAL(selectionThreadsSet(const SELECTIONDATA*)), this, SLOT(selectionThreadsSet(const SELECTIONDATA*)));
connect(Bridge::getBridge(), SIGNAL(selectionThreadsGet(SELECTIONDATA*)), this, SLOT(selectionThreadsGet(SELECTIONDATA*)));
connect(Bridge::getBridge(), SIGNAL(updateThreads()), this, SLOT(updateThreadListSlot()));
connect(this, SIGNAL(doubleClickedSignal()), this, SLOT(doubleClickedSlot()));
connect(this, SIGNAL(contextMenuSignal(QPoint)), this, SLOT(contextMenuSlot(QPoint)));
@ -184,7 +177,32 @@ ThreadView::ThreadView(StdTable* parent) : StdTable(parent)
new DisassemblyPopup(this, Bridge::getArchitecture());
}
void ThreadView::updateThreadList()
void ThreadView::selectionThreadsSet(const SELECTIONDATA* selection)
{
auto selectedThreadId = selection->start;
auto rowCount = getRowCount();
for(duint row = 0; row < rowCount; row++)
{
auto threadId = getCellUserdata(row, ColThreadId);
if(threadId == selectedThreadId)
{
setSingleSelection(row);
Bridge::getBridge()->setResult(BridgeResult::SelectionSet, 1);
return;
}
}
Bridge::getBridge()->setResult(BridgeResult::SelectionSet, 0);
}
void ThreadView::selectionThreadsGet(SELECTIONDATA* selection)
{
auto threadId = getCellUserdata(getInitialSelection(), ColThreadId);
selection->start = selection->end = threadId;
Bridge::getBridge()->setResult(BridgeResult::SelectionGet, 1);
}
void ThreadView::updateThreadListSlot()
{
THREADLIST threadList;
memset(&threadList, 0, sizeof(THREADLIST));
@ -194,15 +212,15 @@ void ThreadView::updateThreadList()
for(int i = 0; i < threadList.count; i++)
{
if(!threadList.list[i].BasicInfo.ThreadNumber)
setCellContent(i, 0, tr("Main"));
setCellContent(i, ColNumber, tr("Main"));
else
setCellContent(i, 0, ToDecString(threadList.list[i].BasicInfo.ThreadNumber));
setCellContent(i, 1, QString().sprintf(tidFormat, threadList.list[i].BasicInfo.ThreadId));
setCellUserdata(i, 1, threadList.list[i].BasicInfo.ThreadId);
setCellContent(i, 2, ToPtrString(threadList.list[i].BasicInfo.ThreadStartAddress));
setCellContent(i, 3, ToPtrString(threadList.list[i].BasicInfo.ThreadLocalBase));
setCellContent(i, 4, ToPtrString(threadList.list[i].ThreadCip));
setCellContent(i, 5, ToDecString(threadList.list[i].SuspendCount));
setCellContent(i, ColNumber, ToDecString(threadList.list[i].BasicInfo.ThreadNumber));
setCellContent(i, ColThreadId, QString().sprintf(tidFormat, threadList.list[i].BasicInfo.ThreadId));
setCellUserdata(i, ColThreadId, threadList.list[i].BasicInfo.ThreadId);
setCellContent(i, ColEntry, ToPtrString(threadList.list[i].BasicInfo.ThreadStartAddress));
setCellContent(i, ColTeb, ToPtrString(threadList.list[i].BasicInfo.ThreadLocalBase));
setCellContent(i, ColCip, ToPtrString(threadList.list[i].ThreadCip));
setCellContent(i, ColSuspendCount, ToDecString(threadList.list[i].SuspendCount));
QString priorityString;
switch(threadList.list[i].Priority)
{
@ -231,7 +249,7 @@ void ThreadView::updateThreadList()
priorityString = tr("Unknown");
break;
}
setCellContent(i, 6, priorityString);
setCellContent(i, ColPriority, priorityString);
QString waitReasonString;
switch(threadList.list[i].WaitReason)
{
@ -350,13 +368,13 @@ void ThreadView::updateThreadList()
waitReasonString = "Unknown";
break;
}
setCellContent(i, 7, waitReasonString);
setCellContent(i, 8, QString("%1").arg(threadList.list[i].LastError, sizeof(unsigned int) * 2, 16, QChar('0')).toUpper());
setCellContent(i, 9, FILETIMEToTime(threadList.list[i].UserTime));
setCellContent(i, 10, FILETIMEToTime(threadList.list[i].KernelTime));
setCellContent(i, 11, FILETIMEToDate(threadList.list[i].CreationTime));
setCellContent(i, 12, ToLongLongHexString(threadList.list[i].Cycles));
setCellContent(i, 13, threadList.list[i].BasicInfo.threadName);
setCellContent(i, ColWaitReason, waitReasonString);
setCellContent(i, ColLastError, QString("%1").arg(threadList.list[i].LastError, sizeof(unsigned int) * 2, 16, QChar('0')).toUpper());
setCellContent(i, ColUserTime, FILETIMEToTime(threadList.list[i].UserTime));
setCellContent(i, ColKernelTime, FILETIMEToTime(threadList.list[i].KernelTime));
setCellContent(i, ColCreationTime, FILETIMEToDate(threadList.list[i].CreationTime));
setCellContent(i, ColCpuCycles, ToLongLongHexString(threadList.list[i].Cycles));
setCellContent(i, ColThreadName, threadList.list[i].BasicInfo.threadName);
}
mCurrentThreadId = -1;
if(threadList.count)
@ -372,7 +390,7 @@ void ThreadView::updateThreadList()
QString ThreadView::paintContent(QPainter* painter, duint row, duint col, int x, int y, int w, int h)
{
QString ret = StdTable::paintContent(painter, row, col, x, y, w, h);
duint threadId = getCellUserdata(row, 1);
duint threadId = getCellUserdata(row, ColThreadId);
if(threadId == mCurrentThreadId && !col)
{
painter->fillRect(QRect(x, y, w, h), QBrush(ConfigColor("ThreadCurrentBackgroundColor")));
@ -385,21 +403,19 @@ QString ThreadView::paintContent(QPainter* painter, duint row, duint col, int x,
void ThreadView::doubleClickedSlot()
{
duint threadId = getCellUserdata(getInitialSelection(), 1);
duint threadId = getCellUserdata(getInitialSelection(), ColThreadId);
DbgCmdExecDirect("switchthread " + ToHexString(threadId));
QString addr_text = getCellContent(getInitialSelection(), 4);
DbgCmdExec("disasm " + addr_text);
QString addrText = getCellContent(getInitialSelection(), ColCip);
DbgCmdExec("disasm " + addrText);
}
void ThreadView::SetNameSlot()
void ThreadView::setNameSlot()
{
duint threadId = getCellUserdata(getInitialSelection(), 1);
LineEditDialog mLineEdit(this);
mLineEdit.setWindowTitle(tr("Name") + threadId);
mLineEdit.setText(getCellContent(getInitialSelection(), 13));
if(mLineEdit.exec() != QDialog::Accepted)
duint threadId = getCellUserdata(getInitialSelection(), ColThreadId);
QString threadName = getCellContent(getInitialSelection(), ColThreadName);
if(!SimpleInputBox(this, tr("Thread name - %1").arg(threadId), threadName, threadName, QString()))
return;
QString escapedName = mLineEdit.editText.replace("\"", "\\\"");
DbgCmdExec(QString("setthreadname %1, \"%2\"").arg(ToHexString(threadId)).arg(escapedName));
DbgCmdExec(QString("setthreadname %1, \"%2\"").arg(ToHexString(threadId)).arg(DbgCmdEscape(threadName)));
}

View File

@ -11,16 +11,39 @@ public:
QString paintContent(QPainter* painter, duint row, duint col, int x, int y, int w, int h) override;
void setupContextMenu();
signals:
void displayThreadsView();
public slots:
void updateThreadList();
void selectionThreadsSet(const SELECTIONDATA* selection);
void selectionThreadsGet(SELECTIONDATA* selection);
void updateThreadListSlot();
void doubleClickedSlot();
void ExecCommand();
void GoToThreadEntry();
void execCommandSlot();
void gotoThreadEntrySlot();
void contextMenuSlot(const QPoint & pos);
void SetNameSlot();
void setNameSlot();
private:
QAction* makeCommandAction(QAction* action, const QString & command);
duint mCurrentThreadId;
MenuBuilder* mMenuBuilder;
enum
{
ColNumber = 0,
ColThreadId,
ColEntry,
ColTeb,
ColCip,
ColSuspendCount,
ColPriority,
ColWaitReason,
ColLastError,
ColUserTime,
ColKernelTime,
ColCreationTime,
ColCpuCycles,
ColThreadName,
};
};

View File

@ -33,7 +33,7 @@ void WatchView::updateWatch()
BridgeList<WATCHINFO> WatchList;
DbgGetWatchList(&WatchList);
setRowCount(WatchList.Count());
if(getInitialSelection() >= WatchList.Count() && WatchList.Count() > 0)
if(getInitialSelection() >= (duint)WatchList.Count() && WatchList.Count() > 0)
setSingleSelection(WatchList.Count() - 1);
for(int i = 0; i < WatchList.Count(); i++)
{
@ -232,7 +232,7 @@ void WatchView::modifyWatchSlot()
BridgeList<WATCHINFO> WatchList;
DbgGetWatchList(&WatchList);
auto sel = getInitialSelection();
if(sel > WatchList.Count())
if(sel > (duint)WatchList.Count())
return;
WordEditDialog modifyDialog(this);
modifyDialog.setup(tr("Modify \"%1\"").arg(QString(WatchList[sel].WatchName)), WatchList[sel].value, sizeof(duint));

View File

@ -230,95 +230,95 @@ void XrefBrowseDialog::onDebuggerClose(DBGSTATE state)
void XrefBrowseDialog::breakpointSlot()
{
QString addr_text = ToPtrString(mXrefInfo.references[ui->listWidget->currentRow()].addr);
QString addrText = ToPtrString(mXrefInfo.references[ui->listWidget->currentRow()].addr);
if(DbgGetBpxTypeAt(mXrefInfo.references[ui->listWidget->currentRow()].addr) & bp_normal)
DbgCmdExec(QString("bc " + addr_text));
DbgCmdExec(QString("bc " + addrText));
else
DbgCmdExec(QString("bp " + addr_text));
DbgCmdExec(QString("bp " + addrText));
}
void XrefBrowseDialog::hardwareAccess1Slot()
{
QString addr_text = ToPtrString(mXrefInfo.references[ui->listWidget->currentRow()].addr);
DbgCmdExec(QString("bphws " + addr_text + ", r, 1"));
QString addrText = ToPtrString(mXrefInfo.references[ui->listWidget->currentRow()].addr);
DbgCmdExec(QString("bphws " + addrText + ", r, 1"));
}
void XrefBrowseDialog::hardwareAccess2Slot()
{
QString addr_text = ToPtrString(mXrefInfo.references[ui->listWidget->currentRow()].addr);
DbgCmdExec(QString("bphws " + addr_text + ", r, 2"));
QString addrText = ToPtrString(mXrefInfo.references[ui->listWidget->currentRow()].addr);
DbgCmdExec(QString("bphws " + addrText + ", r, 2"));
}
void XrefBrowseDialog::hardwareAccess4Slot()
{
QString addr_text = ToPtrString(mXrefInfo.references[ui->listWidget->currentRow()].addr);
DbgCmdExec(QString("bphws " + addr_text + ", r, 4"));
QString addrText = ToPtrString(mXrefInfo.references[ui->listWidget->currentRow()].addr);
DbgCmdExec(QString("bphws " + addrText + ", r, 4"));
}
void XrefBrowseDialog::hardwareAccess8Slot()
{
QString addr_text = ToPtrString(mXrefInfo.references[ui->listWidget->currentRow()].addr);
DbgCmdExec(QString("bphws " + addr_text + ", r, 8"));
QString addrText = ToPtrString(mXrefInfo.references[ui->listWidget->currentRow()].addr);
DbgCmdExec(QString("bphws " + addrText + ", r, 8"));
}
void XrefBrowseDialog::hardwareWrite1Slot()
{
QString addr_text = ToPtrString(mXrefInfo.references[ui->listWidget->currentRow()].addr);
DbgCmdExec(QString("bphws " + addr_text + ", w, 1"));
QString addrText = ToPtrString(mXrefInfo.references[ui->listWidget->currentRow()].addr);
DbgCmdExec(QString("bphws " + addrText + ", w, 1"));
}
void XrefBrowseDialog::hardwareWrite2Slot()
{
QString addr_text = ToPtrString(mXrefInfo.references[ui->listWidget->currentRow()].addr);
DbgCmdExec(QString("bphws " + addr_text + ", w, 2"));
QString addrText = ToPtrString(mXrefInfo.references[ui->listWidget->currentRow()].addr);
DbgCmdExec(QString("bphws " + addrText + ", w, 2"));
}
void XrefBrowseDialog::hardwareWrite4Slot()
{
QString addr_text = ToPtrString(mXrefInfo.references[ui->listWidget->currentRow()].addr);
DbgCmdExec(QString("bphws " + addr_text + ", w, 4"));
QString addrText = ToPtrString(mXrefInfo.references[ui->listWidget->currentRow()].addr);
DbgCmdExec(QString("bphws " + addrText + ", w, 4"));
}
void XrefBrowseDialog::hardwareWrite8Slot()
{
QString addr_text = ToPtrString(mXrefInfo.references[ui->listWidget->currentRow()].addr);
DbgCmdExec(QString("bphws " + addr_text + ", w, 8"));
QString addrText = ToPtrString(mXrefInfo.references[ui->listWidget->currentRow()].addr);
DbgCmdExec(QString("bphws " + addrText + ", w, 8"));
}
void XrefBrowseDialog::hardwareRemoveSlot()
{
QString addr_text = ToPtrString(mXrefInfo.references[ui->listWidget->currentRow()].addr);
DbgCmdExec(QString("bphwc " + addr_text));
QString addrText = ToPtrString(mXrefInfo.references[ui->listWidget->currentRow()].addr);
DbgCmdExec(QString("bphwc " + addrText));
}
void XrefBrowseDialog::memoryAccessSingleshootSlot()
{
QString addr_text = ToPtrString(mXrefInfo.references[ui->listWidget->currentRow()].addr);
DbgCmdExec(QString("bpm " + addr_text + ", 0, a"));
QString addrText = ToPtrString(mXrefInfo.references[ui->listWidget->currentRow()].addr);
DbgCmdExec(QString("bpm " + addrText + ", 0, a"));
}
void XrefBrowseDialog::memoryAccessRestoreSlot()
{
QString addr_text = ToPtrString(mXrefInfo.references[ui->listWidget->currentRow()].addr);
DbgCmdExec(QString("bpm " + addr_text + ", 1, a"));
QString addrText = ToPtrString(mXrefInfo.references[ui->listWidget->currentRow()].addr);
DbgCmdExec(QString("bpm " + addrText + ", 1, a"));
}
void XrefBrowseDialog::memoryWriteSingleshootSlot()
{
QString addr_text = ToPtrString(mXrefInfo.references[ui->listWidget->currentRow()].addr);
DbgCmdExec(QString("bpm " + addr_text + ", 0, w"));
QString addrText = ToPtrString(mXrefInfo.references[ui->listWidget->currentRow()].addr);
DbgCmdExec(QString("bpm " + addrText + ", 0, w"));
}
void XrefBrowseDialog::memoryWriteRestoreSlot()
{
QString addr_text = ToPtrString(mXrefInfo.references[ui->listWidget->currentRow()].addr);
DbgCmdExec(QString("bpm " + addr_text + ", 1, w"));
QString addrText = ToPtrString(mXrefInfo.references[ui->listWidget->currentRow()].addr);
DbgCmdExec(QString("bpm " + addrText + ", 1, w"));
}
void XrefBrowseDialog::memoryRemoveSlot()
{
QString addr_text = ToPtrString(mXrefInfo.references[ui->listWidget->currentRow()].addr);
DbgCmdExec(QString("bpmc " + addr_text));
QString addrText = ToPtrString(mXrefInfo.references[ui->listWidget->currentRow()].addr);
DbgCmdExec(QString("bpmc " + addrText));
}
void XrefBrowseDialog::copyThisSlot()
@ -330,11 +330,11 @@ void XrefBrowseDialog::breakpointAllSlot()
{
for(int i = 0; i < ui->listWidget->count(); i++)
{
QString addr_text = ToPtrString(mXrefInfo.references[i].addr);
QString addrText = ToPtrString(mXrefInfo.references[i].addr);
if(DbgGetBpxTypeAt(mXrefInfo.references[i].addr) & bp_normal)
DbgCmdExec(QString("bc " + addr_text));
DbgCmdExec(QString("bc " + addrText));
else
DbgCmdExec(QString("bp " + addr_text));
DbgCmdExec(QString("bp " + addrText));
}
}

View File

@ -56,20 +56,40 @@ ZehSymbolTable::ZehSymbolTable(QWidget* parent)
Initialize();
}
QString ZehSymbolTable::getCellContent(duint r, duint c)
QString ZehSymbolTable::getCellContent(duint row, duint column)
{
QMutexLocker lock(&mMutex);
if(!isValidIndex(r, c))
if(!isValidIndex(row, column))
return QString();
SymbolInfoWrapper info;
DbgGetSymbolInfo(&mData.at(r), info.put());
return symbolInfoString(info.get(), c);
DbgGetSymbolInfo(&mData.at(row), info.put());
return symbolInfoString(info.get(), column);
}
bool ZehSymbolTable::isValidIndex(duint r, duint c)
duint ZehSymbolTable::getCellUserdata(duint row, duint column)
{
QMutexLocker lock(&mMutex);
return r >= 0 && r < (int)mData.size() && c >= 0 && c <= ColUndecorated;
if(!isValidIndex(row, column))
return 0;
SymbolInfoWrapper info;
DbgGetSymbolInfo(&mData.at(row), info.put());
switch(column)
{
case ColAddr:
return info->addr;
case ColOrdinal:
return info->ordinal;
case ColType:
return info->type;
default:
return 0;
}
}
bool ZehSymbolTable::isValidIndex(duint row, duint column)
{
QMutexLocker lock(&mMutex);
return row >= 0 && row < (int)mData.size() && column >= 0 && column <= ColUndecorated;
}
void ZehSymbolTable::sortRows(duint column, bool ascending)

View File

@ -9,8 +9,9 @@ class ZehSymbolTable : public AbstractStdTable
public:
ZehSymbolTable(QWidget* parent = nullptr);
QString getCellContent(duint r, duint c) override;
bool isValidIndex(duint r, duint c) override;
QString getCellContent(duint row, duint column) override;
duint getCellUserdata(duint row, duint column) override;
bool isValidIndex(duint row, duint column) override;
void sortRows(duint column, bool ascending) override;
friend class SymbolView;

View File

@ -292,9 +292,10 @@ QString TraceBrowser::paintContent(QPainter* painter, duint row, duint col, int
{
return "";
}
if(mTraceFile->isError())
QString reason;
if(mTraceFile->isError(reason))
{
GuiAddLogMessage(tr("An error occurred when reading trace file.\r\n").toUtf8().constData());
GuiAddLogMessage(tr("An error occurred when reading trace file (reason: %1).\r\n").arg(reason).toUtf8().constData());
mTraceFile->Close();
delete mTraceFile;
mTraceFile = nullptr;
@ -1357,9 +1358,10 @@ void TraceBrowser::closeDeleteSlot()
void TraceBrowser::parseFinishedSlot()
{
if(mTraceFile->isError())
QString reason;
if(mTraceFile->isError(reason))
{
SimpleErrorBox(this, tr("Error"), tr("Error when opening trace recording"));
SimpleErrorBox(this, tr("Error"), tr("Error when opening trace recording (reason: %1)").arg(reason));
delete mTraceFile;
mTraceFile = nullptr;
setRowCount(0);

View File

@ -71,6 +71,7 @@ void TraceFileReader::Close()
hashValue = 0;
EXEPath.clear();
error = false;
errorMessage.clear();
}
bool TraceFileReader::Delete()
@ -87,6 +88,7 @@ bool TraceFileReader::Delete()
hashValue = 0;
EXEPath.clear();
error = false;
errorMessage.clear();
return value;
}
@ -105,8 +107,10 @@ void TraceFileReader::parseFinishedSlot()
}
// Return if the file read was error
bool TraceFileReader::isError() const
bool TraceFileReader::isError(QString & reason) const
{
if(error)
reason = errorMessage;
return error;
}
@ -503,18 +507,19 @@ void TraceFileParser::run()
if(index > 0)
that->fileIndex.back().second.second = index - (lastIndex - 1);
that->error = false;
that->errorMessage.clear();
that->length = index;
that->progress = 100;
}
catch(const std::wstring & errReason)
{
Q_UNUSED(errReason);
//MessageBox(0, errReason.c_str(), L"debug", MB_ICONERROR);
that->error = true;
that->errorMessage = "[TraceFileParser::run] " + QString::fromStdWString(errReason);
}
catch(std::bad_alloc &)
{
that->error = true;
that->errorMessage = "[TraceFileParser::run] std::bad_alloc";
}
that->traceFile.moveToThread(that->thread());
@ -562,12 +567,13 @@ void TraceFileReader::purgeLastPage()
if(isBlockExist)
fileIndex.back().second.second = index - (lastIndex - 1);
error = false;
errorMessage.clear();
length = index;
}
catch(std::wstring & errReason)
{
Q_UNUSED(errReason);
error = true;
errorMessage = "[TraceFileReader::purgeLastPage] " + QString::fromStdWString(errReason);
}
}
@ -684,9 +690,10 @@ TraceFilePage::TraceFilePage(TraceFileReader* parent, unsigned long long fileOff
}
}
catch(const std::exception &)
catch(const std::exception & x)
{
mParent->error = true;
mParent->errorMessage = QString("[TraceFilePage::TraceFilePage] %1").arg(x.what());
}
}

View File

@ -20,7 +20,7 @@ public:
bool Open(const QString & fileName);
void Close();
bool Delete();
bool isError() const;
bool isError(QString & reason) const;
int Progress() const;
QString getIndexText(unsigned long long index) const;
@ -64,6 +64,7 @@ private:
std::vector<std::pair<unsigned long long, Range>> fileIndex; //index;<file offset;length>
std::atomic<int> progress;
bool error;
QString errorMessage;
TraceFilePage* lastAccessedPage;
unsigned long long lastAccessedIndexOffset;
friend class TraceFileParser;

View File

@ -234,11 +234,11 @@ void CommonActions::setLabelSlot()
duint va = mGetSelection();
LineEditDialog mLineEdit(widgetparent());
mLineEdit.setTextMaxLength(MAX_LABEL_SIZE - 2);
QString addr_text = ToPtrString(va);
QString addrText = ToPtrString(va);
char label_text[MAX_COMMENT_SIZE] = "";
if(DbgGetLabelAt((duint)va, SEG_DEFAULT, label_text))
mLineEdit.setText(QString(label_text));
mLineEdit.setWindowTitle(tr("Add label at ") + addr_text);
mLineEdit.setWindowTitle(tr("Add label at ") + addrText);
restart:
if(mLineEdit.exec() != QDialog::Accepted)
return;
@ -267,7 +267,7 @@ void CommonActions::setCommentSlot()
duint va = mGetSelection();
LineEditDialog mLineEdit(widgetparent());
mLineEdit.setTextMaxLength(MAX_COMMENT_SIZE - 2);
QString addr_text = ToPtrString(va);
QString addrText = ToPtrString(va);
char comment_text[MAX_COMMENT_SIZE] = "";
if(DbgGetCommentAt((duint)va, comment_text))
{
@ -276,7 +276,7 @@ void CommonActions::setCommentSlot()
else
mLineEdit.setText(QString(comment_text));
}
mLineEdit.setWindowTitle(tr("Add comment at ") + addr_text);
mLineEdit.setWindowTitle(tr("Add comment at ") + addrText);
if(mLineEdit.exec() != QDialog::Accepted)
return;
QString comment = mLineEdit.editText.replace('\r', "").replace('\n', "");

View File

@ -254,7 +254,8 @@ Configuration::Configuration() : QObject(), noMoreMsgbox(false)
disassemblyBool.insert("KeepSize", false);
disassemblyBool.insert("FillNOPs", false);
disassemblyBool.insert("Uppercase", false);
disassemblyBool.insert("FindCommandEntireBlock", false);
disassemblyBool.insert("FindCommandFromSelection", true);
disassemblyBool.insert("FindPatternFromSelection", true);
disassemblyBool.insert("OnlyCipAutoComments", false);
disassemblyBool.insert("TabbedMnemonic", false);
disassemblyBool.insert("LongDataInstruction", false);
@ -292,6 +293,8 @@ Configuration::Configuration() : QObject(), noMoreMsgbox(false)
guiBool.insert("AutoFollowInStack", true);
guiBool.insert("EnableQtHighDpiScaling", true);
guiBool.insert("Topmost", false);
guiBool.insert("CPUDumpStartFromSelect", true);
guiBool.insert("CPUStackStartFromSelect", true);
//Named menu settings
insertMenuBuilderBools(&guiBool, "CPUDisassembly", 50); //CPUDisassembly
insertMenuBuilderBools(&guiBool, "CPUDump", 50); //CPUDump

View File

@ -144,6 +144,8 @@ QString getSymbolicNameStr(duint addr)
finalText = QString("%1.%2").arg(moduleText).arg(addrText);
else if(bHasLabel) //<label>
finalText = QString("<%1>").arg(labelText);
else if(addr == 0)
finalText = addrText;
else
{
finalText = addrText;
@ -159,6 +161,18 @@ QString getSymbolicNameStr(duint addr)
if(c.isPrint() || c.isSpace())
finalText += QString(" L'%1'").arg(EscapeCh(c));
}
else if((addr & 0xFFFFFFFFF0000000ull) == 0xC0000000)
{
auto format = QString("{ntstatus@%1}").arg(ToHexString(addr));
if(DbgFunctions()->StringFormatInline(format.toUtf8().constData(), sizeof(string), string))
{
auto colon = strchr(string, ':');
if(colon)
*colon = '\0';
finalText += " ";
finalText += string;
}
}
}
return finalText;
}

View File

@ -290,3 +290,12 @@ bool GetCommentFormat(duint addr, QString & comment, bool* autoComment)
comment = commentData + a;
return true;
}
QString DbgCmdEscape(QString argument)
{
// TODO: implement this properly
argument.replace("\"", "\\\"");
argument.replace("{", "\\{");
return argument;
}

View File

@ -19,11 +19,11 @@ inline QString ToPtrString(duint Address)
char temp[32];
#ifdef _WIN64
sprintf_s(temp, "%016llX", Address);
auto size = sprintf_s(temp, "%016llX", Address);
#else
sprintf_s(temp, "%08X", Address);
auto size = sprintf_s(temp, "%08X", Address);
#endif // _WIN64
return QString(temp);
return QString::fromLatin1(temp, size);
}
inline QString ToLongLongHexString(unsigned long long Value)
@ -145,3 +145,5 @@ QString FILETIMEToDate(const FILETIME & date);
bool GetCommentFormat(duint addr, QString & comment, bool* autoComment = nullptr);
QString EscapeCh(QChar ch);
QString DbgCmdEscape(QString argument);

View File

@ -190,6 +190,7 @@ int main(int argc, char* argv[])
qRegisterMetaType<duint>("duint");
qRegisterMetaType<byte_t>("byte_t");
qRegisterMetaType<DBGSTATE>("DBGSTATE");
qRegisterMetaType<GUIMSG>("GUIMSG");
// Set QString codec to UTF-8
QTextCodec::setCodecForLocale(QTextCodec::codecForName("UTF-8"));
@ -207,7 +208,7 @@ int main(int argc, char* argv[])
mainWindow->show();
// Set some data
Bridge::getBridge()->winId = (void*)mainWindow->winId();
Bridge::getBridge()->mWinId = (void*)mainWindow->winId();
// Init debugger
const char* errormsg = DbgInit();

View File

@ -714,9 +714,9 @@ int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLi
break;
case PeArch::Invalid:
if(FileExists(szPath))
MessageBox(nullptr, argv[1], LoadResString(IDS_INVDPE), MB_ICONERROR);
MessageBox(nullptr, LoadResString(IDS_INVDPE), argv[1], MB_ICONERROR);
else
MessageBox(nullptr, argv[1], LoadResString(IDS_FILEERR), MB_ICONERROR);
MessageBox(nullptr, LoadResString(IDS_FILEERR), argv[1], MB_ICONERROR);
break;
default:
__debugbreak();

View File

@ -1,12 +1,32 @@
#include <windows.h>
#include <Windows.h>
wchar_t szLibraryPath[512];
#include <stdio.h>
int main()
static wchar_t szLibraryPath[512];
extern "C"
NTSTATUS
NTAPI
RtlGetLastNtStatus(
VOID
);
#ifdef _WIN64
#pragma comment(lib, "..\\dbg\\ntdll\\ntdll_x64.lib")
#else
#pragma comment(lib, "..\\dbg\\ntdll\\ntdll_x86.lib")
#endif // _WIN64
int WinMain(
HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nShowCmd
)
{
wchar_t szName[256];
wsprintfW(szName, L"Local\\szLibraryName%X", (unsigned int)GetCurrentProcessId());
HANDLE hMapFile = OpenFileMappingW(FILE_MAP_READ, false, szName);
wchar_t szTemp[256];
swprintf_s(szTemp, L"Local\\szLibraryName%X", (unsigned int)GetCurrentProcessId());
HANDLE hMapFile = OpenFileMappingW(FILE_MAP_READ, false, szTemp);
if(hMapFile)
{
const wchar_t* szLibraryPathMapping = (const wchar_t*)MapViewOfFile(hMapFile, FILE_MAP_READ, 0, 0, sizeof(szLibraryPath));
@ -17,7 +37,25 @@ int main()
}
CloseHandle(hMapFile);
}
if(szLibraryPath[0])
return (LoadLibraryW(szLibraryPath) != NULL);
return 0;
if(szLibraryPath[0] == L'\0')
{
// NOTE: No MessageBoxW here on purpose (enables DLL sideloading)
return RtlGetLastNtStatus();
}
HINSTANCE hDll = LoadLibraryW(szLibraryPath);
if(hDll == nullptr)
{
auto lastStatus = RtlGetLastNtStatus();
swprintf_s(szTemp, L"Failed to load DLL", GetLastError());
MessageBoxW(0, szLibraryPath, szTemp, MB_ICONERROR | MB_SYSTEMMODAL);
return lastStatus;
}
else
{
swprintf_s(szTemp, L"DLL loaded: 0x%p", hDll);
MessageBoxW(0, szLibraryPath, szTemp, MB_ICONINFORMATION | MB_SYSTEMMODAL);
return EXIT_SUCCESS;
}
}

View File

@ -94,12 +94,13 @@
<Link>
<TargetMachine>MachineX86</TargetMachine>
<GenerateDebugInformation>true</GenerateDebugInformation>
<SubSystem>Console</SubSystem>
<SubSystem>Windows</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<AdditionalManifestDependencies>
</AdditionalManifestDependencies>
<LargeAddressAware>true</LargeAddressAware>
<DelayLoadDLLs>user32.dll</DelayLoadDLLs>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
@ -112,11 +113,12 @@
<Link>
<TargetMachine>MachineX86</TargetMachine>
<GenerateDebugInformation>true</GenerateDebugInformation>
<SubSystem>Console</SubSystem>
<SubSystem>Windows</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<AdditionalManifestDependencies>
</AdditionalManifestDependencies>
<DelayLoadDLLs>user32.dll</DelayLoadDLLs>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
@ -128,11 +130,12 @@
</ClCompile>
<Link>
<GenerateDebugInformation>true</GenerateDebugInformation>
<SubSystem>Console</SubSystem>
<SubSystem>Windows</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<AdditionalManifestDependencies>
</AdditionalManifestDependencies>
<DelayLoadDLLs>user32.dll</DelayLoadDLLs>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
@ -144,11 +147,12 @@
</ClCompile>
<Link>
<GenerateDebugInformation>true</GenerateDebugInformation>
<SubSystem>Console</SubSystem>
<SubSystem>Windows</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<AdditionalManifestDependencies>
</AdditionalManifestDependencies>
<DelayLoadDLLs>user32.dll</DelayLoadDLLs>
</Link>
</ItemDefinitionGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />

View File

@ -1,39 +0,0 @@
#pragma once
#ifdef ZYDIS_STATIC_DEFINE
# define ZYDIS_EXPORT
# define ZYDIS_NO_EXPORT
#else
# ifndef ZYDIS_EXPORT
# ifdef Zydis_EXPORTS
/* We are building this library */
# define ZYDIS_EXPORT
# else
/* We are using this library */
# define ZYDIS_EXPORT
# endif
# endif
# ifndef ZYDIS_NO_EXPORT
# define ZYDIS_NO_EXPORT
# endif
#endif
#ifndef ZYDIS_DEPRECATED
# define ZYDIS_DEPRECATED __attribute__ ((__deprecated__))
#endif
#ifndef ZYDIS_DEPRECATED_EXPORT
# define ZYDIS_DEPRECATED_EXPORT ZYDIS_EXPORT ZYDIS_DEPRECATED
#endif
#ifndef ZYDIS_DEPRECATED_NO_EXPORT
# define ZYDIS_DEPRECATED_NO_EXPORT ZYDIS_NO_EXPORT ZYDIS_DEPRECATED
#endif
#define DEFINE_NO_DEPRECATED 0
#if DEFINE_NO_DEPRECATED
# define ZYDIS_NO_DEPRECATED
#endif

View File

@ -183,14 +183,27 @@ const char* Zydis::RegName(ZydisRegister reg) const
std::string Zydis::OperandText(uint8_t opindex) const
{
if(!Success() || opindex >= mInstr.info.operand_count)
return std::string();
return {};
auto & op = mInstr.operands[opindex];
char buf[200];
if(ZYAN_SUCCESS(ZydisFormatterFormatOperand(&this->mFormatter, &mInstr.info, &mInstr.operands[opindex], buf, sizeof(buf), mAddr, nullptr)))
return std::string(buf);
else
return std::string();
char buf[200] = {};
if(!ZYAN_SUCCESS(ZydisFormatterFormatOperand(&this->mFormatter, &mInstr.info, &op, buf, sizeof(buf), mAddr, nullptr)))
return {};
//Extract only the part inside the []
if(op.type == ZYDIS_OPERAND_TYPE_MEMORY)
{
auto openBracket = strchr(buf, '[');
if(openBracket)
{
std::string result;
result = openBracket + 1;
if(result.back() == ']')
result.pop_back();
return result;
}
}
return buf;
}
uint8_t Zydis::Size() const
@ -604,6 +617,8 @@ uint64_t Zydis::ResolveOpValue(uint8_t opindex, const std::function<uint64_t(Zyd
{
case ZYDIS_OPERAND_TYPE_IMMEDIATE:
dest = uint64_t(op.imm.value.u);
if(!IsBranchType(Zydis::BTJmp | Zydis::BTCall | Zydis::BTLoop | Zydis::BTXbegin))
dest &= (uint64_t(-1) >> (sizeof(uint64_t) * 8 - mInstr.info.operand_width));
break;
case ZYDIS_OPERAND_TYPE_REGISTER:
dest = resolveReg(op.reg.value);