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 System; 8 using System.Text; 9 using System.Linq; 10 using System.Collections.Generic; 11 using Antmicro.Renode.Peripherals; 12 using Antmicro.Renode.Peripherals.CPU; 13 14 namespace Antmicro.Renode.Utilities.GDB.Commands 15 { 16 internal class QueryCommand : Command 17 { QueryCommand(CommandsManager manager)18 public QueryCommand(CommandsManager manager) : base(manager) 19 { 20 } 21 22 [Execute("qXfer")] SendQueryXml( [Argument(Separator = B, Encoding = ArgumentAttribute.ArgumentEncoding.String)]string command, [Argument(Separator = B, Encoding = ArgumentAttribute.ArgumentEncoding.String)]string objectType, [Argument(Separator = B, Encoding = ArgumentAttribute.ArgumentEncoding.String)]string operation, [Argument(Separator = B, Encoding = ArgumentAttribute.ArgumentEncoding.String)]string annex, [Argument(Separator = B, Encoding = ArgumentAttribute.ArgumentEncoding.HexNumber)]int offset, [Argument(Encoding = ArgumentAttribute.ArgumentEncoding.HexNumber)]int length )23 public PacketData SendQueryXml( 24 [Argument(Separator = ':', Encoding = ArgumentAttribute.ArgumentEncoding.String)]string command, 25 [Argument(Separator = ':', Encoding = ArgumentAttribute.ArgumentEncoding.String)]string objectType, 26 [Argument(Separator = ':', Encoding = ArgumentAttribute.ArgumentEncoding.String)]string operation, 27 [Argument(Separator = ':', Encoding = ArgumentAttribute.ArgumentEncoding.String)]string annex, 28 [Argument(Separator = ',', Encoding = ArgumentAttribute.ArgumentEncoding.HexNumber)]int offset, 29 [Argument(Encoding = ArgumentAttribute.ArgumentEncoding.HexNumber)]int length 30 ) 31 { 32 if((objectType != "features" && objectType != "threads") || operation != "read") 33 { 34 return PacketData.Empty; 35 } 36 if(objectType == "features" && annex != "target.xml") 37 { 38 return PacketData.ErrorReply(); 39 } 40 var xmlFile = new StringBuilder(); 41 if(objectType == "features") 42 { 43 xmlFile.Append("<?xml version=\"1.0\"?>\n<!DOCTYPE feature SYSTEM \"gdb-target.dtd\">\n<target version=\"1.0\">\n"); 44 xmlFile.Append($"<architecture>{manager.Cpu.GDBArchitecture}</architecture>\n"); 45 foreach(var feature in manager.GetCompiledFeatures()) 46 { 47 AppendFeature(ref xmlFile, feature); 48 } 49 xmlFile.Append("</target>\n"); 50 } 51 else if(objectType == "threads") 52 { 53 xmlFile.Append("<?xml version=\"1.0\"?>\n<threads>\n"); 54 foreach(var gdbCpuId in manager.ManagedCpus.GdbCpuIds) 55 { 56 xmlFile.Append($"<thread id=\"{gdbCpuId:x}\" core=\"{gdbCpuId - 1}\" name=\"{manager.ManagedCpus[gdbCpuId].GetName()}\"></thread>\n"); 57 } 58 xmlFile.Append("</threads>\n"); 59 } 60 61 var prefix = offset + length >= xmlFile.Length ? "l" : "m"; 62 var xmlSubstring = xmlFile.ToString().Substring(offset, Math.Min(length, xmlFile.Length - offset)); 63 return new PacketData(prefix + xmlSubstring); 64 } 65 AppendFeature(ref StringBuilder xmlFile, GDBFeatureDescriptor feature)66 private static void AppendFeature(ref StringBuilder xmlFile, GDBFeatureDescriptor feature) 67 { 68 xmlFile.Append($"<feature name=\"{feature.Name}\">\n"); 69 foreach(var type in feature.Types) 70 { 71 if(type.Fields?.Any() ?? false) 72 { 73 var tagName = type.Type == "enum" ? "evalue" : "field"; 74 AppendTag(ref xmlFile, type.Type, type.Attributes, false); 75 foreach(var field in type.Fields) 76 { 77 AppendTag(ref xmlFile, tagName, field); 78 79 } 80 xmlFile.Append($"</{type.Type}>\n"); 81 } 82 else 83 { 84 AppendTag(ref xmlFile, type.Type, type.Attributes); 85 } 86 } 87 foreach(var register in feature.Registers) 88 { 89 xmlFile.Append($"<reg name=\"{register.Name}\" bitsize=\"{register.Size}\" regnum=\"{register.Number}\" "); 90 if(!String.IsNullOrEmpty(register.Type)) 91 { 92 xmlFile.Append($"type=\"{register.Type}\" "); 93 } 94 if(!String.IsNullOrEmpty(register.Group)) 95 { 96 xmlFile.Append($"group=\"{register.Group}\" "); 97 } 98 xmlFile.Append("/>\n"); 99 } 100 xmlFile.Append("</feature>\n"); 101 } 102 AppendTag(ref StringBuilder xmlFile, string name, IReadOnlyDictionary<string, string> attributes, bool closed = true)103 private static void AppendTag(ref StringBuilder xmlFile, string name, IReadOnlyDictionary<string, string> attributes, bool closed = true) 104 { 105 xmlFile.Append($"<{name}"); 106 foreach(var pair in attributes) 107 { 108 xmlFile.Append($" {pair.Key}=\"{pair.Value}\""); 109 } 110 xmlFile.Append(closed ? "/>\n" : ">\n"); 111 } 112 } 113 } 114 115