summaryrefslogtreecommitdiff
path: root/src/citra_qt/debugger/disassembler.cpp
diff options
context:
space:
mode:
authorGravatar Yuri Kunde Schlesner2017-05-07 14:36:20 -0700
committerGravatar Yuri Kunde Schlesner2017-05-07 15:29:36 -0700
commit47e806b084e7eaf44f441c84720d1ca36e12595b (patch)
tree423017fad2c89386998285c940b0290515087015 /src/citra_qt/debugger/disassembler.cpp
parentMerge pull request #2682 from nicoboss/filter (diff)
downloadyuzu-47e806b084e7eaf44f441c84720d1ca36e12595b.tar.gz
yuzu-47e806b084e7eaf44f441c84720d1ca36e12595b.tar.xz
yuzu-47e806b084e7eaf44f441c84720d1ca36e12595b.zip
citra-qt: Remove disassembler widget
It has performance problems, a very misleading UI, and is broken in general. It has essentially been superceded by the GDB stub, but if we wanted a built-in disassembler in the future it'd essentially need to be rewritten from scratch anyway. Closes #427, #1480
Diffstat (limited to 'src/citra_qt/debugger/disassembler.cpp')
-rw-r--r--src/citra_qt/debugger/disassembler.cpp272
1 files changed, 0 insertions, 272 deletions
diff --git a/src/citra_qt/debugger/disassembler.cpp b/src/citra_qt/debugger/disassembler.cpp
deleted file mode 100644
index e9c8ad858..000000000
--- a/src/citra_qt/debugger/disassembler.cpp
+++ /dev/null
@@ -1,272 +0,0 @@
1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include <QShortcut>
6#include "citra_qt/bootmanager.h"
7#include "citra_qt/debugger/disassembler.h"
8#include "citra_qt/hotkeys.h"
9#include "citra_qt/util/util.h"
10#include "common/break_points.h"
11#include "common/symbols.h"
12#include "core/arm/arm_interface.h"
13#include "core/arm/disassembler/arm_disasm.h"
14#include "core/core.h"
15#include "core/memory.h"
16
17DisassemblerModel::DisassemblerModel(QObject* parent)
18 : QAbstractListModel(parent), base_address(0), code_size(0), program_counter(0),
19 selection(QModelIndex()) {}
20
21int DisassemblerModel::columnCount(const QModelIndex& parent) const {
22 return 3;
23}
24
25int DisassemblerModel::rowCount(const QModelIndex& parent) const {
26 return code_size;
27}
28
29QVariant DisassemblerModel::data(const QModelIndex& index, int role) const {
30 switch (role) {
31 case Qt::DisplayRole: {
32 u32 address = base_address + index.row() * 4;
33 u32 instr = Memory::Read32(address);
34 std::string disassembly = ARM_Disasm::Disassemble(address, instr);
35
36 if (index.column() == 0) {
37 return QString("0x%1").arg((uint)(address), 8, 16, QLatin1Char('0'));
38 } else if (index.column() == 1) {
39 return QString::fromStdString(disassembly);
40 } else if (index.column() == 2) {
41 if (Symbols::HasSymbol(address)) {
42 TSymbol symbol = Symbols::GetSymbol(address);
43 return QString("%1 - Size:%2")
44 .arg(QString::fromStdString(symbol.name))
45 .arg(symbol.size / 4); // divide by 4 to get instruction count
46 } else if (ARM_Disasm::Decode(instr) == OP_BL) {
47 u32 offset = instr & 0xFFFFFF;
48
49 // Sign-extend the 24-bit offset
50 if ((offset >> 23) & 1)
51 offset |= 0xFF000000;
52
53 // Pre-compute the left-shift and the prefetch offset
54 offset <<= 2;
55 offset += 8;
56
57 TSymbol symbol = Symbols::GetSymbol(address + offset);
58 return QString(" --> %1").arg(QString::fromStdString(symbol.name));
59 }
60 }
61
62 break;
63 }
64
65 case Qt::BackgroundRole: {
66 unsigned int address = base_address + 4 * index.row();
67
68 if (breakpoints.IsAddressBreakPoint(address))
69 return QBrush(QColor(0xFF, 0xC0, 0xC0));
70 else if (address == program_counter)
71 return QBrush(QColor(0xC0, 0xC0, 0xFF));
72
73 break;
74 }
75
76 case Qt::FontRole: {
77 if (index.column() == 0 || index.column() == 1) { // 2 is the symbols column
78 return GetMonospaceFont();
79 }
80 break;
81 }
82
83 default:
84 break;
85 }
86
87 return QVariant();
88}
89
90QModelIndex DisassemblerModel::IndexFromAbsoluteAddress(unsigned int address) const {
91 return index((address - base_address) / 4, 0);
92}
93
94const BreakPoints& DisassemblerModel::GetBreakPoints() const {
95 return breakpoints;
96}
97
98void DisassemblerModel::ParseFromAddress(unsigned int address) {
99
100 // NOTE: A too large value causes lagging when scrolling the disassembly
101 const unsigned int chunk_size = 1000 * 500;
102
103 // If we haven't loaded anything yet, initialize base address to the parameter address
104 if (code_size == 0)
105 base_address = address;
106
107 // If the new area is already loaded, just continue
108 if (base_address + code_size > address + chunk_size && base_address <= address)
109 return;
110
111 // Insert rows before currently loaded data
112 if (base_address > address) {
113 unsigned int num_rows = (address - base_address) / 4;
114
115 beginInsertRows(QModelIndex(), 0, num_rows);
116 code_size += num_rows;
117 base_address = address;
118
119 endInsertRows();
120 }
121
122 // Insert rows after currently loaded data
123 if (base_address + code_size < address + chunk_size) {
124 unsigned int num_rows = (base_address + chunk_size - code_size - address) / 4;
125
126 beginInsertRows(QModelIndex(), 0, num_rows);
127 code_size += num_rows;
128 endInsertRows();
129 }
130
131 SetNextInstruction(address);
132}
133
134void DisassemblerModel::OnSelectionChanged(const QModelIndex& new_selection) {
135 selection = new_selection;
136}
137
138void DisassemblerModel::OnSetOrUnsetBreakpoint() {
139 if (!selection.isValid())
140 return;
141
142 unsigned int address = base_address + selection.row() * 4;
143
144 if (breakpoints.IsAddressBreakPoint(address)) {
145 breakpoints.Remove(address);
146 } else {
147 breakpoints.Add(address);
148 }
149
150 emit dataChanged(selection, selection);
151}
152
153void DisassemblerModel::SetNextInstruction(unsigned int address) {
154 QModelIndex cur_index = IndexFromAbsoluteAddress(program_counter);
155 QModelIndex prev_index = IndexFromAbsoluteAddress(address);
156
157 program_counter = address;
158
159 emit dataChanged(cur_index, cur_index);
160 emit dataChanged(prev_index, prev_index);
161}
162
163DisassemblerWidget::DisassemblerWidget(QWidget* parent, EmuThread* emu_thread)
164 : QDockWidget(parent), base_addr(0), emu_thread(emu_thread) {
165
166 disasm_ui.setupUi(this);
167
168 RegisterHotkey("Disassembler", "Start/Stop", QKeySequence(Qt::Key_F5), Qt::ApplicationShortcut);
169 RegisterHotkey("Disassembler", "Step", QKeySequence(Qt::Key_F10), Qt::ApplicationShortcut);
170 RegisterHotkey("Disassembler", "Step into", QKeySequence(Qt::Key_F11), Qt::ApplicationShortcut);
171 RegisterHotkey("Disassembler", "Set Breakpoint", QKeySequence(Qt::Key_F9),
172 Qt::ApplicationShortcut);
173
174 connect(disasm_ui.button_step, SIGNAL(clicked()), this, SLOT(OnStep()));
175 connect(disasm_ui.button_pause, SIGNAL(clicked()), this, SLOT(OnPause()));
176 connect(disasm_ui.button_continue, SIGNAL(clicked()), this, SLOT(OnContinue()));
177
178 connect(GetHotkey("Disassembler", "Start/Stop", this), SIGNAL(activated()), this,
179 SLOT(OnToggleStartStop()));
180 connect(GetHotkey("Disassembler", "Step", this), SIGNAL(activated()), this, SLOT(OnStep()));
181 connect(GetHotkey("Disassembler", "Step into", this), SIGNAL(activated()), this,
182 SLOT(OnStepInto()));
183
184 setEnabled(false);
185}
186
187void DisassemblerWidget::Init() {
188 model->ParseFromAddress(Core::CPU().GetPC());
189
190 disasm_ui.treeView->resizeColumnToContents(0);
191 disasm_ui.treeView->resizeColumnToContents(1);
192 disasm_ui.treeView->resizeColumnToContents(2);
193
194 QModelIndex model_index = model->IndexFromAbsoluteAddress(Core::CPU().GetPC());
195 disasm_ui.treeView->scrollTo(model_index);
196 disasm_ui.treeView->selectionModel()->setCurrentIndex(
197 model_index, QItemSelectionModel::SelectCurrent | QItemSelectionModel::Rows);
198}
199
200void DisassemblerWidget::OnContinue() {
201 emu_thread->SetRunning(true);
202}
203
204void DisassemblerWidget::OnStep() {
205 OnStepInto(); // change later
206}
207
208void DisassemblerWidget::OnStepInto() {
209 emu_thread->SetRunning(false);
210 emu_thread->ExecStep();
211}
212
213void DisassemblerWidget::OnPause() {
214 emu_thread->SetRunning(false);
215
216 // TODO: By now, the CPU might not have actually stopped...
217 if (Core::System::GetInstance().IsPoweredOn()) {
218 model->SetNextInstruction(Core::CPU().GetPC());
219 }
220}
221
222void DisassemblerWidget::OnToggleStartStop() {
223 emu_thread->SetRunning(!emu_thread->IsRunning());
224}
225
226void DisassemblerWidget::OnDebugModeEntered() {
227 u32 next_instr = Core::CPU().GetPC();
228
229 if (model->GetBreakPoints().IsAddressBreakPoint(next_instr))
230 emu_thread->SetRunning(false);
231
232 model->SetNextInstruction(next_instr);
233
234 QModelIndex model_index = model->IndexFromAbsoluteAddress(next_instr);
235 disasm_ui.treeView->scrollTo(model_index);
236 disasm_ui.treeView->selectionModel()->setCurrentIndex(
237 model_index, QItemSelectionModel::SelectCurrent | QItemSelectionModel::Rows);
238}
239
240void DisassemblerWidget::OnDebugModeLeft() {}
241
242int DisassemblerWidget::SelectedRow() {
243 QModelIndex index = disasm_ui.treeView->selectionModel()->currentIndex();
244 if (!index.isValid())
245 return -1;
246
247 return disasm_ui.treeView->selectionModel()->currentIndex().row();
248}
249
250void DisassemblerWidget::OnEmulationStarting(EmuThread* emu_thread) {
251 this->emu_thread = emu_thread;
252
253 model = new DisassemblerModel(this);
254 disasm_ui.treeView->setModel(model);
255
256 connect(disasm_ui.treeView->selectionModel(),
257 SIGNAL(currentChanged(const QModelIndex&, const QModelIndex&)), model,
258 SLOT(OnSelectionChanged(const QModelIndex&)));
259 connect(disasm_ui.button_breakpoint, SIGNAL(clicked()), model, SLOT(OnSetOrUnsetBreakpoint()));
260 connect(GetHotkey("Disassembler", "Set Breakpoint", this), SIGNAL(activated()), model,
261 SLOT(OnSetOrUnsetBreakpoint()));
262
263 Init();
264 setEnabled(true);
265}
266
267void DisassemblerWidget::OnEmulationStopping() {
268 disasm_ui.treeView->setModel(nullptr);
269 delete model;
270 emu_thread = nullptr;
271 setEnabled(false);
272}