elf-0.1: src/Data/Elf.hs
-- | Data.Elf is a module for parsing a ByteString of an ELF file into an Elf record.
module Data.Elf (getElf, Elf(..), ElfSection(..), ElfClass(..), ElfData(..), ElfOSABI(..), ElfType(..), ElfMachine(..)) where
import Data.Binary
import Data.Binary.Get
import Data.Bits
import Data.Word
import Numeric
import Control.Monad
import qualified Data.ByteString as B
import qualified Data.ByteString.Internal as B
import qualified Data.ByteString.Lazy as L
import System.IO.Unsafe
data Elf = Elf
{ elfClass :: ElfClass -- ^ Identifies the class of the object file.
, elfData :: ElfData -- ^ Identifies the data encoding of the object file.
, elfVersion :: Int -- ^ Identifies the version of the object file format.
, elfOSABI :: ElfOSABI -- ^ Identifies the operating system and ABI for which the object is prepared.
, elfABIVersion :: Int -- ^ Identifies the ABI version for which the object is prepared.
, elfType :: ElfType -- ^ Identifies the object file type.
, elfMachine :: ElfMachine -- ^ Identifies the target architecture.
, elfEntry :: Word64 -- ^ Virtual address of the program entry point. 0 for non-executable Elfs.
, elfSections :: [ElfSection] -- ^ Map from section name to section data.
} deriving (Eq, Show)
data ElfSection = ElfSection
{ elfSectionName :: String -- ^ Identifies the name of the section.
, elfSectionType :: ElfSectionType -- ^ Identifies the type of the section.
, elfSectionFlags :: [ElfSectionFlags] -- ^ Identifies the attributes of the section.
, elfSectionAddr :: Word64 -- ^ The virtual address of the beginning of the section in memory. 0 for sections that are not loaded into target memory.
, elfSectionSize :: Word64 -- ^ The size of the section. Except for SHT_NOBITS sections, this is the size of elfSectionData.
, elfSectionLink :: Word32 -- ^ Contains a section index of an associated section, depending on section type.
, elfSectionInfo :: Word32 -- ^ Contains extra information for the index, depending on type.
, elfSectionAddrAlign :: Word64 -- ^ Contains the required alignment of the section. Must be a power of two.
, elfSectionEntSize :: Word64 -- ^ Size of entries if section has a table.
, elfSectionData :: B.ByteString -- ^ The raw data for the section.
} deriving (Eq, Show)
getElfMagic = do
ei_magic <- liftM (map B.w2c) $ sequence [getWord8, getWord8, getWord8, getWord8]
if ei_magic /= "\DELELF" then
fail "Invalid magic number for ELF"
else
return ei_magic
getElfVersion = do
ei_version <- getWord8
if ei_version /= 1 then
fail "Invalid version number for ELF"
else
return ei_version
data ElfSectionType
= SHT_NULL -- ^ Identifies an empty section header.
| SHT_PROGBITS -- ^ Contains information defined by the program
| SHT_SYMTAB -- ^ Contains a linker symbol table
| SHT_STRTAB -- ^ Contains a string table
| SHT_RELA -- ^ Contains "Rela" type relocation entries
| SHT_HASH -- ^ Contains a symbol hash table
| SHT_DYNAMIC -- ^ Contains dynamic linking tables
| SHT_NOTE -- ^ Contains note information
| SHT_NOBITS -- ^ Contains uninitialized space; does not occupy any space in the file
| SHT_REL -- ^ Contains "Rel" type relocation entries
| SHT_SHLIB -- ^ Reserved
| SHT_DYNSYM -- ^ Contains a dynamic loader symbol table
| SHT_EXT Word32 -- ^ Processor- or environment-specific type
deriving (Eq, Show)
getElfSectionType er = getWord32 er >>= return . getElfSectionType_
where getElfSectionType_ 0 = SHT_NULL
getElfSectionType_ 1 = SHT_PROGBITS
getElfSectionType_ 2 = SHT_SYMTAB
getElfSectionType_ 3 = SHT_STRTAB
getElfSectionType_ 4 = SHT_RELA
getElfSectionType_ 5 = SHT_HASH
getElfSectionType_ 6 = SHT_DYNAMIC
getElfSectionType_ 7 = SHT_NOTE
getElfSectionType_ 8 = SHT_NOBITS
getElfSectionType_ 9 = SHT_REL
getElfSectionType_ 10 = SHT_SHLIB
getElfSectionType_ 11 = SHT_DYNSYM
getElfSectionType_ n = SHT_EXT n
data ElfSectionFlags
= SHF_WRITE -- ^ Section contains writable data
| SHF_ALLOC -- ^ Section is allocated in memory image of program
| SHF_EXECINSTR -- ^ Section contains executable instructions
| SHF_EXT Int -- ^ Processor- or environment-specific flag
deriving (Eq, Show)
getElfSectionFlags32 er = getWord32 er >>= return . getElfSectionFlags_ 31
where getElfSectionFlags_ 0 word = []
getElfSectionFlags_ 1 word | testBit word 1 = SHF_WRITE : getElfSectionFlags_ 0 word
getElfSectionFlags_ 2 word | testBit word 2 = SHF_ALLOC : getElfSectionFlags_ 1 word
getElfSectionFlags_ 3 word | testBit word 4 = SHF_EXECINSTR : getElfSectionFlags_ 2 word
getElfSectionFlags_ n word | testBit word n = SHF_EXT n : getElfSectionFlags_ (n-1) word
getElfSectionFlags_ n word = getElfSectionFlags_ (n-1) word
getElfSectionFlags64 er = getWord64 er >>= return . getElfSectionFlags_ 63
where getElfSectionFlags_ 0 word = []
getElfSectionFlags_ 1 word | testBit word 1 = SHF_WRITE : getElfSectionFlags_ 0 word
getElfSectionFlags_ 2 word | testBit word 2 = SHF_ALLOC : getElfSectionFlags_ 1 word
getElfSectionFlags_ 3 word | testBit word 4 = SHF_EXECINSTR : getElfSectionFlags_ 2 word
getElfSectionFlags_ n word | testBit word n = SHF_EXT n : getElfSectionFlags_ (n-1) word
getElfSectionFlags_ n word = getElfSectionFlags_ (n-1) word
data ElfClass
= ELFCLASS32 -- ^ 32-bit ELF format
| ELFCLASS64 -- ^ 64-bit ELF format
deriving (Eq, Show)
getElfClass = getWord8 >>= getElfClass_
where getElfClass_ 1 = return ELFCLASS32
getElfClass_ 2 = return ELFCLASS64
getElfClass_ _ = fail "Invalid ELF class"
data ElfData
= ELFDATA2LSB -- ^ Little-endian ELF format
| ELFDATA2MSB -- ^ Big-endian ELF format
deriving (Eq, Show)
getElfData = getWord8 >>= getElfData_
where getElfData_ 1 = return ELFDATA2LSB
getElfData_ 2 = return ELFDATA2MSB
getElfData_ _ = fail "Invalid ELF data"
data ElfOSABI
= ELFOSABI_SYSV -- ^ No extensions or unspecified
| ELFOSABI_HPUX -- ^ Hewlett-Packard HP-UX
| ELFOSABI_NETBSD -- ^ NetBSD
| ELFOSABI_LINUX -- ^ Linux
| ELFOSABI_SOLARIS -- ^ Sun Solaris
| ELFOSABI_AIX -- ^ AIX
| ELFOSABI_IRIX -- ^ IRIX
| ELFOSABI_FREEBSD -- ^ FreeBSD
| ELFOSABI_TRU64 -- ^ Compaq TRU64 UNIX
| ELFOSABI_MODESTO -- ^ Novell Modesto
| ELFOSABI_OPENBSD -- ^ Open BSD
| ELFOSABI_OPENVMS -- ^ Open VMS
| ELFOSABI_NSK -- ^ Hewlett-Packard Non-Stop Kernel
| ELFOSABI_AROS -- ^ Amiga Research OS
| ELFOSABI_ARM -- ^ ARM
| ELFOSABI_STANDALONE -- ^ Standalone (embedded) application
| ELFOSABI_EXT Word8 -- ^ Other
deriving (Eq, Show)
getElfOsabi = getWord8 >>= return . getElfOsabi_
where getElfOsabi_ 0 = ELFOSABI_SYSV
getElfOsabi_ 1 = ELFOSABI_HPUX
getElfOsabi_ 2 = ELFOSABI_NETBSD
getElfOsabi_ 3 = ELFOSABI_LINUX
getElfOsabi_ 6 = ELFOSABI_SOLARIS
getElfOsabi_ 7 = ELFOSABI_AIX
getElfOsabi_ 8 = ELFOSABI_IRIX
getElfOsabi_ 9 = ELFOSABI_FREEBSD
getElfOsabi_ 10 = ELFOSABI_TRU64
getElfOsabi_ 11 = ELFOSABI_MODESTO
getElfOsabi_ 12 = ELFOSABI_OPENBSD
getElfOsabi_ 13 = ELFOSABI_OPENVMS
getElfOsabi_ 14 = ELFOSABI_NSK
getElfOsabi_ 15 = ELFOSABI_AROS
getElfOsabi_ 97 = ELFOSABI_ARM
getElfOsabi_ 255 = ELFOSABI_STANDALONE
getElfOsabi_ n = ELFOSABI_EXT n
data ElfType
= ET_NONE -- ^ Unspecified type
| ET_REL -- ^ Relocatable object file
| ET_EXEC -- ^ Executable object file
| ET_DYN -- ^ Shared object file
| ET_CORE -- ^ Core dump object file
| ET_EXT Word16 -- ^ Other
deriving (Eq, Show)
getElfType er = getWord16 er >>= return . getElfType_
where getElfType_ 0 = ET_NONE
getElfType_ 1 = ET_REL
getElfType_ 2 = ET_EXEC
getElfType_ 3 = ET_DYN
getElfType_ 4 = ET_CORE
getElfType_ n = ET_EXT n
data ElfMachine
= EM_NONE -- ^ No machine
| EM_M32 -- ^ AT&T WE 32100
| EM_SPARC -- ^ SPARC
| EM_386 -- ^ Intel 80386
| EM_68K -- ^ Motorola 68000
| EM_88K -- ^ Motorola 88000
| EM_486 -- ^ Intel i486 (DO NOT USE THIS ONE)
| EM_860 -- ^ Intel 80860
| EM_MIPS -- ^ MIPS I Architecture
| EM_S370 -- ^ IBM System/370 Processor
| EM_MIPS_RS3_LE -- ^ MIPS RS3000 Little-endian
| EM_SPARC64 -- ^ SPARC 64-bit
| EM_PARISC -- ^ Hewlett-Packard PA-RISC
| EM_VPP500 -- ^ Fujitsu VPP500
| EM_SPARC32PLUS -- ^ Enhanced instruction set SPARC
| EM_960 -- ^ Intel 80960
| EM_PPC -- ^ PowerPC
| EM_PPC64 -- ^ 64-bit PowerPC
| EM_S390 -- ^ IBM System/390 Processor
| EM_SPU -- ^ Cell SPU
| EM_V800 -- ^ NEC V800
| EM_FR20 -- ^ Fujitsu FR20
| EM_RH32 -- ^ TRW RH-32
| EM_RCE -- ^ Motorola RCE
| EM_ARM -- ^ Advanced RISC Machines ARM
| EM_ALPHA -- ^ Digital Alpha
| EM_SH -- ^ Hitachi SH
| EM_SPARCV9 -- ^ SPARC Version 9
| EM_TRICORE -- ^ Siemens TriCore embedded processor
| EM_ARC -- ^ Argonaut RISC Core, Argonaut Technologies Inc.
| EM_H8_300 -- ^ Hitachi H8/300
| EM_H8_300H -- ^ Hitachi H8/300H
| EM_H8S -- ^ Hitachi H8S
| EM_H8_500 -- ^ Hitachi H8/500
| EM_IA_64 -- ^ Intel IA-64 processor architecture
| EM_MIPS_X -- ^ Stanford MIPS-X
| EM_COLDFIRE -- ^ Motorola ColdFire
| EM_68HC12 -- ^ Motorola M68HC12
| EM_MMA -- ^ Fujitsu MMA Multimedia Accelerator
| EM_PCP -- ^ Siemens PCP
| EM_NCPU -- ^ Sony nCPU embedded RISC processor
| EM_NDR1 -- ^ Denso NDR1 microprocessor
| EM_STARCORE -- ^ Motorola Star*Core processor
| EM_ME16 -- ^ Toyota ME16 processor
| EM_ST100 -- ^ STMicroelectronics ST100 processor
| EM_TINYJ -- ^ Advanced Logic Corp. TinyJ embedded processor family
| EM_X86_64 -- ^ AMD x86-64 architecture
| EM_PDSP -- ^ Sony DSP Processor
| EM_FX66 -- ^ Siemens FX66 microcontroller
| EM_ST9PLUS -- ^ STMicroelectronics ST9+ 8/16 bit microcontroller
| EM_ST7 -- ^ STMicroelectronics ST7 8-bit microcontroller
| EM_68HC16 -- ^ Motorola MC68HC16 Microcontroller
| EM_68HC11 -- ^ Motorola MC68HC11 Microcontroller
| EM_68HC08 -- ^ Motorola MC68HC08 Microcontroller
| EM_68HC05 -- ^ Motorola MC68HC05 Microcontroller
| EM_SVX -- ^ Silicon Graphics SVx
| EM_ST19 -- ^ STMicroelectronics ST19 8-bit microcontroller
| EM_VAX -- ^ Digital VAX
| EM_CRIS -- ^ Axis Communications 32-bit embedded processor
| EM_JAVELIN -- ^ Infineon Technologies 32-bit embedded processor
| EM_FIREPATH -- ^ Element 14 64-bit DSP Processor
| EM_ZSP -- ^ LSI Logic 16-bit DSP Processor
| EM_MMIX -- ^ Donald Knuth's educational 64-bit processor
| EM_HUANY -- ^ Harvard University machine-independent object files
| EM_PRISM -- ^ SiTera Prism
| EM_AVR -- ^ Atmel AVR 8-bit microcontroller
| EM_FR30 -- ^ Fujitsu FR30
| EM_D10V -- ^ Mitsubishi D10V
| EM_D30V -- ^ Mitsubishi D30V
| EM_V850 -- ^ NEC v850
| EM_M32R -- ^ Mitsubishi M32R
| EM_MN10300 -- ^ Matsushita MN10300
| EM_MN10200 -- ^ Matsushita MN10200
| EM_PJ -- ^ picoJava
| EM_OPENRISC -- ^ OpenRISC 32-bit embedded processor
| EM_ARC_A5 -- ^ ARC Cores Tangent-A5
| EM_XTENSA -- ^ Tensilica Xtensa Architecture
| EM_VIDEOCORE -- ^ Alphamosaic VideoCore processor
| EM_TMM_GPP -- ^ Thompson Multimedia General Purpose Processor
| EM_NS32K -- ^ National Semiconductor 32000 series
| EM_TPC -- ^ Tenor Network TPC processor
| EM_SNP1K -- ^ Trebia SNP 1000 processor
| EM_ST200 -- ^ STMicroelectronics (www.st.com) ST200 microcontroller
| EM_IP2K -- ^ Ubicom IP2xxx microcontroller family
| EM_MAX -- ^ MAX Processor
| EM_CR -- ^ National Semiconductor CompactRISC microprocessor
| EM_F2MC16 -- ^ Fujitsu F2MC16
| EM_MSP430 -- ^ Texas Instruments embedded microcontroller msp430
| EM_BLACKFIN -- ^ Analog Devices Blackfin (DSP) processor
| EM_SE_C33 -- ^ S1C33 Family of Seiko Epson processors
| EM_SEP -- ^ Sharp embedded microprocessor
| EM_ARCA -- ^ Arca RISC Microprocessor
| EM_UNICORE -- ^ Microprocessor series from PKU-Unity Ltd. and MPRC of Peking University
| EM_EXT Word16 -- ^ Other
deriving (Eq, Show)
getElfMachine er = getWord16 er >>= return . getElfMachine_
where getElfMachine_ 0 = EM_NONE
getElfMachine_ 1 = EM_M32
getElfMachine_ 2 = EM_SPARC
getElfMachine_ 3 = EM_386
getElfMachine_ 4 = EM_68K
getElfMachine_ 5 = EM_88K
getElfMachine_ 6 = EM_486
getElfMachine_ 7 = EM_860
getElfMachine_ 8 = EM_MIPS
getElfMachine_ 9 = EM_S370
getElfMachine_ 10 = EM_MIPS_RS3_LE
getElfMachine_ 11 = EM_SPARC64
getElfMachine_ 15 = EM_PARISC
getElfMachine_ 17 = EM_VPP500
getElfMachine_ 18 = EM_SPARC32PLUS
getElfMachine_ 19 = EM_960
getElfMachine_ 20 = EM_PPC
getElfMachine_ 21 = EM_PPC64
getElfMachine_ 22 = EM_S390
getElfMachine_ 23 = EM_SPU
getElfMachine_ 36 = EM_V800
getElfMachine_ 37 = EM_FR20
getElfMachine_ 38 = EM_RH32
getElfMachine_ 39 = EM_RCE
getElfMachine_ 40 = EM_ARM
getElfMachine_ 41 = EM_ALPHA
getElfMachine_ 42 = EM_SH
getElfMachine_ 43 = EM_SPARCV9
getElfMachine_ 44 = EM_TRICORE
getElfMachine_ 45 = EM_ARC
getElfMachine_ 46 = EM_H8_300
getElfMachine_ 47 = EM_H8_300H
getElfMachine_ 48 = EM_H8S
getElfMachine_ 49 = EM_H8_500
getElfMachine_ 50 = EM_IA_64
getElfMachine_ 51 = EM_MIPS_X
getElfMachine_ 52 = EM_COLDFIRE
getElfMachine_ 53 = EM_68HC12
getElfMachine_ 54 = EM_MMA
getElfMachine_ 55 = EM_PCP
getElfMachine_ 56 = EM_NCPU
getElfMachine_ 57 = EM_NDR1
getElfMachine_ 58 = EM_STARCORE
getElfMachine_ 59 = EM_ME16
getElfMachine_ 60 = EM_ST100
getElfMachine_ 61 = EM_TINYJ
getElfMachine_ 62 = EM_X86_64
getElfMachine_ 63 = EM_PDSP
getElfMachine_ 66 = EM_FX66
getElfMachine_ 67 = EM_ST9PLUS
getElfMachine_ 68 = EM_ST7
getElfMachine_ 69 = EM_68HC16
getElfMachine_ 70 = EM_68HC11
getElfMachine_ 71 = EM_68HC08
getElfMachine_ 72 = EM_68HC05
getElfMachine_ 73 = EM_SVX
getElfMachine_ 74 = EM_ST19
getElfMachine_ 75 = EM_VAX
getElfMachine_ 76 = EM_CRIS
getElfMachine_ 77 = EM_JAVELIN
getElfMachine_ 78 = EM_FIREPATH
getElfMachine_ 79 = EM_ZSP
getElfMachine_ 80 = EM_MMIX
getElfMachine_ 81 = EM_HUANY
getElfMachine_ 82 = EM_PRISM
getElfMachine_ 83 = EM_AVR
getElfMachine_ 84 = EM_FR30
getElfMachine_ 85 = EM_D10V
getElfMachine_ 86 = EM_D30V
getElfMachine_ 87 = EM_V850
getElfMachine_ 88 = EM_M32R
getElfMachine_ 89 = EM_MN10300
getElfMachine_ 90 = EM_MN10200
getElfMachine_ 91 = EM_PJ
getElfMachine_ 92 = EM_OPENRISC
getElfMachine_ 93 = EM_ARC_A5
getElfMachine_ 94 = EM_XTENSA
getElfMachine_ 95 = EM_VIDEOCORE
getElfMachine_ 96 = EM_TMM_GPP
getElfMachine_ 97 = EM_NS32K
getElfMachine_ 98 = EM_TPC
getElfMachine_ 99 = EM_SNP1K
getElfMachine_ 100 = EM_ST200
getElfMachine_ 101 = EM_IP2K
getElfMachine_ 102 = EM_MAX
getElfMachine_ 103 = EM_CR
getElfMachine_ 104 = EM_F2MC16
getElfMachine_ 105 = EM_MSP430
getElfMachine_ 106 = EM_BLACKFIN
getElfMachine_ 107 = EM_SE_C33
getElfMachine_ 108 = EM_SEP
getElfMachine_ 109 = EM_ARCA
getElfMachine_ 110 = EM_UNICORE
getElfMachine_ n = EM_EXT n
getElf_Shdr_OffsetSize :: ElfClass -> ElfReader -> Get (Word64, Word64)
getElf_Shdr_OffsetSize ei_class er =
case ei_class of
ELFCLASS32 -> do
skip 16
sh_offset <- liftM fromIntegral $ getWord32 er
sh_size <- liftM fromIntegral $ getWord32 er
return (sh_offset, sh_size)
ELFCLASS64 -> do
skip 24
sh_offset <- getWord64 er
sh_size <- getWord64 er
return (sh_offset, sh_size)
getElf_Shdr :: ElfClass -> ElfReader -> B.ByteString -> B.ByteString -> Get ElfSection
getElf_Shdr ei_class er elf_file string_section =
case ei_class of
ELFCLASS32 -> do
sh_name <- getWord32 er
sh_type <- getElfSectionType er
sh_flags <- getElfSectionFlags32 er
sh_addr <- getWord32 er
sh_offset <- getWord32 er
sh_size <- getWord32 er
sh_link <- getWord32 er
sh_info <- getWord32 er
sh_addralign <- getWord32 er
sh_entsize <- getWord32 er
return $ ElfSection
{ elfSectionName = map B.w2c $ B.unpack $ B.takeWhile (/= 0) $ B.drop (fromIntegral sh_name) string_section
, elfSectionType = sh_type
, elfSectionFlags = sh_flags
, elfSectionAddr = fromIntegral sh_addr
, elfSectionSize = fromIntegral sh_size
, elfSectionLink = sh_link
, elfSectionInfo = sh_info
, elfSectionAddrAlign = fromIntegral sh_addralign
, elfSectionEntSize = fromIntegral sh_entsize
, elfSectionData = B.take (fromIntegral sh_size) $ B.drop (fromIntegral sh_offset) elf_file
}
ELFCLASS64 -> do
sh_name <- getWord32 er
sh_type <- getElfSectionType er
sh_flags <- getElfSectionFlags64 er
sh_addr <- getWord64 er
sh_offset <- getWord64 er
sh_size <- getWord64 er
sh_link <- getWord32 er
sh_info <- getWord32 er
sh_addralign <- getWord64 er
sh_entsize <- getWord64 er
return $ ElfSection
{ elfSectionName = map B.w2c $ B.unpack $ B.takeWhile (/= 0) $ B.drop (fromIntegral sh_name) string_section
, elfSectionType = sh_type
, elfSectionFlags = sh_flags
, elfSectionAddr = sh_addr
, elfSectionSize = sh_size
, elfSectionLink = sh_link
, elfSectionInfo = sh_info
, elfSectionAddrAlign = sh_addralign
, elfSectionEntSize = sh_entsize
, elfSectionData = B.take (fromIntegral sh_size) $ B.drop (fromIntegral sh_offset) elf_file
}
getElf_Ehdr :: Get (Elf, Word64, Word16, Word16, Word16)
getElf_Ehdr = do
ei_magic <- getElfMagic
ei_class <- getElfClass
ei_data <- getElfData
ei_version <- liftM fromIntegral getElfVersion
ei_osabi <- getElfOsabi
ei_abiver <- liftM fromIntegral getWord8
skip 7
er <- return $ elfReader ei_data
case ei_class of
ELFCLASS32 -> do
e_type <- getElfType er
e_machine <- getElfMachine er
e_version <- getWord32 er
e_entry <- getWord32 er >>= return . fromIntegral
e_phoff <- getWord32 er
e_shoff <- getWord32 er >>= return . fromIntegral
e_flags <- getWord32 er
e_ehsize <- getWord16 er
e_phentsize <- getWord16 er
e_phnum <- getWord16 er
e_shentsize <- getWord16 er
e_shnum <- getWord16 er
e_shstrndx <- getWord16 er
return (Elf { elfClass = ei_class
, elfData = ei_data
, elfVersion = ei_version
, elfOSABI = ei_osabi
, elfABIVersion = ei_abiver
, elfType = e_type
, elfMachine = e_machine
, elfEntry = e_entry
, elfSections = [] }
, e_shoff, e_shentsize, e_shnum, e_shstrndx)
ELFCLASS64 -> do
e_type <- getElfType er
e_machine <- getElfMachine er
e_version <- getWord32 er
e_entry <- getWord64 er
e_phoff <- getWord64 er
e_shoff <- getWord64 er
e_flags <- getWord32 er
e_ehsize <- getWord16 er
e_phentsize <- getWord16 er
e_phnum <- getWord16 er
e_shentsize <- getWord16 er
e_shnum <- getWord16 er
e_shstrndx <- getWord16 er
return (Elf { elfClass = ei_class
, elfData = ei_data
, elfVersion = ei_version
, elfOSABI = ei_osabi
, elfABIVersion = ei_abiver
, elfType = e_type
, elfMachine = e_machine
, elfEntry = e_entry
, elfSections = [] }
, e_shoff, e_shentsize, e_shnum, e_shstrndx)
data ElfReader = ElfReader
{ getWord16 :: Get Word16
, getWord32 :: Get Word32
, getWord64 :: Get Word64
}
elfReader ELFDATA2LSB = ElfReader { getWord16 = getWord16le, getWord32 = getWord32le, getWord64 = getWord64le }
elfReader ELFDATA2MSB = ElfReader { getWord16 = getWord16be, getWord32 = getWord32be, getWord64 = getWord64be }
divide :: B.ByteString -> Int -> Int -> [B.ByteString]
divide bs s 0 = []
divide bs s n = let (x,y) = B.splitAt s bs in x:(divide y s (n-1))
-- | Parses a ByteString into an Elf record. An error is thrown for unrecognized ByteStrings.
getElf :: B.ByteString -> Elf
getElf b =
let (e, e_shoff, e_shentsize, e_shnum, e_shstrndx) = runGet getElf_Ehdr $ L.fromChunks [b]
sh = B.take (fromIntegral (e_shentsize * e_shnum)) $ B.drop (fromIntegral e_shoff) b
(shstroff, shstrsize) = runGet (getElf_Shdr_OffsetSize (elfClass e) (elfReader $ elfData e)) $ L.fromChunks [B.drop (fromIntegral (e_shentsize * e_shstrndx)) sh]
sh_str = B.take (fromIntegral shstrsize) $ B.drop (fromIntegral shstroff) b
sections = filter (\sec -> elfSectionType sec /= SHT_NULL) $ map (runGet (getElf_Shdr (elfClass e) (elfReader $ elfData e) b sh_str)) (map (\x -> L.fromChunks [x]) (divide sh (fromIntegral e_shentsize) (fromIntegral e_shnum)))
in e { elfSections = sections }