Skip to main content

ddbug_parser/
lib.rs

1//! A library for parsing debuginfo.
2//!
3//! ## Example usage
4//!
5//! ```rust,no_run
6//! # fn main() -> Result<(), Box<dyn std::error::Error>> {
7//! # let a_file_path = String::new();
8//! let ctx = ddbug_parser::File::parse(a_file_path)?;
9//! let file = ctx.file();
10//! for unit in file.units() {
11//!     for function in unit.functions() {
12//!         if let Some(name) = function.name() {
13//!             println!("{}", name);
14//!         }
15//!     }
16//! }
17//! Ok(())
18//! }
19//! ```
20#![deny(missing_docs)]
21// Enable some rust 2018 idioms.
22#![warn(bare_trait_objects)]
23#![warn(unused_extern_crates)]
24// Calm down clippy.
25#![allow(clippy::single_match)]
26#![allow(clippy::match_single_binding)]
27#![allow(clippy::too_many_arguments)]
28#![allow(clippy::uninlined_format_args)]
29
30#[macro_use]
31extern crate log;
32
33mod cfi;
34mod file;
35mod function;
36mod location;
37mod namespace;
38mod range;
39mod source;
40mod types;
41mod unit;
42mod variable;
43
44pub use crate::cfi::*;
45pub use crate::file::*;
46pub use crate::function::*;
47pub use crate::location::*;
48pub use crate::namespace::*;
49pub use crate::range::*;
50pub use crate::source::*;
51pub use crate::types::*;
52pub use crate::unit::*;
53pub use crate::variable::*;
54
55use std::borrow::{Borrow, Cow};
56use std::error;
57use std::fmt;
58use std::io;
59use std::result;
60use std::sync::atomic::{AtomicUsize, Ordering};
61
62/// A parsing error.
63#[derive(Debug)]
64pub struct Error(pub Cow<'static, str>);
65
66impl error::Error for Error {
67    fn description(&self) -> &str {
68        self.0.borrow()
69    }
70}
71
72impl fmt::Display for Error {
73    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
74        write!(f, "{}", self.0)
75    }
76}
77
78impl From<&'static str> for Error {
79    fn from(s: &'static str) -> Error {
80        Error(Cow::Borrowed(s))
81    }
82}
83
84impl From<String> for Error {
85    fn from(s: String) -> Error {
86        Error(Cow::Owned(s))
87    }
88}
89
90impl From<io::Error> for Error {
91    fn from(e: io::Error) -> Error {
92        Error(Cow::Owned(format!("IO error: {}", e)))
93    }
94}
95
96impl From<gimli::Error> for Error {
97    fn from(e: gimli::Error) -> Error {
98        Error(Cow::Owned(format!("DWARF error: {}", e)))
99    }
100}
101
102impl From<object::Error> for Error {
103    fn from(e: object::Error) -> Error {
104        Error(Cow::Owned(format!("object error: {}", e)))
105    }
106}
107
108/*
109impl From<crate_pdb::Error> for Error {
110    fn from(e: crate_pdb::Error) -> Error {
111        Error(Cow::Owned(format!("PDB error: {}", e)))
112    }
113}
114*/
115
116/// A parsing result.
117pub type Result<T> = result::Result<T, Error>;
118
119mod address {
120    /// An optional address.
121    ///
122    /// This is similar to `Option<u64>`, but uses `!0` to encode the `None` case.
123    #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
124    pub struct Address(u64);
125
126    impl Address {
127        /// Create a known address value.
128        #[inline]
129        pub fn new(address: u64) -> Address {
130            debug_assert!(Address(address) != Address::none());
131            Address(address)
132        }
133
134        /// Create an unknown or absent address value.
135        #[inline]
136        pub fn none() -> Address {
137            Address(!0)
138        }
139
140        /// Return true if the address is unknown or absent.
141        #[inline]
142        pub fn is_none(self) -> bool {
143            self == Self::none()
144        }
145
146        /// Return true if the address is known.
147        #[inline]
148        pub fn is_some(self) -> bool {
149            self != Self::none()
150        }
151
152        /// Return the address.
153        #[inline]
154        pub fn get(self) -> Option<u64> {
155            if self.is_none() { None } else { Some(self.0) }
156        }
157    }
158
159    impl Default for Address {
160        #[inline]
161        fn default() -> Self {
162            Address::none()
163        }
164    }
165}
166
167pub use crate::address::Address;
168
169mod size {
170    /// An optional size.
171    ///
172    /// This is similar to `Option<u64>`, but uses `u64::MAX` to encode the `None` case.
173    #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
174    pub struct Size(u64);
175
176    impl Size {
177        /// Create a known size value.
178        #[inline]
179        pub fn new(size: u64) -> Size {
180            debug_assert!(Size(size) != Size::none());
181            Size(size)
182        }
183
184        /// Create an unknown or absent size value.
185        #[inline]
186        pub fn none() -> Size {
187            Size(u64::MAX)
188        }
189
190        /// Return true if the size is unknown or absent.
191        #[inline]
192        pub fn is_none(self) -> bool {
193            self == Self::none()
194        }
195
196        /// Return true if the size is known.
197        #[inline]
198        pub fn is_some(self) -> bool {
199            self != Self::none()
200        }
201
202        /// Return the size.
203        #[inline]
204        pub fn get(self) -> Option<u64> {
205            if self.is_none() { None } else { Some(self.0) }
206        }
207    }
208
209    impl Default for Size {
210        #[inline]
211        fn default() -> Self {
212            Size::none()
213        }
214    }
215
216    impl From<Option<u64>> for Size {
217        fn from(size: Option<u64>) -> Size {
218            match size {
219                Some(size) => Size::new(size),
220                None => Size::none(),
221            }
222        }
223    }
224}
225
226pub use crate::size::Size;
227
228#[derive(Debug, Default)]
229struct Id(AtomicUsize);
230
231impl Clone for Id {
232    fn clone(&self) -> Self {
233        Id(AtomicUsize::new(self.get()))
234    }
235}
236
237impl Id {
238    fn new(id: usize) -> Self {
239        Id(AtomicUsize::new(id))
240    }
241
242    fn get(&self) -> usize {
243        self.0.load(Ordering::Acquire)
244    }
245
246    fn set(&self, id: usize) {
247        self.0.store(id, Ordering::Release)
248    }
249}