1use alloc::vec::Vec;
2use indexmap::IndexSet;
3use std::ops::{Deref, DerefMut};
4
5use crate::common::{DebugFrameOffset, EhFrameOffset, Encoding, Format, Register, SectionId};
6use crate::constants;
7use crate::write::{Address, BaseId, Error, Expression, Result, Section, Writer};
8
9define_section!(
10 DebugFrame,
11 DebugFrameOffset,
12 "A writable `.debug_frame` section."
13);
14
15define_section!(EhFrame, EhFrameOffset, "A writable `.eh_frame` section.");
16
17define_id!(CieId, "An identifier for a CIE in a `FrameTable`.");
18
19/// A table of frame description entries.
20#[derive(Debug, Default)]
21pub struct FrameTable {
22 /// Base id for CIEs.
23 base_id: BaseId,
24 /// The common information entries.
25 cies: IndexSet<CommonInformationEntry>,
26 /// The frame description entries.
27 fdes: Vec<(CieId, FrameDescriptionEntry)>,
28}
29
30impl FrameTable {
31 /// Add a CIE and return its id.
32 ///
33 /// If the CIE already exists, then return the id of the existing CIE.
34 pub fn add_cie(&mut self, cie: CommonInformationEntry) -> CieId {
35 let (index, _) = self.cies.insert_full(cie);
36 CieId::new(self.base_id, index)
37 }
38
39 /// The number of CIEs.
40 pub fn cie_count(&self) -> usize {
41 self.cies.len()
42 }
43
44 /// Add a FDE.
45 ///
46 /// Does not check for duplicates.
47 ///
48 /// # Panics
49 ///
50 /// Panics if the CIE id is invalid.
51 pub fn add_fde(&mut self, cie: CieId, fde: FrameDescriptionEntry) {
52 debug_assert_eq!(self.base_id, cie.base_id);
53 self.fdes.push((cie, fde));
54 }
55
56 /// The number of FDEs.
57 pub fn fde_count(&self) -> usize {
58 self.fdes.len()
59 }
60
61 /// Write the frame table entries to the given `.debug_frame` section.
62 pub fn write_debug_frame<W: Writer>(&self, w: &mut DebugFrame<W>) -> Result<()> {
63 self.write(&mut w.0, false)
64 }
65
66 /// Write the frame table entries to the given `.eh_frame` section.
67 pub fn write_eh_frame<W: Writer>(&self, w: &mut EhFrame<W>) -> Result<()> {
68 self.write(&mut w.0, true)
69 }
70
71 fn write<W: Writer>(&self, w: &mut W, eh_frame: bool) -> Result<()> {
72 let mut cie_offsets = vec![None; self.cies.len()];
73 for (cie_id, fde) in &self.fdes {
74 let cie_index = cie_id.index;
75 let cie = self.cies.get_index(cie_index).unwrap();
76 let cie_offset = match cie_offsets[cie_index] {
77 Some(offset) => offset,
78 None => {
79 // Only write CIEs as they are referenced.
80 let offset = cie.write(w, eh_frame)?;
81 cie_offsets[cie_index] = Some(offset);
82 offset
83 }
84 };
85
86 fde.write(w, eh_frame, cie_offset, cie)?;
87 }
88 // TODO: write length 0 terminator for eh_frame?
89 Ok(())
90 }
91}
92
93/// A common information entry. This contains information that is shared between FDEs.
94#[derive(Debug, Clone, PartialEq, Eq, Hash)]
95pub struct CommonInformationEntry {
96 encoding: Encoding,
97
98 /// A constant that is factored out of code offsets.
99 ///
100 /// This should be set to the minimum instruction length.
101 /// Writing a code offset that is not a multiple of this factor will generate an error.
102 code_alignment_factor: u8,
103
104 /// A constant that is factored out of data offsets.
105 ///
106 /// This should be set to the minimum data alignment for the frame.
107 /// Writing a data offset that is not a multiple of this factor will generate an error.
108 data_alignment_factor: i8,
109
110 /// The return address register. This might not correspond to an actual machine register.
111 return_address_register: Register,
112
113 /// The address of the personality function and its encoding.
114 pub personality: Option<(constants::DwEhPe, Address)>,
115
116 /// The encoding to use for the LSDA address in FDEs.
117 ///
118 /// If set then all FDEs which use this CIE must have a LSDA address.
119 pub lsda_encoding: Option<constants::DwEhPe>,
120
121 /// The encoding to use for addresses in FDEs.
122 pub fde_address_encoding: constants::DwEhPe,
123
124 /// True for signal trampolines.
125 pub signal_trampoline: bool,
126
127 /// The initial instructions upon entry to this function.
128 instructions: Vec<CallFrameInstruction>,
129}
130
131impl CommonInformationEntry {
132 /// Create a new common information entry.
133 ///
134 /// The encoding version must be a CFI version, not a DWARF version.
135 pub fn new(
136 encoding: Encoding,
137 code_alignment_factor: u8,
138 data_alignment_factor: i8,
139 return_address_register: Register,
140 ) -> Self {
141 CommonInformationEntry {
142 encoding,
143 code_alignment_factor,
144 data_alignment_factor,
145 return_address_register,
146 personality: None,
147 lsda_encoding: None,
148 fde_address_encoding: constants::DW_EH_PE_absptr,
149 signal_trampoline: false,
150 instructions: Vec::new(),
151 }
152 }
153
154 /// Add an initial instruction.
155 pub fn add_instruction(&mut self, instruction: CallFrameInstruction) {
156 self.instructions.push(instruction);
157 }
158
159 fn has_augmentation(&self) -> bool {
160 self.personality.is_some()
161 || self.lsda_encoding.is_some()
162 || self.signal_trampoline
163 || self.fde_address_encoding != constants::DW_EH_PE_absptr
164 }
165
166 /// Returns the section offset of the CIE.
167 fn write<W: Writer>(&self, w: &mut W, eh_frame: bool) -> Result<usize> {
168 let encoding = self.encoding;
169 let offset = w.len();
170
171 let length_offset = w.write_initial_length(encoding.format)?;
172 let length_base = w.len();
173
174 if eh_frame {
175 w.write_u32(0)?;
176 } else {
177 match encoding.format {
178 Format::Dwarf32 => w.write_u32(0xffff_ffff)?,
179 Format::Dwarf64 => w.write_u64(0xffff_ffff_ffff_ffff)?,
180 }
181 }
182
183 if eh_frame {
184 if encoding.version != 1 {
185 return Err(Error::UnsupportedVersion(encoding.version));
186 };
187 } else {
188 match encoding.version {
189 1 | 3 | 4 => {}
190 _ => return Err(Error::UnsupportedVersion(encoding.version)),
191 };
192 }
193 w.write_u8(encoding.version as u8)?;
194
195 let augmentation = self.has_augmentation();
196 if augmentation {
197 w.write_u8(b'z')?;
198 if self.lsda_encoding.is_some() {
199 w.write_u8(b'L')?;
200 }
201 if self.personality.is_some() {
202 w.write_u8(b'P')?;
203 }
204 if self.fde_address_encoding != constants::DW_EH_PE_absptr {
205 w.write_u8(b'R')?;
206 }
207 if self.signal_trampoline {
208 w.write_u8(b'S')?;
209 }
210 }
211 w.write_u8(0)?;
212
213 if encoding.version >= 4 {
214 w.write_u8(encoding.address_size)?;
215 // TODO: segment_selector_size
216 w.write_u8(0)?;
217 }
218
219 w.write_uleb128(self.code_alignment_factor.into())?;
220 w.write_sleb128(self.data_alignment_factor.into())?;
221
222 if !eh_frame && encoding.version == 1 {
223 let register = self.return_address_register.0 as u8;
224 if u16::from(register) != self.return_address_register.0 {
225 return Err(Error::ValueTooLarge);
226 }
227 w.write_u8(register)?;
228 } else {
229 w.write_uleb128(self.return_address_register.0.into())?;
230 }
231
232 if augmentation {
233 let augmentation_length_offset = w.len();
234 w.write_u8(0)?;
235 let augmentation_length_base = w.len();
236
237 if let Some(eh_pe) = self.lsda_encoding {
238 w.write_u8(eh_pe.0)?;
239 }
240 if let Some((eh_pe, address)) = self.personality {
241 w.write_u8(eh_pe.0)?;
242 w.write_eh_pointer(address, eh_pe, encoding.address_size)?;
243 }
244 if self.fde_address_encoding != constants::DW_EH_PE_absptr {
245 w.write_u8(self.fde_address_encoding.0)?;
246 }
247
248 let augmentation_length = (w.len() - augmentation_length_base) as u64;
249 debug_assert!(augmentation_length < 0x80);
250 w.write_udata_at(augmentation_length_offset, augmentation_length, 1)?;
251 }
252
253 for instruction in &self.instructions {
254 instruction.write(w, encoding, self)?;
255 }
256
257 write_nop(
258 w,
259 encoding.format.word_size() as usize + w.len() - length_base,
260 encoding.address_size,
261 )?;
262
263 let length = (w.len() - length_base) as u64;
264 w.write_initial_length_at(length_offset, length, encoding.format)?;
265
266 Ok(offset)
267 }
268}
269
270/// A frame description entry. There should be one FDE per function.
271#[derive(Debug, Clone, PartialEq, Eq)]
272pub struct FrameDescriptionEntry {
273 /// The initial address of the function.
274 address: Address,
275
276 /// The length in bytes of the function.
277 length: u32,
278
279 /// The address of the LSDA.
280 pub lsda: Option<Address>,
281
282 /// The instructions for this function, ordered by offset.
283 instructions: Vec<(u32, CallFrameInstruction)>,
284}
285
286impl FrameDescriptionEntry {
287 /// Create a new frame description entry for a function.
288 pub fn new(address: Address, length: u32) -> Self {
289 FrameDescriptionEntry {
290 address,
291 length,
292 lsda: None,
293 instructions: Vec::new(),
294 }
295 }
296
297 /// Add an instruction.
298 ///
299 /// Instructions must be added in increasing order of offset, or writing will fail.
300 pub fn add_instruction(&mut self, offset: u32, instruction: CallFrameInstruction) {
301 debug_assert!(self.instructions.last().map(|x| x.0).unwrap_or(0) <= offset);
302 self.instructions.push((offset, instruction));
303 }
304
305 fn write<W: Writer>(
306 &self,
307 w: &mut W,
308 eh_frame: bool,
309 cie_offset: usize,
310 cie: &CommonInformationEntry,
311 ) -> Result<()> {
312 let encoding = cie.encoding;
313 let length_offset = w.write_initial_length(encoding.format)?;
314 let length_base = w.len();
315
316 if eh_frame {
317 // .eh_frame uses a relative offset which doesn't need relocation.
318 w.write_udata((w.len() - cie_offset) as u64, 4)?;
319 } else {
320 w.write_offset(
321 cie_offset,
322 SectionId::DebugFrame,
323 encoding.format.word_size(),
324 )?;
325 }
326
327 if cie.fde_address_encoding != constants::DW_EH_PE_absptr {
328 w.write_eh_pointer(
329 self.address,
330 cie.fde_address_encoding,
331 encoding.address_size,
332 )?;
333 w.write_eh_pointer_data(
334 self.length.into(),
335 cie.fde_address_encoding.format(),
336 encoding.address_size,
337 )?;
338 } else {
339 w.write_address(self.address, encoding.address_size)?;
340 w.write_udata(self.length.into(), encoding.address_size)?;
341 }
342
343 if cie.has_augmentation() {
344 let mut augmentation_length = 0u64;
345 if self.lsda.is_some() {
346 augmentation_length += u64::from(encoding.address_size);
347 }
348 w.write_uleb128(augmentation_length)?;
349
350 debug_assert_eq!(self.lsda.is_some(), cie.lsda_encoding.is_some());
351 if let (Some(lsda), Some(lsda_encoding)) = (self.lsda, cie.lsda_encoding) {
352 w.write_eh_pointer(lsda, lsda_encoding, encoding.address_size)?;
353 }
354 }
355
356 let mut prev_offset = 0;
357 for (offset, instruction) in &self.instructions {
358 write_advance_loc(w, cie.code_alignment_factor, prev_offset, *offset)?;
359 prev_offset = *offset;
360 instruction.write(w, encoding, cie)?;
361 }
362
363 write_nop(
364 w,
365 encoding.format.word_size() as usize + w.len() - length_base,
366 encoding.address_size,
367 )?;
368
369 let length = (w.len() - length_base) as u64;
370 w.write_initial_length_at(length_offset, length, encoding.format)?;
371
372 Ok(())
373 }
374}
375
376/// An instruction in a frame description entry.
377///
378/// This may be a CFA definition, a register rule, or some other directive.
379#[derive(Debug, Clone, PartialEq, Eq, Hash)]
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: u32 = factored_code_delta(prev_offset, offset, code_alignment_factor)?;
548 if delta < 0x40 {
549 w.write_u8(val:constants::DW_CFA_advance_loc.0 | delta as u8)?;
550 } else if delta < 0x100 {
551 w.write_u8(val:constants::DW_CFA_advance_loc1.0)?;
552 w.write_u8(val:delta as u8)?;
553 } else if delta < 0x10000 {
554 w.write_u8(val:constants::DW_CFA_advance_loc2.0)?;
555 w.write_u16(val:delta as u16)?;
556 } else {
557 w.write_u8(val:constants::DW_CFA_advance_loc4.0)?;
558 w.write_u32(val: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: usize = (!len + 1) & (align as usize - 1);
566 for _ in 0..tail_len {
567 w.write_u8(val: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: u32 = 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};
599 use std::collections::{hash_map, HashMap};
600
601 impl FrameTable {
602 /// Create a frame table by reading the data in the given section.
603 ///
604 /// `convert_address` is a function to convert read addresses into the `Address`
605 /// type. For non-relocatable addresses, this function may simply return
606 /// `Address::Constant(address)`. For relocatable addresses, it is the caller's
607 /// responsibility to determine the symbol and addend corresponding to the address
608 /// and return `Address::Symbol { symbol, addend }`.
609 pub fn from<R, Section>(
610 frame: &Section,
611 convert_address: &dyn Fn(u64) -> Option<Address>,
612 ) -> ConvertResult<FrameTable>
613 where
614 R: Reader<Offset = usize>,
615 Section: read::UnwindSection<R>,
616 Section::Offset: read::UnwindOffset<usize>,
617 {
618 let bases = read::BaseAddresses::default().set_eh_frame(0);
619
620 let mut frame_table = FrameTable::default();
621
622 let mut cie_ids = HashMap::new();
623 let mut entries = frame.entries(&bases);
624 while let Some(entry) = entries.next()? {
625 let partial = match entry {
626 read::CieOrFde::Cie(_) => continue,
627 read::CieOrFde::Fde(partial) => partial,
628 };
629
630 // TODO: is it worth caching the parsed CIEs? It would be better if FDEs only
631 // stored a reference.
632 let from_fde = partial.parse(Section::cie_from_offset)?;
633 let from_cie = from_fde.cie();
634 let cie_id = match cie_ids.entry(from_cie.offset()) {
635 hash_map::Entry::Occupied(o) => *o.get(),
636 hash_map::Entry::Vacant(e) => {
637 let cie =
638 CommonInformationEntry::from(from_cie, frame, &bases, convert_address)?;
639 let cie_id = frame_table.add_cie(cie);
640 e.insert(cie_id);
641 cie_id
642 }
643 };
644 let fde = FrameDescriptionEntry::from(&from_fde, frame, &bases, convert_address)?;
645 frame_table.add_fde(cie_id, fde);
646 }
647
648 Ok(frame_table)
649 }
650 }
651
652 impl CommonInformationEntry {
653 fn from<R, Section>(
654 from_cie: &read::CommonInformationEntry<R>,
655 frame: &Section,
656 bases: &read::BaseAddresses,
657 convert_address: &dyn Fn(u64) -> Option<Address>,
658 ) -> ConvertResult<CommonInformationEntry>
659 where
660 R: Reader<Offset = usize>,
661 Section: read::UnwindSection<R>,
662 Section::Offset: read::UnwindOffset<usize>,
663 {
664 let mut cie = CommonInformationEntry::new(
665 from_cie.encoding(),
666 from_cie.code_alignment_factor() as u8,
667 from_cie.data_alignment_factor() as i8,
668 from_cie.return_address_register(),
669 );
670
671 cie.personality = match from_cie.personality_with_encoding() {
672 // We treat these the same because the encoding already determines
673 // whether it is indirect.
674 Some((eh_pe, read::Pointer::Direct(p)))
675 | Some((eh_pe, read::Pointer::Indirect(p))) => {
676 let address = convert_address(p).ok_or(ConvertError::InvalidAddress)?;
677 Some((eh_pe, address))
678 }
679 _ => None,
680 };
681 cie.lsda_encoding = from_cie.lsda_encoding();
682 cie.fde_address_encoding = from_cie
683 .fde_address_encoding()
684 .unwrap_or(constants::DW_EH_PE_absptr);
685 cie.signal_trampoline = from_cie.is_signal_trampoline();
686
687 let mut offset = 0;
688 let mut from_instructions = from_cie.instructions(frame, bases);
689 while let Some(from_instruction) = from_instructions.next()? {
690 if let Some(instruction) = CallFrameInstruction::from(
691 from_instruction,
692 from_cie,
693 convert_address,
694 &mut offset,
695 )? {
696 cie.instructions.push(instruction);
697 }
698 }
699 Ok(cie)
700 }
701 }
702
703 impl FrameDescriptionEntry {
704 fn from<R, Section>(
705 from_fde: &read::FrameDescriptionEntry<R>,
706 frame: &Section,
707 bases: &read::BaseAddresses,
708 convert_address: &dyn Fn(u64) -> Option<Address>,
709 ) -> ConvertResult<FrameDescriptionEntry>
710 where
711 R: Reader<Offset = usize>,
712 Section: read::UnwindSection<R>,
713 Section::Offset: read::UnwindOffset<usize>,
714 {
715 let address =
716 convert_address(from_fde.initial_address()).ok_or(ConvertError::InvalidAddress)?;
717 let length = from_fde.len() as u32;
718 let mut fde = FrameDescriptionEntry::new(address, length);
719
720 match from_fde.lsda() {
721 // We treat these the same because the encoding already determines
722 // whether it is indirect.
723 Some(read::Pointer::Direct(p)) | Some(read::Pointer::Indirect(p)) => {
724 let address = convert_address(p).ok_or(ConvertError::InvalidAddress)?;
725 fde.lsda = Some(address);
726 }
727 None => {}
728 }
729
730 let from_cie = from_fde.cie();
731 let mut offset = 0;
732 let mut from_instructions = from_fde.instructions(frame, bases);
733 while let Some(from_instruction) = from_instructions.next()? {
734 if let Some(instruction) = CallFrameInstruction::from(
735 from_instruction,
736 from_cie,
737 convert_address,
738 &mut offset,
739 )? {
740 fde.instructions.push((offset, instruction));
741 }
742 }
743
744 Ok(fde)
745 }
746 }
747
748 impl CallFrameInstruction {
749 fn from<R: Reader<Offset = usize>>(
750 from_instruction: read::CallFrameInstruction<R>,
751 from_cie: &read::CommonInformationEntry<R>,
752 convert_address: &dyn Fn(u64) -> Option<Address>,
753 offset: &mut u32,
754 ) -> ConvertResult<Option<CallFrameInstruction>> {
755 let convert_expression =
756 |x| Expression::from(x, from_cie.encoding(), None, None, None, convert_address);
757 // TODO: validate integer type conversions
758 Ok(Some(match from_instruction {
759 read::CallFrameInstruction::SetLoc { .. } => {
760 return Err(ConvertError::UnsupportedCfiInstruction);
761 }
762 read::CallFrameInstruction::AdvanceLoc { delta } => {
763 *offset += delta * from_cie.code_alignment_factor() as u32;
764 return Ok(None);
765 }
766 read::CallFrameInstruction::DefCfa { register, offset } => {
767 CallFrameInstruction::Cfa(register, offset as i32)
768 }
769 read::CallFrameInstruction::DefCfaSf {
770 register,
771 factored_offset,
772 } => {
773 let offset = factored_offset * from_cie.data_alignment_factor();
774 CallFrameInstruction::Cfa(register, offset as i32)
775 }
776 read::CallFrameInstruction::DefCfaRegister { register } => {
777 CallFrameInstruction::CfaRegister(register)
778 }
779
780 read::CallFrameInstruction::DefCfaOffset { offset } => {
781 CallFrameInstruction::CfaOffset(offset as i32)
782 }
783 read::CallFrameInstruction::DefCfaOffsetSf { factored_offset } => {
784 let offset = factored_offset * from_cie.data_alignment_factor();
785 CallFrameInstruction::CfaOffset(offset as i32)
786 }
787 read::CallFrameInstruction::DefCfaExpression { expression } => {
788 CallFrameInstruction::CfaExpression(convert_expression(expression)?)
789 }
790 read::CallFrameInstruction::Undefined { register } => {
791 CallFrameInstruction::Undefined(register)
792 }
793 read::CallFrameInstruction::SameValue { register } => {
794 CallFrameInstruction::SameValue(register)
795 }
796 read::CallFrameInstruction::Offset {
797 register,
798 factored_offset,
799 } => {
800 let offset = factored_offset as i64 * from_cie.data_alignment_factor();
801 CallFrameInstruction::Offset(register, offset as i32)
802 }
803 read::CallFrameInstruction::OffsetExtendedSf {
804 register,
805 factored_offset,
806 } => {
807 let offset = factored_offset * from_cie.data_alignment_factor();
808 CallFrameInstruction::Offset(register, offset as i32)
809 }
810 read::CallFrameInstruction::ValOffset {
811 register,
812 factored_offset,
813 } => {
814 let offset = factored_offset as i64 * from_cie.data_alignment_factor();
815 CallFrameInstruction::ValOffset(register, offset as i32)
816 }
817 read::CallFrameInstruction::ValOffsetSf {
818 register,
819 factored_offset,
820 } => {
821 let offset = factored_offset * from_cie.data_alignment_factor();
822 CallFrameInstruction::ValOffset(register, offset as i32)
823 }
824 read::CallFrameInstruction::Register {
825 dest_register,
826 src_register,
827 } => CallFrameInstruction::Register(dest_register, src_register),
828 read::CallFrameInstruction::Expression {
829 register,
830 expression,
831 } => CallFrameInstruction::Expression(register, convert_expression(expression)?),
832 read::CallFrameInstruction::ValExpression {
833 register,
834 expression,
835 } => CallFrameInstruction::ValExpression(register, convert_expression(expression)?),
836 read::CallFrameInstruction::Restore { register } => {
837 CallFrameInstruction::Restore(register)
838 }
839 read::CallFrameInstruction::RememberState => CallFrameInstruction::RememberState,
840 read::CallFrameInstruction::RestoreState => CallFrameInstruction::RestoreState,
841 read::CallFrameInstruction::ArgsSize { size } => {
842 CallFrameInstruction::ArgsSize(size as u32)
843 }
844 read::CallFrameInstruction::NegateRaState => CallFrameInstruction::NegateRaState,
845 read::CallFrameInstruction::Nop => return Ok(None),
846 }))
847 }
848 }
849}
850
851#[cfg(test)]
852#[cfg(feature = "read")]
853mod tests {
854 use super::*;
855 use crate::arch::X86_64;
856 use crate::read;
857 use crate::write::EndianVec;
858 use crate::{LittleEndian, Vendor};
859
860 #[test]
861 fn test_frame_table() {
862 for &version in &[1, 3, 4] {
863 for &address_size in &[4, 8] {
864 for &format in &[Format::Dwarf32, Format::Dwarf64] {
865 let encoding = Encoding {
866 format,
867 version,
868 address_size,
869 };
870 let mut frames = FrameTable::default();
871
872 let cie1 = CommonInformationEntry::new(encoding, 1, 8, X86_64::RA);
873 let cie1_id = frames.add_cie(cie1.clone());
874 assert_eq!(cie1_id, frames.add_cie(cie1.clone()));
875
876 let mut cie2 = CommonInformationEntry::new(encoding, 1, 8, X86_64::RA);
877 cie2.lsda_encoding = Some(constants::DW_EH_PE_absptr);
878 cie2.personality =
879 Some((constants::DW_EH_PE_absptr, Address::Constant(0x1234)));
880 cie2.signal_trampoline = true;
881 let cie2_id = frames.add_cie(cie2.clone());
882 assert_ne!(cie1_id, cie2_id);
883 assert_eq!(cie2_id, frames.add_cie(cie2.clone()));
884
885 let fde1 = FrameDescriptionEntry::new(Address::Constant(0x1000), 0x10);
886 frames.add_fde(cie1_id, fde1.clone());
887
888 let fde2 = FrameDescriptionEntry::new(Address::Constant(0x2000), 0x20);
889 frames.add_fde(cie1_id, fde2.clone());
890
891 let mut fde3 = FrameDescriptionEntry::new(Address::Constant(0x3000), 0x30);
892 fde3.lsda = Some(Address::Constant(0x3300));
893 frames.add_fde(cie2_id, fde3.clone());
894
895 let mut fde4 = FrameDescriptionEntry::new(Address::Constant(0x4000), 0x40);
896 fde4.lsda = Some(Address::Constant(0x4400));
897 frames.add_fde(cie2_id, fde4.clone());
898
899 let mut cie3 = CommonInformationEntry::new(encoding, 1, 8, X86_64::RA);
900 cie3.fde_address_encoding = constants::DW_EH_PE_pcrel;
901 cie3.lsda_encoding = Some(constants::DW_EH_PE_pcrel);
902 cie3.personality = Some((constants::DW_EH_PE_pcrel, Address::Constant(0x1235)));
903 cie3.signal_trampoline = true;
904 let cie3_id = frames.add_cie(cie3.clone());
905 assert_ne!(cie2_id, cie3_id);
906 assert_eq!(cie3_id, frames.add_cie(cie3.clone()));
907
908 let mut fde5 = FrameDescriptionEntry::new(Address::Constant(0x5000), 0x50);
909 fde5.lsda = Some(Address::Constant(0x5500));
910 frames.add_fde(cie3_id, fde5.clone());
911
912 // Test writing `.debug_frame`.
913 let mut debug_frame = DebugFrame::from(EndianVec::new(LittleEndian));
914 frames.write_debug_frame(&mut debug_frame).unwrap();
915
916 let mut read_debug_frame =
917 read::DebugFrame::new(debug_frame.slice(), LittleEndian);
918 read_debug_frame.set_address_size(address_size);
919 let convert_frames = FrameTable::from(&read_debug_frame, &|address| {
920 Some(Address::Constant(address))
921 })
922 .unwrap();
923 assert_eq!(frames.cies, convert_frames.cies);
924 assert_eq!(frames.fdes.len(), convert_frames.fdes.len());
925 for (a, b) in frames.fdes.iter().zip(convert_frames.fdes.iter()) {
926 assert_eq!(a.1, b.1);
927 }
928
929 if version == 1 {
930 // Test writing `.eh_frame`.
931 let mut eh_frame = EhFrame::from(EndianVec::new(LittleEndian));
932 frames.write_eh_frame(&mut eh_frame).unwrap();
933
934 let mut read_eh_frame = read::EhFrame::new(eh_frame.slice(), LittleEndian);
935 read_eh_frame.set_address_size(address_size);
936 let convert_frames = FrameTable::from(&read_eh_frame, &|address| {
937 Some(Address::Constant(address))
938 })
939 .unwrap();
940 assert_eq!(frames.cies, convert_frames.cies);
941 assert_eq!(frames.fdes.len(), convert_frames.fdes.len());
942 for (a, b) in frames.fdes.iter().zip(convert_frames.fdes.iter()) {
943 assert_eq!(a.1, b.1);
944 }
945 }
946 }
947 }
948 }
949 }
950
951 #[test]
952 fn test_frame_instruction() {
953 let mut expression = Expression::new();
954 expression.op_constu(0);
955
956 let cie_instructions = [
957 CallFrameInstruction::Cfa(X86_64::RSP, 8),
958 CallFrameInstruction::Offset(X86_64::RA, -8),
959 ];
960
961 let fde_instructions = [
962 (0, CallFrameInstruction::Cfa(X86_64::RSP, 0)),
963 (0, CallFrameInstruction::Cfa(X86_64::RSP, -8)),
964 (2, CallFrameInstruction::CfaRegister(X86_64::RBP)),
965 (4, CallFrameInstruction::CfaOffset(8)),
966 (4, CallFrameInstruction::CfaOffset(0)),
967 (4, CallFrameInstruction::CfaOffset(-8)),
968 (6, CallFrameInstruction::CfaExpression(expression.clone())),
969 (8, CallFrameInstruction::Restore(Register(1))),
970 (8, CallFrameInstruction::Restore(Register(101))),
971 (10, CallFrameInstruction::Undefined(Register(2))),
972 (12, CallFrameInstruction::SameValue(Register(3))),
973 (14, CallFrameInstruction::Offset(Register(4), 16)),
974 (14, CallFrameInstruction::Offset(Register(104), 16)),
975 (16, CallFrameInstruction::ValOffset(Register(5), -24)),
976 (16, CallFrameInstruction::ValOffset(Register(5), 24)),
977 (18, CallFrameInstruction::Register(Register(6), Register(7))),
978 (
979 20,
980 CallFrameInstruction::Expression(Register(8), expression.clone()),
981 ),
982 (
983 22,
984 CallFrameInstruction::ValExpression(Register(9), expression.clone()),
985 ),
986 (24 + 0x80, CallFrameInstruction::RememberState),
987 (26 + 0x280, CallFrameInstruction::RestoreState),
988 (28 + 0x20280, CallFrameInstruction::ArgsSize(23)),
989 ];
990
991 let fde_instructions_aarch64 = [(0, CallFrameInstruction::NegateRaState)];
992
993 for &version in &[1, 3, 4] {
994 for &address_size in &[4, 8] {
995 for &vendor in &[Vendor::Default, Vendor::AArch64] {
996 for &format in &[Format::Dwarf32, Format::Dwarf64] {
997 let encoding = Encoding {
998 format,
999 version,
1000 address_size,
1001 };
1002 let mut frames = FrameTable::default();
1003
1004 let mut cie = CommonInformationEntry::new(encoding, 2, 8, X86_64::RA);
1005 for i in &cie_instructions {
1006 cie.add_instruction(i.clone());
1007 }
1008 let cie_id = frames.add_cie(cie);
1009
1010 let mut fde = FrameDescriptionEntry::new(Address::Constant(0x1000), 0x10);
1011 for (o, i) in &fde_instructions {
1012 fde.add_instruction(*o, i.clone());
1013 }
1014 frames.add_fde(cie_id, fde);
1015
1016 if vendor == Vendor::AArch64 {
1017 let mut fde =
1018 FrameDescriptionEntry::new(Address::Constant(0x2000), 0x10);
1019 for (o, i) in &fde_instructions_aarch64 {
1020 fde.add_instruction(*o, i.clone());
1021 }
1022 frames.add_fde(cie_id, fde);
1023 }
1024
1025 let mut debug_frame = DebugFrame::from(EndianVec::new(LittleEndian));
1026 frames.write_debug_frame(&mut debug_frame).unwrap();
1027
1028 let mut read_debug_frame =
1029 read::DebugFrame::new(debug_frame.slice(), LittleEndian);
1030 read_debug_frame.set_address_size(address_size);
1031 read_debug_frame.set_vendor(vendor);
1032 let frames = FrameTable::from(&read_debug_frame, &|address| {
1033 Some(Address::Constant(address))
1034 })
1035 .unwrap();
1036
1037 assert_eq!(
1038 &frames.cies.get_index(0).unwrap().instructions,
1039 &cie_instructions
1040 );
1041 assert_eq!(&frames.fdes[0].1.instructions, &fde_instructions);
1042 if vendor == Vendor::AArch64 {
1043 assert_eq!(&frames.fdes[1].1.instructions, &fde_instructions_aarch64);
1044 }
1045 }
1046 }
1047 }
1048 }
1049 }
1050}
1051