{-# LINE 1 "src/Bindings/Bfd/Target.hsc" #-}
-- This file is part of Bindings-bfd.
{-# LINE 2 "src/Bindings/Bfd/Target.hsc" #-}
--
-- Copyright (C) 2010,2011 Mick Nelso
--
-- Bindings-bfd is free software: you can redistribute it and/or modify
-- it under the terms of the GNU Lesser General Public License as published by
-- the Free Software Foundation, either version 3 of the License, or
-- (at your option) any later version.
--
-- Bindings-bfd 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 Lesser General Public License for more details.

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

-- | The "Target" represents a particular back-end used to interpret the "Bfd".
module Bindings.Bfd.Target (
   -- * Types
     Target
   , TargetName
   -- * Platform
   , listSupported
   , setDefault
   -- * Byte Order
   , getByteorder
   , getHeaderByteorder
   -- *
   , getObjectFlags
   , getSectionFlags
   , Bindings.Bfd.Target.getFlavour
   , getName
   -- ** Symtabs
   , getSymtabUpperBound
   , canonicalizeSymtab
   , getDynamicSymtabUpperBound
   , canonicalizeDynamicSymtab
   , getSyntheticSymtab
   -- ** Relocations
   , getDynamicRelocUpperBound
   , canonicalizeDynamicReloc
   -- * Testing
   -- ** Byte Order
   , isBigEndian
   , isLittleEndian
   , isHeaderBigEndian
   , isHeaderLittleEndian
   -- ** Coff Family
   , isCoffFamily
   -- *
   , getPrintSymbol
   -- * Internal
   , Target'
) where

import Data.Bits
import Data.Word

import Foreign.C
import Foreign.Marshal
import Foreign.Ptr
import Foreign.Storable

import {-# SOURCE #-} Bindings.Bfd
import                Bindings.Bfd.Endian
import                Bindings.Bfd.Exception
import                Bindings.Bfd.Flags         as BfdFlags
import                Bindings.Bfd.Flavour
import                Bindings.Bfd.Misc
import {-# SOURCE #-} Bindings.Bfd.Relocation
import                Bindings.Bfd.Section.Flags as SectionFlags
import {-# SOURCE #-} Bindings.Bfd.Symbol        as Symbol
import {-# SOURCE #-} Bindings.Bfd.SymbolTable


{-# LINE 77 "src/Bindings/Bfd/Target.hsc" #-}


type TargetName = String

type Target = Ptr Target'

data Target' = Name                       TargetName
             | Flavour                    Flavour
             | Byteorder                  Endian
             | HeaderByteorder            Endian
             | ObjectFlags                [BfdFlags.Flags]
             | SectionFlags               [SectionFlags.Flags]
             | GetSymtabUpperBound        (FunPtr (Ptr Bfd' -> IO CLong))
             | CanonicalizeSymtab         (FunPtr (Ptr Bfd' -> Ptr Symbol -> IO CLong))
             | PrintSymbol                (FunPtr (Ptr Bfd' -> File -> Symbol -> CUInt -> IO ()))
             | GetDynamicSymtabUpperBound (FunPtr (Ptr Bfd' -> IO CLong))
             | CanonicalizeDynamicSymtab  (FunPtr (Ptr Bfd' -> Ptr Symbol -> IO CLong))
             | GetSyntheticSymtab         (FunPtr (Ptr Bfd' -> CLong -> Ptr Symbol -> CLong -> Ptr Symbol -> Ptr Symbol -> IO CLong))
             | GetDynamicRelocUpperBound  (FunPtr (Ptr Bfd' -> IO CLong))
             | CanonicalizeDynamicReloc   (FunPtr (Ptr Bfd' -> Ptr (Ptr Relocation) -> Ptr Symbol -> IO CLong))
     deriving (Show)

instance Storable Target' where
   sizeOf _ = (432)
{-# LINE 101 "src/Bindings/Bfd/Target.hsc" #-}
   alignment = sizeOf
   peekByteOff buf off
      | off == ((0)) =
{-# LINE 104 "src/Bindings/Bfd/Target.hsc" #-}
         do
            val <- ((\hsc_ptr -> peekByteOff hsc_ptr 0)) buf
{-# LINE 106 "src/Bindings/Bfd/Target.hsc" #-}
            s   <- peekCString val
            return $ Bindings.Bfd.Target.Name s
      | off == ((4)) =
{-# LINE 109 "src/Bindings/Bfd/Target.hsc" #-}
         do
            val <- ((\hsc_ptr -> peekByteOff hsc_ptr 4)) buf :: IO CUInt
{-# LINE 111 "src/Bindings/Bfd/Target.hsc" #-}
            return $ Flavour $ toEnum $ fromIntegral val
      | off == ((8)) =
{-# LINE 113 "src/Bindings/Bfd/Target.hsc" #-}
         do
            val <- ((\hsc_ptr -> peekByteOff hsc_ptr 8)) buf :: IO CUInt
{-# LINE 115 "src/Bindings/Bfd/Target.hsc" #-}
            return $ Byteorder $ toEnum $ fromIntegral val
      | off == ((12)) =
{-# LINE 117 "src/Bindings/Bfd/Target.hsc" #-}
         do
            val <- ((\hsc_ptr -> peekByteOff hsc_ptr 12)) buf :: IO CUInt
{-# LINE 119 "src/Bindings/Bfd/Target.hsc" #-}
            return $ HeaderByteorder $ toEnum $ fromIntegral val
      | off == ((16)) =
{-# LINE 121 "src/Bindings/Bfd/Target.hsc" #-}
         do
            val <- ((\hsc_ptr -> peekByteOff hsc_ptr 16)) buf :: IO CUInt
{-# LINE 123 "src/Bindings/Bfd/Target.hsc" #-}
            let
               flags = filter f $ enumFrom HasReloc
                  where
                     f e = val .&. (bit $ fromEnum e) /= 0
            return $ ObjectFlags flags
      | off == ((20)) =
{-# LINE 129 "src/Bindings/Bfd/Target.hsc" #-}
         do
            val <- ((\hsc_ptr -> peekByteOff hsc_ptr 20)) buf :: IO CUInt
{-# LINE 131 "src/Bindings/Bfd/Target.hsc" #-}
            let
               flags = filter f $ enumFrom Alloc
                  where
                     f e = val .&. (bit $ fromEnum e) /= 0
            return $ SectionFlags flags
      | off == ((260)) =
{-# LINE 137 "src/Bindings/Bfd/Target.hsc" #-}
         do
            val <- ((\hsc_ptr -> peekByteOff hsc_ptr 260)) buf :: IO Word
{-# LINE 139 "src/Bindings/Bfd/Target.hsc" #-}
            return $ GetSymtabUpperBound $ castPtrToFunPtr $ wordPtrToPtr $ fromIntegral val
      | off == ((264)) =
{-# LINE 141 "src/Bindings/Bfd/Target.hsc" #-}
         do
            val <- ((\hsc_ptr -> peekByteOff hsc_ptr 264)) buf :: IO Word
{-# LINE 143 "src/Bindings/Bfd/Target.hsc" #-}
            return $ CanonicalizeSymtab $ castPtrToFunPtr $ wordPtrToPtr $ fromIntegral val
      | off == ((272)) =
{-# LINE 145 "src/Bindings/Bfd/Target.hsc" #-}
         do
            val <- ((\hsc_ptr -> peekByteOff hsc_ptr 272)) buf :: IO Word
{-# LINE 147 "src/Bindings/Bfd/Target.hsc" #-}
            return $ PrintSymbol $ castPtrToFunPtr $ wordPtrToPtr $ fromIntegral val
      | off == ((404)) =
{-# LINE 149 "src/Bindings/Bfd/Target.hsc" #-}
         do
            val <- ((\hsc_ptr -> peekByteOff hsc_ptr 404)) buf :: IO Word
{-# LINE 151 "src/Bindings/Bfd/Target.hsc" #-}
            return $ GetDynamicSymtabUpperBound $ castPtrToFunPtr $ wordPtrToPtr $ fromIntegral val
      | off == ((408)) =
{-# LINE 153 "src/Bindings/Bfd/Target.hsc" #-}
         do
            val <- ((\hsc_ptr -> peekByteOff hsc_ptr 408)) buf :: IO Word
{-# LINE 155 "src/Bindings/Bfd/Target.hsc" #-}
            return $ CanonicalizeDynamicSymtab $ castPtrToFunPtr $ wordPtrToPtr $ fromIntegral val
      | off == ((412)) =
{-# LINE 157 "src/Bindings/Bfd/Target.hsc" #-}
         do
            val <- ((\hsc_ptr -> peekByteOff hsc_ptr 412)) buf :: IO Word
{-# LINE 159 "src/Bindings/Bfd/Target.hsc" #-}
            return $ GetSyntheticSymtab $ castPtrToFunPtr $ wordPtrToPtr $ fromIntegral val
      | off == ((416)) =
{-# LINE 161 "src/Bindings/Bfd/Target.hsc" #-}
         do
            val <- ((\hsc_ptr -> peekByteOff hsc_ptr 416)) buf :: IO Word
{-# LINE 163 "src/Bindings/Bfd/Target.hsc" #-}
            return $ GetDynamicRelocUpperBound $ castPtrToFunPtr $ wordPtrToPtr $ fromIntegral val
      | off == ((420)) =
{-# LINE 165 "src/Bindings/Bfd/Target.hsc" #-}
         do
            val <- ((\hsc_ptr -> peekByteOff hsc_ptr 420)) buf :: IO Word
{-# LINE 167 "src/Bindings/Bfd/Target.hsc" #-}
            return $ CanonicalizeDynamicReloc $ castPtrToFunPtr $ wordPtrToPtr $ fromIntegral val
      | otherwise = error $ "internal error: Bfd.Target.peekByteOff " ++ show off


-- | Return a list of target names that can possibly be interpreted by this
-- particular platform.
listSupported
   :: IO [TargetName]
listSupported = 
   do
      let
         pts = c_bfd_target_list
      ps <- peekArray0 nullPtr pts
      res <- mapM peekCString ps
      free pts                       -- FIXME is this dodgy?
      return res

-- | Set the default target name for use with 'open' etc. when 'TargetName' is
-- equal to \"default\" or empty.  Returns 'True' if successful.
--
-- /Possible exceptions:/ 'InvalidTarget'
setDefault
   :: TargetName
   -> IO Bool
setDefault tn =
   do
      r <- withCString tn (\s -> c_bfd_set_default_target s)
      throwExceptionIfFalse "setDefault" tn (return $ toBool r)

getByteorder
   :: Target
   -> IO Endian
getByteorder targ =
   do
      bo <- peekByteOff targ ((8))
{-# LINE 202 "src/Bindings/Bfd/Target.hsc" #-}
      return $ unTarget'Byteorder bo

getHeaderByteorder
   :: Target
   -> IO Endian
getHeaderByteorder targ =
   do
      bo <- peekByteOff targ ((12))
{-# LINE 210 "src/Bindings/Bfd/Target.hsc" #-}
      return $ unTarget'HeaderByteorder bo

getObjectFlags
   :: Target
   -> IO [BfdFlags.Flags]
getObjectFlags targ =
   do
      f <- peekByteOff targ ((16))
{-# LINE 218 "src/Bindings/Bfd/Target.hsc" #-}
      return $ unTarget'ObjectFlags f

getSectionFlags
   :: Target
   -> IO [SectionFlags.Flags]
getSectionFlags targ =
   do
      f <- peekByteOff targ ((20))
{-# LINE 226 "src/Bindings/Bfd/Target.hsc" #-}
      return $ unTarget'SectionFlags f

getFlavour
   :: Target
   -> IO Flavour
getFlavour targ =
   do
      flav <- peekByteOff targ ((4))
{-# LINE 234 "src/Bindings/Bfd/Target.hsc" #-}
      return $ unTarget'Flavour flav

getName
   :: Target
   -> IO TargetName
getName targ =
   do
      tn <- peekByteOff targ ((0))
{-# LINE 242 "src/Bindings/Bfd/Target.hsc" #-}
      let
         tn' = unTarget'Name tn
      return tn'


getSymtabUpperBound
   :: Target
   -> Bfd
   -> IO Int
getSymtabUpperBound targ bfd =
   do
      fn <- peekByteOff targ ((260))
{-# LINE 254 "src/Bindings/Bfd/Target.hsc" #-}
      r <- d_Bfd_CLong (unTarget'GetSymtabUpperBound fn) $ ptr bfd
      return $ fromIntegral r

canonicalizeSymtab
   :: Target
   -> Bfd
   -> Ptr Symbol
   -> IO Int
canonicalizeSymtab targ bfd ps =
   do
      fn <- peekByteOff targ ((264))
{-# LINE 265 "src/Bindings/Bfd/Target.hsc" #-}
      r <- d_Bfd_PtrSymbol_CLong (unTarget'CanonicalizeSymtab fn) (ptr bfd) ps
      return $ fromIntegral r

getDynamicSymtabUpperBound
   :: Target
   -> Bfd
   -> IO Int
getDynamicSymtabUpperBound targ bfd =
   do
      fn <- peekByteOff targ ((404))
{-# LINE 275 "src/Bindings/Bfd/Target.hsc" #-}
      r <- d_Bfd_CLong (unTarget'GetDynamicSymtabUpperBound fn) (ptr bfd)
      return $ fromIntegral r

canonicalizeDynamicSymtab
   :: Target
   -> Bfd
   -> Ptr Symbol
   -> IO Int
canonicalizeDynamicSymtab targ bfd ps =
   do
      fn <- peekByteOff targ ((408))
{-# LINE 286 "src/Bindings/Bfd/Target.hsc" #-}
      r <- d_Bfd_PtrSymbol_CLong (unTarget'CanonicalizeDynamicSymtab fn) (ptr bfd) ps
      return $ fromIntegral r

getSyntheticSymtab
   :: Target
   -> Bfd
   -> SymbolTable
   -> SymbolTable
   -> Ptr Symbol
   -> IO Int
getSyntheticSymtab targ bfd sst dst synth =
   do
      fn <- peekByteOff targ ((412))
{-# LINE 299 "src/Bindings/Bfd/Target.hsc" #-}
      r <- d_Bfd_CLong_PtrSymbol_CLong_PtrSymbol_PtrSymbol_CLong (fn' fn) (ptr bfd) sts stp dts dtp synth
      return $ fromIntegral r
   where
      fn' = unTarget'GetSyntheticSymtab
      sts = fromIntegral $ tableSize sst
      stp = tablePtr sst
      dts = fromIntegral $ tableSize dst
      dtp = tablePtr dst

getDynamicRelocUpperBound
   :: Target
   -> Bfd
   -> IO Int
getDynamicRelocUpperBound targ bfd =
   do
      fn <- peekByteOff targ ((416))
{-# LINE 315 "src/Bindings/Bfd/Target.hsc" #-}
      r <- d_Bfd_CLong (unTarget'GetDynamicRelocUpperBound fn) (ptr bfd)
      return $ fromIntegral r

canonicalizeDynamicReloc
   :: Target
   -> Bfd
   -> Ptr (Ptr Relocation)
   -> Ptr Symbol
   -> IO Int
canonicalizeDynamicReloc targ bfd rels syms =
   do
      fn <- peekByteOff targ ((420))
{-# LINE 327 "src/Bindings/Bfd/Target.hsc" #-}
      r <- d_Bfd_PtrPtrRelocation_PtrSymbol_CLong (unTarget'CanonicalizeDynamicReloc fn) (ptr bfd) rels syms
      return $ fromIntegral r

-- Testing =====================================================================
-- Byte Order ------------------------------------------------------------------

-- | Returns 'True' if the 'Target's byte order (see 'getByteorder') is 'Big'.
-- Otherwise 'False'.
isBigEndian
   :: Target
   -> IO Bool
isBigEndian targ =
   do
      bo <- getByteorder targ
      return $ bo == Big

-- | Returns 'True' if the 'Target's byte order (see 'getByteorder') is 'Little'.
-- Otherwise 'False'.
isLittleEndian
   :: Target
   -> IO Bool
isLittleEndian targ =
   do
      bo <- getByteorder targ
      return $ bo == Little

-- | Returns 'True' if the 'Target's header byte order (see 'getHeaderByteOrder')
-- is 'Big'.  Otherwise 'False'.
isHeaderBigEndian
   :: Target
   -> IO Bool
isHeaderBigEndian targ =
   do
      bo <- getHeaderByteorder targ
      return $ bo == Big

-- | Returns 'True' if the 'Target's header byte order (see 'getHeaderByteOrder')
-- is 'Little'.  Otherwise 'False'.
isHeaderLittleEndian
   :: Target
   -> IO Bool
isHeaderLittleEndian targ =
   do
      bo <- getHeaderByteorder targ
      return $ bo == Little

-- Coff Family -----------------------------------------------------------------

-- | Returns 'True' if the 'Flavour' of the 'Target' is either 'Coff' or 'Xcoff'.
--  Otherwise 'False'.
isCoffFamily
   :: Target
   -> IO Bool
isCoffFamily targ =
   do
      flav <- getFlavour targ
      return $ flav == Coff || flav == Xcoff

-- -----------------------------------------------------------------------------

unTarget'Name
   :: Target'
   -> TargetName
unTarget'Name (Bindings.Bfd.Target.Name s) = s
unTarget'Name _                            = error "unTarget'Name"

unTarget'Flavour
   :: Target'
   -> Flavour
unTarget'Flavour (Flavour f) = f
unTarget'Flavour _           = error "unTarget'Flavour"

unTarget'Byteorder
   :: Target'
   -> Endian
unTarget'Byteorder (Byteorder b) = b
unTarget'Byteorder _             = error "unTarget'Byteorder"

unTarget'HeaderByteorder
   :: Target'
   -> Endian
unTarget'HeaderByteorder (HeaderByteorder b) = b
unTarget'HeaderByteorder _                   = error "unTarget'HeaderByteorder"

unTarget'ObjectFlags
   :: Target'
   -> [BfdFlags.Flags]
unTarget'ObjectFlags (ObjectFlags b) = b
unTarget'ObjectFlags _               = error "unTarget'ObjectFlags"

unTarget'SectionFlags
   :: Target'
   -> [SectionFlags.Flags]
unTarget'SectionFlags (SectionFlags b) = b
unTarget'SectionFlags _                = error "unTarget'SectionFlags"

unTarget'GetSymtabUpperBound
   :: Target'
   -> FunPtr (Ptr Bfd' -> IO CLong)
unTarget'GetSymtabUpperBound (GetSymtabUpperBound fn) = fn
unTarget'GetSymtabUpperBound _                        = error "unTarget'GetSymtabUpperBound"

unTarget'CanonicalizeSymtab
   :: Target'
   -> FunPtr (Ptr Bfd' -> Ptr Symbol -> IO CLong)
unTarget'CanonicalizeSymtab (CanonicalizeSymtab fn) = fn
unTarget'CanonicalizeSymtab _                       = error "unTarget'CanonicalizeSymtab"

unTarget'GetDynamicSymtabUpperBound
   :: Target'
   -> FunPtr (Ptr Bfd' -> IO CLong)
unTarget'GetDynamicSymtabUpperBound (GetDynamicSymtabUpperBound fn) = fn
unTarget'GetDynamicSymtabUpperBound _                               = error "unTarget'GetDynamicSymtabUpperBound"

unTarget'CanonicalizeDynamicSymtab
   :: Target'
   -> FunPtr (Ptr Bfd' -> Ptr Symbol -> IO CLong)
unTarget'CanonicalizeDynamicSymtab (CanonicalizeDynamicSymtab fn) = fn
unTarget'CanonicalizeDynamicSymtab _                              = error "unTarget'CanonicalizeDynamicSymtab"

unTarget'GetSyntheticSymtab
   :: Target'
   -> FunPtr (Ptr Bfd' -> CLong -> Ptr Symbol -> CLong -> Ptr Symbol -> Ptr Symbol -> IO CLong)
unTarget'GetSyntheticSymtab (GetSyntheticSymtab fn) = fn
unTarget'GetSyntheticSymtab _                       = error "unTarget'GetSyntheticSymtab"

unTarget'GetDynamicRelocUpperBound
   :: Target'
   -> FunPtr (Ptr Bfd' -> IO CLong)
unTarget'GetDynamicRelocUpperBound (GetDynamicRelocUpperBound fn) = fn
unTarget'GetDynamicRelocUpperBound _                              = error "unTarget'GetDynamicRelocUpperBound"

unTarget'CanonicalizeDynamicReloc
   :: Target'
   -> FunPtr (Ptr Bfd' -> Ptr (Ptr Relocation) -> Ptr Symbol -> IO CLong)
unTarget'CanonicalizeDynamicReloc (CanonicalizeDynamicReloc fn) = fn
unTarget'CanonicalizeDynamicReloc _                             = error "unTarget'CanonicalizeDynamicReloc"

unXVec2
   :: Target'
   -> FunPtr (Ptr Bfd' -> File -> Symbol -> CUInt -> IO ())
unXVec2 (PrintSymbol fn) = fn
unXVec2 x                = error $ "internal error: unXVec2 " ++ show x


getPrintSymbol
   :: Target
   -> Bfd
   -> File
   -> Symbol
   -> IO (IO ())
getPrintSymbol targ bfd file sym =
   do 
      fn <- peekByteOff targ ((272))
{-# LINE 481 "src/Bindings/Bfd/Target.hsc" #-}
      let
         f = d_Bfd_File_Symbol_CUInt_Void (unXVec2 fn) (ptr bfd) file sym 2
      return f

-- -----------------------------------------------------------------------------

foreign import ccall unsafe "bfd.h bfd_target_list" c_bfd_target_list
   :: Ptr CString

foreign import ccall unsafe "bfd.h bfd_set_default_target" c_bfd_set_default_target
   :: CString
   -> IO CInt

foreign import ccall unsafe "dynamic" d_Bfd_CLong
   :: FunPtr (Ptr Bfd' -> IO CLong)
   -> (Ptr Bfd' -> IO CLong)

foreign import ccall unsafe "dynamic" d_Bfd_CLong_PtrSymbol_CLong_PtrSymbol_PtrSymbol_CLong
   :: FunPtr (Ptr Bfd' -> CLong -> Ptr Symbol -> CLong -> Ptr Symbol -> Ptr Symbol -> IO CLong) 
   -> (Ptr Bfd' -> CLong -> Ptr Symbol -> CLong -> Ptr Symbol -> Ptr Symbol -> IO CLong)

foreign import ccall unsafe "dynamic" d_Bfd_PtrSymbol_CLong
   :: FunPtr (Ptr Bfd' -> Ptr Symbol -> IO CLong)
   -> (Ptr Bfd' -> Ptr Symbol -> IO CLong)

foreign import ccall unsafe "dynamic" d_Bfd_PtrPtrRelocation_PtrSymbol_CLong
   :: FunPtr (Ptr Bfd' -> Ptr (Ptr Relocation) -> Ptr Symbol -> IO CLong) 
   -> (Ptr Bfd' -> Ptr (Ptr Relocation) -> Ptr Symbol -> IO CLong)

foreign import ccall unsafe "dynamic" d_Bfd_File_Symbol_CUInt_Void
   :: FunPtr (Ptr Bfd' -> File -> Symbol -> CUInt -> IO ()) 
   -> (Ptr Bfd' -> File -> Symbol -> CUInt -> IO ())