using System; using System.Collections.Generic; using System.Linq; using System.Text; using Microsoft.Build.Utilities; using Microsoft.Build.Framework; using System.Reflection; using Cosmos.Compiler.Assembler; using Cosmos.Compiler.Assembler.X86; using System.IO; using Cosmos.Build.Common; using Microsoft.Win32; using Cosmos.IL2CPU.X86; using Cosmos.IL2CPU; namespace Cosmos.Build.MSBuild { public class IL2CPU : AppDomainIsolatedTask { private static bool mFirstTime = true; public IL2CPU() { // CheckFirstTime(); } private static void CheckFirstTime() { if (mFirstTime) { // mFirstTime = false; var xSearchDirs = new List(); xSearchDirs.Add(Path.GetDirectoryName(typeof(IL2CPU).Assembly.Location)); using (var xReg = Registry.LocalMachine.OpenSubKey("Software\\Cosmos", false)) { var xPath = (string)xReg.GetValue(null); xSearchDirs.Add(xPath); xSearchDirs.Add(Path.Combine(xPath, "Kernel")); } mSearchDirs = xSearchDirs.ToArray(); AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(CurrentDomain_AssemblyResolve); Assembly.LoadWithPartialName("Cosmos.Sys"); Assembly.LoadWithPartialName("Cosmos.Hardware"); Assembly.LoadWithPartialName("Cosmos.Kernel"); Assembly.LoadWithPartialName("Cosmos.Sys.FileSystem"); } } private static string[] mSearchDirs = new string[0]; static Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args) { var xShortName = args.Name; if (xShortName.Contains(',')) { xShortName = xShortName.Substring(0, xShortName.IndexOf(',')); // TODO: remove following statement if it proves unnecessary if (xShortName.Contains(',')) { throw new Exception("Algo error"); } } foreach (var xDir in mSearchDirs) { var xPath = Path.Combine(xDir, xShortName + ".dll"); if (File.Exists(xPath)) { return Assembly.LoadFrom(xPath); } xPath = Path.Combine(xDir, xShortName + ".exe"); if (File.Exists(xPath)) { return Assembly.LoadFrom(xPath); } } if (mStaticLog != null) { mStaticLog("Assembly '" + args.Name + "' not resolved!"); } return null; } private static Action mStaticLog = null; private void DoInitTypes() { var xType = typeof(Cosmos.Hardware.Plugs.FCL.System.Console); Log.LogMessage("Console plug loaded: {0}", xType.FullName); xType = typeof(Cosmos.Sys.Plugs.Deboot); Log.LogMessage("Deboot plug loaded: {0}", xType.FullName); xType = typeof(Cosmos.Kernel.Plugs.ArrayListImpl); Log.LogMessage("ArrayList plug loaded: {0}", xType.FullName); } #region properties [Required] public string DebugMode{ get; set; } public string TraceAssemblies { get; set; } public byte DebugCom { get; set; } [Required] public bool UseNAsm { get; set; } [Required] public ITaskItem[] References { get; set; } [Output] public string OutputFilename { get; set; } public bool EnableLogging { get; set; } [Required] public string OutputDir { get; set; } public bool EmitDebugSymbols { get; set; } #endregion private bool Initialize() { CheckFirstTime(); DoInitTypes(); // load searchpaths: Log.LogMessage("SearchPath: '{0}'", References); if (References!=null) { var xSearchPaths = new List(mSearchDirs); foreach (var xRef in References) { if (xRef.MetadataNames.OfType().Contains("FullPath")) { var xDir = Path.GetDirectoryName(xRef.GetMetadata("FullPath")); if (!xSearchPaths.Contains(xDir)) { xSearchPaths.Add(xDir); } } } mSearchDirs = xSearchPaths.ToArray(); } if (String.IsNullOrEmpty(DebugMode)) { mDebugMode = Cosmos.Build.Common.DebugMode.None; } else { if (!Enum.GetNames(typeof(DebugMode)).Contains(DebugMode, StringComparer.InvariantCultureIgnoreCase)) { Log.LogError("Invalid DebugMode specified"); return false; } mDebugMode = (DebugMode)Enum.Parse(typeof(DebugMode), DebugMode); } if (String.IsNullOrEmpty(TraceAssemblies)) { mTraceAssemblies = Cosmos.Build.Common.TraceAssemblies.User; } else { if (!Enum.GetNames(typeof(TraceAssemblies)).Contains(TraceAssemblies, StringComparer.InvariantCultureIgnoreCase)) { Log.LogError("Invalid TraceAssemblies specified"); return false; } mTraceAssemblies = (TraceAssemblies)Enum.Parse(typeof(TraceAssemblies), TraceAssemblies); } return true; } private DebugMode mDebugMode = Cosmos.Build.Common.DebugMode.None; private TraceAssemblies mTraceAssemblies = Cosmos.Build.Common.TraceAssemblies.All; private void LogTime(string message) { // } public override bool Execute() { try { Log.LogMessage("Executing IL2CPU on assembly"); if (!Initialize()) { return false; } LogTime("Engine execute started"); // find the kernel's entry point now. we are looking for a public class Kernel, with public static void Boot() MethodBase xInitMethod=null; #region detect entry point method foreach (var xRef in References) { if (xRef.MetadataNames.OfType().Contains("FullPath")) { var xFile = xRef.GetMetadata("FullPath"); if (File.Exists(xFile)) { var xAssembly = Assembly.LoadFile(xFile); foreach (var xType in xAssembly.GetExportedTypes()) { if (xType.Name == "Kernel") { var xMethod = xType.GetMethod("Boot"); if (!xMethod.IsStatic) { continue; } if (xInitMethod != null) { // already found an init method. log error. Log.LogError("Project has multiple Kernel.Boot methods!"); return false; } xInitMethod = xMethod; } } } } } #endregion detect entry point method if (xInitMethod == null) { Log.LogError("No Kernel.Boot method found!"); return false; } OutputFilename = xInitMethod.DeclaringType.Assembly.GetName().Name; var xAsm = new AppAssemblerNasm(DebugCom); xAsm.DebugMode = mDebugMode; xAsm.TraceAssemblies = mTraceAssemblies; #if OUTPUT_ELF xAsm.EmitELF = true; #endif var xNasmAsm = (AssemblerNasm)xAsm.Assembler; xAsm.Assembler.Initialize(); using (var xScanner = new ILScanner(xAsm)) { xScanner.TempDebug += x => Log.LogMessage(x); if(EnableLogging) { xScanner.EnableLogging(Path.Combine(OutputDir, OutputFilename + ".log.html")); } xScanner.Execute(xInitMethod); using (var xOut = new StreamWriter(Path.Combine(OutputDir, OutputFilename + ".asm"), false)) { if(EmitDebugSymbols) { xNasmAsm.FlushText(xOut); xAsm.WriteDebugSymbols(Path.Combine(OutputDir, OutputFilename + ".cxdb")); } else { xAsm.Assembler.FlushText(xOut); } } } LogTime("Engine execute finished"); return true; } catch (Exception E) { Log.LogMessage("Loaded assemblies: "); foreach (var xAsm in AppDomain.CurrentDomain.GetAssemblies()) { Log.LogMessage(xAsm.Location); } Log.LogErrorFromException(E, true); return false; } } } }