ppsspp/Qt/ctrldisasmview.cpp
Peter Tissen 520daeeb24 Remove empty lines in disasmview to remove visual noise.
Port over part of the callstack code, still missing function name lookup
and navigation on double click. This is just an intermediate commit, I
don't want to have to rebase this again when I contine to work on it.
2013-11-24 09:26:51 +01:00

423 lines
10 KiB
C++

#include "ctrldisasmview.h"
#include <QPainter>
#include <QKeyEvent>
#include <QClipboard>
#include <QMenu>
#include <QAction>
#include <QApplication>
#include <QInputDialog>
#include <QMessageBox>
#include "math.h"
#include "debugger_disasm.h"
#include "Core/Debugger/SymbolMap.h"
namespace
{
u32 halfAndHalf(u32 a, u32 b)
{
return ((a>>1)&0x7f7f7f7f) + ((b>>1)&0x7f7f7f7f);
}
}
CtrlDisAsmView::CtrlDisAsmView(QWidget *parent) :
QWidget(parent)
{
curAddress=0;
rowHeight=14;
align=2;
selecting=false;
showHex=false;
}
void CtrlDisAsmView::keyPressEvent(QKeyEvent *e)
{
int page=(rect().bottom()/rowHeight)/2-1;
switch (e->key())
{
case Qt::Key_Down: curAddress += align; break;
case Qt::Key_Up: curAddress -= align; break;
case Qt::Key_PageDown: curAddress += page*align; break;
case Qt::Key_PageUp: curAddress -= page*align; break;
default: QWidget::keyPressEvent(e); break;
}
update();
}
void CtrlDisAsmView::mousePressEvent(QMouseEvent *e)
{
int x = e->pos().x();
int y = e->pos().y();
if (x>16)
{
oldSelection=selection;
selection=yToAddress(y);
bool oldselecting=selecting;
selecting=true;
if (!oldselecting || (selection!=oldSelection))
redraw();
}
else
{
debugger->toggleBreakpoint(yToAddress(y));
parentWindow->Update();
redraw();
}
}
void CtrlDisAsmView::wheelEvent(QWheelEvent* e)
{
int numDegrees = e->delta() / 8;
int numSteps = numDegrees / 15;
if (e->orientation() == Qt::Vertical)
{
curAddress -= numSteps*align;
update();
}
}
void CtrlDisAsmView::redraw()
{
update();
}
void CtrlDisAsmView::contextMenu(const QPoint &pos)
{
QMenu menu(this);
QAction *copyAddress = new QAction(tr("Copy &address"), this);
connect(copyAddress, SIGNAL(triggered()), this, SLOT(CopyAddress()));
menu.addAction(copyAddress);
QAction *copyInstrHex = new QAction(tr("Copy instruction (&hex)"), this);
connect(copyInstrHex, SIGNAL(triggered()), this, SLOT(CopyInstrHex()));
menu.addAction(copyInstrHex);
QAction *copyInstrDisAsm = new QAction(tr("Copy instruction (&disasm)"), this);
connect(copyInstrDisAsm, SIGNAL(triggered()), this, SLOT(CopyInstrDisAsm()));
menu.addAction(copyInstrDisAsm);
menu.addSeparator();
QAction *runToHere = new QAction(tr("&Run to here"), this);
connect(runToHere, SIGNAL(triggered()), this, SLOT(RunToHere()));
menu.addAction(runToHere);
QAction *setNextStatement = new QAction(tr("&Set Next Statement"), this);
connect(setNextStatement, SIGNAL(triggered()), this, SLOT(SetNextStatement()));
menu.addAction(setNextStatement);
QAction *toggleBreakpoint = new QAction(tr("&Toggle breakpoint"), this);
connect(toggleBreakpoint, SIGNAL(triggered()), this, SLOT(ToggleBreakpoint()));
menu.addAction(toggleBreakpoint);
QAction *followBranch = new QAction(tr("&Follow branch"), this);
connect(followBranch, SIGNAL(triggered()), this, SLOT(FollowBranch()));
menu.addAction(followBranch);
menu.addSeparator();
//QAction *showDynarecResults = new QAction(tr("&Show Dynarec Results"), this);
//connect(showDynarecResults, SIGNAL(triggered()), this, SLOT(ShowDynarecResults()));
//menu.addAction(showDynarecResults);
QAction *goToMemoryView = new QAction(tr("Go to in &Memory View"), this);
connect(goToMemoryView, SIGNAL(triggered()), this, SLOT(GoToMemoryView()));
menu.addAction(goToMemoryView);
menu.addSeparator();
//QAction *killFunction = new QAction(tr("&Kill function"), this);
//connect(killFunction, SIGNAL(triggered()), this, SLOT(KillFunction()));
//menu.addAction(killFunction);
QAction *renameFunction = new QAction(tr("&Rename function..."), this);
connect(renameFunction, SIGNAL(triggered()), this, SLOT(RenameFunction()));
menu.addAction(renameFunction);
menu.exec( mapToGlobal(pos));
}
void CtrlDisAsmView::GoToMemoryView()
{
parentWindow->ShowMemory(selection);
}
void CtrlDisAsmView::CopyAddress()
{
QApplication::clipboard()->setText(QString("%1").arg(selection,8,16,QChar('0')));
}
void CtrlDisAsmView::CopyInstrDisAsm()
{
QApplication::clipboard()->setText(debugger->disasm(selection,align));
}
void CtrlDisAsmView::CopyInstrHex()
{
QApplication::clipboard()->setText(QString("%1").arg(debugger->readMemory(selection),8,16,QChar('0')));
}
void CtrlDisAsmView::SetNextStatement()
{
debugger->setPC(selection);
redraw();
}
void CtrlDisAsmView::ToggleBreakpoint()
{
debugger->toggleBreakpoint(selection);
parentWindow->Update();
redraw();
}
void CtrlDisAsmView::FollowBranch()
{
const char *temp = debugger->disasm(selection,align);;
const char *mojs=strstr(temp,"->$");
if (mojs)
{
u32 dest;
sscanf(mojs+3,"%08x",&dest);
if (dest)
{
marker = selection;
gotoAddr(dest);
}
}
}
void CtrlDisAsmView::RunToHere()
{
debugger->setBreakpoint(selection);
debugger->runToBreakpoint();
redraw();
}
void CtrlDisAsmView::RenameFunction()
{
int sym = symbolMap.GetSymbolNum(selection);
if (sym != -1)
{
QString name = symbolMap.GetSymbolName(sym);
bool ok;
QString newname = QInputDialog::getText(this, tr("New function name"),
tr("New function name:"), QLineEdit::Normal,
name, &ok);
if (ok && !newname.isEmpty())
{
symbolMap.SetSymbolName(sym,newname.toStdString().c_str());
redraw();
parentWindow->NotifyMapLoaded();
}
}
else
{
QMessageBox::information(this,tr("Warning"),tr("No symbol selected"),QMessageBox::Ok);
}
}
void CtrlDisAsmView::paintEvent(QPaintEvent *)
{
QPainter painter(this);
painter.setBrush(Qt::white);
painter.setPen(Qt::white);
painter.drawRect(rect());
struct branch
{
int src,dst,srcAddr;
bool conditional;
};
branch branches[256];
int numBranches=0;
int width = rect().width();
int numRows=(rect().height()/rowHeight);
QColor bgColor(0xFFFFFFFF);
QPen nullPen(bgColor);
QPen currentPen(QColor(0,0,0));
QPen selPen(QColor(0xFF808080));
QPen condPen(QColor(0xFFFF3020));
QBrush lbr;
lbr.setColor(bgColor);
QBrush currentBrush(QColor(0xFFFFEfE8));
QBrush pcBrush(QColor(0xFF70FF70));
QFont normalFont("Arial", 10);
QFont boldFont("Arial", 10);
QFont alignedFont("Monospace", 10);
alignedFont.setStyleHint(QFont::Monospace);
boldFont.setBold(true);
painter.setFont(normalFont);
QImage breakPoint(":/resources/breakpoint.ico");
int i;
curAddress&=~(align-1);
align=(debugger->getInstructionSize(0));
for (i=0; i<=numRows; i++)
{
unsigned int address=curAddress + (i-(numRows/2))*align;
int rowY1 = rect().top() + rowHeight*i;
int rowY2 = rect().top() + rowHeight*i + rowHeight - 1;
lbr.setColor((unsigned int)marker == address ? QColor(0xFFFFEEE0) : QColor(debugger->getColor(address)));
QColor bg = lbr.color();
painter.setBrush(currentBrush);
painter.setPen(nullPen);
painter.drawRect(0,rowY1,16-1,rowY2-rowY1);
if (selecting && address == (unsigned int)selection)
painter.setPen(selPen);
else
{
if(i==numRows/2)
painter.setPen(currentPen);
else
painter.setPen(bg);
}
painter.setBrush(QBrush(bg));
if (address == debugger->getPC())
{
painter.setBrush(pcBrush);
}
painter.drawRect(16,rowY1,width-16-1,rowY2-rowY1);
painter.setBrush(currentBrush);
QPen textPen(QColor(halfAndHalf(bg.rgba(),0)));
painter.setPen(textPen);
painter.setFont(alignedFont);
painter.drawText(17,rowY1-3+rowHeight,QString("%1").arg(address,8,16,QChar('0')));
painter.setFont(normalFont);
textPen.setColor(QColor(0xFF000000));
painter.setPen(textPen);
if (debugger->isAlive())
{
const char *dizz = debugger->disasm(address, align);
char dis[512];
strcpy(dis, dizz);
char *dis2 = strchr(dis,'\t');
char desc[256]="";
if (dis2)
{
*dis2=0;
dis2++;
const char *mojs=strstr(dis2,"->$");
if (mojs)
{
for (int i=0; i<8; i++)
{
bool found=false;
for (int j=0; j<22; j++)
{
if (mojs[i+3]=="0123456789ABCDEFabcdef"[j])
found=true;
}
if (!found)
{
mojs=0;
break;
}
}
}
if (mojs)
{
int offs;
sscanf(mojs+3,"%08x",&offs);
branches[numBranches].src=rowY1 + rowHeight/2;
branches[numBranches].srcAddr=address/align;
branches[numBranches].dst=(int)(rowY1+((s64)offs-(s64)address)*rowHeight/align + rowHeight/2);
branches[numBranches].conditional = (dis[1]!=0); //unconditional 'b' branch
numBranches++;
const char *t = debugger->getDescription(offs);
if (memcmp(t,"z_",2)==0)
t+=2;
if (memcmp(t,"zz_",3)==0)
t+=3;
sprintf(desc,"-->%s", t);
textPen.setColor(QColor(0xFF600060));
painter.setPen(textPen);
}
else
{
textPen.setColor(QColor(0xFF000000));
painter.setPen(textPen);
}
painter.drawText(149,rowY1-3+rowHeight,QString(dis2));
}
textPen.setColor(QColor(0xFF007000));
painter.setPen(textPen);
painter.setFont(boldFont);
painter.drawText(84,rowY1-3+rowHeight,QString(dis));
painter.setFont(normalFont);
if (desc[0]==0)
{
const char *t = debugger->getDescription(address);
if (memcmp(t,"z_",2)==0)
t+=2;
if (memcmp(t,"zz_",3)==0)
t+=3;
strcpy(desc,t);
}
if (memcmp(desc,"-->",3) == 0)
{
textPen.setColor(QColor(0xFF0000FF));
painter.setPen(textPen);
}
else
{
textPen.setColor(halfAndHalf(halfAndHalf(bg.rgba(),0),bg.rgba()));
painter.setPen(textPen);
}
if (strlen(desc))
painter.drawText(std::max(280,width/3+190),rowY1-3+rowHeight,QString(desc));
if (debugger->isBreakpoint(address))
{
painter.drawImage(2,rowY1+2,breakPoint);
}
}
}
for (i=0; i<numBranches; i++)
{
painter.setPen(branches[i].conditional ? condPen : currentPen);
int x=280+(branches[i].srcAddr%9)*8;
QPoint curPos(x-2,branches[i].src);
if (branches[i].dst<rect().bottom()+200 && branches[i].dst>-200)
{
painter.drawLine(curPos, QPoint(x+2,branches[i].src));
curPos = QPoint(x+2,branches[i].src);
painter.drawLine(curPos, QPoint(x+2,branches[i].dst));
curPos = QPoint(x+2,branches[i].dst);
painter.drawLine(curPos, QPoint(x-4,branches[i].dst));
curPos = QPoint(x,branches[i].dst-4);
painter.drawLine(curPos, QPoint(x-4,branches[i].dst));
curPos = QPoint(x-4,branches[i].dst);
painter.drawLine(curPos, QPoint(x+1,branches[i].dst+5));
}
else
{
painter.drawLine(curPos, QPoint(x+4,branches[i].src));
}
}
}
int CtrlDisAsmView::yToAddress(int y)
{
//int ydiff=y - rect().bottom()/2;//-rowHeight/2;
int ydiff=(int)(floor((float)y / (float)rowHeight));
ydiff -= (rect().height()/rowHeight)/2;
return curAddress + ydiff *align;
}