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#[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}