@@ -74,6 +74,12 @@ public IDebugInfoProvider DebugInfo {
7474
7575 public bool ExpandMemberDefinitions { get ; set ; }
7676
77+ /// <summary>
78+ /// Gets or sets whether custom attribute blobs should be decoded or dumped as raw bytes. Default is <see langword="false"/>.
79+ /// Setting this value to <see langword="true"/> (roughly) corresponds to the <c>/CAVERBAL</c> switch of <c>ildasm</c>.
80+ /// </summary>
81+ public bool DecodeCustomAttributeBlobs { get ; set ; }
82+
7783 public IAssemblyResolver AssemblyResolver { get ; set ; }
7884
7985 public IEntityProcessor EntityProcessor { get ; set ; }
@@ -476,7 +482,7 @@ void WriteSecurityDeclarations(MetadataFile module, DeclarativeSecurityAttribute
476482 }
477483 }
478484
479- class SecurityDeclarationDecoder : ICustomAttributeTypeProvider < ( PrimitiveTypeCode , string ) >
485+ class SecurityDeclarationDecoder : ICustomAttributeTypeProvider < ( PrimitiveTypeCode Code , string Name ) >
480486 {
481487 readonly ITextOutput output ;
482488 readonly IAssemblyResolver resolver ;
@@ -506,12 +512,54 @@ public SecurityDeclarationDecoder(ITextOutput output, IAssemblyResolver resolver
506512
507513 public ( PrimitiveTypeCode , string ) GetTypeFromDefinition ( MetadataReader reader , TypeDefinitionHandle handle , byte rawTypeKind )
508514 {
509- throw new NotImplementedException ( ) ;
515+ string fullTypeName = handle . GetFullTypeName ( reader ) . FullName ;
516+ if ( handle . IsEnum ( reader , out var typeCode ) )
517+ return ( typeCode , "enum " + fullTypeName ) ;
518+ return ( 0 , fullTypeName ) ;
510519 }
511520
512521 public ( PrimitiveTypeCode , string ) GetTypeFromReference ( MetadataReader reader , TypeReferenceHandle handle , byte rawTypeKind )
513522 {
514- throw new NotImplementedException ( ) ;
523+ string fullTypeName = handle . GetFullTypeName ( reader ) . FullName ;
524+ var containingModule = GetDeclaringModule ( handle ) ;
525+
526+ string assemblyQualifiedTypeName = containingModule != null
527+ ? fullTypeName + ", " + containingModule
528+ : fullTypeName ;
529+
530+ PrimitiveTypeCode typeCode = 0 ;
531+ var ( targetModule , resolvedType ) = ResolveType ( assemblyQualifiedTypeName , module ) ;
532+ if ( targetModule != null )
533+ {
534+ if ( ! resolvedType . IsEnum ( targetModule . Metadata , out typeCode ) )
535+ {
536+ typeCode = 0 ;
537+ }
538+ else
539+ {
540+ assemblyQualifiedTypeName = "enum " + assemblyQualifiedTypeName ;
541+ }
542+ }
543+
544+ return ( typeCode , assemblyQualifiedTypeName ) ;
545+
546+ string GetDeclaringModule ( TypeReferenceHandle handle )
547+ {
548+ var tr = reader . GetTypeReference ( handle ) ;
549+ switch ( tr . ResolutionScope . Kind )
550+ {
551+ case HandleKind . TypeReference :
552+ return GetDeclaringModule ( ( TypeReferenceHandle ) tr . ResolutionScope ) ;
553+ case HandleKind . AssemblyReference :
554+ var asmRef = reader . GetAssemblyReference ( ( AssemblyReferenceHandle ) tr . ResolutionScope ) ;
555+ return asmRef . TryGetFullAssemblyName ( reader , out var assemblyName ) ? assemblyName : null ;
556+ case HandleKind . ModuleReference :
557+ var modRef = reader . GetModuleReference ( ( ModuleReferenceHandle ) tr . ResolutionScope ) ;
558+ return reader . GetString ( modRef . Name ) ;
559+ default :
560+ return null ;
561+ }
562+ }
515563 }
516564
517565 public ( PrimitiveTypeCode , string ) GetTypeFromSerializedName ( string name )
@@ -608,17 +656,6 @@ TypeDefinitionHandle FindType(MetadataFile currentModule, string[] name)
608656 }
609657 }
610658
611- PrimitiveTypeCode ResolveEnumUnderlyingType ( string typeName , PEFile module )
612- {
613- if ( typeName . StartsWith ( "enum " , StringComparison . Ordinal ) )
614- typeName = typeName . Substring ( 5 ) ;
615- var ( containingModule , typeDefHandle ) = ResolveType ( typeName , module ) ;
616-
617- if ( typeDefHandle . IsNil || ! typeDefHandle . IsEnum ( containingModule . Metadata , out var typeCode ) )
618- throw new EnumUnderlyingTypeResolveException ( ) ;
619- return typeCode ;
620- }
621-
622659 MetadataFile mscorlib ;
623660
624661 bool TryResolveMscorlib ( out MetadataFile mscorlib )
@@ -704,7 +741,7 @@ void TryDecodeSecurityDeclaration(TextOutputWithRollback output, BlobReader blob
704741 }
705742
706743 output . Write ( argument . Type . Name ?? PrimitiveTypeCodeToString ( argument . Type . Code ) ) ;
707- output . Write ( " " + argument . Name + " = " ) ;
744+ output . Write ( " " + DisassemblerHelpers . Escape ( argument . Name ) + " = " ) ;
708745
709746 WriteValue ( output , argument . Type , argument . Value ) ;
710747 output . WriteLine ( ) ;
@@ -1824,12 +1861,62 @@ void WriteAttributes(MetadataFile module, CustomAttributeHandleCollection attrib
18241861 if ( ! attr . Value . IsNil )
18251862 {
18261863 output . Write ( " = " ) ;
1827- WriteBlob ( attr . Value , metadata ) ;
1864+ if ( DecodeCustomAttributeBlobs )
1865+ WriteDecodedCustomAttributeBlob ( attr , module ) ;
1866+ else
1867+ WriteBlob ( attr . Value , metadata ) ;
18281868 }
18291869 output . WriteLine ( ) ;
18301870 }
18311871 }
18321872
1873+ void WriteDecodedCustomAttributeBlob ( CustomAttribute attr , MetadataFile module )
1874+ {
1875+ CustomAttributeValue < ( PrimitiveTypeCode Code , string Name ) > value ;
1876+ try
1877+ {
1878+ var provider = new SecurityDeclarationDecoder ( output , AssemblyResolver , module ) ;
1879+ value = attr . DecodeValue ( provider ) ;
1880+ }
1881+ catch ( BadImageFormatException )
1882+ {
1883+ output . Write ( "/* Could not decode attribute value */ " ) ;
1884+ WriteBlob ( attr . Value , module . Metadata ) ;
1885+ return ;
1886+ }
1887+
1888+ output . Write ( "{" ) ;
1889+ output . Indent ( ) ;
1890+
1891+ foreach ( var arg in value . FixedArguments )
1892+ {
1893+ output . WriteLine ( ) ;
1894+ WriteValue ( output , arg . Type , arg . Value ) ;
1895+ }
1896+
1897+ foreach ( var arg in value . NamedArguments )
1898+ {
1899+ output . WriteLine ( ) ;
1900+ switch ( arg . Kind )
1901+ {
1902+ case CustomAttributeNamedArgumentKind . Field :
1903+ output . Write ( "field " ) ;
1904+ break ;
1905+ case CustomAttributeNamedArgumentKind . Property :
1906+ output . Write ( "property " ) ;
1907+ break ;
1908+ }
1909+
1910+ output . Write ( arg . Type . Name ?? PrimitiveTypeCodeToString ( arg . Type . Code ) ) ;
1911+ output . Write ( " " + DisassemblerHelpers . Escape ( arg . Name ) + " = " ) ;
1912+ WriteValue ( output , arg . Type , arg . Value ) ;
1913+ }
1914+
1915+ output . WriteLine ( ) ;
1916+ output . Unindent ( ) ;
1917+ output . Write ( "}" ) ;
1918+ }
1919+
18331920 void WriteBlob ( BlobHandle blob , MetadataReader metadata )
18341921 {
18351922 var reader = metadata . GetBlobReader ( blob ) ;
@@ -1839,23 +1926,26 @@ void WriteBlob(BlobHandle blob, MetadataReader metadata)
18391926 void WriteBlob ( BlobReader reader )
18401927 {
18411928 output . Write ( "(" ) ;
1842- output . Indent ( ) ;
1843-
1844- for ( int i = 0 ; i < reader . Length ; i ++ )
1929+ if ( reader . Length > 0 )
18451930 {
1846- if ( i % 16 == 0 && i < reader . Length - 1 )
1847- {
1848- output . WriteLine ( ) ;
1849- }
1850- else
1931+ output . Indent ( ) ;
1932+
1933+ for ( int i = 0 ; i < reader . Length ; i ++ )
18511934 {
1852- output . Write ( ' ' ) ;
1935+ if ( i % 16 == 0 && i < reader . Length - 1 )
1936+ {
1937+ output . WriteLine ( ) ;
1938+ }
1939+ else
1940+ {
1941+ output . Write ( ' ' ) ;
1942+ }
1943+ output . Write ( reader . ReadByte ( ) . ToString ( "x2" ) ) ;
18531944 }
1854- output . Write ( reader . ReadByte ( ) . ToString ( "x2" ) ) ;
1855- }
18561945
1857- output . WriteLine ( ) ;
1858- output . Unindent ( ) ;
1946+ output . WriteLine ( ) ;
1947+ output . Unindent ( ) ;
1948+ }
18591949 output . Write ( ")" ) ;
18601950 }
18611951
0 commit comments