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#[derive(Debug, Default)]
21pub struct FrameTable {
22 base_id: BaseId,
24 cies: IndexSet<CommonInformationEntry>,
26 fdes: Vec<(CieId, FrameDescriptionEntry)>,
28}
29
30impl FrameTable {
31 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 pub fn cie_count(&self) -> usize {
41 self.cies.len()
42 }
43
44 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 pub fn fde_count(&self) -> usize {
58 self.fdes.len()
59 }
60
61 pub fn write_debug_frame<W: Writer>(&self, w: &mut DebugFrame<W>) -> Result<()> {
63 self.write(&mut w.0, false)
64 }
65
66 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 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 Ok(())
90 }
91}
92
93#[derive(Debug, Clone, PartialEq, Eq, Hash)]
95pub struct CommonInformationEntry {
96 encoding: Encoding,
97
98 code_alignment_factor: u8,
103
104 data_alignment_factor: i8,
109
110 return_address_register: Register,
112
113 pub personality: Option<(constants::DwEhPe, Address)>,
115
116 pub lsda_encoding: Option<constants::DwEhPe>,
120
121 pub fde_address_encoding: constants::DwEhPe,
123
124 pub signal_trampoline: bool,
126
127 instructions: Vec<CallFrameInstruction>,
129}
130
131impl CommonInformationEntry {
132 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 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 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)?; }
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#[derive(Debug, Clone, PartialEq, Eq)]
271pub struct FrameDescriptionEntry {
272 address: Address,
274
275 length: u32,
277
278 pub lsda: Option<Address>,
280
281 instructions: Vec<(u32, CallFrameInstruction)>,
283}
284
285impl FrameDescriptionEntry {
286 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 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 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#[derive(Debug, Clone, PartialEq, Eq, Hash)]
381#[non_exhaustive]
382pub enum CallFrameInstruction {
383 Cfa(Register, i32),
385 CfaRegister(Register),
387 CfaOffset(i32),
389 CfaExpression(Expression),
391
392 Restore(Register),
394 Undefined(Register),
396 SameValue(Register),
398 Offset(Register, i32),
400 ValOffset(Register, i32),
402 Register(Register, Register),
404 Expression(Register, Expression),
406 ValExpression(Register, Expression),
408
409 RememberState,
411 RestoreState,
413 ArgsSize(u32),
415
416 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 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 w.write_u8(constants::DW_CFA_def_cfa_offset.0)?;
453 w.write_uleb128(offset as u64)?;
454 }
455 }
456 CallFrameInstruction::CfaExpression(ref expression) => {
457 w.write_u8(constants::DW_CFA_def_cfa_expression.0)?;
458 w.write_uleb128(expression.size(encoding, None)? as u64)?;
459 expression.write(w, None, encoding, None)?;
460 }
461 CallFrameInstruction::Restore(register) => {
462 if register.0 < 0x40 {
463 w.write_u8(constants::DW_CFA_restore.0 | register.0 as u8)?;
464 } else {
465 w.write_u8(constants::DW_CFA_restore_extended.0)?;
466 w.write_uleb128(register.0.into())?;
467 }
468 }
469 CallFrameInstruction::Undefined(register) => {
470 w.write_u8(constants::DW_CFA_undefined.0)?;
471 w.write_uleb128(register.0.into())?;
472 }
473 CallFrameInstruction::SameValue(register) => {
474 w.write_u8(constants::DW_CFA_same_value.0)?;
475 w.write_uleb128(register.0.into())?;
476 }
477 CallFrameInstruction::Offset(register, offset) => {
478 let offset = factored_data_offset(offset, cie.data_alignment_factor)?;
479 if offset < 0 {
480 w.write_u8(constants::DW_CFA_offset_extended_sf.0)?;
481 w.write_uleb128(register.0.into())?;
482 w.write_sleb128(offset.into())?;
483 } else if register.0 < 0x40 {
484 w.write_u8(constants::DW_CFA_offset.0 | register.0 as u8)?;
485 w.write_uleb128(offset as u64)?;
486 } else {
487 w.write_u8(constants::DW_CFA_offset_extended.0)?;
488 w.write_uleb128(register.0.into())?;
489 w.write_uleb128(offset as u64)?;
490 }
491 }
492 CallFrameInstruction::ValOffset(register, offset) => {
493 let offset = factored_data_offset(offset, cie.data_alignment_factor)?;
494 if offset < 0 {
495 w.write_u8(constants::DW_CFA_val_offset_sf.0)?;
496 w.write_uleb128(register.0.into())?;
497 w.write_sleb128(offset.into())?;
498 } else {
499 w.write_u8(constants::DW_CFA_val_offset.0)?;
500 w.write_uleb128(register.0.into())?;
501 w.write_uleb128(offset as u64)?;
502 }
503 }
504 CallFrameInstruction::Register(register1, register2) => {
505 w.write_u8(constants::DW_CFA_register.0)?;
506 w.write_uleb128(register1.0.into())?;
507 w.write_uleb128(register2.0.into())?;
508 }
509 CallFrameInstruction::Expression(register, ref expression) => {
510 w.write_u8(constants::DW_CFA_expression.0)?;
511 w.write_uleb128(register.0.into())?;
512 w.write_uleb128(expression.size(encoding, None)? as u64)?;
513 expression.write(w, None, encoding, None)?;
514 }
515 CallFrameInstruction::ValExpression(register, ref expression) => {
516 w.write_u8(constants::DW_CFA_val_expression.0)?;
517 w.write_uleb128(register.0.into())?;
518 w.write_uleb128(expression.size(encoding, None)? as u64)?;
519 expression.write(w, None, encoding, None)?;
520 }
521 CallFrameInstruction::RememberState => {
522 w.write_u8(constants::DW_CFA_remember_state.0)?;
523 }
524 CallFrameInstruction::RestoreState => {
525 w.write_u8(constants::DW_CFA_restore_state.0)?;
526 }
527 CallFrameInstruction::ArgsSize(size) => {
528 w.write_u8(constants::DW_CFA_GNU_args_size.0)?;
529 w.write_uleb128(size.into())?;
530 }
531 CallFrameInstruction::NegateRaState => {
532 w.write_u8(constants::DW_CFA_AARCH64_negate_ra_state.0)?;
533 }
534 }
535 Ok(())
536 }
537}
538
539fn write_advance_loc<W: Writer>(
540 w: &mut W,
541 code_alignment_factor: u8,
542 prev_offset: u32,
543 offset: u32,
544) -> Result<()> {
545 if offset == prev_offset {
546 return Ok(());
547 }
548 let delta = factored_code_delta(prev_offset, offset, code_alignment_factor)?;
549 if delta < 0x40 {
550 w.write_u8(constants::DW_CFA_advance_loc.0 | delta as u8)?;
551 } else if delta < 0x100 {
552 w.write_u8(constants::DW_CFA_advance_loc1.0)?;
553 w.write_u8(delta as u8)?;
554 } else if delta < 0x10000 {
555 w.write_u8(constants::DW_CFA_advance_loc2.0)?;
556 w.write_u16(delta as u16)?;
557 } else {
558 w.write_u8(constants::DW_CFA_advance_loc4.0)?;
559 w.write_u32(delta)?;
560 }
561 Ok(())
562}
563
564fn write_nop<W: Writer>(w: &mut W, len: usize, align: u8) -> Result<()> {
565 debug_assert_eq!(align & (align - 1), 0);
566 let tail_len = (!len + 1) & (align as usize - 1);
567 for _ in 0..tail_len {
568 w.write_u8(constants::DW_CFA_nop.0)?;
569 }
570 Ok(())
571}
572
573fn factored_code_delta(prev_offset: u32, offset: u32, factor: u8) -> Result<u32> {
574 if offset < prev_offset {
575 return Err(Error::InvalidFrameCodeOffset(offset));
576 }
577 let delta = offset - prev_offset;
578 let factor = u32::from(factor);
579 let factored_delta = delta / factor;
580 if delta != factored_delta * factor {
581 return Err(Error::InvalidFrameCodeOffset(offset));
582 }
583 Ok(factored_delta)
584}
585
586fn factored_data_offset(offset: i32, factor: i8) -> Result<i32> {
587 let factor = i32::from(factor);
588 let factored_offset = offset / factor;
589 if offset != factored_offset * factor {
590 return Err(Error::InvalidFrameDataOffset(offset));
591 }
592 Ok(factored_offset)
593}
594
595#[cfg(feature = "read")]
596pub(crate) mod convert {
597 use super::*;
598 use crate::read::{self, Reader};
599 use crate::write::{ConvertError, ConvertResult};
600 use std::collections::{hash_map, HashMap};
601
602 impl FrameTable {
603 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 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 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 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 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 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 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}