rust_debug/
call_stack.rs

1/**
2 * Good gimli sources:
3 * https://docs.rs/gimli/0.23.0/gimli/read/struct.DebugFrame.html
4 * https://docs.rs/gimli/0.23.0/gimli/read/trait.UnwindSection.html
5 *
6 * Dwarf source: Dwarf 5 section 6.4.1
7 */
8use 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
29/// A trait used for reading memory of the debug target.
30pub trait MemoryAccess {
31    /// Reads a number of bytes from the debugged target.
32    ///
33    /// Description:
34    ///
35    /// * `address` - The address that will be read.
36    /// * `num_bytes` - The number of bytes that will be read.
37    ///
38    /// This function is used for reading `num_bytes` bytes in the debugged target system at the
39    /// address `address`.
40    /// This is done when evaluating variables that are stored in the memory of the debugged
41    /// target.
42    fn get_address(&mut self, address: &u32, num_bytes: usize) -> Option<Vec<u8>>;
43}
44
45/// Will preform a stack trace on the debugged target.
46///
47/// Description:
48///
49/// * `dwarf` - A reference to gimli-rs `Dwarf` struct.
50/// * `debug_frame` - A reference to the DWARF section `.debug_frame`.
51/// * `registers` - A `Registers` struct which is used to read the register values.
52/// * `memory` - Used to read the memory of the debugged target.
53/// * `cwd` - The work directory of the debugged program.
54///
55/// This function will first virtually unwind the call stack.
56/// Then it will evaluate all the variables in each of the stack frames, and return a `Vec` of
57/// `StackFrame`s.
58pub 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    //    println!("\n\nnew stack trace");
66    //    let das = new_stack_trace(dwarf, debug_frame, registers.clone(), memory, cwd)?;
67    //    for sf in &das {
68    //        println!("stack_frame name: {:?}", sf.name);
69    //        println!(
70    //            "line {:?}",
71    //            get_line_number(dwarf, sf.call_frame.code_location)
72    //        );
73    //    }
74    //    println!("\n\n");
75    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, &registers, memory, cwd)?;
80
81        stack_trace.push(stack_frame);
82    }
83    Ok(stack_trace)
84    //Ok(das)
85}
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 &registers.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        &registers,
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    // Check current pc.
143    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    // Get unwind info
152    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    // Get CFA
166    let cfa = unwind_cfa(unwind_registers, unwind_info)?;
167
168    // Unwind registers
169    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 the column is empty then it defaults to undefined.
176                // Source: https://github.com/gimli-rs/gimli/blob/00f4ee6a288d2e7f02b6841a5949d839e99d8359/src/read/cfi.rs#L2289-L2311
177                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")); // TODO
235            }
236            ValExpression(_expr) => {
237                error!("Unimplemented");
238                return Err(anyhow!("Unimplemented")); // TODO
239            }
240            Architectural => {
241                error!("Unimplemented");
242                return Err(anyhow!("Unimplemented")); // TODO
243            }
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    // Get next_code_location
265    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                //println!("here");
293                //Some(unwind_info.start_address())
294                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                // Call address is equal to return address, but the first bit needs to be removed
304                // because of thumb mode.
305                // And take minus one to ensure that it is the caller address and not the return
306                // address.
307                // This address will not be aligend to the instruction address.
308                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/// Describes what a call frame contains.
331#[derive(Debug, Clone)]
332pub struct CallFrame {
333    /// The identifier of the call frame.
334    pub id: u64,
335
336    /// Preserved register values of the call frame.
337    pub registers: [Option<u32>; 16],
338
339    /// The current code location in the frame.
340    pub code_location: u64,
341
342    /// The Canonical Frame Address for this frame.
343    pub cfa: Option<u32>,
344
345    /// First machine code address of this frame.
346    pub start_address: u64,
347
348    /// Last machine code address of this frame.
349    pub end_address: u64,
350}
351
352/// Will virtually unwind the call stack.
353///
354/// Description:
355///
356/// * `registers` - A `Registers` struct which is used to read the register values.
357/// * `memory` - Used to read the memory of the debugged target.
358/// * `debug_frame` - A reference to the DWARF section `.debug_frame`.
359///
360/// This function will virtually unwind the call stack and return a `Vec` of `CallFrame`s.
361pub 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 &registers.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
397/// Helper function for virtually unwind the call stack recursively.
398///
399/// Description:
400///
401/// * `debug_frame` - A reference to the DWARF section `.debug_frame`.
402/// * `memory` - Used to read the memory of the debugged target.
403/// * `pc_reg` - The register number which is the program counter register.
404/// * `link_reg` - The register number which is the link register.
405/// * `sp_reg` - The register number which is the stack pointer register.
406/// * `code_location` - The code location in the call frame.
407/// * `unwind_registers` - The virtually unwind register values.
408/// * `base` - A base address struct which gimli-rs requires.
409/// * `ctx` - Unwind context struct which gimli-rs requires.
410///
411/// This function will virtually unwind the call stack recursively.
412fn 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 the column is empty then it defaults to undefined.
453                // Source: https://github.com/gimli-rs/gimli/blob/00f4ee6a288d2e7f02b6841a5949d839e99d8359/src/read/cfi.rs#L2289-L2311
454                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")); // TODO
512            }
513            ValExpression(_expr) => {
514                error!("Unimplemented");
515                return Err(anyhow!("Unimplemented")); // TODO
516            }
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    // Source: https://github.com/probe-rs/probe-rs/blob/8112c28912125a54aad016b4b935abf168812698/probe-rs/src/debug/mod.rs#L297-L302
536    // Next function is where our current return register is pointing to.
537    // We just have to remove the lowest bit (indicator for Thumb mode).
538    //
539    // We also have to subtract one, as we want the calling instruction for
540    // a backtrace, not the next instruction to be executed.
541    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
557/// A function for virtually unwind the Canonical Frame address.
558///
559/// Description:
560///
561/// * `registers` - The virtually unwind registers.
562/// * `unwind_info` - The current unwind information table row.
563///
564/// Will virtually unwind the Canonical Frame address.
565fn 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")) // TODO
580        }
581    }
582}
583
584/// Describes what a stack frame contains.
585#[derive(Debug, Clone)]
586pub struct StackFrame<R: Reader<Offset = usize>> {
587    /// The related call frame.
588    pub call_frame: CallFrame,
589
590    /// Name of the frames subroutine.
591    pub name: String,
592
593    /// The source code declaration location information.
594    pub source: SourceInformation,
595
596    /// The variables in this frame.
597    pub variables: Vec<Variable<R>>,
598
599    /// The arguments in this frame.
600    pub arguments: Vec<Variable<R>>,
601
602    /// The registers in this frame.
603    pub registers: Vec<Variable<R>>,
604
605    /// The frame base address value.
606    pub frame_base: u64,
607}
608
609impl<R: Reader<Offset = usize>> StackFrame<R> {
610    /// Find a variable in this stack frame.
611    ///
612    /// Description:
613    ///
614    /// * `name` - The name of the searched variable.
615    ///
616    /// This function will go through each of the variables in this stack frame and return the one
617    /// with the same name as the given name.
618    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
634/// Gets the stack frame information.
635///
636/// Description:
637///
638/// * `dwarf` - A reference to gimli-rs `Dwarf` struct.
639/// * `call_frame` - A call frame which is used to evaluate the stack frame.
640/// * `registers` - A register struct for accessing the register values.
641/// * `mem` - A struct for accessing the memory of the debug target.
642/// * `cwd` - The work directory of the debugged program.
643///
644/// This function will find stack frame information using a call frame.
645pub 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    // Find the corresponding function to the call frame.
653    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    // Get the name of the function.
671    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    // Get source information about the function
714    let source = SourceInformation::get_die_source_information(dwarf, &unit, node.entry(), cwd)?;
715
716    // Get all the variable dies to evaluate.
717    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    // Get register values
725    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    //println!("name: {:?}, tag: {:?}", name, die.tag().static_string());
753    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
819/// Will find the DIE representing the searched function
820///
821/// Description:
822///
823/// * `dwarf` - A reference to gimli-rs `Dwarf` struct.
824/// * `address` - Used to find which function this machine code address belongs too.
825///
826/// This function will search DWARF for the function that the given machine code address belongs
827/// too.
828pub 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        // Update depth value, and break out of the loop when we
842        // return to the original starting position.
843        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
880/// Will find the DIE representing the searched non inlined function
881///
882/// Description:
883///
884/// * `dwarf` - A reference to gimli-rs `Dwarf` struct.
885/// * `address` - Used to find which function this machine code address belongs too.
886///
887/// This function will search DWARF for the function that the given machine code address belongs
888/// too.
889pub 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        // Update depth value, and break out of the loop when we
903        // return to the original starting position.
904        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
944/// Will find all the in range variable DIEs in a subroutine.
945///
946/// Description:
947///
948/// * `dwarf` - A reference to gimli-rs `Dwarf` struct.
949/// * `section_offset` - A offset into the DWARF `.debug_info` section which is used to find the
950/// relevant compilation.
951/// * `unit_offset` - A offset into the given compilation unit, which points the subroutine DIE.
952/// * `pc` - A machine code address, it is usually the current code address.
953///
954/// This function will go done the subtree of a subroutine DIE and return all in range variable
955/// DIEs.
956pub 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        // Recursively process the children.
980        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    // Recursively process the children.
1006    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
1014/// Will evaluate the frame base address for a given subroutine.
1015///
1016/// Description:
1017///
1018/// * `dwarf` - A reference to gimli-rs `Dwarf` struct.
1019/// * `unit` - The compilation unit the subroutine DIE is located in.
1020/// * `pc` - A machine code address, it is usually the current code location.
1021/// * `die` - A reference to the subroutine DIE.
1022/// * `registers` - A `Registers` struct which is used to read the register values.
1023/// * `memory` - Used to read the memory of the debugged target.
1024///
1025/// This function is used to evaluate the frame base address for a given subroutine.
1026pub 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    // Get the variable die.
1085    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}