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.Collections.Generic;
9 using System.IO;
10 using System.Linq;
11 using System.Runtime.InteropServices;
12 using Mono.Cecil;
13 
14 namespace Antmicro.Renode.Utilities
15 {
16     public class AssemblyHelper
17     {
TryInitializeBundledAssemblies()18         public static bool TryInitializeBundledAssemblies()
19         {
20             var result = false;
21             for(var i = 0; i < BundledAssembliesCount; i++)
22             {
23                 var bundledAssembly = GetBundledAssemblyById(i);
24                 bundledAssemblies.Add(bundledAssembly);
25                 result = true;
26             }
27 
28             return result;
29         }
30 
GetBundledAssembliesNames()31         public static IEnumerable<string> GetBundledAssembliesNames()
32         {
33             return bundledAssemblies.Select(x => x.Name);
34         }
35 
GetBundledAssemblyByFullName(string fullName)36         public static AssemblyDefinition GetBundledAssemblyByFullName(string fullName)
37         {
38             return bundledAssemblies.Select(x => x.Definition).FirstOrDefault(x => x.FullName == fullName);
39         }
40 
GetBundledAssemblyByName(string name)41         public static AssemblyDefinition GetBundledAssemblyByName(string name)
42         {
43             return bundledAssemblies.FirstOrDefault(x => x.Name == name).Definition;
44         }
45 
GetAssembliesLocations()46         public static IEnumerable<string> GetAssembliesLocations()
47         {
48             if(BundledAssembliesCount > 0)
49             {
50                 foreach(var assembly in bundledAssemblies.Select(x => x.Location))
51                 {
52                     yield return assembly;
53                 }
54             }
55             foreach(var assembly in AppDomain.CurrentDomain.GetAssemblies().Where(x => !x.IsDynamic).Select(x => x.Location).Where(Path.IsPathRooted))
56             {
57                 yield return assembly;
58             }
59         }
60 
61         public static int BundledAssembliesCount
62         {
63             get
64             {
65                 try
66                 {
67                     return GetBundlesCountInternal();
68                 }
69                 catch
70                 {
71                     // an exception means we couldn't locate
72                     // `GetBundlesCount` function in this binary;
73                     // that, in turn, means that there are no
74                     // bundled assemblies - that's why we simply
75                     // return 0
76                     return 0;
77                 }
78             }
79         }
80 
GetBundledAssemblyById(int id)81         private static BundledAssemblyDefinition GetBundledAssemblyById(int id)
82         {
83             unsafe
84             {
85                 var result = new BundledAssemblyDefinition();
86                 using(var stream = new UnmanagedMemoryStream((byte*)GetBundleDataPointerInternal(id).ToPointer(), GetBundleDataSizeInternal(id)))
87                 {
88                     result.Name = Marshal.PtrToStringAnsi(GetBundleNameInternal(id));
89                     result.Definition = AssemblyDefinition.ReadAssembly(stream);
90                     result.Location = ExtractAssemblyToFile(stream, result.Name);
91                 }
92                 return result;
93             }
94         }
95 
ExtractAssemblyToFile(Stream stream, string fileName)96         private static string ExtractAssemblyToFile(Stream stream, string fileName)
97         {
98             var outputFile = TemporaryFilesManager.Instance.GetTemporaryFile(fileName);
99             using(var fileStream = File.Create(outputFile, (int)stream.Length))
100             {
101                 var bytesInStream = new byte[stream.Length];
102                 stream.Seek(0, SeekOrigin.Begin);
103                 stream.Read(bytesInStream, 0, bytesInStream.Length);
104                 fileStream.Write(bytesInStream, 0, bytesInStream.Length);
105             }
106             return outputFile;
107         }
108 
109         [DllImport("__Internal", EntryPoint = "GetBundlesCount")]
GetBundlesCountInternal()110         private static extern int GetBundlesCountInternal();
111 
112         [DllImport("__Internal", EntryPoint = "GetBundleName")]
GetBundleNameInternal(int id)113         private static extern IntPtr GetBundleNameInternal(int id);
114 
115         [DllImport("__Internal", EntryPoint = "GetBundleDataSize")]
GetBundleDataSizeInternal(int id)116         private static extern UInt32 GetBundleDataSizeInternal(int id);
117 
118         [DllImport("__Internal", EntryPoint = "GetBundleDataPointer")]
GetBundleDataPointerInternal(int id)119         private static extern IntPtr GetBundleDataPointerInternal(int id);
120 
121         private static readonly List<BundledAssemblyDefinition> bundledAssemblies = new List<BundledAssemblyDefinition>();
122 
123         private struct BundledAssemblyDefinition
124         {
125             public string Name;
126             public AssemblyDefinition Definition;
127             public string Location;
128         }
129     }
130 }
131