module Data.Dwarf.Elf
  ( loadElfDwarf
  , elfSectionByName
  , parseElfDwarfADT
  ) where

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

elfSectionByName :: Elf -> String -> Either String BS.ByteString
elfSectionByName elf name =
  maybe (Left ("Missing section " ++ name)) Right .
  fmap elfSectionData .
  find ((== name) . 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 return $
    Dwarf.Sections
    <$> get ".debug_info"
    <*> get ".debug_abbrev"
    <*> get ".debug_str"
  pure (elf, Dwarf.parseInfo endianess sections)

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