{-# LINE 1 "src/Bindings/Bfd/Symbol.hsc" #-}
-- This file is part of Bindings-bfd.
{-# LINE 2 "src/Bindings/Bfd/Symbol.hsc" #-}
--
-- Copyright (C) 2010 Michael Nelson
--
-- 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/>.

module Bindings.Bfd.Symbol (
   -- * Types
     Symbol
   , Symbol'
   , SymbolName
   -- * Foo
   , getBase
   , getBfd
   , getFlags
   , Bindings.Bfd.Symbol.getFlavour
   , Bindings.Bfd.Symbol.getName
   , setName
   , getSection
   , setSection
   , Bindings.Bfd.Symbol.getOutputSection
   , getSize
   , getValue
   , setValue
   , getValue'
   , Bindings.Bfd.Symbol.print
) where

import Data.Bits
import Data.Word

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

import System.Posix.IO

import {-# SOURCE #-} Bindings.Bfd              as Bfd
import                Bindings.Bfd.Flavour
import                Bindings.Bfd.Misc
import {-# SOURCE #-} Bindings.Bfd.Section      as Section
import                Bindings.Bfd.Symbol.Flags as SymbolFlags
import                Bindings.Bfd.Target


{-# LINE 57 "src/Bindings/Bfd/Symbol.hsc" #-}


type SymbolName = String

type Symbol = Ptr Symbol'

data Symbol' = Bfd      Bfd      
             | Name     CString
             | Value    Vma
             | Flags    Int
             | Section  Section
     deriving (Show)


instance Storable Symbol' where
   sizeOf _ = ((32))
{-# LINE 73 "src/Bindings/Bfd/Symbol.hsc" #-}
   alignment = sizeOf
   peekByteOff buf off
      | off == ((0)) =
{-# LINE 76 "src/Bindings/Bfd/Symbol.hsc" #-}
         do
            val <- ((\hsc_ptr -> peekByteOff hsc_ptr 0)) buf :: IO Bfd
{-# LINE 78 "src/Bindings/Bfd/Symbol.hsc" #-}
            return $ Bfd val
      | off == ((4)) = 
{-# LINE 80 "src/Bindings/Bfd/Symbol.hsc" #-}
         do
            val <- ((\hsc_ptr -> peekByteOff hsc_ptr 4)) buf :: IO Word
{-# LINE 82 "src/Bindings/Bfd/Symbol.hsc" #-}
            return $ Bindings.Bfd.Symbol.Name $ wordPtrToPtr $ fromIntegral val
      | off == ((8)) =
{-# LINE 84 "src/Bindings/Bfd/Symbol.hsc" #-}
         do 
            val <- ((\hsc_ptr -> peekByteOff hsc_ptr 8)) buf
{-# LINE 86 "src/Bindings/Bfd/Symbol.hsc" #-}
            return $ Value val
      | off == ((16)) =
{-# LINE 88 "src/Bindings/Bfd/Symbol.hsc" #-}
         do
            val <- ((\hsc_ptr -> peekByteOff hsc_ptr 16)) buf :: IO CUInt
{-# LINE 90 "src/Bindings/Bfd/Symbol.hsc" #-}
            return $ Bindings.Bfd.Symbol.Flags $ fromIntegral val
      | off == ((20)) =
{-# LINE 92 "src/Bindings/Bfd/Symbol.hsc" #-}
         do 
            val <- ((\hsc_ptr -> peekByteOff hsc_ptr 20)) buf
{-# LINE 94 "src/Bindings/Bfd/Symbol.hsc" #-}
            return $ Section val
      | otherwise = error $ "internal error: Bfd.Symbol.peekByteOffset " ++ show off
   pokeByteOff buf off val
      | off == ((4)) =
{-# LINE 98 "src/Bindings/Bfd/Symbol.hsc" #-}
           ((\hsc_ptr -> pokeByteOff hsc_ptr 4)) buf (unSymbol'Name val)
{-# LINE 99 "src/Bindings/Bfd/Symbol.hsc" #-}
      | off == ((8)) =
{-# LINE 100 "src/Bindings/Bfd/Symbol.hsc" #-}
           ((\hsc_ptr -> pokeByteOff hsc_ptr 8)) buf (unSymbol'Value val)
{-# LINE 101 "src/Bindings/Bfd/Symbol.hsc" #-}
      | off == ((20)) =
{-# LINE 102 "src/Bindings/Bfd/Symbol.hsc" #-}
           ((\hsc_ptr -> pokeByteOff hsc_ptr 20)) buf (unSymbol'Section val)
{-# LINE 103 "src/Bindings/Bfd/Symbol.hsc" #-}
      | otherwise = error $ "internal error: Bfd.Symbol.pokeByteOff " ++ show off


unSymbol'TheBfd
   :: Symbol'
   -> Bfd
unSymbol'TheBfd (Bfd b) = b
unSymbol'TheBfd _       = error "unSymbol'TheBfd"

unSymbol'Name
   :: Symbol'
   -> CString
unSymbol'Name (Bindings.Bfd.Symbol.Name s) = s
unSymbol'Name _                            = error "unSymbol'Name"

unSymbol'Value
   :: Symbol'
   -> Vma
unSymbol'Value (Value v) = v
unSymbol'Value _         = error "unSymbol'Value"

unSymbol'Flags
   :: Symbol'
   -> Int
unSymbol'Flags (Bindings.Bfd.Symbol.Flags f) = f
unSymbol'Flags _                             = error "unSymbol'Flags"

unSymbol'Section
   :: Symbol'
   -> Section
unSymbol'Section (Section s) = s
unSymbol'Section _           = error "unSymbol'Section"


getBase
   :: Symbol
   -> IO Vma
getBase sym =
   do
      sect <- getSection sym
      getVma sect

getBfd 
   :: Symbol
   -> IO Bfd
getBfd sym =
   do
      bfd <- peekByteOff sym ((0))
{-# LINE 151 "src/Bindings/Bfd/Symbol.hsc" #-}
      return $ unSymbol'TheBfd bfd

getFlags
   :: Symbol
   -> IO [SymbolFlags.Flags]
getFlags sym =
   do
      flags <- peekByteOff sym ((16))
{-# LINE 159 "src/Bindings/Bfd/Symbol.hsc" #-}
      let
         flags' = filter f $ enumFrom Local
            where
               f e = unSymbol'Flags flags .&. (bit $ fromEnum e) /= 0
      return flags'

getFlavour
   :: Symbol
   -> IO Flavour
getFlavour sym =
   do
      flags <- getFlags sym
      case Synthetic `elem` flags of
         True  -> return Unknown
         False ->
            do
               bfd <- getBfd sym
               Bfd.getFlavour bfd

getName
   :: Symbol
   -> IO SymbolName
getName sym =
   do
      s' <- peekByteOff sym ((4))
{-# LINE 184 "src/Bindings/Bfd/Symbol.hsc" #-}
      peekCString $ unSymbol'Name s'

setName
   :: Symbol
   -> SymbolName
   -> IO ()
setName sym name =
   do
      cs <- newCString name
      pokeByteOff sym ((4)) $ Bindings.Bfd.Symbol.Name cs
{-# LINE 194 "src/Bindings/Bfd/Symbol.hsc" #-}

getSection
   :: Symbol
   -> IO Section
getSection sym =
   do
      sect <- peekByteOff sym ((20))
{-# LINE 201 "src/Bindings/Bfd/Symbol.hsc" #-}
      return $ unSymbol'Section sect

setSection
   :: Symbol
   -> Section
   -> IO ()
setSection sym sect = pokeByteOff sym ((20)) $ Section sect
{-# LINE 208 "src/Bindings/Bfd/Symbol.hsc" #-}

getOutputSection
   :: Symbol
   -> IO Section
getOutputSection sym =
   do
      sect <- getSection sym
      Section.getOutputSection sect

getSize
   :: Symbol
   -> Bfd
   -> IO Int
getSize sym bfd =
   do
      str <- Bindings.Bfd.Symbol.print sym bfd
      let
         size = read $ "0x" ++ (head $ tail $ reverse $ words str)
      return size

getValue
   :: Symbol
   -> IO Vma
getValue sym =
   do
      v <- peekByteOff sym ((8))
{-# LINE 234 "src/Bindings/Bfd/Symbol.hsc" #-}
      return $ unSymbol'Value v

setValue
   :: Symbol
   -> Vma
   -> IO ()
setValue sym vma = pokeByteOff sym ((8)) (Value vma)
{-# LINE 241 "src/Bindings/Bfd/Symbol.hsc" #-}

getValue'
   :: Symbol
   -> IO Vma
getValue' sym =
   do
      base <- getBase  sym
      val  <- getValue sym
      return $ base + val

print
   :: Symbol
   -> Bfd
   -> IO String
print sym bfd = 
   do
      (pipeRead, pipeWrite) <- createPipe
      setFdOption pipeRead NonBlockingRead False

      let
         pipeWrite' = fromIntegral pipeWrite
      mode <- newCString "w"
      fpWrite <- c_fdopen pipeWrite' mode

      xvec <- getTarget bfd
      f    <- getPrintSymbol xvec bfd fpWrite sym

      f
      _ <- c_fflush fpWrite

      (s,_) <- fdRead pipeRead 80

      closeFd pipeRead
      closeFd pipeWrite
      return s