module Foreign.NM (
lookupSymbol
#ifdef TESTING
, readFunctions'
, Function(..)
#endif
) where
import Prelude hiding (lookup)
import Data.Map (lookup, fromList)
import Data.Char
import Data.List hiding (lookup)
import Data.Maybe
import Numeric
import System.Process
data Function = Function {
_addr :: Int
, cname :: String
, prettyName :: String
}
deriving (Show, Eq)
lookupSymbol :: String -> String -> IO (Maybe String)
lookupSymbol filename func = do
functions <- readFunctions filename
return $ fmap cname $ find ((==) func . prettyName) functions
readFunctions :: String -> IO [Function]
readFunctions filename = do
nm <- readProcess "nm" [filename] ""
filt <- readProcess "c++filt" [] nm
return $ readFunctions' nm filt
readFunctions' :: String -> String -> [Function]
readFunctions' nm filt =
let addrLen = length $ takeWhile (/= ' ') $ head $ lines nm
f = catMaybes . map (splitLine addrLen) . lines
filt' = fromList $ f filt
in catMaybes $ map (\(a, v) -> lookup a filt' >>= Just . Function a v) (f nm)
splitLine :: Int -> String -> Maybe (Int, String)
splitLine addrLen l =
let (h, t) = fmap n $ splitAt addrLen l
[(v, "")] = readHex h
n :: String -> String
n (' ':_:' ':x) = x
n (' ':x) = x
n _ = error "invalid nm output"
eh = isSuffixOf "(.eh)" t
in if all isHexDigit h && not eh
then Just (v, t)
else Nothing