    {-
    -----------------------------------------------------------------------------
    --
    -- (c) The University of Glasgow 2015
    --
    -- ELF format tools
    --
    -----------------------------------------------------------------------------
    -}

    module GHC.SysTools.Elf (
        readElfSectionByName,
        readElfNoteAsString,
        makeElfNote
      ) where

    import GHC.Prelude

    import GHC.Utils.Asm
    import GHC.Utils.Exception
    import GHC.Platform
    import GHC.Utils.Error
    import GHC.Data.Maybe       (MaybeT(..),runMaybeT)
    import GHC.Utils.Misc       (charToC)
    import GHC.Utils.Outputable (text,hcat)
    import GHC.Utils.Logger

    import Control.Monad (when)
    import Data.Binary.Get
    import Data.Word
    import Data.Char (ord)
    import Data.ByteString.Lazy (ByteString)
    import qualified Data.ByteString.Lazy as LBS
    import qualified Data.ByteString.Lazy.Char8 as B8

    {- Note [ELF specification]
       ~~~~~~~~~~~~~~~~~~~~~~~~

       ELF (Executable and Linking Format) is described in the System V Application
       Binary Interface (or ABI). The latter is composed of two parts: a generic
       part and a processor specific part. The generic ABI describes the parts of
       the interface that remain constant across all hardware implementations of
       System V.

       The latest release of the specification of the generic ABI is the version
       4.1 from March 18, 1997:

         - http://www.sco.com/developers/devspecs/gabi41.pdf

       Since 1997, snapshots of the draft for the "next" version are published:

         - http://www.sco.com/developers/gabi/

       Quoting the notice on the website: "There is more than one instance of these
       chapters to permit references to older instances to remain valid. All
       modifications to these chapters are forward-compatible, so that correct use
       of an older specification will not be invalidated by a newer instance.
       Approximately on a yearly basis, a new instance will be saved, as it reaches
       what appears to be a stable state."

       Nevertheless we will see that since 1998 it is not true for Note sections.

       Many ELF sections
       -----------------

       ELF-4.1: the normal section number fields in ELF are limited to 16 bits,
       which runs out of bits when you try to cram in more sections than that. Two
       fields are concerned: the one containing the number of the sections and the
       one containing the index of the section that contains section's names. (The
       same thing applies to the field containing the number of segments, but we
       don't care about it here).

       ELF-next: to solve this, these fields in the ELF header have an escape
       value (different for each case), and the actual section number is stashed
       into unused fields in the first section header.

       We support this extension as it is forward-compatible with ELF-4.1.
       Moreover, GHC may generate objects with a lot of sections with the
       "function-sections" feature (one section per function).

       Note sections
       -------------

       Sections with type "note" (SHT_NOTE in the specification) are used to add
       arbitrary data into an ELF file. An entry in a note section is composed of a
       name, a type and a value.

       ELF-4.1: "The note information in sections and program header elements holds
       any number of entries, each of which is an array of 4-byte words in the
       format of the target processor." Each entry has the following format:
             | namesz |   Word32: size of the name string (including the ending \0)
             | descsz |   Word32: size of the value
             |  type  |   Word32: type of the note
             |  name  |   Name string (with \0 padding to ensure 4-byte alignment)
             |  ...   |
             |  desc  |   Value (with \0 padding to ensure 4-byte alignment)
             |  ...   |

       ELF-next: "The note information in sections and program header elements
       holds a variable amount of entries. In 64-bit objects (files with
       e_ident[EI_CLASS] equal to ELFCLASS64), each entry is an array of 8-byte
       words in the format of the target processor. In 32-bit objects (files with
       e_ident[EI_CLASS] equal to ELFCLASS32), each entry is an array of 4-byte
       words in the format of the target processor." (from 1998-2015 snapshots)

       This is not forward-compatible with ELF-4.1. In practice, for almost all
       platforms namesz, descz and type fields are 4-byte words for both 32-bit and
       64-bit objects (see elf.h and readelf source code).

       The only exception in readelf source code is for IA_64 machines with OpenVMS
       OS: "This OS has so many departures from the ELF standard that we test it at
       many places" (comment for is_ia64_vms() in readelf.c). In this case, namesz,
       descsz and type fields are 8-byte words and name and value fields are padded
       to ensure 8-byte alignment.

       We don't support this platform in the following code. Reading a note section
       could be done easily (by testing Machine and OS fields in the ELF header).
       Writing a note section, however, requires that we generate a different
       assembly code for GAS depending on the target platform and this is a little
       bit more involved.

    -}

    -- | ELF header
    --
    -- The ELF header indicates the native word size (32-bit or 64-bit) and the
    -- endianness of the target machine. We directly store getters for words of
    -- different sizes as it is more convenient to use. We also store the word size
    -- as it is useful to skip some uninteresting fields.
    --
    -- Other information such as the target machine and OS are left out as we don't
    -- use them yet. We could add them in the future if we ever need them.
    data ElfHeader = ElfHeader
       { ElfHeader -> Get Word16
    gw16     :: Get Word16   -- ^ Get a Word16 with the correct endianness
       , ElfHeader -> Get Word32
    gw32     :: Get Word32   -- ^ Get a Word32 with the correct endianness
       , ElfHeader -> Get Word64
    gwN      :: Get Word64   -- ^ Get a Word with the correct word size
                                  --   and endianness
       , ElfHeader -> Int
    wordSize :: Int          -- ^ Word size in bytes
       }

    -- | Read the ELF header
    readElfHeader :: Logger -> ByteString -> IO (Maybe ElfHeader)
    readElfHeader :: Logger -> ByteString -> IO (Maybe ElfHeader)
    readElfHeader Logger
    logger ByteString
    bs = Get (Maybe ElfHeader) -> ByteString -> IO (Maybe ElfHeader)
    forall a. Get a -> ByteString -> IO a
    runGetOrThrow Get (Maybe ElfHeader)
    getHeader ByteString
    bs IO (Maybe ElfHeader)
    -> (IOException -> IO (Maybe ElfHeader)) -> IO (Maybe ElfHeader)
    forall a. IO a -> (IOException -> IO a) -> IO a
    `catchIO` \IOException
    _ -> do
        Logger -> Int -> SDoc -> IO ()
    debugTraceMsg Logger
    logger Int
    3 (SDoc -> IO ()) -> SDoc -> IO ()
    forall a b. (a -> b) -> a -> b
    $
          String -> SDoc
    forall doc. IsLine doc => String -> doc
    text (String
    "Unable to read ELF header")
        Maybe ElfHeader -> IO (Maybe ElfHeader)
    forall a. a -> IO a
    forall (m :: * -> *) a. Monad m => a -> m a
    return Maybe ElfHeader
    forall a. Maybe a
    Nothing
      where
        getHeader :: Get (Maybe ElfHeader)
    getHeader = do
          Word32
    magic    <- Get Word32
    getWord32be
          Word8
    ws       <- Get Word8
    getWord8
          Word8
    endian   <- Get Word8
    getWord8
          Word8
    version  <- Get Word8
    getWord8
          Int -> Get ()
    skip Int
    9  -- skip OSABI, ABI version and padding
          Bool -> Get () -> Get ()
    forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
    when (Word32
    magic Word32 -> Word32 -> Bool
    forall a. Eq a => a -> a -> Bool
    /= Word32
    0x7F454C46 Bool -> Bool -> Bool
    || Word8
    version Word8 -> Word8 -> Bool
    forall a. Eq a => a -> a -> Bool
    /= Word8
    1) (Get () -> Get ()) -> Get () -> Get ()
    forall a b. (a -> b) -> a -> b
    $ String -> Get ()
    forall a. String -> Get a
    forall (m :: * -> *) a. MonadFail m => String -> m a
    fail String
    "Invalid ELF header"

          case (Word8
    ws, Word8
    endian) of
              -- ELF 32, little endian
              (Word8
    1,Word8
    1) -> Maybe ElfHeader -> Get (Maybe ElfHeader)
    forall a. a -> Get a
    forall (m :: * -> *) a. Monad m => a -> m a
    return (Maybe ElfHeader -> Get (Maybe ElfHeader))
    -> (ElfHeader -> Maybe ElfHeader)
    -> ElfHeader
    -> Get (Maybe ElfHeader)
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . ElfHeader -> Maybe ElfHeader
    forall a. a -> Maybe a
    Just (ElfHeader -> Get (Maybe ElfHeader))
    -> ElfHeader -> Get (Maybe ElfHeader)
    forall a b. (a -> b) -> a -> b
    $ Get Word16 -> Get Word32 -> Get Word64 -> Int -> ElfHeader
    ElfHeader
                               Get Word16
    getWord16le
                               Get Word32
    getWord32le
                               ((Word32 -> Word64) -> Get Word32 -> Get Word64
    forall a b. (a -> b) -> Get a -> Get b
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    fmap Word32 -> Word64
    forall a b. (Integral a, Num b) => a -> b
    fromIntegral Get Word32
    getWord32le) Int
    4
              -- ELF 32, big endian
              (Word8
    1,Word8
    2) -> Maybe ElfHeader -> Get (Maybe ElfHeader)
    forall a. a -> Get a
    forall (m :: * -> *) a. Monad m => a -> m a
    return (Maybe ElfHeader -> Get (Maybe ElfHeader))
    -> (ElfHeader -> Maybe ElfHeader)
    -> ElfHeader
    -> Get (Maybe ElfHeader)
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . ElfHeader -> Maybe ElfHeader
    forall a. a -> Maybe a
    Just (ElfHeader -> Get (Maybe ElfHeader))
    -> ElfHeader -> Get (Maybe ElfHeader)
    forall a b. (a -> b) -> a -> b
    $ Get Word16 -> Get Word32 -> Get Word64 -> Int -> ElfHeader
    ElfHeader
                               Get Word16
    getWord16be
                               Get Word32
    getWord32be
                               ((Word32 -> Word64) -> Get Word32 -> Get Word64
    forall a b. (a -> b) -> Get a -> Get b
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    fmap Word32 -> Word64
    forall a b. (Integral a, Num b) => a -> b
    fromIntegral Get Word32
    getWord32be) Int
    4
              -- ELF 64, little endian
              (Word8
    2,Word8
    1) -> Maybe ElfHeader -> Get (Maybe ElfHeader)
    forall a. a -> Get a
    forall (m :: * -> *) a. Monad m => a -> m a
    return (Maybe ElfHeader -> Get (Maybe ElfHeader))
    -> (ElfHeader -> Maybe ElfHeader)
    -> ElfHeader
    -> Get (Maybe ElfHeader)
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . ElfHeader -> Maybe ElfHeader
    forall a. a -> Maybe a
    Just (ElfHeader -> Get (Maybe ElfHeader))
    -> ElfHeader -> Get (Maybe ElfHeader)
    forall a b. (a -> b) -> a -> b
    $ Get Word16 -> Get Word32 -> Get Word64 -> Int -> ElfHeader
    ElfHeader
                               Get Word16
    getWord16le
                               Get Word32
    getWord32le
                               ((Word64 -> Word64) -> Get Word64 -> Get Word64
    forall a b. (a -> b) -> Get a -> Get b
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    fmap Word64 -> Word64
    forall a b. (Integral a, Num b) => a -> b
    fromIntegral Get Word64
    getWord64le) Int
    8
              -- ELF 64, big endian
              (Word8
    2,Word8
    2) -> Maybe ElfHeader -> Get (Maybe ElfHeader)
    forall a. a -> Get a
    forall (m :: * -> *) a. Monad m => a -> m a
    return (Maybe ElfHeader -> Get (Maybe ElfHeader))
    -> (ElfHeader -> Maybe ElfHeader)
    -> ElfHeader
    -> Get (Maybe ElfHeader)
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . ElfHeader -> Maybe ElfHeader
    forall a. a -> Maybe a
    Just (ElfHeader -> Get (Maybe ElfHeader))
    -> ElfHeader -> Get (Maybe ElfHeader)
    forall a b. (a -> b) -> a -> b
    $ Get Word16 -> Get Word32 -> Get Word64 -> Int -> ElfHeader
    ElfHeader
                               Get Word16
    getWord16be
                               Get Word32
    getWord32be
                               ((Word64 -> Word64) -> Get Word64 -> Get Word64
    forall a b. (a -> b) -> Get a -> Get b
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    fmap Word64 -> Word64
    forall a b. (Integral a, Num b) => a -> b
    fromIntegral Get Word64
    getWord64be) Int
    8
              (Word8, Word8)
    _     -> String -> Get (Maybe ElfHeader)
    forall a. String -> Get a
    forall (m :: * -> *) a. MonadFail m => String -> m a
    fail String
    "Invalid ELF header"

    ------------------
    -- SECTIONS
    ------------------

    -- | Description of the section table
    data SectionTable = SectionTable
      { SectionTable -> Word64
    sectionTableOffset :: Word64  -- ^ offset of the table describing sections
      , SectionTable -> Word16
    sectionEntrySize   :: Word16  -- ^ size of an entry in the section table
      , SectionTable -> Word64
    sectionEntryCount  :: Word64  -- ^ number of sections
      , SectionTable -> Word32
    sectionNameIndex   :: Word32  -- ^ index of a special section which
                                      --   contains section's names
      }

    -- | Read the ELF section table
    readElfSectionTable :: Logger
                        -> ElfHeader
                        -> ByteString
                        -> IO (Maybe SectionTable)

    readElfSectionTable :: Logger -> ElfHeader -> ByteString -> IO (Maybe SectionTable)
    readElfSectionTable Logger
    logger ElfHeader
    hdr ByteString
    bs = IO (Maybe SectionTable)
    action IO (Maybe SectionTable)
    -> (IOException -> IO (Maybe SectionTable))
    -> IO (Maybe SectionTable)
    forall a. IO a -> (IOException -> IO a) -> IO a
    `catchIO` \IOException
    _ -> do
        Logger -> Int -> SDoc -> IO ()
    debugTraceMsg Logger
    logger Int
    3 (SDoc -> IO ()) -> SDoc -> IO ()
    forall a b. (a -> b) -> a -> b
    $
          String -> SDoc
    forall doc. IsLine doc => String -> doc
    text (String
    "Unable to read ELF section table")
        Maybe SectionTable -> IO (Maybe SectionTable)
    forall a. a -> IO a
    forall (m :: * -> *) a. Monad m => a -> m a
    return Maybe SectionTable
    forall a. Maybe a
    Nothing
      where
        getSectionTable :: Get SectionTable
        getSectionTable :: Get SectionTable
    getSectionTable = do
          Int -> Get ()
    skip (Int
    24 Int -> Int -> Int
    forall a. Num a => a -> a -> a
    + Int
    2Int -> Int -> Int
    forall a. Num a => a -> a -> a
    *ElfHeader -> Int
    wordSize ElfHeader
    hdr) -- skip header and some other fields
          Word64
    secTableOffset <- ElfHeader -> Get Word64
    gwN ElfHeader
    hdr
          Int -> Get ()
    skip Int
    10
          Word16
    entrySize      <- ElfHeader -> Get Word16
    gw16 ElfHeader
    hdr
          Word16
    entryCount     <- ElfHeader -> Get Word16
    gw16 ElfHeader
    hdr
          Word16
    secNameIndex   <- ElfHeader -> Get Word16
    gw16 ElfHeader
    hdr
          SectionTable -> Get SectionTable
    forall a. a -> Get a
    forall (m :: * -> *) a. Monad m => a -> m a
    return (Word64 -> Word16 -> Word64 -> Word32 -> SectionTable
    SectionTable Word64
    secTableOffset Word16
    entrySize
                               (Word16 -> Word64
    forall a b. (Integral a, Num b) => a -> b
    fromIntegral Word16
    entryCount)
                               (Word16 -> Word32
    forall a b. (Integral a, Num b) => a -> b
    fromIntegral Word16
    secNameIndex))

        action :: IO (Maybe SectionTable)
    action = do
          SectionTable
    secTable <- Get SectionTable -> ByteString -> IO SectionTable
    forall a. Get a -> ByteString -> IO a
    runGetOrThrow Get SectionTable
    getSectionTable ByteString
    bs
          -- In some cases, the number of entries and the index of the section
          -- containing section's names must be found in unused fields of the first
          -- section entry (see Note [ELF specification])
          let
            offSize0 :: Int64
    offSize0 = Word64 -> Int64
    forall a b. (Integral a, Num b) => a -> b
    fromIntegral (Word64 -> Int64) -> Word64 -> Int64
    forall a b. (a -> b) -> a -> b
    $ SectionTable -> Word64
    sectionTableOffset SectionTable
    secTable Word64 -> Word64 -> Word64
    forall a. Num a => a -> a -> a
    + Word64
    8
                                      Word64 -> Word64 -> Word64
    forall a. Num a => a -> a -> a
    + Word64
    3 Word64 -> Word64 -> Word64
    forall a. Num a => a -> a -> a
    * Int -> Word64
    forall a b. (Integral a, Num b) => a -> b
    fromIntegral (ElfHeader -> Int
    wordSize ElfHeader
    hdr)
            offLink0 :: Int64
    offLink0 = Int64 -> Int64
    forall a b. (Integral a, Num b) => a -> b
    fromIntegral (Int64 -> Int64) -> Int64 -> Int64
    forall a b. (a -> b) -> a -> b
    $ Int64
    offSize0 Int64 -> Int64 -> Int64
    forall a. Num a => a -> a -> a
    + Int -> Int64
    forall a b. (Integral a, Num b) => a -> b
    fromIntegral (ElfHeader -> Int
    wordSize ElfHeader
    hdr)

          Word64
    entryCount'     <- if SectionTable -> Word64
    sectionEntryCount SectionTable
    secTable Word64 -> Word64 -> Bool
    forall a. Eq a => a -> a -> Bool
    /= Word64
    0
                              then Word64 -> IO Word64
    forall a. a -> IO a
    forall (m :: * -> *) a. Monad m => a -> m a
    return (SectionTable -> Word64
    sectionEntryCount SectionTable
    secTable)
                              else Get Word64 -> ByteString -> IO Word64
    forall a. Get a -> ByteString -> IO a
    runGetOrThrow (ElfHeader -> Get Word64
    gwN ElfHeader
    hdr) (Int64 -> ByteString -> ByteString
    LBS.drop Int64
    offSize0 ByteString
    bs)
          Word32
    entryNameIndex' <- if SectionTable -> Word32
    sectionNameIndex SectionTable
    secTable Word32 -> Word32 -> Bool
    forall a. Eq a => a -> a -> Bool
    /= Word32
    0xffff
                              then Word32 -> IO Word32
    forall a. a -> IO a
    forall (m :: * -> *) a. Monad m => a -> m a
    return (SectionTable -> Word32
    sectionNameIndex SectionTable
    secTable)
                              else Get Word32 -> ByteString -> IO Word32
    forall a. Get a -> ByteString -> IO a
    runGetOrThrow (ElfHeader -> Get Word32
    gw32 ElfHeader
    hdr) (Int64 -> ByteString -> ByteString
    LBS.drop Int64
    offLink0 ByteString
    bs)
          Maybe SectionTable -> IO (Maybe SectionTable)
    forall a. a -> IO a
    forall (m :: * -> *) a. Monad m => a -> m a
    return (SectionTable -> Maybe SectionTable
    forall a. a -> Maybe a
    Just (SectionTable -> Maybe SectionTable)
    -> SectionTable -> Maybe SectionTable
    forall a b. (a -> b) -> a -> b
    $ SectionTable
    secTable
            { sectionEntryCount = entryCount'
            , sectionNameIndex  = entryNameIndex'
            })

    -- | A section
    data Section = Section
      { Section -> ByteString
    entryName :: ByteString   -- ^ Name of the section
      , Section -> ByteString
    entryBS   :: ByteString   -- ^ Content of the section
      }

    -- | Read a ELF section
    readElfSectionByIndex :: Logger
                          -> ElfHeader
                          -> SectionTable
                          -> Word64
                          -> ByteString
                          -> IO (Maybe Section)

    readElfSectionByIndex :: Logger
    -> ElfHeader
    -> SectionTable
    -> Word64
    -> ByteString
    -> IO (Maybe Section)
    readElfSectionByIndex Logger
    logger ElfHeader
    hdr SectionTable
    secTable Word64
    i ByteString
    bs = IO (Maybe Section)
    action IO (Maybe Section)
    -> (IOException -> IO (Maybe Section)) -> IO (Maybe Section)
    forall a. IO a -> (IOException -> IO a) -> IO a
    `catchIO` \IOException
    _ -> do
        Logger -> Int -> SDoc -> IO ()
    debugTraceMsg Logger
    logger Int
    3 (SDoc -> IO ()) -> SDoc -> IO ()
    forall a b. (a -> b) -> a -> b
    $
          String -> SDoc
    forall doc. IsLine doc => String -> doc
    text (String
    "Unable to read ELF section")
        Maybe Section -> IO (Maybe Section)
    forall a. a -> IO a
    forall (m :: * -> *) a. Monad m => a -> m a
    return Maybe Section
    forall a. Maybe a
    Nothing
      where
        -- read an entry from the section table
        getEntry :: Get (Word32, ByteString)
    getEntry = do
          Word32
    nameIndex <- ElfHeader -> Get Word32
    gw32 ElfHeader
    hdr
          Int -> Get ()
    skip (Int
    4Int -> Int -> Int
    forall a. Num a => a -> a -> a
    +Int
    2Int -> Int -> Int
    forall a. Num a => a -> a -> a
    *ElfHeader -> Int
    wordSize ElfHeader
    hdr)
          Int64
    offset    <- (Word64 -> Int64) -> Get Word64 -> Get Int64
    forall a b. (a -> b) -> Get a -> Get b
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    fmap Word64 -> Int64
    forall a b. (Integral a, Num b) => a -> b
    fromIntegral (Get Word64 -> Get Int64) -> Get Word64 -> Get Int64
    forall a b. (a -> b) -> a -> b
    $ ElfHeader -> Get Word64
    gwN ElfHeader
    hdr
          Int64
    size      <- (Word64 -> Int64) -> Get Word64 -> Get Int64
    forall a b. (a -> b) -> Get a -> Get b
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    fmap Word64 -> Int64
    forall a b. (Integral a, Num b) => a -> b
    fromIntegral (Get Word64 -> Get Int64) -> Get Word64 -> Get Int64
    forall a b. (a -> b) -> a -> b
    $ ElfHeader -> Get Word64
    gwN ElfHeader
    hdr
          let bs' :: ByteString
    bs' = Int64 -> ByteString -> ByteString
    LBS.take Int64
    size (Int64 -> ByteString -> ByteString
    LBS.drop Int64
    offset ByteString
    bs)
          (Word32, ByteString) -> Get (Word32, ByteString)
    forall a. a -> Get a
    forall (m :: * -> *) a. Monad m => a -> m a
    return (Word32
    nameIndex,ByteString
    bs')

        -- read the entry with the given index in the section table
        getEntryByIndex :: Word64 -> IO (Word32, ByteString)
    getEntryByIndex Word64
    x = Get (Word32, ByteString) -> ByteString -> IO (Word32, ByteString)
    forall a. Get a -> ByteString -> IO a
    runGetOrThrow Get (Word32, ByteString)
    getEntry ByteString
    bs'
          where
            bs' :: ByteString
    bs' = Int64 -> ByteString -> ByteString
    LBS.drop Int64
    off ByteString
    bs
            off :: Int64
    off = Word64 -> Int64
    forall a b. (Integral a, Num b) => a -> b
    fromIntegral (Word64 -> Int64) -> Word64 -> Int64
    forall a b. (a -> b) -> a -> b
    $ SectionTable -> Word64
    sectionTableOffset SectionTable
    secTable Word64 -> Word64 -> Word64
    forall a. Num a => a -> a -> a
    +
                                 Word64
    x Word64 -> Word64 -> Word64
    forall a. Num a => a -> a -> a
    * Word16 -> Word64
    forall a b. (Integral a, Num b) => a -> b
    fromIntegral (SectionTable -> Word16
    sectionEntrySize SectionTable
    secTable)

        -- Get the name of a section
        getEntryName :: Int64 -> IO ByteString
    getEntryName Int64
    nameIndex = do
          let idx :: Word64
    idx = Word32 -> Word64
    forall a b. (Integral a, Num b) => a -> b
    fromIntegral (SectionTable -> Word32
    sectionNameIndex SectionTable
    secTable)
          (Word32
    _,ByteString
    nameTable) <- Word64 -> IO (Word32, ByteString)
    getEntryByIndex Word64
    idx
          let bs' :: ByteString
    bs' = Int64 -> ByteString -> ByteString
    LBS.drop Int64
    nameIndex ByteString
    nameTable
          Get ByteString -> ByteString -> IO ByteString
    forall a. Get a -> ByteString -> IO a
    runGetOrThrow Get ByteString
    getLazyByteStringNul ByteString
    bs'

        action :: IO (Maybe Section)
    action = do
          (Word32
    nameIndex,ByteString
    bs') <- Word64 -> IO (Word32, ByteString)
    getEntryByIndex (Word64 -> Word64
    forall a b. (Integral a, Num b) => a -> b
    fromIntegral Word64
    i)
          ByteString
    name            <- Int64 -> IO ByteString
    getEntryName (Word32 -> Int64
    forall a b. (Integral a, Num b) => a -> b
    fromIntegral Word32
    nameIndex)
          Maybe Section -> IO (Maybe Section)
    forall a. a -> IO a
    forall (m :: * -> *) a. Monad m => a -> m a
    return (Section -> Maybe Section
    forall a. a -> Maybe a
    Just (Section -> Maybe Section) -> Section -> Maybe Section
    forall a b. (a -> b) -> a -> b
    $ ByteString -> ByteString -> Section
    Section ByteString
    name ByteString
    bs')

    -- | Find a section from its name. Return the section contents.
    --
    -- We do not perform any check on the section type.
    findSectionFromName :: Logger
                        -> ElfHeader
                        -> SectionTable
                        -> String
                        -> ByteString
                        -> IO (Maybe ByteString)
    findSectionFromName :: Logger
    -> ElfHeader
    -> SectionTable
    -> String
    -> ByteString
    -> IO (Maybe ByteString)
    findSectionFromName Logger
    logger ElfHeader
    hdr SectionTable
    secTable String
    name ByteString
    bs =
        [Word64] -> IO (Maybe ByteString)
    rec [Word64
    0..SectionTable -> Word64
    sectionEntryCount SectionTable
    secTable Word64 -> Word64 -> Word64
    forall a. Num a => a -> a -> a
    - Word64
    1]
      where
        -- convert the required section name into a ByteString to perform
        -- ByteString comparison instead of String comparison
        name' :: ByteString
    name' = String -> ByteString
    B8.pack String
    name

        -- compare recursively each section name and return the contents of
        -- the matching one, if any
        rec :: [Word64] -> IO (Maybe ByteString)
    rec []     = Maybe ByteString -> IO (Maybe ByteString)
    forall a. a -> IO a
    forall (m :: * -> *) a. Monad m => a -> m a
    return Maybe ByteString
    forall a. Maybe a
    Nothing
        rec (Word64
    x:[Word64]
    xs) = do
          Maybe Section
    me <- Logger
    -> ElfHeader
    -> SectionTable
    -> Word64
    -> ByteString
    -> IO (Maybe Section)
    readElfSectionByIndex Logger
    logger ElfHeader
    hdr SectionTable
    secTable Word64
    x ByteString
    bs
          case Maybe Section
    me of
            Just Section
    e | Section -> ByteString
    entryName Section
    e ByteString -> ByteString -> Bool
    forall a. Eq a => a -> a -> Bool
    == ByteString
    name' -> Maybe ByteString -> IO (Maybe ByteString)
    forall a. a -> IO a
    forall (m :: * -> *) a. Monad m => a -> m a
    return (ByteString -> Maybe ByteString
    forall a. a -> Maybe a
    Just (Section -> ByteString
    entryBS Section
    e))
            Maybe Section
    _                             -> [Word64] -> IO (Maybe ByteString)
    rec [Word64]
    xs

    -- | Given a section name, read its contents as a ByteString.
    --
    -- If the section isn't found or if there is any parsing error, we return
    -- Nothing
    readElfSectionByName :: Logger
                         -> ByteString
                         -> String
                         -> IO (Maybe LBS.ByteString)

    readElfSectionByName :: Logger -> ByteString -> String -> IO (Maybe ByteString)
    readElfSectionByName Logger
    logger ByteString
    bs String
    name = IO (Maybe ByteString)
    action IO (Maybe ByteString)
    -> (IOException -> IO (Maybe ByteString)) -> IO (Maybe ByteString)
    forall a. IO a -> (IOException -> IO a) -> IO a
    `catchIO` \IOException
    _ -> do
        Logger -> Int -> SDoc -> IO ()
    debugTraceMsg Logger
    logger Int
    3 (SDoc -> IO ()) -> SDoc -> IO ()
    forall a b. (a -> b) -> a -> b
    $
          String -> SDoc
    forall doc. IsLine doc => String -> doc
    text (String
    "Unable to read ELF section \"" String -> String -> String
    forall a. [a] -> [a] -> [a]
    ++ String
    name String -> String -> String
    forall a. [a] -> [a] -> [a]
    ++ String
    "\"")
        Maybe ByteString -> IO (Maybe ByteString)
    forall a. a -> IO a
    forall (m :: * -> *) a. Monad m => a -> m a
    return Maybe ByteString
    forall a. Maybe a
    Nothing
      where
        action :: IO (Maybe ByteString)
    action = MaybeT IO ByteString -> IO (Maybe ByteString)
    forall (m :: * -> *) a. MaybeT m a -> m (Maybe a)
    runMaybeT (MaybeT IO ByteString -> IO (Maybe ByteString))
    -> MaybeT IO ByteString -> IO (Maybe ByteString)
    forall a b. (a -> b) -> a -> b
    $ do
          ElfHeader
    hdr      <- IO (Maybe ElfHeader) -> MaybeT IO ElfHeader
    forall (m :: * -> *) a. m (Maybe a) -> MaybeT m a
    MaybeT (IO (Maybe ElfHeader) -> MaybeT IO ElfHeader)
    -> IO (Maybe ElfHeader) -> MaybeT IO ElfHeader
    forall a b. (a -> b) -> a -> b
    $ Logger -> ByteString -> IO (Maybe ElfHeader)
    readElfHeader Logger
    logger ByteString
    bs
          SectionTable
    secTable <- IO (Maybe SectionTable) -> MaybeT IO SectionTable
    forall (m :: * -> *) a. m (Maybe a) -> MaybeT m a
    MaybeT (IO (Maybe SectionTable) -> MaybeT IO SectionTable)
    -> IO (Maybe SectionTable) -> MaybeT IO SectionTable
    forall a b. (a -> b) -> a -> b
    $ Logger -> ElfHeader -> ByteString -> IO (Maybe SectionTable)
    readElfSectionTable Logger
    logger ElfHeader
    hdr ByteString
    bs
          IO (Maybe ByteString) -> MaybeT IO ByteString
    forall (m :: * -> *) a. m (Maybe a) -> MaybeT m a
    MaybeT (IO (Maybe ByteString) -> MaybeT IO ByteString)
    -> IO (Maybe ByteString) -> MaybeT IO ByteString
    forall a b. (a -> b) -> a -> b
    $ Logger
    -> ElfHeader
    -> SectionTable
    -> String
    -> ByteString
    -> IO (Maybe ByteString)
    findSectionFromName Logger
    logger ElfHeader
    hdr SectionTable
    secTable String
    name ByteString
    bs

    ------------------
    -- NOTE SECTIONS
    ------------------

    -- | read a Note as a ByteString
    --
    -- If you try to read a note from a section which does not support the Note
    -- format, the parsing is likely to fail and Nothing will be returned
    readElfNoteBS :: Logger
                  -> ByteString
                  -> String
                  -> String
                  -> IO (Maybe LBS.ByteString)

    readElfNoteBS :: Logger -> ByteString -> String -> String -> IO (Maybe ByteString)
    readElfNoteBS Logger
    logger ByteString
    bs String
    sectionName String
    noteId = IO (Maybe ByteString)
    action IO (Maybe ByteString)
    -> (IOException -> IO (Maybe ByteString)) -> IO (Maybe ByteString)
    forall a. IO a -> (IOException -> IO a) -> IO a
    `catchIO`  \IOException
    _ -> do
        Logger -> Int -> SDoc -> IO ()
    debugTraceMsg Logger
    logger Int
    3 (SDoc -> IO ()) -> SDoc -> IO ()
    forall a b. (a -> b) -> a -> b
    $
             String -> SDoc
    forall doc. IsLine doc => String -> doc
    text (String
    "Unable to read ELF note \"" String -> String -> String
    forall a. [a] -> [a] -> [a]
    ++ String
    noteId String -> String -> String
    forall a. [a] -> [a] -> [a]
    ++
                   String
    "\" in section \"" String -> String -> String
    forall a. [a] -> [a] -> [a]
    ++ String
    sectionName String -> String -> String
    forall a. [a] -> [a] -> [a]
    ++ String
    "\"")
        Maybe ByteString -> IO (Maybe ByteString)
    forall a. a -> IO a
    forall (m :: * -> *) a. Monad m => a -> m a
    return Maybe ByteString
    forall a. Maybe a
    Nothing
      where
        -- align the getter on n bytes
        align :: Int64 -> Get ()
    align Int64
    n = do
          Int64
    m <- Get Int64
    bytesRead
          if Int64
    m Int64 -> Int64 -> Int64
    forall a. Integral a => a -> a -> a
    `mod` Int64
    n Int64 -> Int64 -> Bool
    forall a. Eq a => a -> a -> Bool
    == Int64
    0
            then () -> Get ()
    forall a. a -> Get a
    forall (m :: * -> *) a. Monad m => a -> m a
    return ()
            else Int -> Get ()
    skip Int
    1 Get () -> Get () -> Get ()
    forall a b. Get a -> Get b -> Get b
    forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
    >> Int64 -> Get ()
    align Int64
    n

        -- noteId as a bytestring
        noteId' :: ByteString
    noteId' = String -> ByteString
    B8.pack String
    noteId

        -- read notes recursively until the one with a valid identifier is found
        findNote :: ElfHeader -> Get (Maybe ByteString)
    findNote ElfHeader
    hdr = do
          Int64 -> Get ()
    align Int64
    4
          Word32
    namesz <- ElfHeader -> Get Word32
    gw32 ElfHeader
    hdr
          Word32
    descsz <- ElfHeader -> Get Word32
    gw32 ElfHeader
    hdr
          Word32
    _      <- ElfHeader -> Get Word32
    gw32 ElfHeader
    hdr -- we don't use the note type
          ByteString
    name   <- if Word32
    namesz Word32 -> Word32 -> Bool
    forall a. Eq a => a -> a -> Bool
    == Word32
    0
                      then ByteString -> Get ByteString
    forall a. a -> Get a
    forall (m :: * -> *) a. Monad m => a -> m a
    return ByteString
    LBS.empty
                      else Get ByteString
    getLazyByteStringNul
          Int64 -> Get ()
    align Int64
    4
          ByteString
    desc  <- if Word32
    descsz Word32 -> Word32 -> Bool
    forall a. Eq a => a -> a -> Bool
    == Word32
    0
                      then ByteString -> Get ByteString
    forall a. a -> Get a
    forall (m :: * -> *) a. Monad m => a -> m a
    return ByteString
    LBS.empty
                      else Int64 -> Get ByteString
    getLazyByteString (Word32 -> Int64
    forall a b. (Integral a, Num b) => a -> b
    fromIntegral Word32
    descsz)
          if ByteString
    name ByteString -> ByteString -> Bool
    forall a. Eq a => a -> a -> Bool
    == ByteString
    noteId'
            then Maybe ByteString -> Get (Maybe ByteString)
    forall a. a -> Get a
    forall (m :: * -> *) a. Monad m => a -> m a
    return (Maybe ByteString -> Get (Maybe ByteString))
    -> Maybe ByteString -> Get (Maybe ByteString)
    forall a b. (a -> b) -> a -> b
    $ ByteString -> Maybe ByteString
    forall a. a -> Maybe a
    Just ByteString
    desc
            else ElfHeader -> Get (Maybe ByteString)
    findNote ElfHeader
    hdr

        action :: IO (Maybe ByteString)
    action = MaybeT IO ByteString -> IO (Maybe ByteString)
    forall (m :: * -> *) a. MaybeT m a -> m (Maybe a)
    runMaybeT (MaybeT IO ByteString -> IO (Maybe ByteString))
    -> MaybeT IO ByteString -> IO (Maybe ByteString)
    forall a b. (a -> b) -> a -> b
    $ do
          ElfHeader
    hdr  <- IO (Maybe ElfHeader) -> MaybeT IO ElfHeader
    forall (m :: * -> *) a. m (Maybe a) -> MaybeT m a
    MaybeT (IO (Maybe ElfHeader) -> MaybeT IO ElfHeader)
    -> IO (Maybe ElfHeader) -> MaybeT IO ElfHeader
    forall a b. (a -> b) -> a -> b
    $ Logger -> ByteString -> IO (Maybe ElfHeader)
    readElfHeader Logger
    logger ByteString
    bs
          ByteString
    sec  <- IO (Maybe ByteString) -> MaybeT IO ByteString
    forall (m :: * -> *) a. m (Maybe a) -> MaybeT m a
    MaybeT (IO (Maybe ByteString) -> MaybeT IO ByteString)
    -> IO (Maybe ByteString) -> MaybeT IO ByteString
    forall a b. (a -> b) -> a -> b
    $ Logger -> ByteString -> String -> IO (Maybe ByteString)
    readElfSectionByName Logger
    logger ByteString
    bs String
    sectionName
          IO (Maybe ByteString) -> MaybeT IO ByteString
    forall (m :: * -> *) a. m (Maybe a) -> MaybeT m a
    MaybeT (IO (Maybe ByteString) -> MaybeT IO ByteString)
    -> IO (Maybe ByteString) -> MaybeT IO ByteString
    forall a b. (a -> b) -> a -> b
    $ Get (Maybe ByteString) -> ByteString -> IO (Maybe ByteString)
    forall a. Get a -> ByteString -> IO a
    runGetOrThrow (ElfHeader -> Get (Maybe ByteString)
    findNote ElfHeader
    hdr) ByteString
    sec

    -- | read a Note as a String
    --
    -- If you try to read a note from a section which does not support the Note
    -- format, the parsing is likely to fail and Nothing will be returned
    readElfNoteAsString :: Logger
                        -> FilePath
                        -> String
                        -> String
                        -> IO (Maybe String)

    readElfNoteAsString :: Logger -> String -> String -> String -> IO (Maybe String)
    readElfNoteAsString Logger
    logger String
    path String
    sectionName String
    noteId = IO (Maybe String)
    action IO (Maybe String)
    -> (IOException -> IO (Maybe String)) -> IO (Maybe String)
    forall a. IO a -> (IOException -> IO a) -> IO a
    `catchIO`  \IOException
    _ -> do
        Logger -> Int -> SDoc -> IO ()
    debugTraceMsg Logger
    logger Int
    3 (SDoc -> IO ()) -> SDoc -> IO ()
    forall a b. (a -> b) -> a -> b
    $
             String -> SDoc
    forall doc. IsLine doc => String -> doc
    text (String
    "Unable to read ELF note \"" String -> String -> String
    forall a. [a] -> [a] -> [a]
    ++ String
    noteId String -> String -> String
    forall a. [a] -> [a] -> [a]
    ++
                   String
    "\" in section \"" String -> String -> String
    forall a. [a] -> [a] -> [a]
    ++ String
    sectionName String -> String -> String
    forall a. [a] -> [a] -> [a]
    ++ String
    "\"")
        Maybe String -> IO (Maybe String)
    forall a. a -> IO a
    forall (m :: * -> *) a. Monad m => a -> m a
    return Maybe String
    forall a. Maybe a
    Nothing
      where
        action :: IO (Maybe String)
    action = do
          ByteString
    bs   <- String -> IO ByteString
    LBS.readFile String
    path
          Maybe ByteString
    note <- Logger -> ByteString -> String -> String -> IO (Maybe ByteString)
    readElfNoteBS Logger
    logger ByteString
    bs String
    sectionName String
    noteId
          Maybe String -> IO (Maybe String)
    forall a. a -> IO a
    forall (m :: * -> *) a. Monad m => a -> m a
    return ((ByteString -> String) -> Maybe ByteString -> Maybe String
    forall a b. (a -> b) -> Maybe a -> Maybe b
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    fmap ByteString -> String
    B8.unpack Maybe ByteString
    note)

    -- | Generate the GAS code to create a Note section
    --
    -- Header fields for notes are 32-bit long (see Note [ELF specification]).
    makeElfNote :: Platform -> String -> String -> Word32 -> String -> SDoc
    makeElfNote :: Platform -> String -> String -> Word32 -> String -> SDoc
    makeElfNote Platform
    platform String
    sectionName String
    noteName Word32
    typ String
    contents = [SDoc] -> SDoc
    forall doc. IsLine doc => [doc] -> doc
    hcat [
        String -> SDoc
    forall doc. IsLine doc => String -> doc
    text String
    "\t.section ",
        String -> SDoc
    forall doc. IsLine doc => String -> doc
    text String
    sectionName,
        String -> SDoc
    forall doc. IsLine doc => String -> doc
    text String
    ",\"\",",
        Platform -> String -> SDoc
    forall doc. IsLine doc => Platform -> String -> doc
    sectionType Platform
    platform String
    "note",
        String -> SDoc
    forall doc. IsLine doc => String -> doc
    text String
    "\n",
        String -> SDoc
    forall doc. IsLine doc => String -> doc
    text String
    "\t.balign 4\n",

        -- note name length (+ 1 for ending \0)
        Int -> SDoc
    forall a. Show a => a -> SDoc
    asWord32 (String -> Int
    forall a. [a] -> Int
    forall (t :: * -> *) a. Foldable t => t a -> Int
    length String
    noteName Int -> Int -> Int
    forall a. Num a => a -> a -> a
    + Int
    1),

        -- note contents size
        Int -> SDoc
    forall a. Show a => a -> SDoc
    asWord32 (String -> Int
    forall a. [a] -> Int
    forall (t :: * -> *) a. Foldable t => t a -> Int
    length String
    contents),

        -- note type
        Word32 -> SDoc
    forall a. Show a => a -> SDoc
    asWord32 Word32
    typ,

        -- note name (.asciz for \0 ending string) + padding
        String -> SDoc
    forall doc. IsLine doc => String -> doc
    text String
    "\t.asciz \"",
        String -> SDoc
    forall doc. IsLine doc => String -> doc
    text String
    noteName,
        String -> SDoc
    forall doc. IsLine doc => String -> doc
    text String
    "\"\n",
        String -> SDoc
    forall doc. IsLine doc => String -> doc
    text String
    "\t.balign 4\n",

        -- note contents (.ascii to avoid ending \0) + padding
        String -> SDoc
    forall doc. IsLine doc => String -> doc
    text String
    "\t.ascii \"",
        String -> SDoc
    forall doc. IsLine doc => String -> doc
    text (String -> String
    escape String
    contents),
        String -> SDoc
    forall doc. IsLine doc => String -> doc
    text String
    "\"\n",
        String -> SDoc
    forall doc. IsLine doc => String -> doc
    text String
    "\t.balign 4\n"]
      where
        escape :: String -> String
        escape :: String -> String
    escape = (Char -> String) -> String -> String
    forall (t :: * -> *) a b. Foldable t => (a -> [b]) -> t a -> [b]
    concatMap (Word8 -> String
    charToC(Word8 -> String) -> (Char -> Word8) -> Char -> String
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    .Int -> Word8
    forall a b. (Integral a, Num b) => a -> b
    fromIntegral(Int -> Word8) -> (Char -> Int) -> Char -> Word8
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    .Char -> Int
    ord)

        asWord32 :: Show a => a -> SDoc
        asWord32 :: forall a. Show a => a -> SDoc
    asWord32 a
    x = [SDoc] -> SDoc
    forall doc. IsLine doc => [doc] -> doc
    hcat [
          String -> SDoc
    forall doc. IsLine doc => String -> doc
    text String
    "\t.4byte ",
          String -> SDoc
    forall doc. IsLine doc => String -> doc
    text (a -> String
    forall a. Show a => a -> String
    show a
    x),
          String -> SDoc
    forall doc. IsLine doc => String -> doc
    text String
    "\n"]

    ------------------
    -- Helpers
    ------------------

    -- | runGet in IO monad that throws an IOException on failure
    runGetOrThrow :: Get a -> LBS.ByteString -> IO a
    runGetOrThrow :: forall a. Get a -> ByteString -> IO a
    runGetOrThrow Get a
    g ByteString
    bs = case Get a
    -> ByteString
    -> Either (ByteString, Int64, String) (ByteString, Int64, a)
    forall a.
    Get a
    -> ByteString
    -> Either (ByteString, Int64, String) (ByteString, Int64, a)
    runGetOrFail Get a
    g ByteString
    bs of
      Left (ByteString, Int64, String)
    _        -> String -> IO a
    forall a. String -> IO a
    forall (m :: * -> *) a. MonadFail m => String -> m a
    fail String
    "Error while reading file"
      Right (ByteString
    _,Int64
    _,a
    a) -> a -> IO a
    forall a. a -> IO a
    forall (m :: * -> *) a. Monad m => a -> m a
    return a
    a