-- This file is part of Bindings-bfd. -- -- 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 . module Bindings.Bfd.Symbol ( -- * Types Symbol , SymbolName -- * Addressing , getBase , setValue , getValue , getValue' , getBfd , getFlags , Bindings.Bfd.Symbol.getFlavour -- * SymbolName , setName , Bindings.Bfd.Symbol.getName -- * Sections , setSection , getSection , Bindings.Bfd.Symbol.getOutputSection , Bindings.Bfd.Symbol.getSize , Bindings.Bfd.Symbol.print -- * Internal , Symbol' ) where import Data.Bits ( (.&.), bit ) import Data.Word ( Word ) import Foreign.C ( CString, CUInt, newCString, peekCString ) import Foreign.Ptr ( Ptr, wordPtrToPtr ) import Foreign.Storable ( Storable, alignment, peekByteOff, pokeByteOff, sizeOf ) import System.Posix.IO ( FdOption(NonBlockingRead), closeFd, createPipe, fdRead , setFdOption ) import {-# SOURCE #-} Bindings.Bfd as Bfd ( Bfd, Bfd' , getPrintSymbol , getTarget, mk) import Bindings.Bfd.Flavour ( Flavour(Unknown) ) import Bindings.Bfd.Misc ( Vma, c_fdopen , c_fflush ) import {-# SOURCE #-} Bindings.Bfd.Section as Section ( Section , getOutputSection , getVma ) import Bindings.Bfd.Symbol.Flags as SymbolFlags ( Flags(Local, Synthetic) ) import Bindings.Bfd.Target as Target ( getFlavour ) #include type SymbolName = String type Symbol = Ptr Symbol' data Symbol' = Bfd (Ptr Bfd') | Name CString | Value Vma | Flags Int | Section Section deriving (Show) instance Storable Symbol' where sizeOf _ = (#size struct bfd_symbol) alignment = sizeOf peekByteOff buf off | off == (#offset struct bfd_symbol, the_bfd) = do val <- (#peek struct bfd_symbol, the_bfd) buf :: IO (Ptr Bfd') return $ Bindings.Bfd.Symbol.Bfd val | off == (#offset struct bfd_symbol, name) = do val <- (#peek struct bfd_symbol, name) buf :: IO Word return $ Bindings.Bfd.Symbol.Name $ wordPtrToPtr $ fromIntegral val | off == (#offset struct bfd_symbol, value) = do val <- (#peek struct bfd_symbol, value) buf return $ Value val | off == (#offset struct bfd_symbol, flags) = do val <- (#peek struct bfd_symbol, flags) buf :: IO CUInt return $ Bindings.Bfd.Symbol.Flags $ fromIntegral val | off == (#offset struct bfd_symbol, section) = do val <- (#peek struct bfd_symbol, section) buf return $ Section val | otherwise = error $ "internal error: Bfd.Symbol.peekByteOffset " ++ show off pokeByteOff buf off val | off == (#offset struct bfd_symbol, name) = (#poke struct bfd_symbol, name) buf (unSymbol'Name val) | off == (#offset struct bfd_symbol, value) = (#poke struct bfd_symbol, value) buf (unSymbol'Value val) | off == (#offset struct bfd_symbol, section) = (#poke struct bfd_symbol, section) buf (unSymbol'Section val) | otherwise = error $ "internal error: Bfd.Symbol.pokeByteOff " ++ show off unSymbol'TheBfd :: Symbol' -> Ptr Bfd' unSymbol'TheBfd (Bindings.Bfd.Symbol.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" -- ----------------------------------------------------------------------------- -- | Returns the 'Vma' of the 'Section' that the symbol belongs to. getBase :: Symbol -> IO Vma getBase sym = do sect <- getSection sym getVma sect -- | Set the offset of the 'Symbol' within its 'Section'. setValue :: Symbol -> Vma -> IO () setValue sym vma = pokeByteOff sym (#offset struct bfd_symbol, value) (Value vma) -- | Returns the offset of the 'Symbol' within its 'Section'. getValue :: Symbol -> IO Vma getValue sym = do v <- peekByteOff sym (#offset struct bfd_symbol, value) return $ unSymbol'Value v -- | Returns the absolute 'Vma' of the 'Symbol' (that is, its 'getBase' + -- 'getValue'. getValue' :: Symbol -> IO Vma getValue' sym = do base <- getBase sym val <- getValue sym return $ base + val -- ----------------------------------------------------------------------------- -- | Returns the 'Bfd' that the 'Symbol' belongs to. -- -- /Note:/ If the returned 'Bfd' should not be passed to 'close' or -- 'closeAllDone' there will be memory leaks. getBfd :: Symbol -> IO Bfd getBfd sym = do bfd <- peekByteOff sym (#offset struct bfd_symbol, the_bfd) return $ Bfd.mk $ unSymbol'TheBfd bfd getFlags :: Symbol -> IO [SymbolFlags.Flags] getFlags sym = do flags <- peekByteOff sym (#offset struct bfd_symbol, flags) let flags' = filter f $ enumFrom Local where f e = unSymbol'Flags flags .&. (bit $ fromEnum e) /= 0 return flags' -- | If the 'Symbol' has the 'Synthetic' flag set then return 'Unknown', -- otherwise returns 'getFlavour' on the 'Symbol's 'Bfd'\'s 'Target'. getFlavour :: Symbol -> IO Flavour getFlavour sym = do flags <- getFlags sym case Synthetic `elem` flags of True -> return Unknown False -> do bfd <- getBfd sym targ <- getTarget bfd Target.getFlavour targ -- ----------------------------------------------------------------------------- -- | Sets the 'SymbolName' of the 'Symbol'. -- -- /Note:/ The memory allocated to the 'SymbolName' is never freed. setName :: Symbol -> SymbolName -> IO () setName sym name = do cs <- newCString name pokeByteOff sym (#offset struct bfd_symbol, name) $ Bindings.Bfd.Symbol.Name cs -- | Returns the 'SymbolName' of the 'Symbol'. getName :: Symbol -> IO SymbolName getName sym = do s' <- peekByteOff sym (#offset struct bfd_symbol, name) peekCString $ unSymbol'Name s' -- ----------------------------------------------------------------------------- -- | Sets the 'Symbol's 'Section'. setSection :: Symbol -> Section -> IO () setSection sym sect = pokeByteOff sym (#offset struct bfd_symbol, section) $ Section sect -- | Returns the 'Symbol's 'Section'. getSection :: Symbol -> IO Section getSection sym = do sect <- peekByteOff sym (#offset struct bfd_symbol, section) return $ unSymbol'Section sect -- | Returns the 'Symbol's output 'Section'. 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 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 f <- getPrintSymbol bfd fpWrite sym f _ <- c_fflush fpWrite (s,_) <- fdRead pipeRead 80 closeFd pipeRead closeFd pipeWrite return s