|
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using System.Diagnostics;
using System.IO;
using System.Reflection.Metadata;
using System.Reflection.PortableExecutable;
using Microsoft.CodeAnalysis.VisualBasic;
namespace BuildValidator
{
internal static class Util
{
internal static PortableExecutableInfo? GetPortableExecutableInfo(string filePath)
{
using var stream = File.OpenRead(filePath);
var peReader = new PEReader(stream);
if (GetMvid(peReader) is { } mvid)
{
var isReadyToRun = IsReadyToRunImage(peReader);
var isRefAssembly = IsReferenceAssembly(peReader);
return new PortableExecutableInfo(filePath, mvid, isReadyToRun, isRefAssembly);
}
return null;
}
internal static Guid? GetMvid(PEReader peReader)
{
if (peReader.HasMetadata)
{
var metadataReader = peReader.GetMetadataReader();
var mvidHandle = metadataReader.GetModuleDefinition().Mvid;
return metadataReader.GetGuid(mvidHandle);
}
else
{
return null;
}
}
internal static bool IsReferenceAssembly(this PEReader peReader)
{
var reader = peReader.GetMetadataReader();
foreach (var attributeHandle in reader.GetCustomAttributes(Handle.AssemblyDefinition))
{
var attribute = reader.GetCustomAttribute(attributeHandle);
if (GetAttributeFullName(reader, attribute) == "System.Runtime.CompilerServices.ReferenceAssemblyAttribute")
{
return true;
}
}
return false;
}
internal static string GetAttributeFullName(MetadataReader reader, CustomAttribute attribute)
{
switch (attribute.Constructor.Kind)
{
case HandleKind.MethodDefinition:
{
var methodDef = reader.GetMethodDefinition((MethodDefinitionHandle)attribute.Constructor);
var declaringTypeHandle = methodDef.GetDeclaringType();
var typeDefinition = reader.GetTypeDefinition(declaringTypeHandle);
var @namespace = reader.GetString(typeDefinition.Namespace);
var name = reader.GetString(typeDefinition.Name);
return $"{@namespace}.{name}";
}
case HandleKind.MemberReference:
{
var memberRef = reader.GetMemberReference((MemberReferenceHandle)attribute.Constructor);
Debug.Assert(memberRef.Parent.Kind == HandleKind.TypeReference);
var typeRef = reader.GetTypeReference((TypeReferenceHandle)memberRef.Parent);
var @namespace = reader.GetString(typeRef.Namespace);
var name = reader.GetString(typeRef.Name);
return $"{@namespace}.{name}";
}
default:
throw new InvalidOperationException();
}
}
internal static bool IsReadyToRunImage(PEReader peReader)
{
if (peReader.PEHeaders is null ||
peReader.PEHeaders.PEHeader is null ||
peReader.PEHeaders.CorHeader is null)
{
return false;
}
if ((peReader.PEHeaders.CorHeader.Flags & CorFlags.ILLibrary) == 0)
{
PEExportTable exportTable = peReader.GetExportTable();
return exportTable.TryGetValue("RTR_HEADER", out _);
}
else
{
return peReader.PEHeaders.CorHeader.ManagedNativeHeaderDirectory.Size != 0;
}
}
}
}
|