1 // 2 // Copyright (c) 2010-2025 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; 9 using System.Collections.Generic; 10 using System.Reflection; 11 using System.Text.RegularExpressions; 12 using System.Linq; 13 using Antmicro.Renode.Core; 14 using Antmicro.Renode.Peripherals.Bus; 15 using Antmicro.Renode.Logging; 16 using Antmicro.Renode.Peripherals; 17 using System.IO; 18 using Dynamitey; 19 using System.Text; 20 using System.Runtime.InteropServices; 21 using System.Drawing; 22 using Antmicro.Renode.Network; 23 using System.Diagnostics; 24 using Antmicro.Renode.Core.Structure.Registers; 25 using System.Threading; 26 using Antmicro.Renode.Peripherals.CPU; 27 using Antmicro.Renode.Logging.Profiling; 28 29 namespace Antmicro.Renode.Utilities 30 { 31 public static class Misc 32 { 33 //TODO: isn't it obsolete? 34 //TODO: what if memory_size should be long? CreateAtags(string bootargs, uint memorySize)35 public static List<UInt32> CreateAtags(string bootargs, uint memorySize) 36 { 37 var atags = new List<UInt32> 38 { 39 5u, 40 0x54410001u, 41 1u, 42 0x1000u, 43 0u, 44 4u, 45 0x54410002u, 46 memorySize, 47 0u, 48 (uint)((bootargs.Length >> 2) + 3), 49 0x54410009u 50 }; 51 52 //TODO: should be padded 53 var ascii = new ASCIIEncoding(); 54 var bootargsByte = new List<byte>(); 55 bootargsByte.AddRange(ascii.GetBytes(bootargs)); 56 int i; 57 if((bootargs.Length % 4) != 0) 58 { 59 for(i = 0; i < (4 - (bootargs.Length%4)); i++) 60 { 61 bootargsByte.Add(0); // pad with zeros 62 } 63 } 64 for(i = 0; i < bootargsByte.Count; i += 4) 65 { 66 atags.Add(BitConverter.ToUInt32(bootargsByte.ToArray(), i)); 67 } 68 atags.Add(0u); 69 70 atags.Add(0u); // ATAG_NONE 71 return atags; 72 } 73 Is(this Type type)74 public static bool Is<T>(this Type type) 75 { 76 return type == typeof(T); 77 } 78 IsPeripheral(object o)79 public static bool IsPeripheral(object o) 80 { 81 return o is IPeripheral; 82 } 83 IsPythonObject(object o)84 public static bool IsPythonObject(object o) 85 { 86 return o.GetType().GetFields().Any(x => x.Name == ".class"); 87 } 88 IsPythonType(Type t)89 public static bool IsPythonType(Type t) 90 { 91 return t.GetFields().Any(x => x.Name == ".class"); 92 } 93 GetPythonName(object o)94 public static string GetPythonName(object o) 95 { 96 var cls = Dynamic.InvokeGet(o, ".class"); 97 return cls.__name__; 98 } 99 GetAllMethods(this Type t, bool recursive = true)100 public static IEnumerable<MethodInfo> GetAllMethods(this Type t, bool recursive = true) 101 { 102 if(t == null) 103 { 104 return Enumerable.Empty<MethodInfo>(); 105 } 106 if(recursive) 107 { 108 return t.GetMethods(DefaultBindingFlags).Union(GetAllMethods(t.BaseType)); 109 } 110 return t.GetMethods(DefaultBindingFlags); 111 } 112 113 public static IEnumerable<MethodWithAttribute<T>> GetMethodsWithAttribute<T>(this Type type, bool inheritAttribute = true) where T : Attribute 114 { 115 return type.GetAllMethods() 116 .Select(method => new MethodWithAttribute<T>(method, (T)method.GetCustomAttribute(typeof(T), inheritAttribute))) 117 .Where(m => m.Attribute != null); 118 } 119 GetAllFields(this Type t, bool recursive = true)120 public static IEnumerable<FieldInfo> GetAllFields(this Type t, bool recursive = true) 121 { 122 if(t == null) 123 { 124 return Enumerable.Empty<FieldInfo>(); 125 } 126 if(recursive) 127 { 128 return t.GetFields(DefaultBindingFlags).Union(GetAllFields(t.BaseType)); 129 } 130 return t.GetFields(DefaultBindingFlags); 131 } 132 GetAllNestedTypes(this Type t, bool recursive = true)133 public static IEnumerable<Type> GetAllNestedTypes(this Type t, bool recursive = true) 134 { 135 if(t == null) 136 { 137 return Enumerable.Empty<Type>(); 138 } 139 if(recursive) 140 { 141 return t.GetNestedTypes(DefaultBindingFlags).Union(t.BaseType.GetAllNestedTypes()); 142 } 143 return t.GetNestedTypes(DefaultBindingFlags); 144 } 145 ReadBytes(this Stream stream, int count, bool throwIfEndOfStream = false)146 public static byte[] ReadBytes(this Stream stream, int count, bool throwIfEndOfStream = false) 147 { 148 var buffer = new byte[count]; 149 var read = 0; 150 while(read < count) 151 { 152 var readInThisIteration = stream.Read( 153 buffer, 154 read, 155 count - read 156 ); 157 if(readInThisIteration == 0) 158 { 159 throw new EndOfStreamException(string.Format( 160 "End of stream encountered, only {0} bytes could be read.", 161 read 162 ) 163 ); 164 } 165 read += readInThisIteration; 166 } 167 168 if(throwIfEndOfStream && read < count) 169 { 170 throw new EndOfStreamException( 171 $"End of stream encountered. {count}B were requested but only {read}B could be read" 172 ); 173 } 174 return buffer; 175 } 176 KB(this int value)177 public static int KB(this int value) 178 { 179 return 1024 * value; 180 } 181 MB(this int value)182 public static int MB(this int value) 183 { 184 return 1024 * value.KB(); 185 } 186 GB(this int value)187 public static ulong GB(this int value) 188 { 189 return 1024 * (ulong)value.MB(); 190 } 191 TB(this int value)192 public static ulong TB(this int value) 193 { 194 return 1024 * value.GB(); 195 } 196 197 /// <summary> 198 /// Computes which power of two is given number. You can only use this function if you know 199 /// that this number IS a power of two. 200 /// </summary> Logarithm2(int value)201 public static int Logarithm2(int value) 202 { 203 return MultiplyDeBruijnBitPosition2[(int)((uint)(value * 0x077CB531u) >> 27)]; 204 } 205 206 public static byte[] AsRawBytes<T>(this T structure) where T : struct 207 { 208 var size = Marshal.SizeOf(typeof(T)); 209 var result = new byte[size]; 210 var bufferPointer = Marshal.AllocHGlobal(size); Marshal.StructureToPtrAntmicro.Renode.Utilities.Misc.__anon1211 Marshal.StructureToPtr(structure, bufferPointer, false); Marshal.CopyAntmicro.Renode.Utilities.Misc.__anon1212 Marshal.Copy(bufferPointer, result, 0, size); Marshal.FreeHGlobalAntmicro.Renode.Utilities.Misc.__anon1213 Marshal.FreeHGlobal(bufferPointer); 214 return result; 215 } 216 NormalizeBinary(double what)217 public static String NormalizeBinary(double what) 218 { 219 var prefix = (what < 0) ? "-" : ""; 220 if(what == 0) 221 { 222 return "0"; 223 } 224 if(what < 0) 225 { 226 what = -what; 227 } 228 var power = (int)Math.Log(what, 2); 229 var index = power / 10; 230 if(index >= BytePrefixes.Length) 231 { 232 index = BytePrefixes.Length - 1; 233 } 234 what /= Math.Pow(2, 10 * index); 235 return string.Format( 236 "{0}{1:0.##}{2}", 237 prefix, 238 what, 239 BytePrefixes[index] 240 ); 241 } 242 ByteArrayWrite(long offset, uint value, byte[] array)243 public static void ByteArrayWrite(long offset, uint value, byte[] array) 244 { 245 var index = (int)(offset); 246 var bytes = BitConverter.GetBytes(value); 247 for(var i = 0; i < 4; i++) 248 { 249 array[index + i] = bytes[i]; 250 } 251 } 252 ByteArrayRead(long offset, byte[] array)253 public static uint ByteArrayRead(long offset, byte[] array) 254 { 255 var index = (int)(offset); 256 var bytes = new byte[4]; 257 for(var i = 0; i < 4; i++) 258 { 259 bytes[i] = array[index + i]; 260 } 261 return BitConverter.ToUInt32(bytes, 0); 262 } 263 NormalizeDecimal(double what)264 public static String NormalizeDecimal(double what) 265 { 266 var prefix = (what < 0) ? "-" : ""; 267 if(what == 0) 268 { 269 return "0"; 270 } 271 if(what < 0) 272 { 273 what = -what; 274 } 275 var digits = Convert.ToInt32(Math.Floor(Math.Log10(what))); 276 var power = (long)(3 * Math.Round((digits / 3.0))); 277 var index = power / 3 + ZeroPrefixPosition; 278 if(index < 0) 279 { 280 index = 0; 281 power = 3 * (1 + ZeroPrefixPosition - SIPrefixes.Length); 282 } else if(index >= SIPrefixes.Length) 283 { 284 index = SIPrefixes.Length - 1; 285 power = 3 * (SIPrefixes.Length - ZeroPrefixPosition - 1); 286 } 287 what /= Math.Pow(10, power); 288 var unit = SIPrefixes[index]; 289 what = Math.Round(what, 2); 290 return prefix + what + unit; 291 } 292 GetShortName(object o)293 public static string GetShortName(object o) 294 { 295 if(Misc.IsPythonObject(o)) 296 { 297 return Misc.GetPythonName(o); 298 } 299 var type = o.GetType(); 300 return type.Name; 301 } 302 IsPowerOfTwo(ulong value)303 public static bool IsPowerOfTwo(ulong value) 304 { 305 return (value != 0) && (value & (value - 1)) == 0; 306 } 307 NextPowerOfTwo(int value)308 public static int NextPowerOfTwo(int value) 309 { 310 value--; 311 value |= value >> 1; 312 value |= value >> 2; 313 value |= value >> 4; 314 value |= value >> 8; 315 value |= value >> 16; 316 value++; 317 return value; 318 } 319 Times(this int times, Action<int> action)320 public static void Times(this int times, Action<int> action) 321 { 322 for(var i = 0; i < times; i++) 323 { 324 action(i); 325 } 326 } 327 Times(this int times, Action action)328 public static void Times(this int times, Action action) 329 { 330 for(var i = 0; i < times; i++) 331 { 332 action(); 333 } 334 } 335 AppendIf(this String value, bool condition, string what)336 public static StringBuilder AppendIf(this String value, bool condition, string what) 337 { 338 var builder = new StringBuilder(value); 339 return AppendIf(builder, condition, what); 340 } 341 AppendIf(this StringBuilder value, bool condition, string what)342 public static StringBuilder AppendIf(this StringBuilder value, bool condition, string what) 343 { 344 if(condition) 345 { 346 value.Append(what); 347 } 348 return value; 349 } 350 Indent(this String value, int count)351 public static String Indent(this String value, int count) 352 { 353 return "".PadLeft(count) + value; 354 } 355 Indent(this String value, int count, char fill)356 public static String Indent(this String value, int count, char fill) 357 { 358 return "".PadLeft(count, fill) + value; 359 } 360 Outdent(this String value, int count)361 public static String Outdent(this String value, int count) 362 { 363 return value + "".PadLeft(count); 364 } 365 StartsWith(this String source, char value)366 public static Boolean StartsWith(this String source, char value) 367 { 368 if (source.Length > 0) 369 { 370 return source[0] == value; 371 } 372 return false; 373 } 374 EndsWith(this String source, char value)375 public static Boolean EndsWith(this String source, char value) 376 { 377 if (source.Length > 0) 378 { 379 return source[source.Length - 1] == value; 380 } 381 return false; 382 } 383 Trim(this String value, String toCut)384 public static String Trim(this String value, String toCut) 385 { 386 if (!value.StartsWith(toCut)) 387 { 388 return value; 389 } 390 return value.Substring(toCut.Length); 391 } 392 IndexOf(this IEnumerable<TSource> source, Func<TSource, bool> predicate)393 public static int IndexOf<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate) 394 { 395 var i = 0; 396 foreach (var element in source) 397 { 398 if (predicate(element)) 399 return i; 400 401 i++; 402 } 403 return -1; 404 } 405 LastIndexOf(this IEnumerable<TSource> source, Func<TSource, bool> predicate)406 public static int LastIndexOf<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate) 407 { 408 var revSource = source.Reverse(); 409 var i = revSource.Count() - 1; 410 foreach (var element in revSource) 411 { 412 if (predicate(element)) 413 return i; 414 415 i--; 416 } 417 return -1; 418 } 419 420 #if !NET 421 public static TSource MinBy<TSource, T>(this IEnumerable<TSource> source, Func<TSource, T> map) where T: IComparable<T> 422 { 423 return source.Aggregate((a, b) => map(a).CompareTo(map(b)) < 0 ? a : b); 424 } 425 #endif 426 Stringify(this IEnumerable<TSource> source, string separator = R, int limitPerLine = 0)427 public static string Stringify<TSource>(this IEnumerable<TSource> source, string separator = " ", int limitPerLine = 0) 428 { 429 return Stringify(source.Select(x => x == null ? String.Empty : x.ToString()), separator, limitPerLine); 430 } 431 Stringify(this IEnumerable<string> source, string separator = R, int limitPerLine = 0)432 public static string Stringify(this IEnumerable<string> source, string separator = " ", int limitPerLine = 0) 433 { 434 int idx = 0; 435 if(source.Any()) 436 { 437 return source.Aggregate((x, y) => x + separator + (limitPerLine != 0 && (++idx % limitPerLine == 0) ? "\n" : string.Empty) + y); 438 } 439 return String.Empty; 440 } 441 HexStringToByteArray(string hexString, bool reverse = false, bool ignoreWhitespace = false)442 public static byte[] HexStringToByteArray(string hexString, bool reverse = false, bool ignoreWhitespace = false) 443 { 444 if(ignoreWhitespace) 445 { 446 hexString = Regex.Replace(hexString, @"\s+", ""); 447 } 448 449 if(hexString.Length % 2 != 0) 450 { 451 throw new FormatException($"The length of hex string ({hexString.Length}) is not a multiple of 2."); 452 } 453 454 byte[] bytes = new byte[hexString.Length / 2]; 455 for(int i = 0; i < bytes.Length; i++) 456 { 457 int byteIndex = reverse ? bytes.Length - 1 - i : i; 458 bytes[byteIndex] = Convert.ToByte(hexString.Substring(i * 2, 2), 16); 459 } 460 return bytes; 461 } 462 463 // Can't use the `sizeof` in the generic code unless it is restricted to unmanaged types, and that's possible only in C#7.0 and newer. 464 // Hence the `elementSize` argument - otherwise it would be replaced with a `sizeof(T)` TryParseHexString(string hexString, out T[] outArray, int elementSize, bool endiannessSwap=false)465 public static bool TryParseHexString<T>(string hexString, out T[] outArray, int elementSize, bool endiannessSwap=false) 466 { 467 var byteArray = HexStringToByteArray(hexString); 468 var byteLength = byteArray.Length; 469 if(byteLength % elementSize != 0) 470 { 471 outArray = new T[0]; 472 return false; 473 } 474 outArray = new T[byteLength / elementSize]; 475 if(endiannessSwap) 476 { 477 EndiannessSwapInPlace(byteArray, elementSize); 478 } 479 Buffer.BlockCopy(byteArray, 0, outArray, 0, byteLength); 480 return true; 481 } 482 ToHexString(this byte[] data)483 public static string ToHexString(this byte[] data) 484 { 485 var lookup = hexStringLookup.Value; 486 var builder = new StringBuilder(data.Length * 2); 487 for(var i = 0; i < data.Length; ++i) 488 { 489 builder.Append(lookup[data[i]]); 490 } 491 return builder.ToString(); 492 } 493 ToHex(this byte value)494 public static string ToHex(this byte value) 495 { 496 return hexStringLookup.Value[value]; 497 } 498 ConcatRangeFromTo(this IEnumerable<int> enumerable, int start, int stopIncluded)499 public static IEnumerable<int> ConcatRangeFromTo(this IEnumerable<int> enumerable, int start, int stopIncluded) 500 { 501 return enumerable.Concat(Enumerable.Range(start, stopIncluded - start + 1)); 502 } 503 504 // MoreLINQ - Extensions to LINQ to Objects 505 // Copyright (c) 2008 Jonathan Skeet. All rights reserved. DistinctBy(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector, IEqualityComparer<TKey> comparer = null)506 public static IEnumerable<TSource> DistinctBy<TSource, TKey>(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector, 507 IEqualityComparer<TKey> comparer = null) 508 { 509 if(source == null) 510 { 511 throw new ArgumentNullException("source"); 512 } 513 if(keySelector == null) 514 { 515 throw new ArgumentNullException("keySelector"); 516 } 517 var knownKeys = new HashSet<TKey>(comparer); 518 foreach (var element in source) 519 { 520 if (knownKeys.Add(keySelector(element))) 521 { 522 yield return element; 523 } 524 } 525 } 526 527 /// <summary>Adds elements to the end of an IEnumerable.</summary> 528 /// <typeparam name="T">Type of enumerable to return.</typeparam> 529 /// <returns>IEnumerable containing all the input elements, followed by the 530 /// specified additional elements.</returns> Append(this IEnumerable<T> source, params T[] element)531 public static IEnumerable<T> Append<T>(this IEnumerable<T> source, params T[] element) 532 { 533 if(source == null) 534 { 535 throw new ArgumentNullException("source"); 536 } 537 return ConcatIterator(element, source, false); 538 } 539 540 /// <summary>Adds elements to the start of an IEnumerable.</summary> 541 /// <typeparam name="T">Type of enumerable to return.</typeparam> 542 /// <returns>IEnumerable containing the specified additional elements, followed by 543 /// all the input elements.</returns> Prepend(this IEnumerable<T> tail, params T[] head)544 public static IEnumerable<T> Prepend<T>(this IEnumerable<T> tail, params T[] head) 545 { 546 if(tail == null) 547 { 548 throw new ArgumentNullException("tail"); 549 } 550 return ConcatIterator(head, tail, true); 551 } 552 ConcatIterator(T[] extraElements, IEnumerable<T> source, bool insertAtStart)553 private static IEnumerable<T> ConcatIterator<T>(T[] extraElements, 554 IEnumerable<T> source, bool insertAtStart) 555 { 556 if(insertAtStart) 557 { 558 foreach(var e in extraElements) 559 { 560 yield return e; 561 } 562 } 563 foreach(var e in source) 564 { 565 yield return e; 566 } 567 if(!insertAtStart) 568 { 569 foreach(var e in extraElements) 570 { 571 yield return e; 572 } 573 } 574 } 575 GetOrDefault(this IReadOnlyDictionary<TKey, TValue> @this, TKey key)576 public static TValue GetOrDefault<TKey, TValue>(this IReadOnlyDictionary<TKey, TValue> @this, TKey key) 577 { 578 return @this.GetOrDefault(key, default(TValue)); 579 } 580 GetOrDefault(this IReadOnlyDictionary<TKey, TValue> @this, TKey key, TValue defaultValue)581 public static TValue GetOrDefault<TKey, TValue>(this IReadOnlyDictionary<TKey, TValue> @this, TKey key, TValue defaultValue) 582 { 583 if(@this.TryGetValue(key, out var value)) 584 { 585 return value; 586 } 587 return defaultValue; 588 } 589 HiByte(this UInt16 value)590 public static byte HiByte(this UInt16 value) 591 { 592 return (byte)((value >> 8) & 0xFF); 593 } 594 LoByte(this UInt16 value)595 public static byte LoByte(this UInt16 value) 596 { 597 return (byte)(value & 0xFF); 598 } 599 BinaryToGray(ulong binaryEncoding)600 public static ulong BinaryToGray(ulong binaryEncoding) 601 { 602 return binaryEncoding ^ (binaryEncoding >> 1); 603 } 604 GrayToBinary(ulong grayEncoding)605 public static ulong GrayToBinary(ulong grayEncoding) 606 { 607 ulong binaryEncoding = grayEncoding; 608 while(grayEncoding > 0) 609 { 610 grayEncoding >>= 1; 611 binaryEncoding ^= grayEncoding; 612 } 613 return binaryEncoding; 614 } 615 TryFromResourceToTemporaryFile(this Assembly assembly, string resourceName, out string outputFileFullPath, string nonstandardOutputFilename = null)616 public static bool TryFromResourceToTemporaryFile(this Assembly assembly, string resourceName, out string outputFileFullPath, string nonstandardOutputFilename = null) 617 { 618 // `GetManifestResourceStream` is not supported by dynamic assemblies 619 Stream libraryStream = assembly.IsDynamic 620 ? null 621 : assembly.GetManifestResourceStream(resourceName); 622 623 if(libraryStream == null) 624 { 625 if(File.Exists(resourceName)) 626 { 627 libraryStream = new FileStream(resourceName, FileMode.Open, FileAccess.Read, FileShare.None); 628 } 629 if(libraryStream == null) 630 { 631 outputFileFullPath = null; 632 return false; 633 } 634 } 635 636 string libraryFile; 637 if(nonstandardOutputFilename != null) 638 { 639 // Overwrite file if already exists since nonstandard filenames are not unique due to not being prefixed with GUIDs 640 // This can cause issues when running docker containers which can have reproducable PIDs even after restart and persistent /tmp 641 if(!TemporaryFilesManager.Instance.TryCreateFile(nonstandardOutputFilename, out libraryFile, true)) 642 { 643 Logging.Logger.Log(Logging.LogLevel.Error, "Could not unpack resource {0} to {1}. This likely signifies an internal error.", resourceName, nonstandardOutputFilename); 644 outputFileFullPath = null; 645 return false; 646 } 647 } 648 else 649 { 650 libraryFile = TemporaryFilesManager.Instance.GetTemporaryFile(resourceName); 651 652 if(String.IsNullOrEmpty(libraryFile)) 653 { 654 outputFileFullPath = null; 655 return false; 656 } 657 } 658 outputFileFullPath = CopyToFile(libraryStream, libraryFile); 659 return true; 660 } 661 FromResourceToTemporaryFile(this Assembly assembly, string resourceName)662 public static string FromResourceToTemporaryFile(this Assembly assembly, string resourceName) 663 { 664 if(!TryFromResourceToTemporaryFile(assembly, resourceName, out var result)) 665 { 666 throw new ArgumentException(string.Format("Cannot find library {0}", resourceName)); 667 } 668 return result; 669 } 670 Copy(this Stream from, Stream to)671 public static void Copy(this Stream from, Stream to) 672 { 673 var buffer = new byte[4096]; 674 int read; 675 do 676 { 677 read = from.Read(buffer, 0, buffer.Length); 678 if(read <= 0) // to workaround ionic zip's bug 679 { 680 break; 681 } 682 to.Write(buffer, 0, read); 683 } 684 while(true); 685 } 686 GetPixelFromPngImage(string fileName, int x, int y, out byte r, out byte g, out byte b)687 public static void GetPixelFromPngImage(string fileName, int x, int y, out byte r, out byte g, out byte b) 688 { 689 Bitmap bitmap; 690 if(fileName == LastBitmapName) 691 { 692 bitmap = LastBitmap; 693 } 694 else 695 { 696 bitmap = new Bitmap(fileName); 697 LastBitmap = bitmap; 698 LastBitmapName = fileName; 699 } 700 var color = bitmap.GetPixel(x, y); 701 r = color.R; 702 g = color.G; 703 b = color.B; 704 } 705 706 private static string cachedRootDirectory; 707 GetRootDirectory()708 public static string GetRootDirectory() 709 { 710 if(cachedRootDirectory != null) 711 { 712 return cachedRootDirectory; 713 } 714 715 if(TryGetRootDirectory(out var result)) 716 { 717 return result; 718 } 719 720 // fall-back to the current working directory 721 var cwd = Directory.GetCurrentDirectory(); 722 Logger.Log(LogLevel.Warning, "Could not find '.renode-root' - falling back to current working directory ({0}) - might cause problems.", cwd); 723 cachedRootDirectory = cwd; 724 725 return cwd; 726 } 727 TryGetRootDirectory(out string directory)728 public static bool TryGetRootDirectory(out string directory) 729 { 730 if(TryGetRootDirectory(AppDomain.CurrentDomain.BaseDirectory, out directory)) 731 { 732 // Firstly, try to resolve root directory starting from 733 // directory containing current assembly. This should 734 // work when Renode was run after being manually compiled from the source code. 735 return true; 736 } 737 738 // If we couldn't find root directory in previous step, try again 739 // starting from directory of main process' executable. This is fallback for 740 // when Renode was executed from self-contained binary. 741 var currentProcess = Process.GetCurrentProcess(); 742 var currentModulePath = Path.GetFullPath(currentProcess.MainModule.FileName); 743 var rootDirectory = Path.GetDirectoryName(currentModulePath); 744 return TryGetRootDirectory(rootDirectory, out directory); 745 } 746 TryGetRootDirectory(string baseDirectory, out string directory)747 public static bool TryGetRootDirectory(string baseDirectory, out string directory) 748 { 749 if(cachedRootDirectory != null) 750 { 751 directory = cachedRootDirectory; 752 return true; 753 } 754 755 directory = null; 756 if(baseDirectory.Length == 0) 757 { 758 return false; 759 } 760 761 var currentDirectory = new DirectoryInfo(baseDirectory); 762 while(currentDirectory != null) 763 { 764 var indicatorFiles = Directory.GetFiles(currentDirectory.FullName, ".renode-root"); 765 if(indicatorFiles.Length == 1) 766 { 767 var content = File.ReadAllLines(Path.Combine(currentDirectory.FullName, indicatorFiles[0])); 768 if(content.Length == 1 && content[0] == "5344ec2a-1539-4017-9ae5-a27c279bd454") 769 { 770 directory = currentDirectory.FullName; 771 cachedRootDirectory = directory; 772 return true; 773 } 774 } 775 currentDirectory = currentDirectory.Parent; 776 } 777 return false; 778 } 779 Multiply(this TimeSpan multiplicand, int multiplier)780 public static TimeSpan Multiply(this TimeSpan multiplicand, int multiplier) 781 { 782 return TimeSpan.FromTicks(multiplicand.Ticks * multiplier); 783 } 784 Multiply(this TimeSpan multiplicand, double multiplier)785 public static TimeSpan Multiply(this TimeSpan multiplicand, double multiplier) 786 { 787 return TimeSpan.FromTicks((long)(multiplicand.Ticks * multiplier)); 788 } 789 FormatWith(this String @this, params object[] args)790 public static String FormatWith(this String @this, params object[] args) 791 { 792 if(@this == null) 793 { 794 throw new ArgumentNullException("this"); 795 } 796 if(args == null) 797 { 798 throw new ArgumentNullException("args"); 799 } 800 return String.Format(@this, args); 801 802 } 803 CopyToFile(Stream libraryStream, string libraryFile)804 private static string CopyToFile(Stream libraryStream, string libraryFile) 805 { 806 try 807 { 808 using(var destination = new FileStream(libraryFile, FileMode.Open, FileAccess.Write, FileShare.None)) 809 { 810 libraryStream.Copy(destination); 811 Logger.Noisy(String.Format("Library copied to {0}.", libraryFile)); 812 } 813 return libraryFile; 814 } 815 catch(IOException e) 816 { 817 throw new InvalidOperationException(String.Format("Error while copying file: {0}.", e.Message)); 818 } 819 finally 820 { 821 if(libraryStream != null) 822 { 823 libraryStream.Close(); 824 } 825 } 826 } 827 ComputeHeaderIpChecksum(byte[] header, int start, int length)828 private static ushort ComputeHeaderIpChecksum(byte[] header, int start, int length) 829 { 830 ushort word16; 831 var sum = 0L; 832 for (var i = start; i < (length + start); i+=2) 833 { 834 if(i - start == 10) 835 { 836 //These are IP Checksum fields. 837 continue; 838 } 839 word16 = (ushort)(((header[i] << 8 ) & 0xFF00) 840 + (header[i + 1] & 0xFF)); 841 sum += (long)word16; 842 } 843 844 while ((sum >> 16) != 0) 845 { 846 sum = (sum & 0xFFFF) + (sum >> 16); 847 } 848 sum = ~sum; 849 return (ushort)sum; 850 } 851 852 // Calculates the TCP checksum using the IP Header and TCP Header. 853 // Ensure the TCPHeader contains an even number of bytes before passing to this method. 854 // If an odd number, pad with a 0 byte just for checksumming purposes. GetPacketChecksum(byte[] packet, int startOfIp, int startOfPayload, bool withPseudoHeader)855 static ushort GetPacketChecksum(byte[] packet, int startOfIp, int startOfPayload, bool withPseudoHeader) 856 { 857 var sum = 0u; 858 // Protocol Header 859 for (var x = startOfPayload; x < packet.Length - 1; x += 2) 860 { 861 sum += Ntoh(BitConverter.ToUInt16(packet, x)); 862 } 863 if((packet.Length - startOfPayload) % 2 != 0) 864 { 865 //odd length 866 sum += (ushort)((packet[packet.Length - 1] << 8) | 0x00); 867 } 868 if(withPseudoHeader) 869 { 870 // Pseudo header - Source Address 871 sum += Ntoh(BitConverter.ToUInt16(packet, startOfIp + 12)); 872 sum += Ntoh(BitConverter.ToUInt16(packet, startOfIp + 14)); 873 // Pseudo header - Dest Address 874 sum += Ntoh(BitConverter.ToUInt16(packet, startOfIp + 16)); 875 sum += Ntoh(BitConverter.ToUInt16(packet, startOfIp + 18)); 876 // Pseudo header - Protocol 877 sum += Ntoh(BitConverter.ToUInt16(new byte[] { 0, packet[startOfIp + 9] }, 0)); 878 // Pseudo header - TCP Header length 879 sum += (ushort)(packet.Length - startOfPayload); 880 } 881 // 16 bit 1's compliment 882 while((sum >> 16) != 0) 883 { 884 sum = ((sum & 0xFFFF) + (sum >> 16)); 885 } 886 return (ushort)~sum; 887 } 888 Ntoh(UInt16 input)889 private static ushort Ntoh(UInt16 input) 890 { 891 int x = System.Net.IPAddress.NetworkToHostOrder(input); 892 return (ushort) (x >> 16); 893 } 894 895 public enum TransportLayerProtocol 896 { 897 ICMP = 0x1, 898 TCP = 0x6, 899 UDP = 0x11 900 } 901 public enum PacketType 902 { 903 IP = 0x800, 904 ARP = 0x806, 905 } 906 907 //TODO: Support for ipv6 FillPacketWithChecksums(IPeripheral source, byte[] packet, params TransportLayerProtocol[] interpretedProtocols)908 public static void FillPacketWithChecksums(IPeripheral source, byte[] packet, params TransportLayerProtocol[] interpretedProtocols) 909 { 910 if (packet.Length < MACLength) { 911 source.Log(LogLevel.Error, String.Format("Expected packet of at least {0} bytes, got {1}.", MACLength, packet.Length)); 912 return; 913 } 914 var packet_type = (PacketType) ((packet[12] << 8) | packet[13]); 915 if (packet_type == PacketType.ARP) { 916 // ARP 917 return; 918 } else if (packet_type != PacketType.IP) { 919 source.Log(LogLevel.Error, String.Format("Unknown packet type: 0x{0:X}. Supported are: 0x800 (IP) and 0x806 (ARP).", (ushort)packet_type)); 920 return; 921 } 922 if (packet.Length < (MACLength+12)) { 923 source.Log(LogLevel.Error, "IP Packet is too short!"); 924 return; 925 } 926 // IPvX 927 if ((packet[MACLength] >> 4) != 0x04) { 928 source.Log(LogLevel.Error, String.Format("Only IPv4 packets are supported. Got IPv{0}", (packet[MACLength] >> 4))); 929 return; 930 } 931 // IPv4 932 var ipLength = (packet[MACLength] & 0x0F) * 4; 933 if(ipLength != 0) 934 { 935 var ipChecksum = ComputeHeaderIpChecksum(packet, MACLength, ipLength); 936 packet[MACLength + 10] = (byte)(ipChecksum >> 8); 937 packet[MACLength + 11] = (byte)(ipChecksum & 0xFF); 938 } else { 939 source.Log(LogLevel.Error, "Something is wrong - IP packet of len 0"); 940 } 941 if(interpretedProtocols != null && interpretedProtocols.Contains((TransportLayerProtocol)packet[MACLength + 9])) 942 { 943 var payloadStart = MACLength + ipLength; 944 var protocol = (TransportLayerProtocol)packet[MACLength + 9]; 945 var checksum = GetPacketChecksum(packet, MACLength, payloadStart, protocol != TransportLayerProtocol.ICMP); 946 switch(protocol) 947 { 948 case TransportLayerProtocol.ICMP: 949 packet[payloadStart + 2] = (byte)((checksum >> 8) & 0xFF); 950 packet[payloadStart + 3] = (byte)((checksum ) & 0xFF); 951 break; 952 case TransportLayerProtocol.TCP: 953 packet[payloadStart + 16] = (byte)((checksum >> 8) & 0xFF); 954 packet[payloadStart + 17] = (byte)((checksum ) & 0xFF); 955 break; 956 case TransportLayerProtocol.UDP: 957 packet[payloadStart + 6] = (byte)((checksum >> 8) & 0xFF); 958 packet[payloadStart + 7] = (byte)((checksum ) & 0xFF); 959 break; 960 default: 961 throw new NotImplementedException(); 962 } 963 } 964 } 965 DumpPacket(EthernetFrame packet, bool isSend, IMachine machine)966 public static string DumpPacket(EthernetFrame packet, bool isSend, IMachine machine) 967 { 968 var builder = new StringBuilder(); 969 string machName; 970 if(!EmulationManager.Instance.CurrentEmulation.TryGetMachineName(machine, out machName)) 971 { 972 //probably the emulation is closing now, just return. 973 return string.Empty; 974 } 975 if(isSend) 976 { 977 builder.AppendLine(String.Format("Sending packet from {0}, length: {1}", machName, packet.Bytes.Length)); 978 } 979 else 980 { 981 builder.AppendLine(String.Format("Receiving packet on {0}, length: {1}", machName, packet.Bytes.Length)); 982 } 983 builder.Append(packet.ToString()); 984 return builder.ToString(); 985 } 986 Swap(ref T a, ref T b)987 public static void Swap<T>(ref T a, ref T b) 988 { 989 T temporary = a; 990 a = b; 991 b = temporary; 992 } 993 SwapBytesUShort(ushort val)994 public static ushort SwapBytesUShort(ushort val) 995 { 996 return (ushort)((val << 8) | (val >> 8)); 997 } 998 SwapBytesUInt(uint value)999 public static uint SwapBytesUInt(uint value) 1000 { 1001 return (value & 0xFF000000) >> 24 1002 | (value & 0x00FF0000) >> 8 1003 | (value & 0x0000FF00) << 8 1004 | (value & 0x000000FF) << 24; 1005 } 1006 SwapBytesULong(ulong value)1007 public static ulong SwapBytesULong(ulong value) 1008 { 1009 return (value & 0xFF00000000000000) >> 56 1010 | (value & 0x00FF000000000000) >> 40 1011 | (value & 0x0000FF0000000000) >> 24 1012 | (value & 0x000000FF00000000) >> 8 1013 | (value & 0x00000000FF000000) << 8 1014 | (value & 0x0000000000FF0000) << 24 1015 | (value & 0x000000000000FF00) << 40 1016 | (value & 0x00000000000000FF) << 56; 1017 } 1018 SwapBytes(T value)1019 public static T SwapBytes<T>(T value) 1020 { 1021 var type = typeof(T); 1022 if(type == typeof(uint)) 1023 { 1024 return (T)(object)SwapBytesUInt((uint)(object)value); 1025 } 1026 else if(type == typeof(ushort)) 1027 { 1028 return (T)(object)SwapBytesUShort((ushort)(object)value); 1029 } 1030 else if(type == typeof(byte)) 1031 { 1032 return value; 1033 } 1034 else 1035 { 1036 throw new ArgumentException($"Unhandled type {type}"); 1037 } 1038 } 1039 SwapElements(T[] arr, int id1, int id2)1040 public static void SwapElements<T>(T[] arr, int id1, int id2) 1041 { 1042 var tmp = arr[id1]; 1043 arr[id1] = arr[id2]; 1044 arr[id2] = tmp; 1045 } 1046 EndiannessSwapInPlace(byte[] input, int width, int offset = 0, int? length = null)1047 public static bool EndiannessSwapInPlace(byte[] input, int width, int offset = 0, int? length = null) 1048 { 1049 if(offset > input.Length) 1050 { 1051 return false; 1052 } 1053 1054 var bytesFromOffset = input.Length - offset; 1055 var len = length ?? bytesFromOffset; 1056 if(len > bytesFromOffset || len % width != 0) 1057 { 1058 return false; 1059 } 1060 1061 for(var i = offset; i < offset + len; i += width) 1062 { 1063 for(var j = 0; j < width / 2; j++) 1064 { 1065 SwapElements(input, i + j, i + width - j - 1); 1066 } 1067 } 1068 1069 return true; 1070 } 1071 EndiannessSwap(uint value)1072 public static uint EndiannessSwap(uint value) 1073 { 1074 var temp = new byte[sizeof(uint)]; 1075 Misc.ByteArrayWrite(0, value, temp); 1076 Misc.EndiannessSwapInPlace(temp, sizeof(uint)); 1077 return Misc.ByteArrayRead(0, temp); 1078 } 1079 CalculateUnitSuffix(double value, out double newValue, out string unit)1080 public static bool CalculateUnitSuffix(double value, out double newValue, out string unit) 1081 { 1082 var units = new [] { "B", "KB", "MB", "GB", "TB" }; 1083 1084 var v = value; 1085 var i = 0; 1086 while(i < units.Length - 1 && Math.Round(v / 1024) >= 1) 1087 { 1088 v /= 1024; 1089 i++; 1090 } 1091 1092 newValue = v; 1093 unit = units[i]; 1094 1095 return true; 1096 } 1097 ToOrdinal(this int num)1098 public static string ToOrdinal(this int num) 1099 { 1100 if(num <= 0) 1101 { 1102 return num.ToString(); 1103 } 1104 switch(num % 100) 1105 { 1106 case 11: 1107 case 12: 1108 case 13: 1109 return num + "th"; 1110 } 1111 1112 switch(num % 10) 1113 { 1114 case 1: 1115 return num + "st"; 1116 case 2: 1117 return num + "nd"; 1118 case 3: 1119 return num + "rd"; 1120 default: 1121 return num + "th"; 1122 } 1123 } 1124 1125 private const int MACLength = 14; 1126 1127 private static string LastBitmapName = ""; 1128 private static Bitmap LastBitmap; 1129 1130 private const BindingFlags DefaultBindingFlags = BindingFlags.Public | BindingFlags.NonPublic | 1131 BindingFlags.Instance | BindingFlags.DeclaredOnly; 1132 1133 private static readonly string[] SIPrefixes = { 1134 "p", 1135 "n", 1136 "µ", 1137 "m", 1138 "", 1139 "k", 1140 "M", 1141 "G", 1142 "T" 1143 }; 1144 private static readonly string[] BytePrefixes = { 1145 "", 1146 "Ki", 1147 "Mi", 1148 "Gi", 1149 "Ti" 1150 }; 1151 private const int ZeroPrefixPosition = 4; 1152 private static readonly int[] MultiplyDeBruijnBitPosition2 = 1153 { 1154 0, 1, 28, 2, 29, 14, 24, 3, 30, 22, 20, 15, 25, 17, 4, 8, 1155 31, 27, 13, 23, 21, 19, 16, 7, 26, 12, 18, 6, 11, 5, 10, 9 1156 }; 1157 1158 /// <summary> 1159 /// Checks if the current user is a root. 1160 /// </summary> 1161 /// <value><c>true</c> if is root; otherwise, <c>false</c>.</value> 1162 public static bool IsRoot 1163 { 1164 get { return Environment.UserName == "root"; } 1165 } 1166 1167 public static bool IsOnOsX 1168 { 1169 get 1170 { 1171 if(Environment.OSVersion.Platform == PlatformID.MacOSX) 1172 { 1173 return true; 1174 } 1175 return Directory.Exists("/Library") && Directory.Exists("/Applications"); 1176 } 1177 } 1178 IsCommandAvaialble(string command)1179 public static bool IsCommandAvaialble(string command) 1180 { 1181 var verifyProc = new Process(); 1182 verifyProc.StartInfo.UseShellExecute = false; 1183 verifyProc.StartInfo.RedirectStandardError = true; 1184 verifyProc.StartInfo.RedirectStandardInput = true; 1185 verifyProc.StartInfo.RedirectStandardOutput = true; 1186 verifyProc.EnableRaisingEvents = false; 1187 verifyProc.StartInfo.FileName = "which"; 1188 verifyProc.StartInfo.Arguments = command; 1189 1190 verifyProc.Start(); 1191 1192 verifyProc.WaitForExit(); 1193 return verifyProc.ExitCode == 0; 1194 } 1195 PrettyPrintFlagsEnum(Enum enumeration)1196 public static string PrettyPrintFlagsEnum(Enum enumeration) 1197 { 1198 var values = new List<string>(); 1199 foreach(Enum value in Enum.GetValues(enumeration.GetType())) 1200 { 1201 if((Convert.ToUInt64(enumeration) & Convert.ToUInt64(value)) != 0) 1202 { 1203 values.Add(value.ToString()); 1204 } 1205 } 1206 return values.Count == 0 ? "-" : values.Aggregate((x, y) => x + ", " + y); 1207 } 1208 TryGetMatchingSignature(IEnumerable<Type> signatures, MethodInfo mi, out Type matchingSignature)1209 public static bool TryGetMatchingSignature(IEnumerable<Type> signatures, MethodInfo mi, out Type matchingSignature) 1210 { 1211 matchingSignature = signatures.FirstOrDefault(x => HasMatchingSignature(x, mi)); 1212 return matchingSignature != null; 1213 } 1214 HasMatchingSignature(Type delegateType, MethodInfo mi)1215 public static bool HasMatchingSignature(Type delegateType, MethodInfo mi) 1216 { 1217 var delegateMethodInfo = delegateType.GetMethod("Invoke"); 1218 1219 return mi.ReturnType == delegateMethodInfo.ReturnType && 1220 mi.GetParameters().Select(x => x.ParameterType).SequenceEqual(delegateMethodInfo.GetParameters().Select(x => x.ParameterType)); 1221 } 1222 1223 public static T Clamp<T>(this T @this, T min, T max) where T : IComparable 1224 { 1225 if(@this.CompareTo(min) < 0) 1226 { 1227 return min; 1228 } 1229 else if(@this.CompareTo(max) > 0) 1230 { 1231 return max; 1232 } 1233 return @this; 1234 } 1235 Split(this string value, int size)1236 public static string[] Split(this string value, int size) 1237 { 1238 var ind = 0; 1239 return value.GroupBy(x => ind++ / size).Select(x => string.Join("", x)).ToArray(); 1240 } 1241 Split(this IEnumerable<T> values, int size)1242 public static IEnumerable<T[]> Split<T>(this IEnumerable<T> values, int size) 1243 { 1244 var i = 0; 1245 return values.GroupBy(_ => i++ / size).Select(chunk => chunk.ToArray()); 1246 } 1247 SetBit(this IValueRegisterField field, byte index, bool value)1248 public static void SetBit(this IValueRegisterField field, byte index, bool value) 1249 { 1250 var val = field.Value; 1251 BitHelper.SetBit(ref val, index, value); 1252 field.Value = val; 1253 } 1254 InMicroseconds(this TimeSpan ts)1255 public static ulong InMicroseconds(this TimeSpan ts) 1256 { 1257 return (ulong)(ts.Ticks / 10); 1258 } 1259 WaitWhile(this object @this, Func<bool> condition, string reason)1260 public static void WaitWhile(this object @this, Func<bool> condition, string reason) 1261 { 1262 @this.Trace($"Waiting for '{reason}'..."); 1263 while(condition()) 1264 { 1265 Monitor.Wait(@this); 1266 } 1267 @this.Trace($"Waiting for '{reason}' finished."); 1268 } 1269 FlipFlag(ref TEnum value, TEnum flag, bool state)1270 public static void FlipFlag<TEnum>(ref TEnum value, TEnum flag, bool state) 1271 { 1272 if(!typeof(TEnum).IsEnum) 1273 { 1274 throw new ArgumentException("TEnum must be an enumerated type."); 1275 } 1276 var intValue = (long)(object)value; 1277 var intFlag = (long)(object)flag; 1278 if(state) 1279 { 1280 intValue |= intFlag; 1281 } 1282 else 1283 { 1284 intValue &= ~intFlag; 1285 } 1286 value = (TEnum)(object)intValue; 1287 } 1288 PrettyPrintCollection(IEnumerable<T> collection, Func<T, string> formatter = null)1289 public static string PrettyPrintCollection<T>(IEnumerable<T> collection, Func<T, string> formatter = null) 1290 { 1291 return collection == null || !collection.Any() 1292 ? "[]" 1293 : $"[{(string.Join(", ", collection.Select(x => formatter == null ? x.ToString() : formatter(x))))}]"; 1294 } 1295 PrettyPrintCollectionHex(IEnumerable<T> collection)1296 public static string PrettyPrintCollectionHex<T>(IEnumerable<T> collection) 1297 { 1298 return PrettyPrintCollection(collection, x => "0x{0:X}".FormatWith(x)); 1299 } 1300 ToLazyHexString(this IEnumerable<T> collection)1301 public static LazyHexString<T> ToLazyHexString<T>(this IEnumerable<T> collection) 1302 { 1303 return new LazyHexString<T>(collection); 1304 } 1305 ToUInt32Smart(this byte[] @this)1306 public static UInt32 ToUInt32Smart(this byte[] @this) 1307 { 1308 if(@this.Length > 4) 1309 { 1310 throw new ArgumentException($"Bytes array is tool long. Expected at most 4 bytes, but got {@this.Length}"); 1311 } 1312 var result = 0u; 1313 for(var i = 0; i < @this.Length; i++) 1314 { 1315 result |= ((uint)@this[i] << (8 * i)); 1316 } 1317 return result; 1318 } 1319 With(this DateTime @this, int? year = null, int? month = null, int? day = null, int? hour = null, int? minute = null, int? second = null, double? millisecond = null)1320 public static DateTime With(this DateTime @this, int? year = null, int? month = null, int? day = null, int? hour = null, int? minute = null, int? second = null, double? millisecond = null) 1321 { 1322 var dateTime = new DateTime( 1323 year ?? @this.Year, 1324 month ?? @this.Month, 1325 day ?? @this.Day, 1326 hour ?? @this.Hour, 1327 minute ?? @this.Minute, 1328 second ?? @this.Second); 1329 1330 if(millisecond != null) 1331 { 1332 dateTime = dateTime.AddMilliseconds(millisecond.Value); 1333 } 1334 1335 return dateTime; 1336 } 1337 EnqueueRange(this Queue<T> @this, IEnumerable<T> data, int? limit = null)1338 public static int EnqueueRange<T>(this Queue<T> @this, IEnumerable<T> data, int? limit = null) 1339 { 1340 var counter = 0; 1341 foreach(var e in data.Take(limit ?? int.MaxValue)) 1342 { 1343 @this.Enqueue(e); 1344 counter++; 1345 } 1346 return counter; 1347 } 1348 DequeueRange(this Queue<T> @this, int limit)1349 public static T[] DequeueRange<T>(this Queue<T> @this, int limit) 1350 { 1351 var result = new T[Math.Min(@this.Count, limit)]; 1352 for(var i = 0; i < result.Length; i++) 1353 { 1354 result[i] = @this.Dequeue(); 1355 } 1356 return result; 1357 } 1358 DequeueAll(this Queue<T> @this)1359 public static T[] DequeueAll<T>(this Queue<T> @this) 1360 { 1361 return DequeueRange(@this, @this.Count); 1362 } 1363 TryDequeue(this Queue<T> @this, out T result)1364 public static bool TryDequeue<T>(this Queue<T> @this, out T result) 1365 { 1366 if(@this.Count == 0) 1367 { 1368 result = default(T); 1369 return false; 1370 } 1371 result = @this.Dequeue(); 1372 return true; 1373 } 1374 PopRange(this Stack<T> @this, int limit)1375 public static IEnumerable<T> PopRange<T>(this Stack<T> @this, int limit) 1376 { 1377 while(@this.Count > 0 && limit > 0) 1378 { 1379 limit--; 1380 yield return @this.Pop(); 1381 } 1382 } 1383 PopAll(this Stack<T> @this)1384 public static IEnumerable<T> PopAll<T>(this Stack<T> @this) 1385 { 1386 return PopRange(@this, @this.Count); 1387 } 1388 TryCreateFrameOrLogWarning(IEmulationElement source, byte[] data, out EthernetFrame frame, bool addCrc)1389 public static bool TryCreateFrameOrLogWarning(IEmulationElement source, byte[] data, out EthernetFrame frame, bool addCrc) 1390 { 1391 if(EthernetFrame.TryCreateEthernetFrame(data, addCrc, out frame)) 1392 { 1393 return true; 1394 } 1395 source.Log(LogLevel.Warning, "Insufficient data to create an ethernet frame, expected {0} bytes but got {1} bytes.", 1396 EthernetFrame.MinFrameSizeWithoutCRC + (addCrc ? 0 : EthernetFrame.CRCLength), data.Length); 1397 return false; 1398 } 1399 StripNonSafeCharacters(this string input)1400 public static string StripNonSafeCharacters(this string input) 1401 { 1402 return Encoding.UTF8.GetString(Encoding.UTF8.GetBytes(input).Where(x => (x >= 32 && x <= 126) || (x == '\n')).ToArray()); 1403 } 1404 SurroundWith(this string str, string surrounding)1405 public static string SurroundWith(this string str, string surrounding) 1406 { 1407 return $"{surrounding}{str}{surrounding}"; 1408 } 1409 1410 // allocate file of a given name 1411 // if it already exists - rename it using pattern path.III (III being an integer) 1412 // returns information if there was a rename and III of the last renamed file AllocateFile(string path, out int counter)1413 public static bool AllocateFile(string path, out int counter) 1414 { 1415 counter = 0; 1416 var renamed = false; 1417 var dstName = $"{path}.{counter}"; 1418 1419 while(!TryCreateEmptyFile(path)) 1420 { 1421 while(File.Exists(dstName)) 1422 { 1423 counter++; 1424 dstName = $"{path}.{counter}"; 1425 } 1426 File.Move(path, dstName); 1427 renamed = true; 1428 } 1429 return renamed; 1430 } 1431 1432 // Allows to have static initialization of a two-element tuple list. 1433 // To enable other arities of tuples, add more overloads. Add(this IList<Tuple<T1, T2>> list, T1 item1, T2 item2)1434 public static void Add<T1, T2>(this IList<Tuple<T1, T2>> list, 1435 T1 item1, T2 item2) 1436 { 1437 list.Add(Tuple.Create(item1, item2)); 1438 } 1439 TryCreateEmptyFile(string p)1440 private static bool TryCreateEmptyFile(string p) 1441 { 1442 try 1443 { 1444 File.Open(p, FileMode.CreateNew).Dispose(); 1445 return true; 1446 } 1447 catch(IOException) 1448 { 1449 // this is expected - the file already exists 1450 return false; 1451 } 1452 } 1453 TryParseBitPattern(string pattern, out ulong value, out ulong mask)1454 public static bool TryParseBitPattern(string pattern, out ulong value, out ulong mask) 1455 { 1456 value = 0uL; 1457 mask = 0uL; 1458 1459 if(pattern.Length > 64) 1460 { 1461 return false; 1462 } 1463 1464 var currentBit = pattern.Length - 1; 1465 1466 foreach(var p in pattern) 1467 { 1468 switch(p) 1469 { 1470 case '0': 1471 mask |= (1uL << currentBit); 1472 break; 1473 1474 case '1': 1475 mask |= (1uL << currentBit); 1476 value |= (1uL << currentBit); 1477 break; 1478 1479 default: 1480 // all characters other than '0' or '1' are treated as 'any-value' 1481 break; 1482 } 1483 1484 currentBit--; 1485 } 1486 1487 return true; 1488 } 1489 SetBytesFromValue(this byte[] array, uint value, int startIndex)1490 public static void SetBytesFromValue(this byte[] array, uint value, int startIndex) 1491 { 1492 foreach(var b in BitConverter.GetBytes(value)) 1493 { 1494 array[startIndex++] = b; 1495 } 1496 } 1497 1498 public static bool TryFindPreceedingEnumItem<T>(uint value, out T bestCandidate, out int offset) where T: IConvertible 1499 { 1500 var allValues = Enum.GetValues(typeof(T)); 1501 var maxIndex = allValues.Length - 1; 1502 1503 bestCandidate = default(T); 1504 offset = 0; 1505 1506 if((int)allValues.GetValue(0) > value) 1507 { 1508 // there are no values preceeding given value 1509 return false; 1510 } 1511 1512 int currentValue = 0; 1513 int lowBorder = 0; 1514 int highBorder = maxIndex; 1515 1516 // binary search 1517 while(highBorder != lowBorder) 1518 { 1519 var currentIndex = lowBorder + ((highBorder - lowBorder) / 2); 1520 currentValue = (int)allValues.GetValue(currentIndex); 1521 1522 if(currentValue == value) 1523 { 1524 break; 1525 } 1526 else if(currentValue < value) 1527 { 1528 lowBorder = currentIndex + 1; 1529 } 1530 else 1531 { 1532 highBorder = currentIndex; 1533 } 1534 } 1535 bestCandidate = (T)Enum.ToObject(typeof(T), currentValue); 1536 offset = (int)(value - currentValue); 1537 return true; 1538 } 1539 FillByteArrayWithArray(byte[] destinationArray, byte[] sourceArray)1540 public static void FillByteArrayWithArray(byte[] destinationArray, byte[] sourceArray) 1541 { 1542 var srcLength = sourceArray.Length; 1543 var dstLength = destinationArray.Length; 1544 if(srcLength >= dstLength) 1545 { 1546 Buffer.BlockCopy(sourceArray, 0, destinationArray, 0, dstLength); 1547 } 1548 else 1549 { 1550 var currentIndex = 0; 1551 while((currentIndex + srcLength) < dstLength) 1552 { 1553 Buffer.BlockCopy(sourceArray, 0, destinationArray, currentIndex, srcLength); 1554 currentIndex += srcLength; 1555 } 1556 var remindingElements = dstLength % srcLength; 1557 Buffer.BlockCopy(sourceArray, 0, destinationArray, currentIndex, remindingElements); 1558 } 1559 } 1560 CopyAndResize(this T[] source, int length)1561 public static T[] CopyAndResize<T>(this T[] source, int length) 1562 { 1563 if(source.Length == length) 1564 { 1565 return source.ToArray(); 1566 } 1567 var data = new T[length]; 1568 Array.Copy(source, data, Math.Min(source.Length, length)); 1569 return data; 1570 } 1571 CountTrailingZeroes(uint value)1572 public static int CountTrailingZeroes(uint value) 1573 { 1574 int count = 0; 1575 while((value & 0x1) == 0) 1576 { 1577 count += 1; 1578 value >>= 1; 1579 if(count == sizeof(uint) * 8) 1580 { 1581 break; 1582 } 1583 } 1584 return count; 1585 } 1586 1587 // Remaps a number from [inMin; inMax] to [outMin; outMax]. 1588 // Supports "reversing the direction", like remapping [0; 10] to [1; -1]. 1589 // If the input is null or outside the input range, returns null. 1590 public static decimal? RemapNumber(decimal? value, decimal inMin, decimal inMax, decimal outMin, decimal outMax) 1591 { 1592 if(value == null || value < inMin || value > inMax) 1593 { 1594 return null; 1595 } 1596 1597 var inRangeLen = inMax - inMin; 1598 var outRangeLen = outMax - outMin; 1599 return (value - inMin) * outRangeLen / inRangeLen + outMin; 1600 } 1601 AsBytes(uint[] data)1602 public static byte[] AsBytes(uint[] data) 1603 { 1604 var outLength = data.Length * sizeof(uint); 1605 var dataAsBytes = new byte[outLength]; 1606 Buffer.BlockCopy(data, 0, dataAsBytes, 0, outLength); 1607 return dataAsBytes; 1608 } 1609 1610 public static T ReadStruct<T>(this Stream @this) where T : struct 1611 { 1612 var structSize = Marshal.SizeOf(typeof(T)); 1613 return @this.ReadBytes(structSize).ToStruct<T>(); 1614 } 1615 1616 public static T ToStruct<T>(this byte[] @this) where T : struct 1617 { 1618 var size = @this.Length; 1619 var bufferPointer = Marshal.AllocHGlobal(size); 1620 Marshal.Copy(@this, 0, bufferPointer, size); 1621 var result = (T)Marshal.PtrToStructure(bufferPointer, typeof(T)); Marshal.FreeHGlobalAntmicro.Renode.Utilities.Misc.__anon31622 Marshal.FreeHGlobal(bufferPointer); 1623 return result; 1624 } 1625 TryGetNext(this IEnumerator<T> @this, out T element)1626 public static bool TryGetNext<T>(this IEnumerator<T> @this, out T element) 1627 { 1628 element = default(T); 1629 if(@this.MoveNext()) 1630 { 1631 element = @this.Current; 1632 return true; 1633 } 1634 return false; 1635 } 1636 1637 public static byte ReadWithOffset<T>(this T @this, long register, int offset, bool msbFirst = false) where T : IRegisterCollection 1638 { 1639 int innerOffset; 1640 uint outputValue; 1641 if(@this is ByteRegisterCollection) 1642 { 1643 ByteRegisterCollection byteRegisterCollection = @this as ByteRegisterCollection; 1644 innerOffset = 0; 1645 outputValue = (uint)byteRegisterCollection.Read(register); 1646 } 1647 else if(@this is WordRegisterCollection) 1648 { 1649 WordRegisterCollection wordRegisterCollection = @this as WordRegisterCollection; 1650 innerOffset = offset % 2; 1651 if(msbFirst) 1652 { 1653 innerOffset = 1 - innerOffset; 1654 } 1655 outputValue = (uint)wordRegisterCollection.Read(register + offset / 2); 1656 } 1657 else if(@this is DoubleWordRegisterCollection) 1658 { 1659 DoubleWordRegisterCollection doubleWordRegisterCollection = @this as DoubleWordRegisterCollection; 1660 innerOffset = offset % 4; 1661 if(msbFirst) 1662 { 1663 innerOffset = 3 - innerOffset; 1664 } 1665 outputValue = (uint)doubleWordRegisterCollection.Read(register + offset / 4); 1666 } 1667 else 1668 { 1669 throw new Exception("unreachable code"); 1670 } 1671 var mask = 0xFFUL << (innerOffset * 8); 1672 return (byte)((outputValue & mask) >> (innerOffset * 8)); 1673 } 1674 1675 public static void WriteWithOffset<T>(this T @this, long register, int offset, byte value, bool msbFirst = false) where T : IRegisterCollection 1676 { 1677 int innerOffset; 1678 uint previousValue; 1679 Action<uint> writeFunction; 1680 if(@this is ByteRegisterCollection) 1681 { 1682 ByteRegisterCollection byteRegisterCollection = @this as ByteRegisterCollection; 1683 innerOffset = 0; 1684 previousValue = (uint)byteRegisterCollection.Read(register); 1685 writeFunction = (data) => byteRegisterCollection.Write(register, (byte)data); 1686 } 1687 else if(@this is WordRegisterCollection) 1688 { 1689 WordRegisterCollection wordRegisterCollection = @this as WordRegisterCollection; 1690 innerOffset = offset % 2; 1691 if(msbFirst) 1692 { 1693 innerOffset = 1 - innerOffset; 1694 } 1695 previousValue = (uint)wordRegisterCollection.Read(register + offset / 2); 1696 writeFunction = (data) => wordRegisterCollection.Write(register + offset / 2, (ushort)data); 1697 } 1698 else if(@this is DoubleWordRegisterCollection) 1699 { 1700 DoubleWordRegisterCollection doubleWordRegisterCollection = @this as DoubleWordRegisterCollection; 1701 innerOffset = offset % 4; 1702 if(msbFirst) 1703 { 1704 innerOffset = 3 - innerOffset; 1705 } 1706 previousValue = (uint)doubleWordRegisterCollection.Read(register + offset / 4); 1707 writeFunction = (data) => doubleWordRegisterCollection.Write(register + offset / 4, (uint)data); 1708 } 1709 else 1710 { 1711 throw new Exception("unreachable code"); 1712 } 1713 var mask = 0xFFU << (innerOffset * 8); 1714 var newValue = (previousValue & ~mask) | ((uint)value << (innerOffset * 8)); 1715 writeFunction((uint)newValue); 1716 } 1717 Iterate(Func<T> function)1718 public static IEnumerable<T> Iterate<T>(Func<T> function) 1719 { 1720 while(true) 1721 { 1722 yield return function(); 1723 } 1724 } 1725 1726 #if !NET 1727 // Enumerable.TakeLast is in the standard library on .NET Core but isn't available on .NET Framework TakeLast(this IEnumerable<T> @this, int count)1728 public static IEnumerable<T> TakeLast<T>(this IEnumerable<T> @this, int count) 1729 { 1730 // This will enumerate the collection twice - it might be not optimal for performance sensitive operations 1731 return @this.Skip(Math.Max(0, @this.Count() - count)); 1732 } 1733 Chunk(this IEnumerable<T> @this, int size)1734 public static IEnumerable<T[]> Chunk<T>(this IEnumerable<T> @this, int size) 1735 { 1736 var buffer = new Queue<T>(); 1737 foreach(var item in @this) 1738 { 1739 buffer.Enqueue(item); 1740 if(buffer.Count == size) 1741 { 1742 yield return buffer.ToArray(); 1743 buffer.Clear(); 1744 } 1745 } 1746 1747 if(buffer.Count > 0) 1748 { 1749 yield return buffer.ToArray(); 1750 } 1751 } 1752 Fill(this T[] array, T value, int startIndex = 0, int? count = null)1753 public static void Fill<T>(this T[] array, T value, int startIndex = 0, int? count = null) 1754 { 1755 if(startIndex >= array.Length || startIndex < 0) 1756 { 1757 throw new ArgumentException("has to be a legal index", nameof(startIndex)); 1758 } 1759 count = count ?? array.Length - startIndex; 1760 if(startIndex + count.Value > array.Length) 1761 { 1762 throw new ArgumentException("value out of bounds", nameof(count)); 1763 } 1764 for(var i = 0; i < count.Value; ++i) 1765 { 1766 array[startIndex + i] = value; 1767 } 1768 } 1769 #else Fill(this T[] array, T value, int startIndex = 0, int? count = null)1770 public static void Fill<T>(this T[] array, T value, int startIndex = 0, int? count = null) 1771 { 1772 Array.Fill(array, value, startIndex, count ?? array.Length - startIndex); 1773 } 1774 #endif 1775 CastToULong(dynamic number)1776 public static ulong CastToULong(dynamic number) 1777 { 1778 if(new Type[] { typeof(byte), typeof(ushort), typeof(uint), typeof(ulong)}.Any((t) => number.GetType() == t)) 1779 { 1780 return (ulong)number; 1781 } 1782 throw new ArgumentException($"Can't cast {number.GetType()} to ulong", "number"); 1783 } 1784 Prefix(IEnumerable<T> enumerable, Func<T, T, T> function)1785 public static IEnumerable<T> Prefix<T>(IEnumerable<T> enumerable, Func<T, T, T> function) 1786 { 1787 var enumerator = enumerable.GetEnumerator(); 1788 // Using `out var` here causes a compiler crash in Mono 6.8.0.105+dfsg-3.3 from Debian 1789 if(!enumerator.TryGetNext(out T prefix)) 1790 { 1791 yield break; 1792 } 1793 while(enumerator.MoveNext()) 1794 { 1795 yield return prefix; 1796 prefix = function(prefix, enumerator.Current); 1797 } 1798 yield return prefix; 1799 } 1800 AddIf(this ICollection<T> collection, bool condition, T item)1801 public static void AddIf<T>(this ICollection<T> collection, bool condition, T item) 1802 { 1803 if(condition) 1804 { 1805 collection.Add(item); 1806 } 1807 } 1808 IsStructType(Type type)1809 public static bool IsStructType(Type type) 1810 { 1811 // According to docs, IsValueType return true for structs, enums and primitive types 1812 return type.IsValueType && !type.IsPrimitive && !type.IsEnum; 1813 } 1814 MemoryOperationToMpuAccess(MemoryOperation operation)1815 public static MpuAccess MemoryOperationToMpuAccess(MemoryOperation operation) 1816 { 1817 switch(operation) 1818 { 1819 case MemoryOperation.InsnFetch: 1820 return MpuAccess.InstructionFetch; 1821 case MemoryOperation.MemoryIOWrite: 1822 case MemoryOperation.MemoryWrite: 1823 return MpuAccess.Write; 1824 case MemoryOperation.MemoryIORead: 1825 case MemoryOperation.MemoryRead: 1826 return MpuAccess.Read; 1827 default: 1828 throw new ArgumentException("Invalid conversion from MemoryOperation to MpuAccess"); 1829 } 1830 } 1831 GCD(ulong a, ulong b)1832 public static ulong GCD(ulong a, ulong b) 1833 { 1834 while(a != 0 && b != 0) 1835 { 1836 if(a > b) 1837 { 1838 a %= b; 1839 } 1840 else 1841 { 1842 b %= a; 1843 } 1844 } 1845 return a | b; 1846 } 1847 LCM(ulong a, ulong b)1848 public static ulong LCM(ulong a, ulong b) 1849 { 1850 return a / GCD(a, b) * b; 1851 } 1852 ReturnThenAssign(ref T variable, T value)1853 public static T ReturnThenAssign<T>(ref T variable, T value) 1854 { 1855 var temp = variable; 1856 variable = value; 1857 return temp; 1858 } 1859 ReturnThenSet(ref bool variable, bool value = true)1860 public static bool ReturnThenSet(ref bool variable, bool value = true) => ReturnThenAssign(ref variable, value); 1861 1862 public static bool ReturnThenClear(ref bool variable) => ReturnThenAssign(ref variable, false); 1863 1864 public static DateTime UnixEpoch = new DateTime(1970, 1, 1); 1865 1866 private static readonly Lazy<string[]> hexStringLookup = new Lazy<string[]>(() => 1867 { 1868 var lookup = new string[0x100]; 1869 for(var i = 0; i < lookup.Length; ++i) 1870 { 1871 lookup[i] = $"{i:X02}"; 1872 } 1873 return lookup; 1874 }, isThreadSafe: true); 1875 } 1876 1877 public class MethodWithAttribute<T> where T : Attribute 1878 { MethodWithAttribute(MethodInfo method, T attribute)1879 public MethodWithAttribute(MethodInfo method, T attribute) 1880 { 1881 Method = method; 1882 Attribute = attribute; 1883 } 1884 1885 public MethodInfo Method { get; } 1886 public T Attribute { get; } 1887 } 1888 1889 public class LazyHexString<T> 1890 { LazyHexString(IEnumerable<T> collection)1891 public LazyHexString(IEnumerable<T> collection) 1892 { 1893 this.collection = collection; 1894 } 1895 ToString()1896 public override string ToString() 1897 { 1898 return Misc.PrettyPrintCollectionHex(collection); 1899 } 1900 1901 private readonly IEnumerable<T> collection; 1902 } 1903 } 1904 1905