@@ -23,6 +23,7 @@ limitations under the License.
2323#include < QStringList>
2424#include < algorithm>
2525#include < QMouseEvent>
26+ #include < QInputDialog>
2627#include " breakpointswidget.h"
2728#include " ui.h"
2829#include " menus.h"
@@ -32,13 +33,14 @@ using namespace BinaryNinjaDebuggerAPI;
3233using namespace BinaryNinja ;
3334using namespace std ;
3435
35- BreakpointItem::BreakpointItem (bool enabled, const ModuleNameAndOffset location, uint64_t address) :
36- m_enabled(enabled), m_location(location), m_address(address)
36+ BreakpointItem::BreakpointItem (bool enabled, const ModuleNameAndOffset location, uint64_t address, const std::string& condition ) :
37+ m_enabled(enabled), m_location(location), m_address(address), m_condition(condition)
3738{}
3839
3940
4041bool BreakpointItem::operator ==(const BreakpointItem& other) const
4142{
43+ // Condition is not part of identity - same location = same breakpoint
4244 return (m_enabled == other.enabled ()) && (m_location == other.location ()) && (m_address == other.address ());
4345}
4446
@@ -100,7 +102,7 @@ QVariant DebugBreakpointsListModel::data(const QModelIndex& index, int role) con
100102 if (!item)
101103 return QVariant ();
102104
103- if ((role != Qt::DisplayRole) && (role != Qt::SizeHintRole))
105+ if ((role != Qt::DisplayRole) && (role != Qt::SizeHintRole) && (role != Qt::ToolTipRole) )
104106 return QVariant ();
105107
106108 switch (index.column ())
@@ -138,6 +140,18 @@ QVariant DebugBreakpointsListModel::data(const QModelIndex& index, int role) con
138140
139141 return QVariant (text);
140142 }
143+ case DebugBreakpointsListModel::ConditionColumn:
144+ {
145+ QString condition = QString::fromStdString (item->condition ());
146+
147+ if (role == Qt::ToolTipRole && !condition.isEmpty ())
148+ return QVariant (condition);
149+
150+ if (role == Qt::SizeHintRole)
151+ return QVariant ((qulonglong)condition.size ());
152+
153+ return QVariant (condition);
154+ }
141155 }
142156 return QVariant ();
143157}
@@ -159,6 +173,8 @@ QVariant DebugBreakpointsListModel::headerData(int column, Qt::Orientation orien
159173 return " Location" ;
160174 case DebugBreakpointsListModel::AddressColumn:
161175 return " Remote Address" ;
176+ case DebugBreakpointsListModel::ConditionColumn:
177+ return " Condition" ;
162178 }
163179 return QVariant ();
164180}
@@ -207,6 +223,17 @@ void DebugBreakpointsItemDelegate::paint(
207223 painter->drawText (textRect, data.toString ());
208224 break ;
209225 }
226+ case DebugBreakpointsListModel::ConditionColumn:
227+ {
228+ painter->setFont (m_font);
229+ painter->setPen (option.palette .color (QPalette::WindowText).rgba ());
230+
231+ QString text = data.toString ();
232+ QFontMetrics metrics (m_font);
233+ QString elidedText = metrics.elidedText (text, Qt::ElideRight, textRect.width ());
234+ painter->drawText (textRect, elidedText);
235+ break ;
236+ }
210237 default :
211238 break ;
212239 }
@@ -298,6 +325,15 @@ DebugBreakpointsWidget::DebugBreakpointsWidget(ViewFrame* view, BinaryViewRef da
298325 m_actionHandler.bindAction (
299326 toggleEnabledActionName, UIAction ([&]() { toggleSelected (); }, [&]() { return selectionNotEmpty (); }));
300327
328+ QString editConditionActionName = QString::fromStdString (" Edit Condition..." );
329+ UIAction::registerAction (editConditionActionName);
330+ m_menu->addAction (editConditionActionName, " Options" , MENU_ORDER_NORMAL);
331+ m_actionHandler.bindAction (
332+ editConditionActionName, UIAction ([&]() { editCondition (); }, [&]() {
333+ QModelIndexList sel = selectionModel ()->selectedRows ();
334+ return sel.size () == 1 ;
335+ }));
336+
301337 QString enableAllActionName = QString::fromStdString (" Enable All Breakpoints" );
302338 UIAction::registerAction (enableAllActionName);
303339 m_menu->addAction (enableAllActionName, " Options" , MENU_ORDER_NORMAL);
@@ -510,7 +546,7 @@ void DebugBreakpointsWidget::soloSelected()
510546
511547 // Get the selected breakpoint location
512548 BreakpointItem selectedBp = m_model->getRow (sel[0 ].row ());
513-
549+
514550 // Disable all breakpoints first
515551 std::vector<DebugBreakpoint> breakpoints = m_controller->GetBreakpoints ();
516552 for (const DebugBreakpoint& bp : breakpoints)
@@ -520,12 +556,34 @@ void DebugBreakpointsWidget::soloSelected()
520556 info.offset = bp.offset ;
521557 m_controller->DisableBreakpoint (info);
522558 }
523-
559+
524560 // Enable the selected breakpoint
525561 m_controller->EnableBreakpoint (selectedBp.location ());
526562}
527563
528564
565+ void DebugBreakpointsWidget::editCondition ()
566+ {
567+ QModelIndexList sel = selectionModel ()->selectedRows ();
568+ if (sel.size () != 1 )
569+ return ;
570+
571+ BreakpointItem bp = m_model->getRow (sel[0 ].row ());
572+ std::string currentCondition = m_controller->GetBreakpointCondition (bp.location ());
573+
574+ bool ok;
575+ QString newCondition = QInputDialog::getText (
576+ this , " Edit Condition" , " Condition (e.g., $rax == 0x1234):" ,
577+ QLineEdit::Normal, QString::fromStdString (currentCondition), &ok);
578+
579+ if (ok)
580+ {
581+ m_controller->SetBreakpointCondition (bp.location (), newCondition.trimmed ().toStdString ());
582+ updateContent ();
583+ }
584+ }
585+
586+
529587void DebugBreakpointsWidget::remove ()
530588{
531589 QModelIndexList sel = selectionModel ()->selectedRows ();
@@ -554,12 +612,13 @@ void DebugBreakpointsWidget::updateContent()
554612 ModuleNameAndOffset info;
555613 info.module = bp.module ;
556614 info.offset = bp.offset ;
557- bps.emplace_back (bp.enabled , info, bp.address );
615+ bps.emplace_back (bp.enabled , info, bp.address , bp. condition );
558616 }
559617
560618 m_model->updateRows (bps);
561619
562620 resizeColumnToContents (DebugBreakpointsListModel::EnabledColumn);
563621 resizeColumnToContents (DebugBreakpointsListModel::LocationColumn);
564622 resizeColumnToContents (DebugBreakpointsListModel::AddressColumn);
623+ resizeColumnToContents (DebugBreakpointsListModel::ConditionColumn);
565624}
0 commit comments