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