packages feed

zydiskell-0.2.0.0: src/Zydis/Status.hs

-- Status.hs ---

-- Copyright (C) 2020 Nerd Ed

-- Author: Nerd Ed <nerded.nerded@gmail.com>

-- This program is free software; you can redistribute it and/or
-- modify it under the terms of the GNU General Public License
-- as published by the Free Software Foundation; either version 3
-- of the License, or (at your option) any later version.

-- This program is distributed in the hope that it will be useful,
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-- GNU General Public License for more details.

-- You should have received a copy of the GNU General Public License
-- along with this program. If not, see <http://www.gnu.org/licenses/>.

{-# LANGUAGE DerivingStrategies #-}

-- | This module implement the zycore/zydis status codes.
--
-- Zycore ref: https://github.com/zyantific/zycore-c/blob/71440fa634d1313db735d3262d453be641bb404f/include/Zycore/Status.h#L134
--
-- Zydis ref: https://github.com/zyantific/zydis/blob/675c90ee7bc80d1aa6273e5ecfba0bd293bf89e9/include/Zydis/Status.h#L55
--
module Zydis.Status
  ( ZyanCoreStatus(..)
  , ZydisStatus(..)
  , ZyanStatus
  , ZyanNativeStatus
  , fromZyanNativeStatus
  )
where

import           Data.Bits
import           Data.Word

data ZyanCoreStatus
  = ZyanCoreStatusSuccess
  | ZyanCoreStatusFailed
  | ZyanCoreStatusTrue
  | ZyanCoreStatusFalse
  | ZyanCoreStatusInvalidArgument
  | ZyanCoreStatusInvalidOperation
  | ZyanCoreStatusAccessDenied
  | ZyanCoreStatusNotFound
  | ZyanCoreStatusOutOfRange
  | ZyanCoreStatusInsufficientBufferSize
  | ZyanCoreStatusNotEnoughMemory
  | ZyanCoreStatusBadSystemCall
  | ZyanCoreStatusOutOfResources
  | ZyanCoreStatusMissingDependency
  deriving stock (Show, Eq)

data ZydisStatus
  = ZydisStatusInvalidMask
  | ZydisStatusMalformedMvex
  | ZydisStatusMalformedEvex
  | ZydisStatusInvalidMap
  | ZydisStatusIllegalRex
  | ZydisStatusIllegalLegacyPFX
  | ZydisStatusIllegalLock
  | ZydisStatusBadRegister
  | ZydisStatusInstructionTooLong
  | ZydisStatusNoMoreData
  | ZydisStatusDecodingError
  | ZydisStatusSkipToken
  deriving stock (Show, Eq)

type ZyanStatus = Either ZyanCoreStatus ZydisStatus

type IsError = Bool

type ZyanNativeModule = Word16

type ZyanNativeStatusCode = Word32

type ZyanNativeStatus = Word32

-- | Combine the values into a unique error code.
--
-- This function is a direct copy of https://github.com/zyantific/zycore-c/blob/71440fa634d1313db735d3262d453be641bb404f/include/Zycore/Status.h#L67
--
makeZyanNativeStatus
  :: IsError -> ZyanNativeModule -> ZyanNativeStatusCode -> ZyanNativeStatus
makeZyanNativeStatus e m c =
  ((if e then 1 else 0) `shiftL` 31)
    .|. ((fromIntegral m .&. 0x7FF) `shiftL` 20)
    .|. (c .&. 0xFFFFF)
{-# INLINE makeZyanNativeStatus #-}

-- * Core status

zyanModuleCore :: ZyanNativeModule
zyanModuleCore = 0x001
{-# INLINE zyanModuleCore #-}

zyanCoreStatusSuccess :: ZyanNativeStatus
zyanCoreStatusSuccess = makeZyanNativeStatus False zyanModuleCore 0x00
{-# INLINE zyanCoreStatusSuccess #-}

zyanCoreStatusFailed :: ZyanNativeStatus
zyanCoreStatusFailed = makeZyanNativeStatus True zyanModuleCore 0x01
{-# INLINE zyanCoreStatusFailed #-}

zyanCoreStatusTrue :: ZyanNativeStatus
zyanCoreStatusTrue = makeZyanNativeStatus False zyanModuleCore 0x02
{-# INLINE zyanCoreStatusTrue #-}

zyanCoreStatusFalse :: ZyanNativeStatus
zyanCoreStatusFalse = makeZyanNativeStatus False zyanModuleCore 0x03
{-# INLINE zyanCoreStatusFalse #-}

zyanCoreStatusInvalidArgument :: ZyanNativeStatus
zyanCoreStatusInvalidArgument = makeZyanNativeStatus True zyanModuleCore 0x04
{-# INLINE zyanCoreStatusInvalidArgument #-}

zyanCoreStatusInvalidOperation :: ZyanNativeStatus
zyanCoreStatusInvalidOperation = makeZyanNativeStatus True zyanModuleCore 0x05
{-# INLINE zyanCoreStatusInvalidOperation #-}

zyanCoreStatusAccessDenied :: ZyanNativeStatus
zyanCoreStatusAccessDenied = makeZyanNativeStatus True zyanModuleCore 0x06
{-# INLINE zyanCoreStatusAccessDenied #-}

zyanCoreStatusNotFound :: ZyanNativeStatus
zyanCoreStatusNotFound = makeZyanNativeStatus True zyanModuleCore 0x07
{-# INLINE zyanCoreStatusNotFound #-}

zyanCoreStatusOutOfRange :: ZyanNativeStatus
zyanCoreStatusOutOfRange = makeZyanNativeStatus True zyanModuleCore 0x08
{-# INLINE zyanCoreStatusOutOfRange #-}

zyanCoreStatusInsufficientBufferSize :: ZyanNativeStatus
zyanCoreStatusInsufficientBufferSize =
  makeZyanNativeStatus True zyanModuleCore 0x09
{-# INLINE zyanCoreStatusInsufficientBufferSize #-}

zyanCoreStatusNotEnoughMemory :: ZyanNativeStatus
zyanCoreStatusNotEnoughMemory = makeZyanNativeStatus True zyanModuleCore 0x0A
{-# INLINE zyanCoreStatusNotEnoughMemory #-}

zyanCoreStatusBadSystemCall :: ZyanNativeStatus
zyanCoreStatusBadSystemCall = makeZyanNativeStatus True zyanModuleCore 0x0B
{-# INLINE zyanCoreStatusBadSystemCall #-}

zyanCoreStatusOutOfResources :: ZyanNativeStatus
zyanCoreStatusOutOfResources = makeZyanNativeStatus True zyanModuleCore 0x0C
{-# INLINE zyanCoreStatusOutOfResources #-}

zyanCoreStatusMissingDependency :: ZyanNativeStatus
zyanCoreStatusMissingDependency = makeZyanNativeStatus True zyanModuleCore 0x0D
{-# INLINE zyanCoreStatusMissingDependency #-}

-- * Zydis status
zyanModuleZydis :: ZyanNativeModule
zyanModuleZydis = 0x002
{-# INLINE zyanModuleZydis #-}

zydisStatusNoMoreData :: ZyanNativeStatus
zydisStatusNoMoreData = makeZyanNativeStatus True zyanModuleZydis 0x00
{-# INLINE zydisStatusNoMoreData #-}

zydisStatusDecodingError :: ZyanNativeStatus
zydisStatusDecodingError = makeZyanNativeStatus True zyanModuleZydis 0x01
{-# INLINE zydisStatusDecodingError #-}

zydisStatusInstructionTooLong :: ZyanNativeStatus
zydisStatusInstructionTooLong = makeZyanNativeStatus True zyanModuleZydis 0x02
{-# INLINE zydisStatusInstructionTooLong #-}

zydisStatusBadRegister :: ZyanNativeStatus
zydisStatusBadRegister = makeZyanNativeStatus True zyanModuleZydis 0x03
{-# INLINE zydisStatusBadRegister #-}

zydisStatusIllegalLock :: ZyanNativeStatus
zydisStatusIllegalLock = makeZyanNativeStatus True zyanModuleZydis 0x04
{-# INLINE zydisStatusIllegalLock #-}

zydisStatusIllegalLegacyPFX :: ZyanNativeStatus
zydisStatusIllegalLegacyPFX = makeZyanNativeStatus True zyanModuleZydis 0x05
{-# INLINE zydisStatusIllegalLegacyPFX #-}

zydisStatusIllegalRex :: ZyanNativeStatus
zydisStatusIllegalRex = makeZyanNativeStatus True zyanModuleZydis 0x06
{-# INLINE zydisStatusIllegalRex #-}

zydisStatusInvalidMap :: ZyanNativeStatus
zydisStatusInvalidMap = makeZyanNativeStatus True zyanModuleZydis 0x07
{-# INLINE zydisStatusInvalidMap #-}

zydisStatusMalformedEvex :: ZyanNativeStatus
zydisStatusMalformedEvex = makeZyanNativeStatus True zyanModuleZydis 0x08
{-# INLINE zydisStatusMalformedEvex #-}

zydisStatusMalformedMvex :: ZyanNativeStatus
zydisStatusMalformedMvex = makeZyanNativeStatus True zyanModuleZydis 0x09
{-# INLINE zydisStatusMalformedMvex #-}

zydisStatusInvalidMask :: ZyanNativeStatus
zydisStatusInvalidMask = makeZyanNativeStatus True zyanModuleZydis 0x0A
{-# INLINE zydisStatusInvalidMask #-}

zydisStatusSkipToken :: ZyanNativeStatus
zydisStatusSkipToken = makeZyanNativeStatus False zyanModuleZydis 0x0B
{-# INLINE zydisStatusSkipToken #-}

-- | Marshal low level Zyan/Zydis status to our "ZyanStatus".
--
-- This function must cover the complete range of possibilities.
--
fromZyanNativeStatus :: ZyanNativeStatus -> ZyanStatus
fromZyanNativeStatus s
  | s == zyanCoreStatusSuccess = Left ZyanCoreStatusSuccess
  | s == zyanCoreStatusFailed = Left ZyanCoreStatusFailed
  | s == zyanCoreStatusTrue = Left ZyanCoreStatusTrue
  | s == zyanCoreStatusFalse = Left ZyanCoreStatusFalse
  | s == zyanCoreStatusInvalidArgument = Left ZyanCoreStatusInvalidArgument
  | s == zyanCoreStatusInvalidOperation = Left ZyanCoreStatusInvalidOperation
  | s == zyanCoreStatusAccessDenied = Left ZyanCoreStatusAccessDenied
  | s == zyanCoreStatusNotFound = Left ZyanCoreStatusNotFound
  | s == zyanCoreStatusOutOfRange = Left ZyanCoreStatusOutOfRange
  | s == zyanCoreStatusInsufficientBufferSize = Left
    ZyanCoreStatusInsufficientBufferSize
  | s == zyanCoreStatusNotEnoughMemory = Left ZyanCoreStatusNotEnoughMemory
  | s == zyanCoreStatusBadSystemCall = Left ZyanCoreStatusBadSystemCall
  | s == zyanCoreStatusOutOfResources = Left ZyanCoreStatusOutOfResources
  | s == zyanCoreStatusMissingDependency = Left ZyanCoreStatusMissingDependency
  | s == zydisStatusNoMoreData = Right ZydisStatusNoMoreData
  | s == zydisStatusInvalidMask = Right ZydisStatusInvalidMask
  | s == zydisStatusMalformedMvex = Right ZydisStatusMalformedMvex
  | s == zydisStatusMalformedEvex = Right ZydisStatusMalformedEvex
  | s == zydisStatusInvalidMap = Right ZydisStatusInvalidMap
  | s == zydisStatusIllegalRex = Right ZydisStatusIllegalRex
  | s == zydisStatusIllegalLegacyPFX = Right ZydisStatusIllegalLegacyPFX
  | s == zydisStatusIllegalLock = Right ZydisStatusIllegalLock
  | s == zydisStatusBadRegister = Right ZydisStatusBadRegister
  | s == zydisStatusInstructionTooLong = Right ZydisStatusInstructionTooLong
  | s == zydisStatusDecodingError = Right ZydisStatusDecodingError
  | s == zydisStatusSkipToken = Right ZydisStatusSkipToken
  | otherwise = error $ "Fatal error, missing zyan status code: " <> show s
{-# INLINE fromZyanNativeStatus #-}