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 /// The header holds the trailer sentinel; the partition-table head was
22 /// resolved from a file trailer (surfaced for information only).
23 TrailerResolved {
24 /// Offset of the resolved trailer.
25 trailer_offset: u64,
26 /// Partition-table head recorded in the trailer (0 = empty).
27 head: u64,
28 /// Whether the trailer flags the chain as backward-linked.
29 backward: bool,
30 },
31 /// A partition's stored `data_hash` does not match its bytes.
32 DataHashMismatch { uid: [u8; 16] },
33 /// A table block's stored `table_hash` does not match its bytes.
34 TableHashMismatch { block_index: usize },
35 /// A live entry failed the PCF conformance checks.
36 EntryInvalid { uid: [u8; 16], reason: String },
37 /// The file header could not be parsed.
38 BadHeader { reason: String },
39 /// A table block header could not be parsed.
40 BadBlock { offset: u64, reason: String },
41}
42
43/// How serious a [`Diagnostic`] is.
44#[derive(Debug, Clone, Copy, PartialEq, Eq)]
45pub enum Severity {
46 Info,
47 Warning,
48 Error,
49}
50
51impl Severity {
52 /// Short uppercase tag used in text output.
53 pub fn tag(self) -> &'static str {
54 match self {
55 Severity::Info => "INFO",
56 Severity::Warning => "WARN",
57 Severity::Error => "ERROR",
58 }
59 }
60}
61
62/// One finding about a file.
63#[derive(Debug, Clone)]
64pub struct Diagnostic {
65 pub severity: Severity,
66 pub kind: DiagKind,
67 pub message: String,
68}
69
70impl Diagnostic {
71 pub fn info(kind: DiagKind, message: impl Into<String>) -> Self {
72 Self {
73 severity: Severity::Info,
74 kind,
75 message: message.into(),
76 }
77 }
78 pub fn warn(kind: DiagKind, message: impl Into<String>) -> Self {
79 Self {
80 severity: Severity::Warning,
81 kind,
82 message: message.into(),
83 }
84 }
85 pub fn error(kind: DiagKind, message: impl Into<String>) -> Self {
86 Self {
87 severity: Severity::Error,
88 kind,
89 message: message.into(),
90 }
91 }
92}