Merge pull request #161 from Kingcom/Debugger

Debugger enhancements
This commit is contained in:
Pseudonym 2014-07-30 18:24:38 +01:00
commit e726f82344
10 changed files with 251 additions and 29 deletions

View File

@ -77,7 +77,7 @@ inline wxIcon _wxGetIconFromMemory(const unsigned char *data, int length) {
}
CtrlDisassemblyView::CtrlDisassemblyView(wxWindow* parent, DebugInterface* _cpu)
: wxWindow(parent,wxID_ANY,wxDefaultPosition,wxDefaultSize,wxWANTS_CHARS|wxBORDER|wxVSCROLL), cpu(_cpu)
: wxWindow(parent,wxID_ANY,wxDefaultPosition,wxDefaultSize,wxWANTS_CHARS|wxBORDER_SIMPLE|wxVSCROLL), cpu(_cpu)
{
manager.setCpu(cpu);
windowStart = 0x100000;
@ -145,6 +145,7 @@ void CtrlDisassemblyView::postEvent(wxEventType type, wxString text)
{
wxCommandEvent event( type, GetId() );
event.SetEventObject(this);
event.SetClientData(cpu);
event.SetString(text);
wxPostEvent(this,event);
}
@ -153,6 +154,7 @@ void CtrlDisassemblyView::postEvent(wxEventType type, int value)
{
wxCommandEvent event( type, GetId() );
event.SetEventObject(this);
event.SetClientData(cpu);
event.SetInt(value);
wxPostEvent(this,event);
}
@ -324,9 +326,18 @@ std::set<std::string> CtrlDisassemblyView::getSelectedLineArguments() {
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;

View File

@ -34,6 +34,10 @@ BEGIN_EVENT_TABLE(CtrlMemView, wxWindow)
EVT_CHAR(CtrlMemView::charEvent)
EVT_SET_FOCUS(CtrlMemView::focusEvent)
EVT_KILL_FOCUS(CtrlMemView::focusEvent)
EVT_SCROLLWIN_LINEUP(CtrlMemView::scrollbarEvent)
EVT_SCROLLWIN_LINEDOWN(CtrlMemView::scrollbarEvent)
EVT_SCROLLWIN_PAGEUP(CtrlMemView::scrollbarEvent)
EVT_SCROLLWIN_PAGEDOWN(CtrlMemView::scrollbarEvent)
END_EVENT_TABLE()
enum MemoryViewMenuIdentifiers
@ -94,6 +98,7 @@ void CtrlMemView::postEvent(wxEventType type, wxString text)
{
wxCommandEvent event( type, GetId() );
event.SetEventObject(this);
event.SetClientData(cpu);
event.SetString(text);
wxPostEvent(this,event);
}
@ -102,6 +107,7 @@ void CtrlMemView::postEvent(wxEventType type, int value)
{
wxCommandEvent event( type, GetId() );
event.SetEventObject(this);
event.SetClientData(cpu);
event.SetInt(value);
wxPostEvent(this,event);
}
@ -237,6 +243,19 @@ void CtrlMemView::render(wxDC& dc)
}
}
}
// TODO: make optional?
if (true)
{
dc.SetPen(wxColor(0xFFC0C0C0));
dc.SetBrush(wxColor(0xFFC0C0C0));
for (int i = 4; i < rowSize; i += 4)
{
int x = hexStart+i*3*charWidth-charWidth/2;
int y = (visibleRows+1)*rowHeight;
dc.DrawLine(x,0,x,y);
}
}
}
void CtrlMemView::onPopupClick(wxCommandEvent& evt)
@ -437,6 +456,26 @@ void CtrlMemView::charEvent(wxKeyEvent& evt)
redraw();
}
void CtrlMemView::scrollbarEvent(wxScrollWinEvent& evt)
{
int type = evt.GetEventType();
if (type == wxEVT_SCROLLWIN_LINEUP)
{
scrollCursor(-rowSize);
} else if (type == wxEVT_SCROLLWIN_LINEDOWN)
{
scrollCursor(rowSize);
} else if (type == wxEVT_SCROLLWIN_PAGEUP)
{
scrollWindow(-GetClientSize().y/rowHeight);
} else if (type == wxEVT_SCROLLWIN_PAGEDOWN)
{
scrollWindow(GetClientSize().y/rowHeight);
}
redraw();
}
void CtrlMemView::scrollWindow(int lines)
{
windowStart += lines*rowSize;

View File

@ -27,6 +27,7 @@ public:
void paintEvent(wxPaintEvent & evt);
void mouseEvent(wxMouseEvent& evt);
void keydownEvent(wxKeyEvent& evt);
void scrollbarEvent(wxScrollWinEvent& evt);
void charEvent(wxKeyEvent& evt);
void redraw();
void gotoAddress(u32 address);

View File

@ -41,7 +41,7 @@ enum DisassemblyMenuIdentifiers
CtrlRegisterList::CtrlRegisterList(wxWindow* parent, DebugInterface* _cpu)
: wxWindow(parent,wxID_ANY,wxDefaultPosition,wxDefaultSize,wxWANTS_CHARS|wxBORDER), cpu(_cpu)
: wxWindow(parent,wxID_ANY,wxDefaultPosition,wxDefaultSize,wxWANTS_CHARS|wxBORDER_NONE), cpu(_cpu)
{
rowHeight = g_Conf->EmuOptions.Debugger.FontHeight+2;
charWidth = g_Conf->EmuOptions.Debugger.FontWidth;
@ -195,11 +195,14 @@ void CtrlRegisterList::render(wxDC& dc)
dc.SetPen(wxPen(wxColor(0xFF000000)));
}
dc.DrawRectangle(x-1,-1,piece+1,rowHeight+1);
if (i == cpu->getRegisterCategoryCount()-1)
piece += size.x-piece*cpu->getRegisterCategoryCount()-1;
dc.DrawRectangle(x,0,piece+1,rowHeight);
// center text
x += (piece-strlen(name)*charWidth)/2;
dc.DrawText(wxString(name,wxConvUTF8),x,1);
dc.DrawText(wxString(name,wxConvUTF8),x,2);
}
int nameStart = 17;
@ -484,7 +487,7 @@ void CtrlRegisterList::mouseEvent(wxMouseEvent& evt)
if (y < rowHeight)
{
int piece = GetSize().x/cpu->getRegisterCategoryCount();
int cat = x/piece;
int cat = std::min<int>(x/piece,cpu->getRegisterCategoryCount()-1);
if (cat != category)
{

View File

@ -25,6 +25,7 @@ DEFINE_LOCAL_EVENT_TYPE( debEVT_MAPLOADED )
DEFINE_LOCAL_EVENT_TYPE( debEVT_STEPOVER )
DEFINE_LOCAL_EVENT_TYPE( debEVT_STEPINTO )
DEFINE_LOCAL_EVENT_TYPE( debEVT_UPDATE )
DEFINE_LOCAL_EVENT_TYPE( debEVT_BREAKPOINTWINDOW )
bool parseExpression(const char* exp, DebugInterface* cpu, u64& dest)
{

View File

@ -26,5 +26,6 @@ DECLARE_LOCAL_EVENT_TYPE( debEVT_MAPLOADED, wxNewEventType() )
DECLARE_LOCAL_EVENT_TYPE( debEVT_STEPOVER, wxNewEventType() )
DECLARE_LOCAL_EVENT_TYPE( debEVT_STEPINTO, wxNewEventType() )
DECLARE_LOCAL_EVENT_TYPE( debEVT_UPDATE, wxNewEventType() )
DECLARE_LOCAL_EVENT_TYPE( debEVT_BREAKPOINTWINDOW, wxNewEventType() )
bool executeExpressionWindow(wxWindow* parent, DebugInterface* cpu, u64& dest, const wxString& defaultValue = wxEmptyString);

View File

@ -47,10 +47,21 @@ void resizeListViewColumns(wxListCtrl* list, GenericListViewColumn* columns, int
BEGIN_EVENT_TABLE(BreakpointList, wxWindow)
EVT_SIZE(BreakpointList::sizeEvent)
EVT_KEY_DOWN(BreakpointList::keydownEvent)
EVT_RIGHT_DOWN(BreakpointList::mouseEvent)
EVT_RIGHT_UP(BreakpointList::mouseEvent)
EVT_LIST_ITEM_RIGHT_CLICK(wxID_ANY,BreakpointList::listEvent)
END_EVENT_TABLE()
enum { BPL_TYPE, BPL_OFFSET, BPL_SIZELABEL, BPL_OPCODE, BPL_CONDITION, BPL_HITS, BPL_ENABLED, BPL_COLUMNCOUNT };
enum BreakpointListMenuIdentifiers
{
ID_BREAKPOINTLIST_ENABLE = 1,
ID_BREAKPOINTLIST_EDIT,
ID_BREAKPOINTLIST_ADDNEW,
};
GenericListViewColumn breakpointColumns[BPL_COLUMNCOUNT] = {
{ L"Type", 0.12f },
{ L"Offset", 0.12f },
@ -109,19 +120,19 @@ wxString BreakpointList::OnGetItemText(long item, long col) const
if (isMemory) {
switch ((int)displayedMemChecks_[index].cond) {
case MEMCHECK_READ:
dest.Write(L"Read");
dest.Write("Read");
break;
case MEMCHECK_WRITE:
dest.Write(L"Write");
dest.Write("Write");
break;
case MEMCHECK_READWRITE:
dest.Write(L"Read/Write");
dest.Write("Read/Write");
break;
case MEMCHECK_WRITE | MEMCHECK_WRITE_ONCHANGE:
dest.Write(L"Write Change");
dest.Write("Write Change");
break;
case MEMCHECK_READWRITE | MEMCHECK_WRITE_ONCHANGE:
dest.Write(L"Read/Write Change");
dest.Write("Read/Write Change");
break;
}
} else {
@ -132,9 +143,9 @@ wxString BreakpointList::OnGetItemText(long item, long col) const
case BPL_OFFSET:
{
if (isMemory) {
dest.Write(L"0x%08X",displayedMemChecks_[index].start);
dest.Write("0x%08X",displayedMemChecks_[index].start);
} else {
dest.Write(L"0x%08X",displayedBreakPoints_[index].addr);
dest.Write("0x%08X",displayedBreakPoints_[index].addr);
}
}
break;
@ -143,16 +154,16 @@ wxString BreakpointList::OnGetItemText(long item, long col) const
if (isMemory) {
auto mc = displayedMemChecks_[index];
if (mc.end == 0)
dest.Write(L"0x%08X",1);
dest.Write("0x%08X",1);
else
dest.Write(L"0x%08X",mc.end-mc.start);
dest.Write("0x%08X",mc.end-mc.start);
} else {
const std::string sym = symbolMap.GetLabelString(displayedBreakPoints_[index].addr);
if (!sym.empty())
{
dest.Write(L"%s",sym.c_str());
dest.Write("%s",sym.c_str());
} else {
dest.Write(L"-");
dest.Write("-");
}
}
}
@ -164,34 +175,34 @@ wxString BreakpointList::OnGetItemText(long item, long col) const
} else {
char temp[256];
disasm->getOpcodeText(displayedBreakPoints_[index].addr, temp);
dest.Write(L"%s",temp);
dest.Write("%s",temp);
}
}
break;
case BPL_CONDITION:
{
if (isMemory || displayedBreakPoints_[index].hasCond == false) {
dest.Write(L"-");
dest.Write("-");
} else {
dest.Write(L"%s",displayedBreakPoints_[index].cond.expressionString);
dest.Write("%s",displayedBreakPoints_[index].cond.expressionString);
}
}
break;
case BPL_HITS:
{
if (isMemory) {
dest.Write(L"%d",displayedMemChecks_[index].numHits);
dest.Write("%d",displayedMemChecks_[index].numHits);
} else {
dest.Write(L"-");
dest.Write("-");
}
}
break;
case BPL_ENABLED:
{
if (isMemory) {
dest.Write(L"%s",displayedMemChecks_[index].cond & MEMCHECK_BREAK ? "true" : "false");
dest.Write("%s",displayedMemChecks_[index].result & MEMCHECK_BREAK ? "true" : "false");
} else {
dest.Write(L"%s",displayedBreakPoints_[index].enabled ? "true" : "false");
dest.Write("%s",displayedBreakPoints_[index].enabled ? "true" : "false");
}
}
break;
@ -352,3 +363,70 @@ void BreakpointList::postEvent(wxEventType type, int value)
event.SetInt(value);
wxPostEvent(this,event);
}
void BreakpointList::onPopupClick(wxCommandEvent& evt)
{
int index = GetFirstSelected();
switch (evt.GetId())
{
case ID_BREAKPOINTLIST_ENABLE:
toggleEnabled(index);
break;
case ID_BREAKPOINTLIST_EDIT:
editBreakpoint(index);
break;
case ID_BREAKPOINTLIST_ADDNEW:
postEvent(debEVT_BREAKPOINTWINDOW,0);
break;
default:
wxMessageBox( L"Unimplemented.", L"Unimplemented.", wxICON_INFORMATION);
break;
}
}
void BreakpointList::showMenu(const wxPoint& pos)
{
bool isMemory;
int index = getBreakpointIndex(GetFirstSelected(),isMemory);
wxMenu menu;
if (index != -1)
{
menu.AppendCheckItem(ID_BREAKPOINTLIST_ENABLE, L"Enable");
menu.Append(ID_BREAKPOINTLIST_EDIT, L"Edit");
menu.AppendSeparator();
// check if the breakpoint is enabled
bool enabled;
if (isMemory)
enabled = (displayedMemChecks_[index].result & MEMCHECK_BREAK) != 0;
else
enabled = displayedBreakPoints_[index].enabled;
menu.Check(ID_BREAKPOINTLIST_ENABLE,enabled);
}
menu.Append(ID_BREAKPOINTLIST_ADDNEW, L"Add new");
menu.Connect(wxEVT_COMMAND_MENU_SELECTED, (wxObjectEventFunction)&BreakpointList::onPopupClick, NULL, this);
PopupMenu(&menu,pos);
}
void BreakpointList::mouseEvent(wxMouseEvent& evt)
{
wxEventType type = evt.GetEventType();
if (type == wxEVT_RIGHT_DOWN)
{
clickPos = evt.GetPosition();
evt.Skip();
} else if (type == wxEVT_RIGHT_UP)
{
showMenu(evt.GetPosition());
}
}
void BreakpointList::listEvent(wxListEvent& evt)
{
showMenu(clickPos);
}

View File

@ -35,9 +35,12 @@ public:
DECLARE_EVENT_TABLE()
protected:
wxString OnGetItemText(long item, long col) const;
void onPopupClick(wxCommandEvent& evt);
void sizeEvent(wxSizeEvent& evt);
void keydownEvent(wxKeyEvent& evt);
void mouseEvent(wxMouseEvent& evt);
void listEvent(wxListEvent& evt);
private:
int getBreakpointIndex(int itemIndex, bool& isMemory) const;
int getTotalBreakpointCount();
@ -46,9 +49,11 @@ private:
void gotoBreakpointAddress(int itemIndex);
void removeBreakpoint(int itemIndex);
void postEvent(wxEventType type, int value);
void showMenu(const wxPoint& pos);
std::vector<BreakPoint> displayedBreakPoints_;
std::vector<MemCheck> displayedMemChecks_;
DebugInterface* cpu;
CtrlDisassemblyView* disasm;
wxPoint clickPos;
};

View File

@ -35,9 +35,14 @@ BEGIN_EVENT_TABLE(DisassemblyDialog, wxFrame)
EVT_COMMAND( wxID_ANY, debEVT_STEPOVER, DisassemblyDialog::onDebuggerEvent )
EVT_COMMAND( wxID_ANY, debEVT_STEPINTO, DisassemblyDialog::onDebuggerEvent )
EVT_COMMAND( wxID_ANY, debEVT_UPDATE, DisassemblyDialog::onDebuggerEvent )
EVT_COMMAND( wxID_ANY, debEVT_BREAKPOINTWINDOW, DisassemblyDialog::onDebuggerEvent )
EVT_COMMAND( wxID_ANY, debEVT_MAPLOADED, DisassemblyDialog::onDebuggerEvent )
EVT_CLOSE( DisassemblyDialog::onClose )
END_EVENT_TABLE()
BEGIN_EVENT_TABLE(CpuTabPage, wxPanel)
EVT_LISTBOX_DCLICK( wxID_ANY, CpuTabPage::listBoxHandler)
END_EVENT_TABLE()
DebuggerHelpDialog::DebuggerHelpDialog(wxWindow* parent)
: wxDialog(parent,wxID_ANY,L"Help")
@ -72,16 +77,26 @@ CpuTabPage::CpuTabPage(wxWindow* parent, DebugInterface* _cpu)
wxBoxSizer* mainSizer = new wxBoxSizer(wxVERTICAL);
SetSizer(mainSizer);
leftTabs = new wxNotebook(this,wxID_ANY);
bottomTabs = new wxNotebook(this,wxID_ANY);
disassembly = new CtrlDisassemblyView(this,cpu);
registerList = new CtrlRegisterList(this,cpu);
registerList = new CtrlRegisterList(leftTabs,cpu);
functionList = new wxListBox(leftTabs,wxID_ANY,wxDefaultPosition,wxDefaultSize,0,NULL,wxBORDER_NONE|wxLB_SORT);
memory = new CtrlMemView(bottomTabs,cpu);
// create register list and disassembly section
wxBoxSizer* middleSizer = new wxBoxSizer(wxHORIZONTAL);
wxBoxSizer* miscStuffSizer = new wxBoxSizer(wxHORIZONTAL);
cyclesText = new wxStaticText(this,wxID_ANY,L"");
miscStuffSizer->Add(cyclesText,0,wxLEFT|wxTOP|wxBOTTOM,2);
leftTabs->AddPage(registerList,L"Registers");
leftTabs->AddPage(functionList,L"Functions");
wxBoxSizer* registerSizer = new wxBoxSizer(wxVERTICAL);
registerSizer->Add(registerList,1);
registerSizer->Add(miscStuffSizer,0);
registerSizer->Add(leftTabs,1);
middleSizer->Add(registerSizer,0,wxEXPAND|wxRIGHT,2);
middleSizer->Add(disassembly,2,wxEXPAND);
@ -96,6 +111,40 @@ CpuTabPage::CpuTabPage(wxWindow* parent, DebugInterface* _cpu)
mainSizer->Add(bottomTabs,1,wxEXPAND);
mainSizer->Layout();
lastCycles = 0;
loadCycles();
}
void CpuTabPage::reloadSymbolMap()
{
functionList->Clear();
auto funcs = symbolMap.GetAllSymbols(ST_FUNCTION);
for (size_t i = 0; i < funcs.size(); i++)
{
wxString name = wxString(funcs[i].name.c_str(),wxConvUTF8);
functionList->Append(name,(void*)funcs[i].address);
}
}
void CpuTabPage::listBoxHandler(wxCommandEvent& event)
{
int index = functionList->GetSelection();
if (event.GetEventObject() == functionList && index >= 0)
{
u32 pos = (u32) functionList->GetClientData(index);
postEvent(debEVT_GOTOINDISASM,pos);
}
}
void CpuTabPage::postEvent(wxEventType type, int value)
{
wxCommandEvent event( type, GetId() );
event.SetEventObject(this);
event.SetClientData(cpu);
event.SetInt(value);
wxPostEvent(this,event);
}
void CpuTabPage::setBottomTabPage(wxWindow* win)
@ -116,6 +165,15 @@ void CpuTabPage::update()
Refresh();
}
void CpuTabPage::loadCycles()
{
u32 cycles = cpu->getCycles();
wchar_t str[64];
swprintf(str,64,L"Ctr: %u",cycles-lastCycles);
cyclesText->SetLabel(str);
lastCycles = cycles;
}
DisassemblyDialog::DisassemblyDialog(wxWindow* parent):
wxFrame( parent, wxID_ANY, L"Debugger", wxDefaultPosition,wxDefaultSize,wxRESIZE_BORDER|wxCLOSE_BOX|wxCAPTION|wxSYSTEM_MENU ),
@ -354,8 +412,8 @@ void DisassemblyDialog::onDebuggerEvent(wxCommandEvent& evt)
wxEventType type = evt.GetEventType();
if (type == debEVT_SETSTATUSBARTEXT)
{
CtrlDisassemblyView* view = reinterpret_cast<CtrlDisassemblyView*>(evt.GetEventObject());
if (view != NULL && view == currentCpu->getDisassembly())
DebugInterface* cpu = reinterpret_cast<DebugInterface*>(evt.GetClientData());
if (cpu != NULL && cpu == currentCpu->getCpu())
GetStatusBar()->SetLabel(evt.GetString());
} else if (type == debEVT_UPDATELAYOUT)
{
@ -382,7 +440,8 @@ void DisassemblyDialog::onDebuggerEvent(wxCommandEvent& evt)
{
if (currentCpu != NULL)
{
currentCpu->getDisassembly()->gotoAddress(r5900Debug.getPC());
u32 pos = evt.GetInt();
currentCpu->getDisassembly()->gotoAddress(pos);
currentCpu->getDisassembly()->SetFocus();
update();
}
@ -397,6 +456,14 @@ void DisassemblyDialog::onDebuggerEvent(wxCommandEvent& evt)
} else if (type == debEVT_UPDATE)
{
update();
} else if (type == debEVT_BREAKPOINTWINDOW)
{
wxCommandEvent evt;
onBreakpointClick(evt);
} else if (type == debEVT_MAPLOADED)
{
eeTab->reloadSymbolMap();
iopTab->reloadSymbolMap();
}
}
@ -421,8 +488,10 @@ void DisassemblyDialog::update()
void DisassemblyDialog::reset()
{
eeTab->getDisassembly()->clearFunctions();
eeTab->reloadSymbolMap();
iopTab->getDisassembly()->clearFunctions();
};
iopTab->reloadSymbolMap();
}
void DisassemblyDialog::gotoPc()
{
@ -456,6 +525,9 @@ void DisassemblyDialog::setDebugMode(bool debugMode, bool switchPC)
currentCpu->getDisassembly()->SetFocus();
CBreakPoints::SetBreakpointTriggered(false);
}
if (currentCpu != NULL)
currentCpu->loadCycles();
} else {
breakRunButton->SetLabel(L"Break");

View File

@ -41,14 +41,25 @@ public:
wxNotebook* getBottomTabs() { return bottomTabs; };
void update();
void showMemoryView() { setBottomTabPage(memory); };
void loadCycles();
void reloadSymbolMap();
void listBoxHandler(wxCommandEvent& event);
DECLARE_EVENT_TABLE()
private:
void setBottomTabPage(wxWindow* win);
void postEvent(wxEventType type, int value);
DebugInterface* cpu;
CtrlDisassemblyView* disassembly;
CtrlRegisterList* registerList;
wxListBox* functionList;
CtrlMemView* memory;
wxNotebook* bottomTabs;
wxNotebook* leftTabs;
BreakpointList* breakpointList;
wxStaticText* cyclesText;
u32 lastCycles;
};
class DisassemblyDialog : public wxFrame