diff --git a/source/Cosmos.sln b/source/Cosmos.sln index 8b65884c8..3fd42f53a 100644 --- a/source/Cosmos.sln +++ b/source/Cosmos.sln @@ -627,7 +627,6 @@ Global {B2F76E27-EAE1-4ECF-8A33-77B2CFBB9367}.Release|x86.Build.0 = Release|x86 {6658FCE0-7032-4B7B-BD95-F2765C393442}.Bootstrap|Any CPU.ActiveCfg = Release|x86 {6658FCE0-7032-4B7B-BD95-F2765C393442}.Bootstrap|Mixed Platforms.ActiveCfg = Release|x86 - {6658FCE0-7032-4B7B-BD95-F2765C393442}.Bootstrap|Mixed Platforms.Build.0 = Release|x86 {6658FCE0-7032-4B7B-BD95-F2765C393442}.Bootstrap|x86.ActiveCfg = Debug|x86 {6658FCE0-7032-4B7B-BD95-F2765C393442}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {6658FCE0-7032-4B7B-BD95-F2765C393442}.Debug|Any CPU.Build.0 = Debug|Any CPU @@ -709,7 +708,6 @@ Global {AE684C98-F100-47AE-9C8C-E71BF8C9F8AA}.Bootstrap|Any CPU.ActiveCfg = Release|Any CPU {AE684C98-F100-47AE-9C8C-E71BF8C9F8AA}.Bootstrap|Any CPU.Build.0 = Release|Any CPU {AE684C98-F100-47AE-9C8C-E71BF8C9F8AA}.Bootstrap|Mixed Platforms.ActiveCfg = Release|Any CPU - {AE684C98-F100-47AE-9C8C-E71BF8C9F8AA}.Bootstrap|Mixed Platforms.Build.0 = Release|Any CPU {AE684C98-F100-47AE-9C8C-E71BF8C9F8AA}.Bootstrap|x86.ActiveCfg = Release|Any CPU {AE684C98-F100-47AE-9C8C-E71BF8C9F8AA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {AE684C98-F100-47AE-9C8C-E71BF8C9F8AA}.Debug|Any CPU.Build.0 = Debug|Any CPU @@ -725,7 +723,6 @@ Global {54795C40-B3E8-4DBB-A3DE-FACBADD20ADB}.Bootstrap|Any CPU.ActiveCfg = Release|Any CPU {54795C40-B3E8-4DBB-A3DE-FACBADD20ADB}.Bootstrap|Any CPU.Build.0 = Release|Any CPU {54795C40-B3E8-4DBB-A3DE-FACBADD20ADB}.Bootstrap|Mixed Platforms.ActiveCfg = Release|Any CPU - {54795C40-B3E8-4DBB-A3DE-FACBADD20ADB}.Bootstrap|Mixed Platforms.Build.0 = Release|Any CPU {54795C40-B3E8-4DBB-A3DE-FACBADD20ADB}.Bootstrap|x86.ActiveCfg = Release|Any CPU {54795C40-B3E8-4DBB-A3DE-FACBADD20ADB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {54795C40-B3E8-4DBB-A3DE-FACBADD20ADB}.Debug|Any CPU.Build.0 = Debug|Any CPU @@ -741,7 +738,6 @@ Global {FD4B2006-B518-4884-B196-C2EF2B83FD6F}.Bootstrap|Any CPU.ActiveCfg = Release|Any CPU {FD4B2006-B518-4884-B196-C2EF2B83FD6F}.Bootstrap|Any CPU.Build.0 = Release|Any CPU {FD4B2006-B518-4884-B196-C2EF2B83FD6F}.Bootstrap|Mixed Platforms.ActiveCfg = Release|Any CPU - {FD4B2006-B518-4884-B196-C2EF2B83FD6F}.Bootstrap|Mixed Platforms.Build.0 = Release|Any CPU {FD4B2006-B518-4884-B196-C2EF2B83FD6F}.Bootstrap|x86.ActiveCfg = Release|Any CPU {FD4B2006-B518-4884-B196-C2EF2B83FD6F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {FD4B2006-B518-4884-B196-C2EF2B83FD6F}.Debug|Any CPU.Build.0 = Debug|Any CPU @@ -757,7 +753,6 @@ Global {0D162A82-CBC1-4A39-916D-E1079B212DDE}.Bootstrap|Any CPU.ActiveCfg = Release|Any CPU {0D162A82-CBC1-4A39-916D-E1079B212DDE}.Bootstrap|Any CPU.Build.0 = Release|Any CPU {0D162A82-CBC1-4A39-916D-E1079B212DDE}.Bootstrap|Mixed Platforms.ActiveCfg = Release|Any CPU - {0D162A82-CBC1-4A39-916D-E1079B212DDE}.Bootstrap|Mixed Platforms.Build.0 = Release|Any CPU {0D162A82-CBC1-4A39-916D-E1079B212DDE}.Bootstrap|x86.ActiveCfg = Release|Any CPU {0D162A82-CBC1-4A39-916D-E1079B212DDE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {0D162A82-CBC1-4A39-916D-E1079B212DDE}.Debug|Any CPU.Build.0 = Debug|Any CPU @@ -1166,7 +1161,6 @@ Global {6882C74B-3ED2-4D76-9E7B-67B6A28808BC}.Bootstrap|Any CPU.ActiveCfg = Release|Any CPU {6882C74B-3ED2-4D76-9E7B-67B6A28808BC}.Bootstrap|Any CPU.Build.0 = Release|Any CPU {6882C74B-3ED2-4D76-9E7B-67B6A28808BC}.Bootstrap|Mixed Platforms.ActiveCfg = Release|Any CPU - {6882C74B-3ED2-4D76-9E7B-67B6A28808BC}.Bootstrap|Mixed Platforms.Build.0 = Release|Any CPU {6882C74B-3ED2-4D76-9E7B-67B6A28808BC}.Bootstrap|x86.ActiveCfg = Release|Any CPU {6882C74B-3ED2-4D76-9E7B-67B6A28808BC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {6882C74B-3ED2-4D76-9E7B-67B6A28808BC}.Debug|Any CPU.Build.0 = Debug|Any CPU @@ -1180,7 +1174,6 @@ Global {6882C74B-3ED2-4D76-9E7B-67B6A28808BC}.Release|x86.ActiveCfg = Release|Any CPU {23476FAD-3712-4A4B-90C0-CCCC9AC8D953}.Bootstrap|Any CPU.ActiveCfg = Release|x86 {23476FAD-3712-4A4B-90C0-CCCC9AC8D953}.Bootstrap|Mixed Platforms.ActiveCfg = Release|x86 - {23476FAD-3712-4A4B-90C0-CCCC9AC8D953}.Bootstrap|Mixed Platforms.Build.0 = Release|x86 {23476FAD-3712-4A4B-90C0-CCCC9AC8D953}.Bootstrap|x86.ActiveCfg = Release|x86 {23476FAD-3712-4A4B-90C0-CCCC9AC8D953}.Debug|Any CPU.ActiveCfg = Debug|x86 {23476FAD-3712-4A4B-90C0-CCCC9AC8D953}.Debug|Mixed Platforms.ActiveCfg = Debug|x86 @@ -1194,7 +1187,6 @@ Global {23476FAD-3712-4A4B-90C0-CCCC9AC8D953}.Release|x86.Build.0 = Release|x86 {3296FE8A-A2BA-4291-8FA0-184CA14E1271}.Bootstrap|Any CPU.ActiveCfg = Release|x86 {3296FE8A-A2BA-4291-8FA0-184CA14E1271}.Bootstrap|Mixed Platforms.ActiveCfg = Release|x86 - {3296FE8A-A2BA-4291-8FA0-184CA14E1271}.Bootstrap|Mixed Platforms.Build.0 = Release|x86 {3296FE8A-A2BA-4291-8FA0-184CA14E1271}.Bootstrap|x86.ActiveCfg = Release|x86 {3296FE8A-A2BA-4291-8FA0-184CA14E1271}.Debug|Any CPU.ActiveCfg = Debug|x86 {3296FE8A-A2BA-4291-8FA0-184CA14E1271}.Debug|Mixed Platforms.ActiveCfg = Debug|x86 diff --git a/source2/Build/Cosmos.Build.MSBuild/Cosmos.Build.MSBuild.csproj b/source2/Build/Cosmos.Build.MSBuild/Cosmos.Build.MSBuild.csproj index bf0a4082e..6faf9db7b 100644 --- a/source2/Build/Cosmos.Build.MSBuild/Cosmos.Build.MSBuild.csproj +++ b/source2/Build/Cosmos.Build.MSBuild/Cosmos.Build.MSBuild.csproj @@ -79,7 +79,7 @@ - + diff --git a/source2/Build/Cosmos.Build.MSBuild/Cosmos.targets b/source2/Build/Cosmos.Build.MSBuild/Cosmos.targets index 83c7bb322..3c739d1a9 100644 --- a/source2/Build/Cosmos.Build.MSBuild/Cosmos.targets +++ b/source2/Build/Cosmos.Build.MSBuild/Cosmos.targets @@ -50,7 +50,7 @@ Condition="$(IsELF) == 'true'"/> @@ -69,7 +69,7 @@ diff --git a/source2/Build/Cosmos.Build.MSBuild/ExtractMapFromElfFile.cs b/source2/Build/Cosmos.Build.MSBuild/ExtractMapFromElfFile.cs index d06cca195..69828674c 100644 --- a/source2/Build/Cosmos.Build.MSBuild/ExtractMapFromElfFile.cs +++ b/source2/Build/Cosmos.Build.MSBuild/ExtractMapFromElfFile.cs @@ -21,7 +21,7 @@ namespace Cosmos.Build.MSBuild } [Required] - public string OutputFile + public string DebugInfoFile { get; set; @@ -98,7 +98,10 @@ namespace Cosmos.Build.MSBuild xResult.Add(xAddress, xLabel); } #endregion - SourceInfo.WriteToFile(xResult, Path.Combine(WorkingDir, OutputFile)); + using (var xDebugInfo = new DebugInfo(DebugInfoFile)) + { + xDebugInfo.WriteAddressLabelMappings(xResult); + } return true; } diff --git a/source2/Build/Cosmos.Build.MSBuild/IL2CPUTask.cs b/source2/Build/Cosmos.Build.MSBuild/IL2CPUTask.cs index 7b2227a7f..18ca7f228 100644 --- a/source2/Build/Cosmos.Build.MSBuild/IL2CPUTask.cs +++ b/source2/Build/Cosmos.Build.MSBuild/IL2CPUTask.cs @@ -13,6 +13,7 @@ using System.Linq; using System.Reflection; using System.Reflection.Emit; using System.Text; +using Cosmos.Debug.Common; namespace Cosmos.Build.MSBuild { // Class is separated from MSBuild task so we can call it from debugging and standalone applications. @@ -219,36 +220,40 @@ namespace Cosmos.Build.MSBuild { DebugCom = 0; } var xAsm = new AppAssemblerNasm(DebugCom); - xAsm.DebugMode = mDebugMode; - xAsm.TraceAssemblies = mTraceAssemblies; + File.Delete(xOutputFilename + ".cpdb"); + using (var xDebugInfo = new DebugInfo(xOutputFilename + ".cpdb")) + { + xAsm.DebugInfo = xDebugInfo; + 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 => LogMessage(x); - if (EnableLogging) + var xNasmAsm = (AssemblerNasm)xAsm.Assembler; + xAsm.Assembler.Initialize(); + using (var xScanner = new ILScanner(xAsm)) { - xScanner.EnableLogging(xOutputFilename + ".log.html"); - } - // TODO: shouldn't be here? - xScanner.QueueMethod(xInitMethod.DeclaringType.BaseType.GetMethod("Start")); - xScanner.Execute(xInitMethod); - - using (var xOut = new StreamWriter(OutputFilename, false)) - { - if (EmitDebugSymbols) + xScanner.TempDebug += x => LogMessage(x); + if (EnableLogging) { - xNasmAsm.FlushText(xOut); - File.Delete(xOutputFilename + ".cpdb"); - xAsm.WriteDebugSymbols(xOutputFilename + ".cpdb"); + xScanner.EnableLogging(xOutputFilename + ".log.html"); } - else + // TODO: shouldn't be here? + xScanner.QueueMethod(xInitMethod.DeclaringType.BaseType.GetMethod("Start")); + xScanner.Execute(xInitMethod); + + using (var xOut = new StreamWriter(OutputFilename, false)) { - xAsm.Assembler.FlushText(xOut); + if (EmitDebugSymbols) + { + xNasmAsm.FlushText(xOut); + xAsm.FinalizeDebugInfo(); + } + else + { + xAsm.Assembler.FlushText(xOut); + } } } } diff --git a/source2/Build/Cosmos.Build.MSBuild/ReadNAsmMapToCosmosMap.cs b/source2/Build/Cosmos.Build.MSBuild/ReadNAsmMapToDebugInfo.cs similarity index 70% rename from source2/Build/Cosmos.Build.MSBuild/ReadNAsmMapToCosmosMap.cs rename to source2/Build/Cosmos.Build.MSBuild/ReadNAsmMapToDebugInfo.cs index 977496403..138378f45 100644 --- a/source2/Build/Cosmos.Build.MSBuild/ReadNAsmMapToCosmosMap.cs +++ b/source2/Build/Cosmos.Build.MSBuild/ReadNAsmMapToDebugInfo.cs @@ -8,7 +8,7 @@ using Cosmos.Debug.Common; namespace Cosmos.Build.MSBuild { - public class ReadNAsmMapToCosmosMap : AppDomainIsolatedTask + public class ReadNAsmMapToDebugInfo : AppDomainIsolatedTask { [Required] public string InputBaseDir @@ -18,7 +18,7 @@ namespace Cosmos.Build.MSBuild } [Required] - public string OutputFile + public string DebugInfoFile { get; set; @@ -32,7 +32,10 @@ namespace Cosmos.Build.MSBuild Log.LogError("No SourceInfos found!"); return false; } - SourceInfo.WriteToFile(xSourceInfos, OutputFile); + using (var xDebugInfo = new DebugInfo(DebugInfoFile)) + { + xDebugInfo.WriteAddressLabelMappings(xSourceInfos); + } return true; } diff --git a/source2/Debug/Cosmos.Debug.Common/Cosmos.Debug.Common.csproj b/source2/Debug/Cosmos.Debug.Common/Cosmos.Debug.Common.csproj index 800a5f22e..642e8f9db 100644 --- a/source2/Debug/Cosmos.Debug.Common/Cosmos.Debug.Common.csproj +++ b/source2/Debug/Cosmos.Debug.Common/Cosmos.Debug.Common.csproj @@ -88,6 +88,7 @@ + diff --git a/source2/Debug/Cosmos.Debug.Common/DebugInfo.cs b/source2/Debug/Cosmos.Debug.Common/DebugInfo.cs new file mode 100644 index 000000000..4f7c15d7c --- /dev/null +++ b/source2/Debug/Cosmos.Debug.Common/DebugInfo.cs @@ -0,0 +1,263 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using FirebirdSql.Data.FirebirdClient; +using System.IO; +using Microsoft.Win32; +using FirebirdSql.Data.Isql; + +namespace Cosmos.Debug.Common +{ + public class DebugInfo: IDisposable + { + public class MLDebugSymbol + { + public string LabelName + { + get; + set; + } + + public uint Address + { + get; + set; + } + + public int StackDifference + { + get; + set; + } + + public string AssemblyFile + { + get; + set; + } + public int TypeToken + { + get; + set; + } + public int MethodToken + { + get; + set; + } + public int ILOffset + { + get; + set; + } + + public string MethodName + { + get; + set; + } + } + private FbConnection mConnection; + + public DebugInfo(string file) + { + var xCreate = !File.Exists(file); + if (xCreate) + { + mConnection = CreateCPDB(file); + } + else + { + mConnection = OpenCPDB(file, false); + } + } + #region connection utilities + private static FbConnection OpenCPDB(string aPathname, bool aCreate) + { + var xCSB = new FbConnectionStringBuilder(); + xCSB.ServerType = FbServerType.Embedded; + xCSB.Database = aPathname; + xCSB.UserID = "sysdba"; + xCSB.Password = "masterkey"; + xCSB.Pooling = false; + + // Ugh - The curr dir is the actual .cosmos dir. But we dont want to + // copy the FB Embedded DLLs everywhere, and we don't want them in system + // or path as they might conflict with other apps. + // However the FB .NET provider doesnt let us set the path, so we hack it + // by changing the current dir right before the first load (create or open). + // We set it back after. + string xCurrDir = Directory.GetCurrentDirectory(); + using (var xKey = Registry.LocalMachine.OpenSubKey(@"SOFTWARE\Cosmos", false)) + { + string xCosmosDir = (string)xKey.GetValue(""); + Directory.SetCurrentDirectory(Path.Combine(xCosmosDir, @"Build\VSIP")); + } + + if (aCreate) + { + File.Delete(aPathname); + FbConnection.CreateDatabase(xCSB.ToString(), 16384, false, true); // Specifying false to forcedwrites will improve database speed. + } + + FbConnection DBConn = new FbConnection(xCSB.ToString()); + DBConn.Open(); + + // Set the current directory back to the original + Directory.SetCurrentDirectory(xCurrDir); + + return DBConn; + } + + private static FbConnection CreateCPDB(string aPathname) + { + FbConnection DBConn = OpenCPDB(aPathname, true); + var xExec = new FbBatchExecution(DBConn); + + xExec.SqlStatements.Add( + "CREATE TABLE MLSYMBOL (" + + " LABELNAME VARCHAR(255) NOT NULL" + + " , ADDRESS BIGINT NOT NULL" + + " , STACKDIFF INT NOT NULL" + + " , ILASMFILE VARCHAR(255) NOT NULL" + + " , TYPETOKEN INT NOT NULL" + + " , METHODTOKEN INT NOT NULL" + + " , ILOFFSET INT NOT NULL" + + " , METHODNAME VARCHAR(255) NOT NULL" + + ");" + ); + + xExec.SqlStatements.Add( + "CREATE TABLE ADDRESSLABELMAPPING (" + + " LABELNAME VARCHAR(255) NOT NULL" + + ", ADDRESS BIGINT NOT NULL" + + ");"); + + xExec.Execute(); + // Batch execution closes the connection, so we have to reopen it + DBConn.Open(); + + return DBConn; + } + #endregion + + #region MLDebugSymbol code + public void WriteSymbolsListToFile(IEnumerable aSymbols) + { + using (FbTransaction transaction = mConnection.BeginTransaction()) + { + using (var xCmd = mConnection.CreateCommand()) + { + xCmd.Transaction = transaction; + xCmd.CommandText = "INSERT INTO MLSYMBOL (LABELNAME, ADDRESS, STACKDIFF, ILASMFILE, TYPETOKEN, METHODTOKEN, ILOFFSET, METHODNAME)" + + " VALUES (@LABELNAME, @ADDRESS, @STACKDIFF, @ILASMFILE, @TYPETOKEN, @METHODTOKEN, @ILOFFSET, @METHODNAME)"; + + xCmd.Parameters.Add("@LABELNAME", FbDbType.VarChar); + xCmd.Parameters.Add("@ADDRESS", FbDbType.BigInt); + xCmd.Parameters.Add("@STACKDIFF", FbDbType.Integer); + xCmd.Parameters.Add("@ILASMFILE", FbDbType.VarChar); + xCmd.Parameters.Add("@TYPETOKEN", FbDbType.Integer); + xCmd.Parameters.Add("@METHODTOKEN", FbDbType.Integer); + xCmd.Parameters.Add("@ILOFFSET", FbDbType.Integer); + xCmd.Parameters.Add("@METHODNAME", FbDbType.VarChar); + xCmd.Prepare(); + + // Is a real DB now, but we still store all in RAM. We dont need to. Need to change to query DB as needed instead. + foreach (var xItem in aSymbols) + { + xCmd.Parameters[0].Value = xItem.LabelName; + xCmd.Parameters[1].Value = xItem.Address; + xCmd.Parameters[2].Value = xItem.StackDifference; + xCmd.Parameters[3].Value = xItem.AssemblyFile; + xCmd.Parameters[4].Value = xItem.TypeToken; + xCmd.Parameters[5].Value = xItem.MethodToken; + xCmd.Parameters[6].Value = xItem.ILOffset; + xCmd.Parameters[7].Value = xItem.MethodName; + xCmd.ExecuteNonQuery(); + } + } + + transaction.Commit(); + } + } + public void ReadSymbolsList(List aSymbols) + { + using (var xCmd = mConnection.CreateCommand()) + { + xCmd.CommandText = "select LABELNAME, ADDRESS, STACKDIFF, ILASMFILE, TYPETOKEN, METHODTOKEN, ILOFFSET, METHODNAME from MLSYMBOL"; + using (var xReader = xCmd.ExecuteReader()) + { + while (xReader.Read()) + { + aSymbols.Add(new MLDebugSymbol + { + LabelName = xReader.GetString(0), + Address = (uint)xReader.GetInt64(1), + StackDifference = xReader.GetInt32(2), + AssemblyFile = xReader.GetString(3), + TypeToken = xReader.GetInt32(4), + MethodToken = xReader.GetInt32(5), + ILOffset = xReader.GetInt32(6), + MethodName = xReader.GetString(7) + }); + } + } + } + } + + #endregion + + #region address-label mappings + public void ReadAddressLabelMappings(out IDictionary oAddressLabelMappings, out IDictionary oLabelAddressMappings) + { + oAddressLabelMappings = new Dictionary(); + oLabelAddressMappings = new Dictionary(); + using (var xCmd = mConnection.CreateCommand()) + { + xCmd.CommandText = "select LABELNAME, ADDRESS from ADDRESSLABELMAPPING"; + using (var xReader = xCmd.ExecuteReader()) + { + while (xReader.Read()) + { + oAddressLabelMappings.Add((uint)xReader.GetInt64(1), xReader.GetString(0)); + oLabelAddressMappings.Add(xReader.GetString(0), (uint)xReader.GetInt64(1)); + } + } + } + } + + public void WriteAddressLabelMappings(SortedList aMap) + { + using (var xTrans = mConnection.BeginTransaction()) + { + using (var xCmd = mConnection.CreateCommand()) + { + xCmd.Transaction = xTrans; + xCmd.CommandText = "insert into ADDRESSLABELMAPPING (LABELNAME, ADDRESS) values (@LABELNAME, @ADDRESS)"; + xCmd.Parameters.Add("@LABELNAME", FbDbType.VarChar); + xCmd.Parameters.Add("@ADDRESS", FbDbType.BigInt); + xCmd.Prepare(); + foreach (var xItem in aMap) + { + xCmd.Parameters[0].Value = xItem.Value; + xCmd.Parameters[1].Value = xItem.Key; + xCmd.ExecuteNonQuery(); + } + xTrans.Commit(); + } + } + } + #endregion + + public void Dispose() + { + if (mConnection != null) + { + var xCon = mConnection; + mConnection = null; + xCon.Dispose(); + } + GC.SuppressFinalize(this); + } + } +} \ No newline at end of file diff --git a/source2/Debug/Cosmos.Debug.Common/DebugSymbol.cs b/source2/Debug/Cosmos.Debug.Common/DebugSymbol.cs index 5be6049ad..535e8c6d1 100644 --- a/source2/Debug/Cosmos.Debug.Common/DebugSymbol.cs +++ b/source2/Debug/Cosmos.Debug.Common/DebugSymbol.cs @@ -40,7 +40,7 @@ namespace Cosmos.Debug.Common } } - public class MLDebugSymbol + public class MLDebugSymbol_Old { public static FbConnection OpenOrCreateCPDB(string aPathName) { @@ -122,76 +122,6 @@ namespace Cosmos.Debug.Common return DBConn; } - public static void WriteSymbolsListToFile(IEnumerable aSymbols, string aFile) - { - using (FbConnection DBConn = OpenOrCreateCPDB(aFile)) - { - using (FbTransaction transaction = DBConn.BeginTransaction()) - { - using (var xCmd = DBConn.CreateCommand()) - { - xCmd.Transaction = transaction; - xCmd.CommandText = "INSERT INTO MLSYMBOL (LABELNAME, ADDRESS, STACKDIFF, ILASMFILE, TYPETOKEN, METHODTOKEN, ILOFFSET, METHODNAME)" + - " VALUES (@LABELNAME, @ADDRESS, @STACKDIFF, @ILASMFILE, @TYPETOKEN, @METHODTOKEN, @ILOFFSET, @METHODNAME)"; - - xCmd.Parameters.Add("@LABELNAME", FbDbType.VarChar); - xCmd.Parameters.Add("@ADDRESS", FbDbType.BigInt); - xCmd.Parameters.Add("@STACKDIFF", FbDbType.Integer); - xCmd.Parameters.Add("@ILASMFILE", FbDbType.VarChar); - xCmd.Parameters.Add("@TYPETOKEN", FbDbType.Integer); - xCmd.Parameters.Add("@METHODTOKEN", FbDbType.Integer); - xCmd.Parameters.Add("@ILOFFSET", FbDbType.Integer); - xCmd.Parameters.Add("@METHODNAME", FbDbType.VarChar); - xCmd.Prepare(); - - // Is a real DB now, but we still store all in RAM. We dont need to. Need to change to query DB as needed instead. - foreach (var xItem in aSymbols) - { - xCmd.Parameters[0].Value = xItem.LabelName; - xCmd.Parameters[1].Value = xItem.Address; - xCmd.Parameters[2].Value = xItem.StackDifference; - xCmd.Parameters[3].Value = xItem.AssemblyFile; - xCmd.Parameters[4].Value = xItem.TypeToken; - xCmd.Parameters[5].Value = xItem.MethodToken; - xCmd.Parameters[6].Value = xItem.ILOffset; - xCmd.Parameters[7].Value = xItem.MethodName; - xCmd.ExecuteNonQuery(); - } - } - - transaction.Commit(); - } - } - } - - public static void ReadSymbolsListFromFile(List aSymbols, string aFile) - { - using (var xConn = OpenCPDB(aFile, false)) - { - using (var xCmd = xConn.CreateCommand()) - { - xCmd.CommandText = "select LABELNAME, ADDRESS, STACKDIFF, ILASMFILE, TYPETOKEN, METHODTOKEN, ILOFFSET, METHODNAME from MLSYMBOL"; - using (var xReader = xCmd.ExecuteReader()) - { - while (xReader.Read()) - { - aSymbols.Add(new MLDebugSymbol - { - LabelName=xReader.GetString(0), - Address = (uint)xReader.GetInt64(1), - StackDifference = xReader.GetInt32(2), - AssemblyFile = xReader.GetString(3), - TypeToken = xReader.GetInt32(4), - MethodToken = xReader.GetInt32(5), - ILOffset = xReader.GetInt32(6), - MethodName = xReader.GetString(7) - }); - } - } - } - } - } - public string LabelName { get; diff --git a/source2/Debug/Cosmos.Debug.Common/SourceInfo.cs b/source2/Debug/Cosmos.Debug.Common/SourceInfo.cs index b88fe4e9d..fa599da45 100644 --- a/source2/Debug/Cosmos.Debug.Common/SourceInfo.cs +++ b/source2/Debug/Cosmos.Debug.Common/SourceInfo.cs @@ -50,51 +50,6 @@ namespace Cosmos.Debug.Common set; } - public static void WriteToFile(SortedList aMap, string outFile) - { - using (var xConn = MLDebugSymbol.OpenOrCreateCPDB(outFile)) - { - using (var xTrans = xConn.BeginTransaction()) - { - using (var xCmd = xConn.CreateCommand()) - { - xCmd.Transaction = xTrans; - xCmd.CommandText = "insert into ADDRESSLABELMAPPING (LABELNAME, ADDRESS) values (@LABELNAME, @ADDRESS)"; - xCmd.Parameters.Add("@LABELNAME", FbDbType.VarChar); - xCmd.Parameters.Add("@ADDRESS", FbDbType.BigInt); - xCmd.Prepare(); - foreach(var xItem in aMap){ - xCmd.Parameters[0].Value = xItem.Value; - xCmd.Parameters[1].Value = xItem.Key; - xCmd.ExecuteNonQuery(); - } - xTrans.Commit(); - } - } - } - } - - public static void ReadFromFile(string aFile, out IDictionary oAddressLabelMappings, out IDictionary oLabelAddressMappings) - { - oAddressLabelMappings = new Dictionary(); - oLabelAddressMappings = new Dictionary(); - using (var xConn = MLDebugSymbol.OpenOrCreateCPDB(aFile)) - { - using (var xCmd = xConn.CreateCommand()) - { - xCmd.CommandText = "select LABELNAME, ADDRESS from ADDRESSLABELMAPPING"; - using (var xReader = xCmd.ExecuteReader()) - { - while (xReader.Read()) - { - oAddressLabelMappings.Add((uint)xReader.GetInt64(1), xReader.GetString(0)); - oLabelAddressMappings.Add(xReader.GetString(0), (uint)xReader.GetInt64(1)); - } - } - } - } - } - public static SortedList ParseMapFile(String buildPath) { var xSourceStrings = File.ReadAllLines(Path.Combine(buildPath, "main.map")); @@ -142,11 +97,12 @@ namespace Cosmos.Debug.Common return xIdx; } - public static SourceInfos GetSourceInfo(IDictionary aAddressLabelMappings, IDictionary aLabelAddressMappings, string aDebugFile) { - var xSymbolsList = new List(); - MLDebugSymbol.ReadSymbolsListFromFile(xSymbolsList, aDebugFile); + public static SourceInfos GetSourceInfo(IDictionary aAddressLabelMappings, IDictionary aLabelAddressMappings, DebugInfo debugInfo) { + var xSymbolsList = new List(); + debugInfo.ReadSymbolsList(xSymbolsList); #region sort - xSymbolsList.Sort(delegate(MLDebugSymbol a, MLDebugSymbol b) { + xSymbolsList.Sort(delegate(DebugInfo.MLDebugSymbol a, DebugInfo.MLDebugSymbol b) + { if (a == null) { throw new ArgumentNullException("a"); } diff --git a/source2/Debug/Cosmos.Debug.VSDebugEngine/AD7.Impl/AD7Process.cs b/source2/Debug/Cosmos.Debug.VSDebugEngine/AD7.Impl/AD7Process.cs index aa5cad0d5..fb51d9cb0 100644 --- a/source2/Debug/Cosmos.Debug.VSDebugEngine/AD7.Impl/AD7Process.cs +++ b/source2/Debug/Cosmos.Debug.VSDebugEngine/AD7.Impl/AD7Process.cs @@ -189,24 +189,29 @@ namespace Cosmos.Debug.VSDebugEngine { IDictionary xAddressLabelMappings; IDictionary xLabelAddressMappings; - string xCpdbPath = Path.ChangeExtension(mISO, "cpdb"); + + string xCpdbPath = Path.ChangeExtension(mISO, "cpdb"); if (!File.Exists(xCpdbPath)) { throw new Exception("Debug data file " + xCpdbPath + " not found! Could be a omitted build process of Cosmos project so that not created."); } - Cosmos.Debug.Common.SourceInfo.ReadFromFile(xCpdbPath, out xAddressLabelMappings, out xLabelAddressMappings); - if (xAddressLabelMappings.Count == 0) + + using (var xDebugInfo = new DebugInfo(xCpdbPath)) { - throw new Exception("Debug data not found: LabelByAddressMapping"); - } + xDebugInfo.ReadAddressLabelMappings(out xAddressLabelMappings, out xLabelAddressMappings); + if (xAddressLabelMappings.Count == 0) + { + throw new Exception("Debug data not found: LabelByAddressMapping"); + } - mSourceMappings = Cosmos.Debug.Common.SourceInfo.GetSourceInfo(xAddressLabelMappings, xLabelAddressMappings, xCpdbPath); + mSourceMappings = Cosmos.Debug.Common.SourceInfo.GetSourceInfo(xAddressLabelMappings, xLabelAddressMappings, xDebugInfo); - if (mSourceMappings.Count == 0) { - throw new Exception("Debug data not found: SourceMappings"); + if (mSourceMappings.Count == 0) + { + throw new Exception("Debug data not found: SourceMappings"); + } + mReverseSourceMappings = new ReverseSourceInfos(mSourceMappings); } - mReverseSourceMappings = new ReverseSourceInfos(mSourceMappings); - if (StringComparer.InvariantCultureIgnoreCase.Equals(mDebugInfo["BuildTarget"], "vmware")) { mDbgConnector = new Cosmos.Debug.Common.DebugConnectorPipeServer(); } else { diff --git a/source2/IL2CPU/Cosmos.IL2CPU.X86/AppAssemblerNasm.cs b/source2/IL2CPU/Cosmos.IL2CPU.X86/AppAssemblerNasm.cs index bf0536616..b41ce0669 100644 --- a/source2/IL2CPU/Cosmos.IL2CPU.X86/AppAssemblerNasm.cs +++ b/source2/IL2CPU/Cosmos.IL2CPU.X86/AppAssemblerNasm.cs @@ -13,7 +13,7 @@ using CPUx86 = Cosmos.Compiler.Assembler.X86; namespace Cosmos.IL2CPU.X86 { - public class AppAssemblerNasm: AppAssembler + public class AppAssemblerNasm : AppAssembler { public AppAssemblerNasm(byte comNumber) : base(comNumber) @@ -25,423 +25,456 @@ namespace Cosmos.IL2CPU.X86 } - protected override void MethodBegin(MethodInfo aMethod) { - base.MethodBegin(aMethod); - if (aMethod.PluggedMethod != null) - { - new Label("PLUG_FOR___" + MethodInfoLabelGenerator.GenerateLabelName(aMethod.PluggedMethod.MethodBase)); - } - else - { - new Label(aMethod.MethodBase); - } - if (aMethod.MethodBase.IsStatic && aMethod.MethodBase is ConstructorInfo) - { - new Comment("This is a static constructor. see if it has been called already, and if so, return."); - var xName = DataMember.FilterStringForIncorrectChars("CCTOR_CALLED__" + MethodInfoLabelGenerator.GetFullName(aMethod.MethodBase.DeclaringType)); - var xAsmMember = new DataMember(xName, (byte)0); - Assembler.DataMembers.Add(xAsmMember); - new Compare { DestinationRef = ElementReference.New(xName), DestinationIsIndirect = true, Size = 8, SourceValue = 1 }; - new ConditionalJump { Condition = ConditionalTestEnum.Equal, DestinationLabel = ".BeforeQuickReturn" }; - new Move { DestinationRef = ElementReference.New(xName), DestinationIsIndirect = true, Size = 8, SourceValue = 1 }; - new Jump { DestinationLabel = ".AfterCCTorAlreadyCalledCheck"}; - new Label(".BeforeQuickReturn"); - new Move { DestinationReg = RegistersEnum.ECX, SourceValue = 0 }; - new Return { }; - new Label(".AfterCCTorAlreadyCalledCheck"); - } - - new Push { DestinationReg = Registers.EBP }; - new Move { DestinationReg = Registers.EBP, SourceReg = Registers.ESP }; - //new CPUx86.Push("0"); - //if (!(aLabelName.Contains("Cosmos.Kernel.Serial") || aLabelName.Contains("Cosmos.Kernel.Heap"))) { - // new CPUx86.Push(LdStr.GetContentsArrayName(aAssembler, aLabelName)); - // MethodBase xTempMethod = Engine.GetMethodBase(Engine.GetType("Cosmos.Kernel", "Cosmos.Kernel.Serial"), "Write", "System.Byte", "System.String"); - // new CPUx86.Call(MethodInfoLabelGenerator.GenerateLabelName(xTempMethod)); - // Engine.QueueMethod(xTempMethod); - //} - if (aMethod.MethodAssembler == null && aMethod.PlugMethod == null) { - var xBody = aMethod.MethodBase.GetMethodBody(); - if (xBody != null) { - foreach (var xLocal in xBody.LocalVariables) { - new Comment("Local " + xLocal.LocalIndex); - new Sub { DestinationReg = Registers.ESP, SourceValue = ILOp.Align(ILOp.SizeOfType(xLocal.LocalType), 4) }; - } - } - } - //foreach (var xLocal in aLocals) { - // aAssembler.StackContents.Push(new StackContent(xLocal.Size, xLocal.VariableType)); - // for (int i = 0; i < (xLocal.Size / 4); i++) { - // new CPUx86.Push { DestinationValue = 0 }; - // } - //} - //if (aDebugMode && aIsNonDebuggable) { - // new CPUx86.Call { DestinationLabel = "DebugPoint_DebugSuspend" }; - //} - #region Load CodeOffset - if (DebugMode == DebugMode.Source) - { - var xSymbolReader = GetSymbolReaderForAssembly(aMethod.MethodBase.DeclaringType.Assembly); - if (xSymbolReader != null) - { - var xSmbMethod = xSymbolReader.GetMethod(new SymbolToken(aMethod.MethodBase.MetadataToken)); - // This gets the Sequence Points. - // Sequence Points are spots that identify what the compiler/debugger says is a spot - // that a breakpoint can occur one. Essentially, an atomic source line in C# - if (xSmbMethod != null) - { - xCodeOffsets = new int[xSmbMethod.SequencePointCount]; - var xCodeDocuments = new ISymbolDocument[xSmbMethod.SequencePointCount]; - xCodeLineNumbers = new int[xSmbMethod.SequencePointCount]; - var xCodeColumns = new int[xSmbMethod.SequencePointCount]; - var xCodeEndLines = new int[xSmbMethod.SequencePointCount]; - var xCodeEndColumns = new int[xSmbMethod.SequencePointCount]; - xSmbMethod.GetSequencePoints(xCodeOffsets, xCodeDocuments - , xCodeLineNumbers, xCodeColumns, xCodeEndLines, xCodeEndColumns); - } - } - } - #endregion - } - - protected override void MethodEnd(MethodInfo aMethod) { - base.MethodEnd(aMethod); - uint xReturnSize = 0; - var xMethInfo = aMethod.MethodBase as System.Reflection.MethodInfo; - if (xMethInfo != null) { - xReturnSize = ILOp.Align(ILOp.SizeOfType(xMethInfo.ReturnType), 4); - } - new Label(ILOp.GetMethodLabel(aMethod) + EndOfMethodLabelNameNormal); - new CPUx86.Move { DestinationReg = CPUx86.Registers.ECX, SourceValue = 0 }; - var xTotalArgsSize = (from item in aMethod.MethodBase.GetParameters() - select (int)ILOp.Align(ILOp.SizeOfType(item.ParameterType), 4)).Sum(); - if (!aMethod.MethodBase.IsStatic) { - if (aMethod.MethodBase.DeclaringType.IsValueType) - { - xTotalArgsSize += 4; // only a reference is passed - } - else - { - xTotalArgsSize += (int)ILOp.Align(ILOp.SizeOfType(aMethod.MethodBase.DeclaringType), 4); - } - } - - if (aMethod.PluggedMethod != null) { - xReturnSize = 0; - xMethInfo = aMethod.PluggedMethod.MethodBase as System.Reflection.MethodInfo; - if (xMethInfo != null) { - xReturnSize = ILOp.Align(ILOp.SizeOfType(xMethInfo.ReturnType), 4); - } - xTotalArgsSize = (from item in aMethod.PluggedMethod.MethodBase.GetParameters() - select (int)ILOp.Align(ILOp.SizeOfType(item.ParameterType), 4)).Sum(); - if (!aMethod.PluggedMethod.MethodBase.IsStatic) { - if (aMethod.PluggedMethod.MethodBase.DeclaringType.IsValueType) + protected override void MethodBegin(MethodInfo aMethod) + { + base.MethodBegin(aMethod); + if (aMethod.PluggedMethod != null) { - xTotalArgsSize += 4; // only a reference is passed + new Label("PLUG_FOR___" + MethodInfoLabelGenerator.GenerateLabelName(aMethod.PluggedMethod.MethodBase)); } else { - xTotalArgsSize += (int)ILOp.Align(ILOp.SizeOfType(aMethod.PluggedMethod.MethodBase.DeclaringType), 4); + new Label(aMethod.MethodBase); + } + if (aMethod.MethodBase.IsStatic && aMethod.MethodBase is ConstructorInfo) + { + new Comment("This is a static constructor. see if it has been called already, and if so, return."); + var xName = DataMember.FilterStringForIncorrectChars("CCTOR_CALLED__" + MethodInfoLabelGenerator.GetFullName(aMethod.MethodBase.DeclaringType)); + var xAsmMember = new DataMember(xName, (byte)0); + Assembler.DataMembers.Add(xAsmMember); + new Compare { DestinationRef = ElementReference.New(xName), DestinationIsIndirect = true, Size = 8, SourceValue = 1 }; + new ConditionalJump { Condition = ConditionalTestEnum.Equal, DestinationLabel = ".BeforeQuickReturn" }; + new Move { DestinationRef = ElementReference.New(xName), DestinationIsIndirect = true, Size = 8, SourceValue = 1 }; + new Jump { DestinationLabel = ".AfterCCTorAlreadyCalledCheck" }; + new Label(".BeforeQuickReturn"); + new Move { DestinationReg = RegistersEnum.ECX, SourceValue = 0 }; + new Return { }; + new Label(".AfterCCTorAlreadyCalledCheck"); } - } - } - if (xReturnSize > 0) { - //var xArgSize = (from item in aArgs - // let xSize = item.Size + item.Offset - // select xSize).FirstOrDefault(); - //new Comment(String.Format("ReturnSize = {0}, ArgumentSize = {1}", - // aReturnSize, - // xArgSize)); - //int xOffset = 4; - //if(xArgSize>0) { - // xArgSize -= xReturnSize; - // xOffset = xArgSize; - //} - var xOffset = GetResultCodeOffset(xReturnSize, (uint)xTotalArgsSize); - for (int i = 0; i < xReturnSize / 4; i++) { - new CPUx86.Pop { DestinationReg = CPUx86.Registers.EAX }; - new CPUx86.Move { - DestinationReg = CPUx86.Registers.EBP, - DestinationIsIndirect = true, - DestinationDisplacement = (int)(xOffset + ((i + 0) * 4)), - SourceReg = Registers.EAX - }; - // new CPUx86.Move { - // DestinationReg = CPUx86.Registers.EBP, - // DestinationIsIndirect = true, - // DestinationDisplacement = (int)(xOffset + ((i + 1) * 4) + 4 - xReturnSize), - // SourceReg = Registers.EAX - // }; - } - // extra stack space is the space reserved for example when a "public static int TestMethod();" method is called, 4 bytes is pushed, to make room for result; - } - new Label(ILOp.GetMethodLabel(aMethod) + EndOfMethodLabelNameException); - //for (int i = 0; i < aLocAllocItemCount; i++) { - // new CPUx86.Call { DestinationLabel = aHeapFreeLabel }; - //} - //if (aDebugMode && aIsNonDebuggable) { - // new CPUx86.Call { DestinationLabel = "DebugPoint_DebugResume" }; - //} - - //if ((from xLocal in aLocals - // where xLocal.IsReferenceType - // select 1).Count() > 0 || (from xArg in aArgs - // where xArg.IsReferenceType - // select 1).Count() > 0) { - // new CPUx86.Push { DestinationReg = Registers.ECX }; - // //foreach (MethodInformation.Variable xLocal in aLocals) { - // // if (xLocal.IsReferenceType) { - // // Op.Ldloc(aAssembler, - // // xLocal, - // // false, - // // aGetStorageSizeDelegate(xLocal.VariableType)); - // // new CPUx86.Call { DestinationLabel = aDecRefLabel }; - // // } - // //} - // //foreach (MethodInformation.Argument xArg in aArgs) { - // // if (xArg.IsReferenceType) { - // // Op.Ldarg(aAssembler, - // // xArg, - // // false); - // // //, aGetStorageSizeDelegate(xArg.ArgumentType) - // // new CPUx86.Call { DestinationLabel = aDecRefLabel }; - // // } - // //} - // // todo: add GC code - // new CPUx86.Pop { DestinationReg = CPUx86.Registers.ECX }; - //} - if (aMethod.MethodAssembler == null && aMethod.PlugMethod == null) { - var xBody = aMethod.MethodBase.GetMethodBody(); - if (xBody != null) { - for (int j = xBody.LocalVariables.Count - 1; j >= 0; j--) { - int xLocalSize = (int)ILOp.Align(ILOp.SizeOfType(xBody.LocalVariables[j].LocalType), 4); - new CPUx86.Add { DestinationReg = CPUx86.Registers.ESP, SourceValue = (uint)xLocalSize }; - } - } - } - //new CPUx86.Add(CPUx86.Registers_Old.ESP, "0x4"); - //new CPUx86.Compare { DestinationReg = Registers.EBP, SourceReg = Registers.ESP }; - //new CPUx86.ConditionalJump { Condition = ConditionalTestEnum.Equal, DestinationLabel = MethodInfoLabelGenerator.GenerateLabelName(aMethod.MethodBase) + EndOfMethodLabelNameException + "__2" }; - //new CPUx86.Xchg { DestinationReg = Registers.BX, SourceReg = Registers.BX }; - //new CPUx86.Halt(); - // TODO: not nice coding, still a test - //new CPUx86.Move { DestinationReg = Registers.ESP, SourceReg = Registers.EBP }; - new Label(ILOp.GetMethodLabel(aMethod) + EndOfMethodLabelNameException + "__2"); - new CPUx86.Pop { DestinationReg = CPUx86.Registers.EBP }; - var xRetSize = ((int)xTotalArgsSize) - ((int)xReturnSize); - if (xRetSize < 0) { - xRetSize = 0; - } - WriteDebug(aMethod.MethodBase, (uint)xRetSize, IL.Call.GetStackSizeToReservate(aMethod.MethodBase)); - new CPUx86.Return { DestinationValue = (uint)xRetSize }; - } - - public static uint GetResultCodeOffset(uint aResultSize, uint aTotalArgumentSize) - { - uint xOffset = 8; - if ((aTotalArgumentSize > 0) && (aTotalArgumentSize >= aResultSize)) - { - xOffset += aTotalArgumentSize; - xOffset -= aResultSize; - } - return xOffset; - } - - private static ISymbolReader GetSymbolReaderForAssembly(Assembly aAssembly) - { - try - { - return SymbolAccess.GetReaderForFile(aAssembly.Location); - } - catch (NotSupportedException) - { - return null; - } - } - - protected override void MethodBegin(string aMethodName) { - base.MethodBegin(aMethodName); - new Label(aMethodName); - new Push { DestinationReg = Registers.EBP }; - new Move { DestinationReg = Registers.EBP, SourceReg = Registers.ESP }; - xCodeOffsets = new int[0]; - } - - protected override void MethodEnd(string aMethodName) { - base.MethodEnd(aMethodName); - new Label("_END_OF_" + aMethodName); - new CPUx86.Pop { DestinationReg = CPUx86.Registers.EBP }; - new CPUx86.Return(); - } - - private static HashSet mDebugLines = new HashSet(); - private static void WriteDebug(MethodBase aMethod, uint aSize, uint aSize2) { - var xLine = String.Format("{0}\t{1}\t{2}", MethodInfoLabelGenerator.GenerateFullName(aMethod), aSize, aSize2); - - } - private List mSymbols = new List(); - - // These are all temp functions until we move to the new assembler. - // They are used to clean up the old assembler slightly while retaining compatibiltiy for now - public static string TmpPosLabel(MethodInfo aMethod, int aOffset) - { - // todo: fix to be small again. - return ILOp.GetLabel(aMethod, aOffset); - //TODO: Change to Hex output, will be smaller and slightly faster for NASM - //return "POS_" + aMethod.UID + "_" + aOffset; - } - - public static string TmpPosLabel(MethodInfo aMethod, ILOpCode aOpCode) - { - return TmpPosLabel(aMethod, aOpCode.Position); - } - - public static string TmpBranchLabel(MethodInfo aMethod, ILOpCode aOpCode) - { - return TmpPosLabel(aMethod, ((ILOpCodes.OpBranch)aOpCode).Value); - } - - protected override void BeforeOp(MethodInfo aMethod, ILOpCode aOpCode) - { - base.BeforeOp(aMethod, aOpCode); - new Label(TmpPosLabel(aMethod, aOpCode)); - #region Collection debug information - if (mSymbols != null) - { - var xMLSymbol = new MLDebugSymbol(); - xMLSymbol.LabelName = TmpPosLabel(aMethod, aOpCode); - xMLSymbol.MethodName = aMethod.MethodBase.GetFullName(); - int xStackSize = (from item in mAssembler.Stack - let xSize = (item.Size % 4 == 0) - ? item.Size - : (item.Size + (4 - (item.Size % 4))) - select xSize).Sum(); - xMLSymbol.StackDifference = -1; - if (aMethod.MethodBase != null) + new Push { DestinationReg = Registers.EBP }; + new Move { DestinationReg = Registers.EBP, SourceReg = Registers.ESP }; + //new CPUx86.Push("0"); + //if (!(aLabelName.Contains("Cosmos.Kernel.Serial") || aLabelName.Contains("Cosmos.Kernel.Heap"))) { + // new CPUx86.Push(LdStr.GetContentsArrayName(aAssembler, aLabelName)); + // MethodBase xTempMethod = Engine.GetMethodBase(Engine.GetType("Cosmos.Kernel", "Cosmos.Kernel.Serial"), "Write", "System.Byte", "System.String"); + // new CPUx86.Call(MethodInfoLabelGenerator.GenerateLabelName(xTempMethod)); + // Engine.QueueMethod(xTempMethod); + //} + if (aMethod.MethodAssembler == null && aMethod.PlugMethod == null) { var xBody = aMethod.MethodBase.GetMethodBody(); if (xBody != null) { - var xLocalsSize = (from item in xBody.LocalVariables - select (int)ILOp.Align(ILOp.SizeOfType(item.LocalType), 4)).Sum(); - xMLSymbol.StackDifference = xLocalsSize + xStackSize; + foreach (var xLocal in xBody.LocalVariables) + { + new Comment("Local " + xLocal.LocalIndex); + new Sub { DestinationReg = Registers.ESP, SourceValue = ILOp.Align(ILOp.SizeOfType(xLocal.LocalType), 4) }; + } } } + //foreach (var xLocal in aLocals) { + // aAssembler.StackContents.Push(new StackContent(xLocal.Size, xLocal.VariableType)); + // for (int i = 0; i < (xLocal.Size / 4); i++) { + // new CPUx86.Push { DestinationValue = 0 }; + // } + //} + //if (aDebugMode && aIsNonDebuggable) { + // new CPUx86.Call { DestinationLabel = "DebugPoint_DebugSuspend" }; + //} + #region Load CodeOffset + if (DebugMode == DebugMode.Source) + { + var xSymbolReader = GetSymbolReaderForAssembly(aMethod.MethodBase.DeclaringType.Assembly); + if (xSymbolReader != null) + { + var xSmbMethod = xSymbolReader.GetMethod(new SymbolToken(aMethod.MethodBase.MetadataToken)); + // This gets the Sequence Points. + // Sequence Points are spots that identify what the compiler/debugger says is a spot + // that a breakpoint can occur one. Essentially, an atomic source line in C# + if (xSmbMethod != null) + { + xCodeOffsets = new int[xSmbMethod.SequencePointCount]; + var xCodeDocuments = new ISymbolDocument[xSmbMethod.SequencePointCount]; + xCodeLineNumbers = new int[xSmbMethod.SequencePointCount]; + var xCodeColumns = new int[xSmbMethod.SequencePointCount]; + var xCodeEndLines = new int[xSmbMethod.SequencePointCount]; + var xCodeEndColumns = new int[xSmbMethod.SequencePointCount]; + xSmbMethod.GetSequencePoints(xCodeOffsets, xCodeDocuments + , xCodeLineNumbers, xCodeColumns, xCodeEndLines, xCodeEndColumns); + } + } + } + #endregion + } + + protected override void MethodEnd(MethodInfo aMethod) + { + base.MethodEnd(aMethod); + uint xReturnSize = 0; + var xMethInfo = aMethod.MethodBase as System.Reflection.MethodInfo; + if (xMethInfo != null) + { + xReturnSize = ILOp.Align(ILOp.SizeOfType(xMethInfo.ReturnType), 4); + } + new Label(ILOp.GetMethodLabel(aMethod) + EndOfMethodLabelNameNormal); + new CPUx86.Move { DestinationReg = CPUx86.Registers.ECX, SourceValue = 0 }; + var xTotalArgsSize = (from item in aMethod.MethodBase.GetParameters() + select (int)ILOp.Align(ILOp.SizeOfType(item.ParameterType), 4)).Sum(); + if (!aMethod.MethodBase.IsStatic) + { + if (aMethod.MethodBase.DeclaringType.IsValueType) + { + xTotalArgsSize += 4; // only a reference is passed + } + else + { + xTotalArgsSize += (int)ILOp.Align(ILOp.SizeOfType(aMethod.MethodBase.DeclaringType), 4); + } + } + + if (aMethod.PluggedMethod != null) + { + xReturnSize = 0; + xMethInfo = aMethod.PluggedMethod.MethodBase as System.Reflection.MethodInfo; + if (xMethInfo != null) + { + xReturnSize = ILOp.Align(ILOp.SizeOfType(xMethInfo.ReturnType), 4); + } + xTotalArgsSize = (from item in aMethod.PluggedMethod.MethodBase.GetParameters() + select (int)ILOp.Align(ILOp.SizeOfType(item.ParameterType), 4)).Sum(); + if (!aMethod.PluggedMethod.MethodBase.IsStatic) + { + if (aMethod.PluggedMethod.MethodBase.DeclaringType.IsValueType) + { + xTotalArgsSize += 4; // only a reference is passed + } + else + { + xTotalArgsSize += (int)ILOp.Align(ILOp.SizeOfType(aMethod.PluggedMethod.MethodBase.DeclaringType), 4); + } + } + } + + if (xReturnSize > 0) + { + //var xArgSize = (from item in aArgs + // let xSize = item.Size + item.Offset + // select xSize).FirstOrDefault(); + //new Comment(String.Format("ReturnSize = {0}, ArgumentSize = {1}", + // aReturnSize, + // xArgSize)); + //int xOffset = 4; + //if(xArgSize>0) { + // xArgSize -= xReturnSize; + // xOffset = xArgSize; + //} + var xOffset = GetResultCodeOffset(xReturnSize, (uint)xTotalArgsSize); + for (int i = 0; i < xReturnSize / 4; i++) + { + new CPUx86.Pop { DestinationReg = CPUx86.Registers.EAX }; + new CPUx86.Move + { + DestinationReg = CPUx86.Registers.EBP, + DestinationIsIndirect = true, + DestinationDisplacement = (int)(xOffset + ((i + 0) * 4)), + SourceReg = Registers.EAX + }; + // new CPUx86.Move { + // DestinationReg = CPUx86.Registers.EBP, + // DestinationIsIndirect = true, + // DestinationDisplacement = (int)(xOffset + ((i + 1) * 4) + 4 - xReturnSize), + // SourceReg = Registers.EAX + // }; + } + // extra stack space is the space reserved for example when a "public static int TestMethod();" method is called, 4 bytes is pushed, to make room for result; + } + new Label(ILOp.GetMethodLabel(aMethod) + EndOfMethodLabelNameException); + //for (int i = 0; i < aLocAllocItemCount; i++) { + // new CPUx86.Call { DestinationLabel = aHeapFreeLabel }; + //} + //if (aDebugMode && aIsNonDebuggable) { + // new CPUx86.Call { DestinationLabel = "DebugPoint_DebugResume" }; + //} + + //if ((from xLocal in aLocals + // where xLocal.IsReferenceType + // select 1).Count() > 0 || (from xArg in aArgs + // where xArg.IsReferenceType + // select 1).Count() > 0) { + // new CPUx86.Push { DestinationReg = Registers.ECX }; + // //foreach (MethodInformation.Variable xLocal in aLocals) { + // // if (xLocal.IsReferenceType) { + // // Op.Ldloc(aAssembler, + // // xLocal, + // // false, + // // aGetStorageSizeDelegate(xLocal.VariableType)); + // // new CPUx86.Call { DestinationLabel = aDecRefLabel }; + // // } + // //} + // //foreach (MethodInformation.Argument xArg in aArgs) { + // // if (xArg.IsReferenceType) { + // // Op.Ldarg(aAssembler, + // // xArg, + // // false); + // // //, aGetStorageSizeDelegate(xArg.ArgumentType) + // // new CPUx86.Call { DestinationLabel = aDecRefLabel }; + // // } + // //} + // // todo: add GC code + // new CPUx86.Pop { DestinationReg = CPUx86.Registers.ECX }; + //} + if (aMethod.MethodAssembler == null && aMethod.PlugMethod == null) + { + var xBody = aMethod.MethodBase.GetMethodBody(); + if (xBody != null) + { + for (int j = xBody.LocalVariables.Count - 1; j >= 0; j--) + { + int xLocalSize = (int)ILOp.Align(ILOp.SizeOfType(xBody.LocalVariables[j].LocalType), 4); + new CPUx86.Add { DestinationReg = CPUx86.Registers.ESP, SourceValue = (uint)xLocalSize }; + } + } + } + //new CPUx86.Add(CPUx86.Registers_Old.ESP, "0x4"); + //new CPUx86.Compare { DestinationReg = Registers.EBP, SourceReg = Registers.ESP }; + //new CPUx86.ConditionalJump { Condition = ConditionalTestEnum.Equal, DestinationLabel = MethodInfoLabelGenerator.GenerateLabelName(aMethod.MethodBase) + EndOfMethodLabelNameException + "__2" }; + //new CPUx86.Xchg { DestinationReg = Registers.BX, SourceReg = Registers.BX }; + //new CPUx86.Halt(); + // TODO: not nice coding, still a test + //new CPUx86.Move { DestinationReg = Registers.ESP, SourceReg = Registers.EBP }; + new Label(ILOp.GetMethodLabel(aMethod) + EndOfMethodLabelNameException + "__2"); + new CPUx86.Pop { DestinationReg = CPUx86.Registers.EBP }; + var xRetSize = ((int)xTotalArgsSize) - ((int)xReturnSize); + if (xRetSize < 0) + { + xRetSize = 0; + } + WriteDebug(aMethod.MethodBase, (uint)xRetSize, IL.Call.GetStackSizeToReservate(aMethod.MethodBase)); + new CPUx86.Return { DestinationValue = (uint)xRetSize }; + } + + public static uint GetResultCodeOffset(uint aResultSize, uint aTotalArgumentSize) + { + uint xOffset = 8; + if ((aTotalArgumentSize > 0) && (aTotalArgumentSize >= aResultSize)) + { + xOffset += aTotalArgumentSize; + xOffset -= aResultSize; + } + return xOffset; + } + + private static ISymbolReader GetSymbolReaderForAssembly(Assembly aAssembly) + { try { - xMLSymbol.AssemblyFile = aMethod.MethodBase.DeclaringType.Assembly.Location; + return SymbolAccess.GetReaderForFile(aAssembly.Location); } catch (NotSupportedException) { - xMLSymbol.AssemblyFile = "DYNAMIC: " + aMethod.MethodBase.DeclaringType.Assembly.FullName; + return null; } - xMLSymbol.MethodToken = aMethod.MethodBase.MetadataToken; - xMLSymbol.TypeToken = aMethod.MethodBase.DeclaringType.MetadataToken; - xMLSymbol.ILOffset = aOpCode.Position; - mSymbols.Add(xMLSymbol); } - #endregion - EmitTracer(aMethod, aOpCode, aMethod.MethodBase.DeclaringType.Namespace, xCodeOffsets); - } - public TraceAssemblies TraceAssemblies; - public DebugMode DebugMode; + protected override void MethodBegin(string aMethodName) + { + base.MethodBegin(aMethodName); + new Label(aMethodName); + new Push { DestinationReg = Registers.EBP }; + new Move { DestinationReg = Registers.EBP, SourceReg = Registers.ESP }; + xCodeOffsets = new int[0]; + } - protected void EmitTracer(MethodInfo aMethod, ILOpCode aOp, string aNamespace, int[] aCodeOffsets) { - // NOTE - These if statements can be optimized down - but clarity is - // more importnat the optimizations would not offer much benefit + protected override void MethodEnd(string aMethodName) + { + base.MethodEnd(aMethodName); + new Label("_END_OF_" + aMethodName); + new CPUx86.Pop { DestinationReg = CPUx86.Registers.EBP }; + new CPUx86.Return(); + } - // Determine if a new DebugStub should be emitted - //bool xEmit = false; - // Skip NOOP's so we dont have breakpoints on them - //TODO: Each IL op should exist in IL, and descendants in IL.X86. - // Because of this we have this hack - if (aOp.OpCode == ILOpCode.Code.Nop) { - return; - } else if (DebugMode == DebugMode.None) { - return; - } else if (DebugMode == DebugMode.Source) { - // If the current position equals one of the offsets, then we have - // reached a new atomic C# statement - if (aCodeOffsets != null) { - var xIndex = Array.IndexOf(aCodeOffsets, aOp.Position); - if (xIndex == -1) { + private static HashSet mDebugLines = new HashSet(); + private static void WriteDebug(MethodBase aMethod, uint aSize, uint aSize2) + { + var xLine = String.Format("{0}\t{1}\t{2}", MethodInfoLabelGenerator.GenerateFullName(aMethod), aSize, aSize2); + + } + private List mSymbols = new List(); + + // These are all temp functions until we move to the new assembler. + // They are used to clean up the old assembler slightly while retaining compatibiltiy for now + public static string TmpPosLabel(MethodInfo aMethod, int aOffset) + { + // todo: fix to be small again. + return ILOp.GetLabel(aMethod, aOffset); + //TODO: Change to Hex output, will be smaller and slightly faster for NASM + //return "POS_" + aMethod.UID + "_" + aOffset; + } + + public static string TmpPosLabel(MethodInfo aMethod, ILOpCode aOpCode) + { + return TmpPosLabel(aMethod, aOpCode.Position); + } + + public static string TmpBranchLabel(MethodInfo aMethod, ILOpCode aOpCode) + { + return TmpPosLabel(aMethod, ((ILOpCodes.OpBranch)aOpCode).Value); + } + + protected override void BeforeOp(MethodInfo aMethod, ILOpCode aOpCode) + { + base.BeforeOp(aMethod, aOpCode); + new Label(TmpPosLabel(aMethod, aOpCode)); + #region Collection debug information + if (mSymbols != null) + { + var xMLSymbol = new DebugInfo.MLDebugSymbol(); + xMLSymbol.LabelName = TmpPosLabel(aMethod, aOpCode); + xMLSymbol.MethodName = aMethod.MethodBase.GetFullName(); + int xStackSize = (from item in mAssembler.Stack + let xSize = (item.Size % 4 == 0) + ? item.Size + : (item.Size + (4 - (item.Size % 4))) + select xSize).Sum(); + xMLSymbol.StackDifference = -1; + if (aMethod.MethodBase != null) + { + var xBody = aMethod.MethodBase.GetMethodBody(); + if (xBody != null) + { + var xLocalsSize = (from item in xBody.LocalVariables + select (int)ILOp.Align(ILOp.SizeOfType(item.LocalType), 4)).Sum(); + xMLSymbol.StackDifference = xLocalsSize + xStackSize; + } + } + try + { + xMLSymbol.AssemblyFile = aMethod.MethodBase.DeclaringType.Assembly.Location; + } + catch (NotSupportedException) + { + xMLSymbol.AssemblyFile = "DYNAMIC: " + aMethod.MethodBase.DeclaringType.Assembly.FullName; + } + xMLSymbol.MethodToken = aMethod.MethodBase.MetadataToken; + xMLSymbol.TypeToken = aMethod.MethodBase.DeclaringType.MetadataToken; + xMLSymbol.ILOffset = aOpCode.Position; + mSymbols.Add(xMLSymbol); + } + #endregion + EmitTracer(aMethod, aOpCode, aMethod.MethodBase.DeclaringType.Namespace, xCodeOffsets); + } + + public TraceAssemblies TraceAssemblies; + public DebugMode DebugMode; + + protected void EmitTracer(MethodInfo aMethod, ILOpCode aOp, string aNamespace, int[] aCodeOffsets) + { + // NOTE - These if statements can be optimized down - but clarity is + // more importnat the optimizations would not offer much benefit + + // Determine if a new DebugStub should be emitted + //bool xEmit = false; + // Skip NOOP's so we dont have breakpoints on them + //TODO: Each IL op should exist in IL, and descendants in IL.X86. + // Because of this we have this hack + if (aOp.OpCode == ILOpCode.Code.Nop) + { + return; + } + else if (DebugMode == DebugMode.None) + { + return; + } + else if (DebugMode == DebugMode.Source) + { + // If the current position equals one of the offsets, then we have + // reached a new atomic C# statement + if (aCodeOffsets != null) + { + var xIndex = Array.IndexOf(aCodeOffsets, aOp.Position); + if (xIndex == -1) + { + return; + } + // 0xFEEFEE means hiddenline -> we dont want to stop there + if (xCodeLineNumbers[xIndex] == 0xFEEFEE) + { + return; + } + } + } + + // Check options for Debug Level + // Set based on TracedAssemblies + if (TraceAssemblies == TraceAssemblies.Cosmos || TraceAssemblies == TraceAssemblies.User) + { + if (aNamespace.StartsWith("System.", StringComparison.InvariantCultureIgnoreCase)) + { return; } - // 0xFEEFEE means hiddenline -> we dont want to stop there - if (xCodeLineNumbers[xIndex] == 0xFEEFEE) + else if (aNamespace.ToLower() == "system") + { + return; + } + else if (aNamespace.StartsWith("Microsoft.", StringComparison.InvariantCultureIgnoreCase)) { return; } } + if (TraceAssemblies == TraceAssemblies.User) + { + //TODO: Maybe an attribute that could be used to turn tracing on and off + //TODO: This doesnt match Cosmos.Kernel exact vs Cosmos.Kernel., so a user + // could do Cosmos.KernelMine and it will fail. Need to fix this + if (aNamespace.StartsWith("Cosmos.Kernel", StringComparison.InvariantCultureIgnoreCase)) + { + return; + } + else if (aNamespace.StartsWith("Cosmos.Sys", StringComparison.InvariantCultureIgnoreCase)) + { + return; + } + else if (aNamespace.StartsWith("Cosmos.Hardware", StringComparison.InvariantCultureIgnoreCase)) + { + return; + } + else if (aNamespace.StartsWith("Cosmos.IL2CPU", StringComparison.InvariantCultureIgnoreCase)) + { + return; + } + } + // If we made it this far, emit the Tracer + new CPUx86.Call { DestinationLabel = "DebugStub_TracerEntry" }; } - // Check options for Debug Level - // Set based on TracedAssemblies - if (TraceAssemblies == TraceAssemblies.Cosmos || TraceAssemblies == TraceAssemblies.User) + private int[] xCodeOffsets; + private int[] xCodeLineNumbers; + protected override void AfterOp(MethodInfo aMethod, ILOpCode aOpCode) { - if (aNamespace.StartsWith("System.", StringComparison.InvariantCultureIgnoreCase)) + base.AfterOp(aMethod, aOpCode); + var xContents = ""; + foreach (var xStackItem in mAssembler.Stack) { - return; + xContents += ILOp.Align((uint)xStackItem.Size, 4); + xContents += ", "; } - else if (aNamespace.ToLower() == "system") + if (xContents.EndsWith(", ")) { - return; - } - else if (aNamespace.StartsWith("Microsoft.", StringComparison.InvariantCultureIgnoreCase)) - { - return; + xContents = xContents.Substring(0, xContents.Length - 2); } + new Comment("Stack contains " + mAssembler.Stack.Count + " items: (" + xContents + ")"); } - if (TraceAssemblies == TraceAssemblies.User) - { - //TODO: Maybe an attribute that could be used to turn tracing on and off - //TODO: This doesnt match Cosmos.Kernel exact vs Cosmos.Kernel., so a user - // could do Cosmos.KernelMine and it will fail. Need to fix this - if (aNamespace.StartsWith("Cosmos.Kernel", StringComparison.InvariantCultureIgnoreCase)) - { - return; - } - else if (aNamespace.StartsWith("Cosmos.Sys", StringComparison.InvariantCultureIgnoreCase)) - { - return; - } - else if (aNamespace.StartsWith("Cosmos.Hardware", StringComparison.InvariantCultureIgnoreCase)) - { - return; - } - else if (aNamespace.StartsWith("Cosmos.IL2CPU", StringComparison.InvariantCultureIgnoreCase)) - { - return; - } - } - // If we made it this far, emit the Tracer - new CPUx86.Call { DestinationLabel = "DebugStub_TracerEntry" }; - } - private int[] xCodeOffsets; - private int[] xCodeLineNumbers; - protected override void AfterOp(MethodInfo aMethod, ILOpCode aOpCode) { - base.AfterOp(aMethod, aOpCode); - var xContents = ""; - foreach (var xStackItem in mAssembler.Stack) - { - xContents += ILOp.Align((uint)xStackItem.Size, 4); - xContents += ", "; - } - if (xContents.EndsWith(", ")) { - xContents = xContents.Substring(0, xContents.Length - 2); - } - new Comment("Stack contains " + mAssembler.Stack.Count + " items: (" + xContents + ")"); - } - - public void WriteDebugSymbols(string DebugSymbolsFile) - { - if (mSymbols.Count > 0) + public DebugInfo DebugInfo { - MLDebugSymbol.WriteSymbolsListToFile(mSymbols, DebugSymbolsFile); + get; + set; + } + + public void FinalizeDebugInfo() + { + this.DebugInfo.WriteSymbolsListToFile(mSymbols); } } - } -} +} \ No newline at end of file