Skip to main content

gimli/write/
cfi.rs

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