module Data.Dwarf.CFA where
import Control.Applicative (Applicative(..))
import Data.Binary.Get (getWord8, Get)
import Data.Bits (shiftR, (.&.))
import qualified Data.ByteString as B
import Data.Dwarf.Reader
import Data.Dwarf.Utils
import Data.Int (Int64)
import Data.Word (Word8, Word16, Word32, Word64)
import GHC.Generics (Generic)
import TextShow (TextShow(..))
import TextShow.Generic (genericShowbPrec)
data DW_CFA
= DW_CFA_advance_loc Word8
| DW_CFA_offset Word8 Word64
| DW_CFA_restore Word8
| DW_CFA_nop
| DW_CFA_set_loc Word64
| DW_CFA_advance_loc1 Word8
| DW_CFA_advance_loc2 Word16
| DW_CFA_advance_loc4 Word32
| DW_CFA_offset_extended Word64 Word64
| DW_CFA_restore_extended Word64
| DW_CFA_undefined Word64
| DW_CFA_same_value Word64
| DW_CFA_register Word64 Word64
| DW_CFA_remember_state
| DW_CFA_restore_state
| DW_CFA_def_cfa Word64 Word64
| DW_CFA_def_cfa_register Word64
| DW_CFA_def_cfa_offset Word64
| DW_CFA_def_cfa_expression B.ByteString
| DW_CFA_expression Word64 B.ByteString
| DW_CFA_offset_extended_sf Word64 Int64
| DW_CFA_def_cfa_sf Word64 Int64
| DW_CFA_def_cfa_offset_sf Int64
| DW_CFA_val_offset Word64 Word64
| DW_CFA_val_offset_sf Word64 Int64
| DW_CFA_val_expression Word64 B.ByteString
deriving (Eq, Ord, Read, Show, Generic)
instance TextShow DW_CFA where showbPrec = genericShowbPrec
getDW_CFA :: Reader -> Get DW_CFA
getDW_CFA dr = do
tag <- getWord8
case tag `shiftR` 6 of
0x1 -> pure $ DW_CFA_advance_loc $ tag .&. 0x3f
0x2 -> pure (DW_CFA_offset (tag .&. 0x3f)) <*> getULEB128
0x3 -> pure $ DW_CFA_restore $ tag .&. 0x3f
0x0 -> case tag .&. 0x3f of
0x00 -> pure DW_CFA_nop
0x01 -> pure DW_CFA_set_loc <*> drGetTargetAddress dr
0x02 -> pure DW_CFA_advance_loc1 <*> getWord8
0x03 -> pure DW_CFA_advance_loc2 <*> drGetW16 dr
0x04 -> pure DW_CFA_advance_loc4 <*> drGetW32 dr
0x05 -> pure DW_CFA_offset_extended <*> getULEB128 <*> getULEB128
0x06 -> pure DW_CFA_restore_extended <*> getULEB128
0x07 -> pure DW_CFA_undefined <*> getULEB128
0x08 -> pure DW_CFA_same_value <*> getULEB128
0x09 -> pure DW_CFA_register <*> getULEB128 <*> getULEB128
0x0a -> pure DW_CFA_remember_state
0x0b -> pure DW_CFA_restore_state
0x0c -> pure DW_CFA_def_cfa <*> getULEB128 <*> getULEB128
0x0d -> pure DW_CFA_def_cfa_register <*> getULEB128
0x0e -> pure DW_CFA_def_cfa_offset <*> getULEB128
0x0f -> pure DW_CFA_def_cfa_expression <*> getByteStringLen getULEB128
0x10 -> pure DW_CFA_expression <*> getULEB128 <*> getByteStringLen getULEB128
0x11 -> pure DW_CFA_offset_extended_sf <*> getULEB128 <*> getSLEB128
0x12 -> pure DW_CFA_def_cfa_sf <*> getULEB128 <*> getSLEB128
0x13 -> pure DW_CFA_def_cfa_offset_sf <*> getSLEB128
0x14 -> pure DW_CFA_val_offset <*> getULEB128 <*> getULEB128
0x15 -> pure DW_CFA_val_offset_sf <*> getULEB128 <*> getSLEB128
0x16 -> pure DW_CFA_val_expression <*> getULEB128 <*> getByteStringLen getULEB128
_ -> fail $ "Invalid tag: " ++ show tag
_ -> fail $ "Invalid tag: " ++ show tag