public static void PrintScript(MjoScript script, IColoredWriter writer) { writer.ForegroundColor = ConsoleColor.DarkYellow; writer.Write("readmark "); writer.ForegroundColor = script.EnableReadMark ? ConsoleColor.Green : ConsoleColor.Red; writer.WriteLine(script.EnableReadMark ? "enable" : "disable"); //writer.ForegroundColor = ConsoleColor.DarkYellow; //writer.Write("entrypoint "); //writer.ForegroundColor = ConsoleColor.Blue; //writer.WriteLine($"${script.EntryPointFunction.NameHash:x8}"); writer.ResetColor(); writer.WriteLine(); switch (script.Representation) { case MjoScriptRepresentation.ControlFlowGraph: bool first = true; foreach (var function in script.Functions) { if (!first) { writer.WriteLine(); } first = false; PrintFunction(function, writer); } break; default: foreach (var functionEntry in script.FunctionIndex) { writer.ForegroundColor = ConsoleColor.DarkYellow; writer.Write("index "); writer.ForegroundColor = ConsoleColor.Blue; writer.Write($"${functionEntry.NameHash:x8} "); writer.ForegroundColor = ConsoleColor.DarkGray; writer.Write($"0x{functionEntry.Offset:x4}"); if (functionEntry.Offset == script.EntryPointOffset) { writer.ForegroundColor = ConsoleColor.DarkYellow; writer.Write(" entrypoint"); } writer.ResetColor(); writer.WriteLine(); } writer.WriteLine(); foreach (var instruction in script.Instructions) { PrintInstruction(instruction, writer); } break; } }
public static void PrintFunction(Function function, IColoredWriter writer) { PrintFunctionHeader(function, writer); bool first = true; foreach (var block in function.Blocks) { if (!first) { writer.WriteLine(); } first = false; PrintBasicBlock(block, writer); } writer.WriteLine('}'); }
public static void PrintBasicBlock(BasicBlock block, IColoredWriter writer) { writer.Write(Indent); writer.ForegroundColor = ConsoleColor.Magenta; writer.Write(block.Name); writer.WriteLine(':'); writer.ResetColor(); foreach (var instruction in block.Instructions) { writer.Write(Indent); writer.Write(Indent); PrintInstruction(instruction, writer); } }
public static void PrintFunctionHeader(Function function, IColoredWriter writer) { writer.ForegroundColor = ConsoleColor.Blue; writer.Write("func "); writer.Write($"${function.NameHash:x8}"); writer.ResetColor(); writer.Write("("); bool first = true; foreach (var type in function.ParameterTypes) { if (!first) { writer.Write(", "); } first = false; writer.ForegroundColor = ConsoleColor.Cyan; writer.Write(type.ToString().ToLower()); writer.ResetColor(); } writer.Write(") "); if (function.IsEntryPoint) { writer.ForegroundColor = ConsoleColor.DarkYellow; writer.Write("entrypoint "); writer.ResetColor(); } writer.Write("{"); if (function.Script.Project != null && function.Script.Project.TryGetFunctionName(function.NameHash, out string name) || Data.KnownFunctionNamesByHash.TryGetValue(function.NameHash, out name)) { writer.ForegroundColor = ConsoleColor.DarkGray; writer.Write(" ; "); writer.Write(name); writer.ResetColor(); } writer.WriteLine(); }
public static void PrintInstruction(Instruction instruction, IColoredWriter writer) { if (instruction.Offset != null) { writer.ForegroundColor = ConsoleColor.DarkGray; writer.Write($"{instruction.Offset:x4}: "); } writer.ForegroundColor = instruction.Opcode.Mnemonic == "line" ? ConsoleColor.DarkGray : instruction.Opcode.Mnemonic == "phi" ? ConsoleColor.DarkYellow : ConsoleColor.White; writer.Write($"{instruction.Opcode.Mnemonic,-13}"); writer.ResetColor(); foreach (char operand in instruction.Opcode.Encoding) { if (operand == '0') { continue; } writer.Write(' '); if (operand == 'o' && instruction.Flags.Scope() != MjoScope.Local && instruction.VarOffset == -1) { continue; } switch (operand) { case 't': // type list writer.Write('['); bool first = true; foreach (var type in instruction.TypeList) { if (!first) { writer.Write(", "); } writer.ForegroundColor = ConsoleColor.Cyan; writer.Write(type.ToString().ToLower()); writer.ResetColor(); first = false; } writer.Write(']'); break; case 's': // string data if (instruction.String != null) { writer.ForegroundColor = ConsoleColor.DarkGreen; writer.Write('"'); writer.Write(instruction.String.Escape()); writer.Write('"'); writer.ResetColor(); } else { Debug.Assert(instruction.ExternalKey != null); writer.ForegroundColor = ConsoleColor.Blue; writer.Write('%'); writer.Write('{'); writer.ForegroundColor = ConsoleColor.White; writer.Write(instruction.ExternalKey); writer.ForegroundColor = ConsoleColor.Blue; writer.Write('}'); writer.ForegroundColor = ConsoleColor.DarkGray; if (instruction.Script != null) { writer.Write(" ; "); writer.Write('"'); writer.Write(instruction.Script.ExternalizedStrings[instruction.ExternalKey].Escape()); writer.Write('"'); writer.ResetColor(); } } break; case 'f': { // flags var flags = instruction.Flags; writer.ForegroundColor = ConsoleColor.Cyan; writer.Write(flags.Scope().ToString().ToLower()); writer.Write(' '); writer.Write(flags.Type().ToString().ToLower()); switch (flags.InvertMode()) { case MjoInvertMode.Numeric: writer.Write(" invert_numeric"); break; case MjoInvertMode.Boolean: writer.Write(" invert_boolean"); break; case MjoInvertMode.Bitwise: writer.Write(" invert_bitwise"); break; } switch (flags.Modifier()) { case MjoModifier.PreIncrement: writer.Write(" preinc"); break; case MjoModifier.PreDecrement: writer.Write(" predec"); break; case MjoModifier.PostIncrement: writer.Write(" postinc"); break; case MjoModifier.PostDecrement: writer.Write(" postdec"); break; } switch (flags.Dimension()) { case 1: writer.Write(" dim1"); break; case 2: writer.Write(" dim2"); break; case 3: writer.Write(" dim3"); break; } writer.ResetColor(); break; } case 'h': // name hash if (instruction.IsSysCall) { writer.ForegroundColor = ConsoleColor.Yellow; } else if (instruction.IsCall) { writer.ForegroundColor = ConsoleColor.Blue; } else { writer.ForegroundColor = ConsoleColor.Red; } writer.Write('$'); writer.Write(instruction.Hash.ToString("x8")); writer.ResetColor(); break; case 'o': // variable offset writer.Write(instruction.VarOffset); break; case '0': // 4 byte address placeholder break; case 'i': // integer constant writer.Write(instruction.IntValue); break; case 'r': // float constant writer.Write(instruction.FloatValue.ToString(CultureInfo.InvariantCulture)); break; case 'a': // argument count writer.Write('('); writer.Write(instruction.ArgumentCount); writer.Write(')'); break; case 'j': // jump offset writer.ForegroundColor = ConsoleColor.Magenta; if (instruction.JumpTarget != null) { Debug.Assert(instruction.Block != null); writer.Write('@'); writer.Write(instruction.JumpTarget.Name); } else { Debug.Assert(instruction.Block == null); PrintRelativeJump(instruction.JumpOffset !.Value, writer); } writer.ResetColor(); break; case 'l': // line number writer.ForegroundColor = ConsoleColor.DarkGray; writer.Write('#'); writer.Write(instruction.LineNumber); writer.ResetColor(); break; case 'c': // switch case table first = true; if (instruction.SwitchTargets != null) { Debug.Assert(instruction.Block != null); foreach (var targetBlock in instruction.SwitchTargets) { if (!first) { writer.Write(", "); } writer.ForegroundColor = ConsoleColor.Magenta; writer.Write('@'); writer.Write(targetBlock.Name); writer.ResetColor(); first = false; } } else { Debug.Assert(instruction.Block == null); foreach (int offset in instruction.SwitchOffsets) { if (!first) { writer.Write(", "); } writer.ForegroundColor = ConsoleColor.Magenta; PrintRelativeJump(offset, writer); writer.ResetColor(); first = false; } } break; case 'p': // phi node first = true; if (instruction is PhiInstruction phi) { foreach (var predecessor in phi.Block.Predecessors) { if (!first) { writer.Write(", "); } writer.ForegroundColor = ConsoleColor.Magenta; writer.Write('@'); writer.Write(predecessor.Name); writer.ResetColor(); first = false; } } else { throw new Exception("Only phi instructions are allowed to have the 'p' encoding specifier"); } break; } } if (instruction.IsSysCall && Data.KnownSyscallNamesByHash.TryGetValue(instruction.Hash, out string name)) { writer.ForegroundColor = ConsoleColor.DarkGray; writer.Write(" ; $"); writer.Write(name); writer.ResetColor(); } else if (instruction.IsCall) { var project = instruction.Script?.Project; uint hash = instruction.Hash; if (project != null && project.TryGetFunctionName(hash, out string calleeName) || Data.KnownFunctionNamesByHash.TryGetValue(hash, out calleeName)) { writer.ForegroundColor = ConsoleColor.DarkGray; writer.Write(" ; "); writer.Write(calleeName); writer.ResetColor(); } else if (project != null && project.FunctionMap.TryGetValue(hash, out var functions) && functions.Any()) { writer.ForegroundColor = ConsoleColor.DarkGray; writer.Write(" ; declared in "); writer.Write(functions[0].DeclaringScript); writer.ResetColor(); } } else if (instruction.IsLoad || instruction.IsStore) { uint hash = instruction.Hash; if (Data.KnownVariableNamesByHash.TryGetValue(hash, out string varName)) { writer.ForegroundColor = ConsoleColor.DarkGray; writer.Write(" ; "); writer.Write(varName); writer.ResetColor(); } } writer.WriteLine(); }
public static void PrintLabel(BasicBlock block, IColoredWriter writer) { writer.ForegroundColor = ConsoleColor.Magenta; writer.WriteLine($"{block.Name}:"); writer.ResetColor(); }