From 47e806b084e7eaf44f441c84720d1ca36e12595b Mon Sep 17 00:00:00 2001
From: Yuri Kunde Schlesner <yuriks@yuriks.net>
Date: Sun, 7 May 2017 14:36:20 -0700
Subject: [PATCH] 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
---
 src/citra_qt/CMakeLists.txt            |   3 -
 src/citra_qt/debugger/disassembler.cpp | 272 -------------------------
 src/citra_qt/debugger/disassembler.h   |  76 -------
 src/citra_qt/debugger/disassembler.ui  |  81 --------
 src/citra_qt/main.cpp                  |  14 --
 src/citra_qt/main.h                    |   2 -
 6 files changed, 448 deletions(-)
 delete mode 100644 src/citra_qt/debugger/disassembler.cpp
 delete mode 100644 src/citra_qt/debugger/disassembler.h
 delete mode 100644 src/citra_qt/debugger/disassembler.ui

diff --git a/src/citra_qt/CMakeLists.txt b/src/citra_qt/CMakeLists.txt
index 3e6106f0a3..0b4fe6dd2a 100644
--- a/src/citra_qt/CMakeLists.txt
+++ b/src/citra_qt/CMakeLists.txt
@@ -12,7 +12,6 @@ set(SRCS
             configuration/configure_input.cpp
             configuration/configure_system.cpp
             debugger/callstack.cpp
-            debugger/disassembler.cpp
             debugger/graphics/graphics.cpp
             debugger/graphics/graphics_breakpoint_observer.cpp
             debugger/graphics/graphics_breakpoints.cpp
@@ -44,7 +43,6 @@ set(HEADERS
             configuration/configure_input.h
             configuration/configure_system.h
             debugger/callstack.h
-            debugger/disassembler.h
             debugger/graphics/graphics.h
             debugger/graphics/graphics_breakpoint_observer.h
             debugger/graphics/graphics_breakpoints.h
@@ -75,7 +73,6 @@ set(UIS
             configuration/configure_input.ui
             configuration/configure_system.ui
             debugger/callstack.ui
-            debugger/disassembler.ui
             debugger/registers.ui
             hotkeys.ui
             main.ui
diff --git a/src/citra_qt/debugger/disassembler.cpp b/src/citra_qt/debugger/disassembler.cpp
deleted file mode 100644
index e9c8ad8581..0000000000
--- a/src/citra_qt/debugger/disassembler.cpp
+++ /dev/null
@@ -1,272 +0,0 @@
-// Copyright 2014 Citra Emulator Project
-// Licensed under GPLv2 or any later version
-// Refer to the license.txt file included.
-
-#include <QShortcut>
-#include "citra_qt/bootmanager.h"
-#include "citra_qt/debugger/disassembler.h"
-#include "citra_qt/hotkeys.h"
-#include "citra_qt/util/util.h"
-#include "common/break_points.h"
-#include "common/symbols.h"
-#include "core/arm/arm_interface.h"
-#include "core/arm/disassembler/arm_disasm.h"
-#include "core/core.h"
-#include "core/memory.h"
-
-DisassemblerModel::DisassemblerModel(QObject* parent)
-    : QAbstractListModel(parent), base_address(0), code_size(0), program_counter(0),
-      selection(QModelIndex()) {}
-
-int DisassemblerModel::columnCount(const QModelIndex& parent) const {
-    return 3;
-}
-
-int DisassemblerModel::rowCount(const QModelIndex& parent) const {
-    return code_size;
-}
-
-QVariant DisassemblerModel::data(const QModelIndex& index, int role) const {
-    switch (role) {
-    case Qt::DisplayRole: {
-        u32 address = base_address + index.row() * 4;
-        u32 instr = Memory::Read32(address);
-        std::string disassembly = ARM_Disasm::Disassemble(address, instr);
-
-        if (index.column() == 0) {
-            return QString("0x%1").arg((uint)(address), 8, 16, QLatin1Char('0'));
-        } else if (index.column() == 1) {
-            return QString::fromStdString(disassembly);
-        } else if (index.column() == 2) {
-            if (Symbols::HasSymbol(address)) {
-                TSymbol symbol = Symbols::GetSymbol(address);
-                return QString("%1 - Size:%2")
-                    .arg(QString::fromStdString(symbol.name))
-                    .arg(symbol.size / 4); // divide by 4 to get instruction count
-            } else if (ARM_Disasm::Decode(instr) == OP_BL) {
-                u32 offset = instr & 0xFFFFFF;
-
-                // Sign-extend the 24-bit offset
-                if ((offset >> 23) & 1)
-                    offset |= 0xFF000000;
-
-                // Pre-compute the left-shift and the prefetch offset
-                offset <<= 2;
-                offset += 8;
-
-                TSymbol symbol = Symbols::GetSymbol(address + offset);
-                return QString("    --> %1").arg(QString::fromStdString(symbol.name));
-            }
-        }
-
-        break;
-    }
-
-    case Qt::BackgroundRole: {
-        unsigned int address = base_address + 4 * index.row();
-
-        if (breakpoints.IsAddressBreakPoint(address))
-            return QBrush(QColor(0xFF, 0xC0, 0xC0));
-        else if (address == program_counter)
-            return QBrush(QColor(0xC0, 0xC0, 0xFF));
-
-        break;
-    }
-
-    case Qt::FontRole: {
-        if (index.column() == 0 || index.column() == 1) { // 2 is the symbols column
-            return GetMonospaceFont();
-        }
-        break;
-    }
-
-    default:
-        break;
-    }
-
-    return QVariant();
-}
-
-QModelIndex DisassemblerModel::IndexFromAbsoluteAddress(unsigned int address) const {
-    return index((address - base_address) / 4, 0);
-}
-
-const BreakPoints& DisassemblerModel::GetBreakPoints() const {
-    return breakpoints;
-}
-
-void DisassemblerModel::ParseFromAddress(unsigned int address) {
-
-    // NOTE: A too large value causes lagging when scrolling the disassembly
-    const unsigned int chunk_size = 1000 * 500;
-
-    // If we haven't loaded anything yet, initialize base address to the parameter address
-    if (code_size == 0)
-        base_address = address;
-
-    // If the new area is already loaded, just continue
-    if (base_address + code_size > address + chunk_size && base_address <= address)
-        return;
-
-    // Insert rows before currently loaded data
-    if (base_address > address) {
-        unsigned int num_rows = (address - base_address) / 4;
-
-        beginInsertRows(QModelIndex(), 0, num_rows);
-        code_size += num_rows;
-        base_address = address;
-
-        endInsertRows();
-    }
-
-    // Insert rows after currently loaded data
-    if (base_address + code_size < address + chunk_size) {
-        unsigned int num_rows = (base_address + chunk_size - code_size - address) / 4;
-
-        beginInsertRows(QModelIndex(), 0, num_rows);
-        code_size += num_rows;
-        endInsertRows();
-    }
-
-    SetNextInstruction(address);
-}
-
-void DisassemblerModel::OnSelectionChanged(const QModelIndex& new_selection) {
-    selection = new_selection;
-}
-
-void DisassemblerModel::OnSetOrUnsetBreakpoint() {
-    if (!selection.isValid())
-        return;
-
-    unsigned int address = base_address + selection.row() * 4;
-
-    if (breakpoints.IsAddressBreakPoint(address)) {
-        breakpoints.Remove(address);
-    } else {
-        breakpoints.Add(address);
-    }
-
-    emit dataChanged(selection, selection);
-}
-
-void DisassemblerModel::SetNextInstruction(unsigned int address) {
-    QModelIndex cur_index = IndexFromAbsoluteAddress(program_counter);
-    QModelIndex prev_index = IndexFromAbsoluteAddress(address);
-
-    program_counter = address;
-
-    emit dataChanged(cur_index, cur_index);
-    emit dataChanged(prev_index, prev_index);
-}
-
-DisassemblerWidget::DisassemblerWidget(QWidget* parent, EmuThread* emu_thread)
-    : QDockWidget(parent), base_addr(0), emu_thread(emu_thread) {
-
-    disasm_ui.setupUi(this);
-
-    RegisterHotkey("Disassembler", "Start/Stop", QKeySequence(Qt::Key_F5), Qt::ApplicationShortcut);
-    RegisterHotkey("Disassembler", "Step", QKeySequence(Qt::Key_F10), Qt::ApplicationShortcut);
-    RegisterHotkey("Disassembler", "Step into", QKeySequence(Qt::Key_F11), Qt::ApplicationShortcut);
-    RegisterHotkey("Disassembler", "Set Breakpoint", QKeySequence(Qt::Key_F9),
-                   Qt::ApplicationShortcut);
-
-    connect(disasm_ui.button_step, SIGNAL(clicked()), this, SLOT(OnStep()));
-    connect(disasm_ui.button_pause, SIGNAL(clicked()), this, SLOT(OnPause()));
-    connect(disasm_ui.button_continue, SIGNAL(clicked()), this, SLOT(OnContinue()));
-
-    connect(GetHotkey("Disassembler", "Start/Stop", this), SIGNAL(activated()), this,
-            SLOT(OnToggleStartStop()));
-    connect(GetHotkey("Disassembler", "Step", this), SIGNAL(activated()), this, SLOT(OnStep()));
-    connect(GetHotkey("Disassembler", "Step into", this), SIGNAL(activated()), this,
-            SLOT(OnStepInto()));
-
-    setEnabled(false);
-}
-
-void DisassemblerWidget::Init() {
-    model->ParseFromAddress(Core::CPU().GetPC());
-
-    disasm_ui.treeView->resizeColumnToContents(0);
-    disasm_ui.treeView->resizeColumnToContents(1);
-    disasm_ui.treeView->resizeColumnToContents(2);
-
-    QModelIndex model_index = model->IndexFromAbsoluteAddress(Core::CPU().GetPC());
-    disasm_ui.treeView->scrollTo(model_index);
-    disasm_ui.treeView->selectionModel()->setCurrentIndex(
-        model_index, QItemSelectionModel::SelectCurrent | QItemSelectionModel::Rows);
-}
-
-void DisassemblerWidget::OnContinue() {
-    emu_thread->SetRunning(true);
-}
-
-void DisassemblerWidget::OnStep() {
-    OnStepInto(); // change later
-}
-
-void DisassemblerWidget::OnStepInto() {
-    emu_thread->SetRunning(false);
-    emu_thread->ExecStep();
-}
-
-void DisassemblerWidget::OnPause() {
-    emu_thread->SetRunning(false);
-
-    // TODO: By now, the CPU might not have actually stopped...
-    if (Core::System::GetInstance().IsPoweredOn()) {
-        model->SetNextInstruction(Core::CPU().GetPC());
-    }
-}
-
-void DisassemblerWidget::OnToggleStartStop() {
-    emu_thread->SetRunning(!emu_thread->IsRunning());
-}
-
-void DisassemblerWidget::OnDebugModeEntered() {
-    u32 next_instr = Core::CPU().GetPC();
-
-    if (model->GetBreakPoints().IsAddressBreakPoint(next_instr))
-        emu_thread->SetRunning(false);
-
-    model->SetNextInstruction(next_instr);
-
-    QModelIndex model_index = model->IndexFromAbsoluteAddress(next_instr);
-    disasm_ui.treeView->scrollTo(model_index);
-    disasm_ui.treeView->selectionModel()->setCurrentIndex(
-        model_index, QItemSelectionModel::SelectCurrent | QItemSelectionModel::Rows);
-}
-
-void DisassemblerWidget::OnDebugModeLeft() {}
-
-int DisassemblerWidget::SelectedRow() {
-    QModelIndex index = disasm_ui.treeView->selectionModel()->currentIndex();
-    if (!index.isValid())
-        return -1;
-
-    return disasm_ui.treeView->selectionModel()->currentIndex().row();
-}
-
-void DisassemblerWidget::OnEmulationStarting(EmuThread* emu_thread) {
-    this->emu_thread = emu_thread;
-
-    model = new DisassemblerModel(this);
-    disasm_ui.treeView->setModel(model);
-
-    connect(disasm_ui.treeView->selectionModel(),
-            SIGNAL(currentChanged(const QModelIndex&, const QModelIndex&)), model,
-            SLOT(OnSelectionChanged(const QModelIndex&)));
-    connect(disasm_ui.button_breakpoint, SIGNAL(clicked()), model, SLOT(OnSetOrUnsetBreakpoint()));
-    connect(GetHotkey("Disassembler", "Set Breakpoint", this), SIGNAL(activated()), model,
-            SLOT(OnSetOrUnsetBreakpoint()));
-
-    Init();
-    setEnabled(true);
-}
-
-void DisassemblerWidget::OnEmulationStopping() {
-    disasm_ui.treeView->setModel(nullptr);
-    delete model;
-    emu_thread = nullptr;
-    setEnabled(false);
-}
diff --git a/src/citra_qt/debugger/disassembler.h b/src/citra_qt/debugger/disassembler.h
deleted file mode 100644
index a6e59515c1..0000000000
--- a/src/citra_qt/debugger/disassembler.h
+++ /dev/null
@@ -1,76 +0,0 @@
-// Copyright 2014 Citra Emulator Project
-// Licensed under GPLv2 or any later version
-// Refer to the license.txt file included.
-
-#pragma once
-
-#include <QAbstractListModel>
-#include <QDockWidget>
-#include "common/break_points.h"
-#include "common/common_types.h"
-#include "ui_disassembler.h"
-
-class QAction;
-class EmuThread;
-
-class DisassemblerModel : public QAbstractListModel {
-    Q_OBJECT
-
-public:
-    explicit DisassemblerModel(QObject* parent);
-
-    int columnCount(const QModelIndex& parent = QModelIndex()) const override;
-    int rowCount(const QModelIndex& parent = QModelIndex()) const override;
-    QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override;
-
-    QModelIndex IndexFromAbsoluteAddress(unsigned int address) const;
-    const BreakPoints& GetBreakPoints() const;
-
-public slots:
-    void ParseFromAddress(unsigned int address);
-    void OnSelectionChanged(const QModelIndex&);
-    void OnSetOrUnsetBreakpoint();
-    void SetNextInstruction(unsigned int address);
-
-private:
-    unsigned int base_address;
-    unsigned int code_size;
-    unsigned int program_counter;
-
-    QModelIndex selection;
-    BreakPoints breakpoints;
-};
-
-class DisassemblerWidget : public QDockWidget {
-    Q_OBJECT
-
-public:
-    DisassemblerWidget(QWidget* parent, EmuThread* emu_thread);
-
-    void Init();
-
-public slots:
-    void OnContinue();
-    void OnStep();
-    void OnStepInto();
-    void OnPause();
-    void OnToggleStartStop();
-
-    void OnDebugModeEntered();
-    void OnDebugModeLeft();
-
-    void OnEmulationStarting(EmuThread* emu_thread);
-    void OnEmulationStopping();
-
-private:
-    // returns -1 if no row is selected
-    int SelectedRow();
-
-    Ui::DockWidget disasm_ui;
-
-    DisassemblerModel* model;
-
-    u32 base_addr;
-
-    EmuThread* emu_thread;
-};
diff --git a/src/citra_qt/debugger/disassembler.ui b/src/citra_qt/debugger/disassembler.ui
deleted file mode 100644
index 5ca6dc5d2f..0000000000
--- a/src/citra_qt/debugger/disassembler.ui
+++ /dev/null
@@ -1,81 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<ui version="4.0">
- <class>DockWidget</class>
- <widget class="QDockWidget" name="DockWidget">
-  <property name="geometry">
-   <rect>
-    <x>0</x>
-    <y>0</y>
-    <width>430</width>
-    <height>401</height>
-   </rect>
-  </property>
-  <property name="windowTitle">
-   <string>Disassembly</string>
-  </property>
-  <widget class="QWidget" name="dockWidgetContents">
-   <layout class="QVBoxLayout" name="verticalLayout">
-    <item>
-     <layout class="QHBoxLayout" name="horizontalLayout">
-      <item>
-       <widget class="QPushButton" name="button_step">
-        <property name="text">
-         <string>Step</string>
-        </property>
-       </widget>
-      </item>
-      <item>
-       <widget class="QPushButton" name="button_pause">
-        <property name="text">
-         <string>Pause</string>
-        </property>
-       </widget>
-      </item>
-      <item>
-       <widget class="QPushButton" name="button_continue">
-        <property name="text">
-         <string>Continue</string>
-        </property>
-       </widget>
-      </item>
-      <item>
-       <widget class="QPushButton" name="pushButton">
-        <property name="text">
-         <string>Step Into</string>
-        </property>
-       </widget>
-      </item>
-      <item>
-       <widget class="QPushButton" name="button_breakpoint">
-        <property name="text">
-         <string>Set Breakpoint</string>
-        </property>
-       </widget>
-      </item>
-     </layout>
-    </item>
-    <item>
-     <widget class="QTreeView" name="treeView">
-      <property name="alternatingRowColors">
-       <bool>true</bool>
-      </property>
-      <property name="indentation">
-       <number>20</number>
-      </property>
-      <property name="rootIsDecorated">
-       <bool>false</bool>
-      </property>
-      <property name="uniformRowHeights">
-       <bool>true</bool>
-      </property>
-      <attribute name="headerVisible">
-       <bool>false</bool>
-      </attribute>
-     </widget>
-    </item>
-   </layout>
-  </widget>
- </widget>
- <resources/>
- <connections/>
-</ui>
diff --git a/src/citra_qt/main.cpp b/src/citra_qt/main.cpp
index ea66cc4254..50149bcb08 100644
--- a/src/citra_qt/main.cpp
+++ b/src/citra_qt/main.cpp
@@ -17,7 +17,6 @@
 #include "citra_qt/configuration/config.h"
 #include "citra_qt/configuration/configure_dialog.h"
 #include "citra_qt/debugger/callstack.h"
-#include "citra_qt/debugger/disassembler.h"
 #include "citra_qt/debugger/graphics/graphics.h"
 #include "citra_qt/debugger/graphics/graphics_breakpoints.h"
 #include "citra_qt/debugger/graphics/graphics_cmdlists.h"
@@ -130,15 +129,6 @@ void GMainWindow::InitializeDebugWidgets() {
     debug_menu->addAction(microProfileDialog->toggleViewAction());
 #endif
 
-    disasmWidget = new DisassemblerWidget(this, emu_thread.get());
-    addDockWidget(Qt::BottomDockWidgetArea, disasmWidget);
-    disasmWidget->hide();
-    debug_menu->addAction(disasmWidget->toggleViewAction());
-    connect(this, &GMainWindow::EmulationStarting, disasmWidget,
-            &DisassemblerWidget::OnEmulationStarting);
-    connect(this, &GMainWindow::EmulationStopping, disasmWidget,
-            &DisassemblerWidget::OnEmulationStopping);
-
     registersWidget = new RegistersWidget(this);
     addDockWidget(Qt::RightDockWidgetArea, registersWidget);
     registersWidget->hide();
@@ -391,16 +381,12 @@ void GMainWindow::BootGame(const QString& filename) {
     connect(render_window, SIGNAL(Closed()), this, SLOT(OnStopGame()));
     // BlockingQueuedConnection is important here, it makes sure we've finished refreshing our views
     // before the CPU continues
-    connect(emu_thread.get(), SIGNAL(DebugModeEntered()), disasmWidget, SLOT(OnDebugModeEntered()),
-            Qt::BlockingQueuedConnection);
     connect(emu_thread.get(), SIGNAL(DebugModeEntered()), registersWidget,
             SLOT(OnDebugModeEntered()), Qt::BlockingQueuedConnection);
     connect(emu_thread.get(), SIGNAL(DebugModeEntered()), callstackWidget,
             SLOT(OnDebugModeEntered()), Qt::BlockingQueuedConnection);
     connect(emu_thread.get(), SIGNAL(DebugModeEntered()), waitTreeWidget,
             SLOT(OnDebugModeEntered()), Qt::BlockingQueuedConnection);
-    connect(emu_thread.get(), SIGNAL(DebugModeLeft()), disasmWidget, SLOT(OnDebugModeLeft()),
-            Qt::BlockingQueuedConnection);
     connect(emu_thread.get(), SIGNAL(DebugModeLeft()), registersWidget, SLOT(OnDebugModeLeft()),
             Qt::BlockingQueuedConnection);
     connect(emu_thread.get(), SIGNAL(DebugModeLeft()), callstackWidget, SLOT(OnDebugModeLeft()),
diff --git a/src/citra_qt/main.h b/src/citra_qt/main.h
index 2f398eb7b6..2417dc2cb5 100644
--- a/src/citra_qt/main.h
+++ b/src/citra_qt/main.h
@@ -12,7 +12,6 @@
 
 class CallstackWidget;
 class Config;
-class DisassemblerWidget;
 class EmuThread;
 class GameList;
 class GImageInfo;
@@ -152,7 +151,6 @@ private:
     // Debugger panes
     ProfilerWidget* profilerWidget;
     MicroProfileDialog* microProfileDialog;
-    DisassemblerWidget* disasmWidget;
     RegistersWidget* registersWidget;
     CallstackWidget* callstackWidget;
     GPUCommandStreamWidget* graphicsWidget;