├── .gitignore ├── LICENSE ├── README.md ├── Setup.hs ├── llvm-tools.cabal ├── share ├── OpenLayers.js ├── graph.css ├── img │ ├── cloud-popup-relative.png │ ├── drag-rectangle-off.png │ ├── drag-rectangle-on.png │ ├── east-mini.png │ ├── layer-switcher-maximize.png │ ├── layer-switcher-minimize.png │ ├── marker-blue.png │ ├── marker-gold.png │ ├── marker-green.png │ ├── marker.png │ ├── measuring-stick-off.png │ ├── measuring-stick-on.png │ ├── north-mini.png │ ├── panning-hand-off.png │ ├── panning-hand-on.png │ ├── slider.png │ ├── south-mini.png │ ├── west-mini.png │ ├── zoom-minus-mini.png │ ├── zoom-plus-mini.png │ ├── zoom-world-mini.png │ └── zoombar.png ├── jquery-1.7.1.js └── showGraph.js ├── src └── LLVM │ ├── HtmlWrapper.hs │ ├── SvgInspection.hs │ └── VisualizeGraph.hs └── tools ├── DumpLLVMModule.hs ├── FindValue.hs ├── TypeUnificationCheck.hs └── ViewIRGraph.hs /.gitignore: -------------------------------------------------------------------------------- 1 | dist/ 2 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c)2012, Tristan Ravitch 2 | 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without 6 | modification, are permitted provided that the following conditions are met: 7 | 8 | * Redistributions of source code must retain the above copyright 9 | notice, this list of conditions and the following disclaimer. 10 | 11 | * Redistributions in binary form must reproduce the above 12 | copyright notice, this list of conditions and the following 13 | disclaimer in the documentation and/or other materials provided 14 | with the distribution. 15 | 16 | * Neither the name of Tristan Ravitch nor the names of other 17 | contributors may be used to endorse or promote products derived 18 | from this software without specific prior written permission. 19 | 20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 21 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 23 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 24 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 25 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 26 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 27 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 28 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 30 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | This package includes some tools to visualize the LLVM IR. Current 2 | visualizations include static call graphs, CFGs, CDGs, dominator 3 | trees, and some simple escape graphs. Output formats include most 4 | graphviz-supported formats, along with an HTML-based format. 5 | 6 | # Usage 7 | 8 | Options for the visualizer: 9 | 10 | -o --output=[FILE or DIR] The destination of a file output 11 | -t --type=[GRAPHTYPE] The graph requested. One of Cfg, Cdg, Cg, 12 | Domtree, Postdomtree 13 | -f --format=GVOUT The type of output to produce: Gtk, Xlib, Html, XDot, 14 | Eps, Jpeg, Pdf, Png, Ps, Ps2, Svg. Default: Gtk 15 | -? --help Display help message 16 | 17 | 18 | For all graph types except the call graph, the output specifies a 19 | *directory*. The directory will contain one output file for each 20 | function in the input IR module. For the static call graph, the 21 | output is a single file. If the format is 'Html', the output is 22 | always a directory. 23 | 24 | The Html format is special. It produces an SVG embedded in an HTML 25 | page. The SVG can be navigated (via panning and zooming) using an 26 | openstreetmap-style interface (it uses the OpenLayers library). 27 | 28 | Input files can be LLVM bitcode files, LLVM assembly files, or C/C++ source 29 | files. 30 | 31 | # Dependencies 32 | 33 | This package depends on a few other Haskell libraries that are not yet 34 | on Hackage: 35 | 36 | * hbgl 37 | * haggle 38 | * ifscs 39 | * llvm-base-types 40 | * llvm-data-interop 41 | * llvm-analysis 42 | 43 | Additionally, it requires that you have the LLVM shared libraries (versions 44 | 3.0-3.2) and tools installed on your system (`llvm-config` must be in your 45 | `PATH`). 46 | 47 | # Installation 48 | Installation would look something like: 49 | 50 | ```bash 51 | REPOSITORIES="hbgl-experimental 52 | haggle 53 | ifscs 54 | itanium-abi 55 | llvm-base-types 56 | llvm-data-interop 57 | llvm-analysis 58 | llvm-tools" 59 | 60 | # Download the repositories 61 | for REPO in $REPOSITORIES 62 | do 63 | git clone git://github.com/travitch/$REPO.git 64 | done 65 | 66 | # Add ./ prefixes to each repository (for cabal) 67 | TOINSTALL=`echo ./$REPOSITORIES | sed 's: : ./:g'` 68 | 69 | # Build the tools along with dependencies 70 | cabal install $TOINSTALL 71 | ``` 72 | 73 | -------------------------------------------------------------------------------- /Setup.hs: -------------------------------------------------------------------------------- 1 | import Distribution.Simple 2 | main = defaultMain 3 | -------------------------------------------------------------------------------- /llvm-tools.cabal: -------------------------------------------------------------------------------- 1 | name: llvm-tools 2 | version: 0.2.0.1 3 | synopsis: Useful tools built on llvm-analysis 4 | license: BSD3 5 | license-file: LICENSE 6 | author: Tristan Ravitch 7 | maintainer: travitch@cs.wisc.edu 8 | category: Development 9 | build-type: Simple 10 | cabal-version: >=1.10 11 | extra-source-files: README.md 12 | data-files: share/jquery-1.7.1.js 13 | share/OpenLayers.js 14 | share/showGraph.js 15 | share/*.css 16 | share/img/*.png 17 | description: This package includes some tools to visualize the LLVM IR. 18 | Current visualizations include static call graphs, CFGs, CDGs, 19 | dominator trees, and some simple escape graphs. Output formats 20 | include most graphviz-supported formats, along with an 21 | HTML-based format. 22 | 23 | library 24 | default-language: Haskell2010 25 | build-depends: base == 4.*, 26 | blaze-html >= 0.5, 27 | filemanip >= 0.3.5.2, 28 | llvm-analysis >= 0.2.0, 29 | llvm-data-interop >= 0.2.0, 30 | bytestring, directory, filepath, xml, 31 | graphviz, parallel-io, blaze-markup 32 | hs-source-dirs: src 33 | exposed-modules: LLVM.VisualizeGraph 34 | other-modules: Paths_llvm_tools, 35 | LLVM.HtmlWrapper, 36 | LLVM.SvgInspection 37 | ghc-options: -Wall 38 | ghc-prof-options: -auto-all 39 | 40 | executable DumpLLVMModule 41 | default-language: Haskell2010 42 | build-depends: base == 4.*, 43 | llvm-data-interop >= 0.2.0 44 | main-is: DumpLLVMModule.hs 45 | hs-source-dirs: tools 46 | ghc-options: -Wall -rtsopts 47 | 48 | executable FindValue 49 | default-language: Haskell2010 50 | build-depends: base == 4.*, 51 | llvm-analysis >= 0.2.0, 52 | llvm-data-interop >= 0.2.0, 53 | unordered-containers 54 | main-is: FindValue.hs 55 | hs-source-dirs: tools 56 | ghc-options: -Wall -rtsopts 57 | ghc-prof-options: -auto-all 58 | 59 | executable ViewIRGraph 60 | default-language: Haskell2010 61 | build-depends: base == 4.*, 62 | optparse-applicative >= 0.7.0 && < 0.8, 63 | llvm-analysis >= 0.2.0, 64 | llvm-tools >= 0.2.0.0, 65 | containers, graphviz 66 | main-is: ViewIRGraph.hs 67 | hs-source-dirs: tools 68 | ghc-options: -Wall -rtsopts -threaded 69 | ghc-prof-options: -auto-all 70 | 71 | -- executable TypeUnificationCheck 72 | -- default-language: Haskell2010 73 | -- build-depends: base == 4.*, 74 | -- llvm-analysis >= 0.2.0, 75 | -- llvm-data-interop >= 0.2.0, 76 | -- bytestring, attoparsec, 77 | -- process-conduit, attoparsec-conduit, conduit 78 | -- main-is: TypeUnificationCheck.hs 79 | -- hs-source-dirs: tools 80 | -- ghc-options: -Wall -rtsopts -threaded 81 | -- ghc-prof-options: -auto-all 82 | -------------------------------------------------------------------------------- /share/graph.css: -------------------------------------------------------------------------------- 1 | html, body { 2 | height: 99%; 3 | width: 99%; 4 | } 5 | 6 | #map { 7 | width: 100%; 8 | height: 100%; 9 | border: 1px solid black; 10 | } 11 | -------------------------------------------------------------------------------- /share/img/cloud-popup-relative.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/travitch/llvm-tools/85072a2cf35b2e6ceec014e80fe5c73050d2c55c/share/img/cloud-popup-relative.png -------------------------------------------------------------------------------- /share/img/drag-rectangle-off.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/travitch/llvm-tools/85072a2cf35b2e6ceec014e80fe5c73050d2c55c/share/img/drag-rectangle-off.png -------------------------------------------------------------------------------- /share/img/drag-rectangle-on.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/travitch/llvm-tools/85072a2cf35b2e6ceec014e80fe5c73050d2c55c/share/img/drag-rectangle-on.png -------------------------------------------------------------------------------- /share/img/east-mini.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/travitch/llvm-tools/85072a2cf35b2e6ceec014e80fe5c73050d2c55c/share/img/east-mini.png -------------------------------------------------------------------------------- /share/img/layer-switcher-maximize.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/travitch/llvm-tools/85072a2cf35b2e6ceec014e80fe5c73050d2c55c/share/img/layer-switcher-maximize.png -------------------------------------------------------------------------------- /share/img/layer-switcher-minimize.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/travitch/llvm-tools/85072a2cf35b2e6ceec014e80fe5c73050d2c55c/share/img/layer-switcher-minimize.png -------------------------------------------------------------------------------- /share/img/marker-blue.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/travitch/llvm-tools/85072a2cf35b2e6ceec014e80fe5c73050d2c55c/share/img/marker-blue.png -------------------------------------------------------------------------------- /share/img/marker-gold.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/travitch/llvm-tools/85072a2cf35b2e6ceec014e80fe5c73050d2c55c/share/img/marker-gold.png -------------------------------------------------------------------------------- /share/img/marker-green.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/travitch/llvm-tools/85072a2cf35b2e6ceec014e80fe5c73050d2c55c/share/img/marker-green.png -------------------------------------------------------------------------------- /share/img/marker.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/travitch/llvm-tools/85072a2cf35b2e6ceec014e80fe5c73050d2c55c/share/img/marker.png -------------------------------------------------------------------------------- /share/img/measuring-stick-off.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/travitch/llvm-tools/85072a2cf35b2e6ceec014e80fe5c73050d2c55c/share/img/measuring-stick-off.png -------------------------------------------------------------------------------- /share/img/measuring-stick-on.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/travitch/llvm-tools/85072a2cf35b2e6ceec014e80fe5c73050d2c55c/share/img/measuring-stick-on.png -------------------------------------------------------------------------------- /share/img/north-mini.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/travitch/llvm-tools/85072a2cf35b2e6ceec014e80fe5c73050d2c55c/share/img/north-mini.png -------------------------------------------------------------------------------- /share/img/panning-hand-off.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/travitch/llvm-tools/85072a2cf35b2e6ceec014e80fe5c73050d2c55c/share/img/panning-hand-off.png -------------------------------------------------------------------------------- /share/img/panning-hand-on.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/travitch/llvm-tools/85072a2cf35b2e6ceec014e80fe5c73050d2c55c/share/img/panning-hand-on.png -------------------------------------------------------------------------------- /share/img/slider.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/travitch/llvm-tools/85072a2cf35b2e6ceec014e80fe5c73050d2c55c/share/img/slider.png -------------------------------------------------------------------------------- /share/img/south-mini.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/travitch/llvm-tools/85072a2cf35b2e6ceec014e80fe5c73050d2c55c/share/img/south-mini.png -------------------------------------------------------------------------------- /share/img/west-mini.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/travitch/llvm-tools/85072a2cf35b2e6ceec014e80fe5c73050d2c55c/share/img/west-mini.png -------------------------------------------------------------------------------- /share/img/zoom-minus-mini.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/travitch/llvm-tools/85072a2cf35b2e6ceec014e80fe5c73050d2c55c/share/img/zoom-minus-mini.png -------------------------------------------------------------------------------- /share/img/zoom-plus-mini.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/travitch/llvm-tools/85072a2cf35b2e6ceec014e80fe5c73050d2c55c/share/img/zoom-plus-mini.png -------------------------------------------------------------------------------- /share/img/zoom-world-mini.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/travitch/llvm-tools/85072a2cf35b2e6ceec014e80fe5c73050d2c55c/share/img/zoom-world-mini.png -------------------------------------------------------------------------------- /share/img/zoombar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/travitch/llvm-tools/85072a2cf35b2e6ceec014e80fe5c73050d2c55c/share/img/zoombar.png -------------------------------------------------------------------------------- /share/showGraph.js: -------------------------------------------------------------------------------- 1 | function showGraph(divId, filename, w, h) { 2 | var g = new OpenLayers.Map(divId, {}); 3 | var options = {numZoomLevels: 20}; 4 | var b = new OpenLayers.Bounds(0, 0, w, h); 5 | var s = new OpenLayers.Size(g.getSize().w / 20, g.getSize().h / 20); 6 | var layer = new OpenLayers.Layer.Image('Graph', filename, b, s, options); 7 | g.addLayer(layer); 8 | g.zoomToMaxExtent(); 9 | } 10 | -------------------------------------------------------------------------------- /src/LLVM/HtmlWrapper.hs: -------------------------------------------------------------------------------- 1 | {-# LANGUAGE OverloadedStrings #-} 2 | module LLVM.HtmlWrapper ( writeHtmlIndex, writeHtmlWrapper ) where 3 | 4 | import Control.Monad ( forM_ ) 5 | import qualified Data.ByteString.Lazy as LBS 6 | import Data.Monoid 7 | import System.FilePath 8 | import Text.Blaze.Html5 9 | import qualified Text.Blaze.Html5 as H 10 | import qualified Text.Blaze.Html5.Attributes as A 11 | import Text.Blaze.Html.Renderer.Utf8 ( renderHtml ) 12 | 13 | writeHtmlWrapper :: FilePath -> FilePath -> FilePath -> String -> Double -> Double -> IO () 14 | writeHtmlWrapper dirname hfilename gfilename fname w h = do 15 | let wrapper = htmlWrapper fname gfilename w h 16 | LBS.writeFile (dirname hfilename) (renderHtml wrapper) 17 | 18 | htmlWrapper :: String -> FilePath -> Double -> Double -> Html 19 | htmlWrapper fname gfilename w h = H.docTypeHtml $ do 20 | H.head $ do 21 | H.title (toHtml fname) 22 | H.script ! A.src "OpenLayers.js" ! A.type_ "text/javascript" $ return () 23 | H.script ! A.src "jquery-1.7.1.js" ! A.type_ "text/javascript" $ return () 24 | H.script ! A.src "showGraph.js" ! A.type_ "text/javascript" $ return () 25 | H.link ! A.href "graph.css" ! A.rel "stylesheet" ! A.type_ "text/css" 26 | H.body $ do 27 | H.div ! A.id "map" $ return () 28 | H.script ! A.type_ "text/javascript" $ H.preEscapedToMarkup (loadScript gfilename w h) 29 | 30 | loadScript :: String -> Double -> Double -> String 31 | loadScript n w h = mconcat [ "$(window).bind('load', function () {" 32 | , " showGraph('map', '", n , "', ", show w, ", ", show h, ");\n" 33 | , "});" 34 | ] 35 | 36 | writeHtmlIndex :: FilePath -> [String] -> IO () 37 | writeHtmlIndex dir funcNames = 38 | LBS.writeFile (dir "index.html") (renderHtml (htmlIndex funcNames)) 39 | 40 | htmlIndex :: [String] -> Html 41 | htmlIndex funcNames = H.docTypeHtml $ do 42 | H.head $ do 43 | H.title "Module Summary" 44 | H.body $ do 45 | H.ul $ forM_ funcNames mkLink 46 | where 47 | mkLink n = H.li $ do 48 | let ref = "graphs" n <.> "html" 49 | H.a ! A.href (toValue ref) $ toHtml n -------------------------------------------------------------------------------- /src/LLVM/SvgInspection.hs: -------------------------------------------------------------------------------- 1 | module LLVM.SvgInspection ( getSvgSize ) where 2 | 3 | import Data.ByteString ( ByteString ) 4 | import Text.XML.Light 5 | 6 | getSvgSize :: ByteString -> Maybe (Double, Double) 7 | getSvgSize s = do 8 | root <- parseXMLDoc s 9 | vbox <- findAttr blank_name { qName = "viewBox" } root 10 | let [_, _, w, h] = words vbox 11 | case (reads w, reads h) of 12 | ([(dw, "")], [(dh, "")]) -> Just (dw, dh) 13 | _ -> Nothing 14 | -------------------------------------------------------------------------------- /src/LLVM/VisualizeGraph.hs: -------------------------------------------------------------------------------- 1 | module LLVM.VisualizeGraph ( 2 | OutputType(..), 3 | visualizeGraph 4 | ) where 5 | 6 | import GHC.Conc ( getNumCapabilities ) 7 | 8 | import Control.Arrow 9 | import Control.Concurrent.ParallelIO.Local 10 | import Control.Monad ( when ) 11 | import qualified Data.ByteString as BS 12 | import Data.GraphViz 13 | import Data.Maybe ( isNothing ) 14 | 15 | import System.Directory 16 | import System.FilePath 17 | import System.FilePath.Glob 18 | 19 | import Paths_llvm_tools 20 | 21 | import LLVM.Analysis 22 | import LLVM.Analysis.Util.Testing ( buildModule ) 23 | import LLVM.Parse ( defaultParserOptions, parseLLVMFile ) 24 | 25 | import LLVM.HtmlWrapper 26 | import LLVM.SvgInspection 27 | 28 | data OutputType = CanvasOutput GraphvizCanvas 29 | | FileOutput GraphvizOutput 30 | | HtmlOutput 31 | deriving (Show) 32 | 33 | 34 | -- | Visualize a graph-based analysis with graphviz. It handles many 35 | -- common options including both file and canvas output. 36 | visualizeGraph :: (ToGraphviz a) 37 | => FilePath -- ^ Input file name 38 | -> Maybe FilePath -- ^ Output file name 39 | -> OutputType -- ^ Type of output requested 40 | -> [String] -- ^ Module optimization flags 41 | -> (Module -> [(String, a)]) -- ^ A function to turn a Module into some graphs 42 | -> IO () 43 | visualizeGraph inFile outFile fmt optOptions fromModule = do 44 | let p = parseLLVMFile defaultParserOptions 45 | m <- buildModule [] optOptions p inFile 46 | let gs = fromModule m 47 | 48 | case fmt of 49 | HtmlOutput -> do 50 | when (isNothing outFile) $ ioError $ userError "Output directory not specified" 51 | -- Make a directory for all of the output and render each graph 52 | -- with graphviz to svg format. For each svg, create an html 53 | -- wrapper page (with an index page). The html page should be simple 54 | -- and just embed the SVG and load svgpan (and maybe jquery) 55 | let Just outFile' = outFile 56 | gdir = outFile' "graphs" 57 | 58 | createDirectoryIfMissing True gdir 59 | let jsAndCss = [ "OpenLayers.js" 60 | , "jquery-1.7.1.js" 61 | , "showGraph.js" 62 | , "graph.css" 63 | ] 64 | mapM_ (installStaticFile gdir) jsAndCss 65 | installStaticSubdir "img" gdir 66 | 67 | caps <- getNumCapabilities 68 | let actions = map (makeFunctionPage toGraphviz gdir) gs 69 | withPool caps $ \capPool -> parallel_ capPool actions 70 | writeHtmlIndex outFile' (map fst gs) 71 | 72 | -- If we are showing canvases, ignore function names 73 | CanvasOutput o -> mapM_ (\(_,g) -> runGraphvizCanvas' (toGraphviz g) o) gs 74 | 75 | FileOutput o -> do 76 | when (isNothing outFile) $ ioError $ userError "Output file not specified" 77 | let Just outFile' = outFile 78 | case gs of 79 | [(_, g)] -> runGraphviz (toGraphviz g) o outFile' >> return () 80 | _ -> do 81 | -- If we have more than one function, put all of them in 82 | -- the given directory 83 | createDirectoryIfMissing True outFile' 84 | mapM_ (writeDotGraph toGraphviz outFile' o) gs 85 | 86 | installStaticFile :: FilePath -> FilePath -> IO () 87 | installStaticFile dir name = do 88 | file <- getDataFileName ("share" name) 89 | copyFile file (dir name) 90 | 91 | -- | Install all of the files in the given subdir of the datadir to a 92 | -- destdir. The subdir is created (this is basically cp -R). 93 | installStaticSubdir :: FilePath -> FilePath -> IO () 94 | installStaticSubdir sdir destdir = do 95 | dd <- getDataDir 96 | let patt = dd "share" sdir "*" 97 | files <- namesMatching patt 98 | let toDest f = destdir sdir takeFileName f 99 | let namesAndDests = map (id &&& toDest) files 100 | createDirectoryIfMissing True (destdir sdir) 101 | mapM_ (uncurry copyFile) namesAndDests 102 | 103 | makeFunctionPage :: (PrintDotRepr dg n) 104 | => (a -> dg n) 105 | -> FilePath 106 | -> (FilePath, a) 107 | -> IO () 108 | makeFunctionPage toGraph gdir (fname, g) = do 109 | let svgname = gdir gfilename 110 | dg = toGraph g 111 | -- Use the more general graphvizWithHandle so that we can read the 112 | -- generated image before writing it to disk. This lets us extract 113 | -- its dimensions. The other alternative is to just use the default 114 | -- graphviz to create a file and then read the file - this led to 115 | -- races when writing with multiple threads. This approach is 116 | -- safer. 117 | dims <- graphvizWithHandle (commandFor dg) dg Svg $ \h -> do 118 | svgContent <- BS.hGetContents h 119 | BS.writeFile svgname svgContent 120 | return (getSvgSize svgContent) 121 | let Just (w, h) = dims 122 | writeHtmlWrapper gdir hfilename gfilename fname w h 123 | where 124 | gfilename = fname <.> "svg" 125 | hfilename = fname <.> "html" 126 | 127 | writeDotGraph :: (PrintDotRepr dg n) 128 | => (a -> dg n) 129 | -> FilePath 130 | -> GraphvizOutput 131 | -> (FilePath, a) 132 | -> IO () 133 | writeDotGraph toGraph dirname o (funcName, g) = 134 | runGraphviz (toGraph g) o filename >> return () 135 | where 136 | filename = dirname funcName <.> toExt o 137 | 138 | toExt :: GraphvizOutput -> String 139 | toExt o = 140 | case o of 141 | Canon -> "dot" 142 | XDot {} -> "dot" 143 | Eps -> "eps" 144 | Fig -> "fig" 145 | Jpeg -> "jpg" 146 | Pdf -> "pdf" 147 | Png -> "png" 148 | Ps -> "ps" 149 | Ps2 -> "ps" 150 | Svg -> "svg" 151 | _ -> error $ "Unsupported format: " ++ show o 152 | -------------------------------------------------------------------------------- /tools/DumpLLVMModule.hs: -------------------------------------------------------------------------------- 1 | module Main ( main ) where 2 | 3 | import System.Environment ( getArgs ) 4 | import LLVM.Parse 5 | 6 | main :: IO () 7 | main = do 8 | [bcname] <- getArgs 9 | m <- parseLLVMFile defaultParserOptions bcname 10 | print m 11 | -------------------------------------------------------------------------------- /tools/FindValue.hs: -------------------------------------------------------------------------------- 1 | -- | This program takes a Module and a list of unique Value ids. It 2 | -- prints out the details of each named value that exists in the 3 | -- module. 4 | -- 5 | -- It currently does not dump constants 6 | module Main ( main ) where 7 | 8 | import Data.HashSet ( HashSet ) 9 | import qualified Data.HashSet as HS 10 | import System.Environment ( getArgs ) 11 | import Text.Printf 12 | 13 | import LLVM.Analysis 14 | import LLVM.Parse 15 | 16 | main :: IO () 17 | main = do 18 | fname : nodes <- getArgs 19 | let nodeSet = HS.fromList (map read nodes) 20 | mm <- parseLLVMFile defaultParserOptions fname 21 | let vals = findNodes nodeSet mm 22 | mapM_ showValue vals 23 | 24 | findNodes :: HashSet Int -> Module -> [Value] 25 | findNodes nodes m = filter ((`HS.member` nodes) . valueUniqueId) allVals 26 | where 27 | fs = moduleDefinedFunctions m 28 | allArgs = concatMap functionParameters fs 29 | allBlocks = concatMap functionBody fs 30 | allInsts = concatMap basicBlockInstructions allBlocks 31 | allVals = concat [ map toValue fs 32 | , map toValue (moduleGlobalVariables m) 33 | , map toValue (moduleExternalValues m) 34 | , map toValue (moduleExternalFunctions m) 35 | , map toValue (moduleAliases m) 36 | , map toValue allBlocks 37 | , map toValue allInsts 38 | , map toValue allArgs 39 | ] 40 | 41 | showValue :: Value -> IO () 42 | showValue v = do 43 | _ <- printf "%d\n" (valueUniqueId v) 44 | _ <- case valueContent v of 45 | FunctionC f -> printf " Function: %s\n" (show (functionName f)) 46 | ArgumentC a -> do 47 | let f = argumentFunction a 48 | printf " Argument: <%s:%s>\n" (show (functionName f)) (show (argumentName a)) 49 | BasicBlockC b -> do 50 | let f = basicBlockFunction b 51 | printf " Block: <%s:%s>\n" (show (functionName f)) (show (basicBlockName b)) 52 | GlobalVariableC g -> printf " GlobalVar: %s\n" (show (globalVariableName g)) 53 | GlobalAliasC a -> printf " GlobalAlias: %s\n" (show (globalAliasName a)) 54 | ExternalValueC e -> printf " ExternalValue: %s\n" (show (externalValueName e)) 55 | ExternalFunctionC e -> printf " ExternalFunction: %s\n" (show (externalFunctionName e)) 56 | InstructionC i -> do 57 | let Just b = instructionBasicBlock i 58 | f = basicBlockFunction b 59 | printf " Instruction: <%s:%s:%s>\n" (show (functionName f)) (show (basicBlockName b)) (show v) 60 | ConstantC _ -> printf " Constants not supported\n" 61 | return () -------------------------------------------------------------------------------- /tools/TypeUnificationCheck.hs: -------------------------------------------------------------------------------- 1 | -- | Take a single bitcode file and pump it through opt -S and parse 2 | -- out the named type definitions (structs, unions, and classes). 3 | -- Sort them and print them. 4 | -- 5 | -- Then use llvm-data-interop to parse the bitcode and print its 6 | -- sorted type list. It will be apparent if types were properly 7 | -- unified or not. 8 | module Main ( main ) where 9 | 10 | import Control.Monad ( forM_ ) 11 | import Data.Attoparsec.ByteString.Char8 12 | import Data.Conduit 13 | import Data.Conduit.Attoparsec 14 | import Data.Conduit.Process as P 15 | import Data.List ( sort ) 16 | import Data.Monoid 17 | import Data.ByteString.Char8 ( ByteString ) 18 | import qualified Data.ByteString.Char8 as BS 19 | import System.Environment ( getArgs ) 20 | import Text.Printf 21 | 22 | import LLVM.Analysis 23 | -- import LLVM.Analysis.Util.Environment 24 | import LLVM.Parse 25 | 26 | llvmTypesParser :: Parser [ByteString] 27 | llvmTypesParser = do 28 | skipWhile (/='%') 29 | res <- many1 typeLineParser 30 | skipWhile (const True) 31 | return res 32 | 33 | typePrefix :: Parser ByteString 34 | typePrefix = choice [ string (BS.pack "%struct") 35 | , string (BS.pack "%union") 36 | , string (BS.pack "%class") 37 | ] 38 | 39 | typeLineParser :: Parser ByteString 40 | typeLineParser = do 41 | pfx <- typePrefix 42 | suffix <- takeTill (=='\n') 43 | endOfLine 44 | return $ pfx `mappend` suffix 45 | 46 | main :: IO () 47 | main = do 48 | [bcfile] <- getArgs 49 | 50 | -- First, get the output of opt. This uses process-conduit and 51 | -- attoparsec-conduit to parse the output of opt in constant space. 52 | typeLines <- runResourceT $ do 53 | sourceProcess (P.proc "opt" ["-S", bcfile]) $$ sinkParser llvmTypesParser 54 | 55 | let typeDefs = sort typeLines 56 | 57 | _ <- printf "opt types: %d\n" (length typeDefs) 58 | forM_ typeDefs $ \td -> BS.putStrLn (BS.pack " " `mappend` td) 59 | 60 | m <- parseLLVMFile defaultParserOptions bcfile 61 | let ts = sort $ map show $ filter isStructType (moduleRetainedTypes m) 62 | _ <- printf "unified types: %d\n" (length ts) 63 | forM_ ts $ \td -> putStrLn (" " ++ td) 64 | 65 | isStructType :: Type -> Bool 66 | isStructType t = 67 | case t of 68 | TypeStruct (Right _) _ _ -> True 69 | _ -> False 70 | -------------------------------------------------------------------------------- /tools/ViewIRGraph.hs: -------------------------------------------------------------------------------- 1 | {-# LANGUAGE NoMonomorphismRestriction #-} 2 | module Main ( main ) where 3 | 4 | import Control.Arrow 5 | import Control.Applicative 6 | import Data.GraphViz 7 | import Data.Monoid 8 | import Options.Applicative 9 | 10 | import LLVM.VisualizeGraph 11 | 12 | import LLVM.Analysis 13 | import LLVM.Analysis.CFG 14 | import LLVM.Analysis.CDG 15 | import LLVM.Analysis.CallGraph 16 | import LLVM.Analysis.Dominance 17 | import LLVM.Analysis.PointsTo.TrivialFunction 18 | 19 | data Opts = Opts { outputFile :: Maybe FilePath 20 | , graphType :: GraphType 21 | , outputFormat :: OutputType 22 | , inputFile :: FilePath 23 | } 24 | 25 | cmdOpts :: Parser Opts 26 | cmdOpts = Opts 27 | <$> optional (strOption 28 | ( long "output" 29 | <> short 'o' 30 | <> metavar "FILE/DIR" 31 | <> help "The destination of a file output")) 32 | <*> option 33 | ( long "type" 34 | <> short 't' 35 | <> metavar "TYPE" 36 | <> help "The graph requested. One of Cfg, Cdg, Cg, Domtree, Postdomtree") 37 | <*> nullOption 38 | ( long "format" 39 | <> short 'f' 40 | <> metavar "FORMAT" 41 | <> reader parseOutputType 42 | <> help "The type of output to produce: Gtk, Xlib, Html, Canon, XDot, Eps, Jpeg, Pdf, Png, Ps, Ps2, Svg. Default: Gtk" 43 | <> value (CanvasOutput Gtk)) 44 | <*> argument str ( metavar "FILE" ) 45 | 46 | data GraphType = Cfg 47 | | Cdg 48 | | Cg 49 | | Domtree 50 | | Postdomtree 51 | deriving (Read, Show, Eq, Ord) 52 | 53 | main :: IO () 54 | main = execParser args >>= realMain 55 | where 56 | args = info (helper <*> cmdOpts) 57 | ( fullDesc 58 | <> progDesc "Generate the specified graph TYPE for FILE" 59 | <> header "ViewIRGraph - View different graphs for LLVM IR modules in a variety of formats") 60 | 61 | realMain :: Opts -> IO () 62 | realMain opts = do 63 | let gt = graphType opts 64 | inFile = inputFile opts 65 | outFile = outputFile opts 66 | fmt = outputFormat opts 67 | 68 | vizGraph = visualizeGraph inFile outFile fmt optOptions 69 | 70 | case gt of 71 | Cfg -> vizGraph mkCFGs 72 | Cdg -> vizGraph mkCDGs 73 | Cg -> vizGraph mkCG 74 | Domtree -> vizGraph mkDTs 75 | Postdomtree -> vizGraph mkPDTs 76 | where 77 | optOptions = [ "-mem2reg", "-basicaa" ] 78 | 79 | mkPDTs :: Module -> [(String, PostdominatorTree)] 80 | mkPDTs m = map (getFuncName &&& toTree) fs 81 | where 82 | fs = moduleDefinedFunctions m 83 | toTree = postdominatorTree . controlFlowGraph 84 | 85 | mkDTs :: Module -> [(String, DominatorTree)] 86 | mkDTs m = map (getFuncName &&& toTree) fs 87 | where 88 | fs = moduleDefinedFunctions m 89 | toTree = dominatorTree . controlFlowGraph 90 | 91 | mkCG :: Module -> [(String, CallGraph)] 92 | mkCG m = [("Module", callGraph m aa [])] 93 | where 94 | aa = runPointsToAnalysis m 95 | 96 | mkCFGs :: Module -> [(String, CFG)] 97 | mkCFGs m = map (getFuncName &&& controlFlowGraph) fs 98 | where 99 | fs = moduleDefinedFunctions m 100 | 101 | mkCDGs :: Module -> [(String, CDG)] 102 | mkCDGs m = map (getFuncName &&& toCDG) fs 103 | where 104 | fs = moduleDefinedFunctions m 105 | toCDG = controlDependenceGraph . controlFlowGraph 106 | 107 | getFuncName :: Function -> String 108 | getFuncName = identifierAsString . functionName 109 | 110 | 111 | 112 | -- Command line helpers 113 | 114 | 115 | parseOutputType :: String -> ReadM OutputType 116 | parseOutputType fmt = 117 | case fmt of 118 | "Html" -> return HtmlOutput 119 | _ -> case reads fmt of 120 | [(Gtk, [])] -> return $ CanvasOutput Gtk 121 | [(Xlib, [])] -> return $ CanvasOutput Xlib 122 | _ -> case reads fmt of 123 | [(gout, [])] -> return $ FileOutput gout 124 | _ -> readerError "Invalid output type" 125 | --------------------------------------------------------------------------------