diff --git a/Core/Debugger/Breakpoints.cpp b/Core/Debugger/Breakpoints.cpp index 366e1fbd2f..8231894054 100644 --- a/Core/Debugger/Breakpoints.cpp +++ b/Core/Debugger/Breakpoints.cpp @@ -150,6 +150,18 @@ bool CBreakPoints::IsTempBreakPoint(u32 addr) return bp != INVALID_BREAKPOINT; } +bool CBreakPoints::RangeContainsBreakPoint(u32 addr, u32 size) +{ + const u32 end = addr + size; + for (const auto &bp : breakPoints_) + { + if (bp.addr >= addr && bp.addr < end) + return true; + } + + return false; +} + void CBreakPoints::AddBreakPoint(u32 addr, bool temp) { size_t bp = FindBreakpoint(addr, true, temp); diff --git a/Core/Debugger/Breakpoints.h b/Core/Debugger/Breakpoints.h index e371ab4475..ab501b9e23 100644 --- a/Core/Debugger/Breakpoints.h +++ b/Core/Debugger/Breakpoints.h @@ -115,6 +115,7 @@ public: static bool IsAddressBreakPoint(u32 addr); static bool IsAddressBreakPoint(u32 addr, bool* enabled); static bool IsTempBreakPoint(u32 addr); + static bool RangeContainsBreakPoint(u32 addr, u32 size); static void AddBreakPoint(u32 addr, bool temp = false); static void RemoveBreakPoint(u32 addr); static void ChangeBreakPoint(u32 addr, bool enable); diff --git a/Core/MIPS/MIPSAnalyst.cpp b/Core/MIPS/MIPSAnalyst.cpp index 236f527f04..224c7d7453 100644 --- a/Core/MIPS/MIPSAnalyst.cpp +++ b/Core/MIPS/MIPSAnalyst.cpp @@ -83,7 +83,7 @@ struct HardHashTableEntry { static const HardHashTableEntry hardcodedHashes[] = { { 0x006b570008068310, 184, "strtok_r", }, { 0x019ba2099fb88f3c, 48, "vector_normalize_t", }, - { 0x0266f96d740c7e03, 912, "memcpy", }, // Final Fantasy 4 + { 0x0266f96d740c7e03, 912, "memcpy", }, // Final Fantasy 4 (US) { 0x02bd2859045d2383, 240, "bcmp", }, { 0x030507c9a1f0fc85, 92, "matrix_rot_x", }, { 0x0483fceefa4557ff, 1360, "__udivdi3", }, @@ -93,7 +93,7 @@ static const HardHashTableEntry hardcodedHashes[] = { { 0x06628f6052cda3c1, 1776, "toheart2_download_frame", }, // To Heart 2 Portable { 0x06b243c926fa6ab5, 24, "vf2in_q", }, { 0x06e2826e02056114, 56, "wcslen", }, - { 0x073cf0b61d3b875a, 416, "hexyzforce_monoclome_thread", }, // Hexyz Force + { 0x073cf0b61d3b875a, 416, "hexyzforce_monoclome_thread", }, // Hexyz Force (US) { 0x075fa9b234b41e9b, 32, "fmodf", }, { 0x0a051019bdd786c3, 184, "strcasecmp", }, { 0x0a46dc426054bb9d, 24, "vector_add_t", }, @@ -135,6 +135,7 @@ static const HardHashTableEntry hardcodedHashes[] = { { 0x1daf6eaf0442391d, 1024, "utawarerumono_download_frame", }, // Utawarerumono portable { 0x1e1525e3bc2f6703, 676, "rint", }, { 0x1ec055f28bb9f4d1, 88, "gu_update_stall", }, + { 0x1ef9cfe6afd3c035, 180, "memset", }, // Kingdom Hearts (US) { 0x1f53eac122f96b37, 224, "cosf", }, { 0x2097a8b75c8fe651, 436, "atan2", }, { 0x21411b3c860822c0, 36, "matrix_scale_q_t", }, @@ -159,25 +160,26 @@ static const HardHashTableEntry hardcodedHashes[] = { { 0x2f718936b371fc44, 40, "vcos_s", }, { 0x3024e961d1811dea, 396, "fmod", }, { 0x30c9c4f420573eb6, 540, "expf", }, - { 0x317afeb882ff324a, 212, "memcpy", }, // Mimana + { 0x317afeb882ff324a, 212, "memcpy", }, // Mimana (US) { 0x31ea2e192f5095a1, 52, "vector_add_t", }, { 0x31f523ef18898e0e, 420, "logf", }, - { 0x32215b1d2196377f, 844, "godseaterburst_blit_texture", }, // Gods Eater Burst + { 0x32215b1d2196377f, 844, "godseaterburst_blit_texture", }, // Gods Eater Burst (US) { 0x32806967fe81568b, 40, "vector_sub_t_2", }, { 0x32ceb9a7f72b9385, 440, "_strtoul_r", }, { 0x32e6bc7c151491ed, 68, "memchr", }, { 0x335df69db1073a8d, 96, "wcscpy", }, + { 0x33dc6b144cb302c1, 304, "memmove", }, // Kingdom Hearts (US) { 0x35d3527ff8c22ff2, 56, "matrix_scale_q", }, { 0x368f6cf979709a31, 744, "memmove", }, // Jui Dr. Touma Jotarou { 0x373ce518eee5a2d2, 20, "matrix300_store_q", }, - { 0x3840f5766fada4b1, 592, "dissidia_recordframe_avi", }, // Dissidia, Dissidia 012 + { 0x3840f5766fada4b1, 592, "dissidia_recordframe_avi", }, // Dissidia (US), Dissidia 012 (US) { 0x388043e96b0e11fd, 144, "dl_write_material_2", }, { 0x38f19bc3be215acc, 388, "log10f", }, { 0x393047f06eceaba1, 96, "strcspn", }, { 0x39a651942a0b3861, 204, "tan", }, { 0x3a3bc2b20a55bf02, 68, "memchr", }, { 0x3ab08b5659de1746, 40, "vsin_s", }, - { 0x3c421a9265f37ebc, 700, "memmove", }, // Final Fantasy 4 + { 0x3c421a9265f37ebc, 700, "memmove", }, // Final Fantasy 4 (US) { 0x3cbc2d50a3db59e9, 100, "strncmp", }, { 0x3ce1806699a91d9d, 148, "dl_write_light", }, { 0x3d5e914011c181d4, 444, "scalbnf", }, @@ -230,6 +232,7 @@ static const HardHashTableEntry hardcodedHashes[] = { { 0x5b103d973fd1dd94, 92, "matrix_rot_y", }, { 0x5b9d7e9d4c905694, 196, "_calloc_r", }, { 0x5bf7a77b028e9f66, 324, "sqrtf", }, + { 0x5c0b3edc0e48852c, 148, "memmove", }, // Dissidia 1 (US) { 0x5e898df42c4af6b8, 76, "wcsncmp", }, { 0x5f473780835e3458, 52, "vclamp_q", }, { 0x5fc58ed2c4d48b79, 40, "vtfm_q_transp", }, @@ -293,7 +296,7 @@ static const HardHashTableEntry hardcodedHashes[] = { { 0x8a00e7207e7dbc81, 232, "_exit", }, { 0x8a1f9daadecbaf7f, 104, "vmmul_q_transp", }, { 0x8a610f34078ce360, 32, "vector_copy_q_t", }, - { 0x8c3fd997a544d0b1, 268, "memcpy", }, // Valkyrie Profile + { 0x8c3fd997a544d0b1, 268, "memcpy", }, // Valkyrie Profile (US) { 0x8da0164e69e9b531, 1040, "grisaianokajitsu_download_frame", }, // Grisaia no Kajitsu La Fruit de la Grisaia { 0x8df2928848857e97, 164, "strcat", }, { 0x8e48cabd529ca6b5, 52, "vector_multiply_t", }, @@ -315,8 +318,9 @@ static const HardHashTableEntry hardcodedHashes[] = { { 0x9a06b9d5c16c4c20, 76, "dl_write_clut_ptrload", }, { 0x9b88b739267d189e, 88, "strrchr", }, { 0x9ce53975bb88c0e7, 96, "strncpy", }, - { 0x9e2941c4a5c5e847, 792, "memcpy", }, // LittleBigPlanet - { 0x9e6ce11f9d49f954, 292, "memcpy", }, // Jeanne d'Arc + { 0x9d4f5f56b52f07f2, 808, "memmove", }, // Jeanne d'Arc (US) + { 0x9e2941c4a5c5e847, 792, "memcpy", }, // LittleBigPlanet (US) + { 0x9e6ce11f9d49f954, 292, "memcpy", }, // Jeanne d'Arc (US) { 0x9f269daa6f0da803, 128, "dl_write_scissor_region", }, { 0x9f7919eeb43982b0, 208, "__fixdfsi", }, { 0xa1ca0640f11182e7, 72, "strcspn", }, @@ -324,6 +328,7 @@ static const HardHashTableEntry hardcodedHashes[] = { { 0xa2bcef60a550a3ef, 92, "matrix_rot_z", }, { 0xa373f55c65cd757a, 312, "memcpy_swizzled" }, // God Eater Burst Demo { 0xa41989db0f9bf97e, 1304, "pow", }, + { 0xa44f6227fdbc12b1, 132, "memcmp", }, // Popolocrois (US) { 0xa46cc6ea720d5775, 44, "dl_write_cull", }, { 0xa54967288afe8f26, 600, "ceil", }, { 0xa5ddbbc688e89a4d, 56, "isinf", }, @@ -358,7 +363,7 @@ static const HardHashTableEntry hardcodedHashes[] = { { 0xb6a04277fb1e1a1a, 104, "vmmul_q_transp", }, { 0xb726917d688ac95b, 268, "kagaku_no_ensemble_download_frame", }, // Toaru Majutsu to Kagaku no Ensemble { 0xb7448c5ffdd3b0fc, 356, "atan2f", }, - { 0xb7d88567dc22aab1, 820, "memcpy", }, // Trails in the Sky + { 0xb7d88567dc22aab1, 820, "memcpy", }, // Trails in the Sky (US) { 0xb877d3c37a7aaa5d, 60, "vmmul_q_2", }, { 0xb89aa73b6f94ba95, 52, "vclamp_t", }, { 0xb8bd1f0e02e9ad87, 156, "dl_write_light_dir", }, @@ -372,6 +377,7 @@ static const HardHashTableEntry hardcodedHashes[] = { { 0xbf5d02ccb8514881, 108, "strcmp", }, { 0xbf791954ebef4afb, 396, "expf", }, { 0xbfa8c16038b7753d, 868, "sakurasou_download_frame", }, // Sakurasou No Pet Na Kanojo + { 0xbfe07e305abc4cd1, 808, "memmove" }, // Final Fantasy Tactics (US) { 0xc062f2545ef5dc39, 1076, "kirameki_school_life_download_frame", },// Kirameki School Life SP,and Boku wa Tomodati ga Sukunai { 0xc0feb88cc04a1dc7, 48, "vector_negate_t", }, { 0xc1220040b0599a75, 472, "soranokiseki_sc_download_frame", }, // Sora no kiseki SC @@ -383,7 +389,7 @@ static const HardHashTableEntry hardcodedHashes[] = { { 0xc51519f5dab342d4, 224, "cosf", }, { 0xc52c14b9af8c3008, 76, "memcmp", }, { 0xc54eae62622f1e11, 164, "dl_write_bone_matrix_2", }, - { 0xc6b29de7d3245198, 656, "starocean_write_stencil" }, // Star Ocean 1 + { 0xc6b29de7d3245198, 656, "starocean_write_stencil" }, // Star Ocean 1 (US) { 0xc96e3a087ebf49a9, 100, "dl_write_light_color", }, { 0xca7cb2c0b9410618, 680, "kudwafter_download_frame", }, // Kud Wafter { 0xcb7a2edd603ecfef, 48, "vtfm_p", }, @@ -394,6 +400,7 @@ static const HardHashTableEntry hardcodedHashes[] = { //{ 0xceb5372d0003d951, 52, "dl_write_stenciltest", }, { 0xcee11483b550ce8f, 24, "vocp_q", }, { 0xcfecf208769ed5fd, 272, "cosf", }, + { 0xd019b067b58cf6c3, 700, "memmove", }, // Star Ocean 1 (US) { 0xd12a3a91e0040229, 524, "dl_write_enable_disable", }, { 0xd141d1efbfe13ca3, 968, "kirameki_school_life_download_frame", }, // Kirameki School Life SP,and Boku wa Tomodati ga Sukunai { 0xd1db467a23ebe00d, 724, "rewrite_download_frame", }, // Rewrite Portable @@ -414,7 +421,7 @@ static const HardHashTableEntry hardcodedHashes[] = { { 0xe0214719d8a0aa4e, 104, "strstr", }, { 0xe029f0699ca3a886, 76, "matrix300_transform_by", }, { 0xe086d5c9ce89148f, 212, "bokunonatsuyasumi4_download_frame", }, // Boku no Natsuyasumi 2 and 4, - { 0xe093c2b0194d52b3, 820, "ff1_battle_effect", }, // Final Fantasy 1 + { 0xe093c2b0194d52b3, 820, "ff1_battle_effect", }, // Final Fantasy 1 (US) { 0xe1107cf3892724a0, 460, "_memalign_r", }, { 0xe1724e6e29209d97, 24, "vector_length_t_2", }, { 0xe1a5d939cc308195, 68, "wcscmp", }, @@ -428,7 +435,7 @@ static const HardHashTableEntry hardcodedHashes[] = { { 0xe83a7a9d80a21c11, 4448, "_strtod_r", }, { 0xe894bda909a8a8f9, 1064, "expensive_wipeout_pulse", }, { 0xe8ad7719be44e7c8, 276, "strchr", }, - { 0xeabb9c1b4f83d2b4, 52, "memset", }, // Crisis Core + { 0xeabb9c1b4f83d2b4, 52, "memset", }, // Crisis Core (US) { 0xeb0f7bf63d52ece9, 88, "strncat", }, { 0xeb8c0834d8bbc28c, 416, "fmodf", }, { 0xed8918f378e9a563, 628, "sd_gundam_g_generation_download_frame", }, // SD Gundam G Generation Overworld diff --git a/Core/MIPS/MIPSInt.cpp b/Core/MIPS/MIPSInt.cpp index f1c16f08dc..a3012cad1f 100644 --- a/Core/MIPS/MIPSInt.cpp +++ b/Core/MIPS/MIPSInt.cpp @@ -1041,7 +1041,7 @@ namespace MIPSInt // It's a replacement func! int index = op.encoding & 0xFFFFFF; const ReplacementTableEntry *entry = GetReplacementFunc(index); - if (entry && entry->replaceFunc) { + if (entry && entry->replaceFunc && (entry->flags & REPFLAG_DISABLED) == 0) { entry->replaceFunc(); if (entry->flags & (REPFLAG_HOOKENTER | REPFLAG_HOOKEXIT)) { @@ -1051,7 +1051,11 @@ namespace MIPSInt PC = currentMIPS->r[MIPS_REG_RA]; } } else { - ERROR_LOG(CPU, "Bad replacement function index %i", index); + if (!entry || !entry->replaceFunc) { + ERROR_LOG(CPU, "Bad replacement function index %i", index); + } + // Interpret the original instruction under it. + MIPSInterpret(Memory::Read_Instruction(PC, true)); } } diff --git a/Core/MIPS/x86/Jit.cpp b/Core/MIPS/x86/Jit.cpp index 53b71334b5..6fd834f6b9 100644 --- a/Core/MIPS/x86/Jit.cpp +++ b/Core/MIPS/x86/Jit.cpp @@ -535,6 +535,19 @@ bool Jit::ReplaceJalTo(u32 dest) { if (!MIPS_IS_REPLACEMENT(op.encoding)) return false; + // Make sure we don't replace if there are any breakpoints inside. + u32 funcSize = symbolMap.GetFunctionSize(dest); + if (funcSize == SymbolMap::INVALID_ADDRESS) { + if (CBreakPoints::IsAddressBreakPoint(dest)) { + return false; + } + funcSize = (u32)sizeof(u32); + } else { + if (CBreakPoints::RangeContainsBreakPoint(dest, funcSize)) { + return false; + } + } + int index = op.encoding & MIPS_EMUHACK_VALUE_MASK; const ReplacementTableEntry *entry = GetReplacementFunc(index); if (!entry) { @@ -572,7 +585,7 @@ bool Jit::ReplaceJalTo(u32 dest) { // No writing exits, keep going! // Add a trigger so that if the inlined code changes, we invalidate this block. - blocks.ProxyBlock(js.blockStart, dest, symbolMap.GetFunctionSize(dest) / sizeof(u32), GetCodePtr()); + blocks.ProxyBlock(js.blockStart, dest, funcSize / sizeof(u32), GetCodePtr()); return true; } @@ -591,7 +604,18 @@ void Jit::Comp_ReplacementFunc(MIPSOpcode op) return; } - if (entry->flags & REPFLAG_DISABLED) { + u32 funcSize = symbolMap.GetFunctionSize(js.compilerPC); + bool disabled = (entry->flags & REPFLAG_DISABLED) != 0; + if (!disabled && funcSize != SymbolMap::INVALID_ADDRESS && funcSize > sizeof(u32)) { + // We don't need to disable hooks, the code will still run. + if ((entry->flags & (REPFLAG_HOOKENTER | REPFLAG_HOOKEXIT)) == 0) { + // Any breakpoint at the func entry was already tripped, so we can still run the replacement. + // That's a common case - just to see how often the replacement hits. + disabled = CBreakPoints::RangeContainsBreakPoint(js.compilerPC + sizeof(u32), funcSize - sizeof(u32)); + } + } + + if (disabled) { MIPSCompileOp(Memory::Read_Instruction(js.compilerPC, true)); } else if (entry->jitReplaceFunc) { MIPSReplaceFunc repl = entry->jitReplaceFunc; diff --git a/assets/knownfuncs.ini b/assets/knownfuncs.ini index 4dd2e379e9..25b03d6cdb 100644 --- a/assets/knownfuncs.ini +++ b/assets/knownfuncs.ini @@ -45,6 +45,7 @@ 1d03fa48334ca966:556 = _strtol_r 1e1525e3bc2f6703:676 = rint 1ec055f28bb9f4d1:88 = gu_update_stall +1ef9cfe6afd3c035:180 = memset 1f53eac122f96b37:224 = cosf 2097a8b75c8fe651:436 = atan2 21411b3c860822c0:36 = matrix_scale_q_t @@ -74,6 +75,7 @@ 32ceb9a7f72b9385:440 = _strtoul_r 32e6bc7c151491ed:68 = memchr 335df69db1073a8d:96 = wcscpy +33dc6b144cb302c1:304 = memmove 35d3527ff8c22ff2:56 = matrix_scale_q 373ce518eee5a2d2:20 = matrix300_store_q 388043e96b0e11fd:144 = dl_write_material_2 @@ -100,6 +102,7 @@ 497248c9d12f44fd:68 = strcpy 4a70207212a4c497:24 = strlen 4b16a5c602c74c6c:24 = vsub_t +4bb677dace6ca526:184 = memset 4c4bdedcc13ac77c:624 = dl_write_matrix_5 4c91c556d1aa896b:104 = dl_write_material_3 4cf38c368078181e:616 = dl_write_matrix @@ -132,6 +135,7 @@ 5b103d973fd1dd94:92 = matrix_rot_y 5b9d7e9d4c905694:196 = _calloc_r 5bf7a77b028e9f66:324 = sqrtf +5c0b3edc0e48852c:148 = memmove 5e898df42c4af6b8:76 = wcsncmp 5f473780835e3458:52 = vclamp_q 5fc58ed2c4d48b79:40 = vtfm_q_transp @@ -207,6 +211,7 @@ 9a06b9d5c16c4c20:76 = dl_write_clut_ptrload 9b88b739267d189e:88 = strrchr 9ce53975bb88c0e7:96 = strncpy +9d4f5f56b52f07f2:808 = memmove 9e2941c4a5c5e847:792 = memcpy 9e6ce11f9d49f954:292 = memcpy 9f269daa6f0da803:128 = dl_write_scissor_region @@ -215,6 +220,7 @@ a1ca0640f11182e7:72 = strcspn a243486be51ce224:272 = cosf a2bcef60a550a3ef:92 = matrix_rot_z a41989db0f9bf97e:1304 = pow +a44f6227fdbc12b1:132 = memcmp a46cc6ea720d5775:44 = dl_write_cull a54967288afe8f26:600 = ceil a5ddbbc688e89a4d:56 = isinf @@ -256,6 +262,7 @@ bdf54d66079afb96:200 = dl_write_bone_matrix_3 be773f78afd1a70f:128 = rand bf5d02ccb8514881:108 = strcmp bf791954ebef4afb:396 = expf +bfe07e305abc4cd1:808 = memmove c0feb88cc04a1dc7:48 = vector_negate_t c1f34599d0b9146b:116 = __subdf3 c319f0d107dd2f45:888 = __muldf3 @@ -272,6 +279,7 @@ ce4d18a75b98859f:40 = vector_add_t_2 ceb5372d0003d951:52 = dl_write_stenciltest cee11483b550ce8f:24 = vocp_q cfecf208769ed5fd:272 = cosf +d019b067b58cf6c3:700 = memmove d12a3a91e0040229:524 = dl_write_enable_disable d1faacfc711d61e8:68 = __negdf2 d207b0650a41dd9c:28 = vmin_q