diff --git a/src/dbg/debugger.cpp b/src/dbg/debugger.cpp
index 15a230a8..c2ecbe9b 100644
--- a/src/dbg/debugger.cpp
+++ b/src/dbg/debugger.cpp
@@ -27,6 +27,7 @@
static PROCESS_INFORMATION g_pi = {0, 0, 0, 0};
static char szBaseFileName[MAX_PATH] = "";
+ExpressionParser* RtcondCondition;
static bool bFileIsDll = false;
static duint pDebuggedBase = 0;
static duint pCreateProcessBase = 0;
@@ -774,6 +775,48 @@ void cbRtrStep()
StepOver((void*)cbRtrStep);
}
+void cbTOCNDStep()
+{
+ duint value = 1;
+ if (!RtcondCondition || RtcondCondition->Calculate(value, valuesignedcalc()) == false)
+ {
+ delete RtcondCondition;
+ RtcondCondition = nullptr;
+ cbRtrFinalStep();
+ }
+ else if (value != 0)
+ {
+ delete RtcondCondition;
+ RtcondCondition = nullptr;
+ cbRtrFinalStep();
+ }
+ else
+ {
+ StepOver((void*)cbTOCNDStep);
+ }
+}
+
+void cbTICNDStep()
+{
+ duint value = 1;
+ if (!RtcondCondition || RtcondCondition->Calculate(value, valuesignedcalc()) == false)
+ {
+ delete RtcondCondition;
+ RtcondCondition = nullptr;
+ cbRtrFinalStep();
+ }
+ else if (value != 0)
+ {
+ delete RtcondCondition;
+ RtcondCondition = nullptr;
+ cbRtrFinalStep();
+ }
+ else
+ {
+ StepInto((void*)cbTICNDStep);
+ }
+}
+
static void cbCreateProcess(CREATE_PROCESS_DEBUG_INFO* CreateProcessInfo)
{
void* base = CreateProcessInfo->lpBaseOfImage;
diff --git a/src/dbg/debugger.h b/src/dbg/debugger.h
index 584d54f0..a4532c65 100644
--- a/src/dbg/debugger.h
+++ b/src/dbg/debugger.h
@@ -6,6 +6,7 @@
#include "command.h"
#include "breakpoint.h"
#include "undocumented.h"
+#include "expressionparser.h"
#include "value.h"
#include "_plugins.h"
@@ -104,6 +105,8 @@ bool cbDisableAllMemoryBreakpoints(const BREAKPOINT* bp);
bool cbBreakpointList(const BREAKPOINT* bp);
bool cbDeleteAllMemoryBreakpoints(const BREAKPOINT* bp);
bool cbDeleteAllHardwareBreakpoints(const BREAKPOINT* bp);
+void cbTOCNDStep();
+void cbTICNDStep();
DWORD WINAPI threadAttachLoop(void* lpParameter);
void cbDetach();
bool cbSetModuleBreakpoints(const BREAKPOINT* bp);
@@ -114,6 +117,7 @@ extern HANDLE hActiveThread;
extern HANDLE hProcessToken;
extern char szFileName[MAX_PATH];
extern char szSymbolCachePath[MAX_PATH];
+extern ExpressionParser* RtcondCondition;
extern bool bUndecorateSymbolNames;
extern bool bEnableSourceDebugging;
diff --git a/src/dbg/debugger_commands.cpp b/src/dbg/debugger_commands.cpp
index f897cb3c..d3a4ceee 100644
--- a/src/dbg/debugger_commands.cpp
+++ b/src/dbg/debugger_commands.cpp
@@ -1255,6 +1255,52 @@ CMDRESULT cbDebugeRtr(int argc, char* argv[])
return cbDebugRtr(argc, argv);
}
+CMDRESULT cbDebugTocnd(int argc, char* argv[])
+{
+ if (argc > 2)
+ {
+ dputs("Too many arguments.");
+ return STATUS_ERROR;
+ }
+ else if (argc < 1)
+ {
+ dputs("Too few arguments.");
+ return STATUS_ERROR;
+ }
+ if (RtcondCondition != nullptr)
+ {
+ dputs("Tracing is busy now.");
+ return STATUS_ERROR;
+ }
+ RtcondCondition = new ExpressionParser(argv[1]);
+ StepOver((void*)cbTOCNDStep);
+ cbDebugRun(argc, argv);
+ return STATUS_CONTINUE;
+}
+
+CMDRESULT cbDebugTicnd(int argc, char* argv[])
+{
+ if (argc > 2)
+ {
+ dputs("Too many arguments.");
+ return STATUS_ERROR;
+ }
+ else if (argc < 1)
+ {
+ dputs("Too few arguments.");
+ return STATUS_ERROR;
+ }
+ if (RtcondCondition != nullptr)
+ {
+ dputs("Tracing is busy now.");
+ return STATUS_ERROR;
+ }
+ RtcondCondition = new ExpressionParser(argv[1]);
+ StepInto((void*)cbTICNDStep);
+ cbDebugRun(argc, argv);
+ return STATUS_CONTINUE;
+}
+
CMDRESULT cbDebugAlloc(int argc, char* argv[])
{
duint size = 0x1000;
diff --git a/src/dbg/debugger_commands.h b/src/dbg/debugger_commands.h
index 4c03baac..478d50ab 100644
--- a/src/dbg/debugger_commands.h
+++ b/src/dbg/debugger_commands.h
@@ -56,6 +56,8 @@ CMDRESULT cbDebugStepOver(int argc, char* argv[]);
CMDRESULT cbDebugeStepOver(int argc, char* argv[]);
CMDRESULT cbDebugSingleStep(int argc, char* argv[]);
CMDRESULT cbDebugeSingleStep(int argc, char* argv[]);
+CMDRESULT cbDebugTocnd(int argc, char* argv[]);
+CMDRESULT cbDebugTicnd(int argc, char* argv[]);
CMDRESULT cbDebugHide(int argc, char* argv[]);
CMDRESULT cbDebugDisasm(int argc, char* argv[]);
CMDRESULT cbDebugRtr(int argc, char* argv[]);
diff --git a/src/dbg/x64_dbg.cpp b/src/dbg/x64_dbg.cpp
index 6cc36f86..c853782e 100644
--- a/src/dbg/x64_dbg.cpp
+++ b/src/dbg/x64_dbg.cpp
@@ -89,6 +89,8 @@ static void registercommands()
dbgcmdnew("eSingleStep\1esstep\1esst", cbDebugeSingleStep, true); //SingleStep arg1:count + skip first chance exceptions
dbgcmdnew("StepOut\1rtr", cbDebugRtr, true); //rtr
dbgcmdnew("eStepOut\1ertr", cbDebugeRtr, true); //rtr + skip first chance exceptions
+ dbgcmdnew("tocnd", cbDebugTocnd, true); //tocnd
+ dbgcmdnew("ticnd", cbDebugTicnd, true); //ticnd
dbgcmdnew("DebugContinue\1con", cbDebugContinue, true); //set continue status
@@ -134,8 +136,8 @@ static void registercommands()
//breakpoints (conditional)
dbgcmdnew("SetBreakpointName\1bpname", cbDebugSetBPXName, true); //set breakpoint name
- dbgcmdnew("SetBreakpointCondition\1bpcond", cbDebugSetBPXCondition, true); //set breakpoint breakCondition
- dbgcmdnew("SetBreakpointLog\1bplog", cbDebugSetBPXLog, true); //set breakpoint logText
+ dbgcmdnew("SetBreakpointCondition\1bpcond\1bpcnd", cbDebugSetBPXCondition, true); //set breakpoint breakCondition
+ dbgcmdnew("SetBreakpointLog\1bplog\1bpl", cbDebugSetBPXLog, true); //set breakpoint logText
dbgcmdnew("SetBreakpointLogCondition\1bplogcondition", cbDebugSetBPXLogCondition, true); //set breakpoint logCondition
dbgcmdnew("SetBreakpointCommand", cbDebugSetBPXCommand, true); //set breakpoint command on hit
dbgcmdnew("SetBreakpointCommandCondition", cbDebugSetBPXCommandCondition, true); //set breakpoint commandCondition
diff --git a/src/gui/Src/Gui/MainWindow.cpp b/src/gui/Src/Gui/MainWindow.cpp
index b1b3f870..2c392af3 100644
--- a/src/gui/Src/Gui/MainWindow.cpp
+++ b/src/gui/Src/Gui/MainWindow.cpp
@@ -232,6 +232,8 @@ MainWindow::MainWindow(QWidget* parent)
connect(ui->actioneStepInto, SIGNAL(triggered()), this, SLOT(execeStepInto()));
connect(ui->actioneRun, SIGNAL(triggered()), this, SLOT(execeRun()));
connect(ui->actioneRtr, SIGNAL(triggered()), this, SLOT(execeRtr()));
+ connect(ui->actionTicnd, SIGNAL(triggered()), this, SLOT(execTicnd()));
+ connect(ui->actionTocnd, SIGNAL(triggered()), this, SLOT(execTocnd()));
connect(ui->actionSkipNextInstruction, SIGNAL(triggered()), this, SLOT(execSkip()));
connect(ui->actionScript, SIGNAL(triggered()), this, SLOT(displayScriptWidget()));
connect(ui->actionRunSelection, SIGNAL(triggered()), this, SLOT(runSelection()));
@@ -591,6 +593,26 @@ void MainWindow::execRtr()
DbgCmdExec("rtr");
}
+void MainWindow::execTicnd()
+{
+ if(!DbgIsDebugging())
+ return;
+ LineEditDialog mLineEdit(this);
+ mLineEdit.setWindowTitle(tr("Enter trace into finishing condition."));
+ if(mLineEdit.exec() == QDialog::Accepted)
+ DbgCmdExec(QString("ticnd \"%1\"").arg(mLineEdit.editText).toUtf8().constData());
+}
+
+void MainWindow::execTocnd()
+{
+ if(!DbgIsDebugging())
+ return;
+ LineEditDialog mLineEdit(this);
+ mLineEdit.setWindowTitle(tr("Enter trace over finishing condition."));
+ if(mLineEdit.exec() == QDialog::Accepted)
+ DbgCmdExec(QString("tocnd \"%1\"").arg(mLineEdit.editText).toUtf8().constData());
+}
+
void MainWindow::displayMemMapWidget()
{
showQWidgetTab(mMemMapView);
diff --git a/src/gui/Src/Gui/MainWindow.h b/src/gui/Src/Gui/MainWindow.h
index c99a9773..9f362a84 100644
--- a/src/gui/Src/Gui/MainWindow.h
+++ b/src/gui/Src/Gui/MainWindow.h
@@ -62,6 +62,8 @@ public slots:
void execClose();
void execRun();
void execRtr();
+ void execTocnd();
+ void execTicnd();
void openFile();
void execPause();
void startScylla();
diff --git a/src/gui/Src/Gui/MainWindow.ui b/src/gui/Src/Gui/MainWindow.ui
index f247426d..8648b3b3 100644
--- a/src/gui/Src/Gui/MainWindow.ui
+++ b/src/gui/Src/Gui/MainWindow.ui
@@ -85,8 +85,10 @@
+
+
@@ -765,6 +767,16 @@
Handles
+
+
+ Trace over until condition
+
+
+
+
+ Trace into until condition
+
+