mirror of
https://github.com/PCSX2/pcsx2.git
synced 2025-12-16 04:08:48 +00:00
Debugger: Initial debugger implementation
This commit is contained in:
parent
78c9b7f33e
commit
2f0b244f48
6
3rdparty/demangler/CMakeLists.txt
vendored
Normal file
6
3rdparty/demangler/CMakeLists.txt
vendored
Normal file
@ -0,0 +1,6 @@
|
||||
|
||||
cmake_minimum_required(VERSION 3.6)
|
||||
|
||||
project(demangler CXX)
|
||||
|
||||
add_subdirectory(src)
|
||||
59
3rdparty/demangler/demangler.vcxproj
vendored
Normal file
59
3rdparty/demangler/demangler.vcxproj
vendored
Normal file
@ -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>
|
||||
22
3rdparty/demangler/demangler.vcxproj.filters
vendored
Normal file
22
3rdparty/demangler/demangler.vcxproj.filters
vendored
Normal file
@ -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>
|
||||
45
3rdparty/demangler/include/demangler/demangler.h
vendored
Normal file
45
3rdparty/demangler/include/demangler/demangler.h
vendored
Normal file
@ -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
|
||||
20
3rdparty/demangler/include/demangler/demglobal.h
vendored
Normal file
20
3rdparty/demangler/include/demangler/demglobal.h
vendored
Normal file
@ -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
|
||||
36
3rdparty/demangler/include/demangler/demtools.h
vendored
Normal file
36
3rdparty/demangler/include/demangler/demtools.h
vendored
Normal file
@ -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
|
||||
830
3rdparty/demangler/include/demangler/gparser.h
vendored
Normal file
830
3rdparty/demangler/include/demangler/gparser.h
vendored
Normal file
@ -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
|
||||
23
3rdparty/demangler/include/demangler/igrams.h
vendored
Normal file
23
3rdparty/demangler/include/demangler/igrams.h
vendored
Normal file
@ -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
|
||||
25
3rdparty/demangler/include/demangler/stgrammars/borlandll.h
vendored
Normal file
25
3rdparty/demangler/include/demangler/stgrammars/borlandll.h
vendored
Normal file
@ -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
|
||||
25
3rdparty/demangler/include/demangler/stgrammars/gccll.h
vendored
Normal file
25
3rdparty/demangler/include/demangler/stgrammars/gccll.h
vendored
Normal file
@ -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
|
||||
26
3rdparty/demangler/include/demangler/stgrammars/msll.h
vendored
Normal file
26
3rdparty/demangler/include/demangler/stgrammars/msll.h
vendored
Normal file
@ -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
|
||||
16
3rdparty/demangler/src/CMakeLists.txt
vendored
Normal file
16
3rdparty/demangler/src/CMakeLists.txt
vendored
Normal file
@ -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)
|
||||
131
3rdparty/demangler/src/demangler.cpp
vendored
Normal file
131
3rdparty/demangler/src/demangler.cpp
vendored
Normal file
@ -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
|
||||
82
3rdparty/demangler/src/demtools.cpp
vendored
Normal file
82
3rdparty/demangler/src/demtools.cpp
vendored
Normal file
@ -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
|
||||
467
3rdparty/demangler/src/extgrammars/gramatika-borland
vendored
Normal file
467
3rdparty/demangler/src/extgrammars/gramatika-borland
vendored
Normal file
@ -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> ::=
|
||||
423
3rdparty/demangler/src/extgrammars/gramatika-gcc
vendored
Normal file
423
3rdparty/demangler/src/extgrammars/gramatika-gcc
vendored
Normal file
@ -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> ::=
|
||||
534
3rdparty/demangler/src/extgrammars/gramatika-ms
vendored
Normal file
534
3rdparty/demangler/src/extgrammars/gramatika-ms
vendored
Normal file
@ -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> ::=
|
||||
6145
3rdparty/demangler/src/gparser.cpp
vendored
Normal file
6145
3rdparty/demangler/src/gparser.cpp
vendored
Normal file
File diff suppressed because it is too large
Load Diff
91
3rdparty/demangler/src/igrams.cpp
vendored
Normal file
91
3rdparty/demangler/src/igrams.cpp
vendored
Normal file
@ -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
|
||||
6245
3rdparty/demangler/src/stgrammars/borlandll.cpp
vendored
Normal file
6245
3rdparty/demangler/src/stgrammars/borlandll.cpp
vendored
Normal file
File diff suppressed because it is too large
Load Diff
5166
3rdparty/demangler/src/stgrammars/gccll.cpp
vendored
Normal file
5166
3rdparty/demangler/src/stgrammars/gccll.cpp
vendored
Normal file
File diff suppressed because it is too large
Load Diff
5449
3rdparty/demangler/src/stgrammars/msll.cpp
vendored
Normal file
5449
3rdparty/demangler/src/stgrammars/msll.cpp
vendored
Normal file
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
|
||||
|
||||
206
pcsx2-qt/Debugger/BreakpointDialog.cpp
Normal file
206
pcsx2-qt/Debugger/BreakpointDialog.cpp
Normal file
@ -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();
|
||||
}
|
||||
53
pcsx2-qt/Debugger/BreakpointDialog.h
Normal file
53
pcsx2-qt/Debugger/BreakpointDialog.h
Normal file
@ -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;
|
||||
};
|
||||
325
pcsx2-qt/Debugger/BreakpointDialog.ui
Normal file
325
pcsx2-qt/Debugger/BreakpointDialog.ui
Normal file
@ -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>
|
||||
1017
pcsx2-qt/Debugger/CpuWidget.cpp
Normal file
1017
pcsx2-qt/Debugger/CpuWidget.cpp
Normal file
File diff suppressed because it is too large
Load Diff
120
pcsx2-qt/Debugger/CpuWidget.h
Normal file
120
pcsx2-qt/Debugger/CpuWidget.h
Normal file
@ -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;
|
||||
};
|
||||
667
pcsx2-qt/Debugger/CpuWidget.ui
Normal file
667
pcsx2-qt/Debugger/CpuWidget.ui
Normal file
@ -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>
|
||||
123
pcsx2-qt/Debugger/DebuggerWindow.cpp
Normal file
123
pcsx2-qt/Debugger/DebuggerWindow.cpp
Normal file
@ -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();
|
||||
}
|
||||
46
pcsx2-qt/Debugger/DebuggerWindow.h
Normal file
46
pcsx2-qt/Debugger/DebuggerWindow.h
Normal file
@ -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;
|
||||
};
|
||||
41
pcsx2-qt/Debugger/DebuggerWindow.ui
Normal file
41
pcsx2-qt/Debugger/DebuggerWindow.ui
Normal file
@ -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>
|
||||
702
pcsx2-qt/Debugger/DisassemblyWidget.cpp
Normal file
702
pcsx2-qt/Debugger/DisassemblyWidget.cpp
Normal file
@ -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();
|
||||
}
|
||||
97
pcsx2-qt/Debugger/DisassemblyWidget.h
Normal file
97
pcsx2-qt/Debugger/DisassemblyWidget.h
Normal file
@ -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);
|
||||
};
|
||||
19
pcsx2-qt/Debugger/DisassemblyWidget.ui
Normal file
19
pcsx2-qt/Debugger/DisassemblyWidget.ui
Normal file
@ -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>
|
||||
497
pcsx2-qt/Debugger/MemoryViewWidget.cpp
Normal file
497
pcsx2-qt/Debugger/MemoryViewWidget.cpp
Normal file
@ -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();
|
||||
}
|
||||
129
pcsx2-qt/Debugger/MemoryViewWidget.h
Normal file
129
pcsx2-qt/Debugger/MemoryViewWidget.h
Normal file
@ -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;
|
||||
};
|
||||
19
pcsx2-qt/Debugger/MemoryViewWidget.ui
Normal file
19
pcsx2-qt/Debugger/MemoryViewWidget.ui
Normal file
@ -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>
|
||||
446
pcsx2-qt/Debugger/RegisterWidget.cpp
Normal file
446
pcsx2-qt/Debugger/RegisterWidget.cpp
Normal file
@ -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);
|
||||
}
|
||||
91
pcsx2-qt/Debugger/RegisterWidget.h
Normal file
91
pcsx2-qt/Debugger/RegisterWidget.h
Normal file
@ -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;
|
||||
};
|
||||
63
pcsx2-qt/Debugger/RegisterWidget.ui
Normal file
63
pcsx2-qt/Debugger/RegisterWidget.ui
Normal file
@ -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
Block a user