Merge branch 'development' into patch000000dc

This commit is contained in:
torusrxxx 2024-07-10 10:06:06 +08:00
commit e1b7dfddb6
34 changed files with 268 additions and 59 deletions

View File

@ -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
View 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"

View File

@ -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);
}
};
}

View File

@ -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

View File

@ -3,7 +3,6 @@
\brief Implements the global class.
*/
#include <windows.h>
#include "_global.h"
#include <objbase.h>
#include <shlobj.h>

View File

@ -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>

View File

@ -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__

View File

@ -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);
}

View File

@ -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
View File

@ -0,0 +1,2 @@
// NOTE: this file is only here to make _apichecker.c compile
#include "../bridge/bridgemain.h"

View File

@ -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;

View File

@ -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)

View File

@ -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);
}

View File

@ -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

View File

@ -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;
}

View File

@ -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")));

View File

@ -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" />

View File

@ -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>

View File

@ -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;

View File

@ -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;
}

View File

@ -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));

View File

@ -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);

View File

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

View File

@ -23,6 +23,7 @@ protected slots:
void showSuspectedCallStackSlot();
void followInThreadsSlot();
void renameThreadSlot();
void loadSymbolsForThreadSlot();
private:
enum

View File

@ -168,7 +168,6 @@
<property name="title">
<string>&amp;Plugins</string>
</property>
<addaction name="actionScylla"/>
</widget>
<widget class="QMenu" name="menuOptions">
<property name="title">

View File

@ -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();

View File

@ -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);
}

View File

@ -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();
};

View File

@ -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>

View File

@ -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)
{

View File

@ -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

View File

@ -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

View File

@ -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,