mirror of
https://github.com/x64dbg/x64dbg.git
synced 2024-11-23 13:00:14 +00:00
Merge branch 'development' into patch000000dc
This commit is contained in:
commit
e1b7dfddb6
@ -1,14 +1,14 @@
|
||||
#ifndef _BRIDGEMAIN_H_
|
||||
#define _BRIDGEMAIN_H_
|
||||
|
||||
#include <windows.h>
|
||||
#include <Windows.h>
|
||||
|
||||
#ifndef __cplusplus
|
||||
#include <stdbool.h>
|
||||
#define DEFAULT_PARAM(name, value) name
|
||||
#else
|
||||
#define DEFAULT_PARAM(name, value) name = value
|
||||
#endif
|
||||
#endif // __cplusplus
|
||||
|
||||
//default structure alignments forced
|
||||
#ifdef _WIN64
|
||||
@ -36,7 +36,7 @@ typedef signed long dsint;
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
#endif // __cplusplus
|
||||
|
||||
//Bridge defines
|
||||
#define MAX_SETTING_SIZE 65536
|
||||
@ -147,7 +147,7 @@ BRIDGE_IMPEXP const wchar_t* BridgeUserDirectory();
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif // __cplusplus
|
||||
|
||||
//list structure (and C++ wrapper)
|
||||
#include "bridgelist.h"
|
||||
@ -157,7 +157,7 @@ BRIDGE_IMPEXP const wchar_t* BridgeUserDirectory();
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
#endif // __cplusplus
|
||||
|
||||
//Debugger defines
|
||||
#define MAX_LABEL_SIZE 256
|
||||
@ -1477,7 +1477,7 @@ BRIDGE_IMPEXP DWORD GuiGetMainThreadId();
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif // __cplusplus
|
||||
|
||||
// Some useful C++ wrapper classes
|
||||
#ifdef __cplusplus
|
||||
|
7
src/dbg/_apichecker.c
Normal file
7
src/dbg/_apichecker.c
Normal file
@ -0,0 +1,7 @@
|
||||
// HACK: pretend we are in the same environment as a plugin
|
||||
//#define PLUG_IMPEXP
|
||||
#ifdef BUILD_DBG
|
||||
#undef BUILD_DBG
|
||||
#endif // BUILD_DBG
|
||||
|
||||
#include "_plugins.h"
|
@ -31,6 +31,7 @@
|
||||
#include "exception.h"
|
||||
#include "database.h"
|
||||
#include "dbghelp_safe.h"
|
||||
#include "types.h"
|
||||
|
||||
static DBGFUNCTIONS _dbgfunctions;
|
||||
|
||||
@ -576,4 +577,14 @@ void dbgfunctionsinit()
|
||||
_dbgfunctions.GetAddrFromLineEx = _getaddrfromlineex;
|
||||
_dbgfunctions.ModSymbolStatus = _modsymbolstatus;
|
||||
_dbgfunctions.GetCallStackByThread = _getcallstackbythread;
|
||||
_dbgfunctions.EnumStructs = [](CBSTRING callback, void* userdata)
|
||||
{
|
||||
std::vector<Types::TypeManager::Summary> types;
|
||||
EnumTypes(types);
|
||||
for(const auto & type : types)
|
||||
{
|
||||
if(type.kind == "struct" || type.kind == "union" || type.kind == "class")
|
||||
callback(type.name.c_str(), userdata);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
@ -136,6 +136,8 @@ typedef enum
|
||||
MODSYMLOADED
|
||||
} MODULESYMBOLSTATUS;
|
||||
|
||||
typedef void(*CBSTRING)(const char* str, void* userdata);
|
||||
|
||||
typedef bool (*ASSEMBLEATEX)(duint addr, const char* instruction, char* error, bool fillnop);
|
||||
typedef bool (*SECTIONFROMADDR)(duint addr, char* section);
|
||||
typedef bool (*MODNAMEFROMADDR)(duint addr, char* modname, bool extension);
|
||||
@ -287,6 +289,7 @@ typedef struct DBGFUNCTIONS_
|
||||
GETADDRFROMLINEEX GetAddrFromLineEx;
|
||||
MODSYMBOLSTATUS ModSymbolStatus;
|
||||
GETCALLSTACKBYTHREAD GetCallStackByThread;
|
||||
void (*EnumStructs)(CBSTRING callback, void* userdata);
|
||||
} DBGFUNCTIONS;
|
||||
|
||||
#ifdef BUILD_DBG
|
||||
|
@ -3,7 +3,6 @@
|
||||
\brief Implements the global class.
|
||||
*/
|
||||
|
||||
#include <windows.h>
|
||||
#include "_global.h"
|
||||
#include <objbase.h>
|
||||
#include <shlobj.h>
|
||||
|
@ -11,7 +11,9 @@
|
||||
#endif
|
||||
#define WINVER _WIN32_WINNT
|
||||
|
||||
#ifndef _WIN32_IE
|
||||
#define _WIN32_IE 0x0500
|
||||
#endif //_WIN32_IE
|
||||
|
||||
// Allow including Windows.h without bringing in a redefined and outdated subset of NTSTATUSes.
|
||||
// To get NTSTATUS defines, #undef WIN32_NO_STATUS after Windows.h and then #include <ntstatus.h>
|
||||
|
@ -12,12 +12,14 @@
|
||||
|
||||
#else
|
||||
|
||||
#include <Windows.h>
|
||||
|
||||
#ifdef __GNUC__
|
||||
#include "dbghelp/dbghelp.h"
|
||||
#else
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable:4091)
|
||||
#include <dbghelp.h>
|
||||
#include <DbgHelp.h>
|
||||
#pragma warning(pop)
|
||||
#endif // __GNUC__
|
||||
|
||||
|
@ -163,7 +163,7 @@ bool _plugin_registerexprfunction(int pluginHandle, const char* name, int argc,
|
||||
return pluginexprfuncregister(pluginHandle, name, argc, cbFunction, userdata);
|
||||
}
|
||||
|
||||
bool _plugin_registerexprfunctionex(int pluginHandle, const char* name, const ValueType & returnType, const ValueType* argTypes, size_t argCount, CBPLUGINEXPRFUNCTIONEX cbFunction, void* userdata)
|
||||
bool _plugin_registerexprfunctionex(int pluginHandle, const char* name, ValueType returnType, const ValueType* argTypes, size_t argCount, CBPLUGINEXPRFUNCTIONEX cbFunction, void* userdata)
|
||||
{
|
||||
return pluginexprfuncregisterex(pluginHandle, name, returnType, argTypes, argCount, cbFunction, userdata);
|
||||
}
|
||||
|
@ -348,7 +348,7 @@ PLUG_IMPEXP bool _plugin_menuentryremove(int pluginHandle, int hEntry);
|
||||
PLUG_IMPEXP void _plugin_startscript(CBPLUGINSCRIPT cbScript);
|
||||
PLUG_IMPEXP bool _plugin_waituntilpaused();
|
||||
PLUG_IMPEXP bool _plugin_registerexprfunction(int pluginHandle, const char* name, int argc, CBPLUGINEXPRFUNCTION cbFunction, void* userdata);
|
||||
PLUG_IMPEXP bool _plugin_registerexprfunctionex(int pluginHandle, const char* name, const ValueType & returnType, const ValueType* argTypes, size_t argCount, CBPLUGINEXPRFUNCTIONEX cbFunction, void* userdata);
|
||||
PLUG_IMPEXP bool _plugin_registerexprfunctionex(int pluginHandle, const char* name, ValueType returnType, const ValueType* argTypes, size_t argCount, CBPLUGINEXPRFUNCTIONEX cbFunction, void* userdata);
|
||||
PLUG_IMPEXP bool _plugin_unregisterexprfunction(int pluginHandle, const char* name);
|
||||
PLUG_IMPEXP bool _plugin_unload(const char* pluginName);
|
||||
PLUG_IMPEXP bool _plugin_load(const char* pluginName);
|
||||
|
2
src/dbg/bridgemain.h
Normal file
2
src/dbg/bridgemain.h
Normal file
@ -0,0 +1,2 @@
|
||||
// NOTE: this file is only here to make _apichecker.c compile
|
||||
#include "../bridge/bridgemain.h"
|
@ -53,7 +53,7 @@ bool IsArgumentsLessThan(int argc, int minimumCount)
|
||||
{
|
||||
if(argc < minimumCount)
|
||||
{
|
||||
dprintf(QT_TRANSLATE_NOOP("DBG", "Not enough arguments! At least %d arguments must be specified.\n"), minimumCount - 1);
|
||||
dprintf_html(QT_TRANSLATE_NOOP("DBG", "Not enough arguments! At least %d argument(s) must be specified. Arguments are <a href=\"https://help.x64dbg.com/en/latest/commands/index.html\">comma-separated</a>."), minimumCount - 1);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
@ -523,7 +523,7 @@ struct PrintVisitor : TypeManager::Visitor
|
||||
td.userdata = nullptr;
|
||||
auto node = GuiTypeAddNode(mParents.empty() ? nullptr : parent().node, &td);
|
||||
|
||||
mPath.push_back((member.name == "visit" ? type.name : member.name) + ".");
|
||||
mPath.push_back((member.name == "display" ? type.name : member.name) + ".");
|
||||
mParents.push_back(Parent(type.isunion ? Parent::Union : Parent::Struct));
|
||||
parent().node = node;
|
||||
parent().size = td.size;
|
||||
@ -635,7 +635,7 @@ bool cbInstrVisitType(int argc, char* argv[])
|
||||
if(IsArgumentsLessThan(argc, 2))
|
||||
return false;
|
||||
auto type = argv[1];
|
||||
auto name = "visit";
|
||||
auto name = "display";
|
||||
duint addr = 0;
|
||||
auto maxPtrDepth = 0;
|
||||
if(argc > 2)
|
||||
|
@ -119,3 +119,18 @@ void dprint_untranslated_html(_In_z_ _Printf_format_string_ const char* Text)
|
||||
{
|
||||
GuiAddLogMessageHtmlAsync(Text);
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Print a formatted string to the console.
|
||||
\param format The printf format to use (see documentation of printf for more information).
|
||||
*/
|
||||
void dprintf_html(_In_z_ _Printf_format_string_ const char* Format, ...)
|
||||
{
|
||||
va_list args;
|
||||
|
||||
va_start(args, Format);
|
||||
char buffer[16384];
|
||||
vsnprintf_s(buffer, _TRUNCATE, GuiTranslateText(Format), args);
|
||||
GuiAddLogMessageHtmlAsync(buffer);
|
||||
va_end(args);
|
||||
}
|
||||
|
@ -10,5 +10,6 @@ void dputs_untranslated(_In_z_ const char* Text);
|
||||
void dprintf_untranslated(_In_z_ _Printf_format_string_ const char* Format, ...);
|
||||
void dprintf_args_untranslated(_In_z_ _Printf_format_string_ const char* Format, va_list Args);
|
||||
void dprint_untranslated_html(_In_z_ _Printf_format_string_ const char* Text);
|
||||
void dprintf_html(_In_z_ _Printf_format_string_ const char* Format, ...);
|
||||
|
||||
#endif // _CONSOLE_H
|
@ -816,7 +816,7 @@ namespace Exprfunc
|
||||
|
||||
bool syscall_name(ExpressionValue* result, int argc, const ExpressionValue* argv, void* userdata)
|
||||
{
|
||||
*result = ValueString(SyscallToName(argv[0].number));
|
||||
*result = ValueString(SyscallToName((unsigned int)argv[0].number));
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -392,7 +392,7 @@ static void registercommands()
|
||||
dbgcmdnew("AddArg", cbInstrAddArg, false); //AddArg
|
||||
dbgcmdnew("AppendArg", cbInstrAppendArg, false); //AppendArg
|
||||
dbgcmdnew("SizeofType", cbInstrSizeofType, false); //SizeofType
|
||||
dbgcmdnew("VisitType", cbInstrVisitType, false); //VisitType
|
||||
dbgcmdnew("VisitType,DisplayType,dt", cbInstrVisitType, false); //VisitType
|
||||
dbgcmdnew("ClearTypes", cbInstrClearTypes, false); //ClearTypes
|
||||
dbgcmdnew("RemoveType", cbInstrRemoveType, false); //RemoveType
|
||||
dbgcmdnew("EnumTypes", cbInstrEnumTypes, false); //EnumTypes
|
||||
@ -764,9 +764,8 @@ extern "C" DLL_EXPORT const char* _dbg_dbginit()
|
||||
dputs(QT_TRANSLATE_NOOP("DBG", "Registering expression functions..."));
|
||||
FormatFunctions::Init();
|
||||
dputs(QT_TRANSLATE_NOOP("DBG", "Registering format functions..."));
|
||||
SCRIPTTYPEINFO info;
|
||||
SCRIPTTYPEINFO info = {};
|
||||
strcpy_s(info.name, GuiTranslateText(QT_TRANSLATE_NOOP("DBG", "Default")));
|
||||
info.id = 0;
|
||||
info.execute = [](const char* cmd)
|
||||
{
|
||||
if(!DbgCmdExec(cmd))
|
||||
@ -774,7 +773,6 @@ extern "C" DLL_EXPORT const char* _dbg_dbginit()
|
||||
GuiFlushLog();
|
||||
return true;
|
||||
};
|
||||
info.completeCommand = nullptr;
|
||||
GuiRegisterScriptLanguage(&info);
|
||||
dputs(QT_TRANSLATE_NOOP("DBG", "Registering Script DLL command handler..."));
|
||||
strcpy_s(info.name, GuiTranslateText(QT_TRANSLATE_NOOP("DBG", "Script DLL")));
|
||||
|
@ -114,6 +114,7 @@
|
||||
<ClCompile Include="WinInet-Downloader\downslib.cpp" />
|
||||
<ClCompile Include="x64dbg.cpp" />
|
||||
<ClCompile Include="xrefs.cpp" />
|
||||
<ClCompile Include="_apichecker.c" />
|
||||
<ClCompile Include="_exports.cpp" />
|
||||
<ClCompile Include="_dbgfunctions.cpp" />
|
||||
<ClCompile Include="_global.cpp" />
|
||||
@ -155,6 +156,7 @@
|
||||
<ClInclude Include="assemble.h" />
|
||||
<ClInclude Include="bookmark.h" />
|
||||
<ClInclude Include="breakpoint.h" />
|
||||
<ClInclude Include="bridgemain.h" />
|
||||
<ClInclude Include="btparser\btparser\ast.h" />
|
||||
<ClInclude Include="btparser\btparser\helpers.h" />
|
||||
<ClInclude Include="btparser\btparser\keywords.h" />
|
||||
|
@ -458,6 +458,9 @@
|
||||
<ClCompile Include="symbolsourcebase.cpp">
|
||||
<Filter>Source Files\Symbols</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="_apichecker.c">
|
||||
<Filter>Source Files\Interfaces/Exports</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="dbghelp\dbghelp.h">
|
||||
@ -898,5 +901,8 @@
|
||||
<ClInclude Include="LLVMDemangle\LLVMDemangle.h">
|
||||
<Filter>Header Files\Third Party\LLVMDemangle</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="bridgemain.h">
|
||||
<Filter>Header Files\Interfaces/Exports</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
</Project>
|
@ -10,6 +10,7 @@
|
||||
|
||||
static wchar_t szApplicationDir[MAX_PATH];
|
||||
static bool bPerformSignatureChecks = false;
|
||||
static bool bNewerThanXP = false;
|
||||
|
||||
//#define DEBUG_SIGNATURE_CHECKS
|
||||
|
||||
@ -80,6 +81,10 @@ static bool VerifyEmbeddedSignature(LPCWSTR pwszSourceFile, bool checkRevocation
|
||||
// Check certificate revocations
|
||||
WinTrustData.fdwRevocationChecks = checkRevocation ? WTD_REVOKE_WHOLECHAIN : WTD_REVOKE_NONE;
|
||||
|
||||
// Do not connect to the internet (https://stackoverflow.com/a/48527128/1806760)
|
||||
if(bNewerThanXP)
|
||||
WinTrustData.dwProvFlags = WTD_CACHE_ONLY_URL_RETRIEVAL;
|
||||
|
||||
// Verify an embedded signature on a file.
|
||||
WinTrustData.dwUnionChoice = WTD_CHOICE_FILE;
|
||||
|
||||
@ -355,6 +360,8 @@ bool InitializeSignatureCheck()
|
||||
pAddDllDirectory = (pfnAddDllDirectory)GetProcAddress(hKernel32, "AddDllDirectory");
|
||||
if(pSetDefaultDllDirectories && pSetDllDirectoryW && pAddDllDirectory)
|
||||
{
|
||||
bNewerThanXP = true;
|
||||
|
||||
if(!pSetDllDirectoryW(L""))
|
||||
return false;
|
||||
|
||||
|
@ -189,7 +189,9 @@ void Bridge::doUpdate(GUIMSG msg)
|
||||
auto now = GetTickCount();
|
||||
auto elapsed = now - start;
|
||||
if(elapsed > 5)
|
||||
qDebug() << msg2str(msg) << elapsed << "ms";
|
||||
{
|
||||
//qDebug() << "[DebugMonitor]" << msg2str(msg) << elapsed << "ms";
|
||||
}
|
||||
|
||||
mLastUpdates[msg] = now;
|
||||
}
|
||||
|
@ -372,6 +372,12 @@ void ZydisTokenizer::addToken(TokenType type, QString text, const TokenValue & v
|
||||
{
|
||||
mInst.tokens.push_back(SingleToken(type, text, value));
|
||||
}
|
||||
else if(type == TokenType::Address && text.startsWith("<&"))
|
||||
{
|
||||
mInst.tokens.push_back(SingleToken(TokenType::Address, "<", value));
|
||||
mInst.tokens.push_back(SingleToken(TokenType::MemoryBaseRegister, "&", value));
|
||||
mInst.tokens.push_back(SingleToken(TokenType::Address, text.mid(2)));
|
||||
}
|
||||
else
|
||||
{
|
||||
mInst.tokens.push_back(SingleToken(mIsNop ? TokenType::MnemonicNop : type, text, value));
|
||||
|
@ -282,6 +282,7 @@ void CPUDump::getColumnRichText(duint col, duint rva, RichTextPainter::List & ri
|
||||
curData.text = QString(modname) + "." + QString(label_text);
|
||||
else if(DbgGetStringAt(data, string_text))
|
||||
curData.text = string_text;
|
||||
|
||||
if(!curData.text.length()) //stack comments
|
||||
{
|
||||
auto va = rvaToVa(rva);
|
||||
@ -300,6 +301,10 @@ void CPUDump::getColumnRichText(duint col, duint rva, RichTextPainter::List & ri
|
||||
curData.textColor = ConfigColor("StackInactiveTextColor");
|
||||
curData.text = comment.comment;
|
||||
}
|
||||
else if(*modname)
|
||||
{
|
||||
curData.text = QString("%1.%2").arg(modname, ToPtrString(va));
|
||||
}
|
||||
}
|
||||
if(curData.text.length())
|
||||
richText.push_back(curData);
|
||||
|
@ -49,6 +49,11 @@ void CallStackView::setupContextMenu()
|
||||
{
|
||||
return !getCellContent(getInitialSelection(), ColFrom).isEmpty() && isSelectionValid();
|
||||
});
|
||||
QAction* loadSymbolsForThread = makeAction(DIcon("pdb"), tr("Download Symbols for This Thread"), SLOT(loadSymbolsForThreadSlot()));
|
||||
mMenuBuilder->addAction(loadSymbolsForThread, [this](QMenu*)
|
||||
{
|
||||
return isSelectionValid();
|
||||
});
|
||||
mFollowFrom->setShortcutContext(Qt::WidgetShortcut);
|
||||
mFollowFrom->setShortcut(QKeySequence("enter"));
|
||||
connect(this, SIGNAL(enterPressedSignal()), this, SLOT(followFromSlot()));
|
||||
@ -265,6 +270,28 @@ void CallStackView::renameThreadSlot()
|
||||
DbgCmdExec(QString("setthreadname %1, \"%2\"").arg(ToHexString(threadId)).arg(DbgCmdEscape(threadName)));
|
||||
}
|
||||
|
||||
void CallStackView::loadSymbolsForThreadSlot()
|
||||
{
|
||||
char module[MAX_MODULE_SIZE] = "";
|
||||
duint firstRowForThread = 1;
|
||||
const duint threadId = getCellUserdata(getInitialSelection(), ColThread);
|
||||
for(duint row = getInitialSelection(); row > 0; --row)
|
||||
{
|
||||
if(getCellUserdata(row, ColThread) != threadId)
|
||||
{
|
||||
firstRowForThread = row + 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
for(duint row = firstRowForThread; row < getRowCount(); ++row)
|
||||
{
|
||||
if(getCellUserdata(row, ColThread) != threadId)
|
||||
break;
|
||||
if(DbgGetModuleAt(getCellUserdata(row, ColFrom), module))
|
||||
DbgCmdExec(QString("symdownload \"%0\"").arg(module));
|
||||
}
|
||||
}
|
||||
|
||||
void CallStackView::followInThreadsSlot()
|
||||
{
|
||||
QStringList threadIDName = getCellContent(getInitialSelection(), ColThread).split(" - ");
|
||||
|
@ -23,6 +23,7 @@ protected slots:
|
||||
void showSuspectedCallStackSlot();
|
||||
void followInThreadsSlot();
|
||||
void renameThreadSlot();
|
||||
void loadSymbolsForThreadSlot();
|
||||
|
||||
private:
|
||||
enum
|
||||
|
@ -168,7 +168,6 @@
|
||||
<property name="title">
|
||||
<string>&Plugins</string>
|
||||
</property>
|
||||
<addaction name="actionScylla"/>
|
||||
</widget>
|
||||
<widget class="QMenu" name="menuOptions">
|
||||
<property name="title">
|
||||
|
@ -52,7 +52,7 @@ void RichTextItemDelegate::paint(QPainter* painter, const QStyleOptionViewItem &
|
||||
#else
|
||||
int postfixWidth = metric.width(elidedPostfix);
|
||||
#endif
|
||||
while(doc.size().width() > option.rect.width() - postfixWidth)
|
||||
while(!doc.isEmpty() && doc.size().width() > option.rect.width() - postfixWidth)
|
||||
{
|
||||
cursor.deletePreviousChar();
|
||||
doc.adjustSize();
|
||||
|
@ -1,10 +1,13 @@
|
||||
#include <QFileDialog>
|
||||
#include <QTextDocumentFragment>
|
||||
#include <QMessageBox>
|
||||
|
||||
#include "StructWidget.h"
|
||||
#include "ui_StructWidget.h"
|
||||
#include "Configuration.h"
|
||||
#include "MenuBuilder.h"
|
||||
#include "LineEditDialog.h"
|
||||
#include "GotoDialog.h"
|
||||
#include <QFileDialog>
|
||||
#include "StringUtil.h"
|
||||
#include "MiscUtil.h"
|
||||
#include "RichTextItemDelegate.h"
|
||||
@ -32,8 +35,8 @@ StructWidget::StructWidget(QWidget* parent) :
|
||||
connect(Config(), SIGNAL(shortcutsUpdated()), this, SLOT(shortcutsUpdatedSlot()));
|
||||
colorsUpdatedSlot();
|
||||
fontsUpdatedSlot();
|
||||
setupContextMenu();
|
||||
setupColumns();
|
||||
setupContextMenu();
|
||||
}
|
||||
|
||||
StructWidget::~StructWidget()
|
||||
@ -45,28 +48,26 @@ void StructWidget::saveWindowSettings()
|
||||
{
|
||||
auto saveColumn = [this](int column)
|
||||
{
|
||||
auto settingName = QString("StructWidgetColumn%1").arg(column);
|
||||
auto settingName = QString("StructWidgetV2Column%1").arg(column);
|
||||
BridgeSettingSetUint("Gui", settingName.toUtf8().constData(), ui->treeWidget->columnWidth(column));
|
||||
};
|
||||
saveColumn(0);
|
||||
saveColumn(1);
|
||||
saveColumn(2);
|
||||
saveColumn(3);
|
||||
auto columnCount = ui->treeWidget->columnCount();
|
||||
for(int i = 0; i < columnCount; i++)
|
||||
saveColumn(i);
|
||||
}
|
||||
|
||||
void StructWidget::loadWindowSettings()
|
||||
{
|
||||
auto loadColumn = [this](int column)
|
||||
{
|
||||
auto settingName = QString("StructWidgetColumn%1").arg(column);
|
||||
auto settingName = QString("StructWidgetV2Column%1").arg(column);
|
||||
duint width = 0;
|
||||
if(BridgeSettingGetUint("Gui", settingName.toUtf8().constData(), &width))
|
||||
ui->treeWidget->setColumnWidth(column, width);
|
||||
};
|
||||
loadColumn(0);
|
||||
loadColumn(1);
|
||||
loadColumn(2);
|
||||
loadColumn(3);
|
||||
auto columnCount = ui->treeWidget->columnCount();
|
||||
for(int i = 0; i < columnCount; i++)
|
||||
loadColumn(i);
|
||||
}
|
||||
|
||||
void StructWidget::colorsUpdatedSlot()
|
||||
@ -100,7 +101,19 @@ void StructWidget::typeAddNode(void* parent, const TYPEDESCRIPTOR* type)
|
||||
dtype.type = *type;
|
||||
dtype.name = highlightTypeName(dtype.type.name);
|
||||
dtype.type.name = nullptr;
|
||||
auto text = QStringList() << dtype.name << ToPtrString(dtype.type.addr + dtype.type.offset) << "0x" + ToHexString(dtype.type.size);
|
||||
QStringList text;
|
||||
auto columnCount = ui->treeWidget->columnCount();
|
||||
for(int i = 0; i < columnCount; i++)
|
||||
text.append(QString());
|
||||
|
||||
text[ColOffset] = "+0x" + ToHexString(dtype.type.offset);
|
||||
text[ColField] = dtype.name;
|
||||
if(dtype.type.offset == 0 && true)
|
||||
text[ColAddress] = QString("<u>%1</u>").arg(ToPtrString(dtype.type.addr + dtype.type.offset));
|
||||
else
|
||||
text[ColAddress] = ToPtrString(dtype.type.addr + dtype.type.offset);
|
||||
text[ColSize] = "0x" + ToHexString(dtype.type.size);
|
||||
text[ColValue] = ""; // NOTE: filled in later
|
||||
QTreeWidgetItem* item = parent ? new QTreeWidgetItem((QTreeWidgetItem*)parent, text) : new QTreeWidgetItem(ui->treeWidget, text);
|
||||
item->setExpanded(dtype.type.expanded);
|
||||
QVariant var;
|
||||
@ -125,7 +138,7 @@ void StructWidget::typeUpdateWidget()
|
||||
auto name = type.name.toUtf8();
|
||||
type.type.name = name.constData();
|
||||
auto addr = type.type.addr + type.type.offset;
|
||||
item->setText(1, ToPtrString(addr));
|
||||
item->setText(ColAddress, ToPtrString(addr));
|
||||
QString valueStr;
|
||||
if(type.type.callback) //use the provided callback
|
||||
{
|
||||
@ -155,7 +168,7 @@ void StructWidget::typeUpdateWidget()
|
||||
else if(type.type.addr)
|
||||
valueStr = "???";
|
||||
}
|
||||
item->setText(3, valueStr);
|
||||
item->setText(ColValue, valueStr);
|
||||
}
|
||||
ui->treeWidget->setUpdatesEnabled(true);
|
||||
}
|
||||
@ -169,9 +182,14 @@ void StructWidget::dbgStateChangedSlot(DBGSTATE state)
|
||||
void StructWidget::setupColumns()
|
||||
{
|
||||
auto charWidth = ui->treeWidget->fontMetrics().width(' ');
|
||||
ui->treeWidget->setColumnWidth(0, 4 + charWidth * 60); //Name
|
||||
ui->treeWidget->setColumnWidth(1, 6 + charWidth * sizeof(duint) * 2); //Address
|
||||
ui->treeWidget->setColumnWidth(2, 4 + charWidth * 6); //Size
|
||||
ui->treeWidget->setColumnWidth(ColField, 4 + charWidth * 60);
|
||||
ui->treeWidget->setColumnWidth(ColOffset, 6 + charWidth * 7);
|
||||
ui->treeWidget->setColumnWidth(ColAddress, 6 + charWidth * sizeof(duint) * 2);
|
||||
ui->treeWidget->setColumnWidth(ColSize, 4 + charWidth * 6);
|
||||
|
||||
// NOTE: Trick to display the expander icons in the second column
|
||||
// Reference: https://stackoverflow.com/a/25887454/1806760
|
||||
// ui->treeWidget->header()->moveSection(ColField, ColOffset);
|
||||
}
|
||||
|
||||
#define hasSelection !!ui->treeWidget->selectedItems().count()
|
||||
@ -181,6 +199,10 @@ void StructWidget::setupColumns()
|
||||
void StructWidget::setupContextMenu()
|
||||
{
|
||||
mMenuBuilder = new MenuBuilder(this);
|
||||
mMenuBuilder->addAction(makeAction(DIcon("dump"), tr("&Follow address in Dump"), SLOT(followDumpSlot())), [this](QMenu*)
|
||||
{
|
||||
return hasSelection && DbgMemIsValidReadPtr(selectedType.addr + selectedType.offset);
|
||||
});
|
||||
mMenuBuilder->addAction(makeAction(DIcon("dump"), tr("Follow value in Dump"), SLOT(followValueDumpSlot())), [this](QMenu*)
|
||||
{
|
||||
return DbgMemIsValidReadPtr(selectedValue());
|
||||
@ -189,15 +211,11 @@ void StructWidget::setupContextMenu()
|
||||
{
|
||||
return DbgMemIsValidReadPtr(selectedValue());
|
||||
});
|
||||
mMenuBuilder->addAction(makeAction(DIcon("dump"), tr("&Follow address in Dump"), SLOT(followDumpSlot())), [this](QMenu*)
|
||||
{
|
||||
return hasSelection && DbgMemIsValidReadPtr(selectedType.addr + selectedType.offset);
|
||||
});
|
||||
mMenuBuilder->addAction(makeAction(DIcon("structaddr"), tr("Change address"), SLOT(changeAddrSlot())), [this](QMenu*)
|
||||
{
|
||||
return hasSelection && !selectedItem->parent() && DbgIsDebugging();
|
||||
});
|
||||
mMenuBuilder->addAction(makeAction(DIcon("visitstruct"), tr("Visit type"), SLOT(visitSlot())));
|
||||
mMenuBuilder->addAction(makeAction(DIcon("visitstruct"), tr("Display type"), SLOT(visitSlot())));
|
||||
mMenuBuilder->addAction(makeAction(DIcon("database-import"), tr("Load JSON"), SLOT(loadJsonSlot())));
|
||||
mMenuBuilder->addAction(makeAction(DIcon("source"), tr("Parse header"), SLOT(parseFileSlot())));
|
||||
mMenuBuilder->addAction(makeAction(DIcon("removestruct"), tr("Remove"), SLOT(removeSlot())), [this](QMenu*)
|
||||
@ -206,6 +224,21 @@ void StructWidget::setupContextMenu()
|
||||
});
|
||||
mMenuBuilder->addAction(makeAction(DIcon("eraser"), tr("Clear"), SLOT(clearSlot())));
|
||||
mMenuBuilder->addAction(makeShortcutAction(DIcon("sync"), tr("&Refresh"), SLOT(refreshSlot()), "ActionRefresh"));
|
||||
|
||||
auto copyMenu = new MenuBuilder(this);
|
||||
auto columnCount = ui->treeWidget->columnCount();
|
||||
auto headerItem = ui->treeWidget->headerItem();
|
||||
for(int column = 0; column < columnCount; column++)
|
||||
{
|
||||
auto action = makeAction(headerItem->text(column), SLOT(copyColumnSlot()));
|
||||
action->setObjectName(QString("%1").arg(column));
|
||||
copyMenu->addAction(action, [this, column](QMenu*)
|
||||
{
|
||||
return hasSelection && !selectedItem->text(column).isEmpty();
|
||||
});
|
||||
}
|
||||
mMenuBuilder->addMenu(makeMenu(DIcon("copy"), tr("&Copy")), copyMenu);
|
||||
|
||||
mMenuBuilder->loadFromConfig();
|
||||
}
|
||||
|
||||
@ -226,7 +259,6 @@ QString StructWidget::highlightTypeName(QString name) const
|
||||
"wchar_t",
|
||||
"int16_t",
|
||||
"uint8_t",
|
||||
"struct",
|
||||
"double",
|
||||
"size_t",
|
||||
"uint64",
|
||||
@ -235,7 +267,6 @@ QString StructWidget::highlightTypeName(QString name) const
|
||||
"uint16",
|
||||
"signed",
|
||||
"int8_t",
|
||||
"union",
|
||||
"const",
|
||||
"float",
|
||||
"duint",
|
||||
@ -269,14 +300,18 @@ QString StructWidget::highlightTypeName(QString name) const
|
||||
}();
|
||||
|
||||
name.replace(re, "<b>\\1</b>");
|
||||
return std::move(name);
|
||||
|
||||
static QRegExp sre("^(struct|union|class|enum) ([a-zA-Z0-9_:$]+)");
|
||||
name.replace(sre, "<u>\\1</u> <b>\\2</b>");
|
||||
|
||||
return name;
|
||||
}
|
||||
|
||||
duint StructWidget::selectedValue() const
|
||||
{
|
||||
if(!hasSelection)
|
||||
return 0;
|
||||
QStringList split = selectedItem->text(3).split(',');
|
||||
QStringList split = selectedItem->text(ColValue).split(',');
|
||||
if(split.length() < 1)
|
||||
return 0;
|
||||
return split[0].toULongLong(nullptr, 0);
|
||||
@ -325,18 +360,28 @@ void StructWidget::removeSlot()
|
||||
|
||||
void StructWidget::visitSlot()
|
||||
{
|
||||
//TODO: replace with a list to pick from
|
||||
LineEditDialog mLineEdit(this);
|
||||
mLineEdit.setWindowTitle(tr("Type to visit"));
|
||||
if(mLineEdit.exec() != QDialog::Accepted || !mLineEdit.editText.length())
|
||||
QStringList structs;
|
||||
DbgFunctions()->EnumStructs([](const char* name, void* userdata)
|
||||
{
|
||||
((QStringList*)userdata)->append(name);
|
||||
}, &structs);
|
||||
if(structs.isEmpty())
|
||||
{
|
||||
SimpleErrorBox(this, tr("Error"), tr("No types loaded yet, parse a header first..."));
|
||||
return;
|
||||
}
|
||||
|
||||
QString selection;
|
||||
if(!SimpleChoiceBox(this, tr("Type to display"), "", structs, selection, true, "", &DIcon("struct"), 1) || selection.isEmpty())
|
||||
return;
|
||||
if(!mGotoDialog)
|
||||
mGotoDialog = new GotoDialog(this);
|
||||
duint addr = 0;
|
||||
mGotoDialog->setWindowTitle(tr("Address to visit"));
|
||||
mGotoDialog->setWindowTitle(tr("Address to display %1 at").arg(selection));
|
||||
if(DbgIsDebugging() && mGotoDialog->exec() == QDialog::Accepted)
|
||||
addr = DbgValFromString(mGotoDialog->expressionText.toUtf8().constData());
|
||||
DbgCmdExec(QString("VisitType %1, %2, 2").arg(mLineEdit.editText, ToPtrString(addr)));
|
||||
DbgCmdExec(QString("VisitType %1, %2, 2").arg(selection, ToPtrString(addr)));
|
||||
// TODO: show a proper error message on failure
|
||||
}
|
||||
|
||||
void StructWidget::loadJsonSlot()
|
||||
@ -388,3 +433,15 @@ void StructWidget::refreshSlot()
|
||||
{
|
||||
typeUpdateWidget();
|
||||
}
|
||||
|
||||
void StructWidget::copyColumnSlot()
|
||||
{
|
||||
QAction* action = qobject_cast<QAction*>(sender());
|
||||
if(action == nullptr || !hasSelection)
|
||||
return;
|
||||
auto column = action->objectName().toInt();
|
||||
auto text = selectedItem->text(column);
|
||||
text = QTextDocumentFragment::fromHtml(text).toPlainText();
|
||||
if(!text.isEmpty())
|
||||
Bridge::CopyToClipboard(text);
|
||||
}
|
||||
|
@ -43,6 +43,15 @@ private:
|
||||
QString highlightTypeName(QString name) const;
|
||||
duint selectedValue() const;
|
||||
|
||||
enum
|
||||
{
|
||||
ColField,
|
||||
ColOffset,
|
||||
ColAddress,
|
||||
ColSize,
|
||||
ColValue,
|
||||
};
|
||||
|
||||
private slots:
|
||||
void on_treeWidget_customContextMenuRequested(const QPoint & pos);
|
||||
|
||||
@ -56,4 +65,5 @@ private slots:
|
||||
void parseFileSlot();
|
||||
void changeAddrSlot();
|
||||
void refreshSlot();
|
||||
void copyColumnSlot();
|
||||
};
|
||||
|
@ -51,7 +51,12 @@
|
||||
</attribute>
|
||||
<column>
|
||||
<property name="text">
|
||||
<string>Name</string>
|
||||
<string>Field</string>
|
||||
</property>
|
||||
</column>
|
||||
<column>
|
||||
<property name="text">
|
||||
<string>Offset</string>
|
||||
</property>
|
||||
</column>
|
||||
<column>
|
||||
|
@ -80,6 +80,19 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
void sortRows(duint column, bool ascending) override
|
||||
{
|
||||
// HACK: when sorting by status, forcefully fill in the text so the sorting works
|
||||
if(column == ColStatus)
|
||||
{
|
||||
for(duint row = 0; row < mData.size(); row++)
|
||||
{
|
||||
mData[row][column].text = getCellContent(row, column);
|
||||
}
|
||||
}
|
||||
StdIconTable::sortRows(column, ascending);
|
||||
}
|
||||
|
||||
private:
|
||||
MODULESYMBOLSTATUS getStatus(duint r)
|
||||
{
|
||||
|
@ -208,7 +208,7 @@ void WatchView::addWatchSlot()
|
||||
{
|
||||
QString name;
|
||||
if(SimpleInputBox(this, tr("Enter the expression to watch"), "", name, tr("Example: [EAX]")))
|
||||
DbgCmdExecDirect(QString("AddWatch ").append(name));
|
||||
DbgCmdExecDirect(QString("AddWatch \"%1\"").arg(DbgCmdEscape(name)));
|
||||
updateWatch();
|
||||
}
|
||||
|
||||
@ -223,7 +223,7 @@ void WatchView::renameWatchSlot()
|
||||
QString name;
|
||||
QString originalName = getCellContent(getInitialSelection(), ColName);
|
||||
if(SimpleInputBox(this, tr("Enter the name of the watch variable"), originalName, name, originalName))
|
||||
DbgCmdExecDirect(QString("SetWatchName ").append(getSelectedId() + "," + name));
|
||||
DbgCmdExecDirect(QString("SetWatchName %1, \"%2\"").arg(getSelectedId(), DbgCmdEscape(name)));
|
||||
updateWatch();
|
||||
}
|
||||
|
||||
@ -250,7 +250,7 @@ void WatchView::editWatchSlot()
|
||||
QString originalExpr = getCellContent(getInitialSelection(), ColExpr);
|
||||
QString currentType = getCellContent(getInitialSelection(), ColType);
|
||||
if(SimpleInputBox(this, tr("Enter the expression to watch"), originalExpr, expr, tr("Example: [EAX]")))
|
||||
DbgCmdExecDirect(QString("SetWatchExpression ").append(getSelectedId()).append(",").append(expr).append(",").append(currentType));
|
||||
DbgCmdExecDirect(QString("SetWatchExpression %1, \"%2\", %3").arg(getSelectedId(), DbgCmdEscape(expr), currentType));
|
||||
updateWatch();
|
||||
}
|
||||
|
||||
|
Binary file not shown.
Before Width: | Height: | Size: 759 B After Width: | Height: | Size: 630 B |
@ -421,8 +421,37 @@ static void deleteZoneData(const std::wstring & rootDir)
|
||||
}
|
||||
}
|
||||
|
||||
typedef BOOL(WINAPI* LPFN_SetProcessDpiAwarenessContext)(int);
|
||||
typedef BOOL(WINAPI* LPFN_SetProcessDPIAware)();
|
||||
|
||||
static void EnableHiDPI()
|
||||
{
|
||||
// Windows 10 Build 1607
|
||||
LPFN_SetProcessDpiAwarenessContext SetProcessDpiAwarenessContext = (LPFN_SetProcessDpiAwarenessContext)GetProcAddress(GetModuleHandle(TEXT("user32.dll")), "SetProcessDpiAwarenessContext");
|
||||
if(SetProcessDpiAwarenessContext != nullptr)
|
||||
{
|
||||
// Windows 10 Build 1703
|
||||
if(SetProcessDpiAwarenessContext(-4)) //DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2
|
||||
{
|
||||
return;
|
||||
}
|
||||
// Windows 10 Build 1607
|
||||
if(SetProcessDpiAwarenessContext(-3)) //DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
// Windows Vista
|
||||
LPFN_SetProcessDPIAware SetProcessDPIAware = (LPFN_SetProcessDPIAware)GetProcAddress(GetModuleHandle(TEXT("user32.dll")), "SetProcessDPIAware");
|
||||
if(SetProcessDPIAware != nullptr)
|
||||
{
|
||||
SetProcessDPIAware();
|
||||
}
|
||||
}
|
||||
|
||||
int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd)
|
||||
{
|
||||
EnableHiDPI();
|
||||
InitCommonControls();
|
||||
|
||||
//Initialize COM
|
||||
|
@ -17,7 +17,7 @@ RtlGetLastNtStatus(
|
||||
#pragma comment(lib, "..\\dbg\\ntdll\\ntdll_x86.lib")
|
||||
#endif // _WIN64
|
||||
|
||||
int WinMain(
|
||||
int WINAPI WinMain(
|
||||
HINSTANCE hInstance,
|
||||
HINSTANCE hPrevInstance,
|
||||
LPSTR lpCmdLine,
|
||||
|
Loading…
Reference in New Issue
Block a user