Skip to content

Commit 99a6fb0

Browse files
committed
#1354: Decompiler example is out of date.
Updated the documentation and provided a method `Decompiler.Create` to simplify the creation of a Reko instance for simple scenarios.
1 parent cb9b4f7 commit 99a6fb0

File tree

4 files changed

+131
-16
lines changed

4 files changed

+131
-16
lines changed

doc/guide/api.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,8 @@ class RandomX86ByteDisassembler
2323
var bytes = new byte[1000];
2424
rnd.NextBytes(bytes);
2525

26-
// Put the bytes in a MemoryArea that Reko can consume.
27-
var mem = new MemoryArea(Address.Ptr32(0x00123400), bytes);
26+
// Put the bytes in a ByteMemoryArea that Reko can consume.
27+
var mem = new ByteMemoryArea(Address.Ptr32(0x00123400), bytes);
2828

2929
// Create an instance of an architecture whose disassembler you wish to use.
3030
var arch = new X86ArchitectureFlat32(new ServiceContainer(), "x86-protected-32");

doc/guide/reko.md

Lines changed: 26 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -36,20 +36,41 @@ If you're comfortable with programming, you can access the Reko object model dir
3636
using Reko;
3737
using Reko.Core;
3838

39-
class DumpProcedures {
39+
public class DumpProcedures {
4040
public static int Main(string [] args) {
41-
var dec = DecompilerDriver.Create();
42-
if (!dec.Load("myfile.exe"))
43-
return -1;
41+
var dec = Reko.Decompiler.Create(args[0], "reko/reko.config");
4442
dec.ScanPrograms();
4543
foreach (var program in dec.Project.Programs) {
4644
foreach (var entry in program.Procedures) {
47-
Console.Write("Address {0}, procedure name {1}", entry.Key, entry.Value);
45+
Console.WriteLine("Address {0}, procedure name {1}", entry.Key, entry.Value);
4846
}
4947
}
48+
return 0;
5049
}
5150
}
5251
```
52+
Now use the following C# project file, calling it, say `procs.csproj`:
53+
```xml
54+
<Project Sdk="Microsoft.NET.Sdk">
55+
56+
<PropertyGroup>
57+
<OutputType>Exe</OutputType>
58+
<TargetFramework>net8.0</TargetFramework>
59+
<ImplicitUsings>enable</ImplicitUsings>
60+
<Nullable>enable</Nullable>
61+
</PropertyGroup>
62+
63+
<ItemGroup>
64+
<PackageReference Include="Reko.Decompiler.Runtime" Version="0.12.0" />
65+
</ItemGroup>
66+
67+
</Project>
68+
```
69+
The following command line will build and run the program on a given
70+
executable file:
71+
```
72+
$ dotnet run procs.csproj test.exe
73+
```
5374

5475
Reko has a rich API you can use for reverse engineering. [Read on for more details](api.md).
5576

src/Decompiler/Decompiler.cs

Lines changed: 103 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -20,19 +20,22 @@
2020
using Reko.Analysis;
2121
using Reko.Core;
2222
using Reko.Core.Collections;
23+
using Reko.Core.Configuration;
2324
using Reko.Core.Graphs;
2425
using Reko.Core.Loading;
2526
using Reko.Core.Output;
2627
using Reko.Core.Scripts;
2728
using Reko.Core.Serialization;
2829
using Reko.Core.Services;
2930
using Reko.Core.Types;
31+
using Reko.Loading;
3032
using Reko.Scanning;
3133
using Reko.Services;
3234
using Reko.Structure;
3335
using Reko.Typing;
3436
using System;
3537
using System.Collections.Generic;
38+
using System.ComponentModel.Design;
3639
using System.IO;
3740
using System.Linq;
3841

@@ -48,6 +51,12 @@ public class Decompiler : IDecompiler
4851
private readonly IDecompilerEventListener eventListener;
4952
private readonly IServiceProvider services;
5053

54+
/// <summary>
55+
/// Creates an instance of the Reko decompiler.
56+
/// </summary>
57+
/// <param name="project">Project to be analyzed.</param>
58+
/// <param name="services"><see cref="IServiceProvider"/> instance
59+
/// providing services. </param>
5160
public Decompiler(Project project, IServiceProvider services)
5261
{
5362
this.project = project;
@@ -57,6 +66,55 @@ public Decompiler(Project project, IServiceProvider services)
5766
BuildImageMaps();
5867
}
5968

69+
/// <summary>
70+
/// Convenience method that creates a new instance of the decompiler, loading a binary
71+
/// file into it.
72+
/// </summary>
73+
/// <remarks>
74+
/// This method is a convenient way to create a new instance of the decompiler,
75+
/// at the cost of flexibility. To attain more flexibility, e.g. the capability
76+
/// to override default load address or loading raw binary files that lack
77+
/// any structure, you must load the binary file separately using the one of the methods on the <see cref="Loader"/> class,
78+
/// and call the constructor of this class with the resulting <see cref="Core.Project"/> instance.
79+
/// </remarks>
80+
/// <param name="filePath">File system path to the binary file or Reko project file to load.</param>
81+
/// <param name="rekoConfigFilePath">File system path to the reko.config file which contains all
82+
/// necessary Reko configuration info.
83+
/// </param>
84+
public static Decompiler Create(string filePath, string rekoConfigFilePath)
85+
{
86+
var services = new ServiceContainer();
87+
var pluginSvc = new PluginLoaderService();
88+
services.AddService<IPluginLoaderService>(pluginSvc);
89+
var fsSvc = new FileSystemService();
90+
services.AddService<IFileSystemService>(fsSvc);
91+
var eventListener = new NullDecompilerEventListener();
92+
services.AddService<IDecompilerEventListener>(eventListener);
93+
services.AddService<IEventListener>(eventListener);
94+
var configSvc = RekoConfigurationService.Load(services, rekoConfigFilePath);
95+
services.AddService<IConfigurationService>(configSvc);
96+
var typelibSvc = new TypeLibraryLoaderServiceImpl(services);
97+
services.AddService<ITypeLibraryLoaderService>(typelibSvc);
98+
var decFileSvc = new DecompiledFileService(services, fsSvc, eventListener);
99+
services.AddService<IDecompiledFileService>(decFileSvc);
100+
101+
var loader = new Loader(services);
102+
var input = loader.Load(ImageLocation.FromUri(filePath));
103+
if (input is not Project project)
104+
{
105+
if (input is not Program program)
106+
throw new InvalidOperationException(
107+
"The input file is not a Reko project or a recognized binary file. " +
108+
"Consider loading the file separately using one of the methods of " +
109+
"Reko.Loading.Loader.");
110+
project = Project.FromSingleProgram(program);
111+
}
112+
return new Decompiler(project, services);
113+
}
114+
115+
/// <summary>
116+
/// The Reko project being analyzed.
117+
/// </summary>
60118
public Project Project { get { return project; } set { project = value; ProjectChanged?.Invoke(this, EventArgs.Empty); } }
61119
public event EventHandler? ProjectChanged;
62120
private Project project;
@@ -114,7 +172,7 @@ public virtual void AnalyzeDataFlow()
114172
}
115173
eventListener.Progress.ShowStatus("Building complex expressions.");
116174
dfa.BuildExpressionTrees(ssas);
117-
host.WriteIntermediateCode(program, (name, procs, writer) => { EmitProgram(program, procs, dfa, name, writer); });
175+
host.WriteIntermediateCode(program, (name, procs, writer) => { EmitProgram(program, procs, dfa, writer); });
118176
}
119177
catch (Exception ex)
120178
{
@@ -128,9 +186,18 @@ public virtual void AnalyzeDataFlow()
128186
eventListener.Progress.ShowStatus("Interprocedural analysis complete.");
129187
}
130188

189+
/// <summary>
190+
/// Writes the disassembly of the program to one or more files.
191+
/// Each segment of the binary program generates one more output files.
192+
/// </summary>
193+
/// <param name="program">Program to disassemble.</param>
194+
/// <param name="segmentItems">A dictionary mapping each <see cref="ImageSegment"/>
195+
/// to a list of <see cref="ImageMapItem"/>s discovered in that segment.
196+
/// </param>
197+
/// <param name="wr">Object responsible for formatting the output files.
198+
/// </param>
131199
public void DumpAssembler(
132200
Program program,
133-
string filename,
134201
Dictionary<ImageSegment, List<ImageMapItem>> segmentItems,
135202
Formatter wr)
136203
{
@@ -152,7 +219,11 @@ public void DumpAssembler(
152219
}
153220
}
154221

155-
private void EmitProgram(Program program, IEnumerable<object> objects, DataFlowAnalysis? dfa, string filename, TextWriter output)
222+
private void EmitProgram(
223+
Program program,
224+
IEnumerable<object> objects,
225+
DataFlowAnalysis? dfa,
226+
TextWriter output)
156227
{
157228
if (output is null)
158229
return;
@@ -196,6 +267,9 @@ private void BuildImageMaps()
196267
}
197268
}
198269

270+
/// <summary>
271+
/// Extracts embedded resources from all programs in the project.
272+
/// </summary>
199273
public void ExtractResources()
200274
{
201275
if (project is null)
@@ -209,6 +283,11 @@ public void ExtractResources()
209283
}
210284
}
211285

286+
/// <summary>
287+
/// Extracts embedded resources from the given program.
288+
/// </summary>
289+
/// <param name="program">Program file from which to extract resources.
290+
/// </param>
212291
public void ExtractResources(Program program)
213292
{
214293
var prg = program.Resources;
@@ -282,8 +361,6 @@ private bool WriteResource(
282361
/// <summary>
283362
/// Extracts type information from the typeless rewritten programs.
284363
/// </summary>
285-
/// <param name="host"></param>
286-
/// <param name="ivs"></param>
287364
public void ReconstructTypes()
288365
{
289366
if (Project is null)
@@ -310,7 +387,19 @@ public void ReconstructTypes()
310387
}
311388
}
312389

313-
public void WriteDecompiledObjects(Program program, string filename, IEnumerable<IAddressable> objects, TextWriter w)
390+
/// <summary>
391+
/// Writes the high-level language decompiled objects to a file.
392+
/// </summary>
393+
/// <param name="program">Program that was decompiled.</param>
394+
/// <param name="filename">The filename of the written file.</param>
395+
/// <param name="objects">Objects that are to be written.</param>
396+
/// <param name="w">Formatter object that converts the object to text.
397+
/// </param>
398+
public void WriteDecompiledObjects(
399+
Program program,
400+
string filename,
401+
IEnumerable<IAddressable> objects,
402+
TextWriter w)
314403
{
315404
WriteHeaderComment(filename, program, w);
316405
//$REFACTOR: common code -- hardwired ".h"
@@ -380,6 +469,12 @@ private static void WriteProcedureCallers(Program program, Procedure proc, TextW
380469
}
381470
}
382471

472+
/// <summary>
473+
/// Writes all detected global variables to a file.
474+
/// </summary>
475+
/// <param name="program">Program whose globals are to be written.</param>
476+
/// <param name="filename">The name of the source file receiving the written globals.</param>
477+
/// <param name="w">Formatting object that converts data globals to text.</param>
383478
public void WriteGlobals(Program program, string filename, TextWriter w)
384479
{
385480
var headerfile = DecompiledFileService.GenerateDerivedFilename(program, ".h");
@@ -515,8 +610,8 @@ private void ScanProgram(Program program)
515610
finally
516611
{
517612
eventListener.Progress.ShowStatus("Writing .asm and .dis files.");
518-
host.WriteDisassembly(program, (n, items, w) => DumpAssembler(program, n, items, w));
519-
host.WriteIntermediateCode(program, (n, procs, w) => EmitProgram(program, procs, null, n, w));
613+
host.WriteDisassembly(program, (n, items, w) => DumpAssembler(program, items, w));
614+
host.WriteIntermediateCode(program, (n, procs, w) => EmitProgram(program, procs, null, w));
520615
// Uncomment the following for debugging.
521616
// WriteSccs(program);
522617
}

src/Gui/Forms/InitialPageInteractor.cs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@
2020

2121
using Reko.Core;
2222
using Reko.Core.Assemblers;
23-
using Reko.Core.Configuration;
2423
using Reko.Core.Loading;
2524
using Reko.Core.Services;
2625
using Reko.Gui.Services;

0 commit comments

Comments
 (0)