Files
Cpp2IL/Cpp2IL.Core/Extensions/MiscExtensions.cs

183 lines
6.5 KiB
C#

using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Gee.External.Capstone.Arm;
using Gee.External.Capstone.Arm64;
using Iced.Intel;
using Instruction = Iced.Intel.Instruction;
namespace Cpp2IL.Core.Extensions;
public static class MiscExtensions
{
public static ISIL.Register MakeIndependent(this Register reg) => new ISIL.Register(null, reg.ToString().ToLower());
public static ulong GetImmediateSafe(this Instruction instruction, int op) => instruction.GetOpKind(op).IsImmediate() ? instruction.GetImmediate(op) : 0;
public static bool IsJump(this Mnemonic mnemonic) => mnemonic is Mnemonic.Call or >= Mnemonic.Ja and <= Mnemonic.Js;
public static bool IsConditionalJump(this Mnemonic mnemonic) => mnemonic.IsJump() && mnemonic != Mnemonic.Jmp && mnemonic != Mnemonic.Call;
//Arm Extensions
public static ArmRegister? RegisterSafe(this ArmOperand operand) => operand.Type != ArmOperandType.Register ? null : operand.Register;
public static bool IsImmediate(this ArmOperand operand) => operand.Type is ArmOperandType.CImmediate or ArmOperandType.Immediate or ArmOperandType.PImmediate;
public static int ImmediateSafe(this ArmOperand operand) => operand.IsImmediate() ? operand.Immediate : 0;
private static ArmOperand? MemoryOperand(ArmInstruction instruction) => instruction.Details.Operands.FirstOrDefault(a => a.Type == ArmOperandType.Memory);
public static ArmRegister? MemoryBase(this ArmInstruction instruction) => MemoryOperand(instruction)?.Memory.Base;
public static ArmRegister? MemoryIndex(this ArmInstruction instruction) => MemoryOperand(instruction)?.Memory.Index;
public static int MemoryOffset(this ArmInstruction instruction) => MemoryOperand(instruction)?.Memory.Displacement ?? 0;
//Arm64 Extensions
public static Arm64Register? RegisterSafe(this Arm64Operand operand) => operand.Type != Arm64OperandType.Register ? null : operand.Register;
public static bool IsImmediate(this Arm64Operand operand) => operand.Type is Arm64OperandType.CImmediate or Arm64OperandType.Immediate;
public static long ImmediateSafe(this Arm64Operand operand) => operand.IsImmediate() ? operand.Immediate : 0;
internal static Arm64Operand? MemoryOperand(this Arm64Instruction instruction) => instruction.Details.Operands.FirstOrDefault(a => a.Type == Arm64OperandType.Memory);
public static Arm64Register? MemoryBase(this Arm64Instruction instruction) => instruction.MemoryOperand()?.Memory.Base;
public static Arm64Register? MemoryIndex(this Arm64Instruction instruction) => instruction.MemoryOperand()?.Memory.Index;
public static int MemoryOffset(this Arm64Instruction instruction) => instruction.MemoryOperand()?.Memory.Displacement ?? 0;
public static bool IsConditionalMove(this Instruction instruction)
{
switch (instruction.Mnemonic)
{
case Mnemonic.Cmove:
case Mnemonic.Cmovne:
case Mnemonic.Cmovs:
case Mnemonic.Cmovns:
case Mnemonic.Cmovg:
case Mnemonic.Cmovge:
case Mnemonic.Cmovl:
case Mnemonic.Cmovle:
case Mnemonic.Cmova:
case Mnemonic.Cmovae:
case Mnemonic.Cmovb:
case Mnemonic.Cmovbe:
return true;
default:
return false;
}
}
public static Stack<T> Clone<T>(this Stack<T> original)
{
var arr = new T[original.Count];
original.CopyTo(arr, 0);
Array.Reverse(arr);
return new Stack<T>(arr);
}
public static List<T> Clone<T>(this List<T> original)
{
var arr = new T[original.Count];
original.CopyTo(arr, 0);
return [.. arr];
}
public static Dictionary<T1, T2> Clone<T1, T2>(this Dictionary<T1, T2> original) where T1 : notnull
=> new(original);
public static T[] SubArray<T>(this T[] data, int index, int length) => data.SubArray(index..(index + length));
public static T RemoveAndReturn<T>(this List<T> data, int index)
{
var result = data[index];
data.RemoveAt(index);
return result;
}
public static IEnumerable<T> Repeat<T>(this T t, int count)
{
for (int i = 0; i < count; i++)
{
yield return t;
}
}
public static string Repeat(this string source, int count)
{
var res = new StringBuilder();
for (var i = 0; i < count; i++)
{
res.Append(source);
}
return res.ToString();
}
internal static T[] SubArray<T>(this T[] source, Range range)
{
if (!range.Start.IsFromEnd && !range.End.IsFromEnd)
if (range.Start.Value > range.End.Value)
throw new Exception($"Range {range} - Start must be less than end, when both are fixed offsets");
var (offset, len) = range.GetOffsetAndLength(source.Length);
var dest = new T[len];
Array.Copy(source, offset, dest, 0, len);
return dest;
}
public static T? GetValueSafely<T>(this T[] arr, int i) where T : class
{
if (i >= arr.Length)
return null;
return arr[i];
}
public static bool IsImmediate(this OpKind opKind) => opKind is >= OpKind.Immediate8 and <= OpKind.Immediate32to64;
public static void TrimEndWhile<T>(this List<T> instructions, Func<T, bool> predicate)
{
var i = instructions.Count - 1;
for (; i >= 0; i--)
{
if (!predicate(instructions[i]))
{
break;
}
}
var toRemove = instructions.Count - 1 - i;
if (toRemove <= 0)
return;
instructions.RemoveRange(i, toRemove);
}
public static IEnumerable<T> Peek<T>(this IEnumerable<T> enumerable, Action<T> action)
{
return enumerable.Select(t =>
{
action(t);
return t;
});
}
public static unsafe uint ReadUInt(this ReadOnlySpan<byte> span, int start)
{
if (start >= span.Length)
throw new ArgumentOutOfRangeException(nameof(start), $"start=[{start}], mem.Length=[{span.Length}]");
fixed (byte* ptr = &span[start])
return *(uint*)ptr;
}
public static bool BitsAreEqual(this BitArray first, BitArray second)
{
if (first.Count != second.Count)
return false;
bool areDifferent = false;
for (int i = 0; i < first.Count && !areDifferent; i++)
areDifferent = first.Get(i) != second.Get(i);
return !areDifferent;
}
}