mirror of
https://github.com/PCSX2/pcsx2.git
synced 2025-12-16 04:08:48 +00:00
1310 lines
34 KiB
C++
1310 lines
34 KiB
C++
/* PCSX2 - PS2 Emulator for PCs
|
|
* Copyright (C) 2002-2014 PCSX2 Dev Team
|
|
*
|
|
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
|
|
* of the GNU Lesser General Public License as published by the Free Software Found-
|
|
* ation, either version 3 of the License, or (at your option) any later version.
|
|
*
|
|
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
|
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
|
* PURPOSE. See the GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License along with PCSX2.
|
|
* If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#include "PrecompiledHeader.h"
|
|
#include "CtrlDisassemblyView.h"
|
|
#include "DebugTools/Breakpoints.h"
|
|
#include "DebugTools/Debug.h"
|
|
#include "DebugTools/MipsAssembler.h"
|
|
|
|
#include "DebugEvents.h"
|
|
#include "BreakpointWindow.h"
|
|
#include "AppConfig.h"
|
|
#include "System.h"
|
|
#include "DisassemblyDialog.h"
|
|
|
|
#include <wx/mstream.h>
|
|
#include <wx/clipbrd.h>
|
|
#include <wx/file.h>
|
|
|
|
#include "Resources/Breakpoint_Active.h"
|
|
#include "Resources/Breakpoint_Inactive.h"
|
|
|
|
wxBEGIN_EVENT_TABLE(CtrlDisassemblyView, wxWindow)
|
|
EVT_PAINT(CtrlDisassemblyView::paintEvent)
|
|
EVT_MOUSEWHEEL(CtrlDisassemblyView::mouseEvent)
|
|
EVT_LEFT_DOWN(CtrlDisassemblyView::mouseEvent)
|
|
EVT_LEFT_DCLICK(CtrlDisassemblyView::mouseEvent)
|
|
EVT_RIGHT_DOWN(CtrlDisassemblyView::mouseEvent)
|
|
EVT_RIGHT_UP(CtrlDisassemblyView::mouseEvent)
|
|
EVT_MOTION(CtrlDisassemblyView::mouseEvent)
|
|
EVT_KEY_DOWN(CtrlDisassemblyView::keydownEvent)
|
|
EVT_CHAR(CtrlDisassemblyView::keydownEvent)
|
|
EVT_SCROLLWIN_LINEUP(CtrlDisassemblyView::scrollbarEvent)
|
|
EVT_SCROLLWIN_LINEDOWN(CtrlDisassemblyView::scrollbarEvent)
|
|
EVT_SCROLLWIN_PAGEUP(CtrlDisassemblyView::scrollbarEvent)
|
|
EVT_SCROLLWIN_PAGEDOWN(CtrlDisassemblyView::scrollbarEvent)
|
|
EVT_SIZE(CtrlDisassemblyView::sizeEvent)
|
|
EVT_SET_FOCUS(CtrlDisassemblyView::focusEvent)
|
|
EVT_KILL_FOCUS(CtrlDisassemblyView::focusEvent)
|
|
wxEND_EVENT_TABLE()
|
|
|
|
enum DisassemblyMenuIdentifiers
|
|
{
|
|
ID_DISASM_COPYADDRESS = 1,
|
|
ID_DISASM_COPYINSTRUCTIONHEX,
|
|
ID_DISASM_COPYINSTRUCTIONDISASM,
|
|
ID_DISASM_DISASSEMBLETOFILE,
|
|
ID_DISASM_ASSEMBLE,
|
|
ID_DISASM_RUNTOHERE,
|
|
ID_DISASM_SETPCTOHERE,
|
|
ID_DISASM_TOGGLEBREAKPOINT,
|
|
ID_DISASM_FOLLOWBRANCH,
|
|
ID_DISASM_GOTOADDRESS,
|
|
ID_DISASM_GOTOINMEMORYVIEW,
|
|
ID_DISASM_KILLFUNCTION,
|
|
ID_DISASM_RENAMEFUNCTION,
|
|
ID_DISASM_REMOVEFUNCTION,
|
|
ID_DISASM_ADDFUNCTION
|
|
};
|
|
|
|
class NonAutoSelectTextCtrl: public wxTextCtrl
|
|
{
|
|
public:
|
|
NonAutoSelectTextCtrl(wxWindow *parent, wxWindowID id,
|
|
const wxString& value = wxEmptyString,
|
|
const wxPoint& pos = wxDefaultPosition,
|
|
const wxSize& size = wxDefaultSize,
|
|
long style = 0,
|
|
const wxValidator& validator = wxDefaultValidator,
|
|
const wxString& name = wxTextCtrlNameStr)
|
|
: wxTextCtrl(parent,id,value,pos,size,style,validator,name)
|
|
{
|
|
|
|
}
|
|
#ifdef _WIN32
|
|
|
|
#define WM_GETDLGCODE 0x0087
|
|
#define DLGC_HASSETSEL 0x0008
|
|
|
|
virtual WXLRESULT MSWWindowProc(WXUINT nMsg, WXWPARAM wParam, WXLPARAM lParam)
|
|
{
|
|
WXLRESULT result = wxTextCtrl::MSWWindowProc(nMsg,wParam,lParam);
|
|
if (nMsg == WM_GETDLGCODE)
|
|
result &= ~DLGC_HASSETSEL;
|
|
return result;
|
|
}
|
|
#endif
|
|
};
|
|
|
|
class TextEntryDialog: public wxDialog
|
|
{
|
|
public:
|
|
TextEntryDialog(wxWindow* parent, wxString title, wxString defaultText)
|
|
: wxDialog(parent,wxID_ANY,title)
|
|
{
|
|
wxBoxSizer* sizer = new wxBoxSizer(wxVERTICAL);
|
|
|
|
textControl = new NonAutoSelectTextCtrl(this,wxID_ANY,L"",wxDefaultPosition,wxDefaultSize,0);
|
|
textControl->SetValue(defaultText);
|
|
textControl->SetSelection(textControl->GetLastPosition(),textControl->GetLastPosition());
|
|
sizer->Add(textControl,0,wxEXPAND);
|
|
|
|
wxBoxSizer* buttons = new wxBoxSizer(wxHORIZONTAL);
|
|
okButton = new wxButton(this,wxID_OK,L"OK");
|
|
okButton->SetDefault();
|
|
cancelButton = new wxButton(this,wxID_CANCEL,L"Cancel");
|
|
|
|
buttons->Add(okButton);
|
|
buttons->Add(cancelButton);
|
|
sizer->Add(buttons,0,wxEXPAND);
|
|
|
|
SetSizer(sizer);
|
|
sizer->Layout();
|
|
sizer->Fit(this);
|
|
|
|
textControl->SetFocus();
|
|
textControl->SetFocusFromKbd();
|
|
}
|
|
wxString getText() { return textControl->GetValue(); }
|
|
|
|
private:
|
|
NonAutoSelectTextCtrl* textControl;
|
|
wxButton* okButton;
|
|
wxButton* cancelButton;
|
|
};
|
|
|
|
inline wxIcon _wxGetIconFromMemory(const unsigned char *data, int length) {
|
|
wxMemoryInputStream is(data, length);
|
|
wxBitmap b = wxBitmap(wxImage(is, wxBITMAP_TYPE_ANY, -1), -1);
|
|
wxIcon icon;
|
|
icon.CopyFromBitmap(b);
|
|
return icon;
|
|
}
|
|
|
|
CtrlDisassemblyView::CtrlDisassemblyView(wxWindow* parent, DebugInterface* _cpu)
|
|
: wxWindow(parent,wxID_ANY,wxDefaultPosition,wxDefaultSize,wxWANTS_CHARS|wxBORDER_SIMPLE|wxVSCROLL), cpu(_cpu)
|
|
{
|
|
manager.setCpu(cpu);
|
|
windowStart = 0x100000;
|
|
rowHeight = getDebugFontHeight()+2;
|
|
charWidth = getDebugFontWidth();
|
|
displaySymbols = true;
|
|
visibleRows = 1;
|
|
|
|
bpEnabled = _wxGetIconFromMemory(res_Breakpoint_Active::Data,res_Breakpoint_Active::Length);
|
|
bpDisabled = _wxGetIconFromMemory(res_Breakpoint_Inactive::Data,res_Breakpoint_Inactive::Length);
|
|
|
|
menu.Append(ID_DISASM_COPYADDRESS, L"Copy Address");
|
|
menu.Append(ID_DISASM_COPYINSTRUCTIONHEX, L"Copy Instruction (Hex)");
|
|
menu.Append(ID_DISASM_COPYINSTRUCTIONDISASM, L"Copy Instruction (Disasm)");
|
|
menu.Append(ID_DISASM_DISASSEMBLETOFILE, L"Disassemble to File");
|
|
menu.AppendSeparator();
|
|
menu.Append(ID_DISASM_ASSEMBLE, L"Assemble Opcode");
|
|
menu.AppendSeparator();
|
|
menu.Append(ID_DISASM_RUNTOHERE, L"Run to Cursor");
|
|
menu.Append(ID_DISASM_SETPCTOHERE, L"Jump to Cursor");
|
|
menu.Append(ID_DISASM_TOGGLEBREAKPOINT, L"Toggle Breakpoint");
|
|
menu.Append(ID_DISASM_FOLLOWBRANCH, L"Follow Branch");
|
|
menu.AppendSeparator();
|
|
menu.Append(ID_DISASM_GOTOADDRESS, L"Go to Address");
|
|
menu.Append(ID_DISASM_GOTOINMEMORYVIEW, L"Go to in Memory View");
|
|
menu.AppendSeparator();
|
|
menu.Append(ID_DISASM_ADDFUNCTION, L"Add Function Here");
|
|
menu.Append(ID_DISASM_RENAMEFUNCTION, L"Rename Function");
|
|
menu.Append(ID_DISASM_REMOVEFUNCTION, L"Remove Function");
|
|
menu.Bind(wxEVT_MENU, &CtrlDisassemblyView::onPopupClick, this);
|
|
|
|
SetScrollbar(wxVERTICAL,100,1,201,true);
|
|
SetDoubleBuffered(true);
|
|
calculatePixelPositions();
|
|
setCurAddress(windowStart);
|
|
}
|
|
|
|
#ifdef _WIN32
|
|
WXLRESULT CtrlDisassemblyView::MSWWindowProc(WXUINT nMsg, WXWPARAM wParam, WXLPARAM lParam)
|
|
{
|
|
switch (nMsg)
|
|
{
|
|
case 0x0104: // WM_SYSKEYDOWN, make f10 usable
|
|
if (wParam == 0x79) // f10
|
|
{
|
|
postEvent(debEVT_STEPOVER,0);
|
|
return 0;
|
|
}
|
|
break;
|
|
}
|
|
|
|
return wxWindow::MSWWindowProc(nMsg,wParam,lParam);
|
|
}
|
|
#endif
|
|
|
|
void CtrlDisassemblyView::scanFunctions()
|
|
{
|
|
if (!cpu->isAlive())
|
|
return;
|
|
|
|
manager.analyze(windowStart,manager.getNthNextAddress(windowStart,visibleRows)-windowStart);
|
|
}
|
|
|
|
void CtrlDisassemblyView::postEvent(wxEventType type, wxString text)
|
|
{
|
|
wxCommandEvent event( type, GetId() );
|
|
event.SetEventObject(this);
|
|
event.SetClientData(cpu);
|
|
event.SetString(text);
|
|
wxPostEvent(this,event);
|
|
}
|
|
|
|
void CtrlDisassemblyView::postEvent(wxEventType type, int value)
|
|
{
|
|
wxCommandEvent event( type, GetId() );
|
|
event.SetEventObject(this);
|
|
event.SetClientData(cpu);
|
|
event.SetInt(value);
|
|
wxPostEvent(this,event);
|
|
}
|
|
|
|
void CtrlDisassemblyView::paintEvent(wxPaintEvent & evt)
|
|
{
|
|
wxPaintDC dc(this);
|
|
render(dc);
|
|
}
|
|
|
|
void CtrlDisassemblyView::redraw()
|
|
{
|
|
wxClientDC dc(this);
|
|
render(dc);
|
|
}
|
|
|
|
bool CtrlDisassemblyView::getDisasmAddressText(u32 address, char* dest, bool abbreviateLabels, bool showData)
|
|
{
|
|
if (displaySymbols)
|
|
{
|
|
const std::string addressSymbol = symbolMap.GetLabelString(address);
|
|
if (!addressSymbol.empty())
|
|
{
|
|
for (int k = 0; addressSymbol[k] != 0; k++)
|
|
{
|
|
// abbreviate long names
|
|
if (abbreviateLabels && k == 16 && addressSymbol[k+1] != 0)
|
|
{
|
|
*dest++ = '+';
|
|
break;
|
|
}
|
|
*dest++ = addressSymbol[k];
|
|
}
|
|
*dest++ = ':';
|
|
*dest = 0;
|
|
return true;
|
|
} else {
|
|
sprintf(dest," %08X",address);
|
|
return false;
|
|
}
|
|
} else {
|
|
if (showData)
|
|
sprintf(dest,"%08X %08X",address,cpu->read32(address));
|
|
else
|
|
sprintf(dest,"%08X",address);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
wxColor scaleColor(wxColor color, float factor)
|
|
{
|
|
unsigned char r = color.Red();
|
|
unsigned char g = color.Green();
|
|
unsigned char b = color.Blue();
|
|
unsigned char a = color.Alpha();
|
|
|
|
r = std::min(255,std::max((int)(r*factor),0));
|
|
g = std::min(255,std::max((int)(g*factor),0));
|
|
b = std::min(255,std::max((int)(b*factor),0));
|
|
|
|
return wxColor(r,g,b,a);
|
|
}
|
|
|
|
void CtrlDisassemblyView::drawBranchLine(wxDC& dc, std::map<u32,int>& addressPositions, BranchLine& line)
|
|
{
|
|
u32 windowEnd = manager.getNthNextAddress(windowStart,visibleRows);
|
|
|
|
int winBottom = GetSize().GetHeight();
|
|
|
|
int topY;
|
|
int bottomY;
|
|
if (line.first < windowStart)
|
|
{
|
|
topY = -1;
|
|
} else if (line.first >= windowEnd)
|
|
{
|
|
topY = GetSize().GetHeight()+1;
|
|
} else {
|
|
topY = addressPositions[line.first] + rowHeight/2;
|
|
}
|
|
|
|
if (line.second < windowStart)
|
|
{
|
|
bottomY = -1;
|
|
} else if (line.second >= windowEnd)
|
|
{
|
|
bottomY = GetSize().GetHeight()+1;
|
|
} else {
|
|
bottomY = addressPositions[line.second] + rowHeight/2;
|
|
}
|
|
|
|
if ((topY < 0 && bottomY < 0) || (topY > winBottom && bottomY > winBottom))
|
|
{
|
|
return;
|
|
}
|
|
|
|
// highlight line in a different color if it affects the currently selected opcode
|
|
wxColor color;
|
|
if (line.first == curAddress || line.second == curAddress)
|
|
{
|
|
color = wxColor(0xFF257AFA);
|
|
} else {
|
|
color = wxColor(0xFFFF3020);
|
|
}
|
|
|
|
wxPen pen = wxPen(color);
|
|
dc.SetBrush(wxBrush(color));
|
|
dc.SetPen(wxPen(color));
|
|
|
|
int x = pixelPositions.arrowsStart+line.laneIndex*8;
|
|
|
|
if (topY < 0) // first is not visible, but second is
|
|
{
|
|
dc.DrawLine(x-2,bottomY,x+2,bottomY);
|
|
dc.DrawLine(x+2,bottomY,x+2,0);
|
|
|
|
if (line.type == LINE_DOWN)
|
|
{
|
|
dc.DrawLine(x,bottomY-4,x-4,bottomY);
|
|
dc.DrawLine(x-4,bottomY,x+1,bottomY+5);
|
|
}
|
|
} else if (bottomY > winBottom) // second is not visible, but first is
|
|
{
|
|
dc.DrawLine(x-2,topY,x+2,topY);
|
|
dc.DrawLine(x+2,topY,x+2,winBottom);
|
|
|
|
if (line.type == LINE_UP)
|
|
{
|
|
dc.DrawLine(x,topY-4,x-4,topY);
|
|
dc.DrawLine(x-4,topY,x+1,topY+5);
|
|
}
|
|
} else { // both are visible
|
|
if (line.type == LINE_UP)
|
|
{
|
|
dc.DrawLine(x-2,bottomY,x+2,bottomY);
|
|
dc.DrawLine(x+2,bottomY,x+2,topY);
|
|
dc.DrawLine(x+2,topY,x-4,topY);
|
|
|
|
dc.DrawLine(x,topY-4,x-4,topY);
|
|
dc.DrawLine(x-4,topY,x+1,topY+5);
|
|
} else {
|
|
dc.DrawLine(x-2,topY,x+2,topY);
|
|
dc.DrawLine(x+2,topY,x+2,bottomY);
|
|
dc.DrawLine(x+2,bottomY,x-4,bottomY);
|
|
|
|
dc.DrawLine(x,bottomY-4,x-4,bottomY);
|
|
dc.DrawLine(x-4,bottomY,x+1,bottomY+5);
|
|
}
|
|
}
|
|
}
|
|
|
|
int getBackgroundColor(unsigned int address)
|
|
{
|
|
u32 colors[6] = {0xFFe0FFFF,0xFFFFe0e0,0xFFe8e8FF,0xFFFFe0FF,0xFFe0FFe0,0xFFFFFFe0};
|
|
int n=symbolMap.GetFunctionNum(address);
|
|
if (n==-1) return 0xFFFFFFFF;
|
|
return colors[n%6];
|
|
}
|
|
|
|
std::set<std::string> CtrlDisassemblyView::getSelectedLineArguments() {
|
|
std::set<std::string> args;
|
|
|
|
DisassemblyLineInfo line = DisassemblyLineInfo();
|
|
for (u32 addr = selectRangeStart; addr < selectRangeEnd; addr += 4) {
|
|
manager.getLine(addr, displaySymbols, line);
|
|
size_t p = 0, nextp = line.params.find(',');
|
|
while (nextp != line.params.npos) {
|
|
args.insert(line.params.substr(p, nextp - p));
|
|
p = nextp + 1;
|
|
nextp = line.params.find(',', p);
|
|
}
|
|
|
|
if (p < line.params.size()) {
|
|
args.insert(line.params.substr(p));
|
|
}
|
|
|
|
// check for registers in memory opcodes
|
|
p = line.params.find('(');
|
|
nextp = line.params.find(')');
|
|
if (p != line.params.npos && nextp != line.params.npos && nextp > p) {
|
|
args.insert(line.params.substr(p+1, nextp - p - 1));
|
|
}
|
|
|
|
}
|
|
|
|
return args;
|
|
}
|
|
|
|
void CtrlDisassemblyView::drawArguments(wxDC& dc, const DisassemblyLineInfo &line, int x, int y, wxColor& textColor,
|
|
const std::set<std::string> ¤tArguments)
|
|
{
|
|
if (line.params.empty())
|
|
return;
|
|
|
|
// Don't highlight the selected lines.
|
|
if (isInInterval(selectRangeStart, selectRangeEnd - selectRangeStart, line.info.opcodeAddress))
|
|
{
|
|
dc.DrawText(wxString(line.params.c_str(),wxConvUTF8),x,y);
|
|
return;
|
|
}
|
|
|
|
wxColor highlightedColor = wxColor(textColor == 0xFF0000FF ? 0xFFAABB77 : 0xFFAABB00);
|
|
|
|
size_t p = 0, nextp = line.params.find(',');
|
|
while (nextp != line.params.npos) {
|
|
const std::string arg = line.params.substr(p, nextp - p);
|
|
if (currentArguments.find(arg) != currentArguments.end() && textColor != 0xFFFFFFFF)
|
|
{
|
|
dc.SetTextForeground(highlightedColor);
|
|
}
|
|
dc.DrawText(wxString(arg.c_str(),wxConvUTF8),x,y);
|
|
x += arg.size()*charWidth;
|
|
|
|
p = nextp + 1;
|
|
nextp = line.params.find(',', p);
|
|
|
|
dc.SetTextForeground(textColor);
|
|
dc.DrawText(L",",x,y);
|
|
x += charWidth;
|
|
}
|
|
if (p < line.params.size()) {
|
|
const std::string arg = line.params.substr(p);
|
|
if (currentArguments.find(arg) != currentArguments.end() && textColor != 0xFFFFFFFF)
|
|
{
|
|
dc.SetTextForeground(highlightedColor);
|
|
}
|
|
dc.DrawText(wxString(arg.c_str(),wxConvUTF8),x,y);
|
|
dc.SetTextForeground(textColor);
|
|
}
|
|
}
|
|
|
|
void CtrlDisassemblyView::render(wxDC& dc)
|
|
{
|
|
// init stuff
|
|
int totalWidth, totalHeight;
|
|
GetSize(&totalWidth,&totalHeight);
|
|
visibleRows = totalHeight / rowHeight;
|
|
|
|
// clear background
|
|
wxColor white = wxColor(0xFFFFFFFF);
|
|
|
|
dc.SetBrush(wxBrush(white));
|
|
dc.SetPen(wxPen(white));
|
|
|
|
int width,height;
|
|
dc.GetSize(&width,&height);
|
|
dc.DrawRectangle(0, 0, width, height);
|
|
|
|
if (!cpu->isAlive())
|
|
return;
|
|
|
|
wxFont font = pxGetFixedFont(8);
|
|
wxFont boldFont = pxGetFixedFont(8, wxFONTWEIGHT_BOLD);
|
|
font.SetPixelSize(wxSize(charWidth,rowHeight-2));
|
|
boldFont.SetPixelSize(wxSize(charWidth,rowHeight-2));
|
|
|
|
bool hasFocus = wxWindow::FindFocus() == this;
|
|
|
|
std::map<u32,int> addressPositions;
|
|
|
|
unsigned int address = windowStart;
|
|
|
|
const std::set<std::string> currentArguments = getSelectedLineArguments();
|
|
DisassemblyLineInfo line = DisassemblyLineInfo();
|
|
for (int i = 0; i < visibleRows+1; i++)
|
|
{
|
|
manager.getLine(address,displaySymbols,line);
|
|
|
|
int rowY1 = rowHeight*i;
|
|
|
|
addressPositions[address] = rowY1;
|
|
|
|
wxColor backgroundColor = wxColor(getBackgroundColor(address));
|
|
wxColor textColor = wxColor(0xFF000000);
|
|
|
|
if (isInInterval(address,line.totalSize,cpu->getPC()))
|
|
{
|
|
backgroundColor = scaleColor(backgroundColor,1.05f);
|
|
}
|
|
|
|
if (address >= selectRangeStart && address < selectRangeEnd)
|
|
{
|
|
if (hasFocus)
|
|
{
|
|
backgroundColor = address == curAddress ? 0xFFFF8822 : 0xFFFF9933;
|
|
textColor = 0xFFFFFFFF;
|
|
} else {
|
|
backgroundColor = 0xFFC0C0C0;
|
|
}
|
|
}
|
|
|
|
// display whether the condition of a branch is met
|
|
if (line.info.isConditional && address == cpu->getPC())
|
|
{
|
|
line.params += line.info.conditionMet ? " ; true" : " ; false";
|
|
}
|
|
|
|
// draw background
|
|
dc.SetBrush(wxBrush(backgroundColor));
|
|
dc.SetPen(wxPen(backgroundColor));
|
|
dc.DrawRectangle(0,rowY1,totalWidth,rowHeight);
|
|
|
|
// display address/symbol
|
|
bool enabled;
|
|
if (CBreakPoints::IsAddressBreakPoint(cpu->getCpuType(),address,&enabled))
|
|
{
|
|
if (enabled)
|
|
textColor = 0x0000FF;
|
|
int yOffset = std::max(-1,(rowHeight-14+1)/2);
|
|
dc.DrawIcon(enabled ? bpEnabled : bpDisabled,2,rowY1+1+yOffset);
|
|
}
|
|
|
|
dc.SetTextForeground(textColor);
|
|
|
|
char addressText[64];
|
|
getDisasmAddressText(address,addressText,true,line.type == DISTYPE_OPCODE);
|
|
|
|
dc.SetFont(font);
|
|
dc.DrawText(wxString(addressText,wxConvUTF8),pixelPositions.addressStart,rowY1+2);
|
|
drawArguments(dc, line, pixelPositions.argumentsStart, rowY1 + 2, textColor, currentArguments);
|
|
|
|
if (isInInterval(address,line.totalSize,cpu->getPC()))
|
|
dc.DrawText(L"\u25A0",pixelPositions.opcodeStart-(charWidth+1),rowY1);
|
|
|
|
dc.SetFont(boldFont);
|
|
dc.DrawText(wxString(line.name.c_str(),wxConvUTF8),pixelPositions.opcodeStart,rowY1+2);
|
|
|
|
address += line.totalSize;
|
|
}
|
|
|
|
std::vector<BranchLine> branchLines = manager.getBranchLines(windowStart,address-windowStart);
|
|
for (size_t i = 0; i < branchLines.size(); i++)
|
|
{
|
|
drawBranchLine(dc,addressPositions,branchLines[i]);
|
|
}
|
|
|
|
}
|
|
|
|
void CtrlDisassemblyView::gotoAddress(u32 addr)
|
|
{
|
|
u32 windowEnd = manager.getNthNextAddress(windowStart,visibleRows);
|
|
u32 newAddress = manager.getStartAddress(addr);
|
|
|
|
if (newAddress < windowStart || newAddress >= windowEnd)
|
|
{
|
|
windowStart = manager.getNthPreviousAddress(newAddress,visibleRows/2);
|
|
}
|
|
|
|
setCurAddress(addr);
|
|
scanFunctions();
|
|
redraw();
|
|
}
|
|
|
|
void CtrlDisassemblyView::scrollAddressIntoView()
|
|
{
|
|
u32 windowEnd = manager.getNthNextAddress(windowStart,visibleRows);
|
|
|
|
if (curAddress < windowStart)
|
|
windowStart = curAddress;
|
|
else if (curAddress >= windowEnd)
|
|
windowStart = manager.getNthPreviousAddress(curAddress,visibleRows-1);
|
|
|
|
scanFunctions();
|
|
}
|
|
|
|
void CtrlDisassemblyView::calculatePixelPositions()
|
|
{
|
|
pixelPositions.addressStart = 16;
|
|
pixelPositions.opcodeStart = pixelPositions.addressStart + 18*charWidth;
|
|
pixelPositions.argumentsStart = pixelPositions.opcodeStart + 9*charWidth;
|
|
pixelPositions.arrowsStart = pixelPositions.argumentsStart + 30*charWidth;
|
|
}
|
|
|
|
|
|
void CtrlDisassemblyView::followBranch()
|
|
{
|
|
DisassemblyLineInfo line = DisassemblyLineInfo();
|
|
manager.getLine(curAddress,true,line);
|
|
|
|
if (line.type == DISTYPE_OPCODE || line.type == DISTYPE_MACRO)
|
|
{
|
|
if (line.info.isBranch)
|
|
{
|
|
jumpStack.push_back(curAddress);
|
|
gotoAddress(line.info.branchTarget);
|
|
} else if (line.info.hasRelevantAddress)
|
|
{
|
|
// well, not exactly a branch, but we can do something anyway
|
|
postEvent(debEVT_GOTOINMEMORYVIEW,line.info.releventAddress);
|
|
}
|
|
} else if (line.type == DISTYPE_DATA)
|
|
{
|
|
// jump to the start of the current line
|
|
postEvent(debEVT_GOTOINMEMORYVIEW,curAddress);
|
|
}
|
|
}
|
|
|
|
void CtrlDisassemblyView::assembleOpcode(u32 address, std::string defaultText)
|
|
{
|
|
u32 encoded;
|
|
|
|
if (!cpu->isCpuPaused())
|
|
{
|
|
wxMessageBox( L"Cannot change code while the core is running", L"Error.", wxICON_ERROR);
|
|
return;
|
|
}
|
|
|
|
TextEntryDialog entry(this,L"Assemble opcode",wxString(defaultText.c_str(),wxConvUTF8));
|
|
entry.Layout();
|
|
|
|
if (entry.ShowModal() != wxID_OK)
|
|
return;
|
|
|
|
wxString op = entry.getText();
|
|
std::string errorText;
|
|
bool result = MipsAssembleOpcode(op.To8BitData(),cpu,address,encoded,errorText);
|
|
if (result)
|
|
{
|
|
SysClearExecutionCache();
|
|
cpu->write32(address,encoded);
|
|
|
|
if (address == curAddress)
|
|
gotoAddress(manager.getNthNextAddress(curAddress,1));
|
|
|
|
redraw();
|
|
} else {
|
|
wxMessageBox( wxString(errorText.c_str(),wxConvUTF8), L"Error.", wxICON_ERROR);
|
|
}
|
|
}
|
|
|
|
|
|
void CtrlDisassemblyView::onPopupClick(wxCommandEvent& evt)
|
|
{
|
|
switch (evt.GetId())
|
|
{
|
|
case ID_DISASM_FOLLOWBRANCH:
|
|
followBranch();
|
|
break;
|
|
case ID_DISASM_COPYADDRESS:
|
|
if (wxTheClipboard->Open())
|
|
{
|
|
wchar_t text[64];
|
|
swprintf(text,64,L"%08X",curAddress);
|
|
|
|
wxTheClipboard->SetData(new wxTextDataObject(text));
|
|
wxTheClipboard->Close();
|
|
}
|
|
break;
|
|
case ID_DISASM_GOTOADDRESS:
|
|
postEvent(debEVT_GOTOADDRESS, 0);
|
|
break;
|
|
case ID_DISASM_GOTOINMEMORYVIEW:
|
|
postEvent(debEVT_GOTOINMEMORYVIEW,curAddress);
|
|
break;
|
|
case ID_DISASM_COPYINSTRUCTIONHEX:
|
|
copyInstructions(selectRangeStart,selectRangeEnd,false);
|
|
break;
|
|
case ID_DISASM_COPYINSTRUCTIONDISASM:
|
|
copyInstructions(selectRangeStart,selectRangeEnd,true);
|
|
break;
|
|
case ID_DISASM_SETPCTOHERE:
|
|
cpu->setPc(curAddress);
|
|
redraw();
|
|
break;
|
|
case ID_DISASM_RUNTOHERE:
|
|
postEvent(debEVT_RUNTOPOS,curAddress);
|
|
break;
|
|
case ID_DISASM_TOGGLEBREAKPOINT:
|
|
toggleBreakpoint(false);
|
|
break;
|
|
case ID_DISASM_DISASSEMBLETOFILE:
|
|
disassembleToFile();
|
|
break;
|
|
case ID_DISASM_RENAMEFUNCTION:
|
|
{
|
|
u32 funcBegin = symbolMap.GetFunctionStart(curAddress);
|
|
if (funcBegin != 0xFFFFFFFF)
|
|
{
|
|
wxString newName = wxGetTextFromUser(L"Enter the new function name",L"New function name",
|
|
wxString(symbolMap.GetLabelString(funcBegin).c_str(),wxConvUTF8),this);
|
|
|
|
if (!newName.empty())
|
|
{
|
|
const wxCharBuffer converted = newName.ToUTF8();
|
|
symbolMap.SetLabelName(converted,funcBegin);
|
|
postEvent(debEVT_MAPLOADED,0);
|
|
redraw();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
wxMessageBox(L"No symbol selected",L"Error",wxICON_ERROR);
|
|
}
|
|
break;
|
|
}
|
|
case ID_DISASM_REMOVEFUNCTION:
|
|
{
|
|
u32 funcBegin = symbolMap.GetFunctionStart(curAddress);
|
|
if (funcBegin != 0xFFFFFFFF)
|
|
{
|
|
u32 prevBegin = symbolMap.GetFunctionStart(funcBegin-1);
|
|
if (prevBegin != 0xFFFFFFFF)
|
|
{
|
|
u32 expandedSize = symbolMap.GetFunctionSize(prevBegin)+symbolMap.GetFunctionSize(funcBegin);
|
|
symbolMap.SetFunctionSize(prevBegin,expandedSize);
|
|
}
|
|
|
|
symbolMap.RemoveFunction(funcBegin,true);
|
|
symbolMap.SortSymbols();
|
|
symbolMap.UpdateActiveSymbols();
|
|
manager.clear();
|
|
|
|
postEvent(debEVT_MAPLOADED,0);
|
|
}
|
|
else
|
|
{
|
|
postEvent(debEVT_SETSTATUSBARTEXT,L"WARNING: unable to find function symbol here");
|
|
}
|
|
|
|
redraw();
|
|
break;
|
|
}
|
|
case ID_DISASM_ADDFUNCTION:
|
|
{
|
|
u32 prevBegin = symbolMap.GetFunctionStart(curAddress);
|
|
if (prevBegin != 0xFFFFFFFF)
|
|
{
|
|
if (prevBegin == curAddress)
|
|
{
|
|
postEvent(debEVT_SETSTATUSBARTEXT,L"WARNING: There's already a function entry point at this adress");
|
|
}
|
|
else
|
|
{
|
|
char symname[128];
|
|
u32 prevSize = symbolMap.GetFunctionSize(prevBegin);
|
|
u32 newSize = curAddress-prevBegin;
|
|
symbolMap.SetFunctionSize(prevBegin,newSize);
|
|
|
|
newSize = prevSize-newSize;
|
|
sprintf(symname,"u_un_%08X",curAddress);
|
|
symbolMap.AddFunction(symname,curAddress,newSize);
|
|
symbolMap.SortSymbols();
|
|
symbolMap.UpdateActiveSymbols();
|
|
manager.clear();
|
|
|
|
postEvent(debEVT_MAPLOADED,0);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
char symname[128];
|
|
int newSize = selectRangeEnd - selectRangeStart;
|
|
sprintf(symname, "u_un_%08X", selectRangeStart);
|
|
symbolMap.AddFunction(symname, selectRangeStart, newSize);
|
|
symbolMap.SortSymbols();
|
|
symbolMap.UpdateActiveSymbols();
|
|
|
|
postEvent(debEVT_MAPLOADED,0);
|
|
}
|
|
|
|
redraw();
|
|
break;
|
|
}
|
|
case ID_DISASM_ASSEMBLE:
|
|
assembleOpcode(curAddress, disassembleCurAddress());
|
|
break;
|
|
default:
|
|
wxMessageBox( L"Unimplemented.", L"Unimplemented.", wxICON_INFORMATION);
|
|
break;
|
|
}
|
|
}
|
|
|
|
void CtrlDisassemblyView::keydownEvent(wxKeyEvent& evt)
|
|
{
|
|
u32 windowEnd = manager.getNthNextAddress(windowStart,visibleRows);
|
|
|
|
if (evt.ControlDown())
|
|
{
|
|
switch (evt.GetKeyCode())
|
|
{
|
|
case 'd':
|
|
case 'D':
|
|
toggleBreakpoint(true);
|
|
break;
|
|
case 'e':
|
|
case 'E':
|
|
editBreakpoint();
|
|
break;
|
|
case 'b':
|
|
case 'B':
|
|
{
|
|
BreakpointWindow bpw(this,cpu);
|
|
if (bpw.ShowModal() == wxID_OK)
|
|
{
|
|
bpw.addBreakpoint();
|
|
postEvent(debEVT_UPDATE,0);
|
|
}
|
|
}
|
|
break;
|
|
case 'g':
|
|
case 'G':
|
|
{
|
|
u64 addr;
|
|
if (!executeExpressionWindow(this,cpu,addr))
|
|
return;
|
|
gotoAddress(addr);
|
|
}
|
|
break;
|
|
default:
|
|
evt.Skip();
|
|
break;
|
|
}
|
|
} else {
|
|
if (evt.GetEventType() == wxEVT_CHAR && evt.GetKeyCode() >= 0x20 && evt.GetKeyCode() < 0x80)
|
|
{
|
|
std::string str;
|
|
str += (char) evt.GetKeyCode();
|
|
|
|
assembleOpcode(curAddress,str);
|
|
return;
|
|
}
|
|
|
|
switch (evt.GetKeyCode())
|
|
{
|
|
case WXK_LEFT:
|
|
if (jumpStack.empty())
|
|
{
|
|
gotoAddress(cpu->getPC());
|
|
} else {
|
|
u32 addr = jumpStack[jumpStack.size()-1];
|
|
jumpStack.pop_back();
|
|
gotoAddress(addr);
|
|
}
|
|
break;
|
|
case WXK_RIGHT:
|
|
followBranch();
|
|
break;
|
|
case WXK_UP:
|
|
setCurAddress(manager.getNthPreviousAddress(curAddress,1), wxGetKeyState(WXK_SHIFT));
|
|
scrollAddressIntoView();
|
|
scanFunctions();
|
|
break;
|
|
case WXK_DOWN:
|
|
setCurAddress(manager.getNthNextAddress(curAddress,1), wxGetKeyState(WXK_SHIFT));
|
|
scrollAddressIntoView();
|
|
scanFunctions();
|
|
break;
|
|
case WXK_TAB:
|
|
displaySymbols = !displaySymbols;
|
|
break;
|
|
case WXK_PAGEUP:
|
|
if (curAddress != windowStart && curAddressIsVisible()) {
|
|
setCurAddress(windowStart, wxGetKeyState(WXK_SHIFT));
|
|
scrollAddressIntoView();
|
|
} else {
|
|
setCurAddress(manager.getNthPreviousAddress(windowStart,visibleRows), wxGetKeyState(WXK_SHIFT));
|
|
scrollAddressIntoView();
|
|
}
|
|
scanFunctions();
|
|
break;
|
|
case WXK_PAGEDOWN:
|
|
if (manager.getNthNextAddress(curAddress,1) != windowEnd && curAddressIsVisible()) {
|
|
setCurAddress(manager.getNthPreviousAddress(windowEnd,1), wxGetKeyState(WXK_SHIFT));
|
|
scrollAddressIntoView();
|
|
} else {
|
|
setCurAddress(manager.getNthNextAddress(windowEnd,visibleRows-1), wxGetKeyState(WXK_SHIFT));
|
|
scrollAddressIntoView();
|
|
}
|
|
scanFunctions();
|
|
break;
|
|
case WXK_F8:
|
|
postEvent(debEVT_STEPOUT,0);
|
|
break;
|
|
case WXK_F10:
|
|
postEvent(debEVT_STEPOVER,0);
|
|
return;
|
|
case WXK_F11:
|
|
if (evt.ShiftDown())
|
|
postEvent(debEVT_STEPOUT,0);
|
|
else
|
|
postEvent(debEVT_STEPINTO,0);
|
|
return;
|
|
default:
|
|
evt.Skip();
|
|
break;
|
|
}
|
|
}
|
|
|
|
redraw();
|
|
}
|
|
|
|
void CtrlDisassemblyView::scrollbarEvent(wxScrollWinEvent& evt)
|
|
{
|
|
int type = evt.GetEventType();
|
|
if (type == wxEVT_SCROLLWIN_LINEUP)
|
|
{
|
|
windowStart = manager.getNthPreviousAddress(windowStart,1);
|
|
scanFunctions();
|
|
} else if (type == wxEVT_SCROLLWIN_LINEDOWN)
|
|
{
|
|
windowStart = manager.getNthNextAddress(windowStart,1);
|
|
scanFunctions();
|
|
} else if (type == wxEVT_SCROLLWIN_PAGEUP)
|
|
{
|
|
windowStart = manager.getNthPreviousAddress(windowStart,visibleRows);
|
|
scanFunctions();
|
|
} else if (type == wxEVT_SCROLLWIN_PAGEDOWN)
|
|
{
|
|
windowStart = manager.getNthNextAddress(windowStart,visibleRows);
|
|
scanFunctions();
|
|
}
|
|
|
|
redraw();
|
|
}
|
|
|
|
void CtrlDisassemblyView::toggleBreakpoint(bool toggleEnabled)
|
|
{
|
|
bool enabled;
|
|
if (CBreakPoints::IsAddressBreakPoint(cpu->getCpuType(), curAddress,&enabled))
|
|
{
|
|
if (!enabled)
|
|
{
|
|
// enable disabled breakpoints
|
|
CBreakPoints::ChangeBreakPoint(cpu->getCpuType(), curAddress,true);
|
|
} else if (!toggleEnabled && CBreakPoints::GetBreakPointCondition(cpu->getCpuType(), curAddress) != NULL)
|
|
{
|
|
// don't just delete a breakpoint with a custom condition
|
|
CBreakPoints::RemoveBreakPoint(cpu->getCpuType(), curAddress);
|
|
} else if (toggleEnabled)
|
|
{
|
|
// disable breakpoint
|
|
CBreakPoints::ChangeBreakPoint(cpu->getCpuType(), curAddress,false);
|
|
} else {
|
|
// otherwise just remove breakpoint
|
|
CBreakPoints::RemoveBreakPoint(cpu->getCpuType(), curAddress);
|
|
}
|
|
} else {
|
|
CBreakPoints::AddBreakPoint(cpu->getCpuType(), curAddress);
|
|
}
|
|
}
|
|
|
|
|
|
void CtrlDisassemblyView::updateStatusBarText()
|
|
{
|
|
char text[512];
|
|
DisassemblyLineInfo line = DisassemblyLineInfo();
|
|
manager.getLine(curAddress,true,line);
|
|
|
|
text[0] = 0;
|
|
if (line.type == DISTYPE_OPCODE || line.type == DISTYPE_MACRO)
|
|
{
|
|
if (line.info.isDataAccess)
|
|
{
|
|
if (!cpu->isValidAddress(line.info.dataAddress))
|
|
{
|
|
sprintf(text,"Invalid address %08X",line.info.dataAddress);
|
|
} else if (line.info.lrType == MIPSAnalyst::LOADSTORE_NORMAL && line.info.dataAddress % line.info.dataSize)
|
|
{
|
|
sprintf(text,"Unaligned address %08X",line.info.dataAddress);
|
|
} else {
|
|
switch (line.info.dataSize)
|
|
{
|
|
case 1:
|
|
sprintf(text,"[%08X] = %02X",line.info.dataAddress,cpu->read8(line.info.dataAddress));
|
|
break;
|
|
case 2:
|
|
sprintf(text,"[%08X] = %04X",line.info.dataAddress,cpu->read16(line.info.dataAddress));
|
|
break;
|
|
case 4:
|
|
{
|
|
u32 data;
|
|
if (line.info.lrType != MIPSAnalyst::LOADSTORE_NORMAL)
|
|
{
|
|
u32 address = line.info.dataAddress;
|
|
data = cpu->read32(address & ~3) >> (address & 3) * 8;
|
|
data |= cpu->read32((address + 3) & ~3) << (4 - (address & 3)) * 8;
|
|
} else {
|
|
data = cpu->read32(line.info.dataAddress);
|
|
}
|
|
|
|
const std::string addressSymbol = symbolMap.GetLabelString(data);
|
|
if (!addressSymbol.empty())
|
|
{
|
|
sprintf(text,"[%08X] = %s (%08X)",line.info.dataAddress,addressSymbol.c_str(),data);
|
|
} else {
|
|
sprintf(text,"[%08X] = %08X",line.info.dataAddress,data);
|
|
}
|
|
break;
|
|
}
|
|
case 8:
|
|
{
|
|
u64 data;
|
|
if (line.info.lrType != MIPSAnalyst::LOADSTORE_NORMAL)
|
|
{
|
|
u32 address = line.info.dataAddress;
|
|
data = cpu->read64(address & ~7) >> (address & 7) * 8;
|
|
data |= cpu->read64((address + 7) & ~7) << (8 - (address & 7)) * 8;
|
|
} else {
|
|
data = cpu->read64(line.info.dataAddress);
|
|
}
|
|
|
|
sprintf(text,"[%08X] = %016" PRIX64,line.info.dataAddress,data);
|
|
break;
|
|
}
|
|
case 16:
|
|
{
|
|
__aligned16 u128 data = cpu->read128(line.info.dataAddress);
|
|
sprintf(text,"[%08X] = %016" PRIX64 "%016" PRIX64,line.info.dataAddress,data._u64[1],data._u64[0]);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (line.info.isBranch)
|
|
{
|
|
const std::string addressSymbol = symbolMap.GetLabelString(line.info.branchTarget);
|
|
if (addressSymbol.empty())
|
|
{
|
|
sprintf(text,"%08X",line.info.branchTarget);
|
|
} else {
|
|
sprintf(text,"%08X = %s",line.info.branchTarget,addressSymbol.c_str());
|
|
}
|
|
}
|
|
} else if (line.type == DISTYPE_DATA)
|
|
{
|
|
u32 start = symbolMap.GetDataStart(curAddress);
|
|
if (start == 0xFFFFFFFF)
|
|
start = curAddress;
|
|
|
|
u32 diff = curAddress-start;
|
|
const std::string label = symbolMap.GetLabelString(start);
|
|
|
|
if (!label.empty())
|
|
{
|
|
if (diff != 0)
|
|
sprintf(text,"%08X (%s) + %08X",start,label.c_str(),diff);
|
|
else
|
|
sprintf(text,"%08X (%s)",start,label.c_str());
|
|
} else {
|
|
if (diff != 0)
|
|
sprintf(text,"%08X + %08X",start,diff);
|
|
else
|
|
sprintf(text,"%08X",start);
|
|
}
|
|
}
|
|
|
|
postEvent(debEVT_SETSTATUSBARTEXT,wxString(text,wxConvUTF8));
|
|
}
|
|
|
|
void CtrlDisassemblyView::mouseEvent(wxMouseEvent& evt)
|
|
{
|
|
// left button
|
|
wxEventType type = evt.GetEventType();
|
|
bool hasFocus = wxWindow::FindFocus() == this;
|
|
|
|
if (type == wxEVT_LEFT_DOWN || type == wxEVT_LEFT_DCLICK || type == wxEVT_RIGHT_DOWN )
|
|
{
|
|
u32 newAddress = yToAddress(evt.GetY());
|
|
bool extend = wxGetKeyState(WXK_SHIFT);
|
|
|
|
if (type == wxEVT_RIGHT_DOWN)
|
|
{
|
|
// Maintain the current selection if right clicking into it.
|
|
if (newAddress >= selectRangeStart && newAddress < selectRangeEnd)
|
|
extend = true;
|
|
} else {
|
|
if (curAddress == newAddress && hasFocus)
|
|
toggleBreakpoint(false);
|
|
}
|
|
|
|
setCurAddress(newAddress,extend);
|
|
SetFocus();
|
|
SetFocusFromKbd();
|
|
} else if (evt.GetEventType() == wxEVT_RIGHT_UP)
|
|
{
|
|
PopupMenu(&menu,evt.GetPosition());
|
|
return;
|
|
} else if (evt.GetEventType() == wxEVT_MOUSEWHEEL)
|
|
{
|
|
if (evt.GetWheelRotation() > 0)
|
|
{
|
|
windowStart = manager.getNthPreviousAddress(windowStart,3);
|
|
scanFunctions();
|
|
} else if (evt.GetWheelRotation() < 0) {
|
|
windowStart = manager.getNthNextAddress(windowStart,3);
|
|
scanFunctions();
|
|
}
|
|
} else if (evt.GetEventType() == wxEVT_MOTION)
|
|
{
|
|
if (evt.ButtonIsDown(wxMOUSE_BTN_LEFT))
|
|
{
|
|
int newAddress = yToAddress(evt.GetY());
|
|
setCurAddress(newAddress,wxGetKeyState(WXK_SHIFT));
|
|
} else
|
|
return;
|
|
} else {
|
|
evt.Skip();
|
|
return;
|
|
}
|
|
|
|
redraw();
|
|
}
|
|
|
|
void CtrlDisassemblyView::sizeEvent(wxSizeEvent& evt)
|
|
{
|
|
wxSize s = evt.GetSize();
|
|
visibleRows = s.GetWidth()/rowHeight;
|
|
}
|
|
|
|
u32 CtrlDisassemblyView::yToAddress(int y)
|
|
{
|
|
int line = y/rowHeight;
|
|
return manager.getNthNextAddress(windowStart,line);
|
|
}
|
|
|
|
bool CtrlDisassemblyView::curAddressIsVisible()
|
|
{
|
|
u32 windowEnd = manager.getNthNextAddress(windowStart,visibleRows);
|
|
return curAddress >= windowStart && curAddress < windowEnd;
|
|
}
|
|
|
|
void CtrlDisassemblyView::scrollStepping(u32 newPc)
|
|
{
|
|
u32 windowEnd = manager.getNthNextAddress(windowStart,visibleRows);
|
|
|
|
newPc = manager.getStartAddress(newPc);
|
|
if (newPc >= windowEnd || newPc >= manager.getNthPreviousAddress(windowEnd,1))
|
|
{
|
|
windowStart = manager.getNthPreviousAddress(newPc,visibleRows-2);
|
|
}
|
|
}
|
|
|
|
std::string CtrlDisassemblyView::disassembleRange(u32 start, u32 size)
|
|
{
|
|
std::string result;
|
|
|
|
// gather all branch targets without labels
|
|
std::set<u32> branchAddresses;
|
|
for (u32 i = 0; i < size; i += 4)
|
|
{
|
|
MIPSAnalyst::MipsOpcodeInfo info = MIPSAnalyst::GetOpcodeInfo(cpu,start+i);
|
|
|
|
if (info.isBranch && symbolMap.GetLabelString(info.branchTarget).empty())
|
|
{
|
|
if (branchAddresses.find(info.branchTarget) == branchAddresses.end())
|
|
{
|
|
branchAddresses.insert(info.branchTarget);
|
|
}
|
|
}
|
|
}
|
|
|
|
u32 disAddress = start;
|
|
bool previousLabel = true;
|
|
DisassemblyLineInfo line = DisassemblyLineInfo();
|
|
while (disAddress < start+size)
|
|
{
|
|
char addressText[64],buffer[512];
|
|
|
|
manager.getLine(disAddress,displaySymbols,line);
|
|
bool isLabel = getDisasmAddressText(disAddress,addressText,false,line.type == DISTYPE_OPCODE);
|
|
|
|
if (isLabel)
|
|
{
|
|
if (!previousLabel) result += "\r\n";
|
|
sprintf(buffer,"%s\r\n\r\n",addressText);
|
|
result += buffer;
|
|
} else if (branchAddresses.find(disAddress) != branchAddresses.end())
|
|
{
|
|
if (!previousLabel) result += "\r\n";
|
|
sprintf(buffer,"pos_%08X:\r\n\r\n",disAddress);
|
|
result += buffer;
|
|
}
|
|
|
|
if (line.info.isBranch && !line.info.isBranchToRegister
|
|
&& symbolMap.GetLabelString(line.info.branchTarget).empty()
|
|
&& branchAddresses.find(line.info.branchTarget) != branchAddresses.end())
|
|
{
|
|
sprintf(buffer,"pos_%08X",line.info.branchTarget);
|
|
line.params = line.params.substr(0,line.params.find("0x")) + buffer;
|
|
}
|
|
|
|
sprintf(buffer,"\t%s\t%s\r\n",line.name.c_str(),line.params.c_str());
|
|
result += buffer;
|
|
previousLabel = isLabel;
|
|
disAddress += line.totalSize;
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
std::string CtrlDisassemblyView::disassembleCurAddress()
|
|
{
|
|
DisassemblyLineInfo line = DisassemblyLineInfo();
|
|
manager.getLine(curAddress, displaySymbols, line);
|
|
return line.name + (line.params.length() > 0 ? " " + line.params : "");
|
|
}
|
|
|
|
void CtrlDisassemblyView::copyInstructions(u32 startAddr, u32 endAddr, bool withDisasm)
|
|
{
|
|
if (!wxTheClipboard->Open())
|
|
{
|
|
wxMessageBox( L"Could not open clipboard.", L"Error", wxICON_ERROR);
|
|
return;
|
|
}
|
|
|
|
if (!withDisasm)
|
|
{
|
|
int instructionSize = 4;
|
|
int count = (endAddr - startAddr) / instructionSize;
|
|
int space = count * 32;
|
|
char *temp = new char[space];
|
|
|
|
char *p = temp;
|
|
for (u32 pos = startAddr; pos < endAddr; pos += instructionSize)
|
|
{
|
|
p += sprintf(p, "%08X", cpu->read32(pos));
|
|
|
|
// Don't leave a trailing newline.
|
|
if (pos + instructionSize < endAddr)
|
|
p += sprintf(p,"\r\n");
|
|
}
|
|
|
|
wxTheClipboard->SetData(new wxTextDataObject(wxString(temp,wxConvUTF8)));
|
|
delete [] temp;
|
|
} else
|
|
{
|
|
std::string disassembly = disassembleRange(startAddr,endAddr-startAddr);
|
|
wxTheClipboard->SetData(new wxTextDataObject(wxString(disassembly.c_str(),wxConvUTF8)));
|
|
}
|
|
|
|
wxTheClipboard->Close();
|
|
}
|
|
|
|
void CtrlDisassemblyView::disassembleToFile()
|
|
{
|
|
wxFileDialog dlg(this,wxEmptyString,wxEmptyString,wxEmptyString,L"*.*",wxFD_SAVE);
|
|
|
|
if (dlg.ShowModal() == wxID_CANCEL)
|
|
return;
|
|
|
|
std::string disassembly = disassembleRange(selectRangeStart,selectRangeEnd-selectRangeStart);
|
|
wxFile output(dlg.GetPath(),wxFile::write);
|
|
output.Write(wxString(disassembly.c_str(),wxConvUTF8));
|
|
}
|
|
|
|
void CtrlDisassemblyView::editBreakpoint()
|
|
{
|
|
BreakpointWindow win(this,cpu);
|
|
|
|
bool exists = false;
|
|
if (CBreakPoints::IsAddressBreakPoint(cpu->getCpuType(), curAddress))
|
|
{
|
|
auto breakpoints = CBreakPoints::GetBreakpoints();
|
|
for (size_t i = 0; i < breakpoints.size(); i++)
|
|
{
|
|
if (breakpoints[i].addr == curAddress)
|
|
{
|
|
win.loadFromBreakpoint(breakpoints[i]);
|
|
exists = true;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!exists)
|
|
win.initBreakpoint(curAddress);
|
|
|
|
if (win.ShowModal() == wxID_OK)
|
|
{
|
|
if (exists)
|
|
CBreakPoints::RemoveBreakPoint(cpu->getCpuType(), curAddress);
|
|
win.addBreakpoint();
|
|
postEvent(debEVT_UPDATE,0);
|
|
}
|
|
}
|
|
|
|
void CtrlDisassemblyView::getOpcodeText(u32 address, char* dest)
|
|
{
|
|
DisassemblyLineInfo line = DisassemblyLineInfo();
|
|
address = manager.getStartAddress(address);
|
|
manager.getLine(address,displaySymbols,line);
|
|
sprintf(dest,"%s %s",line.name.c_str(),line.params.c_str());
|
|
}
|