public unsafe static void DumpFunctionToCSV(string name, string filename) { using (FileStream fileStream = File.Open(filename, FileMode.Create, FileAccess.Write, FileShare.Write)) using (StreamWriter streamWriter = new StreamWriter(fileStream)) { VirtualMachine *ptr = *GameFunctions.GetThreadLocalStorage()->Jass.AsUnsafe()->VirtualMachine; HT_Node * ptr2 = ptr->FunctionTable->Lookup(name); if (ptr2 != null) { OpCode *value = (OpCode *)ptr2->Value; string text = string.Empty; int num = -1; while (value[num].OpType != OpCodeType.EndFunction) { text = $"{text}0x{num + 1:X4}{ByteCodeToString(value + num, ";")}{Environment.NewLine}"; num++; } streamWriter.WriteLine(text); Trace.WriteLine($"Function '{name}' dumped to '{filename}'"); } else { Trace.WriteLine($"Function '{name}' could not be found!"); } } }
public unsafe bool TryGetOpCodeFunctionName(OpCode *op, out string name) { while (op->OpType != OpCodeType.Function) { op += -1; if (op < SymbolTable->FirstOperation) { name = string.Empty; return(false); } } name = SymbolTable->StringPool->Nodes[op->Argument]->Value; return(true); }
public unsafe static void DumpFunctionToTrace(string name) { VirtualMachine *ptr = *GameFunctions.GetThreadLocalStorage()->Jass.AsUnsafe()->VirtualMachine; HT_Node * ptr2 = ptr->FunctionTable->Lookup(name); if (ptr2 != null) { OpCode *value = (OpCode *)ptr2->Value; string text = string.Empty; int num = -1; while (value[num].OpType != OpCodeType.EndFunction) { text = $"{text}0x{num + 1:X4}{ByteCodeToString(value + num, "\t")}{Environment.NewLine}"; num++; } Trace.WriteLine(text); Trace.WriteLine($"Function '{name}'"); } else { Trace.WriteLine($"Function '{name}' could not be found!"); } }
private static unsafe CodeResult VirtualMachine__RunCodeHook(VirtualMachine *vm, OpCode *op, IntPtr a3, uint opLimit, IntPtr a5) { CodeResult result = VirtualMachine__RunCode(vm, op, a3, opLimit, a5); try { VirtualMachine__RunCodeCallback?.Invoke(vm, op, a3, opLimit, a5, result); } catch (Exception ex) { Trace.WriteLine($"Unhandled Exception in {nameof(Script)}.{nameof(VirtualMachine__RunCodeHook)}!"); Trace.WriteLine(ex.ToString()); } return(result); }
private static unsafe CodeResult VirtualMachine__RunCodeHook(VirtualMachine *vm, OpCode *op, IntPtr a3, uint opLimit, IntPtr a5) { //string value = vm->TryGetOpCodeFunctionName(op, out string name) ? name : null; //if (value != null) Trace.WriteLine($"[RunCode] {name} Start"); CodeResult result = VirtualMachine__RunCode(vm, op, a3, opLimit, a5); try { VirtualMachine__RunCodeCallback?.Invoke(vm, op, a3, opLimit, a5, result); //if (value != null) Trace.WriteLine($"[RunCode] {name} End"); } catch (Exception ex) { Trace.WriteLine($"Unhandled Exception in {nameof(Script)}.{nameof(VirtualMachine__RunCodeHook)}!"); Trace.WriteLine(ex.ToString()); } return(result); }
private unsafe static void Jass_VirtualMachine__RunCodeCallback(VirtualMachine *vm, OpCode *op, IntPtr a3, uint opLimit, IntPtr a5, CodeResult result) { if (result == CodeResult.Success || result == CodeResult.ThreadPause || result == CodeResult.ThreadSync) { return; } if (!vm->TryGetOpCodeFunctionName(op, out string text)) { text = "unknown function"; } string str = string.Empty; switch (result) { case CodeResult.OpLimit: str = $"[Debugger] |cffff0000Error|r: Op limit({opLimit}) exceeded in {text}."; break; case CodeResult.VariableUninitialized: str = $"[Debugger] |cffff0000Error|r: Uninitialized variable read in {text}."; break; case CodeResult.DivideByZero: str = $"[Debugger] |cffff0000Error|r: Divide by zero in {text}."; break; default: str = $"[Debugger] |cffff0000Error|r: Unknown error({result}) in {text}."; break; } Interface.GameUI->ChatMessage->WriteLine(str, Color.White, 60f); Trace.WriteLine(str); }
public unsafe static string ByteCodeToString(OpCode *op, string split) { VirtualMachine *ptr = *GameFunctions.GetThreadLocalStorage()->Jass.AsUnsafe()->VirtualMachine; string text = $"{split}0x{op->R1:X2}"; OpCodeType opType = op->OpType; if (opType == OpCodeType.GetArray) { text = $"{text}:{JassTypeToString((JassType)op->R1)}"; } text = $"{text}{split}0x{op->R2:X2}"; switch (op->OpType) { case OpCodeType.Literal: case OpCodeType.GetVar: case OpCodeType.Code: text = $"{text}:{JassTypeToString((JassType)op->R2)}"; break; } text = $"{text}{split}0x{op->R2:X2}"; switch (op->OpType) { case OpCodeType.Local: case OpCodeType.Global: case OpCodeType.Constant: case OpCodeType.PopFuncArg: text = $"{text}:{JassTypeToString((JassType)op->R3)}"; break; } text = $"{text}{split}0x{(byte)op->OpType:X2}{split}{op->OpType}"; switch (op->OpType) { case OpCodeType.Function: case OpCodeType.Local: case OpCodeType.Global: case OpCodeType.Constant: case OpCodeType.PopFuncArg: case OpCodeType.GetVar: case OpCodeType.GetArray: case OpCodeType.SetVar: case OpCodeType.SetArray: case OpCodeType.Native: case OpCodeType.JassCall: return(text + split + (*(ptr->SymbolTable->StringPool->Nodes + op->Argument * sizeof(StringNode *) / sizeof(StringNode *)))->Value); case OpCodeType.Literal: switch (op->R2) { case 5: text = $"{text}{split}{Memory.Read<float>(new IntPtr(&op->Argument))}"; goto IL_2FC; case 6: text = $"{text}{split}\"{(*(ptr->SymbolTable->StringPool->Nodes + op->Argument * sizeof(StringNode*) / sizeof(StringNode*)))->Value}\""; goto IL_2FC; case 8: { int argument = op->Argument; if (argument != 0) { if (argument != 1) { text = $"{text}{split} = (boolean){argument}"; } else { text = $"{text}{split} = true"; } } else { text = $"{text}{split} = false"; } goto IL_2FC; } } text = $"{text}{split}{op->Argument}"; IL_2FC: return(text); } text = $"{text}{split}{op->Argument}"; return(text); }