"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 }