// ---------------------------------------------------------------------------- // // Copyright (c) Microsoft Corporation. All rights reserved. // // ---------------------------------------------------------------------------- using System; using System.Collections; public class SyscallBuilder { static Hashtable classTable = new Hashtable(); static Hashtable structTable = new Hashtable(); static Hashtable paramTable = new Hashtable(); static int lineNumber = 0; static void AddType(string t) { if (t.StartsWith("struct ")) { int end = t.IndexOf(" ", 7); if (end == -1) { end = t.Length; } string structName = t.Substring(7, end - 7); if (end < t.Length) { structTable[structName] = ""; } else { int ssize; if (structName.EndsWith("Handle")) { ssize = 4; } else { if (!paramTable.ContainsKey("struct " + structName)) { throw new Exception("unknown struct type: " + t); } ssize = (int) paramTable["struct " + structName]; } structTable[structName] = "char data[" + ssize + "];"; } } } public static void Generate(string[] args) { bool genHdr = args[0] == "/genhdr"; bool genLib = args[0] == "/genlib"; bool genEntry = args[0] == "/genentry"; if (genLib) { Console.WriteLine("#include \"syscalls.h\""); Console.WriteLine(); } if (genEntry) { Console.WriteLine("#include \"syscalls.h\""); } int n = 1; paramTable["void"] = 0; paramTable["int"] = 4; paramTable["unsigned int"] = 4; paramTable["unsigned char"] = 4; paramTable["unsigned short"] = 4; paramTable["wchar_t"] = 4; paramTable["bool"] = 4; paramTable["__int64"] = 8; paramTable["unsigned __int64"] = 8; paramTable["struct Struct_System_TimeSpan"] = 8; paramTable["struct Struct_System_DateTime"] = 8; paramTable["struct Struct_System_SchedulerTime"] = 8; paramTable["struct Struct_Microsoft_Singularity_V1_Types_SystemType"] = 4; paramTable["struct Struct_Microsoft_Singularity_V1_Threads_ThreadState"] = 4; paramTable["struct Struct_Microsoft_Singularity_V1_Processes_ProcessState"] = 4; paramTable["struct Struct_Microsoft_Singularity_V1_Services_ParameterCode"] = 4; while (true) { string s = Console.ReadLine(); lineNumber++; if (s == null) { break; } if (s.IndexOf('?') == -1) { continue; } if ( s.IndexOf("Struct_Microsoft_Singularity_V1_Services_SharedHeapService::g_GetData") != -1 || s.IndexOf("Struct_Microsoft_Singularity_V1_Services_SharedHeapService::g_GetSize") != -1 || s.IndexOf("Struct_Microsoft_Singularity_V1_Types_SystemType::g_IsNull") != -1) { continue; } if (s.IndexOf("(public: ") == -1) { // Skip non attributed exports continue; } s = s.Replace("struct void", "void"); int i = s.IndexOf("static"); if (i == -1) { throw new Exception("not static"); } i += 7; string decl = s.Substring(i, s.IndexOf(')', i) + 1 - i); i = s.IndexOf("__fastcall", i); if (i == -1) { throw new Exception("not fastcall"); } string ret = decl.Substring(0, decl.IndexOf(" __fastcall")); try { AddType(ret); } catch { Console.WriteLine("Failed at input line {0}\n", lineNumber); throw; } i = s.IndexOf(' ', i) + 1; bool isAbi; { int j = s.IndexOf("::", i); int k = s.IndexOf("(", j); string className = s.Substring(i, j - i); string methodName = s.Substring(i, k - i); string methodLocalName = s.Substring(j + 2, k - (j + 2)); // These two symbols are special and shouldn't have ring3 // stubs isAbi = (!methodLocalName.StartsWith("g_LinkStack")) && (!methodLocalName.StartsWith("g_UnlinkStack")); Hashtable methods = (Hashtable)classTable[className]; if (methods == null) { methods = new Hashtable(); classTable[className] = methods; } methods[decl] = true; string typ = ret + "(*)" + s.Substring(k, s.IndexOf(')', k) + 1 - k); if (genEntry && isAbi) { Console.WriteLine("static int f" + n + " = int((" + typ + ")" + methodName + ");"); } } i = s.IndexOf('(', i) + 1; int smallWords = 0; int largeWords = 0; while (s[i] != ')') { int j = s.IndexOf(',', i); if (j == -1) { j = s.IndexOf(')', i); } string param = s.Substring(i, j - i); int size; if (param.EndsWith("*") || param.EndsWith("Handle")) { size = 4; } else { if (!paramTable.ContainsKey(param)) { throw new Exception("unknown parameter type: " + param); } size = (int) paramTable[param]; } //Console.WriteLine(size + ":" + param); try { AddType(param); } catch { Console.WriteLine("Failed at input line {0}\n", lineNumber); throw; } i = j + 1; if (size <= 4) { smallWords++; } else { largeWords += size / 4; } } int paramRegs = (smallWords < 2) ? (smallWords) : 2; int paramSlots = smallWords + largeWords - paramRegs; if (genLib && isAbi) { Console.WriteLine("__declspec(naked dllexport) " + decl); Console.WriteLine("{__asm {"); Console.WriteLine(" push edx"); Console.WriteLine(" push ecx"); Console.WriteLine(" mov ecx, " + n); Console.WriteLine(" mov edx, esp"); Console.WriteLine(" push done"); Console.WriteLine(" _emit 0x0f;"); Console.WriteLine(" _emit 0x34; //sysenter"); Console.WriteLine(" done:"); Console.WriteLine(" ret " + 4 * paramSlots); Console.WriteLine("}}"); Console.WriteLine(); } if (genEntry && isAbi) { Console.WriteLine("__declspec(naked) static void abi" + n + "() {__asm {"); for (int j = paramSlots - 1; j >= 0; j--) { Console.WriteLine(" push [eax + " + (12 + j * 4) + "]"); } Console.WriteLine(" mov edx, [eax + 4]"); Console.WriteLine(" mov ecx, [eax + 0]"); Console.WriteLine(" call f" + n); Console.WriteLine(" ret"); Console.WriteLine("}}"); } if (isAbi) { n++; } } if (genHdr) { foreach (string s in structTable.Keys) { if (!classTable.ContainsKey(s)) { Console.WriteLine("struct " + s + " {" + structTable[s] + "};"); } } Console.WriteLine(); foreach (string c in classTable.Keys) { Console.WriteLine("struct " + c); Console.WriteLine("{"); if (structTable.ContainsKey(c)) { string s = (string) structTable[c]; if (s != "") { Console.WriteLine(" " + s); } } foreach (string m in ((Hashtable)classTable[c]).Keys) { Console.WriteLine(" __declspec(dllexport) static " + m + ";"); } Console.WriteLine("};"); Console.WriteLine(); } } if (genEntry) { Console.WriteLine(); Console.WriteLine("void EnterRing0();"); Console.WriteLine("int syscallEntryTable[] ="); Console.WriteLine("{"); Console.WriteLine("int(EnterRing0)"); for (int i = 1; i < n; i++) { if (i > 0) { Console.WriteLine(","); } Console.Write(" int(abi" + i + ")"); } Console.WriteLine(); Console.WriteLine("};"); } } public static int Main(string[] args) { try { Generate(args); } catch (Exception e) { Console.Write(e); return -1; } return 0; } }