/// <summary> /// Compute the live-in of the procedure whose SSA state is /// in <paramref name="ssaState"/>. /// </summary> /// <remarks> /// Assmumes that any live-in parameters are located in the /// entry block of the procedure.</remarks> /// <param name="ssaState"></param> public ProcedureFlow ComputeLiveIn(SsaState ssaState, bool ignoreUse) { this.procFlow = flow[ssaState.Procedure]; this.ssa = ssaState; this.useLiveness = ignoreUse; foreach (var stm in ssa.Procedure.EntryBlock.Statements) { if (!(stm.Instruction is DefInstruction def)) { continue; } var sid = ssa.Identifiers[def.Identifier]; if ((sid.Identifier.Storage is RegisterStorage || sid.Identifier.Storage is StackArgumentStorage || sid.Identifier.Storage is FpuStackStorage || sid.Identifier.Storage is SequenceStorage)) //$REVIEW: flag groups could theoretically be live in // although it's uncommon. { var n = Classify(ssa, sid, sid.Identifier.Storage, ignoreUse); if (!n.IsEmpty) { procFlow.BitsUsed[sid.Identifier.Storage] = n; } } } return(procFlow); }
public void DumpProgram() { foreach (Procedure proc in program.Procedures.Values) { StringWriter output = new StringWriter(); ProcedureFlow pf = this.flow[proc]; TextFormatter f = new TextFormatter(output); if (pf.Signature != null) { pf.Signature.Emit(proc.Name, FunctionType.EmitFlags.None, f); } else { proc.Signature.Emit(proc.Name, FunctionType.EmitFlags.None, f); } output.WriteLine(); pf.Emit(proc.Architecture, output); output.WriteLine("// {0}", proc.Name); proc.Signature.Emit(proc.Name, FunctionType.EmitFlags.None, f); output.WriteLine(); foreach (Block block in proc.ControlGraph.Blocks) { if (block != null) { block.Write(output); } } Debug.WriteLine(output.ToString()); } }
/// <summary> /// After running the Used register analysis, the ProcedureFlow of /// the procedure <paramref name="proc"/> may have been modified to /// exclude some parameters. Functions in the current SCC need to be /// adjusted to no longer refer to those parameters. /// </summary> /// <param name="proc"></param> private void RemoveDeadArgumentsFromCalls( Procedure proc, ProcedureFlow flow, IEnumerable <SsaTransform> ssts) { var mpProcSsa = ssts.ToDictionary(d => d.SsaState.Procedure, d => d.SsaState); foreach (Statement stm in program.CallGraph.CallerStatements(proc)) { if (!mpProcSsa.TryGetValue(stm.Block.Procedure, out var ssa)) { continue; } // We have a call statement that calls `proc`. Make sure // that only arguments present in the procedure flow are present. if (!(stm.Instruction is CallInstruction call)) { continue; } var filteredUses = ProcedureFlow.IntersectCallBindingsWithUses(call.Uses, flow.BitsUsed) .ToArray(); ssa.RemoveUses(stm); call.Uses.Clear(); call.Uses.UnionWith(filteredUses); ssa.AddUses(stm); } }
public override void InitializeProcedureFlow(ProcedureFlow flow) { flow.MayUse = new BitSet(flow.Summary); flow.Summary.SetAll(false); flow.grfMayUse = flow.grfSummary; flow.grfSummary = 0; }
/// <summary> /// Creates a signature for this procedure, and ensures that all registers accessed by the procedure are in the procedure /// Frame. /// </summary> public void EnsureSignature(Procedure proc, ProcedureFlow flow) { if (proc.Signature != null && proc.Signature.ParametersValid) { return; } SignatureBuilder sb = new SignatureBuilder(proc, Program.Architecture); Frame frame = proc.Frame; if (flow.grfLiveOut != 0) { sb.AddFlagGroupReturnValue(flow.grfLiveOut, frame); } var implicitRegs = Program.Platform.CreateImplicitArgumentRegisters(); BitSet mayUse = flow.MayUse - implicitRegs; foreach (int r in mayUse) { if (!IsSubRegisterOfRegisters(r, mayUse)) { sb.AddRegisterArgument(r); } } foreach (KeyValuePair <int, Identifier> de in GetSortedStackArguments(proc.Frame)) { AddStackArgument(de.Key, de.Value, flow, sb); } foreach (KeyValuePair <int, Identifier> de in GetSortedFpuStackArguments(proc.Frame, 0)) { sb.AddFpuStackArgument(de.Key, de.Value); } BitSet liveOut = flow.LiveOut - implicitRegs; foreach (int r in liveOut) { if (!IsSubRegisterOfRegisters(r, liveOut)) { sb.AddArgument(frame.EnsureRegister(Program.Architecture.GetRegister(r)), true); } } foreach (KeyValuePair <int, Identifier> de in GetSortedFpuStackArguments(proc.Frame, -proc.Signature.FpuStackDelta)) { int i = de.Key; if (i <= proc.Signature.FpuStackOutArgumentMax) { sb.AddArgument(frame.EnsureFpuStackVariable(i, de.Value.DataType), true); } } var sig = sb.BuildSignature(); flow.Signature = sig; proc.Signature = sig; }
public static void Rewrite( IPlatform platform, List <SsaTransform> ssts, ProgramDataFlow summaries, DecompilerEventListener eventListener) { CallRewriter crw = new CallRewriter(platform, summaries, eventListener); foreach (SsaTransform sst in ssts) { if (eventListener.IsCanceled()) { return; } var proc = sst.SsaState.Procedure; ProcedureFlow flow = crw.mpprocflow[proc]; flow.Dump(proc.Architecture); crw.EnsureSignature(sst.SsaState, proc.Frame, flow); } foreach (SsaTransform sst in ssts) { if (eventListener.IsCanceled()) { return; } crw.RewriteCalls(sst.SsaState); crw.RewriteReturns(sst.SsaState); crw.RemoveStatementsFromExitBlock(sst.SsaState); } }
public override void InitializeProcedureFlow(ProcedureFlow flow) { flow.ByPass = flow.Summary.Clone(); flow.Summary.SetAll(false); flow.grfByPass = flow.grfSummary; flow.grfSummary = 0; }
public void CreateFlowsFor(IEnumerable <Procedure> procs) { foreach (Procedure proc in procs) { procFlow[proc] = new ProcedureFlow(proc); } }
public static void Rewrite( Program program, ProgramDataFlow summaries, DecompilerEventListener eventListener) { GlobalCallRewriter crw = new GlobalCallRewriter(program, summaries, eventListener); foreach (Procedure proc in program.Procedures.Values) { if (eventListener.IsCanceled()) { return; } ProcedureFlow flow = crw.mpprocflow[proc]; flow.Dump(proc.Architecture); crw.AdjustLiveOut(flow); crw.EnsureSignature(proc, flow); crw.AddUseInstructionsForOutArguments(proc); } foreach (Procedure proc in program.Procedures.Values) { if (eventListener.IsCanceled()) { return; } crw.RewriteCalls(proc); crw.RewriteReturns(proc); } }
/// <summary> /// Remove any storages in the ProcedureFlow <paramref name="flow"/> associated /// with the procedure <paramref name="proc"/> if they are dead. /// </summary> private bool RemoveLiveInStorages(Procedure proc, ProcedureFlow flow, WorkList <SsaState> wl) { var defs = proc.EntryBlock.Statements .Select(s => s.Instruction as DefInstruction) .Where(s => s != null) .Select(s => s !.Identifier.Storage) .ToHashSet(); var deadStgs = flow.BitsUsed.Keys.Except(defs).ToHashSet(); bool changed = false; foreach (var d in deadStgs) { flow.BitsUsed.Remove(d); changed = true; } if (changed) { foreach (Statement stm in program.CallGraph.CallerStatements(proc)) { if (!(stm.Instruction is CallInstruction ci)) { continue; } var ssaCaller = this.procToSsa[stm.Block.Procedure]; if (RemoveDeadCallUses(ssaCaller, stm, ci, deadStgs)) { wl.Add(ssaCaller); } } } return(changed); }
public override void InitializeProcedureFlow(ProcedureFlow flow) { flow.MayUse = new HashSet <RegisterStorage>(flow.Summary); flow.Summary.Clear(); flow.grfMayUse = flow.grfSummary; flow.grfSummary = 0; }
public void Setup() { arch = new FakeArchitecture(); proc = new Procedure("Test", new Frame(arch.FramePointerType)); flow = new ProcedureFlow(proc, arch); ctx = new SymbolicEvaluationContext(arch, proc.Frame); trs = new TrashedRegisterSummarizer(arch, proc, flow, ctx); }
public override void InitializeProcedureFlow(ProcedureFlow flow) { flow.ByPass = new HashSet <RegisterStorage>(flow.Summary); flow.ByPass.ExceptWith(flow.TrashedRegisters); flow.Summary.Clear(); flow.grfByPass = flow.grfSummary; flow.grfSummary = 0; }
public void Setup() { program = new Program(); program.Architecture = new IntelArchitecture(ProcessorMode.Protected32); program.Platform = new DefaultPlatform(null, program.Architecture); gcr = new GlobalCallRewriter(program, null); proc = new Procedure("foo", program.Architecture.CreateFrame()); flow = new ProcedureFlow(proc, program.Architecture); }
public void Setup() { program = new Program(); program.Architecture = new X86ArchitectureFlat32(); program.Platform = new DefaultPlatform(null, program.Architecture); gcr = new GlobalCallRewriter(program, null, new FakeDecompilerEventListener()); proc = new Procedure("foo", program.Architecture.CreateFrame()); flow = new ProcedureFlow(proc, program.Architecture); }
private void Dump(bool enable, string s, HashSet <RegisterStorage> a) { if (enable) { StringWriter sw = new StringWriter(); sw.Write("{0}: ", s); ProcedureFlow.EmitRegisters(program.Architecture, "", a, sw); Debug.WriteLine(sw.ToString()); } }
public TrashedRegisterSummarizer(IProcessorArchitecture arch, Procedure proc, ProcedureFlow pf, SymbolicEvaluationContext ctx) { this.arch = arch; this.proc = proc; this.pf = pf; trashed = new HashSet<RegisterStorage>(); preserved = new HashSet<RegisterStorage>(); this.ctx = ctx; this.cmp = new ExpressionValueComparer(); }
public TrashedRegisterSummarizer(IProcessorArchitecture arch, Procedure proc, ProcedureFlow pf, SymbolicEvaluationContext ctx) { this.arch = arch; this.proc = proc; this.pf = pf; trashed = new HashSet <RegisterStorage>(); preserved = new HashSet <RegisterStorage>(); this.ctx = ctx; this.cmp = new ExpressionValueComparer(); }
private void Dump() { foreach (Procedure proc in program.Procedures.Values) { StringWriter sw = new StringWriter(); ProcedureFlow flow = mpprocData[proc]; sw.WriteLine(proc.Name); DataFlow.EmitRegisters(program.Architecture, "\tByPass: "******"\tMayUse: ", flow.MayUse, sw); sw.WriteLine(); Debug.WriteLine(sw.ToString()); } }
/// <summary> /// Creates a signature for this procedure by looking at the storages /// modified in the exit block, and ensures that all the registers /// accessed by the procedure are in the procedure Frame. /// </summary> public void EnsureSignature(SsaState ssa, IStorageBinder frame, ProcedureFlow flow) { var proc = ssa.Procedure; // If we already have a signature, we don't need to do this work. if (!proc.Signature.ParametersValid) { var sig = MakeSignature(ssa, frame, flow); flow.Signature = sig; proc.Signature = sig; } }
private void AdjustLiveIn(Procedure proc, ProcedureFlow flow) { var liveDefStms = proc.EntryBlock.Statements .Select(s => s.Instruction) .OfType <DefInstruction>() .Select(d => d.Identifier.Storage); var dead = flow.BitsUsed.Keys .Except(liveDefStms).ToList(); foreach (var dd in dead) { flow.BitsUsed.Remove(dd); } }
private void ApplySignature(FunctionType sig, ProcedureFlow procFlow) { //$REVIEW: do we need this? if a procedure has a signature, // we will always trust that rather than the flow. if (!sig.HasVoidReturn) { procFlow.Trashed.Add(sig.ReturnValue.Storage); } foreach (var stg in sig.Parameters .Select(p => p.Storage) .OfType <OutArgumentStorage>()) { procFlow.Trashed.Add(stg.OriginalIdentifier.Storage); } }
/// <summary> /// Make summary information available in LiveIn and LiveOut for each procedure. /// </summary> private void CompleteWork() { foreach (Procedure proc in program.Procedures.Values) { ProcedureFlow pi = mpprocData[proc]; BlockFlow bi = mpprocData[proc.ExitBlock]; pi.LiveOut = bi.DataOut; pi.grfLiveOut = bi.grfOut; // Remove unneeded data. Done for performance (and to give GC something to do). pi.ByPass.Clear(); } }
public ProgramDataFlow(Program program) : this() { foreach (Procedure proc in program.Procedures.Values) { procFlow[proc] = new ProcedureFlow(proc, program.Architecture); foreach (Block block in proc.ControlGraph.Blocks) { blockFlow[block] = new BlockFlow( block, new HashSet<RegisterStorage>(), new SymbolicEvaluationContext( program.Architecture, proc.Frame)); } } }
public ProgramDataFlow(Program prog) : this() { foreach (Procedure proc in prog.Procedures.Values) { procFlow[proc] = new ProcedureFlow(proc, prog.Architecture); foreach (Block block in proc.ControlGraph.Blocks) { blockFlow[block] = new BlockFlow( block, prog.Architecture.CreateRegisterBitset(), new SymbolicEvaluationContext( prog.Architecture, proc.Frame)); } } }
public ProgramDataFlow(Program program) : this() { foreach (Procedure proc in program.Procedures.Values) { procFlow[proc] = new ProcedureFlow(proc, proc.Architecture); foreach (Block block in proc.ControlGraph.Blocks) { blockFlow[block] = new BlockFlow( block, new HashSet <RegisterStorage>(), new SymbolicEvaluationContext( proc.Architecture, proc.Frame)); } } }
public void AddStackArgument(int x, Identifier id, ProcedureFlow flow, SignatureBuilder sb) { object o = flow.StackArguments[id]; if (o != null) { int bitWidth = (int) o; if (bitWidth < id.DataType.BitSize) { PrimtiveType pt = id.DataType as PrimtiveType; if (pt != null) { id.DataType = PrimtiveType.Create(pt.Domain, bitWidth/8); } } } sb.AddStackArgument(x, id); }
public bool MergeIntoProcedureFlow(IdentifierLiveness varLive, ProcedureFlow flow) { if (varLive.BitSet[0x1F]) { varLive.ToString(); } bool fChange = false; if (!(varLive.BitSet & ~flow.Summary).IsEmpty) { flow.Summary |= varLive.BitSet; fChange = true; } if ((varLive.Grf & ~flow.grfSummary) != 0) { flow.grfSummary |= varLive.Grf; fChange = true; } foreach (KeyValuePair <Storage, int> de in varLive.LiveStorages) { StackArgumentStorage sa = de.Key as StackArgumentStorage; if (sa == null) { continue; } int bits = de.Value; object o = flow.StackArguments[sa]; if (o != null) { int bitsOld = (int)o; if (bitsOld < bits) { flow.StackArguments[sa] = bits; fChange = true; } } else { flow.StackArguments[sa] = bits; fChange = true; } } return(fChange); }
public void AddStackArgument(Identifier id, ProcedureFlow flow, SignatureBuilder sb) { object o = flow.StackArguments[id]; if (o != null) { int bitWidth = (int)o; if (bitWidth < id.DataType.BitSize) { PrimtiveType pt = id.DataType as PrimtiveType; if (pt != null) { id.DataType = PrimtiveType.Create(pt.Domain, bitWidth); } } } sb.AddInParam(id); }
/// <summary> /// When liveness analysis reaches the entry block of the procedure, /// update the procedure summary information with the current set of /// live registers. /// </summary> /// <param name="p"></param> public void PropagateToProcedureSummary(IdentifierLiveness varLive, Procedure p) { ProcedureFlow flow = mpprocData[p]; state.ApplySavedRegisters(flow, varLive); var change = MergeIntoProcedureFlow(varLive, flow); if (change) { Debug.WriteLineIf(trace.TraceInfo, flow.EmitRegisters(program.Architecture, p.Name + " summary:", flow.Summary)); state.UpdateSummary(flow); foreach (Statement stmCaller in program.CallGraph.CallerStatements(p)) { Debug.WriteLineIf(trace.TraceVerbose, string.Format("Propagating to {0} (block {1} in {2}", stmCaller.Instruction.ToString(), stmCaller.Block.Name, stmCaller.Block.Procedure.Name)); worklist.Add(mpprocData[stmCaller.Block]); } } }
public static void Rewrite(Program program, ProgramDataFlow summaries) { GlobalCallRewriter crw = new GlobalCallRewriter(program, summaries); foreach (Procedure proc in program.Procedures.Values) { ProcedureFlow flow = (ProcedureFlow)crw.mpprocflow[proc]; flow.Dump(program.Architecture); crw.AdjustLiveOut(flow); crw.EnsureSignature(proc, flow); crw.AddUseInstructionsForOutArguments(proc); } foreach (Procedure proc in program.Procedures.Values) { crw.RewriteCalls(proc); crw.RewriteReturns(proc); } }
public bool MergeIntoProcedureFlow(IdentifierLiveness varLive, ProcedureFlow flow) { bool fChange = false; int oldcount = flow.Summary.Count; flow.Summary.UnionWith(varLive.Identifiers); if (flow.Summary.Count != oldcount) { fChange = true; } if ((varLive.Grf & ~flow.grfSummary) != 0) { flow.grfSummary |= varLive.Grf; fChange = true; } foreach (KeyValuePair <Storage, int> de in varLive.LiveStorages) { StackArgumentStorage sa = de.Key as StackArgumentStorage; if (sa == null) { continue; } int bits = de.Value; object o = flow.StackArguments[sa]; if (o != null) { int bitsOld = (int)o; if (bitsOld < bits) { flow.StackArguments[sa] = bits; fChange = true; } } else { flow.StackArguments[sa] = bits; fChange = true; } } return(fChange); }
public BitRange Classify( SsaState ssa, SsaIdentifier sid, Storage storage, bool ignoreUseInstructions) { this.procFlow = flow[ssa.Procedure]; this.ssa = ssa; this.useLiveness = ignoreUseInstructions; if (storage is RegisterStorage || storage is StackArgumentStorage || storage is FpuStackStorage || storage is FlagGroupStorage || storage is SequenceStorage) { var n = Classify(sid); return(n); } else { return(BitRange.Empty); } }
private bool MergeLiveOut(ProcedureFlow flow, Dictionary <Storage, BitRange> newLiveOut) { bool change = false; foreach (var de in newLiveOut) { if (flow.BitsLiveOut.TryGetValue(de.Key, out BitRange oldRange)) { var range = oldRange | de.Value; if (range != oldRange) { flow.BitsLiveOut[de.Key] = range; change = true; } } else { var range = de.Value; flow.BitsLiveOut[de.Key] = range; change = true; } } return(change); }
/// <summary> /// Creates a signature for this procedure, and ensures that all /// registers accessed by the procedure are in the procedure /// Frame. /// </summary> public void EnsureSignature(Procedure proc, ProcedureFlow flow) { if (proc.Signature.ParametersValid) { return; } var sb = new SignatureBuilder(proc.Frame, proc.Architecture); var frame = proc.Frame; if (flow.grfLiveOut != 0) { sb.AddFlagGroupReturnValue(flow.grfLiveOut, frame); } var implicitRegs = Program.Platform.CreateImplicitArgumentRegisters(); var mayUse = new HashSet <RegisterStorage>(flow.MayUse); mayUse.ExceptWith(implicitRegs); foreach (var reg in mayUse.OrderBy(r => r.Number)) { if (!IsSubRegisterOfRegisters(reg, mayUse)) { sb.AddRegisterArgument(reg); } } foreach (var id in GetSortedStackArguments(proc.Frame).Values) { AddStackArgument(id, flow, sb); } foreach (KeyValuePair <int, Identifier> de in GetSortedFpuStackArguments(proc.Frame, 0)) { sb.AddFpuStackArgument(de.Key, de.Value); } var liveOut = new HashSet <RegisterStorage>(flow.LiveOut); liveOut.ExceptWith(implicitRegs); // Sort the names in a stable way to avoid regression tests failing. foreach (var r in liveOut.OrderBy(r => r.Number).ThenBy(r => r.BitAddress)) { if (!IsSubRegisterOfRegisters(r, liveOut)) { sb.AddOutParam(frame.EnsureRegister(r)); } } foreach (KeyValuePair <int, Identifier> de in GetSortedFpuStackArguments(proc.Frame, -proc.Signature.FpuStackDelta)) { int i = de.Key; if (i <= proc.Signature.FpuStackOutArgumentMax) { sb.AddOutParam(frame.EnsureFpuStackVariable(i, de.Value.DataType)); } } var sig = sb.BuildSignature(); flow.Signature = sig; proc.Signature = sig; }
public void TrfCallInstruction() { var callee = new Procedure("Callee", program.Architecture.CreateFrame()); var stm = m.Call(callee, 4); var pf = new ProcedureFlow(callee, program.Architecture); pf.TrashedRegisters.Add(Registers.ebx); flow[callee] = pf; trf = CreateTrashedRegisterFinder(); CreateBlockFlow(m.Block, m.Frame); trf.StartProcessingBlock(m.Block); stm.Instruction.Accept(trf); Assert.AreEqual("(ebx:<invalid>)", DumpValues()); }
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)); }
/// <summary> /// Make a function signature based on the procedure flow <paramref name="flow"/>. /// </summary> /// <returns>A valid function signature.</returns> public FunctionType MakeSignature(SsaState ssa, IStorageBinder frame, ProcedureFlow flow) { var allLiveOut = flow.BitsLiveOut; var sb = new SignatureBuilder(frame, platform.Architecture); var implicitRegs = platform.CreateImplicitArgumentRegisters(); var liveOutFlagGroups = flow.grfLiveOut.Select(de => platform.Architecture.GetFlagGroup(de.Key, de.Value) !); AddModifiedFlags(frame, liveOutFlagGroups, sb); var mayUseSeqs = flow.BitsUsed.Keys.OfType <SequenceStorage>().ToHashSet(); var seqRegs = mayUseSeqs.SelectMany(s => s.Elements).Distinct().ToHashSet(); //$BUG: should be sorted by ABI register order. foreach (var seq in mayUseSeqs.OrderBy(r => r.Name)) { sb.AddSequenceArgument(seq); } var mayUseRegs = flow.BitsUsed .Select(de => (Key: de.Key as RegisterStorage, de.Value)) .Where(b => { return(b.Key is RegisterStorage reg && !implicitRegs.Contains(reg)); }) .Select(MakeRegisterParameter) .ToDictionary(de => de.Item1, de => de.Item2); //$BUG: should be sorted by ABI register order. Need a new method // IPlatform.CreateAbiRegisterCollator(). foreach (var reg in mayUseRegs.OrderBy(r => r.Key.Number)) { if (!IsSubRegisterOfRegisters(reg.Key, mayUseRegs) && !seqRegs.Contains(reg.Key)) { sb.AddRegisterArgument(reg.Key); } } foreach (var id in GetSortedStackArguments((Frame)frame, flow.BitsUsed)) { sb.AddInParam(id.Item2); } foreach (var oFpu in flow.BitsUsed .Where(f => f.Key is FpuStackStorage) .OrderBy(r => ((FpuStackStorage)r.Key).FpuStackOffset)) { var fpu = (FpuStackStorage)oFpu.Key; var id = frame.EnsureFpuStackVariable(fpu.FpuStackOffset, fpu.DataType); sb.AddFpuStackArgument(fpu.FpuStackOffset, id); } var liveOut = allLiveOut .Select(de => (Key: de.Key as RegisterStorage, de.Value)) .Where(de => { return(de.Key != null && !implicitRegs.Contains(de.Key)); }) .Select(MakeRegisterParameter) .ToDictionary(de => de.Item1, de => de.Item2); // Sort the names in a stable way to avoid regression tests failing. foreach (var r in liveOut.OrderBy(r => r.Key.Number).ThenBy(r => r.Key.BitAddress)) { if (!IsSubRegisterOfRegisters(r.Key, liveOut)) { var regOut = sb.AddOutParam(frame.EnsureRegister(r.Key)); if (regOut.Storage is OutArgumentStorage && !ssa.Identifiers.TryGetValue(regOut, out var sidOut)) { // Ensure there are SSA identifiers for 'out' registers. ssa.Identifiers.Add(regOut, null, null, false); } } } foreach (var fpu in allLiveOut.Keys.OfType <FpuStackStorage>().OrderBy(r => r.FpuStackOffset)) { sb.AddOutParam(frame.EnsureFpuStackVariable(fpu.FpuStackOffset, fpu.DataType)); } var sig = sb.BuildSignature(); return(sig); }
public void Rl_ProcedureWithTrashedAndPreservedRegisters() { var proc = new Procedure("test", program.Architecture.CreateFrame()); var pf = new ProcedureFlow(proc, program.Architecture); mpprocflow[proc] = pf; pf.TrashedRegisters.Add(Registers.eax); pf.TrashedRegisters.Add(Registers.ebx); pf.PreservedRegisters.Add(Registers.ebp); pf.PreservedRegisters.Add(Registers.bp); RegisterLiveness.State st = new RegisterLiveness.ByPassState(program.Architecture); var bf = CreateBlockFlow(proc.ExitBlock, proc.Frame); mpprocflow[proc.ExitBlock] = bf; st.InitializeBlockFlow(proc.ExitBlock, mpprocflow, true); Assert.IsFalse(bf.DataOut.Contains(Registers.ebp), "preserved registers cannot be live out"); Assert.IsFalse(bf.DataOut.Contains(Registers.bp), "preserved registers cannot be live out"); Assert.IsTrue(bf.DataOut.Contains(Registers.eax), "trashed registers may be live out"); Assert.IsTrue(bf.DataOut.Contains(Registers.esi), "Unmentioned registers may be live out"); }
/// <summary> /// Adjusts LiveOut values for use as out registers. /// </summary> /// <remarks> /// LiveOut sets contain registers that aren't modified by the procedure. When determining /// the returned registers, those unmodified registers must be filtered away. /// </remarks> /// <param name="flow"></param> private void AdjustLiveOut(ProcedureFlow flow) { flow.grfLiveOut &= flow.grfTrashed; flow.LiveOut.IntersectWith(flow.TrashedRegisters); }
public void TrfTerminatingProcedure() { var eax = m.Procedure.Frame.EnsureRegister(Registers.eax); m.Assign(eax, m.Word32(0x40)); m.Call(exit, 4); flow[m.Block] = CreateBlockFlow(m.Block, m.Frame); flow[exit] = new ProcedureFlow(exit, program.Architecture); flow[exit].TerminatesProcess = true; trf = CreateTrashedRegisterFinder(program); trf.ProcessBlock(m.Block); Assert.AreEqual("", DumpValues()); }
/// <summary> /// Creates a signature for this procedure, and ensures that all /// registers accessed by the procedure are in the procedure /// Frame. /// </summary> public void EnsureSignature(Procedure proc, ProcedureFlow flow) { if (proc.Signature != null && proc.Signature.ParametersValid) return; var sb = new SignatureBuilder(proc, Program.Architecture); var frame = proc.Frame; if (flow.grfLiveOut != 0) { sb.AddFlagGroupReturnValue(flow.grfLiveOut, frame); } var implicitRegs = Program.Platform.CreateImplicitArgumentRegisters(); var mayUse = new HashSet<RegisterStorage>(flow.MayUse); mayUse.ExceptWith(implicitRegs); foreach (var reg in mayUse.OrderBy(r => r.Number)) { if (!IsSubRegisterOfRegisters(reg, mayUse)) { sb.AddRegisterArgument(reg); } } foreach (KeyValuePair<int,Identifier> de in GetSortedStackArguments(proc.Frame)) { AddStackArgument(de.Key, de.Value, flow, sb); } foreach (KeyValuePair<int, Identifier> de in GetSortedFpuStackArguments(proc.Frame, 0)) { sb.AddFpuStackArgument(de.Key, de.Value); } var liveOut = new HashSet<RegisterStorage>(flow.LiveOut); liveOut.ExceptWith(implicitRegs); foreach (var r in liveOut.OrderBy(r => r.Number)) { if (!IsSubRegisterOfRegisters(r, liveOut)) { sb.AddOutParam(frame.EnsureRegister(r)); } } foreach (KeyValuePair<int, Identifier> de in GetSortedFpuStackArguments(proc.Frame, -proc.Signature.FpuStackDelta)) { int i = de.Key; if (i <= proc.Signature.FpuStackOutArgumentMax) { sb.AddOutParam(frame.EnsureFpuStackVariable(i, de.Value.DataType)); } } var sig = sb.BuildSignature(); flow.Signature = sig; proc.Signature = sig; }
/// <summary> /// Creates a signature for this procedure, and ensures that all registers accessed by the procedure are in the procedure /// Frame. /// </summary> public void EnsureSignature(Procedure proc, ProcedureFlow flow) { if (proc.Signature != null && proc.Signature.ParametersValid) return; SignatureBuilder sb = new SignatureBuilder(proc, Program.Architecture); Frame frame = proc.Frame; if (flow.grfLiveOut != 0) { sb.AddFlagGroupReturnValue(flow.grfLiveOut, frame); } var implicitRegs = Program.Platform.CreateImplicitArgumentRegisters(); BitSet mayUse = flow.MayUse - implicitRegs; foreach (int r in mayUse) { if (!IsSubRegisterOfRegisters(r, mayUse)) { sb.AddRegisterArgument(r); } } foreach (KeyValuePair<int,Identifier> de in GetSortedStackArguments(proc.Frame)) { AddStackArgument(de.Key, de.Value, flow, sb); } foreach (KeyValuePair<int, Identifier> de in GetSortedFpuStackArguments(proc.Frame, 0)) { sb.AddFpuStackArgument(de.Key, de.Value); } BitSet liveOut = flow.LiveOut - implicitRegs; foreach (int r in liveOut) { if (!IsSubRegisterOfRegisters(r, liveOut)) { sb.AddArgument(frame.EnsureRegister(Program.Architecture.GetRegister(r)), true); } } foreach (KeyValuePair<int, Identifier> de in GetSortedFpuStackArguments(proc.Frame, -proc.Signature.FpuStackDelta)) { int i = de.Key; if (i <= proc.Signature.FpuStackOutArgumentMax) { sb.AddArgument(frame.EnsureFpuStackVariable(i, de.Value.DataType), true); } } var sig = sb.BuildSignature(); flow.Signature = sig; proc.Signature = sig; }
/// <summary> /// Adjusts LiveOut values for use as out registers. /// </summary> /// <remarks> /// LiveOut sets contain registers that aren't modified by the procedure. When determining /// the returned registers, those unmodified registers must be filtered away. /// </remarks> /// <param name="flow"></param> private void AdjustLiveOut(ProcedureFlow flow) { flow.grfLiveOut &= flow.grfTrashed; flow.LiveOut &= flow.TrashedRegisters; }
public void Rl_ProcedureWithTrashedAndPreservedRegisters() { Procedure proc = new Procedure("test", program.Architecture.CreateFrame()); ProcedureFlow pf = new ProcedureFlow(proc, program.Architecture); mpprocflow[proc] = pf; pf.TrashedRegisters[Registers.eax.Number] = true; pf.TrashedRegisters[Registers.ebx.Number] = true; pf.PreservedRegisters[Registers.ebp.Number] = true; pf.PreservedRegisters[Registers.bp.Number] = true; RegisterLiveness.State st = new RegisterLiveness.ByPassState(); BlockFlow bf = CreateBlockFlow(proc.ExitBlock, proc.Frame); mpprocflow[proc.ExitBlock] = bf; st.InitializeBlockFlow(proc.ExitBlock, mpprocflow, true); Assert.IsFalse(bf.DataOut[Registers.ebp.Number], "preserved registers cannot be live out"); Assert.IsFalse(bf.DataOut[Registers.bp.Number], "preserved registers cannot be live out"); Assert.IsTrue(bf.DataOut[Registers.eax.Number], "trashed registers may be live out"); Assert.IsTrue(bf.DataOut[Registers.esi.Number], "Unmentioned registers may be live out"); }
public void TrfPropagateToProcedureSummary() { Procedure proc = new Procedure("proc", program.Architecture.CreateFrame()); program.CallGraph.AddProcedure(proc); Identifier eax = proc.Frame.EnsureRegister(Registers.eax); Identifier ebx = proc.Frame.EnsureRegister(Registers.ebx); Identifier ecx = proc.Frame.EnsureRegister(Registers.ecx); Identifier esi = proc.Frame.EnsureRegister(Registers.esi); flow[proc] = new ProcedureFlow(proc, program.Architecture); trf = CreateTrashedRegisterFinder(); CreateBlockFlow(proc.ExitBlock, proc.Frame); trf.StartProcessingBlock(proc.ExitBlock); trf.RegisterSymbolicValues[(RegisterStorage) eax.Storage] = eax; // preserved trf.RegisterSymbolicValues[(RegisterStorage) ebx.Storage] = ecx; // trashed trf.RegisterSymbolicValues[(RegisterStorage) esi.Storage] = Constant.Invalid; // trashed trf.PropagateToProcedureSummary(proc); ProcedureFlow pf = flow[proc]; Assert.AreEqual(" ebx esi", pf.EmitRegisters(program.Architecture, "", pf.TrashedRegisters)); Assert.AreEqual(" eax", pf.EmitRegisters(program.Architecture, "", pf.PreservedRegisters)); }
public void TrfPropagateFlagsToProcedureSummary() { var proc = new Procedure("proc", program.Architecture.CreateFrame()); program.CallGraph.AddProcedure(proc); var flags = program.Architecture.GetFlagGroup("SZ"); var sz = m.Frame.EnsureFlagGroup(flags.FlagRegister, flags.FlagGroupBits, flags.Name, flags.DataType); var stm = m.Assign(sz, m.Int32(3)); flow[proc] = new ProcedureFlow(proc, program.Architecture); trf = CreateTrashedRegisterFinder(program); CreateBlockFlow(m.Block, m.Frame); trf.StartProcessingBlock(m.Block); stm.Accept(trf); trf.PropagateToProcedureSummary(proc); Assert.AreEqual(" SZ", flow[proc].EmitFlagGroup(program.Architecture, "", flow[proc].grfTrashed)); }