-- |
-- Module      : Binja.Llil
-- Description : Low Level IL instruction interface
-- License     : MIT
-- Maintainer  : hello@bloombit.dev
-- Stability   : alpha
--
-- @Binja.Llil@ implements just enough to support medium level IL and utility functions.
--
-- Official Llil Documentation: <https://docs.binary.ninja/dev/bnil-llil.html Binary Ninja Intermediate Language: Low Level IL>
module Binja.Llil
  ( Binja.Llil.startIndex,
    Binja.Llil.sourceFunc,
    Binja.Llil.fromRef,
    Binja.Llil.at,
    Binja.Llil.llilRefToMlilExprIndex,
  )
where

import Binja.BinaryView (functionsContaining)
import Binja.FFI
import Binja.Function
import Binja.Types

sourceFunc :: BNLlilFunctionPtr -> IO BNFunctionPtr
sourceFunc :: BNLlilFunctionPtr -> IO BNFunctionPtr
sourceFunc BNLlilFunctionPtr
func = do
  BNLlilFunctionPtr -> IO BNFunctionPtr
c_BNGetLowLevelILOwnderFunction BNLlilFunctionPtr
func

startIndex :: BNLlilFunctionPtr -> BNArchPtr -> Word64 -> IO CSize
startIndex :: BNLlilFunctionPtr -> BNArchPtr -> Word64 -> IO CSize
startIndex BNLlilFunctionPtr
func BNArchPtr
arch' Word64
addr = do
  if BNArchPtr
arch' BNArchPtr -> BNArchPtr -> Bool
forall a. Eq a => a -> a -> Bool
== BNArchPtr
forall a. Ptr a
nullPtr Bool -> Bool -> Bool
|| BNLlilFunctionPtr
func BNLlilFunctionPtr -> BNLlilFunctionPtr -> Bool
forall a. Eq a => a -> a -> Bool
== BNLlilFunctionPtr
forall a. Ptr a
nullPtr
    then [Char] -> IO CSize
forall a. HasCallStack => [Char] -> a
error [Char]
"Binja.Llil.startIndex: called with nullPtr argument"
    else do
      startI <- BNLlilFunctionPtr -> BNArchPtr -> Word64 -> IO CSize
c_BNLowLevelILGetInstructionStart BNLlilFunctionPtr
func BNArchPtr
arch' Word64
addr
      count' <- c_BNGetLowLevelILInstructionCount func
      -- \^Ensure start index is less than total llil instructions
      --  in function
      if startI >= count'
        then error ("Binja.Llil.startIndex: startI:" ++ show startI ++ " >= count:" ++ show count')
        else pure startI

-- | Convert an instruction index into an expression index
instIndexToExprIndex :: BNLlilFunctionPtr -> Word64 -> IO CSize
instIndexToExprIndex :: BNLlilFunctionPtr -> Word64 -> IO CSize
instIndexToExprIndex = BNLlilFunctionPtr -> Word64 -> IO CSize
c_BNGetLowLevelILIndexForInstruction

llilByIndex :: BNLlilFunctionPtr -> CSize -> IO BNLowLevelILInstruction
llilByIndex :: BNLlilFunctionPtr -> CSize -> IO BNLowLevelILInstruction
llilByIndex BNLlilFunctionPtr
func CSize
index' =
  (Ptr BNLowLevelILInstruction -> IO BNLowLevelILInstruction)
-> IO BNLowLevelILInstruction
forall a b. Storable a => (Ptr a -> IO b) -> IO b
alloca ((Ptr BNLowLevelILInstruction -> IO BNLowLevelILInstruction)
 -> IO BNLowLevelILInstruction)
-> (Ptr BNLowLevelILInstruction -> IO BNLowLevelILInstruction)
-> IO BNLowLevelILInstruction
forall a b. (a -> b) -> a -> b
$ \Ptr BNLowLevelILInstruction
p -> do
    _ <- Ptr BNLowLevelILInstruction
-> BNLlilFunctionPtr -> CSize -> IO (Ptr BNLowLevelILInstruction)
c_BNGetLowLevelILByIndexPtr Ptr BNLowLevelILInstruction
p BNLlilFunctionPtr
func CSize
index'
    peek p

-- | Retrieve the best LLIL instruction for the address in BNReferenceSource
fromRef :: BNReferenceSource -> IO BNLowLevelILInstruction
fromRef :: BNReferenceSource -> IO BNLowLevelILInstruction
fromRef BNReferenceSource
ref = do
  func <- BNFunctionPtr -> IO BNLlilFunctionPtr
Binja.Function.llil (BNReferenceSource -> BNFunctionPtr
bnFunc BNReferenceSource
ref)
  sIndex <- startIndex func (bnArch ref) (bnAddr ref)
  exprIndex' <- instIndexToExprIndex func (fromIntegral sIndex)
  llilByIndex func exprIndex'

-- | Retrieve the best low level il instruction given an address into a binary view
at :: BNBinaryViewPtr -> Word64 -> IO BNLowLevelILInstruction
at :: BNBinaryViewPtr -> Word64 -> IO BNLowLevelILInstruction
at BNBinaryViewPtr
view Word64
addr = do
  rawFuncs <- BNBinaryViewPtr -> Word64 -> IO [BNFunctionPtr]
functionsContaining BNBinaryViewPtr
view Word64
addr
  if null rawFuncs
    then error $ "Binja.Llil.at: No functions at: " ++ show addr
    else do
      llilFunc <- Binja.Function.llil $ head rawFuncs
      archHandle' <- c_BNGetFunctionArchitecture $ head rawFuncs
      sIndex <- startIndex llilFunc archHandle' addr
      exprIndex' <- instIndexToExprIndex llilFunc (fromIntegral sIndex)
      llilByIndex llilFunc exprIndex'

-- | Retrieve the best low level il instruction expression index for the address in BNReferenceSource
llilRefToMlilExprIndex :: BNReferenceSource -> IO CSize
llilRefToMlilExprIndex :: BNReferenceSource -> IO CSize
llilRefToMlilExprIndex BNReferenceSource
ref = do
  func <- BNFunctionPtr -> IO BNLlilFunctionPtr
Binja.Function.llil (BNReferenceSource -> BNFunctionPtr
bnFunc BNReferenceSource
ref)
  sIndex <- startIndex func (bnArch ref) (bnAddr ref)
  llilExprIndex <- instIndexToExprIndex func (fromIntegral sIndex)
  mlilExprIndex <- c_BNGetMediumLevelILExprIndex func llilExprIndex
  funcSSA <- Binja.Function.mlil (bnFunc ref)
  c_BNGetMediumLevelILSSAExprIndex funcSSA mlilExprIndex