Skip to content

Commit 95a03da

Browse files
authored
ref(symcache): Switch to error with kind (#296)
1 parent 297bd3b commit 95a03da

File tree

5 files changed

+99
-53
lines changed

5 files changed

+99
-53
lines changed

symbolic-cabi/src/core.rs

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -335,33 +335,33 @@ impl SymbolicErrorCode {
335335
return SymbolicErrorCode::ParseSourceMapError;
336336
}
337337

338-
use symbolic::symcache::SymCacheError;
338+
use symbolic::symcache::{SymCacheError, SymCacheErrorKind};
339339
if let Some(error) = error.downcast_ref::<SymCacheError>() {
340-
return match error {
341-
SymCacheError::BadFileMagic => SymbolicErrorCode::SymCacheErrorBadFileMagic,
342-
SymCacheError::BadFileHeader(_) => {
340+
return match error.kind() {
341+
SymCacheErrorKind::BadFileMagic => SymbolicErrorCode::SymCacheErrorBadFileMagic,
342+
SymCacheErrorKind::BadFileHeader => {
343343
SymbolicErrorCode::SymCacheErrorBadFileHeader
344344
}
345-
SymCacheError::BadSegment => SymbolicErrorCode::SymCacheErrorBadSegment,
346-
SymCacheError::BadCacheFile => SymbolicErrorCode::SymCacheErrorBadCacheFile,
347-
SymCacheError::UnsupportedVersion => {
345+
SymCacheErrorKind::BadSegment => SymbolicErrorCode::SymCacheErrorBadSegment,
346+
SymCacheErrorKind::BadCacheFile => SymbolicErrorCode::SymCacheErrorBadCacheFile,
347+
SymCacheErrorKind::UnsupportedVersion => {
348348
SymbolicErrorCode::SymCacheErrorUnsupportedVersion
349349
}
350-
SymCacheError::BadDebugFile(_) => SymbolicErrorCode::SymCacheErrorBadDebugFile,
351-
SymCacheError::MissingDebugSection => {
350+
SymCacheErrorKind::BadDebugFile => SymbolicErrorCode::SymCacheErrorBadDebugFile,
351+
SymCacheErrorKind::MissingDebugSection => {
352352
SymbolicErrorCode::SymCacheErrorMissingDebugSection
353353
}
354-
SymCacheError::MissingDebugInfo => {
354+
SymCacheErrorKind::MissingDebugInfo => {
355355
SymbolicErrorCode::SymCacheErrorMissingDebugInfo
356356
}
357-
SymCacheError::UnsupportedDebugKind => {
357+
SymCacheErrorKind::UnsupportedDebugKind => {
358358
SymbolicErrorCode::SymCacheErrorUnsupportedDebugKind
359359
}
360-
SymCacheError::ValueTooLarge(_) => {
360+
SymCacheErrorKind::ValueTooLarge(_) => {
361361
SymbolicErrorCode::SymCacheErrorValueTooLarge
362362
}
363-
SymCacheError::WriteFailed(_) => SymbolicErrorCode::SymCacheErrorWriteFailed,
364-
SymCacheError::TooManyValues(_) => {
363+
SymCacheErrorKind::WriteFailed => SymbolicErrorCode::SymCacheErrorWriteFailed,
364+
SymCacheErrorKind::TooManyValues(_) => {
365365
SymbolicErrorCode::SymCacheErrorTooManyValues
366366
}
367367
_ => SymbolicErrorCode::SymCacheErrorUnknown,

symbolic-symcache/src/cache.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ use std::fmt;
22

33
use symbolic_common::{Arch, AsSelf, DebugId, Language, Name, NameMangling};
44

5-
use crate::error::SymCacheError;
5+
use crate::error::{SymCacheError, SymCacheErrorKind};
66
use crate::format;
77

88
/// A platform independent symbolication cache.
@@ -267,7 +267,7 @@ impl<'a> SymCache<'a> {
267267
if let Some((line_addr, file_id, line)) = self.run_to_line(fun, addr)? {
268268
// A missing file record indicates a bad symcache.
269269
let file_record = read_file_record(self.data, self.header.files, file_id)?
270-
.ok_or(SymCacheError::BadCacheFile)?;
270+
.ok_or(SymCacheErrorKind::BadCacheFile)?;
271271

272272
// The address was found in the function's line records, so use
273273
// it directly. This should is the default case for all valid

symbolic-symcache/src/error.rs

Lines changed: 58 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
use std::error::Error;
12
use std::fmt;
23

34
use thiserror::Error;
@@ -26,55 +27,94 @@ impl fmt::Display for ValueKind {
2627
}
2728
}
2829

29-
/// An error returned when handling [`SymCache`](struct.SymCache.html).
30+
/// The error type for [`SymCacheError`].
3031
#[non_exhaustive]
31-
#[derive(Debug, Error)]
32-
pub enum SymCacheError {
32+
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
33+
pub enum SymCacheErrorKind {
3334
/// Invalid magic bytes in the symcache header.
34-
#[error("bad symcache magic")]
3535
BadFileMagic,
3636

3737
/// Invalid flags or fields in the symcache header.
38-
#[error("invalid symcache header")]
39-
BadFileHeader(#[source] std::io::Error),
38+
BadFileHeader,
4039

4140
/// A segment could not be read, likely due to IO errors.
42-
#[error("cannot read symcache segment")]
4341
BadSegment,
4442

4543
/// Contents in the symcache file are malformed.
46-
#[error("malformed symcache file")]
4744
BadCacheFile,
4845

4946
/// The symcache version is not known.
50-
#[error("unsupported symcache version")]
5147
UnsupportedVersion,
5248

5349
/// The `Object` contains invalid data and cannot be converted.
54-
#[error("malformed debug info file")]
55-
BadDebugFile(#[source] Box<dyn std::error::Error + Send + Sync + 'static>),
50+
BadDebugFile,
5651

5752
/// A required debug section is missing in the `Object` file.
58-
#[error("missing debug section")]
5953
MissingDebugSection,
6054

6155
/// The `Object` file was stripped of debug information.
62-
#[error("no debug information found in file")]
6356
MissingDebugInfo,
6457

6558
/// The debug information in the `Object` file is not supported.
66-
#[error("unsupported debug information")]
6759
UnsupportedDebugKind,
6860

6961
/// A value cannot be written to symcache as it overflows the record size.
70-
#[error("{0} too large for symcache file format")]
7162
ValueTooLarge(ValueKind),
7263

7364
/// A value cannot be written to symcache as it overflows the segment counter.
74-
#[error("too many {0}s for symcache")]
7565
TooManyValues(ValueKind),
7666

7767
/// Generic error when writing a symcache, most likely IO.
78-
#[error("failed to write symcache")]
79-
WriteFailed(#[source] std::io::Error),
68+
WriteFailed,
69+
}
70+
71+
impl fmt::Display for SymCacheErrorKind {
72+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
73+
match self {
74+
Self::BadFileMagic => write!(f, "bad symcache magic"),
75+
Self::BadFileHeader => write!(f, "invalid symcache header"),
76+
Self::BadSegment => write!(f, "cannot read symcache segment"),
77+
Self::BadCacheFile => write!(f, "malformed symcache file"),
78+
Self::UnsupportedVersion => write!(f, "unsupported symcache version"),
79+
Self::BadDebugFile => write!(f, "malformed debug info file"),
80+
Self::MissingDebugSection => write!(f, "missing debug section"),
81+
Self::MissingDebugInfo => write!(f, "no debug information found in file"),
82+
Self::UnsupportedDebugKind => write!(f, "unsupported debug information"),
83+
Self::ValueTooLarge(kind) => write!(f, "{} too large for symcache file format", kind),
84+
Self::TooManyValues(kind) => write!(f, "too many {}s for symcache", kind),
85+
Self::WriteFailed => write!(f, "failed to write symcache"),
86+
}
87+
}
88+
}
89+
90+
/// An error returned when handling [`SymCache`](struct.SymCache.html).
91+
#[derive(Debug, Error)]
92+
#[error("{kind}")]
93+
pub struct SymCacheError {
94+
kind: SymCacheErrorKind,
95+
#[source]
96+
source: Option<Box<dyn Error + Send + Sync + 'static>>,
97+
}
98+
99+
impl SymCacheError {
100+
/// Creates a new SymCache error from a known kind of error as well as an
101+
/// arbitrary error payload.
102+
pub(crate) fn new<E>(kind: SymCacheErrorKind, source: E) -> Self
103+
where
104+
E: Into<Box<dyn Error + Send + Sync>>,
105+
{
106+
let source = Some(source.into());
107+
Self { kind, source }
108+
}
109+
110+
/// Returns the corresponding [`SymCacheErrorKind`] for this error.
111+
pub fn kind(&self) -> SymCacheErrorKind {
112+
self.kind
113+
}
114+
}
115+
116+
impl From<SymCacheErrorKind> for SymCacheError {
117+
fn from(kind: SymCacheErrorKind) -> Self {
118+
Self { kind, source: None }
119+
}
80120
}

symbolic-symcache/src/format.rs

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ use std::marker::PhantomData;
77

88
use symbolic_common::{DebugId, Uuid};
99

10-
use crate::error::SymCacheError;
10+
use crate::error::{SymCacheError, SymCacheErrorKind};
1111

1212
/// The magic file preamble to identify symcache files.
1313
pub const SYMCACHE_MAGIC: [u8; 4] = *b"SYMC";
@@ -80,7 +80,8 @@ where
8080
let offset = self.offset as usize;
8181
let len = self.len.into() as usize;
8282
let size = std::mem::size_of::<T>() * len;
83-
let slice = get_slice(data, offset, size).map_err(|_| SymCacheError::BadSegment)?;
83+
let slice = get_slice(data, offset, size)
84+
.map_err(|e| SymCacheError::new(SymCacheErrorKind::BadSegment, e))?;
8485
Ok(unsafe { std::slice::from_raw_parts(slice.as_ptr() as *const T, len) })
8586
}
8687

@@ -100,7 +101,9 @@ where
100101
/// Reads an entire binary segment as string.
101102
pub fn read_str<'a>(&self, data: &'a [u8]) -> Result<&'a str, SymCacheError> {
102103
let slice = self.read(data)?;
103-
Ok(std::str::from_utf8(slice).map_err(|_| SymCacheError::BadSegment)?)
104+
let string = std::str::from_utf8(slice)
105+
.map_err(|e| SymCacheError::new(SymCacheErrorKind::BadSegment, e))?;
106+
Ok(string)
104107
}
105108
}
106109

@@ -319,20 +322,21 @@ pub struct Header {
319322
impl Header {
320323
/// Parses the correct version of the SymCache [`Header`](struct.Header.html).
321324
pub fn parse(data: &[u8]) -> Result<Self, SymCacheError> {
322-
let preamble = get_record::<Preamble>(data, 0).map_err(SymCacheError::BadFileHeader)?;
325+
let preamble = get_record::<Preamble>(data, 0)
326+
.map_err(|e| SymCacheError::new(SymCacheErrorKind::BadFileHeader, e))?;
323327

324328
if preamble.magic != SYMCACHE_MAGIC {
325-
return Err(SymCacheError::BadFileMagic);
329+
return Err(SymCacheErrorKind::BadFileMagic.into());
326330
}
327331

328332
Ok(match preamble.version {
329333
1 => get_record::<HeaderV1>(data, 0)
330-
.map_err(SymCacheError::BadFileHeader)?
334+
.map_err(|e| SymCacheError::new(SymCacheErrorKind::BadFileHeader, e))?
331335
.into(),
332336
2..=SYMCACHE_VERSION => get_record::<HeaderV2>(data, 0)
333-
.map_err(SymCacheError::BadFileHeader)?
337+
.map_err(|e| SymCacheError::new(SymCacheErrorKind::BadFileHeader, e))?
334338
.into(),
335-
_ => return Err(SymCacheError::UnsupportedVersion),
339+
_ => return Err(SymCacheErrorKind::UnsupportedVersion.into()),
336340
})
337341
}
338342
}

symbolic-symcache/src/writer.rs

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ use num::FromPrimitive;
88
use symbolic_common::{Arch, DebugId, Language};
99
use symbolic_debuginfo::{DebugSession, FileInfo, Function, LineInfo, ObjectLike, Symbol};
1010

11-
use crate::error::{SymCacheError, ValueKind};
11+
use crate::error::{SymCacheError, SymCacheErrorKind, ValueKind};
1212
use crate::format;
1313

1414
// Performs a shallow check whether this function might contain any lines.
@@ -68,7 +68,7 @@ where
6868
self.position = position;
6969
self.writer
7070
.seek(io::SeekFrom::Start(position))
71-
.map_err(SymCacheError::WriteFailed)?;
71+
.map_err(|e| SymCacheError::new(SymCacheErrorKind::WriteFailed, e))?;
7272

7373
Ok(())
7474
}
@@ -78,7 +78,7 @@ where
7878
fn write_bytes(&mut self, data: &[u8]) -> Result<(), SymCacheError> {
7979
self.writer
8080
.write_all(data)
81-
.map_err(SymCacheError::WriteFailed)?;
81+
.map_err(|e| SymCacheError::new(SymCacheErrorKind::WriteFailed, e))?;
8282

8383
self.position += data.len() as u64;
8484
Ok(())
@@ -110,7 +110,8 @@ where
110110
let bytes = unsafe { std::slice::from_raw_parts(data.as_ptr() as *const u8, byte_size) };
111111

112112
let segment_pos = self.position as u32;
113-
let segment_len = L::from_usize(data.len()).ok_or(SymCacheError::TooManyValues(kind))?;
113+
let segment_len =
114+
L::from_usize(data.len()).ok_or(SymCacheErrorKind::TooManyValues(kind))?;
114115

115116
self.write_bytes(bytes)?;
116117
Ok(format::Seg::new(segment_pos, segment_len))
@@ -205,10 +206,11 @@ where
205206

206207
let session = object
207208
.debug_session()
208-
.map_err(|e| SymCacheError::BadDebugFile(Box::new(e)))?;
209+
.map_err(|e| SymCacheError::new(SymCacheErrorKind::BadDebugFile, e))?;
209210

210211
for function in session.functions() {
211-
let function = function.map_err(|e| SymCacheError::BadDebugFile(Box::new(e)))?;
212+
let function =
213+
function.map_err(|e| SymCacheError::new(SymCacheErrorKind::BadDebugFile, e))?;
212214
writer.add_function(function)?;
213215
}
214216

@@ -372,7 +374,7 @@ where
372374
}
373375

374376
if self.files.len() >= std::u16::MAX as usize {
375-
return Err(SymCacheError::TooManyValues(ValueKind::File));
377+
return Err(SymCacheErrorKind::TooManyValues(ValueKind::File).into());
376378
}
377379

378380
let index = self.files.len() as u16;
@@ -396,7 +398,7 @@ where
396398

397399
// NB: We only use 48 bits to encode symbol offsets in function records.
398400
if self.symbols.len() >= 0x00ff_ffff {
399-
return Err(SymCacheError::TooManyValues(ValueKind::Symbol));
401+
return Err(SymCacheErrorKind::TooManyValues(ValueKind::Symbol).into());
400402
}
401403

402404
// Avoid a potential reallocation by reusing name.
@@ -475,7 +477,7 @@ where
475477
let symbol_id = self.insert_symbol(function.name.as_str().into())?;
476478
let comp_dir = self.write_path(function.compilation_dir)?;
477479
let lang = u8::from_u32(language as u32)
478-
.ok_or(SymCacheError::ValueTooLarge(ValueKind::Language))?;
480+
.ok_or(SymCacheErrorKind::ValueTooLarge(ValueKind::Language))?;
479481

480482
let mut start_address = function.address;
481483
let mut lines = function.lines.iter().peekable();
@@ -532,7 +534,7 @@ where
532534
// functions to the file.
533535
let index = functions.len();
534536
if index >= std::u32::MAX as usize {
535-
return Err(SymCacheError::ValueTooLarge(ValueKind::Function));
537+
return Err(SymCacheErrorKind::ValueTooLarge(ValueKind::Function).into());
536538
}
537539

538540
// For optimization purposes, remember if all functions appear in order. If not, parent
@@ -600,7 +602,7 @@ where
600602

601603
let parent_offset = index - parent_index;
602604
if parent_offset > std::u16::MAX.into() {
603-
return Err(SymCacheError::ValueTooLarge(ValueKind::ParentOffset));
605+
return Err(SymCacheErrorKind::ValueTooLarge(ValueKind::ParentOffset).into());
604606
}
605607

606608
record.parent_offset = parent_offset as u16;

0 commit comments

Comments
 (0)