Compare commits
89 Commits
a4be9f87f5
...
caa578a029
Author | SHA1 | Date |
---|---|---|
|
caa578a029 | |
|
d08913bc54 | |
|
da43aca116 | |
|
7a3851a607 | |
|
a5f73b479f | |
|
9e4c1a4d26 | |
|
517a855e9a | |
|
f3cb3443d1 | |
|
c3642c35be | |
|
399b19f847 | |
|
9c07d82dc8 | |
|
a6e448b598 | |
|
ec9a2a2af1 | |
|
9f6d396c4e | |
|
a006d75ee5 | |
|
e30a70ad4d | |
|
8cb5459629 | |
|
b683fc6a59 | |
|
62129b426e | |
|
9ed6033fb6 | |
|
afb5ac45c5 | |
|
ab9c28549a | |
|
0853cafadc | |
|
81bc337e52 | |
|
ee13290541 | |
|
04c5050015 | |
|
e2093d2d89 | |
|
3eb2070c3a | |
|
f56fa5ce23 | |
|
aa85488fe5 | |
|
911329e8e6 | |
|
03baaa1ae3 | |
|
b17fc86af7 | |
|
93ac4548f7 | |
|
03c6f3b6a5 | |
|
16fccbd2d4 | |
|
050c989dc3 | |
|
218d784a7e | |
|
f8567b59f5 | |
|
eff762460f | |
|
570aaea06d | |
|
d2f6ba72cc | |
|
61814b2da7 | |
|
715831637a | |
|
01c239534a | |
|
2747f72f38 | |
|
4193000159 | |
|
a320227378 | |
|
7c2276681a | |
|
b2b104b79f | |
|
95b790eab1 | |
|
eeab4c47ed | |
|
373b3a538f | |
|
44c3d39165 | |
|
923b894df2 | |
|
c9d80e5c99 | |
|
65d57bfd2e | |
|
2e1fd1f289 | |
|
b84c293f15 | |
|
50d7d988f6 | |
|
735d3ca5f9 | |
|
dfda450b41 | |
|
49f9487a59 | |
|
7f9dc7fc04 | |
|
50fc52b0d2 | |
|
61f99ae5c9 | |
|
e3e6a8a9fa | |
|
8ae5982502 | |
|
f4821ce331 | |
|
de527241cd | |
|
a2594cf1f9 | |
|
0f54d5ebcd | |
|
d52466f981 | |
|
4945c36e85 | |
|
0f39191c9d | |
|
81d72252a8 | |
|
c122eb9e1d | |
|
b0392eda1c | |
|
d0fb3a0b88 | |
|
cb31cbd83b | |
|
99f5e93592 | |
|
e9dfe3020e | |
|
98d08ce826 | |
|
17bd183de2 | |
|
89aee8ad5b | |
|
7dade58481 | |
|
ca637fad33 | |
|
e5dba0ad63 | |
|
3409444e33 |
|
@ -0,0 +1,2 @@
|
|||
# Disable core.autocrlf (https://stackoverflow.com/a/52996849/1806760)
|
||||
* -text
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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[]);
|
||||
|
|
|
@ -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))
|
||||
{
|
||||
|
|
|
@ -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]);
|
||||
|
|
|
@ -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("");
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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)));
|
||||
}
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
|
|
@ -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];
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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&"));
|
||||
|
|
|
@ -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") &&
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
};
|
||||
|
|
|
@ -62,6 +62,7 @@ void ColumnReorderDialog::on_okButton_clicked()
|
|||
mParent->mColumnOrder[i] = col;
|
||||
mParent->setColumnHidden(col, true);
|
||||
}
|
||||
mParent->reloadData();
|
||||
this->done(QDialog::Accepted);
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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! -> </b></font>") + addrText);
|
||||
|
||||
ui->labelError->setToolTip(QString("<qt>%1</qt>").arg(addrText.toHtmlEscaped()));
|
||||
ui->labelError->setText(tr("<font color='#00DD00'><b>Correct expression! -> </b></font>") + addrText.toHtmlEscaped());
|
||||
setOkEnabled(true);
|
||||
expressionText = expression;
|
||||
}
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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&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&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>&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>&Entire Block</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="chkFromSelection">
|
||||
<property name="text">
|
||||
<string>Start from &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>&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>&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>
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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()))
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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.");
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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)));
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
};
|
||||
};
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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', "");
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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" />
|
||||
|
|
|
@ -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
|
||||
|
|
@ -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);
|
||||
|
|
Loading…
Reference in New Issue