public override void VisitCallInstruction(CallInstruction ci) { base.VisitCallInstruction(ci); var pc = ci.Callee as ProcedureConstant; if (pc != null && ProcedureTerminates(pc.Procedure)) { flow[curBlock].TerminatesProcess = true; } }
/// <summary> /// Rewrites CALL instructions to function applications. /// </summary> /// <remarks> /// Converts an opcode: /// <code> /// call procExpr /// </code> /// to one of: /// <code> /// ax = procExpr(bindings); /// procEexpr(bindings); /// </code> /// </remarks> /// <param name="proc">Procedure in which the CALL instruction exists</param> /// <param name="stm">The particular statement of the call instruction</param> /// <param name="call">The actuall CALL instruction.</param> /// <returns>True if the conversion was possible, false if the procedure didn't have /// a signature yet.</returns> public bool RewriteCall(Procedure proc, Statement stm, CallInstruction call) { var callee = call.Callee as ProcedureConstant; if (callee == null) return false; //$REVIEW: what happens with indirect calls? var procCallee = callee.Procedure; var sigCallee = GetProcedureSignature(procCallee); var fn = new ProcedureConstant(Program.Platform.PointerType, procCallee); if (sigCallee == null || !sigCallee.ParametersValid) return false; var ab = new ApplicationBuilder(Program.Architecture, proc.Frame, call.CallSite, fn, sigCallee, true); stm.Instruction = ab.CreateInstruction(); return true; }
private void RewriteCall(Statement stm, CallInstruction call) { var e = expander.Expand(call.Callee); var pt = e.Accept(asc) as Pointer; if (pt == null) return; var ft = pt.Pointee as FunctionType; if (ft == null) return; var returnId = ft.ReturnValue.DataType is VoidType ? null : ft.ReturnValue; var sigCallee = new FunctionType(returnId, ft.Parameters); var ab = new ApplicationBuilder( program.Architecture, proc.Frame, call.CallSite, call.Callee, sigCallee, true); stm.Instruction = ab.CreateInstruction(); ssaIdTransformer.Transform(stm, call); }
private void AddUseInstructions(CallInstruction ci) { var existing = ci.Uses.Select(u => u.Expression).ToHashSet(); ci.Uses.UnionWith(rename.Values .Where(id => !existing.Contains(id)) .Select(id => new UseInstruction(id))); }
public override Instruction TransformCallInstruction(CallInstruction ci) { ci.Callee = ci.Callee.Accept(this); ProcedureConstant pc; if (ci.Callee.As(out pc)) { var procCallee = pc.Procedure as Procedure; ProcedureFlow2 procFlow; if (procCallee != null && programFlow.ProcedureFlows2.TryGetValue(procCallee, out procFlow)) { AddUseInstructions(ci); AddDefInstructions(ci, procFlow); } return ci; } // Hell node implementation - use all register variables. foreach (Identifier id in proc.Frame.Identifiers) { if (id.Storage is RegisterStorage || id.Storage is FlagGroupStorage) { NewUse(id, stmCur); } } return ci; }
public override void VisitCallInstruction(CallInstruction ci) { FunctionType sig = GetProcedureSignature(ci.Callee); if (sig != null && sig.ParametersValid) { var procCallee = ((ProcedureConstant)ci.Callee).Procedure; var ab = new ApplicationBuilder( program.Architecture, Procedure.Frame, ci.CallSite, new ProcedureConstant(program.Platform.PointerType, procCallee), sig, false); if (!sig.HasVoidReturn) { varLive.Def(ab.Bind(sig.ReturnValue)); } foreach (Identifier arg in sig.Parameters) { if (arg.Storage is OutArgumentStorage) { varLive.Def(ab.Bind(arg)); } } foreach (Identifier arg in sig.Parameters) { if (!(arg.Storage is OutArgumentStorage)) { varLive.Use(ab.Bind(arg)); } } } else { var pc = ci.Callee as ProcedureConstant; if (pc == null) { return; } var procCallee = pc.Procedure as Procedure; if (procCallee == null) { return; } if (state.PropagateThroughExitNodes) { PropagateToCalleeExitBlocks(stmCur); } // Update trash information. ProcedureFlow pi = mpprocData[procCallee]; ProcedureFlow item = mpprocData[Procedure]; // The registers that are still live before a call are those // that were live after the call and were bypassed by the called function // or used by the called function. var ids = new HashSet <RegisterStorage>(pi.TrashedRegisters); ids.ExceptWith(pi.ByPass); varLive.Identifiers.ExceptWith(ids); varLive.Identifiers.UnionWith(pi.MayUse); // varLive.BitSet = pi.MayUse | ((pi.ByPass | ~pi.TrashedRegisters) & varLive.BitSet); varLive.Grf = pi.grfMayUse | ((pi.grfByPass | ~pi.grfTrashed) & varLive.Grf); // Any stack parameters are also considered live. MarkLiveStackParameters(ci); } }
public override void VisitCallInstruction(CallInstruction ci) { isCritical = true; }
TranslatedExpression HandleDelegateConstruction(CallInstruction inst) { ILInstruction func = inst.Arguments[1]; IMethod method; switch (func.OpCode) { case OpCode.LdFtn: method = ((LdFtn)func).Method; break; case OpCode.LdVirtFtn: method = ((LdVirtFtn)func).Method; break; case OpCode.ILFunction: method = ((ILFunction)func).Method; return(expressionBuilder.TranslateFunction(inst.Method.DeclaringType, (ILFunction)func)); default: throw new ArgumentException($"Unknown instruction type: {func.OpCode}"); } var invokeMethod = inst.Method.DeclaringType.GetDelegateInvokeMethod(); TranslatedExpression target; IType targetType; if (method.IsExtensionMethod && invokeMethod != null && method.Parameters.Count - 1 == invokeMethod.Parameters.Count) { target = expressionBuilder.Translate(inst.Arguments[0]); targetType = method.Parameters[0].Type; } else { target = expressionBuilder.TranslateTarget(method, inst.Arguments[0], func.OpCode == OpCode.LdFtn); targetType = method.DeclaringType; } var lookup = new MemberLookup(resolver.CurrentTypeDefinition, resolver.CurrentTypeDefinition.ParentAssembly); var or = new OverloadResolution(resolver.Compilation, method.Parameters.SelectArray(p => new TypeResolveResult(p.Type))); var result = lookup.Lookup(target.ResolveResult, method.Name, method.TypeArguments, false); bool needsCast = true; if (result is MethodGroupResolveResult mgrr) { or.AddMethodLists(mgrr.MethodsGroupedByDeclaringType.ToArray()); needsCast = (or.BestCandidateErrors != OverloadResolutionErrors.None || !IsAppropriateCallTarget(method, or.BestCandidate, func.OpCode == OpCode.LdVirtFtn)); } if (needsCast) { target = target.ConvertTo(targetType, expressionBuilder); result = lookup.Lookup(target.ResolveResult, method.Name, method.TypeArguments, false); } var mre = new MemberReferenceExpression(target, method.Name); mre.TypeArguments.AddRange(method.TypeArguments.Select(expressionBuilder.ConvertType)); mre.WithRR(result); var oce = new ObjectCreateExpression(expressionBuilder.ConvertType(inst.Method.DeclaringType), mre) .WithILInstruction(inst) .WithRR(new ConversionResolveResult( inst.Method.DeclaringType, new MemberResolveResult(target.ResolveResult, method), Conversion.MethodGroupConversion(method, func.OpCode == OpCode.LdVirtFtn, false))); return(oce); }
public Statement Call(string procedureName, int retSizeOnStack) { var ci = new CallInstruction(Constant.Invalid, new CallSite(retSizeOnStack, 0)); unresolvedProcedures.Add(new ProcedureConstantUpdater(procedureName, ci)); return Emit(ci); }
public void Transform(Statement stm, CallInstruction call) { this.stm = stm; this.call = call; ssa.ReplaceDefinitions(stm, null); ssa.RemoveUses(stm); Transform(stm.Instruction); }
public abstract void VisitCallInstruction(CallInstruction instruction);
void InstructionVisitor.VisitCallInstruction(CallInstruction ci) { stms.Add(new AbsynSideEffect(new Application(ci.Callee, VoidType.Instance))); }
void InstructionVisitor.VisitCallInstruction(CallInstruction ci) { throw new NotImplementedException(); }
public bool VisitCall(RtlCall call) { if ((call.Class & RtlClass.Delay) != 0) { // Get delay slot instruction cluster. rtlStream.MoveNext(); ProcessRtlCluster(rtlStream.Current); } var site = OnBeforeCall(stackReg, call.ReturnAddressSize); FunctionType sig; ProcedureCharacteristics chr = null; Address addr = call.Target as Address; if (addr != null) { if (!program.SegmentMap.IsValidAddress(addr)) { scanner.Warn(ric.Address, "Call target address {0} is invalid.", addr); sig = new FunctionType(); EmitCall( CreateProcedureConstant( new ExternalProcedure(Procedure.GenerateName(addr), sig)), sig, chr, site); return(OnAfterCall(sig, chr)); } var impProc = scanner.GetImportedProcedure(addr, this.ric.Address); if (impProc != null && impProc.Characteristics.IsAlloca) { return(ProcessAlloca(site, impProc)); } var callee = scanner.ScanProcedure(addr, null, state); var pcCallee = CreateProcedureConstant(callee); sig = callee.Signature; chr = callee.Characteristics; EmitCall(pcCallee, sig, chr, site); var pCallee = callee as Procedure; if (pCallee != null) { program.CallGraph.AddEdge(blockCur.Statements.Last, pCallee); } return(OnAfterCall(sig, chr)); } var procCallee = call.Target as ProcedureConstant; if (procCallee != null) { sig = procCallee.Procedure.Signature; chr = procCallee.Procedure.Characteristics; EmitCall(procCallee, sig, chr, site); return(OnAfterCall(sig, chr)); } sig = scanner.GetCallSignatureAtAddress(ric.Address); if (sig != null) { EmitCall(call.Target, sig, chr, site); return(OnAfterCall(sig, chr)); //$TODO: make characteristics available } Identifier id; if (call.Target.As <Identifier>(out id)) { var ppp = SearchBackForProcedureConstant(id); if (ppp != null) { var e = CreateProcedureConstant(ppp); sig = ppp.Signature; chr = ppp.Characteristics; EmitCall(e, sig, chr, site); return(OnAfterCall(sig, chr)); } } var imp = ImportedProcedureName(call.Target); if (imp != null) { sig = imp.Signature; chr = imp.Characteristics; EmitCall(CreateProcedureConstant(imp), sig, chr, site); //Emit(BuildApplication(CreateProcedureConstant(imp), sig, site)); return(OnAfterCall(sig, chr)); } var syscall = program.Platform.FindService(call, state); if (syscall != null) { return(!EmitSystemServiceCall(syscall)); } ProcessIndirectControlTransfer(ric.Address, call); var ic = new CallInstruction(call.Target, site); Emit(ic); sig = GuessProcedureSignature(ic); return(OnAfterCall(sig, chr)); }
void Run(CallInstruction inst, ILTransformContext context) { if (inst.Method.IsStatic) { return; } if (inst.Method.MetadataToken.IsNil || inst.Method.MetadataToken.Kind != HandleKind.MethodDefinition) { return; } var handle = (MethodDefinitionHandle)inst.Method.MetadataToken; if (!IsDefinedInCurrentOrOuterClass(inst.Method, context.Function.Method.DeclaringTypeDefinition)) { return; } if (!inst.Method.IsCompilerGeneratedOrIsInCompilerGeneratedClass()) { return; } var metadata = context.PEFile.Metadata; MethodDefinition methodDef = metadata.GetMethodDefinition((MethodDefinitionHandle)inst.Method.MetadataToken); if (!methodDef.HasBody()) { return; } // Use the callee's generic context var genericContext = new GenericContext(inst.Method); // partially copied from CSharpDecompiler var ilReader = context.CreateILReader(); var body = context.PEFile.Reader.GetMethodBody(methodDef.RelativeVirtualAddress); var proxyFunction = ilReader.ReadIL(handle, body, genericContext, ILFunctionKind.TopLevelFunction, context.CancellationToken); var transformContext = new ILTransformContext(context, proxyFunction); proxyFunction.RunTransforms(CSharp.CSharpDecompiler.EarlyILTransforms(), transformContext); if (!(proxyFunction.Body is BlockContainer blockContainer)) { return; } if (blockContainer.Blocks.Count != 1) { return; } var block = blockContainer.Blocks[0]; Call call; ILInstruction returnValue; switch (block.Instructions.Count) { case 1: // leave IL_0000 (call Test(ldloc this, ldloc A_1)) if (!block.Instructions[0].MatchLeave(blockContainer, out returnValue)) { return; } call = returnValue as Call; break; case 2: // call Test(ldloc this, ldloc A_1) // leave IL_0000(nop) call = block.Instructions[0] as Call; if (!block.Instructions[1].MatchLeave(blockContainer, out returnValue)) { return; } if (!returnValue.MatchNop()) { return; } break; default: return; } if (call == null || call.Method.IsConstructor) { return; } if (call.Method.IsStatic || call.Method.Parameters.Count != inst.Method.Parameters.Count) { return; } // check if original arguments are only correct ldloc calls for (int i = 0; i < call.Arguments.Count; i++) { var originalArg = call.Arguments[i]; if (!originalArg.MatchLdLoc(out ILVariable var) || var.Kind != VariableKind.Parameter || var.Index != i - 1) { return; } } context.Step("Replace proxy: " + inst.Method.Name + " with " + call.Method.Name, inst); // Apply the wrapper call's substitution to the actual method call. Call newInst = new Call(call.Method.Specialize(inst.Method.Substitution)); // copy flags newInst.ConstrainedTo = call.ConstrainedTo; newInst.ILStackWasEmpty = inst.ILStackWasEmpty; newInst.IsTail = call.IsTail & inst.IsTail; // copy IL ranges newInst.AddILRange(inst); newInst.Arguments.ReplaceList(inst.Arguments); inst.ReplaceWith(newInst); }
public void VisitCallInstruction(CallInstruction call) { call.Callee.Accept(asc); desc.MeetDataType( call.Callee, new Pointer( new CodeType(), program.Platform.PointerType.Size)); call.Callee.Accept(desc, call.Callee.TypeVariable); }
private Func <CallSite, TSelfType, CodeContext, object> MakeGetMemberTarget <TSelfType>(string name, object target) { Type type = CompilerHelpers.GetType(target); // needed for GetMember call until DynamicAction goes away if (typeof(TypeTracker).IsAssignableFrom(type)) { // no fast path for TypeTrackers PerfTrack.NoteEvent(PerfTrack.Categories.BindingSlow, "GetNoFast TypeTracker"); return(null); } MemberGroup members = Context.Binder.GetMember(MemberRequestKind.Get, type, name); if (members.Count == 0 && type.IsInterface) { // all interfaces have object members type = typeof(object); members = Context.Binder.GetMember(MemberRequestKind.Get, type, name); } if (members.Count == 0 && typeof(IStrongBox).IsAssignableFrom(type)) { // no fast path for strong box access PerfTrack.NoteEvent(PerfTrack.Categories.BindingSlow, "GetNoFast StrongBox"); return(null); } MethodInfo getMem = Context.Binder.GetMethod(type, "GetCustomMember"); if (getMem != null && getMem.IsSpecialName) { // no fast path for custom member access PerfTrack.NoteEvent(PerfTrack.Categories.BindingSlow, "GetNoFast GetCustomMember " + type); return(null); } Expression error; TrackerTypes memberType = Context.Binder.GetMemberType(members, out error); if (error == null) { PythonType argType = DynamicHelpers.GetPythonTypeFromType(type); bool isHidden = argType.IsHiddenMember(name); if (isHidden) { PerfTrack.NoteEvent(PerfTrack.Categories.BindingSlow, "GetNoFast FilteredMember " + memberType); return(null); } switch (memberType) { case TrackerTypes.TypeGroup: case TrackerTypes.Type: object typeObj; if (members.Count == 1) { typeObj = DynamicHelpers.GetPythonTypeFromType(((TypeTracker)members[0]).Type); } else { TypeTracker typeTracker = (TypeTracker)members[0]; for (int i = 1; i < members.Count; i++) { typeTracker = TypeGroup.UpdateTypeEntity(typeTracker, (TypeTracker)members[i]); } typeObj = typeTracker; } return(new FastTypeGet <TSelfType>(type, typeObj).GetTypeObject); case TrackerTypes.Method: PythonTypeSlot slot = PythonTypeOps.GetSlot(members, name, _context.DomainManager.Configuration.PrivateBinding); if (slot is BuiltinMethodDescriptor) { return(new FastMethodGet <TSelfType>(type, (BuiltinMethodDescriptor)slot).GetMethod); } else if (slot is BuiltinFunction) { return(new FastSlotGet <TSelfType>(type, slot, DynamicHelpers.GetPythonTypeFromType(type)).GetRetSlot); } return(new FastSlotGet <TSelfType>(type, slot, DynamicHelpers.GetPythonTypeFromType(type)).GetBindSlot); case TrackerTypes.Event: if (members.Count == 1 && !((EventTracker)members[0]).IsStatic) { slot = PythonTypeOps.GetSlot(members, name, _context.DomainManager.Configuration.PrivateBinding); return(new FastSlotGet <TSelfType>(type, slot, DynamicHelpers.GetPythonTypeFromType(((EventTracker)members[0]).DeclaringType)).GetBindSlot); } PerfTrack.NoteEvent(PerfTrack.Categories.BindingSlow, "GetNoFast Event " + members.Count + " " + ((EventTracker)members[0]).IsStatic); return(null); case TrackerTypes.Property: if (members.Count == 1) { PropertyTracker pt = (PropertyTracker)members[0]; if (!pt.IsStatic && pt.GetIndexParameters().Length == 0) { MethodInfo prop = pt.GetGetMethod(); ParameterInfo[] parameters; if (prop != null && (parameters = prop.GetParameters()).Length == 0) { if (prop.ReturnType == typeof(bool)) { return(new FastPropertyGet <TSelfType>(type, CallInstruction.Create(prop, parameters).Invoke).GetPropertyBool); } else if (prop.ReturnType == typeof(int)) { return(new FastPropertyGet <TSelfType>(type, CallInstruction.Create(prop, parameters).Invoke).GetPropertyInt); } else { return(new FastPropertyGet <TSelfType>(type, CallInstruction.Create(prop, parameters).Invoke).GetProperty); } } } } PerfTrack.NoteEvent(PerfTrack.Categories.BindingSlow, "GetNoFast Property " + members.Count + " " + ((PropertyTracker)members[0]).IsStatic); return(null); case TrackerTypes.All: getMem = Context.Binder.GetMethod(type, "GetBoundMember"); if (getMem != null && getMem.IsSpecialName) { PerfTrack.NoteEvent(PerfTrack.Categories.BindingSlow, "GetNoFast GetBoundMember " + type); return(null); } if (IsNoThrow) { return(new FastErrorGet <TSelfType>(type, name).GetErrorNoThrow); } else { return(new FastErrorGet <TSelfType>(type, name).GetError); } default: PerfTrack.NoteEvent(PerfTrack.Categories.BindingSlow, "GetNoFast " + memberType); return(null); } } else { StringBuilder sb = new StringBuilder(); foreach (MemberTracker mi in members) { if (sb.Length != 0) { sb.Append(", "); } sb.Append(mi.MemberType); sb.Append(" : "); sb.Append(mi.ToString()); } return(new FastErrorGet <TSelfType>(type, sb.ToString()).GetAmbiguous); } }
private Procedure GetUserProcedure(CallInstruction ci) { var pc = ci.Callee as ProcedureConstant; if (pc == null) return null; return pc.Procedure as Procedure; }
public void VisitCallInstruction(CallInstruction ci) { writer.Indent(); writer.WriteKeyword("call"); writer.Write(" "); ci.Callee.Accept(this); writer.Write(" ({0})", ci.CallSite); writer.Terminate(); if (ci.Uses.Count > 0) { writer.Indentation += writer.TabSize; writer.Indent(); writer.Write("uses: "); writer.Write(string.Join(",", ci.Uses.OrderBy(u => ((Identifier)(u.Expression)).Name).Select(u => u.Expression))); writer.Terminate(); writer.Indentation -= writer.TabSize; } if (ci.Definitions.Count > 0) { writer.Indentation += writer.TabSize; writer.Indent(); writer.Write("defs: "); writer.Write(string.Join(",", ci.Definitions.OrderBy(d => ((Identifier)d.Expression).Name).Select(d => d.Expression))); writer.Terminate(); writer.Indentation -= writer.TabSize; } }
static bool MatchingGetterAndSetterCalls(CallInstruction getterCall, CallInstruction setterCall, out Action <ILTransformContext> finalizeMatch) { finalizeMatch = null; if (getterCall == null || setterCall == null || !IsSameMember(getterCall.Method.AccessorOwner, setterCall.Method.AccessorOwner)) { return(false); } if (setterCall.OpCode != getterCall.OpCode) { return(false); } var owner = getterCall.Method.AccessorOwner as IProperty; if (owner == null || !IsSameMember(getterCall.Method, owner.Getter) || !IsSameMember(setterCall.Method, owner.Setter)) { return(false); } if (setterCall.Arguments.Count != getterCall.Arguments.Count + 1) { return(false); } // Ensure that same arguments are passed to getterCall and setterCall: for (int j = 0; j < getterCall.Arguments.Count; j++) { if (setterCall.Arguments[j].MatchStLoc(out var v) && v.IsSingleDefinition && v.LoadCount == 1) { if (getterCall.Arguments[j].MatchLdLoc(v)) { // OK, setter call argument is saved in temporary that is re-used for getter call if (finalizeMatch == null) { finalizeMatch = AdjustArguments; } continue; } } if (!SemanticHelper.IsPure(getterCall.Arguments[j].Flags)) { return(false); } if (!getterCall.Arguments[j].Match(setterCall.Arguments[j]).Success) { return(false); } } return(true); void AdjustArguments(ILTransformContext context) { Debug.Assert(setterCall.Arguments.Count == getterCall.Arguments.Count + 1); for (int j = 0; j < getterCall.Arguments.Count; j++) { if (setterCall.Arguments[j].MatchStLoc(out var v, out var value)) { Debug.Assert(v.IsSingleDefinition && v.LoadCount == 1); Debug.Assert(getterCall.Arguments[j].MatchLdLoc(v)); getterCall.Arguments[j] = value; } } } }
public Instruction VisitCallInstruction(CallInstruction ci) { ci.Callee = ci.Callee.Accept(eval); return(ci); }
public Instruction VisitCallInstruction(CallInstruction ci) { return(ci); }
public Statement Call(Expression e, int retSizeOnstack) { CallInstruction ci = new CallInstruction(e, new CallSite(retSizeOnstack, 0)); return Emit(ci); }
public void Rl_CallToProcedureWithValidSignature() { Procedure callee = new Procedure("callee", null); callee.Signature = new ProcedureSignature( f.EnsureRegister(Registers.eax), new Identifier[] { f.EnsureRegister(Registers.ebx), f.EnsureRegister(Registers.ecx), f.EnsureOutArgument(f.EnsureRegister(Registers.edi), PrimitiveType.Pointer32) }); rl.IdentifierLiveness.Identifiers.Add(Registers.eax); rl.IdentifierLiveness.Identifiers.Add(Registers.esi); rl.IdentifierLiveness.Identifiers.Add(Registers.edi); CallInstruction ci = new CallInstruction(new ProcedureConstant(PrimitiveType.Pointer32, callee), new CallSite(4, 0)); rl.VisitCallInstruction(ci); Assert.AreEqual(" ebx ecx esi", Dump(rl.IdentifierLiveness)); }
public override Instruction TransformCallInstruction(CallInstruction ci) { //var proc = ci.Callee.Accept(new TypedMemoryExpressionRewriter(arch, store, globals)); return new SideEffect( new Application(ci.Callee, VoidType.Instance)); }
public void VisitCallInstruction(CallInstruction ci) { throw new NotImplementedException(); }
public TranslatedExpression Build(CallInstruction inst) { IMethod method = inst.Method; // Used for Call, CallVirt and NewObj TranslatedExpression target; if (inst.OpCode == OpCode.NewObj) { if (IL.Transforms.DelegateConstruction.IsDelegateConstruction((NewObj)inst, true)) { return(HandleDelegateConstruction(inst)); } target = default(TranslatedExpression); // no target } else { target = expressionBuilder.TranslateTarget(method, inst.Arguments.FirstOrDefault(), inst.OpCode == OpCode.Call); } int firstParamIndex = (method.IsStatic || inst.OpCode == OpCode.NewObj) ? 0 : 1; // Translate arguments to the expected parameter types var arguments = new List <TranslatedExpression>(method.Parameters.Count); Debug.Assert(inst.Arguments.Count == firstParamIndex + method.Parameters.Count); var expectedParameters = method.Parameters.ToList(); bool isExpandedForm = false; for (int i = 0; i < method.Parameters.Count; i++) { var parameter = expectedParameters[i]; var arg = expressionBuilder.Translate(inst.Arguments[firstParamIndex + i]); if (parameter.IsParams && i + 1 == method.Parameters.Count) { // Parameter is marked params // If the argument is an array creation, inline all elements into the call and add missing default values. // Otherwise handle it normally. if (arg.ResolveResult is ArrayCreateResolveResult acrr && acrr.SizeArguments.Count == 1 && acrr.SizeArguments[0].IsCompileTimeConstant && acrr.SizeArguments[0].ConstantValue is int length) { var expandedParameters = expectedParameters.Take(expectedParameters.Count - 1).ToList(); var expandedArguments = new List <TranslatedExpression>(arguments); if (length > 0) { var arrayElements = ((ArrayCreateExpression)arg.Expression).Initializer.Elements.ToArray(); var elementType = ((ArrayType)acrr.Type).ElementType; for (int j = 0; j < length; j++) { expandedParameters.Add(new DefaultParameter(elementType, parameter.Name + j)); if (j < arrayElements.Length) { expandedArguments.Add(new TranslatedExpression(arrayElements[j])); } else { expandedArguments.Add(expressionBuilder.GetDefaultValueExpression(elementType).WithoutILInstruction()); } } } if (IsUnambiguousCall(inst, target, method, Array.Empty <IType>(), expandedArguments) == OverloadResolutionErrors.None) { isExpandedForm = true; expectedParameters = expandedParameters; arguments = expandedArguments.SelectList(a => new TranslatedExpression(a.Expression.Detach())); continue; } } } arguments.Add(arg.ConvertTo(parameter.Type, expressionBuilder, allowImplicitConversion: true)); if (parameter.IsOut && arguments[i].Expression is DirectionExpression dirExpr) { dirExpr.FieldDirection = FieldDirection.Out; } } if (method is VarArgInstanceMethod) { int regularParameterCount = ((VarArgInstanceMethod)method).RegularParameterCount; var argListArg = new UndocumentedExpression(); argListArg.UndocumentedExpressionType = UndocumentedExpressionType.ArgList; int paramIndex = regularParameterCount; var builder = expressionBuilder; argListArg.Arguments.AddRange(arguments.Skip(regularParameterCount).Select(arg => arg.ConvertTo(expectedParameters[paramIndex++].Type, builder).Expression)); var argListRR = new ResolveResult(SpecialType.ArgList); arguments = arguments.Take(regularParameterCount) .Concat(new[] { argListArg.WithoutILInstruction().WithRR(argListRR) }).ToList(); method = (IMethod)method.MemberDefinition; expectedParameters = method.Parameters.ToList(); } var argumentResolveResults = arguments.Select(arg => arg.ResolveResult).ToList(); ResolveResult rr = new CSharpInvocationResolveResult(target.ResolveResult, method, argumentResolveResults, isExpandedForm: isExpandedForm); if (inst.OpCode == OpCode.NewObj) { if (settings.AnonymousTypes && method.DeclaringType.IsAnonymousType()) { var argumentExpressions = arguments.SelectArray(arg => arg.Expression); AnonymousTypeCreateExpression atce = new AnonymousTypeCreateExpression(); if (CanInferAnonymousTypePropertyNamesFromArguments(argumentExpressions, expectedParameters)) { atce.Initializers.AddRange(argumentExpressions); } else { for (int i = 0; i < argumentExpressions.Length; i++) { atce.Initializers.Add( new NamedExpression { Name = expectedParameters[i].Name, Expression = arguments[i].ConvertTo(expectedParameters[i].Type, expressionBuilder) }); } } return(atce .WithILInstruction(inst) .WithRR(rr)); } else { if (IsUnambiguousCall(inst, target, method, Array.Empty <IType>(), arguments) != OverloadResolutionErrors.None) { for (int i = 0; i < arguments.Count; i++) { if (!settings.AnonymousTypes || !expectedParameters[i].Type.ContainsAnonymousType()) { arguments[i] = arguments[i].ConvertTo(expectedParameters[i].Type, expressionBuilder); } } } return(new ObjectCreateExpression(expressionBuilder.ConvertType(inst.Method.DeclaringType), arguments.SelectArray(arg => arg.Expression)) .WithILInstruction(inst).WithRR(rr)); } } else { int allowedParamCount = (method.ReturnType.IsKnownType(KnownTypeCode.Void) ? 1 : 0); if (method.IsAccessor && (method.AccessorOwner.SymbolKind == SymbolKind.Indexer || expectedParameters.Count == allowedParamCount)) { return(HandleAccessorCall(inst, target, method, arguments.ToList())); } else if (method.Name == "Invoke" && method.DeclaringType.Kind == TypeKind.Delegate) { return(new InvocationExpression(target, arguments.Select(arg => arg.Expression)).WithILInstruction(inst).WithRR(rr)); } else { bool requireTypeArguments = false; bool targetCasted = false; bool argumentsCasted = false; IType[] typeArguments = Array.Empty <IType>(); OverloadResolutionErrors errors; while ((errors = IsUnambiguousCall(inst, target, method, typeArguments, arguments)) != OverloadResolutionErrors.None) { switch (errors) { case OverloadResolutionErrors.TypeInferenceFailed: case OverloadResolutionErrors.WrongNumberOfTypeArguments: if (requireTypeArguments) { goto default; } requireTypeArguments = true; typeArguments = method.TypeArguments.ToArray(); continue; default: if (!argumentsCasted) { argumentsCasted = true; for (int i = 0; i < arguments.Count; i++) { if (!settings.AnonymousTypes || !expectedParameters[i].Type.ContainsAnonymousType()) { arguments[i] = arguments[i].ConvertTo(expectedParameters[i].Type, expressionBuilder); } } } else if (!targetCasted) { targetCasted = true; target = target.ConvertTo(method.DeclaringType, expressionBuilder); } else if (!requireTypeArguments) { requireTypeArguments = true; typeArguments = method.TypeArguments.ToArray(); } else { break; } continue; } break; } Expression targetExpr = target.Expression; string methodName = method.Name; // HACK : convert this.Dispose() to ((IDisposable)this).Dispose(), if Dispose is an explicitly implemented interface method. if (inst.Method.IsExplicitInterfaceImplementation && targetExpr is ThisReferenceExpression) { targetExpr = new CastExpression(expressionBuilder.ConvertType(method.ImplementedInterfaceMembers[0].DeclaringType), targetExpr); methodName = method.ImplementedInterfaceMembers[0].Name; } var mre = new MemberReferenceExpression(targetExpr, methodName); if (requireTypeArguments && (!settings.AnonymousTypes || !method.TypeArguments.Any(a => a.ContainsAnonymousType()))) { mre.TypeArguments.AddRange(method.TypeArguments.Select(expressionBuilder.ConvertType)); } var argumentExpressions = arguments.Select(arg => arg.Expression); return(new InvocationExpression(mre, argumentExpressions).WithILInstruction(inst).WithRR(rr)); } } }
public void Rl_MarkLiveStackParameters() { var callee = new Procedure("callee", program.Architecture.CreateFrame()); callee.Frame.ReturnAddressSize = 4; callee.Frame.ReturnAddressKnown = true; callee.Frame.EnsureStackArgument(0, PrimitiveType.Word32); callee.Frame.EnsureStackArgument(4, PrimitiveType.Word32); Assert.AreEqual(8, callee.Frame.GetStackArgumentSpace()); ProcedureFlow pf = new ProcedureFlow(callee, program.Architecture); mpprocflow[callee] = pf; Identifier loc08 = m.Frame.EnsureStackLocal(-8, PrimitiveType.Word32); Identifier loc0C = m.Frame.EnsureStackLocal(-12, PrimitiveType.Word32); Identifier loc10 = m.Frame.EnsureStackLocal(-16, PrimitiveType.Word32); rl.CurrentState = new RegisterLiveness.ByPassState(program.Architecture); var ci = new CallInstruction( new ProcedureConstant(PrimitiveType.Pointer32, callee), new CallSite(4, 0) { StackDepthOnEntry = 16 }); rl.Procedure = m.Procedure; rl.MarkLiveStackParameters(ci); Assert.AreEqual(" Local -000C Local -0010", Dump(rl.IdentifierLiveness)); }
private void AdjustStackPointerAfterCall( Statement stm, CallInstruction call, int stackDelta) { // Locate the post-call definition of the stack pointer, if any var defSpBinding = call.Definitions.Where( d => d.Expression is Identifier).Where( d => ((Identifier)d.Expression).Storage == program.Architecture.StackRegister) .FirstOrDefault(); if (defSpBinding == null) return; var defSpId = defSpBinding.Expression as Identifier; if (defSpId == null) return; var usedSpExp = call.Uses.Select(u => u.Expression). OfType<Identifier>().Where( u => u.Storage == program.Architecture.StackRegister) .FirstOrDefault(); if (usedSpExp == null) return; var retSize = call.CallSite.SizeOfReturnAddressOnStack; var offset = stackDelta - retSize; Expression src; if (offset == 0) src = usedSpExp; else src = m.IAdd(usedSpExp, Constant.Word32(offset)); // Generate a statement that adjusts the stack pointer according to // the calling convention. var ass = new Assignment(defSpId, src); var defSid = ssa.Identifiers[defSpId]; var stackStm = InsertStatement(stm, ass); defSid.DefExpression = src; defSid.DefStatement = stackStm; call.Definitions.Remove(defSpBinding); Use(stackStm, src); }
public void TrcoIcall() { ProcedureBuilder m = new ProcedureBuilder(); Identifier pfn = m.Local32("pfn"); Expression l = m.Load(PrimitiveType.Word32, pfn); CallInstruction icall = new CallInstruction(l, new CallSite(0, 0)); coll = CreateCollector(); icall.Accept(eqb); icall.Accept(coll); StringWriter sw = new StringWriter(); handler.Traits.Write(sw); string exp = "T_1 (in pfn : word32)" + nl + "\ttrait_primitive(word32)" + nl + "\ttrait_mem(T_2, 0)" + nl + "T_2 (in Mem0[pfn:word32] : word32)" + nl + "\ttrait_primitive((ptr code))" + nl + "\ttrait_primitive(word32)" + nl; Console.WriteLine(sw.ToString()); Assert.AreEqual(exp, sw.ToString()); }
private void RewriteCall(Statement stm, CallInstruction call) { var e = expander.Expand(call.Callee); var pt = e.Accept(asc) as Pointer; if (pt == null) return; var ft = pt.Pointee as FunctionType; if (ft == null) return; AdjustStackPointerAfterCall(stm, call, ft.StackDelta); var ab = new ApplicationBuilder( program.Architecture, proc.Frame, call.CallSite, call.Callee, ft, false); stm.Instruction = ab.CreateInstruction(); ssaIdTransformer.Transform(stm, call); changed = true; }
private void AddDefInstructions(CallInstruction ci, ProcedureFlow2 flow) { var existing = ci.Definitions.Select(d => ssa.Identifiers[(Identifier)d.Expression].OriginalIdentifier).ToHashSet(); var ab = new ApplicationBuilder(null, proc.Frame, null, null, null, true); foreach (var idDef in flow.Trashed) { var idLocal = proc.Frame.EnsureIdentifier(idDef); if (!existing.Contains(idLocal)) { ci.Definitions.Add(new DefInstruction(idLocal)); } } foreach (var def in ci.Definitions) { var idNew = NewDef((Identifier) def.Expression, null, false); def.Expression = idNew; } }
private ApplicationBuilder CreateApplicationBuilder(SsaState ssaCaller, Statement stmCaller, CallInstruction call, Expression fn) { return(new CallApplicationBuilder(ssaCaller, stmCaller, call, fn, false)); }
/// <summary> /// Unresolved calls can be "hell nodes". A hell node is an indirect calls or indirect /// jump that prior passes of the decompiler have been unable to resolve. /// </summary> /// <param name="ci"></param> /// <returns></returns> public override void VisitCallInstruction(CallInstruction ci) { Procedure callee = GetUserProcedure(ci); ProcedureFlow2 flow; if (callee != null && programFlow.ProcedureFlows2.TryGetValue(callee, out flow)) { foreach (var def in flow.Trashed) { var idDef = callee.Frame.EnsureIdentifier(def); MarkDefined(idDef); } } else { // Hell node implementation - define all register variables. foreach (Identifier id in proc.Frame.Identifiers) { if (id.Storage is RegisterStorage || id.Storage is FlagGroupStorage) { MarkDefined(id); } } } }
public override Instruction TransformCallInstruction(CallInstruction ci) { var exp = Rewrite(ci.Callee, true); return(new SideEffect(new Application(exp, VoidType.Instance))); }
public void BlockCloner_CloneCall() { var call = new CallInstruction(new ProcedureConstant(arch.PointerType, procCalling), new CallSite(0, 0)); var cloner = new BlockCloner(null, procCalling, callgraph); var block = new Block(procCalling, "test"); cloner.Statement = new Statement(42, call, block); var newCall = (CallInstruction) call.Accept(cloner); Assert.AreEqual(call.Callee, newCall.Callee); Assert.AreEqual(1, callgraph.CallerStatements(procCalling).Count(), "Should've added a call to the callgraph"); }
TranslatedExpression HandleDelegateConstruction(CallInstruction inst) { ILInstruction func = inst.Arguments[1]; IMethod method; switch (func.OpCode) { case OpCode.LdFtn: method = ((LdFtn)func).Method; break; case OpCode.LdVirtFtn: method = ((LdVirtFtn)func).Method; break; default: throw new ArgumentException($"Unknown instruction type: {func.OpCode}"); } var invokeMethod = inst.Method.DeclaringType.GetDelegateInvokeMethod(); TranslatedExpression target; IType targetType; bool requireTarget; if (method.IsExtensionMethod && invokeMethod != null && method.Parameters.Count - 1 == invokeMethod.Parameters.Count) { targetType = method.Parameters[0].Type; target = expressionBuilder.Translate(inst.Arguments[0], targetType); target = ExpressionBuilder.UnwrapBoxingConversion(target); requireTarget = true; } else { targetType = method.DeclaringType; target = expressionBuilder.TranslateTarget(method, inst.Arguments[0], func.OpCode == OpCode.LdFtn); target = ExpressionBuilder.UnwrapBoxingConversion(target); requireTarget = expressionBuilder.HidesVariableWithName(method.Name) || (method.IsStatic ? !expressionBuilder.IsCurrentOrContainingType(method.DeclaringTypeDefinition) : !(target.Expression is ThisReferenceExpression)); } var expectedTargetDetails = new ExpectedTargetDetails { CallOpCode = inst.OpCode }; bool needsCast = false; ResolveResult result = null; var or = new OverloadResolution(resolver.Compilation, method.Parameters.SelectArray(p => new TypeResolveResult(p.Type))); if (!requireTarget) { result = resolver.ResolveSimpleName(method.Name, method.TypeArguments, isInvocationTarget: false); if (result is MethodGroupResolveResult mgrr) { or.AddMethodLists(mgrr.MethodsGroupedByDeclaringType.ToArray()); requireTarget = (or.BestCandidateErrors != OverloadResolutionErrors.None || !IsAppropriateCallTarget(expectedTargetDetails, method, or.BestCandidate)); } else { requireTarget = true; } } MemberLookup lookup = null; if (requireTarget) { lookup = new MemberLookup(resolver.CurrentTypeDefinition, resolver.CurrentTypeDefinition.ParentAssembly); var rr = lookup.Lookup(target.ResolveResult, method.Name, method.TypeArguments, false); needsCast = true; result = rr; if (rr is MethodGroupResolveResult mgrr) { or.AddMethodLists(mgrr.MethodsGroupedByDeclaringType.ToArray()); needsCast = (or.BestCandidateErrors != OverloadResolutionErrors.None || !IsAppropriateCallTarget(expectedTargetDetails, method, or.BestCandidate)); } } if (needsCast) { Debug.Assert(requireTarget); target = target.ConvertTo(targetType, expressionBuilder); result = lookup.Lookup(target.ResolveResult, method.Name, method.TypeArguments, false); } Expression targetExpression; if (requireTarget) { var mre = new MemberReferenceExpression(target, method.Name); mre.TypeArguments.AddRange(method.TypeArguments.Select(expressionBuilder.ConvertType)); mre.WithRR(result); targetExpression = mre; } else { var ide = new IdentifierExpression(method.Name) .WithRR(result); targetExpression = ide; } var oce = new ObjectCreateExpression(expressionBuilder.ConvertType(inst.Method.DeclaringType), targetExpression) .WithILInstruction(inst) .WithRR(new ConversionResolveResult( inst.Method.DeclaringType, new MemberResolveResult(target.ResolveResult, method), Conversion.MethodGroupConversion(method, func.OpCode == OpCode.LdVirtFtn, false))); return(oce); }
public void VisitCallInstruction(CallInstruction ci) { d.VisitCallInstruction(ci); }
public AbsynStatement VisitCallInstruction(CallInstruction ci) { return(new AbsynSideEffect( new Application(ci.Callee, VoidType.Instance))); }
private Identifier FindUsedId(CallInstruction call, Storage storage) { return call.Uses.Select(u => u.Expression). OfType<Identifier>(). Where(usedId => usedId.Storage.Equals(storage)). FirstOrDefault(); }
public Statement Call(Expression e, int retSizeOnstack) { var ci = new CallInstruction(e, new CallSite(retSizeOnstack, 0)); return(Emit(ci)); }
public ProcedureConstantUpdater(string name, CallInstruction ci) : base(name) { this.ci = ci; }
/// <summary> /// Determines whether <paramref name="enumerator"/> is only used once inside <paramref name="loopBody"/> for accessing the Current property. /// </summary> /// <param name="usingContainer">The using body container. This is only used for variable usage checks.</param> /// <param name="loopBody">The loop body. The first statement of this block is analyzed.</param> /// <param name="enumerator">The current enumerator.</param> /// <param name="moveNextUsage">The call MoveNext(ldloc enumerator) pattern.</param> /// <param name="singleGetter">Returns the call instruction invoking Current's getter.</param> /// <param name="foreachVariable">Returns the the foreach variable, if a suitable was found. This variable is only assigned once and its assignment is the first statement in <paramref name="loopBody"/>.</param> /// <returns><see cref="RequiredGetCurrentTransformation"/> for details.</returns> RequiredGetCurrentTransformation DetectGetCurrentTransformation(BlockContainer usingContainer, Block loopBody, ILVariable enumerator, ILInstruction moveNextUsage, out CallInstruction singleGetter, out ILVariable foreachVariable) { singleGetter = null; foreachVariable = null; var loads = (enumerator.LoadInstructions.OfType <ILInstruction>().Concat(enumerator.AddressInstructions.OfType <ILInstruction>())).Where(ld => !ld.IsDescendantOf(moveNextUsage)).ToArray(); // enumerator is used in multiple locations or not in conjunction with get_Current // => no foreach if (loads.Length != 1 || !ParentIsCurrentGetter(loads[0])) { return(RequiredGetCurrentTransformation.NoForeach); } singleGetter = (CallInstruction)loads[0].Parent; // singleGetter is not part of the first instruction in body or cannot be uninlined // => no foreach if (!(singleGetter.IsDescendantOf(loopBody.Instructions[0]) && ILInlining.CanUninline(singleGetter, loopBody.Instructions[0]))) { return(RequiredGetCurrentTransformation.NoForeach); } ILInstruction inst = singleGetter; // in some cases, i.e. foreach variable with explicit type different from the collection-item-type, // the result of call get_Current is casted. while (inst.Parent is UnboxAny || inst.Parent is CastClass) { inst = inst.Parent; } // Gather all nested assignments to determine the foreach variable. List <StLoc> nestedStores = new List <StLoc>(); while (inst.Parent is StLoc stloc) { nestedStores.Add(stloc); inst = stloc; } // No variable was found: we need a new one. if (nestedStores.Count == 0) { return(RequiredGetCurrentTransformation.IntroduceNewVariable); } // One variable was found. if (nestedStores.Count == 1) { // Must be a plain assignment expression and variable must only be used in 'body' + only assigned once. if (nestedStores[0].Parent == loopBody && VariableIsOnlyUsedInBlock(nestedStores[0], usingContainer)) { foreachVariable = nestedStores[0].Variable; return(RequiredGetCurrentTransformation.UseExistingVariable); } } else { // Check if any of the variables is usable as foreach variable. foreach (var store in nestedStores) { if (VariableIsOnlyUsedInBlock(store, usingContainer)) { foreachVariable = store.Variable; return(RequiredGetCurrentTransformation.UninlineAndUseExistingVariable); } } } // No suitable variable found. return(RequiredGetCurrentTransformation.IntroduceNewVariable); }
public Statement Call(ProcedureBase callee, int retSizeOnStack) { ProcedureConstant c = new ProcedureConstant(PrimitiveType.Pointer32, callee); CallInstruction ci = new CallInstruction(c, new CallSite(retSizeOnStack, 0)); return Emit(ci); }
public override Instruction TransformCallInstruction(CallInstruction ci) { var exp = Rewrite(ci.Callee, true); return new SideEffect(new Application(exp, VoidType.Instance)); }
public virtual void VisitCallInstruction(CallInstruction ci) { ci.Callee.Accept(this); }
void Run(CallInstruction inst, ILTransformContext context) { if (inst.Method.MetadataToken.IsNil || inst.Method.MetadataToken.Kind != HandleKind.MethodDefinition) { return; } var handle = (MethodDefinitionHandle)inst.Method.MetadataToken; if (!IsDefinedInCurrentOrOuterClass(inst.Method, context.Function.Method.DeclaringTypeDefinition)) { return; } if (!inst.Method.IsCompilerGeneratedOrIsInCompilerGeneratedClass()) { return; } var metadata = context.PEFile.Metadata; MethodDefinition methodDef = metadata.GetMethodDefinition((MethodDefinitionHandle)inst.Method.MetadataToken); if (!methodDef.HasBody()) { return; } var genericContext = DelegateConstruction.GenericContextFromTypeArguments(inst.Method.Substitution); if (genericContext == null) { return; } // partially copied from CSharpDecompiler var ilReader = context.CreateILReader(); var body = context.PEFile.Reader.GetMethodBody(methodDef.RelativeVirtualAddress); var proxyFunction = ilReader.ReadIL(handle, body, genericContext.Value, context.CancellationToken); var transformContext = new ILTransformContext(context, proxyFunction); proxyFunction.RunTransforms(CSharp.CSharpDecompiler.EarlyILTransforms(), transformContext); if (!(proxyFunction.Body is BlockContainer blockContainer)) { return; } if (blockContainer.Blocks.Count != 1) { return; } var block = blockContainer.Blocks[0]; Call call = null; if (block.Instructions.Count == 1) { // leave IL_0000 (call Test(ldloc this, ldloc A_1)) if (!block.Instructions[0].MatchLeave(blockContainer, out ILInstruction returnValue)) { return; } call = returnValue as Call; } else if (block.Instructions.Count == 2) { // call Test(ldloc this, ldloc A_1) // leave IL_0000(nop) call = block.Instructions[0] as Call; if (!block.Instructions[1].MatchLeave(blockContainer, out ILInstruction returnValue)) { return; } if (!returnValue.MatchNop()) { return; } } if (call == null) { return; } if (call.Method.IsConstructor) { return; } // check if original arguments are only correct ldloc calls for (int i = 0; i < call.Arguments.Count; i++) { var originalArg = call.Arguments[i]; if (!originalArg.MatchLdLoc(out ILVariable var) || var.Kind != VariableKind.Parameter || var.Index != i - 1) { return; } } Call newInst = (Call)call.Clone(); newInst.Arguments.ReplaceList(inst.Arguments); inst.ReplaceWith(newInst); }