macho_unwind_info/opcodes/
x86.rs1use std::fmt::Display;
2
3use super::bitfield::OpcodeBitfield;
4use super::permutation::decode_permutation_6;
5use crate::consts::*;
6
7#[derive(Copy, Clone, Debug, PartialEq, Eq)]
8pub enum RegisterNameX86 {
9 Ebx,
10 Ecx,
11 Edx,
12 Edi,
13 Esi,
14 Ebp,
15}
16
17impl RegisterNameX86 {
18 pub fn parse(n: u8) -> Option<Self> {
19 match n {
20 1 => Some(RegisterNameX86::Ebx),
21 2 => Some(RegisterNameX86::Ecx),
22 3 => Some(RegisterNameX86::Edx),
23 4 => Some(RegisterNameX86::Edi),
24 5 => Some(RegisterNameX86::Esi),
25 6 => Some(RegisterNameX86::Ebp),
26 _ => None,
27 }
28 }
29
30 pub fn dwarf_name(&self) -> &'static str {
31 match self {
32 RegisterNameX86::Ebx => "reg3",
33 RegisterNameX86::Ecx => "reg1",
34 RegisterNameX86::Edx => "reg2",
35 RegisterNameX86::Edi => "reg7",
36 RegisterNameX86::Esi => "reg6",
37 RegisterNameX86::Ebp => "reg5",
38 }
39 }
40}
41
42#[derive(Copy, Clone, Debug, PartialEq, Eq)]
43pub enum OpcodeX86 {
44 Null,
45 FrameBased {
46 stack_offset_in_bytes: u16,
47 saved_regs: [Option<RegisterNameX86>; 5],
48 },
49 FramelessImmediate {
50 stack_size_in_bytes: u16,
51 saved_regs: [Option<RegisterNameX86>; 6],
52 },
53 FramelessIndirect {
54 immediate_offset_from_function_start: u8,
58
59 stack_adjust_in_bytes: u8,
67
68 saved_regs: [Option<RegisterNameX86>; 6],
73 },
74 Dwarf {
75 eh_frame_fde: u32,
76 },
77 InvalidFrameless,
78 UnrecognizedKind(u8),
79}
80
81impl OpcodeX86 {
82 pub fn parse(opcode: u32) -> Self {
83 match OpcodeBitfield::new(opcode).kind() {
84 OPCODE_KIND_NULL => OpcodeX86::Null,
85 OPCODE_KIND_X86_FRAMEBASED => OpcodeX86::FrameBased {
86 stack_offset_in_bytes: (((opcode >> 16) & 0xff) as u16) * 4,
87 saved_regs: [
88 RegisterNameX86::parse(((opcode >> 12) & 0b111) as u8),
89 RegisterNameX86::parse(((opcode >> 9) & 0b111) as u8),
90 RegisterNameX86::parse(((opcode >> 6) & 0b111) as u8),
91 RegisterNameX86::parse(((opcode >> 3) & 0b111) as u8),
92 RegisterNameX86::parse((opcode & 0b111) as u8),
93 ],
94 },
95 OPCODE_KIND_X86_FRAMELESS_IMMEDIATE => {
96 let stack_size_in_bytes = (((opcode >> 16) & 0xff) as u16) * 4;
97 let register_count = (opcode >> 10) & 0b111;
98 let register_permutation = opcode & 0b11_1111_1111;
99 let saved_registers =
100 match decode_permutation_6(register_count, register_permutation) {
101 Ok(regs) => regs,
102 Err(_) => return OpcodeX86::InvalidFrameless,
103 };
104 OpcodeX86::FramelessImmediate {
105 stack_size_in_bytes,
106 saved_regs: [
107 RegisterNameX86::parse(saved_registers[0]),
108 RegisterNameX86::parse(saved_registers[1]),
109 RegisterNameX86::parse(saved_registers[2]),
110 RegisterNameX86::parse(saved_registers[3]),
111 RegisterNameX86::parse(saved_registers[4]),
112 RegisterNameX86::parse(saved_registers[5]),
113 ],
114 }
115 }
116 OPCODE_KIND_X86_FRAMELESS_INDIRECT => {
117 let immediate_offset_from_function_start = (opcode >> 16) as u8;
118 let stack_adjust_in_bytes = ((opcode >> 13) & 0b111) as u8 * 4;
119 let register_count = (opcode >> 10) & 0b111;
120 let register_permutation = opcode & 0b11_1111_1111;
121 let saved_registers =
122 match decode_permutation_6(register_count, register_permutation) {
123 Ok(regs) => regs,
124 Err(_) => return OpcodeX86::InvalidFrameless,
125 };
126 OpcodeX86::FramelessIndirect {
127 immediate_offset_from_function_start,
128 stack_adjust_in_bytes,
129 saved_regs: [
130 RegisterNameX86::parse(saved_registers[0]),
131 RegisterNameX86::parse(saved_registers[1]),
132 RegisterNameX86::parse(saved_registers[2]),
133 RegisterNameX86::parse(saved_registers[3]),
134 RegisterNameX86::parse(saved_registers[4]),
135 RegisterNameX86::parse(saved_registers[5]),
136 ],
137 }
138 }
139 OPCODE_KIND_X86_DWARF => OpcodeX86::Dwarf {
140 eh_frame_fde: (opcode & 0xffffff),
141 },
142 kind => OpcodeX86::UnrecognizedKind(kind),
143 }
144 }
145}
146
147impl Display for OpcodeX86 {
148 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
149 match self {
150 OpcodeX86::Null => {
151 write!(f, "(uncovered)")?;
152 }
153 OpcodeX86::FrameBased {
154 stack_offset_in_bytes,
155 saved_regs,
156 } => {
157 write!(f, "CFA=reg6+8: reg6=[CFA-8], reg16=[CFA-4]")?;
160 let max_count = (*stack_offset_in_bytes / 4) as usize;
161 let mut offset = *stack_offset_in_bytes + 8; for reg in saved_regs.iter().rev().take(max_count) {
163 if let Some(reg) = reg {
164 write!(f, ", {}=[CFA-{}]", reg.dwarf_name(), offset)?;
165 }
166 offset -= 4;
167 }
168 }
169 OpcodeX86::FramelessImmediate {
170 stack_size_in_bytes,
171 saved_regs,
172 } => {
173 if *stack_size_in_bytes == 0 {
174 write!(f, "CFA=reg7:",)?;
175 } else {
176 write!(f, "CFA=reg7+{}:", *stack_size_in_bytes)?;
177 }
178 write!(f, " reg16=[CFA-4]")?;
179 let mut offset = 2 * 4;
180 for reg in saved_regs.iter().rev().flatten() {
181 write!(f, ", {}=[CFA-{}]", reg.dwarf_name(), offset)?;
182 offset += 4;
183 }
184 }
185 OpcodeX86::FramelessIndirect {
186 immediate_offset_from_function_start,
187 stack_adjust_in_bytes,
188 saved_regs,
189 } => {
190 write!(
191 f,
192 "CFA=[function_start+{}]+{}",
193 immediate_offset_from_function_start, stack_adjust_in_bytes
194 )?;
195 write!(f, " reg16=[CFA-4]")?;
196 let mut offset = 2 * 4;
197 for reg in saved_regs.iter().rev().flatten() {
198 write!(f, ", {}=[CFA-{}]", reg.dwarf_name(), offset)?;
199 offset += 4;
200 }
201 }
202 OpcodeX86::Dwarf { eh_frame_fde } => {
203 write!(f, "(check eh_frame FDE 0x{:x})", eh_frame_fde)?;
204 }
205 OpcodeX86::InvalidFrameless => {
206 write!(
207 f,
208 "!! frameless immediate or indirect with invalid permutation encoding"
209 )?;
210 }
211 OpcodeX86::UnrecognizedKind(kind) => {
212 write!(f, "!! Unrecognized kind {}", kind)?;
213 }
214 }
215 Ok(())
216 }
217}
218
219#[cfg(test)]
220mod test {
221 use super::*;
222
223 #[test]
224 fn test_frameless_indirect() {
225 use RegisterNameX86::*;
226 assert_eq!(
227 OpcodeX86::parse(0x30df800),
228 OpcodeX86::FramelessIndirect {
229 immediate_offset_from_function_start: 13,
230 stack_adjust_in_bytes: 28,
231 saved_regs: [
232 Some(Ebx),
233 Some(Ecx),
234 Some(Edx),
235 Some(Edi),
236 Some(Esi),
237 Some(Ebp)
238 ]
239 }
240 )
241 }
242}