1use thiserror::Error;
9
10pub mod v1;
11pub mod v2;
12pub mod v3;
13
14#[macro_export]
15macro_rules! read_binary {
16 ($data: expr, $le: expr, $ty: ident, $offset: expr) => {{
17 let data_offset = $offset;
18 let mut data_bytes: [u8; core::mem::size_of::<$ty>()] = [0; core::mem::size_of::<$ty>()];
19 data_bytes.copy_from_slice(&$data[data_offset..data_offset + core::mem::size_of::<$ty>()]);
20 if $le {
21 $ty::from_le_bytes(data_bytes)
22 } else {
23 $ty::from_be_bytes(data_bytes)
24 }
25 }};
26}
27
28#[macro_export]
29macro_rules! read_struct {
30 ($struct: ident, $data: expr, $le: expr, $x: ident, $ty: ident) => {{ read_binary!($data, $le, $ty, core::mem::offset_of!($struct, $x)) }};
31}
32
33pub type SFrameResult<T> = core::result::Result<T, SFrameError>;
35
36#[derive(Debug, Clone, Copy)]
40#[allow(dead_code)]
41pub enum SFrameSection<'a> {
42 V1(v1::SFrameSection<'a>),
43 V2(v2::SFrameSection<'a>),
44 V3(v3::SFrameSection<'a>),
45}
46
47const SFRAME_MAGIC: u16 = 0xdee2;
49
50#[repr(C, packed)]
54struct RawSFramePreamble {
55 magic: u16,
56 version: u8,
57 flags: u8,
58}
59
60impl<'a> SFrameSection<'a> {
61 pub fn to_string(&self) -> SFrameResult<String> {
63 match self {
64 SFrameSection::V1(sframe_section) => sframe_section.to_string(),
65 SFrameSection::V2(sframe_section) => sframe_section.to_string(),
66 SFrameSection::V3(sframe_section) => sframe_section.to_string(),
67 }
68 }
69 pub fn from(data: &'a [u8], section_base: u64) -> SFrameResult<SFrameSection<'a>> {
71 if data.len() < core::mem::size_of::<RawSFramePreamble>() {
73 return Err(SFrameError::UnexpectedEndOfData);
74 }
75
76 let magic_offset = core::mem::offset_of!(RawSFramePreamble, magic);
78 let mut magic_bytes: [u8; 2] = [0; 2];
79 magic_bytes.copy_from_slice(&data[magic_offset..magic_offset + 2]);
80 let magic_le = u16::from_le_bytes(magic_bytes);
81 if magic_le != SFRAME_MAGIC {
82 let magic_be = u16::from_be_bytes(magic_bytes);
83 if magic_be != SFRAME_MAGIC {
84 return Err(SFrameError::InvalidMagic);
85 }
86 }
87
88 let version_offset = core::mem::offset_of!(RawSFramePreamble, version);
90 let version = data[version_offset];
91 match version {
92 1 => Ok(SFrameSection::V1(v1::SFrameSection::from(
93 data,
94 section_base,
95 )?)),
96 2 => Ok(SFrameSection::V2(v2::SFrameSection::from(
97 data,
98 section_base,
99 )?)),
100 3 => Ok(SFrameSection::V3(v3::SFrameSection::from(
101 data,
102 section_base,
103 )?)),
104 _ => Err(SFrameError::UnsupportedVersion),
105 }
106 }
107
108 pub fn find_fde(&self, pc: u64) -> SFrameResult<Option<SFrameFDE>> {
109 match self {
110 SFrameSection::V1(sframe_section) => {
111 Ok(sframe_section.find_fde(pc)?.map(SFrameFDE::V1))
112 }
113 SFrameSection::V2(sframe_section) => {
114 Ok(sframe_section.find_fde(pc)?.map(SFrameFDE::V2))
115 }
116 SFrameSection::V3(sframe_section) => {
117 Ok(sframe_section.find_fde(pc)?.map(SFrameFDE::V3))
118 }
119 }
120 }
121}
122
123#[derive(Debug, Clone, Copy)]
127#[allow(dead_code)]
128pub enum SFrameFDE {
129 V1(v1::SFrameFDE),
130 V2(v2::SFrameFDE),
131 V3(v3::SFrameFDE),
132}
133
134impl SFrameFDE {
135 pub fn find_fre(
137 &self,
138 section: &SFrameSection<'_>,
139 pc: u64,
140 ) -> SFrameResult<Option<SFrameFRE>> {
141 match (self, section) {
142 (SFrameFDE::V1(sframe_fde), SFrameSection::V1(sframe_section)) => {
143 Ok(sframe_fde.find_fre(sframe_section, pc)?.map(SFrameFRE::V1))
144 }
145 (SFrameFDE::V2(sframe_fde), SFrameSection::V2(sframe_section)) => {
146 Ok(sframe_fde.find_fre(sframe_section, pc)?.map(SFrameFRE::V2))
147 }
148 (SFrameFDE::V3(sframe_fde), SFrameSection::V3(sframe_section)) => {
149 Ok(sframe_fde.find_fre(sframe_section, pc)?.map(SFrameFRE::V3))
150 }
151 _ => Err(SFrameError::UnsupportedVersion),
152 }
153 }
154}
155
156#[derive(Debug, Clone)]
160#[allow(dead_code)]
161pub enum SFrameFRE {
162 V1(v1::SFrameFRE),
163 V2(v2::SFrameFRE),
164 V3(v3::SFrameFRE),
165}
166
167impl SFrameFRE {
168 pub fn get_cfa_base_reg_id(&self) -> u8 {
170 match self {
171 SFrameFRE::V1(sframe_fre) => sframe_fre.info.get_cfa_base_reg_id(),
172 SFrameFRE::V2(sframe_fre) => sframe_fre.info.get_cfa_base_reg_id(),
173 SFrameFRE::V3(sframe_fre) => sframe_fre.info.get_cfa_base_reg_id(),
174 }
175 }
176
177 pub fn get_cfa_offset(&self, section: &SFrameSection<'_>) -> SFrameResult<Option<i32>> {
179 match (self, section) {
180 (SFrameFRE::V1(sframe_fre), SFrameSection::V1(sframe_section)) => {
181 Ok(sframe_fre.get_cfa_offset(sframe_section))
182 }
183 (SFrameFRE::V2(sframe_fre), SFrameSection::V2(sframe_section)) => {
184 Ok(sframe_fre.get_cfa_offset(sframe_section))
185 }
186 (SFrameFRE::V3(sframe_fre), SFrameSection::V3(sframe_section)) => {
187 Ok(sframe_fre.get_cfa_offset(sframe_section))
188 }
189 _ => Err(SFrameError::UnsupportedVersion),
190 }
191 }
192
193 pub fn get_ra_offset(&self, section: &SFrameSection<'_>) -> SFrameResult<Option<i32>> {
195 match (self, section) {
196 (SFrameFRE::V1(sframe_fre), SFrameSection::V1(sframe_section)) => {
197 Ok(sframe_fre.get_ra_offset(sframe_section))
198 }
199 (SFrameFRE::V2(sframe_fre), SFrameSection::V2(sframe_section)) => {
200 Ok(sframe_fre.get_ra_offset(sframe_section))
201 }
202 (SFrameFRE::V3(sframe_fre), SFrameSection::V3(sframe_section)) => {
203 Ok(sframe_fre.get_ra_offset(sframe_section))
204 }
205 _ => Err(SFrameError::UnsupportedVersion),
206 }
207 }
208
209 pub fn get_fp_offset(&self, section: &SFrameSection<'_>) -> SFrameResult<Option<i32>> {
211 match (self, section) {
212 (SFrameFRE::V1(sframe_fre), SFrameSection::V1(sframe_section)) => {
213 Ok(sframe_fre.get_fp_offset(sframe_section))
214 }
215 (SFrameFRE::V2(sframe_fre), SFrameSection::V2(sframe_section)) => {
216 Ok(sframe_fre.get_fp_offset(sframe_section))
217 }
218 (SFrameFRE::V3(sframe_fre), SFrameSection::V3(sframe_section)) => {
219 Ok(sframe_fre.get_fp_offset(sframe_section))
220 }
221 _ => Err(SFrameError::UnsupportedVersion),
222 }
223 }
224}
225
226#[derive(Error, Debug)]
228pub enum SFrameError {
229 #[error("format error")]
231 Fmt(#[from] core::fmt::Error),
232 #[error("unexpected end of data")]
234 UnexpectedEndOfData,
235 #[error("invalid magic number")]
237 InvalidMagic,
238 #[error("unsupported version")]
240 UnsupportedVersion,
241 #[error("unsupported flags")]
243 UnsupportedFlags,
244 #[error("unsupported abi")]
246 UnsupportedABI,
247 #[error("unsupported fde type")]
249 UnsupportedFDEType,
250 #[error("unsupported fre type")]
252 UnsupportedFREType,
253 #[error("unsupported fre stack offset size")]
255 UnsupportedFREStackOffsetSize,
256 #[error("unsupported fre data word size")]
258 UnsupportedFREDataWordSize,
259}