//===-- RegisterContext_x86.h -----------------------------------*- C++ -*-===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

#ifndef liblldb_RegisterContext_x86_H_
#define liblldb_RegisterContext_x86_H_

//---------------------------------------------------------------------------
// i386 gcc, dwarf, gdb enums
//---------------------------------------------------------------------------

// Register numbers seen in eh_frame (eRegisterKindGCC)
//
// From Jason Molenda: "gcc registers" is the register numbering used in the eh_frame
// CFI.  The only registers that are described in eh_frame CFI are those that are
// preserved across function calls aka callee-saved aka non-volatile.  And none
// of the floating point registers on x86 are preserved across function calls.
//
// The only reason there is a "gcc register" and a "dwarf register" is because of a
// mistake years and years ago with i386 where they got esp and ebp
// backwards when they emitted the eh_frame instructions.  Once there were
// binaries In The Wild using the reversed numbering, we had to stick with it
// forever.
enum
{
    // 2nd parameter in DwarfRegNum() is regnum for exception handling on x86-32.
    // See http://llvm.org/docs/WritingAnLLVMBackend.html#defining-a-register
    gcc_eax_i386 = 0,
    gcc_ecx_i386,
    gcc_edx_i386,
    gcc_ebx_i386,

    // on Darwin esp & ebp are reversed in the eh_frame section for i386 (versus dwarf's reg numbering).
    // To be specific:
    //    i386+darwin eh_frame:        4 is ebp, 5 is esp
    //    i386+everyone else eh_frame: 4 is esp, 5 is ebp
    //    i386 dwarf:                  4 is esp, 5 is ebp
    // lldb will get the darwin-specific eh_frame reg numberings from debugserver instead of here so we
    // only encode the 4 == esp, 5 == ebp numbers in this generic header.
    gcc_esp_i386,
    gcc_ebp_i386,  
    gcc_esi_i386,
    gcc_edi_i386,
    gcc_eip_i386,
    gcc_eflags_i386,
    gcc_st0_i386 = 12,
    gcc_st1_i386,
    gcc_st2_i386,
    gcc_st3_i386,
    gcc_st4_i386,
    gcc_st5_i386,
    gcc_st6_i386,
    gcc_st7_i386,
    gcc_xmm0_i386 = 21,
    gcc_xmm1_i386,
    gcc_xmm2_i386,
    gcc_xmm3_i386,
    gcc_xmm4_i386,
    gcc_xmm5_i386,
    gcc_xmm6_i386,
    gcc_xmm7_i386,
    gcc_mm0_i386 = 29,
    gcc_mm1_i386,
    gcc_mm2_i386,
    gcc_mm3_i386,
    gcc_mm4_i386,
    gcc_mm5_i386,
    gcc_mm6_i386,
    gcc_mm7_i386,
};

// DWARF register numbers (eRegisterKindDWARF)
// Intel's x86 or IA-32
enum
{
    // General Purpose Registers.
    dwarf_eax_i386 = 0,
    dwarf_ecx_i386,
    dwarf_edx_i386,
    dwarf_ebx_i386,
    dwarf_esp_i386,
    dwarf_ebp_i386,
    dwarf_esi_i386,
    dwarf_edi_i386,
    dwarf_eip_i386,
    dwarf_eflags_i386,
    // Floating Point Registers
    dwarf_st0_i386 = 11,
    dwarf_st1_i386,
    dwarf_st2_i386,
    dwarf_st3_i386,
    dwarf_st4_i386,
    dwarf_st5_i386,
    dwarf_st6_i386,
    dwarf_st7_i386,
    // SSE Registers
    dwarf_xmm0_i386 = 21,
    dwarf_xmm1_i386,
    dwarf_xmm2_i386,
    dwarf_xmm3_i386,
    dwarf_xmm4_i386,
    dwarf_xmm5_i386,
    dwarf_xmm6_i386,
    dwarf_xmm7_i386,
    // MMX Registers
    dwarf_mm0_i386 = 29,
    dwarf_mm1_i386,
    dwarf_mm2_i386,
    dwarf_mm3_i386,
    dwarf_mm4_i386,
    dwarf_mm5_i386,
    dwarf_mm6_i386,
    dwarf_mm7_i386,
    dwarf_fctrl_i386 = 37, // x87 control word
    dwarf_fstat_i386 = 38, // x87 status word
    dwarf_mxcsr_i386 = 39,
    dwarf_es_i386 = 40,
    dwarf_cs_i386 = 41,
    dwarf_ss_i386 = 42,
    dwarf_ds_i386 = 43,
    dwarf_fs_i386 = 44,
    dwarf_gs_i386 = 45

    // I believe the ymm registers use the dwarf_xmm%_i386 register numbers and
    //  then differentiate based on size of the register.
};

// Register numbers GDB uses (eRegisterKindGDB)
//
// From Jason Molenda: The "gdb numbers" are what you would see in the stabs debug format.
enum
{
    gdb_eax_i386,
    gdb_ecx_i386,
    gdb_edx_i386,
    gdb_ebx_i386,
    gdb_esp_i386,
    gdb_ebp_i386,
    gdb_esi_i386,
    gdb_edi_i386,
    gdb_eip_i386,
    gdb_eflags_i386,
    gdb_cs_i386,
    gdb_ss_i386,
    gdb_ds_i386,
    gdb_es_i386,
    gdb_fs_i386,
    gdb_gs_i386,
    gdb_st0_i386 = 16,
    gdb_st1_i386,
    gdb_st2_i386,
    gdb_st3_i386,
    gdb_st4_i386,
    gdb_st5_i386,
    gdb_st6_i386,
    gdb_st7_i386,
    gdb_fctrl_i386, // FPU Control Word
    gdb_fstat_i386, // FPU Status Word
    gdb_ftag_i386,  // FPU Tag Word
    gdb_fiseg_i386, // FPU IP Selector 
    gdb_fioff_i386, // FPU IP Offset
    gdb_foseg_i386, // FPU Operand Pointer Selector
    gdb_fooff_i386, // FPU Operand Pointer Offset
    gdb_fop_i386,   // Last Instruction Opcode
    gdb_xmm0_i386 = 32,
    gdb_xmm1_i386,
    gdb_xmm2_i386,
    gdb_xmm3_i386,
    gdb_xmm4_i386,
    gdb_xmm5_i386,
    gdb_xmm6_i386,
    gdb_xmm7_i386,
    gdb_mxcsr_i386 = 40,
    gdb_ymm0h_i386,
    gdb_ymm1h_i386,
    gdb_ymm2h_i386,
    gdb_ymm3h_i386,
    gdb_ymm4h_i386,
    gdb_ymm5h_i386,
    gdb_ymm6h_i386,
    gdb_ymm7h_i386,
    gdb_mm0_i386,
    gdb_mm1_i386,
    gdb_mm2_i386,
    gdb_mm3_i386,
    gdb_mm4_i386,
    gdb_mm5_i386,
    gdb_mm6_i386,
    gdb_mm7_i386,
};

//---------------------------------------------------------------------------
// AMD x86_64, AMD64, Intel EM64T, or Intel 64 gcc, dwarf, gdb enums
//---------------------------------------------------------------------------

// GCC and DWARF Register numbers (eRegisterKindGCC & eRegisterKindDWARF)
//  This is the spec I used (as opposed to x86-64-abi-0.99.pdf):
//  http://software.intel.com/sites/default/files/article/402129/mpx-linux64-abi.pdf
enum
{
    // GP Registers
    gcc_dwarf_rax_x86_64 = 0,
    gcc_dwarf_rdx_x86_64,
    gcc_dwarf_rcx_x86_64,
    gcc_dwarf_rbx_x86_64,
    gcc_dwarf_rsi_x86_64,
    gcc_dwarf_rdi_x86_64,
    gcc_dwarf_rbp_x86_64,
    gcc_dwarf_rsp_x86_64,
    // Extended GP Registers
    gcc_dwarf_r8_x86_64 = 8,
    gcc_dwarf_r9_x86_64,
    gcc_dwarf_r10_x86_64,
    gcc_dwarf_r11_x86_64,
    gcc_dwarf_r12_x86_64,
    gcc_dwarf_r13_x86_64,
    gcc_dwarf_r14_x86_64,
    gcc_dwarf_r15_x86_64,
    // Return Address (RA) mapped to RIP
    gcc_dwarf_rip_x86_64 = 16,
    // SSE Vector Registers
    gcc_dwarf_xmm0_x86_64 = 17,
    gcc_dwarf_xmm1_x86_64,
    gcc_dwarf_xmm2_x86_64,
    gcc_dwarf_xmm3_x86_64,
    gcc_dwarf_xmm4_x86_64,
    gcc_dwarf_xmm5_x86_64,
    gcc_dwarf_xmm6_x86_64,
    gcc_dwarf_xmm7_x86_64,
    gcc_dwarf_xmm8_x86_64,
    gcc_dwarf_xmm9_x86_64,
    gcc_dwarf_xmm10_x86_64,
    gcc_dwarf_xmm11_x86_64,
    gcc_dwarf_xmm12_x86_64,
    gcc_dwarf_xmm13_x86_64,
    gcc_dwarf_xmm14_x86_64,
    gcc_dwarf_xmm15_x86_64,
    // Floating Point Registers
    gcc_dwarf_st0_x86_64 = 33,
    gcc_dwarf_st1_x86_64,
    gcc_dwarf_st2_x86_64,
    gcc_dwarf_st3_x86_64,
    gcc_dwarf_st4_x86_64,
    gcc_dwarf_st5_x86_64,
    gcc_dwarf_st6_x86_64,
    gcc_dwarf_st7_x86_64,
    // MMX Registers
    gcc_dwarf_mm0_x86_64 = 41,
    gcc_dwarf_mm1_x86_64,
    gcc_dwarf_mm2_x86_64,
    gcc_dwarf_mm3_x86_64,
    gcc_dwarf_mm4_x86_64,
    gcc_dwarf_mm5_x86_64,
    gcc_dwarf_mm6_x86_64,
    gcc_dwarf_mm7_x86_64,
    // Control and Status Flags Register
    gcc_dwarf_rflags_x86_64 = 49,
    //  selector registers
    gcc_dwarf_es_x86_64 = 50,
    gcc_dwarf_cs_x86_64,
    gcc_dwarf_ss_x86_64,
    gcc_dwarf_ds_x86_64,
    gcc_dwarf_fs_x86_64,
    gcc_dwarf_gs_x86_64,
    // Floating point control registers
    gcc_dwarf_mxcsr_x86_64 = 64, // Media Control and Status
    gcc_dwarf_fctrl_x86_64,      // x87 control word
    gcc_dwarf_fstat_x86_64,      // x87 status word
    // Upper Vector Registers    
    gcc_dwarf_ymm0h_x86_64 = 67,
    gcc_dwarf_ymm1h_x86_64,
    gcc_dwarf_ymm2h_x86_64,
    gcc_dwarf_ymm3h_x86_64,
    gcc_dwarf_ymm4h_x86_64,
    gcc_dwarf_ymm5h_x86_64,
    gcc_dwarf_ymm6h_x86_64,
    gcc_dwarf_ymm7h_x86_64,
    gcc_dwarf_ymm8h_x86_64,
    gcc_dwarf_ymm9h_x86_64,
    gcc_dwarf_ymm10h_x86_64,
    gcc_dwarf_ymm11h_x86_64,
    gcc_dwarf_ymm12h_x86_64,
    gcc_dwarf_ymm13h_x86_64,
    gcc_dwarf_ymm14h_x86_64,
    gcc_dwarf_ymm15h_x86_64,
    // AVX2 Vector Mask Registers
    // gcc_dwarf_k0_x86_64 = 118,
    // gcc_dwarf_k1_x86_64,
    // gcc_dwarf_k2_x86_64,
    // gcc_dwarf_k3_x86_64,
    // gcc_dwarf_k4_x86_64,
    // gcc_dwarf_k5_x86_64,
    // gcc_dwarf_k6_x86_64,
    // gcc_dwarf_k7_x86_64,
};

// GDB Register numbers (eRegisterKindGDB)
enum
{
    // GP Registers
    gdb_rax_x86_64 = 0,
    gdb_rbx_x86_64,
    gdb_rcx_x86_64,
    gdb_rdx_x86_64,
    gdb_rsi_x86_64,
    gdb_rdi_x86_64,
    gdb_rbp_x86_64,
    gdb_rsp_x86_64,
    // Extended GP Registers
    gdb_r8_x86_64,
    gdb_r9_x86_64,
    gdb_r10_x86_64,
    gdb_r11_x86_64,
    gdb_r12_x86_64,
    gdb_r13_x86_64,
    gdb_r14_x86_64,
    gdb_r15_x86_64,
    // Return Address (RA) mapped to RIP
    gdb_rip_x86_64,
    // Control and Status Flags Register
    gdb_rflags_x86_64,
    gdb_cs_x86_64,
    gdb_ss_x86_64,
    gdb_ds_x86_64,
    gdb_es_x86_64,
    gdb_fs_x86_64,
    gdb_gs_x86_64,
    // Floating Point Registers
    gdb_st0_x86_64,
    gdb_st1_x86_64,
    gdb_st2_x86_64,
    gdb_st3_x86_64,
    gdb_st4_x86_64,
    gdb_st5_x86_64,
    gdb_st6_x86_64,
    gdb_st7_x86_64,
    gdb_fctrl_x86_64,
    gdb_fstat_x86_64,
    gdb_ftag_x86_64,
    gdb_fiseg_x86_64,
    gdb_fioff_x86_64,
    gdb_foseg_x86_64,
    gdb_fooff_x86_64,
    gdb_fop_x86_64,
    // SSE Vector Registers
    gdb_xmm0_x86_64 = 40,
    gdb_xmm1_x86_64,
    gdb_xmm2_x86_64,
    gdb_xmm3_x86_64,
    gdb_xmm4_x86_64,
    gdb_xmm5_x86_64,
    gdb_xmm6_x86_64,
    gdb_xmm7_x86_64,
    gdb_xmm8_x86_64,
    gdb_xmm9_x86_64,
    gdb_xmm10_x86_64,
    gdb_xmm11_x86_64,
    gdb_xmm12_x86_64,
    gdb_xmm13_x86_64,
    gdb_xmm14_x86_64,
    gdb_xmm15_x86_64,
    // Floating point control registers
    gdb_mxcsr_x86_64 = 56,
    gdb_ymm0h_x86_64,
    gdb_ymm1h_x86_64,
    gdb_ymm2h_x86_64,
    gdb_ymm3h_x86_64,
    gdb_ymm4h_x86_64,
    gdb_ymm5h_x86_64,
    gdb_ymm6h_x86_64,
    gdb_ymm7h_x86_64,
    gdb_ymm8h_x86_64,
    gdb_ymm9h_x86_64,
    gdb_ymm10h_x86_64,
    gdb_ymm11h_x86_64,
    gdb_ymm12h_x86_64,
    gdb_ymm13h_x86_64,
    gdb_ymm14h_x86_64,
    gdb_ymm15h_x86_64
};

//---------------------------------------------------------------------------
// Generic floating-point registers
//---------------------------------------------------------------------------

struct MMSReg
{
    uint8_t bytes[10];
    uint8_t pad[6];
};

struct XMMReg
{
    uint8_t bytes[16];      // 128-bits for each XMM register
};

// i387_fxsave_struct
struct FXSAVE
{
    uint16_t fctrl;         // FPU Control Word (fcw)
    uint16_t fstat;         // FPU Status Word (fsw)
    uint16_t ftag;          // FPU Tag Word (ftw)
    uint16_t fop;           // Last Instruction Opcode (fop)
    union
    {
        struct
        {
            uint64_t fip;   // Instruction Pointer
            uint64_t fdp;   // Data Pointer
        } x86_64;
        struct
        {
            uint32_t fioff;   // FPU IP Offset (fip)
            uint32_t fiseg;   // FPU IP Selector (fcs)
            uint32_t fooff;   // FPU Operand Pointer Offset (foo)
            uint32_t foseg;   // FPU Operand Pointer Selector (fos)
        } i386_;// Added _ in the end to avoid error with gcc defining i386 in some cases
    } ptr;
    uint32_t mxcsr;         // MXCSR Register State
    uint32_t mxcsrmask;     // MXCSR Mask 
    MMSReg   stmm[8];       // 8*16 bytes for each FP-reg = 128 bytes
    XMMReg   xmm[16];       // 16*16 bytes for each XMM-reg = 256 bytes
    uint32_t padding[24];
};

//---------------------------------------------------------------------------
// Extended floating-point registers
//---------------------------------------------------------------------------

struct YMMHReg
{
    uint8_t  bytes[16];     // 16 * 8 bits for the high bytes of each YMM register
};

struct YMMReg
{
    uint8_t  bytes[32];     // 16 * 16 bits for each YMM register
};

struct YMM
{
    YMMReg   ymm[16];       // assembled from ymmh and xmm registers
};

struct XSAVE_HDR
{
    uint64_t  xstate_bv;    // OS enabled xstate mask to determine the extended states supported by the processor
    uint64_t  reserved1[2];
    uint64_t  reserved2[5];
} __attribute__((packed));

// x86 extensions to FXSAVE (i.e. for AVX processors) 
struct XSAVE 
{
    FXSAVE    i387;         // floating point registers typical in i387_fxsave_struct
    XSAVE_HDR header;       // The xsave_hdr_struct can be used to determine if the following extensions are usable
    YMMHReg   ymmh[16];     // High 16 bytes of each of 16 YMM registers (the low bytes are in FXSAVE.xmm for compatibility with SSE)
    // Slot any extensions to the register file here
} __attribute__((packed, aligned (64)));

// Floating-point registers
struct FPR
{
    // Thread state for the floating-point unit of the processor read by ptrace.
    union XSTATE
    {
        FXSAVE   fxsave;    // Generic floating-point registers.
        XSAVE    xsave;     // x86 extended processor state.
    } xstate;
};

//---------------------------------------------------------------------------
// ptrace PTRACE_GETREGSET, PTRACE_SETREGSET structure
//---------------------------------------------------------------------------

struct IOVEC
{
    void    *iov_base;      // pointer to XSAVE
    size_t   iov_len;       // sizeof(XSAVE)
};

#endif
