pcf_debug/model/diag.rs
1//! Diagnostics produced while walking and modelling a PCF file.
2//!
3//! A debugger must describe broken files, not reject them. Every structural
4//! anomaly we can detect is captured here as a [`Diagnostic`] rather than an
5//! error that aborts the walk.
6
7/// The class of an anomaly found in a file.
8#[derive(Debug, Clone, PartialEq, Eq)]
9pub enum DiagKind {
10 /// Two physical regions cover overlapping bytes.
11 Overlap { start: u64, len: u64 },
12 /// A run of bytes covered by no region (dead space / padding).
13 Gap { start: u64, len: u64 },
14 /// A declared region runs past the end of the file.
15 Truncated { start: u64, want: u64, have: u64 },
16 /// The block chain links back to a block already visited.
17 ChainCycle { at_offset: u64 },
18 /// A `next_table_offset` points to an earlier offset (legal under the
19 /// PFS-MS append model, surfaced for information only).
20 BackwardChainLink { from: u64, to: u64 },
21 /// A partition's stored `data_hash` does not match its bytes.
22 DataHashMismatch { uid: [u8; 16] },
23 /// A table block's stored `table_hash` does not match its bytes.
24 TableHashMismatch { block_index: usize },
25 /// A live entry failed the PCF conformance checks.
26 EntryInvalid { uid: [u8; 16], reason: String },
27 /// The file header could not be parsed.
28 BadHeader { reason: String },
29 /// A table block header could not be parsed.
30 BadBlock { offset: u64, reason: String },
31}
32
33/// How serious a [`Diagnostic`] is.
34#[derive(Debug, Clone, Copy, PartialEq, Eq)]
35pub enum Severity {
36 Info,
37 Warning,
38 Error,
39}
40
41impl Severity {
42 /// Short uppercase tag used in text output.
43 pub fn tag(self) -> &'static str {
44 match self {
45 Severity::Info => "INFO",
46 Severity::Warning => "WARN",
47 Severity::Error => "ERROR",
48 }
49 }
50}
51
52/// One finding about a file.
53#[derive(Debug, Clone)]
54pub struct Diagnostic {
55 pub severity: Severity,
56 pub kind: DiagKind,
57 pub message: String,
58}
59
60impl Diagnostic {
61 pub fn info(kind: DiagKind, message: impl Into<String>) -> Self {
62 Self {
63 severity: Severity::Info,
64 kind,
65 message: message.into(),
66 }
67 }
68 pub fn warn(kind: DiagKind, message: impl Into<String>) -> Self {
69 Self {
70 severity: Severity::Warning,
71 kind,
72 message: message.into(),
73 }
74 }
75 pub fn error(kind: DiagKind, message: impl Into<String>) -> Self {
76 Self {
77 severity: Severity::Error,
78 kind,
79 message: message.into(),
80 }
81 }
82}