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