mirror of https://github.com/PCSX2/pcsx2.git
Debugger: Initial debugger implementation
This commit is contained in:
parent
78c9b7f33e
commit
2f0b244f48
|
@ -0,0 +1,6 @@
|
|||
|
||||
cmake_minimum_required(VERSION 3.6)
|
||||
|
||||
project(demangler CXX)
|
||||
|
||||
add_subdirectory(src)
|
|
@ -0,0 +1,59 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="$(SolutionDir)common\vsprops\BaseProjectConfig.props" />
|
||||
<Import Project="$(SolutionDir)common\vsprops\WinSDK.props" />
|
||||
<PropertyGroup Label="Globals">
|
||||
<ProjectGuid>{1E3D706C-1D95-4E1B-BDF2-CA3D0007DF7F}</ProjectGuid>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Label="Configuration">
|
||||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||
<PlatformToolset>$(DefaultPlatformToolset)</PlatformToolset>
|
||||
<CharacterSet>MultiByte</CharacterSet>
|
||||
<WholeProgramOptimization Condition="$(Configuration.Contains(Release))">true</WholeProgramOptimization>
|
||||
<UseDebugLibraries Condition="$(Configuration.Contains(Debug))">true</UseDebugLibraries>
|
||||
<UseDebugLibraries Condition="!$(Configuration.Contains(Debug))">false</UseDebugLibraries>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="ExtensionSettings" />
|
||||
<ImportGroup Label="PropertySheets">
|
||||
<Import Project="..\DefaultProjectRootDir.props" />
|
||||
<Import Project="..\3rdparty.props" />
|
||||
<Import Condition="$(Configuration.Contains(Debug))" Project="..\..\common\vsprops\CodeGen_Debug.props" />
|
||||
<Import Condition="$(Configuration.Contains(Devel))" Project="..\..\common\vsprops\CodeGen_Devel.props" />
|
||||
<Import Condition="$(Configuration.Contains(Release))" Project="..\..\common\vsprops\CodeGen_Release.props" />
|
||||
<Import Condition="!$(Configuration.Contains(Release))" Project="..\..\common\vsprops\IncrementalLinking.props" />
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<PropertyGroup>
|
||||
<CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="src\demangler.cpp" />
|
||||
<ClCompile Include="src\demtools.cpp" />
|
||||
<ClCompile Include="src\gparser.cpp" />
|
||||
<ClCompile Include="src\igrams.cpp" />
|
||||
<ClCompile Include="src\stgrammars\borlandll.cpp" />
|
||||
<ClCompile Include="src\stgrammars\gccll.cpp" />
|
||||
<ClCompile Include="src\stgrammars\msll.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="include\demangler\demangler.h" />
|
||||
<ClInclude Include="include\demangler\demglobal.h" />
|
||||
<ClInclude Include="include\demangler\demtools.h" />
|
||||
<ClInclude Include="include\demangler\gparser.h" />
|
||||
<ClInclude Include="include\demangler\igrams.h" />
|
||||
<ClInclude Include="include\demangler\stgrammars\borlandll.h" />
|
||||
<ClInclude Include="include\demangler\stgrammars\gccll.h" />
|
||||
<ClInclude Include="include\demangler\stgrammars\msll.h" />
|
||||
</ItemGroup>
|
||||
<ItemDefinitionGroup>
|
||||
<ClCompile>
|
||||
<PreprocessorDefinitions>%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<WarningLevel>TurnOffAllWarnings</WarningLevel>
|
||||
<AdditionalIncludeDirectories>$(ProjectDir)include;$(ProjectDir)src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
</ItemDefinitionGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets" />
|
||||
</Project>
|
|
@ -0,0 +1,22 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<ClCompile Include="src\demangler.cpp" />
|
||||
<ClCompile Include="src\demtools.cpp" />
|
||||
<ClCompile Include="src\gparser.cpp" />
|
||||
<ClCompile Include="src\igrams.cpp" />
|
||||
<ClCompile Include="src\stgrammars\borlandll.cpp" />
|
||||
<ClCompile Include="src\stgrammars\gccll.cpp" />
|
||||
<ClCompile Include="src\stgrammars\msll.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="include\demangler\demangler.h" />
|
||||
<ClInclude Include="include\demangler\demglobal.h" />
|
||||
<ClInclude Include="include\demangler\demtools.h" />
|
||||
<ClInclude Include="include\demangler\gparser.h" />
|
||||
<ClInclude Include="include\demangler\igrams.h" />
|
||||
<ClInclude Include="include\demangler\stgrammars\borlandll.h" />
|
||||
<ClInclude Include="include\demangler\stgrammars\gccll.h" />
|
||||
<ClInclude Include="include\demangler\stgrammars\msll.h" />
|
||||
</ItemGroup>
|
||||
</Project>
|
|
@ -0,0 +1,45 @@
|
|||
/**
|
||||
* @file include/demangler/demangler.h
|
||||
* @brief Demangler library.
|
||||
* @copyright (c) 2017 Avast Software, licensed under the MIT license
|
||||
*/
|
||||
|
||||
#ifndef DEMANGLER_DEMANGLERL_H
|
||||
#define DEMANGLER_DEMANGLERL_H
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
#include "demangler/gparser.h"
|
||||
|
||||
namespace demangler {
|
||||
|
||||
/**
|
||||
* The grammar parser class - the core of the demangler.
|
||||
*/
|
||||
class CDemangler {
|
||||
cGram *pGram;
|
||||
cName *pName;
|
||||
std::string compiler = "gcc";
|
||||
cGram::errcode errState; /// error state; 0 = everyting is ok
|
||||
|
||||
public:
|
||||
CDemangler(std::string gname, bool i = true);
|
||||
static std::unique_ptr<CDemangler> createGcc(bool i = true);
|
||||
static std::unique_ptr<CDemangler> createMs(bool i = true);
|
||||
static std::unique_ptr<CDemangler> createBorland(bool i = true);
|
||||
virtual ~CDemangler();
|
||||
|
||||
bool isOk();
|
||||
std::string printError();
|
||||
void resetError();
|
||||
|
||||
void createGrammar(std::string inputfilename, std::string outputname);
|
||||
cName *demangleToClass(std::string inputName);
|
||||
std::string demangleToString(std::string inputName);
|
||||
void setSubAnalyze(bool x);
|
||||
};
|
||||
|
||||
} // namespace demangler
|
||||
|
||||
#endif
|
|
@ -0,0 +1,20 @@
|
|||
/**
|
||||
* @file include/demangler/demglobal.h
|
||||
* @brief Global variables in demangler namespace.
|
||||
* @copyright (c) 2017 Avast Software, licensed under the MIT license
|
||||
*/
|
||||
|
||||
#ifndef DEMANGLER_DEMGLOBAL_H
|
||||
#define DEMANGLER_DEMGLOBAL_H
|
||||
|
||||
#include "demangler/igrams.h"
|
||||
|
||||
namespace demangler {
|
||||
|
||||
extern cGram::igram_t internalGrammarStruct;
|
||||
extern cIgram_msll* igram_msll;
|
||||
extern cIgram_gccll* igram_gccll;
|
||||
|
||||
} // namespace demangler
|
||||
|
||||
#endif
|
|
@ -0,0 +1,36 @@
|
|||
/**
|
||||
* @file include/demangler/demtools.h
|
||||
* @brief Tools and extra functions for demangler.
|
||||
* @copyright (c) 2017 Avast Software, licensed under the MIT license
|
||||
*/
|
||||
|
||||
#ifndef DEMANGLER_DEMTOOLS_H
|
||||
#define DEMANGLER_DEMTOOLS_H
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace demangler {
|
||||
|
||||
/**
|
||||
* @brief Structure for date and time.
|
||||
*/
|
||||
struct sdate_t {
|
||||
unsigned int y = 0;
|
||||
unsigned int m = 0;
|
||||
unsigned int d = 0;
|
||||
unsigned int h = 0;
|
||||
unsigned int min = 0;
|
||||
unsigned int s = 0;
|
||||
};
|
||||
|
||||
bool fileExists(const std::string &filename);
|
||||
|
||||
void initSdate_t(sdate_t &x);
|
||||
|
||||
sdate_t genTimeStruct();
|
||||
|
||||
void xreplace(std::string &source, const std::string &tobereplaced, const std::string &replacement);
|
||||
|
||||
} // namespace demangler
|
||||
|
||||
#endif
|
|
@ -0,0 +1,830 @@
|
|||
/**
|
||||
* @file include/demangler/gparser.h
|
||||
* @brief Parser of LL grammar.
|
||||
* @copyright (c) 2017 Avast Software, licensed under the MIT license
|
||||
*/
|
||||
|
||||
#ifndef DEMANGLER_GPARSER_H
|
||||
#define DEMANGLER_GPARSER_H
|
||||
|
||||
#include <map>
|
||||
#include <set>
|
||||
#include <stack>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
//internal grammars
|
||||
|
||||
namespace demangler {
|
||||
|
||||
/**
|
||||
* @brief Class which holds a demangled name.
|
||||
*/
|
||||
class cName {
|
||||
public:
|
||||
/**
|
||||
* @brief Enum of types of the mangled types (Determines whether a type is built-in or named).
|
||||
*/
|
||||
enum ttype { //type of type
|
||||
TT_UNKNOWN = 0, //can be used for unknown return type
|
||||
TT_BUILTIN,
|
||||
TT_NAME,
|
||||
TT_NUM,
|
||||
TT_PEXPR
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Enum of types of the mangled names.
|
||||
*/
|
||||
enum ntype { //type of the mangled name
|
||||
NT_FUNCTION = 0,
|
||||
NT_TEMPLFUNCTION,
|
||||
NT_OPERATOR,
|
||||
NT_CONSTRUCTOR,
|
||||
NT_DESTRUCTOR,
|
||||
NT_DATA,
|
||||
NT_VTABLE,
|
||||
NT_R0,
|
||||
NT_R1,
|
||||
NT_R2,
|
||||
NT_R3,
|
||||
NT_R4,
|
||||
NT__A,
|
||||
NT__B,
|
||||
NT__C,
|
||||
NT__D,
|
||||
NT__E,
|
||||
NT__F,
|
||||
NT__G,
|
||||
NT__H,
|
||||
NT__I,
|
||||
NT__J,
|
||||
NT__K,
|
||||
NT__L,
|
||||
NT__M,
|
||||
NT__N,
|
||||
NT__O,
|
||||
NT__P,
|
||||
NT__Q,
|
||||
NT__R,
|
||||
NT__S,
|
||||
NT__T,
|
||||
NT__U,
|
||||
NT__V,
|
||||
NT__W,
|
||||
NT__X,
|
||||
NT__Y,
|
||||
NT__Z,
|
||||
NT_CLASS
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Enum of operator types.
|
||||
*/
|
||||
enum optype { //type of operator
|
||||
OT_NULL = 0,
|
||||
OT_NEW,
|
||||
OT_NEWARR,
|
||||
OT_DEL,
|
||||
OT_DELARR,
|
||||
OT_UPLUS,
|
||||
OT_UMINUS,
|
||||
OT_UAND,
|
||||
OT_UAST,
|
||||
OT_TILDA,
|
||||
OT_PLUS,
|
||||
OT_MINUS,
|
||||
OT_AST,
|
||||
OT_DIV,
|
||||
OT_MOD,
|
||||
OT_AND,
|
||||
OT_OR,
|
||||
OT_EXP,
|
||||
OT_ASSIGN,
|
||||
OT_PLUSASS,
|
||||
OT_MINUSASS,
|
||||
OT_ASTASS,
|
||||
OT_DIVASS,
|
||||
OT_MODASS,
|
||||
OT_ANDASS,
|
||||
OT_ORASS,
|
||||
OT_EXPASS,
|
||||
OT_LSHIFT,
|
||||
OT_RSHIFT,
|
||||
OT_LSHIFTASS,
|
||||
OT_RSHIFTASS,
|
||||
OT_EQ,
|
||||
OT_NEQ,
|
||||
OT_LT,
|
||||
OT_GT,
|
||||
OT_LE,
|
||||
OT_GE,
|
||||
OT_NOT,
|
||||
OT_ANDAND,
|
||||
OT_OROR,
|
||||
OT_PLUSPLUS,
|
||||
OT_MINUSMINUS,
|
||||
OT_COMMA,
|
||||
OT_PTAST,
|
||||
OT_PT,
|
||||
OT_BRACKETS,
|
||||
OT_ARR,
|
||||
OT_QUESTION,
|
||||
OT_SIZEOFT,
|
||||
OT_SIZEOFE,
|
||||
OT_ALIGNOFT,
|
||||
OT_ALIGNOFE,
|
||||
OT_CAST
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Enum of built-in types.
|
||||
*/
|
||||
enum st_type { //standard built-in types
|
||||
T_VOID = 0,
|
||||
T_WCHAR,
|
||||
T_BOOL,
|
||||
T_CHAR,
|
||||
T_SCHAR,
|
||||
T_UCHAR,
|
||||
T_SHORT,
|
||||
T_USHORT,
|
||||
T_INT,
|
||||
T_UINT,
|
||||
T_LONG,
|
||||
T_ULONG,
|
||||
T_LONGLONG,
|
||||
T_ULONGLONG,
|
||||
T_INT128,
|
||||
T_UINT128,
|
||||
T_FLOAT,
|
||||
T_DOUBLE,
|
||||
T_LONGDOUBLE,
|
||||
T_FLOAT128,
|
||||
T_ELLIPSIS,
|
||||
T_DD,
|
||||
T_DE,
|
||||
T_DF,
|
||||
T_DH,
|
||||
T_CHAR32,
|
||||
T_CHAR16,
|
||||
T_AUTO,
|
||||
T_NULLPTR
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Enum of member function accessibility.
|
||||
*/
|
||||
enum memfacc_t { //standard built-in types
|
||||
MFM_NULL = 0,
|
||||
MFM_PRIVATE,
|
||||
MFM_PUBLIC,
|
||||
MFM_PROTECTED
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Enum of function call conventions.
|
||||
*/
|
||||
enum fcall_t { //standard built-in types
|
||||
FCC_NULL = 0,
|
||||
FCC_CDECL,
|
||||
FCC_PASCAL,
|
||||
FCC_FORTRAN,
|
||||
FCC_THISCALL,
|
||||
FCC_STDCALL,
|
||||
FCC_FASTCALL,
|
||||
FCC_INTERRUPT
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Enum of named type classifications. Union, Struct, Class, Enum.
|
||||
*/
|
||||
enum mstype_t { //standard built-in types
|
||||
MST_NULL = 0,
|
||||
MST_UNION,
|
||||
MST_STRUCT,
|
||||
MST_CLASS,
|
||||
MST_ENUM
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @brief Structure of an unqualified name.
|
||||
* @param un String which holds the name.
|
||||
* @param tpl Pointer to the the template (vector of types) of this unqualified name. If nullptr, the unqualified name consists only of the string.
|
||||
*/
|
||||
struct name_t {
|
||||
std::string un; //unqualified name
|
||||
void *tpl = nullptr; //std::vector<type_t>
|
||||
bool op = false; //is it operator name element?
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Structure of a type.
|
||||
* @param type Type of the type.
|
||||
* @param b Built-in type. This value is defined only if 'type' is TT_BUILTIN.
|
||||
* @param n Qualified name of the type. This value is defined only if 'type' is TT_NAME.
|
||||
* @param is_const Bool value which determines whether the type is const.
|
||||
* @param is_restrict Bool value which determines whether the type is restrict.
|
||||
* @param is_volatile Bool value which determines whether the type is volatile.
|
||||
* @param is_pointer Integer value determining the pointer level of the type.
|
||||
* @param is_reference Bool value which determines whether the type is a reference.
|
||||
* @param is_rvalue Bool value which determines whether the type is an R-value.
|
||||
* @param is_cpair Bool value which determines whether the type is a complex pair.
|
||||
* @param is_imaginary Bool value which determines whether the type is imaginary.
|
||||
*/
|
||||
struct type_t {
|
||||
ttype type = TT_UNKNOWN; //type of type... builtin or named type
|
||||
st_type b = T_VOID; //builtin type
|
||||
void *value = nullptr; //expression value
|
||||
std::vector<name_t> n; //qualified name of named type
|
||||
std::string modifiers;
|
||||
mstype_t mst = MST_NULL;
|
||||
int num = 0;
|
||||
|
||||
bool is_array = false;
|
||||
std::vector<unsigned int> array_dimensions;
|
||||
bool is_const = false;
|
||||
bool is_restrict = false;
|
||||
bool is_volatile = false;
|
||||
unsigned int is_pointer = 0;
|
||||
bool is_reference = false;
|
||||
bool is_rvalue = false; //r-value reference
|
||||
bool is_cpair = false; //complex pair
|
||||
bool is_imaginary = false;
|
||||
|
||||
std::string getLlvmType();
|
||||
|
||||
private:
|
||||
std::string llvmIr;
|
||||
std::string getLlvmTypePrivate();
|
||||
};
|
||||
|
||||
ntype name_type = NT_FUNCTION; //name type
|
||||
optype operator_type = OT_NULL; //type of operator. it is OT_NULL if function is not an operator
|
||||
type_t return_type;
|
||||
type_t special_type; //return value for function or conversion type for operator OT_CAST
|
||||
std::string modifiers;
|
||||
|
||||
memfacc_t member_function_access = MFM_NULL;
|
||||
fcall_t function_call = FCC_NULL;
|
||||
bool is_static = false;
|
||||
bool is_virtual = false;
|
||||
std::string storage_class;
|
||||
std::vector<long int> rttibcd;
|
||||
|
||||
std::vector<type_t> parameters; //function parameters
|
||||
std::vector<name_t> name; //qualified name composed of unqualified names
|
||||
|
||||
void *tf_tpl = nullptr;
|
||||
|
||||
bool last_shown_endtpl = false; //an auxiliary variable which helps to add space between multiple '>' at the end of templates
|
||||
|
||||
void deleteparams(std::vector<type_t> & vec);
|
||||
cName(); //constructor
|
||||
virtual ~cName(); //mass destruction
|
||||
void type_t_clear(type_t &x);
|
||||
void addname(const std::vector<name_t> & inname); //set the function name
|
||||
void addpar(const std::vector<type_t> & inpar); //set the parameters of the name
|
||||
void setnametype(ntype x); //set type of the mangled name
|
||||
void setfcall(fcall_t x); //set type of the function call convention
|
||||
void setmfacc(memfacc_t x); //set type of the member function access level
|
||||
ntype getnametype(void); //get type of the mangled name
|
||||
void setop(optype x); //set operator type
|
||||
void setret(type_t x); //set return type
|
||||
void setspec(type_t x); //set special type
|
||||
void setstatic(); //set name's static flag
|
||||
void setvirtual(); //set name's virtual flag
|
||||
void addmodifier(char x); //add a modifier to the name modifier string
|
||||
void addstcl(char x); //add a modifier to the storage class string
|
||||
void setmodifiers(std::string x); //set modifiers
|
||||
void settftpl(void* x); //set template function template
|
||||
void addrttinum(long int x); //add a RTTI Base Class descriptor num
|
||||
std::string optypetostr(optype x); //operator type to string
|
||||
std::string printmodifiers(std::string x, bool space);
|
||||
std::string printpremodifiers(std::string x, bool space);
|
||||
std::string printpostmodifiers(std::string x, bool space);
|
||||
std::string printname(std::vector<name_t> & vec, std::string compiler = "gcc");
|
||||
std::string printparams(std::vector<type_t> & vec, bool ignorevoid = false, std::string compiler = "gcc");
|
||||
std::string printpexpr(type_t & x);
|
||||
|
||||
/**
|
||||
* @brief Print the calling convention to a string.
|
||||
* @param callconv The calling convention to be printed.
|
||||
* @return String containing calling convention.
|
||||
*/
|
||||
std::string printcallingconvention(fcall_t callconv);
|
||||
|
||||
std::string printall(std::string compiler = "gcc");
|
||||
std::string printall_old(bool msvcpp = false);
|
||||
}; //class cName
|
||||
|
||||
/**
|
||||
* @brief Grammar class. It's member functions allow loading an external grammar and demangling a mangled name using the grammar.
|
||||
*/
|
||||
class cGram {
|
||||
|
||||
public:
|
||||
/**
|
||||
* @brief Global array of semantic action names. Used when building internal LL table from external grammar.
|
||||
*/
|
||||
static const char *semactname[];
|
||||
|
||||
/**
|
||||
* @brief Enum of error codes.
|
||||
*/
|
||||
enum errcode {
|
||||
ERROR_OK = 0,
|
||||
ERROR_FILE,
|
||||
ERROR_FSM,
|
||||
ERROR_SYN,
|
||||
ERROR_MEM,
|
||||
ERROR_GRAM,
|
||||
ERROR_LL,
|
||||
ERROR_UNK
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief An array of error messages.
|
||||
*/
|
||||
static const char *errmsg[];
|
||||
|
||||
/**
|
||||
* @brief Type of a grammar element. It can be either a terminal or a non-terminal.
|
||||
*/
|
||||
enum gelemtype {
|
||||
GE_TERM = 0,
|
||||
GE_NONTERM
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @brief Structure of a grammar element.
|
||||
* @param type Type of the element (terminal or non-terminal).
|
||||
* @param nt The name of the non-terminal. Only vylid if type is GE_NONTERM.
|
||||
* @param t The byte value of the terminal. Only valid if type is GE_TERM.
|
||||
*/
|
||||
struct gelem_t {
|
||||
gelem_t(gelemtype t, char* n, unsigned int i, char c) :
|
||||
type(t),
|
||||
nt(n),
|
||||
ntst(i),
|
||||
t(c)
|
||||
{}
|
||||
gelem_t() {}
|
||||
gelemtype type = GE_TERM;
|
||||
char* nt = nullptr;
|
||||
unsigned int ntst = 0;
|
||||
char t = 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Enum of semantic actions.
|
||||
*/
|
||||
enum semact {
|
||||
//do nothing
|
||||
SA_NULL = 0,
|
||||
|
||||
//set type of name (function, operator, constructor, destructor, data)
|
||||
SA_SETNAMEF,
|
||||
SA_SETNAMETF,
|
||||
SA_SETNAMEO,
|
||||
SA_SETNAMEC,
|
||||
SA_SETNAMED,
|
||||
SA_SETNAMEX,
|
||||
SA_SETNAMEVT,
|
||||
|
||||
//set operator type
|
||||
SA_SETOPXX,
|
||||
SA_SETOPNW,
|
||||
SA_SETOPNA,
|
||||
SA_SETOPDL,
|
||||
SA_SETOPDA,
|
||||
SA_SETOPPS,
|
||||
SA_SETOPNG,
|
||||
SA_SETOPAD,
|
||||
SA_SETOPDE,
|
||||
SA_SETOPCO,
|
||||
SA_SETOPPL,
|
||||
SA_SETOPMI,
|
||||
SA_SETOPML,
|
||||
SA_SETOPDV,
|
||||
SA_SETOPRM,
|
||||
SA_SETOPAN,
|
||||
SA_SETOPOR,
|
||||
SA_SETOPEO,
|
||||
SA_SETOPASS,
|
||||
SA_SETOPPLL,
|
||||
SA_SETOPMII,
|
||||
SA_SETOPMLL,
|
||||
SA_SETOPDVV,
|
||||
SA_SETOPRMM,
|
||||
SA_SETOPANN,
|
||||
SA_SETOPORR,
|
||||
SA_SETOPEOO,
|
||||
SA_SETOPLS,
|
||||
SA_SETOPRS,
|
||||
SA_SETOPLSS,
|
||||
SA_SETOPRSS,
|
||||
SA_SETOPEQ,
|
||||
SA_SETOPNE,
|
||||
SA_SETOPLT,
|
||||
SA_SETOPGT,
|
||||
SA_SETOPLE,
|
||||
SA_SETOPGE,
|
||||
SA_SETOPNT,
|
||||
SA_SETOPAA,
|
||||
SA_SETOPOO,
|
||||
SA_SETOPPP,
|
||||
SA_SETOPMM,
|
||||
SA_SETOPCM,
|
||||
SA_SETOPPM,
|
||||
SA_SETOPPT,
|
||||
SA_SETOPCL,
|
||||
SA_SETOPIX,
|
||||
SA_SETOPQU,
|
||||
SA_SETOPST,
|
||||
SA_SETOPSZ,
|
||||
SA_SETOPAT,
|
||||
SA_SETOPAZ,
|
||||
SA_SETOPCV,
|
||||
|
||||
//builtin types
|
||||
SA_SETTYPEV,
|
||||
SA_SETTYPEW,
|
||||
SA_SETTYPEB,
|
||||
SA_SETTYPEC,
|
||||
SA_SETTYPEA,
|
||||
SA_SETTYPEH,
|
||||
SA_SETTYPES,
|
||||
SA_SETTYPET,
|
||||
SA_SETTYPEI,
|
||||
SA_SETTYPEJ,
|
||||
SA_SETTYPEL,
|
||||
SA_SETTYPEM,
|
||||
SA_SETTYPEX,
|
||||
SA_SETTYPEY,
|
||||
SA_SETTYPEN,
|
||||
SA_SETTYPEO,
|
||||
SA_SETTYPEF,
|
||||
SA_SETTYPED,
|
||||
SA_SETTYPEE,
|
||||
SA_SETTYPEG,
|
||||
SA_SETTYPEZ,
|
||||
|
||||
//parameter modifiers
|
||||
SA_SETCONST,
|
||||
SA_SETRESTRICT,
|
||||
SA_SETVOLATILE,
|
||||
SA_SETPTR,
|
||||
SA_SETREF,
|
||||
SA_SETRVAL,
|
||||
SA_SETCPAIR,
|
||||
SA_SETIM,
|
||||
|
||||
//substitutions
|
||||
SA_SUBSTD, //::std::
|
||||
SA_SUBALC, //::std::allocator
|
||||
SA_SUBSTR, //::std::basic_string
|
||||
SA_SUBSTRS, //::std::basic_string<char,::std::char_traits<char>,::std::allocator<char>>
|
||||
SA_SUBISTR, //::std::basic_istream<char, std::char_traits<char>>
|
||||
SA_SUBOSTR, //::std::basic_ostream<char, std::char_traits<char>>
|
||||
SA_SUBIOSTR, //::std::basic_iostream<char, std::char_traits<char>>
|
||||
|
||||
//other very important semantic actions
|
||||
SA_LOADID, //load an unqualified name into the qualified vector of names
|
||||
SA_LOADSUB, //load a substitution
|
||||
SA_LOADTSUB, //load a template sub
|
||||
SA_LOADARR, //load an array dimension
|
||||
SA_STOREPAR, //store current parameter to vector of parameters
|
||||
SA_STORETEMPARG, //store current parameter to current vector of template arguments
|
||||
SA_STORETEMPLATE, //store the whole template into the last name element of last name vector
|
||||
SA_BEGINTEMPL, //begin a template
|
||||
SA_SKIPTEMPL, //skip a template
|
||||
SA_PAR2F, //store current vector of parameters into the function
|
||||
SA_PAR2RET, //store current parameter to the return value
|
||||
SA_PAR2SPEC, //store current parameter to the special value
|
||||
SA_UNQ2F, //future identifiers are added to the function name
|
||||
SA_UNQ2P, //function identifiers are added to parameter name
|
||||
|
||||
//substitution expansion modifiers
|
||||
SA_SSNEST, //nested sub
|
||||
SA_STUNQ, //unqualified std:: sub
|
||||
SA_SSNO, //other sub derived from <name>
|
||||
|
||||
SA_TYPE2EXPR, //builtin type is converted to primary expression
|
||||
SA_EXPRVAL, //load expression value
|
||||
SA_BEGINPEXPR, //begin a primary expression
|
||||
SA_STOREPEXPR, //end a primary expression
|
||||
SA_COPYTERM, //copy the terminal on the input into current_name in substitution analyzer
|
||||
|
||||
SA_ADDCHARTONAME, //add current character to current unqualified name
|
||||
SA_STORENAME, //move current unqualified name into current name vector
|
||||
SA_REVERSENAME,
|
||||
SA_SETPRIVATE,
|
||||
SA_SETPUBLIC,
|
||||
SA_SETPROTECTED,
|
||||
SA_SETFCDECL,
|
||||
SA_SETFPASCAL,
|
||||
SA_SETFFORTRAN,
|
||||
SA_SETFTHISCALL,
|
||||
SA_SETFSTDCALL,
|
||||
SA_SETFFASTCALL,
|
||||
SA_SETFINTERRUPT,
|
||||
SA_SETUNION,
|
||||
SA_SETSTRUCT,
|
||||
SA_SETCLASS,
|
||||
SA_SETENUM,
|
||||
SA_SETSTATIC,
|
||||
SA_SETVIRTUAL,
|
||||
SA_STCLCONST,
|
||||
SA_STCLVOL,
|
||||
SA_STCLFAR,
|
||||
SA_STCLHUGE,
|
||||
SA_SAVENAMESUB,
|
||||
SA_LOADNAMESUB,
|
||||
SA_MSTEMPLPSUB,
|
||||
SA_SETNAMER0,
|
||||
SA_SETNAMER1,
|
||||
SA_SETNAMER2,
|
||||
SA_SETNAMER3,
|
||||
SA_SETNAMER4,
|
||||
SA_SETNAME_A,
|
||||
SA_SETNAME_B,
|
||||
SA_SETNAME_C,
|
||||
SA_SETNAME_D,
|
||||
SA_SETNAME_E,
|
||||
SA_SETNAME_F,
|
||||
SA_SETNAME_G,
|
||||
SA_SETNAME_H,
|
||||
SA_SETNAME_I,
|
||||
SA_SETNAME_J,
|
||||
SA_SETNAME_K,
|
||||
SA_SETNAME_L,
|
||||
SA_SETNAME_M,
|
||||
SA_SETNAME_N,
|
||||
SA_SETNAME_O,
|
||||
SA_SETNAME_P,
|
||||
SA_SETNAME_Q,
|
||||
SA_SETNAME_R,
|
||||
SA_SETNAME_S,
|
||||
SA_SETNAME_T,
|
||||
SA_SETNAME_U,
|
||||
SA_SETNAME_V,
|
||||
SA_SETNAME_W,
|
||||
SA_SETNAME_X,
|
||||
SA_SETNAME_Y,
|
||||
SA_SETNAME_Z,
|
||||
SA_TEMPL2TFTPL,
|
||||
SA_BEGINBSUB,
|
||||
SA_LOADBSUB,
|
||||
SA_ADDMCONST,
|
||||
SA_ADDMVOL,
|
||||
SA_ADDMFAR,
|
||||
SA_ADDMHUGE,
|
||||
SA_LOADMSNUM,
|
||||
SA_NUMTORTTIBCD,
|
||||
SA_NUMTOTYPE,
|
||||
SA_BORLANDNORMALIZEPARNAME,
|
||||
SA_BORLANDID,
|
||||
SA_LOADBORLANDSUB,
|
||||
SA_BORLANDARR,
|
||||
SA_END
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Structure of an element in an internal LL table.
|
||||
* @param n Rule number. Numbered from 1. 0 is reserved for "no rule", which indicates a syntax error.
|
||||
* @param s Semantic action to be done when this LL element is used.
|
||||
*/
|
||||
struct llelem_t {
|
||||
llelem_t(unsigned int i, semact ss) :
|
||||
n(i),
|
||||
s(ss)
|
||||
{}
|
||||
llelem_t() {}
|
||||
unsigned int n = 0;
|
||||
semact s = SA_NULL;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Struct used to describe a rule boundaries in an internal LL table.
|
||||
* @param offset Offset from the start of ruleelements array.
|
||||
* @param size Number of elements in the current rule.
|
||||
*/
|
||||
struct ruleaddr_t {
|
||||
ruleaddr_t(unsigned int o, unsigned int s) :
|
||||
offset(o),
|
||||
size(s)
|
||||
{}
|
||||
unsigned int offset = 0;
|
||||
unsigned int size = 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Structure of a grammar rule.
|
||||
* @param n Number of the rule. Numbered from 1. 0 is reserved for "no rule", which indicates a syntax error.
|
||||
* @param left The left side of the rule, consisting of only one non-terminal.
|
||||
* @param right The right side of the rule, which is a sequence of terminals or non-terminals. May be empty.
|
||||
*/
|
||||
struct rule_t {
|
||||
unsigned int n = 0;
|
||||
gelem_t left;
|
||||
std::vector<gelem_t> right;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Types of substitution expansion.
|
||||
*/
|
||||
enum subtype {
|
||||
ST_NULL = 0,
|
||||
ST_STUNQ,
|
||||
ST_SSNEST,
|
||||
ST_SSNO
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief States of the FSM for parsing grammar rules from a file.
|
||||
*/
|
||||
enum fsmstate {
|
||||
S_START = 0, //beginning of a line
|
||||
S_NT_LEFT, //non-terminal on the left side
|
||||
S_OP1, //:
|
||||
S_OP2, //:
|
||||
S_OP3, //=
|
||||
S_RIGHT, //right side
|
||||
S_NT_RIGHT, //non-terminal on the right side
|
||||
S_T, //terminal on the right side
|
||||
S_QT, //quoted terminal on the right side
|
||||
S_QT_ESC, //escape sequence of a quoted terminal
|
||||
S_IGNORE, //ignore the rest of the line
|
||||
S_ERROR, //error ocurred
|
||||
S_NULL //just a NULL terminator for the array of final states
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Class for comparing two grammar element structures. Used in std::set of grammar elements.
|
||||
*/
|
||||
class comparegelem_c {
|
||||
public:
|
||||
/**
|
||||
* @brief Comparison function for two grammar element structures
|
||||
* @param t1 First grammar element.
|
||||
* @param t2 Second grammar element.
|
||||
*/
|
||||
bool operator() (const gelem_t t1, const gelem_t t2) const {
|
||||
//if types don't match, terminal is less than non-terminal
|
||||
if (t1.type!= t2.type) {
|
||||
return (t1.type == GE_TERM)?true:false;
|
||||
}
|
||||
//for two terminals, compare their byte values
|
||||
if (t1.type == GE_TERM) {
|
||||
return t1.t < t2.t;
|
||||
}
|
||||
//for two non-terminals, compare the non-terminal name strings
|
||||
else {
|
||||
return t1.nt < t2.nt;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Struct for internal grammar.
|
||||
*/
|
||||
struct igram_t {
|
||||
igram_t(unsigned int tsx, unsigned int rax, unsigned int rex, unsigned int lx, unsigned int ly,
|
||||
gelem_t r, unsigned char* ts, ruleaddr_t* ra, gelem_t* re, llelem_t** lt) :
|
||||
terminal_static_x(tsx),
|
||||
ruleaddrs_x(rax),
|
||||
ruleelements_x(rex),
|
||||
llst_x(lx),
|
||||
llst_y(ly),
|
||||
root(r),
|
||||
terminal_static(ts),
|
||||
ruleaddrs(ra),
|
||||
ruleelements(re),
|
||||
llst(lt)
|
||||
{}
|
||||
igram_t() {}
|
||||
//dimensions of the arrays
|
||||
unsigned int terminal_static_x = 0;
|
||||
unsigned int ruleaddrs_x = 0;
|
||||
unsigned int ruleelements_x = 0;
|
||||
unsigned int llst_x = 0; //first one
|
||||
unsigned int llst_y = 0; //second one
|
||||
//root element
|
||||
gelem_t root;
|
||||
//the arrays
|
||||
unsigned char* terminal_static = nullptr; //array of used terminals
|
||||
ruleaddr_t* ruleaddrs = nullptr; //structures defining offset and size of each rule in the ruleelements table
|
||||
gelem_t* ruleelements = nullptr; //all elements of all rules
|
||||
llelem_t** llst = nullptr; //the LL table
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief The struct variable containing pointers to internal grammar data.
|
||||
*/
|
||||
cGram::igram_t internalGrammarStruct;
|
||||
|
||||
//FSM for parsing external rules
|
||||
static const fsmstate fsm_final[];
|
||||
static const gelem_t T_EOF;
|
||||
|
||||
|
||||
bool internalGrammar = false;
|
||||
std::string compiler;
|
||||
|
||||
/*
|
||||
* Variables used for generation of new internal grammars
|
||||
*/
|
||||
std::string createIGrammar; //if this thing is on, new internal grammar will be generated from external grammar file
|
||||
unsigned int newIG_terminal_static_x = 0;
|
||||
std::size_t newIG_ruleaddrs_x = 0;
|
||||
std::size_t newIG_ruleelements_x = 0;
|
||||
std::size_t newIG_llst_x = 0;
|
||||
std::size_t newIG_llst_y = 0;
|
||||
std::string newIG_root;
|
||||
std::string newIG_terminal_static;
|
||||
std::string newIG_ruleaddrs;
|
||||
std::string newIG_ruleelements;
|
||||
std::string newIG_llst;
|
||||
|
||||
|
||||
/*
|
||||
* Variables for parsed external grammar
|
||||
*/
|
||||
std::vector<rule_t> rules;
|
||||
std::map<std::string,bool> empty;
|
||||
std::map<std::string,std::set<gelem_t,comparegelem_c>> first;
|
||||
std::map<std::string,std::set<gelem_t,comparegelem_c>> follow;
|
||||
std::map<unsigned int,std::set<gelem_t,comparegelem_c>> predict;
|
||||
std::map<std::string,std::map<char,std::pair<unsigned int, semact>>> ll;
|
||||
|
||||
std::vector<unsigned char> terminals;
|
||||
std::vector<std::string> nonterminals;
|
||||
|
||||
size_t lex_position = 0; //position in the source file
|
||||
std::fstream *source = nullptr; //pointer to the input filestream
|
||||
|
||||
/*
|
||||
* methods
|
||||
*/
|
||||
errcode loadfile(const std::string filename);
|
||||
bool is_final(fsmstate s); //is s a final state of fsm?
|
||||
char getc();
|
||||
bool eof();
|
||||
bool lf();
|
||||
errcode getgrammar(const std::string filename);
|
||||
bool copyset(std::set<gelem_t,comparegelem_c> & src, std::set<gelem_t,comparegelem_c> & dst);
|
||||
void genempty();
|
||||
void genfirst();
|
||||
bool getempty(std::vector<gelem_t> & src);
|
||||
std::set<gelem_t,comparegelem_c> getfirst(std::vector<gelem_t> & src);
|
||||
llelem_t getllpair(std::string nt, unsigned int ntst, unsigned char t);
|
||||
void genfollow();
|
||||
void genpredict();
|
||||
errcode genll();
|
||||
errcode genconstll();
|
||||
void genllsem();
|
||||
errcode analyze(std::string input, cName & pName);
|
||||
std::string subanalyze(const std::string input, cGram::errcode *err);
|
||||
semact getsem(const std::string input);
|
||||
void *getbstpl(cName & pName);
|
||||
void *getstrtpl(cName & pName);
|
||||
bool issub(std::string candidate,std::vector<std::string> & vec);
|
||||
void showsubs(std::vector<std::string> & vec);
|
||||
long int b36toint(std::string x);
|
||||
void * copynametpl(void * src);
|
||||
public:
|
||||
//constructor
|
||||
cGram();
|
||||
//destructor
|
||||
virtual ~cGram();
|
||||
errcode initialize(std::string gname, bool i = true);
|
||||
errcode parse(const std::string filename);
|
||||
cName *perform(const std::string input, errcode *err);
|
||||
void demangleClassName(const std::string& input, cName* retvalue, cGram::errcode& err_i);
|
||||
void showrules();
|
||||
void showempty();
|
||||
void showfirst();
|
||||
void showfollow();
|
||||
void showpredict();
|
||||
void showll();
|
||||
unsigned int isnt(std::vector<std::string> & nonterminals, std::string nonterminal);
|
||||
unsigned int ist(std::vector<unsigned char> & terminals, unsigned char terminal);
|
||||
|
||||
void resetError() {errString = "";}
|
||||
std::string errString; //string containing last error message
|
||||
bool errValid = false; //is the gParser valid? false if it has not been properly initialized yet
|
||||
bool SubAnalyzeEnabled = false; //enable substitution analysis for GCC demangler?
|
||||
void setSubAnalyze(bool x);
|
||||
|
||||
errcode generateIgrammar(const std::string inputfilename, const std::string outputname);
|
||||
std::string generatedTerminalStatic;
|
||||
|
||||
}; //class cGram
|
||||
|
||||
} // namespace demangler
|
||||
|
||||
#endif
|
|
@ -0,0 +1,23 @@
|
|||
/**
|
||||
* @file include/demangler/igrams.h
|
||||
* @brief Internal grammar list.
|
||||
* @copyright (c) 2017 Avast Software, licensed under the MIT license
|
||||
*/
|
||||
|
||||
#ifndef DEMANGLER_IGRAMS_H
|
||||
#define DEMANGLER_IGRAMS_H
|
||||
|
||||
//[igram] add internal grammar headers here
|
||||
#include "demangler/stgrammars/borlandll.h"
|
||||
#include "demangler/stgrammars/gccll.h"
|
||||
#include "demangler/stgrammars/msll.h"
|
||||
|
||||
namespace demangler {
|
||||
|
||||
bool initIgram(std::string gname, cGram* gParser);
|
||||
|
||||
void deleteIgrams(cGram* gParser);
|
||||
|
||||
} // namespace demangler
|
||||
|
||||
#endif
|
|
@ -0,0 +1,25 @@
|
|||
/**
|
||||
* @file include/demangler/stgrammars/borlandll.h
|
||||
* @brief Internal LL grammar for demangler.
|
||||
* @copyright (c) 2017 Avast Software, licensed under the MIT license
|
||||
*/
|
||||
|
||||
#ifndef DEMANGLER_STGRAMMARS_BORLANDLL_H
|
||||
#define DEMANGLER_STGRAMMARS_BORLANDLL_H
|
||||
|
||||
#include "demangler/gparser.h"
|
||||
|
||||
namespace demangler {
|
||||
|
||||
class cIgram_borlandll {
|
||||
public:
|
||||
static unsigned char terminal_static[256];
|
||||
static cGram::llelem_t llst[280][69];
|
||||
static cGram::ruleaddr_t ruleaddrs[467];
|
||||
static cGram::gelem_t ruleelements[603];
|
||||
static cGram::gelem_t root;
|
||||
cGram::igram_t getInternalGrammar();
|
||||
};
|
||||
|
||||
} // namespace demangler
|
||||
#endif
|
|
@ -0,0 +1,25 @@
|
|||
/**
|
||||
* @file include/demangler/stgrammars/gccll.h
|
||||
* @brief Internal LL grammar for demangler.
|
||||
* @copyright (c) 2017 Avast Software, licensed under the MIT license
|
||||
*/
|
||||
|
||||
#ifndef DEMANGLER_STGRAMMARS_GCCLL_H
|
||||
#define DEMANGLER_STGRAMMARS_GCCLL_H
|
||||
|
||||
#include "demangler/gparser.h"
|
||||
|
||||
namespace demangler {
|
||||
|
||||
class cIgram_gccll {
|
||||
public:
|
||||
static unsigned char terminal_static[256];
|
||||
static cGram::llelem_t llst[254][64];
|
||||
static cGram::ruleaddr_t ruleaddrs[423];
|
||||
static cGram::gelem_t ruleelements[445];
|
||||
static cGram::gelem_t root;
|
||||
cGram::igram_t getInternalGrammar();
|
||||
};
|
||||
|
||||
} // namespace demangler
|
||||
#endif
|
|
@ -0,0 +1,26 @@
|
|||
/**
|
||||
* @file include/demangler/stgrammars/msll.h
|
||||
* @brief Internal LL grammar for demangler.
|
||||
* @copyright (c) 2017 Avast Software, licensed under the MIT license
|
||||
*/
|
||||
|
||||
#ifndef DEMANGLER_STGRAMMARS_MSLL_H
|
||||
#define DEMANGLER_STGRAMMARS_MSLL_H
|
||||
|
||||
#include "demangler/gparser.h"
|
||||
|
||||
namespace demangler {
|
||||
|
||||
class cIgram_msll {
|
||||
public:
|
||||
static unsigned char terminal_static[256];
|
||||
static cGram::llelem_t llst[249][68];
|
||||
static cGram::ruleaddr_t ruleaddrs[534];
|
||||
static cGram::gelem_t ruleelements[796];
|
||||
static cGram::gelem_t root;
|
||||
cGram::igram_t getInternalGrammar();
|
||||
};
|
||||
|
||||
} // namespace demangler
|
||||
|
||||
#endif
|
|
@ -0,0 +1,16 @@
|
|||
|
||||
set(DEMANGLER_SOURCES
|
||||
demangler.cpp
|
||||
demtools.cpp
|
||||
gparser.cpp
|
||||
igrams.cpp
|
||||
stgrammars/borlandll.cpp
|
||||
stgrammars/gccll.cpp
|
||||
stgrammars/msll.cpp
|
||||
)
|
||||
|
||||
add_library(demangler STATIC ${DEMANGLER_SOURCES})
|
||||
target_include_directories(demangler PUBLIC ${PROJECT_SOURCE_DIR}/include/)
|
||||
|
||||
set_property(TARGET demangler PROPERTY CXX_STANDARD 17)
|
||||
set_property(TARGET demangler PROPERTY CXX_STANDARD_REQUIRED ON)
|
|
@ -0,0 +1,131 @@
|
|||
/**
|
||||
* @file src/demangler/demangler.cpp
|
||||
* @brief Demangler library.
|
||||
* @copyright (c) 2017 Avast Software, licensed under the MIT license
|
||||
*/
|
||||
|
||||
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
|
||||
#include "demangler/demangler.h"
|
||||
|
||||
namespace demangler {
|
||||
|
||||
/**
|
||||
* @brief Constructor of CDemangler class.
|
||||
* @param gname Grammar name. If internal grammar is used, internal grammar of this name must exist.
|
||||
* If external grammar is used file with this name must exist and it used as external grammar.
|
||||
* @param i Use internal grammar? Default setting is true. If set to false, external grammar is used.
|
||||
*/
|
||||
CDemangler::CDemangler(std::string gname, bool i):
|
||||
pGram(new cGram()),
|
||||
pName(nullptr),
|
||||
errState(cGram::ERROR_OK) {
|
||||
//if gname is empty, pGram will not be initialized (may be used for creating new internal grammars)
|
||||
if (!gname.empty()) {
|
||||
errState = pGram->initialize(gname, i);
|
||||
compiler = gname;
|
||||
}
|
||||
}
|
||||
|
||||
std::unique_ptr<CDemangler> CDemangler::createGcc(bool i)
|
||||
{
|
||||
return std::make_unique<CDemangler>("gcc", i);
|
||||
}
|
||||
|
||||
std::unique_ptr<CDemangler> CDemangler::createMs(bool i)
|
||||
{
|
||||
return std::make_unique<CDemangler>("ms", i);
|
||||
}
|
||||
|
||||
std::unique_ptr<CDemangler> CDemangler::createBorland(bool i)
|
||||
{
|
||||
return std::make_unique<CDemangler>("borland", i);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Destructor of CDemangler class.
|
||||
*/
|
||||
CDemangler::~CDemangler() {
|
||||
delete pGram;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Check if the error state of demangler is ok. Returns false if an error has ocurred during the last action.
|
||||
* @return Boolean value determining whether everything is ok.
|
||||
*/
|
||||
bool CDemangler::isOk() {
|
||||
if (errState == cGram::ERROR_OK) {
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns string describing the last error.
|
||||
*/
|
||||
std::string CDemangler::printError() {
|
||||
if (pGram != nullptr) {
|
||||
return pGram->errString;
|
||||
}
|
||||
else {
|
||||
return "No grammar class allocated. Cannot get error state.";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Reset error state.
|
||||
*/
|
||||
void CDemangler::resetError() {
|
||||
if (pGram != nullptr) {
|
||||
pGram->resetError();
|
||||
errState = cGram::ERROR_OK;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Function which converts external grammar into internal grammar.
|
||||
* After using this function the demangler object must not be used for demangling.S
|
||||
* errState may be set if an error occurs.
|
||||
* @param inputfilename The name of the file which contains grammar rules.
|
||||
* @param outputname The name of the output grammar.
|
||||
*/
|
||||
void CDemangler::createGrammar(std::string inputfilename, std::string outputname) {
|
||||
errState = pGram->generateIgrammar(inputfilename, outputname);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Demangle the input string and return the demangled name class. errState may be set if an error occurs.
|
||||
* @param inputName The name to be demangled.
|
||||
* @return Pointer to a cName object containing all info anout the demangled name.
|
||||
*/
|
||||
cName *CDemangler::demangleToClass(std::string inputName) {
|
||||
return pGram->perform(inputName,&errState);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Demangle the input string and return the demangled name as a string. errState may be set if an error occurs.
|
||||
* @param inputName The name to be demangled.
|
||||
* @return String containing the declaration of the demangled name.
|
||||
*/
|
||||
std::string CDemangler::demangleToString(std::string inputName) {
|
||||
std::string retvalue;
|
||||
resetError();
|
||||
pName = pGram->perform(inputName,&errState);
|
||||
retvalue = pName->printall(compiler);
|
||||
delete pName;
|
||||
return retvalue;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set substitution analysis manually to enabled or disabled.
|
||||
* @param x Boolean value. True means enable, false means disable.
|
||||
*/
|
||||
void CDemangler::setSubAnalyze(bool x) {
|
||||
pGram->setSubAnalyze(x);
|
||||
}
|
||||
|
||||
} // namespace demangler
|
|
@ -0,0 +1,82 @@
|
|||
/**
|
||||
* @file src/demangler/demtools.cpp
|
||||
* @brief Tools and extra functions for demangler.
|
||||
* @copyright (c) 2017 Avast Software, licensed under the MIT license
|
||||
*/
|
||||
|
||||
#include <ctime>
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
|
||||
#include "demangler/demtools.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
namespace demangler {
|
||||
|
||||
/**
|
||||
* @brief Function which finds out whether a file exists.
|
||||
* @param filename Name of the file to be checked.
|
||||
* @return Boolean value determining whether the file exists or not.
|
||||
*/
|
||||
bool fileExists(const std::string &filename) {
|
||||
ifstream ifile(filename);
|
||||
return ifile.is_open();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Initializes a sdate_t to default values.
|
||||
* @param x sdate_t to be initialized..
|
||||
*/
|
||||
void initSdate_t(sdate_t &x) {
|
||||
x.y = 0;
|
||||
x.m = 0;
|
||||
x.d = 0;
|
||||
x.h = 0;
|
||||
x.min = 0;
|
||||
x.s = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get stuct with current date and time.
|
||||
* @return Struct with current date and time.
|
||||
*/
|
||||
sdate_t genTimeStruct() {
|
||||
sdate_t retvalue;
|
||||
initSdate_t(retvalue);
|
||||
time_t t = time(nullptr); // get time now
|
||||
struct tm * now = localtime( & t );
|
||||
//year
|
||||
retvalue.y = now->tm_year + 1900;
|
||||
//month
|
||||
retvalue.m = (now->tm_mon + 1);
|
||||
//day
|
||||
retvalue.d = now->tm_mday;
|
||||
//hour
|
||||
retvalue.h = now->tm_hour;
|
||||
//minute
|
||||
retvalue.min = now->tm_min;
|
||||
//second
|
||||
retvalue.s = now->tm_sec;
|
||||
return retvalue;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Replaces strings "tobereplaced" in source with "replacement".
|
||||
* @param source Source string.
|
||||
* @param tobereplaced Substring which will be searched for and all of its instances will be replaced.
|
||||
* @param replacement The replacement string.
|
||||
*/
|
||||
void xreplace(string &source, const string &tobereplaced, const string &replacement) {
|
||||
std::size_t lastfound = 0;
|
||||
if (tobereplaced != "") {
|
||||
while (source.find(tobereplaced,lastfound) != source.npos) {
|
||||
lastfound = source.find(tobereplaced,lastfound);
|
||||
source.replace(source.find(tobereplaced,lastfound),tobereplaced.length(),replacement);
|
||||
lastfound += replacement.length();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace demangler
|
|
@ -0,0 +1,467 @@
|
|||
<mangled-name> ::= <template-prefix> @ <qualified-name> <sem-unq2f> <function-section> <sem-end>
|
||||
<template-prefix> ::=
|
||||
<template-section> ::= % <name-element> $ t <sem-begintempl> <sem-beginbsub> <type> <type-more-template> %
|
||||
<qualified-name> ::= <name-element> <name-element-more>
|
||||
<name-element-more> ::=
|
||||
<name-element-more> ::= @ <name-element> <name-element-more>
|
||||
<name-element> ::= @ <name-element> #double @ for __linksys__ - ignore that for now and just use qualified name
|
||||
<name-element> ::= $ <op>
|
||||
<name-element> ::= <template-section>
|
||||
<name-element> ::= <name-char> <name-char-more>
|
||||
<name-char-more> ::= <sem-storename> #no more characters in name, store the name
|
||||
<name-char-more> ::= <name-char> <name-char-more>
|
||||
<name-char> ::= <sem-addchartoname> _
|
||||
<name-char> ::= <sem-addchartoname> a
|
||||
<name-char> ::= <sem-addchartoname> b
|
||||
<name-char> ::= <sem-addchartoname> c
|
||||
<name-char> ::= <sem-addchartoname> d
|
||||
<name-char> ::= <sem-addchartoname> e
|
||||
<name-char> ::= <sem-addchartoname> f
|
||||
<name-char> ::= <sem-addchartoname> g
|
||||
<name-char> ::= <sem-addchartoname> h
|
||||
<name-char> ::= <sem-addchartoname> i
|
||||
<name-char> ::= <sem-addchartoname> j
|
||||
<name-char> ::= <sem-addchartoname> k
|
||||
<name-char> ::= <sem-addchartoname> l
|
||||
<name-char> ::= <sem-addchartoname> m
|
||||
<name-char> ::= <sem-addchartoname> n
|
||||
<name-char> ::= <sem-addchartoname> o
|
||||
<name-char> ::= <sem-addchartoname> p
|
||||
<name-char> ::= <sem-addchartoname> q
|
||||
<name-char> ::= <sem-addchartoname> r
|
||||
<name-char> ::= <sem-addchartoname> s
|
||||
<name-char> ::= <sem-addchartoname> t
|
||||
<name-char> ::= <sem-addchartoname> u
|
||||
<name-char> ::= <sem-addchartoname> v
|
||||
<name-char> ::= <sem-addchartoname> w
|
||||
<name-char> ::= <sem-addchartoname> x
|
||||
<name-char> ::= <sem-addchartoname> y
|
||||
<name-char> ::= <sem-addchartoname> z
|
||||
<name-char> ::= <sem-addchartoname> A
|
||||
<name-char> ::= <sem-addchartoname> B
|
||||
<name-char> ::= <sem-addchartoname> C
|
||||
<name-char> ::= <sem-addchartoname> D
|
||||
<name-char> ::= <sem-addchartoname> E
|
||||
<name-char> ::= <sem-addchartoname> F
|
||||
<name-char> ::= <sem-addchartoname> G
|
||||
<name-char> ::= <sem-addchartoname> H
|
||||
<name-char> ::= <sem-addchartoname> I
|
||||
<name-char> ::= <sem-addchartoname> J
|
||||
<name-char> ::= <sem-addchartoname> K
|
||||
<name-char> ::= <sem-addchartoname> L
|
||||
<name-char> ::= <sem-addchartoname> M
|
||||
<name-char> ::= <sem-addchartoname> N
|
||||
<name-char> ::= <sem-addchartoname> O
|
||||
<name-char> ::= <sem-addchartoname> P
|
||||
<name-char> ::= <sem-addchartoname> Q
|
||||
<name-char> ::= <sem-addchartoname> R
|
||||
<name-char> ::= <sem-addchartoname> S
|
||||
<name-char> ::= <sem-addchartoname> T
|
||||
<name-char> ::= <sem-addchartoname> U
|
||||
<name-char> ::= <sem-addchartoname> V
|
||||
<name-char> ::= <sem-addchartoname> W
|
||||
<name-char> ::= <sem-addchartoname> X
|
||||
<name-char> ::= <sem-addchartoname> Y
|
||||
<name-char> ::= <sem-addchartoname> Z
|
||||
<name-char> ::= <sem-addchartoname> 0
|
||||
<name-char> ::= <sem-addchartoname> 1
|
||||
<name-char> ::= <sem-addchartoname> 2
|
||||
<name-char> ::= <sem-addchartoname> 3
|
||||
<name-char> ::= <sem-addchartoname> 4
|
||||
<name-char> ::= <sem-addchartoname> 5
|
||||
<name-char> ::= <sem-addchartoname> 6
|
||||
<name-char> ::= <sem-addchartoname> 7
|
||||
<name-char> ::= <sem-addchartoname> 8
|
||||
<name-char> ::= <sem-addchartoname> 9
|
||||
<function-section> ::= <sem-setnamex>
|
||||
<function-section> ::= $ <const-vol> q <calling-convention> <parameters>
|
||||
<const-vol> ::=
|
||||
<const-vol> ::= <sem-addmconst> x <const-vol>
|
||||
<const-vol> ::= <sem-addmvol> w <const-vol>
|
||||
<calling-convention> ::=
|
||||
<calling-convention> ::= <sem-setfpascal> Q
|
||||
<calling-convention> ::= q <calling-convention-q>
|
||||
<calling-convention-q> ::= <sem-setffortran> f
|
||||
<calling-convention-q> ::= <sem-setfstdcall> s
|
||||
<calling-convention-q> ::= <sem-setffastcall> r
|
||||
<calling-convention-q> ::= <sem-setfinterrupt> i
|
||||
<parameters> ::= <sem-beginbsub> <type> <type-more>
|
||||
<type-more> ::= <sem-par2f>
|
||||
<type-more> ::= <sem-storepar> <sem-beginbsub> <type> <type-more>
|
||||
<type-more-template> ::= <sem-storetemplate>
|
||||
<type-more-template> ::= <sem-storetemparg> <sem-beginbsub> <type> <type-more-template>
|
||||
<type> ::= <sem-settypev> v #void
|
||||
<type> ::= <sem-settypec> c #char
|
||||
<type> ::= <sem-settypes> s #short int
|
||||
<type> ::= <sem-settypei> i #int
|
||||
<type> ::= <sem-settypex> j #__int64
|
||||
<type> ::= <sem-settypel> l #long int
|
||||
<type> ::= <sem-settypew> b #wchar_t
|
||||
<type> ::= <sem-settypef> f #float
|
||||
<type> ::= <sem-settyped> d #double
|
||||
<type> ::= <sem-settypee> g #long double
|
||||
<type> ::= <sem-settypeb> o #bool
|
||||
<type> ::= z <type-z>
|
||||
<type> ::= u <type-u>
|
||||
<type> ::= x <sem-setconst> <type>
|
||||
<type> ::= p <sem-setptr> <type>
|
||||
<type> ::= w <sem-setvolatile> <type>
|
||||
<type> ::= r <sem-setref> <type>
|
||||
<type> ::= t <typesub>
|
||||
<type> ::= a <array-number> $ <type>
|
||||
<array-number> ::= <sem-borlandarr> <number>
|
||||
<type> ::= <source-name>
|
||||
<type-z> ::= <sem-settypea> c #signed char
|
||||
<type-u> ::= <sem-settypeh> c #unsigned char
|
||||
<type-u> ::= <sem-settypet> s #unsigned short int
|
||||
<type-u> ::= <sem-settypej> i #unsigned int
|
||||
<type-u> ::= <sem-settypem> l #unsigned long int
|
||||
<typesub> ::= <sem-loadborlandsub> 1
|
||||
<typesub> ::= <sem-loadborlandsub> 2
|
||||
<typesub> ::= <sem-loadborlandsub> 3
|
||||
<typesub> ::= <sem-loadborlandsub> 4
|
||||
<typesub> ::= <sem-loadborlandsub> 5
|
||||
<typesub> ::= <sem-loadborlandsub> 6
|
||||
<typesub> ::= <sem-loadborlandsub> 7
|
||||
<typesub> ::= <sem-loadborlandsub> 8
|
||||
<typesub> ::= <sem-loadborlandsub> 9
|
||||
<typesub> ::= <sem-loadborlandsub> a
|
||||
<typesub> ::= <sem-loadborlandsub> b
|
||||
<typesub> ::= <sem-loadborlandsub> c
|
||||
<typesub> ::= <sem-loadborlandsub> d
|
||||
<typesub> ::= <sem-loadborlandsub> e
|
||||
<typesub> ::= <sem-loadborlandsub> f
|
||||
<typesub> ::= <sem-loadborlandsub> g
|
||||
<typesub> ::= <sem-loadborlandsub> h
|
||||
<typesub> ::= <sem-loadborlandsub> i
|
||||
<typesub> ::= <sem-loadborlandsub> j
|
||||
<typesub> ::= <sem-loadborlandsub> k
|
||||
<typesub> ::= <sem-loadborlandsub> l
|
||||
<typesub> ::= <sem-loadborlandsub> m
|
||||
<typesub> ::= <sem-loadborlandsub> n
|
||||
<typesub> ::= <sem-loadborlandsub> o
|
||||
<typesub> ::= <sem-loadborlandsub> p
|
||||
<typesub> ::= <sem-loadborlandsub> q
|
||||
<typesub> ::= <sem-loadborlandsub> r
|
||||
<typesub> ::= <sem-loadborlandsub> s
|
||||
<typesub> ::= <sem-loadborlandsub> t
|
||||
<typesub> ::= <sem-loadborlandsub> u
|
||||
<typesub> ::= <sem-loadborlandsub> v
|
||||
<typesub> ::= <sem-loadborlandsub> w
|
||||
<typesub> ::= <sem-loadborlandsub> x
|
||||
<typesub> ::= <sem-loadborlandsub> y
|
||||
<typesub> ::= <sem-loadborlandsub> z
|
||||
<source-name> ::= <source-number>
|
||||
<source-number> ::= <sem-borlandid> <number> <qualified-name> <sem-unq2p> |
|
||||
<number> ::= 0
|
||||
<number> ::= 1
|
||||
<number> ::= 2
|
||||
<number> ::= 3
|
||||
<number> ::= 4
|
||||
<number> ::= 5
|
||||
<number> ::= 6
|
||||
<number> ::= 7
|
||||
<number> ::= 8
|
||||
<number> ::= 9
|
||||
<op> ::= b <op-b>
|
||||
<op-b> ::= a <op-ba>
|
||||
<op-ba> ::= d <op-bad>
|
||||
<op-bad> ::= <sem-setnameo> <sem-setoppl> d #operator +
|
||||
<op-bad> ::= <sem-setnameo> <sem-setopad> r #operator & (unary)
|
||||
<op-ba> ::= n <op-ban>
|
||||
<op-ban> ::= <sem-setnameo> <sem-setopan> d #operator &
|
||||
<op-ba> ::= r <op-bar>
|
||||
<op-bar> ::= o <op-baro>
|
||||
<op-baro> ::= <sem-setnameo> <sem-setoppt> w #operator ->
|
||||
<op-bar> ::= w <op-barw>
|
||||
<op-barw> ::= <sem-setnameo> <sem-setoppm> m #operator ->*
|
||||
<op-ba> ::= s <op-bas>
|
||||
<op-bas> ::= <sem-setnameo> <sem-setopass> g #operator =
|
||||
<op-b> ::= c <op-bc>
|
||||
<op-bc> ::= a <op-bca>
|
||||
<op-bca> ::= l <op-bcal>
|
||||
<op-bcal> ::= <sem-setnameo> <sem-setopcl> l #operator ()
|
||||
<op-bc> ::= m <op-bcm>
|
||||
<op-bcm> ::= <sem-setnameo> <sem-setopco> p #operator ~
|
||||
<op-bc> ::= o <op-bco>
|
||||
<op-bco> ::= m <op-bcom>
|
||||
<op-bcom> ::= <sem-setnameo> <sem-setopcm> a #operator ,
|
||||
<op-bc> ::= t <op-bct>
|
||||
<op-bct> ::= <sem-setnamec> r #constructor
|
||||
<op-b> ::= d <op-bd>
|
||||
<op-bd> ::= e <op-bde>
|
||||
<op-bde> ::= <sem-setnameo> <sem-setopmm> c #operator --
|
||||
<op-bde> ::= l <op-bdel>
|
||||
<op-bdel> ::= <sem-setnameo> <sem-setopdl> e #operator delete
|
||||
<op-bd> ::= i <op-bdi>
|
||||
<op-bdi> ::= <sem-setnameo> <sem-setopdv> v #operator /
|
||||
<op-bd> ::= l <op-bdl>
|
||||
<op-bdl> ::= <sem-setnameo> <sem-setopda> a #operator delete[]
|
||||
<op-bd> ::= t <op-bdt>
|
||||
<op-bdt> ::= <sem-setnamed> r #destructor
|
||||
<op-b> ::= e <op-be>
|
||||
<op-be> ::= q <op-beq>
|
||||
<op-beq> ::= <sem-setnameo> <sem-setopeq> l #operator ==
|
||||
<op-b> ::= g <op-bg>
|
||||
<op-bg> ::= e <op-bge>
|
||||
<op-bge> ::= <sem-setnameo> <sem-setopge> q #operator >=
|
||||
<op-bg> ::= t <op-bgt>
|
||||
<op-bgt> ::= <sem-setnameo> <sem-setopgt> r #operator >
|
||||
<op-b> ::= i <op-bi>
|
||||
<op-bi> ::= n <op-bin>
|
||||
<op-bin> ::= <sem-setnameo> <sem-setoppp> c #operator ++
|
||||
<op-bin> ::= <sem-setnameo> <sem-setopde> d #operator * (unary)
|
||||
<op-b> ::= l <op-bl>
|
||||
<op-bl> ::= a <op-bla>
|
||||
<op-bla> ::= n <op-blan>
|
||||
<op-blan> ::= <sem-setnameo> <sem-setopaa> d #operator &&
|
||||
<op-bl> ::= e <op-ble>
|
||||
<op-ble> ::= <sem-setnameo> <sem-setople> q #operator <=
|
||||
<op-bl> ::= o <op-blo>
|
||||
<op-blo> ::= <sem-setnameo> <sem-setopoo> r #operator ||
|
||||
<op-bl> ::= s <op-bls>
|
||||
<op-bls> ::= <sem-setnameo> <sem-setopls> h #operator <<
|
||||
<op-bls> ::= <sem-setnameo> <sem-setoplt> s #operator <
|
||||
<op-b> ::= m <op-bm>
|
||||
<op-bm> ::= o <op-bmo>
|
||||
<op-bmo> ::= <sem-setnameo> <sem-setoprm> d #operator %
|
||||
<op-bm> ::= u <op-bmu>
|
||||
<op-bmu> ::= <sem-setnameo> <sem-setopml> l #operator *
|
||||
<op-b> ::= n <op-bn>
|
||||
<op-bn> ::= e <op-bne>
|
||||
<op-bne> ::= <sem-setnameo> <sem-setopne> q #operator !=
|
||||
<op-bne> ::= <sem-setnameo> <sem-setopnw> w #operator new
|
||||
<op-bn> ::= o <op-bno>
|
||||
<op-bno> ::= <sem-setnameo> <sem-setopnt> t #operator !
|
||||
<op-bn> ::= w <op-bnw>
|
||||
<op-bnw> ::= <sem-setnameo> <sem-setopna> a #operator new[]
|
||||
<op-b> ::= o <op-bo>
|
||||
<op-bo> ::= <sem-setnameo> <sem-setopor> r #operator |
|
||||
<op-b> ::= r <op-br>
|
||||
<op-br> ::= a <op-bra>
|
||||
<op-bra> ::= n <op-bran>
|
||||
<op-bran> ::= <sem-setnameo> <sem-setopann> d #operator &=
|
||||
<op-br> ::= d <op-brd>
|
||||
<op-brd> ::= i <op-brdi>
|
||||
<op-brdi> ::= <sem-setnameo> <sem-setopdvv> v #operator /=
|
||||
<op-br> ::= l <op-brl>
|
||||
<op-brl> ::= s <op-brls>
|
||||
<op-brls> ::= <sem-setnameo> <sem-setoplss> h #operator <<=
|
||||
<op-br> ::= m <op-brm>
|
||||
<op-brm> ::= i <op-brmi>
|
||||
<op-brmi> ::= <sem-setnameo> <sem-setopmii> n #operator -=
|
||||
<op-brm> ::= o <op-brmo>
|
||||
<op-brmo> ::= <sem-setnameo> <sem-setoprmm> d #operator %=
|
||||
<op-brm> ::= u <op-brmu>
|
||||
<op-brmu> ::= <sem-setnameo> <sem-setopmll> l #operator *=
|
||||
<op-br> ::= o <op-bro>
|
||||
<op-bro> ::= <sem-setnameo> <sem-setoporr> r #operator |=
|
||||
<op-br> ::= p <op-brp>
|
||||
<op-brp> ::= l <op-brpl>
|
||||
<op-brpl> ::= <sem-setnameo> <sem-setoppll> u #operator +=
|
||||
<op-br> ::= r <op-brr>
|
||||
<op-brr> ::= s <op-brrs>
|
||||
<op-brrs> ::= <sem-setnameo> <sem-setoprss> h #operator >>=
|
||||
<op-br> ::= s <op-brs>
|
||||
<op-brs> ::= <sem-setnameo> <sem-setoprs> h #operator >>
|
||||
<op-br> ::= x <op-brx>
|
||||
<op-brx> ::= o <op-brxo>
|
||||
<op-brxo> ::= <sem-setnameo> <sem-setopeoo> r #operator ^=
|
||||
<op-b> ::= s <op-bs>
|
||||
<op-bs> ::= u <op-bsu>
|
||||
<op-bsu> ::= b <op-bsub>
|
||||
<op-bsub> ::= <sem-setnameo> <sem-setopmi> #operator -
|
||||
<op-bsub> ::= <sem-setnameo> <sem-setopix> s #operator []
|
||||
<op-b> ::= x <op-bx>
|
||||
<op-bx> ::= o <op-bxo>
|
||||
<op-bxo> ::= <sem-setnameo> <sem-setopeo> r #operator ^
|
||||
<sem-addchartoname> ::=
|
||||
<sem-storename> ::=
|
||||
<sem-loadid> ::=
|
||||
<sem-loadarr> ::=
|
||||
<sem-ssno> ::=
|
||||
<sem-ssnest> ::=
|
||||
<sem-stunq> ::=
|
||||
<sem-loadtsub> ::=
|
||||
<sem-type2expr> ::=
|
||||
<sem-exprval> ::=
|
||||
<sem-beginexpr> ::=
|
||||
<sem-storeexpr> ::=
|
||||
<sem-copyexpr> ::=
|
||||
<sem-storepar> ::=
|
||||
<sem-begintempl> ::=
|
||||
<sem-skiptempl> ::=
|
||||
<sem-storetemparg> ::=
|
||||
<sem-storetemplate> ::=
|
||||
<sem-setnametf> ::=
|
||||
<sem-par2f> ::=
|
||||
<sem-unq2f> ::=
|
||||
<sem-unq2p> ::=
|
||||
<sem-setnamex> ::=
|
||||
<sem-setnameo> ::=
|
||||
<sem-par2spec> ::=
|
||||
<sem-par2ret> ::=
|
||||
<sem-settypev> ::=
|
||||
<sem-settypew> ::=
|
||||
<sem-settypeb> ::=
|
||||
<sem-settypec> ::=
|
||||
<sem-settypea> ::=
|
||||
<sem-settypeh> ::=
|
||||
<sem-settypes> ::=
|
||||
<sem-settypet> ::=
|
||||
<sem-settypei> ::=
|
||||
<sem-settypej> ::=
|
||||
<sem-settypel> ::=
|
||||
<sem-settypem> ::=
|
||||
<sem-settypex> ::=
|
||||
<sem-settypey> ::=
|
||||
<sem-settypen> ::=
|
||||
<sem-settypeo> ::=
|
||||
<sem-settypef> ::=
|
||||
<sem-settyped> ::=
|
||||
<sem-settypee> ::=
|
||||
<sem-settypeg> ::=
|
||||
<sem-settypez> ::=
|
||||
<sem-setrestrict> ::=
|
||||
<sem-setvolatile> ::=
|
||||
<sem-setconst> ::=
|
||||
<sem-setptr> ::=
|
||||
<sem-setref> ::=
|
||||
<sem-setrval> ::=
|
||||
<sem-setcpair> ::=
|
||||
<sem-setim> ::=
|
||||
<sem-substd> ::=
|
||||
<sem-subalc> ::=
|
||||
<sem-substr> ::=
|
||||
<sem-substrs> ::=
|
||||
<sem-subistr> ::=
|
||||
<sem-subostr> ::=
|
||||
<sem-subiostr> ::=
|
||||
<sem-loadsub> ::=
|
||||
<sem-setnamec> ::=
|
||||
<sem-setnamed> ::=
|
||||
<sem-setopnw> ::=
|
||||
<sem-setopna> ::=
|
||||
<sem-setopdl> ::=
|
||||
<sem-setopda> ::=
|
||||
<sem-setopps> ::=
|
||||
<sem-setopng> ::=
|
||||
<sem-setopad> ::=
|
||||
<sem-setopde> ::=
|
||||
<sem-setopco> ::=
|
||||
<sem-setoppl> ::=
|
||||
<sem-setopmi> ::=
|
||||
<sem-setopml> ::=
|
||||
<sem-setopdv> ::=
|
||||
<sem-setoprm> ::=
|
||||
<sem-setopan> ::=
|
||||
<sem-setopor> ::=
|
||||
<sem-setopeo> ::=
|
||||
<sem-setopass> ::=
|
||||
<sem-setoppll> ::=
|
||||
<sem-setopmii> ::=
|
||||
<sem-setopmll> ::=
|
||||
<sem-setopdvv> ::=
|
||||
<sem-setoprmm> ::=
|
||||
<sem-setopann> ::=
|
||||
<sem-setoporr> ::=
|
||||
<sem-setopeoo> ::=
|
||||
<sem-setopls> ::=
|
||||
<sem-setoprs> ::=
|
||||
<sem-setoplss> ::=
|
||||
<sem-setoprss> ::=
|
||||
<sem-setopeq> ::=
|
||||
<sem-setopne> ::=
|
||||
<sem-setoplt> ::=
|
||||
<sem-setopgt> ::=
|
||||
<sem-setople> ::=
|
||||
<sem-setopnt> ::=
|
||||
<sem-setopaa> ::=
|
||||
<sem-setopoo> ::=
|
||||
<sem-setoppp> ::=
|
||||
<sem-setopmm> ::=
|
||||
<sem-setopcm> ::=
|
||||
<sem-setoppm> ::=
|
||||
<sem-setoppt> ::=
|
||||
<sem-setopcl> ::=
|
||||
<sem-setopix> ::=
|
||||
<sem-setopge> ::=
|
||||
<sem-setopqu> ::=
|
||||
<sem-setopst> ::=
|
||||
<sem-setopsz> ::=
|
||||
<sem-setopat> ::=
|
||||
<sem-setopaz> ::=
|
||||
<sem-setopcv> ::=
|
||||
<sem-setopxx> ::=
|
||||
<sem-setnamef> ::=
|
||||
<sem-setnamevt> ::=
|
||||
<sem-reversename> ::=
|
||||
<sem-setprivate> ::=
|
||||
<sem-setpublic> ::=
|
||||
<sem-setprotected> ::=
|
||||
<sem-setfcdecl> ::=
|
||||
<sem-setfpascal> ::=
|
||||
<sem-setffortran> ::=
|
||||
<sem-setfthiscall> ::=
|
||||
<sem-setfstdcall> ::=
|
||||
<sem-setffastcall> ::=
|
||||
<sem-setfinterrupt> ::=
|
||||
<sem-setunion> ::=
|
||||
<sem-setstruct> ::=
|
||||
<sem-setclass> ::=
|
||||
<sem-setenum> ::=
|
||||
<sem-setstatic> ::=
|
||||
<sem-setvirtual> ::=
|
||||
<sem-stclconst> ::=
|
||||
<sem-stclvol> ::=
|
||||
<sem-stclfar> ::=
|
||||
<sem-stclhuge> ::=
|
||||
<sem-savenamesub> ::=
|
||||
<sem-loadnamesub> ::=
|
||||
<sem-mstemplsub> ::=
|
||||
<sem-setnamer0> ::=
|
||||
<sem-setnamer1> ::=
|
||||
<sem-setnamer2> ::=
|
||||
<sem-setnamer3> ::=
|
||||
<sem-setnamer4> ::=
|
||||
<sem-setname_a> ::=
|
||||
<sem-setname_b> ::=
|
||||
<sem-setname_c> ::=
|
||||
<sem-setname_d> ::=
|
||||
<sem-setname_e> ::=
|
||||
<sem-setname_f> ::=
|
||||
<sem-setname_g> ::=
|
||||
<sem-setname_h> ::=
|
||||
<sem-setname_i> ::=
|
||||
<sem-setname_j> ::=
|
||||
<sem-setname_k> ::=
|
||||
<sem-setname_l> ::=
|
||||
<sem-setname_m> ::=
|
||||
<sem-setname_n> ::=
|
||||
<sem-setname_o> ::=
|
||||
<sem-setname_p> ::=
|
||||
<sem-setname_q> ::=
|
||||
<sem-setname_r> ::=
|
||||
<sem-setname_s> ::=
|
||||
<sem-setname_t> ::=
|
||||
<sem-setname_u> ::=
|
||||
<sem-setname_v> ::=
|
||||
<sem-setname_w> ::=
|
||||
<sem-setname_x> ::=
|
||||
<sem-setname_y> ::=
|
||||
<sem-setname_z> ::=
|
||||
<sem-templ2tftpl> ::=
|
||||
<sem-beginbsub> ::= #begin built-in substitution
|
||||
<sem-loadbsub> ::=
|
||||
<sem-addmconst> ::=
|
||||
<sem-addmvol> ::=
|
||||
<sem-addmfar> ::=
|
||||
<sem-addmhuge> ::=
|
||||
<sem-loadmsnum> ::=
|
||||
<sem-numtorttibcd> ::=
|
||||
<sem-numtotype> ::=
|
||||
<sem-normalizeparname> ::=
|
||||
<sem-borlandid> ::=
|
||||
<sem-loadborlandsub> ::=
|
||||
<sem-borlandarr> ::=
|
||||
<sem-end> ::=
|
|
@ -0,0 +1,423 @@
|
|||
<mangled-name> ::= _ <mangled-name2>
|
||||
<mangled-name2> ::= <mangled-name3> <sem-end>
|
||||
<mangled-name2> ::= _ <mangled-name3> <sem-end>
|
||||
<mangled-name3> ::= Z <encoding>
|
||||
<encoding> ::= <name> <bare-function-type>
|
||||
<name> ::= <nested-name>
|
||||
<name> ::= <source-name> <template-args>
|
||||
<name> ::= S <name-sub> #deciding rule
|
||||
<name-sub> ::= <sem-ssno> <substitution2-t> <unqualified-name>
|
||||
<name-sub> ::= <sem-ssno> <substitution2> <template-args>
|
||||
<template-args> ::= <sem-skiptempl>
|
||||
<template-args> ::= <sem-begintempl> I <template-arg> <template-arg-more> E
|
||||
<template-args-nostore> ::= <sem-skiptempl>
|
||||
<template-args-nostore> ::= <sem-begintempl> I <template-arg-nostore> <template-arg-nostore-more> E
|
||||
<template-arg-more> ::= <sem-storetemparg> <template-arg> <template-arg-more>
|
||||
<template-arg-more> ::= <sem-storetemplate>
|
||||
<template-arg> ::= <type>
|
||||
<template-arg> ::= <expr-primary>
|
||||
<template-arg-nostore> ::= <type>
|
||||
<template-arg-nostore> ::= <expr-primary>
|
||||
<template-arg-nostore-more> ::= <sem-storetemparg> <template-arg> <template-arg-more>
|
||||
<template-arg-nostore-more> ::= <sem-templ2tftpl>
|
||||
<template-param> ::= T <template-param2>
|
||||
<template-param2> ::= <sem-loadtsub> _
|
||||
<template-param2> ::= <sem-loadtsub> <number> _ #<unscoped-name> ::= <unqualified-name> #<unscoped-name> ::= St <unqualified-name> # unused, but may be useful in the future
|
||||
<nested-name> ::= <sem-ssnest> N <CV-qualifiers> <unqualified-name> <unqualified-name-more> E
|
||||
<prefix> ::=
|
||||
<prefix> ::= <substitution>
|
||||
<prefix> ::= <template-param>
|
||||
<unqualified-function-name> ::= <unqualified-name>
|
||||
<unqualified-function-name> ::= <ctor-dtor-name> <template-args-nostore>
|
||||
<unqualified-function-name> ::= <operator-name-setname>
|
||||
<operator-name-setname> ::= <sem-setnameo> <operator-name> <template-args>
|
||||
<operator-name-setname> ::= <sem-setnameo> <operator-name-cv>
|
||||
<unqualified-name> ::= <source-name> <template-args>
|
||||
<unqualified-name> ::= <substitution> <template-args>
|
||||
<unqualified-name-more> ::= <unqualified-function-name> <unqualified-name-more>
|
||||
<unqualified-name-more> ::=
|
||||
<source-name> ::= <source-number>
|
||||
<source-number> ::= <sem-loadid> <number>
|
||||
<number> ::= 0
|
||||
<number> ::= 1
|
||||
<number> ::= 2
|
||||
<number> ::= 3
|
||||
<number> ::= 4
|
||||
<number> ::= 5
|
||||
<number> ::= 6
|
||||
<number> ::= 7
|
||||
<number> ::= 8
|
||||
<number> ::= 9
|
||||
<ctor-dtor-name> ::= <sem-setnamec> C <ctor>
|
||||
<ctor> ::= 1 # complete object constructor
|
||||
<ctor> ::= 2 # base object constructor
|
||||
<ctor> ::= 3 # complete object allocating constructor
|
||||
<ctor-dtor-name> ::= <sem-setnamed> D <dtor>
|
||||
<dtor> ::= 0 # deleting destructor
|
||||
<dtor> ::= 1 # complete object destructor
|
||||
<dtor> ::= 2 # base object destructor
|
||||
<CV-qualifiers> ::= <r> <V> <K>
|
||||
<r> ::= <sem-setrestrict> r # restrict
|
||||
<r> ::=
|
||||
<V> ::= <sem-setvolatile> V # volatile
|
||||
<V> ::=
|
||||
<K> ::= <sem-setconst> K # const
|
||||
<K> ::=
|
||||
<bare-function-type> ::= <sem-unq2f> <bare-function-type2>
|
||||
<bare-function-type2> ::= <type> <another-type> <sem-par2f>
|
||||
<bare-function-type2> ::= <sem-setnamex>
|
||||
<another-type> ::= <sem-storepar> <type> <another-type>
|
||||
<another-type> ::=
|
||||
<type> ::= <type-qualifier> <type2>
|
||||
<type-qualifier> ::=
|
||||
<type-qualifier> ::= <sem-setrestrict> r <type-qualifier>
|
||||
<type-qualifier> ::= <sem-setvolatile> V <type-qualifier>
|
||||
<type-qualifier> ::= <sem-setconst> K <type-qualifier>
|
||||
<type-qualifier> ::= <sem-setptr> P <type-qualifier>
|
||||
<type-qualifier> ::= <sem-setref> R <type-qualifier>
|
||||
<type-qualifier> ::= <sem-setrval> O <type-qualifier>
|
||||
<type-qualifier> ::= <sem-setcpair> C <type-qualifier>
|
||||
<type-qualifier> ::= <sem-setim> G <type-qualifier>
|
||||
<type2> ::= <template-param>
|
||||
<type2> ::= <builtin-type>
|
||||
<type2> ::= <class-enum-type>
|
||||
<type2> ::= <array-type>
|
||||
<array-type> ::= A <array-number> _ <type>
|
||||
<array-number> ::= <sem-loadarr> <number>
|
||||
<class-enum-type> ::= <name>
|
||||
<builtin-type> ::= <sem-settypev> v # void
|
||||
<builtin-type> ::= <sem-settypew> w # wchar_t
|
||||
<builtin-type> ::= <sem-settypeb> b # bool
|
||||
<builtin-type> ::= <sem-settypec> c # char
|
||||
<builtin-type> ::= <sem-settypea> a # signed char
|
||||
<builtin-type> ::= <sem-settypeh> h # unsigned char
|
||||
<builtin-type> ::= <sem-settypes> s # short
|
||||
<builtin-type> ::= <sem-settypet> t # unsigned short
|
||||
<builtin-type> ::= <sem-settypei> i # int
|
||||
<builtin-type> ::= <sem-settypej> j # unsigned int
|
||||
<builtin-type> ::= <sem-settypel> l # long
|
||||
<builtin-type> ::= <sem-settypem> m # unsigned long
|
||||
<builtin-type> ::= <sem-settypex> x # long long, __int64
|
||||
<builtin-type> ::= <sem-settypey> y # unsigned long long, __int64
|
||||
<builtin-type> ::= <sem-settypen> n # __int128
|
||||
<builtin-type> ::= <sem-settypeo> o # unsigned __int128
|
||||
<builtin-type> ::= <sem-settypef> f # float
|
||||
<builtin-type> ::= <sem-settyped> d # double
|
||||
<builtin-type> ::= <sem-settypee> e # long double, __float80
|
||||
<builtin-type> ::= <sem-settypeg> g # __float128
|
||||
<builtin-type> ::= <sem-settypez> z # ellipsis
|
||||
<builtin-type> ::= D <builtin-type2>
|
||||
<builtin-type2> ::= d # IEEE 754r decimal floating point (64 bits)
|
||||
<builtin-type2> ::= e # IEEE 754r decimal floating point (128 bits)
|
||||
<builtin-type2> ::= f # IEEE 754r decimal floating point (32 bits)
|
||||
<builtin-type2> ::= h # IEEE 754r half-precision floating point (16 bits)
|
||||
<builtin-type2> ::= i # char32_t
|
||||
<builtin-type2> ::= s # char16_t
|
||||
<builtin-type2> ::= a # auto (in dependent new-expressions)
|
||||
<builtin-type2> ::= n # std::nullptr_t (i.e., decltype(nullptr))
|
||||
<substitution> ::= S <subst>
|
||||
<subst> ::= <substitution2-t> # separating St
|
||||
<subst> ::= <substitution2>
|
||||
<substitution2> ::= <seq-id> _
|
||||
<substitution2> ::= <sem-loadsub> _
|
||||
<seq-id> ::= <sem-loadsub> 0
|
||||
<seq-id> ::= <sem-loadsub> 1
|
||||
<seq-id> ::= <sem-loadsub> 2
|
||||
<seq-id> ::= <sem-loadsub> 3
|
||||
<seq-id> ::= <sem-loadsub> 4
|
||||
<seq-id> ::= <sem-loadsub> 5
|
||||
<seq-id> ::= <sem-loadsub> 6
|
||||
<seq-id> ::= <sem-loadsub> 7
|
||||
<seq-id> ::= <sem-loadsub> 8
|
||||
<seq-id> ::= <sem-loadsub> 9
|
||||
<seq-id> ::= <sem-loadsub> A
|
||||
<seq-id> ::= <sem-loadsub> B
|
||||
<seq-id> ::= <sem-loadsub> C
|
||||
<seq-id> ::= <sem-loadsub> D
|
||||
<seq-id> ::= <sem-loadsub> E
|
||||
<seq-id> ::= <sem-loadsub> F
|
||||
<seq-id> ::= <sem-loadsub> G
|
||||
<seq-id> ::= <sem-loadsub> H
|
||||
<seq-id> ::= <sem-loadsub> I
|
||||
<seq-id> ::= <sem-loadsub> J
|
||||
<seq-id> ::= <sem-loadsub> K
|
||||
<seq-id> ::= <sem-loadsub> L
|
||||
<seq-id> ::= <sem-loadsub> M
|
||||
<seq-id> ::= <sem-loadsub> N
|
||||
<seq-id> ::= <sem-loadsub> O
|
||||
<seq-id> ::= <sem-loadsub> P
|
||||
<seq-id> ::= <sem-loadsub> Q
|
||||
<seq-id> ::= <sem-loadsub> R
|
||||
<seq-id> ::= <sem-loadsub> S
|
||||
<seq-id> ::= <sem-loadsub> T
|
||||
<seq-id> ::= <sem-loadsub> U
|
||||
<seq-id> ::= <sem-loadsub> V
|
||||
<seq-id> ::= <sem-loadsub> W
|
||||
<seq-id> ::= <sem-loadsub> X
|
||||
<seq-id> ::= <sem-loadsub> Y
|
||||
<seq-id> ::= <sem-loadsub> Z
|
||||
<substitution2-t> ::= <sem-substd> t # ::std::
|
||||
<substitution2> ::= <sem-subalc> a # ::std::allocator
|
||||
<substitution2> ::= <sem-substr> b # ::std::basic_string
|
||||
<substitution2> ::= <sem-substrs> s # ::std::basic_string<char,::std::char_traits<char>,::std::allocator<char>>
|
||||
<substitution2> ::= <sem-subistr> i # ::std::basic_istream<char, std::char_traits<char> >
|
||||
<substitution2> ::= <sem-subostr> o # ::std::basic_ostream<char, std::char_traits<char> >
|
||||
<substitution2> ::= <sem-subiostr> d # ::std::basic_iostream<char, std::char_traits<char> >
|
||||
<operator-name> ::= a <operator-name-a>
|
||||
<operator-name> ::= c <operator-name-c>
|
||||
<operator-name> ::= d <operator-name-d>
|
||||
<operator-name> ::= e <operator-name-e>
|
||||
<operator-name> ::= g <operator-name-g>
|
||||
<operator-name> ::= i <operator-name-i>
|
||||
<operator-name> ::= l <operator-name-l>
|
||||
<operator-name> ::= m <operator-name-m>
|
||||
<operator-name> ::= n <operator-name-n>
|
||||
<operator-name> ::= o <operator-name-o>
|
||||
<operator-name> ::= p <operator-name-p>
|
||||
<operator-name> ::= q <operator-name-q>
|
||||
<operator-name> ::= r <operator-name-r>
|
||||
<operator-name> ::= s <operator-name-s>
|
||||
<operator-name-a> ::= <sem-setopaa> a # &&
|
||||
<operator-name-a> ::= <sem-setopad> d # & (unary)
|
||||
<operator-name-a> ::= <sem-setopan> n # &
|
||||
<operator-name-a> ::= <sem-setopat> t # alignof (a type)
|
||||
<operator-name-a> ::= <sem-setopaz> z # alignof (an expression)
|
||||
<operator-name-a> ::= <sem-setopass> S # =
|
||||
<operator-name-a> ::= <sem-setopann> N # &=
|
||||
<operator-name-c> ::= <sem-setopcm> m # ,
|
||||
<operator-name-c> ::= <sem-setopcl> l # ()
|
||||
<operator-name-c> ::= <sem-setopco> o # ~
|
||||
<operator-name-cv> ::= <sem-setopcv> v <type> <sem-par2spec> # (cast)
|
||||
<operator-name-d> ::= <sem-setopdl> l # delete
|
||||
<operator-name-d> ::= <sem-setopda> a # delete[]
|
||||
<operator-name-d> ::= <sem-setopde> e # * (unary)
|
||||
<operator-name-d> ::= <sem-setopdv> v # /
|
||||
<operator-name-d> ::= <sem-setopdvv> V # /=
|
||||
<operator-name-e> ::= <sem-setopeo> o # ^
|
||||
<operator-name-e> ::= <sem-setopeoo> O # ^=
|
||||
<operator-name-e> ::= <sem-setopeq> q # ==
|
||||
<operator-name-g> ::= <sem-setopgt> t # >
|
||||
<operator-name-g> ::= <sem-setopge> e # >=
|
||||
<operator-name-i> ::= <sem-setopix> x # []
|
||||
<operator-name-l> ::= <sem-setopls> s # <<
|
||||
<operator-name-l> ::= <sem-setoplss> S # <<=
|
||||
<operator-name-l> ::= <sem-setoplt> t # <
|
||||
<operator-name-l> ::= <sem-setople> e # <=
|
||||
<operator-name-m> ::= <sem-setopmi> i # -
|
||||
<operator-name-m> ::= <sem-setopml> l # *
|
||||
<operator-name-m> ::= <sem-setopmii> I # -=
|
||||
<operator-name-m> ::= <sem-setopmll> L # *=
|
||||
<operator-name-m> ::= <sem-setopmm> m # -- (postfix in <expression> context)
|
||||
<operator-name-n> ::= <sem-setopnw> w # new
|
||||
<operator-name-n> ::= <sem-setopna> a # new[]
|
||||
<operator-name-n> ::= <sem-setopng> g # - (unary)
|
||||
<operator-name-n> ::= <sem-setopne> e # !=
|
||||
<operator-name-n> ::= <sem-setopnt> t # !
|
||||
<operator-name-o> ::= <sem-setopor> r # |
|
||||
<operator-name-o> ::= <sem-setoporr> R # |=
|
||||
<operator-name-o> ::= <sem-setopoo> o # ||
|
||||
<operator-name-p> ::= <sem-setopps> s # + (unary)
|
||||
<operator-name-p> ::= <sem-setoppl> l # +
|
||||
<operator-name-p> ::= <sem-setoppll> L # +=
|
||||
<operator-name-p> ::= <sem-setoppp> p # ++ (postfix in <expression> context)
|
||||
<operator-name-p> ::= <sem-setoppm> m # ->*
|
||||
<operator-name-p> ::= <sem-setoppt> t # ->
|
||||
<operator-name-q> ::= <sem-setopqu> u # ?
|
||||
<operator-name-r> ::= <sem-setoprm> m # %
|
||||
<operator-name-r> ::= <sem-setoprmm> M # %=
|
||||
<operator-name-r> ::= <sem-setoprs> s # >>
|
||||
<operator-name-r> ::= <sem-setoprss> S # >>=
|
||||
<operator-name-s> ::= <sem-setopst> t # sizeof (a type)
|
||||
<operator-name-s> ::= <sem-setopsz> z # sizeof (an expression)
|
||||
<expr-primary> ::= <sem-beginexpr> L <builtin-type> <sem-type2expr> <expr-number> E <sem-storeexpr>
|
||||
<expr-number> ::= <sem-exprval> <number>
|
||||
<sem-addchartoname> ::=
|
||||
<sem-storename> ::=
|
||||
<sem-loadid> ::=
|
||||
<sem-loadarr> ::=
|
||||
<sem-ssno> ::=
|
||||
<sem-ssnest> ::=
|
||||
<sem-stunq> ::=
|
||||
<sem-loadtsub> ::=
|
||||
<sem-type2expr> ::=
|
||||
<sem-exprval> ::=
|
||||
<sem-beginexpr> ::=
|
||||
<sem-storeexpr> ::=
|
||||
<sem-copyexpr> ::=
|
||||
<sem-storepar> ::=
|
||||
<sem-begintempl> ::=
|
||||
<sem-skiptempl> ::=
|
||||
<sem-storetemparg> ::=
|
||||
<sem-storetemplate> ::=
|
||||
<sem-setnametf> ::=
|
||||
<sem-par2f> ::=
|
||||
<sem-unq2f> ::=
|
||||
<sem-unq2p> ::=
|
||||
<sem-setnamex> ::=
|
||||
<sem-setnameo> ::=
|
||||
<sem-par2spec> ::=
|
||||
<sem-par2ret> ::=
|
||||
<sem-settypev> ::=
|
||||
<sem-settypew> ::=
|
||||
<sem-settypeb> ::=
|
||||
<sem-settypec> ::=
|
||||
<sem-settypea> ::=
|
||||
<sem-settypeh> ::=
|
||||
<sem-settypes> ::=
|
||||
<sem-settypet> ::=
|
||||
<sem-settypei> ::=
|
||||
<sem-settypej> ::=
|
||||
<sem-settypel> ::=
|
||||
<sem-settypem> ::=
|
||||
<sem-settypex> ::=
|
||||
<sem-settypey> ::=
|
||||
<sem-settypen> ::=
|
||||
<sem-settypeo> ::=
|
||||
<sem-settypef> ::=
|
||||
<sem-settyped> ::=
|
||||
<sem-settypee> ::=
|
||||
<sem-settypeg> ::=
|
||||
<sem-settypez> ::=
|
||||
<sem-setrestrict> ::=
|
||||
<sem-setvolatile> ::=
|
||||
<sem-setconst> ::=
|
||||
<sem-setptr> ::=
|
||||
<sem-setref> ::=
|
||||
<sem-setrval> ::=
|
||||
<sem-setcpair> ::=
|
||||
<sem-setim> ::=
|
||||
<sem-substd> ::=
|
||||
<sem-subalc> ::=
|
||||
<sem-substr> ::=
|
||||
<sem-substrs> ::=
|
||||
<sem-subistr> ::=
|
||||
<sem-subostr> ::=
|
||||
<sem-subiostr> ::=
|
||||
<sem-loadsub> ::=
|
||||
<sem-setnamec> ::=
|
||||
<sem-setnamed> ::=
|
||||
<sem-setopnw> ::=
|
||||
<sem-setopna> ::=
|
||||
<sem-setopdl> ::=
|
||||
<sem-setopda> ::=
|
||||
<sem-setopps> ::=
|
||||
<sem-setopng> ::=
|
||||
<sem-setopad> ::=
|
||||
<sem-setopde> ::=
|
||||
<sem-setopco> ::=
|
||||
<sem-setoppl> ::=
|
||||
<sem-setopmi> ::=
|
||||
<sem-setopml> ::=
|
||||
<sem-setopdv> ::=
|
||||
<sem-setoprm> ::=
|
||||
<sem-setopan> ::=
|
||||
<sem-setopor> ::=
|
||||
<sem-setopeo> ::=
|
||||
<sem-setopass> ::=
|
||||
<sem-setoppll> ::=
|
||||
<sem-setopmii> ::=
|
||||
<sem-setopmll> ::=
|
||||
<sem-setopdvv> ::=
|
||||
<sem-setoprmm> ::=
|
||||
<sem-setopann> ::=
|
||||
<sem-setoporr> ::=
|
||||
<sem-setopeoo> ::=
|
||||
<sem-setopls> ::=
|
||||
<sem-setoprs> ::=
|
||||
<sem-setoplss> ::=
|
||||
<sem-setoprss> ::=
|
||||
<sem-setopeq> ::=
|
||||
<sem-setopne> ::=
|
||||
<sem-setoplt> ::=
|
||||
<sem-setopgt> ::=
|
||||
<sem-setople> ::=
|
||||
<sem-setopnt> ::=
|
||||
<sem-setopaa> ::=
|
||||
<sem-setopoo> ::=
|
||||
<sem-setoppp> ::=
|
||||
<sem-setopmm> ::=
|
||||
<sem-setopcm> ::=
|
||||
<sem-setoppm> ::=
|
||||
<sem-setoppt> ::=
|
||||
<sem-setopcl> ::=
|
||||
<sem-setopix> ::=
|
||||
<sem-setopge> ::=
|
||||
<sem-setopqu> ::=
|
||||
<sem-setopst> ::=
|
||||
<sem-setopsz> ::=
|
||||
<sem-setopat> ::=
|
||||
<sem-setopaz> ::=
|
||||
<sem-setopcv> ::=
|
||||
<sem-setopxx> ::=
|
||||
<sem-setnamef> ::=
|
||||
<sem-setnamevt> ::=
|
||||
<sem-reversename> ::=
|
||||
<sem-setprivate> ::=
|
||||
<sem-setpublic> ::=
|
||||
<sem-setprotected> ::=
|
||||
<sem-setfcdecl> ::=
|
||||
<sem-setfpascal> ::=
|
||||
<sem-setffortran> ::=
|
||||
<sem-setfthiscall> ::=
|
||||
<sem-setfstdcall> ::=
|
||||
<sem-setffastcall> ::=
|
||||
<sem-setfinterrupt> ::=
|
||||
<sem-setunion> ::=
|
||||
<sem-setstruct> ::=
|
||||
<sem-setclass> ::=
|
||||
<sem-setenum> ::=
|
||||
<sem-setstatic> ::=
|
||||
<sem-setvirtual> ::=
|
||||
<sem-stclconst> ::=
|
||||
<sem-stclvol> ::=
|
||||
<sem-stclfar> ::=
|
||||
<sem-stclhuge> ::=
|
||||
<sem-savenamesub> ::=
|
||||
<sem-loadnamesub> ::=
|
||||
<sem-mstemplsub> ::=
|
||||
<sem-setnamer0> ::=
|
||||
<sem-setnamer1> ::=
|
||||
<sem-setnamer2> ::=
|
||||
<sem-setnamer3> ::=
|
||||
<sem-setnamer4> ::=
|
||||
<sem-setname_a> ::=
|
||||
<sem-setname_b> ::=
|
||||
<sem-setname_c> ::=
|
||||
<sem-setname_d> ::=
|
||||
<sem-setname_e> ::=
|
||||
<sem-setname_f> ::=
|
||||
<sem-setname_g> ::=
|
||||
<sem-setname_h> ::=
|
||||
<sem-setname_i> ::=
|
||||
<sem-setname_j> ::=
|
||||
<sem-setname_k> ::=
|
||||
<sem-setname_l> ::=
|
||||
<sem-setname_m> ::=
|
||||
<sem-setname_n> ::=
|
||||
<sem-setname_o> ::=
|
||||
<sem-setname_p> ::=
|
||||
<sem-setname_q> ::=
|
||||
<sem-setname_r> ::=
|
||||
<sem-setname_s> ::=
|
||||
<sem-setname_t> ::=
|
||||
<sem-setname_u> ::=
|
||||
<sem-setname_v> ::=
|
||||
<sem-setname_w> ::=
|
||||
<sem-setname_x> ::=
|
||||
<sem-setname_y> ::=
|
||||
<sem-setname_z> ::=
|
||||
<sem-templ2tftpl> ::=
|
||||
<sem-beginbsub> ::= #begin built-in substitution
|
||||
<sem-loadbsub> ::=
|
||||
<sem-addmconst> ::=
|
||||
<sem-addmvol> ::=
|
||||
<sem-addmfar> ::=
|
||||
<sem-addmhuge> ::=
|
||||
<sem-loadmsnum> ::=
|
||||
<sem-numtorttibcd> ::=
|
||||
<sem-numtotype> ::=
|
||||
<sem-normalizeparname> ::=
|
||||
<sem-borlandid> ::=
|
||||
<sem-loadborlandsub> ::=
|
||||
<sem-borlandarr> ::=
|
||||
<sem-end> ::=
|
|
@ -0,0 +1,534 @@
|
|||
<mangled-name> ::= ? <mangled-name-2>
|
||||
<mangled-name-2> ::= ? <mangled-name-qs>
|
||||
<mangled-name-qs> ::= _ <mangled-name-qssub>
|
||||
<mangled-name-qs> ::= 0 <name-cover> <sem-setnamec> <sem-unq2f> <modif> <const-vol> <calling-conv> @ <parameters> <terma> Z <sem-end>
|
||||
<mangled-name-qs> ::= 1 <name-cover> <sem-setnamed> <sem-unq2f> <modif> <const-vol> <calling-conv> @ <parameters> <terma>Z <sem-end>
|
||||
<mangled-name-qs> ::= <sem-setnameo> <optype> <name-cover> <sem-unq2f> <mangled-name-data>
|
||||
<optype> ::= <sem-setopdl> 3
|
||||
<optype> ::= <sem-setopix> A
|
||||
<optype> ::= <sem-setopcl> R
|
||||
<optype> ::= <sem-setoppt> C
|
||||
<optype> ::= <sem-setoppp> E
|
||||
<optype> ::= <sem-setopmm> F
|
||||
<optype> ::= <sem-setopnw> 2
|
||||
<optype> ::= <sem-setopde> D
|
||||
<optype> ::= <sem-setopad> I
|
||||
<optype> ::= <sem-setopps> H
|
||||
<optype> ::= <sem-setopng> G
|
||||
<optype> ::= <sem-setopnt> 7
|
||||
<optype> ::= <sem-setopco> S
|
||||
<optype> ::= <sem-setoppm> J
|
||||
<optype> ::= <sem-setopdv> K
|
||||
<optype> ::= <sem-setoprm> L
|
||||
<optype> ::= <sem-setopls> 6
|
||||
<optype> ::= <sem-setoprs> 5
|
||||
<optype> ::= <sem-setoplt> M
|
||||
<optype> ::= <sem-setopgt> O
|
||||
<optype> ::= <sem-setople> N
|
||||
<optype> ::= <sem-setopge> P
|
||||
<optype> ::= <sem-setopeq> 8
|
||||
<optype> ::= <sem-setopne> 9
|
||||
<optype> ::= <sem-setopor> U
|
||||
<optype> ::= <sem-setopeo> T
|
||||
<optype> ::= <sem-setopaa> V
|
||||
<optype> ::= <sem-setopoo> W
|
||||
<optype> ::= <sem-setopass> 4
|
||||
<optype> ::= <sem-setopmll> X
|
||||
<optype> ::= <sem-setoppll> Y
|
||||
<optype> ::= <sem-setopmii> Z
|
||||
<optype> ::= <sem-setopcm> Q
|
||||
<optype> ::= <sem-setopcv> B
|
||||
<optype_> ::= <sem-setopna> U
|
||||
<optype_> ::= <sem-setopda> V
|
||||
<optype_> ::= <sem-setopdvv> 0
|
||||
<optype_> ::= <sem-setoprmm> 1
|
||||
<optype_> ::= <sem-setoprss> 2
|
||||
<optype_> ::= <sem-setoplss> 3
|
||||
<optype_> ::= <sem-setopann> 4
|
||||
<optype_> ::= <sem-setoporr> 5
|
||||
<optype_> ::= <sem-setopeoo> 6
|
||||
<terma> ::=
|
||||
<terma> ::= @
|
||||
<mangled-name-qssub> ::= 7 <name-cover> <sem-setnamevt> <sem-unq2f> <mangled-name-data>
|
||||
<mangled-name-qssub> ::= R <mangled-name-qssub-r>
|
||||
<mangled-name-qssub-r> ::= <r-num> <name-cover> <sem-unq2f> 8 <sem-end>
|
||||
<mangled-name-qssub-r> ::= <sem-setnamer4> 4 <name-cover> <sem-unq2f> <mangled-name-data>
|
||||
<mangled-name-qssub-r> ::= <sem-setnamer1> 1 <sem-loadmsnum> <msnum> <sem-numtorttibcd> <sem-loadmsnum> <msnum> <sem-numtorttibcd> <sem-loadmsnum> <msnum> <sem-numtorttibcd> <sem-loadmsnum> <msnum> <sem-numtorttibcd> <name-cover> <sem-unq2f> <terma> 8 <sem-end>
|
||||
<mangled-name-qssub-r> ::= <sem-setnamer0> 0 <storage-return> <type> <sem-par2ret> @ 8 <sem-end>
|
||||
<r-num> ::= <sem-setnamer2> 2
|
||||
<r-num> ::= <sem-setnamer3> 3
|
||||
<mangled-name-qssub> ::= <sem-setnameo> <optype_> <name-cover> <sem-unq2f> <mangled-name-data>
|
||||
<mangled-name-qssub> ::= <qssub> <name-cover> <sem-unq2f> <mangled-name-data>
|
||||
<qssub> ::= <sem-setname_a> A
|
||||
<qssub> ::= <sem-setname_b> B
|
||||
<qssub> ::= <sem-setname_d> D
|
||||
<qssub> ::= <sem-setname_e> E
|
||||
<qssub> ::= <sem-setname_f> F
|
||||
<qssub> ::= <sem-setname_g> G
|
||||
<qssub> ::= <sem-setname_h> H
|
||||
<qssub> ::= <sem-setname_i> I
|
||||
<qssub> ::= <sem-setname_j> J
|
||||
<qssub> ::= <sem-setname_k> K
|
||||
<qssub> ::= <sem-setname_l> L
|
||||
<qssub> ::= <sem-setname_m> M
|
||||
<qssub> ::= <sem-setname_n> N
|
||||
<qssub> ::= <sem-setname_o> O
|
||||
<qssub> ::= <sem-setname_q> Q
|
||||
<qssub> ::= <sem-setname_s> S
|
||||
<qssub> ::= <sem-setname_t> T
|
||||
<qssub> ::= <sem-setname_x> X
|
||||
<qssub> ::= <sem-setname_y> Y
|
||||
<storage-return> ::=
|
||||
<storage-return> ::= ? <storage-return-2>
|
||||
<storage-return-2> ::= A
|
||||
<storage-return-2> ::= <sem-setconst> B
|
||||
<storage-return-2> ::= <sem-setvol> C
|
||||
<storage-return-2> ::= <sem-setconst> <sem-setvol> D
|
||||
<mangled-name-qs> ::= <name-cover-qs> <sem-unq2f> <mangled-name-data>
|
||||
<mangled-name-2> ::= <name-cover-noqs> <sem-unq2f> <mangled-name-data>
|
||||
<mangled-name-data> ::= <data-object> <sem-end>
|
||||
<mangled-name-data> ::= <modif> <const-vol> <calling-conv> <storage-return> <type> <sem-par2ret> <parameters> <terma> Z <sem-end>
|
||||
<mangled-name-data> ::= <near-far> <calling-conv> <storage-return> <type> <sem-par2ret> <parameters> <terma> Z <sem-end>
|
||||
<data-object> ::= 6 <storage-class> <terma>
|
||||
<data-object> ::= 3 <sem-setnamex> <type> <sem-par2ret> <storage-class> #global object
|
||||
<data-object> ::= 2 <sem-setnamex> <sem-setpublic> <sem-setstatic> <type> <sem-par2ret> <storage-class> #static class member object
|
||||
<data-object> ::= 1 <sem-setnamex> <sem-setprotected> <sem-setstatic> <type> <sem-par2ret> <storage-class> #static class member object
|
||||
<data-object> ::= 0 <sem-setnamex> <sem-setprivate> <sem-setstatic> <type> <sem-par2ret> <storage-class> #static class member object
|
||||
<msnum> ::= ?
|
||||
<msnum> ::= 0
|
||||
<msnum> ::= 1
|
||||
<msnum> ::= 2
|
||||
<msnum> ::= 3
|
||||
<msnum> ::= 4
|
||||
<msnum> ::= 5
|
||||
<msnum> ::= 6
|
||||
<msnum> ::= 7
|
||||
<msnum> ::= 8
|
||||
<msnum> ::= 9
|
||||
<msnum> ::= A
|
||||
<msnum> ::= B
|
||||
<msnum> ::= C
|
||||
<msnum> ::= D
|
||||
<msnum> ::= E
|
||||
<msnum> ::= F
|
||||
<msnum> ::= G
|
||||
<msnum> ::= H
|
||||
<msnum> ::= I
|
||||
<msnum> ::= J
|
||||
<msnum> ::= K
|
||||
<msnum> ::= L
|
||||
<msnum> ::= M
|
||||
<msnum> ::= N
|
||||
<msnum> ::= O
|
||||
<msnum> ::= P
|
||||
<storage-class> ::= Q1@ #member pointers, member function pointers
|
||||
<storage-class> ::= A #near
|
||||
<storage-class> ::= <sem-stclconst> B #const
|
||||
<storage-class> ::= <sem-stclvol> C #volatile
|
||||
<storage-class> ::= <sem-stclconst> <sem-stclvol> D #const volatile
|
||||
<storage-class> ::= <sem-stclfar> E #far
|
||||
<storage-class> ::= <sem-stclconst> <sem-stclfar> F #const far
|
||||
<storage-class> ::= <sem-stclvol> <sem-stclfar> G #volatile far
|
||||
<storage-class> ::= <sem-stclconst> <sem-stclvol> <sem-stclfar> H #const volatile far
|
||||
<storage-class> ::= <sem-stclhuge> I #huge
|
||||
<modif> ::= <sem-setprivate> A #private default
|
||||
<modif> ::= <sem-setprivate> B #private far
|
||||
<modif> ::= <sem-setprivate> <sem-setstatic> C #private static
|
||||
<modif> ::= <sem-setprivate> <sem-setstatic> D #private static far
|
||||
<modif> ::= <sem-setprivate> <sem-setvirtual> E #private virtual
|
||||
<modif> ::= <sem-setprivate> <sem-setvirtual> F #private virtual far
|
||||
<modif> ::= <sem-setprotected> I #protected default
|
||||
<modif> ::= <sem-setprotected> J #protected far
|
||||
<modif> ::= <sem-setprotected> <sem-setstatic> K #protected static
|
||||
<modif> ::= <sem-setprotected> <sem-setstatic> L #protected static far
|
||||
<modif> ::= <sem-setprotected> <sem-setvirtual> M #protected virtual
|
||||
<modif> ::= <sem-setprotected> <sem-setvirtual> N #protected virtual far
|
||||
<modif> ::= <sem-setpublic> Q #public default
|
||||
<modif> ::= <sem-setpublic> R #public far
|
||||
<modif> ::= <sem-setpublic> <sem-setstatic> S #public static
|
||||
<modif> ::= <sem-setpublic> <sem-setstatic> T #public static far
|
||||
<modif> ::= <sem-setpublic> <sem-setvirtual> U #public virtual
|
||||
<modif> ::= <sem-setpublic> <sem-setvirtual> V #public virtual far
|
||||
<const-vol-e> ::=
|
||||
<const-vol-e> ::= <const-vol>
|
||||
<const-vol> ::= A #default
|
||||
<const-vol> ::= <sem-addmconst> B #const
|
||||
<const-vol> ::= <sem-addmvol> C #volatile
|
||||
<const-vol> ::= <sem-addmconst> <sem-addmvol> D #const volatile
|
||||
<calling-conv> ::= <sem-setfcdecl> A #__cdecl
|
||||
<calling-conv> ::= <sem-setfpascal> C #__pascal
|
||||
<calling-conv> ::= <sem-setfthiscall> E #__thiscall
|
||||
<calling-conv> ::= <sem-setfstdcall> G #__stdcall
|
||||
<calling-conv> ::= <sem-setffastcall> I #__fastcall
|
||||
<name-cover-qs> ::= <name-qs> @ <namespace-x> @
|
||||
<name-cover-noqs> ::= <name-element-noqs> <namespace-x> @
|
||||
<name-cover> ::= <name-element> <namespace-x> @
|
||||
<name-cover> ::= @
|
||||
<name-element> ::= <name> @
|
||||
<name-element> ::= <name-sub>
|
||||
<name-element-noqs> ::= <name-noqs> @
|
||||
<name-element-noqs> ::= <name-sub>
|
||||
<name-sub> ::= <sem-loadnamesub> 0
|
||||
<name-sub> ::= <sem-loadnamesub> 1
|
||||
<name-sub> ::= <sem-loadnamesub> 2
|
||||
<name-sub> ::= <sem-loadnamesub> 3
|
||||
<name-sub> ::= <sem-loadnamesub> 4
|
||||
<name-sub> ::= <sem-loadnamesub> 5
|
||||
<name-sub> ::= <sem-loadnamesub> 6
|
||||
<name-sub> ::= <sem-loadnamesub> 7
|
||||
<name-sub> ::= <sem-loadnamesub> 8
|
||||
<name-sub> ::= <sem-loadnamesub> 9
|
||||
<name-elemental> ::= <name-char-first> <name-char-more>
|
||||
<template-header> ::= <name-elemental> @
|
||||
<template-header> ::= ? <template-op>
|
||||
<template-op> ::= <sem-setnameo> <optype>
|
||||
<template-op> ::= <sem-setnameo> _ <optype_>
|
||||
<name-qs> ::= $ <template-header> <sem-begintempl> <sem-mstemplsub> <template-arg> <template-arg-more> <sem-savenamesub>
|
||||
<name-noqs> ::= <name-elemental> <sem-savenamesub>
|
||||
<name> ::= ? <name-qs>
|
||||
<name> ::= <name-noqs>
|
||||
<name-char-more> ::= <name-char> <name-char-more>
|
||||
<name-char-more> ::= <name-char-first> <name-char-more>
|
||||
<name-char-more> ::= <sem-storename>
|
||||
<namespace-x> ::= <sem-reversename>
|
||||
<namespace-x> ::= <name-element> <namespace-x>
|
||||
<template-arg-more> ::= <sem-storetemplate>
|
||||
<template-arg-more> ::= <sem-storetemparg> <template-arg> <template-arg-more>
|
||||
<template-arg> ::= <type>
|
||||
<parameters> ::= <parameter> <parameter-more>
|
||||
<parameter> ::= <type>
|
||||
<parameter-more> ::= <sem-storepar> <parameter> <parameter-more>
|
||||
<parameter-more> ::= <sem-par2f>
|
||||
<near-far> ::= Y #near
|
||||
<near-far> ::= Z #far
|
||||
<name-char-first> ::= <sem-addchartoname> _
|
||||
<name-char-first> ::= <sem-addchartoname> a
|
||||
<name-char-first> ::= <sem-addchartoname> b
|
||||
<name-char-first> ::= <sem-addchartoname> c
|
||||
<name-char-first> ::= <sem-addchartoname> d
|
||||
<name-char-first> ::= <sem-addchartoname> e
|
||||
<name-char-first> ::= <sem-addchartoname> f
|
||||
<name-char-first> ::= <sem-addchartoname> g
|
||||
<name-char-first> ::= <sem-addchartoname> h
|
||||
<name-char-first> ::= <sem-addchartoname> i
|
||||
<name-char-first> ::= <sem-addchartoname> j
|
||||
<name-char-first> ::= <sem-addchartoname> k
|
||||
<name-char-first> ::= <sem-addchartoname> l
|
||||
<name-char-first> ::= <sem-addchartoname> m
|
||||
<name-char-first> ::= <sem-addchartoname> n
|
||||
<name-char-first> ::= <sem-addchartoname> o
|
||||
<name-char-first> ::= <sem-addchartoname> p
|
||||
<name-char-first> ::= <sem-addchartoname> q
|
||||
<name-char-first> ::= <sem-addchartoname> r
|
||||
<name-char-first> ::= <sem-addchartoname> s
|
||||
<name-char-first> ::= <sem-addchartoname> t
|
||||
<name-char-first> ::= <sem-addchartoname> u
|
||||
<name-char-first> ::= <sem-addchartoname> v
|
||||
<name-char-first> ::= <sem-addchartoname> w
|
||||
<name-char-first> ::= <sem-addchartoname> x
|
||||
<name-char-first> ::= <sem-addchartoname> y
|
||||
<name-char-first> ::= <sem-addchartoname> z
|
||||
<name-char-first> ::= <sem-addchartoname> A
|
||||
<name-char-first> ::= <sem-addchartoname> B
|
||||
<name-char-first> ::= <sem-addchartoname> C
|
||||
<name-char-first> ::= <sem-addchartoname> D
|
||||
<name-char-first> ::= <sem-addchartoname> E
|
||||
<name-char-first> ::= <sem-addchartoname> F
|
||||
<name-char-first> ::= <sem-addchartoname> G
|
||||
<name-char-first> ::= <sem-addchartoname> H
|
||||
<name-char-first> ::= <sem-addchartoname> I
|
||||
<name-char-first> ::= <sem-addchartoname> J
|
||||
<name-char-first> ::= <sem-addchartoname> K
|
||||
<name-char-first> ::= <sem-addchartoname> L
|
||||
<name-char-first> ::= <sem-addchartoname> M
|
||||
<name-char-first> ::= <sem-addchartoname> N
|
||||
<name-char-first> ::= <sem-addchartoname> O
|
||||
<name-char-first> ::= <sem-addchartoname> P
|
||||
<name-char-first> ::= <sem-addchartoname> Q
|
||||
<name-char-first> ::= <sem-addchartoname> R
|
||||
<name-char-first> ::= <sem-addchartoname> S
|
||||
<name-char-first> ::= <sem-addchartoname> T
|
||||
<name-char-first> ::= <sem-addchartoname> U
|
||||
<name-char-first> ::= <sem-addchartoname> V
|
||||
<name-char-first> ::= <sem-addchartoname> W
|
||||
<name-char-first> ::= <sem-addchartoname> X
|
||||
<name-char-first> ::= <sem-addchartoname> Y
|
||||
<name-char-first> ::= <sem-addchartoname> Z
|
||||
<name-char> ::= <sem-addchartoname> 0
|
||||
<name-char> ::= <sem-addchartoname> 1
|
||||
<name-char> ::= <sem-addchartoname> 2
|
||||
<name-char> ::= <sem-addchartoname> 3
|
||||
<name-char> ::= <sem-addchartoname> 4
|
||||
<name-char> ::= <sem-addchartoname> 5
|
||||
<name-char> ::= <sem-addchartoname> 6
|
||||
<name-char> ::= <sem-addchartoname> 7
|
||||
<name-char> ::= <sem-addchartoname> 8
|
||||
<name-char> ::= <sem-addchartoname> 9
|
||||
<name-char> ::= <sem-addchartoname> $
|
||||
<type> ::= <typesub>
|
||||
<type> ::= _ <sem-beginbsub> <type_>
|
||||
<type> ::= $ <type-ds>
|
||||
<type-ds> ::= $ <type-dsds>
|
||||
<type-ds> ::= 0 <sem-loadmsnum> <msnum> <sem-numtotype>
|
||||
<type-dsds> ::= C <dsds-modifier> <type>
|
||||
<dsds-modifier> ::= A
|
||||
<dsds-modifier> ::= <sem-setconst> B
|
||||
<dsds-modifier> ::= <sem-setvolatile> C
|
||||
<dsds-modifier> ::= <sem-setvolatile> <sem-setconst> D
|
||||
<dsds-modifier> ::= E
|
||||
<dsds-modifier> ::= F
|
||||
<dsds-modifier> ::= <sem-setvolatile> G
|
||||
<dsds-modifier> ::= <sem-setvolatile> <sem-setconst> H
|
||||
<dsds-modifier> ::= I
|
||||
<dsds-modifier> ::= <sem-setconst> J
|
||||
<dsds-modifier> ::= <sem-setvolatile> K
|
||||
<dsds-modifier> ::= <sem-setvolatile> <sem-setconst> L
|
||||
<typesub> ::= <sem-loadbsub> 0
|
||||
<typesub> ::= <sem-loadbsub> 1
|
||||
<typesub> ::= <sem-loadbsub> 2
|
||||
<typesub> ::= <sem-loadbsub> 3
|
||||
<typesub> ::= <sem-loadbsub> 4
|
||||
<typesub> ::= <sem-loadbsub> 5
|
||||
<typesub> ::= <sem-loadbsub> 6
|
||||
<typesub> ::= <sem-loadbsub> 7
|
||||
<typesub> ::= <sem-loadbsub> 8
|
||||
<typesub> ::= <sem-loadbsub> 9
|
||||
<type> ::= <sem-settypev> X #void
|
||||
<type> ::= <sem-settypec> D #char
|
||||
<type> ::= <sem-settypea> C #signed char
|
||||
<type> ::= <sem-settypeh> E #unsigned char
|
||||
<type> ::= <sem-settypes> F #short int
|
||||
<type> ::= <sem-settypet> G #unsigned short int
|
||||
<type> ::= <sem-settypei> H #int
|
||||
<type> ::= <sem-settypej> I #unsigned int
|
||||
<type> ::= <sem-settypel> J #long int
|
||||
<type> ::= <sem-settypem> K #unsigned long int
|
||||
<type> ::= <sem-settypef> M #float
|
||||
<type> ::= <sem-settyped> N #double
|
||||
<type> ::= <sem-settypee> O #long double (64-bit precision)
|
||||
<type> ::= T <sem-beginbsub> <type-t>
|
||||
<type> ::= U <sem-beginbsub> <type-u>
|
||||
<type> ::= V <sem-beginbsub> <sem-setclass> <name-cover> <sem-unq2p> #class
|
||||
<type> ::= W <sem-beginbsub> <type-w>
|
||||
<type-t> ::= <sem-setunion> <name-cover> <sem-unq2p> #union
|
||||
<type-u> ::= <sem-setstruct> <name-cover> <sem-unq2p> #struct
|
||||
<type-w> ::= 4 <sem-setenum> <name-cover> <sem-unq2p> #enum
|
||||
<type> ::= P <e> <sem-beginbsub> <type-pe> <type>
|
||||
<type> ::= Q <e> <sem-beginbsub> <type-qe> <type>
|
||||
<type> ::= R <e> <sem-beginbsub> <type-re> <type>
|
||||
<type> ::= S <e> <sem-beginbsub> <type-se> <type>
|
||||
<type> ::= A <e> <sem-beginbsub> <type-ae> <type>
|
||||
<type-pe> ::= <sem-setptr> A #X *
|
||||
<type-pe> ::= <sem-setptr> <sem-setconst> B #const X *
|
||||
<type-pe> ::= <sem-setptr> <sem-setvolatile> C #volatile X *
|
||||
<type-pe> ::= <sem-setptr> <sem-setvolatile> <sem-setconst> D #const volatile X *
|
||||
<type-qe> ::= <sem-setptr> A #X * const
|
||||
<type-qe> ::= <sem-setptr> <sem-setconst> B #const X * const
|
||||
<type-qe> ::= <sem-setptr> <sem-setvolatile> C #volatile X *
|
||||
<type-qe> ::= <sem-setptr> <sem-setvolatile> <sem-setconst> D #const volatile X *
|
||||
<type-re> ::= A #X * volatile
|
||||
<type-se> ::= A #X * const volatile
|
||||
<type-pe> ::= IA #X * __restrict
|
||||
<type-ae> ::= <sem-setref> A #X &
|
||||
<type-ae> ::= <sem-setref> <sem-setconst> B #const X &
|
||||
<type-ae> ::= <sem-setref> <sem-setvolatile> C #volatile X &
|
||||
<type-ae> ::= <sem-setref> <sem-setvolatile> <sem-setconst> D #const volatile X &
|
||||
<type-pa> ::= #X[] (as global object)
|
||||
<type_> ::= <sem-settypeb> N #bool
|
||||
<type_> ::= <sem-settypex> J #long long (__int64)
|
||||
<type_> ::= <sem-settypey> K #unsigned long long (unsigned __int64)
|
||||
<type_> ::= <sem-settypew> W #wchar_t
|
||||
<type_> ::= T #long double (80-bit precision Intel compiler)
|
||||
<type_> ::= Z #long double (80-bit precision Symantec/Digital Mars compiler)
|
||||
<e> ::= E
|
||||
<e> ::=
|
||||
<sem-addchartoname> ::=
|
||||
<sem-storename> ::=
|
||||
<sem-loadid> ::=
|
||||
<sem-loadarr> ::=
|
||||
<sem-ssno> ::=
|
||||
<sem-ssnest> ::=
|
||||
<sem-stunq> ::=
|
||||
<sem-loadtsub> ::=
|
||||
<sem-type2expr> ::=
|
||||
<sem-exprval> ::=
|
||||
<sem-beginexpr> ::=
|
||||
<sem-storeexpr> ::=
|
||||
<sem-copyexpr> ::=
|
||||
<sem-storepar> ::=
|
||||
<sem-begintempl> ::=
|
||||
<sem-skiptempl> ::=
|
||||
<sem-storetemparg> ::=
|
||||
<sem-storetemplate> ::=
|
||||
<sem-setnametf> ::=
|
||||
<sem-par2f> ::=
|
||||
<sem-unq2f> ::=
|
||||
<sem-unq2p> ::=
|
||||
<sem-setnamex> ::=
|
||||
<sem-setnameo> ::=
|
||||
<sem-par2spec> ::=
|
||||
<sem-par2ret> ::=
|
||||
<sem-settypev> ::=
|
||||
<sem-settypew> ::=
|
||||
<sem-settypeb> ::=
|
||||
<sem-settypec> ::=
|
||||
<sem-settypea> ::=
|
||||
<sem-settypeh> ::=
|
||||
<sem-settypes> ::=
|
||||
<sem-settypet> ::=
|
||||
<sem-settypei> ::=
|
||||
<sem-settypej> ::=
|
||||
<sem-settypel> ::=
|
||||
<sem-settypem> ::=
|
||||
<sem-settypex> ::=
|
||||
<sem-settypey> ::=
|
||||
<sem-settypen> ::=
|
||||
<sem-settypeo> ::=
|
||||
<sem-settypef> ::=
|
||||
<sem-settyped> ::=
|
||||
<sem-settypee> ::=
|
||||
<sem-settypeg> ::=
|
||||
<sem-settypez> ::=
|
||||
<sem-setrestrict> ::=
|
||||
<sem-setvolatile> ::=
|
||||
<sem-setconst> ::=
|
||||
<sem-setptr> ::=
|
||||
<sem-setref> ::=
|
||||
<sem-setrval> ::=
|
||||
<sem-setcpair> ::=
|
||||
<sem-setim> ::=
|
||||
<sem-substd> ::=
|
||||
<sem-subalc> ::=
|
||||
<sem-substr> ::=
|
||||
<sem-substrs> ::=
|
||||
<sem-subistr> ::=
|
||||
<sem-subostr> ::=
|
||||
<sem-subiostr> ::=
|
||||
<sem-loadsub> ::=
|
||||
<sem-setnamec> ::=
|
||||
<sem-setnamed> ::=
|
||||
<sem-setopnw> ::=
|
||||
<sem-setopna> ::=
|
||||
<sem-setopdl> ::=
|
||||
<sem-setopda> ::=
|
||||
<sem-setopps> ::=
|
||||
<sem-setopng> ::=
|
||||
<sem-setopad> ::=
|
||||
<sem-setopde> ::=
|
||||
<sem-setopco> ::=
|
||||
<sem-setoppl> ::=
|
||||
<sem-setopmi> ::=
|
||||
<sem-setopml> ::=
|
||||
<sem-setopdv> ::=
|
||||
<sem-setoprm> ::=
|
||||
<sem-setopan> ::=
|
||||
<sem-setopor> ::=
|
||||
<sem-setopeo> ::=
|
||||
<sem-setopass> ::=
|
||||
<sem-setoppll> ::=
|
||||
<sem-setopmii> ::=
|
||||
<sem-setopmll> ::=
|
||||
<sem-setopdvv> ::=
|
||||
<sem-setoprmm> ::=
|
||||
<sem-setopann> ::=
|
||||
<sem-setoporr> ::=
|
||||
<sem-setopeoo> ::=
|
||||
<sem-setopls> ::=
|
||||
<sem-setoprs> ::=
|
||||
<sem-setoplss> ::=
|
||||
<sem-setoprss> ::=
|
||||
<sem-setopeq> ::=
|
||||
<sem-setopne> ::=
|
||||
<sem-setoplt> ::=
|
||||
<sem-setopgt> ::=
|
||||
<sem-setople> ::=
|
||||
<sem-setopnt> ::=
|
||||
<sem-setopaa> ::=
|
||||
<sem-setopoo> ::=
|
||||
<sem-setoppp> ::=
|
||||
<sem-setopmm> ::=
|
||||
<sem-setopcm> ::=
|
||||
<sem-setoppm> ::=
|
||||
<sem-setoppt> ::=
|
||||
<sem-setopcl> ::=
|
||||
<sem-setopix> ::=
|
||||
<sem-setopge> ::=
|
||||
<sem-setopqu> ::=
|
||||
<sem-setopst> ::=
|
||||
<sem-setopsz> ::=
|
||||
<sem-setopat> ::=
|
||||
<sem-setopaz> ::=
|
||||
<sem-setopcv> ::=
|
||||
<sem-setopxx> ::=
|
||||
<sem-setnamef> ::=
|
||||
<sem-setnamevt> ::=
|
||||
<sem-reversename> ::=
|
||||
<sem-setprivate> ::=
|
||||
<sem-setpublic> ::=
|
||||
<sem-setprotected> ::=
|
||||
<sem-setfcdecl> ::=
|
||||
<sem-setfpascal> ::=
|
||||
<sem-setffortran> ::=
|
||||
<sem-setfthiscall> ::=
|
||||
<sem-setfstdcall> ::=
|
||||
<sem-setffastcall> ::=
|
||||
<sem-setfinterrupt> ::=
|
||||
<sem-setunion> ::=
|
||||
<sem-setstruct> ::=
|
||||
<sem-setclass> ::=
|
||||
<sem-setenum> ::=
|
||||
<sem-setstatic> ::=
|
||||
<sem-setvirtual> ::=
|
||||
<sem-stclconst> ::=
|
||||
<sem-stclvol> ::=
|
||||
<sem-stclfar> ::=
|
||||
<sem-stclhuge> ::=
|
||||
<sem-savenamesub> ::=
|
||||
<sem-loadnamesub> ::=
|
||||
<sem-mstemplsub> ::=
|
||||
<sem-setnamer0> ::=
|
||||
<sem-setnamer1> ::=
|
||||
<sem-setnamer2> ::=
|
||||
<sem-setnamer3> ::=
|
||||
<sem-setnamer4> ::=
|
||||
<sem-setname_a> ::=
|
||||
<sem-setname_b> ::=
|
||||
<sem-setname_c> ::=
|
||||
<sem-setname_d> ::=
|
||||
<sem-setname_e> ::=
|
||||
<sem-setname_f> ::=
|
||||
<sem-setname_g> ::=
|
||||
<sem-setname_h> ::=
|
||||
<sem-setname_i> ::=
|
||||
<sem-setname_j> ::=
|
||||
<sem-setname_k> ::=
|
||||
<sem-setname_l> ::=
|
||||
<sem-setname_m> ::=
|
||||
<sem-setname_n> ::=
|
||||
<sem-setname_o> ::=
|
||||
<sem-setname_p> ::=
|
||||
<sem-setname_q> ::=
|
||||
<sem-setname_r> ::=
|
||||
<sem-setname_s> ::=
|
||||
<sem-setname_t> ::=
|
||||
<sem-setname_u> ::=
|
||||
<sem-setname_v> ::=
|
||||
<sem-setname_w> ::=
|
||||
<sem-setname_x> ::=
|
||||
<sem-setname_y> ::=
|
||||
<sem-setname_z> ::=
|
||||
<sem-templ2tftpl> ::=
|
||||
<sem-beginbsub> ::= #begin built-in substitution
|
||||
<sem-loadbsub> ::=
|
||||
<sem-addmconst> ::=
|
||||
<sem-addmvol> ::=
|
||||
<sem-addmfar> ::=
|
||||
<sem-addmhuge> ::=
|
||||
<sem-loadmsnum> ::=
|
||||
<sem-numtorttibcd> ::=
|
||||
<sem-numtotype> ::=
|
||||
<sem-normalizeparname> ::=
|
||||
<sem-borlandid> ::=
|
||||
<sem-loadborlandsub> ::=
|
||||
<sem-borlandarr> ::=
|
||||
<sem-end> ::=
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,91 @@
|
|||
/**
|
||||
* @file src/demangler/igrams.cpp
|
||||
* @brief Internal grammar list.
|
||||
* @copyright (c) 2017 Avast Software, licensed under the MIT license
|
||||
*/
|
||||
|
||||
#include <cstdlib>
|
||||
|
||||
#include "demangler/demglobal.h"
|
||||
#include "demangler/igrams.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
namespace demangler {
|
||||
|
||||
/**
|
||||
* @brief Classes containing internal grammar.
|
||||
*/
|
||||
cIgram_msll* igram_msll = nullptr; //Microsoft Visual C++
|
||||
cIgram_gccll* igram_gccll = nullptr; //GCC
|
||||
cIgram_borlandll* igram_borlandll = nullptr; //Borland
|
||||
|
||||
//[igram] add pointers to internal grammars here
|
||||
|
||||
/**
|
||||
* @brief Function which allocates an internal grammar class and sets the internal grammar structure.
|
||||
* @param gname Grammar name. The particular internal grammar is selected using this name.
|
||||
* @param gParser Pointer to a cGram to send pointers to newly allocated grammar to.
|
||||
* @return Was the initialisation successful?
|
||||
* @retval false Grammar with the specified name was not found.
|
||||
*/
|
||||
bool initIgram(string gname, cGram* gParser) {
|
||||
bool retvalue = false;
|
||||
|
||||
//Microsoft Visual C++ (msll)
|
||||
if (gname == "ms") {
|
||||
igram_msll = new cIgram_msll;
|
||||
gParser->internalGrammarStruct = igram_msll->getInternalGrammar();
|
||||
return true;
|
||||
}
|
||||
//GCC (gccll)
|
||||
else if (gname == "gcc") {
|
||||
igram_gccll = new cIgram_gccll;
|
||||
gParser->internalGrammarStruct = igram_gccll->getInternalGrammar();
|
||||
return true;
|
||||
}
|
||||
//Borland (borlandll)
|
||||
else if (gname == "borland") {
|
||||
igram_borlandll = new cIgram_borlandll;
|
||||
gParser->internalGrammarStruct = igram_borlandll->getInternalGrammar();
|
||||
return true;
|
||||
}
|
||||
|
||||
//[igram] add allocation of internal grammars here
|
||||
|
||||
return retvalue;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Function which deallocates all used internal grammar classes.
|
||||
* @param gParser Pointer to a cGram to clean internal grammars from.
|
||||
*/
|
||||
void deleteIgrams(cGram* gParser) {
|
||||
|
||||
//first, delete the dynamically allocated internal llst if there is any
|
||||
if (gParser->internalGrammarStruct.llst != nullptr) {
|
||||
free(gParser->internalGrammarStruct.llst);
|
||||
gParser->internalGrammarStruct.llst = nullptr;
|
||||
}
|
||||
|
||||
//dealocate all internal grammars here...
|
||||
if (igram_msll != nullptr) {
|
||||
delete igram_msll;
|
||||
igram_msll = nullptr;
|
||||
}
|
||||
|
||||
if (igram_gccll != nullptr) {
|
||||
delete igram_gccll;
|
||||
igram_gccll = nullptr;
|
||||
}
|
||||
|
||||
if (igram_borlandll != nullptr) {
|
||||
delete igram_borlandll;
|
||||
igram_borlandll = nullptr;
|
||||
}
|
||||
|
||||
//[igram] add deallocation of internal grammars here
|
||||
|
||||
}
|
||||
|
||||
} // namespace demangler
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
15
PCSX2_qt.sln
15
PCSX2_qt.sln
|
@ -63,6 +63,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "pcsx2-gsrunner", "pcsx2-gsr
|
|||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "zydis", "3rdparty\zydis\zydis.vcxproj", "{67D0160C-0FE4-44B9-AC2E-82BBCF4104DF}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "demangler", "3rdparty\demangler\demangler.vcxproj", "{1E3D706C-1D95-4E1B-BDF2-CA3D0007DF7F}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug AVX2|x64 = Debug AVX2|x64
|
||||
|
@ -415,6 +417,18 @@ Global
|
|||
{67D0160C-0FE4-44B9-AC2E-82BBCF4104DF}.Release AVX2|x64.Build.0 = Release|x64
|
||||
{67D0160C-0FE4-44B9-AC2E-82BBCF4104DF}.Release|x64.ActiveCfg = Release|x64
|
||||
{67D0160C-0FE4-44B9-AC2E-82BBCF4104DF}.Release|x64.Build.0 = Release|x64
|
||||
{1E3D706C-1D95-4E1B-BDF2-CA3D0007DF7F}.Debug AVX2|x64.ActiveCfg = Debug|x64
|
||||
{1E3D706C-1D95-4E1B-BDF2-CA3D0007DF7F}.Debug AVX2|x64.Build.0 = Debug|x64
|
||||
{1E3D706C-1D95-4E1B-BDF2-CA3D0007DF7F}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{1E3D706C-1D95-4E1B-BDF2-CA3D0007DF7F}.Debug|x64.Build.0 = Debug|x64
|
||||
{1E3D706C-1D95-4E1B-BDF2-CA3D0007DF7F}.Devel AVX2|x64.ActiveCfg = Devel|x64
|
||||
{1E3D706C-1D95-4E1B-BDF2-CA3D0007DF7F}.Devel AVX2|x64.Build.0 = Devel|x64
|
||||
{1E3D706C-1D95-4E1B-BDF2-CA3D0007DF7F}.Devel|x64.ActiveCfg = Devel|x64
|
||||
{1E3D706C-1D95-4E1B-BDF2-CA3D0007DF7F}.Devel|x64.Build.0 = Devel|x64
|
||||
{1E3D706C-1D95-4E1B-BDF2-CA3D0007DF7F}.Release AVX2|x64.ActiveCfg = Release|x64
|
||||
{1E3D706C-1D95-4E1B-BDF2-CA3D0007DF7F}.Release AVX2|x64.Build.0 = Release|x64
|
||||
{1E3D706C-1D95-4E1B-BDF2-CA3D0007DF7F}.Release|x64.ActiveCfg = Release|x64
|
||||
{1E3D706C-1D95-4E1B-BDF2-CA3D0007DF7F}.Release|x64.Build.0 = Release|x64
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
|
@ -444,6 +458,7 @@ Global
|
|||
{95DD0A0C-D14D-4CFF-A593-820EF26EFCC8} = {78EBE642-7A4D-4EA7-86BE-5639C6646C38}
|
||||
{E960DFDF-1BD3-4C29-B251-D1A0919C9B09} = {78EBE642-7A4D-4EA7-86BE-5639C6646C38}
|
||||
{67D0160C-0FE4-44B9-AC2E-82BBCF4104DF} = {78EBE642-7A4D-4EA7-86BE-5639C6646C38}
|
||||
{1E3D706C-1D95-4E1B-BDF2-CA3D0007DF7F} = {78EBE642-7A4D-4EA7-86BE-5639C6646C38}
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {0BC474EA-3628-45D3-9DBC-E22D0B7E0F77}
|
||||
|
|
|
@ -254,6 +254,9 @@ if(QT_BUILD)
|
|||
add_subdirectory(3rdparty/rapidjson EXCLUDE_FROM_ALL)
|
||||
add_subdirectory(3rdparty/discord-rpc EXCLUDE_FROM_ALL)
|
||||
endif()
|
||||
|
||||
# Demangler for the debugger
|
||||
add_subdirectory(3rdparty/demangler EXCLUDE_FROM_ALL)
|
||||
endif()
|
||||
|
||||
if(NOT WIN32 AND QT_BUILD)
|
||||
|
|
|
@ -122,6 +122,24 @@ target_sources(pcsx2-qt PRIVATE
|
|||
Settings/SettingsDialog.ui
|
||||
Settings/USBBindingWidget_DrivingForce.ui
|
||||
Settings/USBBindingWidget_GTForce.ui
|
||||
Debugger/CpuWidget.cpp
|
||||
Debugger/CpuWidget.h
|
||||
Debugger/CpuWidget.ui
|
||||
Debugger/DebuggerWindow.cpp
|
||||
Debugger/DebuggerWindow.h
|
||||
Debugger/DebuggerWindow.ui
|
||||
Debugger/DisassemblyWidget.cpp
|
||||
Debugger/DisassemblyWidget.h
|
||||
Debugger/DisassemblyWidget.ui
|
||||
Debugger/MemoryViewWidget.cpp
|
||||
Debugger/MemoryViewWidget.h
|
||||
Debugger/MemoryViewWidget.ui
|
||||
Debugger/RegisterWidget.cpp
|
||||
Debugger/RegisterWidget.h
|
||||
Debugger/RegisterWidget.ui
|
||||
Debugger/BreakpointDialog.cpp
|
||||
Debugger/BreakpointDialog.h
|
||||
Debugger/BreakpointDialog.ui
|
||||
Tools/InputRecording/NewInputRecordingDlg.cpp
|
||||
Tools/InputRecording/NewInputRecordingDlg.h
|
||||
Tools/InputRecording/NewInputRecordingDlg.ui
|
||||
|
|
|
@ -0,0 +1,206 @@
|
|||
/* PCSX2 - PS2 Emulator for PCs
|
||||
* Copyright (C) 2002-2022 PCSX2 Dev Team
|
||||
*
|
||||
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
|
||||
* of the GNU Lesser General Public License as published by the Free Software Found-
|
||||
* ation, either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* PCSX2 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 PCSX2.
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "PrecompiledHeader.h"
|
||||
|
||||
#include "BreakpointDialog.h"
|
||||
#include "DebugTools/Breakpoints.h"
|
||||
|
||||
#include "QtUtils.h"
|
||||
#include "QtHost.h"
|
||||
#include <QtWidgets/QDialog>
|
||||
#include <QtWidgets/QMessageBox>
|
||||
|
||||
BreakpointDialog::BreakpointDialog(QWidget* parent, DebugInterface* cpu)
|
||||
: QDialog(parent)
|
||||
, m_cpu(cpu)
|
||||
, m_purpose(BPDIALOG_PURPOSE::CREATE)
|
||||
{
|
||||
m_ui.setupUi(this);
|
||||
|
||||
m_ui.grpType->setEnabled(true);
|
||||
m_ui.txtAddress->setEnabled(true);
|
||||
|
||||
connect(m_ui.rdoExecute, &QRadioButton::toggled, this, &BreakpointDialog::onRdoButtonToggled);
|
||||
connect(m_ui.rdoMemory, &QRadioButton::toggled, this, &BreakpointDialog::onRdoButtonToggled);
|
||||
}
|
||||
|
||||
BreakpointDialog::BreakpointDialog(QWidget* parent, DebugInterface* cpu, BreakPoint* bp)
|
||||
: QDialog(parent)
|
||||
, m_cpu(cpu)
|
||||
, m_purpose(BPDIALOG_PURPOSE::EDIT_BP)
|
||||
, m_bp(bp)
|
||||
{
|
||||
m_ui.setupUi(this);
|
||||
|
||||
m_ui.txtAddress->setText(QtUtils::FilledQStringFromValue(m_bp->addr, 16));
|
||||
if (m_bp->hasCond)
|
||||
m_ui.txtCondition->setText(QString::fromLocal8Bit(&m_bp->cond.expressionString[0]));
|
||||
m_ui.chkEnable->setChecked(m_bp->enabled);
|
||||
|
||||
connect(m_ui.rdoExecute, &QRadioButton::toggled, this, &BreakpointDialog::onRdoButtonToggled);
|
||||
connect(m_ui.rdoMemory, &QRadioButton::toggled, this, &BreakpointDialog::onRdoButtonToggled);
|
||||
m_ui.rdoExecute->toggle();
|
||||
}
|
||||
|
||||
BreakpointDialog::BreakpointDialog(QWidget* parent, DebugInterface* cpu, MemCheck* mc)
|
||||
: QDialog(parent)
|
||||
, m_cpu(cpu)
|
||||
, m_purpose(BPDIALOG_PURPOSE::EDIT_MC)
|
||||
, m_mc(mc)
|
||||
{
|
||||
m_ui.setupUi(this);
|
||||
|
||||
m_ui.txtAddress->setText(QtUtils::FilledQStringFromValue(m_mc->start, 16));
|
||||
m_ui.txtSize->setText(QString::number(m_mc->end - m_mc->start, 16).toUpper());
|
||||
m_ui.chkLog->setChecked(m_mc->result & MEMCHECK_LOG);
|
||||
m_ui.chkEnable->setChecked(m_mc->result & MEMCHECK_BREAK);
|
||||
m_ui.chkChange->setChecked(m_mc->cond & MEMCHECK_WRITE_ONCHANGE);
|
||||
m_ui.chkRead->setChecked(m_mc->cond & MEMCHECK_READ);
|
||||
m_ui.chkWrite->setChecked(m_mc->cond & MEMCHECK_WRITE);
|
||||
|
||||
connect(m_ui.rdoExecute, &QRadioButton::toggled, this, &BreakpointDialog::onRdoButtonToggled);
|
||||
connect(m_ui.rdoMemory, &QRadioButton::toggled, this, &BreakpointDialog::onRdoButtonToggled);
|
||||
m_ui.rdoMemory->toggle();
|
||||
}
|
||||
|
||||
BreakpointDialog::~BreakpointDialog()
|
||||
{
|
||||
}
|
||||
|
||||
void BreakpointDialog::onRdoButtonToggled()
|
||||
{
|
||||
const bool isExecute = m_ui.rdoExecute->isChecked();
|
||||
|
||||
m_ui.grpExecute->setEnabled(isExecute);
|
||||
m_ui.grpMemory->setEnabled(!isExecute);
|
||||
|
||||
m_ui.chkLog->setEnabled(!isExecute);
|
||||
}
|
||||
|
||||
// When we are creating a breakpoint, use m_bp or m_mc only as a place to store information for the new breakpoint
|
||||
// When we are modifying a breakpoint, m_bp or m_mc is a pointer to the breakpoint we are updating
|
||||
void BreakpointDialog::accept()
|
||||
{
|
||||
if (m_purpose == BPDIALOG_PURPOSE::CREATE)
|
||||
{
|
||||
if (m_ui.rdoExecute->isChecked())
|
||||
{
|
||||
m_bp = new BreakPoint;
|
||||
m_bp->cpu = m_cpu->getCpuType();
|
||||
m_bp->cond.debug = m_cpu;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_mc = new MemCheck;
|
||||
m_mc->cpu = m_cpu->getCpuType();
|
||||
}
|
||||
}
|
||||
|
||||
PostfixExpression expression;
|
||||
|
||||
// Validate the address
|
||||
u64 address;
|
||||
if (!m_cpu->initExpression(m_ui.txtAddress->text().toLocal8Bit(), expression) || !m_cpu->parseExpression(expression, address))
|
||||
{
|
||||
QMessageBox::warning(this, "Error", "Invalid address \"" + m_ui.txtAddress->text() + "\"");
|
||||
return;
|
||||
}
|
||||
|
||||
u64 size;
|
||||
if (m_ui.rdoMemory->isChecked())
|
||||
{
|
||||
if (!m_cpu->initExpression(m_ui.txtSize->text().toLocal8Bit(), expression) || !m_cpu->parseExpression(expression, size) || !size)
|
||||
{
|
||||
QMessageBox::warning(this, "Error", "Invalid size \"" + m_ui.txtSize->text() + "\"");
|
||||
return;
|
||||
}
|
||||
|
||||
m_mc->start = address;
|
||||
const bool changedSize = m_mc->end != (m_mc->start + size);
|
||||
const u32 prevEnd = m_mc->end;
|
||||
m_mc->end = m_mc->start + size;
|
||||
|
||||
int condition = 0;
|
||||
if (m_ui.chkRead->isChecked())
|
||||
condition |= MEMCHECK_READ;
|
||||
if (m_ui.chkWrite->isChecked())
|
||||
condition |= MEMCHECK_WRITE;
|
||||
if (m_ui.chkChange->isChecked())
|
||||
condition |= MEMCHECK_WRITE_ONCHANGE;
|
||||
|
||||
int result = 0;
|
||||
if (m_ui.chkEnable->isChecked())
|
||||
result |= MEMCHECK_BREAK;
|
||||
if (m_ui.chkLog->isChecked())
|
||||
result |= MEMCHECK_LOG;
|
||||
|
||||
if (m_purpose == BPDIALOG_PURPOSE::CREATE)
|
||||
{
|
||||
Host::RunOnCPUThread([this, condition, result] {
|
||||
CBreakPoints::AddMemCheck(m_cpu->getCpuType(), m_mc->start, m_mc->end, (MemCheckCondition)condition, (MemCheckResult)result);
|
||||
delete m_mc;
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
Host::RunOnCPUThread([this, mc = *m_mc, condition, result, prevEnd, changedSize] {
|
||||
if (changedSize)
|
||||
{
|
||||
CBreakPoints::RemoveMemCheck(m_cpu->getCpuType(), mc.start, prevEnd);
|
||||
CBreakPoints::AddMemCheck(m_cpu->getCpuType(), mc.start, mc.end, static_cast<MemCheckCondition>(condition), static_cast<MemCheckResult>(result));
|
||||
}
|
||||
else
|
||||
{
|
||||
CBreakPoints::ChangeMemCheck(m_cpu->getCpuType(), mc.start, mc.end, static_cast<MemCheckCondition>(condition), static_cast<MemCheckResult>(result));
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (m_purpose == BPDIALOG_PURPOSE::CREATE)
|
||||
Host::RunOnCPUThread([this, address] {
|
||||
CBreakPoints::AddBreakPoint(m_cpu->getCpuType(), address);
|
||||
});
|
||||
|
||||
// Validate the condition
|
||||
// TODO: Expression management in the core should be updated to make this prettier
|
||||
if (!m_ui.txtCondition->text().isEmpty())
|
||||
{
|
||||
auto strData = m_ui.txtCondition->text().toLocal8Bit();
|
||||
expression.clear();
|
||||
if (!m_cpu->initExpression(strData.constData(), expression))
|
||||
{
|
||||
QMessageBox::warning(this, "Error", "Invalid condition \"" + strData + "\"");
|
||||
return;
|
||||
}
|
||||
|
||||
m_bp->cond.expression = expression;
|
||||
strncpy(&m_bp->cond.expressionString[0], strData.constData(), sizeof(m_bp->cond.expressionString));
|
||||
|
||||
Host::RunOnCPUThread([this, address] {
|
||||
CBreakPoints::ChangeBreakPointAddCond(m_cpu->getCpuType(), address, m_bp->cond);
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
Host::RunOnCPUThread([this, address] { CBreakPoints::ChangeBreakPointRemoveCond(m_cpu->getCpuType(), address); }, true);
|
||||
}
|
||||
m_bp->addr = address;
|
||||
}
|
||||
|
||||
QDialog::accept();
|
||||
}
|
|
@ -0,0 +1,53 @@
|
|||
/* PCSX2 - PS2 Emulator for PCs
|
||||
* Copyright (C) 2002-2022 PCSX2 Dev Team
|
||||
*
|
||||
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
|
||||
* of the GNU Lesser General Public License as published by the Free Software Found-
|
||||
* ation, either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* PCSX2 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 PCSX2.
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "ui_BreakpointDialog.h"
|
||||
|
||||
#include "DebugTools/Breakpoints.h"
|
||||
|
||||
#include <QtWidgets/QDialog>
|
||||
|
||||
class BreakpointDialog final : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
BreakpointDialog(QWidget* parent, DebugInterface* cpu);
|
||||
BreakpointDialog(QWidget* parent, DebugInterface* cpu, BreakPoint* bp);
|
||||
BreakpointDialog(QWidget* parent, DebugInterface* cpu, MemCheck* mc);
|
||||
~BreakpointDialog();
|
||||
|
||||
|
||||
public slots:
|
||||
void onRdoButtonToggled();
|
||||
void accept() override;
|
||||
|
||||
private:
|
||||
enum class BPDIALOG_PURPOSE
|
||||
{
|
||||
CREATE,
|
||||
EDIT_BP,
|
||||
EDIT_MC
|
||||
};
|
||||
|
||||
Ui::BreakpointDialog m_ui;
|
||||
DebugInterface* m_cpu;
|
||||
|
||||
const BPDIALOG_PURPOSE m_purpose;
|
||||
BreakPoint* m_bp = nullptr;
|
||||
MemCheck* m_mc = nullptr;
|
||||
};
|
|
@ -0,0 +1,325 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>BreakpointDialog</class>
|
||||
<widget class="QDialog" name="BreakpointDialog">
|
||||
<property name="windowModality">
|
||||
<enum>Qt::ApplicationModal</enum>
|
||||
</property>
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>375</width>
|
||||
<height>250</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>375</width>
|
||||
<height>250</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>375</width>
|
||||
<height>250</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="baseSize">
|
||||
<size>
|
||||
<width>375</width>
|
||||
<height>250</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Create / Modify Breakpoint</string>
|
||||
</property>
|
||||
<widget class="QDialogButtonBox" name="buttonBox">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>20</x>
|
||||
<y>210</y>
|
||||
<width>341</width>
|
||||
<height>32</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="standardButtons">
|
||||
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QGroupBox" name="grpType">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>10</x>
|
||||
<y>0</y>
|
||||
<width>91</width>
|
||||
<height>81</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="title">
|
||||
<string>Type</string>
|
||||
</property>
|
||||
<layout class="QFormLayout" name="formLayout_2">
|
||||
<item row="1" column="0">
|
||||
<widget class="QRadioButton" name="rdoExecute">
|
||||
<property name="text">
|
||||
<string>Execute</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<widget class="QRadioButton" name="rdoMemory">
|
||||
<property name="text">
|
||||
<string>Memory</string>
|
||||
</property>
|
||||
<property name="checked">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QGroupBox" name="groupBox_2">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>110</x>
|
||||
<y>10</y>
|
||||
<width>251</width>
|
||||
<height>41</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="title">
|
||||
<string/>
|
||||
</property>
|
||||
<layout class="QFormLayout" name="formLayout">
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>Address</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QLineEdit" name="txtAddress">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>19</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>16777215</width>
|
||||
<height>19</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>0</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QGroupBox" name="grpMemory">
|
||||
<property name="enabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>110</x>
|
||||
<y>50</y>
|
||||
<width>251</width>
|
||||
<height>91</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="title">
|
||||
<string>Memory</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<widget class="QCheckBox" name="chkRead">
|
||||
<property name="text">
|
||||
<string>Read</string>
|
||||
</property>
|
||||
<property name="checked">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="chkWrite">
|
||||
<property name="text">
|
||||
<string>Write</string>
|
||||
</property>
|
||||
<property name="checked">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="chkChange">
|
||||
<property name="text">
|
||||
<string>Change</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QFormLayout" name="formLayout_4">
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="text">
|
||||
<string>Size</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QLineEdit" name="txtSize">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>19</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>16777215</width>
|
||||
<height>19</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>1</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QGroupBox" name="grpExecute">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>110</x>
|
||||
<y>140</y>
|
||||
<width>251</width>
|
||||
<height>61</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="title">
|
||||
<string>Execute</string>
|
||||
</property>
|
||||
<layout class="QFormLayout" name="formLayout_3">
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label_3">
|
||||
<property name="text">
|
||||
<string>Condition</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QLineEdit" name="txtCondition"/>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QGroupBox" name="groupBox_5">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>10</x>
|
||||
<y>90</y>
|
||||
<width>91</width>
|
||||
<height>71</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="title">
|
||||
<string/>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="QCheckBox" name="chkLog">
|
||||
<property name="enabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Log</string>
|
||||
</property>
|
||||
<property name="checked">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="chkEnable">
|
||||
<property name="text">
|
||||
<string>Enable</string>
|
||||
</property>
|
||||
<property name="checked">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections>
|
||||
<connection>
|
||||
<sender>buttonBox</sender>
|
||||
<signal>accepted()</signal>
|
||||
<receiver>BreakpointDialog</receiver>
|
||||
<slot>accept()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>248</x>
|
||||
<y>254</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>157</x>
|
||||
<y>274</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>buttonBox</sender>
|
||||
<signal>rejected()</signal>
|
||||
<receiver>BreakpointDialog</receiver>
|
||||
<slot>reject()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>316</x>
|
||||
<y>260</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>286</x>
|
||||
<y>274</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
</connections>
|
||||
</ui>
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,120 @@
|
|||
/* PCSX2 - PS2 Emulator for PCs
|
||||
* Copyright (C) 2002-2022 PCSX2 Dev Team
|
||||
*
|
||||
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
|
||||
* of the GNU Lesser General Public License as published by the Free Software Found-
|
||||
* ation, either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* PCSX2 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 PCSX2.
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "ui_CpuWidget.h"
|
||||
|
||||
#include "DebugTools/DebugInterface.h"
|
||||
#include "DebugTools/Breakpoints.h"
|
||||
#include "DebugTools/BiosDebugData.h"
|
||||
#include "DebugTools/MipsStackWalk.h"
|
||||
|
||||
#include "QtHost.h"
|
||||
#include <QtWidgets/QWidget>
|
||||
#include <QtWidgets/QTableWidget>
|
||||
|
||||
#include <vector>
|
||||
|
||||
using namespace MipsStackWalk;
|
||||
|
||||
class CpuWidget final : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
CpuWidget(QWidget* parent, DebugInterface& cpu);
|
||||
~CpuWidget();
|
||||
|
||||
public slots:
|
||||
void resizeEvent(QResizeEvent* event);
|
||||
void paintEvent(QPaintEvent* event);
|
||||
|
||||
void onStepInto();
|
||||
void onStepOver();
|
||||
void onStepOut();
|
||||
|
||||
void onVMPaused();
|
||||
|
||||
void updateBreakpoints();
|
||||
void fixBPListColumnSize();
|
||||
|
||||
void onBPListContextMenu(QPoint pos);
|
||||
void onBPListItemChange(QTableWidgetItem* item);
|
||||
|
||||
void contextBPListCopy();
|
||||
void contextBPListDelete();
|
||||
void contextBPListNew();
|
||||
void contextBPListEdit();
|
||||
|
||||
void updateThreads();
|
||||
void onThreadListContextMenu(QPoint pos);
|
||||
void onThreadListDoubleClick(int row, int column);
|
||||
|
||||
void updateStackFrames();
|
||||
void onStackListContextMenu(QPoint pos);
|
||||
void onStackListDoubleClick(int row, int column);
|
||||
|
||||
void updateFunctionList(bool whenEmpty = false);
|
||||
void onFuncListContextMenu(QPoint pos);
|
||||
void onFuncListDoubleClick(QListWidgetItem* item);
|
||||
|
||||
void reloadCPUWidgets()
|
||||
{
|
||||
if (!QtHost::IsOnUIThread())
|
||||
{
|
||||
QtHost::RunOnUIThread(CBreakPoints::GetUpdateHandler());
|
||||
return;
|
||||
}
|
||||
|
||||
updateBreakpoints();
|
||||
updateThreads();
|
||||
updateStackFrames();
|
||||
updateFunctionList();
|
||||
|
||||
m_ui.registerWidget->update();
|
||||
m_ui.disassemblyWidget->update();
|
||||
m_ui.memoryviewWidget->update();
|
||||
};
|
||||
|
||||
void onSearchButtonClicked();
|
||||
|
||||
private:
|
||||
std::vector<QTableWidget*> m_registerTableViews;
|
||||
|
||||
QMenu* m_bplistContextMenu = 0;
|
||||
QMenu* m_threadlistContextMenu = 0;
|
||||
QMenu* m_stacklistContextMenu = 0;
|
||||
QMenu* m_funclistContextMenu = 0;
|
||||
|
||||
Ui::CpuWidget m_ui;
|
||||
|
||||
DebugInterface& m_cpu;
|
||||
|
||||
// Poor mans variant
|
||||
// Allows us to map row index to breakpoint / memcheck objects
|
||||
struct BreakpointObject
|
||||
{
|
||||
std::shared_ptr<BreakPoint> bp;
|
||||
std::shared_ptr<MemCheck> mc;
|
||||
};
|
||||
|
||||
std::vector<BreakpointObject> m_bplistObjects;
|
||||
std::vector<EEThread> m_threadlistObjects;
|
||||
EEThread m_activeThread;
|
||||
std::vector<StackFrame> m_stacklistObjects;
|
||||
|
||||
bool m_demangleFunctions = true;
|
||||
};
|
|
@ -0,0 +1,667 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>CpuWidget</class>
|
||||
<widget class="QWidget" name="CpuWidget">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>668</width>
|
||||
<height>563</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="font">
|
||||
<font>
|
||||
<family>Monospace</family>
|
||||
</font>
|
||||
</property>
|
||||
<property name="focusPolicy">
|
||||
<enum>Qt::StrongFocus</enum>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string/>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<item row="0" column="0">
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout" stretch="0,0">
|
||||
<item>
|
||||
<widget class="QTabWidget" name="tabWidgetRegFunc">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>320</width>
|
||||
<height>350</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="currentIndex">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<widget class="QWidget" name="tabRegisters">
|
||||
<attribute name="title">
|
||||
<string>Registers</string>
|
||||
</attribute>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_6">
|
||||
<property name="spacing">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="RegisterWidget" name="registerWidget" native="true">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>320</width>
|
||||
<height>300</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>16777215</width>
|
||||
<height>595</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="font">
|
||||
<font>
|
||||
<family>Monospace</family>
|
||||
</font>
|
||||
</property>
|
||||
<property name="focusPolicy">
|
||||
<enum>Qt::StrongFocus</enum>
|
||||
</property>
|
||||
<property name="contextMenuPolicy">
|
||||
<enum>Qt::CustomContextMenu</enum>
|
||||
</property>
|
||||
<property name="autoFillBackground">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="tabFunctions">
|
||||
<attribute name="title">
|
||||
<string>Functions</string>
|
||||
</attribute>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||
<property name="spacing">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QListWidget" name="listFunctions">
|
||||
<property name="contextMenuPolicy">
|
||||
<enum>Qt::CustomContextMenu</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_5">
|
||||
<item>
|
||||
<widget class="QPushButton" name="btnRefreshFunctions">
|
||||
<property name="text">
|
||||
<string>Refresh</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLineEdit" name="txtFuncSearch">
|
||||
<property name="placeholderText">
|
||||
<string>Filter</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="tab">
|
||||
<attribute name="title">
|
||||
<string>Memory Search</string>
|
||||
</attribute>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_3">
|
||||
<item>
|
||||
<layout class="QGridLayout" name="gridLayout_2">
|
||||
<item row="5" column="0">
|
||||
<widget class="QLabel" name="label_5">
|
||||
<property name="text">
|
||||
<string>End</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="1" colspan="3">
|
||||
<widget class="QLineEdit" name="txtSearchStart">
|
||||
<property name="text">
|
||||
<string>0x00</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>Value</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QLineEdit" name="txtSearchValue"/>
|
||||
</item>
|
||||
<item row="4" column="0">
|
||||
<widget class="QLabel" name="label_4">
|
||||
<property name="text">
|
||||
<string>Start</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="1" colspan="3">
|
||||
<widget class="QLineEdit" name="txtSearchEnd">
|
||||
<property name="text">
|
||||
<string>0x2000000</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="text">
|
||||
<string>Type</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QComboBox" name="cmbSearchType">
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>1 Byte (8 bits)</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>2 Bytes (16 bits)</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>4 Bytes (32 bits)</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>8 Bytes (64 bits)</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Float</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Double</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>String</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="2">
|
||||
<widget class="QLabel" name="label_3">
|
||||
<property name="text">
|
||||
<string>Hex</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="3">
|
||||
<widget class="QCheckBox" name="chkSearchHex">
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="checked">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="2" colspan="2">
|
||||
<widget class="QPushButton" name="btnSearch">
|
||||
<property name="text">
|
||||
<string>Search</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QListWidget" name="listSearchResults"/>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="DisassemblyWidget" name="disassemblyWidget" native="true">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Expanding">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>1</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>320</width>
|
||||
<height>350</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>16777215</width>
|
||||
<height>595</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="font">
|
||||
<font>
|
||||
<family>Monospace</family>
|
||||
</font>
|
||||
</property>
|
||||
<property name="focusPolicy">
|
||||
<enum>Qt::StrongFocus</enum>
|
||||
</property>
|
||||
<property name="contextMenuPolicy">
|
||||
<enum>Qt::CustomContextMenu</enum>
|
||||
</property>
|
||||
<property name="autoFillBackground">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QTabWidget" name="tabWidget">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>150</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>16777215</width>
|
||||
<height>215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="tabPosition">
|
||||
<enum>QTabWidget::South</enum>
|
||||
</property>
|
||||
<property name="currentIndex">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<widget class="QWidget" name="tab_memory">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<attribute name="title">
|
||||
<string>Memory</string>
|
||||
</attribute>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_3">
|
||||
<property name="spacing">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="MemoryViewWidget" name="memoryviewWidget" native="true">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>250</width>
|
||||
<height>145</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>16777215</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="font">
|
||||
<font>
|
||||
<family>Monospace</family>
|
||||
</font>
|
||||
</property>
|
||||
<property name="contextMenuPolicy">
|
||||
<enum>Qt::CustomContextMenu</enum>
|
||||
</property>
|
||||
<property name="autoFillBackground">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="tab_breakpoints">
|
||||
<attribute name="title">
|
||||
<string>Breakpoints</string>
|
||||
</attribute>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_4">
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QTableWidget" name="breakpointList">
|
||||
<property name="contextMenuPolicy">
|
||||
<enum>Qt::CustomContextMenu</enum>
|
||||
</property>
|
||||
<property name="horizontalScrollBarPolicy">
|
||||
<enum>Qt::ScrollBarAlwaysOff</enum>
|
||||
</property>
|
||||
<property name="gridStyle">
|
||||
<enum>Qt::NoPen</enum>
|
||||
</property>
|
||||
<property name="rowCount">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<attribute name="horizontalHeaderCascadingSectionResizes">
|
||||
<bool>false</bool>
|
||||
</attribute>
|
||||
<attribute name="horizontalHeaderDefaultSectionSize">
|
||||
<number>75</number>
|
||||
</attribute>
|
||||
<attribute name="horizontalHeaderStretchLastSection">
|
||||
<bool>false</bool>
|
||||
</attribute>
|
||||
<attribute name="verticalHeaderVisible">
|
||||
<bool>false</bool>
|
||||
</attribute>
|
||||
<attribute name="verticalHeaderCascadingSectionResizes">
|
||||
<bool>false</bool>
|
||||
</attribute>
|
||||
<column>
|
||||
<property name="text">
|
||||
<string>Type</string>
|
||||
</property>
|
||||
</column>
|
||||
<column>
|
||||
<property name="text">
|
||||
<string>Offset</string>
|
||||
</property>
|
||||
</column>
|
||||
<column>
|
||||
<property name="text">
|
||||
<string>Size / Label</string>
|
||||
</property>
|
||||
</column>
|
||||
<column>
|
||||
<property name="text">
|
||||
<string>Opcode</string>
|
||||
</property>
|
||||
</column>
|
||||
<column>
|
||||
<property name="text">
|
||||
<string>Condition</string>
|
||||
</property>
|
||||
</column>
|
||||
<column>
|
||||
<property name="text">
|
||||
<string>Hits</string>
|
||||
</property>
|
||||
</column>
|
||||
<column>
|
||||
<property name="text">
|
||||
<string>Enabled</string>
|
||||
</property>
|
||||
</column>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="tab_threads">
|
||||
<attribute name="title">
|
||||
<string>Threads</string>
|
||||
</attribute>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_7">
|
||||
<property name="spacing">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QTableWidget" name="threadList">
|
||||
<property name="contextMenuPolicy">
|
||||
<enum>Qt::CustomContextMenu</enum>
|
||||
</property>
|
||||
<property name="selectionMode">
|
||||
<enum>QAbstractItemView::SingleSelection</enum>
|
||||
</property>
|
||||
<property name="gridStyle">
|
||||
<enum>Qt::NoPen</enum>
|
||||
</property>
|
||||
<property name="cornerButtonEnabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="rowCount">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="columnCount">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<attribute name="horizontalHeaderStretchLastSection">
|
||||
<bool>true</bool>
|
||||
</attribute>
|
||||
<attribute name="verticalHeaderVisible">
|
||||
<bool>false</bool>
|
||||
</attribute>
|
||||
<column>
|
||||
<property name="text">
|
||||
<string>ID</string>
|
||||
</property>
|
||||
</column>
|
||||
<column>
|
||||
<property name="text">
|
||||
<string>PC</string>
|
||||
</property>
|
||||
</column>
|
||||
<column>
|
||||
<property name="text">
|
||||
<string>Entry Point</string>
|
||||
</property>
|
||||
</column>
|
||||
<column>
|
||||
<property name="text">
|
||||
<string>Priority</string>
|
||||
</property>
|
||||
</column>
|
||||
<column>
|
||||
<property name="text">
|
||||
<string>State</string>
|
||||
</property>
|
||||
</column>
|
||||
<column>
|
||||
<property name="text">
|
||||
<string>Wait Type</string>
|
||||
</property>
|
||||
</column>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="tab_callstack">
|
||||
<attribute name="title">
|
||||
<string>Call Stack</string>
|
||||
</attribute>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_8">
|
||||
<property name="spacing">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QTableWidget" name="stackframeList">
|
||||
<property name="contextMenuPolicy">
|
||||
<enum>Qt::CustomContextMenu</enum>
|
||||
</property>
|
||||
<property name="horizontalScrollBarPolicy">
|
||||
<enum>Qt::ScrollBarAlwaysOff</enum>
|
||||
</property>
|
||||
<property name="sizeAdjustPolicy">
|
||||
<enum>QAbstractScrollArea::AdjustToContentsOnFirstShow</enum>
|
||||
</property>
|
||||
<property name="selectionMode">
|
||||
<enum>QAbstractItemView::SingleSelection</enum>
|
||||
</property>
|
||||
<property name="gridStyle">
|
||||
<enum>Qt::NoPen</enum>
|
||||
</property>
|
||||
<property name="cornerButtonEnabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="rowCount">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="columnCount">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<attribute name="horizontalHeaderStretchLastSection">
|
||||
<bool>true</bool>
|
||||
</attribute>
|
||||
<attribute name="verticalHeaderVisible">
|
||||
<bool>false</bool>
|
||||
</attribute>
|
||||
<column>
|
||||
<property name="text">
|
||||
<string>Entry</string>
|
||||
</property>
|
||||
</column>
|
||||
<column>
|
||||
<property name="text">
|
||||
<string>Name</string>
|
||||
</property>
|
||||
</column>
|
||||
<column>
|
||||
<property name="text">
|
||||
<string>PC</string>
|
||||
</property>
|
||||
</column>
|
||||
<column>
|
||||
<property name="text">
|
||||
<string>Opcode</string>
|
||||
</property>
|
||||
</column>
|
||||
<column>
|
||||
<property name="text">
|
||||
<string>SP</string>
|
||||
</property>
|
||||
</column>
|
||||
<column>
|
||||
<property name="text">
|
||||
<string>Frame Size</string>
|
||||
</property>
|
||||
</column>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
<class>DisassemblyWidget</class>
|
||||
<extends>QWidget</extends>
|
||||
<header>pcsx2-qt/Debugger/DisassemblyWidget.h</header>
|
||||
<container>1</container>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
<class>RegisterWidget</class>
|
||||
<extends>QWidget</extends>
|
||||
<header>pcsx2-qt/Debugger/RegisterWidget.h</header>
|
||||
<container>1</container>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
<class>MemoryViewWidget</class>
|
||||
<extends>QWidget</extends>
|
||||
<header>pcsx2-qt/Debugger/MemoryViewWidget.h</header>
|
||||
<container>1</container>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
|
@ -0,0 +1,123 @@
|
|||
/* PCSX2 - PS2 Emulator for PCs
|
||||
* Copyright (C) 2002-2022 PCSX2 Dev Team
|
||||
*
|
||||
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
|
||||
* of the GNU Lesser General Public License as published by the Free Software Found-
|
||||
* ation, either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* PCSX2 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 PCSX2.
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "PrecompiledHeader.h"
|
||||
|
||||
#include "DebuggerWindow.h"
|
||||
|
||||
#include "DebugTools/DebugInterface.h"
|
||||
#include "DebugTools/Breakpoints.h"
|
||||
#include "VMManager.h"
|
||||
#include "QtHost.h"
|
||||
#include "MainWindow.h"
|
||||
|
||||
DebuggerWindow::DebuggerWindow(QWidget* parent)
|
||||
: QMainWindow(parent)
|
||||
{
|
||||
m_ui.setupUi(this);
|
||||
|
||||
// Easiest way to handle cross platform monospace fonts
|
||||
// There are issues related to TabWidget -> Children font inheritance otherwise
|
||||
#ifdef WIN32
|
||||
this->setStyleSheet("font: 8pt 'Lucida Console'");
|
||||
#else
|
||||
this->setStyleSheet("font: 8pt 'Monospace'");
|
||||
#endif
|
||||
|
||||
m_actionRunPause = new QAction("Run", this);
|
||||
m_actionStepInto = new QAction("Step Into", this);
|
||||
m_actionStepOver = new QAction("Step Over", this);
|
||||
m_actionStepOut = new QAction("Step Out", this);
|
||||
|
||||
m_ui.menubar->addAction(m_actionRunPause);
|
||||
m_ui.menubar->addAction(m_actionStepInto);
|
||||
m_ui.menubar->addAction(m_actionStepOver);
|
||||
m_ui.menubar->addAction(m_actionStepOut);
|
||||
|
||||
connect(m_actionRunPause, &QAction::triggered, this, &DebuggerWindow::onRunPause);
|
||||
connect(m_actionStepInto, &QAction::triggered, this, &DebuggerWindow::onStepInto);
|
||||
connect(m_actionStepOver, &QAction::triggered, this, &DebuggerWindow::onStepOver);
|
||||
connect(m_actionStepOut, &QAction::triggered, this, &DebuggerWindow::onStepOut);
|
||||
|
||||
connect(g_emu_thread, &EmuThread::onVMPaused, this, &DebuggerWindow::onVMStateChanged);
|
||||
connect(g_emu_thread, &EmuThread::onVMResumed, this, &DebuggerWindow::onVMStateChanged);
|
||||
|
||||
onVMStateChanged(); // If we missed a state change while we weren't loaded
|
||||
|
||||
m_cpuWidget_r5900 = new CpuWidget(this, r5900Debug);
|
||||
m_cpuWidget_r3000 = new CpuWidget(this, r3000Debug);
|
||||
|
||||
m_ui.cpuTabs->addTab(m_cpuWidget_r5900, "R5900");
|
||||
m_ui.cpuTabs->addTab(m_cpuWidget_r3000, "R3000");
|
||||
return;
|
||||
}
|
||||
|
||||
DebuggerWindow::~DebuggerWindow() = default;
|
||||
|
||||
// TODO: not this
|
||||
bool nextStatePaused = true;
|
||||
void DebuggerWindow::onVMStateChanged()
|
||||
{
|
||||
if (!QtHost::IsVMPaused())
|
||||
{
|
||||
nextStatePaused = true;
|
||||
m_actionRunPause->setText("Pause");
|
||||
m_actionStepInto->setEnabled(false);
|
||||
m_actionStepOver->setEnabled(false);
|
||||
m_actionStepOut->setEnabled(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
nextStatePaused = false;
|
||||
m_actionRunPause->setText("Run");
|
||||
m_actionStepInto->setEnabled(true);
|
||||
m_actionStepOver->setEnabled(true);
|
||||
m_actionStepOut->setEnabled(true);
|
||||
CBreakPoints::ClearTemporaryBreakPoints();
|
||||
|
||||
if (CBreakPoints::GetBreakpointTriggered())
|
||||
{
|
||||
CBreakPoints::SetBreakpointTriggered(false);
|
||||
// Our current PC is on a breakpoint.
|
||||
// When we run the core again, we want to skip this breakpoint and run
|
||||
CBreakPoints::SetSkipFirst(BREAKPOINT_EE, r5900Debug.getPC());
|
||||
CBreakPoints::SetSkipFirst(BREAKPOINT_IOP, r3000Debug.getPC());
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
void DebuggerWindow::onRunPause()
|
||||
{
|
||||
g_emu_thread->setVMPaused(nextStatePaused);
|
||||
}
|
||||
|
||||
void DebuggerWindow::onStepInto()
|
||||
{
|
||||
CpuWidget* currentCpu = static_cast<CpuWidget*>(m_ui.cpuTabs->currentWidget());
|
||||
currentCpu->onStepInto();
|
||||
}
|
||||
|
||||
void DebuggerWindow::onStepOver()
|
||||
{
|
||||
CpuWidget* currentCpu = static_cast<CpuWidget*>(m_ui.cpuTabs->currentWidget());
|
||||
currentCpu->onStepOver();
|
||||
}
|
||||
|
||||
void DebuggerWindow::onStepOut()
|
||||
{
|
||||
CpuWidget* currentCpu = static_cast<CpuWidget*>(m_ui.cpuTabs->currentWidget());
|
||||
currentCpu->onStepOut();
|
||||
}
|
|
@ -0,0 +1,46 @@
|
|||
/* PCSX2 - PS2 Emulator for PCs
|
||||
* Copyright (C) 2002-2022 PCSX2 Dev Team
|
||||
*
|
||||
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
|
||||
* of the GNU Lesser General Public License as published by the Free Software Found-
|
||||
* ation, either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* PCSX2 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 PCSX2.
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "CpuWidget.h"
|
||||
|
||||
#include "ui_DebuggerWindow.h"
|
||||
|
||||
class DebuggerWindow : public QMainWindow
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
DebuggerWindow(QWidget* parent);
|
||||
~DebuggerWindow();
|
||||
|
||||
public slots:
|
||||
void onVMStateChanged();
|
||||
void onRunPause();
|
||||
void onStepInto();
|
||||
void onStepOver();
|
||||
void onStepOut();
|
||||
|
||||
private:
|
||||
Ui::DebuggerWindow m_ui;
|
||||
QAction* m_actionRunPause;
|
||||
QAction* m_actionStepInto;
|
||||
QAction* m_actionStepOver;
|
||||
QAction* m_actionStepOut;
|
||||
|
||||
CpuWidget* m_cpuWidget_r5900;
|
||||
CpuWidget* m_cpuWidget_r3000;
|
||||
};
|
|
@ -0,0 +1,41 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>DebuggerWindow</class>
|
||||
<widget class="QMainWindow" name="DebuggerWindow">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>800</width>
|
||||
<height>600</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>PCSX2 Debugger</string>
|
||||
</property>
|
||||
<widget class="QWidget" name="centralwidget">
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<item row="0" column="0">
|
||||
<widget class="QTabWidget" name="cpuTabs"/>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QMenuBar" name="menubar">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>800</width>
|
||||
<height>22</height>
|
||||
</rect>
|
||||
</property>
|
||||
</widget>
|
||||
<action name="actionRun">
|
||||
<property name="text">
|
||||
<string>Run</string>
|
||||
</property>
|
||||
</action>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
|
@ -0,0 +1,702 @@
|
|||
/* PCSX2 - PS2 Emulator for PCs
|
||||
* Copyright (C) 2002-2022 PCSX2 Dev Team
|
||||
*
|
||||
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
|
||||
* of the GNU Lesser General Public License as published by the Free Software Found-
|
||||
* ation, either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* PCSX2 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 PCSX2.
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "PrecompiledHeader.h"
|
||||
|
||||
#include "DisassemblyWidget.h"
|
||||
|
||||
#include "DebugTools/DebugInterface.h"
|
||||
#include "DebugTools/DisassemblyManager.h"
|
||||
#include "DebugTools/Breakpoints.h"
|
||||
#include "DebugTools/MipsAssembler.h"
|
||||
|
||||
#include "QtUtils.h"
|
||||
#include "QtHost.h"
|
||||
#include <QtGui/QMouseEvent>
|
||||
#include <QtWidgets/QMenu>
|
||||
#include <QtGui/QClipboard>
|
||||
#include <QtWidgets/QInputDialog>
|
||||
#include <QtWidgets/QMessageBox>
|
||||
|
||||
using namespace QtUtils;
|
||||
|
||||
DisassemblyWidget::DisassemblyWidget(QWidget* parent)
|
||||
: QWidget(parent)
|
||||
{
|
||||
ui.setupUi(this);
|
||||
|
||||
CreateCustomContextMenu();
|
||||
connect(this, &DisassemblyWidget::customContextMenuRequested, this, &DisassemblyWidget::customMenuRequested);
|
||||
}
|
||||
|
||||
DisassemblyWidget::~DisassemblyWidget() = default;
|
||||
|
||||
void DisassemblyWidget::CreateCustomContextMenu()
|
||||
{
|
||||
if (m_contextMenu)
|
||||
return; // ???
|
||||
m_contextMenu = new QMenu(this);
|
||||
|
||||
QAction* action = 0;
|
||||
m_contextMenu->addAction(action = new QAction("Copy Address", this));
|
||||
connect(action, &QAction::triggered, this, &DisassemblyWidget::contextCopyAddress);
|
||||
m_contextMenu->addAction(action = new QAction("Copy Instruction Hex", this));
|
||||
connect(action, &QAction::triggered, this, &DisassemblyWidget::contextCopyInstructionHex);
|
||||
m_contextMenu->addAction(action = new QAction("Copy Instruction Text", this));
|
||||
connect(action, &QAction::triggered, this, &DisassemblyWidget::contextCopyInstructionText);
|
||||
// TODO: Disassemble to file. Do people use that?
|
||||
m_contextMenu->addSeparator();
|
||||
m_contextMenu->addAction(action = new QAction("Assemble new Instruction(s)", this));
|
||||
connect(action, &QAction::triggered, this, &DisassemblyWidget::contextAssembleInstruction);
|
||||
m_contextMenu->addSeparator();
|
||||
m_contextMenu->addAction(action = new QAction("Run to Cursor", this));
|
||||
connect(action, &QAction::triggered, this, &DisassemblyWidget::contextRunToCursor);
|
||||
m_contextMenu->addAction(action = new QAction("Jump to Cursor", this));
|
||||
connect(action, &QAction::triggered, this, &DisassemblyWidget::contextJumpToCursor);
|
||||
m_contextMenu->addAction(action = new QAction("Toggle Breakpoint", this));
|
||||
connect(action, &QAction::triggered, this, &DisassemblyWidget::contextToggleBreakpoint);
|
||||
m_contextMenu->addAction(action = new QAction("Follow Branch", this));
|
||||
connect(action, &QAction::triggered, this, &DisassemblyWidget::contextFollowBranch);
|
||||
m_contextMenu->addSeparator();
|
||||
m_contextMenu->addAction(action = new QAction("Go to Address", this));
|
||||
connect(action, &QAction::triggered, this, &DisassemblyWidget::contextGoToAddress);
|
||||
m_contextMenu->addAction(action = new QAction("Go to in Memory View", this));
|
||||
connect(action, &QAction::triggered, this, [this]() { gotoInMemory(m_selectedAddressStart); });
|
||||
m_contextMenu->addSeparator();
|
||||
m_contextMenu->addAction(action = new QAction("Add Function", this));
|
||||
connect(action, &QAction::triggered, this, &DisassemblyWidget::contextAddFunction);
|
||||
m_contextMenu->addAction(action = new QAction("Rename Function", this));
|
||||
connect(action, &QAction::triggered, this, &DisassemblyWidget::contextRenameFunction);
|
||||
m_contextMenu->addAction(action = new QAction("Remove Function", this));
|
||||
connect(action, &QAction::triggered, this, &DisassemblyWidget::contextRemoveFunction);
|
||||
}
|
||||
|
||||
void DisassemblyWidget::contextCopyAddress()
|
||||
{
|
||||
QGuiApplication::clipboard()->setText(FetchSelectionInfo(SelectionInfo::ADDRESS));
|
||||
}
|
||||
|
||||
void DisassemblyWidget::contextCopyInstructionHex()
|
||||
{
|
||||
QGuiApplication::clipboard()->setText(FetchSelectionInfo(SelectionInfo::INSTRUCTIONHEX));
|
||||
}
|
||||
|
||||
void DisassemblyWidget::contextCopyInstructionText()
|
||||
{
|
||||
QGuiApplication::clipboard()->setText(FetchSelectionInfo(SelectionInfo::INSTRUCTIONTEXT));
|
||||
}
|
||||
|
||||
void DisassemblyWidget::contextAssembleInstruction()
|
||||
{
|
||||
if (!m_cpu->isCpuPaused())
|
||||
{
|
||||
QMessageBox::warning(this, "Assemble Error", "Unable to change assembly while core is running");
|
||||
return;
|
||||
}
|
||||
|
||||
DisassemblyLineInfo line;
|
||||
bool ok;
|
||||
m_disassemblyManager.getLine(m_selectedAddressStart, false, line);
|
||||
QString instruction = QInputDialog::getText(this, "Assemble Instruction", "",
|
||||
QLineEdit::Normal, QString("%1 %2").arg(line.name.c_str()).arg(line.params.c_str()), &ok);
|
||||
|
||||
if (!ok)
|
||||
return;
|
||||
|
||||
u32 encodedInstruction;
|
||||
std::string errorText;
|
||||
bool valid = MipsAssembleOpcode(instruction.toLocal8Bit().constData(), m_cpu, m_selectedAddressStart, encodedInstruction, errorText);
|
||||
|
||||
if (!valid)
|
||||
{
|
||||
QMessageBox::warning(this, "Assemble Error", QString::fromStdString(errorText));
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
Host::RunOnCPUThread([this, start = m_selectedAddressStart, end = m_selectedAddressEnd, cpu = m_cpu, val = encodedInstruction] {
|
||||
for (u32 i = start; i <= end; i += 4)
|
||||
{
|
||||
cpu->write32(i, val);
|
||||
}
|
||||
QtHost::RunOnUIThread([this] { VMUpdate(); });
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void DisassemblyWidget::contextRunToCursor()
|
||||
{
|
||||
Host::RunOnCPUThread([&] { CBreakPoints::AddBreakPoint(m_cpu->getCpuType(), m_selectedAddressStart); });
|
||||
|
||||
m_cpu->resumeCpu();
|
||||
}
|
||||
|
||||
void DisassemblyWidget::contextJumpToCursor()
|
||||
{
|
||||
m_cpu->setPc(m_selectedAddressStart);
|
||||
this->repaint();
|
||||
}
|
||||
|
||||
void DisassemblyWidget::contextToggleBreakpoint()
|
||||
{
|
||||
if (CBreakPoints::IsAddressBreakPoint(m_cpu->getCpuType(), m_selectedAddressStart))
|
||||
{
|
||||
Host::RunOnCPUThread([&] { CBreakPoints::RemoveBreakPoint(m_cpu->getCpuType(), m_selectedAddressStart); });
|
||||
}
|
||||
else
|
||||
{
|
||||
Host::RunOnCPUThread([&] { CBreakPoints::AddBreakPoint(m_cpu->getCpuType(), m_selectedAddressStart); });
|
||||
}
|
||||
|
||||
breakpointsChanged();
|
||||
this->repaint();
|
||||
}
|
||||
|
||||
void DisassemblyWidget::contextFollowBranch()
|
||||
{
|
||||
DisassemblyLineInfo line;
|
||||
|
||||
m_disassemblyManager.getLine(m_selectedAddressStart, true, line);
|
||||
|
||||
if (line.type == DISTYPE_OPCODE || line.type == DISTYPE_MACRO)
|
||||
{
|
||||
if (line.info.isBranch)
|
||||
gotoAddress(line.info.branchTarget);
|
||||
else if (line.info.hasRelevantAddress)
|
||||
gotoAddress(line.info.releventAddress);
|
||||
}
|
||||
}
|
||||
|
||||
void DisassemblyWidget::contextGoToAddress()
|
||||
{
|
||||
bool ok;
|
||||
const QString targetString = QInputDialog::getText(this, "Go to address", "",
|
||||
QLineEdit::Normal, "", &ok);
|
||||
|
||||
if (!ok)
|
||||
return;
|
||||
|
||||
const u32 targetAddress = targetString.toUInt(&ok, 16) & ~3;
|
||||
|
||||
if (!ok)
|
||||
{
|
||||
QMessageBox::warning(this, "Go to address error", "Invalid address");
|
||||
return;
|
||||
}
|
||||
|
||||
gotoAddress(targetAddress);
|
||||
}
|
||||
|
||||
void DisassemblyWidget::contextAddFunction()
|
||||
{
|
||||
// Get current function
|
||||
const u32 curAddress = m_selectedAddressStart;
|
||||
const u32 curFuncAddr = m_cpu->GetSymbolMap().GetFunctionStart(m_selectedAddressStart);
|
||||
QString optionaldlgText;
|
||||
|
||||
if (curFuncAddr != SymbolMap::INVALID_ADDRESS)
|
||||
{
|
||||
if (curFuncAddr == curAddress) // There is already a function here
|
||||
{
|
||||
QMessageBox::warning(this, "Add Function Error", "A function entry point already exists here. Consider renaming instead.");
|
||||
}
|
||||
else
|
||||
{
|
||||
const u32 prevSize = m_cpu->GetSymbolMap().GetFunctionSize(curFuncAddr);
|
||||
u32 newSize = curAddress - curFuncAddr;
|
||||
|
||||
bool ok;
|
||||
QString funcName = QInputDialog::getText(this, "Add Function",
|
||||
QString("Function will be (0x%1) instructions long.\nEnter function name").arg(prevSize - newSize, 0, 16), QLineEdit::Normal, "", &ok);
|
||||
if (!ok)
|
||||
return;
|
||||
|
||||
m_cpu->GetSymbolMap().SetFunctionSize(curFuncAddr, newSize); // End the current function to where we selected
|
||||
newSize = prevSize - newSize;
|
||||
m_cpu->GetSymbolMap().AddFunction(funcName.toLocal8Bit().constData(), curAddress, newSize);
|
||||
m_cpu->GetSymbolMap().SortSymbols();
|
||||
m_cpu->GetSymbolMap().UpdateActiveSymbols();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
bool ok;
|
||||
QString funcName = QInputDialog::getText(this, "Add Function",
|
||||
QString("Function will be (0x%1) instructions long.\nEnter function name").arg(m_selectedAddressEnd + 4 - m_selectedAddressStart, 0, 16), QLineEdit::Normal, "", &ok);
|
||||
if (!ok)
|
||||
return;
|
||||
|
||||
m_cpu->GetSymbolMap().AddFunction(funcName.toLocal8Bit().constData(), m_selectedAddressStart, m_selectedAddressEnd + 4 - m_selectedAddressStart);
|
||||
m_cpu->GetSymbolMap().SortSymbols();
|
||||
m_cpu->GetSymbolMap().UpdateActiveSymbols();
|
||||
}
|
||||
}
|
||||
|
||||
void DisassemblyWidget::contextRemoveFunction()
|
||||
{
|
||||
u32 curFuncAddr = m_cpu->GetSymbolMap().GetFunctionStart(m_selectedAddressStart);
|
||||
|
||||
if (curFuncAddr != SymbolMap::INVALID_ADDRESS)
|
||||
{
|
||||
u32 previousFuncAddr = m_cpu->GetSymbolMap().GetFunctionStart(curFuncAddr - 4);
|
||||
if (previousFuncAddr != SymbolMap::INVALID_ADDRESS)
|
||||
{
|
||||
// Extend the previous function to replace the spot of the function that is going to be removed
|
||||
u32 expandedSize = m_cpu->GetSymbolMap().GetFunctionSize(previousFuncAddr) + m_cpu->GetSymbolMap().GetFunctionSize(curFuncAddr);
|
||||
m_cpu->GetSymbolMap().SetFunctionSize(previousFuncAddr, expandedSize);
|
||||
}
|
||||
|
||||
m_cpu->GetSymbolMap().RemoveFunction(curFuncAddr, true);
|
||||
m_cpu->GetSymbolMap().SortSymbols();
|
||||
m_cpu->GetSymbolMap().UpdateActiveSymbols();
|
||||
}
|
||||
}
|
||||
|
||||
void DisassemblyWidget::contextRenameFunction()
|
||||
{
|
||||
const u32 curFuncAddress = m_cpu->GetSymbolMap().GetFunctionStart(m_selectedAddressStart);
|
||||
if (curFuncAddress != SymbolMap::INVALID_ADDRESS)
|
||||
{
|
||||
bool ok;
|
||||
QString funcName = QInputDialog::getText(this, "Rename Function", "Function name", QLineEdit::Normal, m_cpu->GetSymbolMap().GetLabelString(curFuncAddress).c_str(), &ok);
|
||||
if (!ok)
|
||||
return;
|
||||
|
||||
if (funcName.isEmpty())
|
||||
{
|
||||
QMessageBox::warning(this, "Rename Function Error", "Function name cannot be nothing.");
|
||||
}
|
||||
else
|
||||
{
|
||||
m_cpu->GetSymbolMap().SetLabelName(funcName.toLocal8Bit().constData(), curFuncAddress);
|
||||
m_cpu->GetSymbolMap().SortSymbols();
|
||||
m_cpu->GetSymbolMap().UpdateActiveSymbols();
|
||||
this->repaint();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
QMessageBox::warning(this, "Rename Function Error", "No function / symbol is currently selected.");
|
||||
}
|
||||
}
|
||||
|
||||
void DisassemblyWidget::SetCpu(DebugInterface* cpu)
|
||||
{
|
||||
m_cpu = cpu;
|
||||
m_disassemblyManager.setCpu(cpu);
|
||||
}
|
||||
|
||||
QString DisassemblyWidget::GetLineDisasm(u32 address)
|
||||
{
|
||||
DisassemblyLineInfo lineInfo;
|
||||
m_disassemblyManager.getLine(address, true, lineInfo);
|
||||
return QString("%1 %2").arg(lineInfo.name.c_str()).arg(lineInfo.params.c_str());
|
||||
};
|
||||
|
||||
// Here we go!
|
||||
void DisassemblyWidget::paintEvent(QPaintEvent* event)
|
||||
{
|
||||
QPainter painter(this);
|
||||
|
||||
const u32 w = painter.device()->width() - 1;
|
||||
const u32 h = painter.device()->height() - 1;
|
||||
|
||||
// Get the current font size
|
||||
const QFontMetrics fm = painter.fontMetrics();
|
||||
|
||||
// Get the row height
|
||||
m_rowHeight = fm.height() + 2;
|
||||
|
||||
// Find the amount of visible rows
|
||||
m_visibleRows = h / m_rowHeight;
|
||||
|
||||
m_disassemblyManager.analyze(m_visibleStart, m_disassemblyManager.getNthNextAddress(m_visibleStart, m_visibleRows) - m_visibleStart);
|
||||
|
||||
// Draw the rows
|
||||
bool inSelectionBlock = false;
|
||||
bool alternate = m_visibleStart % 8;
|
||||
|
||||
const u32 curPC = m_cpu->getPC(); // Get the PC here, because it'll change when we are drawing and make it seem like there are two PCs
|
||||
|
||||
for (u32 i = 0; i <= m_visibleRows; i++)
|
||||
{
|
||||
const u32 rowAddress = (i * 4) + m_visibleStart;
|
||||
// Row backgrounds
|
||||
|
||||
if (inSelectionBlock || (m_selectedAddressStart <= rowAddress && rowAddress <= m_selectedAddressEnd))
|
||||
{
|
||||
painter.fillRect(0, i * m_rowHeight, w, m_rowHeight, this->palette().highlight());
|
||||
inSelectionBlock = m_selectedAddressEnd != rowAddress;
|
||||
}
|
||||
else
|
||||
{
|
||||
painter.fillRect(0, i * m_rowHeight, w, m_rowHeight, alternate ? this->palette().base() : this->palette().alternateBase());
|
||||
}
|
||||
|
||||
// Row text
|
||||
painter.setPen(GetAddressFunctionColor(rowAddress));
|
||||
QString lineString = DisassemblyStringFromAddress(rowAddress, painter.font(), curPC);
|
||||
|
||||
painter.drawText(2, i * m_rowHeight, w, m_rowHeight, Qt::AlignLeft, lineString);
|
||||
alternate = !alternate;
|
||||
}
|
||||
// Draw the branch lines
|
||||
// This is where it gets a little scary
|
||||
// It's been mostly copied from the wx implementation
|
||||
|
||||
u32 visibleEnd = m_disassemblyManager.getNthNextAddress(m_visibleStart, m_visibleRows);
|
||||
std::vector<BranchLine> branchLines = m_disassemblyManager.getBranchLines(m_visibleStart, visibleEnd - m_visibleStart);
|
||||
|
||||
s32 branchCount = 0;
|
||||
s32 skippedBranches = 0;
|
||||
for (const auto& branchLine : branchLines)
|
||||
{
|
||||
if (branchCount == 5)
|
||||
break;
|
||||
const int winBottom = this->height();
|
||||
|
||||
const int x = this->width() - 10 - ((std::max(0, branchLine.laneIndex - skippedBranches)) * 10);
|
||||
|
||||
int top, bottom;
|
||||
// If the start is technically 'above' our address view
|
||||
if (branchLine.first < m_visibleStart)
|
||||
{
|
||||
top = -1;
|
||||
}
|
||||
// If the start is technically 'below' our address view
|
||||
else if (branchLine.first >= visibleEnd)
|
||||
{
|
||||
top = winBottom + 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Explaination
|
||||
// ((branchLine.first - m_visibleStart) -> Find the amount of bytes from the top of the view
|
||||
// / 4 -> Convert that into rowss in instructions
|
||||
// * m_rowHeight -> convert that into rows in pixels
|
||||
// + (m_rowHeight / 2) -> Add half a row in pixels to center the arrow
|
||||
top = (((branchLine.first - m_visibleStart) / 4) * m_rowHeight) + (m_rowHeight / 2);
|
||||
}
|
||||
|
||||
if (branchLine.second < m_visibleStart)
|
||||
{
|
||||
bottom = -1;
|
||||
}
|
||||
else if (branchLine.second >= visibleEnd)
|
||||
{
|
||||
bottom = winBottom + 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
bottom = (((branchLine.second - m_visibleStart) / 4) * m_rowHeight) + (m_rowHeight / 2);
|
||||
}
|
||||
|
||||
if ((top < 0 && bottom < 0) || (top > winBottom && bottom > winBottom) || (top < 0 && bottom > winBottom) || (top > winBottom && bottom < 0))
|
||||
{
|
||||
skippedBranches++;
|
||||
continue;
|
||||
}
|
||||
|
||||
branchCount++;
|
||||
|
||||
if (branchLine.first == m_selectedAddressStart || branchLine.second == m_selectedAddressStart)
|
||||
{
|
||||
painter.setPen(QColor(0xFF257AFA));
|
||||
}
|
||||
else
|
||||
{
|
||||
painter.setPen(QColor(0xFFFF3020));
|
||||
}
|
||||
|
||||
if (top < 0) // first is not visible, but second is
|
||||
{
|
||||
painter.drawLine(x - 2, bottom, x + 2, bottom);
|
||||
painter.drawLine(x + 2, bottom, x + 2, 0);
|
||||
|
||||
if (branchLine.type == LINE_DOWN)
|
||||
{
|
||||
painter.drawLine(x, bottom - 4, x - 4, bottom);
|
||||
painter.drawLine(x - 4, bottom, x + 1, bottom + 5);
|
||||
}
|
||||
}
|
||||
else if (bottom > winBottom) // second is not visible, but first is
|
||||
{
|
||||
painter.drawLine(x - 2, top, x + 2, top);
|
||||
painter.drawLine(x + 2, top, x + 2, winBottom);
|
||||
|
||||
if (branchLine.type == LINE_UP)
|
||||
{
|
||||
painter.drawLine(x, top - 4, x - 4, top);
|
||||
painter.drawLine(x - 4, top, x + 1, top + 5);
|
||||
}
|
||||
}
|
||||
else
|
||||
{ // both are visible
|
||||
if (branchLine.type == LINE_UP)
|
||||
{
|
||||
painter.drawLine(x - 2, bottom, x + 2, bottom);
|
||||
painter.drawLine(x + 2, bottom, x + 2, top);
|
||||
painter.drawLine(x + 2, top, x - 4, top);
|
||||
|
||||
painter.drawLine(x, top - 4, x - 4, top);
|
||||
painter.drawLine(x - 4, top, x + 1, top + 5);
|
||||
}
|
||||
else
|
||||
{
|
||||
painter.drawLine(x - 2, top, x + 2, top);
|
||||
painter.drawLine(x + 2, top, x + 2, bottom);
|
||||
painter.drawLine(x + 2, bottom, x - 4, bottom);
|
||||
|
||||
painter.drawLine(x, bottom - 4, x - 4, bottom);
|
||||
painter.drawLine(x - 4, bottom, x + 1, bottom + 5);
|
||||
}
|
||||
}
|
||||
}
|
||||
// Draw a border
|
||||
painter.setPen(this->palette().shadow().color());
|
||||
painter.drawRect(0, 0, w, h);
|
||||
}
|
||||
|
||||
void DisassemblyWidget::mousePressEvent(QMouseEvent* event)
|
||||
{
|
||||
const u32 selectedAddress = (event->y() / m_rowHeight * 4) + m_visibleStart;
|
||||
if (event->buttons() & Qt::LeftButton)
|
||||
{
|
||||
if (event->modifiers() & Qt::ShiftModifier)
|
||||
{
|
||||
if (selectedAddress < m_selectedAddressStart)
|
||||
{
|
||||
m_selectedAddressStart = selectedAddress;
|
||||
}
|
||||
else if (selectedAddress > m_visibleStart)
|
||||
{
|
||||
m_selectedAddressEnd = selectedAddress;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
m_selectedAddressStart = selectedAddress;
|
||||
m_selectedAddressEnd = selectedAddress;
|
||||
}
|
||||
}
|
||||
else if (event->buttons() & Qt::RightButton)
|
||||
{
|
||||
if (m_selectedAddressStart == m_selectedAddressEnd)
|
||||
{
|
||||
m_selectedAddressStart = selectedAddress;
|
||||
m_selectedAddressEnd = selectedAddress;
|
||||
}
|
||||
}
|
||||
this->repaint();
|
||||
}
|
||||
|
||||
void DisassemblyWidget::mouseDoubleClickEvent(QMouseEvent* event)
|
||||
{
|
||||
const u32 selectedAddress = (event->y() / m_rowHeight * 4) + m_visibleStart;
|
||||
if (CBreakPoints::IsAddressBreakPoint(m_cpu->getCpuType(), selectedAddress))
|
||||
{
|
||||
Host::RunOnCPUThread([&] { CBreakPoints::RemoveBreakPoint(m_cpu->getCpuType(), selectedAddress); });
|
||||
}
|
||||
else
|
||||
{
|
||||
Host::RunOnCPUThread([&] { CBreakPoints::AddBreakPoint(m_cpu->getCpuType(), selectedAddress); });
|
||||
}
|
||||
breakpointsChanged();
|
||||
this->repaint();
|
||||
}
|
||||
|
||||
void DisassemblyWidget::wheelEvent(QWheelEvent* event)
|
||||
{
|
||||
if (event->angleDelta().y() < 0) // todo: max address bounds check?
|
||||
{
|
||||
m_visibleStart += 4;
|
||||
}
|
||||
else if (event->angleDelta().y() && m_visibleStart > 0)
|
||||
{
|
||||
m_visibleStart -= 4;
|
||||
}
|
||||
this->repaint();
|
||||
}
|
||||
|
||||
void DisassemblyWidget::keyPressEvent(QKeyEvent* event)
|
||||
{
|
||||
switch (event->key())
|
||||
{
|
||||
case Qt::Key_Up:
|
||||
{
|
||||
m_selectedAddressStart -= 4;
|
||||
if (!(event->modifiers() & Qt::ShiftModifier))
|
||||
m_selectedAddressEnd = m_selectedAddressStart;
|
||||
|
||||
// Auto scroll
|
||||
if (m_visibleStart > m_selectedAddressStart)
|
||||
m_visibleStart -= 4;
|
||||
}
|
||||
break;
|
||||
case Qt::Key_Down:
|
||||
{
|
||||
m_selectedAddressEnd += 4;
|
||||
if (!(event->modifiers() & Qt::ShiftModifier))
|
||||
m_selectedAddressStart = m_selectedAddressEnd;
|
||||
|
||||
// Purposely scroll on the second to last row. It's possible to
|
||||
// size the window so part of a row is visible and we don't want to have half a row selected and cut off!
|
||||
if (m_visibleStart + ((m_visibleRows - 1) * 4) < m_selectedAddressEnd)
|
||||
m_visibleStart += 4;
|
||||
}
|
||||
break;
|
||||
case Qt::Key_G:
|
||||
contextGoToAddress();
|
||||
break;
|
||||
case Qt::Key_C:
|
||||
contextCopyInstructionText();
|
||||
break;
|
||||
case Qt::Key_B:
|
||||
contextToggleBreakpoint();
|
||||
break;
|
||||
case Qt::Key_M:
|
||||
contextAssembleInstruction();
|
||||
break;
|
||||
case Qt::Key_Right:
|
||||
contextFollowBranch();
|
||||
break;
|
||||
case Qt::Key_Left:
|
||||
gotoAddress(m_cpu->getPC());
|
||||
break;
|
||||
}
|
||||
|
||||
this->repaint();
|
||||
}
|
||||
|
||||
void DisassemblyWidget::customMenuRequested(QPoint pos)
|
||||
{
|
||||
// m_selectedAddressStart will be properly set as the mouse click handler is called _before_ us
|
||||
// yay :)
|
||||
m_contextMenu->popup(this->mapToGlobal(pos));
|
||||
}
|
||||
|
||||
inline QString DisassemblyWidget::DisassemblyStringFromAddress(u32 address, QFont font, u32 pc)
|
||||
{
|
||||
DisassemblyLineInfo line;
|
||||
|
||||
if (!m_cpu->isValidAddress(address))
|
||||
return QString("%1 NOT VALID ADDRESS").arg(address, 8, 16, QChar('0')).toUpper();
|
||||
// Todo? support non symbol view?
|
||||
m_disassemblyManager.getLine(address, true, line);
|
||||
|
||||
const bool isConditional = line.info.isConditional && m_cpu->getPC() == address;
|
||||
const bool isConditionalMet = line.info.conditionMet;
|
||||
const bool isCurrentPC = m_cpu->getPC() == address;
|
||||
|
||||
const bool isBreakpoint = CBreakPoints::IsAddressBreakPoint(m_cpu->getCpuType(), address) && !CBreakPoints::IsTempBreakPoint(m_cpu->getCpuType(), address);
|
||||
const std::string addressSymbol = m_cpu->GetSymbolMap().GetLabelString(address);
|
||||
|
||||
QString lineString("%1 %2 %3 %4 %5 %6");
|
||||
|
||||
lineString = lineString.arg(isBreakpoint ? "\u25A0" : " "); // Bp block ( ■ )
|
||||
if (addressSymbol.empty()) // The address wont have symbol text if it's the start of a function for example
|
||||
lineString = lineString.arg(address, 8, 16, QChar('0')).toUpper();
|
||||
else
|
||||
{
|
||||
// We want this text elided
|
||||
QFontMetrics metric(font);
|
||||
lineString = lineString.arg(metric.elidedText(QString::fromStdString(addressSymbol), Qt::ElideRight, 8 * font.pointSize()));
|
||||
}
|
||||
|
||||
lineString = lineString.leftJustified(4, ' ') // Address / symbol
|
||||
.arg(line.name.c_str())
|
||||
.arg(line.params.c_str()) // opcode + arguments
|
||||
.arg(isConditional ? (isConditionalMet ? "# true" : "# false") : "")
|
||||
.arg(isCurrentPC ? "<--" : "");
|
||||
|
||||
return lineString;
|
||||
}
|
||||
|
||||
QColor DisassemblyWidget::GetAddressFunctionColor(u32 address)
|
||||
{
|
||||
// This is an attempt to figure out if the current palette is dark or light
|
||||
// We calculate the luminescence of the alternateBase colour
|
||||
// and swap between our darker and lighter function colours
|
||||
|
||||
std::array<QColor, 6> colors;
|
||||
const QColor base = this->palette().alternateBase().color();
|
||||
|
||||
auto Y = (base.redF() * 0.33) + (0.5 * base.greenF()) + (0.16 * base.blueF());
|
||||
|
||||
if (Y > 0.5)
|
||||
{
|
||||
colors = {
|
||||
QColor::fromRgba(0xFFFA3434),
|
||||
QColor::fromRgba(0xFF206b6b),
|
||||
QColor::fromRgba(0xFF858534),
|
||||
QColor::fromRgba(0xFF378c37),
|
||||
QColor::fromRgba(0xFF783278),
|
||||
QColor::fromRgba(0xFF21214a),
|
||||
};
|
||||
}
|
||||
else
|
||||
{
|
||||
colors = {
|
||||
QColor::fromRgba(0xFFe05555),
|
||||
QColor::fromRgba(0xFF55e0e0),
|
||||
QColor::fromRgba(0xFFe8e855),
|
||||
QColor::fromRgba(0xFF55e055),
|
||||
QColor::fromRgba(0xFFe055e0),
|
||||
QColor::fromRgba(0xFFC2C2F5),
|
||||
};
|
||||
}
|
||||
|
||||
auto funNum = m_cpu->GetSymbolMap().GetFunctionNum(address);
|
||||
if (funNum == -1)
|
||||
return this->palette().text().color();
|
||||
|
||||
return colors[funNum % 6];
|
||||
}
|
||||
|
||||
QString DisassemblyWidget::FetchSelectionInfo(SelectionInfo selInfo)
|
||||
{
|
||||
QString infoBlock;
|
||||
for (u32 i = m_selectedAddressStart; i <= m_selectedAddressEnd; i += 4)
|
||||
{
|
||||
if (i != m_selectedAddressStart)
|
||||
infoBlock += '\n';
|
||||
if (selInfo == SelectionInfo::ADDRESS)
|
||||
{
|
||||
infoBlock += FilledQStringFromValue(i, 16);
|
||||
}
|
||||
else if (selInfo == SelectionInfo::INSTRUCTIONTEXT)
|
||||
{
|
||||
DisassemblyLineInfo line;
|
||||
m_disassemblyManager.getLine(i, true, line);
|
||||
infoBlock += QString("%1 %2").arg(line.name.c_str()).arg(line.params.c_str());
|
||||
}
|
||||
else // INSTRUCTIONHEX
|
||||
{
|
||||
infoBlock += FilledQStringFromValue(m_cpu->read32(i), 16);
|
||||
}
|
||||
}
|
||||
return infoBlock;
|
||||
}
|
||||
|
||||
void DisassemblyWidget::gotoAddress(u32 address)
|
||||
{
|
||||
const u32 destAddress = address & ~3;
|
||||
// Center the address
|
||||
m_visibleStart = (destAddress - (m_visibleRows * 4 / 2)) & ~3;
|
||||
m_selectedAddressStart = destAddress;
|
||||
m_selectedAddressEnd = destAddress;
|
||||
|
||||
this->repaint();
|
||||
}
|
|
@ -0,0 +1,97 @@
|
|||
/* PCSX2 - PS2 Emulator for PCs
|
||||
* Copyright (C) 2002-2022 PCSX2 Dev Team
|
||||
*
|
||||
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
|
||||
* of the GNU Lesser General Public License as published by the Free Software Found-
|
||||
* ation, either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* PCSX2 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 PCSX2.
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "ui_DisassemblyWidget.h"
|
||||
|
||||
#include "pcsx2/DebugTools/DebugInterface.h"
|
||||
#include "pcsx2/DebugTools/DisassemblyManager.h"
|
||||
|
||||
#include <QtWidgets/QWidget>
|
||||
#include <QtWidgets/QMenu>
|
||||
#include <QtGui/QPainter>
|
||||
|
||||
class DisassemblyWidget final : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
DisassemblyWidget(QWidget* parent);
|
||||
~DisassemblyWidget();
|
||||
|
||||
// Required because our constructor needs to take no extra arguments.
|
||||
void SetCpu(DebugInterface* cpu);
|
||||
|
||||
// Required for the breakpoint list (ugh wtf)
|
||||
QString GetLineDisasm(u32 address);
|
||||
|
||||
protected:
|
||||
void paintEvent(QPaintEvent* event);
|
||||
void mousePressEvent(QMouseEvent* event);
|
||||
void mouseDoubleClickEvent(QMouseEvent* event);
|
||||
void wheelEvent(QWheelEvent* event);
|
||||
void keyPressEvent(QKeyEvent* event);
|
||||
|
||||
public slots:
|
||||
void customMenuRequested(QPoint pos);
|
||||
|
||||
// Context menu actions
|
||||
// When called, m_selectedAddressStart will be the 'selected' instruction
|
||||
// Of course, m_selectedAddressEnd will be the end of the selection when required
|
||||
void contextCopyAddress();
|
||||
void contextCopyInstructionHex();
|
||||
void contextCopyInstructionText();
|
||||
void contextAssembleInstruction();
|
||||
void contextRunToCursor();
|
||||
void contextJumpToCursor();
|
||||
void contextToggleBreakpoint();
|
||||
void contextFollowBranch();
|
||||
void contextGoToAddress();
|
||||
void contextAddFunction();
|
||||
void contextRenameFunction();
|
||||
void contextRemoveFunction();
|
||||
void gotoAddress(u32 address);
|
||||
|
||||
signals:
|
||||
void gotoInMemory(u32 address);
|
||||
void breakpointsChanged();
|
||||
void VMUpdate();
|
||||
|
||||
private:
|
||||
Ui::DisassemblyWidget ui;
|
||||
|
||||
QMenu* m_contextMenu = 0x0;
|
||||
void CreateCustomContextMenu();
|
||||
|
||||
DebugInterface* m_cpu;
|
||||
u32 m_visibleStart = 0x00336318; // The address of the first opcode shown(row 0)
|
||||
u32 m_visibleRows;
|
||||
u32 m_selectedAddressStart = 0;
|
||||
u32 m_selectedAddressEnd = 0;
|
||||
u32 m_rowHeight = 0;
|
||||
|
||||
DisassemblyManager m_disassemblyManager;
|
||||
|
||||
inline QString DisassemblyStringFromAddress(u32 address, QFont font, u32 pc);
|
||||
QColor GetAddressFunctionColor(u32 address);
|
||||
enum class SelectionInfo
|
||||
{
|
||||
ADDRESS,
|
||||
INSTRUCTIONHEX,
|
||||
INSTRUCTIONTEXT,
|
||||
};
|
||||
QString FetchSelectionInfo(SelectionInfo selInfo);
|
||||
};
|
|
@ -0,0 +1,19 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>DisassemblyWidget</class>
|
||||
<widget class="QWidget" name="DisassemblyWidget">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>400</width>
|
||||
<height>300</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Disassembly</string>
|
||||
</property>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
|
@ -0,0 +1,497 @@
|
|||
/* PCSX2 - PS2 Emulator for PCs
|
||||
* Copyright (C) 2002-2022 PCSX2 Dev Team
|
||||
*
|
||||
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
|
||||
* of the GNU Lesser General Public License as published by the Free Software Found-
|
||||
* ation, either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* PCSX2 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 PCSX2.
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "PrecompiledHeader.h"
|
||||
|
||||
#include "MemoryViewWidget.h"
|
||||
|
||||
#include "common/BitCast.h"
|
||||
|
||||
#include "QtHost.h"
|
||||
#include "QtUtils.h"
|
||||
#include <QtGui/QMouseEvent>
|
||||
#include <QtCore/QObject>
|
||||
#include <QtWidgets/QInputDialog>
|
||||
#include <QtWidgets/QMessageBox>
|
||||
#include <QtGui/QClipboard>
|
||||
#include <QtCore/QtEndian>
|
||||
|
||||
using namespace QtUtils;
|
||||
|
||||
/*
|
||||
MemoryViewTable
|
||||
*/
|
||||
void MemoryViewTable::UpdateStartAddress(u32 start)
|
||||
{
|
||||
startAddress = start & ~0xF;
|
||||
}
|
||||
|
||||
void MemoryViewTable::UpdateSelectedAddress(u32 selected, bool page)
|
||||
{
|
||||
selectedAddress = selected;
|
||||
if (startAddress > selectedAddress)
|
||||
{
|
||||
if (page)
|
||||
startAddress -= 0x10 * rowVisible;
|
||||
else
|
||||
startAddress -= 0x10;
|
||||
}
|
||||
else if (startAddress + ((rowVisible - 1) * 0x10) < selectedAddress)
|
||||
{
|
||||
if (page)
|
||||
startAddress += 0x10 * rowVisible;
|
||||
else
|
||||
startAddress += 0x10;
|
||||
}
|
||||
}
|
||||
|
||||
void MemoryViewTable::DrawTable(QPainter& painter, const QPalette& palette, s32 height)
|
||||
{
|
||||
rowHeight = painter.fontMetrics().height() + 2;
|
||||
const s32 charWidth = painter.fontMetrics().averageCharWidth();
|
||||
const s32 x = charWidth; // Left padding
|
||||
const s32 y = rowHeight;
|
||||
rowVisible = (height / rowHeight);
|
||||
rowCount = rowVisible + 1;
|
||||
|
||||
row1YAxis = 0;
|
||||
|
||||
// Draw the row addresses
|
||||
painter.setPen(palette.text().color());
|
||||
for (u32 i = 0; i < rowCount; i++)
|
||||
{
|
||||
painter.drawText(x, y + (rowHeight * i), FilledQStringFromValue(startAddress + (i * 0x10), 16));
|
||||
}
|
||||
valuexAxis = x + (charWidth * 8);
|
||||
|
||||
// Draw the row values
|
||||
for (u32 i = 0; i < rowCount; i++)
|
||||
{
|
||||
const u32 currentRowAddress = startAddress + (i * 0x10);
|
||||
s32 valX = valuexAxis;
|
||||
segmentXAxis[0] = valX;
|
||||
u32 currentSegmentAddress = currentRowAddress;
|
||||
for (int j = 0; j < 16; j++)
|
||||
{
|
||||
const u32 currentByteAddress = currentRowAddress + j;
|
||||
|
||||
if (!(j % (s32)displayType))
|
||||
{
|
||||
valX += charWidth;
|
||||
currentSegmentAddress = currentByteAddress;
|
||||
}
|
||||
segmentXAxis[j] = valX;
|
||||
|
||||
if ((selectedAddress & ~0xF) == currentRowAddress)
|
||||
{
|
||||
if (selectedAddress == currentByteAddress)
|
||||
{ // If the current byte and row we are drawing is selected
|
||||
if (!selectedText)
|
||||
{
|
||||
painter.setPen(QColor::fromRgb(205, 165, 0)); // SELECTED NIBBLE LINE COLOUR
|
||||
const QPoint lineStart(valX + (selectedNibbleHI ? 0 : charWidth) + 1, y + (rowHeight * i));
|
||||
painter.drawLine(lineStart, lineStart + QPoint(charWidth - 3, 0));
|
||||
}
|
||||
painter.setPen(QColor::fromRgb(0xaa, 0x22, 0x22)); // SELECTED BYTE COLOUR
|
||||
}
|
||||
// If the current selected byte is in our current segment, highlight the entire segment
|
||||
else if (displayType != MemoryViewType::BYTE &&
|
||||
currentSegmentAddress <= selectedAddress && (selectedAddress <= (currentSegmentAddress + (s32)displayType - 1)))
|
||||
{
|
||||
painter.setPen(palette.highlight().color()); // SELECTED SEGMENT COLOUR
|
||||
}
|
||||
else
|
||||
painter.setPen(palette.text().color()); // Default colour
|
||||
}
|
||||
else
|
||||
painter.setPen(palette.text().color()); // Default colour
|
||||
|
||||
bool valid;
|
||||
const u8 val = static_cast<u8>(m_cpu->read8(currentByteAddress, valid));
|
||||
|
||||
painter.drawText(valX, y + (rowHeight * i), valid ? FilledQStringFromValue(val, 16) : "??");
|
||||
|
||||
valX += charWidth * 2;
|
||||
}
|
||||
|
||||
// valX is our new X position after the hex values
|
||||
valX = valX + 6;
|
||||
textXAxis = valX;
|
||||
|
||||
// Print the string representation
|
||||
for (s32 j = 0; j < 16; j++)
|
||||
{
|
||||
if (selectedAddress == j + currentRowAddress)
|
||||
painter.setPen(palette.highlight().color());
|
||||
else
|
||||
painter.setPen(palette.text().color());
|
||||
|
||||
bool valid;
|
||||
const u8 value = m_cpu->read8(currentRowAddress + j, valid);
|
||||
if (valid)
|
||||
{
|
||||
QChar curChar = QChar::fromLatin1(value);
|
||||
if (!curChar.isPrint() && curChar != ' ') // Default to '.' for unprintable characters
|
||||
curChar = '.';
|
||||
|
||||
painter.drawText(valX, y + (rowHeight * i), curChar);
|
||||
}
|
||||
else
|
||||
{
|
||||
painter.drawText(valX, y + (rowHeight * i), "?");
|
||||
}
|
||||
valX += charWidth + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MemoryViewTable::SelectAt(QPoint pos)
|
||||
{
|
||||
const u32 selectedRow = (pos.y() - 2) / (rowHeight);
|
||||
const s32 x = pos.x();
|
||||
const s32 avgSegmentWidth = segmentXAxis[1] - segmentXAxis[0];
|
||||
selectedAddress = (selectedRow * 0x10) + startAddress;
|
||||
|
||||
if (x <= segmentXAxis[0])
|
||||
{
|
||||
selectedText = false;
|
||||
// The user clicked before the first segment
|
||||
selectedNibbleHI = true;
|
||||
}
|
||||
else if (x > valuexAxis && x < textXAxis)
|
||||
{
|
||||
selectedText = false;
|
||||
// The user clicked inside of the hexadecimal area
|
||||
for (s32 i = 0; i < 16; i++)
|
||||
{
|
||||
if (i == 15 || (x >= segmentXAxis[i] && x < (segmentXAxis[i + 1])))
|
||||
{
|
||||
selectedAddress = selectedAddress + i;
|
||||
selectedNibbleHI = ((x - segmentXAxis[i]) < ((avgSegmentWidth / 2) - 2)); // Subtract 2 units, makes selecting nibbles feel more natural
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (x >= textXAxis)
|
||||
{
|
||||
selectedText = true;
|
||||
// The user clicked the text area
|
||||
selectedAddress += std::min((x - textXAxis) / 8, 15);
|
||||
}
|
||||
}
|
||||
|
||||
u128 MemoryViewTable::GetSelectedSegment()
|
||||
{
|
||||
u128 val;
|
||||
switch (displayType)
|
||||
{
|
||||
case MemoryViewType::BYTE:
|
||||
val.lo = m_cpu->read8(selectedAddress);
|
||||
break;
|
||||
case MemoryViewType::BYTEHW:
|
||||
val.lo = qToBigEndian((u16)m_cpu->read16(selectedAddress & ~1));
|
||||
break;
|
||||
case MemoryViewType::WORD:
|
||||
val.lo = qToBigEndian(m_cpu->read32(selectedAddress & ~3));
|
||||
break;
|
||||
case MemoryViewType::DWORD:
|
||||
val._u64[0] = qToBigEndian(m_cpu->read64(selectedAddress & ~7));
|
||||
break;
|
||||
}
|
||||
return val;
|
||||
}
|
||||
|
||||
void MemoryViewTable::InsertIntoSelectedHexView(u8 value)
|
||||
{
|
||||
const u8 mask = selectedNibbleHI ? 0x0f : 0xf0;
|
||||
u8 curVal = m_cpu->read8(selectedAddress) & mask;
|
||||
u8 newVal = value << (selectedNibbleHI ? 4 : 0);
|
||||
curVal |= newVal;
|
||||
|
||||
Host::RunOnCPUThread([this, address = selectedAddress, cpu = m_cpu, val = curVal] {
|
||||
cpu->write8(address, val);
|
||||
QtHost::RunOnUIThread([this] { parent->update(); });
|
||||
});
|
||||
}
|
||||
// We need both key and keychar because `key` is easy to use, but is case insensitive
|
||||
void MemoryViewTable::KeyPress(int key, QChar keychar)
|
||||
{
|
||||
if (!m_cpu->isValidAddress(selectedAddress))
|
||||
return;
|
||||
|
||||
const bool keyCharIsText = keychar.isLetterOrNumber() || keychar.isSpace();
|
||||
|
||||
if (selectedText)
|
||||
{
|
||||
if (keyCharIsText || (!keychar.isNonCharacter() && keychar.category() != QChar::Other_Control))
|
||||
{
|
||||
Host::RunOnCPUThread([this, address = selectedAddress, cpu = m_cpu, val = keychar.toLatin1()] {
|
||||
cpu->write8(address, val);
|
||||
QtHost::RunOnUIThread([this] { UpdateSelectedAddress(selectedAddress + 1); parent->update(); });
|
||||
});
|
||||
}
|
||||
|
||||
switch (key)
|
||||
{
|
||||
case Qt::Key::Key_Backspace:
|
||||
case Qt::Key::Key_Escape:
|
||||
Host::RunOnCPUThread([this, address = selectedAddress, cpu = m_cpu, key] {
|
||||
cpu->write8(address, 0);
|
||||
QtHost::RunOnUIThread([this, key] { UpdateSelectedAddress(selectedAddress - 1); parent->update(); });
|
||||
});
|
||||
break;
|
||||
case Qt::Key::Key_Right:
|
||||
UpdateSelectedAddress(selectedAddress + 1);
|
||||
break;
|
||||
case Qt::Key::Key_Left:
|
||||
UpdateSelectedAddress(selectedAddress - 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Hex view is selected
|
||||
|
||||
if (keyCharIsText)
|
||||
{
|
||||
InsertIntoSelectedHexView(((u8)QString(QChar(key)).toInt(nullptr, 16)));
|
||||
// Increment to the next nibble or byte
|
||||
if (selectedNibbleHI = !selectedNibbleHI)
|
||||
UpdateSelectedAddress(selectedAddress + 1);
|
||||
}
|
||||
|
||||
switch (key)
|
||||
{
|
||||
case Qt::Key::Key_Backspace:
|
||||
case Qt::Key::Key_Escape:
|
||||
InsertIntoSelectedHexView(0);
|
||||
// Move back a byte or nibble if it's backspace being pressed
|
||||
if (!(selectedNibbleHI = !selectedNibbleHI))
|
||||
UpdateSelectedAddress(selectedAddress - 1);
|
||||
break;
|
||||
case Qt::Key::Key_Right:
|
||||
if (selectedNibbleHI = !selectedNibbleHI)
|
||||
UpdateSelectedAddress(selectedAddress + 1);
|
||||
break;
|
||||
case Qt::Key::Key_Left:
|
||||
if (!(selectedNibbleHI = !selectedNibbleHI))
|
||||
UpdateSelectedAddress(selectedAddress - 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Keybinds that are the same for the text and hex view
|
||||
|
||||
switch (key)
|
||||
{
|
||||
case Qt::Key::Key_Up:
|
||||
UpdateSelectedAddress(selectedAddress - 0x10);
|
||||
break;
|
||||
case Qt::Key::Key_PageUp:
|
||||
UpdateSelectedAddress(selectedAddress - (0x10 * rowVisible), true);
|
||||
break;
|
||||
case Qt::Key::Key_Down:
|
||||
UpdateSelectedAddress(selectedAddress + 0x10);
|
||||
break;
|
||||
case Qt::Key::Key_PageDown:
|
||||
UpdateSelectedAddress(selectedAddress + (0x10 * rowVisible), true);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
MemoryViewWidget
|
||||
*/
|
||||
MemoryViewWidget::MemoryViewWidget(QWidget* parent)
|
||||
: QWidget(parent)
|
||||
, m_table(this)
|
||||
{
|
||||
ui.setupUi(this);
|
||||
this->setFocusPolicy(Qt::FocusPolicy::ClickFocus);
|
||||
connect(this, &MemoryViewWidget::customContextMenuRequested, this, &MemoryViewWidget::customMenuRequested);
|
||||
}
|
||||
|
||||
MemoryViewWidget::~MemoryViewWidget() = default;
|
||||
|
||||
void MemoryViewWidget::SetCpu(DebugInterface* cpu)
|
||||
{
|
||||
m_cpu = cpu;
|
||||
m_table.SetCpu(cpu);
|
||||
m_table.UpdateStartAddress(0x480000);
|
||||
}
|
||||
|
||||
void MemoryViewWidget::paintEvent(QPaintEvent* event)
|
||||
{
|
||||
if (!m_cpu->isAlive())
|
||||
return;
|
||||
|
||||
QPainter painter(this);
|
||||
|
||||
m_table.DrawTable(painter, this->palette(), this->height());
|
||||
}
|
||||
|
||||
void MemoryViewWidget::mousePressEvent(QMouseEvent* event)
|
||||
{
|
||||
m_table.SelectAt(event->pos());
|
||||
repaint();
|
||||
}
|
||||
|
||||
void MemoryViewWidget::customMenuRequested(QPoint pos)
|
||||
{
|
||||
if (!m_contextMenu)
|
||||
{
|
||||
m_contextMenu = new QMenu(this);
|
||||
|
||||
QAction* action = new QAction("Go to in disassembly");
|
||||
m_contextMenu->addAction(action);
|
||||
connect(action, &QAction::triggered, this, [this]() { emit gotoInDisasm(m_table.selectedAddress); });
|
||||
|
||||
action = new QAction("Go to address");
|
||||
m_contextMenu->addAction(action);
|
||||
connect(action, &QAction::triggered, this, [this]() { contextGoToAddress(); });
|
||||
|
||||
m_contextMenu->addSeparator();
|
||||
|
||||
// View Types
|
||||
m_actionBYTE = new QAction("Show as 1 byte");
|
||||
m_actionBYTE->setCheckable(true);
|
||||
m_contextMenu->addAction(m_actionBYTE);
|
||||
connect(m_actionBYTE, &QAction::triggered, this, [this]() { m_table.SetViewType(MemoryViewType::BYTE); });
|
||||
|
||||
m_actionBYTEHW = new QAction("Show as 2 bytes");
|
||||
m_actionBYTEHW->setCheckable(true);
|
||||
m_contextMenu->addAction(m_actionBYTEHW);
|
||||
connect(m_actionBYTEHW, &QAction::triggered, this, [this]() { m_table.SetViewType(MemoryViewType::BYTEHW); });
|
||||
|
||||
m_actionWORD = new QAction("Show as 4 bytes");
|
||||
m_actionWORD->setCheckable(true);
|
||||
m_contextMenu->addAction(m_actionWORD);
|
||||
connect(m_actionWORD, &QAction::triggered, this, [this]() { m_table.SetViewType(MemoryViewType::WORD); });
|
||||
|
||||
m_actionDWORD = new QAction("Show as 8 bytes");
|
||||
m_actionDWORD->setCheckable(true);
|
||||
m_contextMenu->addAction(m_actionDWORD);
|
||||
connect(m_actionDWORD, &QAction::triggered, this, [this]() { m_table.SetViewType(MemoryViewType::DWORD); });
|
||||
|
||||
m_contextMenu->addSeparator();
|
||||
|
||||
action = new QAction("Copy Byte");
|
||||
m_contextMenu->addAction(action);
|
||||
connect(action, &QAction::triggered, this, [this]() { contextCopyByte(); });
|
||||
|
||||
action = new QAction("Copy Segment");
|
||||
m_contextMenu->addAction(action);
|
||||
connect(action, &QAction::triggered, this, [this]() { contextCopySegment(); });
|
||||
|
||||
action = new QAction("Copy Character");
|
||||
m_contextMenu->addAction(action);
|
||||
connect(action, &QAction::triggered, this, [this]() { contextCopyCharacter(); });
|
||||
}
|
||||
const MemoryViewType currentViewType = m_table.GetViewType();
|
||||
|
||||
m_actionBYTE->setChecked(currentViewType == MemoryViewType::BYTE);
|
||||
m_actionBYTEHW->setChecked(currentViewType == MemoryViewType::BYTEHW);
|
||||
m_actionWORD->setChecked(currentViewType == MemoryViewType::WORD);
|
||||
m_actionDWORD->setChecked(currentViewType == MemoryViewType::DWORD);
|
||||
m_contextMenu->popup(this->mapToGlobal(pos));
|
||||
|
||||
this->repaint();
|
||||
return;
|
||||
}
|
||||
|
||||
void MemoryViewWidget::contextCopyByte()
|
||||
{
|
||||
QApplication::clipboard()->setText(QString::number(m_cpu->read8(m_table.selectedAddress), 16).toUpper());
|
||||
}
|
||||
|
||||
void MemoryViewWidget::contextCopySegment()
|
||||
{
|
||||
QApplication::clipboard()->setText(QString::number(m_table.GetSelectedSegment().lo, 16).toUpper());
|
||||
}
|
||||
|
||||
void MemoryViewWidget::contextCopyCharacter()
|
||||
{
|
||||
QApplication::clipboard()->setText(QChar::fromLatin1(m_cpu->read8(m_table.selectedAddress)).toUpper());
|
||||
}
|
||||
|
||||
void MemoryViewWidget::contextGoToAddress()
|
||||
{
|
||||
bool ok;
|
||||
QString targetString = QInputDialog::getText(this, "Go to address", "",
|
||||
QLineEdit::Normal, "", &ok);
|
||||
|
||||
if (!ok)
|
||||
return;
|
||||
|
||||
const u32 targetAddress = targetString.toUInt(&ok, 16);
|
||||
|
||||
if (!ok)
|
||||
{
|
||||
QMessageBox::warning(this, "Go to address error", "Invalid address");
|
||||
return;
|
||||
}
|
||||
|
||||
gotoAddress(targetAddress);
|
||||
}
|
||||
|
||||
void MemoryViewWidget::mouseDoubleClickEvent(QMouseEvent* event)
|
||||
{
|
||||
}
|
||||
|
||||
void MemoryViewWidget::wheelEvent(QWheelEvent* event)
|
||||
{
|
||||
if (event->angleDelta().y() < 0)
|
||||
{
|
||||
m_table.UpdateStartAddress(m_table.startAddress + 0x10);
|
||||
}
|
||||
else if (event->angleDelta().y() > 0)
|
||||
{
|
||||
m_table.UpdateStartAddress(m_table.startAddress - 0x10);
|
||||
}
|
||||
this->repaint();
|
||||
}
|
||||
|
||||
void MemoryViewWidget::keyPressEvent(QKeyEvent* event)
|
||||
{
|
||||
bool handledByWidget = true;
|
||||
switch (event->key())
|
||||
{
|
||||
case Qt::Key_G:
|
||||
contextGoToAddress();
|
||||
break;
|
||||
case Qt::Key_C:
|
||||
if (event->modifiers() & Qt::ControlModifier)
|
||||
contextCopySegment();
|
||||
else
|
||||
handledByWidget = false;
|
||||
break;
|
||||
default:
|
||||
handledByWidget = false;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!handledByWidget)
|
||||
m_table.KeyPress(event->key(), event->text().size() ? event->text()[0] : '\0');
|
||||
|
||||
this->repaint();
|
||||
VMUpdate();
|
||||
}
|
||||
|
||||
void MemoryViewWidget::gotoAddress(u32 address)
|
||||
{
|
||||
m_table.UpdateStartAddress(address & ~0xF);
|
||||
m_table.selectedAddress = address;
|
||||
this->repaint();
|
||||
}
|
|
@ -0,0 +1,129 @@
|
|||
/* PCSX2 - PS2 Emulator for PCs
|
||||
* Copyright (C) 2002-2022 PCSX2 Dev Team
|
||||
*
|
||||
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
|
||||
* of the GNU Lesser General Public License as published by the Free Software Found-
|
||||
* ation, either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* PCSX2 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 PCSX2.
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "ui_RegisterWidget.h"
|
||||
|
||||
#include "DebugTools/DebugInterface.h"
|
||||
#include "DebugTools/DisassemblyManager.h"
|
||||
|
||||
#include <QtWidgets/QWidget>
|
||||
#include <QtWidgets/QMenu>
|
||||
#include <QtWidgets/QTabBar>
|
||||
#include <QtGui/QPainter>
|
||||
|
||||
#include <vector>
|
||||
|
||||
enum class MemoryViewType
|
||||
{
|
||||
BYTE = 1,
|
||||
BYTEHW = 2,
|
||||
WORD = 4,
|
||||
DWORD = 8,
|
||||
};
|
||||
|
||||
class MemoryViewTable
|
||||
{
|
||||
QWidget* parent;
|
||||
DebugInterface* m_cpu;
|
||||
MemoryViewType displayType = MemoryViewType::BYTE;
|
||||
u32 rowCount;
|
||||
u32 rowVisible;
|
||||
s32 rowHeight;
|
||||
|
||||
// Stuff used for selection handling
|
||||
// This gets set every paint and depends on the window size / current display mode (1byte,2byte,etc)
|
||||
s32 valuexAxis; // Where the hexadecimal view begins
|
||||
s32 textXAxis; // Where the text view begins
|
||||
s32 row1YAxis; // Where the first row starts
|
||||
s32 segmentXAxis[16]; // Where the segments begin
|
||||
bool selectedText = false; // Whether the user has clicked on text or hex
|
||||
|
||||
bool selectedNibbleHI = false;
|
||||
|
||||
void InsertIntoSelectedHexView(u8 value);
|
||||
|
||||
public:
|
||||
MemoryViewTable(QWidget* parent)
|
||||
: parent(parent){};
|
||||
u32 startAddress;
|
||||
u32 selectedAddress;
|
||||
|
||||
void SetCpu(DebugInterface* cpu)
|
||||
{
|
||||
m_cpu = cpu;
|
||||
}
|
||||
void UpdateStartAddress(u32 start);
|
||||
void UpdateSelectedAddress(u32 selected, bool page = false);
|
||||
void DrawTable(QPainter& painter, const QPalette& palette, s32 height);
|
||||
void SelectAt(QPoint pos);
|
||||
u128 GetSelectedSegment();
|
||||
void KeyPress(int key, QChar keychar);
|
||||
|
||||
MemoryViewType GetViewType()
|
||||
{
|
||||
return displayType;
|
||||
}
|
||||
|
||||
void SetViewType(MemoryViewType viewType)
|
||||
{
|
||||
displayType = viewType;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
class MemoryViewWidget final : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
MemoryViewWidget(QWidget* parent);
|
||||
~MemoryViewWidget();
|
||||
|
||||
void SetCpu(DebugInterface* cpu);
|
||||
|
||||
protected:
|
||||
void paintEvent(QPaintEvent* event);
|
||||
void mousePressEvent(QMouseEvent* event);
|
||||
void mouseDoubleClickEvent(QMouseEvent* event);
|
||||
void wheelEvent(QWheelEvent* event);
|
||||
void keyPressEvent(QKeyEvent* event);
|
||||
|
||||
public slots:
|
||||
void customMenuRequested(QPoint pos);
|
||||
|
||||
void contextGoToAddress();
|
||||
void contextCopyByte();
|
||||
void contextCopySegment();
|
||||
void contextCopyCharacter();
|
||||
void gotoAddress(u32 address);
|
||||
|
||||
signals:
|
||||
void gotoInDisasm(u32 address);
|
||||
void VMUpdate();
|
||||
|
||||
private:
|
||||
Ui::RegisterWidget ui;
|
||||
|
||||
QMenu* m_contextMenu = 0x0;
|
||||
QAction* m_actionBYTE;
|
||||
QAction* m_actionBYTEHW;
|
||||
QAction* m_actionWORD;
|
||||
QAction* m_actionDWORD;
|
||||
|
||||
DebugInterface* m_cpu;
|
||||
MemoryViewTable m_table;
|
||||
};
|
|
@ -0,0 +1,19 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>MemoryViewWidget</class>
|
||||
<widget class="QWidget" name="MemoryViewWidget">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>400</width>
|
||||
<height>300</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Memory</string>
|
||||
</property>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
|
@ -0,0 +1,446 @@
|
|||
/* PCSX2 - PS2 Emulator for PCs
|
||||
* Copyright (C) 2002-2022 PCSX2 Dev Team
|
||||
*
|
||||
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
|
||||
* of the GNU Lesser General Public License as published by the Free Software Found-
|
||||
* ation, either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* PCSX2 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 PCSX2.
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "PrecompiledHeader.h"
|
||||
|
||||
#include "RegisterWidget.h"
|
||||
|
||||
#include "common/BitCast.h"
|
||||
|
||||
#include "QtUtils.h"
|
||||
#include <QtGui/QMouseEvent>
|
||||
#include <QtWidgets/QTabBar>
|
||||
#include <QtWidgets/QStylePainter>
|
||||
#include <QtWidgets/QStyleOptionTab>
|
||||
#include <QtGui/QClipboard>
|
||||
#include <QtWidgets/QInputDialog>
|
||||
#include <QtWidgets/QProxyStyle>
|
||||
#include <QtWidgets/QMessageBox>
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#define CAT_SHOW_FLOAT (categoryIndex == EECAT_FPR && m_showFPRFloat) || (categoryIndex == EECAT_VU0F && m_showVU0FFloat)
|
||||
|
||||
using namespace QtUtils;
|
||||
|
||||
RegisterWidget::RegisterWidget(QWidget* parent)
|
||||
: QWidget(parent)
|
||||
{
|
||||
this->setContextMenuPolicy(Qt::ContextMenuPolicy::CustomContextMenu);
|
||||
|
||||
ui.setupUi(this);
|
||||
ui.registerTabs->setDrawBase(false);
|
||||
|
||||
connect(this, &RegisterWidget::customContextMenuRequested, this, &RegisterWidget::customMenuRequested);
|
||||
connect(ui.registerTabs, &QTabBar::currentChanged, this, &RegisterWidget::tabCurrentChanged);
|
||||
};
|
||||
|
||||
RegisterWidget::~RegisterWidget()
|
||||
{
|
||||
}
|
||||
|
||||
void RegisterWidget::SetCpu(DebugInterface* cpu)
|
||||
{
|
||||
m_cpu = cpu;
|
||||
for (int i = 0; i < m_cpu->getRegisterCategoryCount(); i++)
|
||||
{
|
||||
ui.registerTabs->addTab(m_cpu->getRegisterCategoryName(i));
|
||||
}
|
||||
|
||||
connect(ui.registerTabs, &QTabBar::currentChanged, [this]() { this->repaint(); });
|
||||
}
|
||||
|
||||
void RegisterWidget::tabCurrentChanged(int cur)
|
||||
{
|
||||
m_rowStart = 0;
|
||||
}
|
||||
|
||||
void RegisterWidget::paintEvent(QPaintEvent* event)
|
||||
{
|
||||
if (!m_cpu)
|
||||
return;
|
||||
|
||||
QPainter painter(this);
|
||||
painter.setPen(this->palette().text().color());
|
||||
m_renderStart = QPoint(0, ui.registerTabs->pos().y() + ui.registerTabs->size().height());
|
||||
const QSize renderSize = QSize(this->size().width(), this->size().height() - ui.registerTabs->size().height());
|
||||
|
||||
m_rowHeight = painter.fontMetrics().height() + 2;
|
||||
m_rowEnd = m_rowStart + (renderSize.height() / m_rowHeight) - 1; // Maybe move this to a onsize event
|
||||
|
||||
bool alternate = m_rowStart % 2;
|
||||
|
||||
const int categoryIndex = ui.registerTabs->currentIndex();
|
||||
|
||||
// Used for 128 bit and VU0f registers
|
||||
const int titleStartX = m_renderStart.x() + (painter.fontMetrics().averageCharWidth() * 6);
|
||||
m_fieldWidth = ((renderSize.width() - (painter.fontMetrics().averageCharWidth() * 6)) / 4);
|
||||
|
||||
m_fieldStartX[0] = titleStartX;
|
||||
m_fieldStartX[1] = titleStartX + m_fieldWidth;
|
||||
m_fieldStartX[2] = titleStartX + (m_fieldWidth * 2);
|
||||
m_fieldStartX[3] = titleStartX + (m_fieldWidth * 3);
|
||||
|
||||
if (categoryIndex == EECAT_VU0F)
|
||||
{
|
||||
painter.fillRect(m_renderStart.x(), m_renderStart.y(), renderSize.width(), m_rowHeight, this->palette().highlight());
|
||||
|
||||
painter.drawText(m_fieldStartX[0], m_renderStart.y(), m_fieldWidth, m_rowHeight, Qt::AlignLeft, "W");
|
||||
painter.drawText(m_fieldStartX[1], m_renderStart.y(), m_fieldWidth, m_rowHeight, Qt::AlignLeft, "Z");
|
||||
painter.drawText(m_fieldStartX[2], m_renderStart.y(), m_fieldWidth, m_rowHeight, Qt::AlignLeft, "Y");
|
||||
painter.drawText(m_fieldStartX[3], m_renderStart.y(), m_fieldWidth, m_rowHeight, Qt::AlignLeft, "X");
|
||||
|
||||
m_renderStart += QPoint(0, m_rowHeight); // Make room for VU0f titles
|
||||
}
|
||||
|
||||
// Find the longest register name and calculate where to place our values
|
||||
// off of that.
|
||||
// Can probably constexpr the loop out as register names are known during runtime
|
||||
int safeValueStartX = 0;
|
||||
for (int i = 0; i < m_cpu->getRegisterCount(categoryIndex); i++)
|
||||
{
|
||||
const int registerNameWidth = strlen(m_cpu->getRegisterName(categoryIndex, i));
|
||||
if (safeValueStartX < registerNameWidth)
|
||||
{
|
||||
safeValueStartX = registerNameWidth;
|
||||
}
|
||||
}
|
||||
|
||||
// Add a space between the value and name
|
||||
safeValueStartX += 2;
|
||||
// Convert to width in pixels
|
||||
safeValueStartX *= painter.fontMetrics().averageCharWidth();
|
||||
// Make it relative to where we start rendering
|
||||
safeValueStartX += m_renderStart.x();
|
||||
|
||||
for (s32 i = 0; i < m_cpu->getRegisterCount(categoryIndex) - m_rowStart; i++)
|
||||
{
|
||||
const s32 registerIndex = i + m_rowStart;
|
||||
const int yStart = (i * m_rowHeight) + m_renderStart.y();
|
||||
|
||||
painter.fillRect(m_renderStart.x(), yStart, renderSize.width(), m_rowHeight, alternate ? this->palette().base() : this->palette().alternateBase());
|
||||
alternate = !alternate;
|
||||
|
||||
// Draw register name
|
||||
painter.setPen(this->palette().text().color());
|
||||
painter.drawText(m_renderStart.x() + painter.fontMetrics().averageCharWidth(), yStart, renderSize.width(), m_rowHeight, Qt::AlignLeft, m_cpu->getRegisterName(categoryIndex, registerIndex));
|
||||
|
||||
if (m_cpu->getRegisterSize(categoryIndex) == 128)
|
||||
{
|
||||
const u128 curRegister = m_cpu->getRegister(categoryIndex, registerIndex);
|
||||
|
||||
int regIndex = 3;
|
||||
for (int j = 0; j < 4; j++)
|
||||
{
|
||||
if (m_selectedRow == registerIndex && m_selected128Field == j)
|
||||
painter.setPen(this->palette().highlight().color());
|
||||
else
|
||||
painter.setPen(this->palette().text().color());
|
||||
|
||||
if (categoryIndex == EECAT_VU0F && m_showVU0FFloat)
|
||||
painter.drawText(m_fieldStartX[j], yStart, m_fieldWidth, m_rowHeight, Qt::AlignLeft,
|
||||
painter.fontMetrics().elidedText(QString::number(bit_cast<float>(m_cpu->getRegister(categoryIndex, registerIndex)._u32[regIndex])), Qt::ElideRight, m_fieldWidth - painter.fontMetrics().averageCharWidth()));
|
||||
else
|
||||
painter.drawText(m_fieldStartX[j], yStart, m_fieldWidth, m_rowHeight,
|
||||
Qt::AlignLeft, FilledQStringFromValue(curRegister._u32[regIndex], 16));
|
||||
regIndex--;
|
||||
}
|
||||
painter.setPen(this->palette().text().color());
|
||||
}
|
||||
else
|
||||
{
|
||||
if (m_selectedRow == registerIndex)
|
||||
painter.setPen(this->palette().highlight().color());
|
||||
else
|
||||
painter.setPen(this->palette().text().color());
|
||||
|
||||
if (categoryIndex == EECAT_FPR && m_showFPRFloat)
|
||||
painter.drawText(safeValueStartX, yStart, renderSize.width(), m_rowHeight, Qt::AlignLeft,
|
||||
QString("%1").arg(QString::number(bit_cast<float>(m_cpu->getRegister(categoryIndex, registerIndex)._u32[0]))).toUpper());
|
||||
else if (m_cpu->getRegisterSize(categoryIndex) == 64)
|
||||
painter.drawText(safeValueStartX, yStart, renderSize.width(), m_rowHeight, Qt::AlignLeft,
|
||||
FilledQStringFromValue(m_cpu->getRegister(categoryIndex, registerIndex).lo, 16));
|
||||
else
|
||||
painter.drawText(safeValueStartX, yStart, renderSize.width(), m_rowHeight, Qt::AlignLeft,
|
||||
FilledQStringFromValue(m_cpu->getRegister(categoryIndex, registerIndex)._u32[0], 16));
|
||||
}
|
||||
}
|
||||
painter.end();
|
||||
}
|
||||
|
||||
void RegisterWidget::mousePressEvent(QMouseEvent* event)
|
||||
{
|
||||
const int categoryIndex = ui.registerTabs->currentIndex();
|
||||
m_selectedRow = ((event->y() - m_renderStart.y()) / m_rowHeight) + m_rowStart;
|
||||
|
||||
// For 128 bit types, support selecting segments
|
||||
if (m_cpu->getRegisterSize(categoryIndex) == 128)
|
||||
{
|
||||
constexpr auto inRange = [](u32 low, u32 high, u32 val) {
|
||||
return (low <= val && val <= high);
|
||||
};
|
||||
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
if (inRange(m_fieldStartX[i], m_fieldStartX[i] + m_fieldWidth, event->x()))
|
||||
{
|
||||
m_selected128Field = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
this->repaint();
|
||||
}
|
||||
|
||||
void RegisterWidget::wheelEvent(QWheelEvent* event)
|
||||
{
|
||||
if (event->angleDelta().y() < 0 && m_rowEnd < m_cpu->getRegisterCount(ui.registerTabs->currentIndex()))
|
||||
{
|
||||
m_rowStart += 1;
|
||||
}
|
||||
else if (event->angleDelta().y() > 0 && m_rowStart > 0)
|
||||
{
|
||||
m_rowStart -= 1;
|
||||
}
|
||||
|
||||
this->repaint();
|
||||
}
|
||||
|
||||
void RegisterWidget::customMenuRequested(QPoint pos)
|
||||
{
|
||||
if (m_selectedRow > m_rowEnd) // Unsigned underflow; selectedRow will be > m_rowEnd (technically negative)
|
||||
return;
|
||||
|
||||
// Unlike the disassembly widget, we need to create a new context menu every time
|
||||
// we show it. Because some register groups are special
|
||||
if (!m_contextMenu)
|
||||
m_contextMenu = new QMenu(this);
|
||||
else
|
||||
m_contextMenu->clear();
|
||||
|
||||
int categoryIndex = ui.registerTabs->currentIndex();
|
||||
|
||||
QAction* action = 0;
|
||||
|
||||
if (categoryIndex == EECAT_FPR)
|
||||
{
|
||||
m_contextMenu->addAction(action = new QAction(m_showFPRFloat ? "View as hex" : "View as float"));
|
||||
connect(action, &QAction::triggered, this, [this]() { m_showFPRFloat = !m_showFPRFloat; });
|
||||
m_contextMenu->addSeparator();
|
||||
}
|
||||
|
||||
if (categoryIndex == EECAT_VU0F)
|
||||
{
|
||||
m_contextMenu->addAction(action = new QAction(m_showVU0FFloat ? "View as hex" : "View as float"));
|
||||
connect(action, &QAction::triggered, this, [this]() { m_showVU0FFloat = !m_showVU0FFloat; });
|
||||
m_contextMenu->addSeparator();
|
||||
}
|
||||
|
||||
if (m_cpu->getRegisterSize(categoryIndex) == 128)
|
||||
{
|
||||
m_contextMenu->addAction(action = new QAction("Copy Top Half", this));
|
||||
connect(action, &QAction::triggered, this, &RegisterWidget::contextCopyTop);
|
||||
m_contextMenu->addAction(action = new QAction("Copy Bottom Half", this));
|
||||
connect(action, &QAction::triggered, this, &RegisterWidget::contextCopyBottom);
|
||||
m_contextMenu->addAction(action = new QAction("Copy Segment", this));
|
||||
connect(action, &QAction::triggered, this, &RegisterWidget::contextCopySegment);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_contextMenu->addAction(action = new QAction("Copy Value", this));
|
||||
connect(action, &QAction::triggered, this, &RegisterWidget::contextCopyValue);
|
||||
}
|
||||
|
||||
m_contextMenu->addSeparator();
|
||||
|
||||
if (m_cpu->getRegisterSize(categoryIndex) == 128)
|
||||
{
|
||||
m_contextMenu->addAction(action = new QAction("Change Top Half", this));
|
||||
connect(action, &QAction::triggered, this, &RegisterWidget::contextChangeTop);
|
||||
m_contextMenu->addAction(action = new QAction("Change Bottom Half", this));
|
||||
connect(action, &QAction::triggered, this, &RegisterWidget::contextChangeBottom);
|
||||
m_contextMenu->addAction(action = new QAction("Change Segment", this));
|
||||
connect(action, &QAction::triggered, this, &RegisterWidget::contextChangeSegment);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_contextMenu->addAction(action = new QAction("Change Value", this));
|
||||
connect(action, &QAction::triggered, this, &RegisterWidget::contextChangeValue);
|
||||
}
|
||||
|
||||
m_contextMenu->addSeparator();
|
||||
|
||||
m_contextMenu->addAction(action = new QAction("Go to in Disassembly", this));
|
||||
connect(action, &QAction::triggered, this, &RegisterWidget::contextGotoDisasm);
|
||||
|
||||
m_contextMenu->addAction(action = new QAction("Go to in Memory", this));
|
||||
connect(action, &QAction::triggered, this, &RegisterWidget::contextGotoMemory);
|
||||
|
||||
m_contextMenu->popup(this->mapToGlobal(pos));
|
||||
}
|
||||
|
||||
|
||||
void RegisterWidget::contextCopyValue()
|
||||
{
|
||||
const int categoryIndex = ui.registerTabs->currentIndex();
|
||||
const u128 val = m_cpu->getRegister(categoryIndex, m_selectedRow);
|
||||
if (CAT_SHOW_FLOAT)
|
||||
QApplication::clipboard()->setText(QString("%1").arg(QString::number(bit_cast<float>(val._u32[0])).toUpper(), 16));
|
||||
else
|
||||
QApplication::clipboard()->setText(QString("%1").arg(QString::number(val._u64[0], 16).toUpper(), 16));
|
||||
}
|
||||
|
||||
void RegisterWidget::contextCopyTop()
|
||||
{
|
||||
const int categoryIndex = ui.registerTabs->currentIndex();
|
||||
const u128 val = m_cpu->getRegister(categoryIndex, m_selectedRow);
|
||||
QApplication::clipboard()->setText(FilledQStringFromValue(val.hi, 16));
|
||||
}
|
||||
|
||||
void RegisterWidget::contextCopyBottom()
|
||||
{
|
||||
const int categoryIndex = ui.registerTabs->currentIndex();
|
||||
const u128 val = m_cpu->getRegister(categoryIndex, m_selectedRow);
|
||||
QApplication::clipboard()->setText(FilledQStringFromValue(val.lo, 16));
|
||||
}
|
||||
|
||||
void RegisterWidget::contextCopySegment()
|
||||
{
|
||||
const int categoryIndex = ui.registerTabs->currentIndex();
|
||||
const u128 val = m_cpu->getRegister(categoryIndex, m_selectedRow);
|
||||
if (CAT_SHOW_FLOAT)
|
||||
QApplication::clipboard()->setText(FilledQStringFromValue(bit_cast<float>(val._u32[3 - m_selected128Field]), 10));
|
||||
else
|
||||
QApplication::clipboard()->setText(FilledQStringFromValue(val._u32[3 - m_selected128Field], 16));
|
||||
}
|
||||
|
||||
bool RegisterWidget::contextFetchNewValue(u64& out, u64 currentValue, bool segment)
|
||||
{
|
||||
const int categoryIndex = ui.registerTabs->currentIndex();
|
||||
const bool floatingPoint = CAT_SHOW_FLOAT && segment;
|
||||
const int regSize = m_cpu->getRegisterSize(categoryIndex);
|
||||
bool ok = false;
|
||||
|
||||
QString existingValue("%1");
|
||||
|
||||
if (!floatingPoint)
|
||||
existingValue = existingValue.arg(currentValue, regSize == 64 ? 16 : 8, 16, QChar('0'));
|
||||
else
|
||||
existingValue = existingValue.arg(bit_cast<float>((u32)currentValue));
|
||||
|
||||
QString input = QInputDialog::getText(this, QString("Change %1").arg(m_cpu->getRegisterName(categoryIndex, m_selectedRow)), "",
|
||||
QLineEdit::Normal, existingValue, &ok);
|
||||
|
||||
if (!ok)
|
||||
return false;
|
||||
|
||||
if (!floatingPoint) // Get input as hexadecimal
|
||||
{
|
||||
out = input.toULongLong(&ok, 16);
|
||||
if (!ok)
|
||||
{
|
||||
QMessageBox::warning(this, "Invalid register value", "Invalid hexadecimal register value.");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
out = bit_cast<u32>(input.toFloat(&ok));
|
||||
if (!ok)
|
||||
{
|
||||
QMessageBox::warning(this, "Invalid register value", "Invalid floating-point register value.");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void RegisterWidget::contextChangeValue()
|
||||
{
|
||||
const int categoryIndex = ui.registerTabs->currentIndex();
|
||||
u64 newVal;
|
||||
if (contextFetchNewValue(newVal, m_cpu->getRegister(categoryIndex, m_selectedRow).lo))
|
||||
{
|
||||
m_cpu->setRegister(categoryIndex, m_selectedRow, u128::From64(newVal));
|
||||
VMUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
void RegisterWidget::contextChangeTop()
|
||||
{
|
||||
u64 newVal;
|
||||
u128 oldVal = m_cpu->getRegister(ui.registerTabs->currentIndex(), m_selectedRow);
|
||||
if (contextFetchNewValue(newVal, oldVal.hi))
|
||||
{
|
||||
oldVal.hi = newVal;
|
||||
m_cpu->setRegister(ui.registerTabs->currentIndex(), m_selectedRow, oldVal);
|
||||
VMUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
void RegisterWidget::contextChangeBottom()
|
||||
{
|
||||
u64 newVal;
|
||||
u128 oldVal = m_cpu->getRegister(ui.registerTabs->currentIndex(), m_selectedRow);
|
||||
if (contextFetchNewValue(newVal, oldVal.lo))
|
||||
{
|
||||
oldVal.lo = newVal;
|
||||
m_cpu->setRegister(ui.registerTabs->currentIndex(), m_selectedRow, oldVal);
|
||||
VMUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
void RegisterWidget::contextChangeSegment()
|
||||
{
|
||||
u64 newVal;
|
||||
u128 oldVal = m_cpu->getRegister(ui.registerTabs->currentIndex(), m_selectedRow);
|
||||
if (contextFetchNewValue(newVal, oldVal._u32[3 - m_selected128Field], true))
|
||||
{
|
||||
oldVal._u32[3 - m_selected128Field] = (u32)newVal;
|
||||
m_cpu->setRegister(ui.registerTabs->currentIndex(), m_selectedRow, oldVal);
|
||||
VMUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
void RegisterWidget::contextGotoDisasm()
|
||||
{
|
||||
const int categoryIndex = ui.registerTabs->currentIndex();
|
||||
u128 regVal = m_cpu->getRegister(categoryIndex, m_selectedRow);
|
||||
u32 addr = 0;
|
||||
|
||||
if (m_cpu->getRegisterSize(categoryIndex) == 128)
|
||||
addr = regVal._u32[3 - m_selected128Field];
|
||||
else
|
||||
addr = regVal._u32[0];
|
||||
|
||||
if (m_cpu->isValidAddress(addr))
|
||||
gotoInDisasm(addr);
|
||||
else
|
||||
QMessageBox::warning(this, "Invalid target address", "This register holds an invalid address.");
|
||||
}
|
||||
|
||||
void RegisterWidget::contextGotoMemory()
|
||||
{
|
||||
const int categoryIndex = ui.registerTabs->currentIndex();
|
||||
u128 regVal = m_cpu->getRegister(categoryIndex, m_selectedRow);
|
||||
u32 addr = 0;
|
||||
|
||||
if (m_cpu->getRegisterSize(categoryIndex) == 128)
|
||||
addr = regVal._u32[3 - m_selected128Field];
|
||||
else
|
||||
addr = regVal._u32[0];
|
||||
|
||||
gotoInMemory(addr);
|
||||
}
|
|
@ -0,0 +1,91 @@
|
|||
/* PCSX2 - PS2 Emulator for PCs
|
||||
* Copyright (C) 2002-2022 PCSX2 Dev Team
|
||||
*
|
||||
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
|
||||
* of the GNU Lesser General Public License as published by the Free Software Found-
|
||||
* ation, either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* PCSX2 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 PCSX2.
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "ui_RegisterWidget.h"
|
||||
|
||||
#include "DebugTools/DebugInterface.h"
|
||||
#include "DebugTools/DisassemblyManager.h"
|
||||
|
||||
#include <QtWidgets/QWidget>
|
||||
#include <QtWidgets/QMenu>
|
||||
#include <QtWidgets/QTabBar>
|
||||
#include <QtGui/QPainter>
|
||||
|
||||
class RegisterWidget final : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
RegisterWidget(QWidget* parent);
|
||||
~RegisterWidget();
|
||||
|
||||
void SetCpu(DebugInterface* cpu);
|
||||
|
||||
protected:
|
||||
void paintEvent(QPaintEvent* event);
|
||||
void mousePressEvent(QMouseEvent* event);
|
||||
void wheelEvent(QWheelEvent* event);
|
||||
|
||||
public slots:
|
||||
void customMenuRequested(QPoint pos);
|
||||
void contextCopyValue();
|
||||
void contextCopyTop();
|
||||
void contextCopyBottom();
|
||||
void contextCopySegment();
|
||||
void contextChangeValue();
|
||||
void contextChangeTop();
|
||||
void contextChangeBottom();
|
||||
void contextChangeSegment();
|
||||
|
||||
void contextGotoDisasm();
|
||||
void contextGotoMemory();
|
||||
|
||||
void tabCurrentChanged(int cur);
|
||||
|
||||
signals:
|
||||
void gotoInDisasm(u32 address);
|
||||
void gotoInMemory(u32 address);
|
||||
void VMUpdate();
|
||||
|
||||
private:
|
||||
Ui::RegisterWidget ui;
|
||||
|
||||
QMenu* m_contextMenu = 0x0;
|
||||
|
||||
// Returns true on success
|
||||
bool contextFetchNewValue(u64& out, u64 currentValue, bool segment = false);
|
||||
|
||||
DebugInterface* m_cpu;
|
||||
|
||||
// Used for the height offset the tab bar creates
|
||||
// because we share a widget
|
||||
QPoint m_renderStart;
|
||||
|
||||
s32 m_rowStart = 0; // Index, 0 -> VF00, 1 -> VF01 etc
|
||||
s32 m_rowEnd; // Index, what register is the last one drawn
|
||||
s32 m_rowHeight; // The height of each register row
|
||||
// Used for mouse clicks
|
||||
s32 m_fieldStartX[4]; // Where the register segments start
|
||||
s32 m_fieldWidth; // How wide the register segments are
|
||||
|
||||
s32 m_selectedRow = 0; // Index
|
||||
s32 m_selected128Field = 0; // Values are from 0 to 3
|
||||
|
||||
// TODO: Save this configuration ??
|
||||
bool m_showVU0FFloat;
|
||||
bool m_showFPRFloat;
|
||||
};
|
|
@ -0,0 +1,63 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>RegisterWidget</class>
|
||||
<widget class="QWidget" name="RegisterWidget">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>400</width>
|
||||
<height>300</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Maximum" vsizetype="Maximum">
|
||||
<horstretch>1</horstretch>
|
||||
<verstretch>1</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>325</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Register View</string>
|
||||
</property>
|
||||
<widget class="QWidget" name="horizontalLayoutWidget">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>411</width>
|
||||
<height>301</height>
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<property name="spacing">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item alignment="Qt::AlignLeft|Qt::AlignTop">
|
||||
<widget class="QTabBar" name="registerTabs" native="true">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Maximum" vsizetype="Minimum">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
<class>QTabBar</class>
|
||||
<extends>QWidget</extends>
|
||||
<header>qtabbar.h</header>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
|
@ -426,6 +426,7 @@ void MainWindow::connectVMThreadSignals(EmuThread* thread)
|
|||
connect(m_ui.actionPause, &QAction::toggled, thread, &EmuThread::setVMPaused);
|
||||
connect(m_ui.actionFullscreen, &QAction::triggered, thread, &EmuThread::toggleFullscreen);
|
||||
connect(m_ui.actionToggleSoftwareRendering, &QAction::triggered, thread, &EmuThread::toggleSoftwareRendering);
|
||||
connect(m_ui.actionDebugger, &QAction::triggered, this, &MainWindow::openDebugger);
|
||||
connect(m_ui.actionReloadPatches, &QAction::triggered, thread, &EmuThread::reloadPatches);
|
||||
|
||||
static constexpr GSRendererType renderers[] = {
|
||||
|
@ -2414,6 +2415,20 @@ void MainWindow::doSettings(const char* category /* = nullptr */)
|
|||
dlg->setCategory(category);
|
||||
}
|
||||
|
||||
DebuggerWindow* MainWindow::getDebuggerWindow()
|
||||
{
|
||||
if (!m_debugger_window)
|
||||
m_debugger_window = new DebuggerWindow(this);
|
||||
|
||||
return m_debugger_window;
|
||||
}
|
||||
|
||||
void MainWindow::openDebugger()
|
||||
{
|
||||
DebuggerWindow* dwnd = getDebuggerWindow();
|
||||
dwnd->isVisible() ? dwnd->hide() : dwnd->show();
|
||||
}
|
||||
|
||||
ControllerSettingsDialog* MainWindow::getControllerSettingsDialog()
|
||||
{
|
||||
if (!m_controller_settings_dialog)
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
#include "Tools/InputRecording/InputRecordingViewer.h"
|
||||
#include "Settings/ControllerSettingsDialog.h"
|
||||
#include "Settings/SettingsDialog.h"
|
||||
#include "Debugger/DebuggerWindow.h"
|
||||
#include "ui_MainWindow.h"
|
||||
|
||||
class QProgressBar;
|
||||
|
@ -242,6 +243,9 @@ private:
|
|||
InputRecordingViewer* getInputRecordingViewer();
|
||||
void updateInputRecordingActions(bool started);
|
||||
|
||||
DebuggerWindow* getDebuggerWindow();
|
||||
void openDebugger();
|
||||
|
||||
ControllerSettingsDialog* getControllerSettingsDialog();
|
||||
void doControllerSettings(ControllerSettingsDialog::Category category = ControllerSettingsDialog::Category::Count);
|
||||
|
||||
|
@ -272,6 +276,8 @@ private:
|
|||
ControllerSettingsDialog* m_controller_settings_dialog = nullptr;
|
||||
AutoUpdaterDialog* m_auto_updater_dialog = nullptr;
|
||||
|
||||
DebuggerWindow* m_debugger_window = nullptr;
|
||||
|
||||
QProgressBar* m_status_progress_widget = nullptr;
|
||||
QLabel* m_status_verbose_widget = nullptr;
|
||||
QLabel* m_status_renderer_widget = nullptr;
|
||||
|
|
|
@ -127,6 +127,8 @@
|
|||
</widget>
|
||||
<addaction name="menuDebugSwitchRenderer"/>
|
||||
<addaction name="separator"/>
|
||||
<addaction name="actionDebugger"/>
|
||||
<addaction name="separator"/>
|
||||
<addaction name="actionEnableLogTimestamps"/>
|
||||
<addaction name="separator"/>
|
||||
<addaction name="actionEnableEEConsoleLogging"/>
|
||||
|
@ -720,6 +722,11 @@
|
|||
<string>Toggle Software Rendering</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionDebugger">
|
||||
<property name="text">
|
||||
<string>Open Debugger</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionReloadPatches">
|
||||
<property name="text">
|
||||
<string>Reload Cheats/Patches</string>
|
||||
|
|
|
@ -86,4 +86,11 @@ namespace QtUtils
|
|||
|
||||
/// Returns the common window info structure for a Qt widget.
|
||||
std::optional<WindowInfo> GetWindowInfoForWidget(QWidget* widget);
|
||||
} // namespace QtUtils
|
||||
|
||||
/// Converts a value to a QString of said value with a proper fixed width
|
||||
template <typename T>
|
||||
QString FilledQStringFromValue(T val, u32 base)
|
||||
{
|
||||
return QString("%1").arg(QString::number(val, base), sizeof(val) * 2, '0').toUpper();
|
||||
};
|
||||
} // namespace QtUtils
|
||||
|
|
|
@ -43,10 +43,11 @@
|
|||
<AdditionalIncludeDirectories>$(SolutionDir)3rdparty\glad\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<AdditionalIncludeDirectories>$(SolutionDir)3rdparty\simpleini\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<AdditionalIncludeDirectories>$(SolutionDir)3rdparty\lzma\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<AdditionalIncludeDirectories>$(SolutionDir)3rdparty\demangler\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<AdditionalIncludeDirectories>$(SolutionDir)3rdparty\rapidyaml\rapidyaml\ext\c4core\src\c4\ext\fast_float\include;%(AdditionalIncludeDirectories);</AdditionalIncludeDirectories>
|
||||
<AdditionalIncludeDirectories>$(ProjectDir);$(SolutionDir)pcsx2;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<!-- Needed for moc pch -->
|
||||
<AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(ProjectDir)\Settings;$(ProjectDir)\GameList;$(ProjectDir)\Tools\InputRecording</AdditionalIncludeDirectories>
|
||||
<AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(ProjectDir)\Settings;$(ProjectDir)\GameList;$(ProjectDir)\Tools\InputRecording;$(ProjectDir)\Debugger</AdditionalIncludeDirectories>
|
||||
<ExceptionHandling>Async</ExceptionHandling>
|
||||
<PrecompiledHeader>Use</PrecompiledHeader>
|
||||
<PrecompiledHeaderFile>PrecompiledHeader.h</PrecompiledHeaderFile>
|
||||
|
@ -125,6 +126,9 @@
|
|||
<ProjectReference Include="..\3rdparty\zydis\zydis.vcxproj">
|
||||
<Project>{67d0160c-0fe4-44b9-ac2e-82bbcf4104df}</Project>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\3rdparty\demangler\demangler.vcxproj">
|
||||
<Project>{1e3d706c-1d95-4e1b-bdf2-ca3d0007df7f}</Project>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Manifest Include="..\pcsx2\windows\PCSX2.manifest" />
|
||||
|
@ -137,6 +141,12 @@
|
|||
<ClCompile Include="Settings\MemoryCardConvertWorker.cpp" />
|
||||
<ClCompile Include="Tools\InputRecording\InputRecordingViewer.cpp" />
|
||||
<ClCompile Include="Tools\InputRecording\NewInputRecordingDlg.cpp" />
|
||||
<ClCompile Include="Debugger\CpuWidget.cpp" />
|
||||
<ClCompile Include="Debugger\DebuggerWindow.cpp" />
|
||||
<ClCompile Include="Debugger\DisassemblyWidget.cpp" />
|
||||
<ClCompile Include="Debugger\MemoryViewWidget.cpp" />
|
||||
<ClCompile Include="Debugger\RegisterWidget.cpp" />
|
||||
<ClCompile Include="Debugger\BreakpointDialog.cpp" />
|
||||
<ClCompile Include="Settings\BIOSSettingsWidget.cpp" />
|
||||
<ClCompile Include="Settings\ControllerBindingWidgets.cpp" />
|
||||
<ClCompile Include="Settings\ControllerGlobalSettingsWidget.cpp" />
|
||||
|
@ -211,6 +221,12 @@
|
|||
<QtMoc Include="Tools\InputRecording\NewInputRecordingDlg.h" />
|
||||
<QtMoc Include="Tools\InputRecording\InputRecordingViewer.h" />
|
||||
<ClInclude Include="QtUtils.h" />
|
||||
<QtMoc Include="Debugger\CpuWidget.h" />
|
||||
<QtMoc Include="Debugger\DebuggerWindow.h" />
|
||||
<QtMoc Include="Debugger\DisassemblyWidget.h" />
|
||||
<QtMoc Include="Debugger\MemoryViewWidget.h" />
|
||||
<QtMoc Include="Debugger\RegisterWidget.h" />
|
||||
<QtMoc Include="Debugger\BreakpointDialog.h" />
|
||||
<QtMoc Include="Settings\ControllerBindingWidgets.h" />
|
||||
<QtMoc Include="Settings\ControllerGlobalSettingsWidget.h" />
|
||||
<ClInclude Include="Settings\MemoryCardConvertWorker.h" />
|
||||
|
@ -255,6 +271,12 @@
|
|||
<ClCompile Include="$(IntDir)Settings\moc_AchievementLoginDialog.cpp" />
|
||||
<ClCompile Include="$(IntDir)Settings\moc_AchievementSettingsWidget.cpp" />
|
||||
<ClCompile Include="$(IntDir)Settings\moc_DebugSettingsWidget.cpp" />
|
||||
<ClCompile Include="$(IntDir)Debugger\moc_DebuggerWindow.cpp" />
|
||||
<ClCompile Include="$(IntDir)Debugger\moc_CpuWidget.cpp" />
|
||||
<ClCompile Include="$(IntDir)Debugger\moc_DisassemblyWidget.cpp" />
|
||||
<ClCompile Include="$(IntDir)Debugger\moc_RegisterWidget.cpp" />
|
||||
<ClCompile Include="$(IntDir)Debugger\moc_MemoryViewWidget.cpp" />
|
||||
<ClCompile Include="$(IntDir)Debugger\moc_BreakpointDialog.cpp" />
|
||||
<ClCompile Include="$(IntDir)GameList\moc_GameListModel.cpp" />
|
||||
<ClCompile Include="$(IntDir)GameList\moc_GameListRefreshThread.cpp" />
|
||||
<ClCompile Include="$(IntDir)GameList\moc_GameListWidget.cpp" />
|
||||
|
@ -359,6 +381,24 @@
|
|||
<QtUi Include="Tools\InputRecording\InputRecordingViewer.ui">
|
||||
<FileType>Document</FileType>
|
||||
</QtUi>
|
||||
<QtUi Include="Debugger\DebuggerWindow.ui">
|
||||
<FileType>Document</FileType>
|
||||
</QtUi>
|
||||
<QtUi Include="Debugger\DisassemblyWidget.ui">
|
||||
<FileType>Document</FileType>
|
||||
</QtUi>
|
||||
<QtUi Include="Debugger\CpuWidget.ui">
|
||||
<FileType>Document</FileType>
|
||||
</QtUi>
|
||||
<QtUi Include="Debugger\RegisterWidget.ui">
|
||||
<FileType>Document</FileType>
|
||||
</QtUi>
|
||||
<QtUi Include="Debugger\MemoryViewWidget.ui">
|
||||
<FileType>Document</FileType>
|
||||
</QtUi>
|
||||
<QtUi Include="Debugger\BreakpointDialog.ui">
|
||||
<FileType>Document</FileType>
|
||||
</QtUi>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<QtUi Include="Settings\DebugSettingsWidget.ui">
|
||||
|
|
|
@ -19,6 +19,9 @@
|
|||
<Filter Include="Tools\Input Recording">
|
||||
<UniqueIdentifier>{d5c14016-9690-4e49-bcb9-a634a937951a}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Debugger">
|
||||
<UniqueIdentifier>{ddb40cc4-9996-4ade-b647-eb549063553c}</UniqueIdentifier>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ResourceCompile Include="..\pcsx2\PCSX2.rc">
|
||||
|
@ -256,6 +259,42 @@
|
|||
<ClCompile Include="$(IntDir)Settings\moc_DebugSettingsWidget.cpp">
|
||||
<Filter>moc</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Debugger\DebuggerWindow.cpp">
|
||||
<Filter>Debugger</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Debugger\DisassemblyWidget.cpp">
|
||||
<Filter>Debugger</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Debugger\CpuWidget.cpp">
|
||||
<Filter>Debugger</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Debugger\RegisterWidget.cpp">
|
||||
<Filter>Debugger</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Debugger\MemoryViewWidget.cpp">
|
||||
<Filter>Debugger</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Debugger\BreakpointDialog.cpp">
|
||||
<Filter>Debugger</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="$(IntDir)Debugger\moc_CpuWidget.cpp">
|
||||
<Filter>moc</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="$(IntDir)Debugger\moc_DebuggerWindow.cpp">
|
||||
<Filter>moc</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="$(IntDir)Debugger\moc_DisassemblyWidget.cpp">
|
||||
<Filter>moc</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="$(IntDir)Debugger\moc_RegisterWidget.cpp">
|
||||
<Filter>moc</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="$(IntDir)Debugger\moc_MemoryViewWidget.cpp">
|
||||
<Filter>moc</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="$(IntDir)Debugger\moc_BreakpointDialog.cpp">
|
||||
<Filter>moc</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Manifest Include="..\pcsx2\windows\PCSX2.manifest">
|
||||
|
@ -375,6 +414,24 @@
|
|||
<QtMoc Include="Settings\DebugSettingsWidget.h">
|
||||
<Filter>Settings</Filter>
|
||||
</QtMoc>
|
||||
<QtMoc Include="Debugger\DebuggerWindow.h">
|
||||
<Filter>Debugger</Filter>
|
||||
</QtMoc>
|
||||
<QtMoc Include="Debugger\DisassemblyWidget.h">
|
||||
<Filter>Debugger</Filter>
|
||||
</QtMoc>
|
||||
<QtMoc Include="Debugger\CpuWidget.h">
|
||||
<Filter>Debugger</Filter>
|
||||
</QtMoc>
|
||||
<QtMoc Include="Debugger\RegisterWidget.h">
|
||||
<Filter>Debugger</Filter>
|
||||
</QtMoc>
|
||||
<QtMoc Include="Debugger\MemoryViewWidget.h">
|
||||
<Filter>Debugger</Filter>
|
||||
</QtMoc>
|
||||
<QtMoc Include="Debugger\BreakpointDialog.h">
|
||||
<Filter>Debugger</Filter>
|
||||
</QtMoc>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<QtResource Include="resources\resources.qrc">
|
||||
|
@ -475,6 +532,24 @@
|
|||
<QtUi Include="Settings\DebugSettingsWidget.ui">
|
||||
<Filter>Settings</Filter>
|
||||
</QtUi>
|
||||
<QtUi Include="Debugger\DebuggerWindow.ui">
|
||||
<Filter>Debugger</Filter>
|
||||
</QtUi>
|
||||
<QtUi Include="Debugger\DisassemblyWidget.ui">
|
||||
<Filter>Debugger</Filter>
|
||||
</QtUi>
|
||||
<QtUi Include="Debugger\CpuWidget.ui">
|
||||
<Filter>Debugger</Filter>
|
||||
</QtUi>
|
||||
<QtUi Include="Debugger\RegisterWidget.ui">
|
||||
<Filter>Debugger</Filter>
|
||||
</QtUi>
|
||||
<QtUi Include="Debugger\MemoryViewWidget.ui">
|
||||
<Filter>Debugger</Filter>
|
||||
</QtUi>
|
||||
<QtUi Include="Debugger\BreakpointDialog.ui">
|
||||
<Filter>Debugger</Filter>
|
||||
</QtUi>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="Settings\FolderSettingsWidget.ui">
|
||||
|
|
|
@ -1625,6 +1625,7 @@ target_link_libraries(PCSX2_FLAGS INTERFACE
|
|||
if(PCSX2_CORE)
|
||||
target_link_libraries(PCSX2_FLAGS INTERFACE
|
||||
simpleini
|
||||
demangler
|
||||
)
|
||||
else()
|
||||
target_link_libraries(PCSX2_FLAGS INTERFACE
|
||||
|
|
|
@ -29,6 +29,8 @@ u64 CBreakPoints::breakSkipFirstTicksIop_ = 0;
|
|||
std::vector<MemCheck> CBreakPoints::memChecks_;
|
||||
std::vector<MemCheck *> CBreakPoints::cleanupMemChecks_;
|
||||
bool CBreakPoints::breakpointTriggered_ = false;
|
||||
bool CBreakPoints::corePaused = false;
|
||||
std::function<void()> CBreakPoints::cb_bpUpdated_;
|
||||
|
||||
// called from the dynarec
|
||||
u32 standardizeBreakpointAddress(u32 addr)
|
||||
|
@ -408,6 +410,7 @@ void CBreakPoints::Update(BreakPointCpu cpu, u32 addr)
|
|||
bool resume = false;
|
||||
if (!r5900Debug.isCpuPaused())
|
||||
{
|
||||
corePaused = true; // This will be set to false in whatever handles the VM pause event
|
||||
r5900Debug.pauseCpu();
|
||||
resume = true;
|
||||
}
|
||||
|
@ -424,5 +427,8 @@ void CBreakPoints::Update(BreakPointCpu cpu, u32 addr)
|
|||
auto disassembly_window = wxGetApp().GetDisassemblyPtr();
|
||||
if (disassembly_window) // make sure that valid pointer is recieved to prevent potential NULL dereference.
|
||||
disassembly_window->update();
|
||||
#else
|
||||
if(cb_bpUpdated_)
|
||||
cb_bpUpdated_();
|
||||
#endif
|
||||
}
|
||||
|
|
|
@ -150,6 +150,13 @@ public:
|
|||
static void SetBreakpointTriggered(bool b) { breakpointTriggered_ = b; };
|
||||
static bool GetBreakpointTriggered() { return breakpointTriggered_; };
|
||||
|
||||
static bool GetCorePaused() { return corePaused; };
|
||||
static void SetCorePaused(bool b) { corePaused = b; };
|
||||
|
||||
// This will have to do until a full fledged debugger host interface is made
|
||||
static void SetUpdateHandler(std::function<void()> f) {cb_bpUpdated_ = f; };
|
||||
static std::function<void()> GetUpdateHandler() { return cb_bpUpdated_; };
|
||||
|
||||
private:
|
||||
static size_t FindBreakpoint(BreakPointCpu cpu, u32 addr, bool matchTemp = false, bool temp = false);
|
||||
// Finds exactly, not using a range check.
|
||||
|
@ -162,6 +169,9 @@ private:
|
|||
static u64 breakSkipFirstTicksIop_;
|
||||
|
||||
static bool breakpointTriggered_;
|
||||
static bool corePaused;
|
||||
|
||||
static std::function<void()> cb_bpUpdated_;
|
||||
|
||||
static std::vector<MemCheck> memChecks_;
|
||||
static std::vector<MemCheck *> cleanupMemChecks_;
|
||||
|
|
|
@ -278,6 +278,15 @@ u32 R5900DebugInterface::read8(u32 address)
|
|||
return memRead8(address);
|
||||
}
|
||||
|
||||
u32 R5900DebugInterface::read8(u32 address, bool& valid)
|
||||
{
|
||||
if (!(valid = isValidAddress(address)))
|
||||
return -1;
|
||||
|
||||
return memRead8(address);
|
||||
}
|
||||
|
||||
|
||||
u32 R5900DebugInterface::read16(u32 address)
|
||||
{
|
||||
if (!isValidAddress(address) || address % 2)
|
||||
|
@ -286,6 +295,14 @@ u32 R5900DebugInterface::read16(u32 address)
|
|||
return memRead16(address);
|
||||
}
|
||||
|
||||
u32 R5900DebugInterface::read16(u32 address, bool& valid)
|
||||
{
|
||||
if (!(valid = (isValidAddress(address) || address % 2)))
|
||||
return -1;
|
||||
|
||||
return memRead16(address);
|
||||
}
|
||||
|
||||
u32 R5900DebugInterface::read32(u32 address)
|
||||
{
|
||||
if (!isValidAddress(address) || address % 4)
|
||||
|
@ -294,6 +311,14 @@ u32 R5900DebugInterface::read32(u32 address)
|
|||
return memRead32(address);
|
||||
}
|
||||
|
||||
u32 R5900DebugInterface::read32(u32 address, bool& valid)
|
||||
{
|
||||
if (!(valid = (isValidAddress(address) || address % 4)))
|
||||
return -1;
|
||||
|
||||
return memRead32(address);
|
||||
}
|
||||
|
||||
u64 R5900DebugInterface::read64(u32 address)
|
||||
{
|
||||
if (!isValidAddress(address) || address % 8)
|
||||
|
@ -302,6 +327,14 @@ u64 R5900DebugInterface::read64(u32 address)
|
|||
return memRead64(address);
|
||||
}
|
||||
|
||||
u64 R5900DebugInterface::read64(u32 address, bool& valid)
|
||||
{
|
||||
if (!(valid = (isValidAddress(address) || address % 8)))
|
||||
return -1;
|
||||
|
||||
return memRead64(address);
|
||||
}
|
||||
|
||||
u128 R5900DebugInterface::read128(u32 address)
|
||||
{
|
||||
alignas(16) u128 result;
|
||||
|
@ -690,6 +723,13 @@ u32 R3000DebugInterface::read8(u32 address)
|
|||
return iopMemRead8(address);
|
||||
}
|
||||
|
||||
u32 R3000DebugInterface::read8(u32 address, bool& valid)
|
||||
{
|
||||
if (!(valid = isValidAddress(address)))
|
||||
return -1;
|
||||
return iopMemRead8(address);
|
||||
}
|
||||
|
||||
u32 R3000DebugInterface::read16(u32 address)
|
||||
{
|
||||
if (!isValidAddress(address))
|
||||
|
@ -697,6 +737,13 @@ u32 R3000DebugInterface::read16(u32 address)
|
|||
return iopMemRead16(address);
|
||||
}
|
||||
|
||||
u32 R3000DebugInterface::read16(u32 address, bool& valid)
|
||||
{
|
||||
if (!(valid = isValidAddress(address)))
|
||||
return -1;
|
||||
return iopMemRead16(address);
|
||||
}
|
||||
|
||||
u32 R3000DebugInterface::read32(u32 address)
|
||||
{
|
||||
if (!isValidAddress(address))
|
||||
|
@ -704,11 +751,25 @@ u32 R3000DebugInterface::read32(u32 address)
|
|||
return iopMemRead32(address);
|
||||
}
|
||||
|
||||
u32 R3000DebugInterface::read32(u32 address, bool& valid)
|
||||
{
|
||||
if (!(valid = isValidAddress(address)))
|
||||
return -1;
|
||||
return iopMemRead32(address);
|
||||
|
||||
}
|
||||
|
||||
u64 R3000DebugInterface::read64(u32 address)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
u64 R3000DebugInterface::read64(u32 address, bool& valid)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
u128 R3000DebugInterface::read128(u32 address)
|
||||
{
|
||||
return u128::From32(0);
|
||||
|
|
|
@ -53,9 +53,13 @@ public:
|
|||
};
|
||||
|
||||
virtual u32 read8(u32 address) = 0;
|
||||
virtual u32 read8(u32 address, bool& valid) = 0;
|
||||
virtual u32 read16(u32 address) = 0;
|
||||
virtual u32 read16(u32 address, bool& valid) = 0;
|
||||
virtual u32 read32(u32 address) = 0;
|
||||
virtual u32 read32(u32 address, bool& valid) = 0;
|
||||
virtual u64 read64(u32 address) = 0;
|
||||
virtual u64 read64(u32 address, bool& valid) = 0;
|
||||
virtual u128 read128(u32 address) = 0;
|
||||
virtual void write8(u32 address, u8 value) = 0;
|
||||
virtual void write32(u32 address, u32 value) = 0;
|
||||
|
@ -94,9 +98,13 @@ class R5900DebugInterface : public DebugInterface
|
|||
{
|
||||
public:
|
||||
u32 read8(u32 address) override;
|
||||
u32 read8(u32 address, bool& valid) override;
|
||||
u32 read16(u32 address) override;
|
||||
u32 read16(u32 address, bool& valid) override;
|
||||
u32 read32(u32 address) override;
|
||||
u32 read32(u32 address, bool& valid) override;
|
||||
u64 read64(u32 address) override;
|
||||
u64 read64(u32 address, bool& valid) override;
|
||||
u128 read128(u32 address) override;
|
||||
void write8(u32 address, u8 value) override;
|
||||
void write32(u32 address, u32 value) override;
|
||||
|
@ -128,9 +136,13 @@ class R3000DebugInterface : public DebugInterface
|
|||
{
|
||||
public:
|
||||
u32 read8(u32 address) override;
|
||||
u32 read8(u32 address, bool& valid) override;
|
||||
u32 read16(u32 address) override;
|
||||
u32 read16(u32 address, bool& valid) override;
|
||||
u32 read32(u32 address) override;
|
||||
u32 read32(u32 address, bool& valid) override;
|
||||
u64 read64(u32 address) override;
|
||||
u64 read64(u32 address, bool& valid) override;
|
||||
u128 read128(u32 address) override;
|
||||
void write8(u32 address, u8 value) override;
|
||||
void write32(u32 address, u32 value) override;
|
||||
|
|
|
@ -141,7 +141,7 @@ std::map<u32,DisassemblyEntry*>::iterator findDisassemblyEntry(std::map<u32,Disa
|
|||
|
||||
void DisassemblyManager::analyze(u32 address, u32 size = 1024)
|
||||
{
|
||||
if (!cpu->isAlive())
|
||||
if (!cpu->isAlive() || !cpu->isValidAddress(address))
|
||||
return;
|
||||
|
||||
u32 end = address+size;
|
||||
|
@ -333,6 +333,9 @@ u32 DisassemblyManager::getNthNextAddress(u32 address, int n)
|
|||
it = findDisassemblyEntry(entries,address,false);
|
||||
}
|
||||
|
||||
if ((address + 0x400) < address) // Check for unsigned overflow, we are analysing too high!
|
||||
break;
|
||||
|
||||
analyze(address);
|
||||
}
|
||||
|
||||
|
|
|
@ -301,6 +301,7 @@ void ElfObject::loadSectionHeaders()
|
|||
eS = (Elf32_Sym*)data.GetPtr(secthead[i_st].sh_offset);
|
||||
Console.WriteLn("found %d symbols", secthead[i_st].sh_size / sizeof(Elf32_Sym));
|
||||
|
||||
R5900SymbolMap.Clear();
|
||||
for(uint i = 1; i < (secthead[i_st].sh_size / sizeof(Elf32_Sym)); i++) {
|
||||
if ((eS[i].st_value != 0) && (ELF32_ST_TYPE(eS[i].st_info) == 2))
|
||||
{
|
||||
|
|
|
@ -1581,8 +1581,8 @@ void psxRecompileNextInstruction(bool delayslot, bool swapped_delayslot)
|
|||
if (!delayslot)
|
||||
{
|
||||
// Broken on x64
|
||||
// psxEncodeBreakpoint();
|
||||
// psxEncodeMemcheck();
|
||||
psxEncodeBreakpoint();
|
||||
psxEncodeMemcheck();
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
Loading…
Reference in New Issue