    {-# INCLUDE "windows.h" #-}
    {-# LINE 1 "System\Win32\DebugApi.hsc" #-}
    -----------------------------------------------------------------------------
    {-# LINE 2 "System\Win32\DebugApi.hsc" #-}
    -- |
    -- Module      :  System.Win32.DebugApi
    -- Copyright   :  (c) Esa Ilari Vuokko, 2006
    -- License     :  BSD-style (see the file LICENSE)
    --
    -- Maintainer  :  Esa Ilari Vuokko <ei@vuokko.info>
    -- Stability   :  provisional
    -- Portability :  portable
    --
    -- A collection of FFI declarations for using Windows DebugApi.
    --
    -----------------------------------------------------------------------------
    module System.Win32.DebugApi where

    import Control.Exception( bracket_ )
    import Data.Word        ( Word8, Word32 )
    import Foreign          ( Ptr, nullPtr, ForeignPtr, mallocForeignPtrBytes
                            , peekByteOff, plusPtr, allocaBytes, castPtr, poke
                            , withForeignPtr, Storable, sizeOf, peek, pokeByteOff )
    import System.IO        ( fixIO )
    import System.Win32.Types   ( HANDLE, BOOL, WORD, DWORD, failIf_, failWith
                                , getLastError, failIf, LPTSTR, withTString )

    {-# LINE 26 "System\Win32\DebugApi.hsc" #-}

    type PID = DWORD
    type TID = DWORD
    type DebugEventId = (PID, TID)
    type ForeignAddress = Word32

    type PHANDLE = Ptr ()
    type THANDLE = Ptr ()

    type ThreadInfo = (THANDLE, ForeignAddress, ForeignAddress)   -- handle to thread, thread local, thread start
    type ImageInfo = (HANDLE, ForeignAddress, DWORD, DWORD, ForeignAddress)
    type ExceptionInfo = (Bool, Bool, ForeignAddress) -- First chance, continuable, address

    data Exception
        = UnknownException
        | AccessViolation Bool ForeignAddress
        | ArrayBoundsExceeded
        | Breakpoint
        | DataTypeMisalignment
        | FltDenormalOperand
        | FltDivideByZero
        | FltInexactResult
        | FltInvalidOperation
        | FltOverflow
        | FltStackCheck
        | FltUnderflow
        | IllegalInstruction
        | InPageError
        | IntDivideByZero
        | IntOverflow
        | InvalidDisposition
        | NonContinuable
        | PrivilegedInstruction
        | SingleStep
        | StackOverflow
        deriving (Show)

    data DebugEventInfo
        = UnknownDebugEvent
        | Exception         ExceptionInfo Exception
        | CreateThread      ThreadInfo
        | CreateProcess     PHANDLE ImageInfo ThreadInfo
        | ExitThread        TID
        | ExitProcess       PID
        | LoadDll           ImageInfo
        | UnloadDll         TID
        | DebugString       ForeignAddress Bool WORD
        deriving (Show)

    type DebugEvent = (DebugEventId, DebugEventInfo)

    --------------------------------------------------------------------------
    -- Handling debugevents

    peekDebugEvent :: Ptr a -> IO DebugEvent
    peekDebugEvent p = do
        code <- ((\hsc_ptr -> peekByteOff hsc_ptr 0)) p
    {-# LINE 84 "System\Win32\DebugApi.hsc" #-}
        pid  <- ((\hsc_ptr -> peekByteOff hsc_ptr 4)) p
    {-# LINE 85 "System\Win32\DebugApi.hsc" #-}
        tid  <- ((\hsc_ptr -> peekByteOff hsc_ptr 8)) p
    {-# LINE 86 "System\Win32\DebugApi.hsc" #-}
        r <- rest (code::DWORD) (plusPtr p ((12)))
    {-# LINE 87 "System\Win32\DebugApi.hsc" #-}
        return ((pid,tid), r)
        where
            dwZero = 0 :: DWORD
            wZero = 0 :: WORD

            rest (1) p = do
    {-# LINE 93 "System\Win32\DebugApi.hsc" #-}
                chance  <- ((\hsc_ptr -> peekByteOff hsc_ptr 80)) p
    {-# LINE 94 "System\Win32\DebugApi.hsc" #-}
                flags   <- ((\hsc_ptr -> peekByteOff hsc_ptr 4)) p
    {-# LINE 95 "System\Win32\DebugApi.hsc" #-}
                addr    <- ((\hsc_ptr -> peekByteOff hsc_ptr 12)) p
    {-# LINE 96 "System\Win32\DebugApi.hsc" #-}
                code    <- ((\hsc_ptr -> peekByteOff hsc_ptr 0)) p
    {-# LINE 97 "System\Win32\DebugApi.hsc" #-}
                e <- case code::DWORD of
                    (3221225477)         -> return $ AccessViolation False 0
    {-# LINE 99 "System\Win32\DebugApi.hsc" #-}
                    (3221225612)    -> return ArrayBoundsExceeded
    {-# LINE 100 "System\Win32\DebugApi.hsc" #-}
                    (2147483651)               -> return Breakpoint
    {-# LINE 101 "System\Win32\DebugApi.hsc" #-}
                    (2147483650)    -> return DataTypeMisalignment
    {-# LINE 102 "System\Win32\DebugApi.hsc" #-}
                    (3221225613)     -> return FltDenormalOperand
    {-# LINE 103 "System\Win32\DebugApi.hsc" #-}
                    (3221225614)       -> return FltDivideByZero
    {-# LINE 104 "System\Win32\DebugApi.hsc" #-}
                    (3221225615)       -> return FltInexactResult
    {-# LINE 105 "System\Win32\DebugApi.hsc" #-}
                    (3221225616)    -> return FltInvalidOperation
    {-# LINE 106 "System\Win32\DebugApi.hsc" #-}
                    (3221225617)             -> return FltOverflow
    {-# LINE 107 "System\Win32\DebugApi.hsc" #-}
                    (3221225618)          -> return FltStackCheck
    {-# LINE 108 "System\Win32\DebugApi.hsc" #-}
                    (3221225619)            -> return FltUnderflow
    {-# LINE 109 "System\Win32\DebugApi.hsc" #-}
                    (3221225501)      -> return IllegalInstruction
    {-# LINE 110 "System\Win32\DebugApi.hsc" #-}
                    (3221225478)            -> return InPageError
    {-# LINE 111 "System\Win32\DebugApi.hsc" #-}
                    (3221225620)       -> return IntDivideByZero
    {-# LINE 112 "System\Win32\DebugApi.hsc" #-}
                    (3221225621)             -> return IntOverflow
    {-# LINE 113 "System\Win32\DebugApi.hsc" #-}
                    (3221225510)      -> return InvalidDisposition
    {-# LINE 114 "System\Win32\DebugApi.hsc" #-}
                    (3221225509) -> return NonContinuable
    {-# LINE 115 "System\Win32\DebugApi.hsc" #-}
                    (3221225622)         -> return PrivilegedInstruction
    {-# LINE 116 "System\Win32\DebugApi.hsc" #-}
                    (2147483652)              -> return SingleStep
    {-# LINE 117 "System\Win32\DebugApi.hsc" #-}
                    (3221225725)           -> return StackOverflow
    {-# LINE 118 "System\Win32\DebugApi.hsc" #-}
                    _                                           -> return UnknownException
                return $ Exception (chance/=dwZero, flags==dwZero, addr) e

            rest (2) p = do
    {-# LINE 122 "System\Win32\DebugApi.hsc" #-}
                handle <- ((\hsc_ptr -> peekByteOff hsc_ptr 0))             p
    {-# LINE 123 "System\Win32\DebugApi.hsc" #-}
                local <- ((\hsc_ptr -> peekByteOff hsc_ptr 4))    p
    {-# LINE 124 "System\Win32\DebugApi.hsc" #-}
                start <- ((\hsc_ptr -> peekByteOff hsc_ptr 8))       p
    {-# LINE 125 "System\Win32\DebugApi.hsc" #-}
                return $ CreateThread (handle, local, start)

            rest (3) p = do
    {-# LINE 128 "System\Win32\DebugApi.hsc" #-}
                file    <- ((\hsc_ptr -> peekByteOff hsc_ptr 0)) p
    {-# LINE 129 "System\Win32\DebugApi.hsc" #-}
                proc    <- ((\hsc_ptr -> peekByteOff hsc_ptr 4)) p
    {-# LINE 130 "System\Win32\DebugApi.hsc" #-}
                thread  <- ((\hsc_ptr -> peekByteOff hsc_ptr 8)) p
    {-# LINE 131 "System\Win32\DebugApi.hsc" #-}
                imgbase <- ((\hsc_ptr -> peekByteOff hsc_ptr 12)) p
    {-# LINE 132 "System\Win32\DebugApi.hsc" #-}
                dbgoff  <- ((\hsc_ptr -> peekByteOff hsc_ptr 16)) p
    {-# LINE 133 "System\Win32\DebugApi.hsc" #-}
                dbgsize <- ((\hsc_ptr -> peekByteOff hsc_ptr 20)) p
    {-# LINE 134 "System\Win32\DebugApi.hsc" #-}
                local   <- ((\hsc_ptr -> peekByteOff hsc_ptr 24)) p
    {-# LINE 135 "System\Win32\DebugApi.hsc" #-}
                start   <- ((\hsc_ptr -> peekByteOff hsc_ptr 28)) p
    {-# LINE 136 "System\Win32\DebugApi.hsc" #-}
                imgname <- ((\hsc_ptr -> peekByteOff hsc_ptr 32)) p
    {-# LINE 137 "System\Win32\DebugApi.hsc" #-}
                --unicode <- (#peek CREATE_PROCESS_DEBUG_INFO, fUnicode) p
                return $ CreateProcess proc
                            (file, imgbase, dbgoff, dbgsize, imgname) --, unicode/=wZero)
                            (thread, local, start)

            rest (4) p =
    {-# LINE 143 "System\Win32\DebugApi.hsc" #-}
                ((\hsc_ptr -> peekByteOff hsc_ptr 0)) p >>= return.ExitThread
    {-# LINE 144 "System\Win32\DebugApi.hsc" #-}

            rest (5) p =
    {-# LINE 146 "System\Win32\DebugApi.hsc" #-}
                ((\hsc_ptr -> peekByteOff hsc_ptr 0)) p >>= return.ExitProcess
    {-# LINE 147 "System\Win32\DebugApi.hsc" #-}

            rest (6) p = do
    {-# LINE 149 "System\Win32\DebugApi.hsc" #-}
                file    <- ((\hsc_ptr -> peekByteOff hsc_ptr 0)) p
    {-# LINE 150 "System\Win32\DebugApi.hsc" #-}
                imgbase <- ((\hsc_ptr -> peekByteOff hsc_ptr 4)) p
    {-# LINE 151 "System\Win32\DebugApi.hsc" #-}
                dbgoff  <- ((\hsc_ptr -> peekByteOff hsc_ptr 8)) p
    {-# LINE 152 "System\Win32\DebugApi.hsc" #-}
                dbgsize <- ((\hsc_ptr -> peekByteOff hsc_ptr 12)) p
    {-# LINE 153 "System\Win32\DebugApi.hsc" #-}
                imgname <- ((\hsc_ptr -> peekByteOff hsc_ptr 16)) p
    {-# LINE 154 "System\Win32\DebugApi.hsc" #-}
                --unicode <- (#peek LOAD_DLL_DEBUG_INFO, fUnicode) p
                return $
                    LoadDll (file, imgbase, dbgoff, dbgsize, imgname)--, unicode/=wZero)

            rest (8) p = do
    {-# LINE 159 "System\Win32\DebugApi.hsc" #-}
                dat     <- ((\hsc_ptr -> peekByteOff hsc_ptr 0)) p
    {-# LINE 160 "System\Win32\DebugApi.hsc" #-}
                unicode <- ((\hsc_ptr -> peekByteOff hsc_ptr 4)) p
    {-# LINE 161 "System\Win32\DebugApi.hsc" #-}
                length  <- ((\hsc_ptr -> peekByteOff hsc_ptr 6)) p
    {-# LINE 162 "System\Win32\DebugApi.hsc" #-}
                return $ DebugString dat (unicode/=wZero) length

            rest (7) p =
    {-# LINE 165 "System\Win32\DebugApi.hsc" #-}
                ((\hsc_ptr -> peekByteOff hsc_ptr 0)) p >>= return.UnloadDll
    {-# LINE 166 "System\Win32\DebugApi.hsc" #-}

            rest _ _ = return UnknownDebugEvent

    waitForDebugEvent :: Maybe Int -> IO (Maybe DebugEvent)
    waitForDebugEvent timeout = allocaBytes ((96)) $ \buf -> do
    {-# LINE 173 "System\Win32\DebugApi.hsc" #-}
        res <- c_WaitForDebugEvent buf $ maybe (4294967295) fromIntegral timeout
    {-# LINE 174 "System\Win32\DebugApi.hsc" #-}
        if res
            then peekDebugEvent buf >>= return.Just
            else getLastError >>= \e -> case e of
                (6)   -> return Nothing
    {-# LINE 178 "System\Win32\DebugApi.hsc" #-}
                (121)      -> return Nothing
    {-# LINE 179 "System\Win32\DebugApi.hsc" #-}
                _                               -> die e
        where
            die res = failWith "WaitForDebugEvent" res

    getDebugEvents :: Int -> IO [DebugEvent]
    getDebugEvents timeout = waitForDebugEvent (Just timeout) >>= getMore
        where
            getMore e = case e of
                Nothing -> return []
                Just e  -> do
                    rest <- waitForDebugEvent (Just 0) >>= getMore
                    return $ e:rest

    continueDebugEvent :: DebugEventId -> Bool -> IO ()
    continueDebugEvent (pid,tid) cont =
        failIf_ not "ContinueDebugEvent" $ c_ContinueDebugEvent pid tid cont'
        where
            cont' = if cont
                then (65538)
    {-# LINE 198 "System\Win32\DebugApi.hsc" #-}
                else (2147549185)
    {-# LINE 199 "System\Win32\DebugApi.hsc" #-}

    --------------------------------------------------------------------------
    -- Process control

    debugActiveProcess :: PID -> IO ()
    debugActiveProcess pid =
        failIf_ not "debugActiveProcess: DebugActiveProcess" $
            c_DebugActiveProcess pid

    -- Windows XP
    -- debugActiveProcessStop :: PID -> IO ()
    -- debugActiveProcessStop pid =
    --     failIf_ not "debugActiveProcessStop: DebugActiveProcessStop" $
    --         c_DebugActiveProcessStop pid

    --------------------------------------------------------------------------
    -- Process memory

    peekProcessMemory :: PHANDLE -> ForeignAddress -> Int -> Ptr a -> IO ()
    peekProcessMemory proc addr size buf =
        failIf_ not "peekProcessMemory: ReadProcessMemory" $
            c_ReadProcessMemory proc (plusPtr nullPtr $ fromIntegral addr) (castPtr buf) (fromIntegral size) nullPtr

    readProcessMemory :: PHANDLE -> ForeignAddress -> Int -> IO (ForeignPtr a)
    readProcessMemory proc addr size = do
        res <- mallocForeignPtrBytes size
        withForeignPtr res $ peekProcessMemory proc addr size
        return res

    pokeProcessMemory :: PHANDLE -> ForeignAddress -> Int -> Ptr a -> IO ()
    pokeProcessMemory proc addr size buf =
        failIf_ not "pokeProcessMemory: WriteProcessMemory" $
            c_WriteProcessMemory proc (plusPtr nullPtr $ fromIntegral addr) (castPtr buf) (fromIntegral size) nullPtr

    withProcessMemory :: PHANDLE -> ForeignAddress -> Int -> (Ptr a -> IO b) -> IO b
    withProcessMemory proc addr size act = allocaBytes size $ \buf -> do
        peekProcessMemory proc addr size buf
        res <- act buf
        pokeProcessMemory proc addr size buf
        return res

    peekP :: (Storable a) => PHANDLE -> ForeignAddress -> IO a
    peekP proc addr = fixIO $ \res -> withProcessMemory proc addr (sizeOf res) peek

    pokeP :: (Storable a) => PHANDLE -> ForeignAddress -> a -> IO ()
    pokeP proc addr v = withProcessMemory proc addr (sizeOf v) $ \buf -> poke buf v

    --------------------------------------------------------------------------
    -- Thread Control

    suspendThread :: THANDLE -> IO DWORD
    suspendThread t =
        failIf (==0-1) "SuspendThread" $ c_SuspendThread t

    resumeThread :: THANDLE -> IO DWORD
    resumeThread t =
        failIf (==0-1) "ResumeThread" $ c_ResumeThread t

    withSuspendedThread :: THANDLE -> IO a -> IO a
    withSuspendedThread t = bracket_ (suspendThread t) (resumeThread t)

    --getThreadId :: THANDLE -> IO TID
    --getThreadId = failIf (==0) "GetThreadId" . c_GetThreadId

    --------------------------------------------------------------------------
    -- Thread register control
    getThreadContext :: THANDLE -> Ptr a -> IO ()
    getThreadContext t buf =
        failIf_ not "GetThreadContext" $ c_GetThreadContext t (castPtr buf)

    setThreadContext :: THANDLE -> Ptr a -> IO ()
    setThreadContext t buf =
        failIf_ not "SetThreadContext" $ c_SetThreadContext t (castPtr buf)

    useAllRegs :: Ptr a -> IO ()
    useAllRegs buf = ((\hsc_ptr -> pokeByteOff hsc_ptr 0)) buf v
    {-# LINE 275 "System\Win32\DebugApi.hsc" #-}
        where
            v = (65567) :: DWORD
    {-# LINE 277 "System\Win32\DebugApi.hsc" #-}

    withThreadContext :: THANDLE -> (Ptr a -> IO b) -> IO b
    withThreadContext t act =
        allocaBytes ((716))
    {-# LINE 281 "System\Win32\DebugApi.hsc" #-}
            $ \buf -> bracket_
                (useAllRegs buf >> getThreadContext t buf)
                (useAllRegs buf >> setThreadContext t buf)
                (act buf)

    eax, ebx, ecx, edx :: Int
    esi, edi :: Int
    ebp, eip, esp :: Int
    segCs, segDs, segEs, segFs, segGs :: Int
    eFlags :: Int

    eax = ((176))
    {-# LINE 294 "System\Win32\DebugApi.hsc" #-}
    ebx = ((164))
    {-# LINE 295 "System\Win32\DebugApi.hsc" #-}
    ecx = ((172))
    {-# LINE 296 "System\Win32\DebugApi.hsc" #-}
    edx = ((168))
    {-# LINE 297 "System\Win32\DebugApi.hsc" #-}
    esi = ((160))
    {-# LINE 298 "System\Win32\DebugApi.hsc" #-}
    edi = ((156))
    {-# LINE 299 "System\Win32\DebugApi.hsc" #-}
    ebp = ((180))
    {-# LINE 300 "System\Win32\DebugApi.hsc" #-}
    eip = ((184))
    {-# LINE 301 "System\Win32\DebugApi.hsc" #-}
    esp = ((196))
    {-# LINE 302 "System\Win32\DebugApi.hsc" #-}
    segCs = ((188))
    {-# LINE 303 "System\Win32\DebugApi.hsc" #-}
    segDs = ((152))
    {-# LINE 304 "System\Win32\DebugApi.hsc" #-}
    segEs = ((148))
    {-# LINE 305 "System\Win32\DebugApi.hsc" #-}
    segFs = ((144))
    {-# LINE 306 "System\Win32\DebugApi.hsc" #-}
    segGs = ((140))
    {-# LINE 307 "System\Win32\DebugApi.hsc" #-}
    eFlags  = ((192))
    {-# LINE 308 "System\Win32\DebugApi.hsc" #-}

    dr :: Int -> Int
    dr n = case n of
        0 -> ((4))
    {-# LINE 312 "System\Win32\DebugApi.hsc" #-}
        1 -> ((8))
    {-# LINE 313 "System\Win32\DebugApi.hsc" #-}
        2 -> ((12))
    {-# LINE 314 "System\Win32\DebugApi.hsc" #-}
        3 -> ((16))
    {-# LINE 315 "System\Win32\DebugApi.hsc" #-}
        6 -> ((20))
    {-# LINE 316 "System\Win32\DebugApi.hsc" #-}
        7 -> ((24))
    {-# LINE 317 "System\Win32\DebugApi.hsc" #-}
        _ -> undefined

    setReg :: Ptr a -> Int -> DWORD -> IO ()
    setReg = pokeByteOff

    getReg :: Ptr a -> Int -> IO DWORD
    getReg = peekByteOff

    modReg :: Ptr a -> Int -> (DWORD->DWORD) -> IO DWORD
    modReg buf r f = do
        old <- getReg buf r
        setReg buf r (f old)
        return old

    makeModThreadContext :: [(Int, DWORD->DWORD)] -> Ptr a -> IO [DWORD]
    makeModThreadContext act buf = mapM (uncurry $ modReg buf) act

    modifyThreadContext :: THANDLE -> [(Int, DWORD->DWORD)] -> IO [DWORD]
    modifyThreadContext t a = withThreadContext t $ makeModThreadContext a

    --------------------------------------------------------------------------
    -- On process being debugged

    outputDebugString :: String -> IO ()
    outputDebugString s = withTString s $ \s -> c_OutputDebugString s

    --------------------------------------------------------------------------
    -- Raw imports

    foreign import stdcall "windows.h SuspendThread"
        c_SuspendThread :: THANDLE -> IO DWORD

    foreign import stdcall "windows.h ResumeThread"
        c_ResumeThread :: THANDLE -> IO DWORD

    foreign import stdcall "windows.h WaitForDebugEvent"
        c_WaitForDebugEvent :: Ptr () -> DWORD -> IO BOOL

    foreign import stdcall "windows.h ContinueDebugEvent"
        c_ContinueDebugEvent :: DWORD -> DWORD -> DWORD -> IO BOOL

    foreign import stdcall "windows.h DebugActiveProcess"
        c_DebugActiveProcess :: DWORD -> IO Bool

    -- Windows XP
    -- foreign import stdcall "windows.h DebugActiveProcessStop"
    --     c_DebugActiveProcessStop :: DWORD -> IO Bool

    foreign import stdcall "windows.h ReadProcessMemory" c_ReadProcessMemory ::
        PHANDLE -> Ptr () -> Ptr Word8 -> DWORD -> Ptr DWORD -> IO BOOL

    foreign import stdcall "windows.h WriteProcessMemory" c_WriteProcessMemory ::
        PHANDLE -> Ptr () -> Ptr Word8 -> DWORD -> Ptr DWORD -> IO BOOL

    foreign import stdcall "windows.h GetThreadContext"
        c_GetThreadContext :: THANDLE -> Ptr () -> IO BOOL

    foreign import stdcall "windows.h SetThreadContext"
        c_SetThreadContext :: THANDLE -> Ptr () -> IO BOOL

    --foreign import stdcall "windows.h GetThreadId"
    --    c_GetThreadId :: THANDLE -> IO TID

    foreign import stdcall "windows.h OutputDebugStringW"
        c_OutputDebugString :: LPTSTR -> IO ()

    foreign import stdcall "windows.h IsDebuggerPresent"
        isDebuggerPresent :: IO BOOL

    foreign import stdcall "windows.h  DebugBreak"
        debugBreak :: IO ()