2008-07-12 17:40:22 +00:00
// Copyright (C) 2003-2008 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program 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 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
# include "Debugger.h"
2008-08-23 15:15:25 +00:00
# include "Debugger/PPCDebugInterface.h"
2008-08-24 18:50:51 +00:00
# include "PowerPC/SymbolDB.h"
2008-11-29 08:38:03 +00:00
# include "HW/Memmap.h" // for Write_U32
2008-07-12 17:40:22 +00:00
# include "Common.h"
2008-08-23 15:15:25 +00:00
# include "StringUtil.h"
2008-07-12 17:40:22 +00:00
2008-08-23 15:15:25 +00:00
# include "Host.h"
2008-07-12 17:40:22 +00:00
# include "CodeView.h"
2008-08-21 17:22:55 +00:00
# include "JitWindow.h"
2008-07-12 17:40:22 +00:00
# include <wx/event.h>
# include <wx/clipbrd.h>
2008-08-23 15:15:25 +00:00
# include <wx/textdlg.h>
2008-07-12 17:40:22 +00:00
2008-08-24 20:25:36 +00:00
DEFINE_EVENT_TYPE ( wxEVT_CODEVIEW_CHANGE ) ;
2008-07-12 17:40:22 +00:00
enum
{
IDM_GOTOINMEMVIEW = 12000 ,
IDM_COPYADDRESS ,
IDM_COPYHEX ,
IDM_COPYCODE ,
2008-08-10 18:21:16 +00:00
IDM_INSERTBLR ,
2008-07-12 17:40:22 +00:00
IDM_RUNTOHERE ,
2008-08-21 17:22:55 +00:00
IDM_JITRESULTS ,
2008-08-24 20:25:36 +00:00
IDM_FOLLOWBRANCH ,
2008-08-23 15:15:25 +00:00
IDM_RENAMESYMBOL ,
IDM_PATCHALERT ,
IDM_COPYFUNCTION ,
2008-07-12 17:40:22 +00:00
} ;
BEGIN_EVENT_TABLE ( CCodeView , wxControl )
2008-07-24 09:39:56 +00:00
EVT_ERASE_BACKGROUND ( CCodeView : : OnErase )
EVT_PAINT ( CCodeView : : OnPaint )
EVT_LEFT_DOWN ( CCodeView : : OnMouseDown )
EVT_LEFT_UP ( CCodeView : : OnMouseUpL )
EVT_MOTION ( CCodeView : : OnMouseMove )
EVT_RIGHT_DOWN ( CCodeView : : OnMouseDown )
EVT_RIGHT_UP ( CCodeView : : OnMouseUpR )
EVT_MENU ( - 1 , CCodeView : : OnPopupMenu )
2008-07-12 17:40:22 +00:00
END_EVENT_TABLE ( )
CCodeView : : CCodeView ( DebugInterface * debuginterface , wxWindow * parent , wxWindowID Id , const wxSize & Size )
2008-09-14 09:12:19 +00:00
: wxControl ( parent , Id , wxDefaultPosition , Size ) ,
debugger ( debuginterface ) ,
rowHeight ( 13 ) ,
selection ( 0 ) ,
oldSelection ( 0 ) ,
selectionChanged ( false ) ,
selecting ( false ) ,
hasFocus ( false ) ,
showHex ( false ) ,
lx ( - 1 ) ,
ly ( - 1 )
2008-07-12 17:40:22 +00:00
{
rowHeight = 13 ;
align = debuginterface - > getInstructionSize ( 0 ) ;
curAddress = debuginterface - > getPC ( ) ;
2008-09-14 09:12:19 +00:00
selection = 0 ;
2008-07-12 17:40:22 +00:00
}
wxSize CCodeView : : DoGetBestSize ( ) const
{
wxSize bestSize ;
bestSize . x = 400 ;
bestSize . y = 800 ;
return ( bestSize ) ;
}
int CCodeView : : YToAddress ( int y )
{
wxRect rc = GetClientRect ( ) ;
int ydiff = y - rc . height / 2 - rowHeight / 2 ;
ydiff = ( int ) ( floorf ( ( float ) ydiff / ( float ) rowHeight ) ) + 1 ;
return ( curAddress + ydiff * align ) ;
}
void CCodeView : : OnMouseDown ( wxMouseEvent & event )
{
int x = event . m_x ;
int y = event . m_y ;
if ( x > 16 )
{
oldSelection = selection ;
selection = YToAddress ( y ) ;
// SetCapture(wnd);
bool oldselecting = selecting ;
selecting = true ;
if ( ! oldselecting | | ( selection ! = oldSelection ) )
{
redraw ( ) ;
}
}
else
{
debugger - > toggleBreakpoint ( YToAddress ( y ) ) ;
redraw ( ) ;
}
event . Skip ( true ) ;
}
void CCodeView : : OnMouseMove ( wxMouseEvent & event )
{
wxRect rc = GetClientRect ( ) ;
if ( event . m_leftDown )
{
if ( event . m_x > 16 )
{
if ( event . m_y < 0 )
{
curAddress - = align ;
redraw ( ) ;
}
else if ( event . m_y > rc . height )
{
curAddress + = align ;
redraw ( ) ;
}
else
{
OnMouseDown ( event ) ;
}
}
}
event . Skip ( true ) ;
}
2008-08-24 20:25:36 +00:00
void CCodeView : : RaiseEvent ( )
{
wxCommandEvent ev ( wxEVT_CODEVIEW_CHANGE , GetId ( ) ) ;
ev . SetEventObject ( this ) ;
ev . SetInt ( selection ) ;
GetEventHandler ( ) - > ProcessEvent ( ev ) ;
}
2008-07-12 17:40:22 +00:00
void CCodeView : : OnMouseUpL ( wxMouseEvent & event )
{
if ( event . m_x > 16 )
{
curAddress = YToAddress ( event . m_y ) ;
selecting = false ;
//ReleaseCapture();
redraw ( ) ;
}
2008-08-24 20:25:36 +00:00
RaiseEvent ( ) ;
2008-07-12 17:40:22 +00:00
event . Skip ( true ) ;
}
2008-08-24 20:25:36 +00:00
u32 CCodeView : : AddrToBranch ( u32 addr )
{
const char * temp = debugger - > disasm ( addr ) ;
const char * mojs = strstr ( temp , " ->0x " ) ;
if ( mojs )
{
u32 dest ;
sscanf ( mojs + 4 , " %08x " , & dest ) ;
return dest ;
}
return 0 ;
}
2008-07-12 17:40:22 +00:00
void CCodeView : : OnPopupMenu ( wxCommandEvent & event )
{
# if wxUSE_CLIPBOARD
wxTheClipboard - > Open ( ) ;
# endif
switch ( event . GetId ( ) )
{
case IDM_GOTOINMEMVIEW :
// CMemoryDlg::Goto(selection);
break ;
# if wxUSE_CLIPBOARD
case IDM_COPYADDRESS :
wxTheClipboard - > SetData ( new wxTextDataObject ( wxString : : Format ( _T ( " %08x " ) , selection ) ) ) ;
break ;
case IDM_COPYCODE :
2008-07-20 11:02:41 +00:00
wxTheClipboard - > SetData ( new wxTextDataObject ( wxString : : FromAscii ( debugger - > disasm ( selection ) ) ) ) ; //Have to manually convert from char* to wxString, don't have to in Windows?
2008-07-12 17:40:22 +00:00
break ;
case IDM_COPYHEX :
2008-08-21 17:22:55 +00:00
{
2008-07-12 17:40:22 +00:00
char temp [ 24 ] ;
2008-11-30 14:02:07 +00:00
sprintf ( temp , " %08x " , debugger - > readInstruction ( selection ) ) ;
2008-07-20 11:02:41 +00:00
wxTheClipboard - > SetData ( new wxTextDataObject ( wxString : : FromAscii ( temp ) ) ) ;
2008-08-21 17:22:55 +00:00
}
2008-07-12 17:40:22 +00:00
break ;
2008-08-23 15:15:25 +00:00
case IDM_COPYFUNCTION :
{
2008-08-24 18:50:51 +00:00
Symbol * symbol = g_symbolDB . GetSymbolFromAddr ( selection ) ;
if ( symbol ) {
2008-08-23 15:15:25 +00:00
std : : string text ;
2008-08-24 18:50:51 +00:00
text = text + symbol - > name + " \r \n " ;
2008-08-23 15:15:25 +00:00
// we got a function
2008-08-24 18:50:51 +00:00
u32 start = symbol - > address ;
u32 end = start + symbol - > size ;
2008-08-23 15:15:25 +00:00
for ( u32 addr = start ; addr ! = end ; addr + = 4 ) {
text = text + StringFromFormat ( " %08x: " , addr ) + debugger - > disasm ( addr ) + " \r \n " ;
}
wxTheClipboard - > SetData ( new wxTextDataObject ( wxString : : FromAscii ( text . c_str ( ) ) ) ) ;
}
}
break ;
2008-07-12 17:40:22 +00:00
# endif
case IDM_RUNTOHERE :
debugger - > setBreakpoint ( selection ) ;
debugger - > runToBreakpoint ( ) ;
redraw ( ) ;
break ;
2008-11-29 08:38:03 +00:00
// Insert blr or restore old value
2008-08-10 18:21:16 +00:00
case IDM_INSERTBLR :
2008-11-29 08:38:03 +00:00
{
// Check if this address has been modified
int find = - 1 ;
for ( int i = 0 ; i < BlrList . size ( ) ; i + + )
{
if ( BlrList . at ( i ) . Address = = selection )
{ find = i ; break ; }
}
// Save the old value
if ( find > = 0 )
{
Memory : : Write_U32 ( BlrList . at ( find ) . OldValue , selection ) ;
BlrList . erase ( BlrList . begin ( ) + find ) ;
}
else
{
BlrStruct Temp ;
Temp . Address = selection ;
Temp . OldValue = debugger - > readMemory ( selection ) ;
BlrList . push_back ( Temp ) ;
debugger - > insertBLR ( selection ) ;
}
redraw ( ) ;
}
2008-08-10 18:21:16 +00:00
break ;
2008-08-21 17:22:55 +00:00
case IDM_JITRESULTS :
CJitWindow : : ViewAddr ( selection ) ;
2008-07-12 17:40:22 +00:00
break ;
2008-08-24 20:25:36 +00:00
case IDM_FOLLOWBRANCH :
{
u32 dest = AddrToBranch ( selection ) ;
if ( dest )
Center ( dest ) ;
RaiseEvent ( ) ;
}
break ;
2008-08-23 15:15:25 +00:00
case IDM_RENAMESYMBOL :
{
2008-08-24 18:50:51 +00:00
Symbol * symbol = g_symbolDB . GetSymbolFromAddr ( selection ) ;
if ( symbol ) {
wxTextEntryDialog input_symbol ( this , wxString : : FromAscii ( " Rename symbol: " ) , wxGetTextFromUserPromptStr ,
wxString : : FromAscii ( symbol - > name . c_str ( ) ) ) ;
2008-08-23 15:15:25 +00:00
if ( input_symbol . ShowModal ( ) = = wxID_OK ) {
2008-08-24 18:50:51 +00:00
symbol - > name = input_symbol . GetValue ( ) . mb_str ( ) ;
2008-08-23 15:15:25 +00:00
}
// redraw();
Host_NotifyMapLoaded ( ) ;
}
}
break ;
case IDM_PATCHALERT :
{
}
break ;
2008-07-12 17:40:22 +00:00
}
# if wxUSE_CLIPBOARD
wxTheClipboard - > Close ( ) ;
# endif
event . Skip ( true ) ;
}
void CCodeView : : OnMouseUpR ( wxMouseEvent & event )
{
2008-08-24 20:25:36 +00:00
bool isSymbol = g_symbolDB . GetSymbolFromAddr ( selection ) ! = 0 ;
2008-07-12 17:40:22 +00:00
// popup menu
wxMenu menu ;
//menu.Append(IDM_GOTOINMEMVIEW, "&Goto in mem view");
2008-08-24 20:25:36 +00:00
menu . Append ( IDM_FOLLOWBRANCH , wxString : : FromAscii ( " &Follow branch " ) ) - > Enable ( AddrToBranch ( selection ) ? true : false ) ;
menu . AppendSeparator ( ) ;
2008-07-12 17:40:22 +00:00
# if wxUSE_CLIPBOARD
2008-07-20 11:02:41 +00:00
menu . Append ( IDM_COPYADDRESS , wxString : : FromAscii ( " Copy &address " ) ) ;
2008-08-24 20:25:36 +00:00
menu . Append ( IDM_COPYFUNCTION , wxString : : FromAscii ( " Copy &function " ) ) - > Enable ( isSymbol ) ;
2008-08-23 15:15:25 +00:00
menu . Append ( IDM_COPYCODE , wxString : : FromAscii ( " Copy &code line " ) ) ;
2008-07-20 11:02:41 +00:00
menu . Append ( IDM_COPYHEX , wxString : : FromAscii ( " Copy &hex " ) ) ;
2008-08-23 15:15:25 +00:00
menu . AppendSeparator ( ) ;
2008-07-12 17:40:22 +00:00
# endif
2008-08-24 20:25:36 +00:00
menu . Append ( IDM_RENAMESYMBOL , wxString : : FromAscii ( " Rename &symbol " ) ) - > Enable ( isSymbol ) ;
2008-08-23 15:15:25 +00:00
menu . AppendSeparator ( ) ;
2008-07-12 17:40:22 +00:00
menu . Append ( IDM_RUNTOHERE , _T ( " &Run To Here " ) ) ;
2008-08-21 17:22:55 +00:00
menu . Append ( IDM_JITRESULTS , wxString : : FromAscii ( " PPC vs X86 " ) ) ;
2008-08-23 15:15:25 +00:00
menu . Append ( IDM_INSERTBLR , wxString : : FromAscii ( " Insert &blr " ) ) ;
menu . Append ( IDM_PATCHALERT , wxString : : FromAscii ( " Patch alert " ) ) ;
2008-07-12 17:40:22 +00:00
PopupMenu ( & menu ) ;
event . Skip ( true ) ;
}
void CCodeView : : OnErase ( wxEraseEvent & event )
{ }
void CCodeView : : OnPaint ( wxPaintEvent & event )
{
wxPaintDC dc ( this ) ;
wxRect rc = GetClientRect ( ) ;
wxFont font ( 7 , wxFONTFAMILY_SWISS , wxFONTSTYLE_NORMAL , wxFONTWEIGHT_LIGHT ) ;
dc . SetFont ( font ) ;
struct branch
{
int src , dst , srcAddr ;
} ;
branch branches [ 256 ] ;
int numBranches = 0 ;
// TODO: Add any drawing code here...
int width = rc . width ;
int numRows = ( rc . height / rowHeight ) / 2 + 2 ;
//numRows=(numRows&(~1)) + 1;
dc . SetBackgroundMode ( wxTRANSPARENT ) ;
const wxChar * bgColor = _T ( " #ffffff " ) ;
wxPen nullPen ( bgColor ) ;
wxPen currentPen ( _T ( " #000000 " ) ) ;
wxPen selPen ( _T ( " #808080 " ) ) ;
nullPen . SetStyle ( wxTRANSPARENT ) ;
2008-08-24 22:22:55 +00:00
currentPen . SetStyle ( wxSOLID ) ;
2008-07-12 17:40:22 +00:00
wxBrush currentBrush ( _T ( " #FFEfE8 " ) ) ;
wxBrush pcBrush ( _T ( " #70FF70 " ) ) ;
wxBrush bpBrush ( _T ( " #FF3311 " ) ) ;
wxBrush bgBrush ( bgColor ) ;
wxBrush nullBrush ( bgColor ) ;
nullBrush . SetStyle ( wxTRANSPARENT ) ;
dc . SetPen ( nullPen ) ;
dc . SetBrush ( bgBrush ) ;
dc . DrawRectangle ( 0 , 0 , 16 , rc . height ) ;
dc . DrawRectangle ( 0 , 0 , rc . width , 5 ) ;
// TODO - clean up this freaking mess!!!!!
2008-08-25 20:34:11 +00:00
for ( int i = - numRows ; i < = numRows ; i + + )
2008-07-12 17:40:22 +00:00
{
unsigned int address = curAddress + i * align ;
int rowY1 = rc . height / 2 + rowHeight * i - rowHeight / 2 ;
int rowY2 = rc . height / 2 + rowHeight * i + rowHeight / 2 ;
wxString temp = wxString : : Format ( _T ( " %08x " ) , address ) ;
u32 col = debugger - > getColor ( address ) ;
wxBrush rowBrush ( wxColor ( col > > 16 , col > > 8 , col ) ) ;
dc . SetBrush ( nullBrush ) ;
dc . SetPen ( nullPen ) ;
2008-08-31 13:36:52 +00:00
dc . DrawRectangle ( 0 , rowY1 , 16 , rowY2 - rowY1 + 2 ) ;
2008-07-12 17:40:22 +00:00
if ( selecting & & ( address = = selection ) )
{
dc . SetPen ( selPen ) ;
}
else
{
dc . SetPen ( i = = 0 ? currentPen : nullPen ) ;
}
if ( address = = debugger - > getPC ( ) )
{
dc . SetBrush ( pcBrush ) ;
}
else
{
dc . SetBrush ( rowBrush ) ;
}
2008-08-31 13:36:52 +00:00
dc . DrawRectangle ( 16 , rowY1 , width , rowY2 - rowY1 + 1 ) ;
2008-07-12 17:40:22 +00:00
dc . SetBrush ( currentBrush ) ;
dc . SetTextForeground ( _T ( " #600000 " ) ) ;
dc . DrawText ( temp , 17 , rowY1 ) ;
dc . SetTextForeground ( _T ( " #000000 " ) ) ;
if ( debugger - > isAlive ( ) )
{
char dis [ 256 ] = { 0 } ;
strcpy ( dis , debugger - > disasm ( address ) ) ;
char * dis2 = strchr ( dis , ' \t ' ) ;
char desc [ 256 ] = " " ;
if ( dis2 )
{
* dis2 = 0 ;
dis2 + + ;
const char * mojs = strstr ( dis2 , " 0x8 " ) ;
if ( mojs )
{
2008-09-01 12:11:08 +00:00
for ( int k = 0 ; k < 8 ; k + + )
2008-07-12 17:40:22 +00:00
{
bool found = false ;
for ( int j = 0 ; j < 22 ; j + + )
{
2008-09-01 12:11:08 +00:00
if ( mojs [ k + 2 ] = = " 0123456789ABCDEFabcdef " [ j ] )
2008-07-12 17:40:22 +00:00
{
found = true ;
}
}
if ( ! found )
{
mojs = 0 ;
break ;
}
}
}
if ( mojs )
{
int offs ;
sscanf ( mojs + 2 , " %08x " , & offs ) ;
branches [ numBranches ] . src = rowY1 + rowHeight / 2 ;
branches [ numBranches ] . srcAddr = address / align ;
2008-08-24 22:22:55 +00:00
branches [ numBranches + + ] . dst = ( int ) ( rowY1 + ( ( s64 ) ( u32 ) offs - ( s64 ) ( u32 ) address ) * rowHeight / align + rowHeight / 2 ) ;
2008-07-12 17:40:22 +00:00
sprintf ( desc , " -->%s " , debugger - > getDescription ( offs ) . c_str ( ) ) ;
dc . SetTextForeground ( _T ( " #600060 " ) ) ;
}
else
{
dc . SetTextForeground ( _T ( " #000000 " ) ) ;
}
dc . DrawText ( wxString : : FromAscii ( dis2 ) , 126 , rowY1 ) ;
}
if ( strcmp ( dis , " blr " ) )
{
dc . SetTextForeground ( _T ( " #007000 " ) ) ;
}
else
{
dc . SetTextForeground ( _T ( " #8000FF " ) ) ;
}
dc . DrawText ( wxString : : FromAscii ( dis ) , 70 , rowY1 ) ;
if ( desc [ 0 ] = = 0 )
{
strcpy ( desc , debugger - > getDescription ( address ) . c_str ( ) ) ;
}
dc . SetTextForeground ( _T ( " #0000FF " ) ) ;
//char temp[256];
//UnDecorateSymbolName(desc,temp,255,UNDNAME_COMPLETE);
if ( strlen ( desc ) )
{
dc . DrawText ( wxString : : FromAscii ( desc ) , 235 , rowY1 ) ;
}
if ( debugger - > isBreakpoint ( address ) )
{
dc . SetBrush ( bpBrush ) ;
dc . DrawRectangle ( 2 , rowY1 , 7 , 7 ) ;
// DrawIconEx(hdc, 2, rowY1, breakPoint, 32, 32, 0, 0, DI_NORMAL);
}
}
}
dc . SetPen ( currentPen ) ;
2008-08-24 22:22:55 +00:00
2008-08-25 20:34:11 +00:00
for ( int i = 0 ; i < numBranches ; i + + )
2008-08-24 22:22:55 +00:00
{
int x = 300 + ( branches [ i ] . srcAddr % 9 ) * 8 ;
_MoveTo ( x - 2 , branches [ i ] . src ) ;
2008-07-12 17:40:22 +00:00
2008-08-24 22:22:55 +00:00
if ( branches [ i ] . dst < rc . height + 400 & & branches [ i ] . dst > - 400 )
2008-07-12 17:40:22 +00:00
{
2008-08-24 22:22:55 +00:00
_LineTo ( dc , x + 2 , branches [ i ] . src ) ;
_LineTo ( dc , x + 2 , branches [ i ] . dst ) ;
_LineTo ( dc , x - 4 , branches [ i ] . dst ) ;
2008-07-12 17:40:22 +00:00
2008-08-24 22:22:55 +00:00
_MoveTo ( x , branches [ i ] . dst - 4 ) ;
_LineTo ( dc , x - 4 , branches [ i ] . dst ) ;
_LineTo ( dc , x + 1 , branches [ i ] . dst + 5 ) ;
2008-07-12 17:40:22 +00:00
}
else
{
2008-08-24 22:22:55 +00:00
_LineTo ( dc , x + 4 , branches [ i ] . src ) ;
2008-07-12 17:40:22 +00:00
//MoveToEx(hdc,x+2,branches[i].dst-4,0);
//LineTo(hdc,x+6,branches[i].dst);
//LineTo(hdc,x+1,branches[i].dst+5);
}
//LineTo(hdc,x,branches[i].dst+4);
//LineTo(hdc,x-2,branches[i].dst);
2008-08-24 22:22:55 +00:00
}
2008-07-12 17:40:22 +00:00
}
2008-08-24 22:22:55 +00:00
void CCodeView : : _LineTo ( wxPaintDC & dc , int x , int y )
{
dc . DrawLine ( lx , ly , x , y ) ;
lx = x ;
ly = y ;
}