-- {-# LANGUAGE  #-}


module Binary.Read where

import Binary.Generic
import Binary.Elf
import Binary.Macho

import qualified Data.ByteString as BS
import System.Directory (doesFileExist)

-- | Reading a binary given a filename (ELF or MachO)
read_binary :: String -> String -> IO (Maybe Binary)
read_binary :: String -> String -> IO (Maybe Binary)
read_binary String
dirname String
name = do
  let filename :: String
filename = String
dirname String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
name
  Bool
exists <- String -> IO Bool
doesFileExist String
filename
  if Bool
exists then do
    -- if the original binary is given, we now assume it its an ELF
    ByteString
content <-  String -> IO ByteString
BS.readFile String
filename
    if (ByteString -> [Word8]
BS.unpack (ByteString -> [Word8]) -> ByteString -> [Word8]
forall a b. (a -> b) -> a -> b
$ Int -> ByteString -> ByteString
BS.take Int
4 ByteString
content) [Word8] -> [Word8] -> Bool
forall a. Eq a => a -> a -> Bool
== [Word8
0x7f, Word8
0x45, Word8
0x4C, Word8
0x46] then do
      let elf :: Elf
elf = ByteString -> Elf
elf_read_file ByteString
content
      Maybe Binary -> IO (Maybe Binary)
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return (Maybe Binary -> IO (Maybe Binary))
-> Maybe Binary -> IO (Maybe Binary)
forall a b. (a -> b) -> a -> b
$ Binary -> Maybe Binary
forall a. a -> Maybe a
Just (Binary -> Maybe Binary) -> Binary -> Maybe Binary
forall a b. (a -> b) -> a -> b
$ NamedElf -> Binary
forall b. BinaryClass b => b -> Binary
Binary (NamedElf -> Binary) -> NamedElf -> Binary
forall a b. (a -> b) -> a -> b
$ Elf
-> String
-> String
-> SectionsInfo
-> SymbolTable
-> Set Relocation
-> NamedElf
NamedElf Elf
elf String
dirname String
name (Elf -> SectionsInfo
elf_get_sections_info Elf
elf) (Elf -> SymbolTable
elf_get_symbol_table Elf
elf) (Elf -> Set Relocation
elf_get_relocs Elf
elf)
    else
      Maybe Binary -> IO (Maybe Binary)
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return Maybe Binary
forall a. Maybe a
Nothing
  else do
    -- otherwise, see if the binary is contained in the following files (MachO)
    Bool
exists1 <- String -> IO Bool
doesFileExist (String
filename String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
".dump")
    Bool
exists2 <- String -> IO Bool
doesFileExist (String
filename String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
".data")
    Bool
exists3 <- String -> IO Bool
doesFileExist (String
filename String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
".sections")
    Bool
exists4 <- String -> IO Bool
doesFileExist (String
filename String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
".symbols")
    Bool
exists5 <- String -> IO Bool
doesFileExist (String
filename String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
".entry")
    if [Bool] -> Bool
forall (t :: * -> *). Foldable t => t Bool -> Bool
and [Bool
exists1,Bool
exists2,Bool
exists3,Bool
exists4,Bool
exists5] then do
      Macho
macho <- String -> String -> IO Macho
macho_read_file String
dirname String
name
      Maybe Binary -> IO (Maybe Binary)
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return (Maybe Binary -> IO (Maybe Binary))
-> Maybe Binary -> IO (Maybe Binary)
forall a b. (a -> b) -> a -> b
$ Binary -> Maybe Binary
forall a. a -> Maybe a
Just (Binary -> Maybe Binary) -> Binary -> Maybe Binary
forall a b. (a -> b) -> a -> b
$ Macho -> Binary
forall b. BinaryClass b => b -> Binary
Binary (Macho -> Binary) -> Macho -> Binary
forall a b. (a -> b) -> a -> b
$ Macho
macho
    else
      Maybe Binary -> IO (Maybe Binary)
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return Maybe Binary
forall a. Maybe a
Nothing