3 use crate::read
::{Bytes, ReadError, ReadRef, Result, StringTable}
;
4 use crate::{elf, endian}
;
9 #[derive(Debug, Default, Clone, Copy)]
10 pub struct VersionIndex(pub u16);
13 /// Return the version index.
14 pub fn index(&self) -> u16 {
15 self.0 & elf
::VERSYM_VERSION
18 /// Return true if it is the local index.
19 pub fn is_local(&self) -> bool
{
20 self.index() == elf
::VER_NDX_LOCAL
23 /// Return true if it is the global index.
24 pub fn is_global(&self) -> bool
{
25 self.index() == elf
::VER_NDX_GLOBAL
28 /// Return the hidden flag.
29 pub fn is_hidden(&self) -> bool
{
30 self.0 & elf
::VERSYM_HIDDEN
!= 0
34 /// A version definition or requirement.
36 /// This is derived from entries in the `SHT_GNU_verdef` and `SHT_GNU_verneed` sections.
37 #[derive(Debug, Default, Clone, Copy)]
38 pub struct Version
<'data
> {
41 // Used to keep track of valid indices in `VersionTable`.
45 impl<'data
> Version
<'data
> {
46 /// Return the version name.
47 pub fn name(&self) -> &'data
[u8] {
51 /// Return hash of the version name.
52 pub fn hash(&self) -> u32 {
57 /// A table of version definitions and requirements.
59 /// It allows looking up the version information for a given symbol index.
61 /// This is derived from entries in the `SHT_GNU_versym`, `SHT_GNU_verdef` and `SHT_GNU_verneed` sections.
62 #[derive(Debug, Clone)]
63 pub struct VersionTable
<'data
, Elf
: FileHeader
> {
64 symbols
: &'data
[elf
::Versym
<Elf
::Endian
>],
65 versions
: Vec
<Version
<'data
>>,
68 impl<'data
, Elf
: FileHeader
> Default
for VersionTable
<'data
, Elf
> {
69 fn default() -> Self {
77 impl<'data
, Elf
: FileHeader
> VersionTable
<'data
, Elf
> {
78 /// Parse the version sections.
79 pub fn parse
<R
: ReadRef
<'data
>>(
81 versyms
: &'data
[elf
::Versym
<Elf
::Endian
>],
82 verdefs
: Option
<VerdefIterator
<'data
, Elf
>>,
83 verneeds
: Option
<VerneedIterator
<'data
, Elf
>>,
84 strings
: StringTable
<'data
, R
>,
86 let mut max_index
= 0;
87 if let Some(mut verdefs
) = verdefs
.clone() {
88 while let Some((verdef
, _
)) = verdefs
.next()?
{
89 if verdef
.vd_flags
.get(endian
) & elf
::VER_FLG_BASE
!= 0 {
92 let index
= verdef
.vd_ndx
.get(endian
) & elf
::VERSYM_VERSION
;
93 if max_index
< index
{
98 if let Some(mut verneeds
) = verneeds
.clone() {
99 while let Some((_
, mut vernauxs
)) = verneeds
.next()?
{
100 while let Some(vernaux
) = vernauxs
.next()?
{
101 let index
= vernaux
.vna_other
.get(endian
) & elf
::VERSYM_VERSION
;
102 if max_index
< index
{
109 // Indices should be sequential, but this could be up to
110 // 32k * size_of::<Version>() if max_index is bad.
111 let mut versions
= vec
![Version
::default(); max_index
as usize + 1];
113 if let Some(mut verdefs
) = verdefs
{
114 while let Some((verdef
, mut verdauxs
)) = verdefs
.next()?
{
115 if verdef
.vd_flags
.get(endian
) & elf
::VER_FLG_BASE
!= 0 {
118 let index
= verdef
.vd_ndx
.get(endian
) & elf
::VERSYM_VERSION
;
119 if index
<= elf
::VER_NDX_GLOBAL
{
120 // TODO: return error?
123 if let Some(verdaux
) = verdauxs
.next()?
{
124 versions
[usize::from(index
)] = Version
{
125 name
: verdaux
.name(endian
, strings
)?
,
126 hash
: verdef
.vd_hash
.get(endian
),
132 if let Some(mut verneeds
) = verneeds
{
133 while let Some((_
, mut vernauxs
)) = verneeds
.next()?
{
134 while let Some(vernaux
) = vernauxs
.next()?
{
135 let index
= vernaux
.vna_other
.get(endian
) & elf
::VERSYM_VERSION
;
136 if index
<= elf
::VER_NDX_GLOBAL
{
137 // TODO: return error?
140 versions
[usize::from(index
)] = Version
{
141 name
: vernaux
.name(endian
, strings
)?
,
142 hash
: vernaux
.vna_hash
.get(endian
),
155 /// Return true if the version table is empty.
156 pub fn is_empty(&self) -> bool
{
157 self.symbols
.is_empty()
160 /// Return version index for a given symbol index.
161 pub fn version_index(&self, endian
: Elf
::Endian
, index
: usize) -> VersionIndex
{
162 let version_index
= match self.symbols
.get(index
) {
163 Some(x
) => x
.0.get(endian
),
164 // Ideally this would be VER_NDX_LOCAL for undefined symbols,
165 // but currently there are no checks that need this distinction.
166 None
=> elf
::VER_NDX_GLOBAL
,
168 VersionIndex(version_index
)
171 /// Return version information for a given symbol version index.
173 /// Returns `Ok(None)` for local and global versions.
174 /// Returns `Err(_)` if index is invalid.
175 pub fn version(&self, index
: VersionIndex
) -> Result
<Option
<&Version
<'data
>>> {
176 if index
.index() <= elf
::VER_NDX_GLOBAL
{
180 .get(usize::from(index
.index()))
181 .filter(|version
| version
.valid
)
182 .read_error("Invalid ELF symbol version index")
186 /// Return true if the given symbol index satisfies the requirements of `need`.
188 /// Returns false for any error.
190 /// Note: this function hasn't been fully tested and is likely to be incomplete.
191 pub fn matches(&self, endian
: Elf
::Endian
, index
: usize, need
: Option
<&Version
<'_
>>) -> bool
{
192 let version_index
= self.version_index(endian
, index
);
193 let def
= match self.version(version_index
) {
195 Err(_
) => return false,
198 (Some(def
), Some(need
)) => need
.hash
== def
.hash
&& need
.name
== def
.name
,
199 (None
, Some(_need
)) => {
200 // Version must be present if needed.
203 (Some(_def
), None
) => {
204 // For a dlsym call, use the newest version.
205 // TODO: if not a dlsym call, then use the oldest version.
206 !version_index
.is_hidden()
208 (None
, None
) => true,
213 /// An iterator over the entries in an ELF `SHT_GNU_verdef` section.
214 #[derive(Debug, Clone)]
215 pub struct VerdefIterator
<'data
, Elf
: FileHeader
> {
220 impl<'data
, Elf
: FileHeader
> VerdefIterator
<'data
, Elf
> {
221 pub(super) fn new(endian
: Elf
::Endian
, data
: &'data
[u8]) -> Self {
228 /// Return the next `Verdef` entry.
231 ) -> Result
<Option
<(&'data elf
::Verdef
<Elf
::Endian
>, VerdauxIterator
<'data
, Elf
>)>> {
232 if self.data
.is_empty() {
238 .read_at
::<elf
::Verdef
<_
>>(0)
239 .read_error("ELF verdef is too short")?
;
241 let mut verdaux_data
= self.data
;
243 .skip(verdef
.vd_aux
.get(self.endian
) as usize)
244 .read_error("Invalid ELF vd_aux")?
;
246 VerdauxIterator
::new(self.endian
, verdaux_data
.0, verdef
.vd_cnt
.get(self.endian
));
248 let next
= verdef
.vd_next
.get(self.endian
);
252 .read_error("Invalid ELF vd_next")?
;
254 self.data
= Bytes(&[]);
256 Ok(Some((verdef
, verdaux
)))
260 /// An iterator over the auxiliary records for an entry in an ELF `SHT_GNU_verdef` section.
261 #[derive(Debug, Clone)]
262 pub struct VerdauxIterator
<'data
, Elf
: FileHeader
> {
268 impl<'data
, Elf
: FileHeader
> VerdauxIterator
<'data
, Elf
> {
269 pub(super) fn new(endian
: Elf
::Endian
, data
: &'data
[u8], count
: u16) -> Self {
277 /// Return the next `Verdaux` entry.
278 pub fn next(&mut self) -> Result
<Option
<&'data elf
::Verdaux
<Elf
::Endian
>>> {
285 .read_at
::<elf
::Verdaux
<_
>>(0)
286 .read_error("ELF verdaux is too short")?
;
289 .skip(verdaux
.vda_next
.get(self.endian
) as usize)
290 .read_error("Invalid ELF vda_next")?
;
296 /// An iterator over the entries in an ELF `SHT_GNU_verneed` section.
297 #[derive(Debug, Clone)]
298 pub struct VerneedIterator
<'data
, Elf
: FileHeader
> {
303 impl<'data
, Elf
: FileHeader
> VerneedIterator
<'data
, Elf
> {
304 pub(super) fn new(endian
: Elf
::Endian
, data
: &'data
[u8]) -> Self {
311 /// Return the next `Verneed` entry.
316 &'data elf
::Verneed
<Elf
::Endian
>,
317 VernauxIterator
<'data
, Elf
>,
320 if self.data
.is_empty() {
326 .read_at
::<elf
::Verneed
<_
>>(0)
327 .read_error("ELF verneed is too short")?
;
329 let mut vernaux_data
= self.data
;
331 .skip(verneed
.vn_aux
.get(self.endian
) as usize)
332 .read_error("Invalid ELF vn_aux")?
;
334 VernauxIterator
::new(self.endian
, vernaux_data
.0, verneed
.vn_cnt
.get(self.endian
));
336 let next
= verneed
.vn_next
.get(self.endian
);
340 .read_error("Invalid ELF vn_next")?
;
342 self.data
= Bytes(&[]);
344 Ok(Some((verneed
, vernaux
)))
348 /// An iterator over the auxiliary records for an entry in an ELF `SHT_GNU_verneed` section.
349 #[derive(Debug, Clone)]
350 pub struct VernauxIterator
<'data
, Elf
: FileHeader
> {
356 impl<'data
, Elf
: FileHeader
> VernauxIterator
<'data
, Elf
> {
357 pub(super) fn new(endian
: Elf
::Endian
, data
: &'data
[u8], count
: u16) -> Self {
365 /// Return the next `Vernaux` entry.
366 pub fn next(&mut self) -> Result
<Option
<&'data elf
::Vernaux
<Elf
::Endian
>>> {
373 .read_at
::<elf
::Vernaux
<_
>>(0)
374 .read_error("ELF vernaux is too short")?
;
377 .skip(vernaux
.vna_next
.get(self.endian
) as usize)
378 .read_error("Invalid ELF vna_next")?
;
384 impl<Endian
: endian
::Endian
> elf
::Verdaux
<Endian
> {
385 /// Parse the version name from the string table.
386 pub fn name
<'data
, R
: ReadRef
<'data
>>(
389 strings
: StringTable
<'data
, R
>,
390 ) -> Result
<&'data
[u8]> {
392 .get(self.vda_name
.get(endian
))
393 .read_error("Invalid ELF vda_name")
397 impl<Endian
: endian
::Endian
> elf
::Verneed
<Endian
> {
398 /// Parse the file from the string table.
399 pub fn file
<'data
, R
: ReadRef
<'data
>>(
402 strings
: StringTable
<'data
, R
>,
403 ) -> Result
<&'data
[u8]> {
405 .get(self.vn_file
.get(endian
))
406 .read_error("Invalid ELF vn_file")
410 impl<Endian
: endian
::Endian
> elf
::Vernaux
<Endian
> {
411 /// Parse the version name from the string table.
412 pub fn name
<'data
, R
: ReadRef
<'data
>>(
415 strings
: StringTable
<'data
, R
>,
416 ) -> Result
<&'data
[u8]> {
418 .get(self.vna_name
.get(endian
))
419 .read_error("Invalid ELF vna_name")