1 // Copyright (c) 2012- PPSSPP Project.
2 
3 // This program is free software: you can redistribute it and/or modify
4 // it under the terms of the GNU General Public License as published by
5 // the Free Software Foundation, version 2.0 or later versions.
6 
7 // This program is distributed in the hope that it will be useful,
8 // but WITHOUT ANY WARRANTY; without even the implied warranty of
9 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10 // GNU General Public License 2.0 for more details.
11 
12 // A copy of the GPL 2.0 should have been included with the program.
13 // If not, see http://www.gnu.org/licenses/
14 
15 // Official git repository and contact information can be found at
16 // https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
17 
18 #pragma once
19 
20 #include "ppsspp_config.h"
21 #include <mutex>
22 #include "Common/CommonTypes.h"
23 #include "Core/Debugger/SymbolMap.h"
24 #include "Core/MIPS/MIPSAnalyst.h"
25 
26 #if PPSSPP_ARCH(AMD64)
27 typedef u64 HashType;
28 #else
29 typedef u32 HashType;
30 #endif
31 
32 enum DisassemblyLineType { DISTYPE_OPCODE, DISTYPE_MACRO, DISTYPE_DATA, DISTYPE_OTHER };
33 
34 struct DisassemblyLineInfo
35 {
36 	DisassemblyLineType type;
37 	MIPSAnalyst::MipsOpcodeInfo info;
38 	std::string name;
39 	std::string params;
40 	u32 totalSize;
41 };
42 
43 enum LineType { LINE_UP, LINE_DOWN, LINE_RIGHT };
44 
45 struct BranchLine
46 {
47 	u32 first;
48 	u32 second;
49 	LineType type;
50 	int laneIndex;
51 
52 	bool operator<(const BranchLine& other) const
53 	{
54 		return first < other.first;
55 	}
56 };
57 
58 class DisassemblyEntry
59 {
60 public:
~DisassemblyEntry()61 	virtual ~DisassemblyEntry() { };
62 	virtual void recheck() = 0;
63 	virtual int getNumLines() = 0;
64 	virtual int getLineNum(u32 address, bool findStart) = 0;
65 	virtual u32 getLineAddress(int line) = 0;
66 	virtual u32 getTotalSize() = 0;
67 	virtual bool disassemble(u32 address, DisassemblyLineInfo& dest, bool insertSymbols, DebugInterface *cpuDebug) = 0;
getBranchLines(u32 start,u32 size,std::vector<BranchLine> & dest)68 	virtual void getBranchLines(u32 start, u32 size, std::vector<BranchLine>& dest) { };
69 };
70 
71 class DisassemblyFunction: public DisassemblyEntry
72 {
73 public:
74 	DisassemblyFunction(u32 _address, u32 _size);
75 	~DisassemblyFunction();
76 	void recheck() override;
77 	int getNumLines() override;
78 	int getLineNum(u32 address, bool findStart) override;
79 	u32 getLineAddress(int line) override;
getTotalSize()80 	u32 getTotalSize() override { return size; };
81 	bool disassemble(u32 address, DisassemblyLineInfo& dest, bool insertSymbols, DebugInterface *cpuDebug) override;
82 	void getBranchLines(u32 start, u32 size, std::vector<BranchLine>& dest) override;
83 
84 private:
85 	void generateBranchLines();
86 	void load();
87 	void clear();
88 	void addOpcodeSequence(u32 start, u32 end);
89 
90 	u32 address;
91 	u32 size;
92 	HashType hash;
93 	std::vector<BranchLine> lines;
94 	std::map<u32,DisassemblyEntry*> entries;
95 	std::vector<u32> lineAddresses;
96 	std::recursive_mutex lock_;
97 };
98 
99 class DisassemblyOpcode: public DisassemblyEntry
100 {
101 public:
DisassemblyOpcode(u32 _address,int _num)102 	DisassemblyOpcode(u32 _address, int _num): address(_address), num(_num) { };
~DisassemblyOpcode()103 	virtual ~DisassemblyOpcode() { };
recheck()104 	void recheck() override { };
getNumLines()105 	int getNumLines() override { return num; };
getLineNum(u32 address,bool findStart)106 	int getLineNum(u32 address, bool findStart) override { return (address - this->address) / 4; };
getLineAddress(int line)107 	u32 getLineAddress(int line) override { return address + line * 4; };
getTotalSize()108 	u32 getTotalSize() override { return num * 4; };
109 	bool disassemble(u32 address, DisassemblyLineInfo& dest, bool insertSymbols, DebugInterface *cpuDebug) override;
110 	void getBranchLines(u32 start, u32 size, std::vector<BranchLine>& dest) override;
111 
112 private:
113 	u32 address;
114 	int num;
115 };
116 
117 
118 class DisassemblyMacro: public DisassemblyEntry
119 {
120 public:
DisassemblyMacro(u32 _address)121 	DisassemblyMacro(u32 _address): address(_address) { };
~DisassemblyMacro()122 	virtual ~DisassemblyMacro() { };
123 
124 	void setMacroLi(u32 _immediate, u8 _rt);
125 	void setMacroMemory(std::string _name, u32 _immediate, u8 _rt, int _dataSize);
126 
recheck()127 	void recheck() override { };
getNumLines()128 	int getNumLines() override { return 1; };
getLineNum(u32 address,bool findStart)129 	int getLineNum(u32 address, bool findStart) override { return 0; };
getLineAddress(int line)130 	u32 getLineAddress(int line) override { return address; };
getTotalSize()131 	u32 getTotalSize() override { return numOpcodes * 4; };
132 	bool disassemble(u32 address, DisassemblyLineInfo& dest, bool insertSymbols, DebugInterface *cpuDebug) override;
133 private:
134 	enum MacroType { MACRO_LI, MACRO_MEMORYIMM };
135 
136 	MacroType type;
137 	std::string name;
138 	u32 immediate;
139 	u32 address;
140 	u32 numOpcodes;
141 	u8 rt;
142 	int dataSize;
143 };
144 
145 
146 class DisassemblyData: public DisassemblyEntry
147 {
148 public:
149 	DisassemblyData(u32 _address, u32 _size, DataType _type);
~DisassemblyData()150 	virtual ~DisassemblyData() { };
151 
152 	void recheck() override;
getNumLines()153 	int getNumLines() override { return (int)lines.size(); };
154 	int getLineNum(u32 address, bool findStart) override;
getLineAddress(int line)155 	u32 getLineAddress(int line) override { return lineAddresses[line]; };
getTotalSize()156 	u32 getTotalSize() override { return size; };
157 	bool disassemble(u32 address, DisassemblyLineInfo& dest, bool insertSymbols, DebugInterface *cpuDebug) override;
158 
159 private:
160 	void createLines();
161 
162 	struct DataEntry
163 	{
164 		std::string text;
165 		u32 size;
166 		int lineNum;
167 	};
168 
169 	u32 address;
170 	u32 size;
171 	HashType hash;
172 	DataType type;
173 	std::map<u32,DataEntry> lines;
174 	std::vector<u32> lineAddresses;
175 	std::recursive_mutex lock_;
176 };
177 
178 class DisassemblyComment: public DisassemblyEntry
179 {
180 public:
181 	DisassemblyComment(u32 _address, u32 _size, std::string name, std::string param);
~DisassemblyComment()182 	virtual ~DisassemblyComment() { };
183 
recheck()184 	void recheck() override { };
getNumLines()185 	int getNumLines() override { return 1; };
getLineNum(u32 address,bool findStart)186 	int getLineNum(u32 address, bool findStart) override { return 0; };
getLineAddress(int line)187 	u32 getLineAddress(int line) override { return address; };
getTotalSize()188 	u32 getTotalSize() override { return size; };
189 	bool disassemble(u32 address, DisassemblyLineInfo& dest, bool insertSymbols, DebugInterface *cpuDebug) override;
190 
191 private:
192 	u32 address;
193 	u32 size;
194 	std::string name;
195 	std::string param;
196 };
197 
198 class DebugInterface;
199 
200 class DisassemblyManager
201 {
202 public:
203 	~DisassemblyManager();
204 
205 	void clear();
206 
setCpu(DebugInterface * _cpu)207 	void setCpu(DebugInterface* _cpu) { cpu = _cpu; };
setMaxParamChars(int num)208 	void setMaxParamChars(int num) { maxParamChars = num; clear(); };
209 	void getLine(u32 address, bool insertSymbols, DisassemblyLineInfo &dest, DebugInterface *cpuDebug = nullptr);
210 	void analyze(u32 address, u32 size);
211 	std::vector<BranchLine> getBranchLines(u32 start, u32 size);
212 
213 	u32 getStartAddress(u32 address);
214 	u32 getNthPreviousAddress(u32 address, int n = 1);
215 	u32 getNthNextAddress(u32 address, int n = 1);
216 
getCpu()217 	static DebugInterface* getCpu() { return cpu; };
getMaxParamChars()218 	static int getMaxParamChars() { return maxParamChars; };
219 private:
220 	static std::map<u32,DisassemblyEntry*> entries;
221 	static std::recursive_mutex entriesLock_;
222 	static DebugInterface* cpu;
223 	static int maxParamChars;
224 };
225 
226 bool isInInterval(u32 start, u32 size, u32 value);
227 bool IsLikelyStringAt(uint32_t addr);
228