gimli/write/
cfi.rs

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            w.write_u8(0)?; // segment_selector_size
216        }
217
218        w.write_uleb128(self.code_alignment_factor.into())?;
219        w.write_sleb128(self.data_alignment_factor.into())?;
220
221        if !eh_frame && encoding.version == 1 {
222            let register = self.return_address_register.0 as u8;
223            if u16::from(register) != self.return_address_register.0 {
224                return Err(Error::ValueTooLarge);
225            }
226            w.write_u8(register)?;
227        } else {
228            w.write_uleb128(self.return_address_register.0.into())?;
229        }
230
231        if augmentation {
232            let augmentation_length_offset = w.len();
233            w.write_u8(0)?;
234            let augmentation_length_base = w.len();
235
236            if let Some(eh_pe) = self.lsda_encoding {
237                w.write_u8(eh_pe.0)?;
238            }
239            if let Some((eh_pe, address)) = self.personality {
240                w.write_u8(eh_pe.0)?;
241                w.write_eh_pointer(address, eh_pe, encoding.address_size)?;
242            }
243            if self.fde_address_encoding != constants::DW_EH_PE_absptr {
244                w.write_u8(self.fde_address_encoding.0)?;
245            }
246
247            let augmentation_length = (w.len() - augmentation_length_base) as u64;
248            debug_assert!(augmentation_length < 0x80);
249            w.write_udata_at(augmentation_length_offset, augmentation_length, 1)?;
250        }
251
252        for instruction in &self.instructions {
253            instruction.write(w, encoding, self)?;
254        }
255
256        write_nop(
257            w,
258            encoding.format.word_size() as usize + w.len() - length_base,
259            encoding.address_size,
260        )?;
261
262        let length = (w.len() - length_base) as u64;
263        w.write_initial_length_at(length_offset, length, encoding.format)?;
264
265        Ok(offset)
266    }
267}
268
269/// A frame description entry. There should be one FDE per function.
270#[derive(Debug, Clone, PartialEq, Eq)]
271pub struct FrameDescriptionEntry {
272    /// The initial address of the function.
273    address: Address,
274
275    /// The length in bytes of the function.
276    length: u32,
277
278    /// The address of the LSDA.
279    pub lsda: Option<Address>,
280
281    /// The instructions for this function, ordered by offset.
282    instructions: Vec<(u32, CallFrameInstruction)>,
283}
284
285impl FrameDescriptionEntry {
286    /// Create a new frame description entry for a function.
287    pub fn new(address: Address, length: u32) -> Self {
288        FrameDescriptionEntry {
289            address,
290            length,
291            lsda: None,
292            instructions: Vec::new(),
293        }
294    }
295
296    /// Add an instruction.
297    ///
298    /// Instructions must be added in increasing order of offset, or writing will fail.
299    pub fn add_instruction(&mut self, offset: u32, instruction: CallFrameInstruction) {
300        debug_assert!(self.instructions.last().map(|x| x.0).unwrap_or(0) <= offset);
301        self.instructions.push((offset, instruction));
302    }
303
304    fn write<W: Writer>(
305        &self,
306        w: &mut W,
307        eh_frame: bool,
308        cie_offset: usize,
309        cie: &CommonInformationEntry,
310    ) -> Result<()> {
311        let encoding = cie.encoding;
312        let length_offset = w.write_initial_length(encoding.format)?;
313        let length_base = w.len();
314
315        if eh_frame {
316            // .eh_frame uses a relative offset which doesn't need relocation.
317            w.write_udata((w.len() - cie_offset) as u64, 4)?;
318        } else {
319            w.write_offset(
320                cie_offset,
321                SectionId::DebugFrame,
322                encoding.format.word_size(),
323            )?;
324        }
325
326        if cie.fde_address_encoding != constants::DW_EH_PE_absptr {
327            w.write_eh_pointer(
328                self.address,
329                cie.fde_address_encoding,
330                encoding.address_size,
331            )?;
332            w.write_eh_pointer_data(
333                self.length.into(),
334                cie.fde_address_encoding.format(),
335                encoding.address_size,
336            )?;
337        } else {
338            w.write_address(self.address, encoding.address_size)?;
339            w.write_udata(self.length.into(), encoding.address_size)?;
340        }
341
342        if cie.has_augmentation() {
343            let augmentation_length_offset = w.len();
344            w.write_u8(0)?;
345            let augmentation_length_base = w.len();
346
347            debug_assert_eq!(self.lsda.is_some(), cie.lsda_encoding.is_some());
348            if let (Some(lsda), Some(lsda_encoding)) = (self.lsda, cie.lsda_encoding) {
349                w.write_eh_pointer(lsda, lsda_encoding, encoding.address_size)?;
350            }
351
352            let augmentation_length = (w.len() - augmentation_length_base) as u64;
353            debug_assert!(augmentation_length < 0x80);
354            w.write_udata_at(augmentation_length_offset, augmentation_length, 1)?;
355        }
356
357        let mut prev_offset = 0;
358        for (offset, instruction) in &self.instructions {
359            write_advance_loc(w, cie.code_alignment_factor, prev_offset, *offset)?;
360            prev_offset = *offset;
361            instruction.write(w, encoding, cie)?;
362        }
363
364        write_nop(
365            w,
366            encoding.format.word_size() as usize + w.len() - length_base,
367            encoding.address_size,
368        )?;
369
370        let length = (w.len() - length_base) as u64;
371        w.write_initial_length_at(length_offset, length, encoding.format)?;
372
373        Ok(())
374    }
375}
376
377/// An instruction in a frame description entry.
378///
379/// This may be a CFA definition, a register rule, or some other directive.
380#[derive(Debug, Clone, PartialEq, Eq, Hash)]
381#[non_exhaustive]
382pub enum CallFrameInstruction {
383    /// Define the CFA rule to use the provided register and offset.
384    Cfa(Register, i32),
385    /// Update the CFA rule to use the provided register. The offset is unchanged.
386    CfaRegister(Register),
387    /// Update the CFA rule to use the provided offset. The register is unchanged.
388    CfaOffset(i32),
389    /// Define the CFA rule to use the provided expression.
390    CfaExpression(Expression),
391
392    /// Restore the initial rule for the register.
393    Restore(Register),
394    /// The previous value of the register is not recoverable.
395    Undefined(Register),
396    /// The register has not been modified.
397    SameValue(Register),
398    /// The previous value of the register is saved at address CFA + offset.
399    Offset(Register, i32),
400    /// The previous value of the register is CFA + offset.
401    ValOffset(Register, i32),
402    /// The previous value of the register is stored in another register.
403    Register(Register, Register),
404    /// The previous value of the register is saved at address given by the expression.
405    Expression(Register, Expression),
406    /// The previous value of the register is given by the expression.
407    ValExpression(Register, Expression),
408
409    /// Push all register rules onto a stack.
410    RememberState,
411    /// Pop all register rules off the stack.
412    RestoreState,
413    /// The size of the arguments that have been pushed onto the stack.
414    ArgsSize(u32),
415
416    /// AAarch64 extension: negate the `RA_SIGN_STATE` pseudo-register.
417    NegateRaState,
418}
419
420impl CallFrameInstruction {
421    fn write<W: Writer>(
422        &self,
423        w: &mut W,
424        encoding: Encoding,
425        cie: &CommonInformationEntry,
426    ) -> Result<()> {
427        match *self {
428            CallFrameInstruction::Cfa(register, offset) => {
429                if offset < 0 {
430                    let offset = factored_data_offset(offset, cie.data_alignment_factor)?;
431                    w.write_u8(constants::DW_CFA_def_cfa_sf.0)?;
432                    w.write_uleb128(register.0.into())?;
433                    w.write_sleb128(offset.into())?;
434                } else {
435                    // Unfactored offset.
436                    w.write_u8(constants::DW_CFA_def_cfa.0)?;
437                    w.write_uleb128(register.0.into())?;
438                    w.write_uleb128(offset as u64)?;
439                }
440            }
441            CallFrameInstruction::CfaRegister(register) => {
442                w.write_u8(constants::DW_CFA_def_cfa_register.0)?;
443                w.write_uleb128(register.0.into())?;
444            }
445            CallFrameInstruction::CfaOffset(offset) => {
446                if offset < 0 {
447                    let offset = factored_data_offset(offset, cie.data_alignment_factor)?;
448                    w.write_u8(constants::DW_CFA_def_cfa_offset_sf.0)?;
449                    w.write_sleb128(offset.into())?;
450                } else {
451                    // Unfactored offset.
452                    w.write_u8(constants::DW_CFA_def_cfa_offset.0)?;
453                    w.write_uleb128(offset as u64)?;
454                }
455            }
456            CallFrameInstruction::CfaExpression(ref expression) => {
457                w.write_u8(constants::DW_CFA_def_cfa_expression.0)?;
458                w.write_uleb128(expression.size(encoding, None)? as u64)?;
459                expression.write(w, None, encoding, None)?;
460            }
461            CallFrameInstruction::Restore(register) => {
462                if register.0 < 0x40 {
463                    w.write_u8(constants::DW_CFA_restore.0 | register.0 as u8)?;
464                } else {
465                    w.write_u8(constants::DW_CFA_restore_extended.0)?;
466                    w.write_uleb128(register.0.into())?;
467                }
468            }
469            CallFrameInstruction::Undefined(register) => {
470                w.write_u8(constants::DW_CFA_undefined.0)?;
471                w.write_uleb128(register.0.into())?;
472            }
473            CallFrameInstruction::SameValue(register) => {
474                w.write_u8(constants::DW_CFA_same_value.0)?;
475                w.write_uleb128(register.0.into())?;
476            }
477            CallFrameInstruction::Offset(register, offset) => {
478                let offset = factored_data_offset(offset, cie.data_alignment_factor)?;
479                if offset < 0 {
480                    w.write_u8(constants::DW_CFA_offset_extended_sf.0)?;
481                    w.write_uleb128(register.0.into())?;
482                    w.write_sleb128(offset.into())?;
483                } else if register.0 < 0x40 {
484                    w.write_u8(constants::DW_CFA_offset.0 | register.0 as u8)?;
485                    w.write_uleb128(offset as u64)?;
486                } else {
487                    w.write_u8(constants::DW_CFA_offset_extended.0)?;
488                    w.write_uleb128(register.0.into())?;
489                    w.write_uleb128(offset as u64)?;
490                }
491            }
492            CallFrameInstruction::ValOffset(register, offset) => {
493                let offset = factored_data_offset(offset, cie.data_alignment_factor)?;
494                if offset < 0 {
495                    w.write_u8(constants::DW_CFA_val_offset_sf.0)?;
496                    w.write_uleb128(register.0.into())?;
497                    w.write_sleb128(offset.into())?;
498                } else {
499                    w.write_u8(constants::DW_CFA_val_offset.0)?;
500                    w.write_uleb128(register.0.into())?;
501                    w.write_uleb128(offset as u64)?;
502                }
503            }
504            CallFrameInstruction::Register(register1, register2) => {
505                w.write_u8(constants::DW_CFA_register.0)?;
506                w.write_uleb128(register1.0.into())?;
507                w.write_uleb128(register2.0.into())?;
508            }
509            CallFrameInstruction::Expression(register, ref expression) => {
510                w.write_u8(constants::DW_CFA_expression.0)?;
511                w.write_uleb128(register.0.into())?;
512                w.write_uleb128(expression.size(encoding, None)? as u64)?;
513                expression.write(w, None, encoding, None)?;
514            }
515            CallFrameInstruction::ValExpression(register, ref expression) => {
516                w.write_u8(constants::DW_CFA_val_expression.0)?;
517                w.write_uleb128(register.0.into())?;
518                w.write_uleb128(expression.size(encoding, None)? as u64)?;
519                expression.write(w, None, encoding, None)?;
520            }
521            CallFrameInstruction::RememberState => {
522                w.write_u8(constants::DW_CFA_remember_state.0)?;
523            }
524            CallFrameInstruction::RestoreState => {
525                w.write_u8(constants::DW_CFA_restore_state.0)?;
526            }
527            CallFrameInstruction::ArgsSize(size) => {
528                w.write_u8(constants::DW_CFA_GNU_args_size.0)?;
529                w.write_uleb128(size.into())?;
530            }
531            CallFrameInstruction::NegateRaState => {
532                w.write_u8(constants::DW_CFA_AARCH64_negate_ra_state.0)?;
533            }
534        }
535        Ok(())
536    }
537}
538
539fn write_advance_loc<W: Writer>(
540    w: &mut W,
541    code_alignment_factor: u8,
542    prev_offset: u32,
543    offset: u32,
544) -> Result<()> {
545    if offset == prev_offset {
546        return Ok(());
547    }
548    let delta = factored_code_delta(prev_offset, offset, code_alignment_factor)?;
549    if delta < 0x40 {
550        w.write_u8(constants::DW_CFA_advance_loc.0 | delta as u8)?;
551    } else if delta < 0x100 {
552        w.write_u8(constants::DW_CFA_advance_loc1.0)?;
553        w.write_u8(delta as u8)?;
554    } else if delta < 0x10000 {
555        w.write_u8(constants::DW_CFA_advance_loc2.0)?;
556        w.write_u16(delta as u16)?;
557    } else {
558        w.write_u8(constants::DW_CFA_advance_loc4.0)?;
559        w.write_u32(delta)?;
560    }
561    Ok(())
562}
563
564fn write_nop<W: Writer>(w: &mut W, len: usize, align: u8) -> Result<()> {
565    debug_assert_eq!(align & (align - 1), 0);
566    let tail_len = (!len + 1) & (align as usize - 1);
567    for _ in 0..tail_len {
568        w.write_u8(constants::DW_CFA_nop.0)?;
569    }
570    Ok(())
571}
572
573fn factored_code_delta(prev_offset: u32, offset: u32, factor: u8) -> Result<u32> {
574    if offset < prev_offset {
575        return Err(Error::InvalidFrameCodeOffset(offset));
576    }
577    let delta = offset - prev_offset;
578    let factor = u32::from(factor);
579    let factored_delta = delta / factor;
580    if delta != factored_delta * factor {
581        return Err(Error::InvalidFrameCodeOffset(offset));
582    }
583    Ok(factored_delta)
584}
585
586fn factored_data_offset(offset: i32, factor: i8) -> Result<i32> {
587    let factor = i32::from(factor);
588    let factored_offset = offset / factor;
589    if offset != factored_offset * factor {
590        return Err(Error::InvalidFrameDataOffset(offset));
591    }
592    Ok(factored_offset)
593}
594
595#[cfg(feature = "read")]
596pub(crate) mod convert {
597    use super::*;
598    use crate::read::{self, Reader};
599    use crate::write::{ConvertError, ConvertResult};
600    use std::collections::{hash_map, HashMap};
601
602    impl FrameTable {
603        /// Create a frame table by reading the data in the given section.
604        ///
605        /// `convert_address` is a function to convert read addresses into the `Address`
606        /// type. For non-relocatable addresses, this function may simply return
607        /// `Address::Constant(address)`. For relocatable addresses, it is the caller's
608        /// responsibility to determine the symbol and addend corresponding to the address
609        /// and return `Address::Symbol { symbol, addend }`.
610        pub fn from<R, Section>(
611            frame: &Section,
612            convert_address: &dyn Fn(u64) -> Option<Address>,
613        ) -> ConvertResult<FrameTable>
614        where
615            R: Reader<Offset = usize>,
616            Section: read::UnwindSection<R>,
617            Section::Offset: read::UnwindOffset<usize>,
618        {
619            let bases = read::BaseAddresses::default().set_eh_frame(0);
620
621            let mut frame_table = FrameTable::default();
622
623            let mut cie_ids = HashMap::new();
624            let mut entries = frame.entries(&bases);
625            while let Some(entry) = entries.next()? {
626                let partial = match entry {
627                    read::CieOrFde::Cie(_) => continue,
628                    read::CieOrFde::Fde(partial) => partial,
629                };
630
631                // TODO: is it worth caching the parsed CIEs? It would be better if FDEs only
632                // stored a reference.
633                let from_fde = partial.parse(Section::cie_from_offset)?;
634                let from_cie = from_fde.cie();
635                let cie_id = match cie_ids.entry(from_cie.offset()) {
636                    hash_map::Entry::Occupied(o) => *o.get(),
637                    hash_map::Entry::Vacant(e) => {
638                        let cie =
639                            CommonInformationEntry::from(from_cie, frame, &bases, convert_address)?;
640                        let cie_id = frame_table.add_cie(cie);
641                        e.insert(cie_id);
642                        cie_id
643                    }
644                };
645                let fde = FrameDescriptionEntry::from(&from_fde, frame, &bases, convert_address)?;
646                frame_table.add_fde(cie_id, fde);
647            }
648
649            Ok(frame_table)
650        }
651    }
652
653    impl CommonInformationEntry {
654        fn from<R, Section>(
655            from_cie: &read::CommonInformationEntry<R>,
656            frame: &Section,
657            bases: &read::BaseAddresses,
658            convert_address: &dyn Fn(u64) -> Option<Address>,
659        ) -> ConvertResult<CommonInformationEntry>
660        where
661            R: Reader<Offset = usize>,
662            Section: read::UnwindSection<R>,
663            Section::Offset: read::UnwindOffset<usize>,
664        {
665            let mut cie = CommonInformationEntry::new(
666                from_cie.encoding(),
667                from_cie.code_alignment_factor() as u8,
668                from_cie.data_alignment_factor() as i8,
669                from_cie.return_address_register(),
670            );
671
672            cie.personality = match from_cie.personality_with_encoding() {
673                // We treat these the same because the encoding already determines
674                // whether it is indirect.
675                Some((eh_pe, read::Pointer::Direct(p)))
676                | Some((eh_pe, read::Pointer::Indirect(p))) => {
677                    let address = convert_address(p).ok_or(ConvertError::InvalidAddress)?;
678                    Some((eh_pe, address))
679                }
680                _ => None,
681            };
682            cie.lsda_encoding = from_cie.lsda_encoding();
683            cie.fde_address_encoding = from_cie
684                .fde_address_encoding()
685                .unwrap_or(constants::DW_EH_PE_absptr);
686            cie.signal_trampoline = from_cie.is_signal_trampoline();
687
688            let mut offset = 0;
689            let mut from_instructions = from_cie.instructions(frame, bases);
690            while let Some(from_instruction) = from_instructions.next()? {
691                if let Some(instruction) = CallFrameInstruction::from(
692                    from_instruction,
693                    from_cie,
694                    frame,
695                    convert_address,
696                    &mut offset,
697                )? {
698                    cie.instructions.push(instruction);
699                }
700            }
701            Ok(cie)
702        }
703    }
704
705    impl FrameDescriptionEntry {
706        fn from<R, Section>(
707            from_fde: &read::FrameDescriptionEntry<R>,
708            frame: &Section,
709            bases: &read::BaseAddresses,
710            convert_address: &dyn Fn(u64) -> Option<Address>,
711        ) -> ConvertResult<FrameDescriptionEntry>
712        where
713            R: Reader<Offset = usize>,
714            Section: read::UnwindSection<R>,
715            Section::Offset: read::UnwindOffset<usize>,
716        {
717            let address =
718                convert_address(from_fde.initial_address()).ok_or(ConvertError::InvalidAddress)?;
719            let length = from_fde.len() as u32;
720            let mut fde = FrameDescriptionEntry::new(address, length);
721
722            match from_fde.lsda() {
723                // We treat these the same because the encoding already determines
724                // whether it is indirect.
725                Some(read::Pointer::Direct(p)) | Some(read::Pointer::Indirect(p)) => {
726                    let address = convert_address(p).ok_or(ConvertError::InvalidAddress)?;
727                    fde.lsda = Some(address);
728                }
729                None => {}
730            }
731
732            let from_cie = from_fde.cie();
733            let mut offset = 0;
734            let mut from_instructions = from_fde.instructions(frame, bases);
735            while let Some(from_instruction) = from_instructions.next()? {
736                if let Some(instruction) = CallFrameInstruction::from(
737                    from_instruction,
738                    from_cie,
739                    frame,
740                    convert_address,
741                    &mut offset,
742                )? {
743                    fde.instructions.push((offset, instruction));
744                }
745            }
746
747            Ok(fde)
748        }
749    }
750
751    impl CallFrameInstruction {
752        fn from<R, Section>(
753            from_instruction: read::CallFrameInstruction<R::Offset>,
754            from_cie: &read::CommonInformationEntry<R>,
755            frame: &Section,
756            convert_address: &dyn Fn(u64) -> Option<Address>,
757            offset: &mut u32,
758        ) -> ConvertResult<Option<CallFrameInstruction>>
759        where
760            R: Reader<Offset = usize>,
761            Section: read::UnwindSection<R>,
762        {
763            let convert_expression =
764                |x| Expression::from(x, from_cie.encoding(), None, None, None, convert_address);
765            // TODO: validate integer type conversions
766            Ok(Some(match from_instruction {
767                read::CallFrameInstruction::SetLoc { .. } => {
768                    return Err(ConvertError::UnsupportedCfiInstruction);
769                }
770                read::CallFrameInstruction::AdvanceLoc { delta } => {
771                    *offset += delta * from_cie.code_alignment_factor() as u32;
772                    return Ok(None);
773                }
774                read::CallFrameInstruction::DefCfa { register, offset } => {
775                    CallFrameInstruction::Cfa(register, offset as i32)
776                }
777                read::CallFrameInstruction::DefCfaSf {
778                    register,
779                    factored_offset,
780                } => {
781                    let offset = factored_offset * from_cie.data_alignment_factor();
782                    CallFrameInstruction::Cfa(register, offset as i32)
783                }
784                read::CallFrameInstruction::DefCfaRegister { register } => {
785                    CallFrameInstruction::CfaRegister(register)
786                }
787
788                read::CallFrameInstruction::DefCfaOffset { offset } => {
789                    CallFrameInstruction::CfaOffset(offset as i32)
790                }
791                read::CallFrameInstruction::DefCfaOffsetSf { factored_offset } => {
792                    let offset = factored_offset * from_cie.data_alignment_factor();
793                    CallFrameInstruction::CfaOffset(offset as i32)
794                }
795                read::CallFrameInstruction::DefCfaExpression { expression } => {
796                    let expression = expression.get(frame)?;
797                    CallFrameInstruction::CfaExpression(convert_expression(expression)?)
798                }
799                read::CallFrameInstruction::Undefined { register } => {
800                    CallFrameInstruction::Undefined(register)
801                }
802                read::CallFrameInstruction::SameValue { register } => {
803                    CallFrameInstruction::SameValue(register)
804                }
805                read::CallFrameInstruction::Offset {
806                    register,
807                    factored_offset,
808                } => {
809                    let offset = factored_offset as i64 * from_cie.data_alignment_factor();
810                    CallFrameInstruction::Offset(register, offset as i32)
811                }
812                read::CallFrameInstruction::OffsetExtendedSf {
813                    register,
814                    factored_offset,
815                } => {
816                    let offset = factored_offset * from_cie.data_alignment_factor();
817                    CallFrameInstruction::Offset(register, offset as i32)
818                }
819                read::CallFrameInstruction::ValOffset {
820                    register,
821                    factored_offset,
822                } => {
823                    let offset = factored_offset as i64 * from_cie.data_alignment_factor();
824                    CallFrameInstruction::ValOffset(register, offset as i32)
825                }
826                read::CallFrameInstruction::ValOffsetSf {
827                    register,
828                    factored_offset,
829                } => {
830                    let offset = factored_offset * from_cie.data_alignment_factor();
831                    CallFrameInstruction::ValOffset(register, offset as i32)
832                }
833                read::CallFrameInstruction::Register {
834                    dest_register,
835                    src_register,
836                } => CallFrameInstruction::Register(dest_register, src_register),
837                read::CallFrameInstruction::Expression {
838                    register,
839                    expression,
840                } => {
841                    let expression = expression.get(frame)?;
842                    CallFrameInstruction::Expression(register, convert_expression(expression)?)
843                }
844                read::CallFrameInstruction::ValExpression {
845                    register,
846                    expression,
847                } => {
848                    let expression = expression.get(frame)?;
849                    CallFrameInstruction::ValExpression(register, convert_expression(expression)?)
850                }
851                read::CallFrameInstruction::Restore { register } => {
852                    CallFrameInstruction::Restore(register)
853                }
854                read::CallFrameInstruction::RememberState => CallFrameInstruction::RememberState,
855                read::CallFrameInstruction::RestoreState => CallFrameInstruction::RestoreState,
856                read::CallFrameInstruction::ArgsSize { size } => {
857                    CallFrameInstruction::ArgsSize(size as u32)
858                }
859                read::CallFrameInstruction::NegateRaState => CallFrameInstruction::NegateRaState,
860                read::CallFrameInstruction::Nop => return Ok(None),
861            }))
862        }
863    }
864}
865
866#[cfg(test)]
867#[cfg(feature = "read")]
868mod tests {
869    use super::*;
870    use crate::arch::X86_64;
871    use crate::read;
872    use crate::write::EndianVec;
873    use crate::{LittleEndian, Vendor};
874
875    #[test]
876    fn test_frame_table() {
877        for &version in &[1, 3, 4] {
878            for &address_size in &[4, 8] {
879                for &format in &[Format::Dwarf32, Format::Dwarf64] {
880                    let encoding = Encoding {
881                        format,
882                        version,
883                        address_size,
884                    };
885                    let mut frames = FrameTable::default();
886
887                    let cie1 = CommonInformationEntry::new(encoding, 1, 8, X86_64::RA);
888                    let cie1_id = frames.add_cie(cie1.clone());
889                    assert_eq!(cie1_id, frames.add_cie(cie1.clone()));
890
891                    let mut cie2 = CommonInformationEntry::new(encoding, 1, 8, X86_64::RA);
892                    cie2.lsda_encoding = Some(constants::DW_EH_PE_absptr);
893                    cie2.personality =
894                        Some((constants::DW_EH_PE_absptr, Address::Constant(0x1234)));
895                    cie2.signal_trampoline = true;
896                    let cie2_id = frames.add_cie(cie2.clone());
897                    assert_ne!(cie1_id, cie2_id);
898                    assert_eq!(cie2_id, frames.add_cie(cie2.clone()));
899
900                    let fde1 = FrameDescriptionEntry::new(Address::Constant(0x1000), 0x10);
901                    frames.add_fde(cie1_id, fde1.clone());
902
903                    let fde2 = FrameDescriptionEntry::new(Address::Constant(0x2000), 0x20);
904                    frames.add_fde(cie1_id, fde2.clone());
905
906                    let mut fde3 = FrameDescriptionEntry::new(Address::Constant(0x3000), 0x30);
907                    fde3.lsda = Some(Address::Constant(0x3300));
908                    frames.add_fde(cie2_id, fde3.clone());
909
910                    let mut fde4 = FrameDescriptionEntry::new(Address::Constant(0x4000), 0x40);
911                    fde4.lsda = Some(Address::Constant(0x4400));
912                    frames.add_fde(cie2_id, fde4.clone());
913
914                    let mut cie3 = CommonInformationEntry::new(encoding, 1, 8, X86_64::RA);
915                    cie3.fde_address_encoding =
916                        constants::DW_EH_PE_pcrel | constants::DW_EH_PE_sdata4;
917                    cie3.lsda_encoding =
918                        Some(constants::DW_EH_PE_pcrel | constants::DW_EH_PE_sdata4);
919                    cie3.personality = Some((
920                        constants::DW_EH_PE_pcrel | constants::DW_EH_PE_sdata4,
921                        Address::Constant(0x1235),
922                    ));
923                    cie3.signal_trampoline = true;
924                    let cie3_id = frames.add_cie(cie3.clone());
925                    assert_ne!(cie2_id, cie3_id);
926                    assert_eq!(cie3_id, frames.add_cie(cie3.clone()));
927
928                    let mut fde5 = FrameDescriptionEntry::new(Address::Constant(0x5000), 0x50);
929                    fde5.lsda = Some(Address::Constant(0x5500));
930                    frames.add_fde(cie3_id, fde5.clone());
931
932                    // Test writing `.debug_frame`.
933                    let mut debug_frame = DebugFrame::from(EndianVec::new(LittleEndian));
934                    frames.write_debug_frame(&mut debug_frame).unwrap();
935
936                    let mut read_debug_frame =
937                        read::DebugFrame::new(debug_frame.slice(), LittleEndian);
938                    read_debug_frame.set_address_size(address_size);
939                    let convert_frames = FrameTable::from(&read_debug_frame, &|address| {
940                        Some(Address::Constant(address))
941                    })
942                    .unwrap();
943                    assert_eq!(frames.cies, convert_frames.cies);
944                    assert_eq!(frames.fdes.len(), convert_frames.fdes.len());
945                    for (a, b) in frames.fdes.iter().zip(convert_frames.fdes.iter()) {
946                        assert_eq!(a.1, b.1);
947                    }
948
949                    if version == 1 {
950                        // Test writing `.eh_frame`.
951                        let mut eh_frame = EhFrame::from(EndianVec::new(LittleEndian));
952                        frames.write_eh_frame(&mut eh_frame).unwrap();
953
954                        let mut read_eh_frame = read::EhFrame::new(eh_frame.slice(), LittleEndian);
955                        read_eh_frame.set_address_size(address_size);
956                        let convert_frames = FrameTable::from(&read_eh_frame, &|address| {
957                            Some(Address::Constant(address))
958                        })
959                        .unwrap();
960                        assert_eq!(frames.cies, convert_frames.cies);
961                        assert_eq!(frames.fdes.len(), convert_frames.fdes.len());
962                        for (a, b) in frames.fdes.iter().zip(convert_frames.fdes.iter()) {
963                            assert_eq!(a.1, b.1);
964                        }
965                    }
966                }
967            }
968        }
969    }
970
971    #[test]
972    fn test_frame_instruction() {
973        let mut expression = Expression::new();
974        expression.op_constu(0);
975
976        let cie_instructions = [
977            CallFrameInstruction::Cfa(X86_64::RSP, 8),
978            CallFrameInstruction::Offset(X86_64::RA, -8),
979        ];
980
981        let fde_instructions = [
982            (0, CallFrameInstruction::Cfa(X86_64::RSP, 0)),
983            (0, CallFrameInstruction::Cfa(X86_64::RSP, -8)),
984            (2, CallFrameInstruction::CfaRegister(X86_64::RBP)),
985            (4, CallFrameInstruction::CfaOffset(8)),
986            (4, CallFrameInstruction::CfaOffset(0)),
987            (4, CallFrameInstruction::CfaOffset(-8)),
988            (6, CallFrameInstruction::CfaExpression(expression.clone())),
989            (8, CallFrameInstruction::Restore(Register(1))),
990            (8, CallFrameInstruction::Restore(Register(101))),
991            (10, CallFrameInstruction::Undefined(Register(2))),
992            (12, CallFrameInstruction::SameValue(Register(3))),
993            (14, CallFrameInstruction::Offset(Register(4), 16)),
994            (14, CallFrameInstruction::Offset(Register(104), 16)),
995            (16, CallFrameInstruction::ValOffset(Register(5), -24)),
996            (16, CallFrameInstruction::ValOffset(Register(5), 24)),
997            (18, CallFrameInstruction::Register(Register(6), Register(7))),
998            (
999                20,
1000                CallFrameInstruction::Expression(Register(8), expression.clone()),
1001            ),
1002            (
1003                22,
1004                CallFrameInstruction::ValExpression(Register(9), expression.clone()),
1005            ),
1006            (24 + 0x80, CallFrameInstruction::RememberState),
1007            (26 + 0x280, CallFrameInstruction::RestoreState),
1008            (28 + 0x20280, CallFrameInstruction::ArgsSize(23)),
1009        ];
1010
1011        let fde_instructions_aarch64 = [(0, CallFrameInstruction::NegateRaState)];
1012
1013        for &version in &[1, 3, 4] {
1014            for &address_size in &[4, 8] {
1015                for &vendor in &[Vendor::Default, Vendor::AArch64] {
1016                    for &format in &[Format::Dwarf32, Format::Dwarf64] {
1017                        let encoding = Encoding {
1018                            format,
1019                            version,
1020                            address_size,
1021                        };
1022                        let mut frames = FrameTable::default();
1023
1024                        let mut cie = CommonInformationEntry::new(encoding, 2, 8, X86_64::RA);
1025                        for i in &cie_instructions {
1026                            cie.add_instruction(i.clone());
1027                        }
1028                        let cie_id = frames.add_cie(cie);
1029
1030                        let mut fde = FrameDescriptionEntry::new(Address::Constant(0x1000), 0x10);
1031                        for (o, i) in &fde_instructions {
1032                            fde.add_instruction(*o, i.clone());
1033                        }
1034                        frames.add_fde(cie_id, fde);
1035
1036                        if vendor == Vendor::AArch64 {
1037                            let mut fde =
1038                                FrameDescriptionEntry::new(Address::Constant(0x2000), 0x10);
1039                            for (o, i) in &fde_instructions_aarch64 {
1040                                fde.add_instruction(*o, i.clone());
1041                            }
1042                            frames.add_fde(cie_id, fde);
1043                        }
1044
1045                        let mut debug_frame = DebugFrame::from(EndianVec::new(LittleEndian));
1046                        frames.write_debug_frame(&mut debug_frame).unwrap();
1047
1048                        let mut read_debug_frame =
1049                            read::DebugFrame::new(debug_frame.slice(), LittleEndian);
1050                        read_debug_frame.set_address_size(address_size);
1051                        read_debug_frame.set_vendor(vendor);
1052                        let frames = FrameTable::from(&read_debug_frame, &|address| {
1053                            Some(Address::Constant(address))
1054                        })
1055                        .unwrap();
1056
1057                        assert_eq!(
1058                            &frames.cies.get_index(0).unwrap().instructions,
1059                            &cie_instructions
1060                        );
1061                        assert_eq!(&frames.fdes[0].1.instructions, &fde_instructions);
1062                        if vendor == Vendor::AArch64 {
1063                            assert_eq!(&frames.fdes[1].1.instructions, &fde_instructions_aarch64);
1064                        }
1065                    }
1066                }
1067            }
1068        }
1069    }
1070}