Line data Source code
1 : //! This module wraps DWARF compilation unit
2 :
3 : use lief_ffi as ffi;
4 :
5 : use std::marker::PhantomData;
6 :
7 : use crate::common::{into_optional, into_ranges, FromFFI};
8 : use crate::declare_fwd_iterator;
9 : use crate::Range;
10 :
11 : use super::{Function, Variable};
12 : use crate::dwarf::function::Functions;
13 : use crate::dwarf::types::Types;
14 : use crate::dwarf::variable::CompilationUnitVariables;
15 :
16 : /// A DWARF compilation unit
17 : pub struct CompilationUnit<'a> {
18 : ptr: cxx::UniquePtr<ffi::DWARF_CompilationUnit>,
19 : _owner: PhantomData<&'a ()>,
20 : }
21 :
22 : #[allow(non_camel_case_types)]
23 0 : #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
24 : pub enum Langs {
25 : C,
26 : CPP,
27 : RUST,
28 : DART,
29 : MODULA,
30 : FORTRAN,
31 : SWIFT,
32 : D,
33 : JAVA,
34 : COBOL,
35 : UNKNOWN(u32),
36 : }
37 :
38 : impl From<u32> for Langs {
39 0 : fn from(value: u32) -> Self {
40 0 : match value {
41 0 : 0x00000001 => Langs::C,
42 0 : 0x00000002 => Langs::CPP,
43 0 : 0x00000003 => Langs::RUST,
44 0 : 0x00000004 => Langs::DART,
45 0 : 0x00000005 => Langs::MODULA,
46 0 : 0x00000006 => Langs::FORTRAN,
47 0 : 0x00000007 => Langs::SWIFT,
48 0 : 0x00000008 => Langs::D,
49 0 : 0x00000009 => Langs::JAVA,
50 0 : 0x0000000A => Langs::COBOL,
51 0 : _ => Langs::UNKNOWN(value),
52 : }
53 0 : }
54 : }
55 : impl From<Langs> for u32 {
56 0 : fn from(value: Langs) -> u32 {
57 0 : match value {
58 0 : Langs::C => 0x00000001,
59 0 : Langs::CPP => 0x00000002,
60 0 : Langs::RUST => 0x00000003,
61 0 : Langs::DART => 0x00000004,
62 0 : Langs::MODULA => 0x00000005,
63 0 : Langs::FORTRAN => 0x00000006,
64 0 : Langs::SWIFT => 0x00000007,
65 0 : Langs::D => 0x00000008,
66 0 : Langs::JAVA => 0x00000009,
67 0 : Langs::COBOL => 0x0000000A,
68 0 : Langs::UNKNOWN(_) => 0,
69 : }
70 0 : }
71 : }
72 :
73 : /// Languages supported by the DWARF (v5) format.
74 : /// See: <https://dwarfstd.org/languages.html>
75 : ///
76 : /// Some languages (like C++11, C++17, ..) have a version (11, 17, ...) which
77 : /// is stored in a dedicated attribute: #version
78 0 : #[derive(Debug)]
79 : pub struct Language {
80 : /// The language itself
81 : pub lang: Langs,
82 :
83 : /// Version of the language (e.g. 17 for C++17)
84 : pub version: u32,
85 : }
86 :
87 : impl FromFFI<ffi::DWARF_CompilationUnit_Language> for Language {
88 0 : fn from_ffi(ptr: cxx::UniquePtr<ffi::DWARF_CompilationUnit_Language>) -> Self {
89 0 : let lang_ref = ptr.as_ref().unwrap();
90 0 : Self {
91 0 : lang: Langs::from(lang_ref.lang),
92 0 : version: lang_ref.version,
93 0 : }
94 0 : }
95 : }
96 :
97 : impl FromFFI<ffi::DWARF_CompilationUnit> for CompilationUnit<'_> {
98 0 : fn from_ffi(ptr: cxx::UniquePtr<ffi::DWARF_CompilationUnit>) -> Self {
99 0 : Self {
100 0 : ptr,
101 0 : _owner: PhantomData,
102 0 : }
103 0 : }
104 : }
105 :
106 : impl CompilationUnit<'_> {
107 : /// Name of the file associated with this compilation unit (e.g. `test.cpp`)
108 : /// Return an **empty** string if the name is not found or can't be resolved
109 : ///
110 : /// This value matches the `DW_AT_name` attribute
111 0 : pub fn name(&self) -> String {
112 0 : self.ptr.name().to_string()
113 0 : }
114 :
115 : /// Information about the program (or library) that generated this compilation
116 : /// unit. For instance, it can output: `Debian clang version 17.0.6`.
117 : ///
118 : /// It returns an **empty** string if the producer is not present or can't be
119 : /// resolved
120 : ///
121 : /// This value matches the `DW_AT_producer` attribute
122 0 : pub fn producer(&self) -> String {
123 0 : self.ptr.producer().to_string()
124 0 : }
125 :
126 : /// Return the path to the directory in which the compilation took place for
127 : /// compiling this compilation unit (e.g. `/workdir/build`)
128 : ///
129 : /// It returns an **empty** string if the entry is not present or can't be
130 : /// resolved
131 : ///
132 : /// This value matches the `DW_AT_comp_dir` attributeducer` attribute
133 0 : pub fn compilation_dir(&self) -> String {
134 0 : self.ptr.compilation_dir().to_string()
135 0 : }
136 :
137 : /// Original Language of this compilation unit.
138 : ///
139 : /// This value matches the `DW_AT_language` attribute
140 0 : pub fn language(&self) -> Language {
141 0 : Language::from_ffi(self.ptr.language())
142 0 : }
143 :
144 : /// Return the lowest virtual address owned by this compilation unit.
145 0 : pub fn low_address(&self) -> u64 {
146 0 : self.ptr.low_address()
147 0 : }
148 :
149 : /// Return the highest virtual address owned by this compilation unit.
150 0 : pub fn high_address(&self) -> u64 {
151 0 : self.ptr.high_address()
152 0 : }
153 :
154 : /// Return the size of the compilation unit according to its range of address.
155 : ///
156 : /// If the compilation is fragmented (i.e. there are some address ranges
157 : /// between the lowest address and the highest that are not owned by the CU),
158 : /// then it returns the sum of **all** the address ranges owned by this CU.
159 : ///
160 : /// If the compilation unit is **not** fragmented, then is basically returns
161 : /// `high_address - low_address`.
162 0 : pub fn size(&self) -> u64 {
163 0 : self.ptr.size()
164 0 : }
165 :
166 : /// Return a list of address ranges owned by this compilation unit.
167 : ///
168 : /// If the compilation unit owns a contiguous range, it should return
169 : /// **a single** range.
170 0 : pub fn ranges(&self) -> Vec<Range> {
171 0 : into_ranges(self.ptr.ranges())
172 0 : }
173 :
174 : /// Return an iterator over the functions [`Function`] implemented in this compilation
175 : /// unit.
176 : ///
177 : /// Note that this iterator only iterates over the functions that have a
178 : /// **concrete** implementation in the compilation unit.
179 : ///
180 : /// For instance with this code:
181 : ///
182 : /// ```cpp
183 : /// inline const char* get_secret_env() {
184 : /// return getenv("MY_SECRET_ENV");
185 : /// }
186 : ///
187 : /// int main() {
188 : /// printf("%s", get_secret_env());
189 : /// return 0;
190 : /// }
191 : /// ```
192 : ///
193 : /// The iterator will only return **one function** for `main` since
194 : /// `get_secret_env` is inlined and thus, its implementation is located in
195 : /// `main`.
196 0 : pub fn functions(&self) -> Functions<'_> {
197 0 : Functions::new(self.ptr.functions())
198 0 : }
199 :
200 : /// Return an iterator over the functions **imported** in this compilation
201 : /// unit **but not** implemented.
202 : ///
203 : /// For instance with this code:
204 : ///
205 : /// ```cpp
206 : /// #include <cstdio>
207 : /// int main() {
208 : /// printf("Hello\n");
209 : /// return 0;
210 : /// }
211 : /// ```
212 : ///
213 : /// `printf` is imported from the standard libc so the function is returned by
214 : /// the iterator. On the other hand, `main()` is implemented in this
215 : /// compilation unit so it is not returned by [`CompilationUnit::imported_functions`] but
216 : /// [`CompilationUnit::functions`].
217 0 : pub fn imported_functions(&self) -> Functions<'_> {
218 0 : Functions::new(self.ptr.imported_functions())
219 0 : }
220 :
221 : /// Return an iterator over the variables defined in the **global** scope
222 : /// of this compilation unit:
223 : ///
224 : /// ```cpp
225 : /// static int A = 1; // Returned by the iterator
226 : /// static const char* B = "Hello"; // Returned by the iterator
227 : ///
228 : /// int get() {
229 : /// static int C = 2; // Returned by the iterator
230 : /// return C;
231 : /// }
232 : /// ```
233 0 : pub fn variables(&self) -> CompilationUnitVariables<'_> {
234 0 : CompilationUnitVariables::new(self.ptr.variables())
235 0 : }
236 :
237 0 : pub fn types(&self) -> Types<'_> {
238 0 : Types::new(self.ptr.types())
239 0 : }
240 :
241 : /// Try to find the function whose name is given in parameter.
242 : ///
243 : /// The provided name can be demangled.
244 0 : pub fn function_by_name(&self, name: &str) -> Option<Function<'_>> {
245 0 : into_optional(self.ptr.function_by_name(name))
246 0 : }
247 :
248 : /// Try to find the function at the given address
249 0 : pub fn function_by_addr(&self, address: u64) -> Option<Function<'_>> {
250 0 : into_optional(self.ptr.function_by_address(address))
251 0 : }
252 :
253 : /// Try to find the variable whose name is given in parameter.
254 0 : pub fn variable_by_name(&self, name: &str) -> Option<Variable<'_>> {
255 0 : into_optional(self.ptr.variable_by_name(name))
256 0 : }
257 :
258 : /// Try to find the variable at the given address
259 0 : pub fn variable_by_addr(&self, address: u64) -> Option<Variable<'_>> {
260 0 : into_optional(self.ptr.variable_by_address(address))
261 0 : }
262 : }
263 :
264 0 : declare_fwd_iterator!(
265 0 : CompilationUnits,
266 0 : CompilationUnit<'a>,
267 0 : ffi::DWARF_CompilationUnit,
268 0 : ffi::DWARF_DebugInfo,
269 0 : ffi::DWARF_DebugInfo_it_compilation_units
270 0 : );
|