Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 


Quelle  macho.rs   Sprache: unbekannt

 
use super::arch::ArchX86_64;
use super::unwind_rule::UnwindRuleX86_64;
use crate::instruction_analysis::InstructionAnalysis;
use crate::macho::{CompactUnwindInfoUnwinderError, CompactUnwindInfoUnwinding, CuiUnwindResult};
use macho_unwind_info::opcodes::{OpcodeX86_64, RegisterNameX86_64};
use macho_unwind_info::Function;

impl CompactUnwindInfoUnwinding for ArchX86_64 {
    fn unwind_frame(
        function: Function,
        is_first_frame: bool,
        address_offset_within_function: usize,
        function_bytes: Option<&[u8]>,
    ) -> Result<CuiUnwindResult<UnwindRuleX86_64>, CompactUnwindInfoUnwinderError> {
        let opcode = OpcodeX86_64::parse(function.opcode);
        if is_first_frame {
            // The pc might be in a prologue or an epilogue. The compact unwind info format ignores
            // prologues and epilogues; the opcodes only describe the function body. So we do some
            // instruction analysis to check for prologues and epilogues.
            if let Some(function_bytes) = function_bytes {
                if let Some(rule) = Self::rule_from_instruction_analysis(
                    function_bytes,
                    address_offset_within_function,
                ) {
                    // We are inside a prologue / epilogue. Ignore the opcode and use the rule from
                    // instruction analysis.
                    return Ok(CuiUnwindResult::ExecRule(rule));
                }
                if opcode == OpcodeX86_64::Null
                    && function_bytes.starts_with(&[0x55, 0x48, 0x89, 0xe5])
                {
                    // The function is uncovered but it has a `push rbp; mov rbp, rsp` prologue.
                    return Ok(CuiUnwindResult::ExecRule(UnwindRuleX86_64::UseFramePointer));
                }
            }
            if opcode == OpcodeX86_64::Null {
                return Ok(CuiUnwindResult::ExecRule(UnwindRuleX86_64::JustReturn));
            }
        }

        // At this point we know with high certainty that we are in a function body.
        let r = match opcode {
            OpcodeX86_64::Null => {
                return Err(CompactUnwindInfoUnwinderError::FunctionHasNoInfo);
            }
            OpcodeX86_64::FramelessImmediate {
                stack_size_in_bytes,
                saved_regs,
            } => {
                if stack_size_in_bytes == 8 {
                    CuiUnwindResult::ExecRule(UnwindRuleX86_64::JustReturn)
                } else {
                    let bp_positon_from_outside = saved_regs
                        .iter()
                        .rev()
                        .flatten()
                        .position(|r| *r == RegisterNameX86_64::Rbp);
                    match bp_positon_from_outside {
                        Some(pos) => {
                            let bp_offset_from_sp =
                                stack_size_in_bytes as i32 - 2 * 8 - pos as i32 * 8;
                            let bp_storage_offset_from_sp_by_8 =
                                i16::try_from(bp_offset_from_sp / 8).map_err(|_| {
                                    CompactUnwindInfoUnwinderError::BpOffsetDoesNotFit
                                })?;
                            CuiUnwindResult::ExecRule(UnwindRuleX86_64::OffsetSpAndRestoreBp {
                                sp_offset_by_8: stack_size_in_bytes / 8,
                                bp_storage_offset_from_sp_by_8,
                            })
                        }
                        None => CuiUnwindResult::ExecRule(UnwindRuleX86_64::OffsetSp {
                            sp_offset_by_8: stack_size_in_bytes / 8,
                        }),
                    }
                }
            }
            OpcodeX86_64::FramelessIndirect {
                immediate_offset_from_function_start,
                stack_adjust_in_bytes,
                saved_regs,
            } => {
                let function_bytes = function_bytes.ok_or(
                    CompactUnwindInfoUnwinderError::NoTextBytesToLookUpIndirectStackOffset,
                )?;
                let sub_immediate_bytes = function_bytes
                    .get(
                        immediate_offset_from_function_start as usize
                            ..immediate_offset_from_function_start as usize + 4,
                    )
                    .ok_or(CompactUnwindInfoUnwinderError::IndirectStackOffsetOutOfBounds)?;
                let sub_immediate = u32::from_le_bytes([
                    sub_immediate_bytes[0],
                    sub_immediate_bytes[1],
                    sub_immediate_bytes[2],
                    sub_immediate_bytes[3],
                ]);
                let stack_size_in_bytes =
                    sub_immediate
                        .checked_add(stack_adjust_in_bytes.into())
                        .ok_or(CompactUnwindInfoUnwinderError::StackAdjustOverflow)?;
                let sp_offset_by_8 = u16::try_from(stack_size_in_bytes / 8)
                    .map_err(|_| CompactUnwindInfoUnwinderError::StackSizeDoesNotFit)?;
                let bp_positon_from_outside = saved_regs
                    .iter()
                    .rev()
                    .flatten()
                    .position(|r| *r == RegisterNameX86_64::Rbp);
                match bp_positon_from_outside {
                    Some(pos) => {
                        let bp_offset_from_sp = stack_size_in_bytes as i32 - 2 * 8 - pos as i32 * 8;
                        let bp_storage_offset_from_sp_by_8 =
                            i16::try_from(bp_offset_from_sp / 8)
                                .map_err(|_| CompactUnwindInfoUnwinderError::BpOffsetDoesNotFit)?;
                        CuiUnwindResult::ExecRule(UnwindRuleX86_64::OffsetSpAndRestoreBp {
                            sp_offset_by_8,
                            bp_storage_offset_from_sp_by_8,
                        })
                    }
                    None => {
                        CuiUnwindResult::ExecRule(UnwindRuleX86_64::OffsetSp { sp_offset_by_8 })
                    }
                }
            }
            OpcodeX86_64::Dwarf { eh_frame_fde } => CuiUnwindResult::NeedDwarf(eh_frame_fde),
            OpcodeX86_64::FrameBased { .. } => {
                CuiUnwindResult::ExecRule(UnwindRuleX86_64::UseFramePointer)
            }
            OpcodeX86_64::UnrecognizedKind(kind) => {
                return Err(CompactUnwindInfoUnwinderError::BadOpcodeKind(kind))
            }
            OpcodeX86_64::InvalidFrameless => {
                return Err(CompactUnwindInfoUnwinderError::InvalidFrameless)
            }
        };
        Ok(r)
    }

    fn rule_for_stub_helper(
        offset: u32,
    ) -> Result<CuiUnwindResult<UnwindRuleX86_64>, CompactUnwindInfoUnwinderError> {
        //     shared:
        //  +0x0 235cc4  4C 8D 1D 3D 03 04 00   lea  r11, qword [dyld_stub_binder_276000+8]
        //  +0x7 235ccb  41 53                  push  r11
        //  +0x9 235ccd  FF 25 2D 03 04 00      jmp  qword [dyld_stub_binder_276000] ; tail call
        //  +0xf 235cd3  90                     nop
        //    first stub:
        // +0x10 235cd4  68 F1 61 00 00         push  0x61f1
        // +0x15 235cd9  E9 E6 FF FF FF         jmp  0x235cc4 ; jump to shared
        //    second stub:
        // +0x1a 235cde  68 38 62 00 00         push  0x6238
        // +0x1f 235ce3  E9 DC FF FF FF         jmp  0x235cc4 ; jump to shared
        let rule = if offset < 0x7 {
            // pop 1 and return
            UnwindRuleX86_64::OffsetSp { sp_offset_by_8: 2 }
        } else if offset < 0x10 {
            // pop 2 and return
            UnwindRuleX86_64::OffsetSp { sp_offset_by_8: 3 }
        } else {
            let offset_after_shared = offset - 0x10;
            let offset_within_stub = offset_after_shared % 10;
            if offset_within_stub < 5 {
                UnwindRuleX86_64::JustReturn
                // just return
            } else {
                // pop 1 and return
                UnwindRuleX86_64::OffsetSp { sp_offset_by_8: 2 }
            }
        };
        Ok(CuiUnwindResult::ExecRule(rule))
    }
}

[ Dauer der Verarbeitung: 0.25 Sekunden  (vorverarbeitet)  ]

                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Software

     Produkte
     Quellcodebibliothek

Aktivitäten

     Artikel über Sicherheit
     Anleitung zur Aktivierung von SSL

Muße

     Gedichte
     Musik
     Bilder

Jenseits des Üblichen ....

Besucherstatistik

Besucherstatistik

Monitoring

Montastic status badge