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