let unwind_info_address = function.unwind_info_address.get(); let unwind_info =
UnwindInfo::parse(sections.unwind_info_memory_at_rva(unwind_info_address)?)
.ok_or(PeUnwinderError::UnwindInfoParseError)?;
if is_first_frame { // Check whether the address is in the function epilog. If so, we need to // simulate the remaining epilog instructions (unwind codes don't account for // unwinding from the epilog). We only need to check this for the first unwind info (if // there are chained infos). let bytes = (function.end_address.get() - address) as usize; let instruction = §ions.text_memory_at_rva(address)?[..bytes]; iflet Ok(epilog_instructions) =
FunctionEpilogInstruction::parse_sequence(instruction, unwind_info.frame_register())
{ // If the epilog is an optional AddSP followed by Pops, we can return a cache // rule. iflet Some(rule) =
UnwindRuleX86_64::for_sequence_of_offset_or_pop(epilog_instructions.iter())
{ return Ok(UnwindResult::ExecRule(rule));
}
for instruction in epilog_instructions.iter() { match instruction {
FunctionEpilogInstruction::AddSP(offset) => { let rsp = regs.get(Reg::RSP);
regs.set(Reg::RSP, rsp + *offset as u64);
}
FunctionEpilogInstruction::AddSPFromFP(offset) => { let fp = unwind_info
.frame_register()
.expect("invalid fp register offset"); let fp = convert_pe_register(fp); let fp = regs.get(fp);
regs.set(Reg::RSP, fp + *offset as u64);
}
FunctionEpilogInstruction::Pop(reg) => { let rsp = regs.get(Reg::RSP); let val = read_stack_err(read_stack, rsp)?;
regs.set(convert_pe_register(*reg), val);
regs.set(Reg::RSP, rsp + 8);
}
}
}
let rsp = regs.get(Reg::RSP); let ra = read_stack_err(read_stack, rsp)?;
regs.set(Reg::RSP, rsp + 8);
return Ok(UnwindResult::Uncacheable(ra));
}
}
// Get all chained UnwindInfo and resolve errors when collecting. let chained_info = core::iter::successors(Some(Ok(unwind_info)), |info| { let Ok(info) = info else { return None;
}; iflet Some(UnwindInfoTrailer::ChainedUnwindInfo { chained }) = info.trailer() { let unwind_info_address = chained.unwind_info_address.get();
Some(
sections
.unwind_info_memory_at_rva(unwind_info_address)
.and_then(|data| {
UnwindInfo::parse(data).ok_or(PeUnwinderError::UnwindInfoParseError)
}),
)
} else {
None
}
})
.collect::<Result<Vec<_>, _>>()?;
// Get all operations across chained UnwindInfo. The first should be filtered to only those // operations which are before the offset in the function. let offset = address - function.begin_address.get(); let operations = chained_info.into_iter().enumerate().flat_map(|(i, info)| {
info.unwind_operations()
.skip_while(move |(o, _)| i == 0 && *o as u32 > offset)
.map(|(_, op)| op)
});
// We need to collect operations to first check (without losing ownership) whether an // unwind rule can be returned. let operations = operations.collect::<Vec<_>>(); iflet Some(rule) = UnwindRuleX86_64::for_sequence_of_offset_or_pop(operations.iter()) { return Ok(UnwindResult::ExecRule(rule));
}
// Resolve operations to get the return address. letmut state = State { regs, read_stack }; for op in operations { iflet ControlFlow::Break(ra) = unwind_info
.resolve_operation(&mut state, &op)
.ok_or(PeUnwinderError::MissingStackData(None))?
{ return Ok(UnwindResult::Uncacheable(ra));
}
}
let rsp = regs.get(Reg::RSP); let ra = read_stack_err(read_stack, rsp)?;
regs.set(Reg::RSP, rsp + 8);
Ok(UnwindResult::Uncacheable(ra))
}
}
Messung V0.5 in Prozent
¤ Dauer der Verarbeitung: 0.18 Sekunden
(vorverarbeitet am 2026-06-17)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.