packages feed

Hs2lib-0.6.3: WinDll/Debug/Output.hs

-----------------------------------------------------------------------------
-- |
-- Module      :  Windll
-- Copyright   :  (c) Tamar Christina 2009 - 2010
-- License     :  BSD3
-- 
-- Maintainer  :  tamar@zhox.com
-- Stability   :  experimental
-- Portability :  portable
--
-- Module to process the Memory.dump file. From loading to analysis.
--
-----------------------------------------------------------------------------

module WinDll.Debug.Output where

import WinDll.Session.Debug
import WinDll.Debug.Records
import WinDll.Debug.Stack
import WinDll.Debug.Heap
import WinDll.Debug.Analyzer
import WinDll.Utils.Feedback

import Data.Maybe
import Data.List
import Data.Function

-- | Load and Parse files
loadAndParse :: Exec ()
loadAndParse = do session <- get
                  let file = absPath session
                  inform _normal $ "Reading file '" ++ file ++ "'..."
                  contents <- liftIO $ readFile file
                  let mems = map read $ lines contents
                  let len  = length mems
                  inform _normal $ "Found " ++ show len ++ " record(s)."
                  put $ session { memAllocs    = len `seq` mems
                                , memAllocsLen = len
                                }
                                
data Outstanding = Outs { outCount     :: Int
                        , outStack     :: Stack
                        , outAddresses :: [Address]
                        }
                        
instance Show Outstanding where
  show x = show (outCount x) ++ " unfreed references found originating from " ++ printStack (outStack x)
                                
data MemResult 
  = MemResult { memHeap    :: Heap
              , memRSize   :: Int
              , memOuts    :: [Outstanding]
              , memUnAlloc :: Int
              }
  deriving (Show)
             
-- | Analyze the memory allocation functions             
analyze :: Exec MemResult
analyze = do session <- get
             heap'   <- emulate (memAllocs session) (0, memAllocsLen session) (heap session) 
             hp      <- normalizeHeap heap'
             let allocs = filter isMem $ memAllocs session
                 isMem  = \x -> case x of 
                                  MemAlloc{} -> True
                                  _          -> False
                 locs   = getStartingAddr hp
                 found  = mapMaybe (flip lookupStack allocs) locs
                 size   = sizeHeap hp
                 outst  = size - length found
                 merged = groupBy ((==) `on` snd) $ sortBy (compare `on` snd) found
                 outdat = map (\x -> guard (not $ null x) >> (return $ Outs (length x) (snd $ head x) (map fst x))) merged
             put $ session { memAllocs =[], memAllocsLen = 0, heap = hp }
             return $ MemResult { memHeap    = hp 
                                , memRSize   = size
                                , memUnAlloc = outst
                                , memOuts    = catMaybes outdat
                                }

-- | Lookup an address and return its associated stack
lookupStack :: Address -> [MemAlloc] -> Maybe (Address, Stack)
lookupStack _ []                                           = Nothing
lookupStack p (x:xs) | p >= memStart x && p `lt` memStop x = return (p, memStack x)
                     | otherwise                           = lookupStack p xs

lt = \x -> maybe False id . liftM (x <=)
                                
-- | Show the result of the analysis 
displayResults :: MemResult -> Exec ()
displayResults mem = do echo $ "Found " ++ show (memRSize mem) ++ " outstanding allocation(s)."
                        when (memUnAlloc mem > 0) $ echo $ "Unable to resolve " ++ show (memUnAlloc mem) ++ " allocation(s)."
                        liftIO $ mapM_ print $ memOuts mem
                        when (memUnAlloc mem == 0 && memRSize mem == 0) $ liftIO $ putStrLn "Congratulations, No memory leak(s) detected."
                   
-- | Discover file locations
discoverFiles :: Exec ()
discoverFiles = do return ()