"Fossies" - the Fresh Open Source Software Archive 
Member "mono-6.12.0.122/external/linker/src/linker/Linker.Steps/BodySubstituterStep.cs" (22 Feb 2021, 8807 Bytes) of package /linux/misc/mono-sources/mono/mono-6.12.0.122.tar.xz:
As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C# source code syntax highlighting (style:
standard) with prefixed line numbers and
code folding option.
Alternatively you can here
view or
download the uninterpreted source code file.
1 using System;
2 using System.IO;
3 using System.Linq;
4 using System.Globalization;
5 using System.Xml.XPath;
6 using Mono.Cecil;
7
8 namespace Mono.Linker.Steps
9 {
10 public class BodySubstituterStep : BaseStep
11 {
12 protected override void Process ()
13 {
14 var files = Context.Substitutions;
15 if (files == null)
16 return;
17
18 foreach (var file in files) {
19 try {
20 ReadSubstitutionFile (GetSubstitutions (file));
21 } catch (Exception ex) when (!(ex is XmlResolutionException)) {
22 throw new XmlResolutionException ($"Failed to process XML substitution '{file}'", ex);
23 }
24
25 }
26 }
27
28 static XPathDocument GetSubstitutions (string substitutionsFile)
29 {
30 using (FileStream fs = File.OpenRead (substitutionsFile)) {
31 return GetSubstitutions (fs);
32 }
33 }
34
35 static XPathDocument GetSubstitutions (Stream substitutions)
36 {
37 using (StreamReader sr = new StreamReader (substitutions)) {
38 return new XPathDocument (sr);
39 }
40 }
41
42 void ReadSubstitutionFile (XPathDocument document)
43 {
44 XPathNavigator nav = document.CreateNavigator ();
45
46 // Initial structure check
47 if (!nav.MoveToChild ("linker", ""))
48 return;
49
50 // TODO: Add handling for feature
51
52 ProcessAssemblies (nav.SelectChildren ("assembly", ""));
53 }
54
55 void ProcessAssemblies (XPathNodeIterator iterator)
56 {
57 while (iterator.MoveNext ()) {
58 var name = GetAssemblyName (iterator.Current);
59
60 var cache = Context.Resolver.AssemblyCache;
61
62 if (!cache.TryGetValue (name.Name, out AssemblyDefinition assembly)) {
63 Context.LogMessage (MessageImportance.Low, $"Could not match assembly '{name.FullName}' for substitution");
64 continue;
65 }
66
67 ProcessAssembly (assembly, iterator);
68 }
69 }
70
71 void ProcessAssembly (AssemblyDefinition assembly, XPathNodeIterator iterator)
72 {
73 ProcessTypes (assembly, iterator.Current.SelectChildren ("type", ""));
74 ProcessResources (assembly, iterator.Current.SelectChildren ("resource", ""));
75 }
76
77 void ProcessTypes (AssemblyDefinition assembly, XPathNodeIterator iterator)
78 {
79 while (iterator.MoveNext ()) {
80 XPathNavigator nav = iterator.Current;
81
82 string fullname = GetAttribute (nav, "fullname");
83
84 TypeDefinition type = assembly.MainModule.GetType (fullname);
85
86 if (type == null) {
87 Context.LogMessage (MessageImportance.Low, $"Could not resolve type '{fullname}' for substitution");
88 continue;
89 }
90
91 ProcessType (type, nav);
92 }
93 }
94
95 void ProcessType (TypeDefinition type, XPathNavigator nav)
96 {
97 if (!nav.HasChildren)
98 return;
99
100 XPathNodeIterator methods = nav.SelectChildren ("method", "");
101 if (methods.Count > 0)
102 ProcessMethods (type, methods);
103
104 var fields = nav.SelectChildren ("field", "");
105 if (fields.Count > 0) {
106 while (fields.MoveNext ())
107 ProcessField (type, fields);
108 }
109 }
110
111 void ProcessMethods (TypeDefinition type, XPathNodeIterator iterator)
112 {
113 while (iterator.MoveNext ())
114 ProcessMethod (type, iterator);
115 }
116
117 void ProcessMethod (TypeDefinition type, XPathNodeIterator iterator)
118 {
119 string signature = GetAttribute (iterator.Current, "signature");
120 if (string.IsNullOrEmpty (signature))
121 return;
122
123 MethodDefinition method = FindMethod (type, signature);
124 if (method == null) {
125 Context.LogMessage (MessageImportance.Normal, $"Could not find method '{signature}' for substitution");
126 return;
127 }
128
129 string action = GetAttribute (iterator.Current, "body");
130 switch (action) {
131 case "remove":
132 Annotations.SetAction (method, MethodAction.ConvertToThrow);
133 return;
134 case "stub":
135 string value = GetAttribute (iterator.Current, "value");
136 if (value != "") {
137 if (!TryConvertValue (value, method.ReturnType, out object res)) {
138 Context.LogMessage (MessageImportance.High, $"Invalid value for '{signature}' stub");
139 return;
140 }
141
142 Annotations.SetMethodStubValue (method, res);
143 }
144
145 Annotations.SetAction (method, MethodAction.ConvertToStub);
146 return;
147 default:
148 Context.LogMessage (MessageImportance.High, $"Unknown body modification '{action}' for '{signature}'");
149 return;
150 }
151 }
152
153 void ProcessField (TypeDefinition type, XPathNodeIterator iterator)
154 {
155 string name = GetAttribute (iterator.Current, "name");
156 if (string.IsNullOrEmpty (name))
157 return;
158
159 var field = type.Fields.FirstOrDefault (f => f.Name == name);
160 if (field == null) {
161 Context.LogMessage (MessageImportance.Normal, $"Could not find field '{name}' for substitution.");
162 return;
163 }
164
165 if (!field.IsStatic || field.IsLiteral) {
166 Context.LogMessage (MessageImportance.Normal, $"Substituted field '{name}' needs to be static field.");
167 return;
168 }
169
170 string value = GetAttribute (iterator.Current, "value");
171 if (string.IsNullOrEmpty (value)) {
172 Context.LogMessage (MessageImportance.High, $"Missing 'value' attribute for field '{field}'.");
173 return;
174 }
175 if (!TryConvertValue (value, field.FieldType, out object res)) {
176 Context.LogMessage (MessageImportance.High, $"Invalid value for '{field}': '{value}'.");
177 return;
178 }
179
180 Annotations.SetFieldValue (field, res);
181
182 string init = GetAttribute (iterator.Current, "initialize");
183 if (init?.ToLowerInvariant () == "true") {
184 Annotations.SetSubstitutedInit (field);
185 }
186 }
187
188 void ProcessResources (AssemblyDefinition assembly, XPathNodeIterator iterator)
189 {
190 while (iterator.MoveNext ()) {
191 XPathNavigator nav = iterator.Current;
192
193 string name = GetAttribute (nav, "name");
194 if (String.IsNullOrEmpty (name)) {
195 Context.LogMessage (MessageImportance.High, $"Invalid value for 'name' attribute: '{name}'.");
196 return;
197 }
198
199 Context.Annotations.AddResourceToRemove (assembly, name);
200 }
201 }
202
203 static bool TryConvertValue (string value, TypeReference target, out object result)
204 {
205 switch (target.MetadataType) {
206 case MetadataType.Boolean:
207 if (bool.TryParse (value, out bool bvalue)) {
208 result = bvalue ? 1 : 0;
209 return true;
210 }
211
212 goto case MetadataType.Int32;
213
214 case MetadataType.Byte:
215 if (!byte.TryParse (value, NumberStyles.Integer, CultureInfo.InvariantCulture, out byte byteresult))
216 break;
217
218 result = (int) byteresult;
219 return true;
220
221 case MetadataType.SByte:
222 if (!sbyte.TryParse (value, NumberStyles.Integer, CultureInfo.InvariantCulture, out sbyte sbyteresult))
223 break;
224
225 result = (int) sbyteresult;
226 return true;
227
228 case MetadataType.Int16:
229 if (!short.TryParse (value, NumberStyles.Integer, CultureInfo.InvariantCulture, out short shortresult))
230 break;
231
232 result = (int) shortresult;
233 return true;
234
235 case MetadataType.UInt16:
236 if (!ushort.TryParse (value, NumberStyles.Integer, CultureInfo.InvariantCulture, out ushort ushortresult))
237 break;
238
239 result = (int) ushortresult;
240 return true;
241
242 case MetadataType.Int32:
243 if (!int.TryParse (value, NumberStyles.Integer, CultureInfo.InvariantCulture, out int iresult))
244 break;
245
246 result = iresult;
247 return true;
248
249 case MetadataType.UInt32:
250 if (!uint.TryParse (value, NumberStyles.Integer, CultureInfo.InvariantCulture, out uint uresult))
251 break;
252
253 result = (int)uresult;
254 return true;
255
256 case MetadataType.Double:
257 if (!double.TryParse (value, NumberStyles.Float, CultureInfo.InvariantCulture, out double dresult))
258 break;
259
260 result = dresult;
261 return true;
262
263 case MetadataType.Single:
264 if (!float.TryParse (value, NumberStyles.Float, CultureInfo.InvariantCulture, out float fresult))
265 break;
266
267 result = fresult;
268 return true;
269
270 case MetadataType.Int64:
271 if (!long.TryParse (value, NumberStyles.Integer, CultureInfo.InvariantCulture, out long lresult))
272 break;
273
274 result = lresult;
275 return true;
276
277 case MetadataType.UInt64:
278 if (!ulong.TryParse (value, NumberStyles.Integer, CultureInfo.InvariantCulture, out ulong ulresult))
279 break;
280
281 result = (long)ulresult;
282 return true;
283
284 case MetadataType.Char:
285 if (!char.TryParse (value, out char chresult))
286 break;
287
288 result = (int) chresult;
289 return true;
290
291 case MetadataType.String:
292 if (value is string || value == null) {
293 result = value;
294 return true;
295 }
296
297 break;
298 }
299
300 result = null;
301 return false;
302 }
303
304 static MethodDefinition FindMethod (TypeDefinition type, string signature)
305 {
306 if (!type.HasMethods)
307 return null;
308
309 foreach (MethodDefinition meth in type.Methods)
310 if (signature == ResolveFromXmlStep.GetMethodSignature (meth, includeGenericParameters: true))
311 return meth;
312
313 return null;
314 }
315
316 static AssemblyNameReference GetAssemblyName (XPathNavigator nav)
317 {
318 return AssemblyNameReference.Parse (GetAttribute (nav, "fullname"));
319 }
320
321 static string GetAttribute (XPathNavigator nav, string attribute)
322 {
323 return nav.GetAttribute (attribute, "");
324 }
325 }
326 }