packages feed

llvm-pretty 0.7.0.0 → 0.7.1.0

raw patch · 3 files changed

+374/−2 lines, 3 filesdep +parsecPVP ok

version bump matches the API change (PVP)

Dependencies added: parsec

API changes (from Hackage documentation)

+ Text.LLVM.DebugUtils: BaseType :: String -> Info
+ Text.LLVM.DebugUtils: Pointer :: Info -> Info
+ Text.LLVM.DebugUtils: Structure :: [(String, Info)] -> Info
+ Text.LLVM.DebugUtils: Union :: [(String, Info)] -> Info
+ Text.LLVM.DebugUtils: Unknown :: Info
+ Text.LLVM.DebugUtils: computeFunctionTypes :: Module -> Symbol -> Maybe [Info]
+ Text.LLVM.DebugUtils: data Info
+ Text.LLVM.DebugUtils: derefInfo :: Info -> Info
+ Text.LLVM.DebugUtils: fieldIndexByName :: String -> Info -> Maybe Int
+ Text.LLVM.DebugUtils: fieldIndexByPosition :: Int -> Info -> Info
+ Text.LLVM.DebugUtils: instance GHC.Show.Show Text.LLVM.DebugUtils.Info
+ Text.LLVM.DebugUtils: localVariableNameDeclarations :: IntMap ValMd -> Define -> Map Ident Ident
+ Text.LLVM.DebugUtils: mkMdMap :: Module -> IntMap ValMd
+ Text.LLVM.DebugUtils: valMdToInfo :: MdMap -> ValMd -> Info
+ Text.LLVM.Parser: angles :: Parser a -> Parser a
+ Text.LLVM.Parser: braces :: Parser a -> Parser a
+ Text.LLVM.Parser: brackets :: Parser a -> Parser a
+ Text.LLVM.Parser: pFloatType :: Parser FloatType
+ Text.LLVM.Parser: pIdent :: Parser Ident
+ Text.LLVM.Parser: pInt32 :: Parser Int32
+ Text.LLVM.Parser: pNameChar :: Parser Char
+ Text.LLVM.Parser: pPrimType :: Parser PrimType
+ Text.LLVM.Parser: pSymbol :: Parser Symbol
+ Text.LLVM.Parser: pType :: Parser Type
+ Text.LLVM.Parser: parens :: Parser a -> Parser a
+ Text.LLVM.Parser: parseType :: String -> Either ParseError Type
+ Text.LLVM.Parser: spaced :: Parser a -> Parser a

Files

llvm-pretty.cabal view
@@ -1,5 +1,5 @@ Name:                llvm-pretty-Version:             0.7.0.0+Version:             0.7.1.0 License:             BSD3 License-file:        LICENSE Author:              Trevor Elliott@@ -12,7 +12,7 @@   A pretty printing library that was inspired by the LLVM binding by Lennart   Augustsson.  The library provides a monadic interface to a pretty printer,   that allows functions to be defined and called, generating the corresponding-  LLVM assemblly when run.+  LLVM assembly when run.  source-repository head   type:                 git@@ -25,11 +25,14 @@   Exposed-modules:     Text.LLVM                        Text.LLVM.AST                        Text.LLVM.Labels+                       Text.LLVM.Parser                        Text.LLVM.PP+                       Text.LLVM.DebugUtils   Other-modules:       Text.LLVM.Util    Build-depends:       base       >= 4 && < 5,                        containers >= 0.4,+                       parsec     >= 3,                        pretty     >= 1.0.1,                        monadLib   >= 3.6.1 
+ src/Text/LLVM/DebugUtils.hs view
@@ -0,0 +1,263 @@+{-# Language TransformListComp, MonadComprehensions #-}+{- |+Module           : $Header$+Description      : This module interprets the DWARF information associated+                   with a function's argument and return types in order to+                   interpret field name references.+License          : BSD3+Stability        : provisional+Point-of-contact : emertens+-}+module Text.LLVM.DebugUtils+  ( -- * Definition type analyzer+    Info(..), computeFunctionTypes, valMdToInfo+  , localVariableNameDeclarations++  -- * Metadata lookup+  , mkMdMap++  -- * Type structure dereference+  , derefInfo+  , fieldIndexByPosition+  , fieldIndexByName+  ) where++import           Control.Applicative    ((<|>))+import           Control.Monad          ((<=<))+import           Data.IntMap            (IntMap)+import qualified Data.IntMap as IntMap+import           Data.List              (elemIndex, tails)+import           Data.Map               (Map)+import qualified Data.Map    as Map+import           Data.Maybe             (fromMaybe, listToMaybe, maybeToList)+import           Data.Word              (Word16)+import           Text.LLVM.AST++dbgKind :: String+dbgKind = "dbg"++llvmDbgCuKey :: String+llvmDbgCuKey = "llvm.dbg.cu"++dwarfPointer, dwarfStruct, dwarfTypedef, dwarfUnion, dwarfBasetype,+  dwarfConst :: Word16+dwarfPointer  = 0x0f+dwarfStruct   = 0x13+dwarfTypedef  = 0x16+dwarfUnion    = 0x17+dwarfBasetype = 0x24+dwarfConst    = 0x26++type MdMap = IntMap ValMd++data Info+  = Pointer Info+  | Structure [(String,Info)]+  | Union     [(String,Info)]+  | BaseType String+  | Unknown+  deriving Show++{-+import Text.Show.Pretty+import Data.Foldable++test =+  do test' "/Users/emertens/Source/saw/saw-script\+           \/examples/llvm/dotprod_struct.bc"+     test' "/Users/emertens/Desktop/temp.bc"++test' fn =+  do Right bc <- parseBitCodeFromFile fn+     let mdMap = mkMdMap bc+     traverse_ (putStrLn . ppShow . analyzeDefine mdMap) (modDefines bc)+-}++-- | Compute an 'IntMap' of the unnamed metadata in a module+mkMdMap :: Module -> IntMap ValMd+mkMdMap m = IntMap.fromList [ (umIndex md, umValues md) | md <- modUnnamedMd m ]++------------------------------------------------------------------------++getDebugInfo :: MdMap -> ValMd -> Maybe DebugInfo+getDebugInfo mdMap (ValMdRef i)    = getDebugInfo mdMap =<< IntMap.lookup i mdMap+getDebugInfo _ (ValMdDebugInfo di) = Just di+getDebugInfo _ _                   = Nothing+++getList :: MdMap -> ValMd -> Maybe [Maybe ValMd]+getList mdMap (ValMdRef i) = getList mdMap =<< IntMap.lookup i mdMap+getList _ (ValMdNode di)   = Just di+getList _ _                = Nothing++------------------------------------------------------------------------++valMdToInfo :: MdMap -> ValMd -> Info+valMdToInfo mdMap val =+  maybe Unknown (debugInfoToInfo mdMap) (getDebugInfo mdMap val)+++valMdToInfo' :: MdMap -> Maybe ValMd -> Info+valMdToInfo' = maybe Unknown . valMdToInfo+++debugInfoToInfo :: MdMap -> DebugInfo -> Info+debugInfoToInfo mdMap (DebugInfoDerivedType dt)+  | didtTag dt == dwarfPointer  = Pointer (valMdToInfo' mdMap (didtBaseType dt))+  | didtTag dt == dwarfTypedef  =          valMdToInfo' mdMap (didtBaseType dt)+  | didtTag dt == dwarfConst    =          valMdToInfo' mdMap (didtBaseType dt)+debugInfoToInfo _     (DebugInfoBasicType bt)+  | dibtTag bt == dwarfBasetype = BaseType (dibtName bt)+debugInfoToInfo mdMap (DebugInfoCompositeType ct)+  | dictTag ct == dwarfStruct   = maybe Unknown Structure (getFields mdMap ct)+  | dictTag ct == dwarfUnion    = maybe Unknown Union     (getFields mdMap ct)+debugInfoToInfo _ _             = Unknown+++getFields :: MdMap -> DICompositeType -> Maybe [(String, Info)]+getFields mdMap ct =+  traverse (debugInfoToField mdMap <=< getDebugInfo mdMap)+       =<< sequence =<< getList mdMap =<< dictElements ct+++debugInfoToField :: MdMap -> DebugInfo -> Maybe (String, Info)+debugInfoToField mdMap di =+  do DebugInfoDerivedType dt <- Just di+     fieldName               <- didtName dt+     Just (fieldName, valMdToInfo' mdMap (didtBaseType dt))+++-- | Compute the structures of a function's return and argument types+-- using DWARF information metadata of the LLVM module. Different+-- versions of LLVM make this information available via different+-- paths. This function attempts to support the variations.+computeFunctionTypes ::+  Module       {- ^ module to search                     -} ->+  Symbol       {- ^ function symbol                      -} ->+  Maybe [Info] {- ^ return and argument type information -}+computeFunctionTypes m sym =+  [ maybe (BaseType "void") (valMdToInfo mdMap) <$> types+     | let mdMap = mkMdMap m+     , sp <- findSubprogramViaDefine mdMap m sym+         <|> findSubprogramViaCu     mdMap m sym+     , DebugInfoSubroutineType st <- getDebugInfo mdMap =<< dispType sp+     , types                      <- getList mdMap      =<< distTypeArray st+     ]+++-- | This method of computing argument type information works on at least LLVM 3.8+findSubprogramViaDefine ::+  IntMap ValMd       {- ^ unnamed metadata                             -} ->+  Module             {- ^ module to search                             -} ->+  Symbol             {- ^ function symbol to find                      -} ->+  Maybe DISubprogram {- ^ debug information related to function symbol -}+findSubprogramViaDefine mdMap m sym =+  [ sp+     | def                    <- modDefines m+     , defName def == sym+     , then listToMaybe ----- commits to a choice -----+     , dbgMd                  <- Map.lookup dbgKind (defMetadata def)+     , DebugInfoSubprogram sp <- getDebugInfo mdMap dbgMd+     ]+++-- | This method of computing function debugging information works on LLVM 3.7+findSubprogramViaCu ::+  MdMap              {- ^ map of unnamed metadata                -} ->+  Module             {- ^ module to search                       -} ->+  Symbol             {- ^ function symbol to search for          -} ->+  Maybe DISubprogram {- ^ debugging information for given symbol -}+findSubprogramViaCu mdMap m (Symbol sym) = listToMaybe+  [ sp+    | md                      <- modNamedMd m+    , nmName md == llvmDbgCuKey+    , ref                     <- nmValues md+    , DebugInfoCompileUnit cu <- maybeToList  $ getDebugInfo mdMap $ ValMdRef ref+    , Just entry              <- fromMaybe [] $ getList mdMap =<< dicuSubprograms cu+    , DebugInfoSubprogram sp  <- maybeToList  $ getDebugInfo mdMap entry+    , dispName sp == Just sym+    ]+++------------------------------------------------------------------------++-- | If the argument describes a pointer, return the information for the+-- type that it points do.+derefInfo ::+  Info {- ^ pointer type information                -} ->+  Info {- ^ type information of pointer's base type -}+derefInfo (Pointer x) = x+derefInfo _           = Unknown++-- | If the argument describes a composite type, returns the type of the+-- field by zero-based index into the list of fields.+fieldIndexByPosition ::+  Int  {- ^ zero-based field index               -} ->+  Info {- ^ composite type information           -} ->+  Info {- ^ type information for specified field -}+fieldIndexByPosition i info =+  case info of+    Structure xs -> go xs+    Union     xs -> go xs+    _            -> Unknown+  where+    go xs = case drop i xs of+              []  -> Unknown+              x:_ -> snd x++-- | If the argument describes a composite type, return the first, zero-based+-- index of the field in that type that matches the given name.+fieldIndexByName ::+  String    {- ^ field name                                  -} ->+  Info      {- ^ composite type info                         -} ->+  Maybe Int {- ^ zero-based index of field matching the name -}+fieldIndexByName n info =+  case info of+    Structure xs -> go xs+    Union     xs -> go xs+    _            -> Nothing+  where+    go = elemIndex n . map fst++------------------------------------------------------------------------++localVariableNameDeclarations ::+  IntMap ValMd    {- ^ unnamed metadata      -} ->+  Define          {- ^ function definition   -} ->+  Map Ident Ident {- ^ raw name, actual name -}+localVariableNameDeclarations mdMap def =+  case defBody def of+    blk1 : _ -> foldr aux Map.empty (tails (bbStmts blk1))+    _        -> Map.empty+  where++    aux :: [Stmt] -> Map Ident Ident -> Map Ident Ident+    aux ( Effect (Store src dst _) _+        : Effect (Call _ _ (ValSymbol (Symbol what)) [var,md,_]) _+        : _) sofar+      | what == "llvm.dbg.declare"+      , Just dstIdent <- extractIdent dst+      , Just srcIdent <- extractIdent src+      , Just varIdent <- extractIdent var+      , dstIdent == varIdent+      , Just name <- extractLvName md+      = Map.insert name srcIdent sofar++    aux ( Effect (Call _ _ (ValSymbol (Symbol what)) [var,_,md,_]) _+        : _) sofar+      | what == "llvm.dbg.value"+      , Just key  <- extractIdent var+      , Just name <- extractLvName md+      = Map.insert name key sofar++    aux _ sofar = sofar++    extractIdent :: Typed Value -> Maybe Ident+    extractIdent (Typed _ (ValIdent i)) = Just i+    extractIdent _                      = Nothing++    extractLvName :: Typed Value -> Maybe Ident+    extractLvName mdArg =+      do ValMd md                    <- Just (typedValue mdArg)+         DebugInfoLocalVariable dilv <- getDebugInfo mdMap md+         Ident <$> dilvName dilv
+ src/Text/LLVM/Parser.hs view
@@ -0,0 +1,106 @@+module Text.LLVM.Parser where++import Text.LLVM.AST++import Data.Int (Int32)+import Text.Parsec+import Text.Parsec.String+++-- Identifiers and Symbols -----------------------------------------------------++pNameChar :: Parser Char+pNameChar = letter <|> digit <|> oneOf "-$._"++pIdent :: Parser Ident+pIdent = Ident <$> (char '%' >> many1 pNameChar)++pSymbol :: Parser Symbol+pSymbol = Symbol <$> (char '@' >> many1 pNameChar)+++-- Types -----------------------------------------------------------------------++pInt32 :: Parser Int32+pInt32 = read <$> many1 digit++pPrimType :: Parser PrimType+pPrimType = choice+  [ Integer <$> try (char 'i' >> pInt32)+  , FloatType <$> try pFloatType+  , try (string "label")    >> return Label+  , try (string "void")     >> return Void+  , try (string "x86mmx")   >> return X86mmx+  , try (string "metadata") >> return Metadata+  ]++pFloatType :: Parser FloatType+pFloatType = choice+  [ try (string "half")      >> return Half+  , try (string "float")     >> return Float+  , try (string "double")    >> return Double+  , try (string "fp128")     >> return Fp128+  , try (string "x86_fp80")  >> return X86_fp80+  , try (string "ppc_fp128") >> return PPC_fp128+  ]++pType :: Parser Type+pType = pType0 >>= pFunPtr+  where+    pType0 :: Parser Type+    pType0 =+      choice+      [ Alias <$> pIdent+      , brackets (pNumType Array)+      , braces (Struct <$> pTypeList)+      , angles (braces (PackedStruct <$> pTypeList) <|> spaced (pNumType Vector))+      , string "opaque" >> return Opaque+      , PrimType <$> pPrimType+      ]++    pTypeList :: Parser [Type]+    pTypeList = sepBy (spaced pType) (char ',')++    pNumType :: (Int32 -> Type -> Type) -> Parser Type+    pNumType f =+      do n <- pInt32+         spaces >> char 'x' >> spaces+         t <- pType+         return (f n t)++    pArgList :: Type -> Parser Type+    pArgList t0 = spaces >> (p1 [] <|> return (FunTy t0 [] False))+      where+        p1 ts =+          (string "..." >> spaces >> return (FunTy t0 (reverse ts) True))+          <|> (pType >>= \t -> (spaces >> p2 (t : ts)))+        p2 ts =+          (char ',' >> spaces >> p1 ts)+          <|> return (FunTy t0 (reverse ts) False)++    pFunPtr :: Type -> Parser Type+    pFunPtr t0 = pFun <|> pPtr <|> return t0+      where+        pFun = parens (pArgList t0) >>= pFunPtr+        pPtr = char '*' >> pFunPtr (PtrTo t0)++parseType :: String -> Either ParseError Type+parseType = parse (pType <* eof) "<internal>"+++-- Utilities -------------------------------------------------------------------++angles :: Parser a -> Parser a+angles body = char '<' *> body <* char '>'++braces :: Parser a -> Parser a+braces body = char '{' *> body <* char '}'++brackets :: Parser a -> Parser a+brackets body = char '[' *> body <* char ']'++parens :: Parser a -> Parser a+parens body = char '(' *> body <* char ')'++spaced :: Parser a -> Parser a+spaced body = spaces *> body <* spaces