mirror of
https://github.com/AssetRipper/Cpp2IL.git
synced 2026-11-13 04:26:33 -10:00
183 lines
6.5 KiB
C#
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;
|
|
}
|
|
}
|