Skip to main content

intel_crashlog/
header.rs

1// Copyright (C) 2025 Intel Corporation
2// SPDX-License-Identifier: MIT
3
4//! Data structures used in the Crash Log record headers.
5
6#[cfg(feature = "collateral_manager")]
7use crate::collateral::{CollateralManager, CollateralTree, ItemPath, PVSS};
8use crate::errata::Errata;
9use crate::error::Error;
10use crate::node::Node;
11#[cfg(not(feature = "std"))]
12use alloc::{
13    fmt, format,
14    string::{String, ToString},
15    vec,
16    vec::Vec,
17};
18#[cfg(feature = "std")]
19use std::fmt;
20
21/// Lists all the Crash Log record types.
22///
23/// cbindgen:ignore
24pub mod record_types {
25    pub const PMC: u8 = 0x1;
26    pub const PMC_FW_TRACE: u8 = 0x2;
27    pub const PUNIT: u8 = 0x3;
28    pub const PCORE: u8 = 0x4;
29    pub const ECORE: u8 = 0x6;
30    pub const UNCORE: u8 = 0x8;
31    pub const PMC_TRACE: u8 = 0x11;
32    pub const TCSS: u8 = 0x16;
33    pub const PMC_RST: u8 = 0x17;
34    pub const PCODE: u8 = 0x19;
35    pub const CRASHLOG_AGENT: u8 = 0x1C;
36    pub const BOX: u8 = 0x3D;
37    pub const MCA: u8 = 0x3E;
38}
39
40#[derive(Debug, Default, Clone)]
41pub enum HeaderType {
42    Type0,
43    #[default]
44    Type1,
45    Type2 {
46        timestamp: u64,
47        agent_version: u32,
48        reason: u32,
49    },
50    Type3 {
51        timestamp: u64,
52        agent_version: u32,
53        reason: u32,
54        completion_status: u32,
55        collection_complete: bool,
56    },
57    Type4 {
58        timestamp: u64,
59        agent_version: u32,
60        reason: u32,
61        whoami: u32,
62        misc: u32,
63    },
64    Type5 {
65        timestamp: u64,
66        agent_version: u32,
67        reason: u32,
68        completion_status: u32,
69        collection_complete: bool,
70        error_status: u32,
71    },
72    Type6 {
73        timestamp: u64,
74        agent_version: u32,
75        reason: u32,
76        die_id: u8,
77        socket_id: u8,
78        completion_status_size: u16,
79        completion_status: Vec<u32>,
80        collection_complete: bool,
81    },
82
83    Type0LegacyServer {
84        timestamp: u64,
85        agent_version: u32,
86        reason: u32,
87        die_id: u8,
88        socket_id: u8,
89        completion_status: u32,
90        collection_complete: bool,
91    },
92
93    Type0LegacyGpu {
94        timestamp: u64,
95        agent_version: u32,
96        reason: u32,
97        completion_status: u32,
98        collection_complete: bool,
99    },
100}
101
102impl HeaderType {
103    fn type2_from_slice(slice: &[u8]) -> Option<Self> {
104        let timestamp = u64::from_le_bytes(slice.get(8..16)?.try_into().ok()?);
105        let agent_version = u32::from_le_bytes(slice.get(16..20)?.try_into().ok()?);
106        let reason = u32::from_le_bytes(slice.get(20..24)?.try_into().ok()?);
107
108        Some(HeaderType::Type2 {
109            timestamp,
110            agent_version,
111            reason,
112        })
113    }
114
115    fn type3_from_slice(slice: &[u8]) -> Option<Self> {
116        let timestamp = u64::from_le_bytes(slice.get(8..16)?.try_into().ok()?);
117        let agent_version = u32::from_le_bytes(slice.get(16..20)?.try_into().ok()?);
118        let reason = u32::from_le_bytes(slice.get(20..24)?.try_into().ok()?);
119        let cs_data = u32::from_le_bytes(slice.get(24..28)?.try_into().ok()?);
120        let completion_status = cs_data & 0x7FFFFFFF;
121        let collection_complete = (cs_data >> 31) != 0;
122
123        Some(HeaderType::Type3 {
124            timestamp,
125            agent_version,
126            reason,
127            completion_status,
128            collection_complete,
129        })
130    }
131
132    fn type4_from_slice(slice: &[u8]) -> Option<Self> {
133        let timestamp = u64::from_le_bytes(slice.get(8..16)?.try_into().ok()?);
134        let agent_version = u32::from_le_bytes(slice.get(16..20)?.try_into().ok()?);
135        let reason = u32::from_le_bytes(slice.get(20..24)?.try_into().ok()?);
136        let whoami = u32::from_le_bytes(slice.get(24..28)?.try_into().ok()?);
137        let misc = u32::from_le_bytes(slice.get(28..32)?.try_into().ok()?);
138
139        Some(HeaderType::Type4 {
140            timestamp,
141            agent_version,
142            reason,
143            whoami,
144            misc,
145        })
146    }
147
148    fn type5_from_slice(slice: &[u8]) -> Option<Self> {
149        let timestamp = u64::from_le_bytes(slice.get(8..16)?.try_into().ok()?);
150        let agent_version = u32::from_le_bytes(slice.get(16..20)?.try_into().ok()?);
151        let reason = u32::from_le_bytes(slice.get(20..24)?.try_into().ok()?);
152        let cs_data = u32::from_le_bytes(slice.get(24..28)?.try_into().ok()?);
153        let completion_status = cs_data & 0x7FFFFFFF;
154        let collection_complete = (cs_data >> 31) != 0;
155        let error_status = u32::from_le_bytes(slice.get(28..32)?.try_into().ok()?);
156
157        Some(HeaderType::Type5 {
158            timestamp,
159            agent_version,
160            reason,
161            completion_status,
162            collection_complete,
163            error_status,
164        })
165    }
166
167    fn type6_from_slice(slice: &[u8]) -> Option<Self> {
168        let timestamp = u64::from_le_bytes(slice.get(8..16)?.try_into().ok()?);
169        let agent_version = u32::from_le_bytes(slice.get(16..20)?.try_into().ok()?);
170        let reason = u32::from_le_bytes(slice.get(20..24)?.try_into().ok()?);
171        let die_skt_info = slice.get(24..28)?;
172
173        let die_id = die_skt_info[0];
174        let socket_id = die_skt_info[1];
175        let completion_status_size = u16::from_le_bytes(die_skt_info[2..4].try_into().ok()?) & 0x7F;
176        let collection_complete = (die_skt_info[3] & 0x80) != 0;
177
178        let completion_status = (0..completion_status_size)
179            .map(|dword| {
180                let index = (28 + dword * 4) as usize;
181                Some(u32::from_le_bytes(
182                    slice.get(index..index + 4)?.try_into().ok()?,
183                ))
184            })
185            .collect::<Option<Vec<u32>>>()?;
186
187        Some(HeaderType::Type6 {
188            timestamp,
189            agent_version,
190            reason,
191            die_id,
192            socket_id,
193            completion_status_size,
194            completion_status,
195            collection_complete,
196        })
197    }
198
199    fn type0_legacy_server_from_slice(slice: &[u8]) -> Option<Self> {
200        let reason = u32::from_le_bytes(slice.get(4..8)?.try_into().ok()?);
201        let timestamp = u64::from_le_bytes(slice.get(8..16)?.try_into().ok()?);
202        let agent_version = u32::from_le_bytes(slice.get(20..24)?.try_into().ok()?);
203        let socket_id = *slice.get(24)?;
204        let cs_data = u32::from_le_bytes(slice.get(28..32)?.try_into().ok()?);
205        let completion_status = cs_data & 0x7FFFFFFF;
206        let collection_complete = (cs_data >> 31) != 0;
207
208        // Encoded die_id
209        let revision = slice.first()?;
210        let die_idx = revision & 0x3;
211
212        let die_id = if ((revision >> 7) & 1) == 1 {
213            die_idx + 9
214        } else {
215            die_idx << 2
216        };
217
218        Some(HeaderType::Type0LegacyServer {
219            timestamp,
220            agent_version,
221            reason,
222            die_id,
223            socket_id,
224            completion_status,
225            collection_complete,
226        })
227    }
228
229    fn type0_legacy_gpu_from_slice(slice: &[u8]) -> Option<Self> {
230        let reason = u32::from_le_bytes(slice.get(4..8)?.try_into().ok()?);
231        let timestamp = u64::from_le_bytes(slice.get(8..16)?.try_into().ok()?);
232        let agent_version = u32::from_le_bytes(slice.get(20..24)?.try_into().ok()?);
233        let cs_data = u32::from_le_bytes(slice.get(28..32)?.try_into().ok()?);
234        let completion_status = cs_data & 0x7FFFFFFF;
235        let collection_complete = (cs_data >> 31) != 0;
236
237        Some(HeaderType::Type0LegacyGpu {
238            timestamp,
239            agent_version,
240            reason,
241            completion_status,
242            collection_complete,
243        })
244    }
245
246    pub fn from_slice(header_type_value: u16, slice: &[u8]) -> Result<Self, Error> {
247        match header_type_value {
248            0 => Ok(HeaderType::Type0),
249            1 => Ok(HeaderType::Type1),
250            2 => Self::type2_from_slice(slice).ok_or(Error::InvalidHeader),
251            3 => Self::type3_from_slice(slice).ok_or(Error::InvalidHeader),
252            4 => Self::type4_from_slice(slice).ok_or(Error::InvalidHeader),
253            5 => Self::type5_from_slice(slice).ok_or(Error::InvalidHeader),
254            6 => Self::type6_from_slice(slice).ok_or(Error::InvalidHeader),
255            type_value => Err(Error::InvalidHeaderType(type_value)),
256        }
257    }
258
259    pub fn from_slice_type0_legacy_server(slice: &[u8]) -> Result<Self, Error> {
260        Self::type0_legacy_server_from_slice(slice).ok_or(Error::InvalidHeader)
261    }
262
263    pub fn from_slice_type0_legacy_gpu(slice: &[u8]) -> Result<Self, Error> {
264        Self::type0_legacy_gpu_from_slice(slice).ok_or(Error::InvalidHeader)
265    }
266}
267
268/// Header of a Crash Log record
269#[derive(Debug, Default, Clone)]
270pub struct Header {
271    /// Version ID
272    pub version: Version,
273    /// Size of the record
274    pub size: RecordSize,
275    /// Optional fields
276    pub header_type: HeaderType,
277}
278
279impl Header {
280    /// Decodes a header of a raw Crash Log record.
281    pub fn from_slice(slice: &[u8]) -> Result<Option<Self>, Error> {
282        let Some(version) = Version::from_slice(slice) else {
283            // Termination marker
284            return Ok(None);
285        };
286        let errata = Errata::from_version(&version);
287
288        let size = if errata.type0_legacy_server || errata.type0_legacy_gpu {
289            RecordSize::from_slice_type0_legacy(slice).ok_or(Error::InvalidHeader)?
290        } else {
291            RecordSize::from_slice(slice).ok_or(Error::InvalidHeader)?
292        };
293
294        let header_type = if errata.type0_legacy_server {
295            HeaderType::from_slice_type0_legacy_server(slice)?
296        } else if errata.type0_legacy_gpu {
297            HeaderType::from_slice_type0_legacy_gpu(slice)?
298        } else {
299            HeaderType::from_slice(version.header_type, slice)?
300        };
301
302        Ok(Some(Header {
303            version,
304            size,
305            header_type,
306        }))
307    }
308
309    /// Returns the granularity of the record size fields in bytes
310    #[inline]
311    fn record_size_granularity(&self) -> usize {
312        if self.version.errata().core_record_size_bytes {
313            return 1;
314        }
315        4
316    }
317
318    /// Returns the size of the record in bytes.
319    #[inline]
320    pub fn record_size(&self) -> usize {
321        (self.size.record_size as usize + self.size.extended_record_size as usize)
322            * self.record_size_granularity()
323    }
324
325    /// Returns the offset of the extended record in bytes if present.
326    #[inline]
327    pub fn extended_record_offset(&self) -> Option<usize> {
328        if self.size.extended_record_size > 0 {
329            Some(self.size.record_size as usize * self.record_size_granularity())
330        } else {
331            None
332        }
333    }
334
335    /// Returns the size of the record in bytes.
336    #[inline]
337    pub fn revision(&self) -> u32 {
338        self.version.revision
339    }
340
341    /// Returns the product ID of the record.
342    #[inline]
343    pub fn product_id(&self) -> u32 {
344        self.version.product_id
345    }
346
347    /// Returns the Three-Letter Acronym associated to the product ID specified in the header.
348    #[cfg(feature = "collateral_manager")]
349    pub fn product<'a, T: CollateralTree>(
350        &self,
351        cm: &'a CollateralManager<T>,
352    ) -> Result<&'a str, Error> {
353        cm.target_info
354            .get(&self.product_id())
355            .map(|target_info| target_info.product.as_str())
356            .ok_or_else(|| Error::InvalidProductID(self.product_id()))
357    }
358
359    /// Returns the product variant associated to the product ID specified in the header.
360    #[cfg(feature = "collateral_manager")]
361    pub fn variant<'a, T: CollateralTree>(&self, cm: &'a CollateralManager<T>) -> Option<&'a str> {
362        cm.target_info
363            .get(&self.product_id())
364            .map(|target_info| target_info.variant.as_str())
365    }
366
367    /// Returns the ID of the socket that generated the record.
368    pub fn socket_id(&self) -> u8 {
369        match self.header_type {
370            HeaderType::Type6 { socket_id, .. } => socket_id,
371            HeaderType::Type0LegacyServer { socket_id, .. } => socket_id,
372            _ => 0,
373        }
374    }
375
376    /// Returns the ID of the die that generated the record.
377    pub fn die_id(&self) -> Option<u8> {
378        match self.header_type {
379            HeaderType::Type6 { die_id, .. } => Some(die_id),
380            HeaderType::Type0LegacyServer { die_id, .. } => Some(die_id),
381            _ => None,
382        }
383    }
384
385    /// Returns the name of the die that generated the record.
386    ///
387    /// This requires a [CollateralManager] as the die names are product-specific.
388    #[cfg(feature = "collateral_manager")]
389    pub fn die<'a, T: CollateralTree>(&self, cm: &'a CollateralManager<T>) -> Option<&'a str> {
390        self.get_die_name(&self.die_id()?, cm)
391    }
392
393    #[cfg(feature = "collateral_manager")]
394    pub(crate) fn get_die_name<'a, T: CollateralTree>(
395        &self,
396        die_id: &u8,
397        cm: &'a CollateralManager<T>,
398    ) -> Option<&'a str> {
399        let target_info = cm.target_info.get(&self.product_id())?;
400        let die_name = target_info.die_id.get(die_id)?;
401        Some(die_name)
402    }
403
404    /// Returns the type of the record.
405    pub fn record_type(&self) -> Result<&'static str, Error> {
406        self.version.record_type_as_str()
407    }
408
409    #[cfg(feature = "collateral_manager")]
410    pub(super) fn decode_definitions_paths<T: CollateralTree>(
411        &self,
412        cm: &CollateralManager<T>,
413    ) -> Result<Vec<ItemPath>, Error> {
414        let record_type = self.record_type()?;
415        let revision = self.revision().to_string();
416
417        Ok(if let Some(die) = self.die(cm) {
418            let die_id = die.trim_end_matches(char::is_numeric);
419            vec![ItemPath::new([
420                "decode-defs",
421                record_type,
422                die_id,
423                &revision,
424            ])]
425        } else {
426            vec![
427                ItemPath::new(["decode-defs", record_type, &revision]),
428                ItemPath::new(["decode-defs", record_type, "all"]),
429            ]
430        })
431    }
432
433    #[cfg(feature = "collateral_manager")]
434    /// Returns the [PVSS] associated to this header.
435    pub fn pvss<T: CollateralTree>(&self, cm: &CollateralManager<T>) -> Result<PVSS, Error> {
436        let product = match self.product(cm) {
437            Err(Error::InvalidProductID(0)) => "all",
438            res => res?,
439        };
440        let variant = self.variant(cm).unwrap_or("all");
441
442        Ok(PVSS {
443            product: product.into(),
444            variant: variant.into(),
445            ..PVSS::default()
446        })
447    }
448
449    /// Returns the size of the header in bytes.
450    pub fn header_size(&self) -> usize {
451        match self.header_type {
452            HeaderType::Type0 | HeaderType::Type1 => 8,
453            HeaderType::Type2 { .. } => 24,
454            HeaderType::Type3 { .. } => 28,
455            HeaderType::Type4 { .. } => 32,
456            HeaderType::Type5 { .. } => 32,
457            HeaderType::Type6 {
458                completion_status_size,
459                ..
460            } => 28 + completion_status_size as usize * 4,
461            HeaderType::Type0LegacyServer { .. } => 32,
462            HeaderType::Type0LegacyGpu { .. } => 32,
463        }
464    }
465
466    #[cfg(feature = "collateral_manager")]
467    pub(super) fn get_root_path_using_cm<T: CollateralTree>(
468        &self,
469        cm: &CollateralManager<T>,
470    ) -> Option<String> {
471        if let HeaderType::Type6 { socket_id, .. } | HeaderType::Type0LegacyServer { socket_id, .. } =
472            self.header_type
473            && let Some(die) = self.die(cm)
474        {
475            return Some(format!("processors.cpu{socket_id}.{die}"));
476        }
477
478        None
479    }
480
481    pub(super) fn get_root_path(&self) -> Option<String> {
482        if let HeaderType::Type6 {
483            socket_id, die_id, ..
484        }
485        | HeaderType::Type0LegacyServer {
486            socket_id, die_id, ..
487        } = self.header_type
488        {
489            return Some(format!("processors.cpu{socket_id}.die{die_id}"));
490        }
491
492        None
493    }
494}
495
496impl fmt::Display for Header {
497    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
498        let record_type = self.record_type().unwrap_or("RECORD");
499        let version = format!(
500            "product_id=0x{0:x}, record_type=0x{1:x}, revision=0x{2:x}",
501            self.version.product_id, self.version.record_type, self.version.revision
502        );
503        let header_type = match self.header_type {
504            HeaderType::Type6 {
505                socket_id, die_id, ..
506            }
507            | HeaderType::Type0LegacyServer {
508                socket_id, die_id, ..
509            } => {
510                format!("die_id={die_id}, socket_id={socket_id}")
511            }
512            _ => "..".to_string(),
513        };
514
515        write!(f, "{record_type} - ({version}, {header_type})")
516    }
517}
518
519/// Version of the Crash Log record
520#[derive(Clone, Debug, Default)]
521pub struct Version {
522    /// Revision of the record
523    pub revision: u32,
524    /// Type of the header
525    pub header_type: u16,
526    /// Product that generated the record
527    pub product_id: u32,
528    /// Type of the record
529    pub record_type: u8,
530    /// Indicates if the record has been consumed by IAFW
531    pub consumed: bool,
532    /// Integrity checker present
533    pub cldic: bool,
534}
535
536impl Version {
537    /// Creates a [Version] from the raw record
538    pub fn from_slice(slice: &[u8]) -> Option<Self> {
539        let version = u32::from_le_bytes(slice.get(0..4)?.try_into().ok()?);
540        log::trace!("Decoding record version: {:#x}", version);
541
542        if version == 0 || version == 0xdeadbeef {
543            // Termination marker
544            return None;
545        }
546
547        Some(Version {
548            cldic: (version >> 30) & 1 == 1,
549            consumed: (version >> 31) & 1 == 1,
550            revision: version & 0xFF,
551            header_type: ((version >> 8) & 0xF) as u16,
552            product_id: (version >> 12) & 0xFFF,
553            record_type: ((version >> 24) & 0x3F) as u8,
554        })
555    }
556
557    pub fn as_u32(&self) -> u32 {
558        ((self.consumed as u32) << 31)
559            | ((self.cldic as u32) << 30)
560            | ((self.record_type as u32) << 24)
561            | (self.product_id << 12)
562            | ((self.header_type as u32) << 8)
563            | self.revision
564    }
565
566    fn record_type_as_str(&self) -> Result<&'static str, Error> {
567        Ok(match self.record_type {
568            record_types::PMC => "PMC",
569            record_types::PMC_FW_TRACE => "PMC_FW_Trace",
570            record_types::PUNIT => "Punit",
571            record_types::PCORE => "PCORE",
572            record_types::ECORE => "ECORE",
573            record_types::UNCORE => "UNCORE",
574            record_types::PMC_TRACE => "PMC_TRACE",
575            record_types::TCSS => "TCSS",
576            record_types::PMC_RST => "PMC_RST",
577            record_types::PCODE => "PCODE",
578            record_types::CRASHLOG_AGENT => "CRASHLOG_AGENT",
579            record_types::BOX => "BOX",
580            record_types::MCA => "MCA",
581            rt => return Err(Error::InvalidRecordType(rt)),
582        })
583    }
584
585    pub fn errata(&self) -> Errata {
586        Errata::from_version(self)
587    }
588}
589
590impl fmt::Display for Version {
591    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
592        let record_type = self.record_type_as_str().unwrap_or("UNKNOWN");
593        write!(f, "{} revision {}", record_type, self.revision)
594    }
595}
596
597/// Size of the Crash Log record
598#[derive(Debug, Default, Clone)]
599pub struct RecordSize {
600    /// Size of the main section of the record in dwords
601    pub record_size: u16,
602    /// Size of the extended section of the record in dwords
603    pub extended_record_size: u16,
604}
605
606impl RecordSize {
607    /// Creates a [RecordSize] from the raw record
608    pub fn from_slice(slice: &[u8]) -> Option<Self> {
609        Some(RecordSize {
610            record_size: u16::from_le_bytes(slice.get(4..6)?.try_into().ok()?),
611            extended_record_size: u16::from_le_bytes(slice.get(6..8)?.try_into().ok()?),
612        })
613    }
614
615    /// Creates a [RecordSize] from the raw record of a product with legacy header type0
616    pub fn from_slice_type0_legacy(slice: &[u8]) -> Option<Self> {
617        Some(RecordSize {
618            record_size: u16::from_le_bytes(slice.get(16..18)?.try_into().ok()?),
619            extended_record_size: 0,
620        })
621    }
622}
623
624impl From<&RecordSize> for Node {
625    fn from(size: &RecordSize) -> Self {
626        let mut node = Node::section("record_size");
627        node.add(Node::field("record_size", size.record_size as u64));
628        node.add(Node::field(
629            "extended_record_size",
630            size.extended_record_size as u64,
631        ));
632        node
633    }
634}
635
636impl From<&Version> for Node {
637    fn from(version: &Version) -> Self {
638        let mut node = Node::field("version", version.as_u32() as u64);
639        node.add(Node::field("revision", version.revision as u64));
640        node.add(Node::field("header_type", version.header_type as u64));
641        node.add(Node::field("product_id", version.product_id as u64));
642        node.add(Node::field("record_type", version.record_type as u64));
643        node
644    }
645}
646
647impl From<&Header> for Node {
648    fn from(header: &Header) -> Self {
649        let mut node = Node::section("hdr");
650        node.add(Node::from(&header.version));
651        node.add(Node::from(&header.size));
652
653        match header.header_type {
654            HeaderType::Type2 {
655                timestamp,
656                agent_version,
657                reason,
658            } => {
659                node.add(Node::field("timestamp", timestamp));
660                node.add(Node::field("agent_version", agent_version as u64));
661                node.add(Node::field("reason", reason as u64));
662            }
663            HeaderType::Type3 {
664                timestamp,
665                agent_version,
666                reason,
667                completion_status,
668                collection_complete,
669            } => {
670                node.add(Node::field("timestamp", timestamp));
671                node.add(Node::field("agent_version", agent_version as u64));
672                node.add(Node::field("reason", reason as u64));
673
674                let mut completion_status_node = Node::section("completion_status");
675                completion_status_node
676                    .add(Node::field("completion_status", completion_status as u64));
677                completion_status_node.add(Node::field(
678                    "record_collection_completed",
679                    collection_complete as u64,
680                ));
681                node.add(completion_status_node);
682            }
683            HeaderType::Type4 {
684                timestamp,
685                agent_version,
686                reason,
687                whoami,
688                misc,
689            } => {
690                node.add(Node::field("timestamp", timestamp));
691                node.add(Node::field("agent_version", agent_version as u64));
692                node.add(Node::field("reason", reason as u64));
693                node.add(Node::field("whoami", whoami as u64));
694                node.add(Node::field("misc", misc as u64));
695            }
696            HeaderType::Type5 {
697                timestamp,
698                agent_version,
699                reason,
700                completion_status,
701                collection_complete,
702                error_status,
703            } => {
704                node.add(Node::field("timestamp", timestamp));
705                node.add(Node::field("agent_version", agent_version as u64));
706                node.add(Node::field("reason", reason as u64));
707                node.add(Node::field("error_status", error_status as u64));
708
709                let mut completion_status_node = Node::section("completion_status");
710                completion_status_node
711                    .add(Node::field("completion_status", completion_status as u64));
712                completion_status_node.add(Node::field(
713                    "record_collection_completed",
714                    collection_complete as u64,
715                ));
716                node.add(completion_status_node);
717            }
718            HeaderType::Type6 {
719                timestamp,
720                agent_version,
721                reason,
722                die_id,
723                socket_id,
724                ref completion_status,
725                completion_status_size,
726                collection_complete,
727            } => {
728                node.add(Node::field("timestamp", timestamp));
729                node.add(Node::field("agent_version", agent_version as u64));
730                node.add(Node::field("reason", reason as u64));
731                let mut die_skt_info = Node::section("die_skt_info");
732                die_skt_info.add(Node::field("die_id", die_id as u64));
733                die_skt_info.add(Node::field("socket_id", socket_id as u64));
734                die_skt_info.add(Node::field(
735                    "completion_status_size",
736                    completion_status_size as u64,
737                ));
738                die_skt_info.add(Node::field(
739                    "record_collection_completed",
740                    collection_complete as u64,
741                ));
742                node.add(die_skt_info);
743
744                for (i, completion_status) in completion_status.iter().enumerate() {
745                    node.add(Node::field(
746                        &format!("completion_status{i}"),
747                        *completion_status as u64,
748                    ));
749                }
750            }
751            HeaderType::Type0LegacyServer {
752                timestamp,
753                agent_version,
754                reason,
755                die_id,
756                socket_id,
757                completion_status,
758                collection_complete,
759            } => {
760                node.add(Node::field("timestamp", timestamp));
761                node.add(Node::field("agent_version", agent_version as u64));
762                node.add(Node::field("reason", reason as u64));
763                node.add(Node::field("die_id", die_id as u64));
764                node.add(Node::field("socket_id", socket_id as u64));
765                node.add(Node::field("completion_status", completion_status as u64));
766                node.add(Node::field(
767                    "record_collection_completed",
768                    collection_complete as u64,
769                ));
770            }
771            HeaderType::Type0LegacyGpu {
772                timestamp,
773                agent_version,
774                reason,
775                completion_status,
776                collection_complete,
777            } => {
778                node.add(Node::field("timestamp", timestamp));
779                node.add(Node::field("agent_version", agent_version as u64));
780                node.add(Node::field("reason", reason as u64));
781                node.add(Node::field("completion_status", completion_status as u64));
782                node.add(Node::field(
783                    "record_collection_completed",
784                    collection_complete as u64,
785                ));
786            }
787            _ => (),
788        }
789
790        node
791    }
792}