diff --git a/cleo4opcodes.cpp b/cleo4opcodes.cpp index 87808ce..8950b2d 100644 --- a/cleo4opcodes.cpp +++ b/cleo4opcodes.cpp @@ -27,7 +27,7 @@ std::set gFilesMap; // Game Vars uint8_t* ScriptSpace; -GTAScript **pActiveScripts; +GTAScript **pActiveScripts, **pIdleScripts; uint8_t* LocalVariablesForCurrentMission; int* ScriptParams; uintptr_t gMobileMenu; @@ -220,7 +220,7 @@ CLEO_Fn(GET_THIS_SCRIPT_STRUCT) CLEO_Fn(GOSUB_IF_FALSE) { int offset = cleo->ReadParam(handle)->i; - bool condition = *(bool*)((uintptr_t)handle + ValueForGame(120, 121, 229, 525, 521)); + bool condition = GetCond(handle); if(!condition) { PushStack(handle); @@ -321,7 +321,7 @@ CLEO_Fn(CLEO_CALL) char buf[MAX_STR_LEN]; static int arguments[40]; int maxParams = ValueForSA(40, 16); - int* scope = (int*)((uintptr_t)handle + ValueForGame(48, 48, 60, 96, 520)); + int* scope = GetLocalVars(handle); if(*nGameIdent == GTASA && IsMissionScript(handle)) scope = (int*)LocalVariablesForCurrentMission; int* scopeEnd = scope + maxParams; int* storedLocals = scmFunc->savedTls; @@ -1464,6 +1464,7 @@ void Init4Opcodes() SET_TO(ScriptSpace, cleo->GetMainLibrarySymbol("_ZN11CTheScripts11ScriptSpaceE")); SET_TO(UpdateCompareFlag, cleo->GetMainLibrarySymbol("_ZN14CRunningScript17UpdateCompareFlagEh")); SET_TO(pActiveScripts, cleo->GetMainLibrarySymbol("_ZN11CTheScripts14pActiveScriptsE")); + SET_TO(pIdleScripts, cleo->GetMainLibrarySymbol("_ZN11CTheScripts12pIdleScriptsE")); SET_TO(ScriptParams, cleo->GetMainLibrarySymbol("ScriptParams")); SET_TO(GetPedFromRef, cleo->GetMainLibrarySymbol("_ZN6CPools6GetPedEi")); SET_TO(GetVehicleFromRef, cleo->GetMainLibrarySymbol("_ZN6CPools10GetVehicleEi")); diff --git a/cleohelpers.h b/cleohelpers.h index a8d8071..fdb8f20 100644 --- a/cleohelpers.h +++ b/cleohelpers.h @@ -270,7 +270,7 @@ inline uint16_t& GetStackDepth(void* handle) } inline bool& GetCond(void* handle) { - return *(bool*)((uintptr_t)handle + ValueForGame(121, 121, 229)); + return *(bool*)((uintptr_t)handle + ValueForGame(121, 121, 229, 525, 521)); } inline bool& GetNotFlag(void* handle) { @@ -855,6 +855,44 @@ inline const char* GetVarTypeName(eScriptParameterType type) return "UNKNOWN"; } +extern GTAScript **pActiveScripts, **pIdleScripts; +inline bool IsInActiveScripts(void* handle) +{ + for (GTAScript* script = *pActiveScripts; script != NULL; script = script->next) + { + if (script == handle) + { + return true; + } + } + return false; +} +inline bool IsInPausedScripts(void* handle) +{ + for (GTAScript* script = *pIdleScripts; script != NULL; script = script->next) + { + if (script == handle) + { + return true; + } + } + return false; +} +inline bool IsInCLEOScripts(void* handle) +{ + int len = GetScriptsStorageSize(); + for(int i = 0; i < len; ++i) + { + int storageItem = *(int*)(*pScriptsStorage + i * 4); + if(*(void**)(storageItem + 28) == handle) return true; + } + return false; +} +inline bool IsValidScriptHandle(void* handle) +{ + return IsInActiveScripts(handle) || IsInPausedScripts(handle) || IsInCLEOScripts(handle); +} + // CLEO5 struct PausedScriptInfo { @@ -863,4 +901,4 @@ struct PausedScriptInfo PausedScriptInfo(GTAScript* ptr, const char* msg) : ptr(ptr), msg(msg) {} PausedScriptInfo(void* ptr, const char* msg) : ptr((GTAScript*)ptr), msg(msg) {} }; -extern std::deque pausedScripts; +extern std::deque pausedScripts; \ No newline at end of file diff --git a/main.cpp b/main.cpp index c426698..1f2bc29 100644 --- a/main.cpp +++ b/main.cpp @@ -85,9 +85,11 @@ void** (*LookupForOpcodeFunc)(void* storage, uint16_t& opcode); extern unsigned char cleoData[100160]; // CLEO crashlogging -#define SCRIPTS_LOG_COUNT 16 -void *lastScriptHandle[SCRIPTS_LOG_COUNT] = {NULL}; -uint8_t *lastScriptPC[SCRIPTS_LOG_COUNT] = {NULL}; +#define SCRIPTS_LOG_COUNT 32 +bool scriptDebugger = true; +void *lastScriptHandle[SCRIPTS_LOG_COUNT] = { NULL }; +uint8_t *lastScriptPC[SCRIPTS_LOG_COUNT] = { NULL }; +uint16_t lastScriptOp[SCRIPTS_LOG_COUNT] = { 0x0000 }; // Config-functions const char* pLocations[] = @@ -113,8 +115,6 @@ void OnRedArrowChanged(int oldVal, int newVal, void* userdata) cfg->Save(); } - - extern "C" __attribute__((target("thumb-mode"))) __attribute__((naked)) void Opcode0DD2_inject() { //see https://github.com/XMDS/OP_0DD2FixAsm_call.git (cleo verison) @@ -195,16 +195,18 @@ DECL_HOOKb(CLEO_OnOpcodeCall, void *storageItem, uint16_t opcode) void* g_pForceInterrupt = NULL; DECL_HOOK(int8_t, ProcessOneCommand, void* handle) { - for(int i = SCRIPTS_LOG_COUNT-2; i >= 0; --i) + if(scriptDebugger) { - lastScriptHandle[i + 1] = lastScriptHandle[i]; - lastScriptPC[i + 1] = lastScriptPC[i]; + for(int i = SCRIPTS_LOG_COUNT-2; i >= 0; --i) + { + lastScriptHandle[i + 1] = lastScriptHandle[i]; + lastScriptPC[i + 1] = lastScriptPC[i]; + lastScriptOp[i + 1] = lastScriptOp[i]; + } + lastScriptHandle[0] = handle; + lastScriptPC[0] = GetPC(handle); + lastScriptOp[0] = Read2Bytes_NoSkip(handle); } - lastScriptHandle[0] = handle; - lastScriptPC[0] = GetPC(handle); - - // no lastScriptOpcode here for optimisations! - // its inside lastScriptPC at this stage! :p int siz = pausedScripts.size(); for (size_t i = 0; i < siz; ++i) @@ -563,31 +565,55 @@ extern "C" void OnAllModsLoaded() } } - extern "C" void OnGameCrash(const char* szLibName, int sig, int code, uintptr_t libaddr, mcontext_t* mcontext) { // Print lastScript* data to the cleo logging! if(!cleo) return; cleo->PrintToCleoLog("[ The game crashed ]"); - cleo->PrintToCleoLog("Callstack:"); - char buf[512]; - int callNum = 0; - for(int i = SCRIPTS_LOG_COUNT-1; i >= 0; ++i) + if(scriptDebugger) { - if(!lastScriptHandle[i] || !lastScriptPC[i]) continue; - - // Check if this script handle is still correct - // If it is, we have a name, filename, a complete script code and more! - if(false) return; - uint8_t *backupPC = GetPC(lastScriptHandle[i]); - GetPC(lastScriptHandle[i]) = lastScriptPC[i]; - - uint16_t lastScriptOpcode = Read2Bytes(lastScriptHandle[i]); - bool isCustom = GetAddonInfo(lastScriptHandle[i]).isCustom; - const char* scrName = isCustom ? CLEO_GetScriptFilename(lastScriptHandle[i]) : ((GTAScript*)lastScriptHandle[i])->name; - snprintf(buf, sizeof(buf), "Call #%d, opcode %04X, script %s", callNum++, lastScriptOpcode, scrName); - cleo->PrintToCleoLog(buf); + char buf[512], defName[8], custName[128]; + int callNum = 0; + + cleo->PrintToCleoLog("The data below is not guaranteed to be correct!"); + cleo->PrintToCleoLog("Calling history:"); + for(int i = SCRIPTS_LOG_COUNT-1; i >= 0; --i) + { + if(!lastScriptHandle[i] || !lastScriptPC[i]) continue; + + // Check if this script handle is still correct + // If it is, we have a name, filename, a complete script code and more! + if(!IsValidScriptHandle(lastScriptHandle[i])) + { + // It does not contain a valid data anymore: was deleted or something like that. + snprintf(buf, sizeof(buf), "CALL #%d, Unknown Script 0x%08X, OpCode %04X", ++callNum, (uintptr_t)lastScriptHandle[i], lastScriptOp[i]); + cleo->PrintToCleoLog(buf); + continue; + } + + uint8_t *backupPC = GetPC(lastScriptHandle[i]); + GetPC(lastScriptHandle[i]) = lastScriptPC[i]; + + bool isCustom = GetAddonInfo(lastScriptHandle[i]).isCustom; + uint16_t lastScriptOpcode = Read2Bytes(lastScriptHandle[i]); + strncpy(defName, ((GTAScript*)lastScriptHandle[i])->name, sizeof(defName)); defName[sizeof(defName)-1] = 0; + custName[0] = 0; + if(isCustom) + { + const char* filename = CLEO_GetScriptFilename(lastScriptHandle[i]); + if(filename) strncpy(custName, filename, sizeof(custName)); custName[sizeof(custName)-1] = 0; + } + + snprintf(buf, sizeof(buf), "CALL #%d, %s Script '%s', OpCode %04X", ++callNum, isCustom ? "CLEO" : "Game", custName[0] != 0 ? custName : defName, lastScriptOpcode); + cleo->PrintToCleoLog(buf); + + GetPC(lastScriptHandle[i]) = backupPC; + } + cleo->PrintToCleoLog("[ Crashlog Ending ]"); } - cleo->PrintToCleoLog("[ Crashlog ending ]"); -} + else + { + cleo->PrintToCleoLog("[ Script debugging was not enabled ]"); + } +} \ No newline at end of file