@@ -469,6 +469,7 @@ namespace sdk {
469
469
static void * (*s_context_unhandled_exception_fn)(::REThreadContext*) = nullptr ;
470
470
static void * (*s_context_local_frame_gc_fn)(::REThreadContext*) = nullptr ;
471
471
static void * (*s_context_end_global_frame_fn)(::REThreadContext*) = nullptr ;
472
+ static void * (*s_context_full_cleanup_fn)(::REThreadContext*) = nullptr ;
472
473
473
474
void sdk::VMContext::update_pointers () {
474
475
{
@@ -489,7 +490,7 @@ namespace sdk {
489
490
s_fully_updated_vm_context_pointers = true ;
490
491
}};
491
492
492
- spdlog::info (" Locating funcs" );
493
+ spdlog::info (" [VMContext] Locating funcs" );
493
494
494
495
// Version 1
495
496
// 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 {
498
499
auto ref = utility::scan (utility::get_executable (), " 48 83 78 18 00 74 ? 48 ? ? E8 ? ? ? ? 48 ? ? E8 ? ? ? ? 48 ? ? E8 ? ? ? ?" );
499
500
500
501
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." );
502
561
return ;
503
562
}
504
563
@@ -535,6 +594,11 @@ namespace sdk {
535
594
536
595
spdlog::error (" {}" , reference_count);
537
596
if (count_delta >= 1 ) {
597
+ if (s_context_full_cleanup_fn != nullptr ) {
598
+ s_context_full_cleanup_fn (this );
599
+ return ;
600
+ }
601
+
538
602
--reference_count;
539
603
540
604
// Perform object cleanup that was missed because an exception occurred.
0 commit comments