daedalus/Source/Debug/Dump.cpp
2025-02-22 19:07:04 +11:00

274 lines
6.9 KiB
C++

/*
Copyright (C) 2001 StrmnNrmn
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; either version 2
of the License, or (at your option) any later version.
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 for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
// Display stuff like registers, instructions, memory usage and so on
#include "Base/Types.h"
#include <ctype.h>
#include <filesystem>
#include <iostream>
#include <fstream>
#include <cstring>
#include "Interface/ConfigOptions.h"
#include "Core/CPU.h"
#include "Core/Interrupt.h"
#include "Core/Memory.h"
#include "RomFile/ROMBuffer.h"
#include "Debug/Dump.h"
#include "Debug/DebugLog.h"
#include "Debug/DBGConsole.h"
#include "OSHLE/patch.h" // For GetCorrectOp
#include "Ultra/ultra_R4300.h"
#include "Debug/PrintOpCode.h"
const std::filesystem::path gDumpDir = "Dumps";
// Initialise the directory where files are dumped
// Appends subdir to the global dump base. Stores in rootdir)
// Not really required with std::filesystem
void Dump_GetDumpDirectory(std::filesystem::path& rootdir, const std::filesystem::path& subdir)
{
if (!subdir.empty())
{
rootdir = gDumpDir / subdir;
}
else
{
rootdir = gDumpDir;
}
}
#ifndef DAEDALUS_SILENT
//*****************************************************************************
//
//*****************************************************************************
void Dump_DisassembleMIPSRange(std::ofstream& fh, u32 address_offset, const OpCode * b, const OpCode * e)
{
u32 address( address_offset );
const OpCode * p( b );
while( p < e )
{
char opinfo[400];
OpCode op( GetCorrectOp( *p ) );
#if 0
if (translate_patches)
{
///TODO: We need a way to know this
if (IsJumpTarget( op ))
{
fprintf(fp, "\n");
fprintf(fp, "\n");
fprintf(fp, "// %s():\n", Patch_GetJumpAddressName(current_pc));
}
}
#endif
SprintOpCodeInfo( opinfo, address, op );
std::string data = FORMAT_NAMESPACE::format("0x{}: <0x{}> {}", address, op._u32, opinfo);
fh << data;
// fprintf(fh, "0x%08x: <0x%08x> %s\n", address, op._u32, opinfo);
address += 4;
++p;
}
}
void Dump_Disassemble(u32 start, u32 end, const std::filesystem::path& p_file_name)
{
std::filesystem::path file_path = setBasePath(p_file_name);
// Cute hack - if the end of the range is less than the start,
// assume it is a length to disassemble
if (end < start)
end = start + end;
u8 * p_base;
if (!Memory_GetInternalReadAddress(start, (void**)&p_base))
{
DBGConsole_Msg(0, "[Ydis: Invalid base 0x%08x]", start);
return;
}
std::ofstream fp(file_path, std::ios::out);
DBGConsole_Msg(0, "Disassembling from 0x%08x to 0x%08x ([C%s])", start, end, file_path.string().c_str());
const OpCode * op_start( reinterpret_cast< const OpCode * >( p_base ) );
const OpCode * op_end( reinterpret_cast< const OpCode * >( p_base + (end-start) ) );
Dump_DisassembleMIPSRange(fp, start, op_start, op_end);
}
#endif
#ifndef DAEDALUS_SILENT
// N.B. This assumbes that b/e are 4 byte aligned (otherwise endianness is broken)
void Dump_MemoryRange(std::ofstream& fh, u32 address_offset, const u32 * b, const u32 * e)
{
u32 address( address_offset );
const u32 * p( b );
while( p < e )
{
std::string output = FORMAT_NAMESPACE::format("0x{}x: {} {} {} {} ", address, p[0], p[1], p[2], p[3]);
fh << output;
const u8 * p8( reinterpret_cast< const u8 * >( p ) );
for (u32 i = 0; i < 16; i++)
{
u8 c( p8[i ^ U8_TWIDDLE] );
if (c >= 32 && c < 128)
fh << c;
else
fh << ".";
if ((i%4)==3)
fh << " " ;
}
fh << "\n";
address += 16;
p += 4;
}
}
void Dump_DisassembleRSPRange(std::ofstream& fh, u32 address_offset, const OpCode * b, const OpCode * e)
{
u32 address( address_offset );
const OpCode * p( b );
while( p < e )
{
char opinfo[400];
SprintRSPOpCodeInfo( opinfo, address, *p );
std::string output = FORMAT_NAMESPACE::format("0x{}: <0x{}> {}\n", address, p->_u32, opinfo);
fh << output;
address += 4;
++p;
}
}
void Dump_RSPDisassemble(const std::filesystem::path& p_file_name)
{
u8 * base;
u32 start = 0xa4000000;
u32 end = 0xa4002000;
if (!Memory_GetInternalReadAddress(start, (void**)&base))
{
DBGConsole_Msg(0, "[Yrdis: Invalid base 0x%08x]", start);
return;
}
std::filesystem::path file_path = setBasePath(p_file_name);
DBGConsole_Msg(0, "Disassembling from 0x%08x to 0x%08x ([C%s])", start, end, file_path.string().c_str());
std::ofstream fp(p_file_name, std::ios::out);
const u32 * mem_start( reinterpret_cast< const u32 * >( base + 0x0000 ) );
const u32 * mem_end( reinterpret_cast< const u32 * >( base + 0x1000 ) );
Dump_MemoryRange( fp, start, mem_start, mem_end );
const OpCode * op_start( reinterpret_cast< const OpCode * >( base + 0x1000 ) );
const OpCode * op_end( reinterpret_cast< const OpCode * >( base + 0x2000 ) );
Dump_DisassembleRSPRange( fp, start + 0x1000, op_start, op_end );
// fclose(fp);
}
#endif
#ifndef DAEDALUS_SILENT
//*****************************************************************************
//
//*****************************************************************************
void Dump_Strings( const char * p_file_name )
{
std::filesystem::path file_path;
std::ofstream fp;
static const u32 MIN_LENGTH = 5;
if (p_file_name == NULL || strlen(p_file_name) == 0)
{
file_path /= "strings.txt";
}
else
{
file_path = p_file_name;
}
DBGConsole_Msg(0, "Dumping strings in rom ([C%s])", file_path.string().c_str());
// Overwrite here
fp.open(file_path, std::ios::out);
// Memory dump
u32 ascii_start = 0;
u32 ascii_count = 0;
for ( u32 i = 0; i < RomBuffer::GetRomSize(); i ++)
{
if ( RomBuffer::ReadValueRaw< u8 >( i ^ 0x3 ) >= ' ' &&
RomBuffer::ReadValueRaw< u8 >( i ^ 0x3 ) < 200 )
{
if ( ascii_count == 0 )
{
ascii_start = i;
}
ascii_count++;
}
else
{
if ( ascii_count >= MIN_LENGTH )
{
std::string output = FORMAT_NAMESPACE::format("0x{}", ascii_start);
fp << output;
// fprintf( fp, "0x%08x: ", ascii_start );
for ( u32 j = 0; j < ascii_count; j++ )
{
fp << RomBuffer::ReadValueRaw< u8 >( (ascii_start + j ) ^ 0x3 );
// fprintf( fp, "%c", RomBuffer::ReadValueRaw< u8 >( (ascii_start + j ) ^ 0x3 ) );
}
fp << "\n";
// fprintf( fp, "\n");
}
ascii_count = 0;
}
}
// fclose(fp);
}
#endif