PageRenderTime 61ms CodeModel.GetById 34ms RepoModel.GetById 0ms app.codeStats 0ms

/compiler/nativeGen/Dwarf/Types.hs

https://github.com/scpmw/ghc
Haskell | 212 lines | 164 code | 26 blank | 22 comment | 7 complexity | 8ae3217c5b9da1cf17224ec859c63296 MD5 | raw file
  1. module Dwarf.Types
  2. ( DwarfInfo(..)
  3. , pprDwarfInfo
  4. , pprDwarfInfoOpen
  5. , pprDwarfInfoClose
  6. , abbrevDecls
  7. , DwarfFiles
  8. , pprByte
  9. , pprData4'
  10. , pprWord
  11. , pprLEBWord
  12. , pprBuffer
  13. )
  14. where
  15. import CLabel
  16. import FastString
  17. import Outputable
  18. import Platform
  19. import UniqFM ( UniqFM )
  20. import Dwarf.Constants
  21. import Data.Bits
  22. import Data.Word
  23. import Data.Char
  24. import Binary
  25. import Foreign
  26. import System.IO.Unsafe as Unsafe
  27. -- | Individual dwarf records
  28. data DwarfInfo
  29. = DwarfCompileUnit { dwChildren :: [DwarfInfo]
  30. , dwName :: String
  31. , dwProducer :: String
  32. , dwCompDir :: String
  33. , dwLineLabel :: LitString }
  34. | DwarfSubprogram { dwChildren :: [DwarfInfo]
  35. , dwName :: String
  36. , dwLabel :: CLabel }
  37. | DwarfBlock { dwChildren :: [DwarfInfo]
  38. , dwLabel :: CLabel
  39. , dwMarker :: CLabel }
  40. -- | Abbreviation codes used in dwarf file
  41. data DwarfAbbrev
  42. = DwAbbrNull -- | Pseudo, used for marking the end of lists
  43. | DwAbbrCompileUnit
  44. | DwAbbrSubprogram
  45. | DwAbbrBlock
  46. deriving (Eq, Enum)
  47. -- | Map of files to IDs (used for .loc / .file directives)
  48. type DwarfFiles = UniqFM (FastString, Int)
  49. -- | Gives code to use in binary represenation.
  50. abbrevToCode :: DwarfAbbrev -> Word
  51. abbrevToCode = fromIntegral . fromEnum
  52. pprByte :: Word8 -> SDoc
  53. pprByte x = ptext (sLit "\t.byte ") <> ppr (fromIntegral x :: Word)
  54. -- | Prints a number in "little endian base 128" format. The idea is
  55. -- to optimize for small numbers by stopping once all further bytes
  56. -- would be 0. The highest bit in every byte signals whether there
  57. -- are further bytes to read.
  58. pprLEBWord :: Word -> SDoc
  59. pprLEBWord x = go x
  60. where go x | x < 128 = pprByte (fromIntegral x)
  61. | otherwise = pprByte (fromIntegral $ 128 .|. (x .&. 127)) $$
  62. go (x `shiftR` 7)
  63. -- | Abbreviation declaration. This explains the binary encoding we
  64. -- use for representing @DwarfInfo@.
  65. abbrevDecls :: SDoc
  66. abbrevDecls =
  67. let mkAbbrev abbr tag chld flds =
  68. let fld (tag, form) = pprLEBWord tag $$ pprLEBWord form
  69. in pprLEBWord (abbrevToCode abbr) $$ pprLEBWord tag $$ pprByte chld $$
  70. vcat (map fld flds) $$ pprByte 0 $$ pprByte 0
  71. in dwarfAbbrevSection $$
  72. ptext dwarfAbbrevLabel <> colon $$
  73. mkAbbrev DwAbbrCompileUnit dW_TAG_compile_unit dW_CHILDREN_yes
  74. [ (dW_AT_name, dW_FORM_string)
  75. , (dW_AT_producer, dW_FORM_string)
  76. , (dW_AT_language, dW_FORM_data4)
  77. , (dW_AT_comp_dir, dW_FORM_string)
  78. , (dW_AT_stmt_list, dW_FORM_data4)
  79. ] $$
  80. mkAbbrev DwAbbrSubprogram dW_TAG_subprogram dW_CHILDREN_yes
  81. [ (dW_AT_name, dW_FORM_string)
  82. , (dW_AT_MIPS_linkage_name, dW_FORM_string)
  83. , (dW_AT_external, dW_FORM_flag)
  84. , (dW_AT_low_pc, dW_FORM_addr)
  85. , (dW_AT_high_pc, dW_FORM_addr)
  86. , (dW_AT_frame_base, dW_FORM_block1)
  87. ] $$
  88. mkAbbrev DwAbbrBlock dW_TAG_lexical_block dW_CHILDREN_yes
  89. [ (dW_AT_name, dW_FORM_string)
  90. , (dW_AT_low_pc, dW_FORM_addr)
  91. , (dW_AT_high_pc, dW_FORM_addr)
  92. ]
  93. pprAbbrev :: DwarfAbbrev -> SDoc
  94. pprAbbrev = pprLEBWord . abbrevToCode
  95. pprString' :: SDoc -> SDoc
  96. pprString' str = ptext (sLit "\t.asciz \"") <> str <> char '"'
  97. pprString :: String -> SDoc
  98. pprString = pprString' . hcat . map escape
  99. where escape '\\' = ptext (sLit "\\\\")
  100. escape '\"' = ptext (sLit "\\\"")
  101. escape '\n' = ptext (sLit "\\n")
  102. escape '?' = ptext (sLit "\\?") -- silence trigraph warnings
  103. escape c | isAscii c && isPrint c
  104. = char c
  105. | otherwise
  106. = let ch = ord c
  107. in char '\\' <>
  108. char (intToDigit (ch `div` 64)) <>
  109. char (intToDigit ((ch `div` 8) `mod` 8)) <>
  110. char (intToDigit (ch `mod` 8))
  111. pprData4' :: SDoc -> SDoc
  112. pprData4' x = ptext (sLit "\t.long ") <> x
  113. pprData4 :: Word -> SDoc
  114. pprData4 = pprData4' . ppr
  115. -- | Machine-dependent word directive
  116. pprWord :: SDoc -> SDoc
  117. pprWord s = (<> s) . sdocWithPlatform $ \plat ->
  118. case platformWordSize plat of
  119. 4 -> ptext (sLit "\t.long ")
  120. 8 -> ptext (sLit "\t.quad ")
  121. n -> panic $ "pprWord: Unsupported target platform word length " ++ show n ++ "!"
  122. pprFlag :: Bool -> SDoc
  123. pprFlag True = ptext (sLit "\t.byte 0xff")
  124. pprFlag False = ptext (sLit "\t.byte 0")
  125. pprDwarfInfo :: DwarfInfo -> SDoc
  126. pprDwarfInfo d = pprDwarfInfoOpen d $$
  127. vcat (map pprDwarfInfo (dwChildren d)) $$
  128. pprDwarfInfoClose
  129. -- | Prints assembler data corresponding to DWARF info records. Note
  130. -- that the binary format of this is paramterized in @abbrevDecls@ and
  131. -- has to be kept in synch.
  132. pprDwarfInfoOpen :: DwarfInfo -> SDoc
  133. pprDwarfInfoOpen (DwarfCompileUnit _ name producer compDir lineLbl) =
  134. pprAbbrev DwAbbrCompileUnit
  135. $$ pprString name
  136. $$ pprString producer
  137. $$ pprData4 dW_LANG_Haskell
  138. $$ pprString compDir
  139. $$ pprData4' (ptext lineLbl)
  140. pprDwarfInfoOpen (DwarfSubprogram _ name label) = sdocWithDynFlags $ \df ->
  141. pprAbbrev DwAbbrSubprogram
  142. $$ pprString name
  143. $$ pprString (renderWithStyle df (ppr label) (mkCodeStyle CStyle))
  144. $$ pprFlag (externallyVisibleCLabel label)
  145. $$ pprWord (ppr label)
  146. $$ pprWord (ppr $ mkAsmTempEndLabel label)
  147. $$ pprByte 1
  148. $$ pprByte dW_OP_call_frame_cfa
  149. pprDwarfInfoOpen (DwarfBlock _ label marker) = sdocWithDynFlags $ \df ->
  150. pprAbbrev DwAbbrBlock
  151. $$ pprString (renderWithStyle df (ppr label) (mkCodeStyle CStyle))
  152. $$ pprWord (ppr marker)
  153. $$ pprWord (ppr $ mkAsmTempEndLabel marker)
  154. pprDwarfInfoClose :: SDoc
  155. pprDwarfInfoClose = pprAbbrev DwAbbrNull
  156. -- | Generate code for emitting the given buffer. Will take care to
  157. -- escape it appropriatly.
  158. pprBuffer :: (Int, ForeignPtr Word8) -> SDoc
  159. pprBuffer (len, buf) = Unsafe.unsafePerformIO $ do
  160. -- As we output a string, we need to do escaping. We approximate
  161. -- here that the escaped string will have double the size of the
  162. -- original buffer. That should be plenty of space given the fact
  163. -- that we expect to be converting a lot of text.
  164. bh <- openBinMem (len * 2)
  165. let go p q | p == q = return ()
  166. | otherwise = peek p >>= escape . fromIntegral >> go (p `plusPtr` 1) q
  167. escape c
  168. | c == ord '\\' = putB '\\' >> putB '\\'
  169. | c == ord '\"' = putB '\\' >> putB '"'
  170. | c == ord '\n' = putB '\\' >> putB 'n'
  171. | c == ord '?' = putB '\\' >> putB '?' -- silence trigraph warnings
  172. | isAscii (chr c) && isPrint (chr c)
  173. = putByte bh (fromIntegral c)
  174. | otherwise = do putB '\\'
  175. putB $ intToDigit (c `div` 64)
  176. putB $ intToDigit ((c `div` 8) `mod` 8)
  177. putB $ intToDigit (c `mod` 8)
  178. putB :: Char -> IO ()
  179. putB = putByte bh . fromIntegral . ord
  180. {-# INLINE putB #-}
  181. withForeignPtr buf $ \p ->
  182. go p (p `plusPtr` len)
  183. -- Pack result into a string
  184. (elen, ebuf) <- getBinMemBuf bh
  185. buf <- withForeignPtr ebuf $ \p -> mkFastStringForeignPtr p ebuf elen
  186. return $ ptext (sLit "\t.ascii ") <> doubleQuotes (ftext buf)