mirror of
https://github.com/GaloisInc/macaw.git
synced 2024-11-28 01:35:33 +03:00
[refinement] update run-refinement for summary and verbose modes.
This commit is contained in:
parent
e47887a9f1
commit
3baf55376b
@ -99,11 +99,13 @@ executable run-refinement
|
|||||||
, macaw-x86-symbolic
|
, macaw-x86-symbolic
|
||||||
, optparse-applicative
|
, optparse-applicative
|
||||||
, parameterized-utils
|
, parameterized-utils
|
||||||
|
, prettyprinter
|
||||||
, semmc-ppc
|
, semmc-ppc
|
||||||
, text
|
, text
|
||||||
|
|
||||||
test-suite test-refinements
|
test-suite test-refinements
|
||||||
type: exitcode-stdio-1.0
|
type: exitcode-stdio-1.0
|
||||||
|
buildable: True
|
||||||
default-language: Haskell2010
|
default-language: Haskell2010
|
||||||
GHC-options: -Wall -Werror -Wcompat
|
GHC-options: -Wall -Werror -Wcompat
|
||||||
hs-source-dirs: tests
|
hs-source-dirs: tests
|
||||||
|
@ -16,26 +16,35 @@ import qualified Data.ElfEdit as E
|
|||||||
import Data.Foldable
|
import Data.Foldable
|
||||||
import qualified Data.Macaw.Architecture.Info as AI
|
import qualified Data.Macaw.Architecture.Info as AI
|
||||||
import Data.Macaw.BinaryLoader as MBL
|
import Data.Macaw.BinaryLoader as MBL
|
||||||
import Data.Macaw.X86.Symbolic ()
|
|
||||||
import Data.Macaw.BinaryLoader.X86 ()
|
import Data.Macaw.BinaryLoader.X86 ()
|
||||||
import Data.Macaw.CFG ( ArchAddrWidth )
|
import Data.Macaw.CFG ( ArchAddrWidth )
|
||||||
import qualified Data.Macaw.Discovery as MD
|
import qualified Data.Macaw.Discovery as MD
|
||||||
import qualified Data.Macaw.Memory.ElfLoader as ML
|
import qualified Data.Macaw.Memory.ElfLoader as ML
|
||||||
|
import Data.Macaw.PPC
|
||||||
import qualified Data.Macaw.Refinement as MR
|
import qualified Data.Macaw.Refinement as MR
|
||||||
import Data.Macaw.Symbolic ( SymArchConstraints )
|
import Data.Macaw.Symbolic ( SymArchConstraints )
|
||||||
import GHC.TypeLits
|
|
||||||
import qualified Data.Macaw.X86 as MX86
|
import qualified Data.Macaw.X86 as MX86
|
||||||
|
import Data.Macaw.X86.Symbolic ()
|
||||||
import qualified Data.Map as M
|
import qualified Data.Map as M
|
||||||
|
import Data.Maybe
|
||||||
|
import Data.Monoid
|
||||||
import Data.Parameterized.Some
|
import Data.Parameterized.Some
|
||||||
import Data.Semigroup
|
import Data.Semigroup
|
||||||
|
import Data.Semigroup ()
|
||||||
import qualified Data.Text.IO as TIO
|
import qualified Data.Text.IO as TIO
|
||||||
|
import Data.Text.Prettyprint.Doc
|
||||||
|
import GHC.TypeLits
|
||||||
import qualified Options.Applicative as O
|
import qualified Options.Applicative as O
|
||||||
import qualified SemMC.Architecture.PPC64 as PPC64
|
|
||||||
import qualified SemMC.Architecture.PPC32 as PPC32
|
import qualified SemMC.Architecture.PPC32 as PPC32
|
||||||
|
import qualified SemMC.Architecture.PPC64 as PPC64
|
||||||
import System.Exit
|
import System.Exit
|
||||||
|
|
||||||
|
import Prelude
|
||||||
|
|
||||||
data Options = Options { inputFile :: FilePath
|
data Options = Options { inputFile :: FilePath
|
||||||
, unrefined :: Bool
|
, unrefined :: Bool
|
||||||
|
, summaryOnly :: Bool
|
||||||
|
, verbose :: Bool
|
||||||
}
|
}
|
||||||
|
|
||||||
optionsParser :: O.Parser Options
|
optionsParser :: O.Parser Options
|
||||||
@ -44,8 +53,20 @@ optionsParser = Options
|
|||||||
<> O.help "The binary ELF file to perform discovery on"
|
<> O.help "The binary ELF file to perform discovery on"
|
||||||
)
|
)
|
||||||
<*> O.switch ( O.long "unrefined"
|
<*> O.switch ( O.long "unrefined"
|
||||||
|
<> O.short 'u'
|
||||||
<> O.help "No refinement of discovery results"
|
<> O.help "No refinement of discovery results"
|
||||||
)
|
)
|
||||||
|
<*> O.switch ( O.long "summary"
|
||||||
|
<> O.short 's'
|
||||||
|
<> O.help "Only show summary of discovery/refinement.\n\
|
||||||
|
\Without this flag a full list of all discovered\n\
|
||||||
|
\functions and blocks is output."
|
||||||
|
)
|
||||||
|
<*> O.switch ( O.long "verbose"
|
||||||
|
<> O.short 'v'
|
||||||
|
<> O.help "Show verbose information about each discovered\n\
|
||||||
|
\function and block."
|
||||||
|
)
|
||||||
|
|
||||||
main :: IO ()
|
main :: IO ()
|
||||||
main = O.execParser optParser >>= doRefinement
|
main = O.execParser optParser >>= doRefinement
|
||||||
@ -95,17 +116,102 @@ withBinaryDiscoveredInfo :: ( X.MonadThrow m
|
|||||||
-> m a
|
-> m a
|
||||||
withBinaryDiscoveredInfo opts f arch_info bin = do
|
withBinaryDiscoveredInfo opts f arch_info bin = do
|
||||||
entries <- toList <$> entryPoints bin
|
entries <- toList <$> entryPoints bin
|
||||||
liftIO $ do putStr "Entrypoints: "
|
when (verbose opts) $
|
||||||
putStrLn $ show $ fmap show entries
|
liftIO $ do putStr "Entrypoints: "
|
||||||
-- putStrLn $ show (fmap (show . MM.segoffSegment) entries)
|
putStrLn $ show $ fmap show entries
|
||||||
-- putStrLn $ show (fmap (show . MM.segoffOffset) entries)
|
-- putStrLn $ show (fmap (show . MM.segoffSegment) entries)
|
||||||
|
-- putStrLn $ show (fmap (show . MM.segoffOffset) entries)
|
||||||
di <- liftIO $ if unrefined opts
|
di <- liftIO $ if unrefined opts
|
||||||
then return $ MD.cfgFromAddrs arch_info (memoryImage bin) M.empty entries []
|
then return $ MD.cfgFromAddrs arch_info (memoryImage bin) M.empty entries []
|
||||||
else AI.withArchConstraints arch_info $
|
else AI.withArchConstraints arch_info $
|
||||||
MR.cfgFromAddrs bin arch_info (memoryImage bin) M.empty entries []
|
MR.cfgFromAddrs bin arch_info (memoryImage bin) M.empty entries []
|
||||||
f di
|
f di
|
||||||
|
|
||||||
showDiscoveryInfo _opts di =
|
showDiscoveryInfo opts di = do
|
||||||
|
unless (summaryOnly opts) $
|
||||||
|
if verbose opts then showDetails di else showOverview di
|
||||||
|
showSummary di
|
||||||
|
|
||||||
|
data Summary = Summary { functionCnt :: Int
|
||||||
|
, functionsWithErrors :: Int
|
||||||
|
, blockCnt :: Int
|
||||||
|
, blockTranslateErrors :: Int
|
||||||
|
, blockUnknownTargetErrors :: Int -- ClassifyFailure
|
||||||
|
, maxBlocksPerFunction :: Int
|
||||||
|
}
|
||||||
|
|
||||||
|
instance Semigroup Summary where
|
||||||
|
a <> b =
|
||||||
|
Summary { functionCnt = functionCnt a + functionCnt b
|
||||||
|
, functionsWithErrors = functionsWithErrors a + functionsWithErrors b
|
||||||
|
, blockCnt = blockCnt a + blockCnt b
|
||||||
|
, blockTranslateErrors = blockTranslateErrors a + blockTranslateErrors b
|
||||||
|
, blockUnknownTargetErrors = blockUnknownTargetErrors a + blockUnknownTargetErrors b
|
||||||
|
, maxBlocksPerFunction = max (maxBlocksPerFunction a) (maxBlocksPerFunction b)
|
||||||
|
}
|
||||||
|
|
||||||
|
instance Monoid Summary where
|
||||||
|
mempty = Summary 0 0 0 0 0 0
|
||||||
|
|
||||||
|
instance Pretty Summary where
|
||||||
|
pretty s = vcat $ catMaybes
|
||||||
|
[ Just $ pretty ":: Function count =" <+> pretty (show $ functionCnt s)
|
||||||
|
, if functionsWithErrors s > 0
|
||||||
|
then Just $ pretty ":: with errors =" <+> pretty (show $ functionsWithErrors s)
|
||||||
|
else Nothing
|
||||||
|
, Just $ pretty ":: Total block count =" <+> pretty (show $ blockCnt s)
|
||||||
|
, Just $ pretty ":: Max blocks/function =" <+> pretty (show $ maxBlocksPerFunction s)
|
||||||
|
, if blockTranslateErrors s > 0
|
||||||
|
then Just (pretty ":: blocks with Translate errors (disassembly) =" <+>
|
||||||
|
pretty (show $ blockTranslateErrors s))
|
||||||
|
else Nothing
|
||||||
|
, if blockUnknownTargetErrors s > 0
|
||||||
|
then Just (pretty ":: blocks with Classification/Unknown Target errors (discovery) =" <+>
|
||||||
|
pretty (show $ blockUnknownTargetErrors s))
|
||||||
|
else Nothing
|
||||||
|
]
|
||||||
|
|
||||||
|
showSummary di =
|
||||||
|
let summarizeBlock (_blkAddr, pblk) s =
|
||||||
|
let s' = case MD.stmtsTerm (MD.blockStatementList pblk) of
|
||||||
|
MD.ParsedTranslateError _ ->
|
||||||
|
s { blockTranslateErrors = blockTranslateErrors s + 1 }
|
||||||
|
MD.ClassifyFailure {} ->
|
||||||
|
s { blockUnknownTargetErrors = blockUnknownTargetErrors s + 1 }
|
||||||
|
_ -> s
|
||||||
|
in s'
|
||||||
|
summarizeFunction (_funAddr, (Some dfi)) s =
|
||||||
|
let funcSummary = mempty { functionCnt = 1
|
||||||
|
, blockCnt = numBlks
|
||||||
|
, maxBlocksPerFunction = numBlks
|
||||||
|
}
|
||||||
|
blks = (dfi ^. MD.parsedBlocks . to M.toList)
|
||||||
|
numBlks = length blks
|
||||||
|
blksSummary = foldr summarizeBlock funcSummary blks
|
||||||
|
funcErrs = foldr (\a v -> a blksSummary + v) 0 [ blockTranslateErrors, blockUnknownTargetErrors ]
|
||||||
|
in (mappend s blksSummary)
|
||||||
|
{ functionsWithErrors = functionsWithErrors s + funcErrs
|
||||||
|
}
|
||||||
|
summarize = vcat [ pretty ":: ==== SUMMARY ===="
|
||||||
|
, pretty $ foldr summarizeFunction mempty (di ^. MD.funInfo .to M.toList)
|
||||||
|
]
|
||||||
|
in putStrLn $ show $ summarize
|
||||||
|
|
||||||
|
showOverview di =
|
||||||
|
let getIssue (blkAddr, pblk) =
|
||||||
|
let issue = case MD.stmtsTerm (MD.blockStatementList pblk) of
|
||||||
|
MD.ParsedTranslateError r -> pretty "Translation failure:" <+> pretty (show r)
|
||||||
|
MD.ClassifyFailure _ -> pretty "Classify failure"
|
||||||
|
_ -> emptyDoc
|
||||||
|
in hsep [ pretty "Block @", pretty $ show blkAddr, issue ]
|
||||||
|
funcSummary (funAddr, (Some dfi)) =
|
||||||
|
let blkSummary = map getIssue (dfi ^. MD.parsedBlocks . to M.toList)
|
||||||
|
in vcat [ pretty "Function @" <+> pretty (show funAddr)
|
||||||
|
, indent 2 $ vcat blkSummary
|
||||||
|
]
|
||||||
|
in putStrLn $ show $ vcat $ map funcSummary (di ^. MD.funInfo .to M.toList)
|
||||||
|
|
||||||
|
showDetails di =
|
||||||
forM_ (M.toList (di ^. MD.funInfo)) $ \(funAddr, Some dfi) -> do
|
forM_ (M.toList (di ^. MD.funInfo)) $ \(funAddr, Some dfi) -> do
|
||||||
putStrLn $ "===== BEGIN FUNCTION " ++ show funAddr ++ " ====="
|
putStrLn $ "===== BEGIN FUNCTION " ++ show funAddr ++ " ====="
|
||||||
forM_ (M.toList (dfi ^. MD.parsedBlocks)) $ \(blockAddr, pb) -> do
|
forM_ (M.toList (dfi ^. MD.parsedBlocks)) $ \(blockAddr, pb) -> do
|
||||||
|
Loading…
Reference in New Issue
Block a user