Initial debugger work by Kingcom. Features:

- Advanced disassembly view for R5900 and R3000
  - Register list with change highlight
  - Editable memory view
  - Conditional execute breakpoints (r5900 only)
  - Step over
  - Scan for functions (incomplete), show macros
  - Enable C++11 for debug tools.
  - Expression parser
  - Disasm updates for thread safety
Squashed from: https://github.com/PCSX2/pcsx2/pull/1
Thanks to Kingcom for coding it all and mziab for Linux patches


git-svn-id: http://pcsx2.googlecode.com/svn/trunk@5905 96395faa-99c1-11dd-bbfe-3dabce05a288
This commit is contained in:
gigaherz 2014-02-21 14:29:13 +00:00
parent 038d3bea87
commit babd8868d9
49 changed files with 7481 additions and 89 deletions

View File

@ -361,6 +361,7 @@ static __fi void _reloadElfInfo(wxString elfpath)
ElfCRC = elfptr->getCRC();
ElfEntry = elfptr->header.e_entry;
ElfTextRange = elfptr->getTextRange();
Console.WriteLn( Color_StrongBlue, L"ELF (%s) Game CRC = 0x%08X, EntryPoint = 0x%08X", elfpath.c_str(), ElfCRC, ElfEntry);
// Note: Do not load game database info here. This code is generic and called from

View File

@ -261,6 +261,12 @@ set(pcsx2CDVDHeaders
# DebugTools sources
set(pcsx2DebugToolsSources
DebugTools/DebugInterface.cpp
DebugTools/DisassemblyManager.cpp
DebugTools/ExpressionParser.cpp
DebugTools/MIPSAnalyst.cpp
DebugTools/Breakpoints.cpp
DebugTools/SymbolMap.cpp
DebugTools/DisR3000A.cpp
DebugTools/DisR5900asm.cpp
DebugTools/DisR5900.cpp
@ -269,6 +275,12 @@ set(pcsx2DebugToolsSources
# DebugTools headers
set(pcsx2DebugToolsHeaders
DebugTools/DebugInterface.h
DebugTools/DisassemblyManager.h
DebugTools/ExpressionParser.h
DebugTools/MIPSAnalyst.h
DebugTools/Breakpoints.h
DebugTools/SymbolMap.h
DebugTools/Debug.h
DebugTools/DisASm.h
DebugTools/DisVUmicro.h
@ -307,6 +319,12 @@ set(pcsx2GuiSources
gui/Dialogs/PickUserModeDialog.cpp
gui/Dialogs/StuckThreadDialog.cpp
gui/Dialogs/SysConfigDialog.cpp
gui/Debugger/BreakpointWindow.cpp
gui/Debugger/CtrlDisassemblyView.cpp
gui/Debugger/CtrlRegisterList.cpp
gui/Debugger/CtrlMemView.cpp
gui/Debugger/DisassemblyDialog.cpp
gui/Debugger/DebugEvents.cpp
gui/ExecutorThread.cpp
gui/FrameForGS.cpp
gui/GlobalCommands.cpp
@ -356,6 +374,12 @@ set(pcsx2GuiHeaders
gui/Dialogs/ConfigurationDialog.h
gui/Dialogs/LogOptionsDialog.h
gui/Dialogs/ModalPopups.h
gui/Debugger/BreakpointWindow.h
gui/Debugger/CtrlDisassemblyView.h
gui/Debugger/CtrlRegisterList.h
gui/Debugger/CtrlMemView.h
gui/Debugger/DisassemblyDialog.h
gui/Debugger/DebugEvents.h
gui/i18n.h
gui/IsoDropTarget.h
gui/MainFrame.h
@ -387,6 +411,8 @@ set(pcsx2GuiResources
${res_bin}/ConfigIcon_Speedhacks.h
${res_bin}/ConfigIcon_Video.h
${res_bin}/Dualshock.h
${res_bin}/Breakpoint_Active.h
${res_bin}/Breakpoint_Inactive.h
)
# IPU sources
@ -586,6 +612,9 @@ set(pcsx2SSources
# change language of .S-files to c++
set_source_files_properties(${pcsx2SSources} PROPERTIES LANGUAGE CXX)
# C++11 is used for debug tools, so we enable it
set_source_files_properties(${pcsx2DebugToolsSources} PROPERTIES COMPILE_FLAGS "-std=c++0x")
# common Sources
set(Common
${pcsx2Sources}
@ -593,7 +622,6 @@ set(Common
${pcsx2CDVDSources}
${pcsx2CDVDHeaders}
${pcsx2DebugToolsSources}
${pcsx2DebugToolsSources}
${pcsx2GuiSources}
${pcsx2GuiResources}
${pcsx2GuiHeaders}
@ -652,12 +680,12 @@ add_custom_command(OUTPUT "${res_bin}/Dualshock.h" COMMAND perl ${PROJECT_SOUR
foreach(res_file IN ITEMS
AppIcon16 AppIcon32 AppIcon64 BackgroundLogo ButtonIcon_Camera
ConfigIcon_Appearance ConfigIcon_Cpu ConfigIcon_Gamefixes ConfigIcon_MemoryCard
ConfigIcon_Paths ConfigIcon_Plugins ConfigIcon_Speedhacks ConfigIcon_Video)
ConfigIcon_Paths ConfigIcon_Plugins ConfigIcon_Speedhacks ConfigIcon_Video Breakpoint_Active Breakpoint_Inactive)
add_custom_command(OUTPUT "${res_bin}/${res_file}.h" COMMAND perl ${PROJECT_SOURCE_DIR}/linux_various/hex2h.pl "${res_src}/${res_file}.png" "${res_bin}/${res_file}" )
endforeach(res_file IN ITEMS
AppIcon16 AppIcon32 AppIcon64 BackgroundLogo ButtonIcon_Camera
ConfigIcon_Appearance ConfigIcon_Cpu ConfigIcon_Gamefixes ConfigIcon_MemoryCard
ConfigIcon_Paths ConfigIcon_Plugins ConfigIcon_Speedhacks ConfigIcon_Video)
ConfigIcon_Paths ConfigIcon_Plugins ConfigIcon_Speedhacks ConfigIcon_Video Breakpoint_Active Breakpoint_Inactive)
# Suppress all the system-specific predefined macros outside the reserved namespace.
# Needed when stringifying macros.

View File

@ -0,0 +1,397 @@
#include "PrecompiledHeader.h"
#include "Breakpoints.h"
#include "SymbolMap.h"
#include "MIPSAnalyst.h"
#include <cstdio>
#include "../R5900.h"
#include "../System.h"
std::vector<BreakPoint> CBreakPoints::breakPoints_;
u32 CBreakPoints::breakSkipFirstAt_ = 0;
u64 CBreakPoints::breakSkipFirstTicks_ = 0;
std::vector<MemCheck> CBreakPoints::memChecks_;
std::vector<MemCheck *> CBreakPoints::cleanupMemChecks_;
MemCheck::MemCheck()
{
numHits = 0;
}
void MemCheck::Log(u32 addr, bool write, int size, u32 pc)
{
}
void MemCheck::Action(u32 addr, bool write, int size, u32 pc)
{
int mask = write ? MEMCHECK_WRITE : MEMCHECK_READ;
if (cond & mask)
{
++numHits;
Log(addr, write, size, pc);
if (result & MEMCHECK_BREAK)
{
// Core_EnableStepping(true);
// host->SetDebugMode(true);
}
}
}
void MemCheck::JitBefore(u32 addr, bool write, int size, u32 pc)
{
int mask = MEMCHECK_WRITE | MEMCHECK_WRITE_ONCHANGE;
if (write && (cond & mask) == mask)
{
lastAddr = addr;
lastPC = pc;
lastSize = size;
// We have to break to find out if it changed.
//Core_EnableStepping(true);
}
else
{
lastAddr = 0;
Action(addr, write, size, pc);
}
}
void MemCheck::JitCleanup()
{
if (lastAddr == 0 || lastPC == 0)
return;
/*
// Here's the tricky part: would this have changed memory?
// Note that it did not actually get written.
bool changed = MIPSAnalyst::OpWouldChangeMemory(lastPC, lastAddr);
if (changed)
{
++numHits;
Log(lastAddr, true, lastSize, lastPC);
}
// Resume if it should not have gone to stepping, or if it did not change.
if ((!(result & MEMCHECK_BREAK) || !changed) && coreState == CORE_STEPPING)
{
CBreakPoints::SetSkipFirst(lastPC);
Core_EnableStepping(false);
}
else
host->SetDebugMode(true);*/
}
size_t CBreakPoints::FindBreakpoint(u32 addr, bool matchTemp, bool temp)
{
for (size_t i = 0; i < breakPoints_.size(); ++i)
{
if (breakPoints_[i].addr == addr && (!matchTemp || breakPoints_[i].temporary == temp))
return i;
}
return INVALID_BREAKPOINT;
}
size_t CBreakPoints::FindMemCheck(u32 start, u32 end)
{
for (size_t i = 0; i < memChecks_.size(); ++i)
{
if (memChecks_[i].start == start && memChecks_[i].end == end)
return i;
}
return INVALID_MEMCHECK;
}
bool CBreakPoints::IsAddressBreakPoint(u32 addr)
{
size_t bp = FindBreakpoint(addr);
return bp != INVALID_BREAKPOINT && breakPoints_[bp].enabled;
}
bool CBreakPoints::IsAddressBreakPoint(u32 addr, bool* enabled)
{
size_t bp = FindBreakpoint(addr);
if (bp == INVALID_BREAKPOINT) return false;
if (enabled != NULL) *enabled = breakPoints_[bp].enabled;
return true;
}
bool CBreakPoints::IsTempBreakPoint(u32 addr)
{
size_t bp = FindBreakpoint(addr, true, true);
return bp != INVALID_BREAKPOINT;
}
void CBreakPoints::AddBreakPoint(u32 addr, bool temp)
{
size_t bp = FindBreakpoint(addr, true, temp);
if (bp == INVALID_BREAKPOINT)
{
BreakPoint pt;
pt.enabled = true;
pt.temporary = temp;
pt.addr = addr;
breakPoints_.push_back(pt);
Update(addr);
}
else if (!breakPoints_[bp].enabled)
{
breakPoints_[bp].enabled = true;
breakPoints_[bp].hasCond = false;
Update(addr);
}
}
void CBreakPoints::RemoveBreakPoint(u32 addr)
{
size_t bp = FindBreakpoint(addr);
if (bp != INVALID_BREAKPOINT)
{
breakPoints_.erase(breakPoints_.begin() + bp);
// Check again, there might've been an overlapping temp breakpoint.
bp = FindBreakpoint(addr);
if (bp != INVALID_BREAKPOINT)
breakPoints_.erase(breakPoints_.begin() + bp);
Update(addr);
}
}
void CBreakPoints::ChangeBreakPoint(u32 addr, bool status)
{
size_t bp = FindBreakpoint(addr);
if (bp != INVALID_BREAKPOINT)
{
breakPoints_[bp].enabled = status;
Update(addr);
}
}
void CBreakPoints::ClearAllBreakPoints()
{
if (!breakPoints_.empty())
{
breakPoints_.clear();
Update();
}
}
void CBreakPoints::ClearTemporaryBreakPoints()
{
if (breakPoints_.empty())
return;
for (int i = (int)breakPoints_.size()-1; i >= 0; --i)
{
if (breakPoints_[i].temporary)
{
Update(breakPoints_[i].addr);
breakPoints_.erase(breakPoints_.begin() + i);
}
}
}
void CBreakPoints::ChangeBreakPointAddCond(u32 addr, const BreakPointCond &cond)
{
size_t bp = FindBreakpoint(addr, true, false);
if (bp != INVALID_BREAKPOINT)
{
breakPoints_[bp].hasCond = true;
breakPoints_[bp].cond = cond;
Update();
}
}
void CBreakPoints::ChangeBreakPointRemoveCond(u32 addr)
{
size_t bp = FindBreakpoint(addr, true, false);
if (bp != INVALID_BREAKPOINT)
{
breakPoints_[bp].hasCond = false;
Update();
}
}
BreakPointCond *CBreakPoints::GetBreakPointCondition(u32 addr)
{
size_t bp = FindBreakpoint(addr, true, false);
if (bp != INVALID_BREAKPOINT && breakPoints_[bp].hasCond)
return &breakPoints_[bp].cond;
return NULL;
}
void CBreakPoints::AddMemCheck(u32 start, u32 end, MemCheckCondition cond, MemCheckResult result)
{
// This will ruin any pending memchecks.
cleanupMemChecks_.clear();
size_t mc = FindMemCheck(start, end);
if (mc == INVALID_MEMCHECK)
{
MemCheck check;
check.start = start;
check.end = end;
check.cond = cond;
check.result = result;
memChecks_.push_back(check);
Update();
}
else
{
memChecks_[mc].cond = (MemCheckCondition)(memChecks_[mc].cond | cond);
memChecks_[mc].result = (MemCheckResult)(memChecks_[mc].result | result);
Update();
}
}
void CBreakPoints::RemoveMemCheck(u32 start, u32 end)
{
// This will ruin any pending memchecks.
cleanupMemChecks_.clear();
size_t mc = FindMemCheck(start, end);
if (mc != INVALID_MEMCHECK)
{
memChecks_.erase(memChecks_.begin() + mc);
Update();
}
}
void CBreakPoints::ChangeMemCheck(u32 start, u32 end, MemCheckCondition cond, MemCheckResult result)
{
size_t mc = FindMemCheck(start, end);
if (mc != INVALID_MEMCHECK)
{
memChecks_[mc].cond = cond;
memChecks_[mc].result = result;
Update();
}
}
void CBreakPoints::ClearAllMemChecks()
{
// This will ruin any pending memchecks.
cleanupMemChecks_.clear();
if (!memChecks_.empty())
{
memChecks_.clear();
Update();
}
}
static inline u32 NotCached(u32 val)
{
// Remove the cached part of the address.
return val & ~0x40000000;
}
MemCheck *CBreakPoints::GetMemCheck(u32 address, int size)
{
std::vector<MemCheck>::iterator iter;
for (iter = memChecks_.begin(); iter != memChecks_.end(); ++iter)
{
MemCheck &check = *iter;
if (check.end != 0)
{
if (NotCached(address + size) > NotCached(check.start) && NotCached(address) < NotCached(check.end))
return &check;
}
else
{
if (NotCached(check.start) == NotCached(address))
return &check;
}
}
//none found
return 0;
}
void CBreakPoints::ExecMemCheck(u32 address, bool write, int size, u32 pc)
{
auto check = GetMemCheck(address, size);
if (check)
check->Action(address, write, size, pc);
}
void CBreakPoints::ExecMemCheckJitBefore(u32 address, bool write, int size, u32 pc)
{
auto check = GetMemCheck(address, size);
if (check) {
check->JitBefore(address, write, size, pc);
cleanupMemChecks_.push_back(check);
}
}
void CBreakPoints::ExecMemCheckJitCleanup()
{
for (auto it = cleanupMemChecks_.begin(), end = cleanupMemChecks_.end(); it != end; ++it) {
auto check = *it;
check->JitCleanup();
}
cleanupMemChecks_.clear();
}
void CBreakPoints::SetSkipFirst(u32 pc)
{
breakSkipFirstAt_ = pc;
// breakSkipFirstTicks_ = CoreTiming::GetTicks();
}
u32 CBreakPoints::CheckSkipFirst(u32 cmpPc)
{
u32 pc = breakSkipFirstAt_;
if (pc == cmpPc)
return 1;
return 0;
}
const std::vector<MemCheck> CBreakPoints::GetMemCheckRanges()
{
std::vector<MemCheck> ranges = memChecks_;
for (auto it = memChecks_.begin(), end = memChecks_.end(); it != end; ++it)
{
MemCheck check = *it;
// Toggle the cached part of the address.
check.start ^= 0x40000000;
if (check.end != 0)
check.end ^= 0x40000000;
ranges.push_back(check);
}
return ranges;
}
const std::vector<MemCheck> CBreakPoints::GetMemChecks()
{
return memChecks_;
}
const std::vector<BreakPoint> CBreakPoints::GetBreakpoints()
{
return breakPoints_;
}
void CBreakPoints::Update(u32 addr)
{
bool resume = false;
if (r5900Debug.isCpuPaused() == false)
{
r5900Debug.pauseCpu();
resume = true;
}
if (addr != 0)
Cpu->Clear(addr-4,8);
else
SysClearExecutionCache();
if (resume)
r5900Debug.resumeCpu();
// Redraw in order to show the breakpoint.
// host->UpdateDisassembly();
}

View File

@ -0,0 +1,166 @@
// Copyright (c) 2012- PPSSPP 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 or later versions.
// 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 git repository and contact information can be found at
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
#pragma once
#include <vector>
#include "DebugInterface.h"
#include "Pcsx2Types.h"
struct BreakPointCond
{
DebugInterface *debug;
PostfixExpression expression;
char expressionString[128];
BreakPointCond() : debug(NULL)
{
expressionString[0] = '\0';
}
u32 Evaluate()
{
u64 result;
if (debug->parseExpression(expression,result) == false || result == 0) return 0;
return 1;
}
};
struct BreakPoint
{
BreakPoint() : hasCond(false) {}
u32 addr;
bool enabled;
bool temporary;
bool hasCond;
BreakPointCond cond;
bool operator == (const BreakPoint &other) const {
return addr == other.addr;
}
bool operator < (const BreakPoint &other) const {
return addr < other.addr;
}
};
enum MemCheckCondition
{
MEMCHECK_READ = 0x01,
MEMCHECK_WRITE = 0x02,
MEMCHECK_WRITE_ONCHANGE = 0x04,
MEMCHECK_READWRITE = 0x03,
};
enum MemCheckResult
{
MEMCHECK_IGNORE = 0x00,
MEMCHECK_LOG = 0x01,
MEMCHECK_BREAK = 0x02,
MEMCHECK_BOTH = 0x03,
};
struct MemCheck
{
MemCheck();
u32 start;
u32 end;
MemCheckCondition cond;
MemCheckResult result;
u32 numHits;
u32 lastPC;
u32 lastAddr;
int lastSize;
void Action(u32 addr, bool write, int size, u32 pc);
void JitBefore(u32 addr, bool write, int size, u32 pc);
void JitCleanup();
void Log(u32 addr, bool write, int size, u32 pc);
bool operator == (const MemCheck &other) const {
return start == other.start && end == other.end;
}
};
// BreakPoints cannot overlap, only one is allowed per address.
// MemChecks can overlap, as long as their ends are different.
// WARNING: MemChecks are not used in the interpreter or HLE currently.
class CBreakPoints
{
public:
static const size_t INVALID_BREAKPOINT = -1;
static const size_t INVALID_MEMCHECK = -1;
static bool IsAddressBreakPoint(u32 addr);
static bool IsAddressBreakPoint(u32 addr, bool* enabled);
static bool IsTempBreakPoint(u32 addr);
static void AddBreakPoint(u32 addr, bool temp = false);
static void RemoveBreakPoint(u32 addr);
static void ChangeBreakPoint(u32 addr, bool enable);
static void ClearAllBreakPoints();
static void ClearTemporaryBreakPoints();
// Makes a copy. Temporary breakpoints can't have conditions.
static void ChangeBreakPointAddCond(u32 addr, const BreakPointCond &cond);
static void ChangeBreakPointRemoveCond(u32 addr);
static BreakPointCond *GetBreakPointCondition(u32 addr);
static void AddMemCheck(u32 start, u32 end, MemCheckCondition cond, MemCheckResult result);
static void RemoveMemCheck(u32 start, u32 end);
static void ChangeMemCheck(u32 start, u32 end, MemCheckCondition cond, MemCheckResult result);
static void ClearAllMemChecks();
static MemCheck *GetMemCheck(u32 address, int size);
static void ExecMemCheck(u32 address, bool write, int size, u32 pc);
// Executes memchecks but used by the jit. Cleanup finalizes after jit is done.
static void ExecMemCheckJitBefore(u32 address, bool write, int size, u32 pc);
static void ExecMemCheckJitCleanup();
static void SetSkipFirst(u32 pc);
static u32 CheckSkipFirst(u32 pc);
// Includes uncached addresses.
static const std::vector<MemCheck> GetMemCheckRanges();
static const std::vector<MemCheck> GetMemChecks();
static const std::vector<BreakPoint> GetBreakpoints();
static void Update(u32 addr = 0);
private:
static size_t FindBreakpoint(u32 addr, bool matchTemp = false, bool temp = false);
// Finds exactly, not using a range check.
static size_t FindMemCheck(u32 start, u32 end);
static std::vector<BreakPoint> breakPoints_;
static u32 breakSkipFirstAt_;
static u64 breakSkipFirstTicks_;
static std::vector<MemCheck> memChecks_;
static std::vector<MemCheck *> cleanupMemChecks_;
};

View File

@ -16,6 +16,7 @@
#pragma once
#include "Utilities/TraceLog.h"
#include "../Memory.h"
extern FILE *emuLog;
extern wxString emuLogName;
@ -29,6 +30,9 @@ extern const char * const CP2VFnames[];
extern const char * const disRNameCP2f[];
extern const char * const disRNameCP2i[];
extern const char * const disRNameCP2f[];
extern const char * const disRNameCP2i[];
namespace R5900
{
// [TODO] : These function names can be de-obfuscated with the help of a little namespace love.
@ -42,6 +46,8 @@ namespace R5900
void dFindSym( std::string& output, u32 addr );
extern const char * const disRNameGPR[];
extern const char * const disRNameCP0[];
extern const char * const disRNameCP1[];
// A helper class for getting a quick and efficient string representation of the
// R5900's current instruction. This class is *not* thread safe!

View File

@ -0,0 +1,639 @@
#include "PrecompiledHeader.h"
#include "DebugInterface.h"
#include "Memory.h"
#include "R5900.h"
#include "AppCoreThread.h"
#include "Debug.h"
#include "../VU.h"
#include "../R3000A.h"
#include "../IopMem.h"
#include "SymbolMap.h"
extern AppCoreThread CoreThread;
R5900DebugInterface r5900Debug;
R3000DebugInterface r3000Debug;
enum { EECAT_GPR, EECAT_CP0, EECAT_CP1, EECAT_CP2F, EECAT_CP2I, EECAT_COUNT };
enum { IOPCAT_GPR, IOPCAT_COUNT };
#ifdef WIN32
#define strcasecmp stricmp
#endif
enum ReferenceIndexType {
REF_INDEX_PC = 32,
REF_INDEX_HI = 33,
REF_INDEX_LO = 34,
REF_INDEX_FPU = 0x1000,
REF_INDEX_FPU_INT = 0x2000,
REF_INDEX_VFPU = 0x4000,
REF_INDEX_VFPU_INT = 0x8000,
REF_INDEX_IS_FLOAT = REF_INDEX_FPU | REF_INDEX_VFPU,
};
class MipsExpressionFunctions: public IExpressionFunctions
{
public:
MipsExpressionFunctions(DebugInterface* cpu): cpu(cpu) { };
virtual bool parseReference(char* str, u64& referenceIndex)
{
for (int i = 0; i < 32; i++)
{
char reg[8];
sprintf(reg, "r%d", i);
if (strcasecmp(str, reg) == 0 || strcasecmp(str, cpu->getRegisterName(0, i)) == 0)
{
referenceIndex = i;
return true;
}
}
if (strcasecmp(str, "pc") == 0)
{
referenceIndex = REF_INDEX_PC;
return true;
}
if (strcasecmp(str, "hi") == 0)
{
referenceIndex = REF_INDEX_HI;
return true;
}
if (strcasecmp(str, "lo") == 0)
{
referenceIndex = REF_INDEX_LO;
return true;
}
return false;
}
virtual bool parseSymbol(char* str, u64& symbolValue)
{
u32 value;
bool result = symbolMap.GetLabelValue(str,value);
symbolValue = value;
return result;
}
virtual u64 getReferenceValue(u64 referenceIndex)
{
if (referenceIndex < 32)
return cpu->getRegister(0, referenceIndex)._u64[0];
if (referenceIndex == REF_INDEX_PC)
return cpu->getPC();
if (referenceIndex == REF_INDEX_HI)
return cpu->getHI()._u64[0];
if (referenceIndex == REF_INDEX_LO)
return cpu->getLO()._u64[0];
return -1;
}
virtual ExpressionType getReferenceType(u64 referenceIndex) {
if (referenceIndex & REF_INDEX_IS_FLOAT) {
return EXPR_TYPE_FLOAT;
}
return EXPR_TYPE_UINT;
}
virtual bool getMemoryValue(u32 address, int size, u64& dest, char* error)
{
switch (size)
{
case 1: case 2: case 4: case 8:
break;
default:
sprintf(error,"Invalid memory access size %d",size);
return false;
}
if (address % size)
{
sprintf(error,"Invalid memory access (unaligned)");
return false;
}
switch (size)
{
case 1:
dest = cpu->read8(address);
break;
case 2:
dest = cpu->read16(address);
break;
case 4:
dest = cpu->read32(address);
break;
case 8:
dest = cpu->read64(address);
break;
}
return true;
}
private:
DebugInterface* cpu;
};
//
// DebugInterface
//
bool DebugInterface::isAlive()
{
return GetCoreThread().IsOpen();
}
bool DebugInterface::isCpuPaused()
{
return GetCoreThread().IsPaused();
}
void DebugInterface::pauseCpu()
{
SysCoreThread& core = GetCoreThread();
if (!core.IsPaused())
core.Pause();
}
void DebugInterface::resumeCpu()
{
SysCoreThread& core = GetCoreThread();
if (core.IsPaused())
core.Resume();
}
bool DebugInterface::initExpression(const char* exp, PostfixExpression& dest)
{
MipsExpressionFunctions funcs(this);
return initPostfixExpression(exp,&funcs,dest);
}
bool DebugInterface::parseExpression(PostfixExpression& exp, u64& dest)
{
MipsExpressionFunctions funcs(this);
return parsePostfixExpression(exp,&funcs,dest);
}
//
// R5900DebugInterface
//
u32 R5900DebugInterface::read8(u32 address)
{
if (!isValidAddress(address))
return -1;
return memRead8(address);
}
u32 R5900DebugInterface::read16(u32 address)
{
if (!isValidAddress(address))
return -1;
return memRead16(address);
}
u32 R5900DebugInterface::read32(u32 address)
{
if (!isValidAddress(address))
return -1;
return memRead32(address);
}
u64 R5900DebugInterface::read64(u32 address)
{
if (!isValidAddress(address))
return -1;
u64 result;
memRead64(address,result);
return result;
}
u128 R5900DebugInterface::read128(u32 address)
{
if (!isValidAddress(address))
return u128::From32(-1);
u128 result;
memRead128(address,result);
return result;
}
void R5900DebugInterface::write8(u32 address, u8 value)
{
if (!isValidAddress(address))
return;
memWrite8(address,value);
}
int R5900DebugInterface::getRegisterCategoryCount()
{
return EECAT_COUNT;
}
const char* R5900DebugInterface::getRegisterCategoryName(int cat)
{
switch (cat)
{
case EECAT_GPR:
return "GPR";
case EECAT_CP0:
return "CP0";
case EECAT_CP1:
return "CP1";
case EECAT_CP2F:
return "CP2f";
case EECAT_CP2I:
return "CP2i";
default:
return "Invalid";
}
}
int R5900DebugInterface::getRegisterSize(int cat)
{
switch (cat)
{
case EECAT_GPR:
case EECAT_CP2F:
return 128;
case EECAT_CP0:
case EECAT_CP1:
case EECAT_CP2I:
return 32;
default:
return 0;
}
}
int R5900DebugInterface::getRegisterCount(int cat)
{
switch (cat)
{
case EECAT_GPR:
return 35; // 32 + pc + hi + lo
case EECAT_CP0:
case EECAT_CP1:
case EECAT_CP2F:
case EECAT_CP2I:
return 32;
default:
return 0;
}
}
DebugInterface::RegisterType R5900DebugInterface::getRegisterType(int cat)
{
switch (cat)
{
case EECAT_GPR:
case EECAT_CP0:
case EECAT_CP2F:
case EECAT_CP2I:
default:
return NORMAL;
case EECAT_CP1:
return SPECIAL;
}
}
const char* R5900DebugInterface::getRegisterName(int cat, int num)
{
switch (cat)
{
case EECAT_GPR:
switch (num)
{
case 32: // pc
return "pc";
case 33: // hi
return "hi";
case 34: // lo
return "lo";
default:
return R5900::disRNameGPR[num];
}
case EECAT_CP0:
return R5900::disRNameCP0[num];
case EECAT_CP1:
return R5900::disRNameCP1[num];
case EECAT_CP2F:
return disRNameCP2f[num];
case EECAT_CP2I:
return disRNameCP2i[num];
default:
return "Invalid";
}
}
u128 R5900DebugInterface::getRegister(int cat, int num)
{
u128 result;
switch (cat)
{
case EECAT_GPR:
switch (num)
{
case 32: // pc
result = u128::From32(cpuRegs.pc);
break;
case 33: // hi
result = cpuRegs.HI.UQ;
break;
case 34: // lo
result = cpuRegs.LO.UQ;
break;
default:
result = cpuRegs.GPR.r[num].UQ;
break;
}
break;
case EECAT_CP0:
result = u128::From32(cpuRegs.CP0.r[num]);
break;
case EECAT_CP1:
result = u128::From32(fpuRegs.fpr[num].UL);
break;
case EECAT_CP2F:
result = VU1.VF[num].UQ;
break;
case EECAT_CP2I:
result = u128::From32(VU1.VI[num].UL);
break;
default:
result.From32(0);
break;
}
return result;
}
wxString R5900DebugInterface::getRegisterString(int cat, int num)
{
switch (cat)
{
case EECAT_GPR:
case EECAT_CP0:
return getRegister(cat,num).ToString();
case EECAT_CP1:
{
char str[64];
sprintf(str,"%f",fpuRegs.fpr[num].f);
return wxString(str,wxConvUTF8);
}
default:
return L"";
}
}
u128 R5900DebugInterface::getHI()
{
return cpuRegs.HI.UQ;
}
u128 R5900DebugInterface::getLO()
{
return cpuRegs.LO.UQ;
}
u32 R5900DebugInterface::getPC()
{
return cpuRegs.pc;
}
void R5900DebugInterface::setPc(u32 newPc)
{
cpuRegs.pc = newPc;
}
std::string R5900DebugInterface::disasm(u32 address)
{
std::string out;
u32 op = read32(address);
R5900::disR5900Fasm(out,op,address);
return out;
}
bool R5900DebugInterface::isValidAddress(u32 addr)
{
if (addr < 0x100000)
return false;
if (addr >= 0x10000000 && addr < 0x10010000)
return true;
if (addr >= 0x12000000 && addr < 0x12001100)
return true;
if (addr >= 0x70000000 && addr < 0x70004000)
return true;
return !(addr & 0x40000000) && vtlb_GetPhyPtr(addr & 0x1FFFFFFF) != NULL;
}
//
// R3000DebugInterface
//
u32 R3000DebugInterface::read8(u32 address)
{
if (!isValidAddress(address))
return -1;
return iopMemRead8(address);
}
u32 R3000DebugInterface::read16(u32 address)
{
if (!isValidAddress(address))
return -1;
return iopMemRead16(address);
}
u32 R3000DebugInterface::read32(u32 address)
{
if (!isValidAddress(address))
return -1;
return iopMemRead32(address);
}
u64 R3000DebugInterface::read64(u32 address)
{
return 0;
}
u128 R3000DebugInterface::read128(u32 address)
{
return u128::From32(0);
}
void R3000DebugInterface::write8(u32 address, u8 value)
{
if (!isValidAddress(address))
return;
iopMemWrite8(address,value);
}
int R3000DebugInterface::getRegisterCategoryCount()
{
return IOPCAT_COUNT;
}
const char* R3000DebugInterface::getRegisterCategoryName(int cat)
{
switch (cat)
{
case IOPCAT_GPR:
return "GPR";
default:
return "Invalid";
}
}
int R3000DebugInterface::getRegisterSize(int cat)
{
switch (cat)
{
case IOPCAT_GPR:
return 32;
default:
return 0;
}
}
int R3000DebugInterface::getRegisterCount(int cat)
{
switch (cat)
{
case IOPCAT_GPR:
return 35; // 32 + pc + hi + lo
default:
return 0;
}
}
DebugInterface::RegisterType R3000DebugInterface::getRegisterType(int cat)
{
switch (cat)
{
case IOPCAT_GPR:
default:
return DebugInterface::NORMAL;
}
}
const char* R3000DebugInterface::getRegisterName(int cat, int num)
{
switch (cat)
{
case IOPCAT_GPR:
switch (num)
{
case 32: // pc
return "pc";
case 33: // hi
return "hi";
case 34: // lo
return "lo";
default:
return R5900::disRNameGPR[num];
}
default:
return "Invalid";
}
}
u128 R3000DebugInterface::getRegister(int cat, int num)
{
u32 value;
switch (cat)
{
case IOPCAT_GPR:
switch (num)
{
case 32: // pc
value = psxRegs.pc;
break;
case 33: // hi
value = psxRegs.GPR.n.hi;
break;
case 34: // lo
value = psxRegs.GPR.n.lo;
break;
default:
value = psxRegs.GPR.r[num];
break;
}
break;
default:
value = -1;
break;
}
return u128::From32(value);
}
wxString R3000DebugInterface::getRegisterString(int cat, int num)
{
switch (cat)
{
case IOPCAT_GPR:
return getRegister(cat,num).ToString();
default:
return L"Invalid";
}
}
u128 R3000DebugInterface::getHI()
{
return u128::From32(psxRegs.GPR.n.hi);
}
u128 R3000DebugInterface::getLO()
{
return u128::From32(psxRegs.GPR.n.lo);
}
u32 R3000DebugInterface::getPC()
{
return psxRegs.pc;
}
void R3000DebugInterface::setPc(u32 newPc)
{
psxRegs.pc = newPc;
}
std::string R3000DebugInterface::disasm(u32 address)
{
std::string out;
u32 op = read32(address);
R5900::disR5900Fasm(out,op,address);
return out;
}
bool R3000DebugInterface::isValidAddress(u32 addr)
{
if (addr >= 0x10000000 && addr < 0x10010000)
return true;
if (addr >= 0x12000000 && addr < 0x12001100)
return true;
if (addr >= 0x70000000 && addr < 0x70004000)
return true;
return !(addr & 0x40000000) && vtlb_GetPhyPtr(addr & 0x1FFFFFFF) != NULL;
}

View File

@ -0,0 +1,100 @@
#pragma once
#include "MemoryTypes.h"
#include "ExpressionParser.h"
class DebugInterface
{
public:
enum RegisterType { NORMAL, SPECIAL };
virtual u32 read8(u32 address) = 0;
virtual u32 read16(u32 address) = 0;
virtual u32 read32(u32 address) = 0;
virtual u64 read64(u32 address) = 0;
virtual u128 read128(u32 address) = 0;
virtual void write8(u32 address, u8 value) = 0;
// register stuff
virtual int getRegisterCategoryCount() = 0;
virtual const char* getRegisterCategoryName(int cat) = 0;
virtual int getRegisterSize(int cat) = 0;
virtual int getRegisterCount(int cat) = 0;
virtual RegisterType getRegisterType(int cat) = 0;
virtual const char* getRegisterName(int cat, int num) = 0;
virtual u128 getRegister(int cat, int num) = 0;
virtual wxString getRegisterString(int cat, int num) = 0;
virtual u128 getHI() = 0;
virtual u128 getLO() = 0;
virtual u32 getPC() = 0;
virtual void setPc(u32 newPc) = 0;
virtual std::string disasm(u32 address) = 0;
virtual bool isValidAddress(u32 address) = 0;
bool initExpression(const char* exp, PostfixExpression& dest);
bool parseExpression(PostfixExpression& exp, u64& dest);
bool isAlive();
bool isCpuPaused();
void pauseCpu();
void resumeCpu();
};
class R5900DebugInterface: public DebugInterface
{
public:
virtual u32 read8(u32 address);
virtual u32 read16(u32 address);
virtual u32 read32(u32 address);
virtual u64 read64(u32 address);
virtual u128 read128(u32 address);
virtual void write8(u32 address, u8 value);
// register stuff
virtual int getRegisterCategoryCount();
virtual const char* getRegisterCategoryName(int cat);
virtual int getRegisterSize(int cat);
virtual int getRegisterCount(int cat);
virtual RegisterType getRegisterType(int cat);
virtual const char* getRegisterName(int cat, int num);
virtual u128 getRegister(int cat, int num);
virtual wxString getRegisterString(int cat, int num);
virtual u128 getHI();
virtual u128 getLO();
virtual u32 getPC();
virtual void setPc(u32 newPc);
virtual std::string disasm(u32 address);
virtual bool isValidAddress(u32 address);
};
class R3000DebugInterface: public DebugInterface
{
public:
virtual u32 read8(u32 address);
virtual u32 read16(u32 address);
virtual u32 read32(u32 address);
virtual u64 read64(u32 address);
virtual u128 read128(u32 address);
virtual void write8(u32 address, u8 value);
// register stuff
virtual int getRegisterCategoryCount();
virtual const char* getRegisterCategoryName(int cat);
virtual int getRegisterSize(int cat);
virtual int getRegisterCount(int cat);
virtual RegisterType getRegisterType(int cat);
virtual const char* getRegisterName(int cat, int num);
virtual u128 getRegister(int cat, int num);
virtual wxString getRegisterString(int cat, int num);
virtual u128 getHI();
virtual u128 getLO();
virtual u32 getPC();
virtual void setPc(u32 newPc);
virtual std::string disasm(u32 address);
virtual bool isValidAddress(u32 address);
};
extern R5900DebugInterface r5900Debug;
extern R3000DebugInterface r3000Debug;

View File

@ -24,19 +24,19 @@
#define DECODE_FD (DECODE_SA)
///********
#define DECODE_FUNCTION ((cpuRegs.code) & 0x3F)
#define DECODE_RD ((cpuRegs.code >> 11) & 0x1F) // The rd part of the instruction register
#define DECODE_RT ((cpuRegs.code >> 16) & 0x1F) // The rt part of the instruction register
#define DECODE_RS ((cpuRegs.code >> 21) & 0x1F) // The rs part of the instruction register
#define DECODE_SA ((cpuRegs.code >> 6) & 0x1F) // The sa part of the instruction register
#define DECODE_IMMED ( cpuRegs.code & 0xFFFF) // The immediate part of the instruction register
#define DECODE_FUNCTION ((disasmOpcode) & 0x3F)
#define DECODE_RD ((disasmOpcode >> 11) & 0x1F) // The rd part of the instruction register
#define DECODE_RT ((disasmOpcode >> 16) & 0x1F) // The rt part of the instruction register
#define DECODE_RS ((disasmOpcode >> 21) & 0x1F) // The rs part of the instruction register
#define DECODE_SA ((disasmOpcode >> 6) & 0x1F) // The sa part of the instruction register
#define DECODE_IMMED ( disasmOpcode & 0xFFFF) // The immediate part of the instruction register
#define DECODE_OFFSET ((((short)DECODE_IMMED * 4) + opcode_addr + 4))
#define DECODE_JUMP (opcode_addr & 0xf0000000)|((cpuRegs.code&0x3ffffff)<<2)
#define DECODE_JUMP (opcode_addr & 0xf0000000)|((disasmOpcode&0x3ffffff)<<2)
#define DECODE_SYSCALL ((opcode_addr & 0x03FFFFFF) >> 6)
#define DECODE_BREAK (DECODE_SYSCALL)
#define DECODE_C0BC ((cpuRegs.code >> 16) & 0x03)
#define DECODE_C1BC ((cpuRegs.code >> 16) & 0x03)
#define DECODE_C2BC ((cpuRegs.code >> 16) & 0x03)
#define DECODE_C0BC ((disasmOpcode >> 16) & 0x03)
#define DECODE_C1BC ((disasmOpcode >> 16) & 0x03)
#define DECODE_C2BC ((disasmOpcode >> 16) & 0x03)
//IOP

View File

@ -26,6 +26,7 @@
#include "R5900OpcodeTables.h"
unsigned long opcode_addr;
u32 disasmOpcode;
using namespace std;
@ -41,19 +42,19 @@ namespace R5900
#define DECODE_FD (DECODE_SA)
/// ********
#define DECODE_FUNCTION ((cpuRegs.code) & 0x3F)
#define DECODE_RD ((cpuRegs.code >> 11) & 0x1F) // The rd part of the instruction register
#define DECODE_RT ((cpuRegs.code >> 16) & 0x1F) // The rt part of the instruction register
#define DECODE_RS ((cpuRegs.code >> 21) & 0x1F) // The rs part of the instruction register
#define DECODE_SA ((cpuRegs.code >> 6) & 0x1F) // The sa part of the instruction register
#define DECODE_IMMED ( cpuRegs.code & 0xFFFF) // The immediate part of the instruction register
#define DECODE_FUNCTION ((disasmOpcode) & 0x3F)
#define DECODE_RD ((disasmOpcode >> 11) & 0x1F) // The rd part of the instruction register
#define DECODE_RT ((disasmOpcode >> 16) & 0x1F) // The rt part of the instruction register
#define DECODE_RS ((disasmOpcode >> 21) & 0x1F) // The rs part of the instruction register
#define DECODE_SA ((disasmOpcode >> 6) & 0x1F) // The sa part of the instruction register
#define DECODE_IMMED ( disasmOpcode & 0xFFFF) // The immediate part of the instruction register
#define DECODE_OFFSET ((((short)DECODE_IMMED * 4) + opcode_addr + 4))
#define DECODE_JUMP (opcode_addr & 0xf0000000)|((cpuRegs.code&0x3ffffff)<<2)
#define DECODE_JUMP (opcode_addr & 0xf0000000)|((disasmOpcode&0x3ffffff)<<2)
#define DECODE_SYSCALL ((opcode_addr & 0x03FFFFFF) >> 6)
#define DECODE_BREAK (DECODE_SYSCALL)
#define DECODE_C0BC ((cpuRegs.code >> 16) & 0x03)
#define DECODE_C1BC ((cpuRegs.code >> 16) & 0x03)
#define DECODE_C2BC ((cpuRegs.code >> 16) & 0x03)
#define DECODE_C0BC ((disasmOpcode >> 16) & 0x03)
#define DECODE_C1BC ((disasmOpcode >> 16) & 0x03)
#define DECODE_C2BC ((disasmOpcode >> 16) & 0x03)
*/
/*************************CPUS REGISTERS**************************/
static const char * const GPR_REG[32] = {
@ -609,15 +610,10 @@ void disR5900Fasm( string& output, u32 code, u32 pc )
string dbuf;
char obuf[48];
const u32 scode = cpuRegs.code;
opcode_addr = pc;
cpuRegs.code = code;
disasmOpcode = code;
sprintf(obuf, "%08X:\t", pc );
output.assign( obuf );
GetCurrentInstruction().disasm( output );
cpuRegs.code = scode;
GetInstruction(code).disasm( output );
}
//*************************************************************
@ -632,7 +628,7 @@ void P_COP2_SPECIAL( string& output )
}
void P_COP2_SPECIAL2( string& output )
{
COP2SPECIAL2PrintTable[(cpuRegs.code & 0x3) | ((cpuRegs.code >> 4) & 0x7c)]( output );
COP2SPECIAL2PrintTable[(disasmOpcode & 0x3) | ((disasmOpcode >> 4) & 0x7c)]( output );
}
//**************************UNKNOWN****************************
@ -649,15 +645,7 @@ void P_COP2_Unknown( string& output )
void label_decode( string& output, u32 addr )
{
string buf;
ssprintf(buf, "0x%08X", addr);
const char* label = disR5900GetSym( addr );
if( label != NULL )
{
output += label;
output += ' ';
}
ssprintf(buf, "->$0x%08X", addr);
output += buf;
}
@ -757,7 +745,7 @@ void LQC2( string& output ) { _sap("lqc2\t%s, 0x%04X(%s)") COP2_REG_FP[DECOD
void SLL( string& output )
{
if (cpuRegs.code == 0x00000000)
if (disasmOpcode == 0x00000000)
output += "nop";
else
_sap("sll\t%s, %s, 0x%02X") GPR_REG[DECODE_RD], GPR_REG[DECODE_RT], DECODE_SA);
@ -768,16 +756,16 @@ void SRA( string& output ) { _sap("sra\t%s, %s, 0x%02X") GPR_REG[DECODE_RD],
void SLLV( string& output ) { _sap("sllv\t%s, %s, %s") GPR_REG[DECODE_RD], GPR_REG[DECODE_RT], GPR_REG[DECODE_RS]); }
void SRLV( string& output ) { _sap("srlv\t%s, %s, %s") GPR_REG[DECODE_RD], GPR_REG[DECODE_RT], GPR_REG[DECODE_RS]);}
void SRAV( string& output ) { _sap("srav\t%s, %s, %s") GPR_REG[DECODE_RD], GPR_REG[DECODE_RT], GPR_REG[DECODE_RS]); }
void JR( string& output ) { _sap("jr\t%s") GPR_REG[DECODE_RS]); }
void JR( string& output ) { _sap("jr\t->%s") GPR_REG[DECODE_RS]); }
void JALR( string& output )
{
int rd = DECODE_RD;
if (rd == 31)
_sap("jalr\t%s") GPR_REG[DECODE_RS]);
_sap("jalr\t->%s") GPR_REG[DECODE_RS]);
else
_sap("jalr\t%s, %s") GPR_REG[rd], GPR_REG[DECODE_RS]);
_sap("jalr\t%s, ->%s") GPR_REG[rd], GPR_REG[DECODE_RS]);
}
@ -1032,10 +1020,10 @@ void P_BC2T( string& output ){ output += "bc2t\t"; offset_decode(output)
void P_BC2FL( string& output ){ output += "bc2fl\t"; offset_decode(output); }
void P_BC2TL( string& output ){ output += "bc2tl\t"; offset_decode(output); }
//******************************SPECIAL 1 VUO TABLE****************************************
#define _X ((cpuRegs.code>>24) & 1)
#define _Y ((cpuRegs.code>>23) & 1)
#define _Z ((cpuRegs.code>>22) & 1)
#define _W ((cpuRegs.code>>21) & 1)
#define _X ((disasmOpcode>>24) & 1)
#define _Y ((disasmOpcode>>23) & 1)
#define _Z ((disasmOpcode>>22) & 1)
#define _W ((disasmOpcode>>21) & 1)
const char *dest_string(void)
{
@ -1054,13 +1042,13 @@ const char *dest_string(void)
char dest_fsf()
{
const char arr[4] = { 'x', 'y', 'z', 'w' };
return arr[(cpuRegs.code>>21)&3];
return arr[(disasmOpcode>>21)&3];
}
char dest_ftf()
{
const char arr[4] = { 'x', 'y', 'z', 'w' };
return arr[(cpuRegs.code>>23)&3];
return arr[(disasmOpcode>>23)&3];
}
void P_VADDx( string& output ){_sap("vaddx.%s %s, %s, %sx") dest_string(),COP2_REG_FP[DECODE_FD], COP2_REG_FP[DECODE_FS],COP2_REG_FP[DECODE_FT]); }

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,198 @@
#pragma once
#include "SymbolMap.h"
#include "Utilities/Threading.h"
#include "Pcsx2Types.h"
#include "DebugInterface.h"
#include "MIPSAnalyst.h"
enum DisassemblyLineType { DISTYPE_OPCODE, DISTYPE_MACRO, DISTYPE_DATA, DISTYPE_OTHER };
struct DisassemblyLineInfo
{
DisassemblyLineType type;
MIPSAnalyst::MipsOpcodeInfo info;
std::string name;
std::string params;
u32 totalSize;
};
enum LineType { LINE_UP, LINE_DOWN, LINE_RIGHT };
struct BranchLine
{
u32 first;
u32 second;
LineType type;
int laneIndex;
bool operator<(const BranchLine& other) const
{
return first < other.first;
}
};
class DisassemblyEntry
{
public:
virtual ~DisassemblyEntry() { };
virtual void recheck() = 0;
virtual int getNumLines() = 0;
virtual int getLineNum(u32 address, bool findStart) = 0;
virtual u32 getLineAddress(int line) = 0;
virtual u32 getTotalSize() = 0;
virtual bool disassemble(u32 address, DisassemblyLineInfo& dest, bool insertSymbols) = 0;
virtual void getBranchLines(u32 start, u32 size, std::vector<BranchLine>& dest) { };
};
class DisassemblyFunction: public DisassemblyEntry
{
public:
DisassemblyFunction(DebugInterface* _cpu, u32 _address, u32 _size);
virtual void recheck();
virtual int getNumLines();
virtual int getLineNum(u32 address, bool findStart);
virtual u32 getLineAddress(int line);
virtual u32 getTotalSize() { return size; };
virtual bool disassemble(u32 address, DisassemblyLineInfo& dest, bool insertSymbols);
virtual void getBranchLines(u32 start, u32 size, std::vector<BranchLine>& dest);
private:
void generateBranchLines();
void load();
void clear();
void addOpcodeSequence(u32 start, u32 end);
DebugInterface* cpu;
u32 address;
u32 size;
u32 hash;
std::vector<BranchLine> lines;
std::map<u32,DisassemblyEntry*> entries;
std::vector<u32> lineAddresses;
};
class DisassemblyOpcode: public DisassemblyEntry
{
public:
DisassemblyOpcode(DebugInterface* _cpu, u32 _address, int _num): cpu(_cpu), address(_address), num(_num) { };
virtual ~DisassemblyOpcode() { };
virtual void recheck() { };
virtual int getNumLines() { return num; };
virtual int getLineNum(u32 address, bool findStart) { return (address-this->address)/4; };
virtual u32 getLineAddress(int line) { return address+line*4; };
virtual u32 getTotalSize() { return num*4; };
virtual bool disassemble(u32 address, DisassemblyLineInfo& dest, bool insertSymbols);
virtual void getBranchLines(u32 start, u32 size, std::vector<BranchLine>& dest);
private:
DebugInterface* cpu;
u32 address;
int num;
};
class DisassemblyMacro: public DisassemblyEntry
{
public:
DisassemblyMacro(DebugInterface* _cpu, u32 _address): cpu(_cpu), address(_address) { };
virtual ~DisassemblyMacro() { };
void setMacroLi(u32 _immediate, u8 _rt);
void setMacroMemory(std::string _name, u32 _immediate, u8 _rt, int _dataSize);
virtual void recheck() { };
virtual int getNumLines() { return 1; };
virtual int getLineNum(u32 address, bool findStart) { return 0; };
virtual u32 getLineAddress(int line) { return address; };
virtual u32 getTotalSize() { return numOpcodes*4; };
virtual bool disassemble(u32 address, DisassemblyLineInfo& dest, bool insertSymbols) ;
private:
enum MacroType { MACRO_LI, MACRO_MEMORYIMM };
DebugInterface* cpu;
MacroType type;
std::string name;
u32 immediate;
u32 address;
u32 numOpcodes;
u8 rt;
int dataSize;
};
class DisassemblyData: public DisassemblyEntry
{
public:
DisassemblyData(DebugInterface* _cpu, u32 _address, u32 _size, DataType _type);
virtual ~DisassemblyData() { };
virtual void recheck();
virtual int getNumLines() { return (int)lines.size(); };
virtual int getLineNum(u32 address, bool findStart);
virtual u32 getLineAddress(int line) { return lineAddresses[line]; };
virtual u32 getTotalSize() { return size; };
virtual bool disassemble(u32 address, DisassemblyLineInfo& dest, bool insertSymbols);
private:
void createLines();
struct DataEntry
{
std::string text;
u32 size;
int lineNum;
};
DebugInterface* cpu;
u32 address;
u32 size;
u32 hash;
DataType type;
std::map<u32,DataEntry> lines;
std::vector<u32> lineAddresses;
};
class DisassemblyComment: public DisassemblyEntry
{
public:
DisassemblyComment(DebugInterface* _cpu, u32 _address, u32 _size, std::string name, std::string param);
virtual ~DisassemblyComment() { };
virtual void recheck() { };
virtual int getNumLines() { return 1; };
virtual int getLineNum(u32 address, bool findStart) { return 0; };
virtual u32 getLineAddress(int line) { return address; };
virtual u32 getTotalSize() { return size; };
virtual bool disassemble(u32 address, DisassemblyLineInfo& dest, bool insertSymbols);
private:
DebugInterface* cpu;
u32 address;
u32 size;
std::string name;
std::string param;
};
class DebugInterface;
class DisassemblyManager
{
public:
void clear();
void setCpu(DebugInterface* _cpu) { cpu = _cpu; };
void setMaxParamChars(int num) { maxParamChars = num; clear(); };
void getLine(u32 address, bool insertSymbols, DisassemblyLineInfo& dest);
void analyze(u32 address, u32 size);
std::vector<BranchLine> getBranchLines(u32 start, u32 size);
u32 getStartAddress(u32 address);
u32 getNthPreviousAddress(u32 address, int n = 1);
u32 getNthNextAddress(u32 address, int n = 1);
static int getMaxParamChars() { return maxParamChars; };
private:
DisassemblyEntry* getEntry(u32 address);
std::map<u32,DisassemblyEntry*> entries;
DebugInterface* cpu;
static int maxParamChars;
};
bool isInInterval(u32 start, u32 size, u32 value);

View File

@ -0,0 +1,594 @@
#include "PrecompiledHeader.h"
#include "ExpressionParser.h"
#include <ctype.h>
#include <string.h>
#include <stdio.h>
typedef enum {
EXOP_BRACKETL, EXOP_BRACKETR, EXOP_MEML, EXOP_MEMR, EXOP_MEMSIZE, EXOP_SIGNPLUS, EXOP_SIGNMINUS,
EXOP_BITNOT, EXOP_LOGNOT, EXOP_MUL, EXOP_DIV, EXOP_MOD, EXOP_ADD, EXOP_SUB,
EXOP_SHL, EXOP_SHR, EXOP_GREATEREQUAL, EXOP_GREATER, EXOP_LOWEREQUAL, EXOP_LOWER,
EXOP_EQUAL, EXOP_NOTEQUAL, EXOP_BITAND, EXOP_XOR, EXOP_BITOR, EXOP_LOGAND,
EXOP_LOGOR, EXOP_TERTIF, EXOP_TERTELSE, EXOP_NUMBER, EXOP_MEM, EXOP_NONE, EXOP_COUNT
} ExpressionOpcodeType;
typedef enum { EXCOMM_CONST, EXCOMM_CONST_FLOAT, EXCOMM_REF, EXCOMM_OP } ExpressionCommand;
static char expressionError[256];
typedef struct {
char Name[4];
unsigned char Priority;
unsigned char len;
unsigned char args;
bool sign;
} ExpressionOpcode;
const ExpressionOpcode ExpressionOpcodes[] = {
{ "(", 25, 1, 0, false }, // EXOP_BRACKETL
{ ")", 25, 1, 0, false }, // EXOP_BRACKETR
{ "[", 4, 1, 0, false }, // EXOP_MEML
{ "]", 4, 1, 0, false }, // EXOP_MEMR
{ ",", 5, 1, 2, false }, // EXOP_MEMSIZE
{ "+", 22, 1, 1, true }, // EXOP_SIGNPLUS
{ "-", 22, 1, 1, true }, // EXOP_SIGNMINUS
{ "~", 22, 1, 1, false }, // EXOP_BITNOT
{ "!", 22, 1, 1, false }, // EXOP_LOGNOT
{ "*", 21, 1, 2, false }, // EXOP_MUL
{ "/", 21, 1, 2, false }, // EXOP_DIV
{ "%", 21, 1, 2, false }, // EXOP_MOD
{ "+", 20, 1, 2, false }, // EXOP_ADD
{ "-", 20, 1, 2, false }, // EXOP_SUB
{ "<<", 19, 2, 2, false }, // EXOP_SHL
{ ">>", 19, 2, 2, false }, // EXOP_SHR
{ ">=", 18, 2, 2, false }, // EXOP_GREATEREQUAL
{ ">", 18, 1, 2, false }, // EXOP_GREATER
{ "<=", 18, 2, 2, false }, // EXOP_LOWEREQUAL
{ "<", 18, 1, 2, false }, // EXOP_LOWER
{ "==", 17, 2, 2, false }, // EXOP_EQUAL
{ "!=", 17, 2, 2, false }, // EXOP_NOTEQUAL
{ "&", 16, 1, 2, false }, // EXOP_BITAND
{ "^", 15, 1, 2, false }, // EXOP_XOR
{ "|", 14, 1, 2, false }, // EXOP_BITOR
{ "&&", 13, 2, 2, false }, // EXOP_LOGAND
{ "||", 12, 2, 2, false }, // EXOP_LOGOR
{ "?", 10, 1, 0, false }, // EXOP_TERTIF
{ ":", 11, 1, 3, false }, // EXOP_TERTELSE
{ "", 0, 0, 0, false }, // EXOP_NUMBER
{ "[]", 0, 0, 1, false }, // EXOP_MEM
{ "", 0, 0, 0, false } // EXOP_NONE
};
bool parseNumber(char* str, int defaultrad, int len, u64& result)
{
u64 val = 0;
int r = 0;
if (len == 0) len = (int) strlen(str);
if (str[0] == '0' && tolower(str[1]) == 'x')
{
r = 16;
str+=2;
len-=2;
} else if (str[0] == '$')
{
r = 16;
str++;
len--;
} else if (str[0] == '0' && tolower(str[1]) == 'o')
{
r = 8;
str+=2;
len-=2;
} else {
if (!(str[0] >= '0' && str[0] <= '9')) return false;
if (tolower(str[len-1]) == 'b' && defaultrad != 16)
{
r = 2;
len--;
} else if (tolower(str[len-1]) == 'o')
{
r = 8;
len--;
} else if (tolower(str[len-1]) == 'h')
{
r = 16;
len--;
} else {
r = defaultrad;
}
}
switch (r)
{
case 2: // bin
while (len--)
{
if (*str != '0' && *str != '1') return false;
val = val << 1;
if (*str++ == '1')
{
val++;
}
}
break;
case 8: // oct
while (len--)
{
if (*str < '0' || *str > '7') return false;
val = val << 3;
val+=(*str++-'0');
}
break;
case 10: // dec
while (len--)
{
if (*str < '0' || *str > '9') return false;
val = val * 10;
val += (*str++ - '0');
}
break;
case 16: // hex
while (len--)
{
char c = tolower(*str++);
if ((c < '0' || c > '9') && (c < 'a' || c > 'f')) return false;
val = val << 4;
if (c >= 'a') val += c-'a'+10;
else val += c-'0';
}
break;
default:
return false;
}
result = val;
return true;
}
// Parse only a float, and return as float bits.
static bool parseFloat(const char *str, int len, u64 &result)
{
bool foundDecimal = false;
for (int i = 0; i < len; ++i)
{
if (str[i] == '.')
{
if (foundDecimal)
return false;
foundDecimal = true;
continue;
}
if (str[i] < '0' || str[i] > '9')
return false;
}
result = 0;
float f = (float)atof(str);
memcpy(&result, &f, sizeof(float));
return foundDecimal;
}
ExpressionOpcodeType getExpressionOpcode(const char* str, int& ReturnLen, ExpressionOpcodeType LastOpcode)
{
int longestlen = 0;
ExpressionOpcodeType result = EXOP_NONE;
for (int i = 0; i < EXOP_NUMBER; i++)
{
if (ExpressionOpcodes[i].sign == true &&
(LastOpcode == EXOP_NUMBER || LastOpcode == EXOP_BRACKETR)) continue;
int len = ExpressionOpcodes[i].len;
if (len > longestlen)
{
if (strncmp(ExpressionOpcodes[i].Name,str,len) == 0)
{
result = (ExpressionOpcodeType) i;
longestlen = len;
}
}
}
ReturnLen = longestlen;
return result;
}
bool isAlphaNum(char c)
{
if ((c >= '0' && c <= '9') ||
(c >= 'A' && c <= 'Z') ||
(c >= 'a' && c <= 'z') ||
c == '@' || c == '_' || c == '$' || c == '.')
{
return true;
} else {
return false;
}
}
bool initPostfixExpression(const char* infix, IExpressionFunctions* funcs, PostfixExpression& dest)
{
expressionError[0] = 0;
int infixPos = 0;
int infixLen = (int)strlen(infix);
ExpressionOpcodeType lastOpcode = EXOP_NONE;
std::vector<ExpressionOpcodeType> opcodeStack;
dest.clear();
while (infixPos < infixLen)
{
char first = tolower(infix[infixPos]);
char subStr[256];
int subPos = 0;
if (first == ' ' || first == '\t')
{
infixPos++;
continue;
}
if (first >= '0' && first <= '9')
{
while (isAlphaNum(infix[infixPos]))
{
subStr[subPos++] = infix[infixPos++];
}
subStr[subPos] = 0;
u64 value;
bool isFloat = false;
if (parseFloat(subStr,subPos,value) == true)
isFloat = true;
else if (parseNumber(subStr,16,subPos,value) == false)
{
sprintf(expressionError,"Invalid number \"%s\"",subStr);
return false;
}
dest.push_back(ExpressionPair(isFloat?EXCOMM_CONST_FLOAT:EXCOMM_CONST,value));
lastOpcode = EXOP_NUMBER;
} else if ((first >= 'a' && first <= 'z') || first == '@')
{
while (isAlphaNum(infix[infixPos]))
{
subStr[subPos++] = infix[infixPos++];
}
subStr[subPos] = 0;
u64 value;
if (funcs->parseReference(subStr,value) == true)
{
dest.push_back(ExpressionPair(EXCOMM_REF,value));
lastOpcode = EXOP_NUMBER;
continue;
}
if (funcs->parseSymbol(subStr,value) == true)
{
dest.push_back(ExpressionPair(EXCOMM_CONST,value));
lastOpcode = EXOP_NUMBER;
continue;
}
sprintf(expressionError,"Invalid symbol \"%s\"",subStr);
return false;
} else {
int len;
ExpressionOpcodeType type = getExpressionOpcode(&infix[infixPos],len,lastOpcode);
if (type == EXOP_NONE)
{
sprintf(expressionError,"Invalid operator at \"%s\"",&infix[infixPos]);
return false;
}
switch (type)
{
case EXOP_BRACKETL:
case EXOP_MEML:
opcodeStack.push_back(type);
break;
case EXOP_BRACKETR:
while (true)
{
if (opcodeStack.empty())
{
sprintf(expressionError,"Closing parenthesis without opening one");
return false;
}
ExpressionOpcodeType t = opcodeStack[opcodeStack.size()-1];
opcodeStack.pop_back();
if (t == EXOP_BRACKETL) break;
dest.push_back(ExpressionPair(EXCOMM_OP,t));
}
break;
case EXOP_MEMR:
while (true)
{
if (opcodeStack.empty())
{
sprintf(expressionError,"Closing bracket without opening one");
return false;
}
ExpressionOpcodeType t = opcodeStack[opcodeStack.size()-1];
opcodeStack.pop_back();
if (t == EXOP_MEML)
{
dest.push_back(ExpressionPair(EXCOMM_OP,EXOP_MEM));
break;
}
dest.push_back(ExpressionPair(EXCOMM_OP,t));
}
type = EXOP_NUMBER;
break;
default:
if (opcodeStack.empty() == false)
{
int CurrentPriority = ExpressionOpcodes[type].Priority;
while (!opcodeStack.empty())
{
ExpressionOpcodeType t = opcodeStack[opcodeStack.size()-1];
opcodeStack.pop_back();
if (t == EXOP_BRACKETL || t == EXOP_MEML)
{
opcodeStack.push_back(t);
break;
}
if (ExpressionOpcodes[t].Priority >= CurrentPriority)
{
dest.push_back(ExpressionPair(EXCOMM_OP,t));
} else {
opcodeStack.push_back(t);
break;
}
}
}
opcodeStack.push_back(type);
break;
}
infixPos += len;
lastOpcode = type;
}
}
while (!opcodeStack.empty())
{
ExpressionOpcodeType t = opcodeStack[opcodeStack.size()-1];
opcodeStack.pop_back();
if (t == EXOP_BRACKETL) // opening bracket without closing one
{
sprintf(expressionError,"Parenthesis not closed");
return false;
}
dest.push_back(ExpressionPair(EXCOMM_OP,t));
}
#if 0 // only for testing
char test[1024];
int testPos = 0;
for (int i = 0; i < dest.size(); i++)
{
switch (dest[i].first)
{
case EXCOMM_CONST:
case EXCOMM_CONST_FLOAT:
testPos += sprintf(&test[testPos],"0x%04X ",dest[i].second);
break;
case EXCOMM_REF:
testPos += sprintf(&test[testPos],"r%d ",dest[i].second);
break;
case EXCOMM_OP:
testPos += sprintf(&test[testPos],"%s ",ExpressionOpcodes[dest[i].second].Name);
break;
};
}
#endif
return true;
}
bool parsePostfixExpression(PostfixExpression& exp, IExpressionFunctions* funcs, u64& dest)
{
size_t num = 0;
u64 opcode;
std::vector<u64> valueStack;
u64 arg[5];
float fArg[5];
bool useFloat = false;
while (num < exp.size())
{
switch (exp[num].first)
{
case EXCOMM_CONST: // konstante zahl
valueStack.push_back(exp[num++].second);
break;
case EXCOMM_CONST_FLOAT:
useFloat = true;
valueStack.push_back(exp[num++].second);
break;
case EXCOMM_REF:
useFloat = useFloat || funcs->getReferenceType(exp[num].second) == EXPR_TYPE_FLOAT;
opcode = funcs->getReferenceValue(exp[num++].second);
valueStack.push_back(opcode);
break;
case EXCOMM_OP: // opcode
opcode = exp[num++].second;
if (valueStack.size() < ExpressionOpcodes[opcode].args)
{
sprintf(expressionError,"Not enough arguments");
return false;
}
for (int l = 0; l < ExpressionOpcodes[opcode].args; l++)
{
arg[l] = valueStack[valueStack.size()-1];
fArg[l] = arg[l];
valueStack.pop_back();
}
switch (opcode)
{
case EXOP_MEMSIZE: // must be followed by EXOP_MEM
if (exp[num++].second != EXOP_MEM)
{
sprintf(expressionError,"Invalid memsize operator");
return false;
}
u64 val;
if(funcs->getMemoryValue(arg[1],arg[0],val,expressionError) == false)
{
return false;
}
valueStack.push_back(val);
break;
case EXOP_MEM:
{
u64 val;
if (funcs->getMemoryValue(arg[0],4,val,expressionError) == false)
{
return false;
}
valueStack.push_back(val);
}
break;
case EXOP_SIGNPLUS: // keine aktion nötig
break;
case EXOP_SIGNMINUS: // -0
if (useFloat)
valueStack.push_back(0.0-fArg[0]);
else
valueStack.push_back(0-arg[0]);
break;
case EXOP_BITNOT: // ~b
valueStack.push_back(~arg[0]);
break;
case EXOP_LOGNOT: // !b
valueStack.push_back(!arg[0]);
break;
case EXOP_MUL: // a*b
if (useFloat)
valueStack.push_back(fArg[1]*fArg[0]);
else
valueStack.push_back(arg[1]*arg[0]);
break;
case EXOP_DIV: // a/b
if (arg[0] == 0)
{
sprintf(expressionError,"Division by zero");
return false;
}
if (useFloat)
valueStack.push_back(fArg[1]/fArg[0]);
else
valueStack.push_back(arg[1]/arg[0]);
break;
case EXOP_MOD: // a%b
if (arg[0] == 0)
{
sprintf(expressionError,"Modulo by zero");
return false;
}
valueStack.push_back(arg[1]%arg[0]);
break;
case EXOP_ADD: // a+b
if (useFloat)
valueStack.push_back(fArg[1]+fArg[0]);
else
valueStack.push_back(arg[1]+arg[0]);
break;
case EXOP_SUB: // a-b
if (useFloat)
valueStack.push_back(fArg[1]-fArg[0]);
else
valueStack.push_back(arg[1]-arg[0]);
break;
case EXOP_SHL: // a<<b
valueStack.push_back(arg[1]<<arg[0]);
break;
case EXOP_SHR: // a>>b
valueStack.push_back(arg[1]>>arg[0]);
break;
case EXOP_GREATEREQUAL: // a >= b
if (useFloat)
valueStack.push_back(fArg[1]>=fArg[0]);
else
valueStack.push_back(arg[1]>=arg[0]);
break;
case EXOP_GREATER: // a > b
if (useFloat)
valueStack.push_back(fArg[1]>fArg[0]);
else
valueStack.push_back(arg[1]>arg[0]);
break;
case EXOP_LOWEREQUAL: // a <= b
if (useFloat)
valueStack.push_back(fArg[1]<=fArg[0]);
else
valueStack.push_back(arg[1]<=arg[0]);
break;
case EXOP_LOWER: // a < b
if (useFloat)
valueStack.push_back(fArg[1]<fArg[0]);
else
valueStack.push_back(arg[1]<arg[0]);
break;
case EXOP_EQUAL: // a == b
valueStack.push_back(arg[1]==arg[0]);
break;
case EXOP_NOTEQUAL: // a != b
valueStack.push_back(arg[1]!=arg[0]);
break;
case EXOP_BITAND: // a&b
valueStack.push_back(arg[1]&arg[0]);
break;
case EXOP_XOR: // a^b
valueStack.push_back(arg[1]^arg[0]);
break;
case EXOP_BITOR: // a|b
valueStack.push_back(arg[1]|arg[0]);
break;
case EXOP_LOGAND: // a && b
valueStack.push_back(arg[1]&&arg[0]);
break;
case EXOP_LOGOR: // a || b
valueStack.push_back(arg[1]||arg[0]);
break;
case EXOP_TERTIF: // darf so nicht vorkommen
return false;
case EXOP_TERTELSE: // exp ? exp : exp, else muss zuerst kommen!
if (exp[num++].second != EXOP_TERTIF)
{
sprintf(expressionError,"Invalid tertiary operator");
return false;
}
valueStack.push_back(arg[2]?arg[1]:arg[0]);
break;
}
break;
}
}
if (valueStack.size() != 1) return false;
dest = valueStack[0];
return true;
}
bool parseExpression(char* exp, IExpressionFunctions* funcs, u64& dest)
{
PostfixExpression postfix;
if (initPostfixExpression(exp,funcs,postfix) == false) return false;
return parsePostfixExpression(postfix,funcs,dest);
}
const char* getExpressionError()
{
if (expressionError[0] == 0) strcpy(expressionError,"Invalid expression");
return expressionError;
}

View File

@ -0,0 +1,28 @@
#pragma once
#include "Pcsx2Types.h"
#include <vector>
typedef std::pair<u64,u64> ExpressionPair;
typedef std::vector<ExpressionPair> PostfixExpression;
enum ExpressionType
{
EXPR_TYPE_UINT = 0,
EXPR_TYPE_FLOAT = 2,
};
class IExpressionFunctions
{
public:
virtual bool parseReference(char* str, u64& referenceIndex) = 0;
virtual bool parseSymbol(char* str, u64& symbolValue) = 0;
virtual u64 getReferenceValue(u64 referenceIndex) = 0;
virtual ExpressionType getReferenceType(u64 referenceIndex) = 0;
virtual bool getMemoryValue(u32 address, int size, u64& dest, char* error) = 0;
};
bool initPostfixExpression(const char* infix, IExpressionFunctions* funcs, PostfixExpression& dest);
bool parsePostfixExpression(PostfixExpression& exp, IExpressionFunctions* funcs, u64& dest);
bool parseExpression(const char* exp, IExpressionFunctions* funcs, u64& dest);
const char* getExpressionError();

View File

@ -0,0 +1,395 @@
#include "PrecompiledHeader.h"
#include "MIPSAnalyst.h"
#include "Debug.h"
#include "DebugInterface.h"
#include "SymbolMap.h"
#include "DebugInterface.h"
static std::vector<MIPSAnalyst::AnalyzedFunction> functions;
#define MIPS_MAKE_J(addr) (0x08000000 | ((addr)>>2))
#define MIPS_MAKE_JAL(addr) (0x0C000000 | ((addr)>>2))
#define MIPS_MAKE_JR_RA() (0x03e00008)
#define MIPS_MAKE_NOP() (0)
namespace MIPSAnalyst
{
static const char *DefaultFunctionName(char buffer[256], u32 startAddr) {
sprintf(buffer, "z_un_%08x", startAddr);
return buffer;
}
void ScanForFunctions(u32 startAddr, u32 endAddr, bool insertSymbols) {
AnalyzedFunction currentFunction = {startAddr};
u32 furthestBranch = 0;
bool looking = false;
bool end = false;
bool isStraightLeaf = true;
u32 addr;
for (addr = startAddr; addr <= endAddr; addr += 4) {
// Use pre-existing symbol map info if available. May be more reliable.
SymbolInfo syminfo;
if (symbolMap.GetSymbolInfo(&syminfo, addr, ST_FUNCTION)) {
addr = syminfo.address + syminfo.size - 4;
// We still need to insert the func for hashing purposes.
currentFunction.start = syminfo.address;
currentFunction.end = syminfo.address + syminfo.size - 4;
functions.push_back(currentFunction);
currentFunction.start = addr + 4;
furthestBranch = 0;
looking = false;
end = false;
continue;
}
u32 op = r5900Debug.read32(addr);
/*
MIPSOpcode op = Memory::Read_Instruction(addr);
u32 target = GetBranchTargetNoRA(addr);
if (target != INVALIDTARGET) {
isStraightLeaf = false;
if (target > furthestBranch) {
furthestBranch = target;
}
} else if ((op & 0xFC000000) == 0x08000000) {
u32 sureTarget = GetJumpTarget(addr);
// Check for a tail call. Might not even have a jr ra.
if (sureTarget != INVALIDTARGET && sureTarget < currentFunction.start) {
if (furthestBranch > addr) {
looking = true;
addr += 4;
} else {
end = true;
}
} else if (sureTarget != INVALIDTARGET && sureTarget > addr && sureTarget > furthestBranch) {
// A jump later. Probably tail, but let's check if it jumps back.
u32 knownEnd = furthestBranch == 0 ? addr : furthestBranch;
u32 jumpback = ScanAheadForJumpback(sureTarget, currentFunction.start, knownEnd);
if (jumpback != INVALIDTARGET && jumpback > addr && jumpback > knownEnd) {
furthestBranch = jumpback;
} else {
if (furthestBranch > addr) {
looking = true;
addr += 4;
} else {
end = true;
}
}
}
}*/
if (op == MIPS_MAKE_JR_RA()) {
// If a branch goes to the jr ra, it's still ending here.
if (furthestBranch > addr) {
looking = true;
addr += 4;
} else {
end = true;
}
}
/* if (looking) {
if (addr >= furthestBranch) {
u32 sureTarget = GetSureBranchTarget(addr);
// Regular j only, jals are to new funcs.
if (sureTarget == INVALIDTARGET && ((op & 0xFC000000) == 0x08000000)) {
sureTarget = GetJumpTarget(addr);
}
if (sureTarget != INVALIDTARGET && sureTarget < addr) {
end = true;
} else if (sureTarget != INVALIDTARGET) {
// Okay, we have a downward jump. Might be an else or a tail call...
// If there's a jump back upward in spitting distance of it, it's an else.
u32 knownEnd = furthestBranch == 0 ? addr : furthestBranch;
u32 jumpback = ScanAheadForJumpback(sureTarget, currentFunction.start, knownEnd);
if (jumpback != INVALIDTARGET && jumpback > addr && jumpback > knownEnd) {
furthestBranch = jumpback;
}
}
}
}
*/
if (end) {
currentFunction.end = addr + 4;
currentFunction.isStraightLeaf = isStraightLeaf;
functions.push_back(currentFunction);
furthestBranch = 0;
addr += 4;
looking = false;
end = false;
isStraightLeaf = true;
currentFunction.start = addr+4;
}
}
currentFunction.end = addr + 4;
functions.push_back(currentFunction);
for (auto iter = functions.begin(); iter != functions.end(); iter++) {
iter->size = iter->end - iter->start + 4;
if (insertSymbols) {
char temp[256];
symbolMap.AddFunction(DefaultFunctionName(temp, iter->start), iter->start, iter->end - iter->start + 4);
}
}
}
enum BranchType { NONE, JUMP, BRANCH };
struct BranchInfo
{
BranchType type;
bool link;
bool likely;
bool toRegister;
};
bool getBranchInfo(MipsOpcodeInfo& info)
{
BranchType type = NONE;
bool link = false;
bool likely = false;
bool toRegister = false;
bool met = false;
u32 op = info.encodedOpcode;
u32 opNum = MIPS_GET_OP(op);
u32 rsNum = MIPS_GET_RS(op);
u32 rtNum = MIPS_GET_RT(op);
u32 rs = info.cpu->getRegister(0,rsNum);
u32 rt = info.cpu->getRegister(0,rtNum);
switch (MIPS_GET_OP(op))
{
case 0x00: // special
switch (MIPS_GET_FUNC(op))
{
case 0x08: // jr
type = JUMP;
toRegister = true;
break;
case 0x09: // jalr
type = JUMP;
toRegister = true;
link = true;
break;
}
break;
case 0x01: // regimm
switch (MIPS_GET_RT(op))
{
case 0x00: // bltz
case 0x02: // bltzl
case 0x10: // bltzal
case 0x12: // bltzall
type = BRANCH;
met = (((s32)rs) < 0);
likely = (rt & 2) != 0;
link = rt >= 0x10;
break;
case 0x01: // bgez
case 0x03: // bgezl
case 0x11: // bgezal
case 0x13: // bgezall
type = BRANCH;
met = (((s32)rs) >= 0);
likely = (rt & 2) != 0;
link = rt >= 0x10;
break;
}
break;
case 0x02: // j
type = JUMP;
break;
case 0x03: // jal
type = JUMP;
link = true;
break;
case 0x04: // beq
case 0x14: // beql
type = BRANCH;
met = (rt == rs);
if (MIPS_GET_RT(op) == MIPS_GET_RS(op)) // always true
info.isConditional = false;
likely = opNum >= 0x10;
break;
case 0x05: // bne
case 0x15: // bnel
type = BRANCH;
met = (rt != rs);
if (MIPS_GET_RT(op) == MIPS_GET_RS(op)) // always false
info.isConditional = false;
likely = opNum >= 0x10;
break;
case 0x06: // blez
case 0x16: // blezl
type = BRANCH;
met = (((s32)rs) <= 0);
likely = opNum >= 0x10;
break;
case 0x07: // bgtz
case 0x17: // bgtzl
type = BRANCH;
met = (((s32)rs) > 0);
likely = opNum >= 0x10;
break;
}
if (type == NONE)
return false;
info.isBranch = true;
info.isLinkedBranch = link;
info.isLikelyBranch = true;
info.isBranchToRegister = toRegister;
info.isConditional = type == BRANCH;
info.conditionMet = met;
switch (type)
{
case JUMP:
if (toRegister)
{
info.branchRegisterNum = (int)MIPS_GET_RS(op);
info.branchTarget = info.cpu->getRegister(0,info.branchRegisterNum)._u32[0];
} else {
info.branchTarget = (info.opcodeAddress & 0xF0000000) | ((op&0x03FFFFFF) << 2);
}
break;
case BRANCH:
info.branchTarget = info.opcodeAddress + 4 + ((signed short)(op&0xFFFF)<<2);
break;
}
return true;
}
bool getDataAccessInfo(MipsOpcodeInfo& info)
{
int size = 0;
u32 op = info.encodedOpcode;
int off = 0;
switch (MIPS_GET_OP(op))
{
case 0x20: // lb
case 0x24: // lbu
case 0x28: // sb
size = 1;
break;
case 0x21: // lh
case 0x25: // lhu
case 0x29: // sh
size = 2;
break;
case 0x23: // lw
case 0x26: // lwr
case 0x2B: // sw
case 0x2E: // swr
size = 4;
break;
case 0x22: // lwl
case 0x2A: // swl
size = 4;
off = -3;
break;
case 0x37: // ld
case 0x1B: // ldr
case 0x3F: // sd
case 0x2D: // sdr
size = 8;
break;
case 0x1A: // ldl
case 0x2C: // sdl
size = 8;
off = -7;
break;
}
if (size == 0)
return false;
info.isDataAccess = true;
info.dataSize = size;
u32 rs = info.cpu->getRegister(0, (int)MIPS_GET_RS(op));
s16 imm16 = op & 0xFFFF;
info.dataAddress = rs + imm16 + off;
info.hasRelevantAddress = true;
info.releventAddress = info.dataAddress;
return true;
}
MipsOpcodeInfo GetOpcodeInfo(DebugInterface* cpu, u32 address) {
MipsOpcodeInfo info;
memset(&info, 0, sizeof(info));
if (cpu->isValidAddress(address) == false) {
return info;
}
info.cpu = cpu;
info.opcodeAddress = address;
info.encodedOpcode = cpu->read32(address);
u32 op = info.encodedOpcode;
if (getBranchInfo(info) == true)
return info;
if (getDataAccessInfo(info) == true)
return info;
// gather relevant address for alu operations
// that's usually the value of the dest register
switch (MIPS_GET_OP(op)) {
case 0: // special
switch (MIPS_GET_FUNC(op)) {
case 0x20: // add
case 0x21: // addu
info.hasRelevantAddress = true;
info.releventAddress = cpu->getRegister(0,MIPS_GET_RS(op))._u32[0]+cpu->getRegister(0,MIPS_GET_RT(op))._u32[0];
break;
case 0x22: // sub
case 0x23: // subu
info.hasRelevantAddress = true;
info.releventAddress = cpu->getRegister(0,MIPS_GET_RS(op))._u32[0]-cpu->getRegister(0,MIPS_GET_RT(op))._u32[0];
break;
}
break;
case 0x08: // addi
case 0x09: // adiu
info.hasRelevantAddress = true;
info.releventAddress = cpu->getRegister(0,MIPS_GET_RS(op))._u32[0]+((s16)(op & 0xFFFF));
break;
}
// TODO: rest
/* // movn, movz
if (opInfo & IS_CONDMOVE) {
info.isConditional = true;
u32 rt = cpu->GetRegValue(0, (int)MIPS_GET_RT(op));
switch (opInfo & CONDTYPE_MASK) {
case CONDTYPE_EQ:
info.conditionMet = (rt == 0);
break;
case CONDTYPE_NE:
info.conditionMet = (rt != 0);
break;
}
}*/
return info;
}
}

View File

@ -0,0 +1,56 @@
#pragma once
class DebugInterface;
#define MIPS_GET_OP(op) ((op>>26) & 0x3F)
#define MIPS_GET_FUNC(op) (op & 0x3F)
#define MIPS_GET_SA(op) ((op>>6) & 0x1F)
#define MIPS_GET_RS(op) ((op>>21) & 0x1F)
#define MIPS_GET_RT(op) ((op>>16) & 0x1F)
#define MIPS_GET_RD(op) ((op>>11) & 0x1F)
namespace MIPSAnalyst
{
struct AnalyzedFunction {
u32 start;
u32 end;
u64 hash;
u32 size;
bool isStraightLeaf;
bool hasHash;
bool usesVFPU;
char name[64];
};
void ScanForFunctions(u32 startAddr, u32 endAddr, bool insertSymbols);
typedef struct {
DebugInterface* cpu;
u32 opcodeAddress;
u32 encodedOpcode;
// shared between branches and conditional moves
bool isConditional;
bool conditionMet;
// branches
u32 branchTarget;
bool isBranch;
bool isLinkedBranch;
bool isLikelyBranch;
bool isBranchToRegister;
int branchRegisterNum;
// data access
bool isDataAccess;
int dataSize;
u32 dataAddress;
bool hasRelevantAddress;
u32 releventAddress;
} MipsOpcodeInfo;
MipsOpcodeInfo GetOpcodeInfo(DebugInterface* cpu, u32 address);
};

View File

@ -0,0 +1,704 @@
#include "PrecompiledHeader.h"
#include "SymbolMap.h"
#include <algorithm>
SymbolMap symbolMap;
#ifdef WIN32
#define strcasecmp stricmp
#endif
#define ARRAY_SIZE(x) (sizeof((x))/sizeof(*(x)))
void SymbolMap::SortSymbols() {
Threading::ScopedLock guard(lock_);
AssignFunctionIndices();
}
void SymbolMap::Clear() {
Threading::ScopedLock guard(lock_);
functions.clear();
labels.clear();
data.clear();
activeFunctions.clear();
activeLabels.clear();
activeData.clear();
activeModuleEnds.clear();
modules.clear();
}
bool SymbolMap::LoadNocashSym(const char *filename) {
Threading::ScopedLock guard(lock_);
FILE *f = fopen(filename, "r");
if (!f)
return false;
while (!feof(f)) {
char line[256], value[256] = {0};
char *p = fgets(line, 256, f);
if (p == NULL)
break;
u32 address;
if (sscanf(line, "%08X %s", &address, value) != 2)
continue;
if (address == 0 && strcmp(value, "0") == 0)
continue;
if (value[0] == '.') {
// data directives
char* s = strchr(value, ':');
if (s != NULL) {
*s = 0;
u32 size = 0;
if (sscanf(s + 1, "%04X", &size) != 1)
continue;
if (strcasecmp(value, ".byt") == 0) {
AddData(address, size, DATATYPE_BYTE, 0);
} else if (strcasecmp(value, ".wrd") == 0) {
AddData(address, size, DATATYPE_HALFWORD, 0);
} else if (strcasecmp(value, ".dbl") == 0) {
AddData(address, size, DATATYPE_WORD, 0);
} else if (strcasecmp(value, ".asc") == 0) {
AddData(address, size, DATATYPE_ASCII, 0);
}
}
} else { // labels
int size = 1;
char* seperator = strchr(value, ',');
if (seperator != NULL) {
*seperator = 0;
sscanf(seperator+1,"%08X",&size);
}
if (size != 1) {
AddFunction(value, address,size, 0);
} else {
AddLabel(value, address, 0);
}
}
}
fclose(f);
return true;
}
SymbolType SymbolMap::GetSymbolType(u32 address) const {
Threading::ScopedLock guard(lock_);
if (activeFunctions.find(address) != activeFunctions.end())
return ST_FUNCTION;
if (activeData.find(address) != activeData.end())
return ST_DATA;
return ST_NONE;
}
bool SymbolMap::GetSymbolInfo(SymbolInfo *info, u32 address, SymbolType symmask) const {
u32 functionAddress = INVALID_ADDRESS;
u32 dataAddress = INVALID_ADDRESS;
if (symmask & ST_FUNCTION)
functionAddress = GetFunctionStart(address);
if (symmask & ST_DATA)
dataAddress = GetDataStart(address);
if (functionAddress == INVALID_ADDRESS || dataAddress == INVALID_ADDRESS) {
if (functionAddress != INVALID_ADDRESS) {
if (info != NULL) {
info->type = ST_FUNCTION;
info->address = functionAddress;
info->size = GetFunctionSize(functionAddress);
}
return true;
}
if (dataAddress != INVALID_ADDRESS) {
if (info != NULL) {
info->type = ST_DATA;
info->address = dataAddress;
info->size = GetDataSize(dataAddress);
}
return true;
}
return false;
}
// if both exist, return the function
if (info != NULL) {
info->type = ST_FUNCTION;
info->address = functionAddress;
info->size = GetFunctionSize(functionAddress);
}
return true;
}
u32 SymbolMap::GetNextSymbolAddress(u32 address, SymbolType symmask) {
Threading::ScopedLock guard(lock_);
const auto functionEntry = symmask & ST_FUNCTION ? activeFunctions.upper_bound(address) : activeFunctions.end();
const auto dataEntry = symmask & ST_DATA ? activeData.upper_bound(address) : activeData.end();
if (functionEntry == activeFunctions.end() && dataEntry == activeData.end())
return INVALID_ADDRESS;
u32 funcAddress = (functionEntry != activeFunctions.end()) ? functionEntry->first : 0xFFFFFFFF;
u32 dataAddress = (dataEntry != activeData.end()) ? dataEntry->first : 0xFFFFFFFF;
if (funcAddress <= dataAddress)
return funcAddress;
else
return dataAddress;
}
std::string SymbolMap::GetDescription(unsigned int address) const {
Threading::ScopedLock guard(lock_);
const char* labelName = NULL;
u32 funcStart = GetFunctionStart(address);
if (funcStart != INVALID_ADDRESS) {
labelName = GetLabelName(funcStart);
} else {
u32 dataStart = GetDataStart(address);
if (dataStart != INVALID_ADDRESS)
labelName = GetLabelName(dataStart);
}
if (labelName != NULL)
return labelName;
char descriptionTemp[256];
sprintf(descriptionTemp, "(%08x)", address);
return descriptionTemp;
}
std::vector<SymbolEntry> SymbolMap::GetAllSymbols(SymbolType symmask) {
std::vector<SymbolEntry> result;
if (symmask & ST_FUNCTION) {
Threading::ScopedLock guard(lock_);
for (auto it = activeFunctions.begin(); it != activeFunctions.end(); it++) {
SymbolEntry entry;
entry.address = it->first;
entry.size = GetFunctionSize(entry.address);
const char* name = GetLabelName(entry.address);
if (name != NULL)
entry.name = name;
result.push_back(entry);
}
}
if (symmask & ST_DATA) {
Threading::ScopedLock guard(lock_);
for (auto it = activeData.begin(); it != activeData.end(); it++) {
SymbolEntry entry;
entry.address = it->first;
entry.size = GetDataSize(entry.address);
const char* name = GetLabelName(entry.address);
if (name != NULL)
entry.name = name;
result.push_back(entry);
}
}
return result;
}
void SymbolMap::AddModule(const char *name, u32 address, u32 size) {
Threading::ScopedLock guard(lock_);
for (auto it = modules.begin(), end = modules.end(); it != end; ++it) {
if (!strcmp(it->name, name)) {
// Just reactivate that one.
it->start = address;
it->size = size;
activeModuleEnds.insert(std::make_pair(it->start + it->size, *it));
UpdateActiveSymbols();
return;
}
}
ModuleEntry mod;
strncpy(mod.name, name, ARRAY_SIZE(mod.name));
mod.start = address;
mod.size = size;
mod.index = (int)modules.size() + 1;
modules.push_back(mod);
activeModuleEnds.insert(std::make_pair(mod.start + mod.size, mod));
UpdateActiveSymbols();
}
void SymbolMap::UnloadModule(u32 address, u32 size) {
Threading::ScopedLock guard(lock_);
activeModuleEnds.erase(address + size);
UpdateActiveSymbols();
}
u32 SymbolMap::GetModuleRelativeAddr(u32 address, int moduleIndex) const {
Threading::ScopedLock guard(lock_);
if (moduleIndex == -1) {
moduleIndex = GetModuleIndex(address);
}
for (auto it = modules.begin(), end = modules.end(); it != end; ++it) {
if (it->index == moduleIndex) {
return address - it->start;
}
}
return address;
}
u32 SymbolMap::GetModuleAbsoluteAddr(u32 relative, int moduleIndex) const {
Threading::ScopedLock guard(lock_);
for (auto it = modules.begin(), end = modules.end(); it != end; ++it) {
if (it->index == moduleIndex) {
return it->start + relative;
}
}
return relative;
}
int SymbolMap::GetModuleIndex(u32 address) const {
Threading::ScopedLock guard(lock_);
auto iter = activeModuleEnds.upper_bound(address);
if (iter == activeModuleEnds.end())
return -1;
return iter->second.index;
}
bool SymbolMap::IsModuleActive(int moduleIndex) const {
if (moduleIndex == 0) {
return true;
}
Threading::ScopedLock guard(lock_);
for (auto it = activeModuleEnds.begin(), end = activeModuleEnds.end(); it != end; ++it) {
if (it->second.index == moduleIndex) {
return true;
}
}
return false;
}
std::vector<LoadedModuleInfo> SymbolMap::getAllModules() const {
Threading::ScopedLock guard(lock_);
std::vector<LoadedModuleInfo> result;
for (size_t i = 0; i < modules.size(); i++) {
LoadedModuleInfo m;
m.name = modules[i].name;
m.address = modules[i].start;
m.size = modules[i].size;
u32 key = modules[i].start + modules[i].size;
m.active = activeModuleEnds.find(key) != activeModuleEnds.end();
result.push_back(m);
}
return result;
}
void SymbolMap::AddFunction(const char* name, u32 address, u32 size, int moduleIndex) {
Threading::ScopedLock guard(lock_);
if (moduleIndex == -1) {
moduleIndex = GetModuleIndex(address);
}
// Is there an existing one?
u32 relAddress = GetModuleRelativeAddr(address, moduleIndex);
auto symbolKey = std::make_pair(moduleIndex, relAddress);
auto existing = functions.find(symbolKey);
if (existing == functions.end()) {
// Fall back: maybe it's got moduleIndex = 0.
existing = functions.find(std::make_pair(0, address));
}
if (existing != functions.end()) {
existing->second.size = size;
if (existing->second.module != moduleIndex) {
FunctionEntry func = existing->second;
func.start = relAddress;
func.module = moduleIndex;
functions.erase(existing);
functions[symbolKey] = func;
}
// Refresh the active item if it exists.
auto active = activeFunctions.find(address);
if (active != activeFunctions.end() && active->second.module == moduleIndex) {
activeFunctions.erase(active);
activeFunctions.insert(std::make_pair(address, existing->second));
}
} else {
FunctionEntry func;
func.start = relAddress;
func.size = size;
func.index = (int)functions.size();
func.module = moduleIndex;
functions[symbolKey] = func;
if (IsModuleActive(moduleIndex)) {
activeFunctions.insert(std::make_pair(address, func));
}
}
AddLabel(name, address, moduleIndex);
}
u32 SymbolMap::GetFunctionStart(u32 address) const {
Threading::ScopedLock guard(lock_);
auto it = activeFunctions.upper_bound(address);
if (it == activeFunctions.end()) {
// check last element
auto rit = activeFunctions.rbegin();
if (rit != activeFunctions.rend()) {
u32 start = rit->first;
u32 size = rit->second.size;
if (start <= address && start+size > address)
return start;
}
// otherwise there's no function that contains this address
return INVALID_ADDRESS;
}
if (it != activeFunctions.begin()) {
it--;
u32 start = it->first;
u32 size = it->second.size;
if (start <= address && start+size > address)
return start;
}
return INVALID_ADDRESS;
}
u32 SymbolMap::GetFunctionSize(u32 startAddress) const {
Threading::ScopedLock guard(lock_);
auto it = activeFunctions.find(startAddress);
if (it == activeFunctions.end())
return INVALID_ADDRESS;
return it->second.size;
}
int SymbolMap::GetFunctionNum(u32 address) const {
Threading::ScopedLock guard(lock_);
u32 start = GetFunctionStart(address);
if (start == INVALID_ADDRESS)
return INVALID_ADDRESS;
auto it = activeFunctions.find(start);
if (it == activeFunctions.end())
return INVALID_ADDRESS;
return it->second.index;
}
void SymbolMap::AssignFunctionIndices() {
Threading::ScopedLock guard(lock_);
int index = 0;
for (auto mod = activeModuleEnds.begin(), modend = activeModuleEnds.end(); mod != modend; ++mod) {
int moduleIndex = mod->second.index;
auto begin = functions.lower_bound(std::make_pair(moduleIndex, 0));
auto end = functions.upper_bound(std::make_pair(moduleIndex, 0xFFFFFFFF));
for (auto it = begin; it != end; ++it) {
it->second.index = index++;
}
}
}
void SymbolMap::UpdateActiveSymbols() {
// return; (slow in debug mode)
Threading::ScopedLock guard(lock_);
std::map<int, u32> activeModuleIndexes;
for (auto it = activeModuleEnds.begin(), end = activeModuleEnds.end(); it != end; ++it) {
activeModuleIndexes[it->second.index] = it->second.start;
}
activeFunctions.clear();
activeLabels.clear();
activeData.clear();
for (auto it = functions.begin(), end = functions.end(); it != end; ++it) {
const auto mod = activeModuleIndexes.find(it->second.module);
if (it->second.module <= 0) {
activeFunctions.insert(std::make_pair(it->second.start, it->second));
} else if (mod != activeModuleIndexes.end()) {
activeFunctions.insert(std::make_pair(mod->second + it->second.start, it->second));
}
}
for (auto it = labels.begin(), end = labels.end(); it != end; ++it) {
const auto mod = activeModuleIndexes.find(it->second.module);
if (it->second.module <= 0) {
activeLabels.insert(std::make_pair(it->second.addr, it->second));
} else if (mod != activeModuleIndexes.end()) {
activeLabels.insert(std::make_pair(mod->second + it->second.addr, it->second));
}
}
for (auto it = data.begin(), end = data.end(); it != end; ++it) {
const auto mod = activeModuleIndexes.find(it->second.module);
if (it->second.module <= 0) {
activeData.insert(std::make_pair(it->second.start, it->second));
} else if (mod != activeModuleIndexes.end()) {
activeData.insert(std::make_pair(mod->second + it->second.start, it->second));
}
}
AssignFunctionIndices();
}
bool SymbolMap::SetFunctionSize(u32 startAddress, u32 newSize) {
Threading::ScopedLock guard(lock_);
auto funcInfo = activeFunctions.find(startAddress);
if (funcInfo != activeFunctions.end()) {
auto symbolKey = std::make_pair(funcInfo->second.module, funcInfo->second.start);
auto func = functions.find(symbolKey);
if (func != functions.end()) {
func->second.size = newSize;
UpdateActiveSymbols();
}
}
// TODO: check for overlaps
return true;
}
bool SymbolMap::RemoveFunction(u32 startAddress, bool removeName) {
Threading::ScopedLock guard(lock_);
auto it = activeFunctions.find(startAddress);
if (it == activeFunctions.end())
return false;
auto symbolKey = std::make_pair(it->second.module, it->second.start);
auto it2 = functions.find(symbolKey);
if (it2 != functions.end()) {
functions.erase(it2);
}
activeFunctions.erase(it);
if (removeName) {
auto labelIt = activeLabels.find(startAddress);
if (labelIt != activeLabels.end()) {
symbolKey = std::make_pair(labelIt->second.module, labelIt->second.addr);
auto labelIt2 = labels.find(symbolKey);
if (labelIt2 != labels.end()) {
labels.erase(labelIt2);
}
activeLabels.erase(labelIt);
}
}
return true;
}
void SymbolMap::AddLabel(const char* name, u32 address, int moduleIndex) {
Threading::ScopedLock guard(lock_);
if (moduleIndex == -1) {
moduleIndex = GetModuleIndex(address);
}
// Is there an existing one?
u32 relAddress = GetModuleRelativeAddr(address, moduleIndex);
auto symbolKey = std::make_pair(moduleIndex, relAddress);
auto existing = labels.find(symbolKey);
if (existing == labels.end()) {
// Fall back: maybe it's got moduleIndex = 0.
existing = labels.find(std::make_pair(0, address));
}
if (existing != labels.end()) {
// We leave an existing label alone, rather than overwriting.
// But we'll still upgrade it to the correct module / relative address.
if (existing->second.module != moduleIndex) {
LabelEntry label = existing->second;
label.addr = relAddress;
label.module = moduleIndex;
labels.erase(existing);
labels[symbolKey] = label;
// Refresh the active item if it exists.
auto active = activeLabels.find(address);
if (active != activeLabels.end() && active->second.module == moduleIndex) {
activeLabels.erase(active);
activeLabels.insert(std::make_pair(address, existing->second));
}
}
} else {
LabelEntry label;
label.addr = relAddress;
label.module = moduleIndex;
strncpy(label.name, name, 128);
label.name[127] = 0;
labels[symbolKey] = label;
if (IsModuleActive(moduleIndex)) {
activeLabels.insert(std::make_pair(address, label));
}
}
}
void SymbolMap::SetLabelName(const char* name, u32 address, bool updateImmediately) {
Threading::ScopedLock guard(lock_);
auto labelInfo = activeLabels.find(address);
if (labelInfo == activeLabels.end()) {
AddLabel(name, address);
} else {
auto symbolKey = std::make_pair(labelInfo->second.module, labelInfo->second.addr);
auto label = labels.find(symbolKey);
if (label != labels.end()) {
strcpy(label->second.name,name);
label->second.name[127] = 0;
// Allow the caller to skip this as it causes extreme startup slowdown
// when this gets called for every function identified by the function replacement code.
if (updateImmediately) {
UpdateActiveSymbols();
}
}
}
}
const char *SymbolMap::GetLabelName(u32 address) const {
Threading::ScopedLock guard(lock_);
auto it = activeLabels.find(address);
if (it == activeLabels.end())
return NULL;
return it->second.name;
}
const char *SymbolMap::GetLabelNameRel(u32 relAddress, int moduleIndex) const {
Threading::ScopedLock guard(lock_);
auto it = labels.find(std::make_pair(moduleIndex, relAddress));
if (it == labels.end())
return NULL;
return it->second.name;
}
std::string SymbolMap::GetLabelString(u32 address) const {
Threading::ScopedLock guard(lock_);
const char *label = GetLabelName(address);
if (label == NULL)
return "";
return label;
}
bool SymbolMap::GetLabelValue(const char* name, u32& dest) {
Threading::ScopedLock guard(lock_);
for (auto it = activeLabels.begin(); it != activeLabels.end(); it++) {
if (strcasecmp(name, it->second.name) == 0) {
dest = it->first;
return true;
}
}
return false;
}
void SymbolMap::AddData(u32 address, u32 size, DataType type, int moduleIndex) {
Threading::ScopedLock guard(lock_);
if (moduleIndex == -1) {
moduleIndex = GetModuleIndex(address);
}
// Is there an existing one?
u32 relAddress = GetModuleRelativeAddr(address, moduleIndex);
auto symbolKey = std::make_pair(moduleIndex, relAddress);
auto existing = data.find(symbolKey);
if (existing == data.end()) {
// Fall back: maybe it's got moduleIndex = 0.
existing = data.find(std::make_pair(0, address));
}
if (existing != data.end()) {
existing->second.size = size;
existing->second.type = type;
if (existing->second.module != moduleIndex) {
DataEntry entry = existing->second;
entry.module = moduleIndex;
entry.start = relAddress;
data.erase(existing);
data[symbolKey] = entry;
}
// Refresh the active item if it exists.
auto active = activeData.find(address);
if (active != activeData.end() && active->second.module == moduleIndex) {
activeData.erase(active);
activeData.insert(std::make_pair(address, existing->second));
}
} else {
DataEntry entry;
entry.start = relAddress;
entry.size = size;
entry.type = type;
entry.module = moduleIndex;
data[symbolKey] = entry;
if (IsModuleActive(moduleIndex)) {
activeData.insert(std::make_pair(address, entry));
}
}
}
u32 SymbolMap::GetDataStart(u32 address) const {
Threading::ScopedLock guard(lock_);
auto it = activeData.upper_bound(address);
if (it == activeData.end())
{
// check last element
auto rit = activeData.rbegin();
if (rit != activeData.rend())
{
u32 start = rit->first;
u32 size = rit->second.size;
if (start <= address && start+size > address)
return start;
}
// otherwise there's no data that contains this address
return INVALID_ADDRESS;
}
if (it != activeData.begin()) {
it--;
u32 start = it->first;
u32 size = it->second.size;
if (start <= address && start+size > address)
return start;
}
return INVALID_ADDRESS;
}
u32 SymbolMap::GetDataSize(u32 startAddress) const {
Threading::ScopedLock guard(lock_);
auto it = activeData.find(startAddress);
if (it == activeData.end())
return INVALID_ADDRESS;
return it->second.size;
}
DataType SymbolMap::GetDataType(u32 startAddress) const {
Threading::ScopedLock guard(lock_);
auto it = activeData.find(startAddress);
if (it == activeData.end())
return DATATYPE_NONE;
return it->second.type;
}

View File

@ -0,0 +1,137 @@
#pragma once
#include <vector>
#include <set>
#include <map>
#include <string>
#include "Utilities/Threading.h"
#include "Pcsx2Types.h"
enum SymbolType {
ST_NONE = 0,
ST_FUNCTION = 1,
ST_DATA = 2,
ST_ALL = 3,
};
struct SymbolInfo {
SymbolType type;
u32 address;
u32 size;
};
struct SymbolEntry {
std::string name;
u32 address;
u32 size;
};
struct LoadedModuleInfo {
std::string name;
u32 address;
u32 size;
bool active;
};
enum DataType {
DATATYPE_NONE, DATATYPE_BYTE, DATATYPE_HALFWORD, DATATYPE_WORD, DATATYPE_ASCII
};
class SymbolMap {
public:
SymbolMap() {}
void Clear();
void SortSymbols();
bool LoadNocashSym(const char *ilename);
SymbolType GetSymbolType(u32 address) const;
bool GetSymbolInfo(SymbolInfo *info, u32 address, SymbolType symmask = ST_FUNCTION) const;
u32 GetNextSymbolAddress(u32 address, SymbolType symmask);
std::string GetDescription(unsigned int address) const;
std::vector<SymbolEntry> GetAllSymbols(SymbolType symmask);
void AddModule(const char *name, u32 address, u32 size);
void UnloadModule(u32 address, u32 size);
u32 GetModuleRelativeAddr(u32 address, int moduleIndex = -1) const;
u32 GetModuleAbsoluteAddr(u32 relative, int moduleIndex) const;
int GetModuleIndex(u32 address) const;
bool IsModuleActive(int moduleIndex) const;
std::vector<LoadedModuleInfo> getAllModules() const;
void AddFunction(const char* name, u32 address, u32 size, int moduleIndex = -1);
u32 GetFunctionStart(u32 address) const;
int GetFunctionNum(u32 address) const;
u32 GetFunctionSize(u32 startAddress) const;
bool SetFunctionSize(u32 startAddress, u32 newSize);
bool RemoveFunction(u32 startAddress, bool removeName);
void AddLabel(const char* name, u32 address, int moduleIndex = -1);
std::string GetLabelString(u32 address) const;
void SetLabelName(const char* name, u32 address, bool updateImmediately = true);
bool GetLabelValue(const char* name, u32& dest);
void AddData(u32 address, u32 size, DataType type, int moduleIndex = -1);
u32 GetDataStart(u32 address) const;
u32 GetDataSize(u32 startAddress) const;
DataType GetDataType(u32 startAddress) const;
static const u32 INVALID_ADDRESS = (u32)-1;
void UpdateActiveSymbols();
private:
void AssignFunctionIndices();
const char *GetLabelName(u32 address) const;
const char *GetLabelNameRel(u32 relAddress, int moduleIndex) const;
struct FunctionEntry {
u32 start;
u32 size;
int index;
int module;
};
struct LabelEntry {
u32 addr;
int module;
char name[128];
};
struct DataEntry {
DataType type;
u32 start;
u32 size;
int module;
};
struct ModuleEntry {
// Note: this index is +1, 0 matches any for backwards-compat.
int index;
u32 start;
u32 size;
char name[128];
};
// These are flattened, read-only copies of the actual data in active modules only.
std::map<u32, const FunctionEntry> activeFunctions;
std::map<u32, const LabelEntry> activeLabels;
std::map<u32, const DataEntry> activeData;
// This is indexed by the end address of the module.
std::map<u32, const ModuleEntry> activeModuleEnds;
typedef std::pair<int, u32> SymbolKey;
// These are indexed by the module id and relative address in the module.
std::map<SymbolKey, FunctionEntry> functions;
std::map<SymbolKey, LabelEntry> labels;
std::map<SymbolKey, DataEntry> data;
std::vector<ModuleEntry> modules;
mutable Threading::MutexRecursive lock_;
};
extern SymbolMap symbolMap;

View File

@ -23,6 +23,7 @@ using namespace std;
u32 ElfCRC;
u32 ElfEntry;
std::pair<u32,u32> ElfTextRange;
wxString LastELF;
#if 0
@ -238,6 +239,20 @@ bool ElfObject::hasProgramHeaders() { return (proghead != NULL); }
bool ElfObject::hasSectionHeaders() { return (secthead != NULL); }
bool ElfObject::hasHeaders() { return (hasProgramHeaders() && hasSectionHeaders()); }
std::pair<u32,u32> ElfObject::getTextRange()
{
for (int i = 0; i < header.e_phnum; i++)
{
u32 start = proghead[i].p_vaddr;
u32 size = proghead[i].p_memsz;
if (start <= header.e_entry && (start+size) > header.e_entry)
return std::make_pair(start,size);
}
return std::make_pair(0,0);
}
void ElfObject::readIso(IsoFile file)
{
int rsize = file.read(data.GetPtr(), data.GetSizeInBytes());

View File

@ -155,6 +155,7 @@ class ElfObject
bool hasSectionHeaders();
bool hasHeaders();
std::pair<u32,u32> getTextRange();
u32 getCRC();
};
@ -165,6 +166,7 @@ extern int GetPS2ElfName( wxString& dest );
extern u32 ElfCRC;
extern u32 ElfEntry;
extern std::pair<u32,u32> ElfTextRange;
extern wxString LastELF;
#endif

View File

@ -71,7 +71,17 @@ const R5900::OPCODE& R5900::GetCurrentInstruction()
const OPCODE* opcode = &R5900::OpcodeTables::tbl_Standard[_Opcode_];
while( opcode->getsubclass != NULL )
opcode = &opcode->getsubclass();
opcode = &opcode->getsubclass(cpuRegs.code);
return *opcode;
}
const R5900::OPCODE& R5900::GetInstruction(u32 op)
{
const OPCODE* opcode = &R5900::OpcodeTables::tbl_Standard[op >> 26];
while( opcode->getsubclass != NULL )
opcode = &opcode->getsubclass(op);
return *opcode;
}

View File

@ -619,23 +619,23 @@ namespace R5900
{
using namespace OpcodeTables;
const OPCODE& Class_SPECIAL() { return tbl_Special[_Funct_]; }
const OPCODE& Class_REGIMM() { return tbl_RegImm[_Rt_]; }
const OPCODE& Class_SPECIAL(u32 op) { return tbl_Special[op & 0x3F]; }
const OPCODE& Class_REGIMM(u32 op) { return tbl_RegImm[(op >> 16) & 0x1F]; }
const OPCODE& Class_MMI(u32 op) { return tbl_MMI[op & 0x3F]; }
const OPCODE& Class_MMI0(u32 op) { return tbl_MMI0[(op >> 6) & 0x1F]; }
const OPCODE& Class_MMI1(u32 op) { return tbl_MMI1[(op >> 6) & 0x1F]; }
const OPCODE& Class_MMI2(u32 op) { return tbl_MMI2[(op >> 6) & 0x1F]; }
const OPCODE& Class_MMI3(u32 op) { return tbl_MMI3[(op >> 6) & 0x1F]; }
const OPCODE& Class_MMI() { return tbl_MMI[_Funct_]; }
const OPCODE& Class_MMI0() { return tbl_MMI0[_Sa_]; }
const OPCODE& Class_MMI1() { return tbl_MMI1[_Sa_]; }
const OPCODE& Class_MMI2() { return tbl_MMI2[_Sa_]; }
const OPCODE& Class_MMI3() { return tbl_MMI3[_Sa_]; }
const OPCODE& Class_COP0(u32 op) { return tbl_COP0[(op >> 21) & 0x1F]; }
const OPCODE& Class_COP0_BC0(u32 op) { return tbl_COP0_BC0[(cpuRegs.code >> 16) & 0x03]; }
const OPCODE& Class_COP0_C0(u32 op) { return tbl_COP0_C0[op & 0x3F]; }
const OPCODE& Class_COP0() { return tbl_COP0[_Rs_]; }
const OPCODE& Class_COP0_BC0() { return tbl_COP0_BC0[(cpuRegs.code >> 16) & 0x03]; }
const OPCODE& Class_COP0_C0() { return tbl_COP0_C0[_Funct_]; }
const OPCODE& Class_COP1() { return tbl_COP1[_Rs_]; }
const OPCODE& Class_COP1_BC1() { return tbl_COP1_BC1[_Rt_]; }
const OPCODE& Class_COP1_S() { return tbl_COP1_S[_Funct_]; }
const OPCODE& Class_COP1_W() { return tbl_COP1_W[_Funct_]; }
const OPCODE& Class_COP1(u32 op) { return tbl_COP1[(op >> 21) & 0x1F]; }
const OPCODE& Class_COP1_BC1(u32 op) { return tbl_COP1_BC1[(op >> 16) & 0x1F]; }
const OPCODE& Class_COP1_S(u32 op) { return tbl_COP1_S[op & 0x3F]; }
const OPCODE& Class_COP1_W(u32 op) { return tbl_COP1_W[op & 0x3F]; }
// These are for future use when the COP2 tables are completed.
//const OPCODE& Class_COP2() { return tbl_COP2[_Rs_]; }

View File

@ -79,7 +79,7 @@ namespace R5900
// Number of cycles this instruction normally uses.
u8 cycles;
const OPCODE& (*getsubclass)();
const OPCODE& (*getsubclass)(u32 op);
// Process the instruction using the interpreter.
// The action is performed immediately on the EE's cpu state.
@ -96,7 +96,7 @@ namespace R5900
// Returns the current real instruction, as per the current cpuRegs settings.
const OPCODE& GetCurrentInstruction();
const OPCODE& GetInstruction(u32 op);
namespace OpcodeTables
{
using ::R5900::OPCODE;
@ -126,22 +126,22 @@ namespace R5900
{
using ::R5900::OPCODE;
const OPCODE& Class_SPECIAL();
const OPCODE& Class_REGIMM();
const OPCODE& Class_MMI();
const OPCODE& Class_MMI0();
const OPCODE& Class_MMI1();
const OPCODE& Class_MMI2();
const OPCODE& Class_MMI3();
const OPCODE& Class_SPECIAL(u32 op);
const OPCODE& Class_REGIMM(u32 op);
const OPCODE& Class_MMI(u32 op);
const OPCODE& Class_MMI0(u32 op);
const OPCODE& Class_MMI1(u32 op);
const OPCODE& Class_MMI2(u32 op);
const OPCODE& Class_MMI3(u32 op);
const OPCODE& Class_COP0();
const OPCODE& Class_COP0_BC0();
const OPCODE& Class_COP0_C0();
const OPCODE& Class_COP0(u32 op);
const OPCODE& Class_COP0_BC0(u32 op);
const OPCODE& Class_COP0_C0(u32 op);
const OPCODE& Class_COP1();
const OPCODE& Class_COP1_BC1();
const OPCODE& Class_COP1_S();
const OPCODE& Class_COP1_W();
const OPCODE& Class_COP1(u32 op);
const OPCODE& Class_COP1_BC1(u32 op);
const OPCODE& Class_COP1_S(u32 op);
const OPCODE& Class_COP1_W(u32 op);
}
namespace OpcodeDisasm

View File

@ -25,6 +25,9 @@
#include "SysThreads.h"
#include "MTVU.h"
#include "../DebugTools/MIPSAnalyst.h"
#include "../DebugTools/SymbolMap.h"
#include "Utilities/PageFaultSource.h"
#include "Utilities/TlsVariable.inl"
@ -127,6 +130,7 @@ void SysCoreThread::Reset()
ResetQuick();
GetVmMemory().DecommitAll();
SysClearExecutionCache();
sApp.PostAppMethod( &Pcsx2App::leaveDebugMode );
}
@ -226,6 +230,12 @@ void SysCoreThread::GameStartingInThread()
{
GetMTGS().SendGameCRC(ElfCRC);
#ifdef PCSX2_DEVBUILD
MIPSAnalyst::ScanForFunctions(ElfTextRange.first,ElfTextRange.first+ElfTextRange.second,true);
symbolMap.UpdateActiveSymbols();
sApp.PostAppMethod(&Pcsx2App::resetDebugger);
#endif
if (EmuConfig.EnablePatches) ApplyPatch(0);
if (EmuConfig.EnableCheats) ApplyCheat(0);
}

View File

@ -142,12 +142,28 @@ void SysThreadBase::Pause()
pxAssertDev( m_ExecMode == ExecMode_Pausing, "ExecMode should be nothing other than Pausing..." );
OnPause();
m_sem_event.Post();
}
m_RunningLock.Wait();
}
void SysThreadBase::PauseSelf()
{
if( !IsSelf() || !IsRunning() ) return;
{
ScopedLock locker( m_ExecModeMutex );
if( m_ExecMode == ExecMode_Opened )
m_ExecMode = ExecMode_Pausing;
OnPause();
m_sem_event.Post();
}
}
// Resumes the core execution state, or does nothing is the core is already running. If
// settings were changed, resets will be performed as needed and emulation state resumed from
// memory savestates.

View File

@ -113,7 +113,8 @@ public:
virtual void Suspend( bool isBlocking = true );
virtual void Resume();
virtual void Pause();
virtual void PauseSelf();
protected:
virtual void OnStart();
@ -121,6 +122,7 @@ protected:
// the core emulation thread. You should overload this rather than Resume(), since
// Resume() has a lot of checks and balances to prevent re-entrance and race conditions.
virtual void OnResumeReady() {}
virtual void OnPause() {}
virtual bool StateCheckInThread();
virtual void OnCleanupInThread();

View File

@ -26,6 +26,8 @@
#include "AppCoreThread.h"
#include "RecentIsoList.h"
class DisassemblyDialog;
#include "System.h"
#include "System/SysThreads.h"
@ -503,6 +505,7 @@ protected:
wxWindowID m_id_MainFrame;
wxWindowID m_id_GsFrame;
wxWindowID m_id_ProgramLogBox;
wxWindowID m_id_Disassembler;
wxKeyEvent m_kevt;
@ -521,11 +524,16 @@ public:
SysMainMemory& GetVmReserve();
GSFrame& GetGsFrame() const;
MainEmuFrame& GetMainFrame() const;
GSFrame& GetGsFrame() const;
MainEmuFrame& GetMainFrame() const;
GSFrame* GetGsFramePtr() const { return (GSFrame*)wxWindow::FindWindowById( m_id_GsFrame ); }
MainEmuFrame* GetMainFramePtr() const { return (MainEmuFrame*)wxWindow::FindWindowById( m_id_MainFrame ); }
GSFrame* GetGsFramePtr() const { return (GSFrame*)wxWindow::FindWindowById( m_id_GsFrame ); }
MainEmuFrame* GetMainFramePtr() const { return (MainEmuFrame*)wxWindow::FindWindowById( m_id_MainFrame ); }
DisassemblyDialog* GetDisassemblyPtr() const { return (DisassemblyDialog*)wxWindow::FindWindowById( m_id_Disassembler ); }
void enterDebugMode();
void leaveDebugMode();
void resetDebugger();
bool HasMainFrame() const { return GetMainFramePtr() != NULL; }

View File

@ -20,6 +20,8 @@
#include <wx/stdpaths.h>
#include "Debugger/DisassemblyDialog.h"
#include "Utilities/TlsVariable.inl"
#include "ps2/BiosTools.h"
@ -107,7 +109,7 @@ void AppCoreThread::Reset()
GetSysExecutorThread().PostEvent( SysExecEvent_InvokeCoreThreadMethod(&AppCoreThread::Reset) );
return;
}
_parent::Reset();
}
@ -197,9 +199,17 @@ void AppCoreThread::OnResumeReady()
{
wxGetApp().SysApplySettings();
wxGetApp().PostMethod( AppSaveSettings );
sApp.PostAppMethod( &Pcsx2App::leaveDebugMode );
_parent::OnResumeReady();
}
void AppCoreThread::OnPause()
{
sApp.PostAppMethod( &Pcsx2App::enterDebugMode );
_parent::OnPause();
}
// Load Game Settings found in database
// (game fixes, round modes, clamp modes, etc...)
// Returns number of gamefixes set

View File

@ -146,6 +146,7 @@ protected:
virtual void DoCpuExecute();
virtual void OnResumeReady();
virtual void OnPause();
virtual void OnResumeInThread( bool IsSuspended );
virtual void OnSuspendInThread();
virtual void OnCleanupInThread();

View File

@ -23,6 +23,8 @@
#include "DebugTools/Debug.h"
#include "Dialogs/ModalPopups.h"
#include "Debugger/DisassemblyDialog.h"
#include <wx/cmdline.h>
#include <wx/intl.h>
#include <wx/stdpaths.h>
@ -86,6 +88,9 @@ void Pcsx2App::OpenMainFrame()
MainEmuFrame* mainFrame = new MainEmuFrame( NULL, pxGetAppName() );
m_id_MainFrame = mainFrame->GetId();
DisassemblyDialog* disassembly = new DisassemblyDialog( mainFrame );
m_id_Disassembler = disassembly->GetId();
PostIdleAppMethod( &Pcsx2App::OpenProgramLog );
SetTopWindow( mainFrame ); // not really needed...

View File

@ -28,6 +28,8 @@
#include "Dialogs/ConfigurationDialog.h"
#include "Dialogs/LogOptionsDialog.h"
#include "Debugger/DisassemblyDialog.h"
#include "Utilities/IniInterface.h"
#include <wx/stdpaths.h>
@ -751,6 +753,27 @@ GSFrame& Pcsx2App::GetGsFrame() const
return *gsFrame;
}
void Pcsx2App::enterDebugMode()
{
DisassemblyDialog* dlg = GetDisassemblyPtr();
if (dlg)
dlg->setDebugMode(true);
}
void Pcsx2App::leaveDebugMode()
{
DisassemblyDialog* dlg = GetDisassemblyPtr();
if (dlg)
dlg->setDebugMode(false);
}
void Pcsx2App::resetDebugger()
{
DisassemblyDialog* dlg = GetDisassemblyPtr();
if (dlg)
dlg->reset();
}
// NOTE: Plugins are *not* applied by this function. Changes to plugins need to handled
// manually. The PluginSelectorPanel does this, for example.
void AppApplySettings( const AppConfig* oldconf )

View File

@ -0,0 +1,332 @@
#include "PrecompiledHeader.h"
#include "BreakpointWindow.h"
BEGIN_EVENT_TABLE(BreakpointWindow, wxDialog)
EVT_RADIOBUTTON(wxID_ANY, BreakpointWindow::onRadioChange)
EVT_BUTTON(wxID_OK, BreakpointWindow::onButtonOk)
END_EVENT_TABLE()
BreakpointWindow::BreakpointWindow( wxWindow* parent, DebugInterface* _cpu )
: wxDialog(parent,wxID_ANY,L"Breakpoint"), cpu(_cpu)
{
wxBoxSizer* topLevelSizer = new wxBoxSizer(wxVERTICAL);
wxBoxSizer* upperPart = new wxBoxSizer(wxHORIZONTAL);
wxFlexGridSizer* leftSizer = new wxFlexGridSizer(2,2,7,7);
// address
wxStaticText* addressText = new wxStaticText(this,wxID_ANY,L"Address");
editAddress = new wxTextCtrl(this,wxID_ANY,L"");
leftSizer->Add(addressText,0,wxALIGN_CENTER_VERTICAL|wxBOTTOM,1);
leftSizer->Add(editAddress,1);
// size
wxStaticText* sizeText = new wxStaticText(this,wxID_ANY,L"Size");
editSize = new wxTextCtrl(this,wxID_ANY,L"");
leftSizer->Add(sizeText,0,wxALIGN_CENTER_VERTICAL|wxBOTTOM,1);
leftSizer->Add(editSize,1);
// right part
wxFlexGridSizer* rightSizer = new wxFlexGridSizer(3,2,7,7);
radioMemory = new wxRadioButton(this,wxID_ANY,L"Memory",wxDefaultPosition,wxDefaultSize,wxRB_GROUP);
radioExecute = new wxRadioButton(this,wxID_ANY,L"Execute");
rightSizer->Add(radioMemory,1);
rightSizer->Add(radioExecute,1,wxLEFT,8);
checkRead = new wxCheckBox(this,wxID_ANY,L"Read");
checkWrite = new wxCheckBox(this,wxID_ANY,L"Write");
checkOnChange = new wxCheckBox(this,wxID_ANY,L"On change");
rightSizer->Add(checkRead,1);
rightSizer->Add(new wxStaticText(this,wxID_ANY,L""),1);
rightSizer->Add(checkWrite,1);
rightSizer->Add(checkOnChange,1,wxLEFT,8);
upperPart->Add(leftSizer,1,wxLEFT|wxTOP|wxRIGHT,8);
upperPart->Add(rightSizer,1,wxLEFT|wxTOP|wxRIGHT,8);
// bottom part
wxBoxSizer* conditionSizer = new wxBoxSizer(wxHORIZONTAL);
wxStaticText* conditionText = new wxStaticText(this,wxID_ANY,L"Condition");
editCondition = new wxTextCtrl(this,wxID_ANY,L"");
conditionSizer->Add(conditionText,0,wxALIGN_CENTER_VERTICAL|wxBOTTOM,1);
conditionSizer->AddSpacer(7);
conditionSizer->Add(editCondition,1,wxEXPAND);
wxBoxSizer* bottomRowSizer = new wxBoxSizer(wxHORIZONTAL);
checkEnabled = new wxCheckBox(this,wxID_ANY,L"Enabled");
checkLog = new wxCheckBox(this,wxID_ANY,L"Log");
buttonOk = new wxButton(this,wxID_OK,L"OK");
buttonCancel = new wxButton(this,wxID_CANCEL,L"Cancel");
bottomRowSizer->AddStretchSpacer();
bottomRowSizer->Add(checkEnabled,0,wxALIGN_CENTER_VERTICAL|wxBOTTOM,1);
bottomRowSizer->AddSpacer(8);
bottomRowSizer->Add(checkLog,0,wxALIGN_CENTER_VERTICAL|wxBOTTOM,1);
bottomRowSizer->AddSpacer(8);
bottomRowSizer->Add(buttonOk,1);
bottomRowSizer->AddSpacer(4);
bottomRowSizer->Add(buttonCancel,1);
// align labels
int minWidth = std::max<int>(addressText->GetSize().x,sizeText->GetSize().x);
minWidth = std::max<int>(minWidth,conditionText->GetSize().x);
addressText->SetMinSize(wxSize(minWidth,addressText->GetSize().y));
sizeText->SetMinSize(wxSize(minWidth,sizeText->GetSize().y));
conditionText->SetMinSize(wxSize(minWidth,conditionText->GetSize().y));
// set tab order
radioMemory->MoveAfterInTabOrder(editAddress);
radioExecute->MoveAfterInTabOrder(radioMemory);
editSize->MoveAfterInTabOrder(radioExecute);
checkRead->MoveAfterInTabOrder(editSize);
checkWrite->MoveAfterInTabOrder(checkRead);
checkOnChange->MoveAfterInTabOrder(checkWrite);
editCondition->MoveAfterInTabOrder(checkOnChange);
checkEnabled->MoveAfterInTabOrder(editCondition);
checkLog->MoveAfterInTabOrder(checkEnabled);
buttonOk->MoveAfterInTabOrder(checkLog);
buttonCancel->MoveAfterInTabOrder(buttonOk);
topLevelSizer->Add(upperPart,0);
topLevelSizer->AddSpacer(5);
topLevelSizer->Add(conditionSizer,0,wxLEFT|wxTOP|wxRIGHT|wxEXPAND,8);
topLevelSizer->AddSpacer(5);
topLevelSizer->Add(bottomRowSizer,0,wxLEFT|wxTOP|wxRIGHT|wxBOTTOM,8);
SetSizer(topLevelSizer);
topLevelSizer->Fit(this);
buttonOk->SetDefault();
// default values
memory = true;
onChange = false;
read = write = true;
enabled = log = true;
address = -1;
size = 1;
condition[0] = 0;
setDefaultValues();
}
void BreakpointWindow::setDefaultValues()
{
radioExecute->SetValue(!memory);
radioMemory->SetValue(memory);
checkRead->SetValue(read);
checkWrite->SetValue(write);
checkOnChange->SetValue(onChange);
checkEnabled->SetValue(enabled);
checkLog->SetValue(log);
checkRead->Enable(memory);
checkWrite->Enable(memory);
checkOnChange->Enable(memory);
checkRead->Enable(memory);
editSize->Enable(memory);
editCondition->Enable(!memory);
checkLog->Enable(memory);
wchar_t str[64];
if (address != -1)
{
swprintf(str,64,L"0x%08X",address);
editAddress->SetLabel(str);
}
swprintf(str,64,L"0x%08X",size);
editSize->SetLabel(str);
editCondition->SetLabel(wxString(condition,wxConvUTF8));
}
void BreakpointWindow::loadFromMemcheck(MemCheck& memcheck)
{
memory = true;
read = (memcheck.cond & MEMCHECK_READ) != 0;
write = (memcheck.cond & MEMCHECK_WRITE) != 0;
onChange = (memcheck.cond & MEMCHECK_WRITE_ONCHANGE) != 0;
switch (memcheck.result)
{
case MEMCHECK_BOTH:
log = enabled = true;
break;
case MEMCHECK_LOG:
log = true;
enabled = false;
break;
case MEMCHECK_BREAK:
log = false;
enabled = true;
break;
case MEMCHECK_IGNORE:
log = enabled = false;
break;
}
address = memcheck.start;
size = memcheck.end-address;
setDefaultValues();
}
void BreakpointWindow::loadFromBreakpoint(BreakPoint& breakpoint)
{
memory = false;
enabled = breakpoint.enabled;
address = breakpoint.addr;
size = 1;
if (breakpoint.hasCond)
{
strcpy(condition,breakpoint.cond.expressionString);
} else {
condition[0] = 0;
}
setDefaultValues();
}
void BreakpointWindow::initBreakpoint(u32 _address)
{
memory = false;
enabled = true;
address = _address;
size = 1;
condition[0] = 0;
setDefaultValues();
}
void BreakpointWindow::onRadioChange(wxCommandEvent& evt)
{
memory = radioMemory->GetValue();
checkRead->Enable(memory);
checkWrite->Enable(memory);
checkOnChange->Enable(memory);
checkRead->Enable(memory);
editSize->Enable(memory);
editCondition->Enable(!memory);
checkLog->Enable(memory);
}
bool BreakpointWindow::fetchDialogData()
{
wchar_t errorMessage[512];
PostfixExpression exp;
memory = radioMemory->GetValue();
read = checkRead->GetValue();
write = checkWrite->GetValue();
enabled = checkEnabled->GetValue();
log = checkLog->GetValue();
onChange = checkOnChange->GetValue();
// parse address
wxCharBuffer addressText = editAddress->GetLabel().ToUTF8();
if (cpu->initExpression(addressText,exp) == false)
{
swprintf(errorMessage,512,L"Invalid expression \"%s\".",editAddress->GetLabel().wchar_str());
wxMessageBox(errorMessage,L"Error",wxICON_ERROR);
return false;
}
u64 value;
if (cpu->parseExpression(exp,value) == false)
{
swprintf(errorMessage,512,L"Invalid expression \"%s\".",editAddress->GetLabel().wchar_str());
wxMessageBox(errorMessage,L"Error",wxICON_ERROR);
return false;
}
address = value;
if (memory)
{
// parse size
wxCharBuffer sizeText = editSize->GetLabel().ToUTF8();
if (cpu->initExpression(sizeText,exp) == false)
{
swprintf(errorMessage,512,L"Invalid expression \"%s\".",editSize->GetLabel().wchar_str());
wxMessageBox(errorMessage,L"Error",wxICON_ERROR);
return false;
}
if (cpu->parseExpression(exp,value) == false)
{
swprintf(errorMessage,512,L"Invalid expression \"%s\".",editSize->GetLabel().wchar_str());
wxMessageBox(errorMessage,L"Error",wxICON_ERROR);
return false;
}
size = value;
}
// condition
wxCharBuffer conditionText = editCondition->GetLabel().ToUTF8();
strncpy(condition,conditionText,sizeof(condition));
condition[sizeof(condition)-1] = 0;
compiledCondition.clear();
if (condition[0] != 0)
{
if (cpu->initExpression(condition,compiledCondition) == false)
{
swprintf(errorMessage,512,L"Invalid expression \"%s\".",editCondition->GetLabel().wchar_str());
wxMessageBox(errorMessage,L"Error",wxICON_ERROR);
return false;
}
}
return true;
}
void BreakpointWindow::onButtonOk(wxCommandEvent& evt)
{
if (fetchDialogData() == true)
evt.Skip();
}
void BreakpointWindow::addBreakpoint()
{
if (memory)
{
// add memcheck
int cond = 0;
if (read)
cond |= MEMCHECK_READ;
if (write)
cond |= MEMCHECK_WRITE;
if (onChange)
cond |= MEMCHECK_WRITE_ONCHANGE;
MemCheckResult result;
if (log && enabled) result = MEMCHECK_BOTH;
else if (log) result = MEMCHECK_LOG;
else if (enabled) result = MEMCHECK_BREAK;
else result = MEMCHECK_IGNORE;
CBreakPoints::AddMemCheck(address, address + size, (MemCheckCondition)cond, result);
} else {
// add breakpoint
CBreakPoints::AddBreakPoint(address,false);
if (condition[0] != 0)
{
BreakPointCond cond;
cond.debug = cpu;
strcpy(cond.expressionString,condition);
cond.expression = compiledCondition;
CBreakPoints::ChangeBreakPointAddCond(address,cond);
}
if (enabled == false)
{
CBreakPoints::ChangeBreakPoint(address,false);
}
}
}

View File

@ -0,0 +1,48 @@
#pragma once
#include <wx/wx.h>
#include "DebugTools/DebugInterface.h"
#include "DebugTools/Breakpoints.h"
class BreakpointWindow : public wxDialog
{
public:
BreakpointWindow( wxWindow* parent, DebugInterface* _cpu );
void loadFromMemcheck(MemCheck& memcheck);
void loadFromBreakpoint(BreakPoint& breakpoint);
void initBreakpoint(u32 _address);
void addBreakpoint();
DECLARE_EVENT_TABLE()
protected:
void onRadioChange(wxCommandEvent& evt);
void onButtonOk(wxCommandEvent& evt);
private:
void setDefaultValues();
bool fetchDialogData();
DebugInterface* cpu;
wxTextCtrl* editAddress;
wxTextCtrl* editSize;
wxRadioButton* radioMemory;
wxRadioButton* radioExecute;
wxCheckBox* checkRead;
wxCheckBox* checkWrite;
wxCheckBox* checkOnChange;
wxTextCtrl* editCondition;
wxCheckBox* checkEnabled;
wxCheckBox* checkLog;
wxButton* buttonOk;
wxButton* buttonCancel;
bool memory;
bool read;
bool write;
bool enabled;
bool log;
bool onChange;
u32 address;
u32 size;
char condition[128];
PostfixExpression compiledCondition;
};

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,89 @@
#pragma once
#include <wx/wx.h>
#include "DebugTools/DebugInterface.h"
#include "DebugTools/DisassemblyManager.h"
class CtrlDisassemblyView: public wxWindow
{
public:
CtrlDisassemblyView(wxWindow* parent, DebugInterface* _cpu);
void mouseEvent(wxMouseEvent& evt);
void paintEvent(wxPaintEvent & evt);
void keydownEvent(wxKeyEvent& evt);
void scrollbarEvent(wxScrollWinEvent& evt);
void sizeEvent(wxSizeEvent& evt);
void focusEvent(wxFocusEvent& evt) { Refresh(); };
#ifdef WIN32
WXLRESULT MSWWindowProc(WXUINT nMsg, WXWPARAM wParam, WXLPARAM lParam);
#endif
void scanFunctions();
void clearFunctions() { manager.clear(); };
void redraw();
u32 getInstructionSizeAt(u32 address)
{
u32 start = manager.getStartAddress(address);
u32 next = manager.getNthNextAddress(start,1);
return next-address;
}
void gotoAddress(u32 addr);
void gotoPc() { gotoAddress(cpu->getPC()); };
void scrollStepping(u32 newPc);
DECLARE_EVENT_TABLE()
private:
void drawBranchLine(wxDC& dc, std::map<u32,int>& addressPositions, BranchLine& line);
void render(wxDC& dc);
void calculatePixelPositions();
bool getDisasmAddressText(u32 address, char* dest, bool abbreviateLabels, bool showData);
u32 yToAddress(int y);
bool curAddressIsVisible();
void followBranch();
void toggleBreakpoint(bool toggleEnabled);
void updateStatusBarText();
std::string disassembleRange(u32 start, u32 size);
void copyInstructions(u32 startAddr, u32 endAddr, bool withDisasm);
void disassembleToFile();
void editBreakpoint();
void postEvent(wxEventType type, wxString text);
void postEvent(wxEventType type, int value);
void onPopupClick(wxCommandEvent& evt);
void setCurAddress(u32 newAddress, bool extend = false)
{
newAddress = manager.getStartAddress(newAddress);
u32 after = manager.getNthNextAddress(newAddress,1);
curAddress = newAddress;
selectRangeStart = extend ? std::min(selectRangeStart, newAddress) : newAddress;
selectRangeEnd = extend ? std::max(selectRangeEnd, after) : after;
updateStatusBarText();
}
void scrollAddressIntoView();
struct {
int addressStart;
int opcodeStart;
int argumentsStart;
int arrowsStart;
} pixelPositions;
DebugInterface* cpu;
DisassemblyManager manager;
u32 windowStart;
u32 curAddress;
u32 selectRangeStart;
u32 selectRangeEnd;
int visibleRows;
int rowHeight;
int charWidth;
bool displaySymbols;
std::vector<u32> jumpStack;
wxIcon bpEnabled,bpDisabled;
wxMenu menu;
};

View File

@ -0,0 +1,46 @@
#pragma once
#include <wx/wx.h>
#include "DebugTools/DebugInterface.h"
#include "DebugTools/DisassemblyManager.h"
class CtrlMemView: public wxWindow
{
public:
CtrlMemView(wxWindow* parent, DebugInterface* _cpu);
void paintEvent(wxPaintEvent & evt);
void mouseEvent(wxMouseEvent& evt);
void keydownEvent(wxKeyEvent& evt);
void charEvent(wxKeyEvent& evt);
void redraw();
void gotoAddress(u32 address);
DECLARE_EVENT_TABLE()
private:
void render(wxDC& dc);
void gotoPoint(int x, int y);
void updateStatusBarText();
void postEvent(wxEventType type, wxString text);
void postEvent(wxEventType type, int value);
void scrollWindow(int lines);
void scrollCursor(int bytes);
void onPopupClick(wxCommandEvent& evt);
void focusEvent(wxFocusEvent& evt) { Refresh(); };
DebugInterface* cpu;
int rowHeight;
int charWidth;
u32 windowStart;
u32 curAddress;
int rowSize;
wxFont font,underlineFont;
int addressStart;
int hexStart;
int asciiStart;
bool asciiSelected;
int selectedNibble;
wxMenu menu;
};

View File

@ -0,0 +1,422 @@
#include "PrecompiledHeader.h"
#include "CtrlRegisterList.h"
#include "DebugTools/Debug.h"
#include "DebugEvents.h"
BEGIN_EVENT_TABLE(CtrlRegisterList, wxWindow)
EVT_PAINT(CtrlRegisterList::paintEvent)
EVT_LEFT_DOWN(CtrlRegisterList::mouseEvent)
EVT_RIGHT_DOWN(CtrlRegisterList::mouseEvent)
EVT_RIGHT_UP(CtrlRegisterList::mouseEvent)
EVT_MOTION(CtrlRegisterList::mouseEvent)
EVT_KEY_DOWN(CtrlRegisterList::keydownEvent)
END_EVENT_TABLE()
enum DisassemblyMenuIdentifiers
{
ID_REGISTERLIST_DISPLAY32 = 1,
ID_REGISTERLIST_DISPLAY64,
ID_REGISTERLIST_DISPLAY128,
};
CtrlRegisterList::CtrlRegisterList(wxWindow* parent, DebugInterface* _cpu)
: wxWindow(parent,wxID_ANY,wxDefaultPosition,wxDefaultSize,wxWANTS_CHARS|wxBORDER), cpu(_cpu)
{
rowHeight = 14;
charWidth = 8;
category = 0;
maxBits = 128;
for (int i = 0; i < cpu->getRegisterCategoryCount(); i++)
{
int count = cpu->getRegisterCount(i);
ChangedReg* regs = new ChangedReg[count];
memset(regs,0,sizeof(ChangedReg)*count);
changedCategories.push_back(regs);
int maxLen = 0;
for (int k = 0; k < cpu->getRegisterCount(i); k++)
{
maxLen = std::max<int>(maxLen,strlen(cpu->getRegisterName(i,k)));
}
int x = 17+(maxLen+3)*charWidth;
startPositions.push_back(x);
currentRows.push_back(0);
}
menu.AppendRadioItem(ID_REGISTERLIST_DISPLAY32, L"Display 32 bit");
menu.AppendRadioItem(ID_REGISTERLIST_DISPLAY64, L"Display 64 bit");
menu.AppendRadioItem(ID_REGISTERLIST_DISPLAY128, L"Display 128 bit");
menu.Check(ID_REGISTERLIST_DISPLAY128,true);
menu.Connect(wxEVT_COMMAND_MENU_SELECTED, (wxObjectEventFunction)&CtrlRegisterList::onPopupClick, NULL, this);
SetDoubleBuffered(true);
SetInitialBestSize(ClientToWindowSize(GetMinClientSize()));
}
void CtrlRegisterList::postEvent(wxEventType type, wxString text)
{
wxCommandEvent event( type, GetId() );
event.SetEventObject(this);
event.SetString(text);
wxPostEvent(this,event);
}
void CtrlRegisterList::postEvent(wxEventType type, int value)
{
wxCommandEvent event( type, GetId() );
event.SetEventObject(this);
event.SetInt(value);
wxPostEvent(this,event);
}
void CtrlRegisterList::refreshChangedRegs()
{
if (cpu->getPC() == lastPc)
return;
for (size_t cat = 0; cat < changedCategories.size(); cat++)
{
ChangedReg* regs = changedCategories[cat];
int size = cpu->getRegisterSize(category);
for (int i = 0; i < cpu->getRegisterCount(cat); i++)
{
ChangedReg& reg = regs[i];
memset(&reg.changed,0,sizeof(reg.changed));
u128 newValue = cpu->getRegister(cat,i);
if (reg.oldValue != newValue)
{
bool changed = false;
if (size >= 128 && (reg.oldValue._u32[3] != newValue._u32[3] || reg.oldValue._u32[2] != newValue._u32[2]))
{
changed = true;
reg.changed[3] = true;
reg.changed[2] = true;
}
if (size >= 64 && (reg.oldValue._u32[1] != newValue._u32[1] || changed))
{
changed = true;
reg.changed[1] = true;
}
if (reg.oldValue._u32[0] != newValue._u32[0] || changed)
{
reg.changed[0] = true;
}
reg.oldValue = newValue;
}
}
}
lastPc = cpu->getPC();
}
void CtrlRegisterList::paintEvent(wxPaintEvent & evt)
{
wxPaintDC dc(this);
render(dc);
}
void CtrlRegisterList::redraw()
{
wxClientDC dc(this);
render(dc);
}
void drawU32Text(wxDC& dc, u32 value, int x, int y)
{
char str[32];
sprintf(str,"%08X",value);
dc.DrawText(wxString(str,wxConvUTF8),x,y);
}
void CtrlRegisterList::render(wxDC& dc)
{
#ifdef WIN32
wxFont font = wxFont(wxSize(charWidth,rowHeight-2),wxFONTFAMILY_DEFAULT,wxFONTSTYLE_NORMAL,wxFONTWEIGHT_NORMAL,false,L"Lucida Console");
#else
wxFont font = wxFont(8,wxFONTFAMILY_DEFAULT,wxFONTSTYLE_NORMAL,wxFONTWEIGHT_NORMAL,false,L"Lucida Console");
font.SetPixelSize(wxSize(charWidth,rowHeight-2));
#endif
dc.SetFont(font);
// clear background
wxColor white = wxColor(0xFFFFFFFF);
dc.SetBrush(wxBrush(white));
dc.SetPen(wxPen(white));
wxSize size = GetSize();
dc.DrawRectangle(0,0,size.x,size.y);
refreshChangedRegs();
wxColor colorChanged = wxColor(0xFF0000FF);
wxColor colorUnchanged = wxColor(0xFF004000);
wxColor colorNormal = wxColor(0xFF600000);
// draw categories
int piece = size.x/cpu->getRegisterCategoryCount();
for (int i = 0; i < cpu->getRegisterCategoryCount(); i++)
{
const char* name = cpu->getRegisterCategoryName(i);
int x = i*piece;
if (i == category)
{
dc.SetBrush(wxBrush(wxColor(0xFF70FF70)));
dc.SetPen(wxPen(wxColor(0xFF000000)));
} else {
dc.SetBrush(wxBrush(wxColor(0xFFFFEFE8)));
dc.SetPen(wxPen(wxColor(0xFF000000)));
}
dc.DrawRectangle(x-1,-1,piece+1,rowHeight+1);
// center text
x += (piece-strlen(name)*charWidth)/2;
dc.DrawText(wxString(name,wxConvUTF8),x,1);
}
int nameStart = 17;
int valueStart = startPositions[category];
ChangedReg* changedRegs = changedCategories[category];
int registerBits = cpu->getRegisterSize(category);
DebugInterface::RegisterType type = cpu->getRegisterType(category);
for (int i = 0; i < cpu->getRegisterCount(category); i++)
{
int x = valueStart;
int y = rowHeight*(i+1);
if (currentRows[category] == i)
{
dc.SetBrush(wxBrush(wxColor(0xFFFFEFE8)));
dc.SetPen(wxPen(wxColor(0xFFFFEFE8)));
dc.DrawRectangle(0,y,size.x,rowHeight);
}
const char* name = cpu->getRegisterName(category,i);
dc.SetTextForeground(colorNormal);
dc.DrawText(wxString(name,wxConvUTF8),nameStart,y+2);
u128 value = cpu->getRegister(category,i);
ChangedReg& changed = changedRegs[i];
switch (type)
{
case DebugInterface::NORMAL: // display them in 32 bit parts
switch (registerBits)
{
case 128:
{
int startIndex = std::min<int>(3,maxBits/32-1);
int actualX = size.x-4-(startIndex+1)*(8*charWidth+2);
x = std::max<int>(actualX,x);
if (startIndex != 3)
{
bool c = false;
for (int i = 3; i > startIndex; i--)
c = c || changed.changed[i];
if (c)
{
dc.SetTextForeground(colorChanged);
dc.DrawText(L"+",x-charWidth,y+2);
}
}
for (int i = startIndex; i >= 0; i--)
{
if (changed.changed[i])
dc.SetTextForeground(colorChanged);
else
dc.SetTextForeground(colorUnchanged);
drawU32Text(dc,value._u32[i],x,y+2);
x += charWidth*8+2;
}
break;
}
case 64:
{
if (maxBits < 64 && changed.changed[1])
{
dc.SetTextForeground(colorChanged);
dc.DrawText(L"+",x-charWidth,y+2);
}
for (int i = 1; i >= 0; i--)
{
if (changed.changed[i])
dc.SetTextForeground(colorChanged);
else
dc.SetTextForeground(colorUnchanged);
drawU32Text(dc,value._u32[i],x,y+2);
x += charWidth*8+2;
}
break;
}
case 32:
{
if (changed.changed[0])
dc.SetTextForeground(colorChanged);
else
dc.SetTextForeground(colorUnchanged);
drawU32Text(dc,value._u32[0],x,y+2);
break;
}
}
break;
case DebugInterface::SPECIAL: // let debug interface format them and just display them
{
if (changed.changed[0] || changed.changed[1] || changed.changed[2] || changed.changed[3])
dc.SetTextForeground(colorChanged);
else
dc.SetTextForeground(colorUnchanged);
dc.DrawText(cpu->getRegisterString(category,i),x,y+2);
break;
}
}
}
}
void CtrlRegisterList::onPopupClick(wxCommandEvent& evt)
{
switch (evt.GetId())
{
case ID_REGISTERLIST_DISPLAY32:
maxBits = 32;
SetBestSize(ClientToWindowSize(GetMinClientSize()));
postEvent(debEVT_UPDATELAYOUT,0);
Refresh();
break;
case ID_REGISTERLIST_DISPLAY64:
maxBits = 64;
SetBestSize(ClientToWindowSize(GetMinClientSize()));
postEvent(debEVT_UPDATELAYOUT,0);
Refresh();
break;
case ID_REGISTERLIST_DISPLAY128:
maxBits = 128;
SetBestSize(ClientToWindowSize(GetMinClientSize()));
postEvent(debEVT_UPDATELAYOUT,0);
Refresh();
break;
default:
wxMessageBox( L"Unimplemented.", L"Unimplemented.", wxICON_INFORMATION);
break;
}
}
void CtrlRegisterList::setCurrentRow(int row)
{
char str[256];
u128 value ;
wxString text;
const char* name = cpu->getRegisterName(category,row);
switch (cpu->getRegisterType(category))
{
case DebugInterface::NORMAL:
value = cpu->getRegister(category,row);
switch (cpu->getRegisterSize(category))
{
case 128:
sprintf(str,"%s = 0x%08X%08X%08X%08X",name,value._u32[3],value._u32[2],value._u32[1],value._u32[0]);
break;
case 64:
sprintf(str,"%s = 0x%08X%08X",name,value._u32[1],value._u32[0]);
break;
case 32:
sprintf(str,"%s = 0x%08X",name,value._u32[0]);
break;
}
text = wxString(str,wxConvUTF8);
break;
case DebugInterface::SPECIAL:
text = wxString(name,wxConvUTF8) + L" = " + cpu->getRegisterString(category,row);
break;
}
currentRows[category] = row;
postEvent(debEVT_SETSTATUSBARTEXT,text);
Refresh();
}
void CtrlRegisterList::mouseEvent(wxMouseEvent& evt)
{
if (evt.GetEventType() == wxEVT_RIGHT_UP)
{
int y = evt.GetPosition().y;
if (y >= rowHeight)
{
int row = (y-rowHeight)/rowHeight;
if (row != currentRows[category] && row < cpu->getRegisterCount(category))
setCurrentRow(row);
}
PopupMenu(&menu,evt.GetPosition());
return;
}
if (evt.ButtonIsDown(wxMOUSE_BTN_LEFT) || evt.ButtonIsDown(wxMOUSE_BTN_RIGHT))
{
int x = evt.GetPosition().x;
int y = evt.GetPosition().y;
if (y < rowHeight)
{
int piece = GetSize().x/cpu->getRegisterCategoryCount();
int cat = x/piece;
if (cat != category)
{
category = cat;
Refresh();
}
} else {
int row = (y-rowHeight)/rowHeight;
if (row != currentRows[category] && row < cpu->getRegisterCount(category))
setCurrentRow(row);
}
SetFocus();
SetFocusFromKbd();
}
}
void CtrlRegisterList::keydownEvent(wxKeyEvent& evt)
{
switch (evt.GetKeyCode())
{
case WXK_UP:
setCurrentRow(std::max<int>(currentRows[category]-1,0));
break;
case WXK_DOWN:
setCurrentRow(std::min<int>(currentRows[category]+1,cpu->getRegisterCount(category)));
break;
case WXK_TAB:
category = (category+1) % cpu->getRegisterCategoryCount();
Refresh();
break;
}
}

View File

@ -0,0 +1,72 @@
#pragma once
#include <wx/wx.h>
#include "DebugTools/DebugInterface.h"
#include "DebugTools/DisassemblyManager.h"
class CtrlRegisterList: public wxWindow
{
public:
CtrlRegisterList(wxWindow* parent, DebugInterface* _cpu);
void paintEvent(wxPaintEvent & evt);
void mouseEvent(wxMouseEvent& evt);
void keydownEvent(wxKeyEvent& evt);
void onPopupClick(wxCommandEvent& evt);
void redraw();
DECLARE_EVENT_TABLE()
virtual wxSize GetMinClientSize() const
{
int columnChars = 0;
int maxWidth = 0;
int maxRows = 0;
for (int i = 0; i < cpu->getRegisterCategoryCount(); i++)
{
int bits = std::min<u32>(maxBits,cpu->getRegisterSize(i));
int start = startPositions[i];
int w = start+(bits/4) * charWidth;
if (bits > 32)
w += (bits/32)*2-2;
maxWidth = std::max<int>(maxWidth,w);
columnChars += strlen(cpu->getRegisterCategoryName(i))+1;
maxRows = std::max<int>(maxRows,cpu->getRegisterCount(i));
}
maxWidth = std::max<int>(columnChars*charWidth,maxWidth+4);
return wxSize(maxWidth,(maxRows+1)*rowHeight);
}
virtual wxSize DoGetBestClientSize() const
{
return GetMinClientSize();
}
private:
void render(wxDC& dc);
void refreshChangedRegs();
void setCurrentRow(int row);
void postEvent(wxEventType type, wxString text);
void postEvent(wxEventType type, int value);
struct ChangedReg
{
u128 oldValue;
bool changed[4];
};
std::vector<ChangedReg*> changedCategories;
std::vector<int> startPositions;
std::vector<int> currentRows;
DebugInterface* cpu;
int rowHeight,charWidth;
u32 lastPc;
int category;
int maxBits;
wxMenu menu;
};

View File

@ -0,0 +1,14 @@
#pragma once
#include <wx/wx.h>
#include "DebugTools/DebugInterface.h"
DECLARE_LOCAL_EVENT_TYPE( debEVT_SETSTATUSBARTEXT, wxNewEventType() )
DECLARE_LOCAL_EVENT_TYPE( debEVT_UPDATELAYOUT, wxNewEventType() )
DECLARE_LOCAL_EVENT_TYPE( debEVT_GOTOINMEMORYVIEW, wxNewEventType() )
DECLARE_LOCAL_EVENT_TYPE( debEVT_GOTOINDISASM, wxNewEventType() )
DECLARE_LOCAL_EVENT_TYPE( debEVT_RUNTOPOS, wxNewEventType() )
DECLARE_LOCAL_EVENT_TYPE( debEVT_MAPLOADED, wxNewEventType() )
DECLARE_LOCAL_EVENT_TYPE( debEVT_STEPOVER, wxNewEventType() )
DECLARE_LOCAL_EVENT_TYPE( debEVT_UPDATE, wxNewEventType() )
bool executeExpressionWindow(wxWindow* parent, DebugInterface* cpu, u64& dest);

View File

@ -0,0 +1,287 @@
#include "PrecompiledHeader.h"
#include "DisassemblyDialog.h"
#include "DebugTools/DebugInterface.h"
#include "DebugTools/DisassemblyManager.h"
#include "DebugTools/Breakpoints.h"
#include "BreakpointWindow.h"
BEGIN_EVENT_TABLE(DisassemblyDialog, wxFrame)
EVT_COMMAND( wxID_ANY, debEVT_SETSTATUSBARTEXT, DisassemblyDialog::onDebuggerEvent )
EVT_COMMAND( wxID_ANY, debEVT_UPDATELAYOUT, DisassemblyDialog::onDebuggerEvent )
EVT_COMMAND( wxID_ANY, debEVT_GOTOINMEMORYVIEW, DisassemblyDialog::onDebuggerEvent )
EVT_COMMAND( wxID_ANY, debEVT_RUNTOPOS, DisassemblyDialog::onDebuggerEvent )
EVT_COMMAND( wxID_ANY, debEVT_GOTOINDISASM, DisassemblyDialog::onDebuggerEvent )
EVT_COMMAND( wxID_ANY, debEVT_STEPOVER, DisassemblyDialog::onDebuggerEvent )
EVT_COMMAND( wxID_ANY, debEVT_UPDATE, DisassemblyDialog::onDebuggerEvent )
END_EVENT_TABLE()
CpuTabPage::CpuTabPage(wxWindow* parent, DebugInterface* _cpu)
: wxPanel(parent), cpu(_cpu)
{
wxBoxSizer* mainSizer = new wxBoxSizer(wxVERTICAL);
SetSizer(mainSizer);
bottomTabs = new wxNotebook(this,wxID_ANY);
disassembly = new CtrlDisassemblyView(this,cpu);
registerList = new CtrlRegisterList(this,cpu);
memory = new CtrlMemView(bottomTabs,cpu);
// create register list and disassembly section
wxBoxSizer* middleSizer = new wxBoxSizer(wxHORIZONTAL);
wxBoxSizer* registerSizer = new wxBoxSizer(wxVERTICAL);
registerSizer->Add(registerList,1);
middleSizer->Add(registerSizer,0,wxEXPAND|wxRIGHT,2);
middleSizer->Add(disassembly,2,wxEXPAND);
mainSizer->Add(middleSizer,3,wxEXPAND|wxBOTTOM,3);
// create bottom section
bottomTabs->AddPage(memory,L"Memory");
mainSizer->Add(bottomTabs,1,wxEXPAND);
mainSizer->Layout();
}
DisassemblyDialog::DisassemblyDialog(wxWindow* parent):
wxFrame( parent, wxID_ANY, L"Debugger", wxDefaultPosition,wxDefaultSize,wxRESIZE_BORDER|wxCLOSE_BOX|wxCAPTION|wxSYSTEM_MENU ),
currentCpu(NULL)
{
topSizer = new wxBoxSizer( wxVERTICAL );
wxPanel *panel = new wxPanel(this, wxID_ANY,
wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL, _("panel"));
panel->SetSizer(topSizer);
// create top row
wxBoxSizer* topRowSizer = new wxBoxSizer(wxHORIZONTAL);
breakRunButton = new wxButton(panel, wxID_ANY, L"Run");
Connect(breakRunButton->GetId(), wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(DisassemblyDialog::onBreakRunClicked));
topRowSizer->Add(breakRunButton,0,wxRIGHT,8);
stepIntoButton = new wxButton( panel, wxID_ANY, L"Step Into" );
stepIntoButton->Enable(false);
topRowSizer->Add(stepIntoButton,0,wxBOTTOM,2);
stepOverButton = new wxButton( panel, wxID_ANY, L"Step Over" );
stepOverButton->Enable(false);
Connect( stepOverButton->GetId(), wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DisassemblyDialog::onStepOverClicked ) );
topRowSizer->Add(stepOverButton);
stepOutButton = new wxButton( panel, wxID_ANY, L"Step Out" );
stepOutButton->Enable(false);
topRowSizer->Add(stepOutButton,0,wxRIGHT,8);
breakpointButton = new wxButton( panel, wxID_ANY, L"Breakpoint" );
Connect( breakpointButton->GetId(), wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DisassemblyDialog::onBreakpointClick ) );
topRowSizer->Add(breakpointButton);
topSizer->Add(topRowSizer,0,wxLEFT|wxRIGHT|wxTOP,3);
// create middle part of the window
wxNotebook* middleBook = new wxNotebook(panel,wxID_ANY);
middleBook->SetBackgroundColour(wxColour(0xFFF0F0F0));
eeTab = new CpuTabPage(middleBook,&r5900Debug);
iopTab = new CpuTabPage(middleBook,&r3000Debug);
middleBook->AddPage(eeTab,L"R5900");
middleBook->AddPage(iopTab,L"R3000");
Connect(middleBook->GetId(),wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGED,wxCommandEventHandler( DisassemblyDialog::onPageChanging));
topSizer->Add(middleBook,3,wxEXPAND|wxLEFT|wxRIGHT|wxBOTTOM,3);
currentCpu = eeTab;
CreateStatusBar(1);
SetMinSize(wxSize(1000,600));
panel->GetSizer()->Fit(this);
setDebugMode(true);
}
void DisassemblyDialog::onBreakRunClicked(wxCommandEvent& evt)
{
if (r5900Debug.isCpuPaused())
{
if (CBreakPoints::IsAddressBreakPoint(r5900Debug.getPC()))
CBreakPoints::SetSkipFirst(r5900Debug.getPC());
r5900Debug.resumeCpu();
} else
r5900Debug.pauseCpu();
}
void DisassemblyDialog::onStepOverClicked(wxCommandEvent& evt)
{
stepOver();
}
void DisassemblyDialog::onPageChanging(wxCommandEvent& evt)
{
wxNotebook* notebook = (wxNotebook*)wxWindow::FindWindowById(evt.GetId());
wxWindow* currentPage = notebook->GetCurrentPage();
if (currentPage == eeTab)
currentCpu = eeTab;
else if (currentPage == iopTab)
currentCpu = iopTab;
else
currentCpu = NULL;
if (currentCpu != NULL)
{
currentCpu->getDisassembly()->SetFocus();
currentCpu->Refresh();
}
}
void DisassemblyDialog::stepOver()
{
if (!r5900Debug.isAlive() || !r5900Debug.isCpuPaused() || currentCpu == NULL)
return;
// todo: breakpoints for iop
if (currentCpu != eeTab)
return;
CtrlDisassemblyView* disassembly = currentCpu->getDisassembly();
// If the current PC is on a breakpoint, the user doesn't want to do nothing.
CBreakPoints::SetSkipFirst(r5900Debug.getPC());
u32 currentPc = r5900Debug.getPC();
MIPSAnalyst::MipsOpcodeInfo info = MIPSAnalyst::GetOpcodeInfo(&r5900Debug,r5900Debug.getPC());
u32 breakpointAddress = currentPc+disassembly->getInstructionSizeAt(currentPc);
if (info.isBranch)
{
if (info.isConditional == false)
{
if (info.isLinkedBranch) // jal, jalr
{
// it's a function call with a delay slot - skip that too
breakpointAddress += 4;
} else { // j, ...
// in case of absolute branches, set the breakpoint at the branch target
breakpointAddress = info.branchTarget;
}
} else { // beq, ...
if (info.conditionMet)
{
breakpointAddress = info.branchTarget;
} else {
breakpointAddress = currentPc+2*4;
disassembly->scrollStepping(breakpointAddress);
}
}
} else {
disassembly->scrollStepping(breakpointAddress);
}
CBreakPoints::AddBreakPoint(breakpointAddress,true);
r5900Debug.resumeCpu();
}
void DisassemblyDialog::onBreakpointClick(wxCommandEvent& evt)
{
if (currentCpu == NULL)
return;
BreakpointWindow bpw(this,currentCpu->getCpu());
if (bpw.ShowModal() == wxID_OK)
{
bpw.addBreakpoint();
update();
}
}
void DisassemblyDialog::onDebuggerEvent(wxCommandEvent& evt)
{
wxEventType type = evt.GetEventType();
if (type == debEVT_SETSTATUSBARTEXT)
{
GetStatusBar()->SetLabel(evt.GetString());
} else if (type == debEVT_UPDATELAYOUT)
{
if (currentCpu != NULL)
currentCpu->GetSizer()->Layout();
topSizer->Layout();
update();
} else if (type == debEVT_GOTOINMEMORYVIEW)
{
if (currentCpu != NULL)
currentCpu->getMemoryView()->gotoAddress(evt.GetInt());
} else if (type == debEVT_RUNTOPOS)
{
// todo: breakpoints for iop
if (currentCpu != eeTab)
return;
CBreakPoints::AddBreakPoint(evt.GetInt(),true);
currentCpu->getCpu()->resumeCpu();
} else if (type == debEVT_GOTOINDISASM)
{
if (currentCpu != NULL)
{
currentCpu->getDisassembly()->gotoAddress(r5900Debug.getPC());
currentCpu->getDisassembly()->SetFocus();
update();
}
} else if (type == debEVT_STEPOVER)
{
if (currentCpu != NULL)
stepOver();
} else if (type == debEVT_UPDATE)
{
update();
}
}
void DisassemblyDialog::update()
{
if (currentCpu != NULL)
{
stepOverButton->Enable(true);
breakpointButton->Enable(true);
currentCpu->Refresh();
} else {
stepOverButton->Enable(false);
breakpointButton->Enable(false);
}
}
void DisassemblyDialog::reset()
{
eeTab->getDisassembly()->clearFunctions();
iopTab->getDisassembly()->clearFunctions();
};
void DisassemblyDialog::setDebugMode(bool debugMode)
{
bool running = r5900Debug.isAlive();
eeTab->Enable(running);
iopTab->Enable(running);
if (running)
{
if (debugMode)
{
CBreakPoints::ClearTemporaryBreakPoints();
breakRunButton->SetLabel(L"Run");
stepOverButton->Enable(true);
eeTab->getDisassembly()->gotoPc();
iopTab->getDisassembly()->gotoPc();
if (currentCpu != NULL)
currentCpu->getDisassembly()->SetFocus();
} else {
breakRunButton->SetLabel(L"Break");
stepIntoButton->Enable(false);
stepOverButton->Enable(false);
stepOutButton->Enable(false);
}
}
update();
}

View File

@ -0,0 +1,61 @@
#pragma once
#include <wx/wx.h>
#include <wx/notebook.h>
#include "App.h"
#include "CtrlDisassemblyView.h"
#include "CtrlRegisterList.h"
#include "CtrlMemView.h"
#include "DebugEvents.h"
class CpuTabPage: public wxPanel
{
public:
CpuTabPage(wxWindow* parent, DebugInterface* _cpu);
DebugInterface* getCpu() { return cpu; };
CtrlDisassemblyView* getDisassembly() { return disassembly; };
CtrlRegisterList* getRegisterList() { return registerList; };
CtrlMemView* getMemoryView() { return memory; };
wxNotebook* getBottomTabs() { return bottomTabs; };
private:
DebugInterface* cpu;
CtrlDisassemblyView* disassembly;
CtrlRegisterList* registerList;
CtrlMemView* memory;
wxNotebook* bottomTabs;
};
class DisassemblyDialog : public wxFrame
{
public:
DisassemblyDialog( wxWindow* parent=NULL );
virtual ~DisassemblyDialog() throw() {}
static wxString GetNameStatic() { return L"DisassemblyDialog"; }
wxString GetDialogName() const { return GetNameStatic(); }
void update();
void reset();
void setDebugMode(bool debugMode);
DECLARE_EVENT_TABLE()
protected:
void onBreakRunClicked(wxCommandEvent& evt);
void onStepOverClicked(wxCommandEvent& evt);
void onDebuggerEvent(wxCommandEvent& evt);
void onPageChanging(wxCommandEvent& evt);
void onBreakpointClick(wxCommandEvent& evt);
void stepOver();
private:
CpuTabPage* eeTab;
CpuTabPage* iopTab;
CpuTabPage* currentCpu;
wxBoxSizer* topSizer;
wxStatusBar* statusBar;
wxButton* breakRunButton;
wxButton* stepIntoButton;
wxButton* stepOverButton;
wxButton* stepOutButton;
wxButton* breakpointButton;
};

View File

@ -508,7 +508,7 @@ MainEmuFrame::MainEmuFrame(wxWindow* parent, const wxString& title)
m_menuMisc.Append( MenuId_ChangeLang, L"Change Language" ); // Always in English
#ifdef PCSX2_DEVBUILD
//m_menuDebug.Append(MenuId_Debug_Open, _("Open Debug Window..."), wxEmptyString);
m_menuDebug.Append(MenuId_Debug_Open, _("Open Debug Window..."), wxEmptyString);
//m_menuDebug.Append(MenuId_Debug_MemoryDump, _("Memory Dump..."), wxEmptyString);
m_menuDebug.Append(MenuId_Debug_Logging, _("Logging..."), wxEmptyString);
#endif

View File

@ -24,6 +24,7 @@
#include "Dialogs/ModalPopups.h"
#include "Dialogs/ConfigurationDialog.h"
#include "Dialogs/LogOptionsDialog.h"
#include "Debugger/DisassemblyDialog.h"
#include "Utilities/IniInterface.h"
@ -554,6 +555,9 @@ void MainEmuFrame::Menu_ConfigPlugin_Click(wxCommandEvent &event)
void MainEmuFrame::Menu_Debug_Open_Click(wxCommandEvent &event)
{
DisassemblyDialog* dlg = wxGetApp().GetDisassemblyPtr();
if (dlg)
dlg->Show();
}
void MainEmuFrame::Menu_Debug_MemoryDump_Click(wxCommandEvent &event)

View File

@ -160,6 +160,24 @@
<Outputs Condition="'$(Configuration)|$(Platform)'=='Devel|Win32'">%(RootDir)%(Directory)\%(Filename).h</Outputs>
<Outputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">%(RootDir)%(Directory)\%(Filename).h</Outputs>
</CustomBuild>
<CustomBuild Include="..\..\gui\Resources\Breakpoint_Active.png">
<FileType>Document</FileType>
<Command Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">cmd.exe /c "%(RootDir)%(Directory)\bin2cpp.cmd" %(Filename)%(Extension)</Command>
<Command Condition="'$(Configuration)|$(Platform)'=='Devel|Win32'">cmd.exe /c "%(RootDir)%(Directory)\bin2cpp.cmd" %(Filename)%(Extension)</Command>
<Command Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">cmd.exe /c "%(RootDir)%(Directory)\bin2cpp.cmd" %(Filename)%(Extension)</Command>
<Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">%(RootDir)%(Directory)\%(Filename).h</Outputs>
<Outputs Condition="'$(Configuration)|$(Platform)'=='Devel|Win32'">%(RootDir)%(Directory)\%(Filename).h</Outputs>
<Outputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">%(RootDir)%(Directory)\%(Filename).h</Outputs>
</CustomBuild>
<CustomBuild Include="..\..\gui\Resources\Breakpoint_Inactive.png">
<FileType>Document</FileType>
<Command Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">cmd.exe /c "%(RootDir)%(Directory)\bin2cpp.cmd" %(Filename)%(Extension)</Command>
<Command Condition="'$(Configuration)|$(Platform)'=='Devel|Win32'">cmd.exe /c "%(RootDir)%(Directory)\bin2cpp.cmd" %(Filename)%(Extension)</Command>
<Command Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">cmd.exe /c "%(RootDir)%(Directory)\bin2cpp.cmd" %(Filename)%(Extension)</Command>
<Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">%(RootDir)%(Directory)\%(Filename).h</Outputs>
<Outputs Condition="'$(Configuration)|$(Platform)'=='Devel|Win32'">%(RootDir)%(Directory)\%(Filename).h</Outputs>
<Outputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">%(RootDir)%(Directory)\%(Filename).h</Outputs>
</CustomBuild>
<None Include="..\..\Utilities\folderdesc.txt" />
<None Include="..\..\Docs\License.txt" />
<None Include="..\..\x86\aVUzerorec.S" />
@ -402,11 +420,23 @@
<ItemGroup>
<ClCompile Include="..\..\CDVD\BlockdumpFileReader.cpp" />
<ClCompile Include="..\..\CDVD\OutputIsoFile.cpp" />
<ClCompile Include="..\..\DebugTools\Breakpoints.cpp" />
<ClCompile Include="..\..\DebugTools\DebugInterface.cpp" />
<ClCompile Include="..\..\DebugTools\DisassemblyManager.cpp" />
<ClCompile Include="..\..\DebugTools\ExpressionParser.cpp" />
<ClCompile Include="..\..\DebugTools\MIPSAnalyst.cpp" />
<ClCompile Include="..\..\DebugTools\SymbolMap.cpp" />
<ClCompile Include="..\..\GameDatabase.cpp" />
<ClCompile Include="..\..\Gif_Logger.cpp" />
<ClCompile Include="..\..\Gif_Unit.cpp" />
<ClCompile Include="..\..\gui\AppGameDatabase.cpp" />
<ClCompile Include="..\..\gui\AppUserMode.cpp" />
<ClCompile Include="..\..\gui\Debugger\BreakpointWindow.cpp" />
<ClCompile Include="..\..\gui\Debugger\CtrlDisassemblyView.cpp" />
<ClCompile Include="..\..\gui\Debugger\CtrlMemView.cpp" />
<ClCompile Include="..\..\gui\Debugger\CtrlRegisterList.cpp" />
<ClCompile Include="..\..\gui\Debugger\DebugEvents.cpp" />
<ClCompile Include="..\..\gui\Debugger\DisassemblyDialog.cpp" />
<ClCompile Include="..\..\gui\Dialogs\GameDatabaseDialog.cpp" />
<ClCompile Include="..\..\gui\Dialogs\McdConfigDialog.cpp" />
<ClCompile Include="..\..\gui\Panels\GameDatabasePanel.cpp" />
@ -674,9 +704,21 @@
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\..\AsyncFileReader.h" />
<ClInclude Include="..\..\DebugTools\Breakpoints.h" />
<ClInclude Include="..\..\DebugTools\DebugInterface.h" />
<ClInclude Include="..\..\DebugTools\DisassemblyManager.h" />
<ClInclude Include="..\..\DebugTools\ExpressionParser.h" />
<ClInclude Include="..\..\DebugTools\MIPSAnalyst.h" />
<ClInclude Include="..\..\DebugTools\SymbolMap.h" />
<ClInclude Include="..\..\GameDatabase.h" />
<ClInclude Include="..\..\Gif_Unit.h" />
<ClInclude Include="..\..\gui\AppGameDatabase.h" />
<ClInclude Include="..\..\gui\Debugger\BreakpointWindow.h" />
<ClInclude Include="..\..\gui\Debugger\CtrlDisassemblyView.h" />
<ClInclude Include="..\..\gui\Debugger\CtrlMemView.h" />
<ClInclude Include="..\..\gui\Debugger\CtrlRegisterList.h" />
<ClInclude Include="..\..\gui\Debugger\DebugEvents.h" />
<ClInclude Include="..\..\gui\Debugger\DisassemblyDialog.h" />
<ClInclude Include="..\..\gui\Panels\MemoryCardPanels.h" />
<ClInclude Include="..\..\IPU\IPUdma.h" />
<ClInclude Include="..\..\Patch.h" />

View File

@ -148,6 +148,9 @@
<Filter Include="AppHost\Cheats">
<UniqueIdentifier>{b9da6fbf-4fd9-4cfb-89f7-34ac0f933ce9}</UniqueIdentifier>
</Filter>
<Filter Include="AppHost\Debugger">
<UniqueIdentifier>{02398f88-aadb-4183-be7e-68f0cacdf620}</UniqueIdentifier>
</Filter>
</ItemGroup>
<ItemGroup>
<None Include="..\..\Utilities\folderdesc.txt">
@ -802,6 +805,42 @@
<ClCompile Include="..\..\CDVD\BlockdumpFileReader.cpp">
<Filter>System\ISO</Filter>
</ClCompile>
<ClCompile Include="..\..\gui\Debugger\CtrlDisassemblyView.cpp">
<Filter>AppHost\Debugger</Filter>
</ClCompile>
<ClCompile Include="..\..\gui\Debugger\DisassemblyDialog.cpp">
<Filter>AppHost\Debugger</Filter>
</ClCompile>
<ClCompile Include="..\..\DebugTools\DebugInterface.cpp">
<Filter>System\Ps2\Debug</Filter>
</ClCompile>
<ClCompile Include="..\..\DebugTools\DisassemblyManager.cpp">
<Filter>System\Ps2\Debug</Filter>
</ClCompile>
<ClCompile Include="..\..\DebugTools\MIPSAnalyst.cpp">
<Filter>System\Ps2\Debug</Filter>
</ClCompile>
<ClCompile Include="..\..\DebugTools\SymbolMap.cpp">
<Filter>System\Ps2\Debug</Filter>
</ClCompile>
<ClCompile Include="..\..\DebugTools\Breakpoints.cpp">
<Filter>System\Ps2\Debug</Filter>
</ClCompile>
<ClCompile Include="..\..\gui\Debugger\DebugEvents.cpp">
<Filter>AppHost\Debugger</Filter>
</ClCompile>
<ClCompile Include="..\..\gui\Debugger\CtrlRegisterList.cpp">
<Filter>AppHost\Debugger</Filter>
</ClCompile>
<ClCompile Include="..\..\gui\Debugger\CtrlMemView.cpp">
<Filter>AppHost\Debugger</Filter>
</ClCompile>
<ClCompile Include="..\..\DebugTools\ExpressionParser.cpp">
<Filter>System\Ps2\Debug</Filter>
</ClCompile>
<ClCompile Include="..\..\gui\Debugger\BreakpointWindow.cpp">
<Filter>AppHost\Debugger</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\..\Patch.h">
@ -1171,6 +1210,42 @@
<ClInclude Include="..\..\AsyncFileReader.h">
<Filter>System\ISO</Filter>
</ClInclude>
<ClInclude Include="..\..\gui\Debugger\CtrlDisassemblyView.h">
<Filter>AppHost\Debugger</Filter>
</ClInclude>
<ClInclude Include="..\..\gui\Debugger\DisassemblyDialog.h">
<Filter>AppHost\Debugger</Filter>
</ClInclude>
<ClInclude Include="..\..\DebugTools\DebugInterface.h">
<Filter>System\Ps2\Debug</Filter>
</ClInclude>
<ClInclude Include="..\..\DebugTools\DisassemblyManager.h">
<Filter>System\Ps2\Debug</Filter>
</ClInclude>
<ClInclude Include="..\..\DebugTools\MIPSAnalyst.h">
<Filter>System\Ps2\Debug</Filter>
</ClInclude>
<ClInclude Include="..\..\DebugTools\SymbolMap.h">
<Filter>System\Ps2\Debug</Filter>
</ClInclude>
<ClInclude Include="..\..\DebugTools\Breakpoints.h">
<Filter>System\Ps2\Debug</Filter>
</ClInclude>
<ClInclude Include="..\..\gui\Debugger\DebugEvents.h">
<Filter>AppHost\Debugger</Filter>
</ClInclude>
<ClInclude Include="..\..\gui\Debugger\CtrlRegisterList.h">
<Filter>AppHost\Debugger</Filter>
</ClInclude>
<ClInclude Include="..\..\gui\Debugger\CtrlMemView.h">
<Filter>AppHost\Debugger</Filter>
</ClInclude>
<ClInclude Include="..\..\DebugTools\ExpressionParser.h">
<Filter>System\Ps2\Debug</Filter>
</ClInclude>
<ClInclude Include="..\..\gui\Debugger\BreakpointWindow.h">
<Filter>AppHost\Debugger</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="..\..\..\3rdparty\wxWidgets\include\wx\msw\wx.rc">
@ -1246,5 +1321,11 @@
<CustomBuild Include="..\..\gui\Resources\ConfigIcon_Appearance.png">
<Filter>AppHost\Resources</Filter>
</CustomBuild>
<CustomBuild Include="..\..\gui\Resources\Breakpoint_Inactive.png">
<Filter>AppHost\Resources</Filter>
</CustomBuild>
<CustomBuild Include="..\..\gui\Resources\Breakpoint_Active.png">
<Filter>AppHost\Resources</Filter>
</CustomBuild>
</ItemGroup>
</Project>

View File

@ -407,11 +407,23 @@
<ItemGroup>
<ClCompile Include="..\..\CDVD\BlockdumpFileReader.cpp" />
<ClCompile Include="..\..\CDVD\OutputIsoFile.cpp" />
<ClCompile Include="..\..\DebugTools\Breakpoints.cpp" />
<ClCompile Include="..\..\DebugTools\DebugInterface.cpp" />
<ClCompile Include="..\..\DebugTools\DisassemblyManager.cpp" />
<ClCompile Include="..\..\DebugTools\ExpressionParser.cpp" />
<ClCompile Include="..\..\DebugTools\MIPSAnalyst.cpp" />
<ClCompile Include="..\..\DebugTools\SymbolMap.cpp" />
<ClCompile Include="..\..\GameDatabase.cpp" />
<ClCompile Include="..\..\Gif_Logger.cpp" />
<ClCompile Include="..\..\Gif_Unit.cpp" />
<ClCompile Include="..\..\gui\AppGameDatabase.cpp" />
<ClCompile Include="..\..\gui\AppUserMode.cpp" />
<ClCompile Include="..\..\gui\Debugger\BreakpointWindow.cpp" />
<ClCompile Include="..\..\gui\Debugger\CtrlDisassemblyView.cpp" />
<ClCompile Include="..\..\gui\Debugger\CtrlMemView.cpp" />
<ClCompile Include="..\..\gui\Debugger\CtrlRegisterList.cpp" />
<ClCompile Include="..\..\gui\Debugger\DebugEvents.cpp" />
<ClCompile Include="..\..\gui\Debugger\DisassemblyDialog.cpp" />
<ClCompile Include="..\..\gui\Dialogs\GameDatabaseDialog.cpp" />
<ClCompile Include="..\..\gui\Dialogs\McdConfigDialog.cpp" />
<ClCompile Include="..\..\gui\Panels\GameDatabasePanel.cpp" />
@ -679,9 +691,21 @@
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\..\AsyncFileReader.h" />
<ClInclude Include="..\..\DebugTools\Breakpoints.h" />
<ClInclude Include="..\..\DebugTools\DebugInterface.h" />
<ClInclude Include="..\..\DebugTools\DisassemblyManager.h" />
<ClInclude Include="..\..\DebugTools\ExpressionParser.h" />
<ClInclude Include="..\..\DebugTools\MIPSAnalyst.h" />
<ClInclude Include="..\..\DebugTools\SymbolMap.h" />
<ClInclude Include="..\..\GameDatabase.h" />
<ClInclude Include="..\..\Gif_Unit.h" />
<ClInclude Include="..\..\gui\AppGameDatabase.h" />
<ClInclude Include="..\..\gui\Debugger\BreakpointWindow.h" />
<ClInclude Include="..\..\gui\Debugger\CtrlDisassemblyView.h" />
<ClInclude Include="..\..\gui\Debugger\CtrlMemView.h" />
<ClInclude Include="..\..\gui\Debugger\CtrlRegisterList.h" />
<ClInclude Include="..\..\gui\Debugger\DebugEvents.h" />
<ClInclude Include="..\..\gui\Debugger\DisassemblyDialog.h" />
<ClInclude Include="..\..\gui\Panels\MemoryCardPanels.h" />
<ClInclude Include="..\..\IPU\IPUdma.h" />
<ClInclude Include="..\..\Patch.h" />
@ -887,6 +911,24 @@
<ReferenceOutputAssembly>false</ReferenceOutputAssembly>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<CustomBuild Include="..\..\gui\Resources\Breakpoint_Active.png">
<Command Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">cmd.exe /c "%(RootDir)%(Directory)\bin2cpp.cmd" %(Filename)%(Extension)</Command>
<Command Condition="'$(Configuration)|$(Platform)'=='Devel|Win32'">cmd.exe /c "%(RootDir)%(Directory)\bin2cpp.cmd" %(Filename)%(Extension)</Command>
<Command Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">cmd.exe /c "%(RootDir)%(Directory)\bin2cpp.cmd" %(Filename)%(Extension)</Command>
<Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">%(RootDir)%(Directory)\%(Filename).h</Outputs>
<Outputs Condition="'$(Configuration)|$(Platform)'=='Devel|Win32'">%(RootDir)%(Directory)\%(Filename).h</Outputs>
<Outputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">%(RootDir)%(Directory)\%(Filename).h</Outputs>
</CustomBuild>
<CustomBuild Include="..\..\gui\Resources\Breakpoint_Inactive.png">
<Command Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">cmd.exe /c "%(RootDir)%(Directory)\bin2cpp.cmd" %(Filename)%(Extension)</Command>
<Command Condition="'$(Configuration)|$(Platform)'=='Devel|Win32'">cmd.exe /c "%(RootDir)%(Directory)\bin2cpp.cmd" %(Filename)%(Extension)</Command>
<Command Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">cmd.exe /c "%(RootDir)%(Directory)\bin2cpp.cmd" %(Filename)%(Extension)</Command>
<Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">%(RootDir)%(Directory)\%(Filename).h</Outputs>
<Outputs Condition="'$(Configuration)|$(Platform)'=='Devel|Win32'">%(RootDir)%(Directory)\%(Filename).h</Outputs>
<Outputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">%(RootDir)%(Directory)\%(Filename).h</Outputs>
</CustomBuild>
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
<Import Project="$(VCTargetsPath)\BuildCustomizations\masm.targets" />

View File

@ -148,6 +148,9 @@
<Filter Include="AppHost\Cheats">
<UniqueIdentifier>{b9da6fbf-4fd9-4cfb-89f7-34ac0f933ce9}</UniqueIdentifier>
</Filter>
<Filter Include="AppHost\Debugger">
<UniqueIdentifier>{b49e5139-daa9-411b-995e-a53d98c583ba}</UniqueIdentifier>
</Filter>
</ItemGroup>
<ItemGroup>
<None Include="..\..\Utilities\folderdesc.txt">
@ -802,6 +805,42 @@
<ClCompile Include="..\..\CDVD\BlockdumpFileReader.cpp">
<Filter>System\ISO</Filter>
</ClCompile>
<ClCompile Include="..\..\gui\Debugger\BreakpointWindow.cpp">
<Filter>AppHost\Debugger</Filter>
</ClCompile>
<ClCompile Include="..\..\gui\Debugger\CtrlDisassemblyView.cpp">
<Filter>AppHost\Debugger</Filter>
</ClCompile>
<ClCompile Include="..\..\gui\Debugger\CtrlMemView.cpp">
<Filter>AppHost\Debugger</Filter>
</ClCompile>
<ClCompile Include="..\..\gui\Debugger\CtrlRegisterList.cpp">
<Filter>AppHost\Debugger</Filter>
</ClCompile>
<ClCompile Include="..\..\gui\Debugger\DebugEvents.cpp">
<Filter>AppHost\Debugger</Filter>
</ClCompile>
<ClCompile Include="..\..\gui\Debugger\DisassemblyDialog.cpp">
<Filter>AppHost\Debugger</Filter>
</ClCompile>
<ClCompile Include="..\..\DebugTools\Breakpoints.cpp">
<Filter>System\Ps2\Debug</Filter>
</ClCompile>
<ClCompile Include="..\..\DebugTools\DebugInterface.cpp">
<Filter>System\Ps2\Debug</Filter>
</ClCompile>
<ClCompile Include="..\..\DebugTools\DisassemblyManager.cpp">
<Filter>System\Ps2\Debug</Filter>
</ClCompile>
<ClCompile Include="..\..\DebugTools\ExpressionParser.cpp">
<Filter>System\Ps2\Debug</Filter>
</ClCompile>
<ClCompile Include="..\..\DebugTools\MIPSAnalyst.cpp">
<Filter>System\Ps2\Debug</Filter>
</ClCompile>
<ClCompile Include="..\..\DebugTools\SymbolMap.cpp">
<Filter>System\Ps2\Debug</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\..\Patch.h">
@ -1171,6 +1210,42 @@
<ClInclude Include="..\..\AsyncFileReader.h">
<Filter>System\ISO</Filter>
</ClInclude>
<ClInclude Include="..\..\gui\Debugger\BreakpointWindow.h">
<Filter>AppHost\Debugger</Filter>
</ClInclude>
<ClInclude Include="..\..\gui\Debugger\CtrlDisassemblyView.h">
<Filter>AppHost\Debugger</Filter>
</ClInclude>
<ClInclude Include="..\..\gui\Debugger\CtrlMemView.h">
<Filter>AppHost\Debugger</Filter>
</ClInclude>
<ClInclude Include="..\..\gui\Debugger\CtrlRegisterList.h">
<Filter>AppHost\Debugger</Filter>
</ClInclude>
<ClInclude Include="..\..\gui\Debugger\DebugEvents.h">
<Filter>AppHost\Debugger</Filter>
</ClInclude>
<ClInclude Include="..\..\gui\Debugger\DisassemblyDialog.h">
<Filter>AppHost\Debugger</Filter>
</ClInclude>
<ClInclude Include="..\..\DebugTools\Breakpoints.h">
<Filter>System\Ps2\Debug</Filter>
</ClInclude>
<ClInclude Include="..\..\DebugTools\DebugInterface.h">
<Filter>System\Ps2\Debug</Filter>
</ClInclude>
<ClInclude Include="..\..\DebugTools\DisassemblyManager.h">
<Filter>System\Ps2\Debug</Filter>
</ClInclude>
<ClInclude Include="..\..\DebugTools\ExpressionParser.h">
<Filter>System\Ps2\Debug</Filter>
</ClInclude>
<ClInclude Include="..\..\DebugTools\MIPSAnalyst.h">
<Filter>System\Ps2\Debug</Filter>
</ClInclude>
<ClInclude Include="..\..\DebugTools\SymbolMap.h">
<Filter>System\Ps2\Debug</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="..\..\..\3rdparty\wxWidgets\include\wx\msw\wx.rc">
@ -1246,5 +1321,11 @@
<CustomBuild Include="..\..\gui\Resources\ConfigIcon_Appearance.png">
<Filter>AppHost\Resources</Filter>
</CustomBuild>
<CustomBuild Include="..\..\gui\Resources\Breakpoint_Inactive.png">
<Filter>AppHost\Resources</Filter>
</CustomBuild>
<CustomBuild Include="..\..\gui\Resources\Breakpoint_Active.png">
<Filter>AppHost\Resources</Filter>
</CustomBuild>
</ItemGroup>
</Project>

View File

@ -407,11 +407,23 @@
<ItemGroup>
<ClCompile Include="..\..\CDVD\BlockdumpFileReader.cpp" />
<ClCompile Include="..\..\CDVD\OutputIsoFile.cpp" />
<ClCompile Include="..\..\DebugTools\Breakpoints.cpp" />
<ClCompile Include="..\..\DebugTools\DebugInterface.cpp" />
<ClCompile Include="..\..\DebugTools\DisassemblyManager.cpp" />
<ClCompile Include="..\..\DebugTools\ExpressionParser.cpp" />
<ClCompile Include="..\..\DebugTools\MIPSAnalyst.cpp" />
<ClCompile Include="..\..\DebugTools\SymbolMap.cpp" />
<ClCompile Include="..\..\GameDatabase.cpp" />
<ClCompile Include="..\..\Gif_Logger.cpp" />
<ClCompile Include="..\..\Gif_Unit.cpp" />
<ClCompile Include="..\..\gui\AppGameDatabase.cpp" />
<ClCompile Include="..\..\gui\AppUserMode.cpp" />
<ClCompile Include="..\..\gui\Debugger\BreakpointWindow.cpp" />
<ClCompile Include="..\..\gui\Debugger\CtrlDisassemblyView.cpp" />
<ClCompile Include="..\..\gui\Debugger\CtrlMemView.cpp" />
<ClCompile Include="..\..\gui\Debugger\CtrlRegisterList.cpp" />
<ClCompile Include="..\..\gui\Debugger\DebugEvents.cpp" />
<ClCompile Include="..\..\gui\Debugger\DisassemblyDialog.cpp" />
<ClCompile Include="..\..\gui\Dialogs\GameDatabaseDialog.cpp" />
<ClCompile Include="..\..\gui\Dialogs\McdConfigDialog.cpp" />
<ClCompile Include="..\..\gui\Panels\GameDatabasePanel.cpp" />
@ -679,9 +691,21 @@
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\..\AsyncFileReader.h" />
<ClInclude Include="..\..\DebugTools\Breakpoints.h" />
<ClInclude Include="..\..\DebugTools\DebugInterface.h" />
<ClInclude Include="..\..\DebugTools\DisassemblyManager.h" />
<ClInclude Include="..\..\DebugTools\ExpressionParser.h" />
<ClInclude Include="..\..\DebugTools\MIPSAnalyst.h" />
<ClInclude Include="..\..\DebugTools\SymbolMap.h" />
<ClInclude Include="..\..\GameDatabase.h" />
<ClInclude Include="..\..\Gif_Unit.h" />
<ClInclude Include="..\..\gui\AppGameDatabase.h" />
<ClInclude Include="..\..\gui\Debugger\BreakpointWindow.h" />
<ClInclude Include="..\..\gui\Debugger\CtrlDisassemblyView.h" />
<ClInclude Include="..\..\gui\Debugger\CtrlMemView.h" />
<ClInclude Include="..\..\gui\Debugger\CtrlRegisterList.h" />
<ClInclude Include="..\..\gui\Debugger\DebugEvents.h" />
<ClInclude Include="..\..\gui\Debugger\DisassemblyDialog.h" />
<ClInclude Include="..\..\gui\Panels\MemoryCardPanels.h" />
<ClInclude Include="..\..\IPU\IPUdma.h" />
<ClInclude Include="..\..\Patch.h" />
@ -887,6 +911,24 @@
<ReferenceOutputAssembly>false</ReferenceOutputAssembly>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<CustomBuild Include="..\..\gui\Resources\Breakpoint_Active.png">
<Command Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">cmd.exe /c "%(RootDir)%(Directory)\bin2cpp.cmd" %(Filename)%(Extension)</Command>
<Command Condition="'$(Configuration)|$(Platform)'=='Devel|Win32'">cmd.exe /c "%(RootDir)%(Directory)\bin2cpp.cmd" %(Filename)%(Extension)</Command>
<Command Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">cmd.exe /c "%(RootDir)%(Directory)\bin2cpp.cmd" %(Filename)%(Extension)</Command>
<Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">%(RootDir)%(Directory)\%(Filename).h</Outputs>
<Outputs Condition="'$(Configuration)|$(Platform)'=='Devel|Win32'">%(RootDir)%(Directory)\%(Filename).h</Outputs>
<Outputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">%(RootDir)%(Directory)\%(Filename).h</Outputs>
</CustomBuild>
<CustomBuild Include="..\..\gui\Resources\Breakpoint_Inactive.png">
<Command Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">cmd.exe /c "%(RootDir)%(Directory)\bin2cpp.cmd" %(Filename)%(Extension)</Command>
<Command Condition="'$(Configuration)|$(Platform)'=='Devel|Win32'">cmd.exe /c "%(RootDir)%(Directory)\bin2cpp.cmd" %(Filename)%(Extension)</Command>
<Command Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">cmd.exe /c "%(RootDir)%(Directory)\bin2cpp.cmd" %(Filename)%(Extension)</Command>
<Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">%(RootDir)%(Directory)\%(Filename).h</Outputs>
<Outputs Condition="'$(Configuration)|$(Platform)'=='Devel|Win32'">%(RootDir)%(Directory)\%(Filename).h</Outputs>
<Outputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">%(RootDir)%(Directory)\%(Filename).h</Outputs>
</CustomBuild>
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
<Import Project="$(VCTargetsPath)\BuildCustomizations\masm.targets" />

View File

@ -148,6 +148,9 @@
<Filter Include="AppHost\Cheats">
<UniqueIdentifier>{b9da6fbf-4fd9-4cfb-89f7-34ac0f933ce9}</UniqueIdentifier>
</Filter>
<Filter Include="AppHost\Debugger">
<UniqueIdentifier>{7a0a1104-f9ee-4cd1-aaba-f8267eba1658}</UniqueIdentifier>
</Filter>
</ItemGroup>
<ItemGroup>
<None Include="..\..\Utilities\folderdesc.txt">
@ -802,6 +805,42 @@
<ClCompile Include="..\..\CDVD\BlockdumpFileReader.cpp">
<Filter>System\ISO</Filter>
</ClCompile>
<ClCompile Include="..\..\DebugTools\SymbolMap.cpp">
<Filter>System\Ps2\Debug</Filter>
</ClCompile>
<ClCompile Include="..\..\DebugTools\DebugInterface.cpp">
<Filter>System\Ps2\Debug</Filter>
</ClCompile>
<ClCompile Include="..\..\DebugTools\DisassemblyManager.cpp">
<Filter>System\Ps2\Debug</Filter>
</ClCompile>
<ClCompile Include="..\..\gui\Debugger\CtrlDisassemblyView.cpp">
<Filter>AppHost\Debugger</Filter>
</ClCompile>
<ClCompile Include="..\..\gui\Debugger\DisassemblyDialog.cpp">
<Filter>AppHost\Debugger</Filter>
</ClCompile>
<ClCompile Include="..\..\DebugTools\MIPSAnalyst.cpp">
<Filter>System\Ps2\Debug</Filter>
</ClCompile>
<ClCompile Include="..\..\DebugTools\Breakpoints.cpp">
<Filter>System\Ps2\Debug</Filter>
</ClCompile>
<ClCompile Include="..\..\gui\Debugger\DebugEvents.cpp">
<Filter>AppHost\Debugger</Filter>
</ClCompile>
<ClCompile Include="..\..\gui\Debugger\CtrlRegisterList.cpp">
<Filter>AppHost\Debugger</Filter>
</ClCompile>
<ClCompile Include="..\..\gui\Debugger\CtrlMemView.cpp">
<Filter>AppHost\Debugger</Filter>
</ClCompile>
<ClCompile Include="..\..\DebugTools\ExpressionParser.cpp">
<Filter>System\Ps2\Debug</Filter>
</ClCompile>
<ClCompile Include="..\..\gui\Debugger\BreakpointWindow.cpp">
<Filter>AppHost\Debugger</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\..\Patch.h">
@ -1171,6 +1210,42 @@
<ClInclude Include="..\..\AsyncFileReader.h">
<Filter>System\ISO</Filter>
</ClInclude>
<ClInclude Include="..\..\DebugTools\SymbolMap.h">
<Filter>System\Ps2\Debug</Filter>
</ClInclude>
<ClInclude Include="..\..\DebugTools\DebugInterface.h">
<Filter>System\Ps2\Debug</Filter>
</ClInclude>
<ClInclude Include="..\..\DebugTools\DisassemblyManager.h">
<Filter>System\Ps2\Debug</Filter>
</ClInclude>
<ClInclude Include="..\..\gui\Debugger\CtrlDisassemblyView.h">
<Filter>AppHost\Debugger</Filter>
</ClInclude>
<ClInclude Include="..\..\gui\Debugger\DisassemblyDialog.h">
<Filter>AppHost\Debugger</Filter>
</ClInclude>
<ClInclude Include="..\..\DebugTools\MIPSAnalyst.h">
<Filter>System\Ps2\Debug</Filter>
</ClInclude>
<ClInclude Include="..\..\DebugTools\Breakpoints.h">
<Filter>System\Ps2\Debug</Filter>
</ClInclude>
<ClInclude Include="..\..\gui\Debugger\DebugEvents.h">
<Filter>AppHost\Debugger</Filter>
</ClInclude>
<ClInclude Include="..\..\gui\Debugger\CtrlRegisterList.h">
<Filter>AppHost\Debugger</Filter>
</ClInclude>
<ClInclude Include="..\..\gui\Debugger\CtrlMemView.h">
<Filter>AppHost\Debugger</Filter>
</ClInclude>
<ClInclude Include="..\..\DebugTools\ExpressionParser.h">
<Filter>System\Ps2\Debug</Filter>
</ClInclude>
<ClInclude Include="..\..\gui\Debugger\BreakpointWindow.h">
<Filter>AppHost\Debugger</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="..\..\..\3rdparty\wxWidgets\include\wx\msw\wx.rc">
@ -1246,5 +1321,11 @@
<CustomBuild Include="..\..\gui\Resources\ConfigIcon_Appearance.png">
<Filter>AppHost\Resources</Filter>
</CustomBuild>
<CustomBuild Include="..\..\gui\Resources\Breakpoint_Inactive.png">
<Filter>AppHost\Resources</Filter>
</CustomBuild>
<CustomBuild Include="..\..\gui\Resources\Breakpoint_Active.png">
<Filter>AppHost\Resources</Filter>
</CustomBuild>
</ItemGroup>
</Project>

View File

@ -32,6 +32,8 @@
#include "CDVD/CDVD.h"
#include "Elfheader.h"
#include "../DebugTools/Breakpoints.h"
#if !PCSX2_SEH
# include <csetjmp>
#endif
@ -1254,11 +1256,36 @@ int cop2flags(u32 code)
}
#endif
void dynarecCheckBreakpoint()
{
u32 pc = cpuRegs.pc;
if (CBreakPoints::CheckSkipFirst(pc))
{
CBreakPoints::SetSkipFirst(0xFFFFFFFF);
return;
}
auto cond = CBreakPoints::GetBreakPointCondition(pc);
if (cond && !cond->Evaluate())
return;
GetCoreThread().PauseSelf();
recExitExecution();
}
void recompileNextInstruction(int delayslot)
{
static u8 s_bFlushReg = 1;
int i, count;
// add breakpoint
if (CBreakPoints::IsAddressBreakPoint(pc))
{
iFlushCall(FLUSH_EVERYTHING);
xCALL(&dynarecCheckBreakpoint);
}
s_pCode = (int *)PSM( pc );
pxAssert(s_pCode);
@ -1595,8 +1622,22 @@ static void __fastcall recRecompile( const u32 startpc )
s_nEndBlock = 0xffffffff;
s_branchTo = -1;
// compile breakpoints as individual blocks
if (CBreakPoints::IsAddressBreakPoint(i))
{
s_nEndBlock = i + 4;
goto StartRecomp;
}
while(1) {
BASEBLOCK* pblock = PC_GETBLOCK(i);
// stop before breakpoints
if (CBreakPoints::IsAddressBreakPoint(i))
{
s_nEndBlock = i;
break;
}
if(i != startpc) // Block size truncation checks.
{