Skip to main content

intel_crashlog/
record.rs

1// Copyright (C) 2025 Intel Corporation
2// SPDX-License-Identifier: MIT
3
4//! Provides access to the content of a Crash Log record.
5
6mod core;
7mod decode;
8
9use crate::header::Header;
10#[cfg(not(feature = "std"))]
11use alloc::vec::Vec;
12
13/// A single Crash Log record
14#[derive(Default)]
15pub struct Record {
16    /// Header of the record
17    pub header: Header,
18    /// Raw content of the record
19    pub data: Vec<u8>,
20    /// Additional information provided to the record
21    pub context: Context,
22}
23
24/// Additional data provided to a Crash Log record
25#[derive(Clone, Default)]
26pub struct Context {
27    /// Header of the parent record
28    pub parent_header: Option<Header>,
29}
30
31impl Record {
32    pub fn payload(&self) -> &[u8] {
33        let begin = self.header.header_size();
34
35        // The last DWORD of the record is reserved for the checksum when the CLDIC bit is set
36        let end = self
37            .data
38            .len()
39            .saturating_sub(if self.header.version.cldic { 4 } else { 0 });
40
41        self.data.get(begin..end).unwrap_or_default()
42    }
43
44    pub fn checksum(&self) -> Option<bool> {
45        if !self.header.version.cldic {
46            return None;
47        }
48
49        let checksum = self
50            .data
51            .chunks(4)
52            .map(|dword_slice| u32::from_le_bytes(dword_slice.try_into().unwrap_or([0; 4])))
53            .fold(0, |acc: u32, dword| acc.wrapping_add(dword));
54
55        Some(checksum == 0)
56    }
57}
58
59#[cfg(test)]
60mod tests {
61    use super::*;
62    use crate::header::Version;
63
64    #[test]
65    fn payload() {
66        let record = Record {
67            data: (0..16).collect(),
68            ..Default::default()
69        };
70        assert_eq!(record.payload(), &[8, 9, 10, 11, 12, 13, 14, 15]);
71
72        let record_with_cldic = Record {
73            header: Header {
74                version: Version {
75                    cldic: true,
76                    ..Default::default()
77                },
78                ..Default::default()
79            },
80            data: (0..16).collect(),
81            ..Default::default()
82        };
83        assert_eq!(record_with_cldic.payload(), &[8, 9, 10, 11]);
84    }
85
86    #[test]
87    fn payload_with_invalid_header() {
88        let record = Record::default();
89        assert!(record.payload().is_empty());
90
91        let record_with_cldic = Record {
92            header: Header {
93                version: Version {
94                    cldic: true,
95                    ..Default::default()
96                },
97                ..Default::default()
98            },
99            ..Default::default()
100        };
101        assert!(record_with_cldic.payload().is_empty());
102    }
103}