private static string GetMethodSignature(MethodInfo method, InterceptMethodAttribute attribute) { var returnType = method.ReturnType; var parameters = method.GetParameters().Select(p => p.ParameterType).ToArray(); var requiredParameterTypes = new[] { typeof(int), typeof(int), typeof(long) }; var lastParameterTypes = parameters.Skip(parameters.Length - requiredParameterTypes.Length); if (attribute.MethodReplacementAction == MethodReplacementActionType.ReplaceTargetMethod) { if (!lastParameterTypes.SequenceEqual(requiredParameterTypes)) { throw new Exception( $"Method {method.DeclaringType.FullName}.{method.Name}() does not meet parameter requirements. " + "Wrapper methods must have at least 3 parameters and the last 3 must be of types Int32 (opCode), Int32 (mdToken), and Int64 (moduleVersionPtr)."); } } else if (attribute.MethodReplacementAction == MethodReplacementActionType.InsertFirst) { if (attribute.CallerAssembly == null || attribute.CallerType == null || attribute.CallerMethod == null) { throw new Exception( $"Method {method.DeclaringType.FullName}.{method.Name}() does not meet InterceptMethodAttribute requirements. " + "Currently, InsertFirst methods must have CallerAssembly, CallerType, and CallerMethod defined. " + $"Current values: CallerAssembly=\"{attribute.CallerAssembly}\", CallerType=\"{attribute.CallerType}\", CallerMethod=\"{attribute.CallerMethod}\""); } else if (parameters.Any()) { throw new Exception( $"Method {method.DeclaringType.FullName}.{method.Name}() does not meet parameter requirements. " + "Currently, InsertFirst methods must have zero parameters."); } else if (returnType != typeof(void)) { throw new Exception( $"Method {method.DeclaringType.FullName}.{method.Name}() does not meet return type requirements. " + "Currently, InsertFirst methods must have a void return type."); } } var signatureHelper = SignatureHelper.GetMethodSigHelper(method.CallingConvention, returnType); signatureHelper.AddArguments(parameters, requiredCustomModifiers: null, optionalCustomModifiers: null); var signatureBytes = signatureHelper.GetSignature(); if (method.IsGenericMethod) { // if method is generic, fix first byte (calling convention) // and insert a second byte with generic parameter count const byte IMAGE_CEE_CS_CALLCONV_GENERIC = 0x10; var genericArguments = method.GetGenericArguments(); var newSignatureBytes = new byte[signatureBytes.Length + 1]; newSignatureBytes[0] = (byte)(signatureBytes[0] | IMAGE_CEE_CS_CALLCONV_GENERIC); newSignatureBytes[1] = (byte)genericArguments.Length; Array.Copy(signatureBytes, 1, newSignatureBytes, 2, signatureBytes.Length - 1); signatureBytes = newSignatureBytes; } return(string.Join(" ", signatureBytes.Select(b => b.ToString("X2")))); }
public void AllMethodsHaveProperlyFormedTargetSignatureTypes(MethodInfo wrapperMethod, InterceptMethodAttribute attribute) { Assert.True( attribute.TargetSignatureTypes != null, $"{wrapperMethod.DeclaringType.Name}.{wrapperMethod.Name}: {nameof(attribute.TargetSignatureTypes)} definition missing."); // add 1 for return type, subtract 3 for extra parameters (opcode, mdToken, moduleVersionPtr) // 1 - 3 = -2 var expectedParameterCount = wrapperMethod.GetParameters().Length - 2; if (!StaticInstrumentations.Contains(wrapperMethod)) { // Subtract the instance (this) parameter expectedParameterCount--; } var typeSigLength = attribute.TargetSignatureTypes.Length; Assert.True( expectedParameterCount == typeSigLength, $"{wrapperMethod.DeclaringType.Name}.{wrapperMethod.Name}: {nameof(attribute.TargetSignatureTypes)} has {typeSigLength} items, expected {expectedParameterCount}."); Assert.False( attribute.TargetSignatureTypes.Any(string.IsNullOrWhiteSpace), $"{wrapperMethod.DeclaringType.Name}.{wrapperMethod.Name}: {nameof(attribute.TargetSignatureTypes)} has null or empty arguments."); }