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