1 // 2 // Copyright (c) 2010-2022 Antmicro 3 // 4 // This file is licensed under the MIT License. 5 // Full license text is available in 'licenses/MIT.txt'. 6 // 7 using System; 8 using System.IO; 9 using System.Linq; 10 using System.Text; 11 using System.Text.Json; 12 using System.Reflection; 13 using System.Collections.Generic; 14 using System.Runtime.InteropServices; 15 using Microsoft.CodeAnalysis; 16 using Microsoft.CodeAnalysis.CSharp; 17 using Microsoft.CodeAnalysis.Text; 18 using Antmicro.Renode.Utilities; 19 using Antmicro.Renode.Exceptions; 20 21 namespace Antmicro.Renode.TAPHelper 22 { 23 public class DynamicModuleSpawner 24 { GetTAPHelper()25 public static string GetTAPHelper() 26 { 27 var generatedFilePath = TemporaryFilesManager.Instance.GetTemporaryFile(); 28 var outputFilePath = Path.ChangeExtension(generatedFilePath, ".dll"); 29 var outputFileName = Path.GetFileName(outputFilePath); 30 31 GenerateTAPHelper(outputFilePath, outputFileName); 32 33 // Generate runtimeconfig.json file necessary to run standalone application with dotnet on .NETCore and above 34 File.WriteAllText( 35 Path.ChangeExtension(generatedFilePath, "runtimeconfig.json"), 36 GenerateRuntimeConfig() 37 ); 38 39 // Copy Infrastructure.dll to temp directory 40 var currentAssemblyPath = Assembly.GetExecutingAssembly().Location; 41 var targetPath = Path.Combine(TemporaryFilesManager.Instance.EmulatorTemporaryPath, "Infrastructure.dll"); 42 File.Copy(currentAssemblyPath, targetPath, true); 43 44 return outputFilePath; 45 } 46 GenerateTAPHelper(string path, string filename)47 private static void GenerateTAPHelper(string path, string filename) 48 { 49 var sourceCode = @" 50 using System.Runtime.InteropServices; 51 using Antmicro.Renode.TAPHelper; 52 public class TAP 53 { 54 public static int Main(string[] args) 55 { 56 var deviceName = args[0]; 57 var persistent = bool.Parse(args[1]); 58 var dev = Marshal.StringToCoTaskMemAuto(deviceName); 59 var err = TAPTools.OpenTAP(dev, persistent); 60 Marshal.FreeCoTaskMem(dev); 61 if (err < 0) 62 { 63 return 1; 64 } 65 return 0; 66 } 67 }"; 68 var codeString = SourceText.From(sourceCode); 69 var options = CSharpParseOptions.Default.WithLanguageVersion(LanguageVersion.CSharp9); 70 71 var parsedSyntaxTree = SyntaxFactory.ParseSyntaxTree(codeString, options); 72 73 var references = new List<MetadataReference> 74 { 75 MetadataReference.CreateFromFile(typeof(object).Assembly.Location), 76 }; 77 78 AssemblyHelper.GetAssembliesLocations().ToList() 79 .ForEach(location => references.Add(MetadataReference.CreateFromFile(location))); 80 81 var result = CSharpCompilation.Create(filename, 82 new[] { parsedSyntaxTree }, 83 references: references, 84 options: new CSharpCompilationOptions( 85 OutputKind.ConsoleApplication, 86 optimizationLevel: OptimizationLevel.Release, 87 assemblyIdentityComparer: DesktopAssemblyIdentityComparer.Default)).Emit(path); 88 89 if (!result.Success) 90 { 91 var failures = result.Diagnostics.Where(diagnostic => diagnostic.IsWarningAsError || diagnostic.Severity == DiagnosticSeverity.Error); 92 var diagnosticString = string.Join(Environment.NewLine, failures.Select(x => x.ToString())); 93 throw new RecoverableException("Could not compile TAP assembly. \n" + diagnosticString); 94 } 95 } 96 GenerateRuntimeConfig()97 private static string GenerateRuntimeConfig() 98 { 99 // It writes JSON of the following form: 100 // { 101 // "runtimeOptions": { 102 // "framework": { 103 // "name": "Microsoft.NETCore.App", 104 // "version": "5.0.5" 105 // } 106 // } 107 // } 108 using (var stream = new MemoryStream()) 109 { 110 using (var writer = new Utf8JsonWriter( 111 stream, 112 new JsonWriterOptions() { Indented = true } 113 )) 114 { 115 writer.WriteStartObject(); 116 writer.WriteStartObject("runtimeOptions"); 117 writer.WriteStartObject("framework"); 118 writer.WriteString("name", "Microsoft.NETCore.App"); 119 writer.WriteString( 120 "version", 121 RuntimeInformation.FrameworkDescription.Replace(".NET ", "") 122 ); 123 writer.WriteEndObject(); 124 writer.WriteEndObject(); 125 writer.WriteEndObject(); 126 } 127 128 return Encoding.UTF8.GetString(stream.ToArray()); 129 } 130 } 131 DynamicModuleSpawner()132 private DynamicModuleSpawner() 133 { 134 } 135 } 136 }