From 47e806b084e7eaf44f441c84720d1ca36e12595b Mon Sep 17 00:00:00 2001 From: Yuri Kunde Schlesner Date: Sun, 7 May 2017 14:36:20 -0700 Subject: [PATCH 1/6] 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 -#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 -#include -#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 @@ - - - DockWidget - - - - 0 - 0 - 430 - 401 - - - - Disassembly - - - - - - - - - Step - - - - - - - Pause - - - - - - - Continue - - - - - - - Step Into - - - - - - - Set Breakpoint - - - - - - - - - true - - - 20 - - - false - - - true - - - false - - - - - - - - - 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; From 4af2a1a3d74eb5e77b59e4557c50e230d453d7d9 Mon Sep 17 00:00:00 2001 From: Yuri Kunde Schlesner Date: Sun, 7 May 2017 14:44:43 -0700 Subject: [PATCH 2/6] citra-qt: Remove callstack widget Appears to be currently broken, and given the complexity of doing this for ARM code without debugging information, should probably be left to an external tool or library. Use the GDB stub instead. Closes #586 --- src/citra_qt/CMakeLists.txt | 3 - src/citra_qt/debugger/callstack.cpp | 85 ----------------------------- src/citra_qt/debugger/callstack.h | 28 ---------- src/citra_qt/debugger/callstack.ui | 39 ------------- src/citra_qt/main.cpp | 11 ---- src/citra_qt/main.h | 2 - 6 files changed, 168 deletions(-) delete mode 100644 src/citra_qt/debugger/callstack.cpp delete mode 100644 src/citra_qt/debugger/callstack.h delete mode 100644 src/citra_qt/debugger/callstack.ui diff --git a/src/citra_qt/CMakeLists.txt b/src/citra_qt/CMakeLists.txt index 0b4fe6dd2a..4e837668ef 100644 --- a/src/citra_qt/CMakeLists.txt +++ b/src/citra_qt/CMakeLists.txt @@ -11,7 +11,6 @@ set(SRCS configuration/configure_graphics.cpp configuration/configure_input.cpp configuration/configure_system.cpp - debugger/callstack.cpp debugger/graphics/graphics.cpp debugger/graphics/graphics_breakpoint_observer.cpp debugger/graphics/graphics_breakpoints.cpp @@ -42,7 +41,6 @@ set(HEADERS configuration/configure_graphics.h configuration/configure_input.h configuration/configure_system.h - debugger/callstack.h debugger/graphics/graphics.h debugger/graphics/graphics_breakpoint_observer.h debugger/graphics/graphics_breakpoints.h @@ -72,7 +70,6 @@ set(UIS configuration/configure_graphics.ui configuration/configure_input.ui configuration/configure_system.ui - debugger/callstack.ui debugger/registers.ui hotkeys.ui main.ui diff --git a/src/citra_qt/debugger/callstack.cpp b/src/citra_qt/debugger/callstack.cpp deleted file mode 100644 index 08d2e7a229..0000000000 --- a/src/citra_qt/debugger/callstack.cpp +++ /dev/null @@ -1,85 +0,0 @@ -// Copyright 2014 Citra Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#include -#include "citra_qt/debugger/callstack.h" -#include "common/common_types.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" - -CallstackWidget::CallstackWidget(QWidget* parent) : QDockWidget(parent) { - ui.setupUi(this); - - callstack_model = new QStandardItemModel(this); - callstack_model->setColumnCount(4); - callstack_model->setHeaderData(0, Qt::Horizontal, "Stack Pointer"); - callstack_model->setHeaderData(2, Qt::Horizontal, "Return Address"); - callstack_model->setHeaderData(1, Qt::Horizontal, "Call Address"); - callstack_model->setHeaderData(3, Qt::Horizontal, "Function"); - ui.treeView->setModel(callstack_model); -} - -void CallstackWidget::OnDebugModeEntered() { - // Stack pointer - const u32 sp = Core::CPU().GetReg(13); - - Clear(); - - int counter = 0; - for (u32 addr = 0x10000000; addr >= sp; addr -= 4) { - if (!Memory::IsValidVirtualAddress(addr)) - break; - - const u32 ret_addr = Memory::Read32(addr); - const u32 call_addr = ret_addr - 4; // get call address??? - - if (!Memory::IsValidVirtualAddress(call_addr)) - break; - - /* TODO (mattvail) clean me, move to debugger interface */ - u32 insn = Memory::Read32(call_addr); - if (ARM_Disasm::Decode(insn) == OP_BL) { - std::string name; - // ripped from disasm - u32 i_offset = insn & 0xffffff; - // Sign-extend the 24-bit offset - if ((i_offset >> 23) & 1) - i_offset |= 0xff000000; - - // Pre-compute the left-shift and the prefetch offset - i_offset <<= 2; - i_offset += 8; - const u32 func_addr = call_addr + i_offset; - - callstack_model->setItem( - counter, 0, new QStandardItem(QString("0x%1").arg(addr, 8, 16, QLatin1Char('0')))); - callstack_model->setItem(counter, 1, new QStandardItem(QString("0x%1").arg( - ret_addr, 8, 16, QLatin1Char('0')))); - callstack_model->setItem(counter, 2, new QStandardItem(QString("0x%1").arg( - call_addr, 8, 16, QLatin1Char('0')))); - - name = Symbols::HasSymbol(func_addr) ? Symbols::GetSymbol(func_addr).name : "unknown"; - callstack_model->setItem( - counter, 3, new QStandardItem( - QString("%1_%2") - .arg(QString::fromStdString(name)) - .arg(QString("0x%1").arg(func_addr, 8, 16, QLatin1Char('0'))))); - - counter++; - } - } -} - -void CallstackWidget::OnDebugModeLeft() {} - -void CallstackWidget::Clear() { - for (int row = 0; row < callstack_model->rowCount(); row++) { - for (int column = 0; column < callstack_model->columnCount(); column++) { - callstack_model->setItem(row, column, new QStandardItem()); - } - } -} diff --git a/src/citra_qt/debugger/callstack.h b/src/citra_qt/debugger/callstack.h deleted file mode 100644 index f04ab9c7e2..0000000000 --- a/src/citra_qt/debugger/callstack.h +++ /dev/null @@ -1,28 +0,0 @@ -// Copyright 2014 Citra Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#pragma once - -#include -#include "ui_callstack.h" - -class QStandardItemModel; - -class CallstackWidget : public QDockWidget { - Q_OBJECT - -public: - explicit CallstackWidget(QWidget* parent = nullptr); - -public slots: - void OnDebugModeEntered(); - void OnDebugModeLeft(); - -private: - Ui::CallStack ui; - QStandardItemModel* callstack_model; - - /// Clears the callstack widget while keeping the column widths the same - void Clear(); -}; diff --git a/src/citra_qt/debugger/callstack.ui b/src/citra_qt/debugger/callstack.ui deleted file mode 100644 index 248ea3dd7d..0000000000 --- a/src/citra_qt/debugger/callstack.ui +++ /dev/null @@ -1,39 +0,0 @@ - - - CallStack - - - - 0 - 0 - 400 - 300 - - - - Call Stack - - - - - - - QAbstractItemView::NoEditTriggers - - - true - - - false - - - false - - - - - - - - - diff --git a/src/citra_qt/main.cpp b/src/citra_qt/main.cpp index 50149bcb08..9beec69bcf 100644 --- a/src/citra_qt/main.cpp +++ b/src/citra_qt/main.cpp @@ -16,7 +16,6 @@ #include "citra_qt/bootmanager.h" #include "citra_qt/configuration/config.h" #include "citra_qt/configuration/configure_dialog.h" -#include "citra_qt/debugger/callstack.h" #include "citra_qt/debugger/graphics/graphics.h" #include "citra_qt/debugger/graphics/graphics_breakpoints.h" #include "citra_qt/debugger/graphics/graphics_cmdlists.h" @@ -138,11 +137,6 @@ void GMainWindow::InitializeDebugWidgets() { connect(this, &GMainWindow::EmulationStopping, registersWidget, &RegistersWidget::OnEmulationStopping); - callstackWidget = new CallstackWidget(this); - addDockWidget(Qt::RightDockWidgetArea, callstackWidget); - callstackWidget->hide(); - debug_menu->addAction(callstackWidget->toggleViewAction()); - graphicsWidget = new GPUCommandStreamWidget(this); addDockWidget(Qt::RightDockWidgetArea, graphicsWidget); graphicsWidget->hide(); @@ -383,20 +377,15 @@ void GMainWindow::BootGame(const QString& filename) { // before the CPU continues 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()), registersWidget, SLOT(OnDebugModeLeft()), Qt::BlockingQueuedConnection); - connect(emu_thread.get(), SIGNAL(DebugModeLeft()), callstackWidget, SLOT(OnDebugModeLeft()), - Qt::BlockingQueuedConnection); connect(emu_thread.get(), SIGNAL(DebugModeLeft()), waitTreeWidget, SLOT(OnDebugModeLeft()), Qt::BlockingQueuedConnection); // Update the GUI registersWidget->OnDebugModeEntered(); - callstackWidget->OnDebugModeEntered(); if (ui.action_Single_Window_Mode->isChecked()) { game_list->hide(); } diff --git a/src/citra_qt/main.h b/src/citra_qt/main.h index 2417dc2cb5..ded089580d 100644 --- a/src/citra_qt/main.h +++ b/src/citra_qt/main.h @@ -10,7 +10,6 @@ #include #include "ui_main.h" -class CallstackWidget; class Config; class EmuThread; class GameList; @@ -152,7 +151,6 @@ private: ProfilerWidget* profilerWidget; MicroProfileDialog* microProfileDialog; RegistersWidget* registersWidget; - CallstackWidget* callstackWidget; GPUCommandStreamWidget* graphicsWidget; GPUCommandListWidget* graphicsCommandsWidget; GraphicsBreakPointsWidget* graphicsBreakpointsWidget; From 6577bbc3c5c47d8e3868f1205284337c6c672744 Mon Sep 17 00:00:00 2001 From: Yuri Kunde Schlesner Date: Sun, 7 May 2017 14:56:23 -0700 Subject: [PATCH 3/6] Remove ability to load symbol maps This was now mostly unused except by thread creation, which used a symbol of the entrypoint, if available, to name the thread. --- src/citra_qt/main.cpp | 13 ------------- src/citra_qt/main.h | 1 - src/citra_qt/main.ui | 1 - src/core/hle/svc.cpp | 10 ++-------- src/core/loader/elf.cpp | 32 -------------------------------- 5 files changed, 2 insertions(+), 55 deletions(-) diff --git a/src/citra_qt/main.cpp b/src/citra_qt/main.cpp index 9beec69bcf..d7fad555fd 100644 --- a/src/citra_qt/main.cpp +++ b/src/citra_qt/main.cpp @@ -38,7 +38,6 @@ #include "common/scm_rev.h" #include "common/scope_exit.h" #include "common/string_util.h" -#include "core/arm/disassembler/load_symbol_map.h" #include "core/core.h" #include "core/file_sys/archive_source_sd_savedata.h" #include "core/gdbstub/gdbstub.h" @@ -253,8 +252,6 @@ void GMainWindow::ConnectWidgetEvents() { void GMainWindow::ConnectMenuEvents() { // File connect(ui.action_Load_File, &QAction::triggered, this, &GMainWindow::OnMenuLoadFile); - connect(ui.action_Load_Symbol_Map, &QAction::triggered, this, - &GMainWindow::OnMenuLoadSymbolMap); connect(ui.action_Select_Game_List_Root, &QAction::triggered, this, &GMainWindow::OnMenuSelectGameListRoot); connect(ui.action_Exit, &QAction::triggered, this, &QMainWindow::close); @@ -506,16 +503,6 @@ void GMainWindow::OnMenuLoadFile() { } } -void GMainWindow::OnMenuLoadSymbolMap() { - QString filename = QFileDialog::getOpenFileName( - this, tr("Load Symbol Map"), UISettings::values.symbols_path, tr("Symbol Map (*.*)")); - if (!filename.isEmpty()) { - UISettings::values.symbols_path = QFileInfo(filename).path(); - - LoadSymbolMap(filename.toStdString()); - } -} - void GMainWindow::OnMenuSelectGameListRoot() { QString dir_path = QFileDialog::getExistingDirectory(this, tr("Select Directory")); if (!dir_path.isEmpty()) { diff --git a/src/citra_qt/main.h b/src/citra_qt/main.h index ded089580d..cb2e87cbdc 100644 --- a/src/citra_qt/main.h +++ b/src/citra_qt/main.h @@ -116,7 +116,6 @@ private slots: void OnGameListLoadFile(QString game_path); void OnGameListOpenSaveFolder(u64 program_id); void OnMenuLoadFile(); - void OnMenuLoadSymbolMap(); /// Called whenever a user selects the "File->Select Game List Root" menu item void OnMenuSelectGameListRoot(); void OnMenuRecentFile(); diff --git a/src/citra_qt/main.ui b/src/citra_qt/main.ui index f64b878f0a..b13d578f58 100644 --- a/src/citra_qt/main.ui +++ b/src/citra_qt/main.ui @@ -58,7 +58,6 @@ - diff --git a/src/core/hle/svc.cpp b/src/core/hle/svc.cpp index 2db823c615..8538cfc9de 100644 --- a/src/core/hle/svc.cpp +++ b/src/core/hle/svc.cpp @@ -2,12 +2,12 @@ // Licensed under GPLv2 or any later version // Refer to the license.txt file included. +#include #include #include "common/logging/log.h" #include "common/microprofile.h" #include "common/scope_exit.h" #include "common/string_util.h" -#include "common/symbols.h" #include "core/arm/arm_interface.h" #include "core/core_timing.h" #include "core/hle/function_wrappers.h" @@ -524,13 +524,7 @@ static ResultCode CreateThread(Kernel::Handle* out_handle, s32 priority, u32 ent u32 stack_top, s32 processor_id) { using Kernel::Thread; - std::string name; - if (Symbols::HasSymbol(entry_point)) { - TSymbol symbol = Symbols::GetSymbol(entry_point); - name = symbol.name; - } else { - name = Common::StringFromFormat("unknown-%08x", entry_point); - } + std::string name = Common::StringFromFormat("unknown-%08" PRIX32, entry_point); if (priority > THREADPRIO_LOWEST) { return ResultCode(ErrorDescription::OutOfRange, ErrorModule::OS, diff --git a/src/core/loader/elf.cpp b/src/core/loader/elf.cpp index 8eb5200abd..cfcde91673 100644 --- a/src/core/loader/elf.cpp +++ b/src/core/loader/elf.cpp @@ -8,7 +8,6 @@ #include "common/common_types.h" #include "common/file_util.h" #include "common/logging/log.h" -#include "common/symbols.h" #include "core/hle/kernel/process.h" #include "core/hle/kernel/resource_limit.h" #include "core/loader/elf.h" @@ -210,7 +209,6 @@ public: return (u32)(header->e_flags); } SharedPtr LoadInto(u32 vaddr); - bool LoadSymbols(); int GetNumSegments() const { return (int)(header->e_phnum); @@ -258,8 +256,6 @@ ElfReader::ElfReader(void* ptr) { sections = (Elf32_Shdr*)(base + header->e_shoff); entryPoint = header->e_entry; - - LoadSymbols(); } const char* ElfReader::GetSectionName(int section) const { @@ -362,34 +358,6 @@ SectionID ElfReader::GetSectionByName(const char* name, int firstSection) const return -1; } -bool ElfReader::LoadSymbols() { - bool hasSymbols = false; - SectionID sec = GetSectionByName(".symtab"); - if (sec != -1) { - int stringSection = sections[sec].sh_link; - const char* stringBase = reinterpret_cast(GetSectionDataPtr(stringSection)); - - // We have a symbol table! - const Elf32_Sym* symtab = reinterpret_cast(GetSectionDataPtr(sec)); - unsigned int numSymbols = sections[sec].sh_size / sizeof(Elf32_Sym); - for (unsigned sym = 0; sym < numSymbols; sym++) { - int size = symtab[sym].st_size; - if (size == 0) - continue; - - int type = symtab[sym].st_info & 0xF; - - const char* name = stringBase + symtab[sym].st_name; - - Symbols::Add(symtab[sym].st_value, name, size, type); - - hasSymbols = true; - } - } - - return hasSymbols; -} - //////////////////////////////////////////////////////////////////////////////////////////////////// // Loader namespace From cb4da3975e076c828f77b3517a73e2071c605950 Mon Sep 17 00:00:00 2001 From: Yuri Kunde Schlesner Date: Sun, 7 May 2017 15:01:37 -0700 Subject: [PATCH 4/6] Remove unused symbols code --- src/common/CMakeLists.txt | 2 - src/common/symbols.cpp | 46 ------------------- src/common/symbols.h | 30 ------------ src/core/CMakeLists.txt | 2 - src/core/arm/disassembler/load_symbol_map.cpp | 31 ------------- src/core/arm/disassembler/load_symbol_map.h | 13 ------ 6 files changed, 124 deletions(-) delete mode 100644 src/common/symbols.cpp delete mode 100644 src/common/symbols.h delete mode 100644 src/core/arm/disassembler/load_symbol_map.cpp delete mode 100644 src/core/arm/disassembler/load_symbol_map.h diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt index 13277a5c2e..4b30185f11 100644 --- a/src/common/CMakeLists.txt +++ b/src/common/CMakeLists.txt @@ -38,7 +38,6 @@ set(SRCS param_package.cpp scm_rev.cpp string_util.cpp - symbols.cpp thread.cpp timer.cpp ) @@ -74,7 +73,6 @@ set(HEADERS scope_exit.h string_util.h swap.h - symbols.h synchronized_wrapper.h thread.h thread_queue_list.h diff --git a/src/common/symbols.cpp b/src/common/symbols.cpp deleted file mode 100644 index c4d16af856..0000000000 --- a/src/common/symbols.cpp +++ /dev/null @@ -1,46 +0,0 @@ -// Copyright 2014 Citra Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#include "common/symbols.h" - -TSymbolsMap g_symbols; - -namespace Symbols { -bool HasSymbol(u32 address) { - return g_symbols.find(address) != g_symbols.end(); -} - -void Add(u32 address, const std::string& name, u32 size, u32 type) { - if (!HasSymbol(address)) { - TSymbol symbol; - symbol.address = address; - symbol.name = name; - symbol.size = size; - symbol.type = type; - - g_symbols.emplace(address, symbol); - } -} - -TSymbol GetSymbol(u32 address) { - const auto iter = g_symbols.find(address); - - if (iter != g_symbols.end()) - return iter->second; - - return {}; -} - -const std::string GetName(u32 address) { - return GetSymbol(address).name; -} - -void Remove(u32 address) { - g_symbols.erase(address); -} - -void Clear() { - g_symbols.clear(); -} -} diff --git a/src/common/symbols.h b/src/common/symbols.h deleted file mode 100644 index f5a48e05ac..0000000000 --- a/src/common/symbols.h +++ /dev/null @@ -1,30 +0,0 @@ -// Copyright 2014 Citra Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#pragma once - -#include -#include -#include -#include "common/common_types.h" - -struct TSymbol { - u32 address = 0; - std::string name; - u32 size = 0; - u32 type = 0; -}; - -typedef std::map TSymbolsMap; -typedef std::pair TSymbolsPair; - -namespace Symbols { -bool HasSymbol(u32 address); - -void Add(u32 address, const std::string& name, u32 size, u32 type); -TSymbol GetSymbol(u32 address); -const std::string GetName(u32 address); -void Remove(u32 address); -void Clear(); -} diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index a2866fdd84..190dc985a9 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -1,6 +1,5 @@ set(SRCS arm/disassembler/arm_disasm.cpp - arm/disassembler/load_symbol_map.cpp arm/dynarmic/arm_dynarmic.cpp arm/dynarmic/arm_dynarmic_cp15.cpp arm/dyncom/arm_dyncom.cpp @@ -180,7 +179,6 @@ set(SRCS set(HEADERS arm/arm_interface.h arm/disassembler/arm_disasm.h - arm/disassembler/load_symbol_map.h arm/dynarmic/arm_dynarmic.h arm/dynarmic/arm_dynarmic_cp15.h arm/dyncom/arm_dyncom.h diff --git a/src/core/arm/disassembler/load_symbol_map.cpp b/src/core/arm/disassembler/load_symbol_map.cpp deleted file mode 100644 index 6863c103a0..0000000000 --- a/src/core/arm/disassembler/load_symbol_map.cpp +++ /dev/null @@ -1,31 +0,0 @@ -// Copyright 2014 Citra Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#include -#include -#include -#include "common/file_util.h" -#include "common/symbols.h" -#include "core/arm/disassembler/load_symbol_map.h" - -/* - * Loads a symbol map file for use with the disassembler - * @param filename String filename path of symbol map file - */ -void LoadSymbolMap(std::string filename) { - std::ifstream infile(filename); - - std::string address_str, function_name, line; - u32 size; - - while (std::getline(infile, line)) { - std::istringstream iss(line); - if (!(iss >> address_str >> size >> function_name)) { - break; // Error parsing - } - u32 address = std::stoul(address_str, nullptr, 16); - - Symbols::Add(address, function_name, size, 2); - } -} diff --git a/src/core/arm/disassembler/load_symbol_map.h b/src/core/arm/disassembler/load_symbol_map.h deleted file mode 100644 index d28c551c3b..0000000000 --- a/src/core/arm/disassembler/load_symbol_map.h +++ /dev/null @@ -1,13 +0,0 @@ -// Copyright 2014 Citra Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#pragma once - -#include - -/* - * Loads a symbol map file for use with the disassembler - * @param filename String filename path of symbol map file - */ -void LoadSymbolMap(std::string filename); From f0a582b218f83f19d98c8df0e6130a32f022368b Mon Sep 17 00:00:00 2001 From: Yuri Kunde Schlesner Date: Sun, 7 May 2017 15:15:37 -0700 Subject: [PATCH 5/6] Dyncom: Tweak types and log formatting --- src/core/arm/dyncom/arm_dyncom_dec.cpp | 2 +- src/core/arm/dyncom/arm_dyncom_dec.h | 2 +- src/core/arm/dyncom/arm_dyncom_interpreter.cpp | 14 ++++++++------ 3 files changed, 10 insertions(+), 8 deletions(-) diff --git a/src/core/arm/dyncom/arm_dyncom_dec.cpp b/src/core/arm/dyncom/arm_dyncom_dec.cpp index 64dcaae086..dcfcd6561c 100644 --- a/src/core/arm/dyncom/arm_dyncom_dec.cpp +++ b/src/core/arm/dyncom/arm_dyncom_dec.cpp @@ -415,7 +415,7 @@ const InstructionSetEncodingItem arm_exclusion_code[] = { }; // clang-format on -ARMDecodeStatus DecodeARMInstruction(u32 instr, s32* idx) { +ARMDecodeStatus DecodeARMInstruction(u32 instr, int* idx) { int n = 0; int base = 0; int instr_slots = sizeof(arm_instruction) / sizeof(InstructionSetEncodingItem); diff --git a/src/core/arm/dyncom/arm_dyncom_dec.h b/src/core/arm/dyncom/arm_dyncom_dec.h index 2fb7ac37c5..1dcf7ecd14 100644 --- a/src/core/arm/dyncom/arm_dyncom_dec.h +++ b/src/core/arm/dyncom/arm_dyncom_dec.h @@ -8,7 +8,7 @@ enum class ARMDecodeStatus { SUCCESS, FAILURE }; -ARMDecodeStatus DecodeARMInstruction(u32 instr, s32* idx); +ARMDecodeStatus DecodeARMInstruction(u32 instr, int* idx); struct InstructionSetEncodingItem { const char* name; diff --git a/src/core/arm/dyncom/arm_dyncom_interpreter.cpp b/src/core/arm/dyncom/arm_dyncom_interpreter.cpp index 273bc81678..8073bb7050 100644 --- a/src/core/arm/dyncom/arm_dyncom_interpreter.cpp +++ b/src/core/arm/dyncom/arm_dyncom_interpreter.cpp @@ -5,6 +5,7 @@ #define CITRA_IGNORE_EXIT(x) #include +#include #include #include "common/common_types.h" #include "common/logging/log.h" @@ -808,8 +809,8 @@ MICROPROFILE_DEFINE(DynCom_Decode, "DynCom", "Decode", MP_RGB(255, 64, 64)); static unsigned int InterpreterTranslateInstruction(const ARMul_State* cpu, const u32 phys_addr, ARM_INST_PTR& inst_base) { - unsigned int inst_size = 4; - unsigned int inst = Memory::Read32(phys_addr & 0xFFFFFFFC); + u32 inst_size = 4; + u32 inst = Memory::Read32(phys_addr & 0xFFFFFFFC); // If we are in Thumb mode, we'll translate one Thumb instruction to the corresponding ARM // instruction @@ -828,10 +829,11 @@ static unsigned int InterpreterTranslateInstruction(const ARMul_State* cpu, cons int idx; if (DecodeARMInstruction(inst, &idx) == ARMDecodeStatus::FAILURE) { std::string disasm = ARM_Disasm::Disassemble(phys_addr, inst); - LOG_ERROR(Core_ARM11, "Decode failure.\tPC : [0x%x]\tInstruction : %s [%x]", phys_addr, - disasm.c_str(), inst); - LOG_ERROR(Core_ARM11, "cpsr=0x%x, cpu->TFlag=%d, r15=0x%x", cpu->Cpsr, cpu->TFlag, - cpu->Reg[15]); + LOG_ERROR(Core_ARM11, + "Decode failure.\tPC: [0x%08" PRIX32 "]\tInstruction: %s [%08" PRIX32 "]", + phys_addr, disasm.c_str(), inst); + LOG_ERROR(Core_ARM11, "cpsr=0x%" PRIX32 ", cpu->TFlag=%d, r15=0x%08" PRIX32, cpu->Cpsr, + cpu->TFlag, cpu->Reg[15]); CITRA_IGNORE_EXIT(-1); } inst_base = arm_instruction_trans[idx](inst, idx); From d97b9775409e05ffba8a78632bd41863570e9830 Mon Sep 17 00:00:00 2001 From: Yuri Kunde Schlesner Date: Sun, 7 May 2017 15:21:35 -0700 Subject: [PATCH 6/6] Dyncom: Remove disassembler code Had licensing issue around it, in addition to several bugs. Closes #1632, #1280 --- src/core/CMakeLists.txt | 2 - src/core/arm/disassembler/arm_disasm.cpp | 1344 ----------------- src/core/arm/disassembler/arm_disasm.h | 238 --- .../arm/dyncom/arm_dyncom_interpreter.cpp | 7 +- 4 files changed, 2 insertions(+), 1589 deletions(-) delete mode 100644 src/core/arm/disassembler/arm_disasm.cpp delete mode 100644 src/core/arm/disassembler/arm_disasm.h diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 190dc985a9..e404063f0b 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -1,5 +1,4 @@ set(SRCS - arm/disassembler/arm_disasm.cpp arm/dynarmic/arm_dynarmic.cpp arm/dynarmic/arm_dynarmic_cp15.cpp arm/dyncom/arm_dyncom.cpp @@ -178,7 +177,6 @@ set(SRCS set(HEADERS arm/arm_interface.h - arm/disassembler/arm_disasm.h arm/dynarmic/arm_dynarmic.h arm/dynarmic/arm_dynarmic_cp15.h arm/dyncom/arm_dyncom.h diff --git a/src/core/arm/disassembler/arm_disasm.cpp b/src/core/arm/disassembler/arm_disasm.cpp deleted file mode 100644 index 05d6ed1fb9..0000000000 --- a/src/core/arm/disassembler/arm_disasm.cpp +++ /dev/null @@ -1,1344 +0,0 @@ -// Copyright 2006 The Android Open Source Project - -#include -#include -#include "common/common_types.h" -#include "common/string_util.h" -#include "core/arm/disassembler/arm_disasm.h" -#include "core/arm/skyeye_common/armsupp.h" - -static const char* cond_names[] = {"eq", "ne", "cs", "cc", "mi", "pl", "vs", "vc", - "hi", "ls", "ge", "lt", "gt", "le", "", "RESERVED"}; - -static const char* opcode_names[] = { - "invalid", "undefined", "adc", "add", "and", "b", "bl", "bic", - "bkpt", "blx", "bx", "cdp", "clrex", "clz", "cmn", "cmp", - "eor", "ldc", "ldm", "ldr", "ldrb", "ldrbt", "ldrex", "ldrexb", - "ldrexd", "ldrexh", "ldrh", "ldrsb", "ldrsh", "ldrt", "mcr", "mla", - "mov", "mrc", "mrs", "msr", "mul", "mvn", "nop", "orr", - "pkh", "pld", "qadd16", "qadd8", "qasx", "qsax", "qsub16", "qsub8", - "rev", "rev16", "revsh", "rsb", "rsc", "sadd16", "sadd8", "sasx", - "sbc", "sel", "sev", "shadd16", "shadd8", "shasx", "shsax", "shsub16", - "shsub8", "smlad", "smlal", "smlald", "smlsd", "smlsld", "smmla", "smmls", - "smmul", "smuad", "smull", "smusd", "ssat", "ssat16", "ssax", "ssub16", - "ssub8", "stc", "stm", "str", "strb", "strbt", "strex", "strexb", - "strexd", "strexh", "strh", "strt", "sub", "swi", "swp", "swpb", - "sxtab", "sxtab16", "sxtah", "sxtb", "sxtb16", "sxth", "teq", "tst", - "uadd16", "uadd8", "uasx", "uhadd16", "uhadd8", "uhasx", "uhsax", "uhsub16", - "uhsub8", "umlal", "umull", "uqadd16", "uqadd8", "uqasx", "uqsax", "uqsub16", - "uqsub8", "usad8", "usada8", "usat", "usat16", "usax", "usub16", "usub8", - "uxtab", "uxtab16", "uxtah", "uxtb", "uxtb16", "uxth", "wfe", "wfi", - "yield", - - "undefined", "adc", "add", "and", "asr", "b", "bic", "bkpt", - "bl", "blx", "bx", "cmn", "cmp", "eor", "ldmia", "ldr", - "ldrb", "ldrh", "ldrsb", "ldrsh", "lsl", "lsr", "mov", "mul", - "mvn", "neg", "orr", "pop", "push", "ror", "sbc", "stmia", - "str", "strb", "strh", "sub", "swi", "tst", - - nullptr}; - -// Indexed by the shift type (bits 6-5) -static const char* shift_names[] = {"LSL", "LSR", "ASR", "ROR"}; - -static const char* cond_to_str(u32 cond) { - return cond_names[cond]; -} - -std::string ARM_Disasm::Disassemble(u32 addr, u32 insn) { - Opcode opcode = Decode(insn); - switch (opcode) { - case OP_INVALID: - return "Invalid"; - case OP_UNDEFINED: - return "Undefined"; - case OP_ADC: - case OP_ADD: - case OP_AND: - case OP_BIC: - case OP_CMN: - case OP_CMP: - case OP_EOR: - case OP_MOV: - case OP_MVN: - case OP_ORR: - case OP_RSB: - case OP_RSC: - case OP_SBC: - case OP_SUB: - case OP_TEQ: - case OP_TST: - return DisassembleALU(opcode, insn); - case OP_B: - case OP_BL: - return DisassembleBranch(addr, opcode, insn); - case OP_BKPT: - return DisassembleBKPT(insn); - case OP_BLX: - // not supported yet - break; - case OP_BX: - return DisassembleBX(insn); - case OP_CDP: - return "cdp"; - case OP_CLREX: - return "clrex"; - case OP_CLZ: - return DisassembleCLZ(insn); - case OP_LDC: - return "ldc"; - case OP_LDM: - case OP_STM: - return DisassembleMemblock(opcode, insn); - case OP_LDR: - case OP_LDRB: - case OP_LDRBT: - case OP_LDRT: - case OP_STR: - case OP_STRB: - case OP_STRBT: - case OP_STRT: - return DisassembleMem(insn); - case OP_LDREX: - case OP_LDREXB: - case OP_LDREXD: - case OP_LDREXH: - case OP_STREX: - case OP_STREXB: - case OP_STREXD: - case OP_STREXH: - return DisassembleREX(opcode, insn); - case OP_LDRH: - case OP_LDRSB: - case OP_LDRSH: - case OP_STRH: - return DisassembleMemHalf(insn); - case OP_MCR: - case OP_MRC: - return DisassembleMCR(opcode, insn); - case OP_MLA: - return DisassembleMLA(opcode, insn); - case OP_MRS: - return DisassembleMRS(insn); - case OP_MSR: - return DisassembleMSR(insn); - case OP_MUL: - return DisassembleMUL(opcode, insn); - case OP_NOP: - case OP_SEV: - case OP_WFE: - case OP_WFI: - case OP_YIELD: - return DisassembleNoOperands(opcode, insn); - case OP_PKH: - return DisassemblePKH(insn); - case OP_PLD: - return DisassemblePLD(insn); - case OP_QADD16: - case OP_QADD8: - case OP_QASX: - case OP_QSAX: - case OP_QSUB16: - case OP_QSUB8: - case OP_SADD16: - case OP_SADD8: - case OP_SASX: - case OP_SHADD16: - case OP_SHADD8: - case OP_SHASX: - case OP_SHSAX: - case OP_SHSUB16: - case OP_SHSUB8: - case OP_SSAX: - case OP_SSUB16: - case OP_SSUB8: - case OP_UADD16: - case OP_UADD8: - case OP_UASX: - case OP_UHADD16: - case OP_UHADD8: - case OP_UHASX: - case OP_UHSAX: - case OP_UHSUB16: - case OP_UHSUB8: - case OP_UQADD16: - case OP_UQADD8: - case OP_UQASX: - case OP_UQSAX: - case OP_UQSUB16: - case OP_UQSUB8: - case OP_USAX: - case OP_USUB16: - case OP_USUB8: - return DisassembleParallelAddSub(opcode, insn); - case OP_REV: - case OP_REV16: - case OP_REVSH: - return DisassembleREV(opcode, insn); - case OP_SEL: - return DisassembleSEL(insn); - case OP_SMLAD: - case OP_SMLALD: - case OP_SMLSD: - case OP_SMLSLD: - case OP_SMMLA: - case OP_SMMLS: - case OP_SMMUL: - case OP_SMUAD: - case OP_SMUSD: - case OP_USAD8: - case OP_USADA8: - return DisassembleMediaMulDiv(opcode, insn); - case OP_SSAT: - case OP_SSAT16: - case OP_USAT: - case OP_USAT16: - return DisassembleSAT(opcode, insn); - case OP_STC: - return "stc"; - case OP_SWI: - return DisassembleSWI(insn); - case OP_SWP: - case OP_SWPB: - return DisassembleSWP(opcode, insn); - case OP_SXTAB: - case OP_SXTAB16: - case OP_SXTAH: - case OP_SXTB: - case OP_SXTB16: - case OP_SXTH: - case OP_UXTAB: - case OP_UXTAB16: - case OP_UXTAH: - case OP_UXTB: - case OP_UXTB16: - case OP_UXTH: - return DisassembleXT(opcode, insn); - case OP_UMLAL: - case OP_UMULL: - case OP_SMLAL: - case OP_SMULL: - return DisassembleUMLAL(opcode, insn); - default: - return "Error"; - } - return nullptr; -} - -std::string ARM_Disasm::DisassembleALU(Opcode opcode, u32 insn) { - static const u8 kNoOperand1 = 1; - static const u8 kNoDest = 2; - static const u8 kNoSbit = 4; - - std::string rn_str; - std::string rd_str; - - u8 flags = 0; - u8 cond = (insn >> 28) & 0xf; - u8 is_immed = (insn >> 25) & 0x1; - u8 bit_s = (insn >> 20) & 1; - u8 rn = (insn >> 16) & 0xf; - u8 rd = (insn >> 12) & 0xf; - u8 immed = insn & 0xff; - - const char* opname = opcode_names[opcode]; - switch (opcode) { - case OP_CMN: - case OP_CMP: - case OP_TEQ: - case OP_TST: - flags = kNoDest | kNoSbit; - break; - case OP_MOV: - case OP_MVN: - flags = kNoOperand1; - break; - default: - break; - } - - // The "mov" instruction ignores the first operand (rn). - rn_str[0] = 0; - if ((flags & kNoOperand1) == 0) { - rn_str = Common::StringFromFormat("r%d, ", rn); - } - - // The following instructions do not write the result register (rd): - // tst, teq, cmp, cmn. - rd_str[0] = 0; - if ((flags & kNoDest) == 0) { - rd_str = Common::StringFromFormat("r%d, ", rd); - } - - const char* sbit_str = ""; - if (bit_s && !(flags & kNoSbit)) - sbit_str = "s"; - - if (is_immed) { - return Common::StringFromFormat("%s%s%s\t%s%s#%u ; 0x%x", opname, cond_to_str(cond), - sbit_str, rd_str.c_str(), rn_str.c_str(), immed, immed); - } - - u8 shift_is_reg = (insn >> 4) & 1; - u8 rotate = (insn >> 8) & 0xf; - u8 rm = insn & 0xf; - u8 shift_type = (insn >> 5) & 0x3; - u8 rs = (insn >> 8) & 0xf; - u8 shift_amount = (insn >> 7) & 0x1f; - u32 rotated_val = immed; - u8 rotate2 = rotate << 1; - rotated_val = (rotated_val >> rotate2) | (rotated_val << (32 - rotate2)); - - if (!shift_is_reg && shift_type == 0 && shift_amount == 0) { - return Common::StringFromFormat("%s%s%s\t%s%sr%d", opname, cond_to_str(cond), sbit_str, - rd_str.c_str(), rn_str.c_str(), rm); - } - - const char* shift_name = shift_names[shift_type]; - if (shift_is_reg) { - return Common::StringFromFormat("%s%s%s\t%s%sr%d, %s r%d", opname, cond_to_str(cond), - sbit_str, rd_str.c_str(), rn_str.c_str(), rm, shift_name, - rs); - } - if (shift_amount == 0) { - if (shift_type == 3) { - return Common::StringFromFormat("%s%s%s\t%s%sr%d, RRX", opname, cond_to_str(cond), - sbit_str, rd_str.c_str(), rn_str.c_str(), rm); - } - shift_amount = 32; - } - return Common::StringFromFormat("%s%s%s\t%s%sr%d, %s #%u", opname, cond_to_str(cond), sbit_str, - rd_str.c_str(), rn_str.c_str(), rm, shift_name, shift_amount); -} - -std::string ARM_Disasm::DisassembleBranch(u32 addr, Opcode opcode, u32 insn) { - u8 cond = (insn >> 28) & 0xf; - u32 offset = insn & 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; - addr += offset; - const char* opname = opcode_names[opcode]; - return Common::StringFromFormat("%s%s\t0x%x", opname, cond_to_str(cond), addr); -} - -std::string ARM_Disasm::DisassembleBX(u32 insn) { - u8 cond = (insn >> 28) & 0xf; - u8 rn = insn & 0xf; - return Common::StringFromFormat("bx%s\tr%d", cond_to_str(cond), rn); -} - -std::string ARM_Disasm::DisassembleBKPT(u32 insn) { - u8 cond = (insn >> 28) & 0xf; - u32 immed = (((insn >> 8) & 0xfff) << 4) | (insn & 0xf); - return Common::StringFromFormat("bkpt%s\t#%d", cond_to_str(cond), immed); -} - -std::string ARM_Disasm::DisassembleCLZ(u32 insn) { - u8 cond = (insn >> 28) & 0xf; - u8 rd = (insn >> 12) & 0xf; - u8 rm = insn & 0xf; - return Common::StringFromFormat("clz%s\tr%d, r%d", cond_to_str(cond), rd, rm); -} - -std::string ARM_Disasm::DisassembleMediaMulDiv(Opcode opcode, u32 insn) { - u32 cond = BITS(insn, 28, 31); - u32 rd = BITS(insn, 16, 19); - u32 ra = BITS(insn, 12, 15); - u32 rm = BITS(insn, 8, 11); - u32 m = BIT(insn, 5); - u32 rn = BITS(insn, 0, 3); - - std::string cross = ""; - if (m) { - if (opcode == OP_SMMLA || opcode == OP_SMMUL || opcode == OP_SMMLS) - cross = "r"; - else - cross = "x"; - } - - std::string ext_reg = ""; - std::unordered_set> with_ext_reg = {OP_SMLAD, OP_SMLSD, OP_SMMLA, - OP_SMMLS, OP_USADA8}; - if (with_ext_reg.find(opcode) != with_ext_reg.end()) - ext_reg = Common::StringFromFormat(", r%u", ra); - - std::string rd_low = ""; - if (opcode == OP_SMLALD || opcode == OP_SMLSLD) - rd_low = Common::StringFromFormat("r%u, ", ra); - - return Common::StringFromFormat("%s%s%s\t%sr%u, r%u, r%u%s", opcode_names[opcode], - cross.c_str(), cond_to_str(cond), rd_low.c_str(), rd, rn, rm, - ext_reg.c_str()); -} - -std::string ARM_Disasm::DisassembleMemblock(Opcode opcode, u32 insn) { - std::string tmp_list; - - u8 cond = (insn >> 28) & 0xf; - u8 write_back = (insn >> 21) & 0x1; - u8 bit_s = (insn >> 22) & 0x1; - u8 is_up = (insn >> 23) & 0x1; - u8 is_pre = (insn >> 24) & 0x1; - u8 rn = (insn >> 16) & 0xf; - u16 reg_list = insn & 0xffff; - - const char* opname = opcode_names[opcode]; - - const char* bang = ""; - if (write_back) - bang = "!"; - - const char* carret = ""; - if (bit_s) - carret = "^"; - - const char* comma = ""; - tmp_list[0] = 0; - for (int ii = 0; ii < 16; ++ii) { - if (reg_list & (1 << ii)) { - tmp_list += Common::StringFromFormat("%sr%d", comma, ii); - comma = ","; - } - } - - const char* addr_mode = ""; - if (is_pre) { - if (is_up) { - addr_mode = "ib"; - } else { - addr_mode = "db"; - } - } else { - if (is_up) { - addr_mode = "ia"; - } else { - addr_mode = "da"; - } - } - - return Common::StringFromFormat("%s%s%s\tr%d%s, {%s}%s", opname, cond_to_str(cond), addr_mode, - rn, bang, tmp_list.c_str(), carret); -} - -std::string ARM_Disasm::DisassembleMem(u32 insn) { - u8 cond = (insn >> 28) & 0xf; - u8 is_reg = (insn >> 25) & 0x1; - u8 is_load = (insn >> 20) & 0x1; - u8 write_back = (insn >> 21) & 0x1; - u8 is_byte = (insn >> 22) & 0x1; - u8 is_up = (insn >> 23) & 0x1; - u8 is_pre = (insn >> 24) & 0x1; - u8 rn = (insn >> 16) & 0xf; - u8 rd = (insn >> 12) & 0xf; - u16 offset = insn & 0xfff; - - const char* opname = "ldr"; - if (!is_load) - opname = "str"; - - const char* bang = ""; - if (write_back) - bang = "!"; - - const char* minus = ""; - if (is_up == 0) - minus = "-"; - - const char* byte = ""; - if (is_byte) - byte = "b"; - - if (is_reg == 0) { - if (is_pre) { - if (offset == 0) { - return Common::StringFromFormat("%s%s%s\tr%d, [r%d]", opname, cond_to_str(cond), - byte, rd, rn); - } else { - return Common::StringFromFormat("%s%s%s\tr%d, [r%d, #%s%u]%s", opname, - cond_to_str(cond), byte, rd, rn, minus, offset, - bang); - } - } else { - const char* transfer = ""; - if (write_back) - transfer = "t"; - - return Common::StringFromFormat("%s%s%s%s\tr%d, [r%d], #%s%u", opname, - cond_to_str(cond), byte, transfer, rd, rn, minus, - offset); - } - } - - u8 rm = insn & 0xf; - u8 shift_type = (insn >> 5) & 0x3; - u8 shift_amount = (insn >> 7) & 0x1f; - - const char* shift_name = shift_names[shift_type]; - - if (is_pre) { - if (shift_amount == 0) { - if (shift_type == 0) { - return Common::StringFromFormat("%s%s%s\tr%d, [r%d, %sr%d]%s", opname, - cond_to_str(cond), byte, rd, rn, minus, rm, bang); - } - if (shift_type == 3) { - return Common::StringFromFormat("%s%s%s\tr%d, [r%d, %sr%d, RRX]%s", opname, - cond_to_str(cond), byte, rd, rn, minus, rm, bang); - } - shift_amount = 32; - } - return Common::StringFromFormat("%s%s%s\tr%d, [r%d, %sr%d, %s #%u]%s", opname, - cond_to_str(cond), byte, rd, rn, minus, rm, shift_name, - shift_amount, bang); - } - - const char* transfer = ""; - if (write_back) - transfer = "t"; - - if (shift_amount == 0) { - if (shift_type == 0) { - return Common::StringFromFormat("%s%s%s%s\tr%d, [r%d], %sr%d", opname, - cond_to_str(cond), byte, transfer, rd, rn, minus, rm); - } - if (shift_type == 3) { - return Common::StringFromFormat("%s%s%s%s\tr%d, [r%d], %sr%d, RRX", opname, - cond_to_str(cond), byte, transfer, rd, rn, minus, rm); - } - shift_amount = 32; - } - - return Common::StringFromFormat("%s%s%s%s\tr%d, [r%d], %sr%d, %s #%u", opname, - cond_to_str(cond), byte, transfer, rd, rn, minus, rm, - shift_name, shift_amount); -} - -std::string ARM_Disasm::DisassembleMemHalf(u32 insn) { - u8 cond = (insn >> 28) & 0xf; - u8 is_load = (insn >> 20) & 0x1; - u8 write_back = (insn >> 21) & 0x1; - u8 is_immed = (insn >> 22) & 0x1; - u8 is_up = (insn >> 23) & 0x1; - u8 is_pre = (insn >> 24) & 0x1; - u8 rn = (insn >> 16) & 0xf; - u8 rd = (insn >> 12) & 0xf; - u8 bits_65 = (insn >> 5) & 0x3; - u8 rm = insn & 0xf; - u8 offset = (((insn >> 8) & 0xf) << 4) | (insn & 0xf); - - const char* opname = "ldr"; - if (is_load == 0) - opname = "str"; - - const char* width = ""; - if (bits_65 == 1) - width = "h"; - else if (bits_65 == 2) - width = "sb"; - else - width = "sh"; - - const char* bang = ""; - if (write_back) - bang = "!"; - const char* minus = ""; - if (is_up == 0) - minus = "-"; - - if (is_immed) { - if (is_pre) { - if (offset == 0) { - return Common::StringFromFormat("%s%s%s\tr%d, [r%d]", opname, cond_to_str(cond), - width, rd, rn); - } else { - return Common::StringFromFormat("%s%s%s\tr%d, [r%d, #%s%u]%s", opname, - cond_to_str(cond), width, rd, rn, minus, offset, - bang); - } - } else { - return Common::StringFromFormat("%s%s%s\tr%d, [r%d], #%s%u", opname, cond_to_str(cond), - width, rd, rn, minus, offset); - } - } - - if (is_pre) { - return Common::StringFromFormat("%s%s%s\tr%d, [r%d, %sr%d]%s", opname, cond_to_str(cond), - width, rd, rn, minus, rm, bang); - } else { - return Common::StringFromFormat("%s%s%s\tr%d, [r%d], %sr%d", opname, cond_to_str(cond), - width, rd, rn, minus, rm); - } -} - -std::string ARM_Disasm::DisassembleMCR(Opcode opcode, u32 insn) { - u8 cond = (insn >> 28) & 0xf; - u8 crn = (insn >> 16) & 0xf; - u8 crd = (insn >> 12) & 0xf; - u8 cpnum = (insn >> 8) & 0xf; - u8 opcode2 = (insn >> 5) & 0x7; - u8 crm = insn & 0xf; - - const char* opname = opcode_names[opcode]; - return Common::StringFromFormat("%s%s\t%d, 0, r%d, cr%d, cr%d, {%d}", opname, cond_to_str(cond), - cpnum, crd, crn, crm, opcode2); -} - -std::string ARM_Disasm::DisassembleMLA(Opcode opcode, u32 insn) { - u8 cond = (insn >> 28) & 0xf; - u8 rd = (insn >> 16) & 0xf; - u8 rn = (insn >> 12) & 0xf; - u8 rs = (insn >> 8) & 0xf; - u8 rm = insn & 0xf; - u8 bit_s = (insn >> 20) & 1; - - const char* opname = opcode_names[opcode]; - return Common::StringFromFormat("%s%s%s\tr%d, r%d, r%d, r%d", opname, cond_to_str(cond), - bit_s ? "s" : "", rd, rm, rs, rn); -} - -std::string ARM_Disasm::DisassembleUMLAL(Opcode opcode, u32 insn) { - u8 cond = (insn >> 28) & 0xf; - u8 rdhi = (insn >> 16) & 0xf; - u8 rdlo = (insn >> 12) & 0xf; - u8 rs = (insn >> 8) & 0xf; - u8 rm = insn & 0xf; - u8 bit_s = (insn >> 20) & 1; - - const char* opname = opcode_names[opcode]; - return Common::StringFromFormat("%s%s%s\tr%d, r%d, r%d, r%d", opname, cond_to_str(cond), - bit_s ? "s" : "", rdlo, rdhi, rm, rs); -} - -std::string ARM_Disasm::DisassembleMUL(Opcode opcode, u32 insn) { - u8 cond = (insn >> 28) & 0xf; - u8 rd = (insn >> 16) & 0xf; - u8 rs = (insn >> 8) & 0xf; - u8 rm = insn & 0xf; - u8 bit_s = (insn >> 20) & 1; - - const char* opname = opcode_names[opcode]; - return Common::StringFromFormat("%s%s%s\tr%d, r%d, r%d", opname, cond_to_str(cond), - bit_s ? "s" : "", rd, rm, rs); -} - -std::string ARM_Disasm::DisassembleMRS(u32 insn) { - u8 cond = (insn >> 28) & 0xf; - u8 rd = (insn >> 12) & 0xf; - u8 ps = (insn >> 22) & 1; - - return Common::StringFromFormat("mrs%s\tr%d, %s", cond_to_str(cond), rd, ps ? "spsr" : "cpsr"); -} - -std::string ARM_Disasm::DisassembleMSR(u32 insn) { - char flags[8]; - int flag_index = 0; - u8 cond = (insn >> 28) & 0xf; - u8 is_immed = (insn >> 25) & 0x1; - u8 pd = (insn >> 22) & 1; - u8 mask = (insn >> 16) & 0xf; - - if (mask & 1) - flags[flag_index++] = 'c'; - if (mask & 2) - flags[flag_index++] = 'x'; - if (mask & 4) - flags[flag_index++] = 's'; - if (mask & 8) - flags[flag_index++] = 'f'; - flags[flag_index] = 0; - - if (is_immed) { - u32 immed = insn & 0xff; - u8 rotate = (insn >> 8) & 0xf; - u8 rotate2 = rotate << 1; - u32 rotated_val = (immed >> rotate2) | (immed << (32 - rotate2)); - return Common::StringFromFormat("msr%s\t%s_%s, #0x%x", cond_to_str(cond), - pd ? "spsr" : "cpsr", flags, rotated_val); - } - - u8 rm = insn & 0xf; - - return Common::StringFromFormat("msr%s\t%s_%s, r%d", cond_to_str(cond), pd ? "spsr" : "cpsr", - flags, rm); -} - -std::string ARM_Disasm::DisassembleNoOperands(Opcode opcode, u32 insn) { - u32 cond = BITS(insn, 28, 31); - return Common::StringFromFormat("%s%s", opcode_names[opcode], cond_to_str(cond)); -} - -std::string ARM_Disasm::DisassembleParallelAddSub(Opcode opcode, u32 insn) { - u32 cond = BITS(insn, 28, 31); - u32 rn = BITS(insn, 16, 19); - u32 rd = BITS(insn, 12, 15); - u32 rm = BITS(insn, 0, 3); - - return Common::StringFromFormat("%s%s\tr%u, r%u, r%u", opcode_names[opcode], cond_to_str(cond), - rd, rn, rm); -} - -std::string ARM_Disasm::DisassemblePKH(u32 insn) { - u32 cond = BITS(insn, 28, 31); - u32 rn = BITS(insn, 16, 19); - u32 rd = BITS(insn, 12, 15); - u32 imm5 = BITS(insn, 7, 11); - u32 tb = BIT(insn, 6); - u32 rm = BITS(insn, 0, 3); - - std::string suffix = tb ? "tb" : "bt"; - std::string shift = ""; - - if (tb && imm5 == 0) - imm5 = 32; - - if (imm5 > 0) { - shift = tb ? ", ASR" : ", LSL"; - shift += " #" + std::to_string(imm5); - } - - return Common::StringFromFormat("pkh%s%s\tr%u, r%u, r%u%s", suffix.c_str(), cond_to_str(cond), - rd, rn, rm, shift.c_str()); -} - -std::string ARM_Disasm::DisassemblePLD(u32 insn) { - u8 is_reg = (insn >> 25) & 0x1; - u8 is_up = (insn >> 23) & 0x1; - u8 rn = (insn >> 16) & 0xf; - - const char* minus = ""; - if (is_up == 0) - minus = "-"; - - if (is_reg) { - u8 rm = insn & 0xf; - return Common::StringFromFormat("pld\t[r%d, %sr%d]", rn, minus, rm); - } - - u16 offset = insn & 0xfff; - if (offset == 0) { - return Common::StringFromFormat("pld\t[r%d]", rn); - } else { - return Common::StringFromFormat("pld\t[r%d, #%s%u]", rn, minus, offset); - } -} - -std::string ARM_Disasm::DisassembleREV(Opcode opcode, u32 insn) { - u32 cond = BITS(insn, 28, 31); - u32 rd = BITS(insn, 12, 15); - u32 rm = BITS(insn, 0, 3); - - return Common::StringFromFormat("%s%s\tr%u, r%u", opcode_names[opcode], cond_to_str(cond), rd, - rm); -} - -std::string ARM_Disasm::DisassembleREX(Opcode opcode, u32 insn) { - u32 rn = BITS(insn, 16, 19); - u32 rd = BITS(insn, 12, 15); - u32 rt = BITS(insn, 0, 3); - u32 cond = BITS(insn, 28, 31); - - switch (opcode) { - case OP_STREX: - case OP_STREXB: - case OP_STREXH: - return Common::StringFromFormat("%s%s\tr%d, r%d, [r%d]", opcode_names[opcode], - cond_to_str(cond), rd, rt, rn); - case OP_STREXD: - return Common::StringFromFormat("%s%s\tr%d, r%d, r%d, [r%d]", opcode_names[opcode], - cond_to_str(cond), rd, rt, rt + 1, rn); - - // for LDREX instructions, rd corresponds to Rt from reference manual - case OP_LDREX: - case OP_LDREXB: - case OP_LDREXH: - return Common::StringFromFormat("%s%s\tr%d, [r%d]", opcode_names[opcode], cond_to_str(cond), - rd, rn); - case OP_LDREXD: - return Common::StringFromFormat("%s%s\tr%d, r%d, [r%d]", opcode_names[opcode], - cond_to_str(cond), rd, rd + 1, rn); - default: - return opcode_names[OP_UNDEFINED]; - } -} - -std::string ARM_Disasm::DisassembleSAT(Opcode opcode, u32 insn) { - u32 cond = BITS(insn, 28, 31); - u32 sat_imm = BITS(insn, 16, 20); - u32 rd = BITS(insn, 12, 15); - u32 imm5 = BITS(insn, 7, 11); - u32 sh = BIT(insn, 6); - u32 rn = BITS(insn, 0, 3); - - std::string shift_part = ""; - bool opcode_has_shift = (opcode == OP_SSAT) || (opcode == OP_USAT); - if (opcode_has_shift && !(sh == 0 && imm5 == 0)) { - if (sh == 0) - shift_part += ", LSL #"; - else - shift_part += ", ASR #"; - - if (imm5 == 0) - imm5 = 32; - shift_part += std::to_string(imm5); - } - - if (opcode == OP_SSAT || opcode == OP_SSAT16) - sat_imm++; - - return Common::StringFromFormat("%s%s\tr%u, #%u, r%u%s", opcode_names[opcode], - cond_to_str(cond), rd, sat_imm, rn, shift_part.c_str()); -} - -std::string ARM_Disasm::DisassembleSEL(u32 insn) { - u32 cond = BITS(insn, 28, 31); - u32 rn = BITS(insn, 16, 19); - u32 rd = BITS(insn, 12, 15); - u32 rm = BITS(insn, 0, 3); - - return Common::StringFromFormat("%s%s\tr%u, r%u, r%u", opcode_names[OP_SEL], cond_to_str(cond), - rd, rn, rm); -} - -std::string ARM_Disasm::DisassembleSWI(u32 insn) { - u8 cond = (insn >> 28) & 0xf; - u32 sysnum = insn & 0x00ffffff; - - return Common::StringFromFormat("swi%s 0x%x", cond_to_str(cond), sysnum); -} - -std::string ARM_Disasm::DisassembleSWP(Opcode opcode, u32 insn) { - u8 cond = (insn >> 28) & 0xf; - u8 rn = (insn >> 16) & 0xf; - u8 rd = (insn >> 12) & 0xf; - u8 rm = insn & 0xf; - - const char* opname = opcode_names[opcode]; - return Common::StringFromFormat("%s%s\tr%d, r%d, [r%d]", opname, cond_to_str(cond), rd, rm, rn); -} - -std::string ARM_Disasm::DisassembleXT(Opcode opcode, u32 insn) { - u32 cond = BITS(insn, 28, 31); - u32 rn = BITS(insn, 16, 19); - u32 rd = BITS(insn, 12, 15); - u32 rotate = BITS(insn, 10, 11); - u32 rm = BITS(insn, 0, 3); - - std::string rn_part = ""; - static std::unordered_set> extend_with_add = { - OP_SXTAB, OP_SXTAB16, OP_SXTAH, OP_UXTAB, OP_UXTAB16, OP_UXTAH}; - if (extend_with_add.find(opcode) != extend_with_add.end()) - rn_part = ", r" + std::to_string(rn); - - std::string rotate_part = ""; - if (rotate != 0) - rotate_part = ", ROR #" + std::to_string(rotate << 3); - - return Common::StringFromFormat("%s%s\tr%u%s, r%u%s", opcode_names[opcode], cond_to_str(cond), - rd, rn_part.c_str(), rm, rotate_part.c_str()); -} - -Opcode ARM_Disasm::Decode(u32 insn) { - u32 bits27_26 = (insn >> 26) & 0x3; - switch (bits27_26) { - case 0x0: - return Decode00(insn); - case 0x1: - return Decode01(insn); - case 0x2: - return Decode10(insn); - case 0x3: - return Decode11(insn); - } - return OP_INVALID; -} - -Opcode ARM_Disasm::Decode00(u32 insn) { - u8 bit25 = (insn >> 25) & 0x1; - u8 bit4 = (insn >> 4) & 0x1; - if (bit25 == 0 && bit4 == 1) { - if ((insn & 0x0ffffff0) == 0x012fff10) { - // Bx instruction - return OP_BX; - } - if ((insn & 0x0ff000f0) == 0x01600010) { - // Clz instruction - return OP_CLZ; - } - if ((insn & 0xfff000f0) == 0xe1200070) { - // Bkpt instruction - return OP_BKPT; - } - u32 bits7_4 = (insn >> 4) & 0xf; - if (bits7_4 == 0x9) { - u32 bit24 = BIT(insn, 24); - if (bit24) { - return DecodeSyncPrimitive(insn); - } - // One of the multiply instructions - return DecodeMUL(insn); - } - - u8 bit7 = (insn >> 7) & 0x1; - if (bit7 == 1) { - // One of the load/store halfword/byte instructions - return DecodeLDRH(insn); - } - } - - u32 op1 = BITS(insn, 20, 24); - if (bit25 && (op1 == 0x12 || op1 == 0x16)) { - // One of the MSR (immediate) and hints instructions - return DecodeMSRImmAndHints(insn); - } - - // One of the data processing instructions - return DecodeALU(insn); -} - -Opcode ARM_Disasm::Decode01(u32 insn) { - u8 is_reg = (insn >> 25) & 0x1; - u8 bit4 = (insn >> 4) & 0x1; - if (is_reg == 1 && bit4 == 1) - return DecodeMedia(insn); - u8 is_load = (insn >> 20) & 0x1; - u8 is_byte = (insn >> 22) & 0x1; - if ((insn & 0xfd70f000) == 0xf550f000) { - // Pre-load - return OP_PLD; - } - if (insn == 0xf57ff01f) { - // Clear-Exclusive - return OP_CLREX; - } - if (is_load) { - if (is_byte) { - // Load byte - return OP_LDRB; - } - // Load word - return OP_LDR; - } - if (is_byte) { - // Store byte - return OP_STRB; - } - // Store word - return OP_STR; -} - -Opcode ARM_Disasm::Decode10(u32 insn) { - u8 bit25 = (insn >> 25) & 0x1; - if (bit25 == 0) { - // LDM/STM - u8 is_load = (insn >> 20) & 0x1; - if (is_load) - return OP_LDM; - return OP_STM; - } - - // Branch with link - if ((insn >> 24) & 1) - return OP_BL; - - return OP_B; -} - -Opcode ARM_Disasm::Decode11(u32 insn) { - u8 bit25 = (insn >> 25) & 0x1; - if (bit25 == 0) { - // LDC, SDC - u8 is_load = (insn >> 20) & 0x1; - if (is_load) { - // LDC - return OP_LDC; - } - // STC - return OP_STC; - } - - u8 bit24 = (insn >> 24) & 0x1; - if (bit24 == 0x1) { - // SWI - return OP_SWI; - } - - u8 bit4 = (insn >> 4) & 0x1; - u8 cpnum = (insn >> 8) & 0xf; - - if (cpnum == 15) { - // Special case for coprocessor 15 - u8 opcode = (insn >> 21) & 0x7; - if (bit4 == 0 || opcode != 0) { - // This is an unexpected bit pattern. Create an undefined - // instruction in case this is ever executed. - return OP_UNDEFINED; - } - - // MRC, MCR - u8 is_mrc = (insn >> 20) & 0x1; - if (is_mrc) - return OP_MRC; - return OP_MCR; - } - - if (bit4 == 0) { - // CDP - return OP_CDP; - } - // MRC, MCR - u8 is_mrc = (insn >> 20) & 0x1; - if (is_mrc) - return OP_MRC; - return OP_MCR; -} - -Opcode ARM_Disasm::DecodeSyncPrimitive(u32 insn) { - u32 op = BITS(insn, 20, 23); - u32 bit22 = BIT(insn, 22); - switch (op) { - case 0x0: - if (bit22) - return OP_SWPB; - return OP_SWP; - case 0x8: - return OP_STREX; - case 0x9: - return OP_LDREX; - case 0xA: - return OP_STREXD; - case 0xB: - return OP_LDREXD; - case 0xC: - return OP_STREXB; - case 0xD: - return OP_LDREXB; - case 0xE: - return OP_STREXH; - case 0xF: - return OP_LDREXH; - default: - return OP_UNDEFINED; - } -} - -Opcode ARM_Disasm::DecodeParallelAddSub(u32 insn) { - u32 op1 = BITS(insn, 20, 21); - u32 op2 = BITS(insn, 5, 7); - u32 is_unsigned = BIT(insn, 22); - - if (op1 == 0x0 || op2 == 0x5 || op2 == 0x6) - return OP_UNDEFINED; - - // change op1 range from [1, 3] to range [0, 2] - op1--; - - // change op2 range from [0, 4] U {7} to range [0, 5] - if (op2 == 0x7) - op2 = 0x5; - - static std::vector opcodes = { - // op1 = 0 - OP_SADD16, OP_UADD16, OP_SASX, OP_UASX, OP_SSAX, OP_USAX, OP_SSUB16, OP_USUB16, OP_SADD8, - OP_UADD8, OP_SSUB8, OP_USUB8, - // op1 = 1 - OP_QADD16, OP_UQADD16, OP_QASX, OP_UQASX, OP_QSAX, OP_UQSAX, OP_QSUB16, OP_UQSUB16, - OP_QADD8, OP_UQADD8, OP_QSUB8, OP_UQSUB8, - // op1 = 2 - OP_SHADD16, OP_UHADD16, OP_SHASX, OP_UHASX, OP_SHSAX, OP_UHSAX, OP_SHSUB16, OP_UHSUB16, - OP_SHADD8, OP_UHADD8, OP_SHSUB8, OP_UHSUB8}; - - u32 opcode_index = op1 * 12 + op2 * 2 + is_unsigned; - return opcodes[opcode_index]; -} - -Opcode ARM_Disasm::DecodePackingSaturationReversal(u32 insn) { - u32 op1 = BITS(insn, 20, 22); - u32 a = BITS(insn, 16, 19); - u32 op2 = BITS(insn, 5, 7); - - switch (op1) { - case 0x0: - if (BIT(op2, 0) == 0) - return OP_PKH; - if (op2 == 0x3 && a != 0xf) - return OP_SXTAB16; - if (op2 == 0x3 && a == 0xf) - return OP_SXTB16; - if (op2 == 0x5) - return OP_SEL; - break; - case 0x2: - if (BIT(op2, 0) == 0) - return OP_SSAT; - if (op2 == 0x1) - return OP_SSAT16; - if (op2 == 0x3 && a != 0xf) - return OP_SXTAB; - if (op2 == 0x3 && a == 0xf) - return OP_SXTB; - break; - case 0x3: - if (op2 == 0x1) - return OP_REV; - if (BIT(op2, 0) == 0) - return OP_SSAT; - if (op2 == 0x3 && a != 0xf) - return OP_SXTAH; - if (op2 == 0x3 && a == 0xf) - return OP_SXTH; - if (op2 == 0x5) - return OP_REV16; - break; - case 0x4: - if (op2 == 0x3 && a != 0xf) - return OP_UXTAB16; - if (op2 == 0x3 && a == 0xf) - return OP_UXTB16; - break; - case 0x6: - if (BIT(op2, 0) == 0) - return OP_USAT; - if (op2 == 0x1) - return OP_USAT16; - if (op2 == 0x3 && a != 0xf) - return OP_UXTAB; - if (op2 == 0x3 && a == 0xf) - return OP_UXTB; - break; - case 0x7: - if (BIT(op2, 0) == 0) - return OP_USAT; - if (op2 == 0x3 && a != 0xf) - return OP_UXTAH; - if (op2 == 0x3 && a == 0xf) - return OP_UXTH; - if (op2 == 0x5) - return OP_REVSH; - break; - default: - break; - } - - return OP_UNDEFINED; -} - -Opcode ARM_Disasm::DecodeMUL(u32 insn) { - u8 bit24 = (insn >> 24) & 0x1; - if (bit24 != 0) { - // This is an unexpected bit pattern. Create an undefined - // instruction in case this is ever executed. - return OP_UNDEFINED; - } - u8 bit23 = (insn >> 23) & 0x1; - u8 bit22_U = (insn >> 22) & 0x1; - u8 bit21_A = (insn >> 21) & 0x1; - if (bit23 == 0) { - // 32-bit multiply - if (bit22_U != 0) { - // This is an unexpected bit pattern. Create an undefined - // instruction in case this is ever executed. - return OP_UNDEFINED; - } - if (bit21_A == 0) - return OP_MUL; - return OP_MLA; - } - // 64-bit multiply - if (bit22_U == 0) { - // Unsigned multiply long - if (bit21_A == 0) - return OP_UMULL; - return OP_UMLAL; - } - // Signed multiply long - if (bit21_A == 0) - return OP_SMULL; - return OP_SMLAL; -} - -Opcode ARM_Disasm::DecodeMSRImmAndHints(u32 insn) { - u32 op = BIT(insn, 22); - u32 op1 = BITS(insn, 16, 19); - u32 op2 = BITS(insn, 0, 7); - - if (op == 0 && op1 == 0) { - switch (op2) { - case 0x0: - return OP_NOP; - case 0x1: - return OP_YIELD; - case 0x2: - return OP_WFE; - case 0x3: - return OP_WFI; - case 0x4: - return OP_SEV; - default: - return OP_UNDEFINED; - } - } - - return OP_MSR; -} - -Opcode ARM_Disasm::DecodeMediaMulDiv(u32 insn) { - u32 op1 = BITS(insn, 20, 22); - u32 op2_h = BITS(insn, 6, 7); - u32 a = BITS(insn, 12, 15); - - switch (op1) { - case 0x0: - if (op2_h == 0x0) { - if (a != 0xf) - return OP_SMLAD; - else - return OP_SMUAD; - } else if (op2_h == 0x1) { - if (a != 0xf) - return OP_SMLSD; - else - return OP_SMUSD; - } - break; - case 0x4: - if (op2_h == 0x0) - return OP_SMLALD; - else if (op2_h == 0x1) - return OP_SMLSLD; - break; - case 0x5: - if (op2_h == 0x0) { - if (a != 0xf) - return OP_SMMLA; - else - return OP_SMMUL; - } else if (op2_h == 0x3) { - return OP_SMMLS; - } - break; - default: - break; - } - - return OP_UNDEFINED; -} - -Opcode ARM_Disasm::DecodeMedia(u32 insn) { - u32 op1 = BITS(insn, 20, 24); - u32 rd = BITS(insn, 12, 15); - u32 op2 = BITS(insn, 5, 7); - - switch (BITS(op1, 3, 4)) { - case 0x0: - // unsigned and signed parallel addition and subtraction - return DecodeParallelAddSub(insn); - case 0x1: - // Packing, unpacking, saturation, and reversal - return DecodePackingSaturationReversal(insn); - case 0x2: - // Signed multiply, signed and unsigned divide - return DecodeMediaMulDiv(insn); - case 0x3: - if (op2 == 0 && rd == 0xf) - return OP_USAD8; - if (op2 == 0 && rd != 0xf) - return OP_USADA8; - break; - default: - break; - } - - return OP_UNDEFINED; -} - -Opcode ARM_Disasm::DecodeLDRH(u32 insn) { - u8 is_load = (insn >> 20) & 0x1; - u8 bits_65 = (insn >> 5) & 0x3; - if (is_load) { - if (bits_65 == 0x1) { - // Load unsigned halfword - return OP_LDRH; - } else if (bits_65 == 0x2) { - // Load signed byte - return OP_LDRSB; - } - // Signed halfword - if (bits_65 != 0x3) { - // This is an unexpected bit pattern. Create an undefined - // instruction in case this is ever executed. - return OP_UNDEFINED; - } - // Load signed halfword - return OP_LDRSH; - } - // Store halfword - if (bits_65 != 0x1) { - // This is an unexpected bit pattern. Create an undefined - // instruction in case this is ever executed. - return OP_UNDEFINED; - } - // Store halfword - return OP_STRH; -} - -Opcode ARM_Disasm::DecodeALU(u32 insn) { - u8 is_immed = (insn >> 25) & 0x1; - u8 opcode = (insn >> 21) & 0xf; - u8 bit_s = (insn >> 20) & 1; - u8 shift_is_reg = (insn >> 4) & 1; - u8 bit7 = (insn >> 7) & 1; - if (!is_immed && shift_is_reg && (bit7 != 0)) { - // This is an unexpected bit pattern. Create an undefined - // instruction in case this is ever executed. - return OP_UNDEFINED; - } - switch (opcode) { - case 0x0: - return OP_AND; - case 0x1: - return OP_EOR; - case 0x2: - return OP_SUB; - case 0x3: - return OP_RSB; - case 0x4: - return OP_ADD; - case 0x5: - return OP_ADC; - case 0x6: - return OP_SBC; - case 0x7: - return OP_RSC; - case 0x8: - if (bit_s) - return OP_TST; - return OP_MRS; - case 0x9: - if (bit_s) - return OP_TEQ; - return OP_MSR; - case 0xa: - if (bit_s) - return OP_CMP; - return OP_MRS; - case 0xb: - if (bit_s) - return OP_CMN; - return OP_MSR; - case 0xc: - return OP_ORR; - case 0xd: - return OP_MOV; - case 0xe: - return OP_BIC; - case 0xf: - return OP_MVN; - } - // Unreachable - return OP_INVALID; -} diff --git a/src/core/arm/disassembler/arm_disasm.h b/src/core/arm/disassembler/arm_disasm.h deleted file mode 100644 index 300e228ed8..0000000000 --- a/src/core/arm/disassembler/arm_disasm.h +++ /dev/null @@ -1,238 +0,0 @@ -// Copyright 2006 The Android Open Source Project - -#pragma once - -#include -#include "common/common_types.h" - -// Note: this list of opcodes must match the list used to initialize -// the opflags[] array in opcode.cpp. -enum Opcode { - OP_INVALID, - OP_UNDEFINED, - OP_ADC, - OP_ADD, - OP_AND, - OP_B, - OP_BL, - OP_BIC, - OP_BKPT, - OP_BLX, - OP_BX, - OP_CDP, - OP_CLREX, - OP_CLZ, - OP_CMN, - OP_CMP, - OP_EOR, - OP_LDC, - OP_LDM, - OP_LDR, - OP_LDRB, - OP_LDRBT, - OP_LDREX, - OP_LDREXB, - OP_LDREXD, - OP_LDREXH, - OP_LDRH, - OP_LDRSB, - OP_LDRSH, - OP_LDRT, - OP_MCR, - OP_MLA, - OP_MOV, - OP_MRC, - OP_MRS, - OP_MSR, - OP_MUL, - OP_MVN, - OP_NOP, - OP_ORR, - OP_PKH, - OP_PLD, - OP_QADD16, - OP_QADD8, - OP_QASX, - OP_QSAX, - OP_QSUB16, - OP_QSUB8, - OP_REV, - OP_REV16, - OP_REVSH, - OP_RSB, - OP_RSC, - OP_SADD16, - OP_SADD8, - OP_SASX, - OP_SBC, - OP_SEL, - OP_SEV, - OP_SHADD16, - OP_SHADD8, - OP_SHASX, - OP_SHSAX, - OP_SHSUB16, - OP_SHSUB8, - OP_SMLAD, - OP_SMLAL, - OP_SMLALD, - OP_SMLSD, - OP_SMLSLD, - OP_SMMLA, - OP_SMMLS, - OP_SMMUL, - OP_SMUAD, - OP_SMULL, - OP_SMUSD, - OP_SSAT, - OP_SSAT16, - OP_SSAX, - OP_SSUB16, - OP_SSUB8, - OP_STC, - OP_STM, - OP_STR, - OP_STRB, - OP_STRBT, - OP_STREX, - OP_STREXB, - OP_STREXD, - OP_STREXH, - OP_STRH, - OP_STRT, - OP_SUB, - OP_SWI, - OP_SWP, - OP_SWPB, - OP_SXTAB, - OP_SXTAB16, - OP_SXTAH, - OP_SXTB, - OP_SXTB16, - OP_SXTH, - OP_TEQ, - OP_TST, - OP_UADD16, - OP_UADD8, - OP_UASX, - OP_UHADD16, - OP_UHADD8, - OP_UHASX, - OP_UHSAX, - OP_UHSUB16, - OP_UHSUB8, - OP_UMLAL, - OP_UMULL, - OP_UQADD16, - OP_UQADD8, - OP_UQASX, - OP_UQSAX, - OP_UQSUB16, - OP_UQSUB8, - OP_USAD8, - OP_USADA8, - OP_USAT, - OP_USAT16, - OP_USAX, - OP_USUB16, - OP_USUB8, - OP_UXTAB, - OP_UXTAB16, - OP_UXTAH, - OP_UXTB, - OP_UXTB16, - OP_UXTH, - OP_WFE, - OP_WFI, - OP_YIELD, - - // Define thumb opcodes - OP_THUMB_UNDEFINED, - OP_THUMB_ADC, - OP_THUMB_ADD, - OP_THUMB_AND, - OP_THUMB_ASR, - OP_THUMB_B, - OP_THUMB_BIC, - OP_THUMB_BKPT, - OP_THUMB_BL, - OP_THUMB_BLX, - OP_THUMB_BX, - OP_THUMB_CMN, - OP_THUMB_CMP, - OP_THUMB_EOR, - OP_THUMB_LDMIA, - OP_THUMB_LDR, - OP_THUMB_LDRB, - OP_THUMB_LDRH, - OP_THUMB_LDRSB, - OP_THUMB_LDRSH, - OP_THUMB_LSL, - OP_THUMB_LSR, - OP_THUMB_MOV, - OP_THUMB_MUL, - OP_THUMB_MVN, - OP_THUMB_NEG, - OP_THUMB_ORR, - OP_THUMB_POP, - OP_THUMB_PUSH, - OP_THUMB_ROR, - OP_THUMB_SBC, - OP_THUMB_STMIA, - OP_THUMB_STR, - OP_THUMB_STRB, - OP_THUMB_STRH, - OP_THUMB_SUB, - OP_THUMB_SWI, - OP_THUMB_TST, - - OP_END // must be last -}; - -class ARM_Disasm { -public: - static std::string Disassemble(u32 addr, u32 insn); - static Opcode Decode(u32 insn); - -private: - static Opcode Decode00(u32 insn); - static Opcode Decode01(u32 insn); - static Opcode Decode10(u32 insn); - static Opcode Decode11(u32 insn); - static Opcode DecodeSyncPrimitive(u32 insn); - static Opcode DecodeParallelAddSub(u32 insn); - static Opcode DecodePackingSaturationReversal(u32 insn); - static Opcode DecodeMUL(u32 insn); - static Opcode DecodeMSRImmAndHints(u32 insn); - static Opcode DecodeMediaMulDiv(u32 insn); - static Opcode DecodeMedia(u32 insn); - static Opcode DecodeLDRH(u32 insn); - static Opcode DecodeALU(u32 insn); - - static std::string DisassembleALU(Opcode opcode, u32 insn); - static std::string DisassembleBranch(u32 addr, Opcode opcode, u32 insn); - static std::string DisassembleBX(u32 insn); - static std::string DisassembleBKPT(u32 insn); - static std::string DisassembleCLZ(u32 insn); - static std::string DisassembleMediaMulDiv(Opcode opcode, u32 insn); - static std::string DisassembleMemblock(Opcode opcode, u32 insn); - static std::string DisassembleMem(u32 insn); - static std::string DisassembleMemHalf(u32 insn); - static std::string DisassembleMCR(Opcode opcode, u32 insn); - static std::string DisassembleMLA(Opcode opcode, u32 insn); - static std::string DisassembleUMLAL(Opcode opcode, u32 insn); - static std::string DisassembleMUL(Opcode opcode, u32 insn); - static std::string DisassembleMRS(u32 insn); - static std::string DisassembleMSR(u32 insn); - static std::string DisassembleNoOperands(Opcode opcode, u32 insn); - static std::string DisassembleParallelAddSub(Opcode opcode, u32 insn); - static std::string DisassemblePKH(u32 insn); - static std::string DisassemblePLD(u32 insn); - static std::string DisassembleREV(Opcode opcode, u32 insn); - static std::string DisassembleREX(Opcode opcode, u32 insn); - static std::string DisassembleSAT(Opcode opcode, u32 insn); - static std::string DisassembleSEL(u32 insn); - static std::string DisassembleSWI(u32 insn); - static std::string DisassembleSWP(Opcode opcode, u32 insn); - static std::string DisassembleXT(Opcode opcode, u32 insn); -}; diff --git a/src/core/arm/dyncom/arm_dyncom_interpreter.cpp b/src/core/arm/dyncom/arm_dyncom_interpreter.cpp index 8073bb7050..f4fbb8d04f 100644 --- a/src/core/arm/dyncom/arm_dyncom_interpreter.cpp +++ b/src/core/arm/dyncom/arm_dyncom_interpreter.cpp @@ -10,7 +10,6 @@ #include "common/common_types.h" #include "common/logging/log.h" #include "common/microprofile.h" -#include "core/arm/disassembler/arm_disasm.h" #include "core/arm/dyncom/arm_dyncom_dec.h" #include "core/arm/dyncom/arm_dyncom_interpreter.h" #include "core/arm/dyncom/arm_dyncom_run.h" @@ -828,10 +827,8 @@ static unsigned int InterpreterTranslateInstruction(const ARMul_State* cpu, cons int idx; if (DecodeARMInstruction(inst, &idx) == ARMDecodeStatus::FAILURE) { - std::string disasm = ARM_Disasm::Disassemble(phys_addr, inst); - LOG_ERROR(Core_ARM11, - "Decode failure.\tPC: [0x%08" PRIX32 "]\tInstruction: %s [%08" PRIX32 "]", - phys_addr, disasm.c_str(), inst); + LOG_ERROR(Core_ARM11, "Decode failure.\tPC: [0x%08" PRIX32 "]\tInstruction: %08" PRIX32, + phys_addr, inst); LOG_ERROR(Core_ARM11, "cpsr=0x%" PRIX32 ", cpu->TFlag=%d, r15=0x%08" PRIX32, cpu->Cpsr, cpu->TFlag, cpu->Reg[15]); CITRA_IGNORE_EXIT(-1);