Skip to main content

gimli/write/
dwarf.rs

1use alloc::vec::Vec;
2
3use crate::common::Encoding;
4use crate::write::{
5    AbbreviationTable, LineProgram, LineString, LineStringTable, Result, Sections, StringTable,
6    Unit, UnitTable, Writer,
7};
8
9/// Writable DWARF information for more than one unit.
10#[derive(Debug, Default)]
11pub struct Dwarf {
12    /// A table of units. These are primarily stored in the `.debug_info` section,
13    /// but they also contain information that is stored in other sections.
14    pub units: UnitTable,
15
16    /// Extra line number programs that are not associated with a unit.
17    ///
18    /// These should only be used when generating DWARF5 line-only debug
19    /// information.
20    pub line_programs: Vec<LineProgram>,
21
22    /// A table of strings that will be stored in the `.debug_line_str` section.
23    pub line_strings: LineStringTable,
24
25    /// A table of strings that will be stored in the `.debug_str` section.
26    pub strings: StringTable,
27}
28
29impl Dwarf {
30    /// Create a new `Dwarf` instance.
31    #[inline]
32    pub fn new() -> Self {
33        Self::default()
34    }
35
36    /// Write the DWARF information to the given sections.
37    pub fn write<W: Writer>(&mut self, sections: &mut Sections<W>) -> Result<()> {
38        self.units
39            .write(sections, &mut self.line_strings, &mut self.strings)?;
40        for line_program in &self.line_programs {
41            line_program.write(
42                &mut sections.debug_line,
43                line_program.encoding(),
44                &mut self.line_strings,
45                &mut self.strings,
46            )?;
47        }
48        self.line_strings.write(&mut sections.debug_line_str)?;
49        self.strings.write(&mut sections.debug_str)?;
50        Ok(())
51    }
52
53    /// Get a reference to the data for a line string.
54    pub fn get_line_string<'a>(&'a self, string: &'a LineString) -> &'a [u8] {
55        string.get(&self.strings, &self.line_strings)
56    }
57}
58
59/// Writable DWARF information for a single unit.
60#[derive(Debug)]
61pub struct DwarfUnit {
62    /// A unit. This is primarily stored in the `.debug_info` section,
63    /// but also contains information that is stored in other sections.
64    pub unit: Unit,
65
66    /// A table of strings that will be stored in the `.debug_line_str` section.
67    pub line_strings: LineStringTable,
68
69    /// A table of strings that will be stored in the `.debug_str` section.
70    pub strings: StringTable,
71}
72
73impl DwarfUnit {
74    /// Create a new `DwarfUnit`.
75    ///
76    /// Note: you should set `self.unit.line_program` after creation.
77    /// This cannot be done earlier because it may need to reference
78    /// `self.line_strings`.
79    pub fn new(encoding: Encoding) -> Self {
80        let unit = Unit::new(encoding, LineProgram::none());
81        DwarfUnit {
82            unit,
83            line_strings: LineStringTable::default(),
84            strings: StringTable::default(),
85        }
86    }
87
88    /// Write the DWARf information to the given sections.
89    pub fn write<W: Writer>(&mut self, sections: &mut Sections<W>) -> Result<()> {
90        let abbrev_offset = sections.debug_abbrev.offset();
91        let mut abbrevs = AbbreviationTable::default();
92
93        self.unit.write(
94            sections,
95            abbrev_offset,
96            &mut abbrevs,
97            &mut self.line_strings,
98            &mut self.strings,
99        )?;
100        // None should exist because we didn't give out any UnitId.
101        assert!(sections.debug_info_fixups.is_empty());
102        assert!(sections.debug_loc_fixups.is_empty());
103        assert!(sections.debug_loclists_fixups.is_empty());
104
105        abbrevs.write(&mut sections.debug_abbrev)?;
106        self.line_strings.write(&mut sections.debug_line_str)?;
107        self.strings.write(&mut sections.debug_str)?;
108        Ok(())
109    }
110
111    /// Get a reference to the data for a line string.
112    pub fn get_line_string<'a>(&'a self, string: &'a LineString) -> &'a [u8] {
113        string.get(&self.strings, &self.line_strings)
114    }
115}
116
117#[cfg(feature = "read")]
118pub(crate) mod convert {
119    use super::*;
120    use crate::common::LineEncoding;
121    use crate::read::{self, Reader};
122    use crate::write::{
123        Address, ConvertLineProgram, ConvertResult, ConvertUnitSection, FilterUnitSection,
124    };
125
126    impl Dwarf {
127        /// Create a `write::Dwarf` by converting a `read::Dwarf`.
128        ///
129        /// `convert_address` is a function to convert addresses read by
130        /// `Reader::read_address` into the `Address` type. For executable files,
131        /// it is sufficient to simply map the address to `Address::Constant`.
132        ///
133        /// Relocatable object files are more complicated because there are relocations
134        /// associated with the address. To handle this, you can use a `Reader`
135        /// implementation for which `Reader::read_address` stores the relocation
136        /// information in a map and returns the map key instead of an address. Then
137        /// `convert_address` can look up the mapping to produce an `Address`.
138        ///
139        /// Note that `convert_address` is also used for address and offset pairs in
140        /// DWARF v2-v4 range lists and location lists. In order for the parser to
141        /// correctly handle these, `Reader::read_address` must return the values 0 and -1
142        /// unchanged.
143        ///
144        /// `convert_address` should not be used for complex address transformations, as it
145        /// will not be called for address offsets (such as in `DW_AT_high_pc`, line programs,
146        /// location lists, or range lists). If you need complex transformations, then you
147        /// need to use [`Dwarf::convert`] to enable you to transform the address offsets too.
148        ///
149        /// ## Example
150        ///
151        /// Convert DWARF sections using `Dwarf::from`.
152        ///
153        /// ```rust,no_run
154        /// # fn example() -> Result<(), gimli::write::ConvertError> {
155        /// # let loader = |name| -> Result<gimli::EndianSlice<gimli::RunTimeEndian>, gimli::Error> { unimplemented!() };
156        /// let read_dwarf = gimli::read::Dwarf::load(loader)?;
157        /// let write_dwarf = gimli::write::Dwarf::from(
158        ///     &read_dwarf,
159        ///     &|address| Some(gimli::write::Address::Constant(address)),
160        /// )?;
161        /// # unreachable!()
162        /// # }
163        /// ```
164        pub fn from<R: Reader<Offset = usize>>(
165            from_dwarf: &read::Dwarf<R>,
166            convert_address: &dyn Fn(u64) -> Option<Address>,
167        ) -> ConvertResult<Dwarf> {
168            let mut dwarf = Dwarf::default();
169            let mut convert = dwarf.convert(from_dwarf)?;
170            while let Some((mut unit, root_entry)) = convert.read_unit()? {
171                unit.convert(root_entry, convert_address)?;
172            }
173            // TODO: convert the line programs that were not referenced by a unit.
174            Ok(dwarf)
175        }
176
177        /// Create a converter for all units in the `.debug_info` section of the given
178        /// DWARF object.
179        ///
180        /// ## Example
181        ///
182        /// Convert DWARF sections using `convert`.
183        /// See [`ConvertUnit`](crate::write::ConvertUnit) for an example of the unit
184        /// conversion.
185        ///
186        /// ```rust,no_run
187        /// # fn example() -> Result<(), gimli::write::ConvertError> {
188        /// # let loader = |name| -> Result<gimli::EndianSlice<gimli::RunTimeEndian>, gimli::Error> { unimplemented!() };
189        /// let read_dwarf = gimli::read::Dwarf::load(loader)?;
190        /// let mut write_dwarf = gimli::write::Dwarf::new();
191        /// let mut convert = write_dwarf.convert(&read_dwarf)?;
192        /// while let Some((mut unit, root_entry)) = convert.read_unit()? {
193        ///     // Now you can convert the root DIE attributes, and other DIEs.
194        /// }
195        /// # unreachable!()
196        /// # }
197        /// ```
198        pub fn convert<'a, R: Reader<Offset = usize>>(
199            &'a mut self,
200            dwarf: &'a read::Dwarf<R>,
201        ) -> ConvertResult<ConvertUnitSection<'a, R>> {
202            ConvertUnitSection::new(dwarf, self)
203        }
204
205        /// Create a converter for some of the DIEs in the `.debug_info` section of the
206        /// given DWARF object.
207        ///
208        /// `filter` determines which DIEs are converted. This can be created using
209        /// [`FilterUnitSection::new`].
210        ///
211        /// ## Example
212        ///
213        /// Convert a DWARF section using `convert_with_filter`.
214        /// See [`ConvertUnit`](crate::write::ConvertUnit) for an example of the unit
215        /// conversion.
216        ///
217        /// ```rust,no_run
218        /// # fn example() -> Result<(), gimli::write::ConvertError> {
219        /// # let loader = |name| -> Result<gimli::EndianSlice<gimli::RunTimeEndian>, gimli::Error> { unimplemented!() };
220        /// # let need_entry = &|entry: &gimli::write::FilterUnitEntry<_>| -> Result<bool, gimli::write::ConvertError> { Ok(false) };
221        /// let read_dwarf = gimli::read::Dwarf::load(loader)?;
222        /// let mut filter = gimli::write::FilterUnitSection::new(&read_dwarf)?;
223        /// while let Some(mut unit) = filter.read_unit()? {
224        ///     let mut entry = unit.null_entry();
225        ///     while unit.read_entry(&mut entry)? {
226        ///         if need_entry(&entry)? {
227        ///             unit.require_entry(entry.offset);
228        ///         }
229        ///     }
230        /// }
231        /// let mut write_dwarf = gimli::write::Dwarf::new();
232        /// let mut convert = write_dwarf.convert_with_filter(filter)?;
233        /// while let Some((mut unit, root_entry)) = convert.read_unit()? {
234        ///     // Now you can convert the root DIE attributes, and other DIEs.
235        /// }
236        /// # unreachable!()
237        /// # }
238        /// ```
239        pub fn convert_with_filter<'a, R: Reader<Offset = usize>>(
240            &'a mut self,
241            filter: FilterUnitSection<'a, R>,
242        ) -> ConvertResult<ConvertUnitSection<'a, R>> {
243            ConvertUnitSection::new_with_filter(self, filter)
244        }
245
246        /// Start a new conversion of a line number program.
247        ///
248        /// This is intended for line number programs that do not have an associated
249        /// [`read::Unit`]. If the line number program has an associated [`read::Unit`]
250        /// that you are converting, then you should use
251        /// [`ConvertUnit::read_line_program`](crate::write::ConvertUnit::read_line_program)
252        /// instead.
253        ///
254        /// `encoding` and `line_encoding` apply to the converted program, and
255        /// may be different from the source program. If `None`, the encoding from
256        /// the source program is used.
257        ///
258        /// See [`ConvertLineProgram`] for an example.
259        pub fn read_line_program<'a, R: Reader<Offset = usize>>(
260            &'a mut self,
261            dwarf: &'a read::Dwarf<R>,
262            program: read::IncompleteLineProgram<R>,
263            encoding: Option<Encoding>,
264            line_encoding: Option<LineEncoding>,
265        ) -> ConvertResult<ConvertLineProgram<'a, R>> {
266            ConvertLineProgram::new(
267                dwarf,
268                program,
269                None,
270                encoding,
271                line_encoding,
272                &mut self.line_strings,
273                &mut self.strings,
274            )
275        }
276    }
277}