1 // 2 // Copyright (c) 2010-2023 Antmicro 3 // Copyright (c) 2011-2015 Realtime Embedded 4 // 5 // This file is licensed under the MIT License. 6 // Full license text is available in 'licenses/MIT.txt'. 7 // 8 using System.Collections.Generic; 9 using ELFSharp.ELF.Sections; 10 using Antmicro.Renode.Utilities.Collections; 11 using System; 12 using Antmicro.Renode.Utilities; 13 using Antmicro.Migrant; 14 using Antmicro.Renode.Logging; 15 using Antmicro.Renode.Peripherals.Bus; 16 using CxxDemangler; 17 18 namespace Antmicro.Renode.Core 19 { 20 /// <summary> 21 /// Class representing a Symbol in memory. The symbol represtented spans from Start inclusive, till End exclusive. 22 /// A symbol of zero length is considered to occupy Start. So a symbol (Start, End) does contain (Start, Start). 23 /// Symbols have optional Name, and can be marked as Thumb symbols (in ARM architecture). 24 /// </summary> 25 public class Symbol : IInterval<SymbolAddress>, IEquatable<Symbol> 26 { 27 /// <summary> 28 /// Static constructor initializing the demangling mechanisms. 29 /// </summary> Symbol()30 static Symbol() 31 { 32 } 33 34 /// <summary> 35 /// Allows casting from SymbolEntry to Symbol. <seealso cref="Symbol(SymbolEntry, bool)"/>. 36 /// </summary> operator Symbol(SymbolEntry<uint> originalSymbol)37 public static implicit operator Symbol(SymbolEntry<uint> originalSymbol) 38 { 39 return new Symbol(originalSymbol); 40 } 41 42 /// <summary> 43 /// Allows casting from SymbolEntry to Symbol. <seealso cref="Symbol(SymbolEntry, bool)"/>. 44 /// </summary> operator Symbol(SymbolEntry<ulong> originalSymbol)45 public static implicit operator Symbol(SymbolEntry<ulong> originalSymbol) 46 { 47 return new Symbol(originalSymbol); 48 } 49 50 /// <summary> 51 /// Demangles the symbol name using the CxxDemangler library. 52 /// </summary> 53 /// <returns>Demangled symbol name.</returns> DemangleSymbol(string symbolName)54 public static string DemangleSymbol(string symbolName) 55 { 56 const int globalSymbolPrefixLength = 21; 57 if(string.IsNullOrEmpty(symbolName) || symbolName.Length < 2) 58 { 59 return symbolName; 60 } 61 //length check for the sake of Substring 62 if(symbolName.Length > globalSymbolPrefixLength && symbolName.StartsWith("_GLOBAL__sub_I", StringComparison.Ordinal)) 63 { 64 return string.Format("static initializers for {0}", DemangleSymbol(symbolName.Substring(globalSymbolPrefixLength))); 65 } 66 if(symbolName.Substring(0, 2) != "_Z") 67 { 68 return symbolName; 69 } 70 71 var result = CxxDemangler.CxxDemangler.Demangle(symbolName); 72 73 if(result.Length == 0) 74 { 75 return symbolName; 76 } 77 var substringIndex = result.LastIndexOf('('); 78 if(substringIndex != -1) 79 { 80 result = result.Substring(0, substringIndex); 81 } 82 return result; 83 } 84 Symbol(SymbolAddress start, SymbolAddress end)85 public Symbol(SymbolAddress start, SymbolAddress end) 86 { 87 Start = start; 88 End = end; 89 } 90 91 /// <summary> 92 /// Initializes a new instance of the <see cref="Antmicro.Renode.Core.Symbol"/> class. 93 /// </summary> 94 /// <param name="start">Start.</param> 95 /// <param name="end">End.</param> 96 /// <param name="name">Name.</param> 97 /// <param name="type">SymbolType.</param> 98 /// <param name="binding">SymbolBinding.</param> 99 /// <param name="mayBeThumb">Set to <c>true</c> if symbol is related to architecture that allows thumb symbols.</param> Symbol(SymbolAddress start, SymbolAddress end, string name, SymbolType type = SymbolType.NotSpecified, SymbolBinding binding = SymbolBinding.Global, bool mayBeThumb = false)100 public Symbol(SymbolAddress start, SymbolAddress end, string name, SymbolType type = SymbolType.NotSpecified, SymbolBinding binding = SymbolBinding.Global, bool mayBeThumb = false) 101 { 102 if(end < start) 103 { 104 throw new ArgumentException(string.Format("Symbol cannot have start before the end. Input was: ({0},{1})", start, end)); 105 } 106 Type = type; 107 Binding = binding; 108 Name = DemangleSymbol(name); 109 Start = start; 110 End = end; 111 thumbArchitecture = mayBeThumb; 112 if(mayBeThumb) 113 { 114 UpdateIsThumbSymbol(); 115 } 116 } 117 118 /// <summary> 119 /// Initializes a new instance of the <see cref="Antmicro.Renode.Core.Symbol"/> class. 120 /// </summary> 121 /// <param name="originalSymbol">Original symbol.</param> 122 /// <param name="mayBeThumb">Set to <c>true</c> if symbol is related to architecture that allows thumb symbols.</param> Symbol(ISymbolEntry originalSymbol, bool mayBeThumb = false)123 public Symbol(ISymbolEntry originalSymbol, bool mayBeThumb = false) 124 { 125 Start = originalSymbol.GetValue(); 126 IsThumbSymbol = false; 127 thumbArchitecture = mayBeThumb; 128 if(mayBeThumb) 129 { 130 UpdateIsThumbSymbol(); 131 } 132 End = Start + originalSymbol.GetSize(); 133 Name = DemangleSymbol(originalSymbol.Name); 134 Type = originalSymbol.Type; 135 Binding = originalSymbol.Binding; 136 } 137 138 /// <summary> 139 /// Gets the copy of symbol with changed end of the interval. 140 /// If the requested end is before start, the trial fails. 141 /// If the symbol would not have to be changed, i.e. requested the original reference is returned and trial succeeds. 142 /// Otherwise a truncated copy of symbol is returned and trial succeeds. 143 /// </summary> 144 /// <returns>true if trimming returned a proper symbol, false otherwise.</returns> 145 /// <param name="end">New end.</param> 146 /// <param name = "trimmedSymbol">Trimmed symbol.</param> TryGetRightTrimmed(SymbolAddress end, out Symbol trimmedSymbol)147 public bool TryGetRightTrimmed(SymbolAddress end, out Symbol trimmedSymbol) 148 { 149 trimmedSymbol = null; 150 if(end < Start) 151 { 152 return false; 153 } 154 trimmedSymbol = End < end ? this : GetTrimmedCopy(Start, end); 155 return true; 156 } 157 158 /// <summary> 159 /// Gets the copy of symbol with start of the interval changed to 1st legal address equal or larger than given start. 160 /// Trimming from left ensures that the new symbol does not occupy space before new start. 161 /// If the requested start is after end, the trial fails. 162 /// If the symbol would not have to be changed, i.e. requested the original reference is returned and trial succeeds. 163 /// Otherwise a truncated copy of symbol is returned and trial succeeds. 164 /// 165 /// NOTE: If you create a new thumb symbol with interval (13,15), the acutal interval used will be (12,15); 166 /// However, if you trim this symbol from left to the same start value (12,15).LeftTrim(13), the result will be (14,15). 167 /// </summary> 168 /// <returns>true if trimming returned a proper symbol, false otherwise.</returns> 169 /// <param name = "start">New start.</param> 170 /// <param name = "trimmedSymbol">Trimmed symbol</param> TryGetLeftTrimmed(SymbolAddress start, out Symbol trimmedSymbol)171 public bool TryGetLeftTrimmed(SymbolAddress start, out Symbol trimmedSymbol) 172 { 173 trimmedSymbol = null; 174 if(End < start) 175 { 176 return false; 177 } 178 //if symbol is in thumb architecture and new start is odd, move it to the next legal address 179 if(thumbArchitecture && (start % 2) != 0) 180 { 181 start += 1; 182 } 183 trimmedSymbol = Start >= start ? this : GetTrimmedCopy(start, End); 184 return true; 185 } 186 187 /// <summary> 188 /// Determines whether this instance is more important than the specified argument. 189 /// Two factors are taken into consideration: the Type of the symbol and, if symbol 190 /// types are equal, the Binding of the symbol. For example, Function symbol is more 191 /// important than Object symbol, and Global Function symbol is more important than 192 /// Weak Function symbol. 193 /// As the symbol types may be architecture specific, we only take into consideration 194 /// those types that we are aware of. 195 /// </summary> 196 /// <returns><c>true</c> if this instance is more important than the specified second; otherwise, <c>false</c>.</returns> 197 /// <param name="second">Symbol to compare with.</param> IsMoreImportantThan(Symbol second)198 public bool IsMoreImportantThan(Symbol second) 199 { 200 if(string.IsNullOrWhiteSpace(Name) || !Enum.IsDefined(typeof(SymbolType), Type)) 201 { 202 return false; 203 } 204 if(string.IsNullOrWhiteSpace(second.Name) || !Enum.IsDefined(typeof(SymbolType), second.Type)) 205 { 206 return true; 207 } 208 return (Type == second.Type 209 && (BindingImportance[Binding] - BindingImportance[second.Binding]) > 0) 210 || ((TypeImportance[Type] - TypeImportance[second.Type]) > 0); 211 } 212 Contains(SymbolAddress x)213 public bool Contains(SymbolAddress x) 214 { 215 return Start == x || (Start < x && End > x); 216 } 217 Contains(IInterval<SymbolAddress> other)218 public bool Contains(IInterval<SymbolAddress> other) 219 { 220 return Start <= other.Start && End >= other.End && End > other.Start; 221 } 222 223 /// <summary> 224 /// Checks if two symbols overlap. 225 /// </summary> 226 /// <param name="other">Other.</param> Overlaps(IInterval<SymbolAddress> other)227 public bool Overlaps(IInterval<SymbolAddress> other) 228 { 229 return Contains(other.Start) || other.Contains(Start); 230 } 231 Equals(Symbol other)232 public bool Equals(Symbol other) 233 { 234 return intervalComparer.Compare(this, other) == 0 && string.Compare(Name, other.Name, StringComparison.Ordinal) == 0; 235 } 236 ToStringRelative(SymbolAddress offset)237 public string ToStringRelative(SymbolAddress offset) 238 { 239 if(string.IsNullOrWhiteSpace(this.Name)) 240 { 241 return String.Empty; 242 } 243 if(this.Start == offset) 244 { 245 return "{0} (entry)".FormatWith(this.Name); 246 } 247 if(this.End == this.Start && offset != this.Start) 248 { 249 return "{0}+0x{1:X} (guessed)".FormatWith(this.Name, offset.RawValue - this.Start.RawValue); 250 } 251 return this.Name; 252 } 253 ToString()254 public override string ToString() 255 { 256 return Name ?? string.Empty; 257 } 258 259 public SymbolAddress Start { get; private set; } 260 261 /// <summary> 262 /// Closing bound of the symbol. Remeber the closing bound is exclusive, not inclusive, for non-zero-length symbols. 263 /// </summary> 264 /// <value> 265 /// First address after the symbol. 266 /// </value> 267 public SymbolAddress End { get; private set; } 268 269 public SymbolAddress Length { get { return End - Start; } } 270 public string Name { get; private set; } 271 public SymbolType Type { get; private set; } 272 public SymbolBinding Binding { get; private set; } 273 public bool IsThumbSymbol { get; private set; } 274 275 public bool IsLabel => 276 Type != SymbolType.Function && 277 (Binding == SymbolBinding.Local || Binding == SymbolBinding.Weak) && 278 Length == 0; 279 UpdateIsThumbSymbol()280 private void UpdateIsThumbSymbol() 281 { 282 IsThumbSymbol = (Start & 0x1) != 0; 283 Start -= (IsThumbSymbol ? 1 : 0u); 284 } 285 286 /// <summary> 287 /// Gets the copy of symbol with changed interval. 288 /// </summary> 289 /// <returns>The truncated copy.</returns> 290 /// <param name="start">Start.</param> 291 /// <param name="end">End.</param> GetTrimmedCopy(SymbolAddress start, SymbolAddress end)292 private Symbol GetTrimmedCopy(SymbolAddress start, SymbolAddress end) 293 { 294 return new Symbol(start, end, Name, Type, Binding, thumbArchitecture); 295 } 296 297 static private IntervalComparer<SymbolAddress> intervalComparer = new IntervalComparer<SymbolAddress>(); 298 299 static private Dictionary<SymbolType, int> TypeImportance = new Dictionary<SymbolType, int> 300 { 301 { SymbolType.File, 0 }, 302 { SymbolType.Object, 1 }, 303 { SymbolType.Section, 2 }, 304 { SymbolType.ProcessorSpecific, 3 }, 305 { SymbolType.NotSpecified, 4 }, 306 { SymbolType.Function, 5 } 307 }; 308 309 static private Dictionary<SymbolBinding, int> BindingImportance = new Dictionary<SymbolBinding, int> 310 { 311 { SymbolBinding.Weak, 0 }, 312 { SymbolBinding.ProcessorSpecific, 1 }, 313 { SymbolBinding.Local, 2 }, 314 { SymbolBinding.Global, 3 } 315 }; 316 317 private readonly bool thumbArchitecture; 318 } 319 } 320