Compare commits

...

10 Commits

36 changed files with 942 additions and 96 deletions

View File

@ -0,0 +1,118 @@
// AUTO-GENERATED FILE, MOVE TO 'gh_fix' FOLDER PREVENT OVERWRITING!!!!!
#include <r3/binders/auto.h>
#include <gh_global.h>
extern "C" {
undefined FUN_00470350(void); // 00470350 // FUN_00470350 // cdecl
undefined r3_load_textures_2(void); // 00471760 // r3_load_textures_2 // cdecl
void level_displayFn(byte param); // 00446fc0 // level_displayFn // cdecl
void r3_noop(void * p_cTxt1, void * p_cTxt2); // 00401100 // r3_noop // stdcall
undefined r3_closeConcatTextureFile(void); // 004711d0 // r3_closeConcatTextureFile // cdecl
undefined FUN_00470db0(void); // 00470db0 // FUN_00470db0 // cdecl
undefined FUN_00503710(void); // 00503710 // FUN_00503710 // cdecl
undefined FUN_00443120(undefined4 param_1); // 00443120 // FUN_00443120 // cdecl
undefined FUN_00442c50(void); // 00442c50 // FUN_00442c50 // cdecl
undefined FUN_00470410(void); // 00470410 // FUN_00470410 // cdecl
undefined FUN_00472150(void); // 00472150 // FUN_00472150 // cdecl
undefined FUN_00445460(void); // 00445460 // FUN_00445460 // cdecl
undefined FUN_00442f70(undefined4 param_1); // 00442f70 // FUN_00442f70 // cdecl
undefined FUN_00445440(void); // 00445440 // FUN_00445440 // cdecl
undefined SND_fn_vResumeSound(void); // 0040a1e0 // SND_fn_vResumeSound // cdecl
undefined IPT_fn_vActivateAllEntryElements(void); // 00505490 // IPT_fn_vActivateAllEntryElements // cdecl
undefined r3_windowLockCursor(void); // 00401320 // r3_windowLockCursor // cdecl
undefined FUN_00402470(undefined4 param_1); // 00402470 // FUN_00402470 // cdecl
undefined gfx_init2(void); // 00470be0 // gfx_init2 // cdecl
undefined FUN_004725a0(void); // 004725a0 // FUN_004725a0 // cdecl
undefined FUN_0051a900(short hGLDDevice); // 0051a900 // FUN_0051a900 // cdecl
undefined FUN_005038e0(void); // 005038e0 // FUN_005038e0 // cdecl
undefined FUN_004fb300(void); // 004fb300 // FUN_004fb300 // cdecl
undefined FUN_004fa650(void); // 004fa650 // FUN_004fa650 // cdecl
undefined r3_processInput1(void); // 00446f10 // r3_processInput1 // cdecl
undefined FUN_0047bae0(void); // 0047bae0 // FUN_0047bae0 // cdecl
undefined FUN_0051a7a0(short hGLDDevice, undefined4 param_2); // 0051a7a0 // FUN_0051a7a0 // cdecl
// 00401490
/* WARNING: Inlined function: r3_get_engine_mode */
undefined4 __stdcall r3_restore(undefined4 param_1)
{
HWND hWnd;
int iVar1;
DWORD DVar2;
hWnd = g_gameHWND;
if (g_engineRunning != 0) {
return 0;
}
if (g_gameHWND == (HWND)0x0) {
return 0;
}
SetWindowTextA(g_gameHWND,g_windowTitleRestoring);
UpdateWindow(hWnd);
SetForegroundWindow(hWnd);
if (p_fn_vDisplayAll == r3_noop) {
/* Set window callback? */
p_fn_vDisplayAll = level_displayFn;
}
if ((code *)PTR_r3_processInput1_005bdb1c == r3_noop) {
PTR_r3_processInput1_005bdb1c = r3_processInput1;
IPT_fn_vActivateAllEntryElements();
}
iVar1 = FUN_0047bae0();
if (iVar1 == 0) goto LAB_004015f7;
DVar2 = WaitForSingleObject(g_drawSemaphore,500);
if (DVar2 == 0x102) {
return 0;
}
FUN_004725a0();
if (g_currentBinkMovie + Field<32, 4>() == 0) {
FUN_00470410();
}
FUN_0051a900(g_stEngineStructure.hGLDDevice);
FUN_005038e0();
FUN_00503710();
FUN_004fb300();
FUN_00472150();
FUN_00470db0();
FUN_00445440();
gfx_init2();
FUN_00445460();
FUN_00402470(hWnd);
FUN_0051a7a0(g_stEngineStructure.hGLDDevice,0);
if (g_currentBinkMovie + Field<32, 4>() == 0) {
FUN_00442f70(0);
FUN_00443120(0);
FUN_00442f70(1);
FUN_00443120(1);
FUN_00470350();
if (g_currentBinkMovie + Field<32, 4>() != 0) goto LAB_004015bc;
}
else {
LAB_004015bc:
FUN_00445440();
}
r3_load_textures_2();
if (((g_stEngineStructure.eEngineMode == E_EM_ModeStartingProgram) ||
(g_stEngineStructure.eEngineMode == E_EM_ModeEnterGame)) ||
(g_stEngineStructure.eEngineMode == E_EM_ModeEnterLevel)) {
FUN_004fa650();
}
r3_closeConcatTextureFile();
ReleaseSemaphore(g_drawSemaphore,1,(LPLONG)0x0);
LAB_004015f7:
g_stEngineStructure + Field<91, 1>() = 0;
SetWindowTextA(hWnd,g_windowTitle);
UpdateWindow(hWnd);
SetForegroundWindow(hWnd);
FUN_00442c50();
SND_fn_vResumeSound();
r3_windowLockCursor();
/* Keep suspended
*/
return 0;
}
}

View File

@ -0,0 +1,39 @@
// AUTO-GENERATED FILE, MOVE TO 'gh_fix' FOLDER PREVENT OVERWRITING!!!!!
#include <r3/binders/auto.h>
#include <gh_global.h>
extern "C" {
HWND getHWND(void); // 00401300 // getHWND // stdcall // Params: | Types: | Return: typedef HWND HWND__ *
// 00401320 // r3_windowLockCursor(cdecl)
// Parameters: | Types: | Return: undefined
void unknown r3_windowLockCursor(void)
{
HWND pHVar1;
tagRECT *ptVar2;
RECT RStack_30;
tagRECT local_20;
tagRECT tStack_10;
if (g_initVar0 != '\0') {
ptVar2 = &local_20;
pHVar1 = getHWND();
GetWindowRect(pHVar1,ptVar2);
ptVar2 = &tStack_10;
pHVar1 = getHWND();
GetClientRect(pHVar1,ptVar2);
RStack_30.left = local_20.left + 5;
RStack_30.top = local_20.bottom - tStack_10.bottom;
RStack_30.right = tStack_10.right + -5 + RStack_30.left;
RStack_30.bottom = RStack_30.top + -5 + tStack_10.bottom;
ClipCursor(&RStack_30);
ShowCursor(0);
}
return;
}
}

View File

@ -4,11 +4,11 @@
#include <gh_global.h>
extern "C" {
undefined r3_windowUnlockCursor(void); // 004013a0 // r3_windowUnlockCursor
undefined FUN_00401320(void); // 00401320 // FUN_00401320
undefined FUN_00401320(void); // 00401320 // FUN_00401320 // cdecl
undefined r3_windowUnlockCursor(void); // 004013a0 // r3_windowUnlockCursor // cdecl
// 004025e0
long CALLBACK r3_windowProc(HWND hwnd,UINT uMsg,WPARAM wParam,LPARAM lParam)
long __stdcall r3_windowProc(HWND hwnd,UINT uMsg,WPARAM wParam,LPARAM lParam)
{
long lVar1;

View File

@ -0,0 +1,23 @@
// AUTO-GENERATED FILE, MOVE TO 'gh_fix' FOLDER PREVENT OVERWRITING!!!!!
#include <r3/binders/auto.h>
#include <gh_global.h>
extern "C" {
// 004013a0
void r3_windowUnlockCursor(void)
{
HCURSOR hCursor;
/* IDC_ARROW */
hCursor = LoadCursorA((HINSTANCE)0x0,(LPCSTR)0x7f00);
SetCursor(hCursor);
ClipCursor((RECT *)0x0);
ShowCursor(1);
return;
}
}

View File

@ -1,7 +1,7 @@
// AUTO-GENERATED FILE
#include <r3/binders/global.h>
undefined4& crt_unhandled_exception_handler= (undefined4&) GH_MEM(0x00404a58);
undefined4& DAT_00597ca0= (undefined4&) GH_MEM(0x00597ca0);
dword& DWORD_00597ca0= (dword&) GH_MEM(0x00597ca0);
char(&s__s_not_initialized__005b63e0)[20] = reinterpret_cast<char(&)[20]>(GH_MEM(0x005b63e0));
char(&s_Please_run_the__s_setup__005b63f4)[28] = reinterpret_cast<char(&)[28]>(GH_MEM(0x005b63f4));
char(&s_dashCC)[4] = reinterpret_cast<char(&)[4]>(GH_MEM(0x005b6410));
@ -64,6 +64,8 @@ undefined1& g_errModDInput= (undefined1&) GH_MEM(0x005bd29c);
undefined4& DAT_005bd454= (undefined4&) GH_MEM(0x005bd454);
const char* s__jc_z_d__s_005bd460 = "\\jc\\z%d:%s"; // 005bd460
undefined1& g_errModMmg= (undefined1&) GH_MEM(0x005bd58c);
pointer& PTR_r3_processInput1_005bdb1c= (pointer&) GH_MEM(0x005bdb1c);
level_displayFn *& p_fn_vDisplayAll= (level_displayFn *&) GH_MEM(0x005bdb24);
const char* s_R3_DVD_005bdfd8 = "R3_DVD"; // 005bdfd8
const char* s_R3_DVD_005be0ec = "R3_DVD"; // 005be0ec
const char* s__s_DVD_missing_005be0f4 = "%s DVD missing "; // 005be0f4
@ -83,12 +85,12 @@ const char* lpDefault_005be370 = "1"; // 005be370
const char* s_SoundOnHD_005be374 = "SoundOnHD"; // 005be374
const char* lpDefault_005be380 = "0"; // 005be380
const char* s_TexturesMem_005be384 = "TexturesMem"; // 005be384
pointer& s_Agp= (pointer&) GH_MEM(0x005be390);
const char* s_Agp = "Agp"; // 005be390
const char* s_Outline_005be394 = "Outline"; // 005be394
const char* s_StaticShadows_005be39c = "StaticShadows"; // 005be39c
const char* s_DynamicShadows_005be3ac = "DynamicShadows"; // 005be3ac
const char* s_TriLinear_005be3bc = "TriLinear"; // 005be3bc
pointer& s_Tnl= (pointer&) GH_MEM(0x005be3c8);
const char* s_Tnl = "TnL"; // 005be3c8
const char* s_TexturesCompressed_005be3cc = "TexturesCompressed"; // 005be3cc
const char* s_GLI_Mode_005be3e0 = "GLI_Mode"; // 005be3e0
const char* g_default_display_mode = "1 - 640 x 480 x 16"; // 005be3ec
@ -102,6 +104,7 @@ const char* s_r3_program_files = "\\program files\\Ubi Soft\\Rayman3"; // 005be5
const char* s_driveLetterTemplate = "A:\\"; // 005be568
undefined4& g_config_camera_hor_axis= (undefined4&) GH_MEM(0x005c67c8);
undefined4& g_config_camera_ver_axis= (undefined4&) GH_MEM(0x005c67cc);
undefined1& g_initVar0= (undefined1&) GH_MEM(0x005cf960);
HWND& g_gameHWND1= (HWND&) GH_MEM(0x005cf964);
long& lpDefault_005cf96c= (long&) GH_MEM(0x005cf96c);
dword& DWORD_005cf974= (dword&) GH_MEM(0x005cf974);
@ -112,8 +115,8 @@ char *& PTR_005cf9b4= (char *&) GH_MEM(0x005cf9b4);
GameStructure& g_currentBinkMovie= (GameStructure&) GH_MEM(0x005d2660);
char(&s_volumeNameBuffer)[128] = reinterpret_cast<char(&)[128]>(GH_MEM(0x005d27b0));
r3_main_data& r3_main_data_005d28b6= (r3_main_data&) GH_MEM(0x005d28b6);
undefined4& g_soundOnHD= (undefined4&) GH_MEM(0x005d29bc);
undefined4& g_complete= (undefined4&) GH_MEM(0x005d29c0);
dword& g_soundOnHD= (dword&) GH_MEM(0x005d29bc);
dword& g_complete= (dword&) GH_MEM(0x005d29c0);
int& g_windowInitialized= (int&) GH_MEM(0x0077d0a4);
int& g_runMaximized= (int&) GH_MEM(0x0077d0a8);
undefined4& g_engineShouldRun= (undefined4&) GH_MEM(0x0077d0b0);
@ -132,8 +135,9 @@ char(&s_wndStrRestoring)[256] = reinterpret_cast<char(&)[256]>(GH_MEM(0x0077d5e0
char *& g_crt_cmdLine= (char *&) GH_MEM(0x0077ea84);
char(&s_quitting1)[64] = reinterpret_cast<char(&)[64]>(GH_MEM(0x007825c0));
char(&s_wndStrQuiting)[56] = reinterpret_cast<char(&)[56]>(GH_MEM(0x00782600));
GAM_EngineStructure& g_stEngineStructure= (GAM_EngineStructure&) GH_MEM(0x007d7dc0);
undefined4& DAT_007d9cc4= (undefined4&) GH_MEM(0x007d9cc4);
undefined4& g_config_unused0= (undefined4&) GH_MEM(0x007d9df0);
byte& g_config_unused0= (byte&) GH_MEM(0x007d9df0);
char(&g_driveLetter)[4] = reinterpret_cast<char(&)[4]>(GH_MEM(0x007d9e70));
undefined4& g_GLI_adapter= (undefined4&) GH_MEM(0x007edd60);
undefined1& g_GLI_tnl= (undefined1&) GH_MEM(0x007edd64);

View File

@ -6,7 +6,7 @@
extern undefined4& crt_unhandled_exception_handler; // 00404a58
extern undefined4& DAT_00597ca0; // 00597ca0
extern dword& DWORD_00597ca0; // 00597ca0
extern char(&s__s_not_initialized__005b63e0)[20]; // 005b63e0
extern char(&s_Please_run_the__s_setup__005b63f4)[28]; // 005b63f4
extern char(&s_dashCC)[4]; // 005b6410
@ -69,6 +69,8 @@ extern undefined1& g_errModDInput; // 005bd29c
extern undefined4& DAT_005bd454; // 005bd454
extern const char* s__jc_z_d__s_005bd460; // 005bd460
extern undefined1& g_errModMmg; // 005bd58c
extern pointer& PTR_r3_processInput1_005bdb1c; // 005bdb1c
extern level_displayFn *& p_fn_vDisplayAll; // 005bdb24
extern const char* s_R3_DVD_005bdfd8; // 005bdfd8
extern const char* s_R3_DVD_005be0ec; // 005be0ec
extern const char* s__s_DVD_missing_005be0f4; // 005be0f4
@ -88,12 +90,12 @@ extern const char* lpDefault_005be370; // 005be370
extern const char* s_SoundOnHD_005be374; // 005be374
extern const char* lpDefault_005be380; // 005be380
extern const char* s_TexturesMem_005be384; // 005be384
extern pointer& s_Agp; // 005be390
extern const char* s_Agp; // 005be390
extern const char* s_Outline_005be394; // 005be394
extern const char* s_StaticShadows_005be39c; // 005be39c
extern const char* s_DynamicShadows_005be3ac; // 005be3ac
extern const char* s_TriLinear_005be3bc; // 005be3bc
extern pointer& s_Tnl; // 005be3c8
extern const char* s_Tnl; // 005be3c8
extern const char* s_TexturesCompressed_005be3cc; // 005be3cc
extern const char* s_GLI_Mode_005be3e0; // 005be3e0
extern const char* g_default_display_mode; // 005be3ec
@ -107,6 +109,7 @@ extern const char* s_r3_program_files; // 005be548
extern const char* s_driveLetterTemplate; // 005be568
extern undefined4& g_config_camera_hor_axis; // 005c67c8
extern undefined4& g_config_camera_ver_axis; // 005c67cc
extern undefined1& g_initVar0; // 005cf960
extern HWND& g_gameHWND1; // 005cf964
extern long& lpDefault_005cf96c; // 005cf96c
extern dword& DWORD_005cf974; // 005cf974
@ -117,8 +120,8 @@ extern char *& PTR_005cf9b4; // 005cf9b4
extern GameStructure& g_currentBinkMovie; // 005d2660
extern char(&s_volumeNameBuffer)[128]; // 005d27b0
extern r3_main_data& r3_main_data_005d28b6; // 005d28b6
extern undefined4& g_soundOnHD; // 005d29bc
extern undefined4& g_complete; // 005d29c0
extern dword& g_soundOnHD; // 005d29bc
extern dword& g_complete; // 005d29c0
extern int& g_windowInitialized; // 0077d0a4
extern int& g_runMaximized; // 0077d0a8
extern undefined4& g_engineShouldRun; // 0077d0b0
@ -137,8 +140,9 @@ extern char(&s_wndStrRestoring)[256]; // 0077d5e0
extern char *& g_crt_cmdLine; // 0077ea84
extern char(&s_quitting1)[64]; // 007825c0
extern char(&s_wndStrQuiting)[56]; // 00782600
extern GAM_EngineStructure& g_stEngineStructure; // 007d7dc0
extern undefined4& DAT_007d9cc4; // 007d9cc4
extern undefined4& g_config_unused0; // 007d9df0
extern byte& g_config_unused0; // 007d9df0
extern char(&g_driveLetter)[4]; // 007d9e70
extern undefined4& g_GLI_adapter; // 007edd60
extern undefined1& g_GLI_tnl; // 007edd64

View File

@ -0,0 +1,13 @@
// AUTO-GENERATED FILE!!!!
// This function has yet to be decompiled using 'Dump Current Function' in ghidra
// with possible manualy fixes
#include <r3/binders/auto.h>
#include <r3/binders/stub.h>
#include <gh_global.h>
// 00402470
// FUN_00402470
extern "C" undefined FUN_00402470(undefined4 param_1) {
return gh_stub_impl_cdecl<0x00402470, undefined>(param_1);
}

View File

@ -6,8 +6,8 @@
#include <r3/binders/stub.h>
#include <gh_global.h>
// 00401320
// FUN_00401320
extern "C" undefined FUN_00401320(void) {
return gh_stub_impl_cdecl<0x00401320, undefined>();
// 00442c50
// FUN_00442c50
extern "C" undefined FUN_00442c50(void) {
return gh_stub_impl_cdecl<0x00442c50, undefined>();
}

View File

@ -0,0 +1,13 @@
// AUTO-GENERATED FILE!!!!
// This function has yet to be decompiled using 'Dump Current Function' in ghidra
// with possible manualy fixes
#include <r3/binders/auto.h>
#include <r3/binders/stub.h>
#include <gh_global.h>
// 00442f70
// FUN_00442f70
extern "C" undefined FUN_00442f70(undefined4 param_1) {
return gh_stub_impl_cdecl<0x00442f70, undefined>(param_1);
}

View File

@ -0,0 +1,13 @@
// AUTO-GENERATED FILE!!!!
// This function has yet to be decompiled using 'Dump Current Function' in ghidra
// with possible manualy fixes
#include <r3/binders/auto.h>
#include <r3/binders/stub.h>
#include <gh_global.h>
// 00443120
// FUN_00443120
extern "C" undefined FUN_00443120(undefined4 param_1) {
return gh_stub_impl_cdecl<0x00443120, undefined>(param_1);
}

View File

@ -6,8 +6,8 @@
#include <r3/binders/stub.h>
#include <gh_global.h>
// 004013a0
// r3_windowUnlockCursor
extern "C" undefined r3_windowUnlockCursor(void) {
return gh_stub_impl_cdecl<0x004013a0, undefined>();
// 00445440
// FUN_00445440
extern "C" undefined FUN_00445440(void) {
return gh_stub_impl_cdecl<0x00445440, undefined>();
}

View File

@ -0,0 +1,13 @@
// AUTO-GENERATED FILE!!!!
// This function has yet to be decompiled using 'Dump Current Function' in ghidra
// with possible manualy fixes
#include <r3/binders/auto.h>
#include <r3/binders/stub.h>
#include <gh_global.h>
// 00445460
// FUN_00445460
extern "C" undefined FUN_00445460(void) {
return gh_stub_impl_cdecl<0x00445460, undefined>();
}

View File

@ -0,0 +1,13 @@
// AUTO-GENERATED FILE!!!!
// This function has yet to be decompiled using 'Dump Current Function' in ghidra
// with possible manualy fixes
#include <r3/binders/auto.h>
#include <r3/binders/stub.h>
#include <gh_global.h>
// 00470350
// FUN_00470350
extern "C" undefined FUN_00470350(void) {
return gh_stub_impl_cdecl<0x00470350, undefined>();
}

View File

@ -0,0 +1,13 @@
// AUTO-GENERATED FILE!!!!
// This function has yet to be decompiled using 'Dump Current Function' in ghidra
// with possible manualy fixes
#include <r3/binders/auto.h>
#include <r3/binders/stub.h>
#include <gh_global.h>
// 00470410
// FUN_00470410
extern "C" undefined FUN_00470410(void) {
return gh_stub_impl_cdecl<0x00470410, undefined>();
}

View File

@ -0,0 +1,13 @@
// AUTO-GENERATED FILE!!!!
// This function has yet to be decompiled using 'Dump Current Function' in ghidra
// with possible manualy fixes
#include <r3/binders/auto.h>
#include <r3/binders/stub.h>
#include <gh_global.h>
// 0047bae0
// FUN_0047bae0
extern "C" undefined FUN_0047bae0(void) {
return gh_stub_impl_cdecl<0x0047bae0, undefined>();
}

View File

@ -0,0 +1,13 @@
// AUTO-GENERATED FILE!!!!
// This function has yet to be decompiled using 'Dump Current Function' in ghidra
// with possible manualy fixes
#include <r3/binders/auto.h>
#include <r3/binders/stub.h>
#include <gh_global.h>
// 004fa650
// FUN_004fa650
extern "C" undefined FUN_004fa650(void) {
return gh_stub_impl_cdecl<0x004fa650, undefined>();
}

View File

@ -0,0 +1,13 @@
// AUTO-GENERATED FILE!!!!
// This function has yet to be decompiled using 'Dump Current Function' in ghidra
// with possible manualy fixes
#include <r3/binders/auto.h>
#include <r3/binders/stub.h>
#include <gh_global.h>
// 0051a7a0
// FUN_0051a7a0
extern "C" undefined FUN_0051a7a0(short hGLDDevice, undefined4 param_2) {
return gh_stub_impl_cdecl<0x0051a7a0, undefined>(hGLDDevice, param_2);
}

View File

@ -0,0 +1,13 @@
// AUTO-GENERATED FILE!!!!
// This function has yet to be decompiled using 'Dump Current Function' in ghidra
// with possible manualy fixes
#include <r3/binders/auto.h>
#include <r3/binders/stub.h>
#include <gh_global.h>
// 0051a900
// FUN_0051a900
extern "C" undefined FUN_0051a900(short hGLDDevice) {
return gh_stub_impl_cdecl<0x0051a900, undefined>(hGLDDevice);
}

View File

@ -0,0 +1,13 @@
// AUTO-GENERATED FILE!!!!
// This function has yet to be decompiled using 'Dump Current Function' in ghidra
// with possible manualy fixes
#include <r3/binders/auto.h>
#include <r3/binders/stub.h>
#include <gh_global.h>
// 00505490
// IPT_fn_vActivateAllEntryElements
extern "C" undefined IPT_fn_vActivateAllEntryElements(void) {
return gh_stub_impl_cdecl<0x00505490, undefined>();
}

View File

@ -0,0 +1,13 @@
// AUTO-GENERATED FILE!!!!
// This function has yet to be decompiled using 'Dump Current Function' in ghidra
// with possible manualy fixes
#include <r3/binders/auto.h>
#include <r3/binders/stub.h>
#include <gh_global.h>
// 0040a1e0
// SND_fn_vResumeSound
extern "C" undefined SND_fn_vResumeSound(void) {
return gh_stub_impl_cdecl<0x0040a1e0, undefined>();
}

View File

@ -0,0 +1,13 @@
// AUTO-GENERATED FILE!!!!
// This function has yet to be decompiled using 'Dump Current Function' in ghidra
// with possible manualy fixes
#include <r3/binders/auto.h>
#include <r3/binders/stub.h>
#include <gh_global.h>
// 00401300
// getHWND
extern "C" HWND getHWND(void) {
return gh_stub_impl_stdcall<0x00401300, HWND>();
}

View File

@ -0,0 +1,13 @@
// AUTO-GENERATED FILE!!!!
// This function has yet to be decompiled using 'Dump Current Function' in ghidra
// with possible manualy fixes
#include <r3/binders/auto.h>
#include <r3/binders/stub.h>
#include <gh_global.h>
// 00446fc0
// level_displayFn
extern "C" void level_displayFn(byte param) {
gh_stub_impl_cdecl<0x00446fc0, void>(param);
}

View File

@ -0,0 +1,13 @@
// AUTO-GENERATED FILE!!!!
// This function has yet to be decompiled using 'Dump Current Function' in ghidra
// with possible manualy fixes
#include <r3/binders/auto.h>
#include <r3/binders/stub.h>
#include <gh_global.h>
// 004711d0
// r3_closeConcatTextureFile
extern "C" undefined r3_closeConcatTextureFile(void) {
return gh_stub_impl_cdecl<0x004711d0, undefined>();
}

View File

@ -0,0 +1,13 @@
// AUTO-GENERATED FILE!!!!
// This function has yet to be decompiled using 'Dump Current Function' in ghidra
// with possible manualy fixes
#include <r3/binders/auto.h>
#include <r3/binders/stub.h>
#include <gh_global.h>
// 00471760
// r3_load_textures_2
extern "C" undefined r3_load_textures_2(void) {
return gh_stub_impl_cdecl<0x00471760, undefined>();
}

View File

@ -0,0 +1,13 @@
// AUTO-GENERATED FILE!!!!
// This function has yet to be decompiled using 'Dump Current Function' in ghidra
// with possible manualy fixes
#include <r3/binders/auto.h>
#include <r3/binders/stub.h>
#include <gh_global.h>
// 00446f10
// r3_processInput1
extern "C" undefined r3_processInput1(void) {
return gh_stub_impl_cdecl<0x00446f10, undefined>();
}

View File

@ -11,8 +11,18 @@ static uintptr_t g_gh_translationOffset{};
extern "C" {
#define HOOK(addr, name) void name(void *);
#define HOOK_S0(addr, name) void __stdcall name();
#define HOOK_S1(addr, name) void __stdcall name(int);
#define HOOK_S2(addr, name) void __stdcall name(int, int);
#define HOOK_S3(addr, name) void __stdcall name(int, int, int);
#define HOOK_S4(addr, name) void __stdcall name(int, int, int, int);
#include "hooks.def"
#undef HOOK
#undef HOOK_S0
#undef HOOK_S1
#undef HOOK_S2
#undef HOOK_S3
#undef HOOK_S4
}
struct R3Bin {
@ -33,10 +43,12 @@ struct R3Bin {
g_gh_translationOffset = translationOffset =
uintptr_t(module) - GH_BASE_ADDR;
std::string msg = fmt::format("Rayman3.exe Base address: 0x{:x}\n", uintptr_t(module));
std::string msg =
fmt::format("Rayman3.exe Base address: 0x{:x}\n", uintptr_t(module));
OutputDebugStringA(msg.c_str());
msg = fmt::format("Rayman3.exe Translation offset: 0x{:x}\n", translationOffset);
msg = fmt::format("Rayman3.exe Translation offset: 0x{:x}\n",
translationOffset);
OutputDebugStringA(msg.c_str());
// Now we have to relocate the module to the new base address
@ -44,8 +56,7 @@ struct R3Bin {
patchFunctions();
}
inline void relocate(void *instr, void *from,
void *originalPointee) {
inline void relocate(void *instr, void *from, void *originalPointee) {
void *relocated_addr = (void *)(uintptr_t(from) + translationOffset);
void *relocated_to =
(void *)(uintptr_t(originalPointee) + translationOffset);
@ -176,6 +187,12 @@ struct R3Bin {
}
void patchFunctions() {
#define HOOK(addr, name) patchFunction((void *)addr, &name, #name);
#define HOOK_S0(addr, name) HOOK(addr, name)
#define HOOK_S1(addr, name) HOOK(addr, name)
#define HOOK_S2(addr, name) HOOK(addr, name)
#define HOOK_S3(addr, name) HOOK(addr, name)
#define HOOK_S4(addr, name) HOOK(addr, name)
#include "hooks.def"
}

View File

@ -17,7 +17,11 @@ public class Test extends GhidraScript {
try (FunctionDatabase db = new FunctionDatabase(this)) {
List<FunctionDatabase.FunctionEntry> entries = db.loadAllEntries();
for (FunctionDatabase.FunctionEntry entry : entries) {
println("entry.name: " + entry.name + " entry.address: " + entry.address + " entry.type: " + entry.type);
println("entry.name: " + entry.name + " entry.address: " + entry.address + " entry.type: " + entry.type
+ " calling_convention: " + entry.callingConvention + " return_type: " + entry.returnType);
if (!entry.parameterNames.isEmpty()) {
println(" parameters: " + entry.parameterNames + " | types: " + entry.parameterTypes);
}
}
}
}

View File

@ -150,7 +150,6 @@ public class DataTypeWriter {
}
}
// Step 3: Topological sort and write
List<Block> sortedBlocks = topologicalSort(blocks);
for (Block block : sortedBlocks) {

View File

@ -46,30 +46,121 @@ public class FunctionDatabase implements AutoCloseable {
}
}
public static enum CallingConvention {
Cdecl(0),
Stdcall(1),
Fastcall(2);
private final int value;
CallingConvention(int value) {
this.value = value;
}
public int getValue() {
return value;
}
public static CallingConvention fromValue(int value) {
for (CallingConvention conv : CallingConvention.values()) {
if (conv.value == value) {
return conv;
}
}
throw new IllegalArgumentException("Unknown calling convention value: " + value);
}
public static CallingConvention fromString(String convStr) {
if (convStr == null) {
return Cdecl; // Default
}
String lower = convStr.toLowerCase();
if (lower.contains("fastcall")) {
return Fastcall;
} else if (lower.contains("stdcall")) {
return Stdcall;
} else {
return Cdecl; // Default
}
}
@Override
public String toString() {
switch (this) {
case Fastcall:
return "fastcall";
case Stdcall:
return "stdcall";
case Cdecl:
default:
return "cdecl";
}
}
}
public static class FunctionEntry {
public Address address;
public String name;
public File file;
public Type type;
public CallingConvention callingConvention;
public String parameterNames; // Semicolon-separated parameter names
public String parameterTypes; // Semicolon-separated parameter types
public String returnType; // Function return type
public FunctionEntry(Address address, String name, File file, Type type) {
public FunctionEntry(Address address, String name, File file, Type type, CallingConvention callingConvention,
String parameterNames, String parameterTypes, String returnType) {
this.address = address;
this.name = name;
this.file = file;
this.type = type;
this.callingConvention = callingConvention;
this.parameterNames = parameterNames != null ? parameterNames : "";
this.parameterTypes = parameterTypes != null ? parameterTypes : "";
this.returnType = returnType != null ? returnType : "void";
}
// Helper methods to work with semicolon-separated parameter lists
public String[] getParameterNamesArray() {
if (parameterNames == null || parameterNames.trim().isEmpty()) {
return new String[0];
}
return parameterNames.split(";");
}
public String[] getParameterTypesArray() {
if (parameterTypes == null || parameterTypes.trim().isEmpty()) {
return new String[0];
}
return parameterTypes.split(";");
}
public void setParameterNamesArray(String[] names) {
if (names == null || names.length == 0) {
this.parameterNames = "";
} else {
this.parameterNames = String.join(";", names);
}
}
public void setParameterTypesArray(String[] types) {
if (types == null || types.length == 0) {
this.parameterTypes = "";
} else {
this.parameterTypes = String.join(";", types);
}
}
}
public static class GlobalEntry {
public Address address;
public String name;
public String dataType;
public File file;
public GlobalEntry(Address address, String name, String dataType, File file) {
public GlobalEntry(Address address, String name, File file) {
this.address = address;
this.name = name;
this.dataType = dataType;
this.file = file;
}
}
@ -84,6 +175,7 @@ public class FunctionDatabase implements AutoCloseable {
private PreparedStatement findByAddressFunctions;
private PreparedStatement findByAddressImports;
private PreparedStatement insertOrReplaceFunctions;
private PreparedStatement insertOrReplaceImports;
private PreparedStatement deleteByFilepathFunctions;
private PreparedStatement deleteByFilepathImports;
private PreparedStatement loadAllFunctions;
@ -124,7 +216,8 @@ public class FunctionDatabase implements AutoCloseable {
script.println("Connected to database: " + dbFile);
} catch (SQLException e) {
script.println("Error connecting to database: " + e.getMessage());
throw new Exception("Failed to connect to database", e);
// throw new Exception("Failed to connect to database", e);
throw e;
}
}
@ -151,19 +244,21 @@ public class FunctionDatabase implements AutoCloseable {
private void prepareCachedStatements() throws SQLException {
// Find by name
findByNameFunctions = connection.prepareStatement(
"SELECT filepath, name, address, type FROM Functions WHERE name = ?");
"SELECT filepath, name, address, type, calling_convention, parameter_names, parameter_types, return_type FROM Functions WHERE name = ?");
findByNameImports = connection.prepareStatement(
"SELECT filepath, name, address, type FROM Imports WHERE name = ?");
"SELECT filepath, name, address, type, calling_convention, parameter_names, parameter_types, return_type FROM Imports WHERE name = ?");
// Find by address
findByAddressFunctions = connection.prepareStatement(
"SELECT filepath, name, address, type FROM Functions WHERE address = ?");
"SELECT filepath, name, address, type, calling_convention, parameter_names, parameter_types, return_type FROM Functions WHERE address = ?");
findByAddressImports = connection.prepareStatement(
"SELECT filepath, name, address, type FROM Imports WHERE address = ?");
"SELECT filepath, name, address, type, calling_convention, parameter_names, parameter_types, return_type FROM Imports WHERE address = ?");
// Insert or replace
insertOrReplaceFunctions = connection.prepareStatement(
"INSERT OR REPLACE INTO Functions (filepath, name, address, type) VALUES (?, ?, ?, ?)");
"INSERT OR REPLACE INTO Functions (filepath, name, address, type, calling_convention, parameter_names, parameter_types, return_type) VALUES (?, ?, ?, ?, ?, ?, ?, ?)");
insertOrReplaceImports = connection.prepareStatement(
"INSERT OR REPLACE INTO Imports (filepath, name, address, type, calling_convention, parameter_names, parameter_types, return_type) VALUES (?, ?, ?, ?, ?, ?, ?, ?)");
// Delete by filepath
deleteByFilepathFunctions = connection.prepareStatement(
@ -173,21 +268,21 @@ public class FunctionDatabase implements AutoCloseable {
// Load all entries
loadAllFunctions = connection.prepareStatement(
"SELECT filepath, name, address, type FROM Functions");
"SELECT filepath, name, address, type, calling_convention, parameter_names, parameter_types, return_type FROM Functions");
loadAllImports = connection.prepareStatement(
"SELECT filepath, name, address, type FROM Imports");
"SELECT filepath, name, address, type, calling_convention, parameter_names, parameter_types, return_type FROM Imports");
// Global statements
findByNameGlobals = connection.prepareStatement(
"SELECT filepath, name, address, type FROM Globals WHERE name = ?");
"SELECT filepath, name, address FROM Globals WHERE name = ?");
findByAddressGlobals = connection.prepareStatement(
"SELECT filepath, name, address, type FROM Globals WHERE address = ?");
"SELECT filepath, name, address FROM Globals WHERE address = ?");
insertOrReplaceGlobals = connection.prepareStatement(
"INSERT OR REPLACE INTO Globals (filepath, name, address, type) VALUES (?, ?, ?, ?)");
"INSERT OR REPLACE INTO Globals (filepath, name, address) VALUES (?, ?, ?)");
deleteByFilepathGlobals = connection.prepareStatement(
"DELETE FROM Globals WHERE filepath = ?");
loadAllGlobals = connection.prepareStatement(
"SELECT filepath, name, address, type FROM Globals");
"SELECT filepath, name, address FROM Globals");
}
private void closePreparedStatements() throws SQLException {
@ -201,6 +296,8 @@ public class FunctionDatabase implements AutoCloseable {
findByAddressImports.close();
if (insertOrReplaceFunctions != null)
insertOrReplaceFunctions.close();
if (insertOrReplaceImports != null)
insertOrReplaceImports.close();
if (deleteByFilepathFunctions != null)
deleteByFilepathFunctions.close();
if (deleteByFilepathImports != null)
@ -250,13 +347,19 @@ public class FunctionDatabase implements AutoCloseable {
String name = rs.getString("name");
String addressStr = rs.getString("address");
int typeValue = rs.getInt("type");
int callingConventionValue = rs.getInt("calling_convention");
String parameterNames = rs.getString("parameter_names");
String parameterTypes = rs.getString("parameter_types");
String returnType = rs.getString("return_type");
if (addressStr != null && !addressStr.isEmpty()) {
Address address = script.getCurrentProgram().getAddressFactory().getAddress(addressStr);
File file = new File(RemanConfig.INSTANCE.outputDir, filepath);
Type type = Type.fromValue(typeValue);
CallingConvention callingConvention = CallingConvention.fromValue(callingConventionValue);
return new FunctionEntry(address, name, file, type);
return new FunctionEntry(address, name, file, type, callingConvention,
parameterNames, parameterTypes, returnType);
}
return null;
}
@ -267,7 +370,11 @@ public class FunctionDatabase implements AutoCloseable {
filepath TEXT,
name TEXT,
address TEXT,
type INTEGER,
type INTEGER DEFAULT 0,
calling_convention INTEGER DEFAULT 0,
parameter_names TEXT DEFAULT '',
parameter_types TEXT DEFAULT '',
return_type TEXT DEFAULT '',
PRIMARY KEY (name, filepath)
)""";
@ -276,7 +383,11 @@ public class FunctionDatabase implements AutoCloseable {
filepath TEXT,
name TEXT,
address TEXT,
type INTEGER,
type INTEGER DEFAULT 0,
calling_convention INTEGER DEFAULT 0,
parameter_names TEXT DEFAULT '',
parameter_types TEXT DEFAULT '',
return_type TEXT DEFAULT '',
PRIMARY KEY (name, filepath)
)""";
@ -285,7 +396,6 @@ public class FunctionDatabase implements AutoCloseable {
filepath TEXT,
name TEXT,
address TEXT,
type TEXT,
PRIMARY KEY (name, filepath)
)""";
@ -377,15 +487,46 @@ public class FunctionDatabase implements AutoCloseable {
insertOrReplaceFunctions.setString(2, entry.name);
insertOrReplaceFunctions.setString(3, entry.address.toString());
insertOrReplaceFunctions.setInt(4, entry.type.getValue());
insertOrReplaceFunctions.setInt(5, entry.callingConvention.getValue());
insertOrReplaceFunctions.setString(6, entry.parameterNames);
insertOrReplaceFunctions.setString(7, entry.parameterTypes);
insertOrReplaceFunctions.setString(8, entry.returnType);
insertOrReplaceFunctions.executeUpdate();
script.println("Added/updated entry: " + entry.name + " at " + entry.address + " in " + relativePath);
script.println("Added/updated entry: " + entry.name + " at " + entry.address + " in " + relativePath
+ " (calling convention: " + entry.callingConvention + ", return type: " + entry.returnType + ")");
} catch (SQLException e) {
script.println("Error adding entry: " + e.getMessage());
throw new Exception("Failed to add entry", e);
}
}
// Helper method to add import entry
public void addImportEntry(FunctionEntry entry) throws Exception {
ensureConnection();
String relativePath = new File(RemanConfig.INSTANCE.outputDir).toPath()
.relativize(entry.file.toPath()).toString().replace('\\', '/');
try {
insertOrReplaceImports.setString(1, relativePath);
insertOrReplaceImports.setString(2, entry.name);
insertOrReplaceImports.setString(3, entry.address.toString());
insertOrReplaceImports.setInt(4, entry.type.getValue());
insertOrReplaceImports.setInt(5, entry.callingConvention.getValue());
insertOrReplaceImports.setString(6, entry.parameterNames);
insertOrReplaceImports.setString(7, entry.parameterTypes);
insertOrReplaceImports.setString(8, entry.returnType);
insertOrReplaceImports.executeUpdate();
script.println("Added/updated import entry: " + entry.name + " at " + entry.address + " in " + relativePath
+ " (calling convention: " + entry.callingConvention + ", return type: " + entry.returnType + ")");
} catch (SQLException e) {
script.println("Error adding import entry: " + e.getMessage());
throw new Exception("Failed to add import entry", e);
}
}
// Helper method to remove entry by file path
public void removeEntryAt(String filePath) throws Exception {
ensureConnection();
@ -566,13 +707,12 @@ public class FunctionDatabase implements AutoCloseable {
String filepath = rs.getString("filepath");
String name = rs.getString("name");
String addressStr = rs.getString("address");
String typeStr = rs.getString("type");
if (addressStr != null && !addressStr.isEmpty()) {
Address address = script.getCurrentProgram().getAddressFactory().getAddress(addressStr);
File file = new File(RemanConfig.INSTANCE.outputDir, filepath);
return new GlobalEntry(address, name, typeStr, file);
return new GlobalEntry(address, name, file);
}
return null;
}
@ -622,7 +762,7 @@ public class FunctionDatabase implements AutoCloseable {
}
}
public void addGlobal(Address address, String name, String dataType) throws Exception {
public void addGlobal(Address address, String name) throws Exception {
ensureConnection();
String filepath = RemanConfig.GLOBAL_H_FILE; // Default filepath for globals
@ -632,10 +772,9 @@ public class FunctionDatabase implements AutoCloseable {
insertOrReplaceGlobals.setString(1, filepath);
insertOrReplaceGlobals.setString(2, name);
insertOrReplaceGlobals.setString(3, addressStr);
insertOrReplaceGlobals.setString(4, dataType);
insertOrReplaceGlobals.executeUpdate();
script.println("Added/updated global: " + name + " at " + address + " with type " + dataType);
script.println("Added/updated global: " + name + " at " + address);
} catch (SQLException e) {
script.println("Error adding global: " + e.getMessage());
throw new Exception("Failed to add global", e);

View File

@ -47,6 +47,44 @@ public class FunctionDumper {
initFunctionBlacklist();
}
// Helper method to extract parameter names from Ghidra function
private String extractParameterNames(Function function) {
var parameters = function.getParameters();
if (parameters.length == 0) {
return "";
}
StringBuilder names = new StringBuilder();
for (int i = 0; i < parameters.length; i++) {
if (i > 0) names.append(";");
String paramName = parameters[i].getName();
names.append(paramName != null ? paramName : "param" + i);
}
return names.toString();
}
// Helper method to extract parameter types from Ghidra function
private String extractParameterTypes(Function function) {
var parameters = function.getParameters();
if (parameters.length == 0) {
return "";
}
StringBuilder types = new StringBuilder();
for (int i = 0; i < parameters.length; i++) {
if (i > 0) types.append(";");
String paramType = parameters[i].getDataType().toString();
types.append(paramType != null ? paramType : "void*");
}
return types.toString();
}
// Helper method to extract return type from Ghidra function
private String extractReturnType(Function function) {
var returnType = function.getReturnType();
return returnType != null ? returnType.getDisplayName() : "void";
}
boolean isValidFunction(Function function) {
if (functionAddrBlackList.contains(function.getEntryPoint()))
return false;
@ -131,6 +169,17 @@ public class FunctionDumper {
File f4 = new File(RemanConfig.INSTANCE.dirDecompStub, fileName);
script.println("Generating function stub for " + externalFunction.getName() + " => " + f4.toString());
// Extract calling convention from Ghidra function
String callingConventionName = externalFunction.getCallingConventionName();
FunctionDatabase.CallingConvention callingConvention = FunctionDatabase.CallingConvention
.fromString(callingConventionName);
script.println("Detected calling convention: " + callingConventionName + " -> " + callingConvention);
// Extract parameter information and return type
String parameterNames = extractParameterNames(externalFunction);
String parameterTypes = extractParameterTypes(externalFunction);
String returnType = extractReturnType(externalFunction);
try (PrintWriter writer2 = new PrintWriter(f4, "UTF-8")) {
writer2.println("// AUTO-GENERATED FILE!!!!");
writer2.println("// This function has yet to be decompiled using 'Dump Current Function' in ghidra");
@ -148,16 +197,16 @@ public class FunctionDumper {
String signature = externalFunction.getSignature().getPrototypeString(false);
signature = signature.replace(externalFunction.getName(), sanitizedExtFunctionName);
script.println("Santized Signature: " + signature);
String callingConvention = externalFunction.getCallingConventionName();
String returnType = externalFunction.getReturnType().toString();
// Generate function stub using appropriate forwarding function
writer2.println("extern \"C\" " + signature + " {");
// Determine which stub function to use based on calling convention
String stubFunction;
if (callingConvention != null && callingConvention.equals("__stdcall")) {
if (callingConvention == FunctionDatabase.CallingConvention.Stdcall) {
stubFunction = "gh_stub_impl_stdcall";
} else if (callingConvention == FunctionDatabase.CallingConvention.Fastcall) {
stubFunction = "gh_stub_impl_fastcall";
} else {
// Default to cdecl for most cases
stubFunction = "gh_stub_impl_cdecl";
@ -189,9 +238,10 @@ public class FunctionDumper {
createdFile = true;
}
// Add stub function to database
// Add stub function to database with calling convention and parameter information
FunctionDatabase.FunctionEntry newEntry = new FunctionDatabase.FunctionEntry(externalFunction.getEntryPoint(),
externalFunction.getName(), f4, FunctionDatabase.Type.Stub);
externalFunction.getName(), f4, FunctionDatabase.Type.Stub, callingConvention,
parameterNames, parameterTypes, returnType);
functionDatabase.addEntryAt(newEntry);
}
@ -204,6 +254,19 @@ public class FunctionDumper {
List<FunctionDatabase.FunctionEntry> entries = functionDatabase.findEntriesByAddress(entrypoint);
FunctionDatabase.Type targetType = FunctionDatabase.Type.Auto;
// Extract calling convention from Ghidra function
String callingConventionName = function.getCallingConventionName();
FunctionDatabase.CallingConvention callingConvention = FunctionDatabase.CallingConvention
.fromString(callingConventionName);
script.println("Detected calling convention: " + callingConventionName + " -> " + callingConvention);
// Extract parameter information and return type
String parameterNames = extractParameterNames(function);
String parameterTypes = extractParameterTypes(function);
String returnType = extractReturnType(function);
script.println("Parameters: " + parameterNames + " | Types: " + parameterTypes + " | Return: " + returnType);
// Handle forceFixType flag
if (forceFixType) {
targetType = FunctionDatabase.Type.Fix;
@ -271,14 +334,25 @@ public class FunctionDumper {
File f0 = targetFilename;
script.println("Processing " + function.getName() + " => " + f0.toString());
// Update database
// Update database with calling convention and parameter information
FunctionDatabase.FunctionEntry newEntry = new FunctionDatabase.FunctionEntry(entrypoint, function.getName(), f0,
targetType);
targetType, callingConvention, parameterNames, parameterTypes, returnType);
functionDatabase.addEntryAt(newEntry);
List<Function> externalFunctionCalls = new ArrayList<>();
HashMap<String, String> replacementMap = new HashMap<>();
String newFunctionName = sanitizedFunctionName;
if (callingConvention == FunctionDatabase.CallingConvention.Stdcall ||
callingConvention == FunctionDatabase.CallingConvention.Fastcall) {
newFunctionName = "__" + callingConvention.toString() + " " + newFunctionName;
}
String originalFunctionName = function.getName();
if (newFunctionName != originalFunctionName) {
replacementMap.put(originalFunctionName, newFunctionName);
}
DecompileResults decompRes = RemanConfig.INSTANCE.decompCache.getOrInsert(function);
try (PrintWriter writer2 = new PrintWriter(f0, "UTF-8")) {
writer2.println("// AUTO-GENERATED FILE, MOVE TO 'gh_fix' FOLDER PREVENT OVERWRITING!!!!! ");
@ -305,11 +379,6 @@ public class FunctionDumper {
// Parse preliminary line tokens
for (int i = 0; i < line.getNumTokens(); i++) {
ClangToken token = line.getToken(i);
if (token.getText().equals("__cdecl") || token.getText().equals("__thiscall")
|| token.getText().equals("__stdcall")) {
// Remove function declaration
continue;
}
if (!token.getText().isEmpty())
tokens.add(token);
}
@ -410,9 +479,14 @@ public class FunctionDumper {
String proto = externalFunction.getSignature().getPrototypeString(false);
String name = externalFunction.getName();
proto = proto.replace(name, Utils.sanitizeIdentifier(name));
// Add calling convention information to the comment
String callingConv = externalFunction.getCallingConventionName();
FunctionDatabase.CallingConvention conv = FunctionDatabase.CallingConvention.fromString(callingConv);
headers.add("" + proto
+ "; // " + externalFunction.getEntryPoint() + " // "
+ name);
+ name + " // " + conv);
}
for (String header : headers) {

View File

@ -226,8 +226,7 @@ public class GlobalDumper {
// Add all current globals to database
for (GlobalRec global : globalAddrs.values()) {
String dataTypeName = global.type.getDisplayName();
functionDatabase.addGlobal(global.address, global.name, dataTypeName);
functionDatabase.addGlobal(global.address, global.name);
}
}

View File

@ -8,6 +8,7 @@ import java.util.Iterator;
import java.util.List;
import ghidra.app.script.GhidraScript;
import ghidra.program.model.address.Address;
import ghidra.program.model.data.CategoryPath;
import ghidra.program.model.data.Composite;
import ghidra.program.model.data.DataType;
@ -20,7 +21,9 @@ import ghidra.program.model.data.TypeDef;
import ghidra.program.model.data.TypedefDataType;
import ghidra.program.model.data.Union;
import ghidra.program.model.data.UnionDataType;
import ghidra.program.model.listing.Data;
import ghidra.program.model.listing.Program;
import re3lib.FunctionDatabase.GlobalEntry;
public class TypeDumper {
Program currentProgram;
@ -35,6 +38,25 @@ public class TypeDumper {
public void run() throws Exception {
ProgramBasedDataTypeManager dtm = currentProgram.getDataTypeManager();
HashSet<String> requiredFunctionTypes = new HashSet<>();
FunctionDatabase fd = new FunctionDatabase(script);
List<GlobalEntry> globals = fd.loadAllGlobals();
for (GlobalEntry globalEntry : globals) {
// Fetch type of global from ghidra
Address addr = globalEntry.address;
if (globalEntry.name == "p_fn_vDisplayAll")
script.println("EEEEE");
Data data = script.getDataAt(addr);
if (data != null) {
DataType type = data.getDataType();
if (type instanceof FunctionDefinition) {
requiredFunctionTypes.add(type.getDisplayName());
script.println("Adding required global function type: " + type.getDisplayName());
}
}
}
HashSet<String> typeBlacklist = Utils.loadSimpleBlacklist(RemanConfig.INSTANCE.typeBlacklistPath);
HashSet<String> categoryPathBlacklist = Utils
.loadSimpleBlacklist(RemanConfig.INSTANCE.categoryPathBlacklistPath);
@ -89,7 +111,7 @@ public class TypeDumper {
if (dt instanceof Structure || dt instanceof TypeDef || dt instanceof EnumDataType
|| dt instanceof Union || dt instanceof Enum || dt instanceof FunctionDefinition) {
if (dt.getDisplayName().contains("NormalizeFn") || dt.getDisplayName().contains("_M_IX86"))
if (dt.getDisplayName().contains("level_displayFn") || dt.getDisplayName().contains("_M_IX86"))
script.println("DEBUG " + dt.getDisplayName() + " - " + dt.getClass().getSimpleName());
// if (dt.getDisplayName().contains("tdstObjectTypeElement_") ||
@ -113,6 +135,7 @@ public class TypeDumper {
writer.println("#include <r3/binders/type.h>");
DataTypeWriter dtw = new DataTypeWriter(dtm, writer);
dtw.requiredFunctionTypes = requiredFunctionTypes;
dtw.write(filteredTypes, script.getMonitor());
Utils.headerGuardPost(writer, "STRUCTS");

View File

@ -11,7 +11,8 @@ bool generateHooksFile(const std::string &output_filepath) {
try {
DatabaseManager db(options.db_path);
std::vector<FunctionInfo> fix_functions = db.getFunctionsByType(FileType::Fix);
std::vector<FunctionInfo> fix_functions =
db.getFunctionsByType(FileType::Fix);
std::ofstream output_stream(output_filepath);
if (!output_stream.is_open()) {
@ -23,17 +24,40 @@ bool generateHooksFile(const std::string &output_filepath) {
for (const auto &func : fix_functions) {
// Extract just the filename from the full path
std::string filename = std::filesystem::path(func.filepath).filename().string();
std::string filename =
std::filesystem::path(func.filepath).filename().string();
std::string conv_str = callingConventionToString(func.calling_convention);
size_t numParams = 0;
if (!func.parameter_types.empty()) {
std::string params = func.parameter_types;
std::stringstream ss(params);
std::string param;
while (std::getline(ss, param, ';')) {
if (!param.empty()) {
numParams++;
}
}
}
output_stream << "HOOK(0x" << func.address << ", " << func.name << ", " << conv_str << ") // " << filename << std::endl;
if (func.parameter_types == "void")
numParams = 0;
spdlog::debug("Added hook: {} {} {} from {}", func.address, func.name, conv_str, filename);
if (conv_str == "stdcall") {
output_stream << "HOOK_S" << numParams << "(0x" << func.address << ", "
<< func.name << ") // " << filename << std::endl;
} else {
output_stream << "HOOK(0x" << func.address << ", " << func.name
<< ") // " << filename << std::endl;
}
spdlog::debug("Added hook: {} {} {} from {}", func.address, func.name,
conv_str, filename);
}
output_stream.close();
spdlog::info("Generated {} hooks in {}", fix_functions.size(), output_filepath);
spdlog::info("Generated {} hooks in {}", fix_functions.size(),
output_filepath);
return true;
} catch (const std::exception &e) {
@ -43,7 +67,8 @@ bool generateHooksFile(const std::string &output_filepath) {
}
void register_cmd_hooks(CLI::App &app) {
auto cmd = app.add_subcommand("hooks", "Generate hooks file for Fix-type functions");
auto cmd =
app.add_subcommand("hooks", "Generate hooks file for Fix-type functions");
cmd->add_option("-o,--output", output_file, "Output file for hooks")
->default_val("hooks.def");
cmd->final_callback([]() {

View File

@ -27,11 +27,11 @@ public:
&delete_imports_stmt,
"Failed to prepare delete imports statement");
prepareStatement("INSERT OR REPLACE INTO Functions (filepath, name, "
"address, type, calling_convention) VALUES (?, ?, ?, ?, ?)",
"address, type, calling_convention, parameter_names, parameter_types, return_type) VALUES (?, ?, ?, ?, ?, ?, ?, ?)",
&insert_functions_stmt,
"Failed to prepare insert functions statement");
prepareStatement("INSERT OR REPLACE INTO Imports (filepath, name, address, "
"type, calling_convention) VALUES (?, ?, ?, ?, ?)",
"type, calling_convention, parameter_names, parameter_types, return_type) VALUES (?, ?, ?, ?, ?, ?, ?, ?)",
&insert_imports_stmt,
"Failed to prepare insert imports statement");
prepareStatement("DELETE FROM Globals WHERE filepath = ?",
@ -80,8 +80,8 @@ DatabaseManager::DatabaseManager(const std::string &db_path) : db(nullptr) {
}
const char *create_tables = R"(
CREATE TABLE IF NOT EXISTS Functions (filepath TEXT, name TEXT, address TEXT, type INTEGER DEFAULT 0, calling_convention INTEGER DEFAULT 0, PRIMARY KEY (name, filepath));
CREATE TABLE IF NOT EXISTS Imports (filepath TEXT, name TEXT, address TEXT, type INTEGER DEFAULT 0, calling_convention INTEGER DEFAULT 0, PRIMARY KEY (name, filepath));
CREATE TABLE IF NOT EXISTS Functions (filepath TEXT, name TEXT, address TEXT, type INTEGER DEFAULT 0, calling_convention INTEGER DEFAULT 0, parameter_names TEXT DEFAULT '', parameter_types TEXT DEFAULT '', return_type TEXT DEFAULT '', PRIMARY KEY (name, filepath));
CREATE TABLE IF NOT EXISTS Imports (filepath TEXT, name TEXT, address TEXT, type INTEGER DEFAULT 0, calling_convention INTEGER DEFAULT 0, parameter_names TEXT DEFAULT '', parameter_types TEXT DEFAULT '', return_type TEXT DEFAULT '', PRIMARY KEY (name, filepath));
CREATE TABLE IF NOT EXISTS Globals (filepath TEXT, name TEXT, address TEXT);
)";
@ -119,6 +119,9 @@ void DatabaseManager::insertFunction(const FunctionInfo &func) {
sqlite3_bind_text(stmt, 3, func.address.c_str(), -1, SQLITE_STATIC);
sqlite3_bind_int(stmt, 4, static_cast<int>(func.type));
sqlite3_bind_int(stmt, 5, static_cast<int>(func.calling_convention));
sqlite3_bind_text(stmt, 6, func.parameter_names.c_str(), -1, SQLITE_STATIC);
sqlite3_bind_text(stmt, 7, func.parameter_types.c_str(), -1, SQLITE_STATIC);
sqlite3_bind_text(stmt, 8, func.return_type.c_str(), -1, SQLITE_STATIC);
sqlite3_step(stmt);
}
@ -241,7 +244,7 @@ std::vector<FunctionInfo> DatabaseManager::getFunctionsByType(FileType type) {
std::vector<FunctionInfo> functions;
const char *sql = R"(
SELECT name, address, filepath, calling_convention
SELECT name, address, filepath, calling_convention, parameter_names, parameter_types, return_type
FROM Functions
WHERE type = ? AND address != ''
ORDER BY address;
@ -261,6 +264,9 @@ std::vector<FunctionInfo> DatabaseManager::getFunctionsByType(FileType type) {
func.address = (const char *)sqlite3_column_text(stmt, 1);
func.filepath = (const char *)sqlite3_column_text(stmt, 2);
func.calling_convention = static_cast<CallingConvention>(sqlite3_column_int(stmt, 3));
func.parameter_names = (const char *)sqlite3_column_text(stmt, 4);
func.parameter_types = (const char *)sqlite3_column_text(stmt, 5);
func.return_type = (const char *)sqlite3_column_text(stmt, 6);
func.type = type;
func.is_import = false; // Functions table contains non-imports

View File

@ -281,15 +281,24 @@ void findFunctions(TSNode node, const char *source_code, uint32_t source_length,
// Detect calling convention
CallingConvention calling_conv = getCallingConvention(node, source_code);
FunctionInfo func{func_name, address, "",
strcmp(type, "function_definition") == 0
? !hasFunctionBody(node)
: true,
file_type}; // Add file_type parameter
func.calling_convention = calling_conv; // Set the calling convention
// Extract parameter information and return type
std::string parameter_names = getParameterNames(node, source_code);
std::string parameter_types = getParameterTypes(node, source_code);
std::string return_type = getReturnType(node, source_code);
spdlog::debug("Found function: {} at {} with calling convention: {}",
func_name, address, callingConventionToString(calling_conv));
FunctionInfo func;
func.name = func_name;
func.address = address;
func.filepath = "";
func.parameter_names = parameter_names;
func.parameter_types = parameter_types;
func.return_type = return_type;
func.is_import = strcmp(type, "function_definition") == 0 ? !hasFunctionBody(node) : true;
func.type = file_type;
func.calling_convention = calling_conv;
spdlog::debug("Found function: {} at {} with calling convention: {}, return type: {}, param names: {}, param types: {}",
func_name, address, callingConventionToString(calling_conv), return_type, parameter_names, parameter_types);
functions.push_back(func);
}
@ -354,3 +363,139 @@ void findGlobals(TSNode node, const char *source_code, uint32_t source_length,
findGlobals(ts_node_child(node, i), source_code, source_length, globals);
}
}
// Add helper functions to extract parameter information and return type
std::string getParameterNames(TSNode node, const char *source_code) {
std::vector<std::string> names;
uint32_t child_count = ts_node_child_count(node);
for (uint32_t i = 0; i < child_count; i++) {
TSNode child = ts_node_child(node, i);
const char *type = ts_node_type(child);
if (strcmp(type, "function_declarator") == 0) {
// Look for parameter_list within function_declarator
uint32_t func_child_count = ts_node_child_count(child);
for (uint32_t j = 0; j < func_child_count; j++) {
TSNode func_child = ts_node_child(child, j);
if (strcmp(ts_node_type(func_child), "parameter_list") == 0) {
// Extract each parameter_declaration
uint32_t param_list_count = ts_node_child_count(func_child);
for (uint32_t k = 0; k < param_list_count; k++) {
TSNode param_node = ts_node_child(func_child, k);
if (strcmp(ts_node_type(param_node), "parameter_declaration") == 0) {
// Find the identifier (parameter name) in this parameter
std::string param_name = findIdentifierInDeclarator(param_node, source_code);
if (!param_name.empty()) {
names.push_back(param_name);
}
}
}
break;
}
}
break;
}
}
// Join names with semicolon
std::string result;
for (size_t i = 0; i < names.size(); i++) {
if (i > 0) result += ";";
result += names[i];
}
return result;
}
std::string getParameterTypes(TSNode node, const char *source_code) {
std::vector<std::string> types;
uint32_t child_count = ts_node_child_count(node);
for (uint32_t i = 0; i < child_count; i++) {
TSNode child = ts_node_child(node, i);
const char *type = ts_node_type(child);
if (strcmp(type, "function_declarator") == 0) {
// Look for parameter_list within function_declarator
uint32_t func_child_count = ts_node_child_count(child);
for (uint32_t j = 0; j < func_child_count; j++) {
TSNode func_child = ts_node_child(child, j);
if (strcmp(ts_node_type(func_child), "parameter_list") == 0) {
// Extract each parameter_declaration
uint32_t param_list_count = ts_node_child_count(func_child);
for (uint32_t k = 0; k < param_list_count; k++) {
TSNode param_node = ts_node_child(func_child, k);
if (strcmp(ts_node_type(param_node), "parameter_declaration") == 0) {
// Extract type part by getting everything except the identifier
std::string full_param = extractNodeText(param_node, source_code);
std::string param_name = findIdentifierInDeclarator(param_node, source_code);
// Remove the parameter name from the full parameter text to get just the type
std::string param_type = full_param;
if (!param_name.empty()) {
size_t name_pos = param_type.rfind(param_name);
if (name_pos != std::string::npos) {
param_type = param_type.substr(0, name_pos);
// Clean up trailing whitespace and pointer/reference symbols after the type
param_type.erase(param_type.find_last_not_of(" \t\n\r*&") + 1);
// Add back any pointer/reference symbols that were part of the type
size_t type_end = name_pos;
while (type_end < full_param.length() &&
(full_param[type_end] == ' ' || full_param[type_end] == '\t')) {
type_end++;
}
if (type_end > name_pos + param_name.length()) {
param_type += full_param.substr(name_pos + param_name.length(),
type_end - (name_pos + param_name.length()));
}
}
}
// Clean up any extra whitespace
param_type.erase(0, param_type.find_first_not_of(" \t\n\r"));
param_type.erase(param_type.find_last_not_of(" \t\n\r") + 1);
if (!param_type.empty()) {
types.push_back(param_type);
}
}
}
break;
}
}
break;
}
}
// Join types with semicolon
std::string result;
for (size_t i = 0; i < types.size(); i++) {
if (i > 0) result += ";";
result += types[i];
}
return result;
}
std::string getReturnType(TSNode node, const char *source_code) {
uint32_t child_count = ts_node_child_count(node);
for (uint32_t i = 0; i < child_count; i++) {
TSNode child = ts_node_child(node, i);
const char *type = ts_node_type(child);
// Look for type specifiers (return type comes before function declarator)
if (strcmp(type, "type_identifier") == 0 ||
strcmp(type, "primitive_type") == 0 ||
strcmp(type, "sized_type_specifier") == 0) {
return extractNodeText(child, source_code);
}
// Handle more complex types
else if (strcmp(type, "qualified_identifier") == 0 ||
strcmp(type, "template_type") == 0) {
return extractNodeText(child, source_code);
}
}
return "void"; // Default return type
}

View File

@ -22,6 +22,9 @@ struct FunctionInfo {
std::string name;
std::string address;
std::string filepath;
std::string parameter_names; // Semicolon-separated parameter names
std::string parameter_types; // Semicolon-separated parameter types
std::string return_type; // Function return type
bool is_import;
FileType type;
CallingConvention calling_convention = CallingConvention::Cdecl; // Default to cdecl
@ -50,6 +53,9 @@ std::string findIdentifierInDeclarator(TSNode node, const char *source_code);
std::string getFunctionName(TSNode node, const char *source_code);
std::string getGlobalName(TSNode node, const char *source_code);
std::string getComment(TSNode node, const char *source_code, uint32_t source_length, bool search_before);
std::string getParameterNames(TSNode node, const char *source_code);
std::string getParameterTypes(TSNode node, const char *source_code);
std::string getReturnType(TSNode node, const char *source_code);
bool hasFunctionBody(TSNode node);
void findFunctions(TSNode node, const char *source_code, uint32_t source_length,
std::vector<FunctionInfo> &functions, FileType file_type);