1 //
2 // Copyright (c) 2010-2024 Antmicro
3 //
4 // This file is licensed under the MIT License.
5 // Full license text is available in 'licenses/MIT.txt'.
6 //
7 using Antmicro.Renode.Core;
8 using Antmicro.Renode.UserInterface;
9 using ELFSharp.ELF;
10 using System.Text;
11 using System.Linq;
12 using System.Collections.Generic;
13 
14 namespace Antmicro.Renode.Utilities.GDB.Commands
15 {
16     internal class MonitorCommand : Command
17     {
MonitorCommand(CommandsManager m)18         public MonitorCommand(CommandsManager m) : base(m)
19         {
20             openOcdOverlay = new OpenOcdOverlay(m);
21         }
22 
23         [Execute("qRcmd,")]
Run([Argument(Encoding = ArgumentAttribute.ArgumentEncoding.HexString)]string arg)24         public IEnumerable<PacketData> Run([Argument(Encoding = ArgumentAttribute.ArgumentEncoding.HexString)]string arg)
25         {
26             if(!openOcdOverlay.TryProcess(arg, out var result, out var ok))
27             {
28                 var monitor = ObjectCreator.Instance.GetSurrogate<Monitor>();
29                 var eater = new CommandInteractionEater();
30                 monitor.Parse(arg, eater);
31                 result = eater.HasError
32                     ? eater.GetError()
33                     : eater.GetContents();
34             }
35 
36             var consoleOutput = string.IsNullOrEmpty(result) ? null : string.Join(string.Empty, Encoding.UTF8.GetBytes(result).Select(x => x.ToString("X2")).Prepend("O"));
37             var resultReply = ok ? PacketData.Success : PacketData.ErrorReply();
38             if(consoleOutput != null)
39             {
40                 return new [] { new PacketData(consoleOutput), resultReply };
41             }
42             return new [] { resultReply };
43         }
44 
45         private readonly OpenOcdOverlay openOcdOverlay;
46 
47         private class OpenOcdOverlay
48         {
OpenOcdOverlay(CommandsManager manager)49             public OpenOcdOverlay(CommandsManager manager)
50             {
51                 this.manager = manager;
52             }
53 
54             /// <param name="output">The output generated by the command, if successful; otherwise null.</param>
55             /// <param name="ok">Whether the command completed successfully.</param>
56             /// <returns>true if the command exists; otherwise false.</returns>
TryProcess(string input, out string output, out bool ok)57             public bool TryProcess(string input, out string output, out bool ok)
58             {
59                 output = null;
60                 ok = true;
61 
62                 var argv = input.Split(new [] { ' ' });
63                 switch(argv.FirstOrDefault())
64                 {
65                 case "reset":
66                     if(argv.ElementAtOrDefault(1) != "init")
67                     {
68                         ok = false;
69                         return true;
70                     }
71                     manager.Machine.Pause();
72                     manager.Machine.Reset();
73                     break;
74                 case "halt":
75                     manager.Machine.Pause();
76                     break;
77                 case "reg":
78                     var inputBuilder = new StringBuilder("=====\n");
79                     foreach(var i in manager.Cpu.GetRegisters().Where(x => x.IsGeneral).Select(x => x.Index))
80                     {
81                         inputBuilder.AppendFormat("({0}) r{0} (/32): 0x", i);
82                         var value = manager.Cpu.GetRegister(i);
83                         // We always use big-endian GetBytes because we want 0x12345678 to become [0x12, 0x34, 0x56, 0x78]
84                         // GetBytes also returns an array of the right length and appropriately padded with zeros.
85                         foreach(var b in value.GetBytes(Endianess.BigEndian))
86                         {
87                             inputBuilder.AppendFormat("{0:x2}", b);
88                         }
89                         inputBuilder.Append("\n");
90                     }
91                     output = inputBuilder.ToString();
92                     break;
93                 default:
94                     return false;
95                 }
96                 return true;
97             }
98 
99             private readonly CommandsManager manager;
100         }
101     }
102 }
103 
104