1use crate::evaluate::evaluate;
9use crate::evaluate::evaluate::BaseTypeValue;
10use crate::evaluate::evaluate::EvaluatorValue;
11use crate::evaluate::evaluate::ValueInformation;
12use crate::registers::Registers;
13use crate::source_information::SourceInformation;
14use crate::utils::{die_in_range, get_current_unit, DwarfOffset};
15use crate::variable::{is_variable_die, Variable};
16use anyhow::{anyhow, Result};
17use gimli::AttributeValue::DebugInfoRef;
18use gimli::AttributeValue::UnitRef;
19use gimli::DebugFrame;
20use gimli::{RegisterRule::*, UnwindSection};
21use log::{error, trace};
22use std::convert::TryInto;
23
24use gimli::{
25 AttributeValue::DebugStrRef, DebuggingInformationEntry, Dwarf, EntriesTreeNode, Reader, Unit,
26 UnitOffset, UnitSectionOffset,
27};
28
29pub trait MemoryAccess {
31 fn get_address(&mut self, address: &u32, num_bytes: usize) -> Option<Vec<u8>>;
43}
44
45pub fn stack_trace<'a, R: Reader<Offset = usize>, M: MemoryAccess>(
59 dwarf: &Dwarf<R>,
60 debug_frame: &'a DebugFrame<R>,
61 registers: Registers,
62 memory: &mut M,
63 cwd: &str,
64) -> Result<Vec<StackFrame<R>>> {
65 let call_stacktrace = unwind_call_stack(registers.clone(), memory, debug_frame)?;
76
77 let mut stack_trace = vec![];
78 for call_frame in call_stacktrace {
79 let stack_frame = create_stack_frame(dwarf, call_frame, ®isters, memory, cwd)?;
80
81 stack_trace.push(stack_frame);
82 }
83 Ok(stack_trace)
84 }
86
87pub fn new_stack_trace<'a, R: Reader<Offset = usize>, M: MemoryAccess>(
88 dwarf: &Dwarf<R>,
89 debug_frame: &'a DebugFrame<R>,
90 registers: Registers,
91 memory: &mut M,
92 cwd: &str,
93) -> Result<Vec<StackFrame<R>>> {
94 let pc_reg = registers
95 .program_counter_register
96 .ok_or_else(|| anyhow!("Requires pc register id"))?;
97 let link_reg = registers
98 .link_register
99 .ok_or_else(|| anyhow!("Requires pc register id"))?;
100 let sp_reg = registers
101 .stack_pointer_register
102 .ok_or_else(|| anyhow!("Requires pc register id"))?;
103
104 let mut regs = [None; 16];
105 for (reg, val) in ®isters.registers {
106 regs[*reg as usize] = Some(*val);
107 }
108 let code_location = registers
109 .get_register_value(&(pc_reg as u16))
110 .map(|v| *v as u64);
111
112 new_stack_trace_rec(
113 dwarf,
114 debug_frame,
115 ®isters,
116 memory,
117 cwd,
118 pc_reg,
119 link_reg,
120 sp_reg,
121 code_location,
122 regs,
123 &mut gimli::BaseAddresses::default(),
124 &mut Box::new(gimli::UnwindContext::new()),
125 )
126}
127
128pub fn new_stack_trace_rec<'a, R: Reader<Offset = usize>, M: MemoryAccess>(
129 dwarf: &Dwarf<R>,
130 debug_frame: &'a DebugFrame<R>,
131 registers: &Registers,
132 memory: &mut M,
133 cwd: &str,
134 pc_reg: usize,
135 link_reg: usize,
136 sp_reg: usize,
137 code_location: Option<u64>,
138 mut unwind_registers: [Option<u32>; 16],
139 base: &mut gimli::BaseAddresses,
140 ctx: &mut gimli::UnwindContext<R>,
141) -> Result<Vec<StackFrame<R>>> {
142 let current_location = match code_location {
144 Some(val) => val,
145 None => {
146 trace!("Stopped unwinding call stack, because: Reached end of stack");
147 return Ok(vec![]);
148 }
149 };
150
151 let unwind_info = match debug_frame.unwind_info_for_address(
153 base,
154 ctx,
155 current_location,
156 gimli::DebugFrame::cie_from_offset,
157 ) {
158 Ok(val) => val,
159 Err(err) => {
160 trace!("Stopped unwinding call stack, because: {:?}", err);
161 return Ok(vec![]);
162 }
163 };
164
165 let cfa = unwind_cfa(unwind_registers, unwind_info)?;
167
168 let mut new_registers = [None; 16];
170 for i in 0..16_usize {
171 let reg_rule = unwind_info.register(gimli::Register(i as u16));
172
173 new_registers[i] = match reg_rule {
174 Undefined => {
175 if i == sp_reg {
178 cfa
179 } else if i == pc_reg {
180 Some(current_location as u32)
181 } else {
182 None
183 }
184 }
185 SameValue => unwind_registers[i],
186 Offset(offset) => {
187 let address = (offset
188 + match cfa {
189 Some(val) => i64::from(val),
190 None => return Err(anyhow!("Expected CFA to have a value")),
191 }) as u32;
192
193 let value = {
194 let value = match memory.get_address(&address, 4) {
195 Some(val) => {
196 let mut result = vec![];
197 for v in val {
198 result.push(v);
199 }
200
201 u32::from_le_bytes(match result.as_slice().try_into() {
202 Ok(val) => val,
203 Err(err) => {
204 error!("{:?}", err);
205 return Err(anyhow!("{:?}", err));
206 }
207 })
208 }
209 None => {
210 error!("Could not read 4 bytes from address 0x{:x}", address);
211 return Err(anyhow!(
212 "Could not read 4 bytes from address 0x{:x}",
213 address
214 ));
215 }
216 };
217 value
218 };
219
220 Some(value)
221 }
222 ValOffset(offset) => {
223 let value = (offset
224 + match cfa {
225 Some(val) => i64::from(val),
226 None => return Err(anyhow!("Expected CFA to have a value")),
227 }) as u32;
228
229 Some(value)
230 }
231 Register(reg) => unwind_registers[reg.0 as usize],
232 Expression(_expr) => {
233 error!("Unimplemented");
234 return Err(anyhow!("Unimplemented")); }
236 ValExpression(_expr) => {
237 error!("Unimplemented");
238 return Err(anyhow!("Unimplemented")); }
240 Architectural => {
241 error!("Unimplemented");
242 return Err(anyhow!("Unimplemented")); }
244 };
245 }
246
247 let call_frame = CallFrame {
248 id: current_location,
249 registers: unwind_registers,
250 code_location: current_location,
251 cfa,
252 start_address: unwind_info.start_address(),
253 end_address: unwind_info.end_address(),
254 };
255
256 unwind_registers = new_registers;
257
258 let mut stack_trace = vec![];
259
260 stack_trace.push(create_stack_frame(
261 dwarf, call_frame, registers, memory, cwd,
262 )?);
263
264 let (section_offset, unit_offset) = find_function_die(dwarf, current_location as u32)?;
266 let header =
267 dwarf
268 .debug_info
269 .header_from_offset(match section_offset.as_debug_info_offset() {
270 Some(val) => val,
271 None => {
272 return Err(anyhow!(
273 "Could not convert section offset to debug info offset"
274 ))
275 }
276 })?;
277 let unit = gimli::Unit::new(dwarf, header)?;
278 let die = unit.entry(unit_offset)?;
279 let next_code_location = match die.attr_value(gimli::DW_AT_inline)? {
280 Some(val) => {
281 error!(
282 "Unexpected inlined function with attribute value: {:?}",
283 val
284 );
285 return Err(anyhow!(
286 "Unexpected inlined function with attribute value: {:?}",
287 val
288 ));
289 }
290 None => {
291 if die.tag() == gimli::DW_TAG_inlined_subroutine {
292 match die.attr_value(gimli::DW_AT_low_pc)? {
295 Some(gimli::AttributeValue::Addr(val)) => Some(val),
296 Some(val) => {
297 error!("Unimplemented for {:?}", val);
298 return Err(anyhow!("Unimplemented for {:?}", val));
299 }
300 None => None,
301 }
302 } else {
303 unwind_registers[link_reg as usize].map(|pc| u64::from(pc & !1) - 1)
309 }
310 }
311 };
312
313 stack_trace.append(&mut new_stack_trace_rec(
314 dwarf,
315 debug_frame,
316 registers,
317 memory,
318 cwd,
319 pc_reg,
320 link_reg,
321 sp_reg,
322 next_code_location,
323 unwind_registers,
324 base,
325 ctx,
326 )?);
327 Ok(stack_trace)
328}
329
330#[derive(Debug, Clone)]
332pub struct CallFrame {
333 pub id: u64,
335
336 pub registers: [Option<u32>; 16],
338
339 pub code_location: u64,
341
342 pub cfa: Option<u32>,
344
345 pub start_address: u64,
347
348 pub end_address: u64,
350}
351
352pub fn unwind_call_stack<R: Reader<Offset = usize>, M: MemoryAccess>(
362 registers: Registers,
363 memory: &mut M,
364 debug_frame: &'_ DebugFrame<R>,
365) -> Result<Vec<CallFrame>> {
366 let pc_reg = registers
367 .program_counter_register
368 .ok_or_else(|| anyhow!("Requires pc register id"))?;
369 let link_reg = registers
370 .link_register
371 .ok_or_else(|| anyhow!("Requires pc register id"))?;
372 let sp_reg = registers
373 .stack_pointer_register
374 .ok_or_else(|| anyhow!("Requires pc register id"))?;
375
376 let mut regs = [None; 16];
377 for (reg, val) in ®isters.registers {
378 regs[*reg as usize] = Some(*val);
379 }
380 let code_location = registers
381 .get_register_value(&(pc_reg as u16))
382 .map(|v| *v as u64);
383
384 unwind_call_stack_recursive(
385 debug_frame,
386 memory,
387 pc_reg,
388 link_reg,
389 sp_reg,
390 code_location,
391 regs,
392 &mut gimli::BaseAddresses::default(),
393 &mut Box::new(gimli::UnwindContext::new()),
394 )
395}
396
397fn unwind_call_stack_recursive<'a, M: MemoryAccess, R: Reader<Offset = usize>>(
413 debug_frame: &'a DebugFrame<R>,
414 memory: &mut M,
415 pc_reg: usize,
416 link_reg: usize,
417 sp_reg: usize,
418 code_location: Option<u64>,
419 mut unwind_registers: [Option<u32>; 16],
420 base: &mut gimli::BaseAddresses,
421 ctx: &mut gimli::UnwindContext<R>,
422) -> Result<Vec<CallFrame>> {
423 let current_location = match code_location {
424 Some(val) => val,
425 None => {
426 trace!("Stopped unwinding call stack, because: Reached end of stack");
427 return Ok(vec![]);
428 }
429 };
430
431 let unwind_info = match debug_frame.unwind_info_for_address(
432 base,
433 ctx,
434 current_location,
435 gimli::DebugFrame::cie_from_offset,
436 ) {
437 Ok(val) => val,
438 Err(err) => {
439 trace!("Stopped unwinding call stack, because: {:?}", err);
440 return Ok(vec![]);
441 }
442 };
443
444 let cfa = unwind_cfa(unwind_registers, unwind_info)?;
445
446 let mut new_registers = [None; 16];
447 for i in 0..16_usize {
448 let reg_rule = unwind_info.register(gimli::Register(i as u16));
449
450 new_registers[i] = match reg_rule {
451 Undefined => {
452 if i == sp_reg {
455 cfa
456 } else if i == pc_reg {
457 Some(current_location as u32)
458 } else {
459 None
460 }
461 }
462 SameValue => unwind_registers[i],
463 Offset(offset) => {
464 let address = (offset
465 + match cfa {
466 Some(val) => i64::from(val),
467 None => return Err(anyhow!("Expected CFA to have a value")),
468 }) as u32;
469
470 let value = {
471 let value = match memory.get_address(&address, 4) {
472 Some(val) => {
473 let mut result = vec![];
474 for v in val {
475 result.push(v);
476 }
477
478 u32::from_le_bytes(match result.as_slice().try_into() {
479 Ok(val) => val,
480 Err(err) => {
481 error!("{:?}", err);
482 return Err(anyhow!("{:?}", err));
483 }
484 })
485 }
486 None => {
487 error!("Can not read 4 bytes from address 0x{:x}", address);
488 return Err(anyhow!(
489 "Can not read 4 bytes from address 0x{:x}",
490 address
491 ));
492 }
493 };
494 value
495 };
496
497 Some(value)
498 }
499 ValOffset(offset) => {
500 let value = (offset
501 + match cfa {
502 Some(val) => i64::from(val),
503 None => return Err(anyhow!("Expected CFA to have a value")),
504 }) as u32;
505
506 Some(value)
507 }
508 Register(reg) => unwind_registers[reg.0 as usize],
509 Expression(_expr) => {
510 error!("Unimplemented");
511 return Err(anyhow!("Unimplemented")); }
513 ValExpression(_expr) => {
514 error!("Unimplemented");
515 return Err(anyhow!("Unimplemented")); }
517 Architectural => {
518 error!("Unimplemented");
519 return Err(anyhow!("Unimplemented"));
520 }
521 };
522 }
523
524 let mut call_stack = vec![CallFrame {
525 id: current_location,
526 registers: unwind_registers,
527 code_location: current_location,
528 cfa,
529 start_address: unwind_info.start_address(),
530 end_address: unwind_info.end_address(),
531 }];
532
533 unwind_registers = new_registers;
534
535 let next_code_location = unwind_registers[link_reg as usize].map(|pc| u64::from(pc & !1) - 1);
542
543 call_stack.append(&mut unwind_call_stack_recursive(
544 debug_frame,
545 memory,
546 pc_reg,
547 link_reg,
548 sp_reg,
549 next_code_location,
550 unwind_registers,
551 base,
552 ctx,
553 )?);
554 Ok(call_stack)
555}
556
557fn unwind_cfa<R: Reader<Offset = usize>>(
566 registers: [Option<u32>; 16],
567 unwind_info: &gimli::UnwindTableRow<R>,
568) -> Result<Option<u32>> {
569 match unwind_info.cfa() {
570 gimli::CfaRule::RegisterAndOffset { register, offset } => {
571 let reg_val = match registers[register.0 as usize] {
572 Some(val) => val,
573 None => return Ok(None),
574 };
575 Ok(Some((i64::from(reg_val) + offset) as u32))
576 }
577 gimli::CfaRule::Expression(_expr) => {
578 error!("Unimplemented");
579 Err(anyhow!("Unimplemented")) }
581 }
582}
583
584#[derive(Debug, Clone)]
586pub struct StackFrame<R: Reader<Offset = usize>> {
587 pub call_frame: CallFrame,
589
590 pub name: String,
592
593 pub source: SourceInformation,
595
596 pub variables: Vec<Variable<R>>,
598
599 pub arguments: Vec<Variable<R>>,
601
602 pub registers: Vec<Variable<R>>,
604
605 pub frame_base: u64,
607}
608
609impl<R: Reader<Offset = usize>> StackFrame<R> {
610 pub fn find_variable(&self, name: &str) -> Option<&Variable<R>> {
619 for v in &self.variables {
620 match &v.name {
621 Some(var_name) => {
622 if var_name == name {
623 return Some(v);
624 }
625 }
626 None => (),
627 };
628 }
629
630 None
631 }
632}
633
634pub fn create_stack_frame<M: MemoryAccess, R: Reader<Offset = usize>>(
646 dwarf: &Dwarf<R>,
647 call_frame: CallFrame,
648 registers: &Registers,
649 mem: &mut M,
650 cwd: &str,
651) -> Result<StackFrame<R>> {
652 let (section_offset, unit_offset) = find_function_die(dwarf, call_frame.code_location as u32)?;
654 let header =
655 dwarf
656 .debug_info
657 .header_from_offset(match section_offset.as_debug_info_offset() {
658 Some(val) => val,
659 None => {
660 return Err(anyhow!(
661 "Could not convert section offset to debug info offset"
662 ))
663 }
664 })?;
665 let unit = gimli::Unit::new(dwarf, header)?;
666 let mut tree = unit.entries_tree(Some(unit_offset))?;
667 let node = tree.root()?;
668
669 let die = unit.entry(unit_offset)?;
670 let name = match die.attr_value(gimli::DW_AT_name)? {
672 Some(DebugStrRef(offset)) => format!("{:?}", dwarf.string(offset)?.to_string()?),
673 _ => match die.attr_value(gimli::DW_AT_abstract_origin)? {
674 Some(offset) => match offset {
675 UnitRef(o) => {
676 let ndie = unit.entry(o)?;
677 match ndie.attr_value(gimli::DW_AT_name)? {
678 Some(DebugStrRef(offset)) => {
679 format!("{:?}", dwarf.string(offset)?.to_string()?)
680 }
681 _ => "<unknown>".to_string(),
682 }
683 }
684 DebugInfoRef(di_offset) => {
685 let offset = gimli::UnitSectionOffset::DebugInfoOffset(di_offset);
686 let mut iter = dwarf.debug_info.units();
687 let mut name = "<unknown>".to_string();
688 while let Ok(Some(header)) = iter.next() {
689 let unit = dwarf.unit(header)?;
690 if let Some(offset) = offset.to_unit_offset(&unit) {
691 let ndie = unit.entry(offset)?;
692 name = match ndie.attr_value(gimli::DW_AT_name)? {
693 Some(DebugStrRef(offset)) => {
694 format!("{:?}", dwarf.string(offset)?.to_string()?)
695 }
696 _ => "<unknown>".to_string(),
697 };
698
699 break;
700 }
701 }
702 name
703 }
704 val => {
705 error!("Unimplemented for {:?}", val);
706 return Err(anyhow!("Unimplemented for {:?}", val));
707 }
708 },
709 None => "<unknown>".to_string(),
710 },
711 };
712
713 let source = SourceInformation::get_die_source_information(dwarf, &unit, node.entry(), cwd)?;
715
716 let dies_to_check = get_functions_variables_die_offset(
718 dwarf,
719 section_offset,
720 unit_offset,
721 call_frame.code_location as u32,
722 )?;
723
724 let mut temporary_registers = Registers::default();
726 temporary_registers.program_counter_register = registers.program_counter_register;
727 temporary_registers.link_register = registers.link_register;
728 temporary_registers.stack_pointer_register = registers.stack_pointer_register;
729 temporary_registers.cfa = call_frame.cfa;
730 let pc = call_frame.code_location as u32;
731 for i in 0..call_frame.registers.len() {
732 match call_frame.registers[i] {
733 Some(val) => temporary_registers.add_register_value(i as u16, val),
734 None => (),
735 };
736 }
737
738 let (fb_section_offset, fb_unit_offset) = find_non_inlined_function_die(dwarf, pc)?;
739 let fb_header =
740 dwarf
741 .debug_info
742 .header_from_offset(match fb_section_offset.as_debug_info_offset() {
743 Some(val) => val,
744 None => {
745 return Err(anyhow!(
746 "Could not convert section offset to debug info offset"
747 ))
748 }
749 })?;
750 let fb_unit = gimli::Unit::new(dwarf, fb_header)?;
751 let fb_die = fb_unit.entry(fb_unit_offset)?;
752 let frame_base =
754 match evaluate_frame_base(dwarf, &unit, pc, &fb_die, &mut temporary_registers, mem) {
755 Ok(val) => val,
756 Err(err) => {
757 error!("{:?}", err);
758 return Err(anyhow!("{:?}", err));
759 }
760 };
761
762 let mut variables = vec![];
763 let mut arguments = vec![];
764
765 for variable_die in dies_to_check {
766 let vc = match Variable::get_variable(
767 dwarf,
768 &temporary_registers,
769 mem,
770 DwarfOffset {
771 section_offset,
772 unit_offset: variable_die,
773 },
774 Some(frame_base),
775 cwd,
776 ) {
777 Ok(v) => v,
778 Err(err) => {
779 log::error!("Error: {:?}", err);
780 continue;
781 }
782 };
783
784 if is_argument(dwarf, section_offset, variable_die)? {
785 arguments.push(vc);
786 } else {
787 variables.push(vc);
788 }
789 }
790
791 let mut regs = vec![];
792 for key in 0..call_frame.registers.len() {
793 if let Some(value) = call_frame.registers[key] {
794 regs.push(Variable {
795 name: Some(format!("R{}", key)),
796 value: EvaluatorValue::Value(
797 BaseTypeValue::Reg32(value),
798 ValueInformation {
799 raw: None,
800 pieces: vec![],
801 },
802 ),
803 source: None,
804 });
805 };
806 }
807
808 Ok(StackFrame {
809 call_frame,
810 name,
811 source,
812 variables,
813 arguments,
814 registers: regs,
815 frame_base,
816 })
817}
818
819pub fn find_function_die<R: Reader<Offset = usize>>(
829 dwarf: &'_ Dwarf<R>,
830 address: u32,
831) -> Result<(gimli::UnitSectionOffset, gimli::UnitOffset)> {
832 let unit = get_current_unit(dwarf, address)?;
833 let mut cursor = unit.entries();
834
835 let mut depth = 0;
836 let mut res = None;
837 let mut dies = vec![];
838
839 assert!(cursor.next_dfs()?.is_some());
840 while let Some((delta_depth, current)) = cursor.next_dfs()? {
841 depth += delta_depth;
844 if depth <= 0 {
845 break;
846 }
847
848 match current.tag() {
849 gimli::DW_TAG_subprogram | gimli::DW_TAG_inlined_subroutine => {
850 if let Some(true) = die_in_range(dwarf, &unit, current, address) {
851 match res {
852 Some(val) => {
853 match val {
854 x if x == depth => dies.push(current.clone()),
855 x if x < depth => {
856 res = Some(depth);
857 dies = vec![current.clone()];
858 }
859 _ => (),
860 };
861 }
862 None => {
863 res = Some(depth);
864 dies.push(current.clone());
865 }
866 };
867 }
868 }
869 _ => (),
870 };
871 }
872
873 if dies.len() != 1 {
874 error!("Unreachable");
875 return Err(anyhow!("Unreachable"));
876 }
877 Ok((unit.header.offset(), dies[0].offset()))
878}
879
880pub fn find_non_inlined_function_die<R: Reader<Offset = usize>>(
890 dwarf: &'_ Dwarf<R>,
891 address: u32,
892) -> Result<(gimli::UnitSectionOffset, gimli::UnitOffset)> {
893 let unit = get_current_unit(dwarf, address)?;
894 let mut cursor = unit.entries();
895
896 let mut depth = 0;
897 let mut res = None;
898 let mut dies = vec![];
899
900 assert!(cursor.next_dfs()?.is_some());
901 while let Some((delta_depth, current)) = cursor.next_dfs()? {
902 depth += delta_depth;
905 if depth <= 0 {
906 break;
907 }
908
909 if current.tag() == gimli::DW_TAG_subprogram {
910 if let Some(true) = die_in_range(dwarf, &unit, current, address) {
911 match current.attr_value(gimli::DW_AT_inline)? {
912 Some(val) => {
913 error!("inline attr val: {:?}", val);
914 }
915 None => (),
916 };
917 match res {
918 Some(val) => {
919 match val {
920 x if x == depth => dies.push(current.clone()),
921 x if x < depth => {
922 res = Some(depth);
923 dies = vec![current.clone()];
924 }
925 _ => (),
926 };
927 }
928 None => {
929 res = Some(depth);
930 dies.push(current.clone());
931 }
932 };
933 }
934 };
935 }
936
937 if dies.len() != 1 {
938 error!("Unreachable");
939 return Err(anyhow!("Unreachable"));
940 }
941 Ok((unit.header.offset(), dies[0].offset()))
942}
943
944pub fn get_functions_variables_die_offset<R: Reader<Offset = usize>>(
957 dwarf: &Dwarf<R>,
958 section_offset: UnitSectionOffset,
959 unit_offset: UnitOffset,
960 pc: u32,
961) -> Result<Vec<UnitOffset>> {
962 fn recursive_offset<R: Reader<Offset = usize>>(
963 dwarf: &Dwarf<R>,
964 unit: &Unit<R>,
965 node: EntriesTreeNode<R>,
966 pc: u32,
967 list: &mut Vec<UnitOffset>,
968 ) -> Result<()> {
969 let die = node.entry();
970
971 if let Some(false) = die_in_range(dwarf, unit, die, pc) {
972 return Ok(());
973 };
974
975 if is_variable_die(die) {
976 list.push(die.offset());
977 }
978
979 let mut children = node.children();
981 while let Some(child) = children.next()? {
982 recursive_offset(dwarf, unit, child, pc, list)?;
983 }
984
985 Ok(())
986 }
987
988 let header =
989 dwarf
990 .debug_info
991 .header_from_offset(match section_offset.as_debug_info_offset() {
992 Some(val) => val,
993 None => {
994 return Err(anyhow!(
995 "Could not convert section offset to debug info offset"
996 ))
997 }
998 })?;
999 let unit = gimli::Unit::new(dwarf, header)?;
1000 let mut tree = unit.entries_tree(Some(unit_offset))?;
1001 let node = tree.root()?;
1002
1003 let mut die_offsets = vec![];
1004
1005 let mut children = node.children();
1007 while let Some(child) = children.next()? {
1008 recursive_offset(dwarf, &unit, child, pc, &mut die_offsets)?;
1009 }
1010
1011 Ok(die_offsets)
1012}
1013
1014pub fn evaluate_frame_base<R: Reader<Offset = usize>, T: MemoryAccess>(
1027 dwarf: &Dwarf<R>,
1028 unit: &Unit<R>,
1029 pc: u32,
1030 die: &DebuggingInformationEntry<'_, '_, R>,
1031 registers: &mut Registers,
1032 mem: &mut T,
1033) -> Result<u64> {
1034 if let Some(val) = die.attr_value(gimli::DW_AT_frame_base)? {
1035 if let Some(expr) = val.exprloc_value() {
1036 let value = evaluate(dwarf, unit, pc, expr, None, None, None, registers, mem)?;
1037
1038 match value {
1039 EvaluatorValue::Value(BaseTypeValue::Address32(v), _) => Ok(v as u64),
1040 _ => {
1041 error!("Unreachable");
1042 Err(anyhow!("Unreachable"))
1043 }
1044 }
1045 } else {
1046 error!("Unimplemented");
1047 Err(anyhow!("Unimplemented"))
1048 }
1049 } else if let Some(offset) = die.attr_value(gimli::DW_AT_abstract_origin)? {
1050 match offset {
1051 UnitRef(o) => {
1052 let ndie = unit.entry(o)?;
1053 evaluate_frame_base(dwarf, unit, pc, &ndie, registers, mem)
1054 }
1055 DebugInfoRef(di_offset) => {
1056 let offset = gimli::UnitSectionOffset::DebugInfoOffset(di_offset);
1057 let mut iter = dwarf.debug_info.units();
1058 while let Ok(Some(header)) = iter.next() {
1059 let unit = dwarf.unit(header)?;
1060 if let Some(offset) = offset.to_unit_offset(&unit) {
1061 let ndie = unit.entry(offset)?;
1062 return evaluate_frame_base(dwarf, &unit, pc, &ndie, registers, mem);
1063 }
1064 }
1065
1066 error!("Unimplemented");
1067 Err(anyhow!("Unimplemented"))
1068 }
1069 val => {
1070 error!("Unimplemented for {:?}", val);
1071 Err(anyhow!("Unimplemented for {:?}", val))
1072 }
1073 }
1074 } else {
1075 Err(anyhow!("Die has no DW_AT_frame_base attribute"))
1076 }
1077}
1078
1079fn is_argument<R: Reader<Offset = usize>>(
1080 dwarf: &Dwarf<R>,
1081 section_offset: UnitSectionOffset,
1082 unit_offset: UnitOffset,
1083) -> Result<bool> {
1084 let header =
1086 dwarf
1087 .debug_info
1088 .header_from_offset(match section_offset.as_debug_info_offset() {
1089 Some(val) => val,
1090 None => {
1091 error!("Could not convert section offset into debug info offset");
1092 return Err(anyhow!(
1093 "Could not convert section offset into debug info offset"
1094 ));
1095 }
1096 })?;
1097 let unit = gimli::Unit::new(dwarf, header)?;
1098 let die = unit.entry(unit_offset)?;
1099
1100 match die.tag() {
1101 gimli::DW_TAG_formal_parameter => Ok(true),
1102 _ => Ok(false),
1103 }
1104}