Skip to content

Commit

Permalink
Feature: display the currently selected address range in the status b…
Browse files Browse the repository at this point in the history
…ar (#1232)
  • Loading branch information
uxmal committed Jan 20, 2023
1 parent 1908ab5 commit 040dd1a
Show file tree
Hide file tree
Showing 20 changed files with 372 additions and 98 deletions.
159 changes: 159 additions & 0 deletions src/Core/ProgramAddressRange.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,159 @@
#region License
/*
* Copyright (C) 1999-2023 John Källén.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#endregion

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Reko.Core
{
/// <summary>
/// Represents a range of addresses inside the address space of a <see cref="Program"/>.
/// </summary>
public class ProgramAddressRange
{
private ProgramAddressRange(Program program, Address address, long length)
{
this.Program = program;
this.Address = address;
this.Length = length;
}

public static ProgramAddressRange Create(Program program, AddressRange range)
{
return ProgramAddressRange.HalfOpenRange(program, range.Begin, range.End);
}

public static ProgramAddressRange Create(Program program, Address address, long length)
{
return new ProgramAddressRange(program, address, length);
}

public static ProgramAddressRange Empty(Program program, Address address)
{
return new ProgramAddressRange(program, address, 0);
}

/// <summary>
/// Creates a half open range from two <see cref="Address"/>es. The addresses
/// can be passed in any order; the lowest address will become the start of
/// the range. The result will represent either the range [addr1-addr2) or
/// [addr2-addr1), depending the order of the addresses.
/// </summary>
/// <param name="program"><see cref="Program"/> instance.</param>
/// <param name="addr1">One address.</param>
/// <param name="addr2">Second address.</param>
/// <returns>A <see cref="ProgramAddressRange"/> instance which treats the
/// addresses as a half open range.</returns>
public static ProgramAddressRange HalfOpenRange(Program program, Address addr1, Address addr2)
{
long length = addr2 - addr1;
if (length >= 0)
{
return new ProgramAddressRange(program, addr1, length);
}
else
{
return new ProgramAddressRange(program, addr2, -length);
}
}

/// <summary>
/// Creates a closed range from two <see cref="Address"/>es. The addresses
/// can be passed in any order; the lowest address will become the start of
/// the range. The result will represent either the range [addr1-addr2] or
/// [addr2-addr1], depending the order of the addresses.
/// </summary>
/// <param name="program"><see cref="Program"/> instance.</param>
/// <param name="addr1">One address.</param>
/// <param name="addr2">Second address.</param>
/// <returns>A <see cref="ProgramAddressRange"/> instance which treats the
/// addresses as a closed range.</returns>
public static ProgramAddressRange ClosedRange(Program program, Address addr1, Address addr2)
{
long length = 1 + (addr2 - addr1);
if (length >= 0)
{
return new ProgramAddressRange(program, addr1, length);
}
else
{
return new ProgramAddressRange(program, addr2, 2 - length);
}
}

/// <summary>
/// The <see cref="Program"/> instance inside whose address space contains
/// the <see cref="Address"/> property.
/// </summary>
public Program Program { get; }

/// <summary>
/// The starting address of the range.
/// </summary>
public Address Address { get; }

/// <summary>
/// The length of the range. A value of 0 indicates an empty range.
/// </summary>
//$REVIEW: We cannot represent ranges longer that 2^63-1. Will this
// be a problem? Even with ulong, we cannot represent the range
// corresponding to a full 64-bit address space without using BigInteger.
public long Length { get; }

public override bool Equals(object? obj)
{
if (obj is not ProgramAddressRange that)
return false;
return this == that;
}

public override int GetHashCode()
{
return HashCode.Combine(this.Program, this.Address, this.Length);
}

public static bool operator==(ProgramAddressRange left, ProgramAddressRange right)
{
return
left.Program == right.Program &&
left.Length == right.Length &&
left.Address == right.Address;
}

public static bool operator !=(ProgramAddressRange left, ProgramAddressRange right) =>
!(left == right);


public override string ToString()
{
if (Length > 1)
{
return $"{Program.Name}: {Address} ({Length})";
}
else
{
return $"{Program.Name}: {Address}";
}
}
}
}
18 changes: 9 additions & 9 deletions src/Gui/Forms/MainFormInteractor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -154,9 +154,6 @@ private void CreateServices(IServiceFactory svcFactory, IServiceContainer sc)
var cmdFactory = new Commands.CommandFactory(sc);
sc.AddService<ICommandFactory>(cmdFactory);

var sbSvc = svcFactory.CreateStatusBarService();
sc.AddService<IStatusBarService>(sbSvc);

diagnosticsSvc = svcFactory.CreateDiagnosticsService();
sc.AddService(typeof(IDiagnosticsService), diagnosticsSvc);

Expand All @@ -165,6 +162,12 @@ private void CreateServices(IServiceFactory svcFactory, IServiceContainer sc)

sc.AddService(typeof(IDecompilerUIService), uiSvc);

var selSvc = svcFactory.CreateSelectionService();
sc.AddService<ISelectionService>(selSvc);

var selAddrSvc = svcFactory.CreateSelectedAddressService();
sc.AddService<ISelectedAddressService>(selAddrSvc);

var codeViewSvc = svcFactory.CreateCodeViewerService();
sc.AddService<ICodeViewerService>(codeViewSvc);

Expand All @@ -174,6 +177,9 @@ private void CreateServices(IServiceFactory svcFactory, IServiceContainer sc)
var segmentViewSvc = svcFactory.CreateImageSegmentService();
sc.AddService(typeof(ImageSegmentService), segmentViewSvc);

var sbSvc = svcFactory.CreateStatusBarService(selAddrSvc);
sc.AddService<IStatusBarService>(sbSvc);

var del = svcFactory.CreateDecompilerEventListener();
workerDlgSvc = (IWorkerDialogService)del;
sc.AddService(typeof(IWorkerDialogService), workerDlgSvc);
Expand Down Expand Up @@ -223,12 +229,6 @@ private void CreateServices(IServiceFactory svcFactory, IServiceContainer sc)
var symLdrSvc = svcFactory.CreateSymbolLoadingService();
sc.AddService<ISymbolLoadingService>(symLdrSvc);

var selSvc = svcFactory.CreateSelectionService();
sc.AddService<ISelectionService>(selSvc);

var selAddrSvc = svcFactory.CreateSelectedAddressService();
sc.AddService<ISelectedAddressService>(selAddrSvc);

var testGenSvc = svcFactory.CreateTestGenerationService();
sc.AddService<ITestGenerationService>(testGenSvc);

Expand Down
2 changes: 1 addition & 1 deletion src/Gui/IServiceFactory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ public interface IServiceFactory
IUiPreferencesService CreateUiPreferencesService();
ILoader CreateLoader();
ICallGraphViewService CreateCallGraphViewService();
IStatusBarService CreateStatusBarService();
IStatusBarService CreateStatusBarService(ISelectedAddressService selAddrSvc);
IViewImportsService CreateViewImportService();
ISymbolLoadingService CreateSymbolLoadingService();
ISelectionService CreateSelectionService();
Expand Down
34 changes: 14 additions & 20 deletions src/Gui/SelectedAddressService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -33,35 +33,29 @@ public class SelectedAddressService : ISelectedAddressService
public event EventHandler? SelectedAddressChanged;


private Address? address;
private ProgramAddressRange? addressRange;
private long length;

public SelectedAddressService()
{
}

public Address? SelectedAddress
public ProgramAddressRange? SelectedAddressRange
{
get => address;
get => addressRange;
set
{
if (object.Equals(this.address, value))
return;
this.address = value;
SelectedAddressChanged?.Invoke(this, EventArgs.Empty);
}
}

public long Length
{
get => length;
set
{
if (value < 0)
throw new ArgumentOutOfRangeException();
if (this.length == value)
return;
this.length = value;
if (addressRange is null)
{
if (value is null)
return;
}
else
{
if (value is not null && addressRange == value)
return;
}
this.addressRange = value;
SelectedAddressChanged?.Invoke(this, EventArgs.Empty);
}
}
Expand Down
12 changes: 4 additions & 8 deletions src/Gui/Services/ISelectedAddressService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -40,15 +40,11 @@ public interface ISelectedAddressService

/// <summary>
/// If not null, indicates the address the user has
/// selected.
/// </summary>
public Address? SelectedAddress { get; set; }

/// <summary>
/// Indicates the length of the selection the user has
/// made. A length of 0 indicates that only the address
/// selected. The property value is the currently selected
/// <see cref="ProgramAddressRange"/>.
/// A length of 0 indicates that only the address
/// has been selected, not a range of bytes.
/// </summary>
public long Length { get; }
public ProgramAddressRange? SelectedAddressRange { get; set; }
}
}
53 changes: 53 additions & 0 deletions src/Gui/Services/StatusBarService.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
#region License
/*
* Copyright (C) 1999-2023 John Källén.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#endregion

using Reko.Core;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Reko.Gui.Services
{
public abstract class StatusBarService : IStatusBarService
{
public abstract void HideProgress();
public abstract void SetSubtext(string v);
public abstract void SetText(string text);
public abstract void ShowProgress(int percentDone);

protected string RenderAddressSelection(ProgramAddressRange range)
{
if (range is null)
return "";
var numbase = range.Program.Architecture.DefaultBase;
if (range.Length > 1)
{
return $"{range.Address} (length {Convert.ToString(range.Length, numbase)})";
}
else
{
return range.Address.ToString();
}
}

}
}
4 changes: 0 additions & 4 deletions src/UnitTests/Mocks/FakeArchitecture.cs
Original file line number Diff line number Diff line change
Expand Up @@ -469,10 +469,6 @@ public override bool TryParseAddress(string txtAddr, out Address addr)
}
}

public class MockMachineRegister : RegisterStorage
{
public MockMachineRegister(string name, int i, PrimitiveType dt) : base(name, i, 0, dt) { }
}

public class FakeProcessorState : ProcessorState
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -190,11 +190,11 @@ public IStackTraceService CreateStackTraceService()
return new AvaloniaStackTraceService(services);
}

public IStatusBarService CreateStatusBarService()
public IStatusBarService CreateStatusBarService(ISelectedAddressService selAddrSvc)
{
if (this.mainViewModel.Status is null)
{
mainViewModel.Status = new AvaloniaStatusBarService();
mainViewModel.Status = new AvaloniaStatusBarService(selAddrSvc);
}
return this.mainViewModel.Status;
}
Expand Down
Loading

0 comments on commit 040dd1a

Please sign in to comment.