]> git.proxmox.com Git - rustc.git/blame - vendor/gimli-0.23.0/src/write/cfi.rs
New upstream version 1.55.0+dfsg1
[rustc.git] / vendor / gimli-0.23.0 / src / write / cfi.rs
CommitLineData
f035d41b
XL
1use alloc::vec::Vec;
2use indexmap::IndexSet;
3use std::ops::{Deref, DerefMut};
4
5use crate::common::{DebugFrameOffset, EhFrameOffset, Encoding, Format, Register, SectionId};
6use crate::constants;
7use crate::write::{Address, BaseId, Error, Expression, Result, Section, Writer};
8
9define_section!(
10 DebugFrame,
11 DebugFrameOffset,
12 "A writable `.debug_frame` section."
13);
14
15define_section!(EhFrame, EhFrameOffset, "A writable `.eh_frame` section.");
16
17define_id!(CieId, "An identifier for a CIE in a `FrameTable`.");
18
19/// A table of frame description entries.
20#[derive(Debug, Default)]
21pub struct FrameTable {
22 /// Base id for CIEs.
23 base_id: BaseId,
24 /// The common information entries.
25 cies: IndexSet<CommonInformationEntry>,
26 /// The frame description entries.
27 fdes: Vec<(CieId, FrameDescriptionEntry)>,
28}
29
30impl FrameTable {
31 /// Add a CIE and return its id.
32 ///
33 /// If the CIE already exists, then return the id of the existing CIE.
34 pub fn add_cie(&mut self, cie: CommonInformationEntry) -> CieId {
35 let (index, _) = self.cies.insert_full(cie);
36 CieId::new(self.base_id, index)
37 }
38
39 /// The number of CIEs.
40 pub fn cie_count(&self) -> usize {
41 self.cies.len()
42 }
43
44 /// Add a FDE.
45 ///
46 /// Does not check for duplicates.
47 ///
48 /// # Panics
49 ///
50 /// Panics if the CIE id is invalid.
51 pub fn add_fde(&mut self, cie: CieId, fde: FrameDescriptionEntry) {
52 debug_assert_eq!(self.base_id, cie.base_id);
53 self.fdes.push((cie, fde));
54 }
55
56 /// The number of FDEs.
57 pub fn fde_count(&self) -> usize {
58 self.fdes.len()
59 }
60
61 /// Write the frame table entries to the given `.debug_frame` section.
62 pub fn write_debug_frame<W: Writer>(&self, w: &mut DebugFrame<W>) -> Result<()> {
63 self.write(&mut w.0, false)
64 }
65
66 /// Write the frame table entries to the given `.eh_frame` section.
67 pub fn write_eh_frame<W: Writer>(&self, w: &mut EhFrame<W>) -> Result<()> {
68 self.write(&mut w.0, true)
69 }
70
71 fn write<W: Writer>(&self, w: &mut W, eh_frame: bool) -> Result<()> {
72 let mut cie_offsets = vec![None; self.cies.len()];
73 for (cie_id, fde) in &self.fdes {
74 let cie_index = cie_id.index;
75 let cie = self.cies.get_index(cie_index).unwrap();
76 let cie_offset = match cie_offsets[cie_index] {
77 Some(offset) => offset,
78 None => {
79 // Only write CIEs as they are referenced.
80 let offset = cie.write(w, eh_frame)?;
81 cie_offsets[cie_index] = Some(offset);
82 offset
83 }
84 };
85
86 fde.write(w, eh_frame, cie_offset, cie)?;
87 }
88 // TODO: write length 0 terminator for eh_frame?
89 Ok(())
90 }
91}
92
93/// A common information entry. This contains information that is shared between FDEs.
94#[derive(Debug, Clone, PartialEq, Eq, Hash)]
95pub struct CommonInformationEntry {
96 encoding: Encoding,
97
98 /// A constant that is factored out of code offsets.
99 ///
100 /// This should be set to the minimum instruction length.
101 /// Writing a code offset that is not a multiple of this factor will generate an error.
102 code_alignment_factor: u8,
103
104 /// A constant that is factored out of data offsets.
105 ///
106 /// This should be set to the minimum data alignment for the frame.
107 /// Writing a data offset that is not a multiple of this factor will generate an error.
108 data_alignment_factor: i8,
109
110 /// The return address register. This might not correspond to an actual machine register.
111 return_address_register: Register,
112
113 /// The address of the personality function and its encoding.
114 pub personality: Option<(constants::DwEhPe, Address)>,
115
116 /// The encoding to use for the LSDA address in FDEs.
117 ///
118 /// If set then all FDEs which use this CIE must have a LSDA address.
119 pub lsda_encoding: Option<constants::DwEhPe>,
120
121 /// The encoding to use for addresses in FDEs.
122 pub fde_address_encoding: constants::DwEhPe,
123
124 /// True for signal trampolines.
125 pub signal_trampoline: bool,
126
127 /// The initial instructions upon entry to this function.
128 instructions: Vec<CallFrameInstruction>,
129}
130
131impl CommonInformationEntry {
132 /// Create a new common information entry.
133 ///
134 /// The encoding version must be a CFI version, not a DWARF version.
135 pub fn new(
136 encoding: Encoding,
137 code_alignment_factor: u8,
138 data_alignment_factor: i8,
139 return_address_register: Register,
140 ) -> Self {
141 CommonInformationEntry {
142 encoding,
143 code_alignment_factor,
144 data_alignment_factor,
145 return_address_register,
146 personality: None,
147 lsda_encoding: None,
148 fde_address_encoding: constants::DW_EH_PE_absptr,
149 signal_trampoline: false,
150 instructions: Vec::new(),
151 }
152 }
153
154 /// Add an initial instruction.
155 pub fn add_instruction(&mut self, instruction: CallFrameInstruction) {
156 self.instructions.push(instruction);
157 }
158
159 fn has_augmentation(&self) -> bool {
160 self.personality.is_some()
161 || self.lsda_encoding.is_some()
162 || self.signal_trampoline
163 || self.fde_address_encoding != constants::DW_EH_PE_absptr
164 }
165
166 /// Returns the section offset of the CIE.
167 fn write<W: Writer>(&self, w: &mut W, eh_frame: bool) -> Result<usize> {
168 let encoding = self.encoding;
169 let offset = w.len();
170
171 let length_offset = w.write_initial_length(encoding.format)?;
172 let length_base = w.len();
173
174 if eh_frame {
175 w.write_u32(0)?;
176 } else {
177 match encoding.format {
178 Format::Dwarf32 => w.write_u32(0xffff_ffff)?,
179 Format::Dwarf64 => w.write_u64(0xffff_ffff_ffff_ffff)?,
180 }
181 }
182
183 if eh_frame {
184 if encoding.version != 1 {
185 return Err(Error::UnsupportedVersion(encoding.version));
186 };
187 } else {
188 match encoding.version {
189 1 | 3 | 4 => {}
190 _ => return Err(Error::UnsupportedVersion(encoding.version)),
191 };
192 }
193 w.write_u8(encoding.version as u8)?;
194
195 let augmentation = self.has_augmentation();
196 if augmentation {
197 w.write_u8(b'z')?;
198 if self.lsda_encoding.is_some() {
199 w.write_u8(b'L')?;
200 }
201 if self.personality.is_some() {
202 w.write_u8(b'P')?;
203 }
204 if self.fde_address_encoding != constants::DW_EH_PE_absptr {
205 w.write_u8(b'R')?;
206 }
207 if self.signal_trampoline {
208 w.write_u8(b'S')?;
209 }
210 }
211 w.write_u8(0)?;
212
213 if encoding.version >= 4 {
214 w.write_u8(encoding.address_size)?;
215 // TODO: segment_selector_size
216 w.write_u8(0)?;
217 }
218
219 w.write_uleb128(self.code_alignment_factor.into())?;
220 w.write_sleb128(self.data_alignment_factor.into())?;
221
222 if !eh_frame && encoding.version == 1 {
223 let register = self.return_address_register.0 as u8;
224 if u16::from(register) != self.return_address_register.0 {
225 return Err(Error::ValueTooLarge);
226 }
227 w.write_u8(register)?;
228 } else {
229 w.write_uleb128(self.return_address_register.0.into())?;
230 }
231
232 if augmentation {
233 let augmentation_length_offset = w.len();
234 w.write_u8(0)?;
235 let augmentation_length_base = w.len();
236
237 if let Some(eh_pe) = self.lsda_encoding {
238 w.write_u8(eh_pe.0)?;
239 }
240 if let Some((eh_pe, address)) = self.personality {
241 w.write_u8(eh_pe.0)?;
242 w.write_eh_pointer(address, constants::DW_EH_PE_absptr, encoding.address_size)?;
243 }
244 if self.fde_address_encoding != constants::DW_EH_PE_absptr {
245 w.write_u8(self.fde_address_encoding.0)?;
246 }
247
248 let augmentation_length = (w.len() - augmentation_length_base) as u64;
249 debug_assert!(augmentation_length < 0x80);
250 w.write_udata_at(augmentation_length_offset, augmentation_length, 1)?;
251 }
252
253 for instruction in &self.instructions {
254 instruction.write(w, encoding, self)?;
255 }
256
257 write_nop(
258 w,
259 encoding.format.word_size() as usize + w.len() - length_base,
260 encoding.address_size,
261 )?;
262
263 let length = (w.len() - length_base) as u64;
264 w.write_initial_length_at(length_offset, length, encoding.format)?;
265
266 Ok(offset)
267 }
268}
269
270/// A frame description entry. There should be one FDE per function.
271#[derive(Debug, Clone, PartialEq, Eq)]
272pub struct FrameDescriptionEntry {
273 /// The initial address of the function.
274 address: Address,
275
276 /// The length in bytes of the function.
277 length: u32,
278
279 /// The address of the LSDA.
280 pub lsda: Option<Address>,
281
282 /// The instructions for this function, ordered by offset.
283 instructions: Vec<(u32, CallFrameInstruction)>,
284}
285
286impl FrameDescriptionEntry {
287 /// Create a new frame description entry for a function.
288 pub fn new(address: Address, length: u32) -> Self {
289 FrameDescriptionEntry {
290 address,
291 length,
292 lsda: None,
293 instructions: Vec::new(),
294 }
295 }
296
297 /// Add an instruction.
298 ///
299 /// Instructions must be added in increasing order of offset, or writing will fail.
300 pub fn add_instruction(&mut self, offset: u32, instruction: CallFrameInstruction) {
301 debug_assert!(self.instructions.last().map(|x| x.0).unwrap_or(0) <= offset);
302 self.instructions.push((offset, instruction));
303 }
304
305 fn write<W: Writer>(
306 &self,
307 w: &mut W,
308 eh_frame: bool,
309 cie_offset: usize,
310 cie: &CommonInformationEntry,
311 ) -> Result<()> {
312 let encoding = cie.encoding;
313 let length_offset = w.write_initial_length(encoding.format)?;
314 let length_base = w.len();
315
316 if eh_frame {
317 // .eh_frame uses a relative offset which doesn't need relocation.
318 w.write_udata((w.len() - cie_offset) as u64, 4)?;
319 } else {
320 w.write_offset(
321 cie_offset,
322 SectionId::DebugFrame,
323 encoding.format.word_size(),
324 )?;
325 }
326
327 if cie.fde_address_encoding != constants::DW_EH_PE_absptr {
328 w.write_eh_pointer(
329 self.address,
330 cie.fde_address_encoding,
331 encoding.address_size,
332 )?;
333 w.write_eh_pointer_data(
334 self.length.into(),
335 cie.fde_address_encoding.format(),
336 encoding.address_size,
337 )?;
338 } else {
339 w.write_address(self.address, encoding.address_size)?;
340 w.write_udata(self.length.into(), encoding.address_size)?;
341 }
342
343 if cie.has_augmentation() {
344 let mut augmentation_length = 0u64;
345 if self.lsda.is_some() {
346 augmentation_length += u64::from(encoding.address_size);
347 }
348 w.write_uleb128(augmentation_length)?;
349
350 debug_assert_eq!(self.lsda.is_some(), cie.lsda_encoding.is_some());
351 if let (Some(lsda), Some(lsda_encoding)) = (self.lsda, cie.lsda_encoding) {
352 w.write_eh_pointer(lsda, lsda_encoding, encoding.address_size)?;
353 }
354 }
355
356 let mut prev_offset = 0;
357 for (offset, instruction) in &self.instructions {
358 write_advance_loc(w, cie.code_alignment_factor, prev_offset, *offset)?;
359 prev_offset = *offset;
360 instruction.write(w, encoding, cie)?;
361 }
362
363 write_nop(
364 w,
365 encoding.format.word_size() as usize + w.len() - length_base,
366 encoding.address_size,
367 )?;
368
369 let length = (w.len() - length_base) as u64;
370 w.write_initial_length_at(length_offset, length, encoding.format)?;
371
372 Ok(())
373 }
374}
375
376/// An instruction in a frame description entry.
377///
378/// This may be a CFA definition, a register rule, or some other directive.
379#[derive(Debug, Clone, PartialEq, Eq, Hash)]
380pub enum CallFrameInstruction {
381 /// Define the CFA rule to use the provided register and offset.
382 Cfa(Register, i32),
383 /// Update the CFA rule to use the provided register. The offset is unchanged.
384 CfaRegister(Register),
385 /// Update the CFA rule to use the provided offset. The register is unchanged.
386 CfaOffset(i32),
387 /// Define the CFA rule to use the provided expression.
388 CfaExpression(Expression),
389
390 /// Restore the initial rule for the register.
391 Restore(Register),
392 /// The previous value of the register is not recoverable.
393 Undefined(Register),
394 /// The register has not been modified.
395 SameValue(Register),
396 /// The previous value of the register is saved at address CFA + offset.
397 Offset(Register, i32),
398 /// The previous value of the register is CFA + offset.
399 ValOffset(Register, i32),
400 /// The previous value of the register is stored in another register.
401 Register(Register, Register),
402 /// The previous value of the register is saved at address given by the expression.
403 Expression(Register, Expression),
404 /// The previous value of the register is given by the expression.
405 ValExpression(Register, Expression),
406
407 /// Push all register rules onto a stack.
408 RememberState,
409 /// Pop all register rules off the stack.
410 RestoreState,
411 /// The size of the arguments that have been pushed onto the stack.
412 ArgsSize(u32),
413}
414
415impl CallFrameInstruction {
416 fn write<W: Writer>(
417 &self,
418 w: &mut W,
419 encoding: Encoding,
420 cie: &CommonInformationEntry,
421 ) -> Result<()> {
422 match *self {
423 CallFrameInstruction::Cfa(register, offset) => {
424 if offset < 0 {
425 let offset = factored_data_offset(offset, cie.data_alignment_factor)?;
426 w.write_u8(constants::DW_CFA_def_cfa_sf.0)?;
427 w.write_uleb128(register.0.into())?;
428 w.write_sleb128(offset.into())?;
429 } else {
430 // Unfactored offset.
431 w.write_u8(constants::DW_CFA_def_cfa.0)?;
432 w.write_uleb128(register.0.into())?;
433 w.write_uleb128(offset as u64)?;
434 }
435 }
436 CallFrameInstruction::CfaRegister(register) => {
437 w.write_u8(constants::DW_CFA_def_cfa_register.0)?;
438 w.write_uleb128(register.0.into())?;
439 }
440 CallFrameInstruction::CfaOffset(offset) => {
441 if offset < 0 {
442 let offset = factored_data_offset(offset, cie.data_alignment_factor)?;
443 w.write_u8(constants::DW_CFA_def_cfa_offset_sf.0)?;
444 w.write_sleb128(offset.into())?;
445 } else {
446 // Unfactored offset.
447 w.write_u8(constants::DW_CFA_def_cfa_offset.0)?;
448 w.write_uleb128(offset as u64)?;
449 }
450 }
451 CallFrameInstruction::CfaExpression(ref expression) => {
452 w.write_u8(constants::DW_CFA_def_cfa_expression.0)?;
453 w.write_uleb128(expression.size(encoding, None) as u64)?;
454 expression.write(w, None, encoding, None)?;
455 }
456 CallFrameInstruction::Restore(register) => {
457 if register.0 < 0x40 {
458 w.write_u8(constants::DW_CFA_restore.0 | register.0 as u8)?;
459 } else {
460 w.write_u8(constants::DW_CFA_restore_extended.0)?;
461 w.write_uleb128(register.0.into())?;
462 }
463 }
464 CallFrameInstruction::Undefined(register) => {
465 w.write_u8(constants::DW_CFA_undefined.0)?;
466 w.write_uleb128(register.0.into())?;
467 }
468 CallFrameInstruction::SameValue(register) => {
469 w.write_u8(constants::DW_CFA_same_value.0)?;
470 w.write_uleb128(register.0.into())?;
471 }
472 CallFrameInstruction::Offset(register, offset) => {
473 let offset = factored_data_offset(offset, cie.data_alignment_factor)?;
474 if offset < 0 {
475 w.write_u8(constants::DW_CFA_offset_extended_sf.0)?;
476 w.write_uleb128(register.0.into())?;
477 w.write_sleb128(offset.into())?;
478 } else if register.0 < 0x40 {
479 w.write_u8(constants::DW_CFA_offset.0 | register.0 as u8)?;
480 w.write_uleb128(offset as u64)?;
481 } else {
482 w.write_u8(constants::DW_CFA_offset_extended.0)?;
483 w.write_uleb128(register.0.into())?;
484 w.write_uleb128(offset as u64)?;
485 }
486 }
487 CallFrameInstruction::ValOffset(register, offset) => {
488 let offset = factored_data_offset(offset, cie.data_alignment_factor)?;
489 if offset < 0 {
490 w.write_u8(constants::DW_CFA_val_offset_sf.0)?;
491 w.write_uleb128(register.0.into())?;
492 w.write_sleb128(offset.into())?;
493 } else {
494 w.write_u8(constants::DW_CFA_val_offset.0)?;
495 w.write_uleb128(register.0.into())?;
496 w.write_uleb128(offset as u64)?;
497 }
498 }
499 CallFrameInstruction::Register(register1, register2) => {
500 w.write_u8(constants::DW_CFA_register.0)?;
501 w.write_uleb128(register1.0.into())?;
502 w.write_uleb128(register2.0.into())?;
503 }
504 CallFrameInstruction::Expression(register, ref expression) => {
505 w.write_u8(constants::DW_CFA_expression.0)?;
506 w.write_uleb128(register.0.into())?;
507 w.write_uleb128(expression.size(encoding, None) as u64)?;
508 expression.write(w, None, encoding, None)?;
509 }
510 CallFrameInstruction::ValExpression(register, ref expression) => {
511 w.write_u8(constants::DW_CFA_val_expression.0)?;
512 w.write_uleb128(register.0.into())?;
513 w.write_uleb128(expression.size(encoding, None) as u64)?;
514 expression.write(w, None, encoding, None)?;
515 }
516 CallFrameInstruction::RememberState => {
517 w.write_u8(constants::DW_CFA_remember_state.0)?;
518 }
519 CallFrameInstruction::RestoreState => {
520 w.write_u8(constants::DW_CFA_restore_state.0)?;
521 }
522 CallFrameInstruction::ArgsSize(size) => {
523 w.write_u8(constants::DW_CFA_GNU_args_size.0)?;
524 w.write_uleb128(size.into())?;
525 }
526 }
527 Ok(())
528 }
529}
530
531fn write_advance_loc<W: Writer>(
532 w: &mut W,
533 code_alignment_factor: u8,
534 prev_offset: u32,
535 offset: u32,
536) -> Result<()> {
537 if offset == prev_offset {
538 return Ok(());
539 }
540 let delta = factored_code_delta(prev_offset, offset, code_alignment_factor)?;
541 if delta < 0x40 {
542 w.write_u8(constants::DW_CFA_advance_loc.0 | delta as u8)?;
543 } else if delta < 0x100 {
544 w.write_u8(constants::DW_CFA_advance_loc1.0)?;
545 w.write_u8(delta as u8)?;
546 } else if delta < 0x10000 {
547 w.write_u8(constants::DW_CFA_advance_loc2.0)?;
548 w.write_u16(delta as u16)?;
549 } else {
550 w.write_u8(constants::DW_CFA_advance_loc4.0)?;
551 w.write_u32(delta)?;
552 }
553 Ok(())
554}
555
556fn write_nop<W: Writer>(w: &mut W, len: usize, align: u8) -> Result<()> {
557 debug_assert_eq!(align & (align - 1), 0);
558 let tail_len = (!len + 1) & (align as usize - 1);
559 for _ in 0..tail_len {
560 w.write_u8(constants::DW_CFA_nop.0)?;
561 }
562 Ok(())
563}
564
565fn factored_code_delta(prev_offset: u32, offset: u32, factor: u8) -> Result<u32> {
566 if offset < prev_offset {
567 return Err(Error::InvalidFrameCodeOffset(offset));
568 }
569 let delta = offset - prev_offset;
570 let factor = u32::from(factor);
571 let factored_delta = delta / factor;
572 if delta != factored_delta * factor {
573 return Err(Error::InvalidFrameCodeOffset(offset));
574 }
575 Ok(factored_delta)
576}
577
578fn factored_data_offset(offset: i32, factor: i8) -> Result<i32> {
579 let factor = i32::from(factor);
580 let factored_offset = offset / factor;
581 if offset != factored_offset * factor {
582 return Err(Error::InvalidFrameDataOffset(offset));
583 }
584 Ok(factored_offset)
585}
586
587#[cfg(feature = "read")]
588pub(crate) mod convert {
589 use super::*;
590 use crate::read::{self, Reader};
591 use crate::write::{ConvertError, ConvertResult};
592 use std::collections::{hash_map, HashMap};
593
594 impl FrameTable {
595 /// Create a frame table by reading the data in the given section.
596 ///
597 /// `convert_address` is a function to convert read addresses into the `Address`
598 /// type. For non-relocatable addresses, this function may simply return
599 /// `Address::Constant(address)`. For relocatable addresses, it is the caller's
600 /// responsibility to determine the symbol and addend corresponding to the address
601 /// and return `Address::Symbol { symbol, addend }`.
602 pub fn from<R, Section>(
603 frame: &Section,
604 convert_address: &dyn Fn(u64) -> Option<Address>,
605 ) -> ConvertResult<FrameTable>
606 where
607 R: Reader<Offset = usize>,
608 Section: read::UnwindSection<R>,
609 Section::Offset: read::UnwindOffset<usize>,
610 {
611 let bases = read::BaseAddresses::default().set_eh_frame(0);
612
613 let mut frame_table = FrameTable::default();
614
615 let mut cie_ids = HashMap::new();
616 let mut entries = frame.entries(&bases);
617 while let Some(entry) = entries.next()? {
618 let partial = match entry {
619 read::CieOrFde::Cie(_) => continue,
620 read::CieOrFde::Fde(partial) => partial,
621 };
622
623 // TODO: is it worth caching the parsed CIEs? It would be better if FDEs only
624 // stored a reference.
625 let from_fde = partial.parse(Section::cie_from_offset)?;
626 let from_cie = from_fde.cie();
627 let cie_id = match cie_ids.entry(from_cie.offset()) {
628 hash_map::Entry::Occupied(o) => *o.get(),
629 hash_map::Entry::Vacant(e) => {
630 let cie =
631 CommonInformationEntry::from(from_cie, frame, &bases, convert_address)?;
632 let cie_id = frame_table.add_cie(cie);
633 e.insert(cie_id);
634 cie_id
635 }
636 };
637 let fde = FrameDescriptionEntry::from(&from_fde, frame, &bases, convert_address)?;
638 frame_table.add_fde(cie_id, fde);
639 }
640
641 Ok(frame_table)
642 }
643 }
644
645 impl CommonInformationEntry {
646 fn from<R, Section>(
647 from_cie: &read::CommonInformationEntry<R>,
648 frame: &Section,
649 bases: &read::BaseAddresses,
650 convert_address: &dyn Fn(u64) -> Option<Address>,
651 ) -> ConvertResult<CommonInformationEntry>
652 where
653 R: Reader<Offset = usize>,
654 Section: read::UnwindSection<R>,
655 Section::Offset: read::UnwindOffset<usize>,
656 {
657 let mut cie = CommonInformationEntry::new(
658 from_cie.encoding(),
659 from_cie.code_alignment_factor() as u8,
660 from_cie.data_alignment_factor() as i8,
661 from_cie.return_address_register(),
662 );
663
664 cie.personality = match from_cie.personality_with_encoding() {
665 // We treat these the same because the encoding already determines
666 // whether it is indirect.
667 Some((eh_pe, read::Pointer::Direct(p)))
668 | Some((eh_pe, read::Pointer::Indirect(p))) => {
669 let address = convert_address(p).ok_or(ConvertError::InvalidAddress)?;
670 Some((eh_pe, address))
671 }
672 _ => None,
673 };
674 cie.lsda_encoding = from_cie.lsda_encoding();
675 cie.fde_address_encoding = from_cie
676 .fde_address_encoding()
677 .unwrap_or(constants::DW_EH_PE_absptr);
678 cie.signal_trampoline = from_cie.is_signal_trampoline();
679
680 let mut offset = 0;
681 let mut from_instructions = from_cie.instructions(frame, bases);
682 while let Some(from_instruction) = from_instructions.next()? {
683 if let Some(instruction) = CallFrameInstruction::from(
684 from_instruction,
685 from_cie,
686 convert_address,
687 &mut offset,
688 )? {
689 cie.instructions.push(instruction);
690 }
691 }
692 Ok(cie)
693 }
694 }
695
696 impl FrameDescriptionEntry {
697 fn from<R, Section>(
698 from_fde: &read::FrameDescriptionEntry<R>,
699 frame: &Section,
700 bases: &read::BaseAddresses,
701 convert_address: &dyn Fn(u64) -> Option<Address>,
702 ) -> ConvertResult<FrameDescriptionEntry>
703 where
704 R: Reader<Offset = usize>,
705 Section: read::UnwindSection<R>,
706 Section::Offset: read::UnwindOffset<usize>,
707 {
708 let address =
709 convert_address(from_fde.initial_address()).ok_or(ConvertError::InvalidAddress)?;
710 let length = from_fde.len() as u32;
711 let mut fde = FrameDescriptionEntry::new(address, length);
712
713 match from_fde.lsda() {
714 // We treat these the same because the encoding already determines
715 // whether it is indirect.
716 Some(read::Pointer::Direct(p)) | Some(read::Pointer::Indirect(p)) => {
717 let address = convert_address(p).ok_or(ConvertError::InvalidAddress)?;
718 fde.lsda = Some(address);
719 }
720 None => {}
721 }
722
723 let from_cie = from_fde.cie();
724 let mut offset = 0;
725 let mut from_instructions = from_fde.instructions(frame, bases);
726 while let Some(from_instruction) = from_instructions.next()? {
727 if let Some(instruction) = CallFrameInstruction::from(
728 from_instruction,
729 from_cie,
730 convert_address,
731 &mut offset,
732 )? {
733 fde.instructions.push((offset, instruction));
734 }
735 }
736
737 Ok(fde)
738 }
739 }
740
741 impl CallFrameInstruction {
742 fn from<R: Reader<Offset = usize>>(
743 from_instruction: read::CallFrameInstruction<R>,
744 from_cie: &read::CommonInformationEntry<R>,
745 convert_address: &dyn Fn(u64) -> Option<Address>,
746 offset: &mut u32,
747 ) -> ConvertResult<Option<CallFrameInstruction>> {
748 let convert_expression =
749 |x| Expression::from(x, from_cie.encoding(), None, None, None, convert_address);
750 // TODO: validate integer type conversions
751 Ok(Some(match from_instruction {
752 read::CallFrameInstruction::SetLoc { .. } => {
753 return Err(ConvertError::UnsupportedCfiInstruction);
754 }
755 read::CallFrameInstruction::AdvanceLoc { delta } => {
756 *offset += delta * from_cie.code_alignment_factor() as u32;
757 return Ok(None);
758 }
759 read::CallFrameInstruction::DefCfa { register, offset } => {
760 CallFrameInstruction::Cfa(register, offset as i32)
761 }
762 read::CallFrameInstruction::DefCfaSf {
763 register,
764 factored_offset,
765 } => {
766 let offset = factored_offset * from_cie.data_alignment_factor();
767 CallFrameInstruction::Cfa(register, offset as i32)
768 }
769 read::CallFrameInstruction::DefCfaRegister { register } => {
770 CallFrameInstruction::CfaRegister(register)
771 }
772
773 read::CallFrameInstruction::DefCfaOffset { offset } => {
774 CallFrameInstruction::CfaOffset(offset as i32)
775 }
776 read::CallFrameInstruction::DefCfaOffsetSf { factored_offset } => {
777 let offset = factored_offset * from_cie.data_alignment_factor();
778 CallFrameInstruction::CfaOffset(offset as i32)
779 }
780 read::CallFrameInstruction::DefCfaExpression { expression } => {
781 CallFrameInstruction::CfaExpression(convert_expression(expression)?)
782 }
783 read::CallFrameInstruction::Undefined { register } => {
784 CallFrameInstruction::Undefined(register)
785 }
786 read::CallFrameInstruction::SameValue { register } => {
787 CallFrameInstruction::SameValue(register)
788 }
789 read::CallFrameInstruction::Offset {
790 register,
791 factored_offset,
792 } => {
793 let offset = factored_offset as i64 * from_cie.data_alignment_factor();
794 CallFrameInstruction::Offset(register, offset as i32)
795 }
796 read::CallFrameInstruction::OffsetExtendedSf {
797 register,
798 factored_offset,
799 } => {
800 let offset = factored_offset * from_cie.data_alignment_factor();
801 CallFrameInstruction::Offset(register, offset as i32)
802 }
803 read::CallFrameInstruction::ValOffset {
804 register,
805 factored_offset,
806 } => {
807 let offset = factored_offset as i64 * from_cie.data_alignment_factor();
808 CallFrameInstruction::ValOffset(register, offset as i32)
809 }
810 read::CallFrameInstruction::ValOffsetSf {
811 register,
812 factored_offset,
813 } => {
814 let offset = factored_offset * from_cie.data_alignment_factor();
815 CallFrameInstruction::ValOffset(register, offset as i32)
816 }
817 read::CallFrameInstruction::Register {
818 dest_register,
819 src_register,
820 } => CallFrameInstruction::Register(dest_register, src_register),
821 read::CallFrameInstruction::Expression {
822 register,
823 expression,
824 } => CallFrameInstruction::Expression(register, convert_expression(expression)?),
825 read::CallFrameInstruction::ValExpression {
826 register,
827 expression,
828 } => CallFrameInstruction::ValExpression(register, convert_expression(expression)?),
829 read::CallFrameInstruction::Restore { register } => {
830 CallFrameInstruction::Restore(register)
831 }
832 read::CallFrameInstruction::RememberState => CallFrameInstruction::RememberState,
833 read::CallFrameInstruction::RestoreState => CallFrameInstruction::RestoreState,
834 read::CallFrameInstruction::ArgsSize { size } => {
835 CallFrameInstruction::ArgsSize(size as u32)
836 }
837 read::CallFrameInstruction::Nop => return Ok(None),
838 }))
839 }
840 }
841}
842
843#[cfg(test)]
844#[cfg(feature = "read")]
845mod tests {
846 use super::*;
847 use crate::arch::X86_64;
848 use crate::read;
849 use crate::write::EndianVec;
850 use crate::LittleEndian;
851
852 #[test]
853 fn test_frame_table() {
854 for &version in &[1, 3, 4] {
855 for &address_size in &[4, 8] {
856 for &format in &[Format::Dwarf32, Format::Dwarf64] {
857 let encoding = Encoding {
858 format,
859 version,
860 address_size,
861 };
862 let mut frames = FrameTable::default();
863
864 let cie1 = CommonInformationEntry::new(encoding, 1, 8, X86_64::RA);
865 let cie1_id = frames.add_cie(cie1.clone());
866 assert_eq!(cie1_id, frames.add_cie(cie1.clone()));
867
868 let mut cie2 = CommonInformationEntry::new(encoding, 1, 8, X86_64::RA);
869 cie2.lsda_encoding = Some(constants::DW_EH_PE_absptr);
870 cie2.personality =
871 Some((constants::DW_EH_PE_absptr, Address::Constant(0x1234)));
872 cie2.signal_trampoline = true;
873 let cie2_id = frames.add_cie(cie2.clone());
874 assert_ne!(cie1_id, cie2_id);
875 assert_eq!(cie2_id, frames.add_cie(cie2.clone()));
876
877 let fde1 = FrameDescriptionEntry::new(Address::Constant(0x1000), 0x10);
878 frames.add_fde(cie1_id, fde1.clone());
879
880 let fde2 = FrameDescriptionEntry::new(Address::Constant(0x2000), 0x20);
881 frames.add_fde(cie1_id, fde2.clone());
882
883 let mut fde3 = FrameDescriptionEntry::new(Address::Constant(0x3000), 0x30);
884 fde3.lsda = Some(Address::Constant(0x3300));
885 frames.add_fde(cie2_id, fde3.clone());
886
887 let mut fde4 = FrameDescriptionEntry::new(Address::Constant(0x4000), 0x40);
888 fde4.lsda = Some(Address::Constant(0x4400));
889 frames.add_fde(cie2_id, fde4.clone());
890
891 // Test writing `.debug_frame`.
892 let mut debug_frame = DebugFrame::from(EndianVec::new(LittleEndian));
893 frames.write_debug_frame(&mut debug_frame).unwrap();
894
895 let mut read_debug_frame =
896 read::DebugFrame::new(debug_frame.slice(), LittleEndian);
897 read_debug_frame.set_address_size(address_size);
898 let convert_frames = FrameTable::from(&read_debug_frame, &|address| {
899 Some(Address::Constant(address))
900 })
901 .unwrap();
902 assert_eq!(frames.cies, convert_frames.cies);
903 assert_eq!(frames.fdes.len(), convert_frames.fdes.len());
904 for (a, b) in frames.fdes.iter().zip(convert_frames.fdes.iter()) {
905 assert_eq!(a.1, b.1);
906 }
907
908 if version == 1 {
909 // Test writing `.eh_frame`.
910 let mut eh_frame = EhFrame::from(EndianVec::new(LittleEndian));
911 frames.write_eh_frame(&mut eh_frame).unwrap();
912
913 let mut read_eh_frame = read::EhFrame::new(eh_frame.slice(), LittleEndian);
914 read_eh_frame.set_address_size(address_size);
915 let convert_frames = FrameTable::from(&read_eh_frame, &|address| {
916 Some(Address::Constant(address))
917 })
918 .unwrap();
919 assert_eq!(frames.cies, convert_frames.cies);
920 assert_eq!(frames.fdes.len(), convert_frames.fdes.len());
921 for (a, b) in frames.fdes.iter().zip(convert_frames.fdes.iter()) {
922 assert_eq!(a.1, b.1);
923 }
924 }
925 }
926 }
927 }
928 }
929
930 #[test]
931 fn test_frame_instruction() {
932 let mut expression = Expression::new();
933 expression.op_constu(0);
934
935 let cie_instructions = [
936 CallFrameInstruction::Cfa(X86_64::RSP, 8),
937 CallFrameInstruction::Offset(X86_64::RA, -8),
938 ];
939
940 let fde_instructions = [
941 (0, CallFrameInstruction::Cfa(X86_64::RSP, 0)),
942 (0, CallFrameInstruction::Cfa(X86_64::RSP, -8)),
943 (2, CallFrameInstruction::CfaRegister(X86_64::RBP)),
944 (4, CallFrameInstruction::CfaOffset(8)),
945 (4, CallFrameInstruction::CfaOffset(0)),
946 (4, CallFrameInstruction::CfaOffset(-8)),
947 (6, CallFrameInstruction::CfaExpression(expression.clone())),
948 (8, CallFrameInstruction::Restore(Register(1))),
949 (8, CallFrameInstruction::Restore(Register(101))),
950 (10, CallFrameInstruction::Undefined(Register(2))),
951 (12, CallFrameInstruction::SameValue(Register(3))),
952 (14, CallFrameInstruction::Offset(Register(4), 16)),
953 (14, CallFrameInstruction::Offset(Register(104), 16)),
954 (16, CallFrameInstruction::ValOffset(Register(5), -24)),
955 (16, CallFrameInstruction::ValOffset(Register(5), 24)),
956 (18, CallFrameInstruction::Register(Register(6), Register(7))),
957 (
958 20,
959 CallFrameInstruction::Expression(Register(8), expression.clone()),
960 ),
961 (
962 22,
963 CallFrameInstruction::ValExpression(Register(9), expression.clone()),
964 ),
965 (24 + 0x80, CallFrameInstruction::RememberState),
966 (26 + 0x280, CallFrameInstruction::RestoreState),
967 (28 + 0x20280, CallFrameInstruction::ArgsSize(23)),
968 ];
969
970 for &version in &[1, 3, 4] {
971 for &address_size in &[4, 8] {
972 for &format in &[Format::Dwarf32, Format::Dwarf64] {
973 let encoding = Encoding {
974 format,
975 version,
976 address_size,
977 };
978 let mut frames = FrameTable::default();
979
980 let mut cie = CommonInformationEntry::new(encoding, 2, 8, X86_64::RA);
981 for i in &cie_instructions {
982 cie.add_instruction(i.clone());
983 }
984 let cie_id = frames.add_cie(cie);
985
986 let mut fde = FrameDescriptionEntry::new(Address::Constant(0x1000), 0x10);
987 for (o, i) in &fde_instructions {
988 fde.add_instruction(*o, i.clone());
989 }
990 frames.add_fde(cie_id, fde);
991
992 let mut debug_frame = DebugFrame::from(EndianVec::new(LittleEndian));
993 frames.write_debug_frame(&mut debug_frame).unwrap();
994
995 let mut read_debug_frame =
996 read::DebugFrame::new(debug_frame.slice(), LittleEndian);
997 read_debug_frame.set_address_size(address_size);
998 let frames = FrameTable::from(&read_debug_frame, &|address| {
999 Some(Address::Constant(address))
1000 })
1001 .unwrap();
1002
1003 assert_eq!(
1004 &frames.cies.get_index(0).unwrap().instructions,
1005 &cie_instructions
1006 );
1007 assert_eq!(&frames.fdes[0].1.instructions, &fde_instructions);
1008 }
1009 }
1010 }
1011 }
1012}