1
0
Fork 0

Merge pull request #3285 from x64dbg/ui-lagging

Fix UI lagging
This commit is contained in:
Duncan Ogilvie 2023-12-04 17:45:57 +01:00 committed by GitHub
commit 04c5050015
Signed by: GitHub
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 342 additions and 189 deletions

View File

@ -28,20 +28,188 @@ class BridgeArchitecture : public Architecture
/************************************************************************************
Class Members
************************************************************************************/
static const char* msg2str(GUIMSG msg)
{
switch(msg)
{
case GUI_UPDATE_REGISTER_VIEW:
return "GUI_UPDATE_REGISTER_VIEW";
case GUI_UPDATE_DISASSEMBLY_VIEW:
return "GUI_UPDATE_DISASSEMBLY_VIEW";
case GUI_UPDATE_BREAKPOINTS_VIEW:
return "GUI_UPDATE_BREAKPOINTS_VIEW";
case GUI_UPDATE_DUMP_VIEW:
return "GUI_UPDATE_DUMP_VIEW";
case GUI_UPDATE_THREAD_VIEW:
return "GUI_UPDATE_THREAD_VIEW";
case GUI_UPDATE_MEMORY_VIEW:
return "GUI_UPDATE_MEMORY_VIEW";
case GUI_UPDATE_SIDEBAR:
return "GUI_UPDATE_SIDEBAR";
case GUI_REPAINT_TABLE_VIEW:
return "GUI_REPAINT_TABLE_VIEW";
case GUI_UPDATE_PATCHES:
return "GUI_UPDATE_PATCHES";
case GUI_UPDATE_CALLSTACK:
return "GUI_UPDATE_CALLSTACK";
case GUI_UPDATE_SEHCHAIN:
return "GUI_UPDATE_SEHCHAIN";
case GUI_UPDATE_TIME_WASTED_COUNTER:
return "GUI_UPDATE_TIME_WASTED_COUNTER";
case GUI_UPDATE_ARGUMENT_VIEW:
return "GUI_UPDATE_ARGUMENT_VIEW";
case GUI_UPDATE_WATCH_VIEW:
return "GUI_UPDATE_WATCH_VIEW";
case GUI_UPDATE_GRAPH_VIEW:
return "GUI_UPDATE_GRAPH_VIEW";
case GUI_UPDATE_TYPE_WIDGET:
return "GUI_UPDATE_TYPE_WIDGET";
case GUI_UPDATE_TRACE_BROWSER:
return "GUI_UPDATE_TRACE_BROWSER";
default:
return "<unknown message>";
}
}
void Bridge::throttleUpdateSlot(GUIMSG msg)
{
// NOTE: This is running synchronously on the UI thread
auto lastUpdate = mLastUpdates[msg];
auto now = GetTickCount();
auto elapsed = now - lastUpdate;
const auto interval = 100;
if(lastUpdate > 0 && elapsed < interval)
{
//qDebug() << "Delay update:" << msg2str(msg);
QTimer* timer = mUpdateTimers[msg];
if(timer == nullptr)
{
timer = new QTimer(this);
timer->setSingleShot(true);
connect(timer, &QTimer::timeout, this, [this, msg]
{
doUpdate(msg);
});
mUpdateTimers[msg] = timer;
}
if(!timer->isActive())
{
timer->setInterval(interval - elapsed);
timer->start();
}
}
else
{
//qDebug() << "No delay: " << msg2str(msg);
doUpdate(msg);
}
}
void Bridge::doUpdate(GUIMSG msg)
{
auto start = GetTickCount();
switch(msg)
{
case GUI_UPDATE_REGISTER_VIEW:
updateRegisters();
break;
case GUI_UPDATE_DISASSEMBLY_VIEW:
updateDisassembly();
break;
case GUI_UPDATE_BREAKPOINTS_VIEW:
updateBreakpoints();
break;
case GUI_UPDATE_DUMP_VIEW:
updateDump();
break;
case GUI_UPDATE_THREAD_VIEW:
updateThreads();
break;
case GUI_UPDATE_MEMORY_VIEW:
updateMemory();
break;
case GUI_UPDATE_SIDEBAR:
updateSideBar();
break;
case GUI_REPAINT_TABLE_VIEW:
repaintTableView();
break;
case GUI_UPDATE_PATCHES:
updatePatches();
break;
case GUI_UPDATE_CALLSTACK:
updateCallStack();
break;
case GUI_UPDATE_SEHCHAIN:
updateSEHChain();
break;
case GUI_UPDATE_TIME_WASTED_COUNTER:
updateTimeWastedCounter();
break;
case GUI_UPDATE_ARGUMENT_VIEW:
updateArgumentView();
break;
case GUI_UPDATE_WATCH_VIEW:
updateWatch();
break;
case GUI_UPDATE_GRAPH_VIEW:
updateGraph();
break;
case GUI_UPDATE_TYPE_WIDGET:
typeUpdateWidget();
break;
case GUI_UPDATE_TRACE_BROWSER:
updateTraceBrowser();
break;
default:
__debugbreak();
}
// Log potentially bottlenecked updates
auto now = GetTickCount();
auto elapsed = now - start;
if(elapsed > 5)
qDebug() << msg2str(msg) << elapsed << "ms";
mLastUpdates[msg] = now;
}
Bridge::Bridge(QObject* parent) : QObject(parent)
{
InitializeCriticalSection(&csBridge);
InitializeCriticalSection(&mCsBridge);
for(size_t i = 0; i < BridgeResult::Last; i++)
resultEvents[i] = CreateEventW(nullptr, true, true, nullptr);
dwMainThreadId = GetCurrentThreadId();
mResultEvents[i] = CreateEventW(nullptr, true, true, nullptr);
mMainThreadId = GetCurrentThreadId();
connect(this, &Bridge::throttleUpdate, this, &Bridge::throttleUpdateSlot);
}
Bridge::~Bridge()
{
EnterCriticalSection(&csBridge);
EnterCriticalSection(&mCsBridge);
for(size_t i = 0; i < BridgeResult::Last; i++)
CloseHandle(resultEvents[i]);
DeleteCriticalSection(&csBridge);
CloseHandle(mResultEvents[i]);
DeleteCriticalSection(&mCsBridge);
}
void Bridge::CopyToClipboard(const QString & text)
@ -68,8 +236,8 @@ void Bridge::setResult(BridgeResult::Type type, dsint result)
#ifdef DEBUG
OutputDebugStringA(QString().sprintf("[x64dbg] [%u] Bridge::setResult(%d, %p)\n", GetCurrentThreadId(), type, result).toUtf8().constData());
#endif //DEBUG
bridgeResults[type] = result;
SetEvent(resultEvents[type]);
mBridgeResults[type] = result;
SetEvent(mResultEvents[type]);
}
/************************************************************************************
@ -103,7 +271,7 @@ void Bridge::emitMenuAddToList(QWidget* parent, QMenu* menu, GUIMENUTYPE hMenu,
void Bridge::setDbgStopped()
{
dbgStopped = true;
mDbgStopped = true;
}
/************************************************************************************
@ -112,7 +280,7 @@ void Bridge::setDbgStopped()
void* Bridge::processMessage(GUIMSG type, void* param1, void* param2)
{
if(dbgStopped) //there can be no more messages if the debugger stopped = IGNORE
if(mDbgStopped) //there can be no more messages if the debugger stopped = IGNORE
return nullptr;
switch(type)
{
@ -160,24 +328,12 @@ void* Bridge::processMessage(GUIMSG type, void* param1, void* param2)
emit redirectLogStop();
break;
case GUI_UPDATE_REGISTER_VIEW:
emit updateRegisters();
break;
case GUI_UPDATE_DISASSEMBLY_VIEW:
emit updateDisassembly();
break;
case GUI_UPDATE_BREAKPOINTS_VIEW:
emit updateBreakpoints();
break;
case GUI_UPDATE_WINDOW_TITLE:
emit updateWindowTitle(QString((const char*)param1));
break;
case GUI_GET_WINDOW_HANDLE:
return winId;
return mWinId;
case GUI_DUMP_AT:
emit dumpAt((dsint)param1);
@ -252,25 +408,25 @@ void* Bridge::processMessage(GUIMSG type, void* param1, void* param2)
break;
case GUI_REF_ADDCOLUMN:
if(referenceManager->currentReferenceView())
referenceManager->currentReferenceView()->addColumnAtRef((int)param1, QString((const char*)param2));
if(mReferenceManager->currentReferenceView())
mReferenceManager->currentReferenceView()->addColumnAtRef((int)param1, QString((const char*)param2));
break;
case GUI_REF_SETROWCOUNT:
{
if(referenceManager->currentReferenceView())
referenceManager->currentReferenceView()->setRowCount((dsint)param1);
if(mReferenceManager->currentReferenceView())
mReferenceManager->currentReferenceView()->setRowCount((dsint)param1);
}
break;
case GUI_REF_GETROWCOUNT:
if(referenceManager->currentReferenceView())
return (void*)referenceManager->currentReferenceView()->stdList()->getRowCount();
if(mReferenceManager->currentReferenceView())
return (void*)mReferenceManager->currentReferenceView()->stdList()->getRowCount();
return 0;
case GUI_REF_SEARCH_GETROWCOUNT:
if(referenceManager->currentReferenceView())
return (void*)referenceManager->currentReferenceView()->mCurList->getRowCount();
if(mReferenceManager->currentReferenceView())
return (void*)mReferenceManager->currentReferenceView()->mCurList->getRowCount();
return 0;
case GUI_REF_DELETEALLCOLUMNS:
@ -280,16 +436,16 @@ void* Bridge::processMessage(GUIMSG type, void* param1, void* param2)
case GUI_REF_SETCELLCONTENT:
{
CELLINFO* info = (CELLINFO*)param1;
if(referenceManager->currentReferenceView())
referenceManager->currentReferenceView()->setCellContent(info->row, info->col, QString(info->str));
if(mReferenceManager->currentReferenceView())
mReferenceManager->currentReferenceView()->setCellContent(info->row, info->col, QString(info->str));
}
break;
case GUI_REF_GETCELLCONTENT:
{
QString content;
if(referenceManager->currentReferenceView())
content = referenceManager->currentReferenceView()->stdList()->getCellContent((int)param1, (int)param2);
if(mReferenceManager->currentReferenceView())
content = mReferenceManager->currentReferenceView()->stdList()->getCellContent((int)param1, (int)param2);
auto bytes = content.toUtf8();
auto data = BridgeAlloc(bytes.size() + 1);
memcpy(data, bytes.constData(), bytes.size());
@ -299,8 +455,8 @@ void* Bridge::processMessage(GUIMSG type, void* param1, void* param2)
case GUI_REF_SEARCH_GETCELLCONTENT:
{
QString content;
if(referenceManager->currentReferenceView())
content = referenceManager->currentReferenceView()->mCurList->getCellContent((int)param1, (int)param2);
if(mReferenceManager->currentReferenceView())
content = mReferenceManager->currentReferenceView()->mCurList->getCellContent((int)param1, (int)param2);
auto bytes = content.toUtf8();
auto data = BridgeAlloc(bytes.size() + 1);
memcpy(data, bytes.constData(), bytes.size());
@ -316,26 +472,26 @@ void* Bridge::processMessage(GUIMSG type, void* param1, void* param2)
break;
case GUI_REF_SETPROGRESS:
if(referenceManager->currentReferenceView())
if(mReferenceManager->currentReferenceView())
{
auto newProgress = (int)param1;
if(referenceManager->currentReferenceView()->progress() != newProgress)
if(mReferenceManager->currentReferenceView()->progress() != newProgress)
emit referenceSetProgress(newProgress);
}
break;
case GUI_REF_SETCURRENTTASKPROGRESS:
if(referenceManager->currentReferenceView())
if(mReferenceManager->currentReferenceView())
{
auto newProgress = (int)param1;
if(referenceManager->currentReferenceView()->currentTaskProgress() != newProgress)
if(mReferenceManager->currentReferenceView()->currentTaskProgress() != newProgress)
emit referenceSetCurrentTaskProgress((int)param1, QString((const char*)param2));
}
break;
case GUI_REF_SETSEARCHSTARTCOL:
if(referenceManager->currentReferenceView())
referenceManager->currentReferenceView()->setSearchStartCol((duint)param1);
if(mReferenceManager->currentReferenceView())
mReferenceManager->currentReferenceView()->setSearchStartCol((duint)param1);
break;
case GUI_REF_INITIALIZE:
@ -350,18 +506,6 @@ void* Bridge::processMessage(GUIMSG type, void* param1, void* param2)
emit stackDumpAt((duint)param1, (duint)param2);
break;
case GUI_UPDATE_DUMP_VIEW:
emit updateDump();
break;
case GUI_UPDATE_THREAD_VIEW:
emit updateThreads();
break;
case GUI_UPDATE_MEMORY_VIEW:
emit updateMemory();
break;
case GUI_ADD_RECENT_FILE:
emit addRecentFile(QString((const char*)param1));
break;
@ -619,26 +763,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;
@ -669,17 +793,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);
@ -734,10 +854,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);
@ -764,10 +880,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);
@ -784,17 +896,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:
{
@ -883,10 +991,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;
@ -914,12 +1018,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:
@ -947,7 +1047,28 @@ void* Bridge::processMessage(GUIMSG type, void* param1, void* param2)
break;
case GUI_GET_MAIN_THREAD_ID:
return (void*)dwMainThreadId;
return (void*)mMainThreadId;
case GUI_UPDATE_REGISTER_VIEW:
case GUI_UPDATE_DISASSEMBLY_VIEW:
case GUI_UPDATE_BREAKPOINTS_VIEW:
case GUI_UPDATE_DUMP_VIEW:
case GUI_UPDATE_THREAD_VIEW:
case GUI_UPDATE_MEMORY_VIEW:
case GUI_UPDATE_SIDEBAR:
case GUI_REPAINT_TABLE_VIEW:
case GUI_UPDATE_PATCHES:
case GUI_UPDATE_CALLSTACK:
case GUI_UPDATE_SEHCHAIN:
case GUI_UPDATE_TIME_WASTED_COUNTER:
case GUI_UPDATE_ARGUMENT_VIEW:
case GUI_UPDATE_WATCH_VIEW:
case GUI_UPDATE_GRAPH_VIEW:
case GUI_UPDATE_TYPE_WIDGET:
case GUI_UPDATE_TRACE_BROWSER:
// NOTE: this can run on any thread.
emit throttleUpdate(type);
break;
}
return nullptr;

View File

@ -26,6 +26,11 @@ class Bridge : public QObject
friend class BridgeResult;
void doUpdate(GUIMSG msg);
private slots:
void throttleUpdateSlot(GUIMSG msg);
public:
explicit Bridge(QObject* parent = nullptr);
~Bridge();
@ -49,12 +54,12 @@ public:
void setDbgStopped();
//Public variables
void* winId = nullptr;
ReferenceManager* referenceManager = nullptr;
void* mWinId = nullptr;
ReferenceManager* mReferenceManager = nullptr;
bool mIsRunning = false;
duint mLastCip = 0;
SymbolView* symbolView = nullptr;
bool loggingEnabled = true;
SymbolView* mSymbolView = nullptr;
bool mLoggingEnabled = true;
signals:
void disassembleAt(duint va, duint eip);
@ -183,11 +188,14 @@ signals:
void showReferences();
void gotoTraceIndex(duint index);
void showTraceBrowser();
void throttleUpdate(GUIMSG msg);
private:
CRITICAL_SECTION csBridge;
HANDLE resultEvents[BridgeResult::Last];
duint bridgeResults[BridgeResult::Last];
DWORD dwMainThreadId = 0;
volatile bool dbgStopped = false;
CRITICAL_SECTION mCsBridge;
HANDLE mResultEvents[BridgeResult::Last];
duint mBridgeResults[BridgeResult::Last];
DWORD mMainThreadId = 0;
volatile bool mDbgStopped = false;
QMap<GUIMSG, DWORD> mLastUpdates;
QMap<GUIMSG, QTimer*> mUpdateTimers;
};

View File

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

View File

@ -154,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();
@ -207,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"));

View File

@ -33,9 +33,9 @@ MemoryMapView::MemoryMapView(StdTable* parent)
loadColumnFromConfig("MemoryMap");
setIconColumn(ColParty);
connect(Bridge::getBridge(), SIGNAL(updateMemory()), this, SLOT(refreshMap()));
connect(Bridge::getBridge(), SIGNAL(updateMemory()), this, SLOT(refreshMapSlot()));
connect(Bridge::getBridge(), SIGNAL(dbgStateChanged(DBGSTATE)), this, SLOT(stateChangedSlot(DBGSTATE)));
connect(Bridge::getBridge(), SIGNAL(selectInMemoryMap(duint)), this, SLOT(selectAddress(duint)));
connect(Bridge::getBridge(), SIGNAL(selectInMemoryMap(duint)), this, SLOT(selectAddressSlot(duint)));
connect(Bridge::getBridge(), SIGNAL(selectionMemmapGet(SELECTIONDATA*)), this, SLOT(selectionGetSlot(SELECTIONDATA*)));
connect(Bridge::getBridge(), SIGNAL(selectionMemmapSet(const SELECTIONDATA*)), this, SLOT(selectionSetSlot(const SELECTIONDATA*)));
connect(Bridge::getBridge(), SIGNAL(disassembleAt(duint, duint)), this, SLOT(disassembleAtSlot(duint, duint)));
@ -63,12 +63,12 @@ void MemoryMapView::setupContextMenu()
//Set PageMemory Rights
mPageMemoryRights = new QAction(DIcon("memmap_set_page_memory_rights"), tr("Set Page Memory Rights"), this);
connect(mPageMemoryRights, SIGNAL(triggered()), this, SLOT(pageMemoryRights()));
connect(mPageMemoryRights, SIGNAL(triggered()), this, SLOT(pageMemoryRightsSlot()));
//Switch View
mSwitchView = new QAction(DIcon("change-view"), "", this);
setSwitchViewName();
connect(mSwitchView, SIGNAL(triggered()), this, SLOT(switchView()));
connect(mSwitchView, SIGNAL(triggered()), this, SLOT(switchViewSlot()));
//Breakpoint menu
mBreakpointMenu = new QMenu(tr("Memory &Breakpoint"), this);
@ -169,11 +169,11 @@ void MemoryMapView::setupContextMenu()
//Dump
//TODO: These two actions should also appear in CPUDump
mDumpMemory = new QAction(DIcon("binary_save"), tr("&Dump Memory to File"), this);
connect(mDumpMemory, SIGNAL(triggered()), this, SLOT(dumpMemory()));
connect(mDumpMemory, SIGNAL(triggered()), this, SLOT(dumpMemorySlot()));
//Load
mLoadMemory = new QAction(DIcon(""), tr("&Overwrite with Data from File"), this);
connect(mLoadMemory, SIGNAL(triggered()), this, SLOT(loadMemory()));
connect(mLoadMemory, SIGNAL(triggered()), this, SLOT(loadMemorySlot()));
//Add virtual module
mAddVirtualMod = new QAction(DIcon("virtual"), tr("Add virtual module"), this);
@ -272,17 +272,6 @@ void MemoryMapView::contextMenuSlot(const QPoint & pos)
menu.exec(mapToGlobal(pos)); //execute context menu
}
static QString getProtectionString(DWORD Protect)
{
#define RIGHTS_STRING (sizeof("ERWCG"))
char rights[RIGHTS_STRING];
if(!DbgFunctions()->PageRightsToString(Protect, rights))
return "bad";
return QString(rights);
}
QString MemoryMapView::paintContent(QPainter* painter, duint row, duint col, int x, int y, int w, int h)
{
if(col == 0) //address
@ -377,14 +366,14 @@ void MemoryMapView::setSwitchViewName()
QAction* MemoryMapView::makeCommandAction(QAction* action, const QString & command)
{
action->setData(QVariant(command));
connect(action, SIGNAL(triggered()), this, SLOT(ExecCommand()));
connect(action, SIGNAL(triggered()), this, SLOT(execCommandSlot()));
return action;
}
/**
* @brief MemoryMapView::ExecCommand execute command slot for menus.
* @brief MemoryMapView::execCommandSlot execute command slot for menus.
*/
void MemoryMapView::ExecCommand()
void MemoryMapView::execCommandSlot()
{
QAction* action = qobject_cast<QAction*>(sender());
if(action)
@ -404,16 +393,52 @@ void MemoryMapView::ExecCommand()
}
}
void MemoryMapView::refreshMap()
static QString getProtectionString(DWORD protect)
{
//reserved pages don't have a protection (https://goo.gl/Izkk0c)
if(protect == 0)
{
return QString();
}
#define meme(prot, str) (prot & PAGE_GUARD) ? QStringLiteral(str QT_UNICODE_LITERAL("G")) : QStringLiteral(str QT_UNICODE_LITERAL("-"))
switch(protect & 0xFF)
{
case PAGE_NOACCESS:
return meme(protect, "----");
case PAGE_READONLY:
return meme(protect, "-R--");
case PAGE_READWRITE:
return meme(protect, "-RW-");
case PAGE_WRITECOPY:
return meme(protect, "-RWC");
case PAGE_EXECUTE:
return meme(protect, "E---");
case PAGE_EXECUTE_READ:
return meme(protect, "ER--");
case PAGE_EXECUTE_READWRITE:
return meme(protect, "ERW-");
case PAGE_EXECUTE_WRITECOPY:
return meme(protect, "ERWC");
default:
return meme(protect, "????");
}
}
void MemoryMapView::refreshMapSlot()
{
MEMMAP memoryMap = {};
DbgMemMap(&memoryMap);
setRowCount(memoryMap.count);
auto strUser = tr("User");
auto strSystem = tr("System");
for(int i = 0; i < memoryMap.count; i++)
{
const auto & mbi = (memoryMap.page)[i].mbi;
const auto & mbi = memoryMap.page[i].mbi;
// Base address
setCellContent(i, ColAddress, ToPtrString((duint)mbi.BaseAddress));
@ -428,11 +453,11 @@ void MemoryMapView::refreshMap()
switch(party)
{
case mod_user:
setCellContent(i, ColParty, tr("User"));
setCellContent(i, ColParty, strUser);
setRowIcon(i, DIcon("markasuser"));
break;
case mod_system:
setCellContent(i, ColParty, tr("System"));
setCellContent(i, ColParty, strSystem);
setRowIcon(i, DIcon("markassystem"));
break;
default:
@ -442,64 +467,62 @@ void MemoryMapView::refreshMap()
}
// Information
auto content = QString((memoryMap.page)[i].info);
setCellContent(i, ColPageInfo, content);
auto info = memoryMap.page[i].info;
setCellContent(i, ColPageInfo, info);
// Content, TODO: proper section content analysis in dbg/memory.cpp:MemUpdateMap
QString content;
char comment_text[MAX_COMMENT_SIZE];
if(DbgFunctions()->GetUserComment((duint)mbi.BaseAddress, comment_text)) // user comment present
content = comment_text;
else if(content.contains(".bss"))
else if(strncmp(info, ".bss", 4) == 0)
content = tr("Uninitialized data");
else if(content.contains(".data"))
else if(strncmp(info, ".data", 5) == 0)
content = tr("Initialized data");
else if(content.contains(".edata"))
else if(strncmp(info, ".edata", 6) == 0)
content = tr("Export tables");
else if(content.contains(".idata"))
else if(strncmp(info, ".idata", 6) == 0)
content = tr("Import tables");
else if(content.contains(".pdata"))
else if(strncmp(info, ".pdata", 6) == 0)
content = tr("Exception information");
else if(content.contains(".rdata"))
else if(strncmp(info, ".rdata", 6) == 0)
content = tr("Read-only initialized data");
else if(content.contains(".reloc"))
else if(strncmp(info, ".reloc", 6) == 0)
content = tr("Base relocations");
else if(content.contains(".rsrc"))
else if(strncmp(info, ".rsrc", 5) == 0)
content = tr("Resources");
else if(content.contains(".text"))
else if(strncmp(info, ".text", 5) == 0)
content = tr("Executable code");
else if(content.contains(".tls"))
else if(strncmp(info, ".tls", 4) == 0)
content = tr("Thread-local storage");
else if(content.contains(".xdata"))
else if(strncmp(info, ".xdata", 6) == 0)
content = tr("Exception information");
else
content = QString("");
setCellContent(i, ColContent, std::move(content));
// Type
const char* type = "";
QString type;
switch(mbi.Type)
{
case MEM_IMAGE:
type = "IMG";
type = QStringLiteral("IMG");
break;
case MEM_MAPPED:
type = "MAP";
type = QStringLiteral("MAP");
break;
case MEM_PRIVATE:
type = "PRV";
type = QStringLiteral("PRV");
break;
default:
type = "N/A";
type = QStringLiteral("N/A");
break;
}
setCellContent(i, ColAllocation, type);
setCellContent(i, ColAllocation, std::move(type));
// current access protection
setCellContent(i, ColCurProtect, getProtectionString(mbi.Protect));
// allocation protection
setCellContent(i, ColAllocProtect, getProtectionString(mbi.AllocationProtect));
}
if(memoryMap.page != 0)
BridgeFree(memoryMap.page);
@ -509,7 +532,7 @@ void MemoryMapView::refreshMap()
void MemoryMapView::stateChangedSlot(DBGSTATE state)
{
if(state == paused)
refreshMap();
refreshMapSlot();
}
void MemoryMapView::followDumpSlot()
@ -554,16 +577,16 @@ void MemoryMapView::memoryExecuteSingleshootToggleSlot()
}
}
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();
@ -632,7 +655,7 @@ void MemoryMapView::findPatternSlot()
emit showReferences();
}
void MemoryMapView::dumpMemory()
void MemoryMapView::dumpMemorySlot()
{
duint start = 0;
duint end = 0;
@ -665,7 +688,7 @@ void MemoryMapView::dumpMemory()
}
}
void MemoryMapView::loadMemory()
void MemoryMapView::loadMemorySlot()
{
auto modname = mainModuleName();
if(!modname.isEmpty())
@ -682,7 +705,7 @@ void MemoryMapView::loadMemory()
}
}
void MemoryMapView::selectAddress(duint va)
void MemoryMapView::selectAddressSlot(duint va)
{
auto base = DbgMemFindBaseAddr(va, nullptr);
if(base)
@ -703,7 +726,7 @@ void MemoryMapView::selectAddress(duint va)
void MemoryMapView::gotoOriginSlot()
{
selectAddress(mCipBase);
selectAddressSlot(mCipBase);
}
void MemoryMapView::gotoExpressionSlot()
@ -714,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()));
}
}

View File

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

View File

@ -123,7 +123,7 @@ QAction* ThreadView::makeCommandAction(QAction* action, const QString & command)
}
/**
* @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::execCommandSlot()
{

View File

@ -19,11 +19,11 @@ inline QString ToPtrString(duint Address)
char temp[32];
#ifdef _WIN64
sprintf_s(temp, "%016llX", Address);
auto size = sprintf_s(temp, "%016llX", Address);
#else
sprintf_s(temp, "%08X", Address);
auto size = sprintf_s(temp, "%08X", Address);
#endif // _WIN64
return QString(temp);
return QString::fromLatin1(temp, size);
}
inline QString ToLongLongHexString(unsigned long long Value)

View File

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