mirror of
				https://github.com/JezuzLizard/T4SP-Server-Plugin.git
				synced 2025-10-30 17:27:01 +00:00 
			
		
		
		
	Added more debug dumping for gsc vm
This commit is contained in:
		| @@ -61,7 +61,7 @@ std::string printStack() | ||||
| 	unsigned short frames; | ||||
| 	SYMBOL_INFO  * symbol; | ||||
| 	HANDLE         process; | ||||
| 	std::string answer; | ||||
| 	std::string answer{}; | ||||
|  | ||||
| 	process = GetCurrentProcess(); | ||||
|  | ||||
| @@ -76,7 +76,7 @@ std::string printStack() | ||||
| 	{ | ||||
| 		SymFromAddr( process, ( DWORD64 )( stack[ i ] ), 0, symbol ); | ||||
|  | ||||
| 		answer += std::format("{}: {} - {:06x}\n", frames - i - 1, symbol->Name, symbol->Address); | ||||
| 		answer += std::format("{}: {} - 0x{:06x}\n", frames - i - 1, symbol->Name, symbol->Address); | ||||
| 	} | ||||
|  | ||||
| 	free( symbol ); | ||||
| @@ -84,17 +84,257 @@ std::string printStack() | ||||
| 	return answer; | ||||
| } | ||||
|  | ||||
| int op_idx[game::SCRIPT_INSTANCE_MAX] = { 0, 0 }; | ||||
| bool op_idx_rolled_over[game::SCRIPT_INSTANCE_MAX] = { false, false }; | ||||
| game::OpcodeVM op_history[game::SCRIPT_INSTANCE_MAX][128] = {}; | ||||
|  | ||||
| std::string build_op_history(game::scriptInstance_t inst) | ||||
| { | ||||
| 	static const char* OpcodeVMToString[] = { | ||||
| 		"OP_End", | ||||
| 		"OP_Return", | ||||
| 		"OP_GetUndefined", | ||||
| 		"OP_GetZero", | ||||
| 		"OP_GetByte", | ||||
| 		"OP_GetNegByte", | ||||
| 		"OP_GetUnsignedShort", | ||||
| 		"OP_GetNegUnsignedShort", | ||||
| 		"OP_GetInteger", | ||||
| 		"OP_GetFloat", | ||||
| 		"OP_GetString", | ||||
| 		"OP_GetIString", | ||||
| 		"OP_GetVector", | ||||
| 		"OP_GetLevelObject", | ||||
| 		"OP_GetAnimObject", | ||||
| 		"OP_GetSelf", | ||||
| 		"OP_GetLevel", | ||||
| 		"OP_GetGame", | ||||
| 		"OP_GetAnim", | ||||
| 		"OP_GetAnimation", | ||||
| 		"OP_GetGameRef", | ||||
| 		"OP_GetFunction", | ||||
| 		"OP_CreateLocalVariable", | ||||
| 		"OP_RemoveLocalVariables", | ||||
| 		"OP_EvalLocalVariableCached0", | ||||
| 		"OP_EvalLocalVariableCached1", | ||||
| 		"OP_EvalLocalVariableCached2", | ||||
| 		"OP_EvalLocalVariableCached3", | ||||
| 		"OP_EvalLocalVariableCached4", | ||||
| 		"OP_EvalLocalVariableCached5", | ||||
| 		"OP_EvalLocalVariableCached", | ||||
| 		"OP_EvalLocalArrayCached", | ||||
| 		"OP_EvalArray", | ||||
| 		"OP_EvalLocalArrayRefCached0", | ||||
| 		"OP_EvalLocalArrayRefCached", | ||||
| 		"OP_EvalArrayRef", | ||||
| 		"OP_ClearArray", | ||||
| 		"OP_EmptyArray", | ||||
| 		"OP_GetSelfObject", | ||||
| 		"OP_EvalLevelFieldVariable", | ||||
| 		"OP_EvalAnimFieldVariable", | ||||
| 		"OP_EvalSelfFieldVariable", | ||||
| 		"OP_EvalFieldVariable", | ||||
| 		"OP_EvalLevelFieldVariableRef", | ||||
| 		"OP_EvalAnimFieldVariableRef", | ||||
| 		"OP_EvalSelfFieldVariableRef", | ||||
| 		"OP_EvalFieldVariableRef", | ||||
| 		"OP_ClearFieldVariable", | ||||
| 		"OP_SafeCreateVariableFieldCached", | ||||
| 		"OP_SafeSetVariableFieldCached0", | ||||
| 		"OP_SafeSetVariableFieldCached", | ||||
| 		"OP_SafeSetWaittillVariableFieldCached", | ||||
| 		"OP_clearparams", | ||||
| 		"OP_checkclearparams", | ||||
| 		"OP_EvalLocalVariableRefCached0", | ||||
| 		"OP_EvalLocalVariableRefCached", | ||||
| 		"OP_SetLevelFieldVariableField", | ||||
| 		"OP_SetVariableField", | ||||
| 		"OP_SetAnimFieldVariableField", | ||||
| 		"OP_SetSelfFieldVariableField", | ||||
| 		"OP_SetLocalVariableFieldCached0", | ||||
| 		"OP_SetLocalVariableFieldCached", | ||||
| 		"OP_CallBuiltin0", | ||||
| 		"OP_CallBuiltin1", | ||||
| 		"OP_CallBuiltin2", | ||||
| 		"OP_CallBuiltin3", | ||||
| 		"OP_CallBuiltin4", | ||||
| 		"OP_CallBuiltin5", | ||||
| 		"OP_CallBuiltin", | ||||
| 		"OP_CallBuiltinMethod0", | ||||
| 		"OP_CallBuiltinMethod1", | ||||
| 		"OP_CallBuiltinMethod2", | ||||
| 		"OP_CallBuiltinMethod3", | ||||
| 		"OP_CallBuiltinMethod4", | ||||
| 		"OP_CallBuiltinMethod5", | ||||
| 		"OP_CallBuiltinMethod", | ||||
| 		"OP_wait", | ||||
| 		"OP_waittillFrameEnd", | ||||
| 		"OP_PreScriptCall", | ||||
| 		"OP_ScriptFunctionCall2", | ||||
| 		"OP_ScriptFunctionCall", | ||||
| 		"OP_ScriptFunctionCallPointer", | ||||
| 		"OP_ScriptMethodCall", | ||||
| 		"OP_ScriptMethodCallPointer", | ||||
| 		"OP_ScriptThreadCall", | ||||
| 		"OP_ScriptThreadCallPointer", | ||||
| 		"OP_ScriptMethodThreadCall", | ||||
| 		"OP_ScriptMethodThreadCallPointer", | ||||
| 		"OP_DecTop", | ||||
| 		"OP_CastFieldObject", | ||||
| 		"OP_EvalLocalVariableObjectCached", | ||||
| 		"OP_CastBool", | ||||
| 		"OP_BoolNot", | ||||
| 		"OP_BoolComplement", | ||||
| 		"OP_JumpOnFalse", | ||||
| 		"OP_JumpOnTrue", | ||||
| 		"OP_JumpOnFalseExpr", | ||||
| 		"OP_JumpOnTrueExpr", | ||||
| 		"OP_jump", | ||||
| 		"OP_jumpback", | ||||
| 		"OP_inc", | ||||
| 		"OP_dec", | ||||
| 		"OP_bit_or", | ||||
| 		"OP_bit_ex_or", | ||||
| 		"OP_bit_and", | ||||
| 		"OP_equality", | ||||
| 		"OP_inequality", | ||||
| 		"OP_less", | ||||
| 		"OP_greater", | ||||
| 		"OP_less_equal", | ||||
| 		"OP_greater_equal", | ||||
| 		"OP_shift_left", | ||||
| 		"OP_shift_right", | ||||
| 		"OP_plus", | ||||
| 		"OP_minus", | ||||
| 		"OP_multiply", | ||||
| 		"OP_divide", | ||||
| 		"OP_mod", | ||||
| 		"OP_size", | ||||
| 		"OP_waittillmatch", | ||||
| 		"OP_waittill", | ||||
| 		"OP_notify", | ||||
| 		"OP_endon", | ||||
| 		"OP_voidCodepos", | ||||
| 		"OP_switch", | ||||
| 		"OP_endswitch", | ||||
| 		"OP_vector", | ||||
| 		"OP_NOP", | ||||
| 		"OP_abort", | ||||
| 		"OP_object", | ||||
| 		"OP_thread_object", | ||||
| 		"OP_EvalLocalVariable", | ||||
| 		"OP_EvalLocalVariableRef", | ||||
| 		"OP_prof_begin", | ||||
| 		"OP_prof_end", | ||||
| 		"OP_breakpoint", | ||||
| 		"OP_assignmentBreakpoint", | ||||
| 		"OP_manualAndAssignmentBreakpoint", | ||||
| 		"OP_count" | ||||
| 	}; | ||||
|  | ||||
| 	std::string answer{}; | ||||
|  | ||||
| 	int count = op_idx_rolled_over[inst] ? ARRAY_COUNT(op_history[inst]) : op_idx[inst]; | ||||
|  | ||||
| 	for (auto i = 0; i < count; i++) | ||||
| 	{ | ||||
| 		auto idx = op_idx[inst] - 1 - i; | ||||
| 		if (idx < 0) | ||||
| 		{ | ||||
| 			idx += ARRAY_COUNT(op_history[inst]); | ||||
| 		} | ||||
|  | ||||
| 		if ((int)op_history[inst][idx] >= 0 && op_history[inst][idx] < game::OP_count) | ||||
| 		{ | ||||
| 			answer += std::format("{}\n", OpcodeVMToString[op_history[inst][idx]]); | ||||
| 		} | ||||
| 		else | ||||
| 		{ | ||||
| 			answer += std::format("0x{:02x}\n", (int)op_history[inst][idx]); | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	return answer; | ||||
| } | ||||
|  | ||||
| std::string get_gsc_call_stack(game::scriptInstance_t inst) | ||||
| { | ||||
| 	std::string answer{}; | ||||
|  | ||||
| 	int bufferIndex; | ||||
| 	int prevSourcePos; | ||||
| 	int col; | ||||
| 	char line[1024]; | ||||
| 	int lineNum; | ||||
| 	const char* fileName; | ||||
|  | ||||
| 	if (!game::gFs[inst].pos || !game::Scr_IsInOpcodeMemory(inst, game::gFs[inst].pos)) | ||||
| 	{ | ||||
| 		return answer; | ||||
| 	} | ||||
|  | ||||
| 	for (auto frame = game::gScrVmPub[inst].function_frame_start;; frame++) | ||||
| 	{ | ||||
| 		if (!frame->fs.pos || !game::Scr_IsInOpcodeMemory(inst, frame->fs.pos)) | ||||
| 		{ | ||||
| 			break; | ||||
| 		} | ||||
|  | ||||
| 		bufferIndex = game::Scr_GetSourceBuffer(inst, frame->fs.pos - 1); | ||||
| 		prevSourcePos = game::Scr_GetPrevSourcePos(inst, frame->fs.pos - 1, 0); | ||||
| 		lineNum = game::Scr_GetLineInfo(&col, game::gScrParserPub[inst].sourceBufferLookup[bufferIndex].sourceBuf, prevSourcePos, line); | ||||
| 		fileName = game::gScrParserPub[inst].sourceBufferLookup[bufferIndex].buf; | ||||
|  | ||||
| 		answer += std::format("{}({}, {}): '{}'\n", fileName, lineNum, col, line); | ||||
|  | ||||
| 		if (frame == game::gScrVmPub[inst].function_frame) | ||||
| 		{ | ||||
| 			break; | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	return answer; | ||||
| } | ||||
|  | ||||
| std::string get_full_gsc_state_str(game::scriptInstance_t inst) | ||||
| { | ||||
| 	nlohmann::json answer; | ||||
| 	nlohmann::json answer{}; | ||||
| 	auto t = *game::gInst; | ||||
| 	*game::gInst = inst; | ||||
|  | ||||
| 	answer["inst"] = inst; | ||||
| 	answer["gScrVarPub"] = game::gScrVarPub[inst]; | ||||
| 	answer["stack"] = printStack(); | ||||
| 	answer["codeCallStack"] = printStack(); | ||||
| 	answer["gscCallStack"] = get_gsc_call_stack(inst); | ||||
| 	answer["opHistory"] = build_op_history(inst); | ||||
|  | ||||
| 	*game::gInst = t; | ||||
|  | ||||
| 	return answer.dump(2); | ||||
| } | ||||
|  | ||||
| void push_opcode_to_history(game::scriptInstance_t inst, game::OpcodeVM op) | ||||
| { | ||||
| 	assert(inst == 0 || inst == 1); | ||||
| 	//assert((int)op >= 0 && op < game::OP_count); | ||||
|  | ||||
| 	op_history[inst][op_idx[inst]++] = op; | ||||
|  | ||||
| 	if (op_idx[inst] >= ARRAY_COUNT(op_history[inst])) | ||||
| 	{ | ||||
| 		op_idx_rolled_over[inst] = true; | ||||
| 		op_idx[inst] = 0; | ||||
| 	} | ||||
| } | ||||
|  | ||||
| void push_builtin_history(game::scriptInstance_t inst, int idx) | ||||
| { | ||||
| 	inst = inst; | ||||
| 	idx = idx; | ||||
| } | ||||
|  | ||||
| void push_codepos_history(game::scriptInstance_t inst, const char* pos) | ||||
| { | ||||
| 	inst = inst; | ||||
| 	pos = pos; | ||||
| } | ||||
|   | ||||
| @@ -38,6 +38,5 @@ namespace codsrc | ||||
| 	int SL_ConvertFromString(game::scriptInstance_t inst, const char* str); | ||||
| 	int SL_ConvertFromRefString(game::scriptInstance_t inst, game::RefString* refString); | ||||
| 	game::RefString* GetRefString_0(game::scriptInstance_t inst, const char* str); | ||||
| 	const char* SL_DebugConvertToString(unsigned int stringValue, game::scriptInstance_t inst); | ||||
| 	const char* SL_ConvertToStringSafe(unsigned int id, game::scriptInstance_t inst); | ||||
| } | ||||
|   | ||||
| @@ -1066,6 +1066,8 @@ namespace codsrc | ||||
| 			gScrVmPub[inst].outparamcount = outparamcount; | ||||
| 			}*/ | ||||
|  | ||||
| 			push_builtin_history(inst, builtinIndex); | ||||
|  | ||||
| 			assert(builtinIndex >= 0); | ||||
| 			assert(builtinIndex < 1024); | ||||
|  | ||||
| @@ -1130,6 +1132,8 @@ namespace codsrc | ||||
| 		  gScrVmPub[inst].top = localFs.top - 1; | ||||
| 		}*/ | ||||
|  | ||||
| 			push_builtin_history(inst, builtinIndex); | ||||
|  | ||||
| 			assert(builtinIndex >= 0); | ||||
| 			assert(builtinIndex < 1024); | ||||
|  | ||||
| @@ -1292,6 +1296,10 @@ namespace codsrc | ||||
| 			} | ||||
| 			// | ||||
|  | ||||
| 			// our additions | ||||
| 			push_codepos_history(inst, game::gFs[inst].pos); | ||||
| 			// | ||||
|  | ||||
| 			assert(game::gFs[inst].pos); | ||||
|  | ||||
| 		} | ||||
| @@ -2682,7 +2690,7 @@ namespace codsrc | ||||
| 					int currentCaseValue; | ||||
| 					const char* currentCodePos; | ||||
|  | ||||
| 					do | ||||
| 					do // Scr_ReadIntArray(2 * game::gCaseCount[inst]) | ||||
| 					{ | ||||
| 						currentCaseValue = game::Scr_ReadUnsignedInt(inst, &game::gFs[inst].pos); | ||||
| 						currentCodePos = game::Scr_ReadCodePos(inst, &game::gFs[inst].pos); | ||||
| @@ -2712,6 +2720,10 @@ namespace codsrc | ||||
| 		{ | ||||
| 			game::gOpcode[inst] = (game::OpcodeVM)game::Scr_ReadUnsignedByte(inst, &game::gFs[inst].pos); | ||||
| 		interrupt_return: | ||||
| 			// our addition | ||||
| 			push_opcode_to_history(inst, game::gOpcode[inst]); | ||||
| 			// | ||||
|  | ||||
| 			switch ( game::gOpcode[inst] ) | ||||
| 			{ | ||||
| 			case game::OP_End: | ||||
|   | ||||
| @@ -70,5 +70,8 @@ | ||||
| #include "game/structs.hpp" | ||||
| #include "game/symbols.hpp" | ||||
| std::string get_full_gsc_state_str(game::scriptInstance_t inst); | ||||
| void push_opcode_to_history(game::scriptInstance_t inst, game::OpcodeVM op); | ||||
| void push_builtin_history(game::scriptInstance_t inst, int idx); | ||||
| void push_codepos_history(game::scriptInstance_t inst, const char* pos); | ||||
|  | ||||
| using namespace std::literals; | ||||
		Reference in New Issue
	
	Block a user