Line data Source code
1 : use lief_ffi as ffi;
2 : use std::fmt;
3 : use crate::declare_iterator;
4 : use std::marker::PhantomData;
5 : use crate::common::{FromFFI, into_optional};
6 :
7 : /// Structure which represents an entry defined in the `DT_VERSYM`
8 : /// dynamic entry
9 : pub struct SymbolVersion<'a> {
10 : ptr: cxx::UniquePtr<ffi::ELF_SymbolVersion>,
11 : _owner: PhantomData<&'a ffi::ELF_Binary>
12 : }
13 :
14 : impl SymbolVersion<'_> {
15 : /// Value associated with the symbol
16 : ///
17 : /// If the given [`SymbolVersion`] doesn't have [`SymbolVersion::symbol_version_auxiliary`]:
18 : ///
19 : /// * `0` means **Local**
20 : /// * `1` means **Global**
21 55056 : pub fn value(&self) -> u16 {
22 55056 : self.ptr.value()
23 55056 : }
24 :
25 : /// SymbolVersionAux associated with the current Version if any.
26 55056 : pub fn symbol_version_auxiliary(&self) -> Option<SymbolVersionAux> {
27 55056 : into_optional(self.ptr.symbol_version_auxiliary())
28 55056 : }
29 :
30 : /// Drop the versioning requirement and replace the value (local/global)
31 0 : pub fn drop_version(&mut self, value: u16) {
32 0 : self.ptr.pin_mut().drop_version(value)
33 0 : }
34 :
35 : /// Redefine this version as local by dropping its auxiliary version
36 : ///
37 : /// See: [`SymbolVersion::as_global`], [`SymbolVersion::drop_version`]
38 0 : pub fn as_local(&mut self) {
39 0 : self.ptr.pin_mut().as_local()
40 0 : }
41 :
42 : /// Redefine this version as global by dropping its auxiliary version
43 : ///
44 : /// See: [`SymbolVersion::as_local`], [`SymbolVersion::drop_version`]
45 0 : pub fn as_global(&mut self) {
46 0 : self.ptr.pin_mut().as_global()
47 0 : }
48 : }
49 :
50 : impl fmt::Debug for SymbolVersion<'_> {
51 55056 : fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
52 55056 : f.debug_struct("SymbolVersion")
53 55056 : .field("value", &self.value())
54 55056 : .field("symbol_version_auxiliary", &self.symbol_version_auxiliary())
55 55056 : .finish()
56 55056 : }
57 : }
58 :
59 : impl FromFFI<ffi::ELF_SymbolVersion> for SymbolVersion<'_> {
60 55056 : fn from_ffi(ptr: cxx::UniquePtr<ffi::ELF_SymbolVersion>) -> Self {
61 55056 : Self {
62 55056 : ptr,
63 55056 : _owner: PhantomData
64 55056 : }
65 55056 : }
66 : }
67 :
68 : pub struct SymbolVersionAux<'a> {
69 : ptr: cxx::UniquePtr<ffi::ELF_SymbolVersionAux>,
70 : _owner: PhantomData<&'a ()>
71 : }
72 :
73 :
74 : impl SymbolVersionAux<'_> {
75 30492 : pub fn name(&self) -> String {
76 30492 : self.ptr.name().to_string()
77 30492 : }
78 : }
79 :
80 : impl fmt::Debug for SymbolVersionAux<'_> {
81 30492 : fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
82 30492 : f.debug_struct("SymbolVersionAux")
83 30492 : .field("name", &self.name())
84 30492 : .finish()
85 30492 : }
86 : }
87 :
88 : impl FromFFI<ffi::ELF_SymbolVersionAux> for SymbolVersionAux<'_> {
89 30492 : fn from_ffi(ptr: cxx::UniquePtr<ffi::ELF_SymbolVersionAux>) -> Self {
90 30492 : Self {
91 30492 : ptr,
92 30492 : _owner: PhantomData
93 30492 : }
94 30492 : }
95 : }
96 :
97 : pub struct SymbolVersionAuxRequirement<'a> {
98 : ptr: cxx::UniquePtr<ffi::ELF_SymbolVersionAuxRequirement>,
99 : _owner: PhantomData<&'a ()>
100 : }
101 :
102 : impl SymbolVersionAuxRequirement<'_> {
103 : /// Hash value of the dependency name (use ELF hashing function)
104 552 : pub fn hash(&self) -> u32 {
105 552 : self.ptr.hash()
106 552 : }
107 : /// Bitmask of flags
108 552 : pub fn flags(&self) -> u16 {
109 552 : self.ptr.flags()
110 552 : }
111 :
112 : /// It returns the unique version index for the file which is used in the
113 : /// version symbol table. If the highest bit (bit 15) is set this
114 : /// is a hidden symbol which cannot be referenced from outside the
115 : /// object.
116 552 : pub fn other(&self) -> u16 {
117 552 : self.ptr.other()
118 552 : }
119 :
120 :
121 : /// Symbol's aux name (e.g. `GLIBC_2.2.5`)
122 0 : pub fn name(&self) -> String {
123 0 : self.ptr.name().to_string()
124 0 : }
125 :
126 : }
127 :
128 : impl fmt::Debug for SymbolVersionAuxRequirement<'_> {
129 552 : fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
130 552 : f.debug_struct("SymbolVersionAuxRequirement")
131 552 : .field("hash", &self.hash())
132 552 : .field("flags", &self.flags())
133 552 : .field("other", &self.other())
134 552 : .finish()
135 552 : }
136 : }
137 :
138 : impl FromFFI<ffi::ELF_SymbolVersionAuxRequirement> for SymbolVersionAuxRequirement<'_> {
139 552 : fn from_ffi(ptr: cxx::UniquePtr<ffi::ELF_SymbolVersionAuxRequirement>) -> Self {
140 552 : Self {
141 552 : ptr,
142 552 : _owner: PhantomData
143 552 : }
144 552 : }
145 : }
146 :
147 : /// Structure which represents an entry defined in `DT_VERDEF` or `.gnu.version_d`
148 : pub struct SymbolVersionDefinition<'a> {
149 : ptr: cxx::UniquePtr<ffi::ELF_SymbolVersionDefinition>,
150 : _owner: PhantomData<&'a ()>
151 : }
152 :
153 :
154 : impl SymbolVersionDefinition<'_> {
155 : /// Version revision
156 : ///
157 : /// This field should always have the value `1`. It will be changed
158 : /// if the versioning implementation has to be changed in an incompatible way.
159 36 : pub fn version(&self) -> u16 {
160 36 : self.ptr.version()
161 36 : }
162 :
163 : /// Version information
164 36 : pub fn flags(&self) -> u16 {
165 36 : self.ptr.flags()
166 36 : }
167 :
168 : /// Version index
169 : /// Numeric value used as an index in the [`SymbolVersion`] table
170 36 : pub fn ndx(&self) -> u16 {
171 36 : self.ptr.ndx()
172 36 : }
173 :
174 : /// Hash value of the symbol's name (using ELF hash function)
175 36 : pub fn hash(&self) -> u32 {
176 36 : self.ptr.hash()
177 36 : }
178 :
179 : /// Iterator over the [`SymbolVersionAux`] associated with this entry
180 36 : pub fn auxiliary_symbols(&self) -> DefAuxiliarySymbols {
181 36 : DefAuxiliarySymbols::new(self.ptr.sym_aux())
182 36 : }
183 : }
184 :
185 : impl fmt::Debug for SymbolVersionDefinition<'_> {
186 36 : fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
187 36 : f.debug_struct("SymbolVersionDefinition")
188 36 : .field("version", &self.version())
189 36 : .field("flags", &self.flags())
190 36 : .field("ndx", &self.ndx())
191 36 : .field("hash", &self.hash())
192 36 : .finish()
193 36 : }
194 : }
195 :
196 : impl FromFFI<ffi::ELF_SymbolVersionDefinition> for SymbolVersionDefinition<'_> {
197 36 : fn from_ffi(ptr: cxx::UniquePtr<ffi::ELF_SymbolVersionDefinition>) -> Self {
198 36 : Self {
199 36 : ptr,
200 36 : _owner: PhantomData
201 36 : }
202 36 : }
203 : }
204 :
205 :
206 : /// Structure which represents an entry in the `DT_VERNEED` or `.gnu.version_r` table
207 : pub struct SymbolVersionRequirement<'a> {
208 : ptr: cxx::UniquePtr<ffi::ELF_SymbolVersionRequirement>,
209 : _owner: PhantomData<&'a ()>
210 : }
211 :
212 : impl SymbolVersionRequirement<'_> {
213 : /// Version revision
214 : ///
215 : /// This field should always have the value `1`. It will be changed
216 : /// if the versioning implementation has to be changed in an incompatible way.
217 180 : pub fn version(&self) -> u16 {
218 180 : self.ptr.version()
219 180 : }
220 :
221 : /// Number of auxiliary entries
222 180 : pub fn cnt(&self) -> u32 {
223 180 : self.ptr.cnt()
224 180 : }
225 :
226 : /// Return the library name associated with this requirement (e.g. `libc.so.6`)
227 180 : pub fn name(&self) -> String {
228 180 : self.ptr.name().to_string()
229 180 : }
230 :
231 : /// Auxiliary entries as an iterator over [`SymbolVersionAuxRequirement`]
232 180 : pub fn auxiliary_symbols(&self) -> AuxiliarySymbols {
233 180 : AuxiliarySymbols::new(self.ptr.auxiliary_symbols())
234 180 : }
235 :
236 0 : pub fn set_name(&mut self, name: &str) {
237 0 : self.ptr.pin_mut().set_name(name.to_string());
238 0 : }
239 :
240 0 : pub fn set_version(&mut self, version: u16) {
241 0 : self.ptr.pin_mut().set_version(version);
242 0 : }
243 :
244 : /// Try to find the [`SymbolVersionAuxRequirement`] with the given name (e.g. `GLIBC_2.27`)
245 0 : pub fn find_aux(&self, name: &str) -> Option<SymbolVersionAuxRequirement> {
246 0 : into_optional(self.ptr.find_aux(name.to_string()))
247 0 : }
248 :
249 :
250 : /// Try to remove the auxiliary requirement symbol with the given name.
251 : /// The function returns true if the operation succeed, false otherwise.
252 : ///
253 : /// **warning**:
254 : ///
255 : /// This function invalidates all the references of
256 : /// [`SymbolVersionAuxRequirement`]. Therefore, the user is reponsible
257 : /// to ensure that the auxiliary requirement is no longer used in the
258 : /// ELF binary (e.g. in [`SymbolVersion`])
259 0 : pub fn remove_aux_requirement_by_name(&mut self, name: &str) -> bool {
260 0 : self.ptr.pin_mut().remove_aux_requirement_by_name(name.to_string())
261 0 : }
262 : }
263 :
264 : impl fmt::Debug for SymbolVersionRequirement<'_> {
265 180 : fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
266 180 : f.debug_struct("SymbolVersionRequirement")
267 180 : .field("verison", &self.version())
268 180 : .field("cnt", &self.cnt())
269 180 : .field("name", &self.name())
270 180 : .finish()
271 180 : }
272 : }
273 :
274 : impl FromFFI<ffi::ELF_SymbolVersionRequirement> for SymbolVersionRequirement<'_> {
275 180 : fn from_ffi(ptr: cxx::UniquePtr<ffi::ELF_SymbolVersionRequirement>) -> Self {
276 180 : Self {
277 180 : ptr,
278 180 : _owner: PhantomData,
279 180 : }
280 180 : }
281 : }
282 :
283 552 : declare_iterator!(
284 552 : AuxiliarySymbols,
285 552 : SymbolVersionAuxRequirement<'a>,
286 552 : ffi::ELF_SymbolVersionAuxRequirement,
287 552 : ffi::ELF_SymbolVersionRequirement,
288 552 : ffi::ELF_SymbolVersionRequirement_it_auxiliary_symbols
289 552 : );
290 36 : declare_iterator!(
291 36 : DefAuxiliarySymbols,
292 36 : SymbolVersionAux<'a>,
293 36 : ffi::ELF_SymbolVersionAux,
294 36 : ffi::ELF_SymbolVersionDefinition,
295 36 : ffi::ELF_SymbolVersionDefinition_it_auxiliary_symbols
296 36 : );
297 :
|