Skip to content

Commit 3e8c47d

Browse files
committed
VM (DD2/MHWilds): Fix LocalFrameGC and cleanup code not getting found
1 parent d0617bc commit 3e8c47d

File tree

1 file changed

+66
-2
lines changed

1 file changed

+66
-2
lines changed

shared/sdk/REContext.cpp

+66-2
Original file line numberDiff line numberDiff line change
@@ -469,6 +469,7 @@ namespace sdk {
469469
static void* (*s_context_unhandled_exception_fn)(::REThreadContext*) = nullptr;
470470
static void* (*s_context_local_frame_gc_fn)(::REThreadContext*) = nullptr;
471471
static void* (*s_context_end_global_frame_fn)(::REThreadContext*) = nullptr;
472+
static void* (*s_context_full_cleanup_fn)(::REThreadContext*) = nullptr;
472473

473474
void sdk::VMContext::update_pointers() {
474475
{
@@ -489,7 +490,7 @@ namespace sdk {
489490
s_fully_updated_vm_context_pointers = true;
490491
}};
491492

492-
spdlog::info("Locating funcs");
493+
spdlog::info("[VMContext] Locating funcs");
493494

494495
// Version 1
495496
//auto ref = utility::scan(g_framework->getModule().as<HMODULE>(), "48 83 78 18 00 74 ? 48 89 D9 E8 ? ? ? ? 48 89 D9 E8 ? ? ? ?");
@@ -498,7 +499,65 @@ namespace sdk {
498499
auto ref = utility::scan(utility::get_executable(), "48 83 78 18 00 74 ? 48 ? ? E8 ? ? ? ? 48 ? ? E8 ? ? ? ? 48 ? ? E8 ? ? ? ?");
499500

500501
if (!ref) {
501-
spdlog::error("We're going to crash");
502+
spdlog::info("[VMContext] Could not locate functions we need, trying fallback for full cleanup...");
503+
504+
auto full_cleanup_ref = utility::scan(utility::get_executable(), "48 8B 41 50 48 83 78 18 00");
505+
506+
if (full_cleanup_ref) {
507+
auto fn = utility::find_function_start_with_call(*full_cleanup_ref);
508+
509+
if (!fn) {
510+
spdlog::error("[VMContext] Could not locate full cleanup function.");
511+
return;
512+
}
513+
514+
s_context_full_cleanup_fn = (decltype(s_context_full_cleanup_fn))*fn;
515+
spdlog::info("Context::FullCleanup {:x}", (uintptr_t)s_context_full_cleanup_fn);
516+
517+
// We need LocalFrameGC at least now, the other functions are not important if we have the full cleanup function.
518+
// Because we actually do call LocalFrameGC by itself when needed.
519+
// Doing this because I'm seeing tail calls which can confuse the disassembler
520+
auto basic_blocks = utility::collect_basic_blocks(*fn);
521+
522+
if (basic_blocks.empty()) {
523+
spdlog::error("[VMContext] Could not locate LocalFrameGC function (basic blocks).");
524+
return;
525+
}
526+
527+
for (const auto& bb : basic_blocks) {
528+
if (s_context_local_frame_gc_fn != nullptr) {
529+
break;
530+
}
531+
532+
for (const auto& ix : bb.instructions) {
533+
if (s_context_local_frame_gc_fn != nullptr) {
534+
break;
535+
}
536+
537+
// Hit a call
538+
if (*(uint8_t*)ix.addr == 0xE8) {
539+
const auto dst = utility::calculate_absolute(ix.addr + 1);
540+
541+
// This is always near the very start of the function entry, seen back in RE8 up to MHWilds.
542+
// However it's such a common set of instructions which is why we narrow it to this function.
543+
if (utility::scan_disasm(dst, 20, "48 8B 41 50")) {
544+
s_context_local_frame_gc_fn = (decltype(s_context_local_frame_gc_fn))dst;
545+
spdlog::info("[VMContext] Context::LocalFrameGC {:x}", (uintptr_t)s_context_local_frame_gc_fn);
546+
break;
547+
}
548+
}
549+
}
550+
}
551+
552+
if (s_context_local_frame_gc_fn == nullptr) {
553+
spdlog::error("[VMContext] Could not locate LocalFrameGC function.");
554+
return;
555+
}
556+
557+
return;
558+
}
559+
560+
spdlog::error("[VMContext] We're going to crash, could not locate functions we need.");
502561
return;
503562
}
504563

@@ -535,6 +594,11 @@ namespace sdk {
535594

536595
spdlog::error("{}", reference_count);
537596
if (count_delta >= 1) {
597+
if (s_context_full_cleanup_fn != nullptr) {
598+
s_context_full_cleanup_fn(this);
599+
return;
600+
}
601+
538602
--reference_count;
539603

540604
// Perform object cleanup that was missed because an exception occurred.

0 commit comments

Comments
 (0)