/*
 *      Interactive disassembler (IDA).
 *      Version 3.05
 *      Copyright (c) 1990-95 by Ilfak Guilfanov. (2:5020/209@fidonet)
 *      ALL RIGHTS RESERVED.
 *
 */

//
//      Portable Executable file format (MS Windows 95, MS Windows NT)
//

#ifndef _PE_H_
#define _PE_H_

#include <time.h>
#include <stddef.h>

#pragma pack(push, 1)
//-----------------------------------------------------------------------
//
// 32-bit Portable EXE Header
//
//-----------------------------------------------------------------------
struct petab_t
{
  uint32 rva;           // relative virtual address
  uint32 size;          // size
};                      // PE va/size array element

template <class pointer_t>
struct peheader_tpl
{
  int32 signature;      // 00 Current value is "PE/0/0".

#define PEEXE_ID   0x4550   // 'PE' followed by two zeroes
#define BPEEXE_ID  0x455042 // Borland's extenson for DPMI'host
#define PLEXE_ID   0x4C50   // 'PL', PharLap TNT DOS-Extender Lite file that uses real mode APIs
#define TEEXE_ID   0x5A56   // 'VZ', EFI Terse Executable
  uint16 machine;       // 04 This field specifies the type of CPU
                  // compatibility required by this image to run.
                  // The values are:
#define PECPU_UNKNOWN 0x0000    // unknown

#define PECPU_80386   0x014C    // 80386
#define PECPU_80486   0x014D    // 80486
#define PECPU_80586   0x014E    // 80586

#define PECPU_R3000   0x0162    // MIPS Mark I (R2000, R3000)
#define PECPU_R6000   0x0163    // MIPS Mark II (R6000)
#define PECPU_R4000   0x0166    // MIPS Mark III (R4000)
#define PECPU_R10000  0x0168    // MIPS Mark IV (R10000)
#define PECPU_WCEMIPSV2 0x0169  // MIPS little-endian WCE v2
#define PECPU_MIPS16    0x0266  // MIPS16
#define PECPU_MIPSFPU   0x0366  // MIPS with FPU
#define PECPU_MIPSFPU16 0x0466  // MIPS16 with FPU

#define PECPU_ALPHA   0x0184    // DEC Alpha
#define PECPU_ALPHA64 0x0284    // Dec Alpha 64-bit

#define PECPU_SH3     0x01A2    // SH3
#define PECPU_SH3DSP  0x01A3    // SH3DSP
#define PECPU_SH3E    0x01A4    // SH3E
#define PECPU_SH4     0x01A6    // SH4
#define PECPU_SH5     0x01A8    // SH5

#define PECPU_ARM     0x01C0    // ARM
#define PECPU_ARMI    0x01C2    // ARM with Thumb
#define PECPU_ARMV7   0x01C4    // ARMv7 (or higher) Thumb mode only

#define PECPU_AM33    0x01D3    // Matsushita (Panasonic) AM33/MN10300

#define PECPU_PPC     0x01F0    // PowerPC
#define PECPU_PPCFP   0x01F1    // PowerPC with floating-point
#define PECPU_PPCBE   0x01F2    // PowerPC Big-Endian

#define PECPU_M32R    0x9041    // M32R little-endian

#define PECPU_IA64    0x0200    // Intel Itanium IA64
#define PECPU_EPOC    0x0A00    // ARM EPOC
#define PECPU_AMD64   0x8664    // AMD64 (x64)
#define PECPU_ARM64   0xAA64    // ARMv8 in 64-bit mode
#define PECPU_M68K    0x0268    // Motorola 68000 series
#define PECPU_EBC     0x0EBC    // EFI Bytecode
#define PECPU_CEF     0x0CEF    // ?
#define PECPU_CEE     0xC0EE    // ?
#define PECPU_TRICORE 0x0520    // TRICORE (Infineon)

#define PECPU_LOONGARCH32 0x6232 // LoongArch 32-bit processor family
#define PECPU_LOONGARCH64 0x6264 // LoongArch 64-bit processor family

#define PECPU_RISCV32  0x5032    // RISC-V 32-bit address space
#define PECPU_RISCV64  0x5064    // RISC-V 64-bit address space
#define PECPU_RISCV128 0x5128    // RISC-V 128-bit address space

  bool is_64bit_cpu(void) const
  {
    return machine == PECPU_AMD64
        || machine == PECPU_IA64
        || machine == PECPU_ARM64;
  }
  bool is_pc(void) const
  {
    return machine == PECPU_80386
        || machine == PECPU_80486
        || machine == PECPU_80586
        || machine == PECPU_AMD64;
  }
  bool is_mips(void) const
  {
    return machine == PECPU_R3000
        || machine == PECPU_R6000
        || machine == PECPU_R4000
        || machine == PECPU_R10000
        || machine == PECPU_WCEMIPSV2
        || machine == PECPU_MIPS16
        || machine == PECPU_MIPSFPU
        || machine == PECPU_MIPSFPU16;
  }

  bool is_arm(void) const
  {
    return machine == PECPU_ARM
        || machine == PECPU_ARMI
        || machine == PECPU_ARMV7;
  }

  bool has_code16_bit(void) const
  {
    return is_arm() || is_mips();
  }

  uint16 nobjs;     // 06 This field specifies the number of entries
                    // in the Object Table.
  qtime32_t datetime; // 08 Used to store the time and date the file was
                    // created or modified by the linker.
  uint32 symtof;    // 0C Symbol Table Offset
  uint32 nsyms;     // 10 Number of Symbols in Symbol Table
  uint16 hdrsize;   // 14 This is the number of remaining bytes in the NT
                    // header that follow the FLAGS field.
  uint16 flags;     // 16 Flag bits for the image.  0000h Program image.
#define PEF_BRVHI 0x8000        // Big endian: MSB precedes LSB in memory
#define PEF_UP    0x4000        // File should be run only on a UP machine
#define PEF_DLL   0x2000        // Dynamic Link Library (DLL)
#define PEF_SYS   0x1000        // System file
#define PEF_NSWAP 0x0800        // If the image is on network media, fully load it and copy it to the swap file.
#define PEF_SWAP  0x0400        // If image is on removable media,
                                // copy and run from swap file
#define PEF_NODEB 0x0200        // Debugging info stripped
#define PEF_32BIT 0x0100        // 32-bit word machine
#define PEF_BRVLO 0x0080        // Little endian: LSB precedes MSB in memory
#define PEF_16BIT 0x0040        // 16-bit word machine
#define PEF_2GB   0x0020        // App can handle > 2gb addresses
#define PEF_TMWKS 0x0010        // Aggressively trim working set
#define PEF_NOSYM 0x0008        // Local symbols stripped
#define PEF_NOLIN 0x0004        // Line numbers stripped
#define PEF_EXEC  0x0002        // Image is executable
#define PEF_NOFIX 0x0001        // Relocation info stripped

  int32 first_section_pos(int32 peoff) const
    { return peoff + offsetof(peheader_tpl, magic) + hdrsize; }

        // COFF fields:

  uint16 magic;       // 18 Magic
#define MAGIC_ROM       0x107   // ROM image
#define MAGIC_P32       0x10B   // Normal PE file
#define MAGIC_P32_PLUS  0x20B   // 64-bit image
  bool is_pe_plus(void) const { return magic == MAGIC_P32_PLUS; }
  uchar vstamp_major; // 1A Major Linker Version
  uchar vstamp_minor; // 1B Minor Linker Version
  uint32 tsize;        // 1C TEXT size (padded)
  uint32 dsize;        // 20 DATA size (padded)
  uint32 bsize;        // 24 BSS  size (padded)
  uint32 entry;        // 28 Entry point
  uint32 text_start;   // 2C Base of text
  union
  {
    struct
    {
      uint32 data_start;   // 30 Base of data

        // Win32/NT extensions:

      uint32 imagebase32;    // 34 Virtual base of the image.
    };
    uint64 imagebase64;
  };
  uint64 imagebase() const
  {
    if ( is_pe_plus() )
      return imagebase64;
    else
      return imagebase32;
  }
                      // This will be the virtual address of the first
                      // byte of the file (Dos Header).  This must be
                      // a multiple of 64K.
  uint32 objalign;    // 38 The alignment of the objects. This must be a power
                      // of 2 between 512 and 256M inclusive. The default
                      // is 64K.
  uint32 filealign;   // 3C Alignment factor used to align image pages.
                      // The alignment factor (in bytes) used to align the
                      // base of the image pages and to determine the
                      // granularity of per-object trailing zero pad.
                      // Larger alignment factors will cost more file space;
                      // smaller alignment factors will impact demand load
                      // performance, perhaps significantly. Of the two,
                      // wasting file space is preferable.  This value
                      // should be a power of 2 between 512 and 64K inclusive.
                      // Get the file position aligned:
#define FILEALIGN 512 // IDA5.1: it seems that for standard object alignment (if 4096)
                      // the Windows kernel does not use filealign
                      // (just checks that it is in the valid range) but uses 512
  uint32 get_align_mask(void) const { return ((objalign == 4096 || filealign == 0) ? FILEALIGN : filealign) - 1; }
  uint32 align_up_in_file(uint32 pos) const
  {
    if ( is_efi() )  // apparently EFI images are not aligned
      return pos;
    uint32 mask = get_align_mask();
    return (pos+mask) & ~mask;
  }
  uint32 align_down_in_file(uint32 pos) const
  {
    return is_efi() ? pos : (pos & ~get_align_mask());
  }
  uint16 osmajor;     // 40 OS version number required to run this image.
  uint16 osminor;     // 42 OS version number required to run this image.
  uint16 imagemajor;  // 44 User major version number.
  uint16 imageminor;  // 46 User minor version number.
  uint16 subsysmajor; // 48 Subsystem major version number.
  uint16 subsysminor; // 4A Subsystem minor version number.

  uint32 subsystem_version(void) const
  {
    return (subsysmajor << 16) | subsysminor;
  }

  uint32 reserved;    // 4C
  uint32 imagesize;   // 50 The virtual size (in bytes) of the image.
                      // This includes all headers.  The total image size
                      // must be a multiple of Object Align.
  uint32 allhdrsize;  // 54 Total header size. The combined size of the Dos
                      // Header, PE Header and Object Table.
  uint32 checksum;    // 58 Checksum for entire file.  Set to 0 by the linker.
  uint16 subsys;      // 5C NT Subsystem required to run this image.
#define PES_UNKNOWN 0x0000      // Unknown
#define PES_NATIVE  0x0001      // Native
#define PES_WINGUI  0x0002      // Windows GUI
#define PES_WINCHAR 0x0003      // Windows Character
#define PES_OS2CHAR 0x0005      // OS/2 Character
#define PES_POSIX   0x0007      // Posix Character
#define PES_NAT9x   0x0008      // image is a native Win9x driver
#define PES_WINCE   0x0009      // Runs on Windows CE.
#define PES_EFI_APP 0x000A      // EFI application.
#define PES_EFI_BDV 0x000B      // EFI driver that provides boot services.
#define PES_EFI_RDV 0x000C      // EFI driver that provides runtime services.
#define PES_EFI_ROM 0x000D      // EFI ROM image
#define PES_XBOX    0x000E      // Xbox system
#define PES_BOOTAPP 0x0010      // Windows Boot Application

  bool is_efi(void) const
  {
    return subsys == PES_EFI_APP
        || subsys == PES_EFI_BDV
        || subsys == PES_EFI_RDV
        || subsys == PES_EFI_ROM;
  }
  bool is_console_app(void) const
  {
    return subsys == PES_WINCHAR
        || subsys == PES_OS2CHAR
        || subsys == PES_POSIX;
  }
  bool is_userland(void) const
  {
    return subsys == PES_WINGUI
        || subsys == PES_WINCHAR
        || subsys == PES_OS2CHAR
        || subsys == PES_POSIX
        || subsys == PES_WINCE;
  }
  uint16 dllflags;    // 5E Indicates special loader requirements.
#define PEL_PINIT           0x0001 // Per-Process Library Initialization.
#define PEL_PTERM           0x0002 // Per-Process Library Termination.
#define PEL_TINIT           0x0004 // Per-Thread Library Initialization.
#define PEL_TTERM           0x0008 // Per-Thread Library Termination.
#define PEL_HIGH_ENT        0x0020 // Image can handle a high entropy 64-bit virtual address space.
#define PEL_DYNAMIC_BASE    0x0040 // The DLL can be relocated at load time.
#define PEL_FORCE_INTEGRITY 0x0080 // Code integrity checks are forced.
#define PEF_NX              0x0100 // The image is compatible with data execution prevention (DEP).
#define PEF_NO_ISOLATION    0x0200 // The image is isolation aware, but should not be isolated.
#define PEF_NO_SEH          0x0400 // The image does not use structured exception handling (SEH). No handlers can be called in this image.
#define PEL_NO_BIND         0x0800 // Do not bind image
#define PEL_APPCONTAINER    0x1000 // Image should execute in an AppContainer
#define PEL_WDM_DRV         0x2000 // Driver is a WDM Driver
#define PEL_GUARDCF         0x4000 // Image supports Control Flow Guard checking
#define PEL_TSRVAWA         0x8000 // Image is Terminal Server aware

  pointer_t stackres; // 60 Stack size needed for image. The memory is
                      // reserved, but only the STACK COMMIT SIZE is
                      // committed. The next page of the stack is a
                      // 'guarded page'. When the application hits the
                      // guarded page, the guarded page becomes valid,
                      // and the next page becomes the guarded page.
                      // This continues until the RESERVE SIZE is reached.
  pointer_t stackcom; // 64 Stack commit size.
  pointer_t heapres;  // 68 Size of local heap to reserve.
  pointer_t heapcom;  // 6C Amount to commit in local heap.
  uint32 loaderflags; // 70 ?
  uint32 nrvas;       // 74 Indicates the size of the VA/SIZE array
                      // that follows.
  petab_t expdir;     //  0 78 Export Directory
  petab_t impdir;     //  1 80 Import Directory
  petab_t resdir;     //  2 88 Resource Directory
  petab_t excdir;     //  3 90 Exception Directory
  petab_t secdir;     //  4 98 Security Directory
                      //       The Certificate Table entry points to a table of
                      //       attribute certificates. These certificates are not
                      //       loaded into memory as part of the image. As such,
                      //       the first field of this entry, which is normally
                      //       an RVA, is a File Pointer instead
  petab_t reltab;     //  5 A0 Relocation Table
  petab_t debdir;     //  6 A8 Debug Directory
  petab_t desstr;     //  7 B0 Description String
  petab_t cputab;     //  8 B8 Machine Value
  petab_t tlsdir;     //  9 C0 TLS Directory
  petab_t loddir;     // 10 Load Configuration Directory
  petab_t bimtab;     // 11 Bound Import Table address and size.
  petab_t iat;        // 12 Import Address Table address and size.
  petab_t didtab;     // 13 Address and size of the Delay Import Descriptor.
  petab_t comhdr;     // 14 COM+ Runtime Header address and size
  petab_t x00tab;     // 15 Reserved

  bool is_te() const
    { return signature == TEEXE_ID; }
  inline bool has_debdir() const;
};

typedef peheader_tpl<uint32> peheader_t;
typedef peheader_tpl<uint64> peheader64_t;

constexpr size_t total_rvatab_size = sizeof(peheader_t) - offsetof(peheader_t, expdir);
constexpr size_t total_rvatab_count = total_rvatab_size / sizeof(petab_t);

//-----------------------------------------------------------------------
struct diheader_t
{
  uint16 signature;     // 00 Current value is "DI"
#define DBG_ID 0x4944
  uint16 flags2;        // 02 ?? pedump mentions about this
                        //    I've never seen something other than 0
  uint16 machine;       // 04 This field specifies the type of CPU
                        //    compatibility required by this image to run.
  uint16 flags;         // 06 Flag bits for the image.
  qtime32_t datetime;   // 08 Used to store the time and date the file was
                        //    created or modified by the linker.
  uint32 checksum;      // 12 Checksum
  uint32 imagebase;     // 16 Virtual base of the image.
                        //    This will be the virtual address of the first
                        //    byte of the file (Dos Header).  This must be
                        //    a multiple of 64K.
  uint32 imagesize;     // 20 The virtual size (in bytes) of the image.
                        //    This includes all headers.  The total image size
                        //    must be a multiple of Object Align.
  uint32 n_secs;        // 24 Number of sections
  uint32 exp_name_size; // 28 Exported Names Size
  uint32 dbg_dir_size;  // 32 Debug Directory Size
  uint32 reserved[3];   // 36 Reserved fields
};

//-------------------------------------------------------------------------
//
//      S E C T I O N S
//
struct pesection_t
{
  char   s_name[8];   /* section name */
  uint32 s_vsize;     /* virtual size */
  uint32 s_vaddr;     /* virtual address */
  uint32 s_psize;     /* physical size */
  int32  s_scnptr;    /* file ptr to raw data for section */
  int32  s_relptr;    /* file ptr to relocation */
  int32  s_lnnoptr;   /* file ptr to line numbers */
  uint16 s_nreloc;    /* number of relocation entries */
  uint16 s_nlnno;     /* number of line number entries */
  int32  s_flags;     /* flags */
#define PEST_REG     0x00000000 // obsolete: regular: allocated, relocated, loaded
#define PEST_DUMMY   0x00000001 // obsolete: dummy: not allocated, relocated, not loaded
#define PEST_NOLOAD  0x00000002 // obsolete: noload: allocated, relocated, not loaded
#define PEST_GROUP   0x00000004 // obsolete: grouped: formed of input sections
#define PEST_PAD     0x00000008 // obsolete: padding: not allocated, not relocated, loaded
#define PEST_COPY    0x00000010 // obsolete: copy: for decision function used
                                //    by field update; not
                                //    allocated, not relocated,
                                //    loaded; reloc & lineno
                                //    entries processed normally */
#define PEST_TEXT    0x00000020 // section contains text only
#define PEST_DATA    0x00000040 // section contains data only
#define PEST_BSS     0x00000080 // section contains bss only
#define PEST_EXCEPT  0x00000100 // obsolete: Exception section
#define PEST_INFO    0x00000200 // Comment: not allocated, not relocated, not loaded
#define PEST_OVER    0x00000400 // obsolete: Overlay: not allocated, relocated, not loaded
#define PEST_LIB     0x00000800 // ".lib" section: treated like PEST_INFO

#define PEST_LOADER  0x00001000 // Loader section: COMDAT
#define PEST_DEBUG   0x00002000 // Debug section:
#define PEST_TYPCHK  0x00004000 // Type check section:
#define PEST_OVRFLO  0x00008000 // obsolete: RLD and line number overflow sec hdr
#define PEST_F0000   0x000F0000 // Unknown
#define PEST_ALIGN   0x00F00000 // Alignment 2^(x-1):
  uint32 get_sect_alignment(void) const
  {
    int align = ((s_flags >> 20) & 15);
    return align == 0 ? 0 : (1 << (align-1));
  }

  asize_t get_vsize(const peheader_t &pe) const
  {
    return align_up(s_vsize ? s_vsize : s_psize, pe.objalign ? pe.objalign : 1);
  }

  asize_t get_psize(const peheader_t &pe) const
  {
    return qmin(s_psize, get_vsize(pe));
  }

#define PEST_1000000 0x01000000 // Unknown
#define PEST_DISCARD 0x02000000 // Discardable
#define PEST_NOCACHE 0x04000000 // Not cachable
#define PEST_NOPAGE  0x08000000 // Not pageable
#define PEST_SHARED  0x10000000 // Shareable
#define PEST_EXEC    0x20000000 // Executable
#define PEST_READ    0x40000000 // Readable
#define PEST_WRITE   0x80000000 // Writable
};

//-------------------------------------------------------------------------
//
//      E X P O R T S
//
struct peexpdir_t
{
  uint32 flags;     // Currently set to zero.
  qtime32_t datetime; // Time/Date the export data was created.
  uint16 major;     // A user settable major/minor version number.
  uint16 minor;
  uint32 dllname;   // Relative Virtual Address of the Dll asciiz Name.
                    // This is the address relative to the Image Base.
  uint32 ordbase;   // First valid exported ordinal. This field specifies
                    // the starting ordinal number for the export
                    // address table for this image. Normally set to 1.
  uint32 naddrs;    // Indicates number of entries in the Export Address
                    // Table.
  uint32 nnames;    // This indicates the number of entries in the Name
                    // Ptr Table (and parallel Ordinal Table).
  uint32 adrtab;    // Relative Virtual Address of the Export Address
                    // Table. This address is relative to the Image Base.
  uint32 namtab;    // Relative Virtual Address of the Export Name Table
                    // Pointers. This address is relative to the
                    // beginning of the Image Base. This table is an
                    // array of RVA's with # NAMES entries.
  uint32 ordtab;    // Relative Virtual Address of Export Ordinals
                    // Table Entry. This address is relative to the
                    // beginning of the Image Base.
};

//-------------------------------------------------------------------------
//
//      I M P O R T S
//
struct peimpdir_t
{
  uint32 table1;    // aka OriginalFirstThunk
  qtime32_t datetime;  // Time/Date the import data was pre-snapped or
                    // zero if not pre-snapped.
  uint32 fchain;    // Forwarder chain
  uint32 dllname;   // Relative Virtual Address of the Dll asciiz Name.
                    // This is the address relative to the Image Base.
  uint32 looktab;   // aka FirstThunk
                    // This field contains the address of the start of
                    // the import lookup table for this image. The address
                    // is relative to the beginning of the Image Base.
#define hibit(type) ((type(-1)>>1) ^ type(-1))
#define IMP_BY_ORD32 hibit(uint32)  // Import by ordinal, otherwise by name
#define IMP_BY_ORD64 hibit(uint64)  // Import by ordinal, otherwise by name

  peimpdir_t(void) { memset(this, 0, sizeof(peimpdir_t)); }
};

struct dimpdir_t    // delayed load import table
{
  uint32 attrs;      // Attributes.
#define DIMP_NOBASE 0x0001  // pe.imagebase was not added to addresses
  uint32 dllname;    // Relative virtual address of the name of the DLL
                    // to be loaded. The name resides in the read-only
                    // data section of the image.
  uint32 handle;    // Relative virtual address of the module handle
                    // (in the data section of the image) of the DLL to
                    // be delay-loaded. Used for storage by the routine
                    // supplied to manage delay-loading.
  uint32 diat;      // Relative virtual address of the delay-load import
                    // address table. See below for further details.
  uint32 dint;      // Relative virtual address of the delay-load name
                    // table, which contains the names of the imports
                    // that may need to be loaded. Matches the layout of
                    // the Import Name Table, Section 6.4.3. Hint/Name Table.
  uint32 dbiat;     // Bound Delay Import Table. Relative virtual address
                    // of the bound delay-load address table, if it exists.
  uint32 duiat;     // Unload Delay Import Table. Relative virtual address
                    // of the unload delay-load address table, if it exists.
                    // This is an exact copy of the Delay Import Address
                    // Table. In the event that the caller unloads the DLL,
                    // this table should be copied back over the Delay IAT
                    // such that subsequent calls to the DLL continue to
                    // use the thunking mechanism correctly.
  qtime32_t datetime;  // Time stamp of DLL to which this image has been bound.
};


// Bound Import Table format:

struct BOUND_IMPORT_DESCRIPTOR
{
  qtime32_t TimeDateStamp;
  uint16 OffsetModuleName;
  uint16 NumberOfModuleForwarderRefs;
// Array of zero or more IMAGE_BOUND_FORWARDER_REF follows
};

struct BOUND_FORWARDER_REF
{
  qtime32_t TimeDateStamp;
  uint16 OffsetModuleName;
  uint16 Reserved;
};


//-------------------------------------------------------------------------
//
//      T H R E A D   L O C A L   D A T A
//

struct image_tls_directory64
{
  uint64 StartAddressOfRawData;
  uint64 EndAddressOfRawData;
  uint64 AddressOfIndex;         // PDWORD
  uint64 AddressOfCallBacks;     // PIMAGE_TLS_CALLBACK *;
  uint32  SizeOfZeroFill;
  uint32  Characteristics;
};

struct image_tls_directory32
{
  uint32  StartAddressOfRawData;
  uint32  EndAddressOfRawData;
  uint32  AddressOfIndex;        // PDWORD
  uint32  AddressOfCallBacks;    // PIMAGE_TLS_CALLBACK *
  uint32  SizeOfZeroFill;
  uint32  Characteristics;
};

//-------------------------------------------------------------------------
//
//      Exception Tables (.pdata)
//

// ARM, PowerPC, SH3 and SH4 WindowsCE platforms
struct function_entry_ce
{
  uint32 FuncStart;          // Virtual address of the corresponding function.
  uint32 PrologLen : 8;      // Number of instructions in the function's prolog.
  uint32 FuncLen : 22;       // Number of instructions in the function.
  uint32 ThirtyTwoBit : 1;   // Set if the function is comprised of 32-bit instructions, cleared for a 16-bit function.
  uint32 ExceptionFlag : 1;  // Set if an exception handler exists for the function.
};

// ARMv7, ARM64
struct function_entry_arm_pdata
{
  uint32 BeginAddress;       // The RVA of the corresponding function
  uint32 UnwindInfo;         // The RVA of the unwind information, including function length.
                             // If the low 2 bits are non-zero, then this word represents a
                             // compacted inline form of the unwind information,
                             // including function length.
};

// for MIPS and 32-bit Alpha
struct function_entry_alpha
{
  uint32 BeginAddress;       // Virtual address of the corresponding function.
  uint32 EndAddress;         // Virtual address of the end of the function.
  uint32 ExceptionHandler;   // Pointer to the exception handler to be executed.
  uint32 HandlerData;        // Pointer to additional information to be passed to the handler.
  uint32 PrologEndAddress;   // Virtual address of the end of the function's prolog.
};

// x64
typedef enum _UNWIND_OP_CODES
{
  UWOP_PUSH_NONVOL = 0, // info == register number
  UWOP_ALLOC_LARGE =1,  // alloc size/8 in next 1(info=0) or 2(info=1) slots
  UWOP_ALLOC_SMALL =2,  // info == size of allocation / 8 - 1
  UWOP_SET_FPREG = 3,   // FP = RSP + UNWIND_INFO.FPRegOffset*16
  UWOP_SAVE_NONVOL = 4, // info == register number, offset/8 in next slot
  UWOP_SAVE_NONVOL_FAR=5,// info == register number, offset/8 in next 2 slots
  UWOP_SAVE_XMM    = 6, // Version 1: info == XMM reg number, offset/8 in next slot
  UWOP_EPILOG      = 6, // Version 2; code offset is epilog size;
  UWOP_SAVE_XMM_FAR=7,  // version 1:info == XMM reg number, offset/8 in next 2 slots
  UWOP_SPARE_CODE = 7,  // unused ("previously 64-bit UWOP_SAVE_XMM_FAR"); skip 2 slots
  UWOP_SAVE_XMM128 = 8, // info == XMM reg number, offset/16 in next slot
  UWOP_SAVE_XMM128_FAR = 9,// info == XMM reg number, offset/16 in next 2 slots
  UWOP_PUSH_MACHFRAME = 10,// info == 0: no error-code, 1: with error code
} UNWIND_CODE_OPS;

enum // ARM64_UNWIND_OP_CODES;
{
  // 1 byte long
  ARM64_UWOP_BAD = 0,
  ARM64_UWOP_UNNAMED,
  ARM64_UWOP_ALLOC_S,       // allocate small stack with size < 512 (2^5 * 16).
  ARM64_UWOP_SAVE_R19R20_X, // save <x19,x20> pair at [sp-#Z*8]!, pre-indexed offset >= -248
  ARM64_UWOP_SAVE_FPLR,     // save <x29,lr> pair at [sp+#Z*8], offset <= 504
  ARM64_UWOP_SAVE_FPLR_X,   // save <x29,lr> pair at [sp-(#Z+1)*8]!, pre-indexed offset >= -512
  ARM64_UWOP_SET_FP,        // set up x29: with: mov x29,sp
  ARM64_UWOP_ADD_FP,        // set up x29 with: add x29,sp,#x*8
  ARM64_UWOP_NOP,           // no unwind operation is required
  ARM64_UWOP_END,           // end of unwind code. Implies ret in epilog
  ARM64_UWOP_END_C,         // end of unwind code in current chained scope
  ARM64_UWOP_SAVE_NEXT,     // save next non-volatile Int or FP register pair

  // 2 bytes long
  ARM64_UWOP_ALLOC_M,       // allocate large stack with size < 16k (2^11 * 16)
  ARM64_UWOP_SAVE_REGP,     // save x(19+#X) pair at [sp+#Z*8], offset <= 504
  ARM64_UWOP_SAVE_REGP_X,   // save pair x(19+#X) at [sp-(#Z+1)*8]!, pre-indexed offset >= -512
  ARM64_UWOP_SAVE_REG,      // save reg x(19+#X) at [sp+#Z*8], offset <= 504
  ARM64_UWOP_SAVE_REG_X,    // save reg x(19+#X) at [sp-(#Z+1)*8]!, pre-indexed offset >= -256
  ARM64_UWOP_SAVE_LRPAIR,   // save pair <x(19+2*#X),lr> at [sp+#Z*8], offset <= 504
  ARM64_UWOP_SAVE_FREGP,    // save pair d(8+#X) at [sp+#Z*8], offset <= 504
  ARM64_UWOP_SAVE_FREGP_X,  // save pair d(8+#X), at [sp-(#Z+1)*8]!, pre-indexed offset >= -512
  ARM64_UWOP_SAVE_FREG,     // save reg d(8+#X) at [sp+#Z*8], offset <= 504
  ARM64_UWOP_SAVE_FREG_X,   // save reg d(8+#X) at [sp-(#Z+1)*8]!, pre-indexed offset >= -256
  // 4 bytes long
  ARM64_UWOP_ALLOC_L,       // allocate large stack with size < 256M (2^24 *16)
};

enum // ARM_UNWIND_OP_CODES;
{
  // 1 byte long
  ARM_UWOP_ALLOC = 0,    // add sp,sp, #X    where X = (Code & 0x7F) * 4)
  ARM_UWOP_SAVE_SP,      // mov sp,rX        where X is Code & 0x0F
  ARM_UWOP_POP,          // pop {r4-rX,lr}   where X is (Code & 0x03) + 4 and LR is popped if Code & 0x04
  ARM_UWOP_POP2,         // pop {r4-rX,lr}   where X is (Code & 0x03) + 8 and LR is popped if Code & 0x04
  ARM_UWOP_VPOP,         // vpop {d8-dX}     where X is (Code & 0x07) + 8
  ARM_UWOP_RESERVED,     // Available (no opsize)
  ARM_UWOP_END,          // end
  ARM_UWOP_END32,        // end (+32bit nop in epilogue)
  ARM_UWOP_NOP32,        // nop (32bit)
  ARM_UWOP_END16,        // end (+16bit nop in epilogue)
  ARM_UWOP_NOP16,        // nop (16bit)

  // 2 bytes long
  ARM_UWOP_POP3,         // pop {r0-r12, lr} where LR is popped if Code & 0x2000 and r0-r12 are popped
                         //                 if the corresponding bit is set in Code & 0x1FFF
  ARM_UWOP_ALLOC2,       // addw sp,sp,#X    where X is (Code & 0x03FF) * 4
  ARM_UWOP_POP4,         // pop {r0-r7,lr}   where LR is popped if Code & 0x0100 and r0-r7 are popped
                         //                 if the corresponding bit is set in Code & 0x00FF
  ARM_UWOP_MS_SPECIFIC,  // Microsoft specific
  ARM_UWOP_RESERVED_W,   // Available (16bit opsize)
  ARM_UWOP_LD_PC_UPD_SP, // ldr lr,[sp],#X   where X is (Code & 0x000F) * 4
  ARM_UWOP_RESERVED_DW,  // Available (32bit opsize)
  ARM_UWOP_VPOP2,        // vpop {dS-dE}     where S is (Code & 0x00F0) >> 4 and E is Code & 0x000F
  ARM_UWOP_VPOP3,        // vpop {dS-dE}     where S is ((Code & 0x00F0) >> 4) + 16 and E is (Code & 0x000F) + 16

  // 3 bytes long
  ARM_UWOP_ALLOC3,       // add sp,sp,#X     where X is (Code & 0x00FFFF) * 4
  ARM_UWOP_ALLOC4,       // add sp,sp,#X     where X is (Code & 0x00FFFF) * 4

  // 4 bytes long
  ARM_UWOP_ALLOC5,       // add sp,sp,#X     where X is (Code & 0x00FFFFFF) * 4
  ARM_UWOP_ALLOC6,       // add sp,sp,#X     where X is (Code & 0x00FFFFFF) * 4
};

// Define unwind information flags.
//

#define UNW_FLAG_NHANDLER 0x0
#define UNW_FLAG_EHANDLER 0x1
#define UNW_FLAG_UHANDLER 0x2
#define UNW_FLAG_CHAININFO 0x4

//-------------------------------------------------------------------------
//
//      F I X U P S
//
struct pefixup_t
{
  uint32 page;// The image base plus the page rva is added to each offset
              // to create the virtual address of where the fixup needs to
              // be applied.
  uint32 size;// Number of bytes in the fixup block. This includes the
              // PAGE RVA and SIZE fields.
};

#define PER_OFF  0x0FFF
#define PER_TYPE 0xF000
#define PER_ABS         0x0000  // This is a NOP. The fixup is skipped.
#define PER_HIGH        0x1000  // Add the high 16-bits of the delta to the
                                // 16-bit field at Offset. The 16-bit field
                                // represents the high value of a 32-bit word.
#define PER_LOW         0x2000  // Add the low 16-bits of the delta to the
                                // 16-bit field at Offset. The 16-bit field
                                // represents the low half value of a
                                // 32-bit word.  This fixup will only be
                                // emitted for a RISC machine when the image
                                // Object Align isn't the default of 64K.
#define PER_HIGHLOW     0x3000  // Apply the 32-bit delta to the 32-bit field
                                // at Offset.
#define PER_HIGHADJUST  0x4000  // This fixup requires a full 32-bit value.
                                // The high 16-bits is located at Offset, and
                                // the low 16-bits is located in the next
                                // Offset array element (this array element
                                // is included in the SIZE field). The two
                                // need to be combined into a signed variable.
                                // Add the 32-bit delta. Then add 0x8000 and
                                // store the high 16-bits of the signed
                                // variable to the 16-bit field at Offset.
#define PER_REL5000      0x5000 // Machine-specific
#define PER_SECTION      0x6000 // Reserved for future use
#define PER_REL32        0x7000 // Relative intrasection
#define PER_REL7000      0x7000 // Machine-specific
#define PER_REL8000      0x8000 // Machine-specific
#define PER_REL9000      0x9000 // Machine-specific
#define PER_DIR64        0xA000 // This fixup applies the delta to the 64-bit
                                // field at Offset
#define PER_HIGH3ADJ     0xB000 // The fixup adds the high 16 bits of the delta
                                // to the 16-bit field at Offset. The 16-bit
                                // field represents the high value of a 48-bit
                                // word. The low 32 bits of the 48-bit value are
                                // stored in the 32-bit word that follows this
                                // base relocation. This means that this base
                                // relocation occupies three slots.

// Platform-specific based relocation types.

#define PER_IA64_IMM64   0x9000

#define PER_MIPS_JMPADDR    0x5000  // base relocation applies to a MIPS jump instruction.
#define PER_MIPS_JMPADDR16  0x9000  // base relocation applies to a MIPS16 jump instruction.

#define PER_ARM_MOV32A      0x5000  // base relocation applies the difference to the
                                    // 32-bit value encoded in the immediate fields of
                                    // a contiguous MOVW+MOVT pair in ARM mode at offset.
#define PER_ARM_MOV32T      0x7000  // base relocation applies the difference to the
                                    // 32-bit value encoded in the immediate fields of
                                    // a contiguous MOVW+MOVT pair in Thumb mode at offset.


//-------------------------------------------------------------------------
//
//      DBG file debug entry format
//
struct debug_entry_t
{
  uint32 flags;                  // usually zero
  qtime32_t datetime;
  uint16 major;
  uint16 minor;
  int32 type;
#define DBG_COFF          1
#define DBG_CV            2
#define DBG_FPO           3
#define DBG_MISC          4
#define DBG_EXCEPTION     5
#define DBG_FIXUP         6
#define DBG_OMAP_TO_SRC   7
#define DBG_OMAP_FROM_SRC 8
#define DBG_BORLAND       9
#define DBG_RES10         10
#define DBG_CLSID         11
#define DBG_VCFEATURE     12
#define DBG_POGO          13
#define DBG_ILTCG         14
#define DBG_MPX           15
  uint32 size;
  uint32 rva;       // virtual address
  uint32 seek;      // ptr to data in the file
};

// now we can define has_debdir() because we have debug_entry_t defined
template<>
inline bool peheader_t::has_debdir() const
    { return debdir.size >= sizeof(debug_entry_t) && debdir.rva != 0; }

//-------------------------------------------------------------------------
//
//      DBG file COFF debug information header
//
struct coff_debug_t
{
  uint32 NumberOfSymbols;
  uint32 LvaToFirstSymbol;
  uint32 NumberOfLinenumbers;
  uint32 LvaToFirstLinenumber;
  uint32 RvaToFirstByteOfCode;
  uint32 RvaToLastByteOfCode;
  uint32 RvaToFirstByteOfData;
  uint32 RvaToLastByteOfData;
};

//-------------------------------------------------------------------------
//
//      DBG file FPO debug information
//
struct fpo_t
{
  uint32 address;
  uint32 size;
  uint32 locals;
  uint16 params;
  uchar prolog;
  uchar regs;
#define FPO_REGS      0x07  // register number
#define FPO_SEH       0x08  //
#define FPO_BP        0x10  // has BP frame?
#define FPO_TYPE      0xC0
#define FPO_T_FPO     0x00
#define FPO_T_TRAP    0x40
#define FPO_T_TSS     0x80
#define FPO_T_NONFPO    0xC0
};


//      DBG file OMAP debug information

struct omap_t
{
  uint32 a1;
  uint32 a2;
};

// misc entry format
struct misc_debug_t
{
  uint32 type;         // type of misc data, see defines
#define MISC_EXENAME 1
  uint32 length;       // total length of record, rounded to four
                       // byte multiple.
  uchar  unicode;      // TRUE if data is unicode string
  uchar  reserved[3];  // padding
  uchar  data[1];      // Actual data
};

//----------------------------------------------------------------------
// Resource information
struct rsc_dir_t
{
  uint32 Characteristics;
  uint32 TimeDateStamp;
  uint16 MajorVersion;
  uint16 MinorVersion;
  uint16 NumberOfNamedEntries;
  uint16 NumberOfIdEntries;
};

struct rsc_dir_entry_t
{
  union
  {
    struct
    {
      uint32 NameOffset:31;
      uint32 NameIsString:1;
    };
    uint32 Name;
    uint16 Id;
  };
  union
  {
    uint32 OffsetToData;
    struct
    {
      uint32 OffsetToDirectory:31;
      uint32 DataIsDirectory:1;
    };
  };
};

struct rsc_data_entry_t
{
  uint32 OffsetToData;
  uint32 Size;
  uint32 CodePage;
  uint32 Reserved;
};


// Resource types
#define PE_RT_CURSOR       1
#define PE_RT_BITMAP       2
#define PE_RT_ICON         3
#define PE_RT_MENU         4
#define PE_RT_DIALOG       5
#define PE_RT_STRING       6
#define PE_RT_FONTDIR      7
#define PE_RT_FONT         8
#define PE_RT_ACCELERATOR  9
#define PE_RT_RCDATA       10
#define PE_RT_MESSAGETABLE 11
#define PE_RT_GROUP_CURSOR 12
#define PE_RT_GROUP_ICON   14
#define PE_RT_VERSION      16
#define PE_RT_DLGINCLUDE   17
#define PE_RT_PLUGPLAY     19
#define PE_RT_VXD          20
#define PE_RT_ANICURSOR    21
#define PE_RT_ANIICON      22
#define PE_RT_HTML         23
#define PE_RT_MANIFEST     24

// Language codes
#define PE_LANG_NEUTRAL     0x00
#define PE_LANG_INVARIANT   0x7f

#define PE_LANG_AFRIKAANS   0x36
#define PE_LANG_ALBANIAN    0x1c
#define PE_LANG_ARABIC      0x01
#define PE_LANG_ARMENIAN    0x2b
#define PE_LANG_ASSAMESE    0x4d
#define PE_LANG_AZERI       0x2c
#define PE_LANG_BASQUE      0x2d
#define PE_LANG_BELARUSIAN  0x23
#define PE_LANG_BENGALI     0x45
#define PE_LANG_BULGARIAN   0x02
#define PE_LANG_CATALAN     0x03
#define PE_LANG_CHINESE     0x04
#define PE_LANG_CROATIAN    0x1a
#define PE_LANG_CZECH       0x05
#define PE_LANG_DANISH      0x06
#define PE_LANG_DIVEHI      0x65
#define PE_LANG_DUTCH       0x13
#define PE_LANG_ENGLISH     0x09
#define PE_LANG_ESTONIAN    0x25
#define PE_LANG_FAEROESE    0x38
#define PE_LANG_FARSI       0x29
#define PE_LANG_FINNISH     0x0b
#define PE_LANG_FRENCH      0x0c
#define PE_LANG_GALICIAN    0x56
#define PE_LANG_GEORGIAN    0x37
#define PE_LANG_GERMAN      0x07
#define PE_LANG_GREEK       0x08
#define PE_LANG_GUJARATI    0x47
#define PE_LANG_HEBREW      0x0d
#define PE_LANG_HINDI       0x39
#define PE_LANG_HUNGARIAN   0x0e
#define PE_LANG_ICELANDIC   0x0f
#define PE_LANG_INDONESIAN  0x21
#define PE_LANG_ITALIAN     0x10
#define PE_LANG_JAPANESE    0x11
#define PE_LANG_KANNADA     0x4b
#define PE_LANG_KASHMIRI    0x60
#define PE_LANG_KAZAK       0x3f
#define PE_LANG_KONKANI     0x57
#define PE_LANG_KOREAN      0x12
#define PE_LANG_KYRGYZ      0x40
#define PE_LANG_LATVIAN     0x26
#define PE_LANG_LITHUANIAN  0x27
#define PE_LANG_MACEDONIAN  0x2f   // the Former Yugoslav Republic of Macedonia
#define PE_LANG_MALAY       0x3e
#define PE_LANG_MALAYALAM   0x4c
#define PE_LANG_MANIPURI    0x58
#define PE_LANG_MARATHI     0x4e
#define PE_LANG_MONGOLIAN   0x50
#define PE_LANG_NEPALI      0x61
#define PE_LANG_NORWEGIAN   0x14
#define PE_LANG_ORIYA       0x48
#define PE_LANG_POLISH      0x15
#define PE_LANG_PORTUGUESE  0x16
#define PE_LANG_PUNJABI     0x46
#define PE_LANG_ROMANIAN    0x18
#define PE_LANG_RUSSIAN     0x19
#define PE_LANG_SANSKRIT    0x4f
#define PE_LANG_SINDHI      0x59
#define PE_LANG_SLOVAK      0x1b
#define PE_LANG_SLOVENIAN   0x24
#define PE_LANG_SPANISH     0x0a
#define PE_LANG_SWAHILI     0x41
#define PE_LANG_SWEDISH     0x1d
#define PE_LANG_SYRIAC      0x5a
#define PE_LANG_TAMIL       0x49
#define PE_LANG_TATAR       0x44
#define PE_LANG_TELUGU      0x4a
#define PE_LANG_THAI        0x1e
#define PE_LANG_TURKISH     0x1f
#define PE_LANG_UKRAINIAN   0x22
#define PE_LANG_URDU        0x20
#define PE_LANG_UZBEK       0x43
#define PE_LANG_VIETNAMESE  0x2a

//----------------------------------------------------------------------

#define PE_NODE "$ PE header" // netnode name for PE header
                              // value()        -> peheader_t
                              // altval(segnum) -> s->start_ea
#define PE_ALT_DBG_FPOS   nodeidx_t(-1)  // altval() -> translated fpos of debuginfo
#define PE_ALT_IMAGEBASE  nodeidx_t(-2)  // altval() -> loading address (usually pe.imagebase)
#define PE_ALT_PEHDR_OFF  nodeidx_t(-3)  // altval() -> offset of PE header
#define PE_ALT_NEFLAGS    nodeidx_t(-4)  // altval() -> neflags
#define PE_ALT_TDS_LOADED nodeidx_t(-5)  // altval() -> tds already loaded(1) or invalid(-1)
#define PE_ALT_PSXDLL     nodeidx_t(-6)  // altval() -> if POSIX(x86) imports from PSXDLL netnode
#define PE_ALT_OVRVA      nodeidx_t(-7)  // altval() -> overlay rva (if present)
#define PE_ALT_OVRSZ      nodeidx_t(-8)  // altval() -> overlay size (if present)
#define PE_SUPSTR_PDBNM   nodeidx_t(-9)  // supstr() -> pdb file name
                              // supval(segnum) -> pesection_t
                              // blob(0, PE_NODE_RELOC)  -> relocation info
                              // blob(0, RSDS_TAG)  -> rsds_t structure
                              // blob(0, NB10_TAG)  -> cv_info_pdb20_t structure
#define PE_ALT_NTAPI      nodeidx_t(-10) // altval() -> uses Native API
#define PE_EMBED_PDB_OFF  nodeidx_t(-11) // altval() -> offset of embedded PDB file
#define PE_NODE_RELOC 'r'
#define RSDS_TAG 's'
#define NB10_TAG 'n'
#define UTDS_TAG 't'

#if !defined(_WINNT_) || !defined(_WIN32_WINNT_WIN10)
typedef struct _IMAGE_LOAD_CONFIG_CODE_INTEGRITY
{
  uint16  Flags;          // Flags to indicate if CI information is available, etc.
  uint16  Catalog;        // 0xFFFF means not available
  uint32  CatalogOffset;
  uint32  Reserved;       // Additional bitmask to be defined later
} IMAGE_LOAD_CONFIG_CODE_INTEGRITY;
#endif

struct load_config_t
{
  uint32 Size;
  uint32 TimeDateStamp;
  uint16 MajorVersion;
  uint16 MinorVersion;
  uint32 GlobalFlagsClear;
  uint32 GlobalFlagsSet;
  uint32 CriticalSectionDefaultTimeout;
  uint32 DeCommitFreeBlockThreshold;
  uint32 DeCommitTotalFreeThreshold;
  uint32 LockPrefixTable;            // VA
  uint32 MaximumAllocationSize;
  uint32 VirtualMemoryThreshold;
  uint32 ProcessHeapFlags;
  uint32 ProcessAffinityMask;
  uint16 CSDVersion;
  uint16 Reserved1;
  uint32 EditList;                   // VA
  uint32 SecurityCookie;             // VA
  // Version 2
  uint32 SEHandlerTable;             // VA
  uint32 SEHandlerCount;
  // Version 3
  uint32 GuardCFCheckFunctionPointer; // VA
  uint32 GuardCFDispatchFunctionPointer; // VA
  uint32 GuardCFFunctionTable;       // VA
  uint32 GuardCFFunctionCount;
  uint32 GuardFlags;
  IMAGE_LOAD_CONFIG_CODE_INTEGRITY CodeIntegrity;
  uint32  GuardAddressTakenIatEntryTable; // VA
  uint32  GuardAddressTakenIatEntryCount;
  uint32  GuardLongJumpTargetTable;       // VA
  uint32  GuardLongJumpTargetCount;
  uint32  DynamicValueRelocTable;         // VA
  uint32  CHPEMetadataPointer;
  uint32  GuardRFFailureRoutine;          // VA
  uint32  GuardRFFailureRoutineFunctionPointer; // VA
  uint32  DynamicValueRelocTableOffset;
  uint16  DynamicValueRelocTableSection;
  uint16  Reserved2;
  uint32  GuardRFVerifyStackPointerFunctionPointer; // VA
  uint32  HotPatchTableOffset;
  uint32  Reserved3;
  uint32  EnclaveConfigurationPointer;    // VA
  uint32  VolatileMetadataPointer;        // VA
  uint32  GuardEHContinuationTable;       // VA
  uint32  GuardEHContinuationCount;
  uint32  GuardXFGCheckFunctionPointer;    // VA
  uint32  GuardXFGDispatchFunctionPointer; // VA
  uint32  GuardXFGTableDispatchFunctionPointer; // VA
  uint32  CastGuardOsDeterminedFailureMode; // VA
  uint32  GuardMemcpyFunctionPointer;     // VA
};

struct load_config64_t
{
  uint32 Size;
  uint32 TimeDateStamp;
  uint16 MajorVersion;
  uint16 MinorVersion;
  uint32 GlobalFlagsClear;
  uint32 GlobalFlagsSet;
  uint32 CriticalSectionDefaultTimeout;
  uint64 DeCommitFreeBlockThreshold;
  uint64 DeCommitTotalFreeThreshold;
  uint64 LockPrefixTable;            // VA
  uint64 MaximumAllocationSize;
  uint64 VirtualMemoryThreshold;
  uint64 ProcessAffinityMask;
  uint32 ProcessHeapFlags;
  uint16 CSDVersion;
  uint16 Reserved1;
  uint64 EditList;                   // VA
  uint64 SecurityCookie;             // VA
  // Version 2
  uint64 SEHandlerTable;             // VA
  uint64 SEHandlerCount;
  // Version 3
  uint64 GuardCFCheckFunctionPointer; // VA
  uint64 GuardCFDispatchFunctionPointer; // VA
  uint64 GuardCFFunctionTable;       // VA
  uint64 GuardCFFunctionCount;
  uint32 GuardFlags;
  IMAGE_LOAD_CONFIG_CODE_INTEGRITY CodeIntegrity;
  uint64  GuardAddressTakenIatEntryTable; // VA
  uint64  GuardAddressTakenIatEntryCount;
  uint64  GuardLongJumpTargetTable;       // VA
  uint64  GuardLongJumpTargetCount;
  uint64  DynamicValueRelocTable;         // VA
  uint64  CHPEMetadataPointer;            // VA
  uint64  GuardRFFailureRoutine;          // VA
  uint64  GuardRFFailureRoutineFunctionPointer; // VA
  uint32  DynamicValueRelocTableOffset;
  uint16  DynamicValueRelocTableSection;
  uint16  Reserved2;
  uint64  GuardRFVerifyStackPointerFunctionPointer; // VA
  uint32  HotPatchTableOffset;
  uint32  Reserved3;
  uint64  EnclaveConfigurationPointer;     // VA
  uint64  VolatileMetadataPointer;         // VA
  uint64  GuardEHContinuationTable;        // VA
  uint64  GuardEHContinuationCount;
  uint64  GuardXFGCheckFunctionPointer;    // VA
  uint64  GuardXFGDispatchFunctionPointer; // VA
  uint64  GuardXFGTableDispatchFunctionPointer; // VA
  uint64  CastGuardOsDeterminedFailureMode; // VA
  uint64  GuardMemcpyFunctionPointer;       // VA
};

#ifndef IMAGE_GUARD_CF_INSTRUMENTED
#define IMAGE_GUARD_CF_INSTRUMENTED               0x000000100 // Module performs control flow integrity checks using system-supplied support
#define IMAGE_GUARD_CFW_INSTRUMENTED              0x000000200 // Module performs control flow and write integrity checks
#define IMAGE_GUARD_CF_FUNCTION_TABLE_PRESENT     0x000000400 // Module contains valid control flow target metadata
#define IMAGE_GUARD_SECURITY_COOKIE_UNUSED        0x000000800 // Module does not make use of the /GS security cookie
#define IMAGE_GUARD_PROTECT_DELAYLOAD_IAT         0x00001000 // Module supports read only delay load IAT
#define IMAGE_GUARD_DELAYLOAD_IAT_IN_ITS_OWN_SECTION 0x00002000 // Delayload import table in its own .didat section (with nothing else in it) that can be freely reprotected
#define IMAGE_GUARD_CF_FUNCTION_TABLE_SIZE_MASK   0xF0000000  // Stride of Guard CF function table encoded in these bits (additional count of bytes per element)
#define IMAGE_GUARD_CF_FUNCTION_TABLE_SIZE_SHIFT  28          // Shift to right-justify Guard CF function table stride
#endif
#ifndef IMAGE_GUARD_CF_EXPORT_SUPPRESSION_INFO_PRESENT
#define IMAGE_GUARD_CF_EXPORT_SUPPRESSION_INFO_PRESENT 0x00004000 // Module contains suppressed export information. This also infers that the address taken
                                                                  // taken IAT table is also present in the load config.
#define IMAGE_GUARD_CF_ENABLE_EXPORT_SUPPRESSION  0x00008000 // Module enables suppression of exports
#define IMAGE_GUARD_CF_LONGJUMP_TABLE_PRESENT     0x00010000 // Module contains longjmp target information
#define IMAGE_GUARD_RF_INSTRUMENTED               0x00020000 // Module contains return flow instrumentation and metadata
#define IMAGE_GUARD_RF_ENABLE                     0x00040000 // Module requests that the OS enable return flow protection
#define IMAGE_GUARD_RF_STRICT                     0x00080000 // Module requests that the OS enable return flow protection in strict mode
#define IMAGE_GUARD_RETPOLINE_PRESENT             0x00100000 // Module was built with retpoline support
// DO_NOT_USE                                     0x00200000 // Was EHCont flag on VB (20H1)
#endif // IMAGE_GUARD_CF_EXPORT_SUPPRESSION_INFO_PRESENT
#ifndef IMAGE_GUARD_XFG_ENABLED
#define IMAGE_GUARD_EH_CONTINUATION_TABLE_PRESENT 0x00400000 // Module contains EH continuation target information
#define IMAGE_GUARD_XFG_ENABLED                   0x00800000 // Module was built with xfg
#endif // IMAGE_GUARD_XFG_ENABLED

//----------------------------------------------------------------------
// MS Windows CLSID, GUID
struct clsid_t
{
  uint32 id1;
  uint16 id2;
  uint16 id3;
  uchar id4[8];
  bool operator == (const struct clsid_t &r) const
    { return memcmp(this, &r, sizeof(r)) == 0; }
};

//----------------------------------------------------------------------
// RSDS debug information
struct rsds_t
{
  uint32 magic;
#define RSDS_MAGIC MC4('R','S','D','S')
#define UTDS_MAGIC MC4('u','T','D','S')
  clsid_t guid;
  uint32 age;
//  char name[];  // followed by a zero-terminated UTF8 file name
};

//----------------------------------------------------------------------
// NB10 debug information
struct cv_info_pdb20_t
{
  uint32 magic;  // 'NB10'
#define NB10_MAGIC MC4('N', 'B', '1', '0')
  uint32 offset;
  uint32 signature;
  uint32 age;
  // char pdb_file_name[];
};

//----------------------------------------------------------------------
// MTOC debug information.
// denotes EFI binaries that were built on OSX as Mach-O, then converted to PE by the 'mtoc' utility.
// see https://opensource.apple.com/source/cctools/cctools-921/efitools/mtoc.c.auto.html
struct mtoc_info_t
{
  uint32 magic;   // 'MTOC'
#define MTOC_MAGIC MC4('M', 'T', 'O', 'C')
  uchar uuid[16]; // UUID of original Mach-O file
  // char debug_filename[];
};

// TE (Terse Executable)
struct teheader_t
{
  uint16 signature;     // 00
  uint16 machine;       // 02 same as in PE

  bool is_64bit_cpu(void) const { return machine == PECPU_AMD64 || machine == PECPU_IA64 || machine == PECPU_ARM64; }

  uint8   nobjs;        // 04 number of sections
  uint8   subsys;       // 05 target subsystem
  uint16  strippedsize; // 06 number of bytes removed from the base of the original image

  int32 first_section_pos(int32 peoff) const
    { return peoff + sizeof(teheader_t); }

  // value which should be added to the sections' file offsets and RVAs
  int32 te_adjust() const
    { return sizeof(teheader_t) - strippedsize; }

  uint32 entry;         // 08 Entry point
  uint32 text_start;    // 0C Base of code
  uint64 imagebase64;   // 10 Virtual base of the image.
  uint64 imagebase() const
  {
    return imagebase64;
  }
  petab_t reltab;       // 18 Relocation Table
  petab_t debdir;       // 20 Debug Directory
};

const char *get_pe_machine_name(uint16 machine);
void print_pe_flags(uint16 flags);

#pragma pack(pop)
#endif
