diff --git a/lib/src/lib.rs b/lib/src/lib.rs index 7129efd..d191a2d 100644 --- a/lib/src/lib.rs +++ b/lib/src/lib.rs @@ -82,11 +82,13 @@ //! let nodes = crashlog.decode(&mut cm); //! //! // Get the status register of the fourth MCA bank from the register tree. -//! let status = nodes.get_by_path("core0.thread.arch_state.mca.bank3.status").unwrap(); +//! let status = nodes.get_by_path( +//! "pcore.core0.thread0.thread.arch_state.mca.bank3.status" +//! ).unwrap(); //! assert_eq!(status.kind, NodeType::Field { value: 0xbe000000e1840400 }); //! //! // Get the instruction pointer of the first core. -//! let lip = nodes.get_by_path("core0.thread.arch_state.lip").unwrap(); +//! let lip = nodes.get_by_path("pcore.core0.thread0.thread.arch_state.lip").unwrap(); //! assert_eq!(lip.kind, NodeType::Field { value: 0xfffff80577036530 }); //! ``` //! diff --git a/lib/src/node.rs b/lib/src/node.rs index 8e74006..92d09e6 100644 --- a/lib/src/node.rs +++ b/lib/src/node.rs @@ -177,6 +177,46 @@ impl Node { Some(ptr) } + /// Returns the value associated to the node if present. + /// + /// # Examples + /// + /// ``` + /// use intel_crashlog::prelude::*; + /// + /// let field = Node::field("foo", 42); + /// assert_eq!(field.value(), Some(42)); + /// let section = Node::section("bar"); + /// assert_eq!(section.value(), None); + /// ``` + pub fn value(&self) -> Option { + if let NodeType::Field { value } = self.kind { + Some(value) + } else { + None + } + } + + /// Returns the value of the field stored at the given path. + /// + /// # Examples + /// + /// ``` + /// use intel_crashlog::prelude::*; + /// + /// let mut foo = Node::section("foo"); + /// foo.add(Node::field("bar", 42)); + /// let mut root = Node::root(); + /// root.add(foo); + /// + /// assert_eq!(root.get_value_by_path("foo.bar"), Some(42)); + /// assert_eq!(root.get_value_by_path("foo"), None); + /// assert_eq!(root.get_value_by_path("foo.baz"), None); + /// ``` + pub fn get_value_by_path(&self, path: &str) -> Option { + self.get_by_path(path).and_then(|node| node.value()) + } + fn merge_instance(&mut self, mut other: Node) { let mut instance = 0; let name = other.name.clone(); diff --git a/lib/src/record/core.rs b/lib/src/record/core.rs index 46fd0bf..410903b 100644 --- a/lib/src/record/core.rs +++ b/lib/src/record/core.rs @@ -5,7 +5,7 @@ use super::Record; use crate::Error; #[cfg(feature = "collateral_manager")] use crate::collateral::{CollateralManager, CollateralTree}; -use crate::node::{Node, NodeType}; +use crate::node::Node; #[cfg(not(feature = "std"))] use alloc::format; @@ -15,33 +15,43 @@ impl Record { &self, cm: &mut CollateralManager, ) -> Result { - let mut section = Node::section("core"); - - for decode_def in ["layout_thread.csv", "layout_core.csv"] { - if let Ok(thread) = self.decode_with_decode_def(cm, decode_def, 0) { - let core_id = thread - .children() - .next() - .and_then(|child| child.get_by_path("hdr.whoami.core_id")) - .map(|core_id| &core_id.kind); - if let Some(NodeType::Field { value }) = core_id { - section.name = format!("core{value}"); - } - section.merge(thread); - } - } + let mut section = Node::section(self.header.record_type()?); + + for subsection_name in ["thread", "core"] { + let decode_def = format!("layout_{subsection_name}.csv"); + let Ok(mut root) = self.decode_with_decode_def(cm, &decode_def, 0) else { + continue; + }; - if let Some(offset) = self.header.extended_record_offset() { - for decode_def in ["layout_sq.csv", "layout_module.csv"] { - if let Ok(node) = self.decode_with_decode_def(cm, decode_def, offset) { - section.merge(node); + if let Some(offset) = self.header.extended_record_offset() { + for decode_def in ["layout_sq.csv", "layout_module.csv"] { + let Ok(extension) = self.decode_with_decode_def(cm, decode_def, offset) else { + continue; + }; + + root.merge(extension); break; } } + + let Some(subsection) = root.get(subsection_name) else { + continue; + }; + let hierarchy = ["module", "core", "thread"] + .into_iter() + .filter_map(|level| { + subsection + .get_value_by_path(&format!("hdr.whoami.{level}_id")) + .map(|id| format!("{level}{id}")) + }); + + section.create_hierarchy_from_iter(hierarchy).merge(root); + + let mut root = Node::root(); + root.add(section); + return Ok(root); } - let mut root = Node::root(); - root.add(section); - Ok(root) + Err(Error::MissingDecodeDefinitions(self.header.version.clone())) } } diff --git a/lib/tests/core.rs b/lib/tests/core.rs index 9bbf7fa..2a4e9b0 100644 --- a/lib/tests/core.rs +++ b/lib/tests/core.rs @@ -11,7 +11,7 @@ fn lnc_three_strike_timeout() { let nodes = crashlog.decode(&mut cm); let status = nodes - .get_by_path("core0.thread.arch_state.mca.bank3.status") + .get_by_path("pcore.core0.thread0.thread.arch_state.mca.bank3.status") .unwrap(); assert_eq!( status.kind, @@ -20,7 +20,9 @@ fn lnc_three_strike_timeout() { } ); - let lip = nodes.get_by_path("core0.thread.arch_state.lip").unwrap(); + let lip = nodes + .get_by_path("pcore.core0.thread0.thread.arch_state.lip") + .unwrap(); assert_eq!( lip.kind, NodeType::Field { @@ -28,7 +30,7 @@ fn lnc_three_strike_timeout() { } ); - let entry = nodes.get_by_path("core0.sq.entry0").unwrap(); + let entry = nodes.get_by_path("pcore.core0.thread0.sq.entry0").unwrap(); assert_eq!( entry.kind, NodeType::Field { diff --git a/lib/tests/crashlog.rs b/lib/tests/crashlog.rs index d0a0636..c984690 100644 --- a/lib/tests/crashlog.rs +++ b/lib/tests/crashlog.rs @@ -46,7 +46,7 @@ fn core_box_header_type6() { let root = crashlog.decode(&mut cm); let entry0 = root - .get_by_path("processors.cpu0.die8.core0.sq.entry0") + .get_by_path("processors.cpu0.die8.pcore.core0.thread0.sq.entry0") .unwrap(); assert_eq!( @@ -62,7 +62,7 @@ fn core_box_header_type6() { assert_eq!(record_type_box.kind, NodeType::Field { value: 0x3d }); let bank3 = root - .get_by_path("processors.cpu0.die8.core0.thread.arch_state.mca.bank3.status") + .get_by_path("processors.cpu0.die8.pcore.core0.thread0.thread.arch_state.mca.bank3.status") .unwrap(); assert_eq!(