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 #include "ppsspp_config.h"
19 #include <map>
20 #include <set>
21 #include <unordered_map>
22 #include <unordered_set>
23 #include <mutex>
24 
25 #include "ext/cityhash/city.h"
26 #include "ext/xxhash.h"
27 
28 #include "Common/File/FileUtil.h"
29 #include "Common/Log.h"
30 #include "Common/TimeUtil.h"
31 #include "Core/Config.h"
32 #include "Core/MemMap.h"
33 #include "Core/System.h"
34 #include "Core/MIPS/MIPS.h"
35 #include "Core/MIPS/MIPSVFPUUtils.h"
36 #include "Core/MIPS/MIPSTables.h"
37 #include "Core/MIPS/MIPSAnalyst.h"
38 #include "Core/MIPS/MIPSCodeUtils.h"
39 #include "Core/Debugger/SymbolMap.h"
40 #include "Core/Debugger/DebugInterface.h"
41 #include "Core/HLE/ReplaceTables.h"
42 
43 using namespace MIPSCodeUtils;
44 
45 // Not in a namespace because MSVC's debugger doesn't like it
46 typedef std::vector<MIPSAnalyst::AnalyzedFunction> FunctionsVector;
47 static FunctionsVector functions;
48 std::recursive_mutex functions_lock;
49 
50 // One function can appear in multiple copies in memory, and they will all have
51 // the same hash and should all be replaced if possible.
52 static std::unordered_multimap<u64, MIPSAnalyst::AnalyzedFunction *> hashToFunction;
53 
54 struct HashMapFunc {
55 	char name[64];
56 	u64 hash;
57 	u32 size; //number of bytes
58 	bool hardcoded;  // should not be saved
59 
operator <HashMapFunc60 	bool operator < (const HashMapFunc &other) const {
61 		return hash < other.hash || (hash == other.hash && size < other.size);
62 	}
63 
operator ==HashMapFunc64 	bool operator == (const HashMapFunc &other) const {
65 		return hash == other.hash && size == other.size;
66 	}
67 };
68 
69 namespace std {
70 	template <>
71 	struct hash<HashMapFunc> {
operator ()std::hash72 		size_t operator()(const HashMapFunc &f) const {
73 			return std::hash<u64>()(f.hash) ^ f.size;
74 		}
75 	};
76 }
77 
78 static std::unordered_set<HashMapFunc> hashMap;
79 
80 static Path hashmapFileName;
81 
82 #define MIPSTABLE_IMM_MASK 0xFC000000
83 
84 // Similar to HashMapFunc but has a char pointer for the name for efficiency.
85 struct HardHashTableEntry {
86 	uint64_t hash;
87 	int funcSize;
88 	const char *funcName;
89 
operator <HardHashTableEntry90 	bool operator <(const HardHashTableEntry &e) const {
91 		if (hash < e.hash) return true;
92 		if (hash > e.hash) return false;
93 		return funcSize < e.funcSize;
94 	}
95 };
96 
97 // Some hardcoded hashes.  Some have a comment specifying at least one game they are found in.
98 static const HardHashTableEntry hardcodedHashes[] = {
99 	{ 0x006b570008068310, 184, "strtok_r", },
100 	{ 0x019ba2099fb88f3c, 48, "vector_normalize_t", },
101 	{ 0x0266f96d740c7e03, 912, "memcpy", }, // Final Fantasy 4 (US)
102 	{ 0x02bd2859045d2383, 240, "bcmp", },
103 	{ 0x030507c9a1f0fc85, 92, "matrix_rot_x", },
104 	{ 0x0483fceefa4557ff, 1360, "__udivdi3", },
105 	{ 0x0558ad5c5be00ca1, 76, "vtfm_t", },
106 	{ 0x05aceb23092fd6a1, 36, "zettai_hero_update_minimap_tex", }, // Zettai Hero Project (US)
107 	{ 0x05aedd0c04b451a1, 356, "sqrt", },
108 	{ 0x0654fc8adbe16ef7, 28, "vmul_q", },
109 	{ 0x06628f6052cda3c1, 1776, "toheart2_download_frame", }, // To Heart 2 Portable
110 	{ 0x06b243c926fa6ab5, 24, "vf2in_q", },
111 	{ 0x06e2826e02056114, 56, "wcslen", },
112 	{ 0x073cf0b61d3b875a, 416, "hexyzforce_monoclome_thread", }, // Hexyz Force (US)
113 	{ 0x075fa9b234b41e9b, 32, "fmodf", },
114 	{ 0x0a051019bdd786c3, 184, "strcasecmp", },
115 	{ 0x0a1bed70958935d2, 644, "youkosohitsujimura_download_frame", }, // Youkoso Hitsuji-Mura Portable
116 	{ 0x0a46dc426054bb9d, 24, "vector_add_t", },
117 	{ 0x0c0173ed70f84f66, 48, "vnormalize_t", },
118 	{ 0x0c65188f5bfb3915, 24, "vsgn_q", },
119 	{ 0x0d898513a722ea3c, 40, "copysignf", },
120 	{ 0x0e99b037b852c8ea, 68, "isnan", },
121 	// Unsafe due to immediates.
122 	//{ 0x0eb5f2e95f59276a, 40, "dl_write_lightmode", },
123 	{ 0x0f1e7533a546f6a1, 228, "dl_write_bone_matrix_4", },
124 	{ 0x0f2a1106ad84fb74, 52, "strcmp", },
125 	{ 0x0ffa5db8396d4274, 64, "memcpy_jak", }, // CRUSH
126 	{ 0x1252e902d0b49bfb, 44, "vector_sub_q_2", },
127 	{ 0x12df3d33a58d0298, 52, "vmidt_t", },
128 	{ 0x12feef7b017d3431, 700, "memmove", },
129 	{ 0x1322c7e3fe6dff4d, 784, "_free_r", },
130 	{ 0x1376c115d5f1d90c, 36, "strlen", },
131 	{ 0x1448134dd3acd1f9, 240, "memchr", },
132 	{ 0x14800e59c04968d7, 100, "wcsstr", },
133 	{ 0x14b56e858a27a8a4, 24, "vi2f_q", },
134 	{ 0x15c4662d5d3c728e, 308, "acosf", },
135 	{ 0x1616ee7052542059, 48, "vtfm_t", },
136 	{ 0x16965ca11a4e7dac, 104, "vmmul_q_transp", },
137 	{ 0x16afe830a5dd2de2, 40, "vdiv_q", },
138 	{ 0x184e834a63a79016, 32, "isnanf", },
139 	{ 0x1874ee898c7b9f16, 512, "kokoroconnect_download_frame", }, // Kokoro Connect Yochi Random
140 	{ 0x189212bda9c94df1, 736, "atanf", },
141 	{ 0x199821ce500ef9d2, 24, "vocp_t", },
142 	{ 0x1a3c8e9d637ed421, 104, "__adddf3", },
143 	{ 0x1a7564fa3e25c992, 844, "memcpy", }, // Valkyria Chronicles 3
144 	{ 0x1aad94c0723edfc0, 124, "vmmul_t_transp", },
145 	{ 0x1ab33b12b3cb8cb0, 28, "vqmul_q", },
146 	{ 0x1ac05627df1f87f4, 112, "memcpy16", }, // Valkyria Chronicles 3
147 	{ 0x1bdf3600844373fd, 112, "strstr", },
148 	{ 0x1c967be07917ddc9, 92, "strcat", },
149 	{ 0x1d03fa48334ca966, 556, "_strtol_r", },
150 	{ 0x1d1311966d2243e9, 428, "suikoden1_and_2_download_frame_1", }, // Gensou Suikoden 1&2
151 	{ 0x1d7de04b4e87d00b, 680, "kankabanchoutbr_download_frame", }, // Kenka Banchou Bros: Tokyo Battle Royale
152 	{ 0x1daf6eaf0442391d, 1024, "utawarerumono_download_frame", }, // Utawarerumono portable
153 	{ 0x1e1525e3bc2f6703, 676, "rint", },
154 	{ 0x1ec055f28bb9f4d1, 88, "gu_update_stall", },
155 	{ 0x1ef9cfe6afd3c035, 180, "memset", }, // Kingdom Hearts (US)
156 	{ 0x1f53eac122f96b37, 224, "cosf", },
157 	{ 0x2097a8b75c8fe651, 436, "atan2", },
158 	{ 0x21411b3c860822c0, 36, "matrix_scale_q_t", },
159 	{ 0x24d82a8675800808, 220, "ceilf", },
160 	{ 0x26cc90cb25af9d27, 476, "log10", },
161 	{ 0x275c79791a2bab83, 116, "rezel_cross_download_frame", }, // Rezel Cross
162 	{ 0x2774614d57d4baa2, 28, "vsub_q", },
163 	{ 0x279c6bf9cf99cc85, 436, "strncpy", },
164 	{ 0x2876ed93c5fd1211, 328, "dl_write_matrix_4", },
165 	{ 0x2965b1ad3ca15cc1, 44, "vtfm_t", },
166 	{ 0x299a370587df078f, 116, "strange_copy_routine", },
167 	{ 0x2aa9634a9951c7df, 212, "sdgundamggenerationportable_download_frame", }, // SD Gundam G Generation Portable
168 	{ 0x2abca53599f09ea7, 608, "dl_write_matrix_3", },
169 	{ 0x2adb92e8855c454e, 48, "vtfm_q", },
170 	{ 0x2adc229bef7bbc75, 40, "isnan", },
171 	{ 0x2bcf5268dd26345a, 340, "acos", },
172 	{ 0x2c4cb2028a1735bf, 600, "floor", },
173 	{ 0x2c61a9a06a345b43, 1084, "otomenoheihou_download_frame", }, // Sangoku Koi Senki Otome no Heihou
174 	{ 0x2ca5958bb816c72e, 44, "vector_i2f_t", },
175 	{ 0x2e7022d9767c9018, 2100, "atan", },
176 	{ 0x2f10d3faec84b5bb, 276, "sinf", },
177 	{ 0x2f639673670caa0e, 772, "dl_write_matrix_2", },
178 	{ 0x2f718936b371fc44, 40, "vcos_s", },
179 	{ 0x3024e961d1811dea, 396, "fmod", },
180 	{ 0x3050bfd0e729dfbf, 220, "atvoffroadfuryblazintrails_download_frame", }, // ATV Offroad Fury Blazin' Trails (US)
181 	{ 0x30c9c4f420573eb6, 540, "expf", },
182 	{ 0x311779b4db21dbf3, 124, "motorstorm_pixel_read" }, // Motorstorm Arctic Edge (US)
183 	{ 0x317afeb882ff324a, 212, "memcpy", }, // Mimana (US)
184 	{ 0x31ea2e192f5095a1, 52, "vector_add_t", },
185 	{ 0x31f523ef18898e0e, 420, "logf", },
186 	{ 0x32215b1d2196377f, 844, "godseaterburst_blit_texture", }, // Gods Eater Burst (US)
187 	{ 0x32806967fe81568b, 40, "vector_sub_t_2", },
188 	{ 0x32ceb9a7f72b9385, 440, "_strtoul_r", },
189 	{ 0x32e6bc7c151491ed, 68, "memchr", },
190 	{ 0x335df69db1073a8d, 96, "wcscpy", },
191 	{ 0x33dc6b144cb302c1, 304, "memmove", }, // Kingdom Hearts (US)
192 	{ 0x35d3527ff8c22ff2, 56, "matrix_scale_q", },
193 	{ 0x368f6cf979709a31, 744, "memmove", }, // Jui Dr. Touma Jotarou
194 	{ 0x373ce518eee5a2d2, 20, "matrix300_store_q", },
195 	{ 0x3840f5766fada4b1, 592, "dissidia_recordframe_avi", }, // Dissidia (US), Dissidia 012 (US)
196 	{ 0x388043e96b0e11fd, 144, "dl_write_material_2", },
197 	{ 0x38f19bc3be215acc, 388, "log10f", },
198 	{ 0x3913b81ddcbe1efe, 880, "katamari_render_check", }, // Me and My Katamari (US)
199 	{ 0x393047f06eceaba1, 96, "strcspn", },
200 	{ 0x39a651942a0b3861, 204, "tan", },
201 	{ 0x3a3bc2b20a55bf02, 68, "memchr", },
202 	{ 0x3ab08b5659de1746, 40, "vsin_s", },
203 	{ 0x3c421a9265f37ebc, 700, "memmove", }, // Final Fantasy 4 (US)
204 	{ 0x3cbc2d50a3db59e9, 100, "strncmp", },
205 	{ 0x3ce1806699a91d9d, 148, "dl_write_light", },
206 	{ 0x3d5e914011c181d4, 444, "scalbnf", },
207 	{ 0x3ea41eafb53fc99a, 388, "logf", },
208 	{ 0x3fe38bff09ac3da0, 436, "_strtoul_r", },
209 	{ 0x40a25c7e1fd44fe2, 24, "fabsf", },
210 	// Unsafe due to immediates.
211 	//{ 0x410d48d9b6580b4a, 36, "dl_write_ztest", },
212 	{ 0x42dc17c8018f30f2, 44, "vtan.s", },
213 	{ 0x436b07caa2aab931, 352, "acos", },
214 	{ 0x444472537eedf966, 32, "vmzero_q", },
215 	{ 0x449ff96982626338, 28, "vmidt_q", },
216 	{ 0x44f65b1a72c45703, 36, "strlen", },
217 	{ 0x45528de3948615dc, 64, "memcpy", },
218 	{ 0x456a0d78ac318d15, 164, "gta_dl_write_matrix", },
219 	{ 0x497248c9d12f44fd, 68, "strcpy", },
220 	{ 0x4a70207212a4c497, 24, "strlen", },
221 	{ 0x4b16a5c602c74c6c, 24, "vsub_t", },
222 	{ 0x4bb677dace6ca526, 184, "memset", }, // Final FantasyTactics (JPN)
223 	{ 0x4c4bdedcc13ac77c, 624, "dl_write_matrix_5", },
224 	{ 0x4c91c556d1aa896b, 104, "dl_write_material_3", },
225 	{ 0x4cf38c368078181e, 616, "dl_write_matrix", },
226 	{ 0x4d3e7085e01d30e4, 324, "memcpy", }, // PoPoLoCrois (JPN)
227 	{ 0x4d72b294501cddfb, 80, "copysign", },
228 	{ 0x4ddd83b7f4ed8d4e, 844, "memcpy", },
229 	{ 0x4e266783291b0220, 28, "vsub_t", },
230 	{ 0x4e5950928c0bb082, 44, "vmmul_q_transp4", },
231 	{ 0x4f34fc596ecf5b25, 40, "vdiv_t", },
232 	{ 0x500a949afb39133f, 24, "vf2iu_q", },
233 	{ 0x50d8f01ea8fa713d, 48, "send_commandi", },
234 	{ 0x50fa6db2fb14814a, 544, "rint", },
235 	{ 0x513ce13cd7ce97ea, 332, "scalbnf", },
236 	{ 0x514161da54d37416, 1416, "__umoddi3", },
237 	{ 0x51c52d7dd4d2191c, 360, "cos", },
238 	{ 0x5287d4b8abd5806b, 768, "_strtoll_r", },
239 	{ 0x52d5141545a75eda, 60, "dl_write_clutformat", },
240 	{ 0x530cbe1ce9b45d58, 108, "dl_write_light_vector", },
241 	{ 0x53c9aa23504a630f, 96, "vmmul_q_5", },
242 	{ 0x54015ccbcbc75374, 24, "strlen", }, // Metal Gear Solid: Peace Walker demo
243 	{ 0x5550d87a851c218c, 168, "dl_write_viewport", },
244 	{ 0x55c1294280bfade0, 88, "dl_write_blend_fixed", },
245 	{ 0x5642a63f3802a792, 456, "orenoimouto_download_frame", }, // Ore no Imouto ga Konnani Kawaii Wake ga Nai
246 	{ 0x56c9929e8c8c5768, 24, "fabsf", },
247 	{ 0x572b2d9e57e6e363, 788, "memcpy_thingy", },
248 	{ 0x580200b840b47c58, 1856, "_realloc_r", },
249 	{ 0x5961f681bbd69035, 28, "vfad_q", },
250 	{ 0x598b91c64cf7e036, 2388, "qsort", },
251 	{ 0x59a0cb08f5ecf8b6, 28, "copysignf", },
252 	{ 0x5ae4ec2a5e133de3, 28, "vector_cross_t", },
253 	{ 0x5b005f8375d7c364, 236, "floorf", },
254 	{ 0x5b103d973fd1dd94, 92, "matrix_rot_y", },
255 	{ 0x5b9d7e9d4c905694, 196, "_calloc_r", },
256 	{ 0x5bf7a77b028e9f66, 324, "sqrtf", },
257 	{ 0x5c0b3edc0e48852c, 148, "memmove", }, // Dissidia 1 (US)
258 	{ 0x5e898df42c4af6b8, 76, "wcsncmp", },
259 	{ 0x5f473780835e3458, 52, "vclamp_q", },
260 	{ 0x5fc58ed2c4d48b79, 40, "vtfm_q_transp", },
261 	{ 0x6145029ef86f0365, 76, "__extendsfdf2", },
262 	{ 0x62815f41fa86a131, 656, "scalbn", },
263 	{ 0x6301fa5149bd973a, 120, "wcscat", },
264 	{ 0x658b07240a690dbd, 36, "strlen", },
265 	{ 0x66122f0ab50b2ef9, 296, "dl_write_dither_matrix_5", },
266 	{ 0x66f7f1beccbc104a, 256, "memcpy_swizzled", }, // God Eater 2
267 	{ 0x679e647e34ecf7f1, 132, "roundf", },
268 	{ 0x67afe74d9ec72f52, 4380, "_strtod_r", },
269 	{ 0x68b22c2aa4b8b915, 400, "sqrt", },
270 	{ 0x6962da85a6dad937, 60, "strrchr", },
271 	{ 0x69a3c4f774859404, 64, "vmmul_q_transp2", },
272 	{ 0x6ab54910104ef000, 628, "sd_gundam_g_generation_download_frame", }, // SD Gundam G Generation World
273 	{ 0x6ac2cd44e042592b, 252, "atvoffroadfurypro_download_frame", }, // ATV Offroad Fury Pro (US)
274 	{ 0x6b022e20ee3fa733, 68, "__negdf2", },
275 	{ 0x6b2a6347c0dfcb57, 152, "strcpy", },
276 	{ 0x6b4148322c569cb3, 240, "wmemchr", },
277 	{ 0x6c4cb6d25851553a, 44, "vtfm_t", },
278 	{ 0x6c7b2462b9ec7bc7, 56, "vmmul_q", },
279 	{ 0x6ca9cc8fa485d096, 304, "__ieee754_sqrtf", },
280 	{ 0x6ccffc753d2c148e, 96, "strlwr", },
281 	{ 0x6e40ec681fb5c571, 40, "matrix_copy_q", },
282 	{ 0x6e9884c842a51142, 236, "strncasecmp", },
283 	{ 0x6f101c5c4311c144, 276, "floorf", },
284 	{ 0x6f1731f84bbf76c3, 116, "strcmp", },
285 	{ 0x6f4e1a1a84df1da0, 68, "dl_write_texmode", },
286 	{ 0x6f7c9109b5b8fa47, 688, "danganronpa1_2_download_frame", }, // Danganronpa 1
287 	{ 0x70649c7211f6a8da, 16, "fabsf", },
288 	{ 0x70a6152b265228e8, 296, "unendingbloodycall_download_frame", }, // unENDing Bloody Call
289 	{ 0x7245b74db370ae72, 64, "vmmul_q_transp3", },
290 	{ 0x7259d52b21814a5a, 40, "vtfm_t_transp", },
291 	{ 0x7354fd206796d817, 864, "flowers_download_frame", }, // Flowers
292 	{ 0x736b34ebc702d873, 104, "vmmul_q_transp", },
293 	{ 0x73a614c08f777d52, 792, "danganronpa2_2_download_frame", }, // Danganronpa 2
294 	{ 0x7499a2ce8b60d801, 12, "abs", },
295 	{ 0x74c77fb521740cd2, 284, "toheart2_download_frame_2", }, // To Heart 2 Portable
296 	{ 0x74ebbe7d341463f3, 72, "dl_write_colortest", },
297 	{ 0x755a41f9183bb89a, 60, "vmmul_q", },
298 	{ 0x757d7ab0afbc03f5, 948, "kirameki_school_life_download_frame", }, // Toradora! Portable
299 	{ 0x759834c69bb12c12, 68, "strcpy", },
300 	{ 0x75c5a88d62c9c99f, 276, "sinf", },
301 	{ 0x76c661fecbb39990, 364, "sin", },
302 	{ 0x770c9c07bf58fd14, 16, "fabsf", },
303 	{ 0x774e479eb9634525, 464, "_strtol_r", },
304 	{ 0x77aeb1c23f9aa2ad, 56, "strchr", },
305 	{ 0x78e8c65b5a458f33, 148, "memcmp", },
306 	{ 0x794d1b073c183c77, 24, "fabsf", },
307 	{ 0x7978a886cf70b1c9, 56, "wcschr", },
308 	{ 0x79faa339fff5a80c, 28, "finitef", },
309 	{ 0x7c50728008c288e3, 36, "vector_transform_q_4x4", },
310 	{ 0x7e33d4eaf573f937, 208, "memset", }, // Toukiden (JPN)
311 	{ 0x7f1fc0dce6be120a, 404, "fmod", },
312 	{ 0x8126a59ffa504614, 540, "brandish_download_frame", }, // Brandish, Zero no Kiseki, and Ao no Kiseki
313 	{ 0x828b98925af9ff8f, 40, "vector_distance_t", },
314 	{ 0x83ac39971df4b966, 336, "sqrtf", },
315 	{ 0x84c6cd47834f4c79, 1284, "powf", },
316 	{ 0x8734dc1d155ea493, 24, "vf2iz_q", },
317 	{ 0x87fe3f7e621ddebb, 212, "memcpy", },
318 	{ 0x891ca854e1c664e9, 2392, "qsort", },
319 	{ 0x8965d4b004adad28, 420, "log10f", },
320 	{ 0x89e1858ba11b84e4, 52, "memset", },
321 	{ 0x8a00e7207e7dbc81, 232, "_exit", },
322 	{ 0x8a1f9daadecbaf7f, 104, "vmmul_q_transp", },
323 	{ 0x8a610f34078ce360, 32, "vector_copy_q_t", },
324 	{ 0x8c3fd997a544d0b1, 268, "memcpy", }, // Valkyrie Profile (US)
325 	{ 0x8da0164e69e9b531, 1040, "grisaianokajitsu_download_frame", }, // Grisaia no Kajitsu La Fruit de la Grisaia
326 	{ 0x8dd0546db930ef25, 992, "memmove", }, // PoPoLoCrois (JPN)
327 	{ 0x8df2928848857e97, 164, "strcat", },
328 	{ 0x8e48cabd529ca6b5, 52, "vector_multiply_t", },
329 	{ 0x8e97dcb03fbaba5c, 104, "vmmul_q_transp", },
330 	{ 0x8ecf804bbe7922e5, 572, "worms_copy_normalize_alpha" }, // Worms Battle Islands (US)
331 	{ 0x8ee81b03d2eef1e7, 28, "vmul_t", },
332 	{ 0x8f09fb8693c3c49d, 992, "kirameki_school_life_download_frame", }, // Hentai Ouji To Warawanai Neko
333 	{ 0x8f19c41e8b987e18, 100, "matrix_mogrify", },
334 	{ 0x8ff11e9bed387401, 700, "memmove", }, // God Eater 2
335 	{ 0x910140c1a07aa59e, 256, "rot_matrix_euler_zyx", },
336 	{ 0x91606bd72ae90481, 44, "wmemcpy", },
337 	{ 0x92c7d2de74068c9c, 32, "vcross_t", },
338 	{ 0x93d8a275ba288b26, 32, "vdot_t", },
339 	{ 0x94c7083b64a946b4, 2028, "powf", },
340 	{ 0x94eb1e7dccca76a4, 680, "shinigamitoshoujo_download_frame", }, // Shinigami to Shoujo (JP)
341 	{ 0x95a52ce1bc460108, 2036, "_malloc_r", },
342 	{ 0x95bd33ac373c019a, 24, "fabsf", },
343 	{ 0x9705934b0950d68d, 280, "dl_write_framebuffer_ptr", },
344 	{ 0x9734cf721bc0f3a1, 732, "atanf", },
345 	{ 0x99b85c5fce389911, 408, "mytranwars_upload_frame", }, // Mytran Wars
346 	{ 0x99c9288185c352ea, 592, "orenoimouto_download_frame_2", }, // Ore no Imouto ga Konnani Kawaii Wake ga Nai
347 	{ 0x9a06b9d5c16c4c20, 76, "dl_write_clut_ptrload", },
348 	{ 0x9b88b739267d189e, 88, "strrchr", },
349 	{ 0x9ce53975bb88c0e7, 96, "strncpy", },
350 	{ 0x9d4f5f56b52f07f2, 808, "memmove", }, // Jeanne d'Arc (US)
351 	{ 0x9e2941c4a5c5e847, 792, "memcpy", }, // LittleBigPlanet (US)
352 	{ 0x9e6ce11f9d49f954, 292, "memcpy", }, // Jeanne d'Arc (US)
353 	{ 0x9f269daa6f0da803, 128, "dl_write_scissor_region", },
354 	{ 0x9f7919eeb43982b0, 208, "__fixdfsi", },
355 	{ 0xa1c9b0a2c71235bf, 1752, "marvelalliance1_copy" }, // Marvel Ultimate Alliance 1 (EU)
356 	{ 0xa1ca0640f11182e7, 72, "strcspn", },
357 	{ 0xa243486be51ce224, 272, "cosf", },
358 	{ 0xa2bcef60a550a3ef, 92, "matrix_rot_z", },
359 	{ 0xa373f55c65cd757a, 312, "memcpy_swizzled" }, // God Eater Burst Demo
360 	{ 0xa41989db0f9bf97e, 1304, "pow", },
361 	{ 0xa44f6227fdbc12b1, 132, "memcmp", }, // Popolocrois (US)
362 	{ 0xa46cc6ea720d5775, 44, "dl_write_cull", },
363 	{ 0xa54967288afe8f26, 600, "ceil", },
364 	{ 0xa5ddbbc688e89a4d, 56, "isinf", },
365 	{ 0xa615f6bd33195dae, 220, "atvoffroadfuryprodemo_download_frame", }, // ATV Offroad Fury Pro (US) demo
366 	{ 0xa662359e30b829e4, 148, "memcmp", },
367 	{ 0xa6a03f0487a911b0, 392, "danganronpa1_1_download_frame", }, // Danganronpa 1
368 	{ 0xa8390e65fa087c62, 140, "vtfm_t_q", },
369 	{ 0xa85e48ee10b2dc50, 432, "omertachinmokunookitethelegacy_download_frame", }, // Omerta Chinmoku No Okite The Legacy
370 	{ 0xa85fe8abb88b1c6f, 52, "vector_sub_t", },
371 	{ 0xa9194e55cc586557, 268, "memcpy", },
372 	{ 0xa91b3d60bd75105b, 28, "vadd_t", },
373 	{ 0xab97ec58c58a7c75, 52, "vector_divide_t", },
374 	{ 0xac84fa7571895c9a, 68, "memcpy", }, // Marvel Ultimate Alliance 2
375 	{ 0xacc2c11c3ea28320, 268, "ceilf", },
376 	{ 0xad67add5122b8c64, 52, "matrix_q_translate_t", },
377 	{ 0xada952a1adcea4f5, 60, "vmmul_q_transp5", },
378 	{ 0xadfbf8fb8c933193, 56, "fabs", },
379 	{ 0xae39bac51fd6e76b, 628, "gakuenheaven_download_frame", }, // Gakuen Heaven: Boy's Love Scramble!
380 	{ 0xae50226363135bdd, 24, "vector_sub_t", },
381 	{ 0xae6cd7dfac82c244, 48, "vpow_s", },
382 	{ 0xaf85d47f95ad2921, 1936, "pow", },
383 	{ 0xafb2c7e56c04c8e9, 48, "vtfm_q", },
384 	{ 0xafc9968e7d246a5e, 1588, "atan", },
385 	{ 0xafcb7dfbc4d72588, 44, "vector_transform_3x4", },
386 	{ 0xb07f9d82d79deea9, 536, "brandish_download_frame", },  // Brandish, and Sora no kiseki 3rd
387 	{ 0xb09c9bc1343a774c, 456, "danganronpa2_1_download_frame", }, // Danganronpa 2
388 	{ 0xb0db731f27d3aa1b, 40, "vmax_s", },
389 	{ 0xb0ef265e87899f0a, 32, "vector_divide_t_s", },
390 	{ 0xb183a37baa12607b, 32, "vscl_t", },
391 	{ 0xb1a3e60a89af9857, 20, "fabs", },
392 	{ 0xb25670ff47b4843d, 232, "starocean_clear_framebuf" },
393 	{ 0xb3fef47fb27d57c9, 44, "vector_scale_t", },
394 	{ 0xb43fd5078ae78029, 84, "send_commandi_stall", },
395 	{ 0xb43ffbd4dc446dd2, 324, "atan2f", },
396 	{ 0xb5fdb3083e6f4b3f, 36, "vhtfm_t", },
397 	{ 0xb6a04277fb1e1a1a, 104, "vmmul_q_transp", },
398 	{ 0xb726917d688ac95b, 268, "kagaku_no_ensemble_download_frame", }, // Toaru Majutsu to Kagaku no Ensemble
399 	{ 0xb7448c5ffdd3b0fc, 356, "atan2f", },
400 	{ 0xb7d88567dc22aab1, 820, "memcpy", }, // Trails in the Sky (US)
401 	{ 0xb877d3c37a7aaa5d, 60, "vmmul_q_2", },
402 	{ 0xb89aa73b6f94ba95, 52, "vclamp_t", },
403 	{ 0xb8bd1f0e02e9ad87, 156, "dl_write_light_dir", },
404 	{ 0xb8cfaeebfeb2de20, 7548, "_vfprintf_r", },
405 	{ 0xb97f352e85661af6, 32, "finitef", },
406 	{ 0xba76a8e853426baa, 544, "soranokiseki_fc_download_frame", }, // Sora no kiseki FC
407 	{ 0xbb3c6592ed319ba4, 132, "dl_write_fog_params", },
408 	{ 0xbb7d7c93e4c08577, 124, "__truncdfsf2", },
409 	{ 0xbdf54d66079afb96, 200, "dl_write_bone_matrix_3", },
410 	{ 0xbe773f78afd1a70f, 128, "rand", },
411 	{ 0xbf5d02ccb8514881, 108, "strcmp", },
412 	{ 0xbf791954ebef4afb, 396, "expf", },
413 	{ 0xbfa8c16038b7753d, 868, "sakurasou_download_frame", }, // Sakurasou No Pet Na Kanojo
414 	{ 0xbfe07e305abc4cd1, 808, "memmove" }, // Final Fantasy Tactics (US)
415 	{ 0xc062f2545ef5dc39, 1076, "kirameki_school_life_download_frame", },// Kirameki School Life SP,and Boku wa Tomodati ga Sukunai
416 	{ 0xc0feb88cc04a1dc7, 48, "vector_negate_t", },
417 	{ 0xc1220040b0599a75, 472, "soranokiseki_sc_download_frame", }, // Sora no kiseki SC
418 	{ 0xc1f34599d0b9146b, 116, "__subdf3", },
419 	{ 0xc3089f66ee6f0a24, 464, "growlanser_create_saveicon", }, // Growlanswer IV
420 	{ 0xc319f0d107dd2f45, 888, "__muldf3", },
421 	{ 0xc35c10300b6b6091, 620, "floor", },
422 	{ 0xc3dbf3e6c80a0a51, 164, "dl_write_bone_matrix", },
423 	{ 0xc51519f5dab342d4, 224, "cosf", },
424 	{ 0xc52c14b9af8c3008, 76, "memcmp", },
425 	{ 0xc54eae62622f1e11, 164, "dl_write_bone_matrix_2", },
426 	{ 0xc6b29de7d3245198, 656, "starocean_write_stencil" }, // Star Ocean 1 (US)
427 	{ 0xc7b1113cfdfedab6, 104, "tonyhawkp8_upload_tutorial_frame", }, // Tony Hawk's Project 8 (US)
428 	{ 0xc96e3a087ebf49a9, 100, "dl_write_light_color", },
429 	{ 0xca7cb2c0b9410618, 680, "kudwafter_download_frame", }, // Kud Wafter
430 	{ 0xcb22120018386319, 692, "photokano_download_frame", }, // Photo Kano
431 	{ 0xcb7a2edd603ecfef, 48, "vtfm_p", },
432 	{ 0xcdf64d21418b2667, 24, "vzero_q", },
433 	{ 0xce1c95ee25b8e2ea, 448, "fmod", },
434 	{ 0xce4d18a75b98859f, 40, "vector_add_t_2", },
435 	// Unsafe due to immediates.
436 	//{ 0xceb5372d0003d951, 52, "dl_write_stenciltest", },
437 	{ 0xcee11483b550ce8f, 24, "vocp_q", },
438 	{ 0xcfecf208769ed5fd, 272, "cosf", },
439 	{ 0xd019b067b58cf6c3, 700, "memmove", }, // Star Ocean 1 (US)
440 	{ 0xd12a3a91e0040229, 524, "dl_write_enable_disable", },
441 	{ 0xd141d1efbfe13ca3, 968, "kirameki_school_life_download_frame", }, // Kirameki School Life SP,and Boku wa Tomodati ga Sukunai
442 	{ 0xd1db467a23ebe00d, 724, "rewrite_download_frame", }, // Rewrite Portable
443 	{ 0xd1faacfc711d61e8, 68, "__negdf2", },
444 	{ 0xd207b0650a41dd9c, 28, "vmin_q", },
445 	{ 0xd6d6e0bb21654778, 24, "vneg_t", },
446 	{ 0xd7229fee680e7851, 40, "vmin_s", },
447 	{ 0xd75670860a7f4b05, 144, "wcsncpy", },
448 	{ 0xd76d1a8804c7ec2c, 100, "dl_write_material", },
449 	{ 0xd7d350c0b33a4662, 28, "vadd_q", },
450 	{ 0xd80051931427dca0, 116, "__subdf3", },
451 	{ 0xd96ba6e4ff86f1bf, 276, "katamari_screenshot_to_565", }, // Me and My Katamari (US)
452 	{ 0xda51dab503b06979, 32, "vmidt_q", },
453 	{ 0xdc0cc8b400ecfbf2, 36, "strcmp", },
454 	{ 0xdcab869acf2bacab, 292, "strncasecmp", },
455 	{ 0xdcdf7e1c1a3dc260, 372, "strncmp", },
456 	{ 0xdcfc28e624a81bf1, 5476, "_dtoa_r", },
457 	{ 0xddfa5a85937aa581, 32, "vdot_q", },
458 	{ 0xdeb6a583659e3948, 1080, "littlebustersce_download_frame", }, // Little Busters! Converted Edition (JP)
459 	{ 0xe0214719d8a0aa4e, 104, "strstr", },
460 	{ 0xe029f0699ca3a886, 76, "matrix300_transform_by", },
461 	{ 0xe086d5c9ce89148f, 212, "bokunonatsuyasumi4_download_frame", }, // Boku no Natsuyasumi 2 and 4,
462 	{ 0xe093c2b0194d52b3, 820, "ff1_battle_effect", }, // Final Fantasy 1 (US)
463 	{ 0xe1107cf3892724a0, 460, "_memalign_r", },
464 	{ 0xe1724e6e29209d97, 24, "vector_length_t_2", },
465 	{ 0xe1a5d939cc308195, 68, "wcscmp", },
466 	{ 0xe2d9106e5b9e39e6, 80, "strnlen", },
467 	{ 0xe3154c81a76515fa, 208, "narisokonai_download_frame", }, // Narisokonai Eiyuutan
468 	{ 0xe32cb5c062d1a1c4, 700, "_strtoull_r", },
469 	{ 0xe3835fb2c9c04e59, 44, "vmmul_q", },
470 	{ 0xe527c62d8613f297, 136, "strcpy", },
471 	{ 0xe6002fc9affd678e, 480, "topx_create_saveicon", }, // Tales of Phantasia X
472 	{ 0xe7b36c2c1348551d, 148, "tan", },
473 	{ 0xe83a7a9d80a21c11, 4448, "_strtod_r", },
474 	{ 0xe894bda909a8a8f9, 1064, "expensive_wipeout_pulse", },
475 	{ 0xe8ad7719be44e7c8, 276, "strchr", },
476 	{ 0xeabb9c1b4f83d2b4, 52, "memset_jak", }, // Crisis Core (US), Jak and Daxter (this is a slow memset and needs to have slow timing)
477 	{ 0xeb0f7bf63d52ece9, 88, "strncat", },
478 	{ 0xeb8c0834d8bbc28c, 416, "fmodf", },
479 	{ 0xed8918f378e9a563, 628, "sd_gundam_g_generation_download_frame", }, // SD Gundam G Generation Overworld
480 	{ 0xedbbe9bf9fbceca8, 172, "dl_write_viewport2", },
481 	{ 0xedc3f476221f96e6, 148, "tanf", },
482 	{ 0xf1f660fdf349eac2, 1588, "_malloc_r", },
483 	{ 0xf38a356a359dbe06, 28, "vmax_q", },
484 	{ 0xf3fc2220ed0f2703, 32, "send_commandf", },
485 	{ 0xf4d797cef4ac88cd, 684, "_free_r", },
486 	{ 0xf4ea7d2ec943fa02, 224, "sinf", },
487 	{ 0xf4f8cdf479dfc4a4, 224, "sinf", },
488 	{ 0xf527d906d69005a0, 848, "photokano_download_frame_2", }, // Photo Kano
489 	{ 0xf52f993e444b6c52, 44, "dl_write_shademode", },
490 	{ 0xf56641884b36c638, 468, "scalbn", },
491 	{ 0xf5e91870b5b76ddc, 288, "motorstorm_download_frame", }, // MotorStorm: Arctic Edge
492 	{ 0xf5f7826b4a61767c, 40, "matrix_copy_q", },
493 	{ 0xf73c094e492bc163, 396, "hypot", },
494 	{ 0xf773297d89ff7a63, 532, "kumonohatateni_download_frame", }, // Amatsumi Sora ni Kumo no Hatate ni, and Hanakisou
495 	{ 0xf7fc691db0147e25, 96, "strspn", },
496 	{ 0xf842aea3baa61f29, 32, "vector_length_t", },
497 	{ 0xf8e0902f4099a9d6, 2260, "qsort", },
498 	{ 0xf972543ab7df071a, 32, "vsqrt_s", },
499 	{ 0xf9b00ef163e8b9d4, 32, "vscl_q", },
500 	{ 0xf9ea1bf2a897ef24, 588, "ceil", },
501 	{ 0xfa156c48461eeeb9, 24, "vf2id_q", },
502 	{ 0xfb4253a1d9d9df9f, 20, "isnanf", },
503 	{ 0xfd34a9ad94fa6241, 76, "__extendsfdf2", },
504 	{ 0xfe2566ad957054b7, 232, "suikoden1_and_2_download_frame_2", }, // Gensou Suikoden 1&2
505 	{ 0xfe4f0280240008e9, 28, "vavg_q", },
506 	{ 0xfe5dd338ab862291, 216, "memset", }, // Metal Gear Solid: Peace Walker demo
507 	{ 0xffc8f5f8f946152c, 192, "dl_write_light_color", },
508 	{ 0x249a3c5981c73480, 1472, "openseason_data_decode", },  // Open Season
509 };
510 
511 namespace MIPSAnalyst {
512 	// Only can ever output a single reg.
GetOutGPReg(MIPSOpcode op)513 	MIPSGPReg GetOutGPReg(MIPSOpcode op) {
514 		MIPSInfo opinfo = MIPSGetInfo(op);
515 		if (opinfo & OUT_RT) {
516 			return MIPS_GET_RT(op);
517 		}
518 		if (opinfo & OUT_RD) {
519 			return MIPS_GET_RD(op);
520 		}
521 		if (opinfo & OUT_RA) {
522 			return MIPS_REG_RA;
523 		}
524 		return MIPS_REG_INVALID;
525 	}
526 
ReadsFromGPReg(MIPSOpcode op,MIPSGPReg reg)527 	bool ReadsFromGPReg(MIPSOpcode op, MIPSGPReg reg) {
528 		MIPSInfo info = MIPSGetInfo(op);
529 		if ((info & IN_RS) != 0 && MIPS_GET_RS(op) == reg) {
530 			return true;
531 		}
532 		if ((info & IN_RT) != 0 && MIPS_GET_RT(op) == reg) {
533 			return true;
534 		}
535 		return false;
536 	}
537 
IsDelaySlotNiceReg(MIPSOpcode branchOp,MIPSOpcode op,MIPSGPReg reg1,MIPSGPReg reg2)538 	bool IsDelaySlotNiceReg(MIPSOpcode branchOp, MIPSOpcode op, MIPSGPReg reg1, MIPSGPReg reg2) {
539 		MIPSInfo branchInfo = MIPSGetInfo(branchOp);
540 		MIPSInfo info = MIPSGetInfo(op);
541 		if (info & IS_CONDBRANCH) {
542 			return false;
543 		}
544 		// $0 is never an out reg, it's always 0.
545 		if (reg1 != MIPS_REG_ZERO && GetOutGPReg(op) == reg1) {
546 			return false;
547 		}
548 		if (reg2 != MIPS_REG_ZERO && GetOutGPReg(op) == reg2) {
549 			return false;
550 		}
551 		// If the branch is an "and link" branch, check the delay slot for RA.
552 		if ((branchInfo & OUT_RA) != 0) {
553 			return GetOutGPReg(op) != MIPS_REG_RA && !ReadsFromGPReg(op, MIPS_REG_RA);
554 		}
555 		return true;
556 	}
557 
IsDelaySlotNiceVFPU(MIPSOpcode branchOp,MIPSOpcode op)558 	bool IsDelaySlotNiceVFPU(MIPSOpcode branchOp, MIPSOpcode op) {
559 		MIPSInfo info = MIPSGetInfo(op);
560 		if (info & IS_CONDBRANCH) {
561 			return false;
562 		}
563 		return (info & OUT_VFPU_CC) == 0;
564 	}
565 
IsDelaySlotNiceFPU(MIPSOpcode branchOp,MIPSOpcode op)566 	bool IsDelaySlotNiceFPU(MIPSOpcode branchOp, MIPSOpcode op) {
567 		MIPSInfo info = MIPSGetInfo(op);
568 		if (info & IS_CONDBRANCH) {
569 			return false;
570 		}
571 		return (info & OUT_FPUFLAG) == 0;
572 	}
573 
IsSyscall(MIPSOpcode op)574 	bool IsSyscall(MIPSOpcode op) {
575 		// Syscalls look like this: 0000 00-- ---- ---- ---- --00 1100
576 		return (op >> 26) == 0 && (op & 0x3f) == 12;
577 	}
578 
IsSWInstr(MIPSOpcode op)579 	static bool IsSWInstr(MIPSOpcode op) {
580 		return (op & MIPSTABLE_IMM_MASK) == 0xAC000000;
581 	}
IsSBInstr(MIPSOpcode op)582 	static bool IsSBInstr(MIPSOpcode op) {
583 		return (op & MIPSTABLE_IMM_MASK) == 0xA0000000;
584 	}
IsSHInstr(MIPSOpcode op)585 	static bool IsSHInstr(MIPSOpcode op) {
586 		return (op & MIPSTABLE_IMM_MASK) == 0xA4000000;
587 	}
588 
IsSWLInstr(MIPSOpcode op)589 	static bool IsSWLInstr(MIPSOpcode op) {
590 		return (op & MIPSTABLE_IMM_MASK) == 0xA8000000;
591 	}
IsSWRInstr(MIPSOpcode op)592 	static bool IsSWRInstr(MIPSOpcode op) {
593 		return (op & MIPSTABLE_IMM_MASK) == 0xB8000000;
594 	}
595 
IsSWC1Instr(MIPSOpcode op)596 	static bool IsSWC1Instr(MIPSOpcode op) {
597 		return (op & MIPSTABLE_IMM_MASK) == 0xE4000000;
598 	}
IsSVSInstr(MIPSOpcode op)599 	static bool IsSVSInstr(MIPSOpcode op) {
600 		return (op & MIPSTABLE_IMM_MASK) == 0xE8000000;
601 	}
IsSVQInstr(MIPSOpcode op)602 	static bool IsSVQInstr(MIPSOpcode op) {
603 		return (op & MIPSTABLE_IMM_MASK) == 0xF8000000;
604 	}
605 
OpMemoryAccessSize(u32 pc)606 	int OpMemoryAccessSize(u32 pc) {
607 		const auto op = Memory::Read_Instruction(pc, true);
608 		MIPSInfo info = MIPSGetInfo(op);
609 		if ((info & (IN_MEM | OUT_MEM)) == 0) {
610 			return 0;
611 		}
612 
613 		// TODO: Verify lwl/lwr/etc.?
614 		switch (info & MEMTYPE_MASK) {
615 		case MEMTYPE_BYTE:
616 			return 1;
617 		case MEMTYPE_HWORD:
618 			return 2;
619 		case MEMTYPE_WORD:
620 		case MEMTYPE_FLOAT:
621 			return 4;
622 		case MEMTYPE_VQUAD:
623 			return 16;
624 		}
625 
626 		return 0;
627 	}
628 
IsOpMemoryWrite(u32 pc)629 	bool IsOpMemoryWrite(u32 pc) {
630 		const auto op = Memory::Read_Instruction(pc, true);
631 		MIPSInfo info = MIPSGetInfo(op);
632 		return (info & OUT_MEM) != 0;
633 	}
634 
OpHasDelaySlot(u32 pc)635 	bool OpHasDelaySlot(u32 pc) {
636 		const auto op = Memory::Read_Instruction(pc, true);
637 		MIPSInfo info = MIPSGetInfo(op);
638 		return (info & DELAYSLOT) != 0;
639 	}
640 
OpWouldChangeMemory(u32 pc,u32 addr,u32 size)641 	bool OpWouldChangeMemory(u32 pc, u32 addr, u32 size) {
642 		const auto op = Memory::Read_Instruction(pc, true);
643 
644 		// TODO: Trap sc/ll, svl.q, svr.q?
645 
646 		int gprMask = 0;
647 		if (IsSWInstr(op))
648 			gprMask = 0xFFFFFFFF;
649 		if (IsSHInstr(op))
650 			gprMask = 0x0000FFFF;
651 		if (IsSBInstr(op))
652 			gprMask = 0x000000FF;
653 		if (IsSWLInstr(op)) {
654 			const u32 shift = (addr & 3) * 8;
655 			gprMask = 0xFFFFFFFF >> (24 - shift);
656 		}
657 		if (IsSWRInstr(op)) {
658 			const u32 shift = (addr & 3) * 8;
659 			gprMask = 0xFFFFFFFF << shift;
660 		}
661 
662 		u32 writeVal = 0xFFFFFFFF;
663 		u32 prevVal = 0x00000000;
664 
665 		if (gprMask != 0)
666 		{
667 			MIPSGPReg rt = MIPS_GET_RT(op);
668 			writeVal = currentMIPS->r[rt] & gprMask;
669 			prevVal = Memory::Read_U32(addr) & gprMask;
670 		}
671 
672 		if (IsSWC1Instr(op)) {
673 			int ft = MIPS_GET_FT(op);
674 			writeVal = currentMIPS->fi[ft];
675 			prevVal = Memory::Read_U32(addr);
676 		}
677 
678 		if (IsSVSInstr(op)) {
679 			int vt = ((op >> 16) & 0x1f) | ((op & 3) << 5);
680 			writeVal = currentMIPS->vi[voffset[vt]];
681 			prevVal = Memory::Read_U32(addr);
682 		}
683 
684 		if (IsSVQInstr(op)) {
685 			int vt = (((op >> 16) & 0x1f)) | ((op & 1) << 5);
686 			float rd[4];
687 			ReadVector(rd, V_Quad, vt);
688 			return memcmp(rd, Memory::GetPointer(addr), sizeof(float) * 4) != 0;
689 		}
690 
691 		// TODO: Technically, the break might be for 1 byte in the middle of a sw.
692 		return writeVal != prevVal;
693 	}
694 
Analyze(u32 address)695 	AnalysisResults Analyze(u32 address) {
696 		const int MAX_ANALYZE = 10000;
697 
698 		AnalysisResults results;
699 
700 		//set everything to -1 (FF)
701 		memset(&results, 255, sizeof(AnalysisResults));
702 		for (int i = 0; i < MIPS_NUM_GPRS; i++) {
703 			results.r[i].used = false;
704 			results.r[i].readCount = 0;
705 			results.r[i].writeCount = 0;
706 			results.r[i].readAsAddrCount = 0;
707 		}
708 
709 		for (u32 addr = address, endAddr = address + MAX_ANALYZE; addr <= endAddr; addr += 4) {
710 			MIPSOpcode op = Memory::Read_Instruction(addr, true);
711 			MIPSInfo info = MIPSGetInfo(op);
712 
713 			MIPSGPReg rs = MIPS_GET_RS(op);
714 			MIPSGPReg rt = MIPS_GET_RT(op);
715 
716 			if (info & IN_RS) {
717 				if ((info & IN_RS_ADDR) == IN_RS_ADDR) {
718 					results.r[rs].MarkReadAsAddr(addr);
719 				} else {
720 					results.r[rs].MarkRead(addr);
721 				}
722 			}
723 
724 			if (info & IN_RT) {
725 				results.r[rt].MarkRead(addr);
726 			}
727 
728 			MIPSGPReg outReg = GetOutGPReg(op);
729 			if (outReg != MIPS_REG_INVALID) {
730 				results.r[outReg].MarkWrite(addr);
731 			}
732 
733 			if (info & DELAYSLOT) {
734 				// Let's just finish the delay slot before bailing.
735 				endAddr = addr + 4;
736 			}
737 		}
738 
739 		int numUsedRegs = 0;
740 		static int totalUsedRegs = 0;
741 		static int numAnalyzings = 0;
742 		for (int i = 0; i < MIPS_NUM_GPRS; i++) {
743 			if (results.r[i].used) {
744 				numUsedRegs++;
745 			}
746 		}
747 		totalUsedRegs += numUsedRegs;
748 		numAnalyzings++;
749 		VERBOSE_LOG(CPU, "[ %08x ] Used regs: %i Average: %f", address, numUsedRegs, (float)totalUsedRegs / (float)numAnalyzings);
750 
751 		return results;
752 	}
753 
Reset()754 	void Reset() {
755 		std::lock_guard<std::recursive_mutex> guard(functions_lock);
756 		functions.clear();
757 		hashToFunction.clear();
758 	}
759 
UpdateHashToFunctionMap()760 	void UpdateHashToFunctionMap() {
761 		std::lock_guard<std::recursive_mutex> guard(functions_lock);
762 		hashToFunction.clear();
763 		// Really need to detect C++11 features with better defines.
764 #if !PPSSPP_PLATFORM(IOS)
765 		hashToFunction.reserve(functions.size());
766 #endif
767 		for (auto iter = functions.begin(); iter != functions.end(); iter++) {
768 			AnalyzedFunction &f = *iter;
769 			if (f.hasHash && f.size > 16) {
770 				hashToFunction.insert(std::make_pair(f.hash, &f));
771 			}
772 		}
773 	}
774 
775 	enum RegisterUsage {
776 		USAGE_CLOBBERED,
777 		USAGE_INPUT,
778 		USAGE_UNKNOWN,
779 	};
780 
DetermineInOutUsage(u64 inFlag,u64 outFlag,u32 addr,int instrs)781 	static RegisterUsage DetermineInOutUsage(u64 inFlag, u64 outFlag, u32 addr, int instrs) {
782 		const u32 start = addr;
783 		u32 end = addr + instrs * sizeof(u32);
784 		bool canClobber = true;
785 		while (addr < end) {
786 			const MIPSOpcode op = Memory::Read_Instruction(addr, true);
787 			const MIPSInfo info = MIPSGetInfo(op);
788 
789 			// Yes, used.
790 			if (info & inFlag)
791 				return USAGE_INPUT;
792 
793 			// Clobbered, so not used.
794 			if (info & outFlag)
795 				return canClobber ? USAGE_CLOBBERED : USAGE_UNKNOWN;
796 
797 			// Bail early if we hit a branch (could follow each path for continuing?)
798 			if ((info & IS_CONDBRANCH) || (info & IS_JUMP)) {
799 				// Still need to check the delay slot (so end after it.)
800 				// We'll assume likely are taken.
801 				end = addr + 8;
802 				// The reason for the start != addr check is that we compile delay slots before branches.
803 				// That means if we're starting at the branch, it's not safe to allow the delay slot
804 				// to clobber, since it might have already been compiled.
805 				// As for LIKELY, we don't know if it'll run the branch or not.
806 				canClobber = (info & LIKELY) == 0 && start != addr;
807 			}
808 			addr += 4;
809 		}
810 		return USAGE_UNKNOWN;
811 	}
812 
DetermineRegisterUsage(MIPSGPReg reg,u32 addr,int instrs)813 	static RegisterUsage DetermineRegisterUsage(MIPSGPReg reg, u32 addr, int instrs) {
814 		switch (reg) {
815 		case MIPS_REG_HI:
816 			return DetermineInOutUsage(IN_HI, OUT_HI, addr, instrs);
817 		case MIPS_REG_LO:
818 			return DetermineInOutUsage(IN_LO, OUT_LO, addr, instrs);
819 		case MIPS_REG_FPCOND:
820 			return DetermineInOutUsage(IN_FPUFLAG, OUT_FPUFLAG, addr, instrs);
821 		case MIPS_REG_VFPUCC:
822 			return DetermineInOutUsage(IN_VFPU_CC, OUT_VFPU_CC, addr, instrs);
823 		default:
824 			break;
825 		}
826 
827 		if (reg > 32) {
828 			return USAGE_UNKNOWN;
829 		}
830 
831 		const u32 start = addr;
832 		u32 end = addr + instrs * sizeof(u32);
833 		bool canClobber = true;
834 		while (addr < end) {
835 			const MIPSOpcode op = Memory::Read_Instruction(addr, true);
836 			const MIPSInfo info = MIPSGetInfo(op);
837 
838 			// Yes, used.
839 			if ((info & IN_RS) && (MIPS_GET_RS(op) == reg))
840 				return USAGE_INPUT;
841 			if ((info & IN_RT) && (MIPS_GET_RT(op) == reg))
842 				return USAGE_INPUT;
843 
844 			// Clobbered, so not used.
845 			bool clobbered = false;
846 			if ((info & OUT_RT) && (MIPS_GET_RT(op) == reg))
847 				clobbered = true;
848 			if ((info & OUT_RD) && (MIPS_GET_RD(op) == reg))
849 				clobbered = true;
850 			if ((info & OUT_RA) && (reg == MIPS_REG_RA))
851 				clobbered = true;
852 			if (clobbered) {
853 				if (!canClobber || (info & IS_CONDMOVE))
854 					return USAGE_UNKNOWN;
855 				return USAGE_CLOBBERED;
856 			}
857 
858 			// Bail early if we hit a branch (could follow each path for continuing?)
859 			if ((info & IS_CONDBRANCH) || (info & IS_JUMP)) {
860 				// Still need to check the delay slot (so end after it.)
861 				// We'll assume likely are taken.
862 				end = addr + 8;
863 				// The reason for the start != addr check is that we compile delay slots before branches.
864 				// That means if we're starting at the branch, it's not safe to allow the delay slot
865 				// to clobber, since it might have already been compiled.
866 				// As for LIKELY, we don't know if it'll run the branch or not.
867 				canClobber = (info & LIKELY) == 0 && start != addr;
868 			}
869 			addr += 4;
870 		}
871 		return USAGE_UNKNOWN;
872 	}
873 
IsRegisterUsed(MIPSGPReg reg,u32 addr,int instrs)874 	bool IsRegisterUsed(MIPSGPReg reg, u32 addr, int instrs) {
875 		return DetermineRegisterUsage(reg, addr, instrs) == USAGE_INPUT;
876 	}
877 
IsRegisterClobbered(MIPSGPReg reg,u32 addr,int instrs)878 	bool IsRegisterClobbered(MIPSGPReg reg, u32 addr, int instrs) {
879 		return DetermineRegisterUsage(reg, addr, instrs) == USAGE_CLOBBERED;
880 	}
881 
HashFunctions()882 	void HashFunctions() {
883 		std::lock_guard<std::recursive_mutex> guard(functions_lock);
884 		std::vector<u32> buffer;
885 
886 		for (auto iter = functions.begin(), end = functions.end(); iter != end; iter++) {
887 			AnalyzedFunction &f = *iter;
888 			if (!Memory::IsValidRange(f.start, f.end - f.start + 4)) {
889 				continue;
890 			}
891 
892 			// This is unfortunate.  In case of emuhacks or relocs, we have to make a copy.
893 			buffer.resize((f.end - f.start + 4) / 4);
894 			size_t pos = 0;
895 			for (u32 addr = f.start; addr <= f.end; addr += 4) {
896 				u32 validbits = 0xFFFFFFFF;
897 				MIPSOpcode instr = Memory::ReadUnchecked_Instruction(addr, true);
898 				if (MIPS_IS_EMUHACK(instr)) {
899 					f.hasHash = false;
900 					goto skip;
901 				}
902 
903 				MIPSInfo flags = MIPSGetInfo(instr);
904 				if (flags & IN_IMM16)
905 					validbits &= ~0xFFFF;
906 				if (flags & IN_IMM26)
907 					validbits &= ~0x03FFFFFF;
908 				buffer[pos++] = instr & validbits;
909 			}
910 
911 			f.hash = CityHash64((const char *) &buffer[0], buffer.size() * sizeof(u32));
912 			f.hasHash = true;
913 skip:
914 			;
915 		}
916 	}
917 
PrecompileFunction(u32 startAddr,u32 length)918 	void PrecompileFunction(u32 startAddr, u32 length) {
919 		// Direct calls to this ignore the bPreloadFunctions flag, since it's just for stubs.
920 		if (MIPSComp::jit) {
921 			MIPSComp::jit->CompileFunction(startAddr, length);
922 		}
923 	}
924 
PrecompileFunctions()925 	void PrecompileFunctions() {
926 		if (!g_Config.bPreloadFunctions) {
927 			return;
928 		}
929 		std::lock_guard<std::recursive_mutex> guard(functions_lock);
930 
931 		// TODO: Load from cache file if available instead.
932 
933 		double st = time_now_d();
934 		for (auto iter = functions.begin(), end = functions.end(); iter != end; iter++) {
935 			const AnalyzedFunction &f = *iter;
936 
937 			PrecompileFunction(f.start, f.end - f.start + 4);
938 		}
939 		double et = time_now_d();
940 
941 		NOTICE_LOG(JIT, "Precompiled %d MIPS functions in %0.2f milliseconds", (int)functions.size(), (et - st) * 1000.0);
942 	}
943 
DefaultFunctionName(char buffer[256],u32 startAddr)944 	static const char *DefaultFunctionName(char buffer[256], u32 startAddr) {
945 		sprintf(buffer, "z_un_%08x", startAddr);
946 		return buffer;
947 	}
948 
IsDefaultFunction(const char * name)949 	static bool IsDefaultFunction(const char *name) {
950 		if (name == NULL) {
951 			// Must be I guess?
952 			return true;
953 		}
954 
955 		// Assume any z_un, not just the address, is a default func.
956 		return !strncmp(name, "z_un_", strlen("z_un_")) || !strncmp(name, "u_un_", strlen("u_un_"));
957 	}
958 
IsDefaultFunction(const std::string & name)959 	static bool IsDefaultFunction(const std::string &name) {
960 		if (name.empty()) {
961 			// Must be I guess?
962 			return true;
963 		}
964 
965 		return IsDefaultFunction(name.c_str());
966 	}
967 
ScanAheadForJumpback(u32 fromAddr,u32 knownStart,u32 knownEnd)968 	static u32 ScanAheadForJumpback(u32 fromAddr, u32 knownStart, u32 knownEnd) {
969 		static const u32 MAX_AHEAD_SCAN = 0x1000;
970 		// Maybe a bit high... just to make sure we don't get confused by recursive tail recursion.
971 		static const u32 MAX_FUNC_SIZE = 0x20000;
972 
973 		if (fromAddr > knownEnd + MAX_FUNC_SIZE) {
974 			return INVALIDTARGET;
975 		}
976 
977 		// Code might jump halfway up to before fromAddr, but after knownEnd.
978 		// In that area, there could be another jump up to the valid range.
979 		// So we track that for a second scan.
980 		u32 closestJumpbackAddr = INVALIDTARGET;
981 		u32 closestJumpbackTarget = fromAddr;
982 
983 		// We assume the furthest jumpback is within the func.
984 		u32 furthestJumpbackAddr = INVALIDTARGET;
985 
986 		const u32 scanEnd = fromAddr + Memory::ValidSize(fromAddr, MAX_AHEAD_SCAN);
987 		for (u32 ahead = fromAddr; ahead < scanEnd; ahead += 4) {
988 			MIPSOpcode aheadOp = Memory::Read_Instruction(ahead, true);
989 			u32 target = GetBranchTargetNoRA(ahead, aheadOp);
990 			if (target == INVALIDTARGET && ((aheadOp & 0xFC000000) == 0x08000000)) {
991 				target = GetJumpTarget(ahead);
992 			}
993 
994 			if (target != INVALIDTARGET) {
995 				// Only if it comes back up to known code within this func.
996 				if (target >= knownStart && target <= knownEnd) {
997 					furthestJumpbackAddr = ahead;
998 				}
999 				// But if it jumps above fromAddr, we should scan that area too...
1000 				if (target < closestJumpbackTarget && target < fromAddr && target > knownEnd) {
1001 					closestJumpbackAddr = ahead;
1002 					closestJumpbackTarget = target;
1003 				}
1004 			}
1005 			if (aheadOp == MIPS_MAKE_JR_RA()) {
1006 				break;
1007 			}
1008 		}
1009 
1010 		if (closestJumpbackAddr != INVALIDTARGET && furthestJumpbackAddr == INVALIDTARGET) {
1011 			for (u32 behind = closestJumpbackTarget; behind < fromAddr; behind += 4) {
1012 				MIPSOpcode behindOp = Memory::Read_Instruction(behind, true);
1013 				u32 target = GetBranchTargetNoRA(behind, behindOp);
1014 				if (target == INVALIDTARGET && ((behindOp & 0xFC000000) == 0x08000000)) {
1015 					target = GetJumpTarget(behind);
1016 				}
1017 
1018 				if (target != INVALIDTARGET) {
1019 					if (target >= knownStart && target <= knownEnd) {
1020 						furthestJumpbackAddr = closestJumpbackAddr;
1021 					}
1022 				}
1023 			}
1024 		}
1025 
1026 		return furthestJumpbackAddr;
1027 	}
1028 
ScanForFunctions(u32 startAddr,u32 endAddr,bool insertSymbols)1029 	bool ScanForFunctions(u32 startAddr, u32 endAddr, bool insertSymbols) {
1030 		std::lock_guard<std::recursive_mutex> guard(functions_lock);
1031 
1032 		FunctionsVector new_functions;
1033 
1034 		AnalyzedFunction currentFunction = {startAddr};
1035 
1036 		u32 furthestBranch = 0;
1037 		bool looking = false;
1038 		bool end = false;
1039 		bool isStraightLeaf = true;
1040 		bool decreasedSp = false;
1041 
1042 		u32 addr;
1043 		for (addr = startAddr; addr <= endAddr; addr += 4) {
1044 			MIPSOpcode op = Memory::Read_Instruction(addr, true);
1045 			u32 target = GetBranchTargetNoRA(addr, op);
1046 			if (target != INVALIDTARGET) {
1047 				isStraightLeaf = false;
1048 				if (target > furthestBranch) {
1049 					furthestBranch = target;
1050 				}
1051 			// j X
1052 			} else if ((op & 0xFC000000) == 0x08000000) {
1053 				u32 sureTarget = GetJumpTarget(addr);
1054 				// Check for a tail call.  Might not even have a jr ra.
1055 				if (sureTarget != INVALIDTARGET && sureTarget < currentFunction.start) {
1056 					if (furthestBranch > addr) {
1057 						looking = true;
1058 						addr += 4;
1059 					} else {
1060 						end = true;
1061 					}
1062 				} else if (sureTarget != INVALIDTARGET && sureTarget > addr && sureTarget > furthestBranch) {
1063 					static const u32 MAX_JUMP_FORWARD = 128;
1064 					// If it's a nearby forward jump, and not a stackless leaf, assume not a tail call.
1065 					if (sureTarget <= addr + MAX_JUMP_FORWARD && decreasedSp) {
1066 						// But let's check the delay slot.
1067 						MIPSOpcode op = Memory::Read_Instruction(addr + 4, true);
1068 						// addiu sp, sp, +X
1069 						if ((op & 0xFFFF8000) != 0x27BD0000) {
1070 							furthestBranch = sureTarget;
1071 							continue;
1072 						}
1073 					}
1074 
1075 					// A jump later.  Probably tail, but let's check if it jumps back.
1076 					// We use + 8 here in case it jumps right back to the delay slot.  We'll consider that inside the func.
1077 					u32 knownEnd = furthestBranch == 0 ? addr + 8 : furthestBranch;
1078 					u32 jumpback = ScanAheadForJumpback(sureTarget, currentFunction.start, knownEnd);
1079 					if (jumpback != INVALIDTARGET && jumpback > addr && jumpback > knownEnd) {
1080 						furthestBranch = jumpback;
1081 					} else {
1082 						if (furthestBranch > addr) {
1083 							looking = true;
1084 							addr += 4;
1085 						} else {
1086 							end = true;
1087 						}
1088 					}
1089 				}
1090 			}
1091 			if (op == MIPS_MAKE_JR_RA()) {
1092 				// If a branch goes to the jr ra, it's still ending here.
1093 				if (furthestBranch > addr) {
1094 					looking = true;
1095 					addr += 4;
1096 				} else {
1097 					end = true;
1098 				}
1099 			}
1100 			// addiu sp, sp, -X
1101 			if ((op & 0xFFFF8000) == 0x27BD8000) {
1102 				decreasedSp = true;
1103 			}
1104 			// addiu sp, sp, +X
1105 			if ((op & 0xFFFF8000) == 0x27BD0000) {
1106 				decreasedSp = false;
1107 			}
1108 			if (op == MIPS_MAKE_NOP() && currentFunction.start == addr) {
1109 				// Skip nop padding at the beginning of functions (alignment?)
1110 				currentFunction.start += 4;
1111 			}
1112 
1113 			if (looking) {
1114 				if (addr >= furthestBranch) {
1115 					u32 sureTarget = GetSureBranchTarget(addr);
1116 					// Regular j only, jals are to new funcs.
1117 					if (sureTarget == INVALIDTARGET && ((op & 0xFC000000) == 0x08000000)) {
1118 						sureTarget = GetJumpTarget(addr);
1119 					}
1120 
1121 					if (sureTarget != INVALIDTARGET && sureTarget < addr) {
1122 						end = true;
1123 					} else if (sureTarget != INVALIDTARGET) {
1124 						// Okay, we have a downward jump.  Might be an else or a tail call...
1125 						// If there's a jump back upward in spitting distance of it, it's an else.
1126 						u32 knownEnd = furthestBranch == 0 ? addr : furthestBranch;
1127 						u32 jumpback = ScanAheadForJumpback(sureTarget, currentFunction.start, knownEnd);
1128 						if (jumpback != INVALIDTARGET && jumpback > addr && jumpback > knownEnd) {
1129 							furthestBranch = jumpback;
1130 						}
1131 					}
1132 				}
1133 			}
1134 
1135 			if (end) {
1136 				currentFunction.end = addr + 4;
1137 				currentFunction.isStraightLeaf = isStraightLeaf;
1138 
1139 				// Check if we already have symbol info starting here.  If so, skip insertion.
1140 				// We used to use the symbols to find the functions, but sometimes we'd find
1141 				// wrong ones due to two modules with the same name.
1142 				u32 existingSize = g_symbolMap->GetFunctionSize(currentFunction.start);
1143 				if (existingSize != SymbolMap::INVALID_ADDRESS) {
1144 					currentFunction.foundInSymbolMap = true;
1145 
1146 					// If we run into a func with a different size, skip updating the hash map.
1147 					// This will prevent us saving incorrectly named funcs with wrong hashes.
1148 					u32 detectedSize = currentFunction.end - currentFunction.start + 4;
1149 					if (existingSize != detectedSize) {
1150 						insertSymbols = false;
1151 					}
1152 				}
1153 
1154 				new_functions.push_back(currentFunction);
1155 
1156 				furthestBranch = 0;
1157 				addr += 4;
1158 				looking = false;
1159 				end = false;
1160 				isStraightLeaf = true;
1161 				decreasedSp = false;
1162 				currentFunction.start = addr + 4;
1163 				currentFunction.foundInSymbolMap = false;
1164 			}
1165 		}
1166 
1167 		if (addr <= endAddr) {
1168 			currentFunction.end = addr + 4;
1169 			new_functions.push_back(currentFunction);
1170 		}
1171 
1172 		for (auto iter = new_functions.begin(); iter != new_functions.end(); iter++) {
1173 			iter->size = iter->end - iter->start + 4;
1174 			if (insertSymbols && !iter->foundInSymbolMap) {
1175 				char temp[256];
1176 				g_symbolMap->AddFunction(DefaultFunctionName(temp, iter->start), iter->start, iter->end - iter->start + 4);
1177 			}
1178 		}
1179 
1180 		// Concatenate the new functions to the end of the old ones.
1181 		functions.insert(functions.end(), new_functions.begin(), new_functions.end());
1182 		return insertSymbols;
1183 	}
1184 
FinalizeScan(bool insertSymbols)1185 	void FinalizeScan(bool insertSymbols) {
1186 		HashFunctions();
1187 
1188 		Path hashMapFilename = GetSysDirectory(DIRECTORY_SYSTEM) / "knownfuncs.ini";
1189 		if (g_Config.bFuncHashMap || g_Config.bFuncReplacements) {
1190 			LoadBuiltinHashMap();
1191 			if (g_Config.bFuncHashMap) {
1192 				LoadHashMap(hashMapFilename);
1193 				StoreHashMap(hashMapFilename);
1194 			}
1195 			if (insertSymbols) {
1196 				ApplyHashMap();
1197 			}
1198 			if (g_Config.bFuncReplacements) {
1199 				ReplaceFunctions();
1200 			}
1201 		}
1202 	}
1203 
RegisterFunction(u32 startAddr,u32 size,const char * name)1204 	void RegisterFunction(u32 startAddr, u32 size, const char *name) {
1205 		std::lock_guard<std::recursive_mutex> guard(functions_lock);
1206 
1207 		// Check if we have this already
1208 		for (auto iter = functions.begin(); iter != functions.end(); iter++) {
1209 			if (iter->start == startAddr) {
1210 				// Let's just add it to the hashmap.
1211 				if (iter->hasHash && size > 16) {
1212 					HashMapFunc hfun;
1213 					hfun.hash = iter->hash;
1214 					strncpy(hfun.name, name, 64);
1215 					hfun.name[63] = 0;
1216 					hfun.size = size;
1217 					hashMap.insert(hfun);
1218 					return;
1219 				} else if (!iter->hasHash || size == 0) {
1220 					ERROR_LOG(HLE, "%s: %08x %08x : match but no hash (%i) or no size", name, startAddr, size, iter->hasHash);
1221 				}
1222 			}
1223 		}
1224 
1225 		// Cheats a little.
1226 		AnalyzedFunction fun;
1227 		fun.start = startAddr;
1228 		fun.end = startAddr + size - 4;
1229 		fun.isStraightLeaf = false;  // dunno really
1230 		strncpy(fun.name, name, 64);
1231 		fun.name[63] = 0;
1232 		functions.push_back(fun);
1233 
1234 		HashFunctions();
1235 	}
1236 
ForgetFunctions(u32 startAddr,u32 endAddr)1237 	void ForgetFunctions(u32 startAddr, u32 endAddr) {
1238 		std::lock_guard<std::recursive_mutex> guard(functions_lock);
1239 
1240 		// It makes sense to forget functions as modules are unloaded but it breaks
1241 		// the easy way of saving a hashmap by unloading and loading a game. I added
1242 		// an alternative way.
1243 
1244 		// Most of the time, functions from the same module will be contiguous in functions.
1245 		FunctionsVector::iterator prevMatch = functions.end();
1246 		size_t originalSize = functions.size();
1247 		for (auto iter = functions.begin(); iter != functions.end(); ++iter) {
1248 			const bool hadPrevMatch = prevMatch != functions.end();
1249 			const bool match = iter->start >= startAddr && iter->start <= endAddr;
1250 
1251 			if (!hadPrevMatch && match) {
1252 				// Entering a range.
1253 				prevMatch = iter;
1254 			} else if (hadPrevMatch && !match) {
1255 				// Left a range.
1256 				iter = functions.erase(prevMatch, iter);
1257 				prevMatch = functions.end();
1258 			}
1259 		}
1260 		if (prevMatch != functions.end()) {
1261 			// Cool, this is the fastest way.
1262 			functions.erase(prevMatch, functions.end());
1263 		}
1264 
1265 		RestoreReplacedInstructions(startAddr, endAddr);
1266 
1267 		if (functions.empty()) {
1268 			hashToFunction.clear();
1269 		} else if (originalSize != functions.size()) {
1270 			UpdateHashToFunctionMap();
1271 		}
1272 	}
1273 
ReplaceFunctions()1274 	void ReplaceFunctions() {
1275 		std::lock_guard<std::recursive_mutex> guard(functions_lock);
1276 
1277 		for (size_t i = 0; i < functions.size(); i++) {
1278 			WriteReplaceInstructions(functions[i].start, functions[i].hash, functions[i].size);
1279 		}
1280 	}
1281 
UpdateHashMap()1282 	void UpdateHashMap() {
1283 		std::lock_guard<std::recursive_mutex> guard(functions_lock);
1284 
1285 		for (auto it = functions.begin(), end = functions.end(); it != end; ++it) {
1286 			const AnalyzedFunction &f = *it;
1287 			// Small functions aren't very interesting.
1288 			if (!f.hasHash || f.size <= 16) {
1289 				continue;
1290 			}
1291 			// Functions with default names aren't very interesting either.
1292 			const std::string name = g_symbolMap->GetLabelString(f.start);
1293 			if (IsDefaultFunction(name)) {
1294 				continue;
1295 			}
1296 
1297 			HashMapFunc mf = { "", f.hash, f.size };
1298 			strncpy(mf.name, name.c_str(), sizeof(mf.name) - 1);
1299 			hashMap.insert(mf);
1300 		}
1301 	}
1302 
LookupHash(u64 hash,u32 funcsize)1303 	const char *LookupHash(u64 hash, u32 funcsize) {
1304 		const HashMapFunc f = { "", hash, funcsize };
1305 		auto it = hashMap.find(f);
1306 		if (it != hashMap.end()) {
1307 			return it->name;
1308 		}
1309 		return 0;
1310 	}
1311 
SetHashMapFilename(const std::string & filename)1312 	void SetHashMapFilename(const std::string& filename) {
1313 		if (filename.empty())
1314 			hashmapFileName = GetSysDirectory(DIRECTORY_SYSTEM) / "knownfuncs.ini";
1315 		else
1316 			hashmapFileName = Path(filename);
1317 	}
1318 
StoreHashMap(Path filename)1319 	void StoreHashMap(Path filename) {
1320 		if (filename.empty())
1321 			filename = hashmapFileName;
1322 
1323 		UpdateHashMap();
1324 		if (hashMap.empty()) {
1325 			return;
1326 		}
1327 
1328 		FILE *file = File::OpenCFile(filename, "wt");
1329 		if (!file) {
1330 			WARN_LOG(LOADER, "Could not store hash map: %s", filename.c_str());
1331 			return;
1332 		}
1333 
1334 		for (auto it = hashMap.begin(), end = hashMap.end(); it != end; ++it) {
1335 			const HashMapFunc &mf = *it;
1336 			if (!mf.hardcoded) {
1337 				if (fprintf(file, "%016llx:%d = %s\n", mf.hash, mf.size, mf.name) <= 0) {
1338 					WARN_LOG(LOADER, "Could not store hash map: %s", filename.c_str());
1339 					break;
1340 				}
1341 			}
1342 		}
1343 		fclose(file);
1344 	}
1345 
ApplyHashMap()1346 	void ApplyHashMap() {
1347 		UpdateHashToFunctionMap();
1348 
1349 		for (auto mf = hashMap.begin(), end = hashMap.end(); mf != end; ++mf) {
1350 			auto range = hashToFunction.equal_range(mf->hash);
1351 			if (range.first == range.second) {
1352 				continue;
1353 			}
1354 
1355 			// Yay, found a function.
1356 			for (auto iter = range.first; iter != range.second; ++iter) {
1357 				AnalyzedFunction &f = *iter->second;
1358 				if (f.hash == mf->hash && f.size == mf->size) {
1359 					strncpy(f.name, mf->name, sizeof(mf->name) - 1);
1360 
1361 					std::string existingLabel = g_symbolMap->GetLabelString(f.start);
1362 					char defaultLabel[256];
1363 					// If it was renamed, keep it.  Only change the name if it's still the default.
1364 					if (existingLabel.empty() || existingLabel == DefaultFunctionName(defaultLabel, f.start)) {
1365 						g_symbolMap->SetLabelName(mf->name, f.start);
1366 					}
1367 				}
1368 			}
1369 		}
1370 	}
1371 
LoadBuiltinHashMap()1372 	void LoadBuiltinHashMap() {
1373 		HashMapFunc mf;
1374 		for (size_t i = 0; i < ARRAY_SIZE(hardcodedHashes); i++) {
1375 			mf.hash = hardcodedHashes[i].hash;
1376 			mf.size = hardcodedHashes[i].funcSize;
1377 			strncpy(mf.name, hardcodedHashes[i].funcName, sizeof(mf.name));
1378 			mf.name[sizeof(mf.name) - 1] = 0;
1379 			mf.hardcoded = true;
1380 			hashMap.insert(mf);
1381 		}
1382 	}
1383 
LoadHashMap(const Path & filename)1384 	void LoadHashMap(const Path &filename) {
1385 		FILE *file = File::OpenCFile(filename, "rt");
1386 		if (!file) {
1387 			WARN_LOG(LOADER, "Could not load hash map: %s", filename.c_str());
1388 			return;
1389 		}
1390 		hashmapFileName = filename;
1391 
1392 		while (!feof(file)) {
1393 			HashMapFunc mf = { "" };
1394 			mf.hardcoded = false;
1395 			if (fscanf(file, "%llx:%d = %63s\n", &mf.hash, &mf.size, mf.name) < 3) {
1396 				char temp[1024];
1397 				if (!fgets(temp, 1024, file)) {
1398 					WARN_LOG(LOADER, "Could not read from hash map: %s", filename.c_str());
1399 				}
1400 				continue;
1401 			}
1402 
1403 			hashMap.insert(mf);
1404 		}
1405 		fclose(file);
1406 	}
1407 
GetInputRegs(MIPSOpcode op)1408 	std::vector<MIPSGPReg> GetInputRegs(MIPSOpcode op) {
1409 		std::vector<MIPSGPReg> vec;
1410 		MIPSInfo info = MIPSGetInfo(op);
1411 		if (info & IN_RS) vec.push_back(MIPS_GET_RS(op));
1412 		if (info & IN_RT) vec.push_back(MIPS_GET_RT(op));
1413 		return vec;
1414 	}
1415 
GetOutputRegs(MIPSOpcode op)1416 	std::vector<MIPSGPReg> GetOutputRegs(MIPSOpcode op) {
1417 		std::vector<MIPSGPReg> vec;
1418 		MIPSInfo info = MIPSGetInfo(op);
1419 		if (info & OUT_RD) vec.push_back(MIPS_GET_RD(op));
1420 		if (info & OUT_RT) vec.push_back(MIPS_GET_RT(op));
1421 		if (info & OUT_RA) vec.push_back(MIPS_REG_RA);
1422 		return vec;
1423 	}
1424 
GetOpcodeInfo(DebugInterface * cpu,u32 address)1425 	MipsOpcodeInfo GetOpcodeInfo(DebugInterface* cpu, u32 address) {
1426 		MipsOpcodeInfo info;
1427 		memset(&info, 0, sizeof(info));
1428 
1429 		if (!Memory::IsValidAddress(address)) {
1430 			info.opcodeAddress = address;
1431 			return info;
1432 		}
1433 
1434 		info.cpu = cpu;
1435 		info.opcodeAddress = address;
1436 		info.encodedOpcode = Memory::Read_Instruction(address);
1437 
1438 		MIPSOpcode op = info.encodedOpcode;
1439 		MIPSInfo opInfo = MIPSGetInfo(op);
1440 		info.isLikelyBranch = (opInfo & LIKELY) != 0;
1441 
1442 		// gather relevant address for alu operations
1443 		// that's usually the value of the dest register
1444 		switch (MIPS_GET_OP(op)) {
1445 		case 0:		// special
1446 			switch (MIPS_GET_FUNC(op)) {
1447 			case 0x20:	// add
1448 			case 0x21:	// addu
1449 				info.hasRelevantAddress = true;
1450 				info.relevantAddress = cpu->GetRegValue(0,MIPS_GET_RS(op))+cpu->GetRegValue(0,MIPS_GET_RT(op));
1451 				break;
1452 			case 0x22:	// sub
1453 			case 0x23:	// subu
1454 				info.hasRelevantAddress = true;
1455 				info.relevantAddress = cpu->GetRegValue(0,MIPS_GET_RS(op))-cpu->GetRegValue(0,MIPS_GET_RT(op));
1456 				break;
1457 			}
1458 			break;
1459 		case 0x08:	// addi
1460 		case 0x09:	// adiu
1461 			info.hasRelevantAddress = true;
1462 			info.relevantAddress = cpu->GetRegValue(0,MIPS_GET_RS(op))+((s16)(op & 0xFFFF));
1463 			break;
1464 		}
1465 
1466 		//j , jal, ...
1467 		if (opInfo & IS_JUMP) {
1468 			info.isBranch = true;
1469 			if ((opInfo & OUT_RA) || (opInfo & OUT_RD)) {	// link
1470 				info.isLinkedBranch = true;
1471 			}
1472 
1473 			if (opInfo & IN_RS) { // to register
1474 				info.isBranchToRegister = true;
1475 				info.branchRegisterNum = (int)MIPS_GET_RS(op);
1476 				info.branchTarget = cpu->GetRegValue(0,info.branchRegisterNum);
1477 			} else {				// to immediate
1478 				info.branchTarget = GetJumpTarget(address);
1479 			}
1480 		}
1481 
1482 		// movn, movz
1483 		if (opInfo & IS_CONDMOVE) {
1484 			info.isConditional = true;
1485 
1486 			u32 rt = cpu->GetRegValue(0, (int)MIPS_GET_RT(op));
1487 			switch (opInfo & CONDTYPE_MASK) {
1488 			case CONDTYPE_EQ:
1489 				info.conditionMet = (rt == 0);
1490 				break;
1491 			case CONDTYPE_NE:
1492 				info.conditionMet = (rt != 0);
1493 				break;
1494 			}
1495 		}
1496 
1497 		// beq, bgtz, ...
1498 		if (opInfo & IS_CONDBRANCH) {
1499 			info.isBranch = true;
1500 			info.isConditional = true;
1501 			info.branchTarget = GetBranchTarget(address);
1502 
1503 			if (opInfo & OUT_RA) {  // link
1504 				info.isLinkedBranch = true;
1505 			}
1506 
1507 			u32 rt = cpu->GetRegValue(0, (int)MIPS_GET_RT(op));
1508 			u32 rs = cpu->GetRegValue(0, (int)MIPS_GET_RS(op));
1509 			switch (opInfo & CONDTYPE_MASK) {
1510 			case CONDTYPE_EQ:
1511 				if (opInfo & IN_FPUFLAG) {	// fpu branch
1512 					info.conditionMet = currentMIPS->fpcond == 0;
1513 				} else {
1514 					info.conditionMet = (rt == rs);
1515 					if (MIPS_GET_RT(op) == MIPS_GET_RS(op))	{	// always true
1516 						info.isConditional = false;
1517 					}
1518 				}
1519 				break;
1520 			case CONDTYPE_NE:
1521 				if (opInfo & IN_FPUFLAG) {	// fpu branch
1522 					info.conditionMet = currentMIPS->fpcond != 0;
1523 				} else {
1524 					info.conditionMet = (rt != rs);
1525 					if (MIPS_GET_RT(op) == MIPS_GET_RS(op))	{	// always true
1526 						info.isConditional = false;
1527 					}
1528 				}
1529 				break;
1530 			case CONDTYPE_LEZ:
1531 				info.conditionMet = (((s32)rs) <= 0);
1532 				break;
1533 			case CONDTYPE_GTZ:
1534 				info.conditionMet = (((s32)rs) > 0);
1535 				break;
1536 			case CONDTYPE_LTZ:
1537 				info.conditionMet = (((s32)rs) < 0);
1538 				break;
1539 			case CONDTYPE_GEZ:
1540 				info.conditionMet = (((s32)rs) >= 0);
1541 				break;
1542 			}
1543 		}
1544 
1545 		// lw, sh, ...
1546 		if (!IsSyscall(op) && (opInfo & (IN_MEM | OUT_MEM)) != 0) {
1547 			info.isDataAccess = true;
1548 			switch (opInfo & MEMTYPE_MASK) {
1549 			case MEMTYPE_BYTE:
1550 				info.dataSize = 1;
1551 				break;
1552 			case MEMTYPE_HWORD:
1553 				info.dataSize = 2;
1554 				break;
1555 			case MEMTYPE_WORD:
1556 			case MEMTYPE_FLOAT:
1557 				info.dataSize = 4;
1558 				break;
1559 
1560 			case MEMTYPE_VQUAD:
1561 				info.dataSize = 16;
1562 			}
1563 
1564 			u32 rs = cpu->GetRegValue(0, (int)MIPS_GET_RS(op));
1565 			s16 imm16 = op & 0xFFFF;
1566 			info.dataAddress = rs + imm16;
1567 
1568 			info.hasRelevantAddress = true;
1569 			info.relevantAddress = info.dataAddress;
1570 		}
1571 
1572 		return info;
1573 	}
1574 }
1575