Skip to content

Commit

Permalink
Implement usage of debug files within debugger
Browse files Browse the repository at this point in the history
  • Loading branch information
TollyH committed May 18, 2023
1 parent a59d533 commit c944d5c
Show file tree
Hide file tree
Showing 2 changed files with 107 additions and 14 deletions.
83 changes: 72 additions & 11 deletions DebugInfo.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
namespace AssEmbly
using System.Text.RegularExpressions;

namespace AssEmbly
{
public static class DebugInfo
{
Expand All @@ -14,11 +16,33 @@ public static class DebugInfo
{Separator}
";

public static readonly string AssembledInstructionsHeader = $"\n[1]: Assembled Instructions\n{Separator}";
public static readonly string AssembledInstructionsHeader = $"\r\n[1]: Assembled Instructions\r\n{Separator}";

public static readonly string AddressLabelsHeader = $"\r\n[2]: Address Labels\r\n{Separator}";

public static readonly string ResolvedImportsHeader = $"\r\n[3]: Resolved Imports\r\n{Separator}";

public static readonly string AddressLabelsHeader = $"\n[2]: Address Labels\n{Separator}";
public static readonly Regex DebugFileRegex = new(@"AssEmbly Debug Information File
Format Version: (?<Version>.+)
Date: .*
Command Line: .*
Total Program Size: .*
===============================================================================
public static readonly string ResolvedImportsHeader = $"\n[3]: Resolved Imports\n{Separator}";
\[1\]: Assembled Instructions
===============================================================================
(?<Instructions>(?:\r\n|.)+?)
===============================================================================
\[2\]: Address Labels
===============================================================================
(?<Labels>(?:\r\n|.)+?)
===============================================================================
\[3\]: Resolved Imports
===============================================================================
(?:\r\n|.)+?
===============================================================================");

/// <summary>
/// Generates the contents of a debug information file based on the provided parameters.
Expand All @@ -31,31 +55,68 @@ public static class DebugInfo
/// <param name="resolvedImports">An array of imported file names as seen in AssEmbly code along with the full file path to each one</param>
/// <returns>A completely formatted debug info file string ready to be saved.</returns>
public static string GenerateDebugInfoFile(ulong totalProgramSize,
IList<(ulong, string)> assembledInstructions, IList<(ulong, List<string>)> addressLabels, IList<(string, string)> resolvedImports)
IList<(ulong Address, string Line)> assembledInstructions, IList<(ulong Address, List<string> LabelNames)> addressLabels,
IList<(string LocalPath, string FullPath)> resolvedImports)
{
string fileText = string.Format(DebugInfoFileHeader, DateTime.Now, Environment.CommandLine, totalProgramSize);

fileText += AssembledInstructionsHeader;
foreach ((ulong address, string instruction) in assembledInstructions)
{
fileText += $"\n{address:X16} @ {instruction}";
fileText += $"\r\n{address:X16} @ {instruction}";
}

fileText += $"\n{Separator}\n{AddressLabelsHeader}";
fileText += $"\r\n{Separator}\r\n{AddressLabelsHeader}";
foreach ((ulong address, List<string> labels) in addressLabels)
{
fileText += $"\n{address:X16} @ {string.Join(',', labels)}";
fileText += $"\r\n{address:X16} @ {string.Join(',', labels)}";
}

fileText += $"\n{Separator}\n{ResolvedImportsHeader}";
fileText += $"\r\n{Separator}\r\n{ResolvedImportsHeader}";
foreach ((string sourceName, string resolvedName) in resolvedImports)
{
fileText += $"\n\"{sourceName}\" -> \"{resolvedName}\"";
fileText += $"\r\n\"{sourceName}\" -> \"{resolvedName}\"";
}

fileText += '\n' + Separator;
fileText += "\r\n" + Separator;

return fileText;
}

public readonly record struct DebugInfoFile(
Dictionary<ulong, string> AssembledInstructions,
Dictionary<ulong, string[]> AddressLabels);

public static DebugInfoFile ParseDebugInfoFile(string fileText)
{
Match fileMatch = DebugFileRegex.Match(fileText);
if (!fileMatch.Success)
{
throw new FormatException("The provided debug information file was in an invalid format");
}
if (fileMatch.Groups["Version"].Value != FormatVersion)
{
throw new FormatException("The provided debug information file was created for a different version of AssEmbly");
}

List<(ulong Address, string Line)> assembledInstructions = new();
List<(ulong Address, string[] LabelNames)> addressLabels = new();

foreach (string line in fileMatch.Groups["Instructions"].Value.Split('\n'))
{
string[] split = line.Split(" @ ");
assembledInstructions.Add((Convert.ToUInt64(split[0], 16), split[1]));
}

foreach (string line in fileMatch.Groups["Labels"].Value.Split('\n'))
{
string[] split = line.Split(" @ ");
addressLabels.Add((Convert.ToUInt64(split[0], 16), split[1].Split(',')));
}

return new DebugInfoFile(
assembledInstructions.ToDictionary(x => x.Address, x => x.Line),
addressLabels.ToDictionary(x => x.Address, x => x.LabelNames));
}
}
}
38 changes: 35 additions & 3 deletions Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -220,6 +220,25 @@ static void Main(string[] args)
}
}
processor = new(memSize);

DebugInfo.DebugInfoFile? debugInfoFile = null;
if (args.Length >= 3 && !args[2].StartsWith('-'))
{
string debugFilePath = args[2];
try
{
string debugInfoText = File.ReadAllText(debugFilePath);
debugInfoFile = DebugInfo.ParseDebugInfoFile(debugInfoText);
}
catch (Exception exc)
{
Console.ForegroundColor = ConsoleColor.DarkYellow;
Console.WriteLine($"An error occurred whilst loading the debug information file:\n\"{exc.Message}\".\n" +
$"Label names and original source lines will not be available.");
Console.ResetColor();
}
}

try
{
processor.LoadProgram(File.ReadAllBytes(args[1]));
Expand All @@ -230,10 +249,22 @@ static void Main(string[] args)
{
void DisplayDebugInfo()
{
ulong currentAddress = processor.Registers[Data.Register.rpo];
// Disassemble line on-the-fly, unless a provided debugging file provides the original text for the line
string lineDisassembly = debugInfoFile is null
|| !debugInfoFile.Value.AssembledInstructions.TryGetValue(currentAddress, out string? inst)
? Disassembler.DisassembleInstruction(processor.Memory.AsSpan()[(int)currentAddress..]).Line
: inst;

Console.Write($"\n\nAbout to execute instruction:\n ");
Console.WriteLine(Disassembler.DisassembleInstruction(
processor.Memory.AsSpan()[(int)processor.Registers[Data.Register.rpo]..]).Line);
Console.WriteLine(lineDisassembly);
Console.WriteLine();
if (debugInfoFile is not null && debugInfoFile.Value.AddressLabels.TryGetValue(currentAddress, out string[]? labels))
{
Console.Write("This address is referenced by the following labels:\n ");
Console.WriteLine(string.Join("\n ", labels));
Console.WriteLine();
}
Console.WriteLine("Register states:");
foreach ((Data.Register register, ulong value) in processor.Registers)
{
Expand Down Expand Up @@ -678,9 +709,10 @@ void DisplayDebugInfo()
Console.WriteLine(" Memory size will be 2046 bytes if parameter is not given.");
Console.WriteLine();
Console.WriteLine("debug - Step through an assembled bytecode file, pausing before each instruction begins execution.");
Console.WriteLine(" Usage: 'AssEmbly debug <file-path> [--mem-size=2046]'");
Console.WriteLine(" Usage: 'AssEmbly debug <file-path> [debug-info-file-path] [--mem-size=2046]'");
Console.WriteLine(" --mem-size=2046 - Sets the total size of memory available to the program in bytes.");
Console.WriteLine(" Memory size will be 2046 bytes if parameter is not given.");
Console.WriteLine(" Providing a debug info file will allow label names and original AssEmbly source lines to be made available.");
Console.WriteLine();
Console.WriteLine("disassemble - Generate an AssEmbly program listing from already assembled bytecode.");
Console.WriteLine(" Usage: 'AssEmbly disassemble <file-path> [destination-path] [--no-strings|--no-pads]'");
Expand Down

0 comments on commit c944d5c

Please sign in to comment.