minidump_common/traits.rs
1//! Some common traits used by minidump-related crates.
2
3use debugid::{CodeId, DebugId};
4use range_map::{Range, RangeMap};
5
6use std::borrow::Cow;
7use std::cmp;
8use std::fmt::Debug;
9
10/// An executable or shared library loaded in a process.
11pub trait Module {
12 /// The base address of this code module as it was loaded by the process.
13 fn base_address(&self) -> u64;
14 /// The size of the code module.
15 fn size(&self) -> u64;
16 /// The path or file name that the code module was loaded from.
17 fn code_file(&self) -> Cow<'_, str>;
18 /// An identifying string used to discriminate between multiple versions and
19 /// builds of the same code module. This may contain a uuid, timestamp,
20 /// version number, or any combination of this or other information, in an
21 /// implementation-defined format.
22 fn code_identifier(&self) -> Option<CodeId>;
23 /// The filename containing debugging information associated with the code
24 /// module. If debugging information is stored in a file separate from the
25 /// code module itself (as is the case when .pdb or .dSYM files are used),
26 /// this will be different from code_file. If debugging information is
27 /// stored in the code module itself (possibly prior to stripping), this
28 /// will be the same as code_file.
29 fn debug_file(&self) -> Option<Cow<'_, str>>;
30 /// An identifying string similar to code_identifier, but identifies a
31 /// specific version and build of the associated debug file. This may be
32 /// the same as code_identifier when the debug_file and code_file are
33 /// identical or when the same identifier is used to identify distinct
34 /// debug and code files.
35 fn debug_identifier(&self) -> Option<DebugId>;
36 /// A human-readable representation of the code module's version.
37 fn version(&self) -> Option<Cow<'_, str>>;
38}
39
40/// Implement Module for 2-tuples of (&str, DebugId) for convenience.
41/// `breakpad-symbols`' `Symbolizer::get_symbol_at_address` uses this.
42impl Module for (&str, DebugId) {
43 fn base_address(&self) -> u64 {
44 0
45 }
46 fn size(&self) -> u64 {
47 0
48 }
49 fn code_file(&self) -> Cow<'_, str> {
50 Cow::Borrowed("")
51 }
52 fn code_identifier(&self) -> Option<CodeId> {
53 None
54 }
55 fn debug_file(&self) -> Option<Cow<'_, str>> {
56 let &(file, _id) = self;
57 Some(Cow::Borrowed(file))
58 }
59 fn debug_identifier(&self) -> Option<DebugId> {
60 let &(_file, id) = self;
61 Some(id)
62 }
63 fn version(&self) -> Option<Cow<'_, str>> {
64 None
65 }
66}
67
68/// This trait exists to allow creating `RangeMap`s from possibly-overlapping input data.
69///
70/// The `RangeMap` struct will panic if you attempt to initialize it with overlapping data,
71/// and we deal with many sources of untrusted input data that could run afoul of this.
72/// [Upstream issue](https://github.com/jneem/range-map/issues/1)
73pub trait IntoRangeMapSafe<V>: IntoIterator<Item = (Option<Range<u64>>, V)> + Sized
74where
75 V: Clone + Debug + Eq,
76{
77 fn into_rangemap_safe(self) -> RangeMap<u64, V> {
78 let mut input: Vec<_> = self.into_iter().collect();
79 input.sort_by_key(|x| x.0);
80 let mut vec: Vec<(Range<u64>, V)> = Vec::with_capacity(input.len());
81 for (range, val) in input.into_iter() {
82 if range.is_none() {
83 // warn!("Unable to create valid range for {:?}", val);
84 continue;
85 }
86 let range = range.unwrap();
87
88 if let Some(&mut (ref mut last_range, ref last_val)) = vec.last_mut() {
89 if range.start <= last_range.end && &val != last_val {
90 // This logging is nice to have but some symbol files are absolutely
91 // horribly polluted with duplicate entries with different values(!!!)
92 // and this generates literally a gigabyte of logs, yikes!
93
94 /*
95 warn!("overlapping ranges {:?} and {:?}", last_range, range);
96 warn!(" value1: {:?}", last_val);
97 warn!(" value2: {:?}\n", val);
98 */
99 continue;
100 }
101
102 if range.start <= last_range.end.saturating_add(1) && &val == last_val {
103 last_range.end = cmp::max(range.end, last_range.end);
104 continue;
105 }
106 }
107
108 vec.push((range, val));
109 }
110 RangeMap::try_from_iter(vec).unwrap()
111 }
112}
113
114impl<I, V> IntoRangeMapSafe<V> for I
115where
116 I: IntoIterator<Item = (Option<Range<u64>>, V)> + Sized,
117 V: Clone + Debug + Eq,
118{
119}