1use super::dwarf_expr::{self, read_sleb128, read_uleb128};
7use super::registers::RegisterContext;
8use super::{MemoryReader, SectionRef, UnwindError};
9
10#[derive(Debug, Clone)]
16pub struct CieAugmentation {
17 pub fde_pointer_encoding: u8,
19 pub lsda_encoding: Option<u8>,
21 pub personality_encoding: Option<u8>,
23 pub is_signal_frame: bool,
25}
26
27impl Default for CieAugmentation {
28 fn default() -> Self {
29 Self {
30 fde_pointer_encoding: DW_EH_PE_ABSPTR,
31 lsda_encoding: None,
32 personality_encoding: None,
33 is_signal_frame: false,
34 }
35 }
36}
37
38#[derive(Debug, Clone)]
44pub struct Cie {
45 pub code_alignment_factor: u64,
46 pub data_alignment_factor: i64,
47 pub return_address_register: u16,
48 pub augmentation: CieAugmentation,
49 pub initial_instructions: Vec<u8>,
50}
51
52#[derive(Debug, Clone)]
54pub struct Fde {
55 pub cie: Cie,
56 pub pc_begin: u64,
57 pub pc_range: u64,
58 pub instructions: Vec<u8>,
59}
60
61#[derive(Debug, Clone)]
67pub enum CfaRule {
68 RegisterOffset { register: u16, offset: i64 },
69 Expression(Vec<u8>),
70}
71
72#[derive(Debug, Clone)]
74pub enum RegisterRule {
75 Undefined,
76 SameValue,
77 Offset(i64),
78 ValOffset(i64),
79 Register(u16),
80 Expression(Vec<u8>),
81 ValExpression(Vec<u8>),
82}
83
84#[derive(Debug, Clone)]
86struct UnwindRow {
87 cfa: CfaRule,
88 rules: Vec<(u16, RegisterRule)>,
89}
90
91pub const DW_EH_PE_ABSPTR: u8 = 0x00;
96pub const DW_EH_PE_ULEB128: u8 = 0x01;
97pub const DW_EH_PE_UDATA2: u8 = 0x02;
98pub const DW_EH_PE_UDATA4: u8 = 0x03;
99pub const DW_EH_PE_UDATA8: u8 = 0x04;
100pub const DW_EH_PE_SLEB128: u8 = 0x09;
101pub const DW_EH_PE_SDATA2: u8 = 0x0A;
102pub const DW_EH_PE_SDATA4: u8 = 0x0B;
103pub const DW_EH_PE_SDATA8: u8 = 0x0C;
104
105pub const DW_EH_PE_PCREL: u8 = 0x10;
107pub const DW_EH_PE_DATAREL: u8 = 0x30;
108pub const DW_EH_PE_INDIRECT: u8 = 0x80;
109pub const DW_EH_PE_OMIT: u8 = 0xFF;
110
111mod cfa_op {
116 pub const ADVANCE_LOC: u8 = 0x40; pub const OFFSET: u8 = 0x80; pub const RESTORE: u8 = 0xC0; pub const NOP: u8 = 0x00;
121 pub const SET_LOC: u8 = 0x01;
122 pub const ADVANCE_LOC1: u8 = 0x02;
123 pub const ADVANCE_LOC2: u8 = 0x03;
124 pub const ADVANCE_LOC4: u8 = 0x04;
125 pub const OFFSET_EXTENDED: u8 = 0x05;
126 pub const RESTORE_EXTENDED: u8 = 0x06;
127 pub const UNDEFINED: u8 = 0x07;
128 pub const SAME_VALUE: u8 = 0x08;
129 pub const REGISTER: u8 = 0x09;
130 pub const REMEMBER_STATE: u8 = 0x0A;
131 pub const RESTORE_STATE: u8 = 0x0B;
132 pub const DEF_CFA: u8 = 0x0C;
133 pub const DEF_CFA_REGISTER: u8 = 0x0D;
134 pub const DEF_CFA_OFFSET: u8 = 0x0E;
135 pub const DEF_CFA_EXPRESSION: u8 = 0x0F;
136 pub const EXPRESSION: u8 = 0x10;
137 pub const OFFSET_EXTENDED_SF: u8 = 0x11;
138 pub const DEF_CFA_SF: u8 = 0x12;
139 pub const DEF_CFA_OFFSET_SF: u8 = 0x13;
140 pub const VAL_OFFSET: u8 = 0x14;
141 pub const VAL_OFFSET_SF: u8 = 0x15;
142 pub const VAL_EXPRESSION: u8 = 0x16;
143 pub const GNU_ARGS_SIZE: u8 = 0x2E;
144}
145
146pub fn find_fde(
152 reader: &dyn MemoryReader,
153 eh_frame: &SectionRef,
154 target_pc: u64,
155 is_64_bit: bool,
156) -> Option<Fde> {
157 let mut offset = 0u64;
158
159 while offset < eh_frame.size {
160 let entry_addr = eh_frame.vm_addr + offset;
161
162 let length32 = reader.read_u32(entry_addr)?;
164 if length32 == 0 {
165 break; }
167
168 let (length, header_size) = if length32 == 0xFFFF_FFFF {
169 let length64 = reader.read_u64(entry_addr + 4)?;
171 (length64, 12u64)
172 } else {
173 (length32 as u64, 4u64)
174 };
175
176 let entry_data_start = entry_addr + header_size;
177 let entry_end = entry_data_start + length;
178
179 let cie_offset_field = reader.read_u32(entry_data_start)?;
181
182 if cie_offset_field == 0 {
183 offset = entry_end - eh_frame.vm_addr;
185 continue;
186 }
187
188 let cie_addr = entry_data_start - cie_offset_field as u64;
190 let cie = parse_cie(reader, cie_addr, is_64_bit)?;
191
192 let fde_data_start = entry_data_start + 4;
194 let pc_begin = read_encoded_pointer(
195 reader,
196 fde_data_start,
197 cie.augmentation.fde_pointer_encoding,
198 fde_data_start,
199 is_64_bit,
200 )?;
201
202 let ptr_size = encoded_pointer_size(cie.augmentation.fde_pointer_encoding, is_64_bit);
203 let pc_range_addr = fde_data_start + ptr_size as u64;
204 let range_encoding = cie.augmentation.fde_pointer_encoding & 0x0F;
206 let pc_range = read_encoded_pointer(
207 reader,
208 pc_range_addr,
209 range_encoding,
210 pc_range_addr,
211 is_64_bit,
212 )?;
213
214 if target_pc >= pc_begin && target_pc < pc_begin + pc_range {
215 let mut instr_start = pc_range_addr + ptr_size as u64;
217
218 if cie.augmentation.lsda_encoding.is_some()
220 || cie.augmentation.personality_encoding.is_some()
221 {
222 let aug_data = reader.read_memory(instr_start, 16)?;
224 let mut aug_pos = 0;
225 let aug_len = read_uleb128(&aug_data, &mut aug_pos).ok()?;
226 instr_start += aug_pos as u64 + aug_len;
227 }
228
229 let instr_len = (entry_end - instr_start) as usize;
230 let instructions = reader.read_memory(instr_start, instr_len)?;
231
232 return Some(Fde {
233 cie,
234 pc_begin,
235 pc_range,
236 instructions,
237 });
238 }
239
240 offset = entry_end - eh_frame.vm_addr;
241 }
242
243 None
244}
245
246fn parse_cie(reader: &dyn MemoryReader, addr: u64, is_64_bit: bool) -> Option<Cie> {
248 let length32 = reader.read_u32(addr)?;
249 let (length, header_size) = if length32 == 0xFFFF_FFFF {
250 (reader.read_u64(addr + 4)?, 12u64)
251 } else {
252 (length32 as u64, 4u64)
253 };
254
255 let data_start = addr + header_size;
256 let entry_end = data_start + length;
257
258 let cie_id = reader.read_u32(data_start)?;
260 if cie_id != 0 {
261 return None; }
263
264 let mut pos = data_start + 4;
265
266 let _version = reader.read_u8(pos)?;
268 pos += 1;
269
270 let mut aug_string = Vec::new();
272 loop {
273 let b = reader.read_u8(pos)?;
274 pos += 1;
275 if b == 0 {
276 break;
277 }
278 aug_string.push(b);
279 }
280
281 let remaining = (entry_end - pos) as usize;
283 let data = reader.read_memory(pos, remaining)?;
284 let mut dpos = 0;
285
286 let code_alignment_factor = read_uleb128(&data, &mut dpos).ok()?;
287 let data_alignment_factor = read_sleb128(&data, &mut dpos).ok()?;
288 let return_address_register = read_uleb128(&data, &mut dpos).ok()? as u16;
289
290 let mut augmentation = CieAugmentation::default();
292 let aug_str = String::from_utf8_lossy(&aug_string);
293
294 if aug_str.starts_with('z') {
295 let aug_data_len = read_uleb128(&data, &mut dpos).ok()? as usize;
296 let aug_data_start = dpos;
297
298 for ch in aug_str.chars().skip(1) {
299 match ch {
300 'R' if dpos < data.len() => {
301 augmentation.fde_pointer_encoding = data[dpos];
302 dpos += 1;
303 }
304 'L' if dpos < data.len() => {
305 augmentation.lsda_encoding = Some(data[dpos]);
306 dpos += 1;
307 }
308 'P' if dpos < data.len() => {
309 let enc = data[dpos];
310 dpos += 1;
311 augmentation.personality_encoding = Some(enc);
312 let psize = encoded_pointer_size(enc, is_64_bit);
314 dpos += psize;
315 }
316 'S' => {
317 augmentation.is_signal_frame = true;
318 }
319 _ => {}
320 }
321 }
322
323 dpos = aug_data_start + aug_data_len;
325 }
326
327 let initial_instructions = data[dpos..].to_vec();
328
329 Some(Cie {
330 code_alignment_factor,
331 data_alignment_factor,
332 return_address_register,
333 augmentation,
334 initial_instructions,
335 })
336}
337
338pub fn apply_dwarf_unwind(
345 fde: &Fde,
346 target_pc: u64,
347 regs: &RegisterContext,
348 reader: &dyn MemoryReader,
349 is_64_bit: bool,
350) -> Result<RegisterContext, UnwindError> {
351 let row = evaluate_cfa_program(fde, target_pc)?;
353
354 let cfa = compute_cfa(&row.cfa, regs, reader, is_64_bit)?;
356
357 let mut new_regs = regs.clone();
359 new_regs.clear_volatile();
360
361 for (reg, rule) in &row.rules {
362 let val = match rule {
363 RegisterRule::Undefined => continue,
364 RegisterRule::SameValue => regs.get(*reg),
365 RegisterRule::Offset(offset) => {
366 let addr = (cfa as i64 + offset) as u64;
367 reader.read_pointer(addr, is_64_bit)
368 }
369 RegisterRule::ValOffset(offset) => Some((cfa as i64 + offset) as u64),
370 RegisterRule::Register(src) => regs.get(*src),
371 RegisterRule::Expression(expr) => {
372 let addr = dwarf_expr::evaluate(expr, regs, reader, is_64_bit)?;
373 reader.read_pointer(addr, is_64_bit)
374 }
375 RegisterRule::ValExpression(expr) => {
376 Some(dwarf_expr::evaluate(expr, regs, reader, is_64_bit)?)
377 }
378 };
379
380 if let Some(v) = val {
381 new_regs.set(*reg, v);
382 }
383 }
384
385 new_regs.set_sp(cfa);
387
388 let ra_reg = fde.cie.return_address_register;
390 if let Some(ra_val) = new_regs.get(ra_reg) {
391 new_regs.set_pc(ra_val);
392 }
393
394 Ok(new_regs)
395}
396
397fn compute_cfa(
398 rule: &CfaRule,
399 regs: &RegisterContext,
400 reader: &dyn MemoryReader,
401 is_64_bit: bool,
402) -> Result<u64, UnwindError> {
403 match rule {
404 CfaRule::RegisterOffset { register, offset } => {
405 let reg_val = regs.get(*register).ok_or_else(|| {
406 UnwindError::InvalidDwarf(format!("CFA reg {} not set", register))
407 })?;
408 Ok((reg_val as i64 + offset) as u64)
409 }
410 CfaRule::Expression(expr) => dwarf_expr::evaluate(expr, regs, reader, is_64_bit),
411 }
412}
413
414fn evaluate_cfa_program(fde: &Fde, target_pc: u64) -> Result<UnwindRow, UnwindError> {
415 let cie = &fde.cie;
416 let caf = cie.code_alignment_factor;
417 let daf = cie.data_alignment_factor;
418
419 let mut row = UnwindRow {
420 cfa: CfaRule::RegisterOffset {
421 register: 0,
422 offset: 0,
423 },
424 rules: Vec::new(),
425 };
426
427 let mut state_stack: Vec<UnwindRow> = Vec::new();
428 let mut current_pc = fde.pc_begin;
429
430 execute_instructions(
432 &cie.initial_instructions,
433 &mut row,
434 &mut state_stack,
435 &mut current_pc,
436 target_pc,
437 caf,
438 daf,
439 false, )?;
441
442 current_pc = fde.pc_begin;
444 execute_instructions(
445 &fde.instructions,
446 &mut row,
447 &mut state_stack,
448 &mut current_pc,
449 target_pc,
450 caf,
451 daf,
452 true, )?;
454
455 Ok(row)
456}
457
458#[allow(clippy::too_many_arguments)]
459fn execute_instructions(
460 instructions: &[u8],
461 row: &mut UnwindRow,
462 state_stack: &mut Vec<UnwindRow>,
463 current_pc: &mut u64,
464 target_pc: u64,
465 caf: u64,
466 daf: i64,
467 check_pc: bool,
468) -> Result<(), UnwindError> {
469 let mut pos = 0;
470
471 while pos < instructions.len() {
472 let opcode = instructions[pos];
473 pos += 1;
474
475 let high2 = opcode & 0xC0;
476 let low6 = opcode & 0x3F;
477
478 match high2 {
479 cfa_op::ADVANCE_LOC if high2 != 0 => {
480 let delta = low6 as u64 * caf;
481 *current_pc += delta;
482 if check_pc && *current_pc > target_pc {
483 return Ok(());
484 }
485 }
486 cfa_op::OFFSET if high2 == 0x80 => {
487 let reg = low6 as u16;
488 let offset = read_uleb128(instructions, &mut pos)? as i64 * daf;
489 set_rule(&mut row.rules, reg, RegisterRule::Offset(offset));
490 }
491 cfa_op::RESTORE if high2 == 0xC0 => {
492 let reg = low6 as u16;
493 set_rule(&mut row.rules, reg, RegisterRule::SameValue);
496 }
497 _ => {
498 match opcode {
500 cfa_op::NOP => {}
501 cfa_op::SET_LOC => {
502 *current_pc = read_u64_from_slice(instructions, &mut pos)?;
504 if check_pc && *current_pc > target_pc {
505 return Ok(());
506 }
507 }
508 cfa_op::ADVANCE_LOC1 => {
509 if pos >= instructions.len() {
510 return Err(UnwindError::InvalidDwarf("advance_loc1 past end".into()));
511 }
512 let delta = instructions[pos] as u64 * caf;
513 pos += 1;
514 *current_pc += delta;
515 if check_pc && *current_pc > target_pc {
516 return Ok(());
517 }
518 }
519 cfa_op::ADVANCE_LOC2 => {
520 if pos + 2 > instructions.len() {
521 return Err(UnwindError::InvalidDwarf("advance_loc2 past end".into()));
522 }
523 let delta = u16::from_le_bytes([instructions[pos], instructions[pos + 1]])
524 as u64
525 * caf;
526 pos += 2;
527 *current_pc += delta;
528 if check_pc && *current_pc > target_pc {
529 return Ok(());
530 }
531 }
532 cfa_op::ADVANCE_LOC4 => {
533 if pos + 4 > instructions.len() {
534 return Err(UnwindError::InvalidDwarf("advance_loc4 past end".into()));
535 }
536 let delta = u32::from_le_bytes([
537 instructions[pos],
538 instructions[pos + 1],
539 instructions[pos + 2],
540 instructions[pos + 3],
541 ]) as u64
542 * caf;
543 pos += 4;
544 *current_pc += delta;
545 if check_pc && *current_pc > target_pc {
546 return Ok(());
547 }
548 }
549 cfa_op::DEF_CFA => {
550 let reg = read_uleb128(instructions, &mut pos)? as u16;
551 let offset = read_uleb128(instructions, &mut pos)? as i64;
552 row.cfa = CfaRule::RegisterOffset {
553 register: reg,
554 offset,
555 };
556 }
557 cfa_op::DEF_CFA_SF => {
558 let reg = read_uleb128(instructions, &mut pos)? as u16;
559 let offset = read_sleb128(instructions, &mut pos)? * daf;
560 row.cfa = CfaRule::RegisterOffset {
561 register: reg,
562 offset,
563 };
564 }
565 cfa_op::DEF_CFA_REGISTER => {
566 let reg = read_uleb128(instructions, &mut pos)? as u16;
567 if let CfaRule::RegisterOffset { offset, .. } = row.cfa {
568 row.cfa = CfaRule::RegisterOffset {
569 register: reg,
570 offset,
571 };
572 }
573 }
574 cfa_op::DEF_CFA_OFFSET => {
575 let offset = read_uleb128(instructions, &mut pos)? as i64;
576 if let CfaRule::RegisterOffset { register, .. } = row.cfa {
577 row.cfa = CfaRule::RegisterOffset { register, offset };
578 }
579 }
580 cfa_op::DEF_CFA_OFFSET_SF => {
581 let offset = read_sleb128(instructions, &mut pos)? * daf;
582 if let CfaRule::RegisterOffset { register, .. } = row.cfa {
583 row.cfa = CfaRule::RegisterOffset { register, offset };
584 }
585 }
586 cfa_op::DEF_CFA_EXPRESSION => {
587 let len = read_uleb128(instructions, &mut pos)? as usize;
588 let expr = instructions[pos..pos + len].to_vec();
589 pos += len;
590 row.cfa = CfaRule::Expression(expr);
591 }
592 cfa_op::OFFSET_EXTENDED => {
593 let reg = read_uleb128(instructions, &mut pos)? as u16;
594 let offset = read_uleb128(instructions, &mut pos)? as i64 * daf;
595 set_rule(&mut row.rules, reg, RegisterRule::Offset(offset));
596 }
597 cfa_op::OFFSET_EXTENDED_SF => {
598 let reg = read_uleb128(instructions, &mut pos)? as u16;
599 let offset = read_sleb128(instructions, &mut pos)? * daf;
600 set_rule(&mut row.rules, reg, RegisterRule::Offset(offset));
601 }
602 cfa_op::VAL_OFFSET => {
603 let reg = read_uleb128(instructions, &mut pos)? as u16;
604 let offset = read_uleb128(instructions, &mut pos)? as i64 * daf;
605 set_rule(&mut row.rules, reg, RegisterRule::ValOffset(offset));
606 }
607 cfa_op::VAL_OFFSET_SF => {
608 let reg = read_uleb128(instructions, &mut pos)? as u16;
609 let offset = read_sleb128(instructions, &mut pos)? * daf;
610 set_rule(&mut row.rules, reg, RegisterRule::ValOffset(offset));
611 }
612 cfa_op::REGISTER => {
613 let reg = read_uleb128(instructions, &mut pos)? as u16;
614 let src = read_uleb128(instructions, &mut pos)? as u16;
615 set_rule(&mut row.rules, reg, RegisterRule::Register(src));
616 }
617 cfa_op::EXPRESSION => {
618 let reg = read_uleb128(instructions, &mut pos)? as u16;
619 let len = read_uleb128(instructions, &mut pos)? as usize;
620 let expr = instructions[pos..pos + len].to_vec();
621 pos += len;
622 set_rule(&mut row.rules, reg, RegisterRule::Expression(expr));
623 }
624 cfa_op::VAL_EXPRESSION => {
625 let reg = read_uleb128(instructions, &mut pos)? as u16;
626 let len = read_uleb128(instructions, &mut pos)? as usize;
627 let expr = instructions[pos..pos + len].to_vec();
628 pos += len;
629 set_rule(&mut row.rules, reg, RegisterRule::ValExpression(expr));
630 }
631 cfa_op::UNDEFINED => {
632 let reg = read_uleb128(instructions, &mut pos)? as u16;
633 set_rule(&mut row.rules, reg, RegisterRule::Undefined);
634 }
635 cfa_op::SAME_VALUE => {
636 let reg = read_uleb128(instructions, &mut pos)? as u16;
637 set_rule(&mut row.rules, reg, RegisterRule::SameValue);
638 }
639 cfa_op::RESTORE_EXTENDED => {
640 let reg = read_uleb128(instructions, &mut pos)? as u16;
641 set_rule(&mut row.rules, reg, RegisterRule::SameValue);
642 }
643 cfa_op::REMEMBER_STATE => {
644 state_stack.push(row.clone());
645 }
646 cfa_op::RESTORE_STATE => {
647 if let Some(saved) = state_stack.pop() {
648 *row = saved;
649 }
650 }
651 cfa_op::GNU_ARGS_SIZE => {
652 let _ = read_uleb128(instructions, &mut pos)?;
654 }
655 _ => {
656 break;
658 }
659 }
660 }
661 }
662 }
663
664 Ok(())
665}
666
667fn set_rule(rules: &mut Vec<(u16, RegisterRule)>, reg: u16, rule: RegisterRule) {
668 for (r, existing) in rules.iter_mut() {
669 if *r == reg {
670 *existing = rule;
671 return;
672 }
673 }
674 rules.push((reg, rule));
675}
676
677fn read_u64_from_slice(data: &[u8], pos: &mut usize) -> Result<u64, UnwindError> {
678 if *pos + 8 > data.len() {
679 return Err(UnwindError::InvalidDwarf("read_u64 past end".into()));
680 }
681 let val = u64::from_le_bytes([
682 data[*pos],
683 data[*pos + 1],
684 data[*pos + 2],
685 data[*pos + 3],
686 data[*pos + 4],
687 data[*pos + 5],
688 data[*pos + 6],
689 data[*pos + 7],
690 ]);
691 *pos += 8;
692 Ok(val)
693}
694
695fn read_encoded_pointer(
700 reader: &dyn MemoryReader,
701 addr: u64,
702 encoding: u8,
703 pc_rel_base: u64,
704 is_64_bit: bool,
705) -> Option<u64> {
706 if encoding == DW_EH_PE_OMIT {
707 return None;
708 }
709
710 let format = encoding & 0x0F;
711 let application = encoding & 0x70;
712
713 let raw = match format {
714 DW_EH_PE_ABSPTR => {
715 if is_64_bit {
716 reader.read_u64(addr)?
717 } else {
718 reader.read_u32(addr)? as u64
719 }
720 }
721 DW_EH_PE_ULEB128 => {
722 let data = reader.read_memory(addr, 10)?;
723 let mut pos = 0;
724 read_uleb128(&data, &mut pos).ok()?
725 }
726 DW_EH_PE_UDATA2 => reader.read_u16(addr)? as u64,
727 DW_EH_PE_UDATA4 => reader.read_u32(addr)? as u64,
728 DW_EH_PE_UDATA8 => reader.read_u64(addr)?,
729 DW_EH_PE_SLEB128 => {
730 let data = reader.read_memory(addr, 10)?;
731 let mut pos = 0;
732 read_sleb128(&data, &mut pos).ok()? as u64
733 }
734 DW_EH_PE_SDATA2 => reader.read_u16(addr)? as i16 as i64 as u64,
735 DW_EH_PE_SDATA4 => reader.read_u32(addr)? as i32 as i64 as u64,
736 DW_EH_PE_SDATA8 => reader.read_u64(addr)?,
737 _ => return None,
738 };
739
740 let adjusted = match application {
741 0 => raw,
742 DW_EH_PE_PCREL => pc_rel_base.wrapping_add(raw),
743 DW_EH_PE_DATAREL => raw, _ => raw,
745 };
746
747 if encoding & DW_EH_PE_INDIRECT != 0 {
748 reader.read_pointer(adjusted, is_64_bit)
749 } else {
750 Some(adjusted)
751 }
752}
753
754fn encoded_pointer_size(encoding: u8, is_64_bit: bool) -> usize {
755 match encoding & 0x0F {
756 DW_EH_PE_ABSPTR => {
757 if is_64_bit {
758 8
759 } else {
760 4
761 }
762 }
763 DW_EH_PE_UDATA2 | DW_EH_PE_SDATA2 => 2,
764 DW_EH_PE_UDATA4 | DW_EH_PE_SDATA4 => 4,
765 DW_EH_PE_UDATA8 | DW_EH_PE_SDATA8 => 8,
766 _ => {
767 if is_64_bit {
768 8
769 } else {
770 4
771 }
772 }
773 }
774}
775
776#[cfg(test)]
777mod tests {
778 use super::*;
779 use crate::types::CpuType;
780 use crate::unwind::SliceMemoryReader;
781
782 #[test]
783 fn evaluate_simple_cfa_program() {
784 let cie = Cie {
785 code_alignment_factor: 1,
786 data_alignment_factor: -8,
787 return_address_register: 30, augmentation: CieAugmentation::default(),
789 initial_instructions: vec![cfa_op::DEF_CFA, 31, 0],
791 };
792
793 let fde = Fde {
794 cie,
795 pc_begin: 0x1000,
796 pc_range: 0x100,
797 instructions: vec![
801 cfa_op::DEF_CFA_OFFSET,
802 16,
803 0x80 | 29,
804 2, 0x80 | 30,
806 1, ],
808 };
809
810 let mut regs = RegisterContext::new(CpuType::ARM64);
812 regs.set(31, 0x8000); regs.set(29, 0x7FF0); let mut data = vec![0u8; 0x1000];
818 data[0xFF0..0xFF8].copy_from_slice(&0xAAAA_BBBBu64.to_le_bytes());
820 data[0xFF8..0x1000].copy_from_slice(&0xDEAD_0042u64.to_le_bytes());
822
823 let reader = SliceMemoryReader {
824 data,
825 base_address: 0x7000,
826 };
827
828 let new_regs = apply_dwarf_unwind(&fde, 0x1050, ®s, &reader, true).unwrap();
829
830 assert_eq!(new_regs.sp(), Some(0x8010));
834
835 }
844
845 #[test]
846 fn remember_restore_state() {
847 let cie = Cie {
848 code_alignment_factor: 1,
849 data_alignment_factor: -8,
850 return_address_register: 30,
851 augmentation: CieAugmentation::default(),
852 initial_instructions: vec![cfa_op::DEF_CFA, 31, 16],
853 };
854
855 let fde = Fde {
856 cie,
857 pc_begin: 0x1000,
858 pc_range: 0x100,
859 instructions: vec![
860 0x80 | 29,
861 2, cfa_op::REMEMBER_STATE,
863 cfa_op::ADVANCE_LOC1,
864 0x10, cfa_op::DEF_CFA_OFFSET,
866 32, cfa_op::ADVANCE_LOC1,
868 0x10, cfa_op::RESTORE_STATE,
870 ],
871 };
872
873 let row = evaluate_cfa_program(&fde, 0x1030).unwrap();
875 match row.cfa {
876 CfaRule::RegisterOffset { offset, .. } => assert_eq!(offset, 16),
877 _ => panic!("expected RegisterOffset"),
878 }
879 }
880
881 #[test]
882 fn encoded_pointer_sizes() {
883 assert_eq!(encoded_pointer_size(DW_EH_PE_ABSPTR, true), 8);
884 assert_eq!(encoded_pointer_size(DW_EH_PE_ABSPTR, false), 4);
885 assert_eq!(encoded_pointer_size(DW_EH_PE_UDATA4, true), 4);
886 assert_eq!(encoded_pointer_size(DW_EH_PE_SDATA8, true), 8);
887 assert_eq!(encoded_pointer_size(DW_EH_PE_UDATA2, true), 2);
888 }
889}