{-# LANGUAGE OverloadedStrings #-}
module Data.Dwarf.Elf
  ( loadElfDwarf
  , elfSectionByName
  , parseElfDwarfADT
  ) where

import           Control.Applicative (Applicative(..), (<$>))
import qualified Data.ByteString as BS
import qualified Data.Dwarf as Dwarf
import           Data.Dwarf.ADT (Dwarf)
import qualified Data.Dwarf.ADT as Dwarf.ADT
import           Data.Elf (parseElf, Elf(..), ElfSection(..))
import           Data.List (find)
import           Data.Monoid ((<>))
import           Data.Text (Text)
import qualified Data.Text as Text
import           System.IO.Posix.MMap (unsafeMMapFile)

elfSectionByName :: Elf -> Text -> Either Text BS.ByteString
elfSectionByName elf name =
  maybe (Left ("Missing section " <> name)) Right .
  fmap elfSectionData .
  find ((== name) . Text.pack . elfSectionName) $ elfSections elf

loadElfDwarf :: Dwarf.Endianess -> FilePath -> IO (Elf, ([Dwarf.DIE], Dwarf.DIEMap))
loadElfDwarf endianess filename = do
  bs <- unsafeMMapFile filename
  let elf = parseElf bs
      get = elfSectionByName elf
  sections <-
    either (fail . Text.unpack) return $
    Dwarf.Sections
    <$> get ".debug_info"
    <*> get ".debug_abbrev"
    <*> get ".debug_str"
  pure (elf, Dwarf.parseInfo endianess sections)

parseElfDwarfADT :: Dwarf.Endianess -> FilePath -> IO (Dwarf, [Dwarf.ADT.Warning])
parseElfDwarfADT endianess filename = do
  (_elf, (cuDies, dieMap)) <- loadElfDwarf endianess filename
  pure $ Dwarf.ADT.fromDies dieMap cuDies