A Haskell library for reading and writing DWARF debugging information.

Files
README.md

thorin #

A Haskell library for reading and writing DWARF 2–5 debugging information.

Overview #

thorin provides strongly-typed, lazy parsing and generation of DWARF debugging sections. It supports:

  • DWARF 2–5 — all standard section types including .debug_info, .debug_line, .debug_frame, .eh_frame, range lists, location lists, macro info, and name tables
  • Split DWARF — read and write .dwo files and .dwp package files
  • Assembly output — emit .s text with label-diff expressions for relocatable sections
  • Minimal dependencies — only base, bytestring, containers, deepseq, and vector

Architecture #

The library is organized in three layers:

  • Core (Data.Dwarf.Constants, Data.Dwarf.Encoding, Data.Dwarf.Types, Data.Dwarf.Section) — DWARF constants, encoding parameters, and section wrappers
  • Read (Data.Dwarf.Read.*) — incremental parsers for all section types. Entry point: Data.Dwarf.Read.Unit.parseUnits
  • Write (Data.Dwarf.Write.*) — section generators with automatic abbreviation tables and string pools. Entry point: Data.Dwarf.Write.writeSections

The top-level Data.Dwarf module re-exports the most commonly used types.

Quick start #

Reading DWARF sections #

import Data.Dwarf.Encoding (Endianness(..), endianReader)
import Data.Dwarf.Read.Unit (parseUnits)
import Data.Dwarf.Section

-- Build a Sections record from raw ByteStrings
let secs = Sections
      { secDebugInfo   = DebugInfo (endianReader LittleEndian infoBytes)
      , secDebugAbbrev = DebugAbbrev (endianReader LittleEndian abbrevBytes)
      , secDebugStr    = Just (DebugStr (endianReader LittleEndian strBytes))
      , ...            -- remaining fields Nothing
      }

-- Parse lazily — only decodes units as you consume the list
let units = parseUnits secs  -- [Either DwarfError Unit]

Writing DWARF sections #

import Data.Dwarf.Write (writeSections, WriteSections(..))

let unit = Unit
      { unitEnc       = Encoding 5 8 Dwarf32
      , unitType      = UnitCompile
      , unitAbbrevs   = AbbrevTable IntMap.empty
      , unitDieForest = Vector.singleton myDieTree
      }

case writeSections LittleEndian enc [unit] of
  Just ws -> do
    BS.writeFile "debug_info.bin"   (wsDebugInfo ws)
    BS.writeFile "debug_abbrev.bin" (wsDebugAbbrev ws)
    BS.writeFile "debug_str.bin"    (wsDebugStr ws)
  Nothing -> error "writeSections failed"

Examples #

The package includes three example programs:

  • simple-writer — construct a DIE tree and write binary DWARF sections
    cabal run simple-writer
    
  • simple-reader — read binary DWARF sections and print the parsed DIE tree
    cabal run simple-reader -- debug_info.bin debug_abbrev.bin debug_str.bin
    
  • dwarf-splitter — demonstrate split DWARF and DWP package file generation
    cabal run dwarf-splitter
    

License #

BSD-3-Clause — see LICENSE.