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