2016-02-18 01:09:23 -08:00
// Copyright (c) .NET Foundation and contributors. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
using System.Collections.Generic ;
using System.IO ;
using System.Linq ;
using System.Reflection.Metadata ;
using System.Reflection.PortableExecutable ;
2016-02-18 02:27:35 -08:00
namespace Microsoft.DotNet.Tools.Test.Utilities
2016-02-18 01:09:23 -08:00
{
public static class PeReaderUtils
{
2016-04-18 10:51:32 -07:00
public static bool IsCrossgened ( this PEReader peReader )
{
2016-04-18 12:20:30 -07:00
const int CROSSGEN_FLAG = 4 ;
2016-04-18 10:51:32 -07:00
bool isCrossgened = false ;
if ( peReader . HasMetadata )
{
// 4 is the magic numbers that is set in the CLR header's flags when crossgened.
2016-04-18 12:20:30 -07:00
isCrossgened = ( ( int ) peReader . PEHeaders . CorHeader . Flags & CROSSGEN_FLAG ) = = CROSSGEN_FLAG ;
2016-04-18 10:51:32 -07:00
}
return isCrossgened ;
}
2016-02-18 02:27:35 -08:00
public static string GetAssemblyAttributeValue ( string assemblyPath , string attributeName )
2016-02-18 01:09:23 -08:00
{
if ( ! File . Exists ( assemblyPath ) )
{
return null ;
}
using ( var stream = File . OpenRead ( assemblyPath ) )
using ( var peReader = new PEReader ( stream ) )
{
if ( ! peReader . HasMetadata )
{
return null ;
}
var mdReader = peReader . GetMetadataReader ( ) ;
var attrs = mdReader . GetAssemblyDefinition ( ) . GetCustomAttributes ( )
. Select ( ah = > mdReader . GetCustomAttribute ( ah ) ) ;
foreach ( var attr in attrs )
{
var ctorHandle = attr . Constructor ;
if ( ctorHandle . Kind ! = HandleKind . MemberReference )
{
continue ;
}
var container = mdReader . GetMemberReference ( ( MemberReferenceHandle ) ctorHandle ) . Parent ;
var name = mdReader . GetTypeReference ( ( TypeReferenceHandle ) container ) . Name ;
if ( ! string . Equals ( mdReader . GetString ( name ) , attributeName ) )
{
continue ;
}
var arguments = GetFixedStringArguments ( mdReader , attr ) ;
if ( arguments . Count = = 1 )
{
return arguments [ 0 ] ;
}
}
}
return null ;
}
/// <summary>
/// Gets the fixed (required) string arguments of a custom attribute.
/// Only attributes that have only fixed string arguments.
/// </summary>
private static List < string > GetFixedStringArguments ( MetadataReader reader , CustomAttribute attribute )
{
// TODO: Nick Guerrera (Nick.Guerrera@microsoft.com) hacked this method for temporary use.
// There is a blob decoder feature in progress but it won't ship in time for our milestone.
// Replace this method with the blob decoder feature when later it is availale.
var signature = reader . GetMemberReference ( ( MemberReferenceHandle ) attribute . Constructor ) . Signature ;
var signatureReader = reader . GetBlobReader ( signature ) ;
var valueReader = reader . GetBlobReader ( attribute . Value ) ;
var arguments = new List < string > ( ) ;
var prolog = valueReader . ReadUInt16 ( ) ;
if ( prolog ! = 1 )
{
// Invalid custom attribute prolog
return arguments ;
}
var header = signatureReader . ReadSignatureHeader ( ) ;
if ( header . Kind ! = SignatureKind . Method | | header . IsGeneric )
{
// Invalid custom attribute constructor signature
return arguments ;
}
int parameterCount ;
if ( ! signatureReader . TryReadCompressedInteger ( out parameterCount ) )
{
// Invalid custom attribute constructor signature
return arguments ;
}
var returnType = signatureReader . ReadSignatureTypeCode ( ) ;
if ( returnType ! = SignatureTypeCode . Void )
{
// Invalid custom attribute constructor signature
return arguments ;
}
for ( int i = 0 ; i < parameterCount ; i + + )
{
var signatureTypeCode = signatureReader . ReadSignatureTypeCode ( ) ;
if ( signatureTypeCode = = SignatureTypeCode . String )
{
// Custom attribute constructor must take only strings
arguments . Add ( valueReader . ReadSerializedString ( ) ) ;
}
}
return arguments ;
}
}
}