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 56472 : pub fn value(&self) -> u16 {
22 56472 : self.ptr.value()
23 56472 : }
24 :
25 : /// SymbolVersionAux associated with the current Version if any.
26 56472 : pub fn symbol_version_auxiliary(&self) -> Option<SymbolVersionAux<'_>> {
27 56472 : into_optional(self.ptr.symbol_version_auxiliary())
28 56472 : }
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 56472 : fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
52 56472 : f.debug_struct("SymbolVersion")
53 56472 : .field("value", &self.value())
54 56472 : .field("symbol_version_auxiliary", &self.symbol_version_auxiliary())
55 56472 : .finish()
56 56472 : }
57 : }
58 :
59 : impl FromFFI<ffi::ELF_SymbolVersion> for SymbolVersion<'_> {
60 56472 : fn from_ffi(ptr: cxx::UniquePtr<ffi::ELF_SymbolVersion>) -> Self {
61 56472 : Self {
62 56472 : ptr,
63 56472 : _owner: PhantomData
64 56472 : }
65 56472 : }
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 30780 : pub fn name(&self) -> String {
76 30780 : self.ptr.name().to_string()
77 30780 : }
78 : }
79 :
80 : impl fmt::Debug for SymbolVersionAux<'_> {
81 30780 : fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
82 30780 : f.debug_struct("SymbolVersionAux")
83 30780 : .field("name", &self.name())
84 30780 : .finish()
85 30780 : }
86 : }
87 :
88 : impl FromFFI<ffi::ELF_SymbolVersionAux> for SymbolVersionAux<'_> {
89 30780 : fn from_ffi(ptr: cxx::UniquePtr<ffi::ELF_SymbolVersionAux>) -> Self {
90 30780 : Self {
91 30780 : ptr,
92 30780 : _owner: PhantomData
93 30780 : }
94 30780 : }
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 600 : pub fn hash(&self) -> u32 {
105 600 : self.ptr.hash()
106 600 : }
107 : /// Bitmask of flags
108 600 : pub fn flags(&self) -> u16 {
109 600 : self.ptr.flags()
110 600 : }
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 600 : pub fn other(&self) -> u16 {
117 600 : self.ptr.other()
118 600 : }
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 600 : fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
130 600 : f.debug_struct("SymbolVersionAuxRequirement")
131 600 : .field("hash", &self.hash())
132 600 : .field("flags", &self.flags())
133 600 : .field("other", &self.other())
134 600 : .finish()
135 600 : }
136 : }
137 :
138 : impl FromFFI<ffi::ELF_SymbolVersionAuxRequirement> for SymbolVersionAuxRequirement<'_> {
139 600 : fn from_ffi(ptr: cxx::UniquePtr<ffi::ELF_SymbolVersionAuxRequirement>) -> Self {
140 600 : Self {
141 600 : ptr,
142 600 : _owner: PhantomData
143 600 : }
144 600 : }
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 204 : pub fn version(&self) -> u16 {
218 204 : self.ptr.version()
219 204 : }
220 :
221 : /// Number of auxiliary entries
222 204 : pub fn cnt(&self) -> u32 {
223 204 : self.ptr.cnt()
224 204 : }
225 :
226 : /// Return the library name associated with this requirement (e.g. `libc.so.6`)
227 204 : pub fn name(&self) -> String {
228 204 : self.ptr.name().to_string()
229 204 : }
230 :
231 : /// Auxiliary entries as an iterator over [`SymbolVersionAuxRequirement`]
232 204 : pub fn auxiliary_symbols(&self) -> AuxiliarySymbols<'_> {
233 204 : AuxiliarySymbols::new(self.ptr.auxiliary_symbols())
234 204 : }
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 204 : fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
266 204 : f.debug_struct("SymbolVersionRequirement")
267 204 : .field("verison", &self.version())
268 204 : .field("cnt", &self.cnt())
269 204 : .field("name", &self.name())
270 204 : .finish()
271 204 : }
272 : }
273 :
274 : impl FromFFI<ffi::ELF_SymbolVersionRequirement> for SymbolVersionRequirement<'_> {
275 204 : fn from_ffi(ptr: cxx::UniquePtr<ffi::ELF_SymbolVersionRequirement>) -> Self {
276 204 : Self {
277 204 : ptr,
278 204 : _owner: PhantomData,
279 204 : }
280 204 : }
281 : }
282 :
283 600 : declare_iterator!(
284 600 : AuxiliarySymbols,
285 600 : SymbolVersionAuxRequirement<'a>,
286 600 : ffi::ELF_SymbolVersionAuxRequirement,
287 600 : ffi::ELF_SymbolVersionRequirement,
288 600 : ffi::ELF_SymbolVersionRequirement_it_auxiliary_symbols
289 600 : );
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 :
|