data-elf-0.2: src/Data/Elf.hs
{-# LANGUAGE UnicodeSyntax #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE DeriveDataTypeable #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE StandaloneDeriving #-}
{-# LANGUAGE RecordWildCards #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE TypeSynonymInstances #-}
{-# LANGUAGE TypeFamilies #-}
-- | This module provides ELF data structures and (de)serialization routines.
module Data.Elf
(
-- * File class
FileClass(..)
, invalidFileClass
, elf32FileClass
, elf64FileClass
, IsFileClass(..)
, Elf32(..)
, anElf32
, Elf64(..)
, anElf64
-- * File header
-- ** File type
, FileType(..)
, noneFileType
, relFileType
, execFileType
, dynFileType
, coreFileType
, loOsFileType
, hiOsFileType
, loProcFileType
, hiProcFileType
-- ** Machine code
, Machine(..)
, undefMachine
, i386Machine
, amd64Machine
-- ** Machine flags
, MachFlags(..)
-- ** ELF version
, Version(..)
, invalidVersion
, firstVersion
-- ** Data encoding
, DataEnc(..)
, invalidDataEnc
, lsbDataEnc
, msbDataEnc
-- ** Operating system ABI
, OsAbi(..)
, sysvOsAbi
, hpuxOsAbi
, netBsdOsAbi
, gnuOsAbi
, solarisOsAbi
, aixOsAbi
, irixOsAbi
, freeBsdOsAbi
, tru64OsAbi
, modestoOsAbi
, openBsdOsAbi
, openVmsOsAbi
, nskOsAbi
, arosOsAbi
, fenixOsAbi
, embedOsAbi
, AbiVer(..)
, undefAbiVer
-- ** Identification
, Ident(..)
, anIdent
-- ** File header
, FileHdr(..)
, FileHdr32
, aFileHdr32
, FileHdr64
, aFileHdr64
-- * Program header
-- ** Segment type
, SegType(..)
, unusedSegType
, loadSegType
, dynSegType
, interpSegType
, noteSegType
, shlibSegType
, phdrSegType
, loOsSegType
, hiOsSegType
, loProcSegType
, hiProcSegType
-- ** Segment flags
, SegFlags(..)
, execSegFlag
, writeSegFlag
, readSegFlag
, osSegFlags
, procSegFlags
-- ** Program header
, ProgHdr(..)
, ProgHdr32
, aProgHdr32
, ProgHdr64
, aProgHdr64
-- * Section header
-- ** String table index
, StrIx
-- ** Section header table index
, SecIx(..)
, undefSecIx
, lastSecIx
, loOsSecIx
, hiOsSecIx
, loProcSecIx
, hiProcSecIx
, absSecIx
, commonSecIx
, xIndexSecIx
-- ** Section type
, SecType(..)
, unusedSecType
, progBitsSecType
, symSecType
, strSecType
, relaSecType
, hashSecType
, dynSecType
, noteSecType
, noBitsSecType
, relSecType
, shlibSecType
, dynSymSecType
, loOsSecType
, hiOsSecType
, loProcSecType
, hiProcSecType
-- ** Section flags
, SecFlags(..)
, writeSecFlag
, allocSecFlag
, execSecFlag
, mergeSecFlag
, infoLinkSecFlag
, osSecFlags
, procSecFlags
-- ** Section header
, SecHdr(..)
, SecHdr32
, aSecHdr32
, SecHdr64
, aSecHdr64
, zeroSecHdr
-- * Symbol table
-- ** Symbol type
, SymType(..)
, undefSymType
, objSymType
, funSymType
, secSymType
, fileSymType
, commonSymType
, tlsSymType
, loOsSymType
, hiOsSymType
, loProcSymType
, hiProcSymType
-- ** Symbol binding
, SymBind(..)
, localSymBind
, globalSymBind
, weakSymBind
, loOsSymBind
, hiOsSymBind
, loProcSymBind
, hiProcSymBind
-- ** Symbol visibility
, SymVisi(..)
, defSymVisi
, intSymVisi
, hiddenSymVisi
, protSymVisi
, exportSymVisi
, singSymVisi
, elimSymVisi
-- ** Symbol table index
, SymIx(..)
, undefSymIx
-- ** Symbol table entry
, SymEnt(..)
, SymEnt32
, aSymEnt32
, SymEnt64
, aSymEnt64
, zeroSymEnt
-- * Relocation table
-- ** Relocation type
, RelType(..)
, RelType32
, RelType64
-- ** Relocation table entry
, RelEnt(..)
, RelEnt32
, aRelEnt32
, RelEnt64
, aRelEnt64
, RelaEnt(..)
, RelaEnt32
, aRelaEnt32
, RelaEnt64
, aRelaEnt64
) where
import Data.Typeable (Typeable)
import Data.Data (Data)
import Data.Proxy (Proxy(..))
import Data.Ix (Ix)
import Data.Bits (Bits, shiftL, shiftR, (.|.), FiniteBits)
import Data.Flags (Flags(noFlags), BoundedFlags)
import Data.Word (Word8, Word16, Word32, Word64)
import Data.ShortWord (Word4, Word24)
import Data.Monoid ((<>))
import Data.Serializer (Serializable, SizedSerializable)
import qualified Data.Serializer as S
import Data.Deserializer (Deserializable, (<?>))
import qualified Data.Deserializer as D
import Control.Applicative ((<$>))
import Control.Monad (void, unless)
-- | File class.
newtype FileClass = FileClass { unFileClass ∷ Word8 }
deriving (Typeable, Data, Show, Read,
Eq, Ord, Bounded, Enum, Ix)
-- | Invalid class (@ELFCLASSNONE@).
invalidFileClass ∷ FileClass
invalidFileClass = FileClass 0
-- | ELF32 class (@ELFCLASS32@).
elf32FileClass ∷ FileClass
elf32FileClass = FileClass 1
-- | ELF64 class (@ELFCLASS64@).
elf64FileClass ∷ FileClass
elf64FileClass = FileClass 2
-- | File class type-level index.
class (Typeable c,
Typeable (Addr c), Data (Addr c),
Typeable (Off c), Data (Off c),
Typeable (UnSymIx c), Data (UnSymIx c),
Typeable (UnRelType c), Data (UnRelType c),
Show (Addr c), Read (Addr c),
Show (Off c), Read (Off c),
Show (UnSymIx c), Read (UnSymIx c),
Show (UnRelType c), Read (UnRelType c),
Eq (Addr c), Ord (Addr c), Bounded (Addr c), Enum (Addr c),
Num (Addr c), Integral (Addr c), Real (Addr c),
Bits (Addr c), FiniteBits (Addr c),
Eq (Off c), Ord (Off c), Bounded (Off c), Enum (Off c),
Num (Off c), Integral (Off c), Real (Off c),
Bits (Off c), FiniteBits (Off c),
Eq (UnSymIx c), Ord (UnSymIx c), Bounded (UnSymIx c), Enum (UnSymIx c),
Ix (UnSymIx c), Num (UnSymIx c), Integral (UnSymIx c),
Real (UnSymIx c), Bits (UnSymIx c), FiniteBits (UnSymIx c),
Eq (UnRelType c), Ord (UnRelType c), Bounded (UnRelType c),
Enum (UnRelType c), Ix (UnRelType c))
⇒ IsFileClass c where
type Addr c
type Off c
type UnSymIx c
type UnRelType c
fileClass ∷ Proxy c → FileClass
-- | 32-bit ELF class type-level index.
data Elf32 = Elf32 deriving (Typeable, Data)
-- | 'Elf32' proxy value.
anElf32 ∷ Proxy Elf32
anElf32 = Proxy
instance IsFileClass Elf32 where
type Addr Elf32 = Word32
type Off Elf32 = Word32
type UnSymIx Elf32 = Word24
type UnRelType Elf32 = Word8
fileClass _ = elf32FileClass
-- | 64-bit ELF class type-level index.
data Elf64 = Elf64 deriving (Typeable, Data)
-- | 'Elf64' proxy value.
anElf64 ∷ Proxy Elf64
anElf64 = Proxy
instance IsFileClass Elf64 where
type Addr Elf64 = Word64
type Off Elf64 = Word64
type UnSymIx Elf64 = Word32
type UnRelType Elf64 = Word32
fileClass _ = elf64FileClass
-- | File type.
newtype FileType = FileType { unFileType ∷ Word16 }
deriving (Typeable, Data, Show, Read,
Eq, Ord, Bounded, Enum, Ix)
-- | No file type (@ET_NONE@).
noneFileType ∷ FileType
noneFileType = FileType 0
-- | Relocatable object file (@ET_REL@).
relFileType ∷ FileType
relFileType = FileType 1
-- | Executable file (@ET_EXEC@).
execFileType ∷ FileType
execFileType = FileType 2
-- | Shared object file (@ET_DYN@).
dynFileType ∷ FileType
dynFileType = FileType 3
-- | Core file (@ET_CORE@).
coreFileType ∷ FileType
coreFileType = FileType 4
-- | First environment-specific type (@ET_LOOS@).
loOsFileType ∷ FileType
loOsFileType = FileType 0xFE00
-- | Last environment-specific type (@ET_HIOS@).
hiOsFileType ∷ FileType
hiOsFileType = FileType 0xFEFF
-- | First processor-specific type (@ET_LOPROC@).
loProcFileType ∷ FileType
loProcFileType = FileType 0xFF00
-- | Last processor-specific type (@ET_HIPROC@).
hiProcFileType ∷ FileType
hiProcFileType = FileType 0xFFFF
-- | Machine architecture.
newtype Machine = Machine { unMachine ∷ Word16 }
deriving (Typeable, Data, Show, Read,
Eq, Ord, Bounded, Enum, Ix)
-- | No machine (@EM_NONE@).
undefMachine ∷ Machine
undefMachine = Machine 0
-- | Intel 80386 (@EM_386@).
i386Machine ∷ Machine
i386Machine = Machine 3
-- | AMD x86-64 (@EM_X86_64@).
amd64Machine ∷ Machine
amd64Machine = Machine 62
-- | Architecture-specific flags.
newtype MachFlags = MachFlags { unMachFlags ∷ Word32 }
deriving (Typeable, Data, Show, Read,
Eq, Flags, BoundedFlags)
-- | ELF version.
newtype Version = Version { unVersion ∷ Word8 }
deriving (Typeable, Data, Show, Read,
Eq, Ord, Bounded, Enum, Ix)
-- | Invalid version.
invalidVersion ∷ Version
invalidVersion = Version 0
-- | Version 1.
firstVersion ∷ Version
firstVersion = Version 1
-- | Data encoding.
newtype DataEnc = DataEnc { unDataEnc ∷ Word8 }
deriving (Typeable, Data, Show, Read,
Eq, Ord, Bounded, Enum, Ix)
-- | Invalid data encoding.
invalidDataEnc ∷ DataEnc
invalidDataEnc = DataEnc 0
-- | Little-endian data encoding (@ELFDATA2LSB@).
lsbDataEnc ∷ DataEnc
lsbDataEnc = DataEnc 1
-- | Big-endian data encoding (@ELFDATA2MSB@).
msbDataEnc ∷ DataEnc
msbDataEnc = DataEnc 2
-- | System ABI.
newtype OsAbi = OsAbi { unOsAbi ∷ Word8 }
deriving (Typeable, Data, Show, Read,
Eq, Ord, Bounded, Enum, Ix)
-- | System V (@ELFOSABI_NONE@).
sysvOsAbi ∷ OsAbi
sysvOsAbi = OsAbi 0
-- | HP-UX (@ELFOSABI_HPUX@).
hpuxOsAbi ∷ OsAbi
hpuxOsAbi = OsAbi 1
-- | NetBSD (@ELFOSABI_NETBSD@).
netBsdOsAbi ∷ OsAbi
netBsdOsAbi = OsAbi 2
-- | GNU (@ELFOSABI_GNU@, @ELFOSABI_LINUX@).
gnuOsAbi ∷ OsAbi
gnuOsAbi = OsAbi 3
-- | Solaris (@ELFOSABI_SOLARIS@).
solarisOsAbi ∷ OsAbi
solarisOsAbi = OsAbi 6
-- | AIX (@ELFOSABI_AIX@).
aixOsAbi ∷ OsAbi
aixOsAbi = OsAbi 7
-- | IRIX (@ELFOSABI_IRIX@).
irixOsAbi ∷ OsAbi
irixOsAbi = OsAbi 8
-- | FreeBSD (@ELFOSABI_FREEBSD@).
freeBsdOsAbi ∷ OsAbi
freeBsdOsAbi = OsAbi 9
-- | Tru64 UNIX (@ELFOSABI_TRU64@).
tru64OsAbi ∷ OsAbi
tru64OsAbi = OsAbi 10
-- | Novell Modesto (@ELFOSABI_MODESTO@).
modestoOsAbi ∷ OsAbi
modestoOsAbi = OsAbi 11
-- | OpenBSD (@ELFOSABI_OPENBSD@).
openBsdOsAbi ∷ OsAbi
openBsdOsAbi = OsAbi 12
-- | OpenVMS (@ELFOSABI_OPENVMS@).
openVmsOsAbi ∷ OsAbi
openVmsOsAbi = OsAbi 13
-- | Hewlett-Packard Non-Stop Kernel (@ELFOSABI_NSK@).
nskOsAbi ∷ OsAbi
nskOsAbi = OsAbi 14
-- | Amiga Research OS (@ELFOSABI_AROS@).
arosOsAbi ∷ OsAbi
arosOsAbi = OsAbi 15
-- | FenixOS (@ELFOSABI_FENIXOS@).
fenixOsAbi ∷ OsAbi
fenixOsAbi = OsAbi 16
-- | Standalone (embedded) application.
embedOsAbi ∷ OsAbi
embedOsAbi = OsAbi 255
-- | ABI version.
newtype AbiVer = AbiVer { unAbiVer ∷ Word8 }
deriving (Typeable, Data, Show, Read,
Eq, Ord, Bounded, Enum, Ix)
-- | Undefined ABI version.
undefAbiVer ∷ AbiVer
undefAbiVer = AbiVer 0
-- | Identification.
data Ident = Ident { idClass ∷ FileClass
, idVersion ∷ Version
, idDataEnc ∷ DataEnc
, idOsAbi ∷ OsAbi
, idAbiVer ∷ AbiVer }
deriving (Typeable, Data, Show, Read, Eq)
-- | 'Ident' proxy value.
anIdent ∷ Proxy Ident
anIdent = Proxy
instance Serializable Ident where
put (Ident {..})
= S.byteString "\127ELF"
<> S.word8 (unFileClass idClass)
<> S.word8 (unDataEnc idDataEnc)
<> S.word8 (unVersion idVersion)
<> S.word8 (unOsAbi idOsAbi)
<> S.word8 (unAbiVer idAbiVer)
<> S.byteString "\0\0\0\0\0\0\0"
instance SizedSerializable Ident where
size _ = 16
{-# INLINE size #-}
instance Deserializable Ident where
get = do
void $ D.bytes "\127ELF" <?> "ELF magic number"
fileCls ← FileClass <$> D.word8 <?> "file class"
dataEnc ← DataEnc <$> D.word8 <?> "data encoding"
version ← Version <$> D.word8 <?> "file version"
osAbi ← OsAbi <$> D.word8 <?> "OS ABI code"
abiVer ← AbiVer <$> D.word8 <?> "OS ABI version"
D.skip 7
return $ Ident { idClass = fileCls
, idDataEnc = dataEnc
, idVersion = version
, idOsAbi = osAbi
, idAbiVer = abiVer }
-- | File header.
data FileHdr c = FileHdr { fhType ∷ FileType
, fhMachine ∷ Machine
, fhEntry ∷ Addr c
, fhFlags ∷ MachFlags
, fhPhOff ∷ Off c
, fhPhNum ∷ Word16
, fhShOff ∷ Off c
, fhShNum ∷ Word16
, fhSnStIx ∷ SecIx }
deriving Typeable
deriving instance (Data c, IsFileClass c) ⇒ Data (FileHdr c)
deriving instance IsFileClass c ⇒ Show (FileHdr c)
deriving instance IsFileClass c ⇒ Read (FileHdr c)
deriving instance IsFileClass c ⇒ Eq (FileHdr c)
-- | ELF32 file header.
type FileHdr32 = FileHdr Elf32
-- | 'FileHdr32' proxy value.
aFileHdr32 ∷ Proxy FileHdr32
aFileHdr32 = Proxy
instance Serializable FileHdr32 where
put (FileHdr {..})
= S.word16 (unFileType fhType)
<> S.word16 (unMachine fhMachine)
<> S.word32 1
<> S.word32 fhEntry
<> S.word32 fhPhOff
<> S.word32 fhShOff
<> S.word32 (unMachFlags fhFlags)
<> S.word16 (fromIntegral $ S.size anIdent + S.size aFileHdr32)
<> S.word16 (fromIntegral $ S.size aProgHdr32)
<> S.word16 fhPhNum
<> S.word16 (fromIntegral $ S.size aSecHdr32)
<> S.word16 fhShNum
<> S.word16 (unSecIx fhSnStIx)
instance SizedSerializable FileHdr32 where
size _ = 36
{-# INLINE size #-}
instance Deserializable FileHdr32 where
get = do
fileType ← FileType <$> D.word16 <?> "file type"
machine ← Machine <$> D.word16 <?> "machine"
version ← D.word32 <?> "version"
unless (version == 1) $ D.unexpected "Unexpected ELF version"
entry ← D.word32 <?> "entry point address"
phOff ← D.word32 <?> "program header table offset"
shOff ← D.word32 <?> "section header table offset"
flags ← MachFlags <$> D.word32 <?> "machine flags"
fileHdrSize ← D.word16 <?> "file header size"
unless (fileHdrSize ==
fromIntegral (S.size anIdent + S.size aFileHdr32)) $
D.unexpected "Unexpected ELF file header size"
progHdrSize ← D.word16 <?> "program header size"
unless (progHdrSize == fromIntegral (S.size aProgHdr32)) $
D.unexpected "Unexpected ELF program header size"
phNum ← D.word16 <?> "program header table size"
secHdrSize ← D.word16 <?> "section header size"
unless (secHdrSize == fromIntegral (S.size aSecHdr32)) $
D.unexpected "Unexpected ELF section header size"
shNum ← D.word16 <?> "section header table size"
snStIx ← SecIx <$> D.word16 <?> "section name string table section index"
return $ FileHdr { fhType = fileType
, fhMachine = machine
, fhEntry = entry
, fhPhOff = phOff
, fhShOff = shOff
, fhFlags = flags
, fhPhNum = phNum
, fhShNum = shNum
, fhSnStIx = snStIx }
-- | ELF64 file header.
type FileHdr64 = FileHdr Elf64
-- | 'FileHdr64' proxy value.
aFileHdr64 ∷ Proxy FileHdr64
aFileHdr64 = Proxy
instance Serializable FileHdr64 where
put (FileHdr {..})
= S.word16 (unFileType fhType)
<> S.word16 (unMachine fhMachine)
<> S.word32 1
<> S.word64 fhEntry
<> S.word64 fhPhOff
<> S.word64 fhShOff
<> S.word32 (unMachFlags fhFlags)
<> S.word16 (fromIntegral $ S.size anIdent + S.size aFileHdr64)
<> S.word16 (fromIntegral $ S.size aProgHdr64)
<> S.word16 fhPhNum
<> S.word16 (fromIntegral $ S.size aSecHdr64)
<> S.word16 fhShNum
<> S.word16 (unSecIx fhSnStIx)
instance SizedSerializable FileHdr64 where
size _ = 56
{-# INLINE size #-}
instance Deserializable FileHdr64 where
get = do
fileType ← FileType <$> D.word16 <?> "file type"
machine ← Machine <$> D.word16 <?> "machine code"
version ← D.word32 <?> "version"
unless (version == 1) $ D.unexpected "Unexpected ELF version"
entry ← D.word64 <?> "entry point address"
phOff ← D.word64 <?> "program header table offset"
shOff ← D.word64 <?> "section header table offset"
flags ← MachFlags <$> D.word32 <?> "machine flags"
fileHdrSize ← D.word16 <?> "file header size"
unless (fileHdrSize ==
fromIntegral (S.size anIdent + S.size aFileHdr64)) $
D.unexpected "Unexpected ELF file header size"
progHdrSize ← D.word16 <?> "program header size"
unless (progHdrSize == fromIntegral (S.size aProgHdr64)) $
D.unexpected "Unexpected ELF program header size"
phNum ← D.word16 <?> "program header table size"
secHdrSize ← D.word16 <?> "section header size"
unless (secHdrSize == fromIntegral (S.size aSecHdr64)) $
D.unexpected "Unexpected ELF section header size"
shNum ← D.word16 <?> "section header table size"
snStIx ← SecIx <$> D.word16 <?> "section name string table section index"
return $ FileHdr { fhType = fileType
, fhMachine = machine
, fhEntry = entry
, fhPhOff = phOff
, fhShOff = shOff
, fhFlags = flags
, fhPhNum = phNum
, fhShNum = shNum
, fhSnStIx = snStIx }
-- | Segment type.
newtype SegType = SegType { unSegType ∷ Word32 }
deriving (Typeable, Data, Show, Read,
Eq, Ord, Bounded, Enum, Ix)
-- | Unused program header entry (@PT_NULL@).
unusedSegType ∷ SegType
unusedSegType = SegType 0
-- | Loadable segment (@PT_LOAD@).
loadSegType ∷ SegType
loadSegType = SegType 1
-- | Dynamic linking tables (@PT_DYNAMIC@).
dynSegType ∷ SegType
dynSegType = SegType 2
-- | Program interpreter path name (@PT_INTERP@).
interpSegType ∷ SegType
interpSegType = SegType 3
-- | Note sections (@PT_NOTE@).
noteSegType ∷ SegType
noteSegType = SegType 4
-- | A reserved segment type (@PT_SHLIB@).
shlibSegType ∷ SegType
shlibSegType = SegType 5
-- | Program header table (@PT_PHDR@).
phdrSegType ∷ SegType
phdrSegType = SegType 6
-- | First environment-specific segment type (@PT_LOOS@).
loOsSegType ∷ SegType
loOsSegType = SegType 0x60000000
-- | Last environment-specific segment type (@PT_HIOS@).
hiOsSegType ∷ SegType
hiOsSegType = SegType 0x6FFFFFFF
-- | First processor-specific segment type (@PT_LOPROC@).
loProcSegType ∷ SegType
loProcSegType = SegType 0x70000000
-- | Last processor-specific segment type (@PT_HIPROC@).
hiProcSegType ∷ SegType
hiProcSegType = SegType 0x7FFFFFFF
-- | Segment flags.
newtype SegFlags = SegFlags { unSegFlags ∷ Word32 }
deriving (Typeable, Data, Show, Read,
Eq, Flags, BoundedFlags)
-- | Execute permission (@PF_X@).
execSegFlag ∷ SegFlags
execSegFlag = SegFlags 1
-- | Write permission (@PF_W@).
writeSegFlag ∷ SegFlags
writeSegFlag = SegFlags 2
-- | Read permission (@PF_R@).
readSegFlag ∷ SegFlags
readSegFlag = SegFlags 4
-- | Environment-specific flags mask (@PF_MASKOS@).
osSegFlags ∷ SegFlags
osSegFlags = SegFlags 0x00FF0000
-- | Processor-specific flags mask (@PF_MASKPROC@).
procSegFlags ∷ SegFlags
procSegFlags = SegFlags 0xFF000000
-- | Program header table entry.
data ProgHdr c = ProgHdr { phType ∷ SegType
, phFlags ∷ SegFlags
, phOff ∷ Off c
, phVirtAddr ∷ Addr c
, phPhysAddr ∷ Addr c
, phFileSize ∷ Off c
, phMemSize ∷ Addr c
, phAlign ∷ Addr c }
deriving Typeable
deriving instance (Data c, IsFileClass c) ⇒ Data (ProgHdr c)
deriving instance IsFileClass c ⇒ Show (ProgHdr c)
deriving instance IsFileClass c ⇒ Read (ProgHdr c)
deriving instance IsFileClass c ⇒ Eq (ProgHdr c)
-- | ELF32 program header table entry.
type ProgHdr32 = ProgHdr Elf32
-- | 'ProgHdr32' proxy value.
aProgHdr32 ∷ Proxy ProgHdr32
aProgHdr32 = Proxy
instance Serializable ProgHdr32 where
put (ProgHdr {..})
= S.word32 (unSegType phType)
<> S.word32 phOff
<> S.word32 phVirtAddr
<> S.word32 phPhysAddr
<> S.word32 phFileSize
<> S.word32 phMemSize
<> S.word32 (unSegFlags phFlags)
<> S.word32 phAlign
instance SizedSerializable ProgHdr32 where
size _ = 32
{-# INLINE size #-}
instance Deserializable ProgHdr32 where
get = do
segType ← SegType <$> D.word32 <?> "type"
off ← D.word32 <?> "offset"
virtAddr ← D.word32 <?> "virtual address"
physAddr ← D.word32 <?> "physical address"
fileSize ← D.word32 <?> "in-file size"
memSize ← D.word32 <?> "in-memory size"
flags ← SegFlags <$> D.word32 <?> "flags"
align ← D.word32 <?> "alignment"
return $ ProgHdr { phType = segType
, phOff = off
, phVirtAddr = virtAddr
, phPhysAddr = physAddr
, phFileSize = fileSize
, phMemSize = memSize
, phFlags = flags
, phAlign = align }
-- | ELF64 program header table entry.
type ProgHdr64 = ProgHdr Elf64
-- | 'ProgHdr64' proxy value.
aProgHdr64 ∷ Proxy ProgHdr64
aProgHdr64 = Proxy
instance Serializable ProgHdr64 where
put (ProgHdr {..})
= S.word32 (unSegType phType)
<> S.word32 (unSegFlags phFlags)
<> S.word64 phOff
<> S.word64 phVirtAddr
<> S.word64 phPhysAddr
<> S.word64 phFileSize
<> S.word64 phMemSize
<> S.word64 phAlign
instance SizedSerializable ProgHdr64 where
size _ = 56
{-# INLINE size #-}
instance Deserializable ProgHdr64 where
get = do
segType ← SegType <$> D.word32 <?> "type"
flags ← SegFlags <$> D.word32 <?> "flags"
off ← D.word64 <?> "offset"
virtAddr ← D.word64 <?> "virtual address"
physAddr ← D.word64 <?> "physical address"
fileSize ← D.word64 <?> "in-file size"
memSize ← D.word64 <?> "in-memory size"
align ← D.word64 <?> "alignment"
return $ ProgHdr { phType = segType
, phOff = off
, phVirtAddr = virtAddr
, phPhysAddr = physAddr
, phFileSize = fileSize
, phMemSize = memSize
, phFlags = flags
, phAlign = align }
-- | String table index.
type StrIx = Word32
-- | Section header entry index.
newtype SecIx = SecIx { unSecIx ∷ Word16 }
deriving (Typeable, Data, Show, Read,
Eq, Ord, Bounded, Enum, Ix, Num, Bits, FiniteBits,
Integral, Real)
-- | Undefined section reference (@SHN_UNDEF@).
undefSecIx ∷ SecIx
undefSecIx = 0
-- | Last regular section index.
lastSecIx ∷ SecIx
lastSecIx = 0xFEFF
-- | First environment-specific section index (@SHN_LOOS@).
loOsSecIx ∷ SecIx
loOsSecIx = 0xFF20
-- | Last environment-specific section index (@SHN_HIOS@).
hiOsSecIx ∷ SecIx
hiOsSecIx = 0xFF3F
-- | First processor-specific section index (@SHN_LOPROC@).
loProcSecIx ∷ SecIx
loProcSecIx = 0xFF00
-- | Last processor-specific section index (@SHN_HIPROC@).
hiProcSecIx ∷ SecIx
hiProcSecIx = 0xFF1F
-- | Absolute value indicator (@SHN_ABS@).
absSecIx ∷ SecIx
absSecIx = 0xFFF1
-- | Common block indicator (@SHN_COMMON@).
commonSecIx ∷ SecIx
commonSecIx = 0xFFF2
-- | Escape value (@SHN_XINDEX@).
xIndexSecIx ∷ SecIx
xIndexSecIx = 0xFFFF
-- | Section type.
newtype SecType = SecType { unSecType ∷ Word32 }
deriving (Typeable, Data, Show, Read,
Eq, Ord, Bounded, Enum, Ix)
-- | Unused section (@SHT_NULL@).
unusedSecType ∷ SecType
unusedSecType = SecType 0
-- | Program information (@SHT_PROGBITS@).
progBitsSecType ∷ SecType
progBitsSecType = SecType 1
-- | Symbol table (@SHT_SYMTAB@).
symSecType ∷ SecType
symSecType = SecType 2
-- | String table (@SHT_STRTAB@).
strSecType ∷ SecType
strSecType = SecType 3
-- | Relocation entries (@SHT_RELA@).
relaSecType ∷ SecType
relaSecType = SecType 4
-- | Symbol hash table (@SHT_HASH@).
hashSecType ∷ SecType
hashSecType = SecType 5
-- | Dynamic linking table (@SHT_DYNAMIC@).
dynSecType ∷ SecType
dynSecType = SecType 6
-- | Note information (@SHT_NOTE@).
noteSecType ∷ SecType
noteSecType = SecType 7
-- | Uninitialized space (@SHT_NOBITS@).
noBitsSecType ∷ SecType
noBitsSecType = SecType 8
-- | Relocation entries (@SHT_REL@).
relSecType ∷ SecType
relSecType = SecType 9
-- | A reserved section type (@SHT_SHLIB@).
shlibSecType ∷ SecType
shlibSecType = SecType 10
-- | Dynamic loader symbol table (@SHT_DYNSYM@).
dynSymSecType ∷ SecType
dynSymSecType = SecType 11
-- | First environment-specific section type (@SHT_LOOS@).
loOsSecType ∷ SecType
loOsSecType = SecType 0x60000000
-- | Last environment-specific section type (@SHT_HIOS@).
hiOsSecType ∷ SecType
hiOsSecType = SecType 0x6FFFFFFF
-- | First processor-specific section type (@SHT_LOPROC@).
loProcSecType ∷ SecType
loProcSecType = SecType 0x70000000
-- | Last processor-specific section type (@SHT_HIPROC@).
hiProcSecType ∷ SecType
hiProcSecType = SecType 0x7FFFFFFF
-- | Section flags.
newtype SecFlags = SecFlags { unSecFlags ∷ Word32 }
deriving (Typeable, Data, Show, Read,
Eq, Flags, BoundedFlags)
-- | Writable data (@SHF_WRITE@).
writeSecFlag ∷ SecFlags
writeSecFlag = SecFlags 1
-- | Allocated data (@SHF_ALLOC@).
allocSecFlag ∷ SecFlags
allocSecFlag = SecFlags 2
-- | Executable instructions (@SHF_EXECINSTR@).
execSecFlag ∷ SecFlags
execSecFlag = SecFlags 4
-- | Mergeable data (@SHF_MERGE@).
mergeSecFlag ∷ SecFlags
mergeSecFlag = SecFlags 0x10
-- | Flag that indicates that 'shInfo' is a section header table index.
-- (@SHF_INFO_LINK@)
infoLinkSecFlag ∷ SecFlags
infoLinkSecFlag = SecFlags 0x40
-- | Environment-specific flags mask (@SHF_MASKOS@).
osSecFlags ∷ SecFlags
osSecFlags = SecFlags 0x0F000000
-- | Processor-specific flags mask (@SHF_MASKOS@).
procSecFlags ∷ SecFlags
procSecFlags = SecFlags 0xF0000000
-- | Section header table entry.
data SecHdr c = SecHdr { shName ∷ StrIx
, shType ∷ SecType
, shFlags ∷ SecFlags
, shAddr ∷ Addr c
, shOff ∷ Off c
, shSize ∷ Addr c
, shLink ∷ Word32
, shInfo ∷ Word32
, shAlign ∷ Addr c
, shEntSize ∷ Addr c }
deriving Typeable
deriving instance (Data c, IsFileClass c) ⇒ Data (SecHdr c)
deriving instance IsFileClass c ⇒ Show (SecHdr c)
deriving instance IsFileClass c ⇒ Read (SecHdr c)
deriving instance IsFileClass c ⇒ Eq (SecHdr c)
-- | ELF32 section header table entry.
type SecHdr32 = SecHdr Elf32
-- | 'SecHdr32' proxy value.
aSecHdr32 ∷ Proxy SecHdr32
aSecHdr32 = Proxy
instance Serializable SecHdr32 where
put (SecHdr {..})
= S.word32 shName
<> S.word32 (unSecType shType)
<> S.word32 (unSecFlags shFlags)
<> S.word32 shAddr
<> S.word32 shOff
<> S.word32 shSize
<> S.word32 shLink
<> S.word32 shInfo
<> S.word32 shAlign
<> S.word32 shEntSize
instance SizedSerializable SecHdr32 where
size _ = 40
{-# INLINE size #-}
instance Deserializable SecHdr32 where
get = do
name ← D.word32 <?> "name"
tp ← SecType <$> D.word32 <?> "type"
flags ← SecFlags <$> D.word32 <?> "flags"
addr ← D.word32 <?> "address"
off ← D.word32 <?> "offset"
size ← D.word32 <?> "size"
link ← D.word32 <?> "link"
info ← D.word32 <?> "extra information"
align ← D.word32 <?> "alignment"
entSize ← D.word32 <?> "entry size"
return $ SecHdr { shName = name
, shType = tp
, shFlags = flags
, shAddr = addr
, shOff = off
, shSize = size
, shLink = link
, shInfo = info
, shAlign = align
, shEntSize = entSize }
-- | ELF64 section header table entry.
type SecHdr64 = SecHdr Elf64
-- | 'SecHdr64' proxy value.
aSecHdr64 ∷ Proxy SecHdr64
aSecHdr64 = Proxy
instance Serializable SecHdr64 where
put (SecHdr {..})
= S.word32 shName
<> S.word32 (unSecType shType)
<> S.word64 (fromIntegral (unSecFlags shFlags))
<> S.word64 shAddr
<> S.word64 shOff
<> S.word64 shSize
<> S.word32 shLink
<> S.word32 shInfo
<> S.word64 shAlign
<> S.word64 shEntSize
instance SizedSerializable SecHdr64 where
size _ = 64
{-# INLINE size #-}
instance Deserializable SecHdr64 where
get = do
name ← D.word32 <?> "name"
tp ← SecType <$> D.word32 <?> "type"
flags ← SecFlags . fromIntegral <$> D.word64 <?> "flags"
addr ← D.word64 <?> "address"
off ← D.word64 <?> "offset"
size ← D.word64 <?> "size"
link ← D.word32 <?> "link"
info ← D.word32 <?> "extra information"
align ← D.word64 <?> "alignment"
entSize ← D.word64 <?> "entry size"
return $ SecHdr { shName = name
, shType = tp
, shFlags = flags
, shAddr = addr
, shOff = off
, shSize = size
, shLink = link
, shInfo = info
, shAlign = align
, shEntSize = entSize }
-- | Section header filled with zeros.
zeroSecHdr ∷ IsFileClass c ⇒ SecHdr c
zeroSecHdr = SecHdr { shName = 0
, shType = unusedSecType
, shFlags = noFlags
, shAddr = 0
, shOff = 0
, shSize = 0
, shLink = 0
, shInfo = 0
, shAlign = 0
, shEntSize = 0 }
-- | Symbol type.
newtype SymType = SymType { unSymType ∷ Word4 }
deriving (Typeable, Data, Show, Read,
Eq, Ord, Bounded, Enum, Ix)
-- | Undefined symbol type (@STT_NOTYPE@).
undefSymType ∷ SymType
undefSymType = SymType 0
-- | Object (@STT_OBJECT@).
objSymType ∷ SymType
objSymType = SymType 1
-- | Function (@STT_FUNC@).
funSymType ∷ SymType
funSymType = SymType 2
-- | Section (@STT_SECTION@).
secSymType ∷ SymType
secSymType = SymType 3
-- | Source file name (@STT_FILE@).
fileSymType ∷ SymType
fileSymType = SymType 4
-- | Common block label (@STT_COMMON@).
commonSymType ∷ SymType
commonSymType = SymType 5
-- | Thread-local storage (@STT_TLS@).
tlsSymType ∷ SymType
tlsSymType = SymType 6
-- | First environment-specific symbol type (@STT_LOOS@).
loOsSymType ∷ SymType
loOsSymType = SymType 10
-- | Last environment-specific symbol type (@STT_HIOS@).
hiOsSymType ∷ SymType
hiOsSymType = SymType 12
-- | First processor-specific symbol type (@STT_LOPROC@).
loProcSymType ∷ SymType
loProcSymType = SymType 13
-- | Last processor-specific symbol type (@STT_HIPROC@).
hiProcSymType ∷ SymType
hiProcSymType = SymType 15
-- | Symbol binding type.
newtype SymBind = SymBind { unSymBind ∷ Word4 }
deriving (Typeable, Data, Show, Read,
Eq, Ord, Bounded, Enum, Ix)
-- | Local symbol (@STB_LOCAL@).
localSymBind ∷ SymBind
localSymBind = SymBind 0
-- | Global symbol (@STB_GLOBAL@).
globalSymBind ∷ SymBind
globalSymBind = SymBind 1
-- | Lower precedence global symbol (@STB_WEAK@).
weakSymBind ∷ SymBind
weakSymBind = SymBind 2
-- | First environment-specific symbol binding type (@STB_LOOS@).
loOsSymBind ∷ SymBind
loOsSymBind = SymBind 10
-- | Last environment-specific symbol binding type (@STB_HIOS@).
hiOsSymBind ∷ SymBind
hiOsSymBind = SymBind 12
-- | First processor-specific symbol binding type (@STB_LOPROC@).
loProcSymBind ∷ SymBind
loProcSymBind = SymBind 13
-- | Last processor-specific symbol binding type (@STB_HIPROC@).
hiProcSymBind ∷ SymBind
hiProcSymBind = SymBind 15
-- | Symbol visibility.
newtype SymVisi = SymVisi { unSymVisi ∷ Word4 }
deriving (Typeable, Data, Show, Read,
Eq, Ord, Bounded, Enum, Ix)
-- | Default symbol visibility (specified by the binding type;
-- @STV_DEFAULT@).
defSymVisi ∷ SymVisi
defSymVisi = SymVisi 0
-- | Internal symbol visibility (processor-specific hidden type;
-- @STV_INTERNAL@).
intSymVisi ∷ SymVisi
intSymVisi = SymVisi 1
-- | Hidden symbol (@STV_HIDDEN@).
hiddenSymVisi ∷ SymVisi
hiddenSymVisi = SymVisi 2
-- | Protected symbol (@STV_PROTECTED@).
protSymVisi ∷ SymVisi
protSymVisi = SymVisi 3
-- | Global symbol (@STV_EXPORTED@).
exportSymVisi ∷ SymVisi
exportSymVisi = SymVisi 4
-- | Global singleton symbol (@STV_SINGLETON@).
singSymVisi ∷ SymVisi
singSymVisi = SymVisi 5
-- | Extra hidden symbol (@STV_ELIMINATE@).
elimSymVisi ∷ SymVisi
elimSymVisi = SymVisi 6
-- | Symbol table index.
newtype SymIx c = SymIx { unSymIx ∷ UnSymIx c }
deriving Typeable
deriving instance (Data c, IsFileClass c) ⇒ Data (SymIx c)
deriving instance IsFileClass c ⇒ Show (SymIx c)
deriving instance IsFileClass c ⇒ Read (SymIx c)
deriving instance IsFileClass c ⇒ Eq (SymIx c)
deriving instance IsFileClass c ⇒ Ord (SymIx c)
deriving instance IsFileClass c ⇒ Bounded (SymIx c)
deriving instance IsFileClass c ⇒ Enum (SymIx c)
deriving instance IsFileClass c ⇒ Ix (SymIx c)
deriving instance IsFileClass c ⇒ Num (SymIx c)
deriving instance IsFileClass c ⇒ Bits (SymIx c)
deriving instance IsFileClass c ⇒ FiniteBits (SymIx c)
deriving instance IsFileClass c ⇒ Integral (SymIx c)
deriving instance IsFileClass c ⇒ Real (SymIx c)
-- | Undefined symbol table index.
undefSymIx ∷ IsFileClass c ⇒ SymIx c
undefSymIx = SymIx 0
-- | Symbol table entry.
data SymEnt c = SymEnt { symName ∷ StrIx
, symBind ∷ SymBind
, symType ∷ SymType
, symVisi ∷ SymVisi
, symSecIx ∷ SecIx
, symAddr ∷ Addr c
, symSize ∷ Addr c }
deriving Typeable
deriving instance (Data c, IsFileClass c) ⇒ Data (SymEnt c)
deriving instance IsFileClass c ⇒ Show (SymEnt c)
deriving instance IsFileClass c ⇒ Read (SymEnt c)
deriving instance IsFileClass c ⇒ Eq (SymEnt c)
-- | ELF32 symbol table entry.
type SymEnt32 = SymEnt Elf32
-- | 'SymEnt32' proxy value.
aSymEnt32 ∷ Proxy SymEnt32
aSymEnt32 = Proxy
instance Serializable SymEnt32 where
put (SymEnt {..})
= S.word32 symName
<> S.word32 symAddr
<> S.word32 symSize
<> S.word8 (shiftL (fromIntegral $ unSymBind symBind) 4 .|.
fromIntegral (unSymType symType))
<> S.word8 (fromIntegral (unSymVisi symVisi))
<> S.word16 (unSecIx symSecIx)
instance SizedSerializable SymEnt32 where
size _ = 16
{-# INLINE size #-}
instance Deserializable SymEnt32 where
get = do
name ← D.word32 <?> "name"
addr ← D.word32 <?> "address"
size ← D.word32 <?> "size"
info ← D.word8 <?> "info"
let bind = SymBind (fromIntegral $ shiftR info 4)
tp = SymType (fromIntegral info)
visi ← SymVisi . fromIntegral <$> D.word8 <?> "visibility"
secIx ← SecIx <$> D.word16 <?> "section index"
return $ SymEnt { symName = name
, symAddr = addr
, symSize = size
, symBind = bind
, symType = tp
, symVisi = visi
, symSecIx = secIx }
-- | ELF64 symbol table entry.
type SymEnt64 = SymEnt Elf64
-- | 'SymEnt64' proxy value.
aSymEnt64 ∷ Proxy SymEnt64
aSymEnt64 = Proxy
instance Serializable SymEnt64 where
put (SymEnt {..})
= S.word32 symName
<> S.word8 (shiftL (fromIntegral $ unSymBind symBind) 4 .|.
fromIntegral (unSymType symType))
<> S.word8 (fromIntegral (unSymVisi symVisi))
<> S.word16 (unSecIx symSecIx)
<> S.word64 symAddr
<> S.word64 symSize
instance SizedSerializable SymEnt64 where
size _ = 24
{-# INLINE size #-}
instance Deserializable SymEnt64 where
get = do
name ← D.word32 <?> "name"
info ← D.word8 <?> "info"
let bind = SymBind (fromIntegral $ shiftR info 4)
tp = SymType (fromIntegral info)
visi ← SymVisi . fromIntegral <$> D.word8 <?> "visibility"
secIx ← SecIx <$> D.word16 <?> "section index"
addr ← D.word64 <?> "address"
size ← D.word64 <?> "size"
return $ SymEnt { symName = name
, symAddr = addr
, symSize = size
, symBind = bind
, symType = tp
, symVisi = visi
, symSecIx = secIx }
-- | Symbol table entry filled with zeros.
zeroSymEnt ∷ IsFileClass c ⇒ SymEnt c
zeroSymEnt = SymEnt { symName = 0
, symBind = localSymBind
, symType = undefSymType
, symVisi = defSymVisi
, symSecIx = undefSecIx
, symAddr = 0
, symSize = 0 }
-- | Relocation type.
newtype RelType c = RelType { unRelType ∷ UnRelType c }
deriving Typeable
deriving instance (Data c, IsFileClass c) ⇒ Data (RelType c)
deriving instance IsFileClass c ⇒ Show (RelType c)
deriving instance IsFileClass c ⇒ Read (RelType c)
deriving instance IsFileClass c ⇒ Eq (RelType c)
deriving instance IsFileClass c ⇒ Ord (RelType c)
deriving instance IsFileClass c ⇒ Bounded (RelType c)
deriving instance IsFileClass c ⇒ Enum (RelType c)
deriving instance IsFileClass c ⇒ Ix (RelType c)
-- | ELF32 relocation type.
type RelType32 = RelType Elf32
-- | ELF64 relocation type.
type RelType64 = RelType Elf64
-- | Relocation table entry (REL).
data RelEnt c = RelEnt { relOff ∷ Addr c
, relSymIx ∷ SymIx c
, relType ∷ RelType c }
deriving Typeable
deriving instance (Data c, IsFileClass c) ⇒ Data (RelEnt c)
deriving instance IsFileClass c ⇒ Show (RelEnt c)
deriving instance IsFileClass c ⇒ Read (RelEnt c)
deriving instance IsFileClass c ⇒ Eq (RelEnt c)
-- | ELF32 relocation table entry (REL).
type RelEnt32 = RelEnt Elf32
-- | 'RelEnt32' proxy value.
aRelEnt32 ∷ Proxy RelEnt32
aRelEnt32 = Proxy
instance Serializable RelEnt32 where
put (RelEnt {..})
= S.word32 relOff
<> S.word32 (shiftL (fromIntegral relSymIx) 8 .|.
fromIntegral (unRelType relType))
instance SizedSerializable RelEnt32 where
size _ = 8
{-# INLINE size #-}
instance Deserializable RelEnt32 where
get = do
off ← D.word32 <?> "offset"
info ← D.word32 <?> "info"
let symIx = SymIx $ fromIntegral $ shiftR info 8
tp = RelType $ fromIntegral info
return $ RelEnt { relOff = off
, relSymIx = symIx
, relType = tp }
-- | ELF64 relocation table entry (REL).
type RelEnt64 = RelEnt Elf64
-- | 'RelEnt64' proxy value.
aRelEnt64 ∷ Proxy RelEnt64
aRelEnt64 = Proxy
instance Serializable RelEnt64 where
put (RelEnt {..})
= S.word64 relOff
<> S.word64 (shiftL (fromIntegral relSymIx) 32 .|.
fromIntegral (unRelType relType))
instance SizedSerializable RelEnt64 where
size _ = 16
{-# INLINE size #-}
instance Deserializable RelEnt64 where
get = do
off ← D.word64 <?> "offset"
info ← D.word64 <?> "info"
let symIx = SymIx $ fromIntegral $ shiftR info 32
tp = RelType $ fromIntegral info
return $ RelEnt { relOff = off
, relSymIx = symIx
, relType = tp }
-- | Relocation table entry (RELA).
data RelaEnt c = RelaEnt { relaOff ∷ Addr c
, relaSymIx ∷ SymIx c
, relaType ∷ RelType c
, relaAddend ∷ Addr c }
deriving Typeable
deriving instance (Data c, IsFileClass c) ⇒ Data (RelaEnt c)
deriving instance IsFileClass c ⇒ Show (RelaEnt c)
deriving instance IsFileClass c ⇒ Read (RelaEnt c)
deriving instance IsFileClass c ⇒ Eq (RelaEnt c)
-- | ELF32 relocation table entry (RELA).
type RelaEnt32 = RelaEnt Elf32
-- | 'RelaEnt32' proxy value.
aRelaEnt32 ∷ Proxy RelaEnt32
aRelaEnt32 = Proxy
instance Serializable RelaEnt32 where
put (RelaEnt {..})
= S.word32 relaOff
<> S.word32 (shiftL (fromIntegral relaSymIx) 8 .|.
fromIntegral (unRelType relaType))
<> S.word32 relaAddend
instance SizedSerializable RelaEnt32 where
size _ = 12
{-# INLINE size #-}
instance Deserializable RelaEnt32 where
get = do
off ← D.word32 <?> "offset"
info ← D.word32 <?> "info"
let symIx = SymIx $ fromIntegral $ shiftR info 8
tp = RelType $ fromIntegral info
addend ← D.word32 <?> "addend"
return $ RelaEnt { relaOff = off
, relaSymIx = symIx
, relaType = tp
, relaAddend = addend }
-- | ELF64 relocation table entry (RELA).
type RelaEnt64 = RelaEnt Elf64
-- | 'RelaEnt64' proxy value.
aRelaEnt64 ∷ Proxy RelaEnt64
aRelaEnt64 = Proxy
instance Serializable RelaEnt64 where
put (RelaEnt {..})
= S.word64 relaOff
<> S.word64 (shiftL (fromIntegral relaSymIx) 32 .|.
fromIntegral (unRelType relaType))
<> S.word64 relaAddend
instance SizedSerializable RelaEnt64 where
size _ = 24
{-# INLINE size #-}
instance Deserializable RelaEnt64 where
get = do
off ← D.word64 <?> "offset"
info ← D.word64 <?> "info"
let symIx = SymIx $ fromIntegral $ shiftR info 32
tp = RelType $ fromIntegral info
addend ← D.word64 <?> "addend"
return $ RelaEnt { relaOff = off
, relaSymIx = symIx
, relaType = tp
, relaAddend = addend }