]> git.proxmox.com Git - rustc.git/blob - vendor/gimli/src/write/loc.rs
New upstream version 1.56.0~beta.4+dfsg1
[rustc.git] / vendor / gimli / src / write / loc.rs
1 use alloc::vec::Vec;
2 use indexmap::IndexSet;
3 use std::ops::{Deref, DerefMut};
4
5 use crate::common::{Encoding, LocationListsOffset, SectionId};
6 use crate::write::{
7 Address, BaseId, DebugInfoReference, Error, Expression, Result, Section, Sections, UnitOffsets,
8 Writer,
9 };
10
11 define_section!(
12 DebugLoc,
13 LocationListsOffset,
14 "A writable `.debug_loc` section."
15 );
16 define_section!(
17 DebugLocLists,
18 LocationListsOffset,
19 "A writable `.debug_loclists` section."
20 );
21
22 define_offsets!(
23 LocationListOffsets: LocationListId => LocationListsOffset,
24 "The section offsets of a series of location lists within the `.debug_loc` or `.debug_loclists` sections."
25 );
26
27 define_id!(
28 LocationListId,
29 "An identifier for a location list in a `LocationListTable`."
30 );
31
32 /// A table of location lists that will be stored in a `.debug_loc` or `.debug_loclists` section.
33 #[derive(Debug, Default)]
34 pub struct LocationListTable {
35 base_id: BaseId,
36 locations: IndexSet<LocationList>,
37 }
38
39 impl LocationListTable {
40 /// Add a location list to the table.
41 pub fn add(&mut self, loc_list: LocationList) -> LocationListId {
42 let (index, _) = self.locations.insert_full(loc_list);
43 LocationListId::new(self.base_id, index)
44 }
45
46 /// Write the location list table to the appropriate section for the given DWARF version.
47 pub(crate) fn write<W: Writer>(
48 &self,
49 sections: &mut Sections<W>,
50 encoding: Encoding,
51 unit_offsets: Option<&UnitOffsets>,
52 ) -> Result<LocationListOffsets> {
53 if self.locations.is_empty() {
54 return Ok(LocationListOffsets::none());
55 }
56
57 match encoding.version {
58 2..=4 => self.write_loc(
59 &mut sections.debug_loc,
60 &mut sections.debug_loc_refs,
61 encoding,
62 unit_offsets,
63 ),
64 5 => self.write_loclists(
65 &mut sections.debug_loclists,
66 &mut sections.debug_loclists_refs,
67 encoding,
68 unit_offsets,
69 ),
70 _ => Err(Error::UnsupportedVersion(encoding.version)),
71 }
72 }
73
74 /// Write the location list table to the `.debug_loc` section.
75 fn write_loc<W: Writer>(
76 &self,
77 w: &mut DebugLoc<W>,
78 refs: &mut Vec<DebugInfoReference>,
79 encoding: Encoding,
80 unit_offsets: Option<&UnitOffsets>,
81 ) -> Result<LocationListOffsets> {
82 let address_size = encoding.address_size;
83 let mut offsets = Vec::new();
84 for loc_list in self.locations.iter() {
85 offsets.push(w.offset());
86 for loc in &loc_list.0 {
87 // Note that we must ensure none of the ranges have both begin == 0 and end == 0.
88 // We do this by ensuring that begin != end, which is a bit more restrictive
89 // than required, but still seems reasonable.
90 match *loc {
91 Location::BaseAddress { address } => {
92 let marker = !0 >> (64 - address_size * 8);
93 w.write_udata(marker, address_size)?;
94 w.write_address(address, address_size)?;
95 }
96 Location::OffsetPair {
97 begin,
98 end,
99 ref data,
100 } => {
101 if begin == end {
102 return Err(Error::InvalidRange);
103 }
104 w.write_udata(begin, address_size)?;
105 w.write_udata(end, address_size)?;
106 write_expression(&mut w.0, refs, encoding, unit_offsets, data)?;
107 }
108 Location::StartEnd {
109 begin,
110 end,
111 ref data,
112 } => {
113 if begin == end {
114 return Err(Error::InvalidRange);
115 }
116 w.write_address(begin, address_size)?;
117 w.write_address(end, address_size)?;
118 write_expression(&mut w.0, refs, encoding, unit_offsets, data)?;
119 }
120 Location::StartLength {
121 begin,
122 length,
123 ref data,
124 } => {
125 let end = match begin {
126 Address::Constant(begin) => Address::Constant(begin + length),
127 Address::Symbol { symbol, addend } => Address::Symbol {
128 symbol,
129 addend: addend + length as i64,
130 },
131 };
132 if begin == end {
133 return Err(Error::InvalidRange);
134 }
135 w.write_address(begin, address_size)?;
136 w.write_address(end, address_size)?;
137 write_expression(&mut w.0, refs, encoding, unit_offsets, data)?;
138 }
139 Location::DefaultLocation { .. } => {
140 return Err(Error::InvalidRange);
141 }
142 }
143 }
144 w.write_udata(0, address_size)?;
145 w.write_udata(0, address_size)?;
146 }
147 Ok(LocationListOffsets {
148 base_id: self.base_id,
149 offsets,
150 })
151 }
152
153 /// Write the location list table to the `.debug_loclists` section.
154 fn write_loclists<W: Writer>(
155 &self,
156 w: &mut DebugLocLists<W>,
157 refs: &mut Vec<DebugInfoReference>,
158 encoding: Encoding,
159 unit_offsets: Option<&UnitOffsets>,
160 ) -> Result<LocationListOffsets> {
161 let mut offsets = Vec::new();
162
163 if encoding.version != 5 {
164 return Err(Error::NeedVersion(5));
165 }
166
167 let length_offset = w.write_initial_length(encoding.format)?;
168 let length_base = w.len();
169
170 w.write_u16(encoding.version)?;
171 w.write_u8(encoding.address_size)?;
172 w.write_u8(0)?; // segment_selector_size
173 w.write_u32(0)?; // offset_entry_count (when set to zero DW_FORM_rnglistx can't be used, see section 7.28)
174 // FIXME implement DW_FORM_rnglistx writing and implement the offset entry list
175
176 for loc_list in self.locations.iter() {
177 offsets.push(w.offset());
178 for loc in &loc_list.0 {
179 match *loc {
180 Location::BaseAddress { address } => {
181 w.write_u8(crate::constants::DW_LLE_base_address.0)?;
182 w.write_address(address, encoding.address_size)?;
183 }
184 Location::OffsetPair {
185 begin,
186 end,
187 ref data,
188 } => {
189 w.write_u8(crate::constants::DW_LLE_offset_pair.0)?;
190 w.write_uleb128(begin)?;
191 w.write_uleb128(end)?;
192 write_expression(&mut w.0, refs, encoding, unit_offsets, data)?;
193 }
194 Location::StartEnd {
195 begin,
196 end,
197 ref data,
198 } => {
199 w.write_u8(crate::constants::DW_LLE_start_end.0)?;
200 w.write_address(begin, encoding.address_size)?;
201 w.write_address(end, encoding.address_size)?;
202 write_expression(&mut w.0, refs, encoding, unit_offsets, data)?;
203 }
204 Location::StartLength {
205 begin,
206 length,
207 ref data,
208 } => {
209 w.write_u8(crate::constants::DW_LLE_start_length.0)?;
210 w.write_address(begin, encoding.address_size)?;
211 w.write_uleb128(length)?;
212 write_expression(&mut w.0, refs, encoding, unit_offsets, data)?;
213 }
214 Location::DefaultLocation { ref data } => {
215 w.write_u8(crate::constants::DW_LLE_default_location.0)?;
216 write_expression(&mut w.0, refs, encoding, unit_offsets, data)?;
217 }
218 }
219 }
220
221 w.write_u8(crate::constants::DW_LLE_end_of_list.0)?;
222 }
223
224 let length = (w.len() - length_base) as u64;
225 w.write_initial_length_at(length_offset, length, encoding.format)?;
226
227 Ok(LocationListOffsets {
228 base_id: self.base_id,
229 offsets,
230 })
231 }
232 }
233
234 /// A locations list that will be stored in a `.debug_loc` or `.debug_loclists` section.
235 #[derive(Clone, Debug, Eq, PartialEq, Hash)]
236 pub struct LocationList(pub Vec<Location>);
237
238 /// A single location.
239 #[derive(Clone, Debug, Eq, PartialEq, Hash)]
240 pub enum Location {
241 /// DW_LLE_base_address
242 BaseAddress {
243 /// Base address.
244 address: Address,
245 },
246 /// DW_LLE_offset_pair
247 OffsetPair {
248 /// Start of range relative to base address.
249 begin: u64,
250 /// End of range relative to base address.
251 end: u64,
252 /// Location description.
253 data: Expression,
254 },
255 /// DW_LLE_start_end
256 StartEnd {
257 /// Start of range.
258 begin: Address,
259 /// End of range.
260 end: Address,
261 /// Location description.
262 data: Expression,
263 },
264 /// DW_LLE_start_length
265 StartLength {
266 /// Start of range.
267 begin: Address,
268 /// Length of range.
269 length: u64,
270 /// Location description.
271 data: Expression,
272 },
273 /// DW_LLE_default_location
274 DefaultLocation {
275 /// Location description.
276 data: Expression,
277 },
278 }
279
280 fn write_expression<W: Writer>(
281 w: &mut W,
282 refs: &mut Vec<DebugInfoReference>,
283 encoding: Encoding,
284 unit_offsets: Option<&UnitOffsets>,
285 val: &Expression,
286 ) -> Result<()> {
287 let size = val.size(encoding, unit_offsets) as u64;
288 if encoding.version <= 4 {
289 w.write_udata(size, 2)?;
290 } else {
291 w.write_uleb128(size)?;
292 }
293 val.write(w, Some(refs), encoding, unit_offsets)?;
294 Ok(())
295 }
296
297 #[cfg(feature = "read")]
298 mod convert {
299 use super::*;
300
301 use crate::read::{self, Reader};
302 use crate::write::{ConvertError, ConvertResult, ConvertUnitContext};
303
304 impl LocationList {
305 /// Create a location list by reading the data from the give location list iter.
306 pub(crate) fn from<R: Reader<Offset = usize>>(
307 mut from: read::RawLocListIter<R>,
308 context: &ConvertUnitContext<R>,
309 ) -> ConvertResult<Self> {
310 let mut have_base_address = context.base_address != Address::Constant(0);
311 let convert_address =
312 |x| (context.convert_address)(x).ok_or(ConvertError::InvalidAddress);
313 let convert_expression = |x| {
314 Expression::from(
315 x,
316 context.unit.encoding(),
317 Some(context.dwarf),
318 Some(context.unit),
319 Some(context.entry_ids),
320 context.convert_address,
321 )
322 };
323 let mut loc_list = Vec::new();
324 while let Some(from_loc) = from.next()? {
325 let loc = match from_loc {
326 read::RawLocListEntry::AddressOrOffsetPair { begin, end, data } => {
327 // These were parsed as addresses, even if they are offsets.
328 let begin = convert_address(begin)?;
329 let end = convert_address(end)?;
330 let data = convert_expression(data)?;
331 match (begin, end) {
332 (Address::Constant(begin_offset), Address::Constant(end_offset)) => {
333 if have_base_address {
334 Location::OffsetPair {
335 begin: begin_offset,
336 end: end_offset,
337 data,
338 }
339 } else {
340 Location::StartEnd { begin, end, data }
341 }
342 }
343 _ => {
344 if have_base_address {
345 // At least one of begin/end is an address, but we also have
346 // a base address. Adding addresses is undefined.
347 return Err(ConvertError::InvalidRangeRelativeAddress);
348 }
349 Location::StartEnd { begin, end, data }
350 }
351 }
352 }
353 read::RawLocListEntry::BaseAddress { addr } => {
354 have_base_address = true;
355 let address = convert_address(addr)?;
356 Location::BaseAddress { address }
357 }
358 read::RawLocListEntry::BaseAddressx { addr } => {
359 have_base_address = true;
360 let address = convert_address(context.dwarf.address(context.unit, addr)?)?;
361 Location::BaseAddress { address }
362 }
363 read::RawLocListEntry::StartxEndx { begin, end, data } => {
364 let begin = convert_address(context.dwarf.address(context.unit, begin)?)?;
365 let end = convert_address(context.dwarf.address(context.unit, end)?)?;
366 let data = convert_expression(data)?;
367 Location::StartEnd { begin, end, data }
368 }
369 read::RawLocListEntry::StartxLength {
370 begin,
371 length,
372 data,
373 } => {
374 let begin = convert_address(context.dwarf.address(context.unit, begin)?)?;
375 let data = convert_expression(data)?;
376 Location::StartLength {
377 begin,
378 length,
379 data,
380 }
381 }
382 read::RawLocListEntry::OffsetPair { begin, end, data } => {
383 let data = convert_expression(data)?;
384 Location::OffsetPair { begin, end, data }
385 }
386 read::RawLocListEntry::StartEnd { begin, end, data } => {
387 let begin = convert_address(begin)?;
388 let end = convert_address(end)?;
389 let data = convert_expression(data)?;
390 Location::StartEnd { begin, end, data }
391 }
392 read::RawLocListEntry::StartLength {
393 begin,
394 length,
395 data,
396 } => {
397 let begin = convert_address(begin)?;
398 let data = convert_expression(data)?;
399 Location::StartLength {
400 begin,
401 length,
402 data,
403 }
404 }
405 read::RawLocListEntry::DefaultLocation { data } => {
406 let data = convert_expression(data)?;
407 Location::DefaultLocation { data }
408 }
409 };
410 // In some cases, existing data may contain begin == end, filtering
411 // these out.
412 match loc {
413 Location::StartLength { length, .. } if length == 0 => continue,
414 Location::StartEnd { begin, end, .. } if begin == end => continue,
415 Location::OffsetPair { begin, end, .. } if begin == end => continue,
416 _ => (),
417 }
418 loc_list.push(loc);
419 }
420 Ok(LocationList(loc_list))
421 }
422 }
423 }
424
425 #[cfg(test)]
426 #[cfg(feature = "read")]
427 mod tests {
428 use super::*;
429 use crate::common::{
430 DebugAbbrevOffset, DebugAddrBase, DebugInfoOffset, DebugLocListsBase, DebugRngListsBase,
431 DebugStrOffsetsBase, Format,
432 };
433 use crate::read;
434 use crate::write::{
435 ConvertUnitContext, EndianVec, LineStringTable, RangeListTable, StringTable,
436 };
437 use crate::LittleEndian;
438 use std::collections::HashMap;
439
440 #[test]
441 fn test_loc_list() {
442 let mut line_strings = LineStringTable::default();
443 let mut strings = StringTable::default();
444 let mut expression = Expression::new();
445 expression.op_constu(0);
446
447 for &version in &[2, 3, 4, 5] {
448 for &address_size in &[4, 8] {
449 for &format in &[Format::Dwarf32, Format::Dwarf64] {
450 let encoding = Encoding {
451 format,
452 version,
453 address_size,
454 };
455
456 let mut loc_list = LocationList(vec![
457 Location::StartLength {
458 begin: Address::Constant(6666),
459 length: 7777,
460 data: expression.clone(),
461 },
462 Location::StartEnd {
463 begin: Address::Constant(4444),
464 end: Address::Constant(5555),
465 data: expression.clone(),
466 },
467 Location::BaseAddress {
468 address: Address::Constant(1111),
469 },
470 Location::OffsetPair {
471 begin: 2222,
472 end: 3333,
473 data: expression.clone(),
474 },
475 ]);
476 if version >= 5 {
477 loc_list.0.push(Location::DefaultLocation {
478 data: expression.clone(),
479 });
480 }
481
482 let mut locations = LocationListTable::default();
483 let loc_list_id = locations.add(loc_list.clone());
484
485 let mut sections = Sections::new(EndianVec::new(LittleEndian));
486 let loc_list_offsets = locations.write(&mut sections, encoding, None).unwrap();
487 assert!(sections.debug_loc_refs.is_empty());
488 assert!(sections.debug_loclists_refs.is_empty());
489
490 let read_debug_loc =
491 read::DebugLoc::new(sections.debug_loc.slice(), LittleEndian);
492 let read_debug_loclists =
493 read::DebugLocLists::new(sections.debug_loclists.slice(), LittleEndian);
494 let read_loc = read::LocationLists::new(read_debug_loc, read_debug_loclists);
495 let offset = loc_list_offsets.get(loc_list_id);
496 let read_loc_list = read_loc.raw_locations(offset, encoding).unwrap();
497
498 let dwarf = read::Dwarf {
499 locations: read_loc,
500 ..Default::default()
501 };
502 let unit = read::Unit {
503 header: read::UnitHeader::new(
504 encoding,
505 0,
506 read::UnitType::Compilation,
507 DebugAbbrevOffset(0),
508 DebugInfoOffset(0).into(),
509 read::EndianSlice::default(),
510 ),
511 abbreviations: read::Abbreviations::default(),
512 name: None,
513 comp_dir: None,
514 low_pc: 0,
515 str_offsets_base: DebugStrOffsetsBase(0),
516 addr_base: DebugAddrBase(0),
517 loclists_base: DebugLocListsBase(0),
518 rnglists_base: DebugRngListsBase(0),
519 line_program: None,
520 dwo_id: None,
521 };
522 let context = ConvertUnitContext {
523 dwarf: &dwarf,
524 unit: &unit,
525 line_strings: &mut line_strings,
526 strings: &mut strings,
527 ranges: &mut RangeListTable::default(),
528 locations: &mut locations,
529 convert_address: &|address| Some(Address::Constant(address)),
530 base_address: Address::Constant(0),
531 line_program_offset: None,
532 line_program_files: Vec::new(),
533 entry_ids: &HashMap::new(),
534 };
535 let convert_loc_list = LocationList::from(read_loc_list, &context).unwrap();
536
537 if version <= 4 {
538 loc_list.0[0] = Location::StartEnd {
539 begin: Address::Constant(6666),
540 end: Address::Constant(6666 + 7777),
541 data: expression.clone(),
542 };
543 }
544 assert_eq!(loc_list, convert_loc_list);
545 }
546 }
547 }
548 }
549 }