C#: Extract function pointer types from CIL

This commit is contained in:
Tamas Vajk
2020-12-16 14:12:25 +01:00
parent 5fa0dd719c
commit 0c213d0926
13 changed files with 228 additions and 12 deletions

View File

@@ -8,6 +8,7 @@ namespace Semmle.Extraction.CIL.Entities
ValueOrRefType,
TypeParameter,
Array,
Pointer
Pointer,
FunctionPointer
}
}

View File

@@ -0,0 +1,116 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Reflection.Metadata;
namespace Semmle.Extraction.CIL.Entities
{
internal sealed class FunctionPointerType : Type, IParameterizable, ICustomModifierReceiver
{
private readonly MethodSignature<Type> signature;
public FunctionPointerType(Context cx, MethodSignature<Type> signature) : base(cx)
{
this.signature = signature;
}
public override CilTypeKind Kind => CilTypeKind.FunctionPointer;
public override string Name
{
get
{
using var id = new StringWriter();
WriteName(
id.Write,
t => id.Write(t.Name),
signature
);
return id.ToString();
}
}
public override Namespace? ContainingNamespace => Cx.GlobalNamespace;
public override Type? ContainingType => null;
public override int ThisTypeParameterCount => throw new System.NotImplementedException();
public override IEnumerable<Type> TypeParameters => throw new System.NotImplementedException();
public override Type Construct(IEnumerable<Type> typeArguments) => throw new System.NotImplementedException();
public override void WriteAssemblyPrefix(TextWriter trapFile) { }
public override void WriteId(TextWriter trapFile, bool inContext)
{
WriteName(
trapFile.Write,
t => t.WriteId(trapFile, inContext),
signature
);
}
internal static void WriteName<TType>(Action<string> write, Action<TType> writeType, MethodSignature<TType> signature)
{
write("delegate* ");
write(GetCallingConvention(signature.Header.CallingConvention));
write("<");
foreach (var pt in signature.ParameterTypes)
{
writeType(pt);
write(",");
}
writeType(signature.ReturnType);
write(">");
}
internal static string GetCallingConvention(SignatureCallingConvention callingConvention)
{
if (callingConvention == SignatureCallingConvention.Default)
{
return "managed";
}
if (callingConvention == SignatureCallingConvention.Unmanaged)
{
return "unmanaged";
}
return $"unmanaged[{callingConvention}]";
}
public override IEnumerable<IExtractionProduct> Contents
{
get
{
foreach (var c in base.Contents)
{
yield return c;
}
var retType = signature.ReturnType;
if (retType is ModifiedType mt)
{
retType = mt.Unmodified;
yield return Tuples.cil_custom_modifiers(this, mt.Modifier, mt.IsRequired);
}
yield return Tuples.cil_function_pointer_return_type(this, retType);
yield return Tuples.cil_function_pointer_calling_conventions(this, signature.Header.CallingConvention);
var i = 0;
foreach (var p in signature.ParameterTypes)
{
var t = p;
if (t is ModifiedType mtparam)
{
t = mtparam.Unmodified;
yield return Tuples.cil_custom_modifiers(this, mtparam.Modifier, mtparam.IsRequired);
}
yield return Cx.Populate(new Parameter(Cx, this, i++, t));
}
}
}
}
}

View File

@@ -0,0 +1,7 @@
namespace Semmle.Extraction.CIL.Entities
{
internal interface IParameterizable : IEntity
{
}
}

View File

@@ -9,7 +9,7 @@ namespace Semmle.Extraction.CIL.Entities
/// <summary>
/// A method entity.
/// </summary>
internal abstract class Method : TypeContainer, IMember, ICustomModifierReceiver
internal abstract class Method : TypeContainer, IMember, ICustomModifierReceiver, IParameterizable
{
protected MethodTypeParameter[]? genericParams;
protected GenericContext gc;

View File

@@ -37,6 +37,13 @@ namespace Semmle.Extraction.CIL.Entities
public override void WriteAssemblyPrefix(TextWriter trapFile) => throw new NotImplementedException();
public override void WriteId(TextWriter trapFile, bool inContext) => throw new NotImplementedException();
public override void WriteId(TextWriter trapFile, bool inContext)
{
Unmodified.WriteId(trapFile, inContext);
trapFile.Write(IsRequired ? " modreq" : " modopt");
trapFile.Write("(");
Modifier.WriteId(trapFile, inContext);
trapFile.Write(")");
}
}
}

View File

@@ -8,11 +8,11 @@ namespace Semmle.Extraction.CIL.Entities
/// </summary>
internal sealed class Parameter : LabelledEntity
{
private readonly Method method;
private readonly IParameterizable method;
private readonly int index;
private readonly Type type;
public Parameter(Context cx, Method m, int i, Type t) : base(cx)
public Parameter(Context cx, IParameterizable m, int i, Type t) : base(cx)
{
method = m;
index = i;

View File

@@ -48,10 +48,20 @@ namespace Semmle.Extraction.CIL.Entities
private struct FnPtr : ITypeSignature
{
private readonly MethodSignature<ITypeSignature> signature;
public FnPtr(MethodSignature<ITypeSignature> signature)
{
this.signature = signature;
}
public void WriteId(TextWriter trapFile, GenericContext gc)
{
trapFile.Write("<method signature>");
FunctionPointerType.WriteName(
trapFile.Write,
t => t.WriteId(trapFile, gc),
signature
);
}
}
@@ -62,7 +72,7 @@ namespace Semmle.Extraction.CIL.Entities
new ByRef(elementType);
ITypeSignature ISignatureTypeProvider<ITypeSignature, object>.GetFunctionPointerType(MethodSignature<ITypeSignature> signature) =>
new FnPtr();
new FnPtr(signature);
private class Instantiation : ITypeSignature
{

View File

@@ -23,7 +23,7 @@ namespace Semmle.Extraction.CIL.Entities
elementType; // ??
Type ISignatureTypeProvider<Type, GenericContext>.GetFunctionPointerType(MethodSignature<Type> signature) =>
cx.ErrorType; // Don't know what to do !!
cx.Populate(new FunctionPointerType(cx, signature));
Type IConstructedTypeProvider<Type>.GetGenericInstantiation(Type genericType, ImmutableArray<Type> typeArguments) =>
genericType.Construct(typeArguments);

View File

@@ -86,6 +86,12 @@ namespace Semmle.Extraction.CIL
internal static Tuple cil_method(Method method, string name, Type declType, Type returnType) =>
new Tuple("cil_method", method, name, declType, returnType);
internal static Tuple cil_function_pointer_return_type(FunctionPointerType fnptr, Type returnType) =>
new Tuple("cil_function_pointer_return_type", fnptr, returnType);
internal static Tuple cil_function_pointer_calling_conventions(FunctionPointerType fnptr, System.Reflection.Metadata.SignatureCallingConvention callingConvention) =>
new Tuple("cil_function_pointer_calling_conventions", fnptr, (int)callingConvention);
internal static Tuple cil_method_implementation(MethodImplementation impl, Method method, Assembly assembly) =>
new Tuple("cil_method_implementation", impl, method, assembly);
@@ -101,7 +107,7 @@ namespace Semmle.Extraction.CIL
internal static Tuple cil_newslot(Method method) =>
new Tuple("cil_newslot", method);
internal static Tuple cil_parameter(Parameter p, Method m, int i, Type t) =>
internal static Tuple cil_parameter(Parameter p, IParameterizable m, int i, Type t) =>
new Tuple("cil_parameter", p, m, i, t);
internal static Tuple cil_parameter_in(Parameter p) =>