| 204 | } |
| 205 | |
| 206 | fn decode_one<'a>(bytes: &mut &'a [u8]) -> Result<Event<'a>> { |
| 207 | match bytes.split_first().unwrap() { |
| 208 | (&ID_FUNCTION, rest) => { |
| 209 | let (addr, rest) = rest |
| 210 | .split_first_chunk() |
| 211 | .ok_or_else(|| anyhow!("invalid addr"))?; |
| 212 | let addr = u64::from_le_bytes(*addr); |
| 213 | |
| 214 | let (name_len, rest) = rest |
| 215 | .split_first_chunk() |
| 216 | .ok_or_else(|| anyhow!("invalid name byte len"))?; |
| 217 | let name_len = u32::from_le_bytes(*name_len); |
| 218 | let (name, rest) = rest |
| 219 | .split_at_checked(name_len as usize) |
| 220 | .ok_or_else(|| anyhow!("invalid name contents"))?; |
| 221 | let name = std::str::from_utf8(name)?; |
| 222 | |
| 223 | let (body_len, rest) = rest |
| 224 | .split_first_chunk() |
| 225 | .ok_or_else(|| anyhow!("invalid body byte len"))?; |
| 226 | let body_len = u32::from_le_bytes(*body_len); |
| 227 | let (body, rest) = rest |
| 228 | .split_at_checked(body_len as usize) |
| 229 | .ok_or_else(|| anyhow!("invalid body contents"))?; |
| 230 | |
| 231 | *bytes = rest; |
| 232 | Ok(Event::Function(addr, name, body)) |
| 233 | } |
| 234 | |
| 235 | (&ID_SAMPLES, rest) => { |
| 236 | let (samples, rest) = rest |
| 237 | .split_first_chunk() |
| 238 | .ok_or_else(|| anyhow!("invalid sample count"))?; |
| 239 | let samples = u32::from_le_bytes(*samples); |
| 240 | let (samples, rest) = rest |
| 241 | .split_at_checked(samples as usize * 8) |
| 242 | .ok_or_else(|| anyhow!("invalid sample data"))?; |
| 243 | *bytes = rest; |
| 244 | |
| 245 | let (before, mid, after) = unsafe { samples.align_to::<SamplePc>() }; |
| 246 | if !before.is_empty() || !after.is_empty() { |
| 247 | bail!("invalid sample data contents"); |
| 248 | } |
| 249 | Ok(Event::Samples(mid)) |
| 250 | } |
| 251 | |
| 252 | _ => bail!("unknown ID in profile"), |
| 253 | } |
| 254 | } |