Skip to content

Commit fa61862

Browse files
committed
Disassembly accessibility support
1 parent 1dc5df6 commit fa61862

File tree

8 files changed

+222
-12
lines changed

8 files changed

+222
-12
lines changed

CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/gui/Src/Accessible/Accessible.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,15 @@
22
#include "Accessible.h"
33
#include "AccessibleRegistersView.h"
44
#include "AccessibleAbstractTableView.h"
5+
#include "AccessibleDisassembly.h"
56
#include "AccessibleStdTable.h"
67

78
QAccessibleInterface* accessibleInterfaceFactory(const QString & classname, QObject* object)
89
{
910
QAccessibleInterface* ptr = nullptr;
10-
if((classname == "CPUDisassembly") && object && dynamic_cast<AbstractTableView*>(object) != nullptr)
11+
if((classname == "Disassembly") && object && dynamic_cast<Disassembly*>(object) != nullptr)
1112
{
12-
ptr = new AccessibleAbstractTableView(dynamic_cast<QWidget*>(object));
13+
ptr = new AccessibleDisassembly(dynamic_cast<QWidget*>(object));
1314
}
1415
if((classname == "AbstractStdTable") && object && dynamic_cast<AbstractStdTable*>(object) != nullptr)
1516
{
Lines changed: 166 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,166 @@
1+
// This file implements accessibility interface for Disassembly
2+
#ifndef QT_NO_ACCESSIBILITY
3+
#include "AccessibleDisassembly.h"
4+
#include "Disassembly.h"
5+
#include "Bridge.h"
6+
7+
AccessibleDisassembly::AccessibleDisassembly(QWidget* w) : AccessibleAbstractTableView(w)
8+
{
9+
}
10+
11+
AccessibleDisassembly::~AccessibleDisassembly()
12+
{
13+
}
14+
15+
Disassembly* AccessibleDisassembly::dis() const
16+
{
17+
return dynamic_cast<Disassembly*>(m_tableView);
18+
}
19+
20+
bool AccessibleDisassembly::isRowSelected(int row) const
21+
{
22+
// row includes title
23+
auto dis = this->dis();
24+
try
25+
{
26+
return dis->getInitialSelection() == dis->mInstBuffer.at(row - 1).rva;
27+
}
28+
catch(std::out_of_range)
29+
{
30+
return false;
31+
}
32+
}
33+
34+
// TODO: multi-selection
35+
int AccessibleDisassembly::selectedRowCount() const
36+
{
37+
// row includes title
38+
auto dis = this->dis();
39+
const auto & inst = dis->mInstBuffer;
40+
auto sel = dis->getInitialSelection();
41+
if(sel >= inst.first().rva && sel <= inst.back().rva)
42+
return 1;
43+
else
44+
return 0;
45+
}
46+
47+
static int findFirstSelection(duint sel, const QList<Instruction_t> & inst)
48+
{
49+
if(sel >= inst.first().rva && sel <= inst.back().rva)
50+
{
51+
for(int i = 0; i < inst.size(); i++)
52+
{
53+
if(inst[i].rva == sel)
54+
{
55+
return i + 1;
56+
}
57+
}
58+
}
59+
return -1;
60+
}
61+
62+
QList<int> AccessibleDisassembly::selectedRows() const
63+
{
64+
auto dis = this->dis();
65+
int selectedRow = findFirstSelection(dis->getInitialSelection(), dis->mInstBuffer);
66+
if(selectedRow != -1)
67+
return QList<int>({ selectedRow });
68+
else
69+
return QList<int>();
70+
}
71+
72+
int AccessibleDisassembly::selectedCellCount() const
73+
{
74+
return selectedRowCount();
75+
}
76+
77+
QList<QAccessibleInterface*> AccessibleDisassembly::selectedCells() const
78+
{
79+
auto dis = this->dis();
80+
int selectedRow = findFirstSelection(dis->getInitialSelection(), dis->mInstBuffer);
81+
if(selectedRow != -1)
82+
return QList<QAccessibleInterface*>({ cellAt(selectedRow, selectedColumns().first()) });
83+
else
84+
return QList<QAccessibleInterface*>();
85+
}
86+
87+
static QString getDisassemblyMnemonicBrief(const Instruction_t & inst)
88+
{
89+
char brief[MAX_STRING_SIZE] = "";
90+
QString mnem;
91+
for(const ZydisTokenizer::SingleToken & token : inst.tokens.tokens)
92+
{
93+
if(token.type != ZydisTokenizer::TokenType::Space && token.type != ZydisTokenizer::TokenType::Prefix)
94+
{
95+
mnem = token.text;
96+
break;
97+
}
98+
}
99+
if(mnem.isEmpty())
100+
mnem = inst.instStr;
101+
102+
int index = mnem.indexOf(' ');
103+
if(index != -1)
104+
mnem.truncate(index);
105+
DbgFunctions()->GetMnemonicBrief(mnem.toUtf8().constData(), MAX_STRING_SIZE, brief);
106+
return QString::fromUtf8(brief);
107+
}
108+
109+
QString AccessibleDisassembly::getCellContent(int row, int col) const
110+
{
111+
const Disassembly & d = *dis();
112+
const Instruction_t & inst = d.mInstBuffer.at(row);
113+
duint cur_addr = d.rvaToVa(inst.rva);
114+
switch(col)
115+
{
116+
case Disassembly::ColAddress:
117+
{
118+
QString label;
119+
return d.getAddrText(cur_addr, label, true);
120+
}
121+
case Disassembly::ColBytes:
122+
{
123+
QString bytes;
124+
RichTextPainter::htmlRichText(d.getRichBytes(inst, false), nullptr, bytes);
125+
return bytes;
126+
}
127+
case Disassembly::ColDisassembly:
128+
{
129+
QString disassembly;
130+
for(const auto & token : inst.tokens.tokens)
131+
disassembly += token.text;
132+
return disassembly;
133+
}
134+
case Disassembly::ColMnemonicBrief:
135+
{
136+
RichTextPainter::List richText;
137+
if(d.mShowMnemonicBrief)
138+
return getDisassemblyMnemonicBrief(inst);
139+
else
140+
return QString();
141+
}
142+
case Disassembly::ColComment:
143+
{
144+
QString comment;
145+
bool autocomment;
146+
GetCommentFormat(cur_addr, comment, &autocomment);
147+
if(autocomment || comment.isEmpty()) // prefer label over auto-comment
148+
{
149+
char label[MAX_LABEL_SIZE];
150+
if(DbgGetLabelAt(cur_addr, SEG_DEFAULT, label))
151+
{
152+
comment = QString::fromUtf8(label);
153+
}
154+
}
155+
if(d.mShowMnemonicBrief && d.getColumnHidden(Disassembly::ColMnemonicBrief))
156+
{
157+
comment += ' ' + getDisassemblyMnemonicBrief(inst);
158+
}
159+
return comment;
160+
}
161+
default:
162+
return QString();
163+
}
164+
}
165+
166+
#endif
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
#pragma once
2+
#ifndef QT_NO_ACCESSIBILITY
3+
#include <QAccessibleWidget>
4+
#include "AccessibleAbstractTableView.h"
5+
#include "Disassembly.h"
6+
7+
class AccessibleDisassembly : public AccessibleAbstractTableView
8+
{
9+
public:
10+
AccessibleDisassembly(QWidget* w);
11+
~AccessibleDisassembly();
12+
13+
bool isRowSelected(int row) const override;
14+
QList<int> selectedRows() const override;
15+
int selectedRowCount() const override;
16+
int selectedCellCount() const override;
17+
QList<QAccessibleInterface*> selectedCells() const override;
18+
private:
19+
virtual QString getCellContent(int row, int col) const; // Get plain text of a cell
20+
Disassembly* dis() const;
21+
};
22+
23+
#endif

src/gui/Src/BasicView/AbstractStdTable.cpp

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
#include <QAccessible>
21
#include "AbstractStdTable.h"
32
#include "Bridge.h"
43
#include <Utils/RichTextPainter.h>

src/gui/Src/BasicView/AbstractTableView.cpp

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1412,13 +1412,17 @@ void AbstractTableView::accessibilitySelectionChanged()
14121412
QAccessible::updateAccessibility(&selectionEvent);
14131413
if(hasFocus())
14141414
{
1415-
QAccessibleTableInterface* tableInterface = (QAccessibleTableInterface*)accessible->interface_cast(QAccessible::TableInterface);
1416-
assert(tableInterface);
1417-
QAccessibleInterface* cell = tableInterface->cellAt(accessibilitySelectedRow() + 1, accessibilitySelectedColumn);
1418-
if(cell)
1415+
auto sel = accessibilitySelectedRow();
1416+
if(sel != -1)
14191417
{
1420-
QAccessibleEvent focusEvent(cell, QAccessible::Focus);
1421-
QAccessible::updateAccessibility(&focusEvent);
1418+
QAccessibleTableInterface* tableInterface = (QAccessibleTableInterface*)accessible->interface_cast(QAccessible::TableInterface);
1419+
assert(tableInterface);
1420+
QAccessibleInterface* cell = tableInterface->cellAt(sel + 1, accessibilitySelectedColumn);
1421+
if(cell)
1422+
{
1423+
QAccessibleEvent focusEvent(cell, QAccessible::Focus);
1424+
QAccessible::updateAccessibility(&focusEvent);
1425+
}
14221426
}
14231427
}
14241428
}
@@ -1444,7 +1448,7 @@ void AbstractTableView::accessibilityTableModelChanged()
14441448
void AbstractTableView::accessibilityMousePressSetColumn(QMouseEvent* event)
14451449
{
14461450
// update selected column
1447-
if(QAccessible::isActive() && mHeader.isVisible && getColumnCount() && event->y() > getHeaderHeight())
1451+
if(QAccessible::isActive() && getColumnCount() && event->y() > getHeaderHeight())
14481452
{
14491453
accessibilitySelectedColumn = getColumnDisplayIndexFromX(event->x());
14501454
if(accessibilitySelectedColumn == -1)

src/gui/Src/BasicView/Disassembly.cpp

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -831,6 +831,7 @@ void Disassembly::mousePressEvent(QMouseEvent* event)
831831
updateViewport();
832832

833833
accept = true;
834+
accessibilityMousePressSetColumn(event);
834835
}
835836
}
836837
}
@@ -1589,6 +1590,7 @@ void Disassembly::selectionChangedSlot(duint Va)
15891590
}
15901591
if(DbgIsDebugging())
15911592
DbgXrefGet(Va, &mXrefInfo);
1593+
accessibilitySelectionChanged();
15921594
}
15931595

15941596
void Disassembly::selectNext(bool expand)
@@ -2261,7 +2263,7 @@ bool Disassembly::historyHasNext() const
22612263
return true;
22622264
}
22632265

2264-
QString Disassembly::getAddrText(duint cur_addr, QString & label, bool getLabel)
2266+
QString Disassembly::getAddrText(duint cur_addr, QString & label, bool getLabel) const
22652267
{
22662268
QString addrText = "";
22672269
if(mRvaDisplayEnabled) //RVA display
@@ -2389,3 +2391,14 @@ bool Disassembly::followInstruction(duint rva)
23892391
#endif // X64DBG
23902392
return false;
23912393
}
2394+
2395+
int Disassembly::accessibilitySelectedRow() const
2396+
{
2397+
auto sel = getInitialSelection();
2398+
for(int i = 0; i < mInstBuffer.size(); i++)
2399+
{
2400+
if(mInstBuffer[i].rva == sel)
2401+
return i;
2402+
}
2403+
return -1;
2404+
}

src/gui/Src/BasicView/Disassembly.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ class Disassembly : public AbstractTableView
8383
QList<Instruction_t>* instructionsBuffer(); // ugly
8484
const duint baseAddress() const;
8585

86-
QString getAddrText(duint cur_addr, QString & label, bool getLabel = true);
86+
QString getAddrText(duint cur_addr, QString & label, bool getLabel = true) const;
8787
void prepareDataCount(const QList<duint> & rvas, QList<Instruction_t>* instBuffer);
8888
void prepareDataRange(duint startRva, duint endRva, const std::function<bool(int, const Instruction_t &)> & disassembled);
8989
RichTextPainter::List getRichBytes(const Instruction_t & instr, bool isSelected) const;
@@ -279,4 +279,6 @@ public slots:
279279

280280
void paintRichText(int x, int y, int w, int h, int xinc, const RichTextPainter::List & richText, int rowOffset, int column);
281281
void paintRichText(int x, int y, int w, int h, int xinc, RichTextPainter::List && richText, int rowOffset, int column);
282+
friend class AccessibleDisassembly;
283+
int accessibilitySelectedRow() const override;
282284
};

0 commit comments

Comments
 (0)