Coverage Report

Created: 2026-03-26 07:41

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/rust/registry/src/index.crates.io-1949cf8c6b5b557f/gimli-0.33.0/src/write/dwarf.rs
Line
Count
Source
1
use alloc::vec::Vec;
2
3
use crate::common::Encoding;
4
use 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)]
11
pub 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
29
impl Dwarf {
30
    /// Create a new `Dwarf` instance.
31
    #[inline]
32
0
    pub fn new() -> Self {
33
0
        Self::default()
34
0
    }
35
36
    /// Write the DWARF information to the given sections.
37
0
    pub fn write<W: Writer>(&mut self, sections: &mut Sections<W>) -> Result<()> {
38
0
        self.units
39
0
            .write(sections, &mut self.line_strings, &mut self.strings)?;
40
0
        for line_program in &self.line_programs {
41
0
            line_program.write(
42
0
                &mut sections.debug_line,
43
0
                line_program.encoding(),
44
0
                &mut self.line_strings,
45
0
                &mut self.strings,
46
0
            )?;
47
        }
48
0
        self.line_strings.write(&mut sections.debug_line_str)?;
49
0
        self.strings.write(&mut sections.debug_str)?;
50
0
        Ok(())
51
0
    }
52
53
    /// Get a reference to the data for a line string.
54
0
    pub fn get_line_string<'a>(&'a self, string: &'a LineString) -> &'a [u8] {
55
0
        string.get(&self.strings, &self.line_strings)
56
0
    }
57
}
58
59
/// Writable DWARF information for a single unit.
60
#[derive(Debug)]
61
pub 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
73
impl 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
0
    pub fn new(encoding: Encoding) -> Self {
80
0
        let unit = Unit::new(encoding, LineProgram::none());
81
0
        DwarfUnit {
82
0
            unit,
83
0
            line_strings: LineStringTable::default(),
84
0
            strings: StringTable::default(),
85
0
        }
86
0
    }
87
88
    /// Write the DWARf information to the given sections.
89
0
    pub fn write<W: Writer>(&mut self, sections: &mut Sections<W>) -> Result<()> {
90
0
        let abbrev_offset = sections.debug_abbrev.offset();
91
0
        let mut abbrevs = AbbreviationTable::default();
92
93
0
        self.unit.write(
94
0
            sections,
95
0
            abbrev_offset,
96
0
            &mut abbrevs,
97
0
            &mut self.line_strings,
98
0
            &mut self.strings,
99
0
        )?;
100
        // None should exist because we didn't give out any UnitId.
101
0
        assert!(sections.debug_info_fixups.is_empty());
102
0
        assert!(sections.debug_loc_fixups.is_empty());
103
0
        assert!(sections.debug_loclists_fixups.is_empty());
104
105
0
        abbrevs.write(&mut sections.debug_abbrev)?;
106
0
        self.line_strings.write(&mut sections.debug_line_str)?;
107
0
        self.strings.write(&mut sections.debug_str)?;
108
0
        Ok(())
109
0
    }
110
111
    /// Get a reference to the data for a line string.
112
0
    pub fn get_line_string<'a>(&'a self, string: &'a LineString) -> &'a [u8] {
113
0
        string.get(&self.strings, &self.line_strings)
114
0
    }
115
}
116
117
#[cfg(feature = "read")]
118
pub(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
0
        pub fn from<R: Reader<Offset = usize>>(
165
0
            from_dwarf: &read::Dwarf<R>,
166
0
            convert_address: &dyn Fn(u64) -> Option<Address>,
167
0
        ) -> ConvertResult<Dwarf> {
168
0
            let mut dwarf = Dwarf::default();
169
0
            let mut convert = dwarf.convert(from_dwarf)?;
170
0
            while let Some((mut unit, root_entry)) = convert.read_unit()? {
171
0
                unit.convert(root_entry, convert_address)?;
172
            }
173
            // TODO: convert the line programs that were not referenced by a unit.
174
0
            Ok(dwarf)
175
0
        }
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
0
        pub fn convert<'a, R: Reader<Offset = usize>>(
199
0
            &'a mut self,
200
0
            dwarf: &'a read::Dwarf<R>,
201
0
        ) -> ConvertResult<ConvertUnitSection<'a, R>> {
202
0
            ConvertUnitSection::new(dwarf, self)
203
0
        }
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
0
        pub fn convert_with_filter<'a, R: Reader<Offset = usize>>(
240
0
            &'a mut self,
241
0
            filter: FilterUnitSection<'a, R>,
242
0
        ) -> ConvertResult<ConvertUnitSection<'a, R>> {
243
0
            ConvertUnitSection::new_with_filter(self, filter)
244
0
        }
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
0
        pub fn read_line_program<'a, R: Reader<Offset = usize>>(
260
0
            &'a mut self,
261
0
            dwarf: &'a read::Dwarf<R>,
262
0
            program: read::IncompleteLineProgram<R>,
263
0
            encoding: Option<Encoding>,
264
0
            line_encoding: Option<LineEncoding>,
265
0
        ) -> ConvertResult<ConvertLineProgram<'a, R>> {
266
0
            ConvertLineProgram::new(
267
0
                dwarf,
268
0
                program,
269
0
                None,
270
0
                encoding,
271
0
                line_encoding,
272
0
                &mut self.line_strings,
273
0
                &mut self.strings,
274
            )
275
0
        }
276
    }
277
}