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