module Data.Dwarf.Reader where
import Control.Applicative ((<$>), pure)
import Data.Binary.Get (getWord16be, getWord32be, getWord64be, getWord16le, getWord32le, getWord64le, Get)
import qualified Data.Binary.Get as Get
import Data.Word (Word16, Word32, Word64)
import GHC.Generics (Generic)
import TextShow (TextShow(..))
import TextShow.Generic (genericShowbPrec)
data Endianess = LittleEndian | BigEndian
deriving (Eq, Ord, Read, Show, Generic)
instance TextShow Endianess where showbPrec = genericShowbPrec
data Encoding = Encoding32 | Encoding64
deriving (Eq, Ord, Read, Show, Generic)
instance TextShow Encoding where showbPrec = genericShowbPrec
data TargetSize = TargetSize32 | TargetSize64
deriving (Eq, Ord, Read, Show, Generic)
instance TextShow TargetSize where showbPrec = genericShowbPrec
endianReader :: Endianess -> EndianReader
endianReader LittleEndian = EndianReader LittleEndian getWord16le getWord32le getWord64le
endianReader BigEndian = EndianReader BigEndian getWord16be getWord32be getWord64be
endianSizeReader :: Encoding -> EndianReader -> EndianSizeReader
endianSizeReader Encoding64 der = EndianSizeReader der Encoding64 0xffffffffffffffff (derGetW64 der)
endianSizeReader Encoding32 der = EndianSizeReader der Encoding32 0xffffffff (fromIntegral <$> derGetW32 der)
reader :: TargetSize -> EndianSizeReader -> Reader
reader TargetSize64 desr = Reader desr TargetSize64 0xffffffffffffffff (desrGetW64 desr)
reader TargetSize32 desr = Reader desr TargetSize32 0xffffffff $ fromIntegral <$> desrGetW32 desr
desrGetW16 :: EndianSizeReader -> Get Word16
desrGetW16 = derGetW16 . desrEndianReader
desrGetW32 :: EndianSizeReader -> Get Word32
desrGetW32 = derGetW32 . desrEndianReader
desrGetW64 :: EndianSizeReader -> Get Word64
desrGetW64 = derGetW64 . desrEndianReader
drGetW16 :: Reader -> Get Word16
drGetW16 = desrGetW16 . drDesr
drGetW32 :: Reader -> Get Word32
drGetW32 = desrGetW32 . drDesr
drGetW64 :: Reader -> Get Word64
drGetW64 = desrGetW64 . drDesr
drGetOffset :: Reader -> Get Word64
drGetOffset = desrGetOffset . drDesr
drLargestOffset :: Reader -> Word64
drLargestOffset = desrLargestOffset . drDesr
data EndianReader = EndianReader
{ derEndianess :: Endianess
, derGetW16 :: Get Word16
, derGetW32 :: Get Word32
, derGetW64 :: Get Word64
}
data EndianSizeReader = EndianSizeReader
{ desrEndianReader :: EndianReader
, desrEncoding :: Encoding
, desrLargestOffset :: Word64
, desrGetOffset :: Get Word64
}
data Reader = Reader
{ drDesr :: EndianSizeReader
, drTarget64 :: TargetSize
, drLargestTargetAddress :: Word64
, drGetTargetAddress :: Get Word64
}
getUnitLength :: EndianReader -> Get (EndianSizeReader, Word64)
getUnitLength der = do
size <- derGetW32 der
if size == 0xffffffff then do
size64 <- derGetW64 der
pos <- Get.bytesRead
pure (endianSizeReader Encoding64 der, fromIntegral pos + size64)
else
if size < 0xffffff00 then do
pos <- Get.bytesRead
pure (endianSizeReader Encoding32 der, fromIntegral pos + fromIntegral size)
else
fail $ "Invalid DWARF size: " ++ show size