{-# LANGUAGE CPP, UnboxedTuples, MagicHash #-}
{-# OPTIONS_GHC -fno-warn-name-shadowing #-}
module GHCi.ObjLink
( initObjLinker, ShouldRetainCAFs(..)
, loadDLL
, loadArchive
, loadObj
, unloadObj
, purgeObj
, lookupSymbol
, lookupClosure
, resolveObjs
, addLibrarySearchPath
, removeLibrarySearchPath
, findSystemLibrary
) where
import Prelude
import GHCi.RemoteTypes
import Control.Exception (throwIO, ErrorCall(..))
import Control.Monad ( when )
import Foreign.C
import Foreign.Marshal.Alloc ( free )
import Foreign ( nullPtr )
import GHC.Exts
import System.Posix.Internals ( CFilePath, withFilePath, peekFilePath )
import System.FilePath ( dropExtension, normalise )
data ShouldRetainCAFs
= RetainCAFs
| DontRetainCAFs
initObjLinker :: ShouldRetainCAFs -> IO ()
initObjLinker :: ShouldRetainCAFs -> IO ()
initObjLinker ShouldRetainCAFs
RetainCAFs = CInt -> IO ()
c_initLinker_ CInt
1
initObjLinker ShouldRetainCAFs
_ = CInt -> IO ()
c_initLinker_ CInt
0
lookupSymbol :: String -> IO (Maybe (Ptr a))
lookupSymbol :: String -> IO (Maybe (Ptr a))
lookupSymbol String
str_in = do
let str :: String
str = String -> String
prefixUnderscore String
str_in
String -> (CString -> IO (Maybe (Ptr a))) -> IO (Maybe (Ptr a))
forall a. String -> (CString -> IO a) -> IO a
withCAString String
str ((CString -> IO (Maybe (Ptr a))) -> IO (Maybe (Ptr a)))
-> (CString -> IO (Maybe (Ptr a))) -> IO (Maybe (Ptr a))
forall a b. (a -> b) -> a -> b
$ \CString
c_str -> do
Ptr a
addr <- CString -> IO (Ptr a)
forall a. CString -> IO (Ptr a)
c_lookupSymbol CString
c_str
if Ptr a
addr Ptr a -> Ptr a -> Bool
forall a. Eq a => a -> a -> Bool
== Ptr a
forall a. Ptr a
nullPtr
then Maybe (Ptr a) -> IO (Maybe (Ptr a))
forall (m :: * -> *) a. Monad m => a -> m a
return Maybe (Ptr a)
forall a. Maybe a
Nothing
else Maybe (Ptr a) -> IO (Maybe (Ptr a))
forall (m :: * -> *) a. Monad m => a -> m a
return (Ptr a -> Maybe (Ptr a)
forall a. a -> Maybe a
Just Ptr a
addr)
lookupClosure :: String -> IO (Maybe HValueRef)
lookupClosure :: String -> IO (Maybe HValueRef)
lookupClosure String
str = do
Maybe (Ptr Any)
m <- String -> IO (Maybe (Ptr Any))
forall a. String -> IO (Maybe (Ptr a))
lookupSymbol String
str
case Maybe (Ptr Any)
m of
Maybe (Ptr Any)
Nothing -> Maybe HValueRef -> IO (Maybe HValueRef)
forall (m :: * -> *) a. Monad m => a -> m a
return Maybe HValueRef
forall a. Maybe a
Nothing
Just (Ptr Addr#
addr) -> case Addr# -> (# Any #)
forall a. Addr# -> (# a #)
addrToAny# Addr#
addr of
(# Any
a #) -> HValueRef -> Maybe HValueRef
forall a. a -> Maybe a
Just (HValueRef -> Maybe HValueRef)
-> IO HValueRef -> IO (Maybe HValueRef)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> HValue -> IO HValueRef
forall a. a -> IO (RemoteRef a)
mkRemoteRef (Any -> HValue
HValue Any
a)
prefixUnderscore :: String -> String
prefixUnderscore :: String -> String
prefixUnderscore
| Bool
cLeadingUnderscore = (Char
'_'Char -> String -> String
forall a. a -> [a] -> [a]
:)
| Bool
otherwise = String -> String
forall a. a -> a
id
loadDLL :: String -> IO (Maybe String)
loadDLL :: String -> IO (Maybe String)
loadDLL String
str0 = do
let
str :: String
str | Bool
isWindowsHost = String -> String
dropExtension String
str0
| Bool
otherwise = String
str0
CString
maybe_errmsg <- String -> (CString -> IO CString) -> IO CString
forall a. String -> (CString -> IO a) -> IO a
withFilePath (String -> String
normalise String
str) ((CString -> IO CString) -> IO CString)
-> (CString -> IO CString) -> IO CString
forall a b. (a -> b) -> a -> b
$ \CString
dll -> CString -> IO CString
c_addDLL CString
dll
if CString
maybe_errmsg CString -> CString -> Bool
forall a. Eq a => a -> a -> Bool
== CString
forall a. Ptr a
nullPtr
then Maybe String -> IO (Maybe String)
forall (m :: * -> *) a. Monad m => a -> m a
return Maybe String
forall a. Maybe a
Nothing
else do String
str <- CString -> IO String
peekCString CString
maybe_errmsg
CString -> IO ()
forall a. Ptr a -> IO ()
free CString
maybe_errmsg
Maybe String -> IO (Maybe String)
forall (m :: * -> *) a. Monad m => a -> m a
return (String -> Maybe String
forall a. a -> Maybe a
Just String
str)
loadArchive :: String -> IO ()
loadArchive :: String -> IO ()
loadArchive String
str = do
String -> (CString -> IO ()) -> IO ()
forall a. String -> (CString -> IO a) -> IO a
withFilePath String
str ((CString -> IO ()) -> IO ()) -> (CString -> IO ()) -> IO ()
forall a b. (a -> b) -> a -> b
$ \CString
c_str -> do
Int
r <- CString -> IO Int
c_loadArchive CString
c_str
Bool -> IO () -> IO ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (Int
r Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
0) (ErrorCall -> IO ()
forall e a. Exception e => e -> IO a
throwIO (String -> ErrorCall
ErrorCall (String
"loadArchive " String -> String -> String
forall a. [a] -> [a] -> [a]
++ String -> String
forall a. Show a => a -> String
show String
str String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
": failed")))
loadObj :: String -> IO ()
loadObj :: String -> IO ()
loadObj String
str = do
String -> (CString -> IO ()) -> IO ()
forall a. String -> (CString -> IO a) -> IO a
withFilePath String
str ((CString -> IO ()) -> IO ()) -> (CString -> IO ()) -> IO ()
forall a b. (a -> b) -> a -> b
$ \CString
c_str -> do
Int
r <- CString -> IO Int
c_loadObj CString
c_str
Bool -> IO () -> IO ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (Int
r Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
0) (ErrorCall -> IO ()
forall e a. Exception e => e -> IO a
throwIO (String -> ErrorCall
ErrorCall (String
"loadObj " String -> String -> String
forall a. [a] -> [a] -> [a]
++ String -> String
forall a. Show a => a -> String
show String
str String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
": failed")))
unloadObj :: String -> IO ()
unloadObj :: String -> IO ()
unloadObj String
str =
String -> (CString -> IO ()) -> IO ()
forall a. String -> (CString -> IO a) -> IO a
withFilePath String
str ((CString -> IO ()) -> IO ()) -> (CString -> IO ()) -> IO ()
forall a b. (a -> b) -> a -> b
$ \CString
c_str -> do
Int
r <- CString -> IO Int
c_unloadObj CString
c_str
Bool -> IO () -> IO ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (Int
r Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
0) (ErrorCall -> IO ()
forall e a. Exception e => e -> IO a
throwIO (String -> ErrorCall
ErrorCall (String
"unloadObj " String -> String -> String
forall a. [a] -> [a] -> [a]
++ String -> String
forall a. Show a => a -> String
show String
str String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
": failed")))
purgeObj :: String -> IO ()
purgeObj :: String -> IO ()
purgeObj String
str =
String -> (CString -> IO ()) -> IO ()
forall a. String -> (CString -> IO a) -> IO a
withFilePath String
str ((CString -> IO ()) -> IO ()) -> (CString -> IO ()) -> IO ()
forall a b. (a -> b) -> a -> b
$ \CString
c_str -> do
Int
r <- CString -> IO Int
c_purgeObj CString
c_str
Bool -> IO () -> IO ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (Int
r Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
0) (ErrorCall -> IO ()
forall e a. Exception e => e -> IO a
throwIO (String -> ErrorCall
ErrorCall (String
"purgeObj " String -> String -> String
forall a. [a] -> [a] -> [a]
++ String -> String
forall a. Show a => a -> String
show String
str String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
": failed")))
addLibrarySearchPath :: String -> IO (Ptr ())
addLibrarySearchPath :: String -> IO (Ptr ())
addLibrarySearchPath String
str =
String -> (CString -> IO (Ptr ())) -> IO (Ptr ())
forall a. String -> (CString -> IO a) -> IO a
withFilePath String
str CString -> IO (Ptr ())
c_addLibrarySearchPath
removeLibrarySearchPath :: Ptr () -> IO Bool
removeLibrarySearchPath :: Ptr () -> IO Bool
removeLibrarySearchPath = Ptr () -> IO Bool
c_removeLibrarySearchPath
findSystemLibrary :: String -> IO (Maybe String)
findSystemLibrary :: String -> IO (Maybe String)
findSystemLibrary String
str = do
CString
result <- String -> (CString -> IO CString) -> IO CString
forall a. String -> (CString -> IO a) -> IO a
withFilePath String
str CString -> IO CString
c_findSystemLibrary
case CString
result CString -> CString -> Bool
forall a. Eq a => a -> a -> Bool
== CString
forall a. Ptr a
nullPtr of
Bool
True -> Maybe String -> IO (Maybe String)
forall (m :: * -> *) a. Monad m => a -> m a
return Maybe String
forall a. Maybe a
Nothing
Bool
False -> do String
path <- CString -> IO String
peekFilePath CString
result
CString -> IO ()
forall a. Ptr a -> IO ()
free CString
result
Maybe String -> IO (Maybe String)
forall (m :: * -> *) a. Monad m => a -> m a
return (Maybe String -> IO (Maybe String))
-> Maybe String -> IO (Maybe String)
forall a b. (a -> b) -> a -> b
$ String -> Maybe String
forall a. a -> Maybe a
Just String
path
resolveObjs :: IO Bool
resolveObjs :: IO Bool
resolveObjs = do
Int
r <- IO Int
c_resolveObjs
Bool -> IO Bool
forall (m :: * -> *) a. Monad m => a -> m a
return (Int
r Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
/= Int
0)
foreign import ccall unsafe "addDLL" c_addDLL :: CFilePath -> IO CString
foreign import ccall unsafe "initLinker_" c_initLinker_ :: CInt -> IO ()
foreign import ccall unsafe "lookupSymbol" c_lookupSymbol :: CString -> IO (Ptr a)
foreign import ccall unsafe "loadArchive" c_loadArchive :: CFilePath -> IO Int
foreign import ccall unsafe "loadObj" c_loadObj :: CFilePath -> IO Int
foreign import ccall unsafe "purgeObj" c_purgeObj :: CFilePath -> IO Int
foreign import ccall unsafe "unloadObj" c_unloadObj :: CFilePath -> IO Int
foreign import ccall unsafe "resolveObjs" c_resolveObjs :: IO Int
foreign import ccall unsafe "addLibrarySearchPath" c_addLibrarySearchPath :: CFilePath -> IO (Ptr ())
foreign import ccall unsafe "findSystemLibrary" c_findSystemLibrary :: CFilePath -> IO CFilePath
foreign import ccall unsafe "removeLibrarySearchPath" c_removeLibrarySearchPath :: Ptr() -> IO Bool
#include "ghcautoconf.h"
cLeadingUnderscore :: Bool
#if defined(LEADING_UNDERSCORE)
cLeadingUnderscore = True
#else
cLeadingUnderscore :: Bool
cLeadingUnderscore = Bool
False
#endif
isWindowsHost :: Bool
#if defined(mingw32_HOST_OS)
isWindowsHost = True
#else
isWindowsHost :: Bool
isWindowsHost = Bool
False
#endif