use super::super::unwind_rule::UnwindRuleX86_64;
pub fn unwind_rule_from_detected_prologue(
text_bytes: &[u8],
pc_offset: usize,
) -> Option<UnwindRuleX86_64> {
let (slice_from_start, slice_to_end) = text_bytes.split_at(pc_offset);
if !is_next_instruction_expected_in_prologue(slice_to_end) {
return None;
}
let mut cursor = slice_from_start.len();
let mut sp_offset_by_8 = 0;
loop {
if cursor >= 4 {
if slice_from_start[cursor - 4..cursor] == [0x55, 0x48, 0x89, 0xe5] {
return Some(UnwindRuleX86_64::UseFramePointer);
}
}
if cursor >= 1 {
let byte = slice_from_start[cursor - 1];
if byte & 0xf8 == 0x50 {
sp_offset_by_8 += 1;
cursor -= 1;
if cursor >= 1 && slice_from_start[cursor - 1] & 0xfe == 0x40 {
cursor -= 1;
}
continue;
}
}
break;
}
sp_offset_by_8 += 1; Some(UnwindRuleX86_64::OffsetSp { sp_offset_by_8 })
}
fn is_next_instruction_expected_in_prologue(bytes: &[u8]) -> bool {
if bytes.len() < 4 {
return false;
}
if bytes[0] & 0xf8 == 0x50 {
return true;
}
if bytes[0] & 0xfe == 0x40 && bytes[1] & 0xf8 == 0x50 {
return true;
}
if bytes[0..2] == [0x83, 0xec] {
return true;
}
if bytes[0..3] == [0x48, 0x83, 0xec] {
return true;
}
if bytes[0..2] == [0x81, 0xec] {
return true;
}
if bytes[0..3] == [0x48, 0x81, 0xec] {
return true;
}
if bytes[0..3] == [0x48, 0x89, 0xe5] {
return true;
}
false
}