/*
 *     Copyright (c) 2017-2018, NVIDIA CORPORATION.  All rights reserved.
 *
 * NVIDIA CORPORATION and its licensors retain all intellectual property
 * and proprietary rights in and to this software, related documentation
 * and any modifications thereto.  Any use, reproduction, disclosure or
 * distribution of this software and related documentation without an express
 * license agreement from NVIDIA CORPORATION is strictly prohibited.
 *
 */

#ifndef __MACHO_X_H__
#define __MACHO_X_H__

#include "universal.h"

#if defined(HOST_WIN) || defined(HOST_LINUX) || defined(HOST_OSX_X86) || \
    defined(HOST_ELFX)
typedef unsigned char macho_uint8_t;
typedef unsigned short macho_uint16_t;
typedef unsigned int macho_uint32_t;
typedef int macho_int32_t;
typedef unsigned int macho_cputype_t;
typedef unsigned int macho_cpusubtype_t;
typedef unsigned int macho_prot_t;
#else
#error "Unknown host, please adapt macho_x.h to your platform"
#endif

#if defined(HOST_WIN) || defined(HOST_LINUX) || defined(HOST_OSX_X86) || \
    defined(HOST_ELFX)
typedef unsigned long long macho_uint64_t;
#elif defined(HOST_LINUX_X8664)
typedef unsigned long long macho_uint64_t;
#else
#error "Unknown host, please adapt macho_x.h to your platform"
#endif

/*
 * mach-o magic numbers
 */
#define macho_magic_fat (macho_uint32_t)(0xcafebabe)
#define macho_magic_fat_rev (macho_uint32_t)(0xbebafeca)
#define macho_magic_i86 (macho_uint32_t)(0xfeedface)
#define macho_magic_i86_rev (macho_uint32_t)(0xcefaedfe)
#define macho_magic_i86_64 (macho_uint32_t)(0xfeedfacf)
#define macho_magic_i86_64_rev (macho_uint32_t)(0xcffaedfe)

#define macho_magic_fat1 (unsigned char)(0xca)
#define macho_magic_fat2 (unsigned char)(0xfe)
#define macho_magic_fat3 (unsigned char)(0xba)
#define macho_magic_fat4 (unsigned char)(0xbe)

#define macho_magic_i861 (unsigned char)(0xce)
#define macho_magic_i862 (unsigned char)(0xfa)
#define macho_magic_i863 (unsigned char)(0xed)
#define macho_magic_i864 (unsigned char)(0xfe)

#define macho_magic_i86_641 (unsigned char)(0xcf)
#define macho_magic_i86_642 (unsigned char)(0xfa)
#define macho_magic_i86_643 (unsigned char)(0xed)
#define macho_magic_i86_644 (unsigned char)(0xfe)

#define macho_cputype_i86 (macho_cputype_t)(0x00000007)
#define macho_cputype_i86_rev (macho_cputype_t)(0x07000000)
#define macho_cputype_i86_64 (macho_cputype_t)(0x01000007)
#define macho_cputype_i86_64_rev (macho_cputype_t)(0x07000001)
#define macho_cputype_pgi (macho_cputype_t)(0x00009998)
#define macho_cputype_pgi_rev (macho_cputype_t)(0x98990000)

/*
 * file header of a fat object file
 */
typedef struct macho_fatheader_t {
  macho_uint32_t magic; /* CAFEBABE:big-endian or BEBAFECA: little endian */
  macho_uint32_t nfat;  /* always stored in big endian mode */
} macho_fatheader_t;

/*
 * 1:nfat
 * follows fat object file fat header
 */
typedef struct macho_fatarch_t {
  macho_cputype_t cputype;
  macho_cpusubtype_t cpusubtype;
  macho_uint32_t offset, size, align;
} macho_fatarch_t;

/*
 * file header of 32-bit macho file
 */
typedef struct macho_header32_t {
  macho_uint32_t magic; /* FEEDFACE:native or CEFAEDFE:swap */
  macho_cputype_t cputype;
  macho_cpusubtype_t cpusubtype;
  macho_uint32_t filetype, ncmds, sizeofcmds, flags;
} macho_header32_t;

/*
 * file header of 64-bit macho file
 */
typedef struct macho_header64_t {
  macho_uint32_t magic; /* FEEDFACF:native or CFFAEDFE:swap */
  macho_cputype_t cputype;
  macho_cpusubtype_t cpusubtype;
  macho_uint32_t filetype, ncmds, sizeofcmds, flags, reserved;
} macho_header64_t;

/*
 * 1:ncmds
 */

typedef struct macho_loadcmd_t {
  macho_uint32_t cmd;     /* macho_load_... */
  macho_uint32_t cmdsize; /* size of this command structure */
} macho_loadcmd_t;

#define macho_load_segment32 1
#define macho_load_symtab 2
#define macho_load_symseg 3
#define macho_load_thread 4
#define macho_load_unixthread 5
#define macho_load_loadfvmlib 6
#define macho_load_idfbmlib 7
#define macho_load_ident 8
#define macho_load_fvmfile 9
#define macho_load_prepage 10
#define macho_load_dysymtab 11
#define macho_load_load_dylib 12
#define macho_load_id_dylib 13
#define macho_load_load_dylinker 14
#define macho_load_id_dylinker 15
#define macho_load_prebound_dylib 16
#define macho_load_routines 17
#define macho_load_subframework 18
#define macho_load_subumbrella 19
#define macho_load_subclient 20
#define macho_load_sublibrary 21
#define macho_load_twolevelhints 22
#define macho_load_prebindchecksum 23
#define macho_load_load_weakdylib 24
#define macho_load_segment64 25
#define macho_load_routines_64 26
#define macho_load_uuid 27
#define macho_load_mask 0x7fffffff

/*
 * macho_load_segment32
 */
typedef struct macho_segment32_t {
  char segname[16];
  macho_uint32_t vmaddr, vmsize, fileoff, filesize;
  macho_prot_t maxprot, initprot;
  macho_uint32_t nsects, flags;
} macho_segment32_t;

/*
 * 1:nsects
 */
typedef struct macho_section32_t {
  char sectname[16];
  char segname[16];
  macho_uint32_t addr, size;
  macho_uint32_t offset, align, reloff, nreloc, flags, rsv1, rsv2;
} macho_section32_t;

/*
 * macho_load_segment64
 */
typedef struct macho_segment64_t {
  char segname[16];
  macho_uint64_t vmaddr, vmsize, fileoff, filesize;
  macho_prot_t maxprot, initprot;
  macho_uint32_t nsects, flags;
} macho_segment64_t;

/*
 * 1:nsects
 */
typedef struct macho_section64_t {
  char sectname[16];
  char segname[16];
  macho_uint64_t addr, size;
  macho_uint32_t offset, align, reloff, nreloc, flags, rsv1, rsv2;
} macho_section64_t;

#define macho_sectflag_debug 0x02000000
#define macho_sectflag_nodead 0x10000000

/*
 * macho_two_levelhints
 */
typedef struct macho_twolevelhint_t {
  macho_uint32_t offset;
  macho_uint32_t hints;
} macho_twolevelhint_t;

/*
 * macho_load_symtab
 */
typedef struct macho_symtab_t {
  macho_uint32_t symoff;  /* file offset to array of macho_symlist_t */
  macho_uint32_t nsyms;   /* number of entries in macho_symlist_t array */
  macho_uint32_t stroff;  /* file offset to string table */
  macho_uint32_t strsize; /* size of string table */
} macho_symtab_t;

/*
 * macho 32-bit symtab list entry
 */
typedef struct macho_symlist32_t {
  macho_uint32_t symstrx;  /* index to string table for name, 0=null */
  macho_uint8_t symtype;   /* symbol type info */
  macho_uint8_t symsect;   /* section number */
  macho_uint16_t symdesc;  /* descriptive information */
  macho_uint32_t symvalue; /* value */
} macho_symlist32_t;

/*
 * macho 64-bit symtab list entry
 */
typedef struct macho_symlist64_t {
  macho_uint32_t symstrx;  /* index to string table for name, 0=null */
  macho_uint8_t symtype;   /* symbol type info */
  macho_uint8_t symsect;   /* section number */
  macho_uint16_t symdesc;  /* descriptive information */
  macho_uint64_t symvalue; /* value */
} macho_symlist64_t;

/* is this a stab (debugging) entry? */
#define MACHO_STAB(symtype) ((symtype) & (macho_uint8_t)(0xe0))
/* is this a private external */
#define MACHO_PEXT(symtype) ((symtype) & (macho_uint8_t)(0x10))
/* type of symbol */
#define MACHO_TYPE(symtype) ((symtype) & (macho_uint8_t)(0x0e))
/* external (global) symbol */
#define MACHO_EXT(symtype) ((symtype) & (macho_uint8_t)(0x01))
/* values for MACHO_TYPE() */
/* unknown */
#define MACHO_TYPE_UNK 0
/* absolute value */
#define MACHO_TYPE_ABS 2
/* defined in section symsect */
#define MACHO_TYPE_SECT 14
/* prebound */
#define MACHO_TYPE_PREBOUND 12
/* use value for symbol indexed by symvalue */
#define MACHO_TYPE_INDIR 10

/* reference flags */
#define MACHO_FLAG(symdesc) ((symdesc) & (macho_uint16_t)(0x0f))
/* values for flags */
/* external nonlazy symbol, e.g., data */
#define MACHO_FLAG_UNDEF 0
/* external lazy symbol, e.g., function call */
#define MACHO_FLAG_UNDEF_LAZY 1
/* defined in this module */
#define MACHO_FLAG_DEF 2
/* defined in this module, private */
#define MACHO_FLAG_PRIV_DEF 3
/* external, nonlazy, private */
#define MACHO_FLAG_PRIV_UNDEF 4
/* external, lazy, private */
#define MACHO_FLAG_PRIV_UNDEF_LAZY 5

/* referenced dynamically */
#define MACHO_DYNAMIC(symdesc) ((symdesc) & (macho_uint16_t)(0x10))
/* do not strip */
#define MACHO_NO_STRIP(symdesc) ((symdesc) & (macho_uint16_t)(0x20))
/* weak reference */
#define MACHO_WEAK_REF(symdesc) ((symdesc) & (macho_uint16_t)(0x40))
/* weak definition */
#define MACHO_WEAK_DEF(symdesc) ((symdesc) & (macho_uint16_t)(0x80))
#define MACHO_WEAK_REFDEF(symdesc) ((symdesc) & (macho_uint16_t)(0xc0))

/*
 * macho_load_dysymtab
 */
typedef struct macho_dysymtab_t {
  macho_uint32_t ilocalsym, nlocalsym, iextdefsym, nextdefsym, iundefsym,
      nundefsym;
  macho_uint32_t tocoff, ntoc, modtaboff, nmodtab;
  macho_uint32_t extrefsymoff, nextrefsyms, indirectsymoff, nindirectsyms;
  macho_uint32_t extreloff, nextrel, locreloff, nlocrel;
} macho_dysymtab_t;

typedef struct macho_dylib_toc_t {
  macho_uint32_t symbol_index, module_index;
} macho_dylib_toc_t;

typedef struct macho_dylib_module_t {
  macho_uint32_t module_name;
  macho_uint32_t iextdefsym, nextdefsym;
  macho_uint32_t irefsym, nrefsym;
  macho_uint32_t ilocalsym, nlocalsym;
  macho_uint32_t iextrel, nextrel;
  macho_uint32_t iinit_iterm, ninit_nterm;
  macho_uint32_t objc_module_info_addr, objc_module_info_size;
} macho_dylib_module_t;

typedef struct macho_dylib_module64_t {
  macho_uint32_t module_name;
  macho_uint32_t iextdefsym, nextdefsym;
  macho_uint32_t irefsym, nrefsym;
  macho_uint32_t ilocalsym, nlocalsym;
  macho_uint32_t iextrel, nextrel;
  macho_uint32_t iinit_iterm, ninit_nterm;
  macho_uint32_t objc_module_info_size;
  macho_uint64_t objc_module_info_addr;
} macho_dylib_module64_t;

macho_uint32_t macho_symtab_pos(void);

#endif /* __MACHO_X_H__ */
