2019-12-11 21:38:57 +00:00
|
|
|
#include <QAction>
|
2019-12-12 00:20:49 +00:00
|
|
|
#include <QApplication>
|
|
|
|
#include <QClipboard>
|
2019-12-11 21:38:57 +00:00
|
|
|
#include <QMenu>
|
2019-12-19 22:20:32 +00:00
|
|
|
#include <QString>
|
|
|
|
#include <QInputDialog>
|
|
|
|
#include <QMessageBox>
|
|
|
|
#include <QHeaderView>
|
|
|
|
|
2019-12-11 14:52:12 +00:00
|
|
|
#include "DisAsmWnd.h"
|
2019-12-11 21:38:57 +00:00
|
|
|
#include "ee/VuAnalysis.h"
|
2019-12-19 22:20:32 +00:00
|
|
|
#include "QtDisAsmTableModel.h"
|
|
|
|
#include "QtDisAsmVuTableModel.h"
|
|
|
|
|
2019-12-11 21:38:57 +00:00
|
|
|
#include "countof.h"
|
2019-12-19 22:20:32 +00:00
|
|
|
#include "string_cast.h"
|
|
|
|
#include "string_format.h"
|
|
|
|
#include "lexical_cast_ex.h"
|
|
|
|
|
|
|
|
#include "DebugExpressionEvaluator.h"
|
2019-12-11 14:52:12 +00:00
|
|
|
|
|
|
|
#define WNDSTYLE (WS_CLIPCHILDREN | WS_THICKFRAME | WS_CAPTION | WS_SYSMENU | WS_CHILD | WS_MAXIMIZEBOX)
|
|
|
|
|
2019-12-19 22:20:32 +00:00
|
|
|
CDisAsmWnd::CDisAsmWnd(QMdiArea* parent, CVirtualMachine& virtualMachine, CMIPS* ctx, const char* name, CQtDisAsmTableModel::DISASM_TYPE disAsmType)
|
2019-12-11 14:52:12 +00:00
|
|
|
: QMdiSubWindow(parent)
|
2019-12-19 22:20:32 +00:00
|
|
|
, m_virtualMachine(virtualMachine)
|
|
|
|
, m_ctx(ctx)
|
2019-12-11 21:38:57 +00:00
|
|
|
, m_disAsmType(disAsmType)
|
2019-12-11 14:52:12 +00:00
|
|
|
{
|
|
|
|
|
|
|
|
resize(320, 240);
|
|
|
|
|
|
|
|
parent->addSubWindow(this);
|
2019-12-12 12:58:26 +00:00
|
|
|
setWindowTitle("Disassembly");
|
2019-12-11 14:52:12 +00:00
|
|
|
|
|
|
|
switch(disAsmType)
|
|
|
|
{
|
2019-12-19 22:20:32 +00:00
|
|
|
case CQtDisAsmTableModel::DISASM_STANDARD:
|
|
|
|
m_model = new CQtDisAsmTableModel(this, virtualMachine, ctx);
|
|
|
|
m_instructionSize = 4;
|
2019-12-11 14:52:12 +00:00
|
|
|
break;
|
2019-12-19 22:20:32 +00:00
|
|
|
case CQtDisAsmTableModel::DISASM_VU:
|
|
|
|
m_model = new CQtDisAsmVuTableModel(this, virtualMachine, ctx);
|
|
|
|
m_instructionSize = 8;
|
2019-12-11 14:52:12 +00:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
assert(0);
|
|
|
|
break;
|
|
|
|
}
|
2019-12-19 22:20:32 +00:00
|
|
|
m_tableView = new QTableView(this);
|
|
|
|
setWidget(m_tableView);
|
|
|
|
m_tableView->setModel(m_model);
|
|
|
|
|
|
|
|
auto header = m_tableView->horizontalHeader();
|
|
|
|
header->setSectionResizeMode(0, QHeaderView::ResizeToContents);
|
|
|
|
header->setSectionResizeMode(1, QHeaderView::ResizeToContents);
|
|
|
|
header->setSectionResizeMode(2, QHeaderView::ResizeToContents);
|
|
|
|
header->setSectionResizeMode(3, QHeaderView::ResizeToContents);
|
|
|
|
header->setSectionResizeMode(4, QHeaderView::ResizeToContents);
|
|
|
|
header->setSectionResizeMode(5, QHeaderView::ResizeToContents);
|
|
|
|
if(disAsmType == CQtDisAsmTableModel::DISASM_STANDARD)
|
|
|
|
{
|
|
|
|
header->setSectionResizeMode(6, QHeaderView::Stretch);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
header->setSectionResizeMode(6, QHeaderView::ResizeToContents);
|
|
|
|
header->setSectionResizeMode(7, QHeaderView::ResizeToContents);
|
|
|
|
header->setSectionResizeMode(8, QHeaderView::Stretch);
|
|
|
|
}
|
|
|
|
|
|
|
|
m_tableView->verticalHeader()->hide();
|
|
|
|
m_tableView->resizeColumnsToContents();
|
|
|
|
|
2019-12-11 21:38:57 +00:00
|
|
|
m_tableView->setContextMenuPolicy(Qt::CustomContextMenu);
|
|
|
|
connect(m_tableView, &QTableView::customContextMenuRequested, this, &CDisAsmWnd::showMenu);
|
2019-12-11 23:41:09 +00:00
|
|
|
|
|
|
|
m_tableView->setSelectionBehavior(QAbstractItemView::SelectRows);
|
|
|
|
m_tableView->setSelectionMode(QAbstractItemView::ContiguousSelection);
|
|
|
|
connect(m_tableView->selectionModel(), &QItemSelectionModel::selectionChanged, this, &CDisAsmWnd::selectionChanged);
|
2019-12-11 14:52:12 +00:00
|
|
|
// RefreshLayout();
|
2019-12-12 00:20:49 +00:00
|
|
|
|
|
|
|
QAction* copyAction = new QAction("copy",this);
|
|
|
|
copyAction->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_C));
|
|
|
|
connect(copyAction, &QAction::triggered, this, &CDisAsmWnd::OnCopy);
|
|
|
|
m_tableView->addAction(copyAction);
|
2019-12-12 01:18:27 +00:00
|
|
|
|
|
|
|
QAction* breakpointAction = new QAction("breakpoint toggle",this);
|
|
|
|
breakpointAction->setShortcut(QKeySequence(Qt::Key_F9));
|
|
|
|
connect(breakpointAction, &QAction::triggered, this, &CDisAsmWnd::OnListDblClick);
|
|
|
|
m_tableView->addAction(breakpointAction);
|
|
|
|
|
|
|
|
connect(m_tableView, &QTableView::doubleClicked, this, &CDisAsmWnd::OnListDblClick);
|
|
|
|
|
2019-12-11 14:52:12 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
CDisAsmWnd::~CDisAsmWnd()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2019-12-11 21:38:57 +00:00
|
|
|
void CDisAsmWnd::showMenu(const QPoint &pos)
|
|
|
|
{
|
|
|
|
QMenu *rightClickMenu = new QMenu(this);
|
|
|
|
|
|
|
|
QAction *goToPcAction = new QAction(this);
|
|
|
|
goToPcAction->setText("GoTo PC");
|
|
|
|
connect(goToPcAction, &QAction::triggered, std::bind(&CDisAsmWnd::GotoPC, this));
|
|
|
|
rightClickMenu->addAction(goToPcAction);
|
|
|
|
|
|
|
|
QAction *goToAddrAction = new QAction(this);
|
|
|
|
goToAddrAction->setText("Goto Address...");
|
|
|
|
connect(goToAddrAction, &QAction::triggered, std::bind(&CDisAsmWnd::GotoAddress, this));
|
|
|
|
rightClickMenu->addAction(goToAddrAction);
|
|
|
|
|
|
|
|
QAction *editCommentAction = new QAction(this);
|
|
|
|
editCommentAction->setText("Edit Comment...");
|
|
|
|
connect(editCommentAction, &QAction::triggered, std::bind(&CDisAsmWnd::EditComment, this));
|
|
|
|
rightClickMenu->addAction(editCommentAction);
|
|
|
|
|
|
|
|
QAction *findCallerAction = new QAction(this);
|
|
|
|
findCallerAction->setText("Find Callers");
|
|
|
|
connect(findCallerAction, &QAction::triggered, std::bind(&CDisAsmWnd::FindCallers, this));
|
|
|
|
rightClickMenu->addAction(findCallerAction);
|
|
|
|
|
|
|
|
auto index = m_tableView->currentIndex();
|
|
|
|
if(index.isValid())
|
|
|
|
{
|
2019-12-11 23:09:02 +00:00
|
|
|
if(m_selected != MIPS_INVALID_PC)
|
2019-12-11 21:38:57 +00:00
|
|
|
{
|
|
|
|
uint32 nOpcode = GetInstruction(m_selected);
|
|
|
|
if(m_ctx->m_pArch->IsInstructionBranch(m_ctx, m_selected, nOpcode) == MIPS_BRANCH_NORMAL)
|
|
|
|
{
|
|
|
|
char sTemp[256];
|
|
|
|
uint32 nAddress = m_ctx->m_pArch->GetInstructionEffectiveAddress(m_ctx, m_selected, nOpcode);
|
|
|
|
snprintf(sTemp, countof(sTemp), ("Go to 0x%08X"), nAddress);
|
|
|
|
QAction *goToEaAction = new QAction(this);
|
|
|
|
goToEaAction->setText(sTemp);
|
|
|
|
connect(goToEaAction, &QAction::triggered, std::bind(&CDisAsmWnd::GotoEA, this));
|
|
|
|
rightClickMenu->addAction(goToEaAction);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if(HistoryHasPrevious())
|
|
|
|
{
|
|
|
|
char sTemp[256];
|
|
|
|
snprintf(sTemp, countof(sTemp), ("Go back (0x%08X)"), HistoryGetPrevious());
|
|
|
|
QAction *goToEaAction = new QAction(this);
|
|
|
|
goToEaAction->setText(sTemp);
|
|
|
|
connect(goToEaAction, &QAction::triggered, std::bind(&CDisAsmWnd::HistoryGoBack, this));
|
|
|
|
rightClickMenu->addAction(goToEaAction);
|
|
|
|
}
|
|
|
|
|
|
|
|
if(HistoryHasNext())
|
|
|
|
{
|
|
|
|
char sTemp[256];
|
|
|
|
snprintf(sTemp, countof(sTemp), ("Go forward (0x%08X)"), HistoryGetNext());
|
|
|
|
QAction *goToEaAction = new QAction(this);
|
|
|
|
goToEaAction->setText(sTemp);
|
|
|
|
connect(goToEaAction, &QAction::triggered, std::bind(&CDisAsmWnd::HistoryGoForward, this));
|
|
|
|
rightClickMenu->addAction(goToEaAction);
|
|
|
|
}
|
|
|
|
|
|
|
|
if(m_disAsmType == CQtDisAsmTableModel::DISASM_VU)
|
|
|
|
{
|
|
|
|
QAction *analyseVuction = new QAction(this);
|
|
|
|
analyseVuction->setText("Analyse Microprogram");
|
|
|
|
connect(analyseVuction, &QAction::triggered,
|
|
|
|
[&]()
|
|
|
|
{
|
|
|
|
CVuAnalysis::Analyse(m_ctx, 0, 0x4000);
|
|
|
|
m_model->Redraw();
|
|
|
|
}
|
|
|
|
);
|
|
|
|
rightClickMenu->addAction(analyseVuction);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
rightClickMenu->popup(m_tableView->viewport()->mapToGlobal(pos));
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2019-12-19 22:20:32 +00:00
|
|
|
void CDisAsmWnd::SetAddress(uint32 address)
|
|
|
|
{
|
|
|
|
m_tableView->scrollTo(m_model->index(address / m_instructionSize, 0), QAbstractItemView::PositionAtTop);
|
|
|
|
m_address = address;
|
|
|
|
}
|
|
|
|
|
|
|
|
void CDisAsmWnd::SetCenterAtAddress(uint32 address)
|
|
|
|
{
|
|
|
|
m_tableView->scrollTo(m_model->index(m_address / m_instructionSize, 0), QAbstractItemView::PositionAtCenter);
|
2019-12-11 23:09:02 +00:00
|
|
|
m_address = address;
|
2019-12-19 22:20:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void CDisAsmWnd::SetSelectedAddress(uint32 address)
|
2019-12-11 14:52:12 +00:00
|
|
|
{
|
2019-12-19 22:20:32 +00:00
|
|
|
m_selectionEnd = -1;
|
|
|
|
m_selected = address;
|
|
|
|
auto index = m_model->index(address / m_instructionSize, 0);
|
|
|
|
m_tableView->scrollTo(index, QAbstractItemView::PositionAtTop);
|
|
|
|
m_tableView->setCurrentIndex(index);
|
2019-12-11 14:52:12 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void CDisAsmWnd::HandleMachineStateChange()
|
|
|
|
{
|
2019-12-19 22:20:32 +00:00
|
|
|
m_model->Redraw();
|
2019-12-11 14:52:12 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void CDisAsmWnd::HandleRunningStateChange(CVirtualMachine::STATUS newState)
|
|
|
|
{
|
2019-12-19 22:20:32 +00:00
|
|
|
if(newState == CVirtualMachine::STATUS::PAUSED)
|
|
|
|
{
|
|
|
|
//Recenter view if we just got into paused state
|
|
|
|
m_address = m_ctx->m_State.nPC & ~(m_instructionSize - 1);
|
|
|
|
SetCenterAtAddress(m_address);
|
|
|
|
}
|
|
|
|
m_model->Redraw();
|
2019-12-11 14:52:12 +00:00
|
|
|
}
|
|
|
|
|
2019-12-19 22:20:32 +00:00
|
|
|
void CDisAsmWnd::GotoAddress()
|
|
|
|
{
|
|
|
|
if(m_virtualMachine.GetStatus() == CVirtualMachine::RUNNING)
|
|
|
|
{
|
|
|
|
// MessageBeep(-1);
|
|
|
|
return;
|
|
|
|
}
|
2019-12-11 14:52:12 +00:00
|
|
|
|
2019-12-19 22:20:32 +00:00
|
|
|
bool ok;
|
|
|
|
QString sValue = QInputDialog::getText(this, ("Goto Address"),
|
|
|
|
("Enter new address:"), QLineEdit::Normal,
|
|
|
|
((("0x") + lexical_cast_hex<std::string>(m_address, 8)).c_str()), &ok);
|
|
|
|
if (!ok || sValue.isEmpty())
|
|
|
|
return;
|
2019-12-11 14:52:12 +00:00
|
|
|
|
2019-12-19 22:20:32 +00:00
|
|
|
{
|
|
|
|
try
|
|
|
|
{
|
|
|
|
uint32 nAddress = CDebugExpressionEvaluator::Evaluate(sValue.toStdString().c_str(), m_ctx);
|
|
|
|
if(nAddress & (m_instructionSize - 1))
|
|
|
|
{
|
2019-12-18 12:34:04 +00:00
|
|
|
QMessageBox::warning(this, tr("Warning"),
|
|
|
|
tr("Invalid address"),
|
|
|
|
QMessageBox::Ok , QMessageBox::Ok);
|
2019-12-19 22:20:32 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(m_address != nAddress)
|
|
|
|
{
|
|
|
|
HistorySave(m_address);
|
|
|
|
}
|
|
|
|
|
|
|
|
m_address = nAddress;
|
|
|
|
SetAddress(nAddress);
|
|
|
|
}
|
|
|
|
catch(const std::exception& exception)
|
|
|
|
{
|
|
|
|
std::string message = std::string("Error evaluating expression: ") + exception.what();
|
2019-12-18 12:34:04 +00:00
|
|
|
QMessageBox::critical(this, tr("Error"),
|
|
|
|
tr(message.c_str()),
|
|
|
|
QMessageBox::Ok , QMessageBox::Ok);
|
2019-12-19 22:20:32 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void CDisAsmWnd::GotoPC()
|
|
|
|
{
|
|
|
|
if(m_virtualMachine.GetStatus() == CVirtualMachine::RUNNING)
|
|
|
|
{
|
|
|
|
// MessageBeep(-1);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
m_address = m_ctx->m_State.nPC;
|
|
|
|
SetAddress(m_ctx->m_State.nPC);
|
|
|
|
}
|
|
|
|
|
|
|
|
void CDisAsmWnd::GotoEA()
|
|
|
|
{
|
|
|
|
if(m_virtualMachine.GetStatus() == CVirtualMachine::RUNNING)
|
|
|
|
{
|
|
|
|
// MessageBeep(-1);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
uint32 nOpcode = GetInstruction(m_selected);
|
|
|
|
if(m_ctx->m_pArch->IsInstructionBranch(m_ctx, m_selected, nOpcode) == MIPS_BRANCH_NORMAL)
|
|
|
|
{
|
|
|
|
uint32 nAddress = m_ctx->m_pArch->GetInstructionEffectiveAddress(m_ctx, m_selected, nOpcode);
|
|
|
|
|
|
|
|
if(m_address != nAddress)
|
|
|
|
{
|
|
|
|
HistorySave(m_address);
|
|
|
|
}
|
|
|
|
|
|
|
|
m_address = nAddress;
|
|
|
|
SetAddress(nAddress);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void CDisAsmWnd::EditComment()
|
|
|
|
{
|
|
|
|
if(m_virtualMachine.GetStatus() == CVirtualMachine::RUNNING)
|
|
|
|
{
|
|
|
|
// MessageBeep(-1);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
const char* comment = m_ctx->m_Comments.Find(m_selected);
|
|
|
|
std::string commentConv;
|
|
|
|
|
|
|
|
if(comment != nullptr)
|
|
|
|
{
|
|
|
|
commentConv = comment;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
commentConv = ("");
|
|
|
|
}
|
|
|
|
|
|
|
|
bool ok;
|
|
|
|
QString value = QInputDialog::getText(this, ("Edit Comment"),
|
|
|
|
("Enter new comment:"), QLineEdit::Normal,
|
|
|
|
(commentConv.c_str()), &ok);
|
|
|
|
if (!ok || value.isEmpty())
|
|
|
|
return;
|
|
|
|
|
2019-12-18 12:34:21 +00:00
|
|
|
m_ctx->m_Comments.InsertTag(m_selected, value.toStdString().c_str());
|
|
|
|
m_model->Redraw(m_selected);
|
2019-12-19 22:20:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void CDisAsmWnd::FindCallers()
|
|
|
|
{
|
|
|
|
if(m_virtualMachine.GetStatus() == CVirtualMachine::RUNNING)
|
|
|
|
{
|
|
|
|
// MessageBeep(-1);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
FindCallersRequested(m_selected);
|
|
|
|
}
|
|
|
|
|
|
|
|
CDisAsmWnd::SelectionRangeType CDisAsmWnd::GetSelectionRange()
|
|
|
|
{
|
|
|
|
if(m_selectionEnd == -1)
|
|
|
|
{
|
|
|
|
return SelectionRangeType(m_selected, m_selected);
|
|
|
|
}
|
|
|
|
|
|
|
|
if(m_selectionEnd > m_selected)
|
|
|
|
{
|
|
|
|
return SelectionRangeType(m_selected, m_selectionEnd);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
return SelectionRangeType(m_selectionEnd, m_selected);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void CDisAsmWnd::HistoryReset()
|
|
|
|
{
|
|
|
|
m_historyPosition = -1;
|
|
|
|
m_historySize = 0;
|
|
|
|
memset(m_history, 0, sizeof(uint32) * HISTORY_STACK_MAX);
|
|
|
|
}
|
|
|
|
|
|
|
|
void CDisAsmWnd::HistorySave(uint32 nAddress)
|
|
|
|
{
|
|
|
|
if(m_historySize == HISTORY_STACK_MAX)
|
|
|
|
{
|
|
|
|
memmove(m_history + 1, m_history, HISTORY_STACK_MAX - 1);
|
|
|
|
m_historySize--;
|
|
|
|
}
|
|
|
|
|
|
|
|
m_history[m_historySize] = nAddress;
|
|
|
|
m_historyPosition = m_historySize;
|
|
|
|
m_historySize++;
|
|
|
|
}
|
|
|
|
|
|
|
|
void CDisAsmWnd::HistoryGoBack()
|
|
|
|
{
|
|
|
|
if(m_historyPosition == -1) return;
|
|
|
|
|
|
|
|
uint32 address = HistoryGetPrevious();
|
|
|
|
m_history[m_historyPosition] = m_address;
|
|
|
|
m_address = address;
|
2019-12-11 14:52:12 +00:00
|
|
|
|
2019-12-19 22:20:32 +00:00
|
|
|
m_historyPosition--;
|
|
|
|
SetAddress(address);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
void CDisAsmWnd::HistoryGoForward()
|
|
|
|
{
|
|
|
|
if(m_historyPosition == m_historySize) return;
|
|
|
|
|
|
|
|
uint32 address = HistoryGetNext();
|
|
|
|
m_historyPosition++;
|
|
|
|
m_history[m_historyPosition] = m_address;
|
|
|
|
m_address = address;
|
|
|
|
SetAddress(address);
|
|
|
|
}
|
|
|
|
|
|
|
|
uint32 CDisAsmWnd::HistoryGetPrevious()
|
|
|
|
{
|
|
|
|
return m_history[m_historyPosition];
|
|
|
|
}
|
|
|
|
|
|
|
|
uint32 CDisAsmWnd::HistoryGetNext()
|
|
|
|
{
|
|
|
|
if(m_historyPosition == m_historySize) return 0;
|
|
|
|
return m_history[m_historyPosition + 1];
|
|
|
|
}
|
|
|
|
|
|
|
|
bool CDisAsmWnd::HistoryHasPrevious()
|
|
|
|
{
|
|
|
|
return (m_historySize != 0) && (m_historyPosition != -1);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool CDisAsmWnd::HistoryHasNext()
|
|
|
|
{
|
|
|
|
return (m_historySize != 0) && (m_historyPosition != (m_historySize - 1));
|
|
|
|
}
|
|
|
|
|
|
|
|
uint32 CDisAsmWnd::GetInstruction(uint32 address)
|
|
|
|
{
|
|
|
|
//Address translation perhaps?
|
|
|
|
return m_ctx->m_pMemoryMap->GetInstruction(address);
|
|
|
|
}
|
|
|
|
|
|
|
|
void CDisAsmWnd::ToggleBreakpoint(uint32 address)
|
|
|
|
{
|
|
|
|
if(m_virtualMachine.GetStatus() == CVirtualMachine::RUNNING)
|
|
|
|
{
|
|
|
|
// MessageBeep(-1);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
m_ctx->ToggleBreakpoint(address);
|
|
|
|
m_model->Redraw(address);
|
|
|
|
}
|
|
|
|
|
|
|
|
void CDisAsmWnd::UpdatePosition(int delta)
|
|
|
|
{
|
|
|
|
m_address += delta;
|
|
|
|
SetAddress(m_address);
|
|
|
|
}
|
2019-12-11 23:41:09 +00:00
|
|
|
|
|
|
|
void CDisAsmWnd::selectionChanged()
|
|
|
|
{
|
|
|
|
auto indexes = m_tableView->selectionModel()->selectedIndexes();
|
|
|
|
if(!indexes.empty())
|
|
|
|
{
|
|
|
|
auto selected = indexes.first().row() * m_instructionSize;
|
|
|
|
auto selectionEnd = indexes.last().row() * m_instructionSize;
|
|
|
|
m_selected = selected;
|
|
|
|
m_selectionEnd = (selectionEnd == selected) ? -1 : selectionEnd;
|
|
|
|
}
|
|
|
|
}
|
2019-12-12 00:20:49 +00:00
|
|
|
|
|
|
|
void CDisAsmWnd::OnCopy()
|
|
|
|
{
|
|
|
|
std::string text;
|
|
|
|
auto selectionRange = GetSelectionRange();
|
|
|
|
for(uint32 address = selectionRange.first; address <= selectionRange.second; address += m_instructionSize)
|
|
|
|
{
|
|
|
|
if(address != selectionRange.first)
|
|
|
|
{
|
|
|
|
text += ("\r\n");
|
|
|
|
}
|
|
|
|
if(m_disAsmType == CQtDisAsmTableModel::DISASM_STANDARD)
|
|
|
|
{
|
|
|
|
text += GetInstructionDetailsText(address);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
text += GetInstructionDetailsTextVu(address);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
QApplication::clipboard()->setText(text.c_str());
|
|
|
|
}
|
|
|
|
|
|
|
|
std::string CDisAsmWnd::GetInstructionDetailsText(uint32 address)
|
|
|
|
{
|
|
|
|
uint32 opcode = GetInstruction(address);
|
|
|
|
|
|
|
|
std::string result;
|
|
|
|
|
|
|
|
result += lexical_cast_hex<std::string>(address, 8) + (" ");
|
|
|
|
result += lexical_cast_hex<std::string>(opcode, 8) + (" ");
|
|
|
|
|
|
|
|
char disasm[256];
|
|
|
|
m_ctx->m_pArch->GetInstructionMnemonic(m_ctx, address, opcode, disasm, countof(disasm));
|
|
|
|
|
|
|
|
result += disasm;
|
|
|
|
for(auto j = strlen(disasm); j < 15; j++)
|
|
|
|
{
|
|
|
|
result += (" ");
|
|
|
|
}
|
|
|
|
|
|
|
|
m_ctx->m_pArch->GetInstructionOperands(m_ctx, address, opcode, disasm, countof(disasm));
|
|
|
|
result += disasm;
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
std::string CDisAsmWnd::GetInstructionDetailsTextVu(uint32 address)
|
|
|
|
{
|
|
|
|
assert((address & 0x07) == 0);
|
|
|
|
|
|
|
|
uint32 lowerInstruction = GetInstruction(address + 0);
|
|
|
|
uint32 upperInstruction = GetInstruction(address + 4);
|
|
|
|
|
|
|
|
std::string result;
|
|
|
|
|
|
|
|
result += lexical_cast_hex<std::string>(address, 8) + (" ");
|
|
|
|
result += lexical_cast_hex<std::string>(upperInstruction, 8) + (" ") + lexical_cast_hex<std::string>(lowerInstruction, 8) + (" ");
|
|
|
|
|
|
|
|
char disasm[256];
|
|
|
|
|
|
|
|
m_ctx->m_pArch->GetInstructionMnemonic(m_ctx, address + 4, upperInstruction, disasm, countof(disasm));
|
|
|
|
result += disasm;
|
|
|
|
|
|
|
|
for(auto j = strlen(disasm); j < 15; j++)
|
|
|
|
{
|
|
|
|
result += (" ");
|
|
|
|
}
|
|
|
|
|
|
|
|
m_ctx->m_pArch->GetInstructionOperands(m_ctx, address + 4, upperInstruction, disasm, countof(disasm));
|
|
|
|
result += disasm;
|
|
|
|
|
|
|
|
for(auto j = strlen(disasm); j < 31; j++)
|
|
|
|
{
|
|
|
|
result += (" ");
|
|
|
|
}
|
|
|
|
|
|
|
|
m_ctx->m_pArch->GetInstructionMnemonic(m_ctx, address + 0, lowerInstruction, disasm, countof(disasm));
|
|
|
|
result += disasm;
|
|
|
|
|
|
|
|
for(auto j = strlen(disasm); j < 16; j++)
|
|
|
|
{
|
|
|
|
result += (" ");
|
|
|
|
}
|
|
|
|
|
|
|
|
m_ctx->m_pArch->GetInstructionOperands(m_ctx, address + 0, lowerInstruction, disasm, countof(disasm));
|
|
|
|
result += disasm;
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
2019-12-12 01:18:27 +00:00
|
|
|
|
|
|
|
void CDisAsmWnd::OnListDblClick()
|
|
|
|
{
|
|
|
|
ToggleBreakpoint(m_selected);
|
|
|
|
}
|