2009-07-28 21:32:10 +00:00
// Copyright (C) 2003 Dolphin Project.
2008-12-08 05:30:24 +00:00
// 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"
#include <wx/button.h>
#include <wx/textctrl.h>
#include <wx/listctrl.h>
#include <wx/thread.h>
#include <wx/listctrl.h>
#include "MemoryWindow.h"
#include "HW/CPU.h"
#include "PowerPC/PowerPC.h"
#include "Host.h"
2010-02-02 21:56:29 +00:00
#include "FileUtil.h"
2008-12-08 05:30:24 +00:00
#include "Debugger/PPCDebugInterface.h"
2009-06-21 08:39:21 +00:00
#include "PowerPC/PPCSymbolDB.h"
2008-12-08 05:30:24 +00:00
#include "Core.h"
#include "LogManager.h"
#include "HW/Memmap.h"
2009-06-30 21:11:39 +00:00
#include "HW/DSP.h"
2008-12-08 05:30:24 +00:00
// ugly that this lib included code from the main
#include "../../DolphinWX/Src/Globals.h"
enum
{
2009-08-25 01:50:27 +00:00
IDM_MEM_ADDRBOX = 350 ,
2008-12-08 05:30:24 +00:00
IDM_SYMBOLLIST ,
2009-01-21 17:02:01 +00:00
IDM_SETVALBUTTON ,
IDM_DUMP_MEMORY ,
2009-06-17 19:50:59 +00:00
IDM_VALBOX ,
2009-11-25 10:07:56 +00:00
IDM_U8 , //Feel free to rename these
IDM_U16 ,
IDM_U32 ,
IDM_SEARCH ,
IDM_ASCII ,
IDM_HEX
2008-12-08 05:30:24 +00:00
};
2009-09-07 20:51:02 +00:00
BEGIN_EVENT_TABLE ( CMemoryWindow , wxPanel )
2010-01-16 19:01:00 +00:00
EVT_TEXT ( IDM_MEM_ADDRBOX , CMemoryWindow :: OnAddrBoxChange )
EVT_LISTBOX ( IDM_SYMBOLLIST , CMemoryWindow :: OnSymbolListChange )
EVT_HOST_COMMAND ( wxID_ANY , CMemoryWindow :: OnHostMessage )
EVT_BUTTON ( IDM_SETVALBUTTON , CMemoryWindow :: SetMemoryValue )
EVT_BUTTON ( IDM_DUMP_MEMORY , CMemoryWindow :: OnDumpMemory )
EVT_CHECKBOX ( IDM_U8 , CMemoryWindow :: U8 )
EVT_CHECKBOX ( IDM_U16 , CMemoryWindow :: U16 )
EVT_CHECKBOX ( IDM_U32 , CMemoryWindow :: U32 )
EVT_BUTTON ( IDM_SEARCH , CMemoryWindow :: onSearch )
EVT_CHECKBOX ( IDM_ASCII , CMemoryWindow :: onAscii )
EVT_CHECKBOX ( IDM_HEX , CMemoryWindow :: onHex )
2008-12-08 05:30:24 +00:00
END_EVENT_TABLE ()
CMemoryWindow :: CMemoryWindow ( wxWindow * parent , wxWindowID id ,
2010-01-16 19:01:00 +00:00
const wxString & title , const wxPoint & pos , const wxSize & size , long style )
: wxPanel ( parent , id , pos , size , style )
2008-12-08 05:30:24 +00:00
{
wxBoxSizer * sizerBig = new wxBoxSizer ( wxHORIZONTAL );
wxBoxSizer * sizerRight = new wxBoxSizer ( wxVERTICAL );
// didn't see anything usefull in the left part
//wxBoxSizer* sizerLeft = new wxBoxSizer(wxVERTICAL);
2009-06-28 12:15:31 +00:00
DebugInterface * di = & PowerPC :: debug_interface ;
2008-12-08 05:30:24 +00:00
//sizerLeft->Add(symbols = new wxListBox(this, IDM_SYMBOLLIST, wxDefaultPosition, wxSize(20, 100), 0, NULL, wxLB_SORT), 1, wxEXPAND);
memview = new CMemoryView ( di , this , wxID_ANY );
2009-11-25 10:07:56 +00:00
memview -> dataType = 0 ;
2008-12-08 05:30:24 +00:00
//sizerBig->Add(sizerLeft, 1, wxEXPAND);
sizerBig -> Add ( memview , 20 , wxEXPAND );
sizerBig -> Add ( sizerRight , 0 , wxEXPAND | wxALL , 3 );
2009-08-25 01:50:27 +00:00
sizerRight -> Add ( addrbox = new wxTextCtrl ( this , IDM_MEM_ADDRBOX , _T ( "" )));
2008-12-08 05:30:24 +00:00
sizerRight -> Add ( valbox = new wxTextCtrl ( this , IDM_VALBOX , _T ( "" )));
sizerRight -> Add ( new wxButton ( this , IDM_SETVALBUTTON , _T ( "Set &Value" )));
2010-01-16 19:01:00 +00:00
2009-01-21 17:02:01 +00:00
sizerRight -> AddSpacer ( 5 );
sizerRight -> Add ( new wxButton ( this , IDM_DUMP_MEMORY , _T ( "&Dump Memory" )));
2008-12-08 05:30:24 +00:00
2009-11-25 10:07:56 +00:00
wxStaticBoxSizer * sizerSearchType = new wxStaticBoxSizer ( wxVERTICAL , this , wxT ( "Search" ));
sizerSearchType -> Add ( btnSearch = new wxButton ( this , IDM_SEARCH , _T ( "Search" )));
sizerSearchType -> Add ( chkAscii = new wxCheckBox ( this , IDM_ASCII , _T ( "&Ascii " )));
sizerSearchType -> Add ( chkHex = new wxCheckBox ( this , IDM_HEX , _T ( "&Hex" )));
2010-01-16 19:01:00 +00:00
sizerRight -> Add ( sizerSearchType );
2009-11-25 10:07:56 +00:00
wxStaticBoxSizer * sizerDataTypes = new wxStaticBoxSizer ( wxVERTICAL , this , wxT ( "Data Type" ));
2010-01-16 19:01:00 +00:00
2009-11-25 10:07:56 +00:00
sizerDataTypes -> Add ( chk8 = new wxCheckBox ( this , IDM_U8 , _T ( "&U8 " ))); //Excesss spaces are to get the DataType to show properly
sizerDataTypes -> Add ( chk16 = new wxCheckBox ( this , IDM_U16 , _T ( "&U16 " )));
sizerDataTypes -> Add ( chk32 = new wxCheckBox ( this , IDM_U32 , _T ( "&U32 " )));
2010-01-16 19:01:00 +00:00
sizerRight -> Add ( sizerDataTypes );
2008-12-08 05:30:24 +00:00
SetSizer ( sizerBig );
2009-11-25 10:07:56 +00:00
chkHex -> SetValue ( 1 ); //Set defaults
chk8 -> SetValue ( 1 );
2008-12-08 05:30:24 +00:00
//sizerLeft->SetSizeHints(this);
//sizerLeft->Fit(this);
sizerRight -> SetSizeHints ( this );
sizerRight -> Fit ( this );
sizerBig -> SetSizeHints ( this );
sizerBig -> Fit ( this );
}
CMemoryWindow ::~ CMemoryWindow ()
{
}
void CMemoryWindow :: Save ( IniFile & _IniFile ) const
{
// Prevent these bad values that can happen after a crash or hanging
if ( GetPosition (). x != - 32000 && GetPosition (). y != - 32000 )
{
_IniFile . Set ( "MemoryWindow" , "x" , GetPosition (). x );
_IniFile . Set ( "MemoryWindow" , "y" , GetPosition (). y );
_IniFile . Set ( "MemoryWindow" , "w" , GetSize (). GetWidth ());
_IniFile . Set ( "MemoryWindow" , "h" , GetSize (). GetHeight ());
}
}
void CMemoryWindow :: Load ( IniFile & _IniFile )
{
int x , y , w , h ;
_IniFile . Get ( "MemoryWindow" , "x" , & x , GetPosition (). x );
_IniFile . Get ( "MemoryWindow" , "y" , & y , GetPosition (). y );
_IniFile . Get ( "MemoryWindow" , "w" , & w , GetSize (). GetWidth ());
_IniFile . Get ( "MemoryWindow" , "h" , & h , GetSize (). GetHeight ());
SetSize ( x , y , w , h );
}
void CMemoryWindow :: JumpToAddress ( u32 _Address )
{
2010-01-16 19:01:00 +00:00
memview -> Center ( _Address );
2008-12-08 05:30:24 +00:00
}
void CMemoryWindow :: SetMemoryValue ( wxCommandEvent & event )
{
std :: string str_addr = std :: string ( addrbox -> GetValue (). mb_str ());
std :: string str_val = std :: string ( valbox -> GetValue (). mb_str ());
u32 addr ;
u32 val ;
if ( ! TryParseUInt ( std :: string ( "0x" ) + str_addr , & addr )) {
2010-01-16 19:01:00 +00:00
PanicAlert ( "Invalid Address: %s" , str_addr . c_str ());
return ;
2008-12-08 05:30:24 +00:00
}
if ( ! TryParseUInt ( std :: string ( "0x" ) + str_val , & val )) {
2010-01-16 19:01:00 +00:00
PanicAlert ( "Invalid Value: %s" , str_val . c_str ());
return ;
2008-12-08 05:30:24 +00:00
}
Memory :: Write_U32 ( val , addr );
memview -> Refresh ();
}
2009-06-17 19:50:59 +00:00
2008-12-08 05:30:24 +00:00
void CMemoryWindow :: OnAddrBoxChange ( wxCommandEvent & event )
{
wxString txt = addrbox -> GetValue ();
2009-06-17 19:50:59 +00:00
if ( txt . size ())
2008-12-08 05:30:24 +00:00
{
u32 addr ;
sscanf ( txt . mb_str (), "%08x" , & addr );
2009-06-17 19:50:59 +00:00
memview -> Center ( addr & ~ 3 );
2008-12-08 05:30:24 +00:00
}
event . Skip ( 1 );
}
void CMemoryWindow :: Update ()
{
memview -> Refresh ();
memview -> Center ( PC );
}
void CMemoryWindow :: NotifyMapLoaded ()
{
symbols -> Show ( false ); // hide it for faster filling
symbols -> Clear ();
/*
2010-01-16 19:01:00 +00:00
#ifdef _WIN32
2008-12-08 05:30:24 +00:00
const FunctionDB::XFuncMap &syms = g_symbolDB.Symbols();
for (FuntionDB::XFuncMap::iterator iter = syms.begin(); iter != syms.end(); ++iter)
{
2010-01-16 19:01:00 +00:00
int idx = symbols->Append(iter->second.name.c_str());
symbols->SetClientData(idx, (void*)&iter->second);
2008-12-08 05:30:24 +00:00
}
//
2010-01-16 19:01:00 +00:00
#endif
*/
2008-12-08 05:30:24 +00:00
symbols -> Show ( true );
Update ();
}
void CMemoryWindow :: OnSymbolListChange ( wxCommandEvent & event )
{
int index = symbols -> GetSelection ();
if ( index >= 0 ) {
Symbol * pSymbol = static_cast < Symbol *> ( symbols -> GetClientData ( index ));
if ( pSymbol != NULL )
{
memview -> Center ( pSymbol -> address );
}
}
}
void CMemoryWindow :: OnHostMessage ( wxCommandEvent & event )
{
switch ( event . GetId ())
{
2010-01-16 19:01:00 +00:00
case IDM_NOTIFYMAPLOADED :
NotifyMapLoaded ();
break ;
2008-12-08 05:30:24 +00:00
}
}
2009-01-21 17:02:01 +00:00
// so we can view memory in a tile/hex viewer for data analysis
void CMemoryWindow :: OnDumpMemory ( wxCommandEvent & event )
{
2009-06-30 21:11:39 +00:00
switch ( memview -> GetMemoryType ())
2009-01-21 17:02:01 +00:00
{
2009-06-30 21:11:39 +00:00
case 0 :
default :
2009-01-21 17:02:01 +00:00
{
2010-02-02 21:56:29 +00:00
FILE * pDumpFile = fopen ( File :: GetUserPath ( F_RAMDUMP_IDX ), "wb" );
2009-06-30 21:11:39 +00:00
if ( pDumpFile )
{
if ( Memory :: m_pRAM )
{
fwrite ( Memory :: m_pRAM , Memory :: REALRAM_SIZE , 1 , pDumpFile );
}
fclose ( pDumpFile );
}
2009-01-21 17:02:01 +00:00
}
2009-06-30 21:11:39 +00:00
break ;
2008-12-08 05:30:24 +00:00
2009-06-30 21:11:39 +00:00
case 1 :
{
2010-02-02 21:56:29 +00:00
FILE * pDumpFile = fopen ( File :: GetUserPath ( F_ARAMDUMP_IDX ), "wb" );
2009-06-30 21:11:39 +00:00
if ( pDumpFile )
{
u8 * aram = DSP :: GetARAMPtr ();
if ( aram )
{
fwrite ( aram , DSP :: ARAM_SIZE , 1 , pDumpFile );
}
fclose ( pDumpFile );
}
}
break ;
}
}
2009-11-25 10:07:56 +00:00
2010-01-16 19:01:00 +00:00
void CMemoryWindow :: U8 ( wxCommandEvent & event ) {
chk16 -> SetValue ( 0 );
chk32 -> SetValue ( 0 );
memview -> dataType = 0 ;
memview -> Refresh ();
2009-11-25 10:07:56 +00:00
}
2010-01-16 19:01:00 +00:00
void CMemoryWindow :: U16 ( wxCommandEvent & event ) {
chk8 -> SetValue ( 0 );
chk32 -> SetValue ( 0 );
memview -> dataType = 1 ;
memview -> Refresh ();
2009-11-25 10:07:56 +00:00
}
2010-01-16 19:01:00 +00:00
void CMemoryWindow :: U32 ( wxCommandEvent & event ) {
chk16 -> SetValue ( 0 );
chk8 -> SetValue ( 0 );
memview -> dataType = 2 ;
memview -> Refresh ();
2009-11-25 10:07:56 +00:00
}
2010-01-16 19:01:00 +00:00
void CMemoryWindow :: onSearch ( wxCommandEvent & event ) {
2009-11-25 10:07:56 +00:00
u8 * TheRAM = 0 ;
u32 szRAM = 0 ;
switch ( memview -> GetMemoryType ())
{
case 0 :
default :
2010-01-16 19:01:00 +00:00
if ( Memory :: m_pRAM )
2009-11-25 10:07:56 +00:00
{
2010-01-16 19:01:00 +00:00
TheRAM = Memory :: m_pRAM ;
szRAM = Memory :: REALRAM_SIZE ;
2009-11-25 10:07:56 +00:00
}
break ;
case 1 :
{
2010-01-16 19:01:00 +00:00
u8 * aram = DSP :: GetARAMPtr ();
if ( aram )
{
TheRAM = aram ;
szRAM = DSP :: ARAM_SIZE ;
}
2009-11-25 10:07:56 +00:00
}
break ;
}
//Now we have memory to look in
//Are we looking for ASCII string, or hex?
//memview->cu
2010-01-16 19:01:00 +00:00
wxString rawData = valbox -> GetValue ();
std :: vector < u8 > Dest ; //May need a better name
u32 size = 0 ;
int pad = rawData . size () % 2 ; //If it's uneven
unsigned long i = 0 ;
long count = 0 ;
char copy [ 3 ] = { 0 };
long newsize = 0 ;
unsigned char * tmp2 = 0 ;
char * tmpstr = 0 ;
switch ( chkHex -> GetValue ()){
2009-11-25 10:07:56 +00:00
case 1 : //We are looking for hex
2010-01-16 19:01:00 +00:00
//If it's uneven
2009-11-25 10:07:56 +00:00
size = ( rawData . size () / 2 ) + pad ;
2010-01-16 19:01:00 +00:00
Dest . resize ( size + 32 );
newsize = rawData . size ();
if ( pad ) {
tmpstr = new char [ newsize + 2 ];
memset ( tmpstr , 0 , newsize + 2 );
tmpstr [ 0 ] = '0' ;
} else {
tmpstr = new char [ newsize + 1 ];
memset ( tmpstr , 0 , newsize + 1 );
2009-11-25 10:07:56 +00:00
}
//sprintf(tmpstr,"%s%s",tmpstr,rawData.c_str());
2010-01-16 19:01:00 +00:00
//strcpy(&tmpstr[1],rawData.ToAscii());
2009-11-25 10:07:56 +00:00
//memcpy(&tmpstr[1],&rawData.c_str()[0],rawData.size());
2009-12-15 14:40:03 +00:00
sprintf ( tmpstr , "%s%s" , tmpstr ,( const char * ) rawData . mb_str ());
2010-01-16 19:01:00 +00:00
tmp2 =& Dest . front ();
count = 0 ;
for ( i = 0 ; i < strlen ( tmpstr ); i ++ ){
copy [ 0 ] = tmpstr [ i ];
copy [ 1 ] = tmpstr [ i + 1 ];
copy [ 2 ] = 0 ;
int tmpint ;
sscanf ( copy , "%02x" , & tmpint );
tmp2 [ count ++ ] = tmpint ;
//sscanf(copy,"%02x",&tmp2[count++]);//Dest[count] should now be the hex of what the two chars were! Also should add a check to make sure it's A-F only
i += 1 ; //
}
delete [] tmpstr ;
break ;
case 0 : //Looking for an ascii string
size = rawData . size ();
Dest . resize ( size + 1 );
tmpstr = new char [ size + 1 ];
tmp2 =& Dest . front ();
sprintf ( tmpstr , "%s" ,( const char * ) rawData . mb_str ());
for ( i = 0 ; i < size ; i ++ ){
tmp2 [ i ] = tmpstr [ i ];
}
delete [] tmpstr ;
2009-11-25 10:07:56 +00:00
break ;
}
if ( size ){
2010-01-16 19:01:00 +00:00
unsigned char * pnt =& Dest . front ();
unsigned int k = 0 ;
//grab
wxString txt = addrbox -> GetValue ();
u32 addr = 0 ;
if ( txt . size ())
{
sscanf ( txt . mb_str (), "%08x" , & addr );
}
i = addr + 4 ;
for (; szRAM ; i ++ ){
2009-11-25 10:07:56 +00:00
for ( k = 0 ; k < size ; k ++ ){
if ( i + k > szRAM ) break ;
if ( k > size ) break ;
if ( pnt [ k ] != TheRAM [ i + k ]){
k = 0 ;
break ;
}
}
if ( k == size ){
//Match was found
wxMessageBox ( _T ( "A match was found. Placing viewer at the offset." ));
2010-02-21 18:55:00 +00:00
wxChar tmpwxstr [ 128 ] = { 0 };
wxSprintf ( tmpwxstr , _T ( "%08x" ), i );
wxString tmpwx ( tmpwxstr );
2009-11-25 10:07:56 +00:00
addrbox -> SetValue ( tmpwx );
//memview->curAddress=i;
//memview->Refresh();
OnAddrBoxChange ( event );
return ;
}
}
2010-01-16 19:01:00 +00:00
wxMessageBox ( _T ( "No match was found." ));
2009-11-25 10:07:56 +00:00
}
}
2010-01-16 19:01:00 +00:00
void CMemoryWindow :: onAscii ( wxCommandEvent & event ) {
chkHex -> SetValue ( 0 );
2009-11-25 10:07:56 +00:00
}
2010-01-16 19:01:00 +00:00
void CMemoryWindow :: onHex ( wxCommandEvent & event ) {
chkAscii -> SetValue ( 0 );
2009-12-15 14:40:03 +00:00
}