1 //
2 // Copyright (c) 2010-2023 Antmicro
3 // Copyright (c) 2011-2015 Realtime Embedded
4 //
5 // This file is licensed under the MIT License.
6 // Full license text is available in 'licenses/MIT.txt'.
7 //
8 using System;
9 using System.Reflection;
10 using System.Reflection.Emit;
11 using System.Runtime.InteropServices;
12 using System.IO;
13 using Antmicro.Renode.Utilities;
14 
15 namespace Antmicro.Renode.TAPHelper
16 {
17     public class DynamicModuleSpawner
18     {
GetTAPHelper()19         public static string GetTAPHelper()
20         {
21             var generatedFileName = TemporaryFilesManager.Instance.GetTemporaryFile();
22             var dirName = Path.GetDirectoryName(generatedFileName);
23             var filName = Path.GetFileName(generatedFileName);
24 
25             // Copy Infrastructure.dll to temp directory
26             var currentAssemblyPath = Assembly.GetExecutingAssembly().CodeBase.Substring(7);
27             var targetPath = Path.Combine(TemporaryFilesManager.Instance.EmulatorTemporaryPath, "Infrastructure.dll");
28             File.Copy(currentAssemblyPath, targetPath, true);
29 
30             // Generate binary
31             GenerateTAPHelper(dirName, filName, currentAssemblyPath);
32 
33             return generatedFileName;
34         }
35 
DynamicModuleSpawner()36         private DynamicModuleSpawner()
37         {
38         }
39 
GenerateTAPHelper(string path, string filename, string extensionsAssemblyPath)40         private static void GenerateTAPHelper(string path, string filename, string extensionsAssemblyPath)
41         {
42             var assembly = new AssemblyName { Name = "TAPHelperAssembly" };
43             var assemblyBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(assembly, AssemblyBuilderAccess.Save, path);
44 
45             var moduleBuilder = assemblyBuilder.DefineDynamicModule(assembly.Name, filename);
46             var typeBuilder = moduleBuilder.DefineType("TAPHelper", TypeAttributes.Public|TypeAttributes.Class);
47             var mainMethodBuilder = typeBuilder.DefineMethod("Main", MethodAttributes.Public | MethodAttributes.Static, typeof(int), new Type[] { typeof(string[]) });
48 
49             //
50             // Main method
51             //
52             var generator = mainMethodBuilder.GetILGenerator();
53             var intptrLocale = generator.DeclareLocal(typeof(IntPtr));
54             var setReturnFail = generator.DefineLabel();
55             var freeMemoryAndFinish = generator.DefineLabel();
56 
57             // load the proper assembly
58             generator.Emit(OpCodes.Ldtoken, typeof(Func<IntPtr, bool, int>));
59             generator.Emit(OpCodes.Call, typeof(Type).GetMethod("GetTypeFromHandle"));
60             generator.Emit(OpCodes.Ldstr, extensionsAssemblyPath);
61             generator.Emit(OpCodes.Call, typeof(Assembly).GetMethod("LoadFrom", new [] { typeof(string) }));
62             generator.Emit(OpCodes.Ldstr, "Antmicro.Renode.TAPHelper.TAPTools");
63             generator.Emit(OpCodes.Callvirt, typeof(Assembly).GetMethod("GetType", new [] { typeof(string) }));
64             generator.Emit(OpCodes.Ldstr, "OpenTAP");
65             generator.Emit(OpCodes.Call, typeof(Delegate).GetMethod("CreateDelegate", new [] { typeof(Type), typeof(Type), typeof(string) }));
66             generator.Emit(OpCodes.Castclass, typeof(Func<IntPtr, bool, int>));
67 
68             // push device name on stack
69             generator.Emit(OpCodes.Ldarg_0);
70             generator.Emit(OpCodes.Ldc_I4, 0);
71             generator.Emit(OpCodes.Ldelem, typeof(string));
72             generator.Emit(OpCodes.Call, typeof(Marshal).GetMethod("StringToCoTaskMemAuto"));
73             generator.Emit(OpCodes.Dup);
74             generator.Emit(OpCodes.Stloc, intptrLocale);
75 
76             // push 'persistant' flag on stack
77             generator.Emit(OpCodes.Ldarg_0);
78             generator.Emit(OpCodes.Ldc_I4, 1);
79             generator.Emit(OpCodes.Ldelem, typeof(string));
80             generator.Emit(OpCodes.Call, typeof(bool).GetMethod("Parse", new [] { typeof(string) }));
81 
82             // call OpenTAP method
83             generator.Emit(OpCodes.Callvirt, typeof(Func<IntPtr, bool, int>).GetMethod("Invoke", new [] { typeof(IntPtr), typeof(bool) }));
84 
85             generator.Emit(OpCodes.Ldc_I4, 0);
86             generator.Emit(OpCodes.Blt, setReturnFail);
87             generator.Emit(OpCodes.Ldc_I4, 0);
88             generator.Emit(OpCodes.Br, freeMemoryAndFinish);
89 
90             generator.MarkLabel(setReturnFail);
91             /*
92             generator.Emit(OpCodes.Ldtoken, typeof(Func<int>));
93             generator.Emit(OpCodes.Call, typeof(Type).GetMethod("GetTypeFromHandle"));
94             generator.Emit(OpCodes.Ldstr, extensionsAssemblyPath);
95             generator.Emit(OpCodes.Call, typeof(Assembly).GetMethod("LoadFrom", new [] { typeof(string) }));
96             generator.Emit(OpCodes.Ldstr, "Antmicro.Renode.TAPHelper.LibC");
97             generator.Emit(OpCodes.Callvirt, typeof(Assembly).GetMethod("GetType", new [] { typeof(string) }));
98             generator.Emit(OpCodes.Ldstr, "GetLastError");
99             generator.Emit(OpCodes.Call, typeof(Delegate).GetMethod("CreateDelegate", new [] { typeof(Type), typeof(Type), typeof(string) }));
100             generator.Emit(OpCodes.Castclass, typeof(Func<int>));
101             generator.Emit(OpCodes.Callvirt, typeof(Func<int>).GetMethod("Invoke", Type.EmptyTypes));
102             */
103             generator.Emit(OpCodes.Ldc_I4, 1);
104 
105             // free memory
106             generator.MarkLabel(freeMemoryAndFinish);
107             generator.Emit(OpCodes.Ldloc, intptrLocale);
108             generator.Emit(OpCodes.Call, typeof(Marshal).GetMethod("FreeCoTaskMem"));
109 
110             generator.Emit(OpCodes.Ret);
111 
112             typeBuilder.CreateType();
113 
114             // Set the entrypoint (thereby declaring it an EXE)
115             assemblyBuilder.SetEntryPoint(mainMethodBuilder,PEFileKinds.ConsoleApplication);
116             assemblyBuilder.Save(filename);
117         }
118     }
119 }
120 
121