intel_crashlog/
crashlog.rs1use crate::Error;
5use crate::bert::{Berr, Bert};
6#[cfg(feature = "collateral_manager")]
7use crate::collateral::{CollateralManager, CollateralTree};
8use crate::cper::{Cper, CperSectionBody};
9use crate::metadata::Metadata;
10use crate::node::Node;
11use crate::region::Region;
12#[cfg(not(feature = "std"))]
13use alloc::{collections::VecDeque, vec, vec::Vec};
14#[cfg(feature = "std")]
15use std::collections::VecDeque;
16
17use crate::header::record_types;
18
19#[derive(Default)]
21pub struct CrashLog {
22 pub regions: Vec<Region>,
24 pub metadata: Metadata,
26}
27
28impl CrashLog {
29 pub(crate) fn from_regions(regions: Vec<Region>) -> Result<Self, Error> {
30 let mut queue = VecDeque::from(regions);
31 let mut regions = Vec::new();
32
33 while let Some(region) = queue.pop_front() {
34 for record in region.records.iter() {
35 let errata = record.header.version.into_errata();
36 let is_box = record.header.version.record_type == record_types::BOX
37 || errata.type0_legacy_server_box;
38
39 if !is_box {
40 continue;
41 }
42
43 let Some(payload) = record.data.get(record.header.header_size()..) else {
44 log::error!("The Box record has an empty payload");
45 continue;
46 };
47
48 match Region::from_slice(payload) {
49 Ok(mut region) => {
50 region.set_child_context(&record.header);
51 queue.push_front(region)
52 }
53 Err(err) => log::warn!("Invalid region in Box record: {err}"),
54 }
55 }
56
57 regions.push(region)
58 }
59
60 if regions.is_empty() {
61 return Err(Error::InvalidCrashLog);
62 }
63
64 Ok(CrashLog {
65 regions,
66 ..CrashLog::default()
67 })
68 }
69
70 pub(crate) fn from_berr(berr: Berr) -> Result<Self, Error> {
72 let regions = berr
73 .entries
74 .iter()
75 .filter_map(|entry| Region::from_cper_section(&entry.cper_section))
76 .collect();
77 CrashLog::from_regions(regions)
78 }
79
80 #[cfg(any(all(target_os = "windows", feature = "extraction"), doc))]
81 pub fn from_windows_event_logs(path: Option<&std::path::Path>) -> Result<Vec<Self>, Error> {
85 Self::from_event_logs(path).map_err(|err| {
86 log::error!("Error while accessing windows event logs: {err}");
87 Error::InternalError
88 })
89 }
90
91 pub(crate) fn from_cper(cper: Cper) -> Result<Self, Error> {
93 let mut regions: Vec<Region> = Vec::new();
94 let mut extra_cper_sections: Vec<CperSectionBody> = Vec::new();
95
96 for section in cper.sections {
97 if let Some(region) = Region::from_cper_section(§ion.body) {
98 regions.push(region);
99 } else {
100 extra_cper_sections.push(section.body);
101 }
102 }
103
104 if regions.is_empty() {
105 return Err(Error::NoCrashLogFound);
106 }
107
108 let mut crashlog = CrashLog::from_regions(regions)?;
109 crashlog.metadata.extra_cper_sections = extra_cper_sections;
110 Ok(crashlog)
111 }
112
113 pub fn from_slice(s: &[u8]) -> Result<Self, Error> {
115 if let Some(berr) = Berr::from_bert_file(s) {
116 CrashLog::from_berr(berr)
117 } else if let Some(cper) = Cper::from_slice(s) {
118 CrashLog::from_cper(cper)
119 } else {
120 CrashLog::from_regions(vec![Region::from_slice(s)?])
122 }
123 }
124
125 pub fn to_bert(&self) -> Vec<u8> {
127 let mut berr = Berr::from_crashlog(self).to_bytes();
128 let bert = Bert {
129 region: 0,
130 region_length: berr.len() as u32,
131 ..Bert::dummy()
132 };
133
134 let mut bytes = bert.to_bytes();
135 bytes.append(&mut berr);
136 bytes
137 }
138
139 pub fn to_bytes(&self) -> Vec<u8> {
142 Cper::from_raw_crashlog(self).to_bytes()
143 }
144
145 pub fn decode_without_cm(&self) -> Node {
147 let mut root = Node::root();
148 for region in self.regions.iter() {
149 for record in region.records.iter() {
150 root.merge(record.decode_without_cm())
151 }
152 }
153 root
154 }
155
156 #[cfg(feature = "collateral_manager")]
158 pub fn decode<T: CollateralTree>(&self, cm: &mut CollateralManager<T>) -> Node {
159 let mut root = Node::root();
160 for region in self.regions.iter() {
161 for record in region.records.iter() {
162 root.merge(record.decode(cm))
163 }
164 }
165 root
166 }
167}