{-|
Copyright   : (c) Galois Inc, 2015-2018
Maintainer  : jhendrix@galois.com

Defines constructors for precisely capturing symbol table information.
-}
module Data.Macaw.Memory.Symbols
  ( -- * Symbols
    SymbolInfo(..)
  , SymbolBinding(..)
  , Data.BinarySymbols.SymbolVersion(..)
    -- ** Defined symbol information
  , SymbolPrecedence(..)
  , SymbolDefType(..)
    -- ** Undefined symbol infomration
  , SymbolRequirement(..)
  , SymbolUndefType(..)
  ) where

import           Data.BinarySymbols
import qualified Data.ByteString as BS

-- | Describes symbol precedence
data SymbolPrecedence
   = SymbolStrong
     -- ^ Symbol has high precedence
   | SymbolLocal
     -- ^ The symbol has high precedence, but only visible within the
     -- object file that created it.
   | SymbolWeak
     -- ^ Symbol has low precedence

-- | This denotes type information associated with a defined
data SymbolDefType
   = SymbolDefUnknown
     -- ^ We do not know what type of object this refers to.
   | SymbolDefFunc
     -- ^ This symbol denotes a defined function.
   | SymbolDefObject
     -- ^ This symbol denotes a object.
   | SymbolDefThreadLocal
     -- ^ This symbol denotes a thread local identifier
   | SymbolDefIFunc
     -- ^ This symbol is a "IFUNC" (e.g., it calls a function to resolve the symbol)
   | SymbolDefNoType
     -- ^ This symbol does not have a specified type.


-- | Describes whether an undefined symbol is required during linking.
data SymbolRequirement
   = SymbolRequired
     -- ^ Undefined symbol must be found during linking
   | SymbolOptional
     -- ^ Undefined symbol treated as zero if not found during linking.

-- | Flags information about an undefined symbol.
data SymbolUndefType
   = SymbolUndefThreadLocal
     -- ^ This symbol denotes data stored in a thread.
   | SymbolUndefNoType
     -- ^ This is stored globally for application, but otherwise has
     -- no type information.
     --
     -- Concretely we have seen this symbol type generated by gcc for
     -- external functions and data and _GLOBAL_OFFSET_TABLE_
   | SymbolUndefFunc
     -- ^ This symbol is intended to denote a function.
   | SymbolUndefObject
     -- ^ This symbol is intended to denote some data.

-- | This defines information about the symbol related to whether
-- it is defined (and if so how it binds) or undefined (and if so what
-- requiremens there are for a match).
data SymbolBinding
   = DefinedSymbol !SymbolPrecedence !SymbolDefType
     -- ^ The symbol is defined and globally visible.
     --
     -- The strong symbol flag controls the precedence.  If true, then
     -- this definition must be used for the symbol with that name,
     -- and the linker is not allowed to replace the symbol.  Is
     -- false, then the linker will use a strong symbol if it exists,
     -- and one of the weak symbols if it does not.
     --
     -- The address is the address the symbol was loaded at.  It may
     -- not be a valid segment offset if the original binary used
     -- symbols at unexpected addresses.
   | SymbolSection !SectionIndex
     -- ^ The symbol denotes a section in an object file with the
     -- given index.  These are primarily intended for relocations.
     --
     -- The symbol version should be @UnversionedSymbol@ with this.
   | SymbolFile !BS.ByteString
     -- ^ This symbol denotes a file name with the given string
     --
     -- The symbol version should be @UnversionedSymbol@ with this.
   | UndefinedSymbol !SymbolRequirement !SymbolUndefType
     -- ^ An undefined symbol
     --
     -- The Boolean flag controls whether the symbol must be defined.
     -- If it is @False@ and the linker cannot find a definition, then
     -- it just treats the symbol address as @0@.  If it is @True@ and
     -- the linker cannot find a definition, then it must throw an
     -- error.

-- | This provides information about a symbol in the file.
data SymbolInfo =
  SymbolInfo { SymbolInfo -> SymbolName
symbolName :: !SymbolName
               -- ^ The name of the symbol
               --
               -- Symbols are used for many purposes in a file.
               -- Symbol names may not be unique, and may even be
               -- empty.  For example, Elf files uses the empty name
               -- for section symbols.  On ARM, "$a", "$d" and "$t"
               -- are used to indicate regions of ARM code, data, thumb.
             , SymbolInfo -> SymbolVersion
symbolVersion :: !SymbolVersion
               -- ^ Version information used to constrain when one
               -- symbol matches another.
             , SymbolInfo -> SymbolBinding
symbolDef :: !SymbolBinding
             }