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}