/// Tries to unwind the stack.
///
/// Returns the next frame and true if there are more frames or false if there are no more frames left
Tries to unwind the stack.
Returns the next frame and true if there are more frames or false if there are no more frames left
Tries to unwind the stack . Returns the next frame and true if there are more frames or false if there are no more frames left
pub fn try_unwind(
        &mut self,
        last_frame: Option<&mut Frame<u32>>,
    ) -> Result<(Option<Frame<u32>>, bool), TraceError> {
        let unwind_info = self.debug_frame.unwind_info_for_address(
            &self.bases,
            &mut self.unwind_context,
            self.device_memory.register(gimli::Arm::PC)? as u64,
            DebugFrame::cie_from_offset,
        );
        let unwind_info = match unwind_info {
            Ok(unwind_info) => unwind_info.clone(),
            Err(_e) => {
                return Ok((Some(Frame { function: "Unknown".into(), location: crate::Location { file: None, line: None, column: None }, frame_type: FrameType::Corrupted(format!("debug information for address {:#x} is missing. Likely fixes:
                1. compile the Rust code with `debug = 1` or higher. This is configured in the `profile.{{release,bench}}` sections of Cargo.toml (`profile.{{dev,test}}` default to `debug = 2`)
                2. use a recent version of the `cortex-m` crates (e.g. cortex-m 0.6.3 or newer). Check versions in Cargo.lock
                3. if linking to C code, compile the C code with the `-g` flag", self.device_memory.register(gimli::Arm::PC)?)),
                    variables: Vec::new(), }), false));
            }
        };
        // We can update the stackpointer and other registers to the previous frame by applying the unwind info
        let stack_pointer_changed = match self.apply_unwind_info(unwind_info) {
            Ok(stack_pointer_changed) => stack_pointer_changed,
            Err(e) => {
                return Ok((
                    Some(Frame {
                        function: "Unknown".into(),
                        location: crate::Location {
                            file: None,
                            line: None,
                            column: None,
                        },
                        frame_type: FrameType::Corrupted(e.to_string()),
                        variables: Vec::new(),
                    }),
                    false,
                ));
            }
        };
        // We're not at the last frame. What's the reason?
        // Do we have a corrupted stack?
        if !stack_pointer_changed
            && self.device_memory.register(gimli::Arm::LR)? & !THUMB_BIT
                == self.device_memory.register(gimli::Arm::PC)? & !THUMB_BIT
        {
            // The stack pointer didn't change and our LR points to our current PC
            // If we unwound further we'd get the same frame again so we better stop
            return Ok((
                Some(Frame {
                    function: "Unknown".into(),
                    location: crate::Location {
                        file: None,
                        line: None,
                        column: None,
                    },
                    frame_type: FrameType::Corrupted(
                        "CFA did not change and LR and PC are equal".into(),
                    ),
                    variables: Vec::new(),
                }),
                false,
            ));
        }
        // Stack is not corrupted, but unwinding is not done
        // Are we returning from an exception? (EXC_RETURN)
        if self.device_memory.register(gimli::Arm::LR)? > 0xffff_ffe0 {
            // Yes, so the registers were pushed to the stack and we need to get them back
            // Check the value to know if there are fpu registers to read
            let fpu = match self.device_memory.register(gimli::Arm::LR)? {
                0xFFFFFFF1 | 0xFFFFFFF9 | 0xFFFFFFFD => false,
                0xFFFFFFE1 | 0xFFFFFFE9 | 0xFFFFFFED => true,
                _ => {
                    return Ok((
                        Some(Frame {
                            function: "Unknown".into(),
                            location: crate::Location {
                                file: None,
                                line: None,
                                column: None,
                            },
                            frame_type: FrameType::Corrupted(format!(
                                "LR contains invalid EXC_RETURN value {:#10X}",
                                self.device_memory.register(gimli::Arm::LR)?
                            )),
                            variables: Vec::new(),
                        }),
                        false,
                    ));
                }
            };
            if let Some(last_frame) = last_frame {
                last_frame.frame_type = FrameType::Exception;
            }
            match self.update_registers_with_exception_stack(fpu) {
                Ok(()) => {}
                Err(TraceError::MissingMemory(address)) => {
                    return Ok((
                        Some(Frame {
                            function: "Unknown".into(),
                            location: crate::Location {
                                file: None,
                                line: None,
                                column: None,
                            },
                            frame_type: FrameType::Corrupted(format!(
                                "Could not read address {:#10X} from the stack",
                                address
                            )),
                            variables: Vec::new(),
                        }),
                        false,
                    ));
                }
                Err(e) => return Err(e),
            }
        } else {
            // No exception, so follow the LR back
            *self.device_memory.register_mut(gimli::Arm::PC)? =
                self.device_memory.register(gimli::Arm::LR)?
        }
        // Have we reached the reset vector?
        if self
            .reset_vector_address_range
            .contains(self.device_memory.register_ref(gimli::Arm::PC)?)
        {
            // Yes, let's make that a frame as well
            // We'll also make an assumption that there's no frames before reset
            return Ok((
                Some(Frame {
                    function: "RESET".into(),
                    location: crate::Location {
                        file: None,
                        line: None,
                        column: None,
                    },
                    frame_type: FrameType::Function,
                    variables: Vec::new(),
                }),
                false,
            ));
        }
        if self.is_last_frame()? {
            Ok((None, false))
        } else {
            // Is our stack pointer in a weird place?
            if self
                .device_memory
                .read_u32(
                    self.device_memory.register(gimli::Arm::SP)? as u64,
                    RunTimeEndian::Little,
                )
                .is_none()
            {
                Ok((Some(Frame {
                    function: "Unknown".into(),
                    location: crate::Location { file: None, line: None, column: None },
                    frame_type: FrameType::Corrupted(
                        format!("The stack pointer ({:#08X}) is corrupted or the dump does not contain the full stack", self.device_memory
                        .register(gimli::Arm::SP)?),
                    ),
                    variables: Vec::new(),
                }), false))
            } else {
                Ok((None, true))
            }
        }
    }
pub fn try_unwind ( & mut self , last_frame : Option < & mut Frame < u32 > > , ) -> Result < ( Option < Frame < u32 > > , bool ) , TraceError > { let unwind_info = self . debug_frame . unwind_info_for_address ( & self . bases , & mut self . unwind_context , self . device_memory . register ( gimli :: Arm :: PC ) ? as u64 , DebugFrame :: cie_from_offset , ) ; let unwind_info = match unwind_info { Ok ( unwind_info ) => unwind_info . clone ( ) , Err ( _e ) => { return Ok ( ( Some ( Frame { function : " " . into ( ) , location : crate :: Location { file : None , line : None , column : None } , frame_type : FrameType :: Corrupted ( format ! ( " " self device_memory register ( gimli Arm PC ) ) ) , variables : Vec :: new ( ) , } ) , false ) ) ; } } ; // We can update the stackpointer and other registers to the previous frame by applying the unwind info let stack_pointer_changed = match self . apply_unwind_info ( unwind_info ) { Ok ( stack_pointer_changed ) => stack_pointer_changed , Err ( e ) => { return Ok ( ( Some ( Frame { function : " " . into ( ) , location : crate :: Location { file : None , line : None , column : None , } , frame_type : FrameType :: Corrupted ( e . to_string ( ) ) , variables : Vec :: new ( ) , } ) , false , ) ) ; } } ; // We're not at the last frame. What's the reason? // Do we have a corrupted stack? if ! stack_pointer_changed && self . device_memory . register ( gimli :: Arm :: LR ) ? & ! THUMB_BIT == self . device_memory . register ( gimli :: Arm :: PC ) ? & ! THUMB_BIT { // The stack pointer didn't change and our LR points to our current PC // If we unwound further we'd get the same frame again so we better stop return Ok ( ( Some ( Frame { function : " " . into ( ) , location : crate :: Location { file : None , line : None , column : None , } , frame_type : FrameType :: Corrupted ( " " . into ( ) , ) , variables : Vec :: new ( ) , } ) , false , ) ) ; } // Stack is not corrupted, but unwinding is not done // Are we returning from an exception? (EXC_RETURN) if self . device_memory . register ( gimli :: Arm :: LR ) ? > 0xffff_ffe0 { // Yes, so the registers were pushed to the stack and we need to get them back // Check the value to know if there are fpu registers to read let fpu = match self . device_memory . register ( gimli :: Arm :: LR ) ? { 0xFFFFFFF1 | 0xFFFFFFF9 | 0xFFFFFFFD => false , 0xFFFFFFE1 | 0xFFFFFFE9 | 0xFFFFFFED => true , _ => { return Ok ( ( Some ( Frame { function : " " . into ( ) , location : crate :: Location { file : None , line : None , column : None , } , frame_type : FrameType :: Corrupted ( format ! ( " " self device_memory register ( gimli Arm LR ) ) ) , variables : Vec :: new ( ) , } ) , false , ) ) ; } } ; if let Some ( last_frame ) = last_frame { last_frame . frame_type = FrameType :: Exception ; } match self . update_registers_with_exception_stack ( fpu ) { Ok ( ( ) ) => { } Err ( TraceError :: MissingMemory ( address ) ) => { return Ok ( ( Some ( Frame { function : " " . into ( ) , location : crate :: Location { file : None , line : None , column : None , } , frame_type : FrameType :: Corrupted ( format ! ( " " address ) ) , variables : Vec :: new ( ) , } ) , false , ) ) ; } Err ( e ) => return Err ( e ) , } } else { // No exception, so follow the LR back * self . device_memory . register_mut ( gimli :: Arm :: PC ) ? = self . device_memory . register ( gimli :: Arm :: LR ) ? } // Have we reached the reset vector? if self . reset_vector_address_range . contains ( self . device_memory . register_ref ( gimli :: Arm :: PC ) ? ) { // Yes, let's make that a frame as well // We'll also make an assumption that there's no frames before reset return Ok ( ( Some ( Frame { function : " " . into ( ) , location : crate :: Location { file : None , line : None , column : None , } , frame_type : FrameType :: Function , variables : Vec :: new ( ) , } ) , false , ) ) ; } if self . is_last_frame ( ) ? { Ok ( ( None , false ) ) } else { // Is our stack pointer in a weird place? if self . device_memory . read_u32 ( self . device_memory . register ( gimli :: Arm :: SP ) ? as u64 , RunTimeEndian :: Little , ) . is_none ( ) { Ok ( ( Some ( Frame { function : " " . into ( ) , location : crate :: Location { file : None , line : None , column : None } , frame_type : FrameType :: Corrupted ( format ! ( " " self device_memory register ( gimli Arm SP ) ) , ) , variables : Vec :: new ( ) , } ) , false ) ) } else { Ok ( ( None , true ) ) } } }
Tries to unwind the stack.
Tries to unwind the stack .
&mut self
last_frame
Option<&mut Frame<u32>>