samply_symbols/
error.rs

1use std::path::PathBuf;
2
3use debugid::DebugId;
4use linux_perf_data::jitdump::JitDumpError;
5use object::FileKind;
6use pdb_addr2line::pdb::Error as PdbError;
7use thiserror::Error;
8
9use crate::breakpad::BreakpadParseError;
10use crate::{CodeId, FatArchiveMember, LibraryInfo};
11
12/// The error type used in this crate.
13#[derive(Error, Debug)]
14#[non_exhaustive]
15pub enum Error {
16    #[error("Unmatched breakpad_id: Expected {0}, but received {1}")]
17    UnmatchedDebugId(DebugId, DebugId),
18
19    #[error("Unmatched breakpad_id: Expected {0}, but received {1:?}")]
20    UnmatchedDebugIdOptional(DebugId, Option<DebugId>),
21
22    #[error("Unmatched CodeId: Expected {0}, but received {recvd}", recvd=.1.as_ref().map_or("<none>".into(), ToString::to_string))]
23    UnmatchedCodeId(CodeId, Option<CodeId>),
24
25    #[error("The Breakpad sym file was malformed, causing a parsing error: {0}")]
26    BreakpadParsing(#[from] BreakpadParseError),
27
28    #[error("The JITDUMP file was malformed, causing a parsing error: {0}")]
29    JitDumpParsing(#[from] JitDumpError),
30
31    #[error("Invalid index {0} for file or inline_origin in breakpad sym file")]
32    InvalidFileOrInlineOriginIndexInBreakpadFile(u32),
33
34    #[error("Invalid breakpad ID {0}")]
35    InvalidBreakpadId(String),
36
37    #[error("Not enough information was supplied to identify the requested binary.")]
38    NotEnoughInformationToIdentifyBinary,
39
40    #[error("Could not determine the FileKind of the external file.")]
41    CouldNotDetermineExternalFileFileKind,
42
43    #[error("External file has an unexpected FileKind: {0:?}")]
44    UnexpectedExternalFileFileKind(FileKind),
45
46    #[error("Error parsing external archive file: {0}")]
47    ParseErrorInExternalArchive(#[source] object::read::Error),
48
49    #[error("Not enough information was supplied to identify the requested symbol map. The debug ID is required.")]
50    NotEnoughInformationToIdentifySymbolMap,
51
52    #[error("The FileLocation for the debug file does not support loading dyld subcache files.")]
53    FileLocationRefusedSubcacheLocation,
54
55    #[error("The FileLocation for the debug file does not support loading external objects.")]
56    FileLocationRefusedExternalObjectLocation,
57
58    #[error(
59        "The FileLocation for the binary file does not allow following the PDB path found in it."
60    )]
61    FileLocationRefusedPdbLocation,
62
63    #[error("The FileLocation for the debug file does not support loading source files.")]
64    FileLocationRefusedSourceFileLocation,
65
66    #[error(
67        "No disambiguator supplied for universal binary, available images: {}", format_multiarch_members(.0)
68    )]
69    NoDisambiguatorForFatArchive(Vec<FatArchiveMember>),
70
71    #[error("The universal binary (fat archive) was empty")]
72    EmptyFatArchive,
73
74    #[error("No match in multi-arch binary, available UUIDs: {}", format_multiarch_members(.0))]
75    NoMatchMultiArch(Vec<FatArchiveMember>),
76
77    #[error("Couldn't get symbols from system library, errors: {}", format_errors(.0))]
78    NoLuckMacOsSystemLibrary(Vec<Error>),
79
80    #[error("CRC mismatch on file found via GNU debug link, got {0}, expected {1}")]
81    DebugLinkCrcMismatch(u32, u32),
82
83    #[error("PDB error: {1} ({0})")]
84    PdbError(&'static str, PdbError),
85
86    #[error("pdb-addr2line error: {1} ({0})")]
87    PdbAddr2lineErrorWithContext(&'static str, #[source] pdb_addr2line::Error),
88
89    #[error("Invalid input: {0}")]
90    InvalidInputError(&'static str),
91
92    #[error("Object could not parse the file as {0:?}: {1}")]
93    ObjectParseError(object::read::FileKind, #[source] object::read::Error),
94
95    #[error("Dyld cache parsing error: {0}")]
96    DyldCacheParseError(#[source] object::read::Error),
97
98    #[error("The dyld shared cache file did not include an entry for the dylib at {0}")]
99    NoMatchingDyldCacheImagePath(String),
100
101    #[error("MachOHeader parsing error: {0}")]
102    MachOHeaderParseError(#[source] object::read::Error),
103
104    #[error("get_candidate_paths_for_debug_file helper callback for {0:?} returned error: {1}")]
105    HelperErrorDuringGetCandidatePathsForDebugFile(
106        Box<LibraryInfo>,
107        #[source] Box<dyn std::error::Error + Send + Sync>,
108    ),
109
110    #[error("get_candidate_paths_for_binary helper callback for returned error: {0}")]
111    HelperErrorDuringGetCandidatePathsForBinary(#[source] Box<dyn std::error::Error + Send + Sync>),
112
113    #[error("get_dyld_shared_cache_paths helper callback returned error: {0}")]
114    HelperErrorDuringGetDyldSharedCachePaths(#[source] Box<dyn std::error::Error + Send + Sync>),
115
116    #[error("open_file helper callback for file {0} returned error: {1}")]
117    HelperErrorDuringOpenFile(String, #[source] Box<dyn std::error::Error + Send + Sync>),
118
119    #[error("FileContents read_bytes_at for file {0} returned error: {1}")]
120    HelperErrorDuringFileReading(String, #[source] Box<dyn std::error::Error + Send + Sync>),
121
122    #[error("FileContents read_bytes_at during JITDUMP parsing returned error: {0}")]
123    JitDumpFileReading(#[source] std::io::Error),
124
125    #[error("No candidate path for binary, for {0:?} {1:?}")]
126    NoCandidatePathForBinary(Option<String>, Option<DebugId>),
127
128    #[error("No candidate path for dyld shared cache")]
129    NoCandidatePathForDyldCache,
130
131    #[error("No candidate path for binary, for {0:?}")]
132    NoCandidatePathForDebugFile(Box<LibraryInfo>),
133
134    #[error("All candidate paths encountered failures:\n{}", .0.iter().map(|e| e.to_string()).collect::<Vec<_>>().join("\n"))]
135    NoSuccessfulCandidate(Vec<Error>),
136
137    #[error("No associated PDB file with the right debug ID was found for the PE (Windows) binary at path {0}")]
138    NoMatchingPdbForBinary(String),
139
140    #[error("The PE (Windows) binary at path {0} did not contain information about an associated PDB file")]
141    NoDebugInfoInPeBinary(String),
142
143    #[error("In the PE (Windows) binary at path {0}, the embedded path to the PDB file was not valid utf-8.")]
144    PdbPathNotUtf8(String),
145
146    #[error("In the PE (Windows) binary, the embedded path to the PDB file did not end with a file name: {0}")]
147    PdbPathWithoutFilename(String),
148
149    #[error("Could not parse archive file at {0}, ArchiveFile::parse returned error: {1}.")]
150    ArchiveParseError(PathBuf, #[source] Box<dyn std::error::Error + Send + Sync>),
151
152    #[error("Could not find file {0} in the archive file.")]
153    FileNotInArchive(String),
154
155    #[error("Error while getting function info from PDB: {0}")]
156    PdbAddr2lineError(
157        #[from]
158        #[source]
159        pdb_addr2line::Error,
160    ),
161
162    #[error("Error while parsing srcsrv stream from PDB: {0}")]
163    SrcSrvParseError(
164        #[from]
165        #[source]
166        srcsrv::ParseError,
167    ),
168
169    #[error("Error while evaluating srcsrv entry PDB: {0}")]
170    SrcSrvEvalError(
171        #[from]
172        #[source]
173        srcsrv::EvalError,
174    ),
175
176    #[error("Could not create addr2line Context: {0}")]
177    Addr2lineContextCreationError(#[source] gimli::Error),
178}
179
180fn format_errors(errors: &[Error]) -> String {
181    errors
182        .iter()
183        .map(|e| format!("{e}"))
184        .collect::<Vec<String>>()
185        .join(", ")
186}
187
188fn format_multiarch_members(members: &[FatArchiveMember]) -> String {
189    members
190        .iter()
191        .map(|member| {
192            let uuid_string = member
193                .uuid
194                .map(|uuid| DebugId::from_uuid(uuid).breakpad().to_string());
195            format!(
196                "{} ({} {:08x}/{:08x})",
197                uuid_string.as_deref().unwrap_or("<no debug ID>"),
198                member.arch.as_deref().unwrap_or("<unrecognized arch>"),
199                member.cputype,
200                member.cpusubtype
201            )
202        })
203        .collect::<Vec<String>>()
204        .join(", ")
205}
206
207pub trait Context<T> {
208    fn context(self, context_description: &'static str) -> Result<T, Error>;
209}
210
211impl<T> Context<T> for std::result::Result<T, PdbError> {
212    fn context(self, context_description: &'static str) -> Result<T, Error> {
213        self.map_err(|e| Error::PdbError(context_description, e))
214    }
215}
216
217impl<T> Context<T> for std::result::Result<T, pdb_addr2line::Error> {
218    fn context(self, context_description: &'static str) -> Result<T, Error> {
219        self.map_err(|e| Error::PdbAddr2lineErrorWithContext(context_description, e))
220    }
221}
222
223impl From<PdbError> for Error {
224    fn from(err: PdbError) -> Error {
225        Error::PdbError("Unknown", err)
226    }
227}
228
229impl Error {
230    pub fn enum_as_string(&self) -> &'static str {
231        match self {
232            Error::UnmatchedDebugId(_, _) => "UnmatchedDebugId",
233            Error::NoDisambiguatorForFatArchive(_) => "NoDisambiguatorForFatArchive",
234            Error::BreakpadParsing(_) => "BreakpadParsing",
235            Error::JitDumpParsing(_) => "JitDumpParsing",
236            Error::NotEnoughInformationToIdentifyBinary => "NotEnoughInformationToIdentifyBinary",
237            Error::NotEnoughInformationToIdentifySymbolMap => {
238                "NotEnoughInformationToIdentifySymbolMap"
239            }
240            Error::InvalidFileOrInlineOriginIndexInBreakpadFile(_) => {
241                "InvalidFileOrInlineOriginIndexInBreakpadFile"
242            }
243            Error::UnmatchedDebugIdOptional(_, _) => "UnmatchedDebugIdOptional",
244            Error::DebugLinkCrcMismatch(_, _) => "DebugLinkCrcMismatch",
245            Error::UnmatchedCodeId(_, _) => "UnmatchedCodeId",
246            Error::InvalidBreakpadId(_) => "InvalidBreakpadId",
247            Error::EmptyFatArchive => "EmptyFatArchive",
248            Error::CouldNotDetermineExternalFileFileKind => "CouldNotDetermineExternalFileFileKind",
249            Error::ParseErrorInExternalArchive(_) => "ParseErrorInExternalArchive",
250            Error::FileLocationRefusedSubcacheLocation => "FileLocationRefusedSubcacheLocation",
251            Error::FileLocationRefusedExternalObjectLocation => {
252                "FileLocationRefusedExternalObjectLocation"
253            }
254            Error::FileLocationRefusedPdbLocation => "FileLocationRefusedPdbLocation",
255            Error::FileLocationRefusedSourceFileLocation => "FileLocationRefusedSourceFileLocation",
256            Error::UnexpectedExternalFileFileKind(_) => "UnexpectedExternalFileFileKind",
257            Error::NoMatchMultiArch(_) => "NoMatchMultiArch",
258            Error::NoLuckMacOsSystemLibrary(_) => "NoLuckMacOsSystemLibrary",
259            Error::PdbError(_, _) => "PdbError",
260            Error::PdbAddr2lineErrorWithContext(_, _) => "PdbAddr2lineErrorWithContext",
261            Error::InvalidInputError(_) => "InvalidInputError",
262            Error::DyldCacheParseError(_) => "DyldCacheParseError",
263            Error::NoMatchingDyldCacheImagePath(_) => "NoMatchingDyldCacheImagePath",
264            Error::ObjectParseError(_, _) => "ObjectParseError",
265            Error::MachOHeaderParseError(_) => "MachOHeaderParseError",
266            Error::HelperErrorDuringGetCandidatePathsForDebugFile(_, _) => {
267                "HelperErrorDuringGetCandidatePathsForDebugFile"
268            }
269            Error::HelperErrorDuringGetCandidatePathsForBinary(_) => {
270                "HelperErrorDuringGetCandidatePathsForBinary"
271            }
272            Error::HelperErrorDuringGetDyldSharedCachePaths(_) => {
273                "HelperErrorDuringGetDyldSharedCachePaths"
274            }
275            Error::HelperErrorDuringOpenFile(_, _) => "HelperErrorDuringOpenFile",
276            Error::HelperErrorDuringFileReading(_, _) => "HelperErrorDuringFileReading",
277            Error::JitDumpFileReading(_) => "JitDumpFileReading",
278            Error::NoCandidatePathForDebugFile(_) => "NoCandidatePathForDebugFile",
279            Error::NoCandidatePathForBinary(_, _) => "NoCandidatePathForBinary",
280            Error::NoCandidatePathForDyldCache => "NoCandidatePathForDyldCache",
281            Error::NoSuccessfulCandidate(_) => "NoSuccessfulCandidate",
282            Error::NoDebugInfoInPeBinary(_) => "NoDebugInfoInPeBinary",
283            Error::NoMatchingPdbForBinary(_) => "NoMatchingPdbForBinary",
284            Error::PdbPathNotUtf8(_) => "PdbPathNotUtf8",
285            Error::PdbPathWithoutFilename(_) => "PdbPathWithoutFilename",
286            Error::ArchiveParseError(_, _) => "ArchiveParseError",
287            Error::FileNotInArchive(_) => "FileNotInArchive",
288            Error::PdbAddr2lineError(_) => "PdbAddr2lineError",
289            Error::SrcSrvParseError(_) => "SrcSrvParseError",
290            Error::SrcSrvEvalError(_) => "SrcSrvEvalError",
291            Error::Addr2lineContextCreationError(_) => "Addr2lineContextCreationError",
292        }
293    }
294}