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