mirror of
https://github.com/RetroDECK/Supermodel.git
synced 2024-11-27 16:15:40 +00:00
263 lines
6.9 KiB
C++
263 lines
6.9 KiB
C++
/**
|
|
** Supermodel
|
|
** A Sega Model 3 Arcade Emulator.
|
|
** Copyright 2011 Bart Trzynadlowski, Nik Henson
|
|
**
|
|
** This file is part of Supermodel.
|
|
**
|
|
** Supermodel is free software: you can redistribute it and/or modify it under
|
|
** the terms of the GNU General Public License as published by the Free
|
|
** Software Foundation, either version 3 of the License, or (at your option)
|
|
** any later version.
|
|
**
|
|
** Supermodel is distributed in the hope that it will be useful, but WITHOUT
|
|
** ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
** FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
|
** more details.
|
|
**
|
|
** You should have received a copy of the GNU General Public License along
|
|
** with Supermodel. If not, see <http://www.gnu.org/licenses/>.
|
|
**/
|
|
|
|
/*
|
|
* CodeAnalyser.h
|
|
*/
|
|
|
|
#ifdef SUPERMODEL_DEBUGGER
|
|
#ifndef INCLUDED_CODEANALYSER_H
|
|
#define INCLUDED_CODEANALYSER_H
|
|
|
|
#include <stdio.h>
|
|
#include <vector>
|
|
#include <map>
|
|
#include <set>
|
|
#include <algorithm>
|
|
|
|
#include "Types.h"
|
|
#include "Debugger.h"
|
|
#include "AddressTable.h"
|
|
|
|
#ifdef DEBUGGER_HASBLOCKFILE
|
|
#include "BlockFile.h"
|
|
#endif // DEBUGGER_HASBLOCKFILE
|
|
|
|
namespace Debugger
|
|
{
|
|
class CCPUDebug;
|
|
class CRegion;
|
|
class CLabel;
|
|
|
|
enum ELabelFlags
|
|
{
|
|
LFNone = 0,
|
|
LFEntryPoint = 1,
|
|
LFExcepHandler = 2,
|
|
LFInterHandler = 4,
|
|
LFJumpTarget = 8,
|
|
LFLoopPoint = 16,
|
|
LFSubroutine = 32,
|
|
LFUnseenCode = 64,
|
|
LFAll = (LFEntryPoint | LFExcepHandler | LFInterHandler | LFJumpTarget | LFSubroutine | LFLoopPoint | LFUnseenCode)
|
|
};
|
|
|
|
/*
|
|
* Class that represents an entry point into a program's code in memory, eg a CPU's reset address or exception handler's address etc.
|
|
*/
|
|
class CEntryPoint
|
|
{
|
|
private:
|
|
char autoLabelStr[255];
|
|
|
|
public:
|
|
UINT32 addr;
|
|
ELabelFlags autoFlag;
|
|
const char *autoLabel;
|
|
|
|
CEntryPoint(const CEntryPoint &other);
|
|
|
|
CEntryPoint(UINT32 eAddr, ELabelFlags eAutoFlag, const char *eAutoLabel);
|
|
|
|
CEntryPoint &operator=(const CEntryPoint &other);
|
|
|
|
bool operator==(const CEntryPoint &other);
|
|
|
|
bool operator!=(const CEntryPoint &other);
|
|
};
|
|
|
|
/*
|
|
* Class that represents an auto-generated label that resulted from code analysis, eg a known entry point or the destination of a subroutine call.
|
|
*/
|
|
class CAutoLabel : public CAddressRef
|
|
{
|
|
private:
|
|
static const char *s_defaultLabelFmts[];
|
|
|
|
const char *m_subLabels[7];
|
|
|
|
unsigned m_acquired;
|
|
|
|
const char *CreateDefaultSubLabel(ELabelFlags flag);
|
|
|
|
public:
|
|
static const unsigned numLabelFlags;
|
|
|
|
static ELabelFlags GetLabelFlag(int index);
|
|
|
|
static int GetFlagIndex(ELabelFlags flag);
|
|
|
|
static const char *GetFlagString(ELabelFlags flag);
|
|
|
|
ELabelFlags flags;
|
|
|
|
CAutoLabel(CCPUDebug *lCPU, UINT32 lAddr);
|
|
|
|
~CAutoLabel();
|
|
|
|
void Acquire();
|
|
|
|
void Release();
|
|
|
|
void AddFlag(ELabelFlags flag, const char *subLabel);
|
|
|
|
bool GetLabel(char *label, ELabelFlags flag = LFAll);
|
|
|
|
bool ContainsSubLabel(const char *subLabel);
|
|
};
|
|
|
|
class CCodeAnalyser;
|
|
|
|
/*
|
|
* Class that holds the results of having analysed the program code.
|
|
*/
|
|
class CCodeAnalysis
|
|
{
|
|
friend class CCodeAnalyser;
|
|
|
|
private:
|
|
std::vector<CEntryPoint> m_entryPoints;
|
|
std::vector<UINT32> m_unseenEntryAddrs;
|
|
std::vector<bool> m_seenIndices;
|
|
std::vector<bool> m_validIndices;
|
|
std::map<UINT32,CAutoLabel*> m_autoLabelsMap;
|
|
|
|
unsigned m_acquired;
|
|
|
|
CCodeAnalysis(CCodeAnalyser *aAnalyser);
|
|
|
|
CCodeAnalysis(CCodeAnalyser *aAnalyser, unsigned aTotalIndices, std::vector<CEntryPoint> &entryPoints, std::vector<UINT32> &m_unseenEntryAddrs);
|
|
|
|
CCodeAnalysis(CCodeAnalysis *oldAnalysis, std::vector<CEntryPoint> &entryPoints, std::vector<UINT32> &m_unseenEntryAddrs);
|
|
|
|
void FinishAnalysis();
|
|
|
|
public:
|
|
CCodeAnalyser *analyser;
|
|
std::set<unsigned> validIndexSet;
|
|
std::vector<CAutoLabel*> autoLabels;
|
|
|
|
~CCodeAnalysis();
|
|
|
|
void Acquire();
|
|
|
|
void Release();
|
|
|
|
bool IsAddrValid(UINT32 addr);
|
|
|
|
bool GetNextValidAddr(UINT32 &addr);
|
|
|
|
bool IsIndexValid(unsigned index);
|
|
|
|
bool GetNextValidIndex(unsigned &index);
|
|
|
|
bool HasSeenAddr(UINT32 addr);
|
|
|
|
bool HaveSeenIndex(unsigned index);
|
|
|
|
CAutoLabel *GetAutoLabel(UINT32 addr);
|
|
|
|
CAutoLabel *GetAutoLabel(const char *subLabel);
|
|
|
|
std::vector<CAutoLabel*> GetAutoLabels(ELabelFlags flag);
|
|
};
|
|
|
|
/*
|
|
* Class that analyses a program's code to work out all the reachable program locations from a given set of entry points into the code.
|
|
* During the analysis, it keeps track of valid memory locations (to help with the disassembly of code for CPUs with variable-length
|
|
* instruction sets) and generates a set of auto-labels that identify places of interest such as subroutines, jump destinations and
|
|
* exception handlers etc.
|
|
* This sort of analysis works well for static addressing modes but not so well for dynamic address referencing or self-modifying code.
|
|
* To allow for the latter cases the analyser updates its analysis whenever it encounters an unseen memory location or it sees
|
|
* that code has changed from a previous inspection.
|
|
*/
|
|
class CCodeAnalyser
|
|
{
|
|
private:
|
|
std::vector<CRegion*> m_codeRegions;
|
|
std::vector<unsigned> m_indexBounds;
|
|
|
|
std::vector<UINT32> m_customEntryAddrs;
|
|
|
|
bool m_abortAnalysis;
|
|
|
|
void CheckEntryPoints(std::vector<CEntryPoint> &entryPoints, std::vector<UINT32> &unseenEntryAddrs, std::vector<CEntryPoint> &prevPoints,
|
|
bool &needsAnalysis, bool &reanalyse);
|
|
|
|
void GatherEntryPoints(std::vector<CEntryPoint> &entryPoints, std::vector<UINT32> &unseenEntryAddrs, bool &reanalyse);
|
|
|
|
void AddEntryPoint(std::vector<CEntryPoint> &entryPoints, UINT32 addr, ELabelFlags autoFlag, const char *autoLabel);
|
|
|
|
void AnalyseCode(std::vector<bool> &seenIndices, std::vector<bool> &validIndices, std::set<unsigned> &validIndexSet, std::map<UINT32, CAutoLabel*> &autoLabelsMap, UINT32 addr);
|
|
|
|
void AddFlagToAddr(std::map<UINT32, CAutoLabel*> &autoLabelsMap, UINT32 addr, ELabelFlags autoFlag, const char *autoLabel);
|
|
|
|
public:
|
|
CCPUDebug *cpu;
|
|
|
|
CCodeAnalysis emptyAnalysis;
|
|
|
|
CCodeAnalysis *analysis;
|
|
|
|
unsigned instrAlign;
|
|
unsigned totalIndices;
|
|
|
|
CCodeAnalyser(CCPUDebug *aCPU);
|
|
|
|
~CCodeAnalyser();
|
|
|
|
void Reset();
|
|
|
|
bool GetAddrOfIndex(unsigned index, UINT32 &addr);
|
|
|
|
bool GetIndexOfAddr(UINT32 addr, unsigned &index);
|
|
|
|
//
|
|
// Methods to check, run or abort analysis
|
|
//
|
|
|
|
bool NeedsAnalysis();
|
|
|
|
bool AnalyseCode();
|
|
|
|
void AbortAnalysis();
|
|
|
|
//
|
|
// Methods to manipulate custom entry addresses
|
|
//
|
|
|
|
void ClearCustomEntryAddrs();
|
|
|
|
void AddCustomEntryAddr(UINT32 entryAddr);
|
|
|
|
bool RemoveCustomEntryAddr(UINT32 entryAddr);
|
|
|
|
#ifdef DEBUGGER_HASBLOCKFILE
|
|
bool LoadState(CBlockFile *state);
|
|
|
|
bool SaveState(CBlockFile *state);
|
|
#endif // DEBUGGER_HASBLOCKFILE
|
|
};
|
|
}
|
|
|
|
#endif // INCLUDED_CODEANALYSER_H
|
|
#endif // SUPERMODEL_DEBUGGER
|