from abc import ABCMeta, abstractmethod

import lldb
import json, struct, signal


class ScriptedProcess(metaclass=ABCMeta):
    """
    The base class for a scripted process.

    Most of the base class methods are `@abstractmethod` that need to be
    overwritten by the inheriting class.
    """

    capabilities = None
    memory_regions = None
    loaded_images = None
    threads = None
    metadata = None

    @abstractmethod
    def __init__(self, exe_ctx, args):
        """Construct a scripted process.

        Args:
            exe_ctx (lldb.SBExecutionContext): The execution context for the scripted process.
            args (lldb.SBStructuredData): A Dictionary holding arbitrary
                key/value pairs used by the scripted process.
        """
        target = None
        self.target = None
        self.args = None
        self.arch = None
        if isinstance(exe_ctx, lldb.SBExecutionContext):
            target = exe_ctx.target
        if isinstance(target, lldb.SBTarget) and target.IsValid():
            self.target = target
            self.arch = target.arch_name
            self.dbg = target.GetDebugger()
        if isinstance(args, lldb.SBStructuredData) and args.IsValid():
            self.args = args
        self.threads = {}
        self.loaded_images = []
        self.metadata = {}
        self.capabilities = {}
        self.pid = 42

    def get_capabilities(self):
        """Get a dictionary containing the process capabilities.

        Returns:
            Dict[str:bool]: The dictionary of capability, with the capability
            name as the key and a boolean flag as the value.
            The dictionary can be empty.
        """
        return self.capabilities

    def get_memory_region_containing_address(self, addr):
        """Get the memory region for the scripted process, containing a
            specific address.

        Args:
            addr (int): Address to look for in the scripted process memory
                regions.

        Returns:
            lldb.SBMemoryRegionInfo: The memory region containing the address.
                None if out of bounds.
        """
        return None

    def get_threads_info(self):
        """Get the dictionary describing the process' Scripted Threads.

        Returns:
            Dict: The dictionary of threads, with the thread ID as the key and
            a Scripted Thread instance as the value.
            The dictionary can be empty.
        """
        return self.threads

    @abstractmethod
    def read_memory_at_address(self, addr, size, error):
        """Get a memory buffer from the scripted process at a certain address,
            of a certain size.

        Args:
            addr (int): Address from which we should start reading.
            size (int): Size of the memory to read.
            error (lldb.SBError): Error object.

        Returns:
            lldb.SBData: An `lldb.SBData` buffer with the target byte size and
                byte order storing the memory read.
        """
        pass

    def write_memory_at_address(self, addr, data, error):
        """Write a buffer to the scripted process memory.

        Args:
            addr (int): Address from which we should start reading.
            data (lldb.SBData): An `lldb.SBData` buffer to write to the process
            memory.
            error (lldb.SBError): Error object.

        Returns:
            size (int): Size of the memory to read.
        """
        error.SetErrorString(
            "%s doesn't support memory writes." % self.__class__.__name__
        )
        return 0

    def get_loaded_images(self):
        """Get the list of loaded images for the scripted process.

        .. code-block:: python

            scripted_image = {
                uuid = "c6ea2b64-f77c-3d27-9528-74f507b9078b",
                path = "/usr/lib/dyld"
                load_addr = 0xbadc0ffee
            }

        Returns:
            List[scripted_image]: A list of `scripted_image` dictionaries
                containing for each entry the library UUID or its file path
                and its load address.
                None if the list is empty.
        """
        return self.loaded_images

    def get_process_id(self):
        """Get the scripted process identifier.

        Returns:
            int: The scripted process identifier.
        """
        return self.pid

    def launch(self):
        """Simulate the scripted process launch.

        Returns:
            lldb.SBError: An `lldb.SBError` with error code 0.
        """
        return lldb.SBError()

    def attach(self, attach_info):
        """Simulate the scripted process attach.

        Args:
            attach_info (lldb.SBAttachInfo): The information related to the
            process we're attaching to.

        Returns:
            lldb.SBError: An `lldb.SBError` with error code 0.
        """
        return lldb.SBError()

    def resume(self, should_stop=True):
        """Simulate the scripted process resume.

        Args:
            should_stop (bool): If True, resume will also force the process
            state to stopped after running it.

        Returns:
            lldb.SBError: An `lldb.SBError` with error code 0.
        """
        process = self.target.GetProcess()
        if not process:
            error = lldb.SBError()
            error.SetErrorString("Invalid process.")
            return error

        process.ForceScriptedState(lldb.eStateRunning)
        if should_stop:
            process.ForceScriptedState(lldb.eStateStopped)
        return lldb.SBError()

    @abstractmethod
    def is_alive(self):
        """Check if the scripted process is alive.

        Returns:
            bool: True if scripted process is alive. False otherwise.
        """
        pass

    @abstractmethod
    def get_scripted_thread_plugin(self):
        """Get scripted thread plugin name.

        Returns:
            str: Name of the scripted thread plugin.
        """
        return None

    def get_process_metadata(self):
        """Get some metadata for the scripted process.

        Returns:
            Dict: A dictionary containing metadata for the scripted process.
                  None if the process as no metadata.
        """
        return self.metadata

    def create_breakpoint(self, addr, error):
        """Create a breakpoint in the scripted process from an address.
            This is mainly used with interactive scripted process debugging.

        Args:
            addr (int): Address at which the breakpoint should be set.
            error (lldb.SBError): Error object.

        Returns:
            SBBreakpoint: A valid breakpoint object that was created a the specified
                          address. None if the breakpoint creation failed.
        """
        error.SetErrorString(
            "%s doesn't support creating breakpoints." % self.__class__.__name__
        )
        return False


class ScriptedThread(metaclass=ABCMeta):
    """
    The base class for a scripted thread.

    Most of the base class methods are `@abstractmethod` that need to be
    overwritten by the inheriting class.
    """

    @abstractmethod
    def __init__(self, process, args):
        """Construct a scripted thread.

        Args:
            process (ScriptedProcess/lldb.SBProcess): The process owning this thread.
            args (lldb.SBStructuredData): A Dictionary holding arbitrary
                key/value pairs used by the scripted thread.
        """
        self.target = None
        self.arch = None
        self.originating_process = None
        self.process = None
        self.args = None
        self.idx = 0
        self.tid = 0
        self.idx = None
        self.name = None
        self.queue = None
        self.state = None
        self.stop_reason = None
        self.register_info = None
        self.register_ctx = {}
        self.frames = []
        self.extended_info = []

        if (
            isinstance(process, ScriptedProcess)
            or isinstance(process, lldb.SBProcess)
            and process.IsValid()
        ):
            self.target = process.target
            triple = self.target.triple
            if triple:
                self.arch = triple.split("-")[0]
            self.originating_process = process
            self.process = self.target.GetProcess()
            self.get_register_info()

    def get_thread_idx(self):
        """Get the scripted thread index.

        Returns:
            int: The index of the scripted thread in the scripted process.
        """
        return self.idx

    def get_thread_id(self):
        """Get the scripted thread identifier.

        Returns:
            int: The identifier of the scripted thread.
        """
        return self.tid

    def get_name(self):
        """Get the scripted thread name.

        Returns:
            str: The name of the scripted thread.
        """
        return self.name

    def get_state(self):
        """Get the scripted thread state type.

        .. code-block:: python

            eStateStopped,   ///< Process or thread is stopped and can be examined.
            eStateRunning,   ///< Process or thread is running and can't be examined.
            eStateStepping,  ///< Process or thread is in the process of stepping and
                             /// can not be examined.
            eStateCrashed,   ///< Process or thread has crashed and can be examined.

        Returns:
            int: The state type of the scripted thread.
                 Returns lldb.eStateStopped by default.
        """
        return lldb.eStateStopped

    def get_queue(self):
        """Get the scripted thread associated queue name.
            This method is optional.

        Returns:
            str: The queue name associated with the scripted thread.
        """
        return self.queue

    @abstractmethod
    def get_stop_reason(self):
        """Get the dictionary describing the stop reason type with some data.
            This method is optional.

        Returns:
            Dict: The dictionary holding the stop reason type and the possibly
            the stop reason data.
        """
        pass

    def get_stackframes(self):
        """Get the list of stack frames for the scripted thread.

        .. code-block:: python

            scripted_frame = {
                idx = 0,
                pc = 0xbadc0ffee
            }

        Returns:
            List[scripted_frame]: A list of `scripted_frame` dictionaries
                containing at least for each entry, the frame index and
                the program counter value for that frame.
                The list can be empty.
        """
        return self.frames

    def get_register_info(self):
        if self.register_info is None:
            self.register_info = dict()
            if "x86_64" in self.arch:
                self.register_info["sets"] = ["General Purpose Registers"]
                self.register_info["registers"] = INTEL64_GPR
            elif "arm64" in self.arch or self.arch == "aarch64":
                self.register_info["sets"] = ["General Purpose Registers"]
                self.register_info["registers"] = ARM64_GPR
            elif "arm" in self.arch or "thumb" in self.arch:
                self.register_info["sets"] = ["General Purpose Registers"]
                self.register_info["registers"] = ARM32_GPR
            else:
                raise ValueError("Unknown architecture", self.arch)
        return self.register_info

    @abstractmethod
    def get_register_context(self):
        """Get the scripted thread register context

        Returns:
            str: A byte representing all register's value.
        """
        pass

    def get_extended_info(self):
        """Get scripted thread extended information.

        Returns:
            List: A list containing the extended information for the scripted process.
                  None if the thread as no extended information.
        """
        return self.extended_info

    def get_scripted_frame_plugin(self):
        """Get scripted frame plugin name.

        Returns:
            str: Name of the scripted frame plugin.
        """
        return None


class ScriptedFrame(metaclass=ABCMeta):
    """
    The base class for a scripted frame.

    Most of the base class methods are `@abstractmethod` that need to be
    overwritten by the inheriting class.
    """

    @abstractmethod
    def __init__(self, thread, args):
        """Construct a scripted frame.

        Args:
            thread (ScriptedThread/lldb.SBThread): The thread owning this frame.
            args (lldb.SBStructuredData): A Dictionary holding arbitrary
                key/value pairs used by the scripted frame.
        """
        self.target = None
        self.arch = None
        self.originating_thread = None
        self.thread = None
        self.args = None
        self.id = None
        self.name = None
        self.register_info = None
        self.register_ctx = {}
        self.variables = []

        if isinstance(thread, ScriptedThread) or (
            isinstance(thread, lldb.SBThread) and thread.IsValid()
        ):
            self.process = thread.process
            self.target = self.process.target
            triple = self.target.triple
            if triple:
                self.arch = triple.split("-")[0]
            tid = thread.tid if isinstance(thread, ScriptedThread) else thread.id
            self.originating_thread = thread
            self.thread = self.process.GetThreadByIndexID(tid)
            self.get_register_info()

    @abstractmethod
    def get_id(self):
        """Get the scripted frame identifier.

        Returns:
            int: The identifier of the scripted frame in the scripted thread.
        """
        pass

    def get_pc(self):
        """Get the scripted frame address.

        Returns:
            int: The optional address of the scripted frame in the scripted thread.
        """
        return None

    def get_symbol_context(self):
        """Get the scripted frame symbol context.

        Returns:
            lldb.SBSymbolContext: The symbol context of the scripted frame in the scripted thread.
        """
        return None

    def is_inlined(self):
        """Check if the scripted frame is inlined.

        Returns:
            bool: True if scripted frame is inlined. False otherwise.
        """
        return False

    def is_artificial(self):
        """Check if the scripted frame is artificial.

        Returns:
            bool: True if scripted frame is artificial. False otherwise.
        """
        return True

    def is_hidden(self):
        """Check if the scripted frame is hidden.

        Returns:
            bool: True if scripted frame is hidden. False otherwise.
        """
        return False

    def get_function_name(self):
        """Get the scripted frame function name.

        Returns:
            str: The function name of the scripted frame.
        """
        return self.name

    def get_display_function_name(self):
        """Get the scripted frame display function name.

        Returns:
            str: The display function name of the scripted frame.
        """
        return self.get_function_name()

    def get_variables(self, filters):
        """Get the scripted thread state type.

        Args:
            filter (lldb.SBVariablesOptions): The filter used to resolve the variables
        Returns:
            lldb.SBValueList: The SBValueList containing the SBValue for each resolved variable.
                              Returns None by default.
        """
        return None

    def get_register_info(self):
        if self.register_info is None:
            if isinstance(self.originating_thread, ScriptedThread):
                self.register_info = self.originating_thread.get_register_info()
            elif isinstance(self.originating_thread, lldb.SBThread):
                self.register_info = dict()
                if "x86_64" in self.arch:
                    self.register_info["sets"] = ["General Purpose Registers"]
                    self.register_info["registers"] = INTEL64_GPR
                elif "arm64" in self.arch or self.arch == "aarch64":
                    self.register_info["sets"] = ["General Purpose Registers"]
                    self.register_info["registers"] = ARM64_GPR
                elif "arm" in self.arch or "thumb" in self.arch:
                    self.register_info["sets"] = ["General Purpose Registers"]
                    self.register_info["registers"] = ARM32_GPR
                else:
                    raise ValueError("Unknown architecture", self.arch)
        return self.register_info

    @abstractmethod
    def get_register_context(self):
        """Get the scripted thread register context

        Returns:
            str: A byte representing all register's value.
        """
        pass

class PassthroughScriptedProcess(ScriptedProcess):
    driving_target = None
    driving_process = None

    def __init__(self, exe_ctx, args, launched_driving_process=True):
        super().__init__(exe_ctx, args)

        self.driving_target = None
        self.driving_process = None

        self.driving_target_idx = args.GetValueForKey("driving_target_idx")
        if self.driving_target_idx and self.driving_target_idx.IsValid():
            idx = self.driving_target_idx.GetUnsignedIntegerValue(42)
            self.driving_target = self.target.GetDebugger().GetTargetAtIndex(idx)

            if launched_driving_process:
                self.driving_process = self.driving_target.GetProcess()
                for driving_thread in self.driving_process:
                    structured_data = lldb.SBStructuredData()
                    structured_data.SetFromJSON(
                        json.dumps(
                            {
                                "driving_target_idx": idx,
                                "thread_idx": driving_thread.GetIndexID(),
                            }
                        )
                    )

                    self.threads[driving_thread.GetThreadID()] = (
                        PassthroughScriptedThread(self, structured_data)
                    )

                for module in self.driving_target.modules:
                    path = module.file.fullpath
                    load_addr = module.GetObjectFileHeaderAddress().GetLoadAddress(
                        self.driving_target
                    )
                    self.loaded_images.append({"path": path, "load_addr": load_addr})

    def get_memory_region_containing_address(self, addr):
        mem_region = lldb.SBMemoryRegionInfo()
        error = self.driving_process.GetMemoryRegionInfo(addr, mem_region)
        if error.Fail():
            return None
        return mem_region

    def read_memory_at_address(self, addr, size, error):
        data = lldb.SBData()
        bytes_read = self.driving_process.ReadMemory(addr, size, error)

        if error.Fail():
            return data

        data.SetDataWithOwnership(
            error,
            bytes_read,
            self.driving_target.GetByteOrder(),
            self.driving_target.GetAddressByteSize(),
        )

        return data

    def write_memory_at_address(self, addr, data, error):
        return self.driving_process.WriteMemory(
            addr, bytearray(data.uint8.all()), error
        )

    def get_process_id(self):
        return self.driving_process.GetProcessID()

    def is_alive(self):
        return True

    def get_scripted_thread_plugin(self):
        return f"{PassthroughScriptedThread.__module__}.{PassthroughScriptedThread.__name__}"


class PassthroughScriptedThread(ScriptedThread):
    def __init__(self, process, args):
        super().__init__(process, args)
        driving_target_idx = args.GetValueForKey("driving_target_idx")
        thread_idx = args.GetValueForKey("thread_idx")

        # TODO: Change to Walrus operator (:=) with oneline if assignment
        # Requires python 3.8
        val = thread_idx.GetUnsignedIntegerValue()
        if val is not None:
            self.idx = val

        self.driving_target = None
        self.driving_process = None
        self.driving_thread = None

        # TODO: Change to Walrus operator (:=) with oneline if assignment
        # Requires python 3.8
        val = driving_target_idx.GetUnsignedIntegerValue()
        if val is not None:
            self.driving_target = self.target.GetDebugger().GetTargetAtIndex(val)
            self.driving_process = self.driving_target.GetProcess()
            self.driving_thread = self.driving_process.GetThreadByIndexID(self.idx)

        if self.driving_thread:
            self.id = self.driving_thread.GetThreadID()

    def get_thread_id(self):
        return self.id

    def get_name(self):
        return f"{PassthroughScriptedThread.__name__}.thread-{self.idx}"

    def get_stop_reason(self):
        stop_reason = {"type": lldb.eStopReasonInvalid, "data": {}}

        if (
            self.driving_thread
            and self.driving_thread.IsValid()
            and self.get_thread_id() == self.driving_thread.GetThreadID()
        ):
            stop_reason["type"] = lldb.eStopReasonNone

            # TODO: Passthrough stop reason from driving process
            if self.driving_thread.GetStopReason() != lldb.eStopReasonNone:
                if "arm64" in self.arch:
                    stop_reason["type"] = lldb.eStopReasonException
                    stop_reason["data"]["desc"] = (
                        self.driving_thread.GetStopDescription(100)
                    )
                elif self.arch == "x86_64":
                    stop_reason["type"] = lldb.eStopReasonSignal
                    stop_reason["data"]["signal"] = signal.SIGTRAP
                else:
                    stop_reason["type"] = self.driving_thread.GetStopReason()

        return stop_reason

    def get_register_context(self):
        if not self.driving_thread or self.driving_thread.GetNumFrames() == 0:
            return None
        frame = self.driving_thread.GetFrameAtIndex(0)

        GPRs = None
        registerSet = frame.registers  # Returns an SBValueList.
        for regs in registerSet:
            if "general purpose" in regs.name.lower():
                GPRs = regs
                break

        if not GPRs:
            return None

        for reg in GPRs:
            self.register_ctx[reg.name] = int(reg.value, base=16)

        return struct.pack(f"{len(self.register_ctx)}Q", *self.register_ctx.values())

ARM32_GPR = [
    {
        "name": "r0",
        "bitsize": 32,
        "offset": 0,
        "encoding": "uint",
        "format": "hex",
        "set": 0,
        "gcc": 0,
        "dwarf": 0,
        "generic": "arg0",
        "alt-name": "arg0",
    },
    {
        "name": "r1",
        "bitsize": 32,
        "offset": 4,
        "encoding": "uint",
        "format": "hex",
        "set": 0,
        "gcc": 1,
        "dwarf": 1,
        "generic": "arg1",
        "alt-name": "arg1",
    },
    {
        "name": "r2",
        "bitsize": 32,
        "offset": 8,
        "encoding": "uint",
        "format": "hex",
        "set": 0,
        "gcc": 2,
        "dwarf": 2,
        "generic": "arg2",
        "alt-name": "arg2",
    },
    {
        "name": "r3",
        "bitsize": 32,
        "offset": 12,
        "encoding": "uint",
        "format": "hex",
        "set": 0,
        "gcc": 3,
        "dwarf": 3,
        "generic": "arg3",
        "alt-name": "arg3",
    },
    {
        "name": "r4",
        "bitsize": 32,
        "offset": 16,
        "encoding": "uint",
        "format": "hex",
        "set": 0,
        "gcc": 4,
        "dwarf": 4,
    },
    {
        "name": "r5",
        "bitsize": 32,
        "offset": 20,
        "encoding": "uint",
        "format": "hex",
        "set": 0,
        "gcc": 5,
        "dwarf": 5,
    },
    {
        "name": "r6",
        "bitsize": 32,
        "offset": 24,
        "encoding": "uint",
        "format": "hex",
        "set": 0,
        "gcc": 6,
        "dwarf": 6,
    },
    {
        "name": "r7",
        "bitsize": 32,
        "offset": 28,
        "encoding": "uint",
        "format": "hex",
        "set": 0,
        "gcc": 7,
        "dwarf": 7,
    },
    {
        "name": "r8",
        "bitsize": 32,
        "offset": 32,
        "encoding": "uint",
        "format": "hex",
        "set": 0,
        "gcc": 8,
        "dwarf": 8,
    },
    {
        "name": "r9",
        "bitsize": 32,
        "offset": 36,
        "encoding": "uint",
        "format": "hex",
        "set": 0,
        "gcc": 9,
        "dwarf": 9,
    },
    {
        "name": "r10",
        "bitsize": 32,
        "offset": 40,
        "encoding": "uint",
        "format": "hex",
        "set": 0,
        "gcc": 10,
        "dwarf": 10,
    },
    {
        "name": "r11",
        "bitsize": 32,
        "offset": 44,
        "encoding": "uint",
        "format": "hex",
        "set": 0,
        "gcc": 11,
        "dwarf": 11,
        "generic": "fp",
        "alt-name": "fp",
    },
    {
        "name": "r12",
        "bitsize": 32,
        "offset": 48,
        "encoding": "uint",
        "format": "hex",
        "set": 0,
        "gcc": 12,
        "dwarf": 12,
    },
    {
        "name": "sp",
        "bitsize": 32,
        "offset": 52,
        "encoding": "uint",
        "format": "hex",
        "set": 0,
        "gcc": 13,
        "dwarf": 13,
        "generic": "sp",
        "alt-name": "r13",
    },
    {
        "name": "lr",
        "bitsize": 32,
        "offset": 56,
        "encoding": "uint",
        "format": "hex",
        "set": 0,
        "gcc": 14,
        "dwarf": 14,
        "generic": "lr",
        "alt-name": "r14",
    },
    {
        "name": "pc",
        "bitsize": 32,
        "offset": 60,
        "encoding": "uint",
        "format": "hex",
        "set": 0,
        "gcc": 15,
        "dwarf": 15,
        "generic": "pc",
        "alt-name": "r15",
    },
    {
        "name": "cpsr",
        "bitsize": 32,
        "offset": 64,
        "encoding": "uint",
        "format": "hex",
        "set": 0,
        "dwarf": 128,
    },
]

ARM64_GPR = [
    {
        "name": "x0",
        "bitsize": 64,
        "offset": 0,
        "encoding": "uint",
        "format": "hex",
        "set": 0,
        "gcc": 0,
        "dwarf": 0,
        "generic": "arg0",
        "alt-name": "arg0",
    },
    {
        "name": "x1",
        "bitsize": 64,
        "offset": 8,
        "encoding": "uint",
        "format": "hex",
        "set": 0,
        "gcc": 1,
        "dwarf": 1,
        "generic": "arg1",
        "alt-name": "arg1",
    },
    {
        "name": "x2",
        "bitsize": 64,
        "offset": 16,
        "encoding": "uint",
        "format": "hex",
        "set": 0,
        "gcc": 2,
        "dwarf": 2,
        "generic": "arg2",
        "alt-name": "arg2",
    },
    {
        "name": "x3",
        "bitsize": 64,
        "offset": 24,
        "encoding": "uint",
        "format": "hex",
        "set": 0,
        "gcc": 3,
        "dwarf": 3,
        "generic": "arg3",
        "alt-name": "arg3",
    },
    {
        "name": "x4",
        "bitsize": 64,
        "offset": 32,
        "encoding": "uint",
        "format": "hex",
        "set": 0,
        "gcc": 4,
        "dwarf": 4,
        "generic": "arg4",
        "alt-name": "arg4",
    },
    {
        "name": "x5",
        "bitsize": 64,
        "offset": 40,
        "encoding": "uint",
        "format": "hex",
        "set": 0,
        "gcc": 5,
        "dwarf": 5,
        "generic": "arg5",
        "alt-name": "arg5",
    },
    {
        "name": "x6",
        "bitsize": 64,
        "offset": 48,
        "encoding": "uint",
        "format": "hex",
        "set": 0,
        "gcc": 6,
        "dwarf": 6,
        "generic": "arg6",
        "alt-name": "arg6",
    },
    {
        "name": "x7",
        "bitsize": 64,
        "offset": 56,
        "encoding": "uint",
        "format": "hex",
        "set": 0,
        "gcc": 7,
        "dwarf": 7,
        "generic": "arg7",
        "alt-name": "arg7",
    },
    {
        "name": "x8",
        "bitsize": 64,
        "offset": 64,
        "encoding": "uint",
        "format": "hex",
        "set": 0,
        "gcc": 8,
        "dwarf": 8,
    },
    {
        "name": "x9",
        "bitsize": 64,
        "offset": 72,
        "encoding": "uint",
        "format": "hex",
        "set": 0,
        "gcc": 9,
        "dwarf": 9,
    },
    {
        "name": "x10",
        "bitsize": 64,
        "offset": 80,
        "encoding": "uint",
        "format": "hex",
        "set": 0,
        "gcc": 10,
        "dwarf": 10,
    },
    {
        "name": "x11",
        "bitsize": 64,
        "offset": 88,
        "encoding": "uint",
        "format": "hex",
        "set": 0,
        "gcc": 11,
        "dwarf": 11,
    },
    {
        "name": "x12",
        "bitsize": 64,
        "offset": 96,
        "encoding": "uint",
        "format": "hex",
        "set": 0,
        "gcc": 12,
        "dwarf": 12,
    },
    {
        "name": "x13",
        "bitsize": 64,
        "offset": 104,
        "encoding": "uint",
        "format": "hex",
        "set": 0,
        "gcc": 13,
        "dwarf": 13,
    },
    {
        "name": "x14",
        "bitsize": 64,
        "offset": 112,
        "encoding": "uint",
        "format": "hex",
        "set": 0,
        "gcc": 14,
        "dwarf": 14,
    },
    {
        "name": "x15",
        "bitsize": 64,
        "offset": 120,
        "encoding": "uint",
        "format": "hex",
        "set": 0,
        "gcc": 15,
        "dwarf": 15,
    },
    {
        "name": "x16",
        "bitsize": 64,
        "offset": 128,
        "encoding": "uint",
        "format": "hex",
        "set": 0,
        "gcc": 16,
        "dwarf": 16,
    },
    {
        "name": "x17",
        "bitsize": 64,
        "offset": 136,
        "encoding": "uint",
        "format": "hex",
        "set": 0,
        "gcc": 17,
        "dwarf": 17,
    },
    {
        "name": "x18",
        "bitsize": 64,
        "offset": 144,
        "encoding": "uint",
        "format": "hex",
        "set": 0,
        "gcc": 18,
        "dwarf": 18,
    },
    {
        "name": "x19",
        "bitsize": 64,
        "offset": 152,
        "encoding": "uint",
        "format": "hex",
        "set": 0,
        "gcc": 19,
        "dwarf": 19,
    },
    {
        "name": "x20",
        "bitsize": 64,
        "offset": 160,
        "encoding": "uint",
        "format": "hex",
        "set": 0,
        "gcc": 20,
        "dwarf": 20,
    },
    {
        "name": "x21",
        "bitsize": 64,
        "offset": 168,
        "encoding": "uint",
        "format": "hex",
        "set": 0,
        "gcc": 21,
        "dwarf": 21,
    },
    {
        "name": "x22",
        "bitsize": 64,
        "offset": 176,
        "encoding": "uint",
        "format": "hex",
        "set": 0,
        "gcc": 22,
        "dwarf": 22,
    },
    {
        "name": "x23",
        "bitsize": 64,
        "offset": 184,
        "encoding": "uint",
        "format": "hex",
        "set": 0,
        "gcc": 23,
        "dwarf": 23,
    },
    {
        "name": "x24",
        "bitsize": 64,
        "offset": 192,
        "encoding": "uint",
        "format": "hex",
        "set": 0,
        "gcc": 24,
        "dwarf": 24,
    },
    {
        "name": "x25",
        "bitsize": 64,
        "offset": 200,
        "encoding": "uint",
        "format": "hex",
        "set": 0,
        "gcc": 25,
        "dwarf": 25,
    },
    {
        "name": "x26",
        "bitsize": 64,
        "offset": 208,
        "encoding": "uint",
        "format": "hex",
        "set": 0,
        "gcc": 26,
        "dwarf": 26,
    },
    {
        "name": "x27",
        "bitsize": 64,
        "offset": 216,
        "encoding": "uint",
        "format": "hex",
        "set": 0,
        "gcc": 27,
        "dwarf": 27,
    },
    {
        "name": "x28",
        "bitsize": 64,
        "offset": 224,
        "encoding": "uint",
        "format": "hex",
        "set": 0,
        "gcc": 28,
        "dwarf": 28,
    },
    {
        "name": "x29",
        "bitsize": 64,
        "offset": 232,
        "encoding": "uint",
        "format": "hex",
        "set": 0,
        "gcc": 29,
        "dwarf": 29,
        "generic": "fp",
        "alt-name": "fp",
    },
    {
        "name": "x30",
        "bitsize": 64,
        "offset": 240,
        "encoding": "uint",
        "format": "hex",
        "set": 0,
        "gcc": 30,
        "dwarf": 30,
        "generic": "lr",
        "alt-name": "lr",
    },
    {
        "name": "sp",
        "bitsize": 64,
        "offset": 248,
        "encoding": "uint",
        "format": "hex",
        "set": 0,
        "gcc": 31,
        "dwarf": 31,
        "generic": "sp",
        "alt-name": "sp",
    },
    {
        "name": "pc",
        "bitsize": 64,
        "offset": 256,
        "encoding": "uint",
        "format": "hex",
        "set": 0,
        "gcc": 32,
        "dwarf": 32,
        "generic": "pc",
        "alt-name": "pc",
    },
    {
        "name": "cpsr",
        "bitsize": 32,
        "offset": 264,
        "encoding": "uint",
        "format": "hex",
        "set": 0,
        "gcc": 33,
        "dwarf": 33,
    },
]

INTEL64_GPR = [
    {
        "name": "rax",
        "bitsize": 64,
        "offset": 0,
        "encoding": "uint",
        "format": "hex",
        "set": 0,
        "gcc": 0,
        "dwarf": 0,
    },
    {
        "name": "rbx",
        "bitsize": 64,
        "offset": 8,
        "encoding": "uint",
        "format": "hex",
        "set": 0,
        "gcc": 3,
        "dwarf": 3,
    },
    {
        "name": "rcx",
        "bitsize": 64,
        "offset": 16,
        "encoding": "uint",
        "format": "hex",
        "set": 0,
        "gcc": 2,
        "dwarf": 2,
        "generic": "arg4",
        "alt-name": "arg4",
    },
    {
        "name": "rdx",
        "bitsize": 64,
        "offset": 24,
        "encoding": "uint",
        "format": "hex",
        "set": 0,
        "gcc": 1,
        "dwarf": 1,
        "generic": "arg3",
        "alt-name": "arg3",
    },
    {
        "name": "rdi",
        "bitsize": 64,
        "offset": 32,
        "encoding": "uint",
        "format": "hex",
        "set": 0,
        "gcc": 5,
        "dwarf": 5,
        "generic": "arg1",
        "alt-name": "arg1",
    },
    {
        "name": "rsi",
        "bitsize": 64,
        "offset": 40,
        "encoding": "uint",
        "format": "hex",
        "set": 0,
        "gcc": 4,
        "dwarf": 4,
        "generic": "arg2",
        "alt-name": "arg2",
    },
    {
        "name": "rbp",
        "bitsize": 64,
        "offset": 48,
        "encoding": "uint",
        "format": "hex",
        "set": 0,
        "gcc": 6,
        "dwarf": 6,
        "generic": "fp",
        "alt-name": "fp",
    },
    {
        "name": "rsp",
        "bitsize": 64,
        "offset": 56,
        "encoding": "uint",
        "format": "hex",
        "set": 0,
        "gcc": 7,
        "dwarf": 7,
        "generic": "sp",
        "alt-name": "sp",
    },
    {
        "name": "r8",
        "bitsize": 64,
        "offset": 64,
        "encoding": "uint",
        "format": "hex",
        "set": 0,
        "gcc": 8,
        "dwarf": 8,
        "generic": "arg5",
        "alt-name": "arg5",
    },
    {
        "name": "r9",
        "bitsize": 64,
        "offset": 72,
        "encoding": "uint",
        "format": "hex",
        "set": 0,
        "gcc": 9,
        "dwarf": 9,
        "generic": "arg6",
        "alt-name": "arg6",
    },
    {
        "name": "r10",
        "bitsize": 64,
        "offset": 80,
        "encoding": "uint",
        "format": "hex",
        "set": 0,
        "gcc": 10,
        "dwarf": 10,
    },
    {
        "name": "r11",
        "bitsize": 64,
        "offset": 88,
        "encoding": "uint",
        "format": "hex",
        "set": 0,
        "gcc": 11,
        "dwarf": 11,
    },
    {
        "name": "r12",
        "bitsize": 64,
        "offset": 96,
        "encoding": "uint",
        "format": "hex",
        "set": 0,
        "gcc": 12,
        "dwarf": 12,
    },
    {
        "name": "r13",
        "bitsize": 64,
        "offset": 104,
        "encoding": "uint",
        "format": "hex",
        "set": 0,
        "gcc": 13,
        "dwarf": 13,
    },
    {
        "name": "r14",
        "bitsize": 64,
        "offset": 112,
        "encoding": "uint",
        "format": "hex",
        "set": 0,
        "gcc": 14,
        "dwarf": 14,
    },
    {
        "name": "r15",
        "bitsize": 64,
        "offset": 120,
        "encoding": "uint",
        "format": "hex",
        "set": 0,
        "gcc": 15,
        "dwarf": 15,
    },
    {
        "name": "rip",
        "bitsize": 64,
        "offset": 128,
        "encoding": "uint",
        "format": "hex",
        "set": 0,
        "gcc": 16,
        "dwarf": 16,
        "generic": "pc",
        "alt-name": "pc",
    },
    {
        "name": "rflags",
        "bitsize": 64,
        "offset": 136,
        "encoding": "uint",
        "format": "hex",
        "set": 0,
        "generic": "flags",
        "alt-name": "flags",
    },
    {
        "name": "cs",
        "bitsize": 64,
        "offset": 144,
        "encoding": "uint",
        "format": "hex",
        "set": 0,
    },
    {
        "name": "fs",
        "bitsize": 64,
        "offset": 152,
        "encoding": "uint",
        "format": "hex",
        "set": 0,
    },
    {
        "name": "gs",
        "bitsize": 64,
        "offset": 160,
        "encoding": "uint",
        "format": "hex",
        "set": 0,
    },
]
