public void CollectTypes() { CollectGlobalType(); CollectUserGlobalVariableTypes(); CollectImageSymbols(); int cProc = program.Procedures.Count; int i = 0; foreach (Procedure proc in program.Procedures.Values) { eventListener.ShowProgress("Collecting data types.", i++, cProc); CollectProcedureSignature(proc); foreach (Statement stm in proc.Statements) { if (eventListener.IsCanceled()) { return; } try { this.stmCur = stm; stm.Instruction.Accept(this); } catch (Exception ex) { eventListener.Error( eventListener.CreateStatementNavigator(program, stm), ex, "An error occurred while processing the statement {0}.", stm); } } } }
public void CollectTypes() { desc.MeetDataType(program.Globals, factory.CreatePointer( factory.CreateStructureType(), program.Platform.PointerType.BitSize)); CollectUserGlobalVariableTypes(store.SegmentTypes); int cProc = program.Procedures.Count; int i = 0; foreach (Procedure proc in program.Procedures.Values) { eventListener.ShowProgress("Collecting data types.", i++, cProc); CollectProcedureSignature(proc); foreach (Statement stm in proc.Statements) { if (eventListener.IsCanceled()) { return; } try { this.stmCur = stm; stm.Instruction.Accept(this); } catch (Exception ex) { eventListener.Error( eventListener.CreateStatementNavigator(program, stm), ex, "An error occurred while processing the statement {0}.", stm); } } } }
/// <summary> /// Performs a shingle scan of the executable segments of the program, /// returning the interprocedural control flow graph (ICFG) and locations /// of likely call destinations. /// </summary> /// <returns></returns> public ScanResults ScanNew() { ICodeLocation location = null; Exception error; try { var q = ScanExecutableSegments(); } catch (AddressCorrelatedException aex) { location = eventListener.CreateAddressNavigator(program, aex.Address); error = aex; } catch (Exception ex) { location = new NullCodeLocation(""); error = ex; } if (location != null) { eventListener.Error(location, "An error occurred while scanning {0}."); } return(new ScanResults { ICFG = new DiGraph <RtlBlock>(), DirectlyCalledAddresses = this.sr.DirectlyCalledAddresses, KnownProcedures = sr.KnownProcedures, }); }
private static RekoEventsAPI Evaluate( TextWriter outputWriter, DecompilerEventListener eventListener, IConfigurationService cfgSvc, IFileSystemService fsSvc, string script, string filename) { var engine = CreateEngine(outputWriter); outputWriter.WriteLine($"Evaluating {filename}"); var pythonAPI = new PythonAPI(cfgSvc, fsSvc, engine); var eventsAPI = new RekoEventsAPI(engine); var scope = CreateRekoVariable(engine, pythonAPI, eventsAPI); var src = engine.CreateScriptSourceFromString(script, filename); try { src.Execute(scope); } catch (Exception ex) { var scriptError = CreateError( filename, ex, "An error occurred while evaluating the Python script.", engine); eventListener.Error(scriptError); DumpPythonStack(outputWriter, ex, engine); return(new RekoEventsAPI(engine)); } return(eventsAPI); }
private IPlatform MakePlatform() { string envName; switch (this.hdr.os_type) { case TargetOS.OS2: envName = "os2-32"; break; case TargetOS.Win32: if (hdr.module_flags.HasFlag(ModuleFlags.VirtualDeviceDriver)) { envName = "win-vmm"; } else { envName = "win32"; } break; default: listener.Error($"Unsupported operating environment {this.hdr.os_type}."); return(new DefaultPlatform(this.Services, this.arch)); } var platform = Services.RequireService <IConfigurationService>() .GetEnvironment(envName) .Load(Services, arch); return(platform); }
public void CollectTypes() { desc.MeetDataType(program.Globals, factory.CreatePointer( factory.CreateStructureType(), program.Platform.PointerType.Size)); CollectSegmentTypes(); foreach (Procedure p in program.Procedures.Values) { proc = p; CollectProcedureSignature(p); foreach (Statement stm in p.Statements) { if (eventListener.IsCanceled()) { return; } try { stm.Instruction.Accept(this); } catch (Exception ex) { eventListener.Error( eventListener.CreateStatementNavigator(program, stm), ex, "An error occurred while processing the statement {0}.", stm); } } } }
/// <summary> /// Processes procedures individually, building complex expression /// trees out of the simple, close-to-the-machine code generated by /// the disassembly. /// </summary> /// <param name="rl"></param> public void BuildExpressionTrees() { eventListener.ShowProgress("Building expressions.", 0, program.Procedures.Count); foreach (var sst in this.ssts) { var ssa = sst.SsaState; try { DumpWatchedProcedure("Before expression coalescing", ssa.Procedure); // Procedures should be untangled from each other. Now process // each one separately. DeadCode.Eliminate(ssa); // Build expressions. A definition with a single use can be subsumed // into the using expression. var coa = new Coalescer(ssa); coa.Transform(); DeadCode.Eliminate(ssa); var vp = new ValuePropagator(program.SegmentMap, ssa, program.CallGraph, dynamicLinker, eventListener); vp.Transform(); DumpWatchedProcedure("After expression coalescing", ssa.Procedure); var liv = new LinearInductionVariableFinder( ssa, new BlockDominatorGraph( ssa.Procedure.ControlGraph, ssa.Procedure.EntryBlock)); liv.Find(); foreach (var de in liv.Contexts) { var str = new StrengthReduction(ssa, de.Key, de.Value); str.ClassifyUses(); str.ModifyUses(); } DeadCode.Eliminate(ssa); DumpWatchedProcedure("After strength reduction", ssa.Procedure); // Definitions with multiple uses and variables joined by PHI functions become webs. var web = new WebBuilder(program, ssa, program.InductionVariables, eventListener); web.Transform(); ssa.ConvertBack(false); DumpWatchedProcedure("After data flow analysis", ssa.Procedure); } catch (Exception ex) { eventListener.Error( eventListener.CreateProcedureNavigator(program, ssa.Procedure), ex, "An internal error occurred while building the expressions of {0}", ssa.Procedure.Name); } eventListener.Advance(1); } }
/// <summary> /// Loads the image into memory at the specified address, using the provided /// <seealso cref="IProcessorArchitecture"/> and <seealso cref="IPlatform"/>. /// Used when loading raw files; not all image loaders can support this. /// </summary> /// <param name="addrLoad">Loading address *IGNORED*.</param> /// <param name="arch">Processor architecture.</param> /// <param name="platform">Platform/operating environment.</param> /// <returns> /// A <see cref="Program"/> instance. /// </returns> public override Program Load(Address addrLoad, IProcessorArchitecture arch, IPlatform platform) { listener = Services.RequireService <DecompilerEventListener>(); var memChunks = new MemoryChunksList(); Address addrEp = null; using (var rdr = new IntelHexReader(new MemoryStream(RawImage))) { try { for (; ;) { if (!rdr.TryReadRecord(out uint address, out byte[] data)) { break; } if (data != null) { memChunks.AddData(address, data); continue; } } addrEp = rdr.StartAddress; } catch (IntelHexException ex) { listener.Error(new NullCodeLocation(""), ex.Message); return(null); } } var segs = new SegmentMap(PreferredBaseAddress); // Generate the image segments with fake names. int i = 0; foreach (var mchk in memChunks) { var mem = new MemoryArea(mchk.BaseAddress, mchk.Datum.ToArray()); var seg = new ImageSegment($"CODE_{i++:d2}", mem, AccessMode.ReadExecute); segs.AddSegment(seg); } var prog = new Program() { SegmentMap = segs, Architecture = arch, Platform = platform }; if (addrEp != null) { prog.EntryPoints.Add(addrEp, new Core.ImageSymbol(addrEp) { Type = SymbolType.Procedure }); } return(prog); }
public override void FireEvent(ScriptEvent @event, Program program) { try { var programAPI = new RekoProgramAPI(program); var programWrapper = pythonAPI.CreateProgramWrapper( programAPI); eventsAPI.FireEvent(@event, programWrapper); } catch (Exception ex) { eventListener.Error( new NullCodeLocation(Filename), ex, "An error occurred while running the Python script."); DumpPythonStack(ex, engine); } }
/// <summary> /// Loads the image into memory at the specified address, using the provided /// <seealso cref="IProcessorArchitecture"/> and <seealso cref="IPlatform"/>. /// Used when loading raw files; not all image loaders can support this. /// </summary> /// <param name="addrLoad">Loading address *IGNORED*.</param> /// <param name="arch">Processor architecture.</param> /// <param name="platform">Platform/operating environment.</param> /// <returns> /// A <see cref="Program"/> instance. /// </returns> public override Program LoadProgram(Address addrLoad, IProcessorArchitecture arch, IPlatform platform) { listener = Services.RequireService <DecompilerEventListener>(); var memChunks = new MemoryChunksList(); Address?addrEp = null; Address addrBase = MakeZeroAddress(arch); using (var rdr = new IntelHexReader(new MemoryStream(RawImage), addrBase)) { try { for (; ;) { if (!rdr.TryReadRecord(out Address address, out byte[] data)) { break; } if (data != null) { memChunks.AddData(address, data); continue; } } addrEp = rdr.StartAddress; } catch (IntelHexException ex) { listener.Error(ex.Message); return(null !); } } var segs = new SegmentMap(PreferredBaseAddress); // Generate the image segments with fake names. int i = 0; foreach (var mchk in memChunks) { var mem = arch.CreateMemoryArea(mchk.BaseAddress, mchk.Datum.ToArray()); var seg = new ImageSegment($"CODE_{i:d2}", mem, AccessMode.ReadExecute); ++i; segs.AddSegment(seg); } var program = new Program(segs, arch, platform); if (addrEp != null) { program.EntryPoints.Add(addrEp, ImageSymbol.Procedure(arch, addrEp)); } return(program); }
/// <summary> /// Main entry point of the decompiler. Loads, decompiles, and outputs the results. /// </summary> public void Decompile(string filename) { try { Load(filename); ScanPrograms(); AnalyzeDataFlow(); ReconstructTypes(); StructureProgram(); WriteDecompilerProducts(); } catch (Exception ex) { eventListener.Error( new NullCodeLocation(filename), ex, "An internal error occurred while decompiling."); } finally { eventListener.ShowStatus("Decompilation finished."); } }
private void PopulateImports() { BeImageReader memRdr = new BeImageReader(xexData.memoryData); for (int i = 0; i < xexData.import_records.Count; i++) { UInt32 tableAddress = xexData.import_records[i]; UInt32 memOffset = tableAddress - xexData.exe_address; if (memOffset > xexData.memorySize) { throw new BadImageFormatException($"XEX: invalid import record offset: 0x{memOffset}"); } UInt32 value = memRdr.ReadAt <UInt32>(memOffset, rdr => rdr.ReadUInt32()); XexImportType type = (XexImportType)((value & 0xFF000000) >> 24); byte libIndex = (byte)((value & 0x00FF0000) >> 16); if (type > XexImportType.Function) { decompilerEventListener.Error( $"XEX: Unsupported import type {type}, value: 0x{value:X}"); continue; } if (libIndex >= xexData.libNames.Count) { throw new BadImageFormatException($"XEX: invalid import record lib index ({libIndex}, max:{xexData.libNames.Count})"); } UInt32 importOrdinal = (value & 0xFFFF); string importLibName = xexData.libNames[libIndex]; Address32 importAddress = new Address32(xexData.import_records[i]); SymbolType symbolType = SymbolType.Unknown; switch (type) { case XexImportType.Data: symbolType = SymbolType.Data; break; case XexImportType.Function: symbolType = SymbolType.ExternalProcedure; break; } imports.Add(importAddress, new OrdinalImportReference(importAddress, importLibName, (int)importOrdinal, symbolType)); } }
private bool ProcessLine(string line, int num, MemoryStream loaded) { line = line.TrimEnd(); if (line.Length == 0 || line[0] != ':') { listener.Error(new NullCodeLocation(""), "Line {0} is invalid.", num); return(false); } uint?byteCount = Unhex(line, 1, 2); if (byteCount == null) { // Invalid byte count. listener.Error(new NullCodeLocation(""), "Line {0} is invalid.", num); return(false); } if (line.Length != 1 + 2 * (1 + 2 + 1 + byteCount + 1)) { // Invalid line length listener.Error(new NullCodeLocation(""), "Line {0} is invalid.", num); return(false); } uint?address = Unhex(line, 3, 4); if (address == null) { // Invalid address listener.Error(new NullCodeLocation(""), "Line {0} is invalid.", num); return(false); } uint?recordType = Unhex(line, 7, 2); if (recordType == null) { // Invalid record type listener.Error(new NullCodeLocation(""), "Line {0} is invalid.", num); return(false); } for (int i = 0; i < byteCount; ++i) { uint?b = Unhex(line, 9 + i * 2, 2); if (b == null) { // invalid data listener.Error(new NullCodeLocation(""), "Line {0} is invalid.", num); return(false); } loaded.WriteByte((byte)b); } return(true); }
/// <summary> /// Rewrites indirect call statements to applications using /// user-defined data. Also generates statements that adjust /// the stack pointer according to the calling convention. /// </summary> /// <returns>True if statements were changed.</returns> public bool Rewrite() { changed = false; foreach (Statement stm in proc.Statements.ToList()) { if (stm.Instruction is CallInstruction ci) { try { RewriteCall(stm, ci); } catch (Exception ex) { eventListener.Error( eventListener.CreateStatementNavigator(program, stm), ex, "Indirect call rewriter encountered an error while processing the statement {0}.", stm); } } } return(changed); }
public void Rewrite() { foreach (Statement stm in proc.Statements) { CallInstruction ci = stm.Instruction as CallInstruction; if (ci != null) { try { RewriteCall(stm, ci); throw new NotImplementedException("bleh"); //$DEBUG } catch (Exception ex) { eventListener.Error( eventListener.CreateStatementNavigator(program, stm), ex, "Indirect call rewriter encountered an error while processing the statement {0}.", stm); } } } }
public void Transform() { foreach (var s in ssaIds.ToList()) { sidGrf = s; if (!IsLocallyDefinedFlagGroup(sidGrf)) { continue; } if (sidGrf.DefStatement !.Instruction is AliasAssignment) { continue; } var uses = new HashSet <Statement>(); this.aliases.Clear(); ClosureOfUsingStatements(sidGrf, uses, aliases); trace.Inform("CCE: Tracing {0}", sidGrf.DefStatement.Instruction); foreach (var u in uses) { try { useStm = u; trace.Inform("CCE: used {0}", useStm.Instruction); useStm.Instruction.Accept(this); trace.Inform("CCE: now {0}", useStm.Instruction); } catch (Exception ex) { var loc = listener.CreateStatementNavigator(program, u); listener.Error(loc, ex, "An error occurred while eliminating condition codes in procedure {0}.", ssa.Procedure.Name); } } } }
public override void FireEvent(ScriptEvent @event, Program program) { var eventsAPI = this.eventsAPI; var engine = eventsAPI.Engine; try { var pythonAPI = new PythonAPI(cfgSvc, fsSvc, engine); var programAPI = new RekoProgramAPI(program); var programWrapper = pythonAPI.CreateProgramWrapper( programAPI); eventsAPI.FireEvent(@event, programWrapper); } catch (Exception ex) { var scriptError = CreateError( Location.FilesystemPath, ex, "An error occurred while running the Python script.", engine); eventListener.Error(scriptError); DumpPythonStack(outputWriter, ex, engine); } }
/// <summary> /// Processes procedures individually, building complex expression trees out /// of the simple, close-to-the-machine code generated by the disassembly. /// </summary> /// <param name="rl"></param> public void BuildExpressionTrees() { int i = 0; foreach (Procedure proc in program.Procedures.Values) { eventListener.ShowProgress("Building complex expressions.", i, program.Procedures.Values.Count); ++i; try { var larw = new LongAddRewriter(proc, program.Architecture); larw.Transform(); Aliases alias = new Aliases(proc, program.Architecture, flow); alias.Transform(); var doms = new DominatorGraph <Block>(proc.ControlGraph, proc.EntryBlock); var sst = new SsaTransform(flow, proc, importResolver, doms); var ssa = sst.SsaState; var cce = new ConditionCodeEliminator(ssa.Identifiers, program.Platform); cce.Transform(); //var cd = new ConstDivisionImplementedByMultiplication(ssa); //cd.Transform(); DeadCode.Eliminate(proc, ssa); var vp = new ValuePropagator(program.Architecture, ssa.Identifiers, proc); vp.Transform(); DeadCode.Eliminate(proc, ssa); // Build expressions. A definition with a single use can be subsumed // into the using expression. var coa = new Coalescer(proc, ssa); coa.Transform(); DeadCode.Eliminate(proc, ssa); var liv = new LinearInductionVariableFinder( proc, ssa.Identifiers, new BlockDominatorGraph(proc.ControlGraph, proc.EntryBlock)); liv.Find(); foreach (KeyValuePair <LinearInductionVariable, LinearInductionVariableContext> de in liv.Contexts) { var str = new StrengthReduction(ssa, de.Key, de.Value); str.ClassifyUses(); str.ModifyUses(); } var opt = new OutParameterTransformer(proc, ssa.Identifiers); opt.Transform(); DeadCode.Eliminate(proc, ssa); // Definitions with multiple uses and variables joined by PHI functions become webs. var web = new WebBuilder(proc, ssa.Identifiers, program.InductionVariables); web.Transform(); ssa.ConvertBack(false); } catch (StatementCorrelatedException stex) { eventListener.Error( eventListener.CreateBlockNavigator(program, stex.Statement.Block), stex, "An error occurred during data flow analysis."); } catch (Exception ex) { eventListener.Error( new NullCodeLocation(proc.Name), ex, "An error occurred during data flow analysis."); } } }
public void Error(Address addr, string message, params object[] args) { eventListener.Error(eventListener.CreateAddressNavigator(Program, addr), message, args); }
/// <summary> /// Apply relocations to a segment. /// </summary> private bool ApplyRelocations(EndianImageReader rdr, int cRelocations, NeSegment seg) { Address address = null; NeRelocationEntry rep; Debug.Print("== Relocating segment {0}", seg.Address); for (int i = 0; i < cRelocations; i++) { rep = new NeRelocationEntry { address_type = (NE_RADDR)rdr.ReadByte(), relocation_type = (NE_RELTYPE)rdr.ReadByte(), offset = rdr.ReadLeUInt16(), target1 = rdr.ReadLeUInt16(), target2 = rdr.ReadLeUInt16(), }; Debug.Print(" {0}", WriteRelocationEntry(rep)); // Get the target address corresponding to this entry. // If additive, there is no target chain list. Instead, add source // and target. bool additive = (rep.relocation_type & NE_RELTYPE.ADDITIVE) != 0; Tuple <Address, ImportReference> impRef; uint lp; string module = ""; switch (rep.relocation_type & (NE_RELTYPE)3) { case NE_RELTYPE.ORDINAL: module = moduleNames[rep.target1 - 1]; // Synthesize an import lp = ((uint)rep.target1 << 16) | rep.target2; if (importStubs.TryGetValue(lp, out impRef)) { address = impRef.Item1; } else { address = addrImportStubs; importStubs.Add(lp, new Tuple <Address, ImportReference>( address, new OrdinalImportReference(address, module, rep.target2, SymbolType.ExternalProcedure))); addrImportStubs += 8; } break; case NE_RELTYPE.NAME: module = moduleNames[rep.target1 - 1]; uint offName = lfaNew + this.offImportedNamesTable + rep.target2; var nameRdr = new LeImageReader(RawImage, offName); byte fnNameLength = nameRdr.ReadByte(); var abFnName = nameRdr.ReadBytes(fnNameLength); // Synthesize the import. lp = ((uint)rep.target1 << 16) | rep.target2; if (importStubs.TryGetValue(lp, out impRef)) { address = impRef.Item1; } else { address = addrImportStubs; string fnName = Encoding.ASCII.GetString(abFnName); importStubs.Add(lp, new Tuple <Address, ImportReference>( address, new NamedImportReference(address, module, fnName, SymbolType.ExternalProcedure))); addrImportStubs += 8; } break; case NE_RELTYPE.INTERNAL: if ((rep.target1 & 0xff) == 0xff) { address = this.entryPoints[rep.target2 - 1].Address; } else { address = segments[rep.target1 - 1].Address + rep.target2; } Debug.Print(" {0}: {1:X4}:{2:X4} {3}", i + 1, address.Selector.Value, address.Offset, ""); break; case NE_RELTYPE.OSFIXUP: /* Relocation type 7: * * These appear to be used as fixups for the Windows * floating point emulator. Let's just ignore them and * try to use the hardware floating point. Linux should * successfully emulate the coprocessor if it doesn't * exist. */ /* * TRACE("%d: TYPE %d, OFFSET %04x, TARGET %04x %04x %s\n", * i + 1, rep->relocation_type, rep->offset, * rep->target1, rep->target2, * NE_GetRelocAddrName( rep->address_type, additive ) ); */ continue; } ushort offset = rep.offset; // Apparently, high bit of address_type is sometimes set; // we ignore it for now. if (rep.address_type > NE_RADDR.OFFSET32) { listener.Error( string.Format( "Module {0}: unknown relocation address type {1:X2}. Please report", module, rep.address_type)); return(false); } if (additive) { var sp = seg.Address + offset; Debug.Print(" {0} (contains: {1:X4})", sp, mem.ReadLeUInt16(sp)); byte b; ushort w; switch (rep.address_type & (NE_RADDR)0x7f) { case NE_RADDR.LOWBYTE: b = mem.ReadByte(sp); mem.WriteByte(sp, (byte)(b + address.Offset)); break; case NE_RADDR.OFFSET16: w = mem.ReadLeUInt16(sp); mem.WriteLeUInt16(sp, (ushort)(w + address.Offset)); break; case NE_RADDR.POINTER32: w = mem.ReadLeUInt16(sp); mem.WriteLeUInt16(sp, (ushort)(w + address.Offset)); mem.WriteLeUInt16(sp + 2, address.Selector.Value); break; case NE_RADDR.SELECTOR: // Borland creates additive records with offset zero. Strange, but OK. w = mem.ReadLeUInt16(sp); if (w != 0) { listener.Error(string.Format("Additive selector to {0:X4}. Please report.", w)); } else { mem.WriteLeUInt16(sp, address.Selector.Value); } break; default: goto unknown; } } else { // Non-additive fixup. do { var sp = seg.Address + offset; ushort next_offset = mem.ReadLeUInt16(sp); Debug.Print(" {0} (contains: {1:X4})", sp, next_offset); switch (rep.address_type & (NE_RADDR)0x7f) { case NE_RADDR.LOWBYTE: mem.WriteByte(sp, (byte)address.Offset); break; case NE_RADDR.OFFSET16: mem.WriteLeUInt16(sp, (ushort)address.Offset); break; case NE_RADDR.POINTER32: mem.WriteLeUInt16(sp, (ushort)address.Offset); mem.WriteLeUInt16(sp + 2, address.Selector.Value); break; case NE_RADDR.SELECTOR: mem.WriteLeUInt16(sp, address.Selector.Value); break; default: goto unknown; } if (next_offset == offset) { break; // avoid infinite loop } if (next_offset >= seg.Alloc) { break; } offset = next_offset; } while (offset != 0xffff); } } return(true); unknown: listener.Warn("{0}: unknown ADDR TYPE {1}, " + "TYPE {2}, OFFSET {3:X4}, TARGET {4:X4} {5:X4}", seg.Address.Selector, rep.address_type, rep.relocation_type, rep.offset, rep.target1, rep.target2); return(false); }
public void Error(Address addr, string message) { eventListener.Error(eventListener.CreateAddressNavigator(program, addr), message); }
/// <summary> /// Processes procedures individually, building complex expression /// trees out of the simple, close-to-the-machine code generated by /// the disassembly. /// </summary> /// <param name="rl"></param> public void BuildExpressionTrees() { eventListener.ShowProgress("Building expressions.", 0, program.Procedures.Count); foreach (var sst in this.ssts !) { var ssa = sst.SsaState; try { if (program.User.AggressiveBranchRemoval) { // This ends up being very aggressive and doesn't replicate the original // binary code. See discussion on https://github.com/uxmal/reko/issues/932 DumpWatchedProcedure("urb", "Before unreachable block removal", ssa.Procedure); var urb = new UnreachableBlockRemover(ssa, eventListener); urb.Transform(); } DumpWatchedProcedure("precoa", "Before expression coalescing", ssa.Procedure); // Procedures should be untangled from each other. Now process // each one separately. DeadCode.Eliminate(ssa); // Build expressions. A definition with a single use can be subsumed // into the using expression. var coa = new Coalescer(ssa); coa.Transform(); DeadCode.Eliminate(ssa); var vp = new ValuePropagator(program.SegmentMap, ssa, program.CallGraph, dynamicLinker, eventListener); vp.Transform(); DumpWatchedProcedure("postcoa", "After expression coalescing", ssa.Procedure); var liv = new LinearInductionVariableFinder( ssa, new BlockDominatorGraph( ssa.Procedure.ControlGraph, ssa.Procedure.EntryBlock)); liv.Find(); foreach (var de in liv.Contexts) { var str = new StrengthReduction(ssa, de.Key, de.Value); str.ClassifyUses(); str.ModifyUses(); } DeadCode.Eliminate(ssa); DumpWatchedProcedure("sr", "After strength reduction", ssa.Procedure); // Definitions with multiple uses and variables joined by PHI functions become webs. var web = new WebBuilder(program, ssa, program.InductionVariables, eventListener); web.Transform(); ssa.ConvertBack(false); DumpWatchedProcedure("dfa", "After data flow analysis", ssa.Procedure); } catch (Exception ex) { eventListener.Error( eventListener.CreateProcedureNavigator(program, ssa.Procedure), ex, "An internal error occurred while building the expressions of {0}", ssa.Procedure.Name); } eventListener.Advance(1); } }
/// <summary> /// Processes procedures individually, building complex expression trees out /// of the simple, close-to-the-machine code generated by the disassembly. /// </summary> /// <param name="rl"></param> public void BuildExpressionTrees() { int i = 0; foreach (Procedure proc in program.Procedures.Values) { if (eventListener.IsCanceled()) { break; } eventListener.ShowProgress("Building complex expressions.", i, program.Procedures.Values.Count); ++i; try { var sst = BuildSsaTransform(proc); var ssa = sst.SsaState; var fuser = new UnalignedMemoryAccessFuser(ssa); fuser.Transform(); var vp = new ValuePropagator(program.SegmentMap, ssa, importResolver, eventListener); sst.RenameFrameAccesses = true; var icrw = new IndirectCallRewriter(program, ssa, eventListener); while (!eventListener.IsCanceled() && icrw.Rewrite()) { vp.Transform(); sst.Transform(); } var cce = new ConditionCodeEliminator(ssa, program.Platform); cce.Transform(); //var cd = new ConstDivisionImplementedByMultiplication(ssa); //cd.Transform(); DeadCode.Eliminate(proc, ssa); vp.Transform(); DeadCode.Eliminate(proc, ssa); // Build expressions. A definition with a single use can be subsumed // into the using expression. var coa = new Coalescer(proc, ssa); coa.Transform(); DeadCode.Eliminate(proc, ssa); vp.Transform(); var liv = new LinearInductionVariableFinder( proc, ssa.Identifiers, new BlockDominatorGraph(proc.ControlGraph, proc.EntryBlock)); liv.Find(); foreach (KeyValuePair <LinearInductionVariable, LinearInductionVariableContext> de in liv.Contexts) { var str = new StrengthReduction(ssa, de.Key, de.Value); str.ClassifyUses(); str.ModifyUses(); } var opt = new OutParameterTransformer(proc, ssa.Identifiers); opt.Transform(); DeadCode.Eliminate(proc, ssa); // Definitions with multiple uses and variables joined by PHI functions become webs. var web = new WebBuilder(proc, ssa.Identifiers, program.InductionVariables); web.Transform(); ssa.ConvertBack(false); } catch (StatementCorrelatedException stex) { eventListener.Error( eventListener.CreateStatementNavigator(program, stex.Statement), stex, "An error occurred during data flow analysis."); } catch (Exception ex) { eventListener.Error( new NullCodeLocation(proc.Name), ex, "An error occurred during data flow analysis."); } } }