{-# LANGUAGE PartialTypeSignatures , FlexibleContexts, Strict, DeriveGeneric, StandaloneDeriving #-}

module Instantiation.BinaryElf (elf_read_file) where

import Base

import Generic.Binary

import Data.Elf

import qualified Data.Map as M
import qualified Data.Set as S
import qualified Data.IntMap as IM
import qualified Data.IntSet as IS
import Data.Word 
import Data.List
import Data.Bits
import Data.Maybe (fromJust)
import Data.List.Extra (firstJust)
import qualified Data.ByteString as BS
import GHC.Generics
import qualified Data.Serialize as Cereal hiding (get,put)
import qualified Data.Text                  as T
import qualified Data.Text.Encoding         as T

deriving instance Generic ElfMachine
deriving instance Generic ElfSegmentType
deriving instance Generic ElfSegmentFlag
deriving instance Generic ElfSegment
deriving instance Generic ElfType
deriving instance Generic ElfOSABI
deriving instance Generic ElfClass
deriving instance Generic ElfData
deriving instance Generic ElfSectionFlags
deriving instance Generic ElfSectionType
deriving instance Generic ElfSection
deriving instance Generic Elf

instance Cereal.Serialize ElfMachine
instance Cereal.Serialize ElfSegmentType
instance Cereal.Serialize ElfSegmentFlag
instance Cereal.Serialize ElfSegment
instance Cereal.Serialize ElfType
instance Cereal.Serialize ElfOSABI
instance Cereal.Serialize ElfClass
instance Cereal.Serialize ElfData
instance Cereal.Serialize ElfSectionFlags
instance Cereal.Serialize ElfSectionType
instance Cereal.Serialize ElfSection
instance Cereal.Serialize Elf




-- | Overview of sections with read only data.
sections_ro_data :: [([Char], [Char])]
sections_ro_data = [
   ([Char]
"",[Char]
".text"),
   ([Char]
"",[Char]
".init"),
   ([Char]
"",[Char]
".fini"),
   ([Char]
"",[Char]
".rodata"),
   ([Char]
"",[Char]
".plt"),
   ([Char]
"",[Char]
".plt.got"),
   ([Char]
"",[Char]
".plt.sec"),
   ([Char]
"",[Char]
".data.rel.ro"),
   ([Char]
"",[Char]
".init_array"),
   ([Char]
"",[Char]
".fini_array")
 ]

sections_data :: [([Char], [Char])]
sections_data = [
   ([Char]
"",[Char]
".data")
 ]

sections_bss :: [([Char], [Char])]
sections_bss = [
   ([Char]
"",[Char]
".bss")
 ]


sections_text :: [([Char], [Char])]
sections_text = [
   ([Char]
"",[Char]
".text")
 ]



isRelevantElfSection :: ElfSection -> Bool
isRelevantElfSection ElfSection
section = ([Char]
"",ElfSection -> [Char]
elfSectionName ElfSection
section) ([Char], [Char]) -> [([Char], [Char])] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` [([Char], [Char])]
sections_ro_data [([Char], [Char])] -> [([Char], [Char])] -> [([Char], [Char])]
forall a. [a] -> [a] -> [a]
++ [([Char], [Char])]
sections_data [([Char], [Char])] -> [([Char], [Char])] -> [([Char], [Char])]
forall a. [a] -> [a] -> [a]
++ [([Char], [Char])]
sections_bss

isAllocated :: ElfSection -> Bool
isAllocated ElfSection
section = ElfSectionFlags
SHF_ALLOC ElfSectionFlags -> [ElfSectionFlags] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` ElfSection -> [ElfSectionFlags]
elfSectionFlags ElfSection
section



-- reading bytes from sections. 
read_bytes_section :: Word64 -> Int -> ElfSection -> [Word8]
read_bytes_section Word64
a Int
si ElfSection
section = ByteString -> [Word8]
BS.unpack (ByteString -> [Word8]) -> ByteString -> [Word8]
forall a b. (a -> b) -> a -> b
$ Int -> ByteString -> ByteString
BS.take Int
si (ByteString -> ByteString) -> ByteString -> ByteString
forall a b. (a -> b) -> a -> b
$ Int -> ByteString -> ByteString
BS.drop (Word64 -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Word64 -> Int) -> Word64 -> Int
forall a b. (a -> b) -> a -> b
$ Word64
a Word64 -> Word64 -> Word64
forall a. Num a => a -> a -> a
- ElfSection -> Word64
elfSectionAddr ElfSection
section) (ByteString -> ByteString) -> ByteString -> ByteString
forall a b. (a -> b) -> a -> b
$ ElfSection -> ByteString
elfSectionData ElfSection
section

contains_address :: Word64 -> p -> ElfSection -> Bool
contains_address Word64
a p
si ElfSection
section = 
  let a0 :: Word64
a0  = ElfSection -> Word64
elfSectionAddr ElfSection
section
      si0 :: Word64
si0 = ElfSection -> Word64
elfSectionSize ElfSection
section in
    Word64
a0 Word64 -> Word64 -> Bool
forall a. Ord a => a -> a -> Bool
<= Word64
a Bool -> Bool -> Bool
&& Word64
a Word64 -> Word64 -> Bool
forall a. Ord a => a -> a -> Bool
< Word64
a0 Word64 -> Word64 -> Word64
forall a. Num a => a -> a -> a
+ Word64
si0

elf_read_ro_data :: Elf -> Word64 -> Int -> Maybe [Word8]
elf_read_ro_data :: Elf -> Word64 -> Int -> Maybe [Word8]
elf_read_ro_data Elf
elf Word64
a Int
si =
  case (ElfSection -> Bool) -> [ElfSection] -> [ElfSection]
forall a. (a -> Bool) -> [a] -> [a]
filter ElfSection -> Bool
isRelevant ([ElfSection] -> [ElfSection]) -> [ElfSection] -> [ElfSection]
forall a b. (a -> b) -> a -> b
$ (ElfSection -> Bool) -> [ElfSection] -> [ElfSection]
forall a. (a -> Bool) -> [a] -> [a]
filter (Word64 -> Int -> ElfSection -> Bool
forall p. Word64 -> p -> ElfSection -> Bool
contains_address Word64
a Int
si) ([ElfSection] -> [ElfSection]) -> [ElfSection] -> [ElfSection]
forall a b. (a -> b) -> a -> b
$ Elf -> [ElfSection]
elfSections Elf
elf of
    [] -> Maybe [Word8]
forall a. Maybe a
Nothing
    [ElfSection
section] -> [Word8] -> Maybe [Word8]
forall a. a -> Maybe a
Just ([Word8] -> Maybe [Word8]) -> [Word8] -> Maybe [Word8]
forall a b. (a -> b) -> a -> b
$ Word64 -> Int -> ElfSection -> [Word8]
read_bytes_section Word64
a Int
si ElfSection
section
 where
  isRelevant :: ElfSection -> Bool
isRelevant ElfSection
section
    |  ([Char]
"",ElfSection -> [Char]
elfSectionName ElfSection
section) ([Char], [Char]) -> [([Char], [Char])] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` [([Char], [Char])]
sections_ro_data = Bool
True
    | Bool
otherwise = Bool
False

elf_read_data :: Elf -> Word64 -> Int -> Maybe [Word8]
elf_read_data :: Elf -> Word64 -> Int -> Maybe [Word8]
elf_read_data Elf
elf Word64
a Int
si =
  case (ElfSection -> Bool) -> [ElfSection] -> [ElfSection]
forall a. (a -> Bool) -> [a] -> [a]
filter ElfSection -> Bool
isBss ([ElfSection] -> [ElfSection]) -> [ElfSection] -> [ElfSection]
forall a b. (a -> b) -> a -> b
$ (ElfSection -> Bool) -> [ElfSection] -> [ElfSection]
forall a. (a -> Bool) -> [a] -> [a]
filter (Word64 -> Int -> ElfSection -> Bool
forall p. Word64 -> p -> ElfSection -> Bool
contains_address Word64
a Int
si) ([ElfSection] -> [ElfSection]) -> [ElfSection] -> [ElfSection]
forall a b. (a -> b) -> a -> b
$ Elf -> [ElfSection]
elfSections Elf
elf of
    [ElfSection
section] -> [Word8] -> Maybe [Word8]
forall a. a -> Maybe a
Just ([Word8] -> Maybe [Word8]) -> [Word8] -> Maybe [Word8]
forall a b. (a -> b) -> a -> b
$ Int -> Word8 -> [Word8]
forall a. Int -> a -> [a]
replicate Int
si Word8
0
    [] -> Maybe [Word8]
try_read_data
 where 
  try_read_data :: Maybe [Word8]
try_read_data =
    case (ElfSection -> Bool) -> [ElfSection] -> [ElfSection]
forall a. (a -> Bool) -> [a] -> [a]
filter ElfSection -> Bool
isData ([ElfSection] -> [ElfSection]) -> [ElfSection] -> [ElfSection]
forall a b. (a -> b) -> a -> b
$ (ElfSection -> Bool) -> [ElfSection] -> [ElfSection]
forall a. (a -> Bool) -> [a] -> [a]
filter (Word64 -> Int -> ElfSection -> Bool
forall p. Word64 -> p -> ElfSection -> Bool
contains_address Word64
a Int
si) ([ElfSection] -> [ElfSection]) -> [ElfSection] -> [ElfSection]
forall a b. (a -> b) -> a -> b
$ Elf -> [ElfSection]
elfSections Elf
elf of
      [] -> Maybe [Word8]
forall a. Maybe a
Nothing
      [ElfSection
section] -> [Word8] -> Maybe [Word8]
forall a. a -> Maybe a
Just ([Word8] -> Maybe [Word8]) -> [Word8] -> Maybe [Word8]
forall a b. (a -> b) -> a -> b
$ Word64 -> Int -> ElfSection -> [Word8]
read_bytes_section Word64
a Int
si ElfSection
section

  isData :: ElfSection -> Bool
isData ElfSection
section 
    | ([Char]
"",ElfSection -> [Char]
elfSectionName ElfSection
section) ([Char], [Char]) -> [([Char], [Char])] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` [([Char], [Char])]
sections_data = Bool
True
    | Bool
otherwise = Bool
False
  isBss :: ElfSection -> Bool
isBss ElfSection
section 
    | ([Char]
"",ElfSection -> [Char]
elfSectionName ElfSection
section) ([Char], [Char]) -> [([Char], [Char])] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` [([Char], [Char])]
sections_bss = Bool
True
    | Bool
otherwise = Bool
False



elf_get_relocs :: Elf -> Set Relocation
elf_get_relocs Elf
elf = [Relocation] -> Set Relocation
forall a. Ord a => [a] -> Set a
S.fromList ([Relocation] -> Set Relocation) -> [Relocation] -> Set Relocation
forall a b. (a -> b) -> a -> b
$ [Relocation]
mk_relocs
 where
  -- go through all relocations
  mk_relocs :: [Relocation]
mk_relocs = (ElfRelocationSection -> [Relocation])
-> [ElfRelocationSection] -> [Relocation]
forall (t :: * -> *) a b. Foldable t => (a -> [b]) -> t a -> [b]
concatMap ElfRelocationSection -> [Relocation]
mk_reloc ([ElfRelocationSection] -> [Relocation])
-> [ElfRelocationSection] -> [Relocation]
forall a b. (a -> b) -> a -> b
$ Elf -> [ElfRelocationSection]
parseRelocations Elf
elf
  
  mk_reloc :: ElfRelocationSection -> [Relocation]
mk_reloc ElfRelocationSection
sec = (ElfRel -> [Relocation]) -> [ElfRel] -> [Relocation]
forall (t :: * -> *) a b. Foldable t => (a -> [b]) -> t a -> [b]
concatMap (ElfRelocationSection -> ElfRel -> [Relocation]
forall p. p -> ElfRel -> [Relocation]
try_mk_reloc ElfRelocationSection
sec) (ElfRelocationSection -> [ElfRel]
elfRelSectRelocations ElfRelocationSection
sec)

  try_mk_reloc :: p -> ElfRel -> [Relocation]
try_mk_reloc p
sec ElfRel
reloc
   | ElfRel -> Word8
elfRelType ElfRel
reloc Word8 -> Word8 -> Bool
forall a. Eq a => a -> a -> Bool
== Word8
8 =
     -- R_X86_64_RELATIVE
     -- The SymAddend provides the relocation address
      [Word64 -> Word64 -> Relocation
Relocation (Word64 -> Word64
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Word64 -> Word64) -> Word64 -> Word64
forall a b. (a -> b) -> a -> b
$ ElfRel -> Word64
elfRelOffset ElfRel
reloc) (Int64 -> Word64
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Int64 -> Word64) -> Int64 -> Word64
forall a b. (a -> b) -> a -> b
$ Maybe Int64 -> Int64
forall a. HasCallStack => Maybe a -> a
fromJust (Maybe Int64 -> Int64) -> Maybe Int64 -> Int64
forall a b. (a -> b) -> a -> b
$ ElfRel -> Maybe Int64
elfRelSymAddend ElfRel
reloc)]
   | Bool
otherwise = []


elf_get_symbol_table :: Elf -> SymbolTable
elf_get_symbol_table Elf
elf = IntMap Symbol -> SymbolTable
SymbolTable (IntMap Symbol -> SymbolTable) -> IntMap Symbol -> SymbolTable
forall a b. (a -> b) -> a -> b
$ [(Int, Symbol)] -> IntMap Symbol
forall a. [(Int, a)] -> IntMap a
IM.fromList ([(Int, Symbol)] -> IntMap Symbol)
-> [(Int, Symbol)] -> IntMap Symbol
forall a b. (a -> b) -> a -> b
$ ((Int, Symbol) -> Bool) -> [(Int, Symbol)] -> [(Int, Symbol)]
forall a. (a -> Bool) -> [a] -> [a]
filter (Maybe [Char] -> Maybe [Char] -> Bool
forall a. Eq a => a -> a -> Bool
(/=) ([Char] -> Maybe [Char]
forall a. a -> Maybe a
Just [Char]
"") (Maybe [Char] -> Bool)
-> ((Int, Symbol) -> Maybe [Char]) -> (Int, Symbol) -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Symbol -> Maybe [Char]
symbol_to_name (Symbol -> Maybe [Char])
-> ((Int, Symbol) -> Symbol) -> (Int, Symbol) -> Maybe [Char]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Int, Symbol) -> Symbol
forall a b. (a, b) -> b
snd) ([(Int, Symbol)] -> [(Int, Symbol)])
-> [(Int, Symbol)] -> [(Int, Symbol)]
forall a b. (a -> b) -> a -> b
$ [(Int, Symbol)]
symbols_from_ELF_symbol_tables [(Int, Symbol)] -> [(Int, Symbol)] -> [(Int, Symbol)]
forall a. [a] -> [a] -> [a]
++ [(Int, Symbol)]
symbols_from_relocations
 where
  -- go through all relocations
  symbols_from_relocations :: [(Int, Symbol)]
symbols_from_relocations = (ElfRelocationSection -> [(Int, Symbol)])
-> [ElfRelocationSection] -> [(Int, Symbol)]
forall (t :: * -> *) a b. Foldable t => (a -> [b]) -> t a -> [b]
concatMap ElfRelocationSection -> [(Int, Symbol)]
forall a. Num a => ElfRelocationSection -> [(a, Symbol)]
mk_symbol_table_for_reloc_section ([ElfRelocationSection] -> [(Int, Symbol)])
-> [ElfRelocationSection] -> [(Int, Symbol)]
forall a b. (a -> b) -> a -> b
$ Elf -> [ElfRelocationSection]
parseRelocations Elf
elf
  
  mk_symbol_table_for_reloc_section :: ElfRelocationSection -> [(a, Symbol)]
mk_symbol_table_for_reloc_section ElfRelocationSection
sec = (ElfRel -> [(a, Symbol)]) -> [ElfRel] -> [(a, Symbol)]
forall (t :: * -> *) a b. Foldable t => (a -> [b]) -> t a -> [b]
concatMap (ElfRelocationSection -> ElfRel -> [(a, Symbol)]
forall a. Num a => ElfRelocationSection -> ElfRel -> [(a, Symbol)]
try_mk_symbol_entry ElfRelocationSection
sec) (ElfRelocationSection -> [ElfRel]
elfRelSectRelocations ElfRelocationSection
sec)

  try_mk_symbol_entry :: ElfRelocationSection -> ElfRel -> [(a, Symbol)]
try_mk_symbol_entry ElfRelocationSection
sec ElfRel
reloc
    | ElfRel -> Word8
elfRelType ElfRel
reloc Word8 -> Word8 -> Bool
forall a. Eq a => a -> a -> Bool
== Word8
7 =
      -- R_X86_64_JUMP_SLOT
      -- the RelSymbol provides an index into a lookup table that contains the name of the symbol
      [(Word64 -> a
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Word64 -> a) -> Word64 -> a
forall a b. (a -> b) -> a -> b
$ ElfRel -> Word64
elfRelOffset ElfRel
reloc, [Char] -> Symbol
Relocated_Function ([Char] -> Symbol) -> [Char] -> Symbol
forall a b. (a -> b) -> a -> b
$ ElfRelocationSection -> ElfRel -> [Char]
get_name_from_reloc ElfRelocationSection
sec ElfRel
reloc)]
    | ElfRel -> Word8
elfRelType ElfRel
reloc Word8 -> Word8 -> Bool
forall a. Eq a => a -> a -> Bool
== Word8
6 =
      -- R_X86_64_GLOB_DAT, objects
      -- the RelSymbol provides an index into a lookup table that contains the name of the symbol
      let typ :: [Char] -> Symbol
typ = if ElfRelocationSection -> ElfRel -> ElfSymbolType
get_symbol_type_of_reloc ElfRelocationSection
sec ElfRel
reloc ElfSymbolType -> [ElfSymbolType] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` [ElfSymbolType
STTObject,ElfSymbolType
STTCommon] then [Char] -> Symbol
Relocated_Label else [Char] -> Symbol
Relocated_Function in
        [(Word64 -> a
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Word64 -> a) -> Word64 -> a
forall a b. (a -> b) -> a -> b
$ ElfRel -> Word64
elfRelOffset ElfRel
reloc, [Char] -> Symbol
typ ([Char] -> Symbol) -> [Char] -> Symbol
forall a b. (a -> b) -> a -> b
$ ElfRelocationSection -> ElfRel -> [Char]
get_name_from_reloc ElfRelocationSection
sec ElfRel
reloc)]
   | ElfRel -> Word8
elfRelType ElfRel
reloc Word8 -> Word8 -> Bool
forall a. Eq a => a -> a -> Bool
== Word8
5 =
      -- R_X86_64_COPY
      -- the RelSymbol provides an index into a lookup table that contains the name of the symbol
      [(Word64 -> a
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Word64 -> a) -> Word64 -> a
forall a b. (a -> b) -> a -> b
$ ElfRel -> Word64
elfRelOffset ElfRel
reloc, [Char] -> Symbol
Relocated_Label ([Char] -> Symbol) -> [Char] -> Symbol
forall a b. (a -> b) -> a -> b
$ ElfRelocationSection -> ElfRel -> [Char]
get_name_from_reloc ElfRelocationSection
sec ElfRel
reloc)]
   | Bool
otherwise = []


  -- go through all ELF symbol tables
  -- each symbol table entry that has as type STTObject with binding /= Local is considered external and that is not hidden
  -- its value is the address at which a relocation happens
  symbols_from_ELF_symbol_tables :: [(Int, Symbol)]
symbols_from_ELF_symbol_tables = (ElfSymbolTableEntry -> [(Int, Symbol)])
-> [ElfSymbolTableEntry] -> [(Int, Symbol)]
forall (t :: * -> *) a b. Foldable t => (a -> [b]) -> t a -> [b]
concatMap ElfSymbolTableEntry -> [(Int, Symbol)]
forall a. Num a => ElfSymbolTableEntry -> [(a, Symbol)]
mk_symbol_entry ([ElfSymbolTableEntry] -> [(Int, Symbol)])
-> [ElfSymbolTableEntry] -> [(Int, Symbol)]
forall a b. (a -> b) -> a -> b
$ [[ElfSymbolTableEntry]] -> [ElfSymbolTableEntry]
forall (t :: * -> *) a. Foldable t => t [a] -> [a]
concat ([[ElfSymbolTableEntry]] -> [ElfSymbolTableEntry])
-> [[ElfSymbolTableEntry]] -> [ElfSymbolTableEntry]
forall a b. (a -> b) -> a -> b
$ Elf -> [[ElfSymbolTableEntry]]
parseSymbolTables Elf
elf

  mk_symbol_entry :: ElfSymbolTableEntry -> [(a, Symbol)]
mk_symbol_entry ElfSymbolTableEntry
sym_entry
    --   | is_external_var_symbol_entry sym_entry = [(fromIntegral $ steValue sym_entry, Relocated_Label $ get_string_from_steName $ steName sym_entry)]
    | ElfSymbolTableEntry -> Bool
is_internal_symbol_entry ElfSymbolTableEntry
sym_entry     = [(Word64 -> a
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Word64 -> a) -> Word64 -> a
forall a b. (a -> b) -> a -> b
$ ElfSymbolTableEntry -> Word64
steValue ElfSymbolTableEntry
sym_entry, [Char] -> Symbol
Internal_Label ([Char] -> Symbol) -> [Char] -> Symbol
forall a b. (a -> b) -> a -> b
$ (Word32, Maybe ByteString) -> [Char]
forall a. (a, Maybe ByteString) -> [Char]
get_string_from_steName ((Word32, Maybe ByteString) -> [Char])
-> (Word32, Maybe ByteString) -> [Char]
forall a b. (a -> b) -> a -> b
$ ElfSymbolTableEntry -> (Word32, Maybe ByteString)
steName ElfSymbolTableEntry
sym_entry)]
    | Bool
otherwise = []


  -- external_variables = map mk_symbol_entry $ filter is_external_var_symbol_entry $ concat $ parseSymbolTables elf
  is_external_var_symbol_entry :: ElfSymbolTableEntry -> Bool
is_external_var_symbol_entry ElfSymbolTableEntry
sym_entry = ElfSymbolTableEntry -> ElfSymbolType
steType ElfSymbolTableEntry
sym_entry ElfSymbolType -> [ElfSymbolType] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` [ElfSymbolType
STTObject,ElfSymbolType
STTCommon] Bool -> Bool -> Bool
&& ElfSymbolTableEntry -> ElfSymbolBinding
steBind ElfSymbolTableEntry
sym_entry ElfSymbolBinding -> [ElfSymbolBinding] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` [ElfSymbolBinding
STBGlobal, ElfSymbolBinding
STBWeak] Bool -> Bool -> Bool
&& Bool -> Bool
not (ElfSymbolTableEntry -> Bool
isHiddenSymEntry ElfSymbolTableEntry
sym_entry)
  
  is_internal_symbol_entry :: ElfSymbolTableEntry -> Bool
is_internal_symbol_entry ElfSymbolTableEntry
sym_entry = [Bool] -> Bool
forall (t :: * -> *). Foldable t => t Bool -> Bool
or
    [ ElfSymbolTableEntry -> Maybe ElfSection
steEnclosingSection ElfSymbolTableEntry
sym_entry Maybe ElfSection -> Maybe ElfSection -> Bool
forall a. Eq a => a -> a -> Bool
/= Maybe ElfSection
forall a. Maybe a
Nothing Bool -> Bool -> Bool
&& ElfSymbolTableEntry -> ElfSymbolType
steType ElfSymbolTableEntry
sym_entry ElfSymbolType -> [ElfSymbolType] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`notElem` [ElfSymbolType
STTObject,ElfSymbolType
STTCommon]
    , ElfSymbolTableEntry -> Bool
is_hidden ElfSymbolTableEntry
sym_entry ]


  get_name_from_reloc :: ElfRelocationSection -> ElfRel -> [Char]
get_name_from_reloc ElfRelocationSection
sec ElfRel
reloc = (Word32, Maybe ByteString) -> [Char]
forall a. (a, Maybe ByteString) -> [Char]
get_string_from_steName ((Word32, Maybe ByteString) -> [Char])
-> (Word32, Maybe ByteString) -> [Char]
forall a b. (a -> b) -> a -> b
$ ElfSymbolTableEntry -> (Word32, Maybe ByteString)
steName (ElfSymbolTableEntry -> (Word32, Maybe ByteString))
-> ElfSymbolTableEntry -> (Word32, Maybe ByteString)
forall a b. (a -> b) -> a -> b
$ (ElfRelocationSection -> [ElfSymbolTableEntry]
elfRelSectSymbolTable ElfRelocationSection
sec) [ElfSymbolTableEntry] -> Int -> ElfSymbolTableEntry
forall a. [a] -> Int -> a
!! (Word64 -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Word64 -> Int) -> Word64 -> Int
forall a b. (a -> b) -> a -> b
$ ElfRel -> Word64
elfRelSymbol ElfRel
reloc)

  get_symbol_type_of_reloc :: ElfRelocationSection -> ElfRel -> ElfSymbolType
get_symbol_type_of_reloc ElfRelocationSection
sec ElfRel
reloc = ElfSymbolTableEntry -> ElfSymbolType
steType (ElfSymbolTableEntry -> ElfSymbolType)
-> ElfSymbolTableEntry -> ElfSymbolType
forall a b. (a -> b) -> a -> b
$ (ElfRelocationSection -> [ElfSymbolTableEntry]
elfRelSectSymbolTable ElfRelocationSection
sec) [ElfSymbolTableEntry] -> Int -> ElfSymbolTableEntry
forall a. [a] -> Int -> a
!! (Word64 -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Word64 -> Int) -> Word64 -> Int
forall a b. (a -> b) -> a -> b
$ ElfRel -> Word64
elfRelSymbol ElfRel
reloc)

  isHiddenSymEntry :: ElfSymbolTableEntry -> Bool
isHiddenSymEntry ElfSymbolTableEntry
sym_entry = ElfSymbolTableEntry -> Word8
steOther ElfSymbolTableEntry
sym_entry Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
.&. Word8
0x3 Word8 -> Word8 -> Bool
forall a. Eq a => a -> a -> Bool
== Word8
0x2
  is_hidden :: ElfSymbolTableEntry -> Bool
is_hidden ElfSymbolTableEntry
sym_entry = ElfSymbolTableEntry -> ElfSymbolType
steType ElfSymbolTableEntry
sym_entry ElfSymbolType -> [ElfSymbolType] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` [ElfSymbolType
STTObject,ElfSymbolType
STTCommon] Bool -> Bool -> Bool
&& ElfSymbolTableEntry -> ElfSymbolBinding
steBind ElfSymbolTableEntry
sym_entry ElfSymbolBinding -> [ElfSymbolBinding] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` [ElfSymbolBinding
STBGlobal, ElfSymbolBinding
STBWeak] Bool -> Bool -> Bool
&& ElfSymbolTableEntry -> Bool
isHiddenSymEntry ElfSymbolTableEntry
sym_entry

  
{--
  plt_relocations = concatMap mk_entries_relocated_function $ parseRelocations elf
  -- for each such section, filter out relocations with type 7 (R_X86_64_JUMP_SLOT)
  mk_entries_relocated_function sec = 
    let relocs = filter (((==) 7) . elfRelType) $ elfRelSectRelocations sec in
      filter ((/=) "") $ map (mk_entry_relocated_function $ elfRelSectSymbolTable sec) relocs 

  mk_entry_relocated_function table sym_reloc = (fromIntegral $ elfRelOffset sym_reloc, Relocated_Function $ get_name_from_reloc table sym_reloc)

  external_variables = concatMap mk_entries_external_variable $ parseRelocations elf
  -- for each such section, filter out relocations with type 6 (R_X86_64_GLOB_DAT)
  -- for each such relocation, the offset is the address at which a relocation happens
  -- the RelSymbol provides an index into a lookup table that contains the name of the symbol
  mk_entries_external_variable sec = 
    let relocs = filter (((==) 6) . elfRelType) $ elfRelSectRelocations sec in
      filter ((/=) "") $ map (mk_entry_relocated_function $ elfRelSectSymbolTable sec) relocs 

  mk_entry_relocated_function table sym_reloc = (fromIntegral $ elfRelOffset sym_reloc, Relocated_Label $ get_name_from_reloc table sym_reloc)





  -- go through all symbol tables
  -- each symbol table entry that has as type STTObject with binding /= Local is considered external and that is not hidden
  -- its value is the address at which a relocation happens
  external_variables = map mk_symbol_entry $ filter is_external_var_symbol_entry $ concat $ parseSymbolTables elf
  is_external_var_symbol_entry sym_entry = steType sym_entry == STTObject && steBind sym_entry `elem` [STBGlobal, STBWeak] && not (isHiddenSymEntry sym_entry)
  mk_symbol_entry sym_entry = (fromIntegral $ steValue sym_entry, get_string_from_steName $ steName sym_entry)




-- retrieve a mapping of addresses to symbols (internal)
elf_get_symbol_table_internal elf = IM.filter ((/=) "") $ IM.fromList $ internal_symbols 
 where
  -- this is how to find internal symbols:
  -- go through all symbol tables
  internal_symbols = map mk_symbol_entry $ filter is_internal_symbol_entry $ concat $ parseSymbolTables elf
  -- each symbol table entry that has a section associated to it is internal
  -- its value is the the address at which a relocation happens
  -- hidden symbols are considered inernal as well
  is_internal_symbol_entry sym_entry = or
    [ steEnclosingSection sym_entry /= Nothing && steType sym_entry /= STTObject
    , is_hidden sym_entry ]
  mk_symbol_entry sym_entry = (fromIntegral $ steValue sym_entry, get_string_from_steName $ steName sym_entry)
  
  is_hidden sym_entry = steType sym_entry == STTObject && steBind sym_entry `elem` [STBGlobal, STBWeak] && isHiddenSymEntry sym_entry
--}


-- get the name from a symbol table entry
get_string_from_steName :: (a, Maybe ByteString) -> [Char]
get_string_from_steName (a
_, Just ByteString
name) = Text -> [Char]
T.unpack (Text -> [Char]) -> Text -> [Char]
forall a b. (a -> b) -> a -> b
$ ByteString -> Text
T.decodeUtf8 ByteString
name
get_string_from_steName (a, Maybe ByteString)
_ = [Char]
""

elf_min_address :: Elf -> Word64
elf_min_address Elf
elf = [Word64] -> Word64
forall (t :: * -> *) a. (Foldable t, Ord a) => t a -> a
minimum ([Word64] -> Word64) -> [Word64] -> Word64
forall a b. (a -> b) -> a -> b
$ (ElfSection -> Word64) -> [ElfSection] -> [Word64]
forall a b. (a -> b) -> [a] -> [b]
map ElfSection -> Word64
elfSectionAddr ([ElfSection] -> [Word64]) -> [ElfSection] -> [Word64]
forall a b. (a -> b) -> a -> b
$ (ElfSection -> Bool) -> [ElfSection] -> [ElfSection]
forall a. (a -> Bool) -> [a] -> [a]
filter ElfSection -> Bool
isRelevantElfSection ([ElfSection] -> [ElfSection]) -> [ElfSection] -> [ElfSection]
forall a b. (a -> b) -> a -> b
$ Elf -> [ElfSection]
elfSections Elf
elf

elf_max_address :: Elf -> Word64
elf_max_address Elf
elf = [Word64] -> Word64
forall (t :: * -> *) a. (Foldable t, Ord a) => t a -> a
maximum ([Word64] -> Word64) -> [Word64] -> Word64
forall a b. (a -> b) -> a -> b
$ (ElfSection -> Word64) -> [ElfSection] -> [Word64]
forall a b. (a -> b) -> [a] -> [b]
map ElfSection -> Word64
get_max_address ([ElfSection] -> [Word64]) -> [ElfSection] -> [Word64]
forall a b. (a -> b) -> a -> b
$ (ElfSection -> Bool) -> [ElfSection] -> [ElfSection]
forall a. (a -> Bool) -> [a] -> [a]
filter ElfSection -> Bool
isRelevantElfSection ([ElfSection] -> [ElfSection]) -> [ElfSection] -> [ElfSection]
forall a b. (a -> b) -> a -> b
$ Elf -> [ElfSection]
elfSections Elf
elf
 where
  get_max_address :: ElfSection -> Word64
get_max_address ElfSection
section = ElfSection -> Word64
elfSectionAddr ElfSection
section Word64 -> Word64 -> Word64
forall a. Num a => a -> a -> a
+ ElfSection -> Word64
elfSectionSize ElfSection
section Word64 -> Word64 -> Word64
forall a. Num a => a -> a -> a
- Word64
1


elf_read_file :: ByteString -> Elf
elf_read_file = ByteString -> Elf
parseElf


pp_elf_section :: ElfSection -> [Char]
pp_elf_section ElfSection
section = [Char]
"[" [Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
++ [Char] -> [[Char]] -> [Char]
forall a. [a] -> [[a]] -> [a]
intercalate [Char]
", " [ElfSection -> [Char]
elfSectionName ElfSection
section, ElfSectionType -> [Char]
forall a. Show a => a -> [Char]
show (ElfSectionType -> [Char]) -> ElfSectionType -> [Char]
forall a b. (a -> b) -> a -> b
$ ElfSection -> ElfSectionType
elfSectionType ElfSection
section, Word64 -> [Char]
forall a. (Integral a, Show a) => a -> [Char]
showHex (ElfSection -> Word64
elfSectionAddr ElfSection
section), Word64 -> [Char]
forall a. (Integral a, Show a) => a -> [Char]
showHex (ElfSection -> Word64
elfSectionSize ElfSection
section)] [Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
++ [Char]
"]" 
pp_elf :: Elf -> [Char]
pp_elf Elf
elf = [Char] -> [[Char]] -> [Char]
forall a. [a] -> [[a]] -> [a]
intercalate [Char]
"\n" ([[Char]] -> [Char]) -> [[Char]] -> [Char]
forall a b. (a -> b) -> a -> b
$ [[Char]]
pp_sections [[Char]] -> [[Char]] -> [[Char]]
forall a. [a] -> [a] -> [a]
++ [[Char]]
pp_boundaries [[Char]] -> [[Char]] -> [[Char]]
forall a. [a] -> [a] -> [a]
++ [[Char]]
pp_symbols [[Char]] -> [[Char]] -> [[Char]]
forall a. [a] -> [a] -> [a]
++ [[Char]]
pp_relocs [[Char]] -> [[Char]] -> [[Char]]
forall a. [a] -> [a] -> [a]
++ [[Char]]
pp_all_relocs [[Char]] -> [[Char]] -> [[Char]]
forall a. [a] -> [a] -> [a]
++ [[Char]]
pp_all_symbols [[Char]] -> [[Char]] -> [[Char]]
forall a. [a] -> [a] -> [a]
++ [[Char]]
pp_entry
 where
  pp_sections :: [[Char]]
pp_sections = (ElfSection -> [Char]) -> [ElfSection] -> [[Char]]
forall a b. (a -> b) -> [a] -> [b]
map ElfSection -> [Char]
pp_elf_section ([ElfSection] -> [[Char]]) -> [ElfSection] -> [[Char]]
forall a b. (a -> b) -> a -> b
$ Elf -> [ElfSection]
elfSections Elf
elf
  pp_boundaries :: [[Char]]
pp_boundaries = [[Char]
"Address range: " [Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
++ Word64 -> [Char]
forall a. (Integral a, Show a) => a -> [Char]
showHex (Elf -> Word64
elf_min_address Elf
elf) [Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
++ [Char]
" --> " [Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
++ Word64 -> [Char]
forall a. (Integral a, Show a) => a -> [Char]
showHex (Elf -> Word64
elf_max_address Elf
elf)]
  pp_symbols :: [[Char]]
pp_symbols = [[Char]
"Symbol table:\n" [Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
++ SymbolTable -> [Char]
forall a. Show a => a -> [Char]
show (Elf -> SymbolTable
elf_get_symbol_table Elf
elf)] 
  pp_relocs :: [[Char]]
pp_relocs = [[Char]
"Relocations:\n" [Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
++ Set Relocation -> [Char]
forall a. Show a => a -> [Char]
show (Elf -> Set Relocation
elf_get_relocs Elf
elf)] 


  pp_all_relocs :: [[Char]]
pp_all_relocs  = [Char]
"Complete relocation list:" [Char] -> [[Char]] -> [[Char]]
forall a. a -> [a] -> [a]
: (ElfRel -> [Char]) -> [ElfRel] -> [[Char]]
forall a b. (a -> b) -> [a] -> [b]
map ElfRel -> [Char]
forall a. Show a => a -> [Char]
show ((ElfRelocationSection -> [ElfRel])
-> [ElfRelocationSection] -> [ElfRel]
forall (t :: * -> *) a b. Foldable t => (a -> [b]) -> t a -> [b]
concatMap ElfRelocationSection -> [ElfRel]
elfRelSectRelocations ([ElfRelocationSection] -> [ElfRel])
-> [ElfRelocationSection] -> [ElfRel]
forall a b. (a -> b) -> a -> b
$ Elf -> [ElfRelocationSection]
parseRelocations Elf
elf)
  pp_all_symbols :: [[Char]]
pp_all_symbols = [Char]
"Complete symbol table:" [Char] -> [[Char]] -> [[Char]]
forall a. a -> [a] -> [a]
: (ElfSymbolTableEntry -> [Char])
-> [ElfSymbolTableEntry] -> [[Char]]
forall a b. (a -> b) -> [a] -> [b]
map ElfSymbolTableEntry -> [Char]
show_symbol_entry ([[ElfSymbolTableEntry]] -> [ElfSymbolTableEntry]
forall (t :: * -> *) a. Foldable t => t [a] -> [a]
concat ([[ElfSymbolTableEntry]] -> [ElfSymbolTableEntry])
-> [[ElfSymbolTableEntry]] -> [ElfSymbolTableEntry]
forall a b. (a -> b) -> a -> b
$ Elf -> [[ElfSymbolTableEntry]]
parseSymbolTables Elf
elf)
  show_symbol_entry :: ElfSymbolTableEntry -> [Char]
show_symbol_entry ElfSymbolTableEntry
sym_entry = [Char] -> [[Char]] -> [Char]
forall a. [a] -> [[a]] -> [a]
intercalate [Char]
"; " [ (Word32, Maybe ByteString) -> [Char]
forall a. Show a => a -> [Char]
show (ElfSymbolTableEntry -> (Word32, Maybe ByteString)
steName ElfSymbolTableEntry
sym_entry), ElfSymbolType -> [Char]
forall a. Show a => a -> [Char]
show (ElfSymbolTableEntry -> ElfSymbolType
steType ElfSymbolTableEntry
sym_entry) , Word64 -> [Char]
forall a. (Integral a, Show a) => a -> [Char]
showHex (ElfSymbolTableEntry -> Word64
steValue ElfSymbolTableEntry
sym_entry), ElfSectionIndex -> [Char]
forall a. Show a => a -> [Char]
show (ElfSectionIndex -> [Char]) -> ElfSectionIndex -> [Char]
forall a b. (a -> b) -> a -> b
$ ElfSymbolTableEntry -> ElfSectionIndex
steIndex ElfSymbolTableEntry
sym_entry, ElfSymbolBinding -> [Char]
forall a. Show a => a -> [Char]
show (ElfSymbolBinding -> [Char]) -> ElfSymbolBinding -> [Char]
forall a b. (a -> b) -> a -> b
$ ElfSymbolTableEntry -> ElfSymbolBinding
steBind ElfSymbolTableEntry
sym_entry ]


  pp_entry :: [[Char]]
pp_entry = [[Char]
"Entry: " [Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
++ (Word64 -> [Char]
forall a. (Integral a, Show a) => a -> [Char]
showHex (Word64 -> [Char]) -> Word64 -> [Char]
forall a b. (a -> b) -> a -> b
$ Elf -> Word64
elfEntry Elf
elf)]
  

elf_get_sections_info :: Elf -> SectionsInfo
elf_get_sections_info Elf
elf = [([Char], [Char], Word64, Word64)]
-> Word64 -> Word64 -> SectionsInfo
SectionsInfo ((ElfSection -> ([Char], [Char], Word64, Word64))
-> [ElfSection] -> [([Char], [Char], Word64, Word64)]
forall a b. (a -> b) -> [a] -> [b]
map ElfSection -> ([Char], [Char], Word64, Word64)
mk_section_info ([ElfSection] -> [([Char], [Char], Word64, Word64)])
-> [ElfSection] -> [([Char], [Char], Word64, Word64)]
forall a b. (a -> b) -> a -> b
$ (ElfSection -> Bool) -> [ElfSection] -> [ElfSection]
forall a. (a -> Bool) -> [a] -> [a]
filter ElfSection -> Bool
isRelevantElfSection ([ElfSection] -> [ElfSection]) -> [ElfSection] -> [ElfSection]
forall a b. (a -> b) -> a -> b
$ Elf -> [ElfSection]
elfSections Elf
elf) (Elf -> Word64
elf_min_address Elf
elf) (Elf -> Word64
elf_max_address Elf
elf)
 where
  mk_section_info :: ElfSection -> ([Char], [Char], Word64, Word64)
mk_section_info ElfSection
section = ([Char]
"",ElfSection -> [Char]
elfSectionName ElfSection
section,ElfSection -> Word64
elfSectionAddr ElfSection
section,ElfSection -> Word64
elfSectionSize ElfSection
section)



elf_text_section_size :: Elf -> Int
elf_text_section_size = [Int] -> Int
forall (t :: * -> *) a. (Foldable t, Num a) => t a -> a
sum ([Int] -> Int) -> (Elf -> [Int]) -> Elf -> Int
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (ElfSection -> Int) -> [ElfSection] -> [Int]
forall a b. (a -> b) -> [a] -> [b]
map (Word64 -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Word64 -> Int) -> (ElfSection -> Word64) -> ElfSection -> Int
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ElfSection -> Word64
elfSectionSize) ([ElfSection] -> [Int]) -> (Elf -> [ElfSection]) -> Elf -> [Int]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (ElfSection -> Bool) -> [ElfSection] -> [ElfSection]
forall a. (a -> Bool) -> [a] -> [a]
filter ElfSection -> Bool
isTextSection ([ElfSection] -> [ElfSection])
-> (Elf -> [ElfSection]) -> Elf -> [ElfSection]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Elf -> [ElfSection]
elfSections
 where
  isTextSection :: ElfSection -> Bool
isTextSection ElfSection
sec = ([Char]
"",ElfSection -> [Char]
elfSectionName ElfSection
sec) ([Char], [Char]) -> [([Char], [Char])] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` [([Char], [Char])]
sections_text

instance BinaryClass Elf 
  where
    binary_read_ro_data :: Elf -> Word64 -> Int -> Maybe [Word8]
binary_read_ro_data = Elf -> Word64 -> Int -> Maybe [Word8]
elf_read_ro_data
    binary_read_data :: Elf -> Word64 -> Int -> Maybe [Word8]
binary_read_data = Elf -> Word64 -> Int -> Maybe [Word8]
elf_read_data
    binary_get_sections_info :: Elf -> SectionsInfo
binary_get_sections_info = Elf -> SectionsInfo
elf_get_sections_info
    binary_get_symbols :: Elf -> SymbolTable
binary_get_symbols = Elf -> SymbolTable
elf_get_symbol_table
    binary_get_relocations :: Elf -> Set Relocation
binary_get_relocations = Elf -> Set Relocation
elf_get_relocs
    binary_pp :: Elf -> [Char]
binary_pp = Elf -> [Char]
pp_elf
    binary_entry :: Elf -> Word64
binary_entry = Elf -> Word64
elfEntry
    binary_text_section_size :: Elf -> Int
binary_text_section_size = Elf -> Int
elf_text_section_size