/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 | | } |