From d30fefa39b067aa1efd43190c91604905574b9af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?John=20K=C3=A4ll=C3=A9n?= Date: Mon, 5 Dec 2022 12:00:12 +0100 Subject: [PATCH] Feature: Procedure uses types + names of user and symbolic procedures. --- .../Scanning/ProcedureGraphBuilder.cs | 70 ++++++++++++------- .../Scanning/ProcedureGraphBuilderTests.cs | 57 +++++++++++++++ 2 files changed, 102 insertions(+), 25 deletions(-) diff --git a/src/Decompiler/Scanning/ProcedureGraphBuilder.cs b/src/Decompiler/Scanning/ProcedureGraphBuilder.cs index adf507030e..835e0fc121 100644 --- a/src/Decompiler/Scanning/ProcedureGraphBuilder.cs +++ b/src/Decompiler/Scanning/ProcedureGraphBuilder.cs @@ -23,6 +23,8 @@ using Reko.Core.Collections; using Reko.Core.Expressions; using Reko.Core.Rtl; +using Reko.Core.Serialization; +using Reko.Core.Types; using System; using System.Collections.Generic; using System.Diagnostics; @@ -147,47 +149,65 @@ private Procedure CreateEmptyProcedure(RtlProcedure rtlProc) { var addr = rtlProc.Address; var arch = rtlProc.Architecture; - var name = GetProcedureName(rtlProc.Address); - var proc = Procedure.Create(arch, name, addr, arch.CreateFrame()); - return proc; + if (program.User.Procedures.TryGetValue(addr, out var userProc)) + { + var proc = CreateEmptyProcedure(arch, addr, userProc.Name, userProc.Signature, userProc.Characteristics); + return proc; + } + if (program.ImageSymbols.TryGetValue(addr, out var sym)) + { + var proc = CreateEmptyProcedure(sym.Architecture ?? arch, addr, sym.Name, sym.Signature, null); + return proc; + } + else + { + var proc = Procedure.Create(arch, addr, arch.CreateFrame()); + return proc; + } } - private string GetProcedureName(Address addr) + + private Procedure CreateEmptyProcedure( + IProcessorArchitecture arch, + Address addr, + string? name, + SerializedSignature? ssig, + ProcedureCharacteristics? characteristics) { - if (program.User.Procedures.TryGetValue(addr, out var userProc) && - !string.IsNullOrEmpty(userProc.Name)) - { - return userProc.Name; - } - if (program.ImageSymbols.TryGetValue(addr, out var sym) && - !string.IsNullOrEmpty(sym.Name)) + var proc = Procedure.Create(arch, name, addr, arch.CreateFrame()); + if (ssig is not null) { - var sProc = program.Platform.SignatureFromName(sym.Name); - if (sProc?.Name != null) + var sser = program.CreateProcedureSerializer(); + var sig = sser.Deserialize(ssig, proc.Frame); + if (sig is not null) { - return sProc.Name; - } - else - { - return sym.Name; + proc.Signature = sig; } + proc.EnclosingType = ssig.EnclosingType; } - if (program.EntryPoints.TryGetValue(addr, out var ep) && - !string.IsNullOrEmpty(ep.Name)) + else if (!string.IsNullOrEmpty(name)) { - var sProc = program.Platform.SignatureFromName(ep.Name); - if (sProc?.Name != null) + var sProc = program.Platform.SignatureFromName(name); + if (sProc is not null) { - return sProc.Name; + var loader = program.CreateTypeLibraryDeserializer(); + var exp = loader.LoadExternalProcedure(sProc); + if (exp != null) + { + proc.Name = exp!.Name; + proc.Signature = exp.Signature; + proc.EnclosingType = exp.EnclosingType; + } } else { - return ep.Name; + proc.Name = name; } } - return program.NamingPolicy.ProcedureName(addr); + return proc; } + public Instruction VisitAssignment(RtlAssignment ass, Context ctx) { var src = ass.Src.Accept(this, ctx.Procedure); diff --git a/src/UnitTests/Decompiler/Scanning/ProcedureGraphBuilderTests.cs b/src/UnitTests/Decompiler/Scanning/ProcedureGraphBuilderTests.cs index ed15f36c58..db5a4704b8 100644 --- a/src/UnitTests/Decompiler/Scanning/ProcedureGraphBuilderTests.cs +++ b/src/UnitTests/Decompiler/Scanning/ProcedureGraphBuilderTests.cs @@ -23,6 +23,7 @@ using Reko.Core; using Reko.Core.Expressions; using Reko.Core.Rtl; +using Reko.Core.Serialization; using Reko.Core.Types; using Reko.Scanning; using System; @@ -64,6 +65,8 @@ public void Setup() arch.Setup(a => a.CreateFrame()).Returns(MakeFrame); arch.Setup(a => a.Name).Returns("testArch"); arch.Setup(a => a.StackRegister).Returns(new RegisterStorage("sp", 31, 0, PrimitiveType.Ptr32)); + arch.Setup(a => a.MemoryGranularity).Returns(8); + arch.Setup(a => a.PointerType).Returns(PrimitiveType.Ptr32); platform.Setup(p => p.Architecture).Returns(arch.Object); @@ -123,6 +126,19 @@ private void Given_Edge(uint uAddrFrom, uint uAddrTo) succ.Add(addrTo); } + private void Given_UserProcedure(uint uAddr, string name, SerializedSignature ssig) + { + var addr = Address.Ptr32(uAddr); + if (!program.User.Procedures.TryGetValue(addr, out var u)) + { + u = new UserProcedure(addr, program.NamingPolicy.ProcedureName(addr)); + program.User.Procedures.Add(addr, u); + } + u.Name = name; + u.Signature = ssig; + } + + private void RunTest(string sExp) { var pgb = new ProcedureGraphBuilder(sr, program); @@ -407,5 +423,46 @@ define fn00001010 RunTest(sExpected); } + + [Test] + public void Pgb_UserSignature() + { + Given_Block(0x1000, + m => m.Assign(r1, m.Mem32(r2)), + m => m.Return(0, 0)); + Given_Procedure(0x1000); + + Given_UserProcedure(0x1000, "proc", new SerializedSignature + { + EnclosingType = new StructType_v1 { Name="method" }, + ReturnValue = new() { Type = PrimitiveType_v1.Int32() }, + Arguments = new Argument_v1[] + { + new() { Name = "arg", Type = PrimitiveType_v1.Real32() }, + } + }); + + string sExpected = + #region Expected +@" +// proc (00001000) +// method::proc +// Return size: 0 +define method::proc +proc_entry: + sp = fp + // succ: l00001000 +l00001000: + r1 = Mem0[r2:word32] + return + // succ: proc_exit +proc_exit: + +Procedure proc calls: +"; + #endregion + + RunTest(sExpected); + } } }