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