Skip to main content

gsym/convert/
diagnostic.rs

1use std::fmt;
2
3use crate::AddressRange;
4
5/// Non-fatal issue observed while importing ELF or DWARF data.
6///
7/// A warning means some input was skipped and conversion continued, so a report
8/// carrying warnings is still usable. Anything that makes the whole conversion
9/// impossible is an [`Error`](crate::Error) instead.
10///
11/// All variants implement `Display`, so `{warning}` is enough for a log line.
12/// Matching specific variants needs a fallback arm.
13#[derive(Clone, Debug, Eq, PartialEq)]
14#[non_exhaustive]
15pub enum ConversionWarning {
16    /// Embedded mini-debug data was present but unusable.
17    EmbeddedDebugData {
18        /// Rejection reason.
19        reason: Box<str>,
20    },
21    /// A debuginfod request or cache operation failed.
22    Debuginfod {
23        /// Server or cache endpoint involved, when known.
24        endpoint: Option<Box<str>>,
25        /// Failure description.
26        reason: Box<str>,
27    },
28    /// Neither an individual DWO nor a packaged DWP supplied a skeleton unit.
29    SplitDwarfUnavailable {
30        /// Split-DWARF unit identifier.
31        dwo_id: u64,
32        /// Failures encountered while trying each source.
33        reasons: Box<[Box<str>]>,
34    },
35    /// Inline import was enabled but produced no valid inline records.
36    NoInlineRecords,
37    /// A DWARF range list contained malformed data.
38    MalformedRanges {
39        /// Whether parsing had to stop rather than skip one range.
40        stopped: bool,
41        /// Parser diagnostic.
42        reason: Box<str>,
43    },
44    /// A DWARF range was invalid or outside live executable code.
45    RejectedRange {
46        /// Rejected virtual-address range.
47        range: AddressRange,
48    },
49    /// `DW_AT_LLVM_stmt_sequence` did not identify a valid line sequence.
50    InvalidStatementSequence {
51        /// Absolute debug-info offset of the function DIE.
52        die_offset: u64,
53        /// Referenced line-program offset.
54        sequence_offset: u64,
55    },
56    /// Executed line sequences could not be paired with scanned offsets.
57    LineSequenceMismatch {
58        /// Number of executed line sequences.
59        sequences: usize,
60        /// Number of scanned sequence offsets.
61        offsets: usize,
62    },
63    /// A line row referenced a missing file-table entry.
64    MissingLineFile {
65        /// Row address.
66        address: u64,
67        /// Missing DWARF file index.
68        index: u64,
69    },
70    /// A line number could not fit the GSYM `u32` field.
71    UnrepresentableLine {
72        /// Row address.
73        address: u64,
74        /// Original DWARF line number.
75        line: u64,
76    },
77    /// An inline DIE referenced a missing call-site file.
78    MissingInlineCallFile {
79        /// Absolute debug-info offset of the inline DIE.
80        die_offset: u64,
81        /// Missing DWARF file index.
82        index: u64,
83    },
84    /// An inline call line could not fit the GSYM `u32` field.
85    InvalidInlineCallLine {
86        /// Absolute debug-info offset of the inline DIE.
87        die_offset: u64,
88        /// Original DWARF line number.
89        line: u64,
90    },
91    /// A declaration location referenced a missing file.
92    InvalidDeclarationFile {
93        /// Absolute debug-info offset of the function DIE.
94        die_offset: u64,
95        /// Missing DWARF file index.
96        index: u64,
97    },
98    /// A declaration line could not fit the GSYM `u32` field.
99    InvalidDeclarationLine {
100        /// Absolute debug-info offset of the function DIE.
101        die_offset: u64,
102        /// Original DWARF line number.
103        line: u64,
104    },
105}
106
107impl fmt::Display for ConversionWarning {
108    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
109        match self {
110            Self::EmbeddedDebugData { reason } => {
111                write!(formatter, "ignoring malformed .gnu_debugdata: {reason}")
112            }
113            Self::Debuginfod { endpoint, reason } => {
114                formatter.write_str("debuginfod")?;
115                if let Some(endpoint) = endpoint {
116                    write!(formatter, " {endpoint}")?;
117                }
118                write!(formatter, ": {reason}")
119            }
120            Self::SplitDwarfUnavailable { dwo_id, reasons } => {
121                write!(
122                    formatter,
123                    "split DWARF unit {dwo_id:#x} has no usable .dwo or .dwp data"
124                )?;
125                for (index, reason) in reasons.iter().enumerate() {
126                    formatter.write_str(if index == 0 { ": " } else { "; " })?;
127                    formatter.write_str(reason)?;
128                }
129                Ok(())
130            }
131            Self::NoInlineRecords => {
132                formatter.write_str("no valid DWARF inline records were found")
133            }
134            Self::MalformedRanges { stopped, reason } => write!(
135                formatter,
136                "{} malformed DWARF ranges: {reason}",
137                if *stopped { "stopped at" } else { "skipping" }
138            ),
139            Self::RejectedRange { range } => write!(
140                formatter,
141                "skipping non-live or invalid DWARF range {:#x}..{:#x}",
142                range.start, range.end
143            ),
144            Self::InvalidStatementSequence {
145                die_offset,
146                sequence_offset,
147            } => write!(
148                formatter,
149                "function DIE at {die_offset:#x} has an invalid DW_AT_LLVM_stmt_sequence value {sequence_offset:#x}; using matching rows from other sequences"
150            ),
151            Self::LineSequenceMismatch { sequences, offsets } => write!(
152                formatter,
153                "could not associate {sequences} line sequences with {offsets} statement-sequence offsets"
154            ),
155            Self::MissingLineFile { address, index } => write!(
156                formatter,
157                "ignoring DWARF line row at {address:#x} with missing file index {index}"
158            ),
159            Self::UnrepresentableLine { address, line } => write!(
160                formatter,
161                "ignoring DWARF line row at {address:#x} with unrepresentable line number {line}"
162            ),
163            Self::MissingInlineCallFile { die_offset, index } => write!(
164                formatter,
165                "inline DIE at {die_offset:#x} references missing DW_AT_call_file index {index}"
166            ),
167            Self::InvalidInlineCallLine { die_offset, line } => write!(
168                formatter,
169                "inline DIE at {die_offset:#x} has unrepresentable DW_AT_call_line value {line}"
170            ),
171            Self::InvalidDeclarationFile { die_offset, index } => write!(
172                formatter,
173                "function DIE at {die_offset:#x} has invalid DW_AT_decl_file index {index}"
174            ),
175            Self::InvalidDeclarationLine { die_offset, line } => write!(
176                formatter,
177                "function DIE at {die_offset:#x} has unrepresentable DW_AT_decl_line value {line}"
178            ),
179        }
180    }
181}