Output source notes in extended DWARF DIEs
authorBen Gamari <ben@smart-cactus.org>
Fri, 23 Oct 2015 08:52:12 +0000 (10:52 +0200)
committerBen Gamari <ben@smart-cactus.org>
Mon, 23 Nov 2015 16:49:05 +0000 (17:49 +0100)
In order to accomplish this we need to ensure that emit DIEs for all
DebugBlocks, even those that have been optimized out, lest we end up
with undefined symbols of parents at link time.

Differential Revision: https://phabricator.haskell.org/D1279

compiler/cmm/CLabel.hs
compiler/nativeGen/Dwarf.hs
compiler/nativeGen/Dwarf/Constants.hs
compiler/nativeGen/Dwarf/Types.hs

index 0f1d61b..2682421 100644 (file)
@@ -46,6 +46,7 @@ module CLabel (
         mkAsmTempLabel,
         mkAsmTempDerivedLabel,
         mkAsmTempEndLabel,
+        mkAsmTempDieLabel,
 
         mkPlainModuleInitLabel,
 
@@ -562,6 +563,11 @@ mkAsmTempEndLabel l = mkAsmTempDerivedLabel l (fsLit "_end")
 mkPlainModuleInitLabel :: Module -> CLabel
 mkPlainModuleInitLabel mod      = PlainModuleInitLabel mod
 
+-- | Construct a label for a DWARF Debug Information Entity (DIE)
+-- describing another symbol.
+mkAsmTempDieLabel :: CLabel -> CLabel
+mkAsmTempDieLabel l = mkAsmTempDerivedLabel l (fsLit "_die")
+
 -- -----------------------------------------------------------------------------
 -- Convert between different kinds of label
 
index b19f534..54422ec 100644 (file)
@@ -18,6 +18,7 @@ import UniqSupply
 import Dwarf.Constants
 import Dwarf.Types
 
+import Control.Monad    ( mfilter )
 import Data.Maybe
 import Data.List        ( sortBy )
 import Data.Ord         ( comparing )
@@ -172,23 +173,33 @@ parent, B.
 -- | Generate DWARF info for a procedure debug block
 procToDwarf :: DynFlags -> DebugBlock -> DwarfInfo
 procToDwarf df prc
-  = DwarfSubprogram { dwChildren = foldr blockToDwarf [] $ dblBlocks prc
+  = DwarfSubprogram { dwChildren = map (blockToDwarf df) (dblBlocks prc)
                     , dwName     = case dblSourceTick prc of
                          Just s@SourceNote{} -> sourceName s
                          _otherwise -> showSDocDump df $ ppr $ dblLabel prc
                     , dwLabel    = dblCLabel prc
+                    , dwParent   = fmap mkAsmTempDieLabel
+                                   $ mfilter (/= dblCLabel prc)
+                                   $ fmap dblCLabel (dblParent prc)
+                      -- Omit parent if it would be self-referential
                     }
 
 -- | Generate DWARF info for a block
-blockToDwarf :: DebugBlock -> [DwarfInfo] -> [DwarfInfo]
-blockToDwarf blk dws
-  | isJust (dblPosition blk) = dw : dws
-  | otherwise                = nested ++ dws -- block was optimized out, flatten
-  where nested = foldr blockToDwarf [] $ dblBlocks blk
-        dw = DwarfBlock { dwChildren = nested
-                        , dwLabel    = dblCLabel blk
-                        , dwMarker   = mkAsmTempLabel (dblLabel blk)
-                        }
+blockToDwarf :: DynFlags -> DebugBlock -> DwarfInfo
+blockToDwarf df blk
+  = DwarfBlock { dwChildren = concatMap (tickToDwarf df) (dblTicks blk)
+                              ++ map (blockToDwarf df) (dblBlocks blk)
+               , dwLabel    = dblCLabel blk
+               , dwMarker   = marker
+               }
+  where
+    marker
+      | Just _ <- dblPosition blk = Just $ mkAsmTempLabel $ dblLabel blk
+      | otherwise                 = Nothing   -- block was optimized out
+
+tickToDwarf :: DynFlags -> Tickish () -> [DwarfInfo]
+tickToDwarf _  (SourceNote ss _) = [DwarfSrcNote ss]
+tickToDwarf _ _ = []
 
 -- | Generates the data for the debug frame section, which encodes the
 -- desired stack unwind behaviour for the debugger
index a46d113..40e4e7d 100644 (file)
@@ -22,7 +22,8 @@ dW_TAG_compile_unit, dW_TAG_subroutine_type,
   dW_TAG_file_type, dW_TAG_subprogram, dW_TAG_lexical_block,
   dW_TAG_base_type, dW_TAG_structure_type, dW_TAG_pointer_type,
   dW_TAG_array_type, dW_TAG_subrange_type, dW_TAG_typedef,
-  dW_TAG_variable, dW_TAG_arg_variable, dW_TAG_auto_variable :: Word
+  dW_TAG_variable, dW_TAG_arg_variable, dW_TAG_auto_variable,
+  dW_TAG_ghc_src_note :: Word
 dW_TAG_array_type      = 1
 dW_TAG_lexical_block   = 11
 dW_TAG_pointer_type    = 15
@@ -38,6 +39,8 @@ dW_TAG_variable        = 52
 dW_TAG_auto_variable   = 256
 dW_TAG_arg_variable    = 257
 
+dW_TAG_ghc_src_note    = 0x5b00
+
 -- * Dwarf attributes
 dW_AT_name, dW_AT_stmt_list, dW_AT_low_pc, dW_AT_high_pc, dW_AT_language,
   dW_AT_comp_dir, dW_AT_producer, dW_AT_external, dW_AT_frame_base,
@@ -54,19 +57,41 @@ dW_AT_frame_base        = 0x40
 dW_AT_use_UTF8          = 0x53
 dW_AT_MIPS_linkage_name = 0x2007
 
--- * Abbrev declaration
+-- * Custom DWARF attributes
+-- Chosen a more or less random section of the vendor-extensible region
+
+-- ** Describing C-- blocks
+-- These appear in DW_TAG_lexical_scope DIEs corresponding to C-- blocks
+dW_AT_ghc_tick_parent :: Word
+dW_AT_ghc_tick_parent     = 0x2b20
+
+-- ** Describing source notes
+-- These appear in DW_TAG_ghc_src_note DIEs
+dW_AT_ghc_span_file, dW_AT_ghc_span_start_line,
+  dW_AT_ghc_span_start_col, dW_AT_ghc_span_end_line,
+  dW_AT_ghc_span_end_col :: Word
+dW_AT_ghc_span_file       = 0x2b00
+dW_AT_ghc_span_start_line = 0x2b01
+dW_AT_ghc_span_start_col  = 0x2b02
+dW_AT_ghc_span_end_line   = 0x2b03
+dW_AT_ghc_span_end_col    = 0x2b04
+
+
+-- * Abbrev declarations
 dW_CHILDREN_no, dW_CHILDREN_yes :: Word8
 dW_CHILDREN_no  = 0
 dW_CHILDREN_yes = 1
 
-dW_FORM_addr, dW_FORM_data4, dW_FORM_string, dW_FORM_flag,
-  dW_FORM_block1, dW_FORM_ref4, dW_FORM_flag_present :: Word
+dW_FORM_addr, dW_FORM_data2, dW_FORM_data4, dW_FORM_string, dW_FORM_flag,
+  dW_FORM_block1, dW_FORM_ref4, dW_FORM_ref_addr, dW_FORM_flag_present :: Word
 dW_FORM_addr   = 0x01
+dW_FORM_data2  = 0x05
 dW_FORM_data4  = 0x06
 dW_FORM_string = 0x08
 dW_FORM_flag   = 0x0c
 dW_FORM_block1 = 0x0a
-dW_FORM_ref4   = 0x13
+dW_FORM_ref_addr     = 0x10
+dW_FORM_ref4         = 0x13
 dW_FORM_flag_present = 0x19
 
 -- * Dwarf native types
index 8647253..91a5e41 100644 (file)
@@ -31,6 +31,7 @@ import Outputable
 import Platform
 import Unique
 import Reg
+import SrcLoc
 
 import Dwarf.Constants
 
@@ -54,10 +55,16 @@ data DwarfInfo
                      , dwLineLabel :: LitString }
   | DwarfSubprogram { dwChildren :: [DwarfInfo]
                     , dwName :: String
-                    , dwLabel :: CLabel }
+                    , dwLabel :: CLabel
+                    , dwParent :: Maybe CLabel
+                      -- ^ label of DIE belonging to the parent tick
+                    }
   | DwarfBlock { dwChildren :: [DwarfInfo]
                , dwLabel :: CLabel
-               , dwMarker :: CLabel }
+               , dwMarker :: Maybe CLabel
+               }
+  | DwarfSrcNote { dwSrcSpan :: RealSrcSpan
+                 }
 
 -- | Abbreviation codes used for encoding above records in the
 -- @.debug_info@ section.
@@ -65,7 +72,10 @@ data DwarfAbbrev
   = DwAbbrNull          -- ^ Pseudo, used for marking the end of lists
   | DwAbbrCompileUnit
   | DwAbbrSubprogram
+  | DwAbbrSubprogramWithParent
+  | DwAbbrBlockWithoutCode
   | DwAbbrBlock
+  | DwAbbrGhcSrcNote
   deriving (Eq, Enum)
 
 -- | Generate assembly for the given abbreviation code
@@ -81,6 +91,16 @@ pprAbbrevDecls haveDebugLine =
         let fld (tag, form) = pprLEBWord tag $$ pprLEBWord form
         in pprAbbrev abbr $$ pprLEBWord tag $$ pprByte chld $$
            vcat (map fld flds) $$ pprByte 0 $$ pprByte 0
+      -- These are shared between DwAbbrSubprogram and
+      -- DwAbbrSubprogramWithParent
+      subprogramAttrs =
+           [ (dW_AT_name, dW_FORM_string)
+           , (dW_AT_MIPS_linkage_name, dW_FORM_string)
+           , (dW_AT_external, dW_FORM_flag)
+           , (dW_AT_low_pc, dW_FORM_addr)
+           , (dW_AT_high_pc, dW_FORM_addr)
+           , (dW_AT_frame_base, dW_FORM_block1)
+           ]
   in dwarfAbbrevSection $$
      ptext dwarfAbbrevLabel <> colon $$
      mkAbbrev DwAbbrCompileUnit dW_TAG_compile_unit dW_CHILDREN_yes
@@ -96,26 +116,40 @@ pprAbbrevDecls haveDebugLine =
         then [ (dW_AT_stmt_list, dW_FORM_data4) ]
         else [])) $$
      mkAbbrev DwAbbrSubprogram dW_TAG_subprogram dW_CHILDREN_yes
+       subprogramAttrs $$
+     mkAbbrev DwAbbrSubprogramWithParent dW_TAG_subprogram dW_CHILDREN_yes
+       (subprogramAttrs ++ [(dW_AT_ghc_tick_parent, dW_FORM_ref_addr)]) $$
+     mkAbbrev DwAbbrBlockWithoutCode dW_TAG_lexical_block dW_CHILDREN_yes
        [ (dW_AT_name, dW_FORM_string)
-       , (dW_AT_MIPS_linkage_name, dW_FORM_string)
-       , (dW_AT_external, dW_FORM_flag)
-       , (dW_AT_low_pc, dW_FORM_addr)
-       , (dW_AT_high_pc, dW_FORM_addr)
-       , (dW_AT_frame_base, dW_FORM_block1)
        ] $$
      mkAbbrev DwAbbrBlock dW_TAG_lexical_block dW_CHILDREN_yes
        [ (dW_AT_name, dW_FORM_string)
        , (dW_AT_low_pc, dW_FORM_addr)
        , (dW_AT_high_pc, dW_FORM_addr)
        ] $$
+     mkAbbrev DwAbbrGhcSrcNote dW_TAG_ghc_src_note dW_CHILDREN_no
+       [ (dW_AT_ghc_span_file, dW_FORM_string)
+       , (dW_AT_ghc_span_start_line, dW_FORM_data4)
+       , (dW_AT_ghc_span_start_col, dW_FORM_data2)
+       , (dW_AT_ghc_span_end_line, dW_FORM_data4)
+       , (dW_AT_ghc_span_end_col, dW_FORM_data2)
+       ] $$
      pprByte 0
 
 -- | Generate assembly for DWARF data
 pprDwarfInfo :: Bool -> DwarfInfo -> SDoc
 pprDwarfInfo haveSrc d
-  = pprDwarfInfoOpen haveSrc d $$
-    vcat (map (pprDwarfInfo haveSrc) (dwChildren d)) $$
-    pprDwarfInfoClose
+  = case d of
+      DwarfCompileUnit {}  -> hasChildren
+      DwarfSubprogram {}   -> hasChildren
+      DwarfBlock {}        -> hasChildren
+      DwarfSrcNote {}      -> noChildren
+  where
+    hasChildren =
+        pprDwarfInfoOpen haveSrc d $$
+        vcat (map (pprDwarfInfo haveSrc) (dwChildren d)) $$
+        pprDwarfInfoClose
+    noChildren = pprDwarfInfoOpen haveSrc d
 
 -- | Prints assembler data corresponding to DWARF info records. Note
 -- that the binary format of this is paramterized in @abbrevDecls@ and
@@ -133,8 +167,10 @@ pprDwarfInfoOpen haveSrc (DwarfCompileUnit _ name producer compDir lowLabel
   $$ if haveSrc
      then sectionOffset (ptext lineLbl) (ptext dwarfLineLabel)
      else empty
-pprDwarfInfoOpen _ (DwarfSubprogram _ name label) = sdocWithDynFlags $ \df ->
-  pprAbbrev DwAbbrSubprogram
+pprDwarfInfoOpen _ (DwarfSubprogram _ name label
+                                    parent) = sdocWithDynFlags $ \df ->
+  ppr (mkAsmTempDieLabel label) <> colon
+  $$ pprAbbrev abbrev
   $$ pprString name
   $$ pprString (renderWithStyle df (ppr label) (mkCodeStyle CStyle))
   $$ pprFlag (externallyVisibleCLabel label)
@@ -142,11 +178,29 @@ pprDwarfInfoOpen _ (DwarfSubprogram _ name label) = sdocWithDynFlags $ \df ->
   $$ pprWord (ppr $ mkAsmTempEndLabel label)
   $$ pprByte 1
   $$ pprByte dW_OP_call_frame_cfa
-pprDwarfInfoOpen _ (DwarfBlock _ label marker) = sdocWithDynFlags $ \df ->
-  pprAbbrev DwAbbrBlock
+  $$ parentValue
+  where
+    abbrev = case parent of Nothing -> DwAbbrSubprogram
+                            Just _  -> DwAbbrSubprogramWithParent
+    parentValue = maybe empty pprParentDie parent
+    pprParentDie sym = sectionOffset (ppr sym) (ptext dwarfInfoLabel)
+pprDwarfInfoOpen _ (DwarfBlock _ label Nothing) = sdocWithDynFlags $ \df ->
+  ppr (mkAsmTempDieLabel label) <> colon
+  $$ pprAbbrev DwAbbrBlockWithoutCode
+  $$ pprString (renderWithStyle df (ppr label) (mkCodeStyle CStyle))
+pprDwarfInfoOpen _ (DwarfBlock _ label (Just marker)) = sdocWithDynFlags $ \df ->
+  ppr (mkAsmTempDieLabel label) <> colon
+  $$ pprAbbrev DwAbbrBlock
   $$ pprString (renderWithStyle df (ppr label) (mkCodeStyle CStyle))
   $$ pprWord (ppr marker)
   $$ pprWord (ppr $ mkAsmTempEndLabel marker)
+pprDwarfInfoOpen _ (DwarfSrcNote ss) =
+  pprAbbrev DwAbbrGhcSrcNote
+  $$ pprString' (ftext $ srcSpanFile ss)
+  $$ pprData4 (fromIntegral $ srcSpanStartLine ss)
+  $$ pprHalf (fromIntegral $ srcSpanStartCol ss)
+  $$ pprData4 (fromIntegral $ srcSpanEndLine ss)
+  $$ pprHalf (fromIntegral $ srcSpanEndCol ss)
 
 -- | Close a DWARF info record with children
 pprDwarfInfoClose :: SDoc