Add mikros ELF loader to std
This commit is contained in:
parent
a428b626e5
commit
a9084ef21d
@ -1255,6 +1255,14 @@ dependencies = [
|
||||
"serde_json",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "elf"
|
||||
version = "0.7.4"
|
||||
dependencies = [
|
||||
"compiler_builtins",
|
||||
"rustc-std-workspace-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "elsa"
|
||||
version = "1.7.1"
|
||||
@ -5377,6 +5385,7 @@ dependencies = [
|
||||
"compiler_builtins",
|
||||
"core",
|
||||
"dlmalloc",
|
||||
"elf",
|
||||
"fortanix-sgx-abi",
|
||||
"hashbrown",
|
||||
"hermit-abi 0.4.0",
|
||||
|
@ -71,7 +71,7 @@ x86_64 = { path = "../../mikros_std_deps/x86_64-0.15.1", default-features = fals
|
||||
# derive-try-from-primitive = "1.0.0"
|
||||
# serde = { version = "1.0.151", default-features = false, features = ["alloc", "derive"] }
|
||||
# postcard = { version = "1.0.2", default-features = false, features = ["alloc"] }
|
||||
# elf = { version = "0.7.4", default-features = false }
|
||||
elf = { path = "../../mikros_std_deps/elf-0.7.4/", default-features = false, features = ["rustc-dep-of-std"] }
|
||||
|
||||
|
||||
[features]
|
||||
|
@ -3,7 +3,7 @@
|
||||
|
||||
use crate::sys::{
|
||||
buffers::KernelBufferAllocator,
|
||||
syscalls::{copy_to, drop_space, map_assert_unused, map_only_unused, map_free, new_space},
|
||||
syscalls::{copy_to, drop_space, map_assert_unused, map_only_unused, map_free, new_space, adsp_zero},
|
||||
};
|
||||
use alloc::vec::Vec;
|
||||
use crate::mem;
|
||||
@ -81,6 +81,11 @@ pub fn copy_to(&self, dst: *mut u8, src: &[u8]) -> Result<(), PagingError> {
|
||||
buf.extend_from_slice(src);
|
||||
copy_to(self.0, buf, dst, src.len()).map_err(|_| PagingError)
|
||||
}
|
||||
|
||||
#[stable(feature = "mikros", since = "1.80.0")]
|
||||
pub fn zero(&self, dst: *mut u8, len: usize) -> Result<(), PagingError> {
|
||||
adsp_zero(self.0, dst, len).map_err(|_| PagingError)
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "mikros", since = "1.80.0")]
|
||||
|
75
library/std/src/os/mikros/loader.rs
Normal file
75
library/std/src/os/mikros/loader.rs
Normal file
@ -0,0 +1,75 @@
|
||||
#![stable(feature = "mikros", since = "1.80.0")]
|
||||
|
||||
use elf::{abi::{PT_DYNAMIC, PT_GNU_EH_FRAME, PT_GNU_RELRO, PT_GNU_STACK, PT_LOAD, PT_NULL, PT_PHDR, R_X86_64_RELATIVE, SHT_REL, SHT_RELA}, endian::AnyEndian, ElfBytes};
|
||||
use x86_64::{structures::paging::Page, VirtAddr};
|
||||
|
||||
use super::address_space::AddressSpace;
|
||||
use crate::ptr;
|
||||
|
||||
#[stable(feature = "mikros", since = "1.80.0")]
|
||||
pub struct Loader;
|
||||
|
||||
impl Loader {
|
||||
#[must_use]
|
||||
#[stable(feature = "mikros", since = "1.80.0")]
|
||||
pub fn load(binary_raw: &[u8]) -> (AddressSpace, *const ()) {
|
||||
let binary = ElfBytes::<AnyEndian>::minimal_parse(&binary_raw).unwrap();
|
||||
let mut addr_space = AddressSpace::new();
|
||||
for mut pheader in binary.segments().unwrap().iter() {
|
||||
match pheader.p_type {
|
||||
PT_NULL => (),
|
||||
PT_LOAD => {
|
||||
if pheader.p_vaddr < 0x1000 {
|
||||
if pheader.p_memsz < 0x1000 {
|
||||
continue;
|
||||
}
|
||||
pheader.p_offset += 0x1000-pheader.p_vaddr;
|
||||
pheader.p_memsz -= 0x1000-pheader.p_vaddr;
|
||||
pheader.p_filesz -= 0x1000-pheader.p_vaddr;
|
||||
pheader.p_vaddr = 0x1000;
|
||||
}
|
||||
let start_page = Page::containing_address(VirtAddr::new(pheader.p_vaddr));
|
||||
let num_pages = (pheader.p_memsz.div_ceil(4096)
|
||||
+ (pheader.p_vaddr & 0xFFF).div_ceil(4096))
|
||||
as usize;
|
||||
assert!(
|
||||
(start_page.start_address().as_u64() + num_pages as u64 * 4096)
|
||||
>= (pheader.p_vaddr + pheader.p_memsz)
|
||||
);
|
||||
#[allow(clippy::cast_possible_truncation)]
|
||||
addr_space
|
||||
.map_only_unused(start_page, num_pages)
|
||||
.expect("Unable to map region");
|
||||
addr_space.copy_to(ptr::with_exposed_provenance_mut(pheader.p_vaddr as usize), &binary_raw[(pheader.p_offset as usize)..((pheader.p_offset+pheader.p_filesz) as usize)]).unwrap();
|
||||
addr_space.zero(ptr::with_exposed_provenance_mut((pheader.p_vaddr + pheader.p_filesz) as usize), (pheader.p_memsz - pheader.p_filesz) as usize).unwrap();
|
||||
}
|
||||
PT_GNU_RELRO => (),
|
||||
PT_GNU_EH_FRAME => (),
|
||||
PT_GNU_STACK => (),
|
||||
PT_DYNAMIC => (),
|
||||
PT_PHDR => (),
|
||||
_ => println!("Warning: Unimplemented ELF program header type {:#x}", pheader.p_type),
|
||||
}
|
||||
}
|
||||
for section in binary.section_headers().unwrap().iter() {
|
||||
if section.sh_type == SHT_REL {
|
||||
for rel in binary.section_data_as_rels(§ion).unwrap() {
|
||||
match rel.r_type {
|
||||
_ => unimplemented!("ELF relocation type {}", rel.r_type),
|
||||
}
|
||||
}
|
||||
}
|
||||
if section.sh_type == SHT_RELA {
|
||||
for rela in binary.section_data_as_relas(§ion).unwrap() {
|
||||
match rela.r_type {
|
||||
R_X86_64_RELATIVE => {
|
||||
addr_space.copy_to(ptr::with_exposed_provenance_mut(rela.r_offset as usize), (rela.r_addend as u64).to_ne_bytes().as_ref()).unwrap();
|
||||
}
|
||||
_ => unimplemented!("ELF relocation type {}", rela.r_type),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
(addr_space, ptr::with_exposed_provenance(binary.ehdr.e_entry as usize))
|
||||
}
|
||||
}
|
@ -4,4 +4,5 @@
|
||||
|
||||
pub mod ipc;
|
||||
pub mod address_space;
|
||||
|
||||
pub mod loader;
|
||||
pub mod syscalls;
|
||||
|
33
library/std/src/os/mikros/syscalls.rs
Normal file
33
library/std/src/os/mikros/syscalls.rs
Normal file
@ -0,0 +1,33 @@
|
||||
#![stable(feature = "mikros", since = "1.80.0")]
|
||||
#![allow(clippy::result_unit_err)]
|
||||
|
||||
use crate::sys::syscalls;
|
||||
use crate::os::mikros::address_space::AddressSpace;
|
||||
|
||||
#[must_use]
|
||||
#[stable(feature = "mikros", since = "1.80.0")]
|
||||
pub fn get_initrd() -> &'static [u8] {
|
||||
syscalls::get_initrd()
|
||||
}
|
||||
|
||||
#[stable(feature = "mikros", since = "1.80.0")]
|
||||
pub fn new_process(entry_point: u64, space: AddressSpace) -> Result<u64, ()> {
|
||||
syscalls::new_process(entry_point, space)
|
||||
}
|
||||
|
||||
#[stable(feature = "mikros", since = "1.80.0")]
|
||||
pub fn register(typ: u64) {
|
||||
syscalls::register(typ)
|
||||
}
|
||||
|
||||
#[stable(feature = "mikros", since = "1.80.0")]
|
||||
#[must_use]
|
||||
pub fn try_get_registered(typ: u64) -> Option<u64> {
|
||||
syscalls::try_get_registered(typ)
|
||||
}
|
||||
|
||||
#[stable(feature = "mikros", since = "1.80.0")]
|
||||
#[must_use]
|
||||
pub fn get_pid() -> u64 {
|
||||
syscalls::get_pid()
|
||||
}
|
@ -160,3 +160,15 @@ pub(crate) fn map_only_unused(
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn adsp_zero(
|
||||
space: u64,
|
||||
dst: *mut u8,
|
||||
len: usize,
|
||||
) -> Result<(), ()> {
|
||||
if syscall3(17, space, dst as u64, len as u64) == 1 {
|
||||
Err(())
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
6
mikros_std_deps/elf-0.7.4/.cargo_vcs_info.json
Normal file
6
mikros_std_deps/elf-0.7.4/.cargo_vcs_info.json
Normal file
@ -0,0 +1,6 @@
|
||||
{
|
||||
"git": {
|
||||
"sha1": "94d6780552465ebdc3d732f4a32d6bd00f1b8d70"
|
||||
},
|
||||
"path_in_vcs": ""
|
||||
}
|
190
mikros_std_deps/elf-0.7.4/CHANGELOG.md
Normal file
190
mikros_std_deps/elf-0.7.4/CHANGELOG.md
Normal file
@ -0,0 +1,190 @@
|
||||
# Change Log
|
||||
All notable changes to this project will be documented in this file.
|
||||
|
||||
The format is based on [Keep a Changelog](http://keepachangelog.com/)
|
||||
|
||||
## [0.7.4] - 2023-11-22
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- Fix note parsing for notes with n_namesz == (align * x + 1)
|
||||
|
||||
## [0.7.3] - 2023-10-09
|
||||
|
||||
### New Features
|
||||
|
||||
- Derive Debug on LittleEndian and BigEndian
|
||||
|
||||
### Misc Improvements
|
||||
|
||||
- Enable #![forbid(unsafe_code)]
|
||||
- Enable #![deny(missing_debug_implementations)]
|
||||
- Enable #![warn(rust_2018_idioms)]
|
||||
- Fix doc comment on file::Class
|
||||
- Fix README example so it compiles
|
||||
|
||||
## [0.7.2] - 2023-02-15
|
||||
|
||||
### New Features
|
||||
|
||||
- Implement core::error::Error for ParsingError accessible via a new non-default "nightly" cargo feature
|
||||
- Add abi constants for note descriptor types (n_type)
|
||||
- Add C-style struct definitions for various abi structs (Elf[32|64]_Ehdr etc). These aren't used by the parser, but are useful definitions for folks wanting to manually muck with elf bytes.
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- Fix an 'attempt to shift right with overflow' panic in the GnuHashTable if nshift is wider than the bloom filter word size
|
||||
|
||||
### Misc Improvements
|
||||
|
||||
- Add doc comments for EM_* abi constants
|
||||
- Tweak formatting and update language for various doc comments
|
||||
|
||||
## [0.7.1] - 2023-01-08
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- Fix a divide by zero panic in GnuHashTable.find() for tables with nbloom = 0
|
||||
|
||||
## [0.7.0] - 2022-11-14
|
||||
|
||||
### New Features
|
||||
|
||||
- Add new ElfBytes type with better ergonomics for parsing from a &[u8]
|
||||
- Add GnuHashTable which interprets the contents of a SHT_GNU_HASH section
|
||||
- Add convenience method section_header_by_name to ElfBytes and ElfStream
|
||||
- Add GnuBuildIdNote and parsing for NT_GNU_BUILD_ID note contents
|
||||
- Add GnuAbiTagNote and parsing for NT_GNU_ABI_TAG note contents
|
||||
- Add ElfBytes::symbol_version_table() to get the GNU extension symbol version table.
|
||||
- Add ElfBytes::find_common_data() to efficiently discover common ELF structures
|
||||
- Add a new endian-aware integer parsing trait impl
|
||||
- Add ParsingTable.is_empty()
|
||||
- Add abi constants for powerpc and powerpc64
|
||||
- Add abi constants for RISC-V
|
||||
- Add abi constants for x86_64
|
||||
- Add abi constants for ARM32 and ARM64 (AARCH64)
|
||||
- Add abi constant for GNU-extension ELF note name ELF_NOTE_GNU
|
||||
- Add abi constant for PT_GNU_PROPERTY
|
||||
- Add abi constants for SHN_ABS and SHN_COMMON
|
||||
- Add elf::to_str::d_tag_to_str()
|
||||
- Add elf::to_str::note_abi_tag_os_to_str()
|
||||
|
||||
### Changed Interfaces
|
||||
|
||||
- Rename elf::File -> elf::ElfStream and make it specific to the Read + Seek interface
|
||||
- Rename gabi -> abi since it also includes extension constants
|
||||
- Make ELF structures generic across the new endian-aware integer parsing trait EndianParse
|
||||
- Refactor parsed Note type to be a typed enum
|
||||
- Rename ElfStream::dynamic_section() -> dynamic() to match ElfBytes
|
||||
- Change ElfStream::dynamic() to yield a DynamicTable just like in ElfBytes
|
||||
- Standardize ElfBytes' interfaces for the .dynamic contents to return a DynamicTable
|
||||
- Export the parsing utilities ParsingTable, ParsingIterator in the public interface
|
||||
- Refactor section_headers_with_strtab to work with files that have shdrs but no shstrtab
|
||||
- Remove redundant hash arg from SysVHashTable.find()
|
||||
- Expose Class in the public interface alongside FileHeader
|
||||
- Remove opinionated Display impl for file::Class
|
||||
- Remove section_data_as_symbol_table() from public ElfBytes interface
|
||||
- Change SymbolVersionTable::new() to take Options instead of Default-empty iterators
|
||||
- Change ElfStream to parse out the ProgramHeaders into an allocated vec as part of ElfStream::open_stream()
|
||||
- Change ElfStream to parse out the SectionHeaders into an allocated Vec as part of ElfStream::open_stream()
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- Properly parse program header table when ehdr.e_phnum > 0xffff
|
||||
- Fix OOM in ElfStream parsing when parsing corrupted files
|
||||
- Fix a divide by zero panic in SysVHashTable.find() for empty tables
|
||||
|
||||
### Misc Improvements
|
||||
|
||||
- Add more fuzz testing
|
||||
- Add some simple parsing smoke tests for the various sample architecture objects
|
||||
- Add sample object and testing with > 0xff00 section headers
|
||||
- Add a lot more doc comments to each of the modules
|
||||
|
||||
## [0.6.1] - 2022-11-05
|
||||
|
||||
### New Features
|
||||
- Expose Class and Endian in the public interface. These types are exposed in the FileHeader type and so they should also be accessible for users to inspect.
|
||||
|
||||
## [0.6.0] - 2022-11-01
|
||||
|
||||
### New Features
|
||||
|
||||
- Add fuzz targets for parts of our ELF parsing interface via cargo-fuzz
|
||||
- Add SysVHashTable which interprets the contents of a SHT_HASH section
|
||||
- Add StringTable::get_raw() to get an uninterpreted &[u8]
|
||||
- Add ParsingTable.len() method to get the number of elements in the table
|
||||
- Add some note n_type constants for GNU extension notes.
|
||||
- Add default "to_str" feature to get &str for gabi constant names
|
||||
|
||||
### Changed Interfaces
|
||||
|
||||
- Change File::segments() to return a ParsingTable instead of just a ParsingIterator
|
||||
- Change File's SectionHeader interfaces to provide a ParsingTable instead of just a ParsingIterator
|
||||
- Remove deprecated File::section_data_for_header() in favor of File::section_data()
|
||||
- Remove FileHeader wrapper types OSABI, Architecture, and ObjectFileType
|
||||
- Remove ProgramHeader wrapper types ProgType and ProgFlag
|
||||
- Remove Symbol wrapper types SymbolType SymbolBind SymbolVis
|
||||
- Remove wrapper type SectionType
|
||||
- Remove unhelpful SectionFlag wrapper type
|
||||
- Remove Display impl for FileHeader, SectionHeader, ProgramHeader, Symbol
|
||||
- Remove ParseError::UnsupportedElfVersion in favor of more general ParseError::UnsupportedVersion
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- Fix divide by zero panic when parsing a note with alignment of 0 (Error instead of panic)
|
||||
- Use checked integer math all over the parsing code (Error instead of panic or overflow)
|
||||
- Fix note parsing for 8-byte aligned .note.gnu.property sections (Successfully parse instead of Erroring)
|
||||
- Add size validation when parsing tables with entsizes (Error instead of panic)
|
||||
|
||||
## [0.5.0] - 2022-10-30
|
||||
|
||||
### New Features
|
||||
|
||||
- Add File::symbol_version_table() interface to get the GNU extension symbol versioning table
|
||||
- Add Symbol.is_undefined() helper to check if a symbol is defined in this object
|
||||
- Add File::section_data() which opportunistically parses the CompressionHeader if present
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- Fix StringTable to return a ParseError on index out of bounds instead of panicking
|
||||
- Fix File::section_data_as_rels to properly parse Rels (not Relas)
|
||||
|
||||
## [0.4.0] - 2022-10-24
|
||||
|
||||
### New Features
|
||||
|
||||
- Add .note section and segment parsing
|
||||
- Add .dynamic section and segment parsing
|
||||
- Add .rel and .rela section parsing
|
||||
- Add File::section_headers_with_strtab to get both a header iter and strtab concurrently.
|
||||
|
||||
### Changed Interfaces
|
||||
|
||||
- The ReadBytesAt trait was changed to be implemented for an owned CachedReadBytes. This means that File::open_stream now expects to move-own the CachedReadBytes as opposed to taking a mutable reference.
|
||||
|
||||
## [0.3.1] - 2022-10-21
|
||||
|
||||
### New Features
|
||||
- Add File::section_data_for_header() to get raw section data for a given section
|
||||
|
||||
### Bug fixes
|
||||
- Fix section header table parsing when ehdr.e_shnum > 0xff00
|
||||
|
||||
## [0.3.0] - 2022-10-20
|
||||
|
||||
### New Features
|
||||
- Add a `no_std` option by fully moving the parser over to lazy zero-alloc parsing patterns.
|
||||
|
||||
<!-- next-url -->
|
||||
[0.7.4]: https://github.com/cole14/rust-elf/compare/v0.7.3...v0.7.4
|
||||
[0.7.3]: https://github.com/cole14/rust-elf/compare/v0.7.2...v0.7.3
|
||||
[0.7.2]: https://github.com/cole14/rust-elf/compare/v0.7.1...v0.7.2
|
||||
[0.7.1]: https://github.com/cole14/rust-elf/compare/v0.7.0...v0.7.1
|
||||
[0.7.0]: https://github.com/cole14/rust-elf/compare/v0.6.1...v0.7.0
|
||||
[0.6.1]: https://github.com/cole14/rust-elf/compare/v0.6.0...v0.6.1
|
||||
[0.6.0]: https://github.com/cole14/rust-elf/compare/v0.5.0...v0.6.0
|
||||
[0.5.0]: https://github.com/cole14/rust-elf/compare/v0.4.0...v0.5.0
|
||||
[0.4.0]: https://github.com/cole14/rust-elf/compare/v0.3.1...v0.4.0
|
||||
[0.3.1]: https://github.com/cole14/rust-elf/compare/v0.3.0...v0.3.1
|
||||
[0.3.0]: https://github.com/cole14/rust-elf/compare/v0.2.0...v0.3.0
|
12
mikros_std_deps/elf-0.7.4/COPYRIGHT
Normal file
12
mikros_std_deps/elf-0.7.4/COPYRIGHT
Normal file
@ -0,0 +1,12 @@
|
||||
rust-elf is licensed under either of
|
||||
|
||||
* Apache License, Version 2.0 (LICENSE-APACHE or
|
||||
http://www.apache.org/licenses/LICENSE-2.0)
|
||||
* MIT license ([LICENSE-MIT](LICENSE-MIT) or
|
||||
http://opensource.org/licenses/MIT)
|
||||
|
||||
at your option.
|
||||
|
||||
Unless you explicitly state otherwise, any contribution intentionally submitted
|
||||
for inclusion in the work by you, as defined in the Apache-2.0 license, shall
|
||||
be dual licensed as above, without any additional terms or conditions.
|
62
mikros_std_deps/elf-0.7.4/Cargo.toml
Normal file
62
mikros_std_deps/elf-0.7.4/Cargo.toml
Normal file
@ -0,0 +1,62 @@
|
||||
# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO
|
||||
#
|
||||
# When uploading crates to the registry Cargo will automatically
|
||||
# "normalize" Cargo.toml files for maximal compatibility
|
||||
# with all versions of Cargo and also rewrite `path` dependencies
|
||||
# to registry (e.g., crates.io) dependencies.
|
||||
#
|
||||
# If you are reading this file be aware that the original Cargo.toml
|
||||
# will likely look very different (and much more reasonable).
|
||||
# See Cargo.toml.orig for the original contents.
|
||||
|
||||
[package]
|
||||
edition = "2021"
|
||||
name = "elf"
|
||||
version = "0.7.4"
|
||||
authors = ["Christopher Cole <chris.cole.09@gmail.com>"]
|
||||
exclude = [
|
||||
".gitignore",
|
||||
"/.github",
|
||||
"/sample-objects",
|
||||
]
|
||||
description = "A pure-rust library for parsing ELF files"
|
||||
documentation = "https://docs.rs/elf/latest/elf/"
|
||||
readme = "README.md"
|
||||
keywords = [
|
||||
"binary",
|
||||
"elf",
|
||||
"object",
|
||||
"parser",
|
||||
]
|
||||
categories = [
|
||||
"no-std",
|
||||
"os",
|
||||
"embedded",
|
||||
]
|
||||
license = "MIT/Apache-2.0"
|
||||
repository = "https://github.com/cole14/rust-elf/"
|
||||
|
||||
[lib]
|
||||
name = "elf"
|
||||
|
||||
[dependencies.core]
|
||||
version = "1.0.0"
|
||||
optional = true
|
||||
package = "rustc-std-workspace-core"
|
||||
|
||||
[dependencies.compiler_builtins]
|
||||
version = "0.1"
|
||||
optional = true
|
||||
|
||||
[features]
|
||||
default = [
|
||||
"std",
|
||||
"to_str",
|
||||
]
|
||||
nightly = []
|
||||
std = []
|
||||
to_str = []
|
||||
rustc-dep-of-std = [
|
||||
"core",
|
||||
"compiler_builtins",
|
||||
]
|
25
mikros_std_deps/elf-0.7.4/Cargo.toml.orig
Normal file
25
mikros_std_deps/elf-0.7.4/Cargo.toml.orig
Normal file
@ -0,0 +1,25 @@
|
||||
[package]
|
||||
name = "elf"
|
||||
version = "0.7.4"
|
||||
authors = ["Christopher Cole <chris.cole.09@gmail.com>"]
|
||||
license = "MIT/Apache-2.0"
|
||||
repository = "https://github.com/cole14/rust-elf/"
|
||||
documentation = "https://docs.rs/elf/latest/elf/"
|
||||
description = "A pure-rust library for parsing ELF files"
|
||||
keywords = ["binary", "elf", "object", "parser"]
|
||||
categories = ["no-std", "os", "embedded"]
|
||||
exclude = [".gitignore", "/.github", "/sample-objects"]
|
||||
readme = "README.md"
|
||||
edition = "2021"
|
||||
|
||||
[lib]
|
||||
name = "elf"
|
||||
|
||||
[dependencies]
|
||||
|
||||
[features]
|
||||
default = ["std", "to_str"]
|
||||
std = []
|
||||
to_str = []
|
||||
# Enable for nightly feature(error_in_core) to impl core::error::Error on ParseError
|
||||
nightly = []
|
202
mikros_std_deps/elf-0.7.4/LICENSE-APACHE
Normal file
202
mikros_std_deps/elf-0.7.4/LICENSE-APACHE
Normal file
@ -0,0 +1,202 @@
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "{}"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright 2016 Christopher Cole
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
25
mikros_std_deps/elf-0.7.4/LICENSE-MIT
Normal file
25
mikros_std_deps/elf-0.7.4/LICENSE-MIT
Normal file
@ -0,0 +1,25 @@
|
||||
Copyright (c) 2016 Christopher Cole
|
||||
|
||||
Permission is hereby granted, free of charge, to any
|
||||
person obtaining a copy of this software and associated
|
||||
documentation files (the "Software"), to deal in the
|
||||
Software without restriction, including without
|
||||
limitation the rights to use, copy, modify, merge,
|
||||
publish, distribute, sublicense, and/or sell copies of
|
||||
the Software, and to permit persons to whom the Software
|
||||
is furnished to do so, subject to the following
|
||||
conditions:
|
||||
|
||||
The above copyright notice and this permission notice
|
||||
shall be included in all copies or substantial portions
|
||||
of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
|
||||
ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
|
||||
TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
|
||||
PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
|
||||
SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
|
||||
IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
DEALINGS IN THE SOFTWARE.
|
136
mikros_std_deps/elf-0.7.4/README.md
Normal file
136
mikros_std_deps/elf-0.7.4/README.md
Normal file
@ -0,0 +1,136 @@
|
||||
[![](https://img.shields.io/crates/v/elf.svg)](https://crates.io/crates/elf)
|
||||
[![](https://img.shields.io/crates/d/elf.svg)](https://crates.io/crates/elf)
|
||||
[![Build Status](https://github.com/cole14/rust-elf/actions/workflows/rust.yml/badge.svg)](https://github.com/cole14/rust-elf/actions)
|
||||
[![](https://docs.rs/elf/badge.svg)](https://docs.rs/elf/)
|
||||
|
||||
# rust-elf
|
||||
|
||||
The `elf` crate provides a pure-safe-rust interface for reading ELF object files.
|
||||
|
||||
[Documentation](https://docs.rs/elf/)
|
||||
|
||||
# Capabilities
|
||||
|
||||
### ✨ Works in `no_std` environments ✨
|
||||
This crate provides an elf parsing interface which does not allocate or use any std
|
||||
features, so it can be used in `no_std` environments such as kernels and bootloaders.
|
||||
The no_std variant merely disables the additional stream-oriented `std:: Read + Seek` interface.
|
||||
All core parsing functionality is the same!
|
||||
|
||||
### ✨ Endian-aware ✨
|
||||
This crate handles translating between file and host endianness when
|
||||
parsing the ELF contents and provides four endian parsing implementations
|
||||
optimized to support the different common use-cases for an ELF parsing library.
|
||||
Parsing is generic across the specifications and each trait impl represents a
|
||||
specification that encapsulates an interface for parsing integers from some
|
||||
set of allowed byte orderings.
|
||||
|
||||
* `AnyEndian`: Dynamically parsing either byte order at runtime based on the type of ELF object being parsed.
|
||||
* `BigEndian`/`LittleEndian`: For tools that know they only want to parse a single given byte order known at compile time.
|
||||
* `NativeEndian`: For tools that know they want to parse the same byte order as the compilation target's byte order.
|
||||
|
||||
When the limited specifications are used, errors are properly returned when asked to parse an ELF file
|
||||
with an unexpected byte ordering.
|
||||
|
||||
### ✨ Zero-alloc parser ✨
|
||||
This crate implements parsing in a way that avoids heap allocations. ELF structures
|
||||
are parsed and stored on the stack and provided by patterns such as lazily parsed iterators
|
||||
that yield stack allocated rust types, or lazily parsing tables that only parse out a particular
|
||||
entry on table.get(index). The structures are copy-converted as needed from the underlying file
|
||||
data into Rust's native struct representation.
|
||||
|
||||
### ✨ Fuzz Tested ✨
|
||||
Various parts of the library are fuzz tested for panics and crashes (see `fuzz/`).
|
||||
|
||||
Memory safety is a core goal, as is providing a safe interface that errors on bad data
|
||||
over crashing or panicking. Checked integer math is used where appropriate, and ParseErrors are
|
||||
returned when bad or corrupted ELF structures are encountered.
|
||||
|
||||
### ✨ Uses only safe interfaces ✨
|
||||
With memory safety a core goal, this crate contains zero unsafe code blocks of
|
||||
its own and only uses safe interface methods from core and std, so you can
|
||||
trust in rust's memory safety guarantees without also having to trust this
|
||||
library developer as having truly been "right" in why some unsafe block was
|
||||
safe. 💃
|
||||
|
||||
Note: I'd love to see this crate be enhanced further once rust provides safe transmutes.
|
||||
|
||||
See: <https://github.com/rust-lang/project-safe-transmute>
|
||||
|
||||
### ✨ Some zero-copy interfaces ✨
|
||||
The StringTable, for instance, yields `&[u8]` and `&str` backed by the raw string table bytes.
|
||||
|
||||
The `ElfBytes` parser type also does not make raw copies of the underlying file data to back
|
||||
the parser lazy parser interfaces `ParsingIterator` and `ParsingTable`. They merely wrap byte slices
|
||||
internally, and yield rust repr values on demand, which does entail copying of the bytes into the
|
||||
parsed rust-native format.
|
||||
|
||||
Depending on the use-case, it can be more efficient to restructure the raw ELF into different layouts
|
||||
for more efficient interpretation, say, by re-indexing a flat table into a HashMap. `ParsingIterator`s
|
||||
make that easy and rustily-intuitive.
|
||||
|
||||
The `ParsingIterator`s are also nice in that you can easily zip/enumerate/filter/collect them
|
||||
how you wish. Do you know that you want to do multiple passes over pairs from different tables? Just
|
||||
zip/collect them into another type so you only parse/endian-flip each entry once!
|
||||
|
||||
### ✨ Stream-based lazy i/o interface ✨
|
||||
The `ElfStream` parser type takes a `std:: Read + Seek` (such as `std::fs::File`) where ranges of
|
||||
file contents are read lazily on-demand based on what the user wants to parse.
|
||||
|
||||
This, alongside the bytes-oriented interface, allow you to decide which tradeoffs
|
||||
you want to make. If you're going to be working with the whole file contents,
|
||||
then the byte slice approach is probably worthwhile to minimize i/o overhead by
|
||||
streaming the whole file into memory at once. If you're only going to be
|
||||
inspecting part of the file, then the `ElfStream` approach would help avoid the
|
||||
overhead of reading a bunch of unused file data just to parse out a few things, (like
|
||||
grabbing the `.gnu.note.build-id`)
|
||||
|
||||
### ✨ Tiny library with no dependencies and fast compilation times ✨
|
||||
Release-target compilation times on this developer's 2021 m1 macbook are sub-second.
|
||||
|
||||
## Example using `ElfBytes`:
|
||||
|
||||
```rust
|
||||
use elf::ElfBytes;
|
||||
use elf::endian::AnyEndian;
|
||||
use elf::note::Note;
|
||||
use elf::note::NoteGnuBuildId;
|
||||
use elf::section::SectionHeader;
|
||||
|
||||
let path = std::path::PathBuf::from("sample-objects/symver.x86_64.so");
|
||||
let file_data = std::fs::read(path).expect("Could not read file.");
|
||||
let slice = file_data.as_slice();
|
||||
let file = ElfBytes::<AnyEndian>::minimal_parse(slice).expect("Open test1");
|
||||
|
||||
// Get the ELF file's build-id
|
||||
let abi_shdr: SectionHeader = file
|
||||
.section_header_by_name(".note.gnu.build-id")
|
||||
.expect("section table should be parseable")
|
||||
.expect("file should have a .note.ABI-tag section");
|
||||
|
||||
let notes: Vec<Note> = file
|
||||
.section_data_as_notes(&abi_shdr)
|
||||
.expect("Should be able to get note section data")
|
||||
.collect();
|
||||
assert_eq!(
|
||||
notes[0],
|
||||
Note::GnuBuildId(NoteGnuBuildId(
|
||||
&[140, 51, 19, 23, 221, 90, 215, 131, 169, 13,
|
||||
210, 183, 215, 77, 216, 175, 167, 110, 3, 209]))
|
||||
);
|
||||
|
||||
// Find lazy-parsing types for the common ELF sections (we want .dynsym, .dynstr, .hash)
|
||||
let common = file.find_common_data().expect("shdrs should parse");
|
||||
let (dynsyms, strtab) = (common.dynsyms.unwrap(), common.dynsyms_strs.unwrap());
|
||||
let hash_table = common.sysv_hash.unwrap();
|
||||
|
||||
// Use the hash table to find a given symbol in it.
|
||||
let name = b"memset";
|
||||
let (sym_idx, sym) = hash_table.find(name, &dynsyms, &strtab)
|
||||
.expect("hash table and symbols should parse").unwrap();
|
||||
|
||||
// Verify that we got the same symbol from the hash table we expected
|
||||
assert_eq!(sym_idx, 2);
|
||||
assert_eq!(strtab.get(sym.st_name as usize).unwrap(), "memset");
|
||||
assert_eq!(sym, dynsyms.get(sym_idx).unwrap());
|
||||
```
|
2660
mikros_std_deps/elf-0.7.4/src/abi.rs
Normal file
2660
mikros_std_deps/elf-0.7.4/src/abi.rs
Normal file
File diff suppressed because it is too large
Load Diff
153
mikros_std_deps/elf-0.7.4/src/compression.rs
Normal file
153
mikros_std_deps/elf-0.7.4/src/compression.rs
Normal file
@ -0,0 +1,153 @@
|
||||
//! Parsing [CompressionHeader] from compressed ELF sections
|
||||
//!
|
||||
//! Note: This library does not provide any decompression functionality, but
|
||||
//! does expose parsed ELF compression headers alongside the raw compressed data.
|
||||
//!
|
||||
//! It is up to users of the library to choose the decompression library of
|
||||
//! their choice when dealing with compressed section contents.
|
||||
use crate::endian::EndianParse;
|
||||
use crate::file::Class;
|
||||
use crate::parse::{ParseAt, ParseError};
|
||||
|
||||
/// C-style 32-bit ELF Compression Header definition
|
||||
///
|
||||
/// These C-style definitions are for users who want to implement their own ELF manipulation logic.
|
||||
#[derive(Debug)]
|
||||
#[repr(C)]
|
||||
pub struct Elf32_Chdr {
|
||||
pub ch_type: u32,
|
||||
pub ch_size: u32,
|
||||
pub ch_addralign: u32,
|
||||
}
|
||||
|
||||
/// C-style 64-bit ELF Compression Header definition
|
||||
///
|
||||
/// These C-style definitions are for users who want to implement their own ELF manipulation logic.
|
||||
#[derive(Debug)]
|
||||
#[repr(C)]
|
||||
pub struct Elf64_Chdr {
|
||||
pub ch_type: u32,
|
||||
pub ch_reserved: u32,
|
||||
pub ch_size: u64,
|
||||
pub ch_addralign: u64,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct CompressionHeader {
|
||||
pub ch_type: u32,
|
||||
pub ch_size: u64,
|
||||
pub ch_addralign: u64,
|
||||
}
|
||||
|
||||
impl ParseAt for CompressionHeader {
|
||||
fn parse_at<E: EndianParse>(
|
||||
endian: E,
|
||||
class: Class,
|
||||
offset: &mut usize,
|
||||
data: &[u8],
|
||||
) -> Result<Self, ParseError> {
|
||||
match class {
|
||||
Class::ELF32 => Ok(CompressionHeader {
|
||||
ch_type: endian.parse_u32_at(offset, data)?,
|
||||
ch_size: endian.parse_u32_at(offset, data)? as u64,
|
||||
ch_addralign: endian.parse_u32_at(offset, data)? as u64,
|
||||
}),
|
||||
Class::ELF64 => {
|
||||
let ch_type = endian.parse_u32_at(offset, data)?;
|
||||
let _ch_reserved = endian.parse_u32_at(offset, data)?;
|
||||
Ok(CompressionHeader {
|
||||
ch_type,
|
||||
ch_size: endian.parse_u64_at(offset, data)?,
|
||||
ch_addralign: endian.parse_u64_at(offset, data)?,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn size_for(class: Class) -> usize {
|
||||
match class {
|
||||
Class::ELF32 => 12,
|
||||
Class::ELF64 => 24,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod parse_tests {
|
||||
use super::*;
|
||||
use crate::endian::{BigEndian, LittleEndian};
|
||||
use crate::parse::{test_parse_for, test_parse_fuzz_too_short};
|
||||
|
||||
#[test]
|
||||
fn parse_chdr32_lsb() {
|
||||
test_parse_for(
|
||||
LittleEndian,
|
||||
Class::ELF32,
|
||||
CompressionHeader {
|
||||
ch_type: 0x03020100,
|
||||
ch_size: 0x07060504,
|
||||
ch_addralign: 0x0B0A0908,
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_chdr32_msb() {
|
||||
test_parse_for(
|
||||
BigEndian,
|
||||
Class::ELF32,
|
||||
CompressionHeader {
|
||||
ch_type: 0x00010203,
|
||||
ch_size: 0x04050607,
|
||||
ch_addralign: 0x08090A0B,
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_chdr64_lsb() {
|
||||
test_parse_for(
|
||||
LittleEndian,
|
||||
Class::ELF64,
|
||||
CompressionHeader {
|
||||
ch_type: 0x03020100,
|
||||
ch_size: 0x0F0E0D0C0B0A0908,
|
||||
ch_addralign: 0x1716151413121110,
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_chdr64_msb() {
|
||||
test_parse_for(
|
||||
BigEndian,
|
||||
Class::ELF64,
|
||||
CompressionHeader {
|
||||
ch_type: 0x00010203,
|
||||
ch_size: 0x08090A0B0C0D0E0F,
|
||||
ch_addralign: 0x1011121314151617,
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_chdr32_lsb_fuzz_too_short() {
|
||||
test_parse_fuzz_too_short::<_, CompressionHeader>(LittleEndian, Class::ELF32);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_chdr32_msb_fuzz_too_short() {
|
||||
test_parse_fuzz_too_short::<_, CompressionHeader>(BigEndian, Class::ELF32);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_chdr64_lsb_fuzz_too_short() {
|
||||
test_parse_fuzz_too_short::<_, CompressionHeader>(LittleEndian, Class::ELF64);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_chdr64_msb_fuzz_too_short() {
|
||||
test_parse_fuzz_too_short::<_, CompressionHeader>(BigEndian, Class::ELF64);
|
||||
}
|
||||
}
|
147
mikros_std_deps/elf-0.7.4/src/dynamic.rs
Normal file
147
mikros_std_deps/elf-0.7.4/src/dynamic.rs
Normal file
@ -0,0 +1,147 @@
|
||||
//! Parsing `.dynamic` section or [PT_DYNAMIC](crate::abi::PT_DYNAMIC) segment contents
|
||||
use crate::endian::EndianParse;
|
||||
use crate::file::Class;
|
||||
use crate::parse::{ParseAt, ParseError, ParsingTable};
|
||||
|
||||
pub type DynamicTable<'data, E> = ParsingTable<'data, E, Dyn>;
|
||||
|
||||
/// C-style 32-bit ELF Dynamic section entry definition
|
||||
///
|
||||
/// These C-style definitions are for users who want to implement their own ELF manipulation logic.
|
||||
#[derive(Debug)]
|
||||
#[repr(C)]
|
||||
pub struct Elf32_Dyn {
|
||||
pub d_tag: i32,
|
||||
// union of both {d_val, d_ptr}
|
||||
pub d_un: u32,
|
||||
}
|
||||
|
||||
/// C-style 64-bit ELF Dynamic section entry definition
|
||||
///
|
||||
/// These C-style definitions are for users who want to implement their own ELF manipulation logic.
|
||||
#[derive(Debug)]
|
||||
#[repr(C)]
|
||||
pub struct Elf64_Dyn {
|
||||
pub d_tag: i64,
|
||||
// union of both {d_val, d_ptr}
|
||||
pub d_un: u64,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct Dyn {
|
||||
pub d_tag: i64,
|
||||
pub(super) d_un: u64,
|
||||
}
|
||||
|
||||
impl Dyn {
|
||||
pub fn d_val(self) -> u64 {
|
||||
self.d_un
|
||||
}
|
||||
|
||||
pub fn d_ptr(self) -> u64 {
|
||||
self.d_un
|
||||
}
|
||||
}
|
||||
|
||||
impl ParseAt for Dyn {
|
||||
fn parse_at<E: EndianParse>(
|
||||
endian: E,
|
||||
class: Class,
|
||||
offset: &mut usize,
|
||||
data: &[u8],
|
||||
) -> Result<Self, ParseError> {
|
||||
match class {
|
||||
Class::ELF32 => Ok(Dyn {
|
||||
d_tag: endian.parse_i32_at(offset, data)? as i64,
|
||||
d_un: endian.parse_u32_at(offset, data)? as u64,
|
||||
}),
|
||||
Class::ELF64 => Ok(Dyn {
|
||||
d_tag: endian.parse_i64_at(offset, data)?,
|
||||
d_un: endian.parse_u64_at(offset, data)?,
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn size_for(class: Class) -> usize {
|
||||
match class {
|
||||
Class::ELF32 => 8,
|
||||
Class::ELF64 => 16,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod parse_tests {
|
||||
use super::*;
|
||||
use crate::endian::{BigEndian, LittleEndian};
|
||||
use crate::parse::{test_parse_for, test_parse_fuzz_too_short};
|
||||
|
||||
#[test]
|
||||
fn parse_dyn32_lsb() {
|
||||
test_parse_for(
|
||||
LittleEndian,
|
||||
Class::ELF32,
|
||||
Dyn {
|
||||
d_tag: 0x03020100,
|
||||
d_un: 0x07060504,
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_dyn32_msb() {
|
||||
test_parse_for(
|
||||
BigEndian,
|
||||
Class::ELF32,
|
||||
Dyn {
|
||||
d_tag: 0x00010203,
|
||||
d_un: 0x04050607,
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_dyn64_lsb() {
|
||||
test_parse_for(
|
||||
LittleEndian,
|
||||
Class::ELF64,
|
||||
Dyn {
|
||||
d_tag: 0x0706050403020100,
|
||||
d_un: 0x0F0E0D0C0B0A0908,
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_dyn64_msb() {
|
||||
test_parse_for(
|
||||
BigEndian,
|
||||
Class::ELF64,
|
||||
Dyn {
|
||||
d_tag: 0x0001020304050607,
|
||||
d_un: 0x08090A0B0C0D0E0F,
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_dyn32_lsb_fuzz_too_short() {
|
||||
test_parse_fuzz_too_short::<_, Dyn>(LittleEndian, Class::ELF32);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_dyn32_msb_fuzz_too_short() {
|
||||
test_parse_fuzz_too_short::<_, Dyn>(BigEndian, Class::ELF32);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_dyn64_lsb_fuzz_too_short() {
|
||||
test_parse_fuzz_too_short::<_, Dyn>(LittleEndian, Class::ELF64);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_dyn64_msb_fuzz_too_short() {
|
||||
test_parse_fuzz_too_short::<_, Dyn>(BigEndian, Class::ELF64);
|
||||
}
|
||||
}
|
1580
mikros_std_deps/elf-0.7.4/src/elf_bytes.rs
Normal file
1580
mikros_std_deps/elf-0.7.4/src/elf_bytes.rs
Normal file
File diff suppressed because it is too large
Load Diff
1280
mikros_std_deps/elf-0.7.4/src/elf_stream.rs
Normal file
1280
mikros_std_deps/elf-0.7.4/src/elf_stream.rs
Normal file
File diff suppressed because it is too large
Load Diff
327
mikros_std_deps/elf-0.7.4/src/endian.rs
Normal file
327
mikros_std_deps/elf-0.7.4/src/endian.rs
Normal file
@ -0,0 +1,327 @@
|
||||
//! An all-safe-code endian-aware integer parsing implementation via the
|
||||
//! [EndianParse] trait.
|
||||
//!
|
||||
//! This module provides four endian parsing implementations optimized to support the different
|
||||
//! common use-cases for an ELF parsing library. Each trait impl represents a
|
||||
//! specification that encapsulates an interface for parsing integers from some
|
||||
//! set of allowed byte orderings.
|
||||
//!
|
||||
//! * [AnyEndian]: Dynamically parsing either byte order at runtime based on the type of ELF object being parsed.
|
||||
//! * [BigEndian]/[LittleEndian]: For tools that know they only want to parse a single given byte order known at compile time.
|
||||
//! * [type@NativeEndian]: For tools that know they want to parse the same byte order as the target's byte order.
|
||||
//
|
||||
// Note:
|
||||
// I'd love to see this get replaced with safe transmutes, if that RFC ever gets formalized.
|
||||
// Until then, this crate serves as an example implementation for what's possible with purely safe rust.
|
||||
use crate::abi;
|
||||
use crate::parse::ParseError;
|
||||
|
||||
/// This macro writes out safe code to get a subslice from the the byte slice $data
|
||||
/// at the given $off as a [u8; size_of<$typ>], then calls the corresponding safe
|
||||
/// endian-aware conversion on it.
|
||||
///
|
||||
/// This uses safe integer math and returns a ParseError on overflow or if $data did
|
||||
/// not contain enough bytes at $off to perform the conversion.
|
||||
macro_rules! safe_from {
|
||||
( $self:ident, $typ:ty, $off:ident, $data:ident) => {{
|
||||
const SIZE: usize = core::mem::size_of::<$typ>();
|
||||
|
||||
let end = (*$off)
|
||||
.checked_add(SIZE)
|
||||
.ok_or(ParseError::IntegerOverflow)?;
|
||||
|
||||
let buf: [u8; SIZE] = $data
|
||||
.get(*$off..end)
|
||||
.ok_or(ParseError::SliceReadError((*$off, end)))?
|
||||
.try_into()?;
|
||||
|
||||
*$off = end;
|
||||
|
||||
// Note: This check evaluates to a constant true/false for the "fixed" types
|
||||
// so the compiler should optimize out the check (LittleEndian, BigEndian, NativeEndian)
|
||||
if $self.is_little() {
|
||||
Ok(<$typ>::from_le_bytes(buf))
|
||||
} else {
|
||||
Ok(<$typ>::from_be_bytes(buf))
|
||||
}
|
||||
}};
|
||||
}
|
||||
|
||||
/// An all-safe-code endian-aware integer parsing trait.
|
||||
///
|
||||
/// These methods use safe code to get a subslice from the the byte slice $data
|
||||
/// at the given $off as a [u8; size_of<$typ>], then calls the corresponding safe
|
||||
/// endian-aware conversion on it.
|
||||
///
|
||||
/// These use checked integer math and returns a ParseError on overflow or if $data did
|
||||
/// not contain enough bytes at $off to perform the conversion.
|
||||
pub trait EndianParse: Clone + Copy + Default + PartialEq + Eq {
|
||||
fn parse_u8_at(self, offset: &mut usize, data: &[u8]) -> Result<u8, ParseError> {
|
||||
safe_from!(self, u8, offset, data)
|
||||
}
|
||||
|
||||
fn parse_u16_at(self, offset: &mut usize, data: &[u8]) -> Result<u16, ParseError> {
|
||||
safe_from!(self, u16, offset, data)
|
||||
}
|
||||
|
||||
fn parse_u32_at(self, offset: &mut usize, data: &[u8]) -> Result<u32, ParseError> {
|
||||
safe_from!(self, u32, offset, data)
|
||||
}
|
||||
|
||||
fn parse_u64_at(self, offset: &mut usize, data: &[u8]) -> Result<u64, ParseError> {
|
||||
safe_from!(self, u64, offset, data)
|
||||
}
|
||||
|
||||
fn parse_i32_at(self, offset: &mut usize, data: &[u8]) -> Result<i32, ParseError> {
|
||||
safe_from!(self, i32, offset, data)
|
||||
}
|
||||
|
||||
fn parse_i64_at(self, offset: &mut usize, data: &[u8]) -> Result<i64, ParseError> {
|
||||
safe_from!(self, i64, offset, data)
|
||||
}
|
||||
|
||||
/// Get an endian-aware integer parsing spec for an ELF [FileHeader](crate::file::FileHeader)'s
|
||||
/// `ident[EI_DATA]` byte.
|
||||
///
|
||||
/// Returns an [UnsupportedElfEndianness](ParseError::UnsupportedElfEndianness) if this spec
|
||||
/// doesn't support parsing the byte-order represented by ei_data. If you're
|
||||
/// seeing this error, are you trying to read files of any endianness? i.e.
|
||||
/// did you want to use AnyEndian?
|
||||
fn from_ei_data(ei_data: u8) -> Result<Self, ParseError>;
|
||||
|
||||
fn is_little(self) -> bool;
|
||||
|
||||
#[inline(always)]
|
||||
fn is_big(self) -> bool {
|
||||
!self.is_little()
|
||||
}
|
||||
}
|
||||
|
||||
/// An endian parsing type that can choose at runtime which byte order to parse integers as.
|
||||
/// This is useful for scenarios where a single compiled binary wants to dynamically
|
||||
/// interpret ELF files of any byte order.
|
||||
#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
|
||||
pub enum AnyEndian {
|
||||
/// Used for a little-endian ELF structures that have been parsed with AnyEndian
|
||||
#[default]
|
||||
Little,
|
||||
/// Used for a big-endian ELF structures that have been parsed with AnyEndian
|
||||
Big,
|
||||
}
|
||||
|
||||
/// A zero-sized type that always parses integers as if they're in little-endian order.
|
||||
/// This is useful for scenarios where a combiled binary knows it only wants to interpret
|
||||
/// little-endian ELF files and doesn't want the performance penalty of evaluating a match
|
||||
/// each time it parses an integer.
|
||||
#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
|
||||
pub struct LittleEndian;
|
||||
|
||||
/// A zero-sized type that always parses integers as if they're in big-endian order.
|
||||
/// This is useful for scenarios where a combiled binary knows it only wants to interpret
|
||||
/// big-endian ELF files and doesn't want the performance penalty of evaluating a match
|
||||
/// each time it parses an integer.
|
||||
#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
|
||||
pub struct BigEndian;
|
||||
|
||||
/// A zero-sized type that always parses integers as if they're in the compilation target's native-endian order.
|
||||
/// This is useful for toolchain scenarios where a combiled binary knows it only wants to interpret
|
||||
/// ELF files compiled for the same target and doesn't want the performance penalty of evaluating a match
|
||||
/// each time it parses an integer.
|
||||
#[cfg(target_endian = "little")]
|
||||
pub type NativeEndian = LittleEndian;
|
||||
|
||||
#[cfg(target_endian = "little")]
|
||||
#[allow(non_upper_case_globals)]
|
||||
#[doc(hidden)]
|
||||
pub const NativeEndian: LittleEndian = LittleEndian;
|
||||
|
||||
/// A zero-sized type that always parses integers as if they're in the compilation target's native-endian order.
|
||||
/// This is useful for toolchain scenarios where a combiled binary knows it only wants to interpret
|
||||
/// ELF files compiled for the same target and doesn't want the performance penalty of evaluating a match
|
||||
/// each time it parses an integer.
|
||||
#[cfg(target_endian = "big")]
|
||||
pub type NativeEndian = BigEndian;
|
||||
|
||||
#[cfg(target_endian = "big")]
|
||||
#[allow(non_upper_case_globals)]
|
||||
#[doc(hidden)]
|
||||
pub const NativeEndian: BigEndian = BigEndian;
|
||||
|
||||
impl EndianParse for LittleEndian {
|
||||
fn from_ei_data(ei_data: u8) -> Result<Self, ParseError> {
|
||||
match ei_data {
|
||||
abi::ELFDATA2LSB => Ok(LittleEndian),
|
||||
_ => Err(ParseError::UnsupportedElfEndianness(ei_data)),
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn is_little(self) -> bool {
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
impl EndianParse for BigEndian {
|
||||
fn from_ei_data(ei_data: u8) -> Result<Self, ParseError> {
|
||||
match ei_data {
|
||||
abi::ELFDATA2MSB => Ok(BigEndian),
|
||||
_ => Err(ParseError::UnsupportedElfEndianness(ei_data)),
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn is_little(self) -> bool {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
impl EndianParse for AnyEndian {
|
||||
fn from_ei_data(ei_data: u8) -> Result<Self, ParseError> {
|
||||
match ei_data {
|
||||
abi::ELFDATA2LSB => Ok(AnyEndian::Little),
|
||||
abi::ELFDATA2MSB => Ok(AnyEndian::Big),
|
||||
_ => Err(ParseError::UnsupportedElfEndianness(ei_data)),
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn is_little(self) -> bool {
|
||||
match self {
|
||||
AnyEndian::Little => true,
|
||||
AnyEndian::Big => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
macro_rules! parse_test {
|
||||
( $endian:expr, $res_typ:ty, $method:ident, $expect:expr) => {{
|
||||
let bytes = [
|
||||
0x01u8, 0x02u8, 0x03u8, 0x04u8, 0x05u8, 0x06u8, 0x07u8, 0x08u8,
|
||||
];
|
||||
let mut offset = 0;
|
||||
let result = $endian.$method(&mut offset, &bytes).unwrap();
|
||||
assert_eq!(result, $expect);
|
||||
assert_eq!(offset, core::mem::size_of::<$res_typ>());
|
||||
}};
|
||||
}
|
||||
|
||||
macro_rules! fuzz_too_short_test {
|
||||
( $endian:expr, $res_typ:ty, $method:ident) => {{
|
||||
let bytes = [
|
||||
0x01u8, 0x02u8, 0x03u8, 0x04u8, 0x05u8, 0x06u8, 0x07u8, 0x08u8,
|
||||
];
|
||||
let size = core::mem::size_of::<$res_typ>();
|
||||
for n in 0..size {
|
||||
let buf = bytes.split_at(n).0.as_ref();
|
||||
let mut offset: usize = 0;
|
||||
let error = $endian
|
||||
.$method(&mut offset, buf)
|
||||
.expect_err("Expected an error, but parsed: ");
|
||||
assert!(
|
||||
matches!(error, ParseError::SliceReadError(_)),
|
||||
"Unexpected Error type found: {error}"
|
||||
);
|
||||
}
|
||||
}};
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_u8_at() {
|
||||
parse_test!(LittleEndian, u8, parse_u8_at, 0x01u8);
|
||||
parse_test!(BigEndian, u8, parse_u8_at, 0x01u8);
|
||||
parse_test!(AnyEndian::Little, u8, parse_u8_at, 0x01u8);
|
||||
parse_test!(AnyEndian::Big, u8, parse_u8_at, 0x01u8);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_u16_at() {
|
||||
parse_test!(LittleEndian, u16, parse_u16_at, 0x0201u16);
|
||||
parse_test!(BigEndian, u16, parse_u16_at, 0x0102u16);
|
||||
parse_test!(AnyEndian::Little, u16, parse_u16_at, 0x0201u16);
|
||||
parse_test!(AnyEndian::Big, u16, parse_u16_at, 0x0102u16);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_u32_at() {
|
||||
parse_test!(LittleEndian, u32, parse_u32_at, 0x04030201u32);
|
||||
parse_test!(BigEndian, u32, parse_u32_at, 0x01020304u32);
|
||||
parse_test!(AnyEndian::Little, u32, parse_u32_at, 0x04030201u32);
|
||||
parse_test!(AnyEndian::Big, u32, parse_u32_at, 0x01020304u32);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_u64_at() {
|
||||
parse_test!(LittleEndian, u64, parse_u64_at, 0x0807060504030201u64);
|
||||
parse_test!(BigEndian, u64, parse_u64_at, 0x0102030405060708u64);
|
||||
parse_test!(AnyEndian::Little, u64, parse_u64_at, 0x0807060504030201u64);
|
||||
parse_test!(AnyEndian::Big, u64, parse_u64_at, 0x0102030405060708u64);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_i32_at() {
|
||||
parse_test!(LittleEndian, i32, parse_i32_at, 0x04030201i32);
|
||||
parse_test!(BigEndian, i32, parse_i32_at, 0x01020304i32);
|
||||
parse_test!(AnyEndian::Little, i32, parse_i32_at, 0x04030201i32);
|
||||
parse_test!(AnyEndian::Big, i32, parse_i32_at, 0x01020304i32);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_i64_at() {
|
||||
parse_test!(LittleEndian, i64, parse_i64_at, 0x0807060504030201i64);
|
||||
parse_test!(BigEndian, i64, parse_i64_at, 0x0102030405060708i64);
|
||||
parse_test!(AnyEndian::Little, i64, parse_i64_at, 0x0807060504030201i64);
|
||||
parse_test!(AnyEndian::Big, i64, parse_i64_at, 0x0102030405060708i64);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn fuzz_u8_too_short() {
|
||||
fuzz_too_short_test!(LittleEndian, u8, parse_u8_at);
|
||||
fuzz_too_short_test!(BigEndian, u8, parse_u8_at);
|
||||
fuzz_too_short_test!(AnyEndian::Little, u8, parse_u8_at);
|
||||
fuzz_too_short_test!(AnyEndian::Big, u8, parse_u8_at);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn fuzz_u16_too_short() {
|
||||
fuzz_too_short_test!(LittleEndian, u16, parse_u16_at);
|
||||
fuzz_too_short_test!(BigEndian, u16, parse_u16_at);
|
||||
fuzz_too_short_test!(AnyEndian::Little, u16, parse_u16_at);
|
||||
fuzz_too_short_test!(AnyEndian::Big, u16, parse_u16_at);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn fuzz_u32_too_short() {
|
||||
fuzz_too_short_test!(LittleEndian, u32, parse_u32_at);
|
||||
fuzz_too_short_test!(BigEndian, u32, parse_u32_at);
|
||||
fuzz_too_short_test!(AnyEndian::Little, u32, parse_u32_at);
|
||||
fuzz_too_short_test!(AnyEndian::Big, u32, parse_u32_at);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn fuzz_i32_too_short() {
|
||||
fuzz_too_short_test!(LittleEndian, i32, parse_i32_at);
|
||||
fuzz_too_short_test!(BigEndian, i32, parse_i32_at);
|
||||
fuzz_too_short_test!(AnyEndian::Little, i32, parse_i32_at);
|
||||
fuzz_too_short_test!(AnyEndian::Big, i32, parse_i32_at);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn fuzz_u64_too_short() {
|
||||
fuzz_too_short_test!(LittleEndian, u64, parse_u64_at);
|
||||
fuzz_too_short_test!(BigEndian, u64, parse_u64_at);
|
||||
fuzz_too_short_test!(AnyEndian::Little, u64, parse_u64_at);
|
||||
fuzz_too_short_test!(AnyEndian::Big, u64, parse_u64_at);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn fuzz_i64_too_short() {
|
||||
fuzz_too_short_test!(LittleEndian, i64, parse_i64_at);
|
||||
fuzz_too_short_test!(BigEndian, i64, parse_i64_at);
|
||||
fuzz_too_short_test!(AnyEndian::Little, i64, parse_i64_at);
|
||||
fuzz_too_short_test!(AnyEndian::Big, i64, parse_i64_at);
|
||||
}
|
||||
}
|
478
mikros_std_deps/elf-0.7.4/src/file.rs
Normal file
478
mikros_std_deps/elf-0.7.4/src/file.rs
Normal file
@ -0,0 +1,478 @@
|
||||
//! Parsing the ELF File Header
|
||||
use crate::abi;
|
||||
use crate::endian::EndianParse;
|
||||
use crate::parse::ParseError;
|
||||
|
||||
/// Represents the ELF file word size (32-bit vs 64-bit)
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
|
||||
pub enum Class {
|
||||
ELF32,
|
||||
ELF64,
|
||||
}
|
||||
|
||||
/// C-style 32-bit ELF File Header definition
|
||||
///
|
||||
/// These C-style definitions are for users who want to implement their own ELF manipulation logic.
|
||||
#[derive(Debug)]
|
||||
#[repr(C)]
|
||||
pub struct Elf32_Ehdr {
|
||||
pub e_ident: [u8; abi::EI_NIDENT],
|
||||
pub e_type: u16,
|
||||
pub e_machine: u16,
|
||||
pub e_version: u32,
|
||||
pub e_entry: u32,
|
||||
pub e_phoff: u32,
|
||||
pub e_shoff: u32,
|
||||
pub e_flags: u32,
|
||||
pub e_ehsize: u16,
|
||||
pub e_phentsize: u16,
|
||||
pub e_phnum: u16,
|
||||
pub e_shentsize: u16,
|
||||
pub e_shnum: u16,
|
||||
pub e_shstrndx: u16,
|
||||
}
|
||||
|
||||
/// C-style 64-bit ELF File Header definition
|
||||
///
|
||||
/// These C-style definitions are for users who want to implement their own ELF manipulation logic.
|
||||
#[derive(Debug)]
|
||||
#[repr(C)]
|
||||
pub struct Elf64_Ehdr {
|
||||
pub e_ident: [u8; abi::EI_NIDENT],
|
||||
pub e_type: u16,
|
||||
pub e_machine: u16,
|
||||
pub e_version: u32,
|
||||
pub e_entry: u64,
|
||||
pub e_phoff: u64,
|
||||
pub e_shoff: u64,
|
||||
pub e_flags: u32,
|
||||
pub e_ehsize: u16,
|
||||
pub e_phentsize: u16,
|
||||
pub e_phnum: u16,
|
||||
pub e_shentsize: u16,
|
||||
pub e_shnum: u16,
|
||||
pub e_shstrndx: u16,
|
||||
}
|
||||
|
||||
/// Encapsulates the contents of the ELF File Header
|
||||
///
|
||||
/// The ELF File Header starts off every ELF file and both identifies the
|
||||
/// file contents and informs how to interpret said contents. This includes
|
||||
/// the width of certain fields (32-bit vs 64-bit), the data endianness, the
|
||||
/// file type, and more.
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||
pub struct FileHeader<E: EndianParse> {
|
||||
/// 32-bit vs 64-bit
|
||||
pub class: Class,
|
||||
// file byte order
|
||||
pub endianness: E,
|
||||
/// elf version
|
||||
pub version: u32,
|
||||
/// OS ABI
|
||||
pub osabi: u8,
|
||||
/// Version of the OS ABI
|
||||
pub abiversion: u8,
|
||||
/// ELF file type
|
||||
pub e_type: u16,
|
||||
/// Target machine architecture
|
||||
pub e_machine: u16,
|
||||
/// Virtual address of program entry point
|
||||
/// This member gives the virtual address to which the system first transfers control,
|
||||
/// thus starting the process. If the file has no associated entry point, this member holds zero.
|
||||
///
|
||||
/// Note: Type is Elf32_Addr or Elf64_Addr which are either 4 or 8 bytes. We aren't trying to zero-copy
|
||||
/// parse the FileHeader since there's only one per file and its only ~45 bytes anyway, so we use
|
||||
/// u64 for the three Elf*_Addr and Elf*_Off fields here.
|
||||
pub e_entry: u64,
|
||||
/// This member holds the program header table's file offset in bytes. If the file has no program header
|
||||
/// table, this member holds zero.
|
||||
pub e_phoff: u64,
|
||||
/// This member holds the section header table's file offset in bytes. If the file has no section header
|
||||
/// table, this member holds zero.
|
||||
pub e_shoff: u64,
|
||||
/// This member holds processor-specific flags associated with the file. Flag names take the form EF_machine_flag.
|
||||
pub e_flags: u32,
|
||||
/// This member holds the ELF header's size in bytes.
|
||||
pub e_ehsize: u16,
|
||||
/// This member holds the size in bytes of one entry in the file's program header table; all entries are the same size.
|
||||
pub e_phentsize: u16,
|
||||
/// This member holds the number of entries in the program header table. Thus the product of e_phentsize and e_phnum
|
||||
/// gives the table's size in bytes. If a file has no program header table, e_phnum holds the value zero.
|
||||
pub e_phnum: u16,
|
||||
/// This member holds a section header's size in bytes. A section header is one entry in the section header table;
|
||||
/// all entries are the same size.
|
||||
pub e_shentsize: u16,
|
||||
/// This member holds the number of entries in the section header table. Thus the product of e_shentsize and e_shnum
|
||||
/// gives the section header table's size in bytes. If a file has no section header table, e_shnum holds the value zero.
|
||||
///
|
||||
/// If the number of sections is greater than or equal to SHN_LORESERVE (0xff00), this member has the value zero and
|
||||
/// the actual number of section header table entries is contained in the sh_size field of the section header at index 0.
|
||||
/// (Otherwise, the sh_size member of the initial entry contains 0.)
|
||||
pub e_shnum: u16,
|
||||
/// This member holds the section header table index of the entry associated with the section name string table. If the
|
||||
/// file has no section name string table, this member holds the value SHN_UNDEF.
|
||||
///
|
||||
/// If the section name string table section index is greater than or equal to SHN_LORESERVE (0xff00), this member has
|
||||
/// the value SHN_XINDEX (0xffff) and the actual index of the section name string table section is contained in the
|
||||
/// sh_link field of the section header at index 0. (Otherwise, the sh_link member of the initial entry contains 0.)
|
||||
pub e_shstrndx: u16,
|
||||
}
|
||||
|
||||
pub const ELF32_EHDR_TAILSIZE: usize = 36;
|
||||
pub const ELF64_EHDR_TAILSIZE: usize = 48;
|
||||
|
||||
fn verify_ident(buf: &[u8]) -> Result<(), ParseError> {
|
||||
// Verify the magic number
|
||||
let magic = buf.split_at(abi::EI_CLASS).0;
|
||||
if magic != abi::ELFMAGIC {
|
||||
return Err(ParseError::BadMagic([
|
||||
magic[0], magic[1], magic[2], magic[3],
|
||||
]));
|
||||
}
|
||||
|
||||
// Verify ELF Version
|
||||
let version = buf[abi::EI_VERSION];
|
||||
if version != abi::EV_CURRENT {
|
||||
return Err(ParseError::UnsupportedVersion((
|
||||
version as u64,
|
||||
abi::EV_CURRENT as u64,
|
||||
)));
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn parse_ident<E: EndianParse>(data: &[u8]) -> Result<(E, Class, u8, u8), ParseError> {
|
||||
verify_ident(data)?;
|
||||
|
||||
let e_class = data[abi::EI_CLASS];
|
||||
let class = match e_class {
|
||||
abi::ELFCLASS32 => Class::ELF32,
|
||||
abi::ELFCLASS64 => Class::ELF64,
|
||||
_ => {
|
||||
return Err(ParseError::UnsupportedElfClass(e_class));
|
||||
}
|
||||
};
|
||||
|
||||
// Verify endianness is something we know how to parse
|
||||
let file_endian = E::from_ei_data(data[abi::EI_DATA])?;
|
||||
|
||||
Ok((
|
||||
file_endian,
|
||||
class,
|
||||
data[abi::EI_OSABI],
|
||||
data[abi::EI_ABIVERSION],
|
||||
))
|
||||
}
|
||||
|
||||
impl<E: EndianParse> FileHeader<E> {
|
||||
pub fn parse_tail(ident: (E, Class, u8, u8), data: &[u8]) -> Result<FileHeader<E>, ParseError> {
|
||||
let (file_endian, class, osabi, abiversion) = ident;
|
||||
|
||||
let mut offset = 0;
|
||||
let e_type = file_endian.parse_u16_at(&mut offset, data)?;
|
||||
let e_machine = file_endian.parse_u16_at(&mut offset, data)?;
|
||||
let version = file_endian.parse_u32_at(&mut offset, data)?;
|
||||
|
||||
let e_entry: u64;
|
||||
let e_phoff: u64;
|
||||
let e_shoff: u64;
|
||||
|
||||
if class == Class::ELF32 {
|
||||
e_entry = file_endian.parse_u32_at(&mut offset, data)? as u64;
|
||||
e_phoff = file_endian.parse_u32_at(&mut offset, data)? as u64;
|
||||
e_shoff = file_endian.parse_u32_at(&mut offset, data)? as u64;
|
||||
} else {
|
||||
e_entry = file_endian.parse_u64_at(&mut offset, data)?;
|
||||
e_phoff = file_endian.parse_u64_at(&mut offset, data)?;
|
||||
e_shoff = file_endian.parse_u64_at(&mut offset, data)?;
|
||||
}
|
||||
|
||||
let e_flags = file_endian.parse_u32_at(&mut offset, data)?;
|
||||
let e_ehsize = file_endian.parse_u16_at(&mut offset, data)?;
|
||||
let e_phentsize = file_endian.parse_u16_at(&mut offset, data)?;
|
||||
let e_phnum = file_endian.parse_u16_at(&mut offset, data)?;
|
||||
let e_shentsize = file_endian.parse_u16_at(&mut offset, data)?;
|
||||
let e_shnum = file_endian.parse_u16_at(&mut offset, data)?;
|
||||
let e_shstrndx = file_endian.parse_u16_at(&mut offset, data)?;
|
||||
|
||||
Ok(FileHeader {
|
||||
class,
|
||||
endianness: file_endian,
|
||||
version,
|
||||
e_type,
|
||||
e_machine,
|
||||
osabi,
|
||||
abiversion,
|
||||
e_entry,
|
||||
e_phoff,
|
||||
e_shoff,
|
||||
e_flags,
|
||||
e_ehsize,
|
||||
e_phentsize,
|
||||
e_phnum,
|
||||
e_shentsize,
|
||||
e_shnum,
|
||||
e_shstrndx,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod parse_tests {
|
||||
use super::*;
|
||||
use crate::endian::AnyEndian;
|
||||
|
||||
#[test]
|
||||
fn test_verify_ident_valid() {
|
||||
let data: [u8; abi::EI_NIDENT] = [
|
||||
abi::ELFMAG0,
|
||||
abi::ELFMAG1,
|
||||
abi::ELFMAG2,
|
||||
abi::ELFMAG3,
|
||||
abi::ELFCLASS32,
|
||||
abi::ELFDATA2LSB,
|
||||
abi::EV_CURRENT,
|
||||
abi::ELFOSABI_LINUX,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
];
|
||||
verify_ident(data.as_ref()).expect("Expected Ok result");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_verify_ident_invalid_mag0() {
|
||||
let data: [u8; abi::EI_NIDENT] = [
|
||||
0xFF,
|
||||
abi::ELFMAG1,
|
||||
abi::ELFMAG2,
|
||||
abi::ELFMAG3,
|
||||
abi::ELFCLASS32,
|
||||
abi::ELFDATA2LSB,
|
||||
abi::EV_CURRENT,
|
||||
abi::ELFOSABI_LINUX,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
];
|
||||
let result = verify_ident(data.as_ref()).expect_err("Expected an error");
|
||||
assert!(
|
||||
matches!(result, ParseError::BadMagic(_)),
|
||||
"Unexpected Error type found: {result}"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_verify_ident_invalid_mag1() {
|
||||
let data: [u8; abi::EI_NIDENT] = [
|
||||
abi::ELFMAG0,
|
||||
0xFF,
|
||||
abi::ELFMAG2,
|
||||
abi::ELFMAG3,
|
||||
abi::ELFCLASS32,
|
||||
abi::ELFDATA2LSB,
|
||||
abi::EV_CURRENT,
|
||||
abi::ELFOSABI_LINUX,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
];
|
||||
let result = verify_ident(data.as_ref()).expect_err("Expected an error");
|
||||
assert!(
|
||||
matches!(result, ParseError::BadMagic(_)),
|
||||
"Unexpected Error type found: {result}"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_verify_ident_invalid_mag2() {
|
||||
let data: [u8; abi::EI_NIDENT] = [
|
||||
abi::ELFMAG0,
|
||||
abi::ELFMAG1,
|
||||
0xFF,
|
||||
abi::ELFMAG3,
|
||||
abi::ELFCLASS32,
|
||||
abi::ELFDATA2LSB,
|
||||
abi::EV_CURRENT,
|
||||
abi::ELFOSABI_LINUX,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
];
|
||||
let result = verify_ident(data.as_ref()).expect_err("Expected an error");
|
||||
assert!(
|
||||
matches!(result, ParseError::BadMagic(_)),
|
||||
"Unexpected Error type found: {result}"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_verify_ident_invalid_mag3() {
|
||||
let data: [u8; abi::EI_NIDENT] = [
|
||||
abi::ELFMAG0,
|
||||
abi::ELFMAG1,
|
||||
abi::ELFMAG2,
|
||||
0xFF,
|
||||
abi::ELFCLASS32,
|
||||
abi::ELFDATA2LSB,
|
||||
abi::EV_CURRENT,
|
||||
abi::ELFOSABI_LINUX,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
];
|
||||
let result = verify_ident(data.as_ref()).expect_err("Expected an error");
|
||||
assert!(
|
||||
matches!(result, ParseError::BadMagic(_)),
|
||||
"Unexpected Error type found: {result}"
|
||||
);
|
||||
}
|
||||
|
||||
#[allow(deprecated)]
|
||||
#[test]
|
||||
fn test_verify_ident_invalid_version() {
|
||||
let data: [u8; abi::EI_NIDENT] = [
|
||||
abi::ELFMAG0,
|
||||
abi::ELFMAG1,
|
||||
abi::ELFMAG2,
|
||||
abi::ELFMAG3,
|
||||
abi::ELFCLASS32,
|
||||
abi::ELFDATA2LSB,
|
||||
42,
|
||||
abi::ELFOSABI_LINUX,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
];
|
||||
let result = verify_ident(data.as_ref()).expect_err("Expected an error");
|
||||
assert!(
|
||||
matches!(result, ParseError::UnsupportedVersion((42, 1))),
|
||||
"Unexpected Error type found: {result}"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_parse_ehdr32_works() {
|
||||
let ident = (AnyEndian::Little, Class::ELF32, abi::ELFOSABI_LINUX, 7u8);
|
||||
let mut tail = [0u8; ELF64_EHDR_TAILSIZE];
|
||||
for (n, elem) in tail.iter_mut().enumerate().take(ELF64_EHDR_TAILSIZE) {
|
||||
*elem = n as u8;
|
||||
}
|
||||
|
||||
assert_eq!(
|
||||
FileHeader::parse_tail(ident, &tail).unwrap(),
|
||||
FileHeader {
|
||||
class: Class::ELF32,
|
||||
endianness: AnyEndian::Little,
|
||||
version: 0x7060504,
|
||||
osabi: abi::ELFOSABI_LINUX,
|
||||
abiversion: 7,
|
||||
e_type: 0x100,
|
||||
e_machine: 0x302,
|
||||
e_entry: 0x0B0A0908,
|
||||
e_phoff: 0x0F0E0D0C,
|
||||
e_shoff: 0x13121110,
|
||||
e_flags: 0x17161514,
|
||||
e_ehsize: 0x1918,
|
||||
e_phentsize: 0x1B1A,
|
||||
e_phnum: 0x1D1C,
|
||||
e_shentsize: 0x1F1E,
|
||||
e_shnum: 0x2120,
|
||||
e_shstrndx: 0x2322,
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_parse_ehdr32_fuzz_too_short() {
|
||||
let ident = (AnyEndian::Little, Class::ELF32, abi::ELFOSABI_LINUX, 7u8);
|
||||
let tail = [0u8; ELF32_EHDR_TAILSIZE];
|
||||
|
||||
for n in 0..ELF32_EHDR_TAILSIZE {
|
||||
let buf = tail.split_at(n).0;
|
||||
let result = FileHeader::parse_tail(ident, buf).expect_err("Expected an error");
|
||||
assert!(
|
||||
matches!(result, ParseError::SliceReadError(_)),
|
||||
"Unexpected Error type found: {result:?}"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_parse_ehdr64_works() {
|
||||
let ident = (AnyEndian::Big, Class::ELF64, abi::ELFOSABI_LINUX, 7u8);
|
||||
let mut tail = [0u8; ELF64_EHDR_TAILSIZE];
|
||||
for (n, elem) in tail.iter_mut().enumerate().take(ELF64_EHDR_TAILSIZE) {
|
||||
*elem = n as u8;
|
||||
}
|
||||
|
||||
assert_eq!(
|
||||
FileHeader::parse_tail(ident, &tail).unwrap(),
|
||||
FileHeader {
|
||||
class: Class::ELF64,
|
||||
endianness: AnyEndian::Big,
|
||||
version: 0x04050607,
|
||||
osabi: abi::ELFOSABI_LINUX,
|
||||
abiversion: 7,
|
||||
e_type: 0x0001,
|
||||
e_machine: 0x0203,
|
||||
e_entry: 0x08090A0B0C0D0E0F,
|
||||
e_phoff: 0x1011121314151617,
|
||||
e_shoff: 0x18191A1B1C1D1E1F,
|
||||
e_flags: 0x20212223,
|
||||
e_ehsize: 0x2425,
|
||||
e_phentsize: 0x2627,
|
||||
e_phnum: 0x2829,
|
||||
e_shentsize: 0x2A2B,
|
||||
e_shnum: 0x2C2D,
|
||||
e_shstrndx: 0x2E2F,
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_parse_ehdr64_fuzz_too_short() {
|
||||
let ident = (AnyEndian::Little, Class::ELF64, abi::ELFOSABI_LINUX, 7u8);
|
||||
let tail = [0u8; ELF64_EHDR_TAILSIZE];
|
||||
|
||||
for n in 0..ELF64_EHDR_TAILSIZE {
|
||||
let buf = tail.split_at(n).0;
|
||||
let result = FileHeader::parse_tail(ident, buf).expect_err("Expected an error");
|
||||
assert!(
|
||||
matches!(result, ParseError::SliceReadError(_)),
|
||||
"Unexpected Error type found: {result:?}"
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
1592
mikros_std_deps/elf-0.7.4/src/gnu_symver.rs
Normal file
1592
mikros_std_deps/elf-0.7.4/src/gnu_symver.rs
Normal file
File diff suppressed because it is too large
Load Diff
495
mikros_std_deps/elf-0.7.4/src/hash.rs
Normal file
495
mikros_std_deps/elf-0.7.4/src/hash.rs
Normal file
@ -0,0 +1,495 @@
|
||||
//! Parsing hash table sections for symbol tables: `.hash`, and `.gnu.hash`
|
||||
use core::mem::size_of;
|
||||
|
||||
use crate::endian::EndianParse;
|
||||
use crate::file::Class;
|
||||
use crate::parse::{ParseAt, ParseError, ParsingTable, ReadBytesExt};
|
||||
use crate::string_table::StringTable;
|
||||
use crate::symbol::{Symbol, SymbolTable};
|
||||
|
||||
impl ParseAt for u32 {
|
||||
fn parse_at<E: EndianParse>(
|
||||
endian: E,
|
||||
_class: Class,
|
||||
offset: &mut usize,
|
||||
data: &[u8],
|
||||
) -> Result<Self, ParseError> {
|
||||
endian.parse_u32_at(offset, data)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn size_for(_class: Class) -> usize {
|
||||
core::mem::size_of::<u32>()
|
||||
}
|
||||
}
|
||||
|
||||
type U32Table<'data, E> = ParsingTable<'data, E, u32>;
|
||||
|
||||
/// Header at the start of SysV Hash Table sections of type [SHT_HASH](crate::abi::SHT_HASH).
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct SysVHashHeader {
|
||||
pub nbucket: u32,
|
||||
pub nchain: u32,
|
||||
}
|
||||
|
||||
impl ParseAt for SysVHashHeader {
|
||||
fn parse_at<E: EndianParse>(
|
||||
endian: E,
|
||||
_class: Class,
|
||||
offset: &mut usize,
|
||||
data: &[u8],
|
||||
) -> Result<Self, ParseError> {
|
||||
Ok(SysVHashHeader {
|
||||
nbucket: endian.parse_u32_at(offset, data)?,
|
||||
nchain: endian.parse_u32_at(offset, data)?,
|
||||
})
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn size_for(_class: Class) -> usize {
|
||||
size_of::<u32>() + size_of::<u32>()
|
||||
}
|
||||
}
|
||||
|
||||
/// Calculate the SysV hash value for a given symbol name.
|
||||
pub fn sysv_hash(name: &[u8]) -> u32 {
|
||||
let mut hash = 0u32;
|
||||
for byte in name {
|
||||
hash = hash.wrapping_mul(16).wrapping_add(*byte as u32);
|
||||
hash ^= (hash >> 24) & 0xf0;
|
||||
}
|
||||
hash & 0xfffffff
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct SysVHashTable<'data, E: EndianParse> {
|
||||
buckets: U32Table<'data, E>,
|
||||
chains: U32Table<'data, E>,
|
||||
}
|
||||
|
||||
/// This constructs a lazy-parsing type that keeps a reference to the provided data
|
||||
/// bytes from which it lazily parses and interprets its contents.
|
||||
impl<'data, E: EndianParse> SysVHashTable<'data, E> {
|
||||
/// Construct a SysVHashTable from given bytes. Keeps a reference to the data for lazy parsing.
|
||||
pub fn new(endian: E, class: Class, data: &'data [u8]) -> Result<Self, ParseError> {
|
||||
let mut offset = 0;
|
||||
let hdr = SysVHashHeader::parse_at(endian, class, &mut offset, data)?;
|
||||
|
||||
let buckets_size = size_of::<u32>()
|
||||
.checked_mul(hdr.nbucket.try_into()?)
|
||||
.ok_or(ParseError::IntegerOverflow)?;
|
||||
let buckets_end = offset
|
||||
.checked_add(buckets_size)
|
||||
.ok_or(ParseError::IntegerOverflow)?;
|
||||
let buckets_buf = data.get_bytes(offset..buckets_end)?;
|
||||
let buckets = U32Table::new(endian, class, buckets_buf);
|
||||
offset = buckets_end;
|
||||
|
||||
let chains_size = size_of::<u32>()
|
||||
.checked_mul(hdr.nchain.try_into()?)
|
||||
.ok_or(ParseError::IntegerOverflow)?;
|
||||
let chains_end = offset
|
||||
.checked_add(chains_size)
|
||||
.ok_or(ParseError::IntegerOverflow)?;
|
||||
let chains_buf = data.get_bytes(offset..chains_end)?;
|
||||
let chains = U32Table::new(endian, class, chains_buf);
|
||||
|
||||
Ok(SysVHashTable { buckets, chains })
|
||||
}
|
||||
|
||||
/// Use the hash table to find the symbol table entry with the given name and hash.
|
||||
pub fn find(
|
||||
&self,
|
||||
name: &[u8],
|
||||
symtab: &SymbolTable<'data, E>,
|
||||
strtab: &StringTable<'data>,
|
||||
) -> Result<Option<(usize, Symbol)>, ParseError> {
|
||||
// empty hash tables don't have any entries. This avoids a divde by zero in the modulus calculation
|
||||
if self.buckets.is_empty() {
|
||||
return Ok(None);
|
||||
}
|
||||
|
||||
let hash = sysv_hash(name);
|
||||
|
||||
let start = (hash as usize) % self.buckets.len();
|
||||
let mut index = self.buckets.get(start)? as usize;
|
||||
|
||||
// Bound the number of chain lookups by the chain size so we don't loop forever
|
||||
let mut i = 0;
|
||||
while index != 0 && i < self.chains.len() {
|
||||
let symbol = symtab.get(index)?;
|
||||
if strtab.get_raw(symbol.st_name as usize)? == name {
|
||||
return Ok(Some((index, symbol)));
|
||||
}
|
||||
|
||||
index = self.chains.get(index)? as usize;
|
||||
i += 1;
|
||||
}
|
||||
Ok(None)
|
||||
}
|
||||
}
|
||||
|
||||
/// Calculate the GNU hash for a given symbol name.
|
||||
pub fn gnu_hash(name: &[u8]) -> u32 {
|
||||
let mut hash = 5381u32;
|
||||
for byte in name {
|
||||
hash = hash.wrapping_mul(33).wrapping_add(u32::from(*byte));
|
||||
}
|
||||
hash
|
||||
}
|
||||
|
||||
/// Header at the start of a GNU extension Hash Table section of type [SHT_GNU_HASH](crate::abi::SHT_GNU_HASH).
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct GnuHashHeader {
|
||||
pub nbucket: u32,
|
||||
/// The symbol table index of the first symbol in the hash table.
|
||||
/// (GNU hash sections omit symbols at the start of the table that wont be looked up)
|
||||
pub table_start_idx: u32,
|
||||
/// The number of words in the bloom filter. (must be a non-zero power of 2)
|
||||
pub nbloom: u32,
|
||||
/// The bit shift count for the bloom filter.
|
||||
pub nshift: u32,
|
||||
}
|
||||
|
||||
impl ParseAt for GnuHashHeader {
|
||||
fn parse_at<E: EndianParse>(
|
||||
endian: E,
|
||||
_class: Class,
|
||||
offset: &mut usize,
|
||||
data: &[u8],
|
||||
) -> Result<Self, ParseError> {
|
||||
Ok(GnuHashHeader {
|
||||
nbucket: endian.parse_u32_at(offset, data)?,
|
||||
table_start_idx: endian.parse_u32_at(offset, data)?,
|
||||
nbloom: endian.parse_u32_at(offset, data)?,
|
||||
nshift: endian.parse_u32_at(offset, data)?,
|
||||
})
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn size_for(_class: Class) -> usize {
|
||||
size_of::<u32>() + size_of::<u32>() + size_of::<u32>() + size_of::<u32>()
|
||||
}
|
||||
}
|
||||
|
||||
type U64Table<'data, E> = ParsingTable<'data, E, u64>;
|
||||
|
||||
impl ParseAt for u64 {
|
||||
fn parse_at<E: EndianParse>(
|
||||
endian: E,
|
||||
_class: Class,
|
||||
offset: &mut usize,
|
||||
data: &[u8],
|
||||
) -> Result<Self, ParseError> {
|
||||
endian.parse_u64_at(offset, data)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn size_for(_class: Class) -> usize {
|
||||
core::mem::size_of::<u64>()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct GnuHashTable<'data, E: EndianParse> {
|
||||
pub hdr: GnuHashHeader,
|
||||
|
||||
endian: E,
|
||||
class: Class,
|
||||
bloom: &'data [u8],
|
||||
buckets: U32Table<'data, E>,
|
||||
chains: U32Table<'data, E>,
|
||||
}
|
||||
|
||||
impl<'data, E: EndianParse> GnuHashTable<'data, E> {
|
||||
/// Construct a GnuHashTable from given bytes. Keeps a reference to the data for lazy parsing.
|
||||
pub fn new(endian: E, class: Class, data: &'data [u8]) -> Result<Self, ParseError> {
|
||||
let mut offset = 0;
|
||||
let hdr = GnuHashHeader::parse_at(endian, class, &mut offset, data)?;
|
||||
|
||||
// length of the bloom filter in bytes. ELF32 is [u32; nbloom], ELF64 is [u64; nbloom].
|
||||
let nbloom: usize = hdr.nbloom as usize;
|
||||
let bloom_size = match class {
|
||||
Class::ELF32 => nbloom
|
||||
.checked_mul(size_of::<u32>())
|
||||
.ok_or(ParseError::IntegerOverflow)?,
|
||||
Class::ELF64 => nbloom
|
||||
.checked_mul(size_of::<u64>())
|
||||
.ok_or(ParseError::IntegerOverflow)?,
|
||||
};
|
||||
let bloom_end = offset
|
||||
.checked_add(bloom_size)
|
||||
.ok_or(ParseError::IntegerOverflow)?;
|
||||
let bloom_buf = data.get_bytes(offset..bloom_end)?;
|
||||
offset = bloom_end;
|
||||
|
||||
let buckets_size = size_of::<u32>()
|
||||
.checked_mul(hdr.nbucket.try_into()?)
|
||||
.ok_or(ParseError::IntegerOverflow)?;
|
||||
let buckets_end = offset
|
||||
.checked_add(buckets_size)
|
||||
.ok_or(ParseError::IntegerOverflow)?;
|
||||
let buckets_buf = data.get_bytes(offset..buckets_end)?;
|
||||
let buckets = U32Table::new(endian, class, buckets_buf);
|
||||
offset = buckets_end;
|
||||
|
||||
// the rest of the section is the chains
|
||||
let chains_buf = data
|
||||
.get(offset..)
|
||||
.ok_or(ParseError::SliceReadError((offset, data.len())))?;
|
||||
let chains = U32Table::new(endian, class, chains_buf);
|
||||
|
||||
Ok(GnuHashTable {
|
||||
hdr,
|
||||
endian,
|
||||
class,
|
||||
bloom: bloom_buf,
|
||||
buckets,
|
||||
chains,
|
||||
})
|
||||
}
|
||||
|
||||
/// Use the hash table to find the symbol table entry with the given name.
|
||||
pub fn find(
|
||||
&self,
|
||||
name: &[u8],
|
||||
symtab: &SymbolTable<'data, E>,
|
||||
strtab: &StringTable<'data>,
|
||||
) -> Result<Option<(usize, Symbol)>, ParseError> {
|
||||
// empty hash tables don't have any entries. This avoids a divde by zero in the modulus calculation,
|
||||
// and also avoids a potential division by zero panic in the bloom filter index calculation.
|
||||
if self.buckets.is_empty() || self.hdr.nbloom == 0 {
|
||||
return Ok(None);
|
||||
}
|
||||
|
||||
let hash = gnu_hash(name);
|
||||
|
||||
// Test against bloom filter.
|
||||
let (bloom_width, filter) = match self.class {
|
||||
Class::ELF32 => {
|
||||
let bloom_width: u32 = 8 * size_of::<u32>() as u32; // 32
|
||||
let bloom_idx = (hash / (bloom_width)) % self.hdr.nbloom;
|
||||
let bloom_table = U32Table::new(self.endian, self.class, self.bloom);
|
||||
(bloom_width, bloom_table.get(bloom_idx as usize)? as u64)
|
||||
}
|
||||
Class::ELF64 => {
|
||||
let bloom_width: u32 = 8 * size_of::<u64>() as u32; // 64
|
||||
let bloom_idx = (hash / (bloom_width)) % self.hdr.nbloom;
|
||||
let bloom_table = U64Table::new(self.endian, self.class, self.bloom);
|
||||
(bloom_width, bloom_table.get(bloom_idx as usize)?)
|
||||
}
|
||||
};
|
||||
|
||||
// Check bloom filter for both hashes - symbol is present in the hash table IFF both bits are set.
|
||||
if filter & (1 << (hash % bloom_width)) == 0 {
|
||||
return Ok(None);
|
||||
}
|
||||
let hash2 = hash
|
||||
.checked_shr(self.hdr.nshift)
|
||||
.ok_or(ParseError::IntegerOverflow)?;
|
||||
if filter & (1 << (hash2 % bloom_width)) == 0 {
|
||||
return Ok(None);
|
||||
}
|
||||
|
||||
let table_start_idx = self.hdr.table_start_idx as usize;
|
||||
let chain_start_idx = self.buckets.get((hash as usize) % self.buckets.len())? as usize;
|
||||
if chain_start_idx < table_start_idx {
|
||||
// All symbols before table_start_idx don't exist in the hash table
|
||||
return Ok(None);
|
||||
}
|
||||
|
||||
let chain_len = self.chains.len();
|
||||
for chain_idx in (chain_start_idx - table_start_idx)..chain_len {
|
||||
let chain_hash = self.chains.get(chain_idx)?;
|
||||
|
||||
// compare the hashes by or'ing the 1's bit back on
|
||||
if hash | 1 == chain_hash | 1 {
|
||||
// we have a hash match!
|
||||
// let's see if this symtab[sym_idx].name is what we're looking for
|
||||
let sym_idx = chain_idx
|
||||
.checked_add(table_start_idx)
|
||||
.ok_or(ParseError::IntegerOverflow)?;
|
||||
let symbol = symtab.get(sym_idx)?;
|
||||
let r_sym_name = strtab.get_raw(symbol.st_name as usize)?;
|
||||
|
||||
if r_sym_name == name {
|
||||
return Ok(Some((sym_idx, symbol)));
|
||||
}
|
||||
}
|
||||
|
||||
// the chain uses the 1's bit to signal chain comparison stoppage
|
||||
if chain_hash & 1 != 0 {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(None)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod sysv_parse_tests {
|
||||
use super::*;
|
||||
use crate::endian::{BigEndian, LittleEndian};
|
||||
use crate::parse::{test_parse_for, test_parse_fuzz_too_short};
|
||||
|
||||
#[test]
|
||||
fn parse_sysvhdr32_lsb() {
|
||||
test_parse_for(
|
||||
LittleEndian,
|
||||
Class::ELF32,
|
||||
SysVHashHeader {
|
||||
nbucket: 0x03020100,
|
||||
nchain: 0x07060504,
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_sysvhdr32_msb() {
|
||||
test_parse_for(
|
||||
BigEndian,
|
||||
Class::ELF32,
|
||||
SysVHashHeader {
|
||||
nbucket: 0x00010203,
|
||||
nchain: 0x04050607,
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_sysvhdr64_lsb() {
|
||||
test_parse_for(
|
||||
LittleEndian,
|
||||
Class::ELF64,
|
||||
SysVHashHeader {
|
||||
nbucket: 0x03020100,
|
||||
nchain: 0x07060504,
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_sysvhdr64_msb() {
|
||||
test_parse_for(
|
||||
BigEndian,
|
||||
Class::ELF64,
|
||||
SysVHashHeader {
|
||||
nbucket: 0x00010203,
|
||||
nchain: 0x04050607,
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_sysvhdr32_lsb_fuzz_too_short() {
|
||||
test_parse_fuzz_too_short::<_, SysVHashHeader>(LittleEndian, Class::ELF32);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_sysvhdr32_msb_fuzz_too_short() {
|
||||
test_parse_fuzz_too_short::<_, SysVHashHeader>(BigEndian, Class::ELF32);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_sysvhdr64_lsb_fuzz_too_short() {
|
||||
test_parse_fuzz_too_short::<_, SysVHashHeader>(LittleEndian, Class::ELF64);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_sysvhdr64_msb_fuzz_too_short() {
|
||||
test_parse_fuzz_too_short::<_, SysVHashHeader>(BigEndian, Class::ELF64);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod gnu_parse_tests {
|
||||
use super::*;
|
||||
use crate::endian::{BigEndian, LittleEndian};
|
||||
use crate::parse::{test_parse_for, test_parse_fuzz_too_short};
|
||||
|
||||
#[test]
|
||||
fn gnu_hash_tests() {
|
||||
// some known example hash values
|
||||
assert_eq!(gnu_hash(b""), 0x00001505);
|
||||
assert_eq!(gnu_hash(b"printf"), 0x156b2bb8);
|
||||
assert_eq!(gnu_hash(b"exit"), 0x7c967e3f);
|
||||
assert_eq!(gnu_hash(b"syscall"), 0xbac212a0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_gnuhdr32_lsb() {
|
||||
test_parse_for(
|
||||
LittleEndian,
|
||||
Class::ELF32,
|
||||
GnuHashHeader {
|
||||
nbucket: 0x03020100,
|
||||
table_start_idx: 0x07060504,
|
||||
nbloom: 0x0B0A0908,
|
||||
nshift: 0x0F0E0D0C,
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_gnuhdr32_msb() {
|
||||
test_parse_for(
|
||||
BigEndian,
|
||||
Class::ELF32,
|
||||
GnuHashHeader {
|
||||
nbucket: 0x00010203,
|
||||
table_start_idx: 0x04050607,
|
||||
nbloom: 0x008090A0B,
|
||||
nshift: 0x0C0D0E0F,
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_gnuhdr64_lsb() {
|
||||
test_parse_for(
|
||||
LittleEndian,
|
||||
Class::ELF64,
|
||||
GnuHashHeader {
|
||||
nbucket: 0x03020100,
|
||||
table_start_idx: 0x07060504,
|
||||
nbloom: 0x0B0A0908,
|
||||
nshift: 0x0F0E0D0C,
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_gnuhdr64_msb() {
|
||||
test_parse_for(
|
||||
BigEndian,
|
||||
Class::ELF64,
|
||||
GnuHashHeader {
|
||||
nbucket: 0x00010203,
|
||||
table_start_idx: 0x04050607,
|
||||
nbloom: 0x008090A0B,
|
||||
nshift: 0x0C0D0E0F,
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_gnuhdr32_lsb_fuzz_too_short() {
|
||||
test_parse_fuzz_too_short::<_, GnuHashHeader>(LittleEndian, Class::ELF32);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_gnuhdr32_msb_fuzz_too_short() {
|
||||
test_parse_fuzz_too_short::<_, GnuHashHeader>(BigEndian, Class::ELF32);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_gnuhdr64_lsb_fuzz_too_short() {
|
||||
test_parse_fuzz_too_short::<_, GnuHashHeader>(LittleEndian, Class::ELF64);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_gnuhdr64_msb_fuzz_too_short() {
|
||||
test_parse_fuzz_too_short::<_, GnuHashHeader>(BigEndian, Class::ELF64);
|
||||
}
|
||||
}
|
163
mikros_std_deps/elf-0.7.4/src/lib.rs
Normal file
163
mikros_std_deps/elf-0.7.4/src/lib.rs
Normal file
@ -0,0 +1,163 @@
|
||||
//! The `elf` crate provides a pure-safe-rust interface for reading ELF object files.
|
||||
//!
|
||||
//! # Capabilities
|
||||
//!
|
||||
//! ### ✨ Works in `no_std` environments ✨
|
||||
//! This crate provides an elf parsing interface which does not allocate or use any std
|
||||
//! features, so it can be used in `no_std` environments such as kernels and bootloaders.
|
||||
//! The no_std variant merely disables the additional stream-oriented `std:: Read + Seek` interface.
|
||||
//! All core parsing functionality is the same!
|
||||
//!
|
||||
//! ### ✨ Endian-aware ✨
|
||||
//! This crate handles translating between file and host endianness when
|
||||
//! parsing the ELF contents and provides four endian parsing implementations
|
||||
//! optimized to support the different common use-cases for an ELF parsing library.
|
||||
//! Parsing is generic across the specifications and each trait impl represents a
|
||||
//! specification that encapsulates an interface for parsing integers from some
|
||||
//! set of allowed byte orderings.
|
||||
//!
|
||||
//! * [AnyEndian](endian::AnyEndian): Dynamically parsing either byte order at runtime based on the type of ELF object being parsed.
|
||||
//! * [BigEndian](endian::BigEndian)/[LittleEndian](endian::LittleEndian): For tools that know they only want to parse a single given byte order known at compile time.
|
||||
//! * [NativeEndian](type@endian::NativeEndian): For tools that know they want to parse the same byte order as the compilation target's byte order.
|
||||
//!
|
||||
//! When the limited specifications are used, errors are properly returned when asked to parse an ELF file
|
||||
//! with an unexpected byte ordering.
|
||||
//!
|
||||
//! ### ✨ Zero-alloc parser ✨
|
||||
//! This crate implements parsing in a way that avoids heap allocations. ELF structures
|
||||
//! are parsed and stored on the stack and provided by patterns such as lazily parsed iterators
|
||||
//! that yield stack allocated rust types, or lazily parsing tables that only parse out a particular
|
||||
//! entry on table.get(index). The structures are copy-converted as needed from the underlying file
|
||||
//! data into Rust's native struct representation.
|
||||
//!
|
||||
//! ### ✨ Fuzz Tested ✨
|
||||
//! Various parts of the library are fuzz tested for panics and crashes (see `fuzz/`).
|
||||
//!
|
||||
//! Memory safety is a core goal, as is providing a safe interface that errors on bad data
|
||||
//! over crashing or panicking. Checked integer math is used where appropriate, and ParseErrors are
|
||||
//! returned when bad or corrupted ELF structures are encountered.
|
||||
//!
|
||||
//! ### ✨ Uses only safe interfaces ✨
|
||||
//! With memory safety a core goal, this crate contains zero unsafe code blocks
|
||||
//! of its own and only uses safe interface methods from core and std, so you can
|
||||
//! trust in rust's memory safety guarantees without also having to trust this
|
||||
//! library developer as having truly been "right" in why some unsafe block was
|
||||
//! safe. 💃
|
||||
//!
|
||||
//! Note: I'd love to see this crate be enhanced further once rust provides safe transmutes.
|
||||
//!
|
||||
//! See: <https://github.com/rust-lang/project-safe-transmute>
|
||||
//!
|
||||
//! ### ✨ Some zero-copy interfaces ✨
|
||||
//! The StringTable, for instance, yields `&[u8]` and `&str` backed by the raw string table bytes.
|
||||
//!
|
||||
//! The [ElfBytes] parser type also does not make raw copies of the underlying file data to back
|
||||
//! the parser lazy parser interfaces `ParsingIterator` and `ParsingTable`. They merely wrap byte slices
|
||||
//! internally, and yield rust repr values on demand, which does entail copying of the bytes into the
|
||||
//! parsed rust-native format.
|
||||
//!
|
||||
//! Depending on the use-case, it can be more efficient to restructure the raw ELF into different layouts
|
||||
//! for more efficient interpretation, say, by re-indexing a flat table into a HashMap. `ParsingIterator`s
|
||||
//! make that easy and rustily-intuitive.
|
||||
//!
|
||||
//! The `ParsingIterator`s are also nice in that you can easily zip/enumerate/filter/collect them
|
||||
//! how you wish. Do you know that you want to do multiple passes over pairs from different tables? Just
|
||||
//! zip/collect them into another type so you only parse/endian-flip each entry once!
|
||||
//!
|
||||
//! ### ✨ Stream-based lazy i/o interface ✨
|
||||
//! The [ElfStream] parser type takes a `std:: Read + Seek` (such as `std::fs::File`) where ranges of
|
||||
//! file contents are read lazily on-demand based on what the user wants to parse.
|
||||
//!
|
||||
//! This, alongside the bytes-oriented interface, allow you to decide which tradeoffs
|
||||
//! you want to make. If you're going to be working with the whole file contents,
|
||||
//! then the byte slice approach is probably worthwhile to minimize i/o overhead by
|
||||
//! streaming the whole file into memory at once. If you're only going to be
|
||||
//! inspecting part of the file, then the [ElfStream] approach would help avoid the
|
||||
//! overhead of reading a bunch of unused file data just to parse out a few things, (like
|
||||
//! grabbing the `.gnu.note.build-id`)
|
||||
//!
|
||||
//! ### ✨ Tiny library with no dependencies and fast compilation times ✨
|
||||
//! Release-target compilation times on this developer's 2021 m1 macbook are sub-second.
|
||||
//!
|
||||
//! Example using [ElfBytes]:
|
||||
//! ```
|
||||
//! use elf::ElfBytes;
|
||||
//! use elf::endian::AnyEndian;
|
||||
//! use elf::note::Note;
|
||||
//! use elf::note::NoteGnuBuildId;
|
||||
//! use elf::section::SectionHeader;
|
||||
//!
|
||||
//! let path = std::path::PathBuf::from("sample-objects/symver.x86_64.so");
|
||||
//! let file_data = std::fs::read(path).expect("Could not read file.");
|
||||
//! let slice = file_data.as_slice();
|
||||
//! let file = ElfBytes::<AnyEndian>::minimal_parse(slice).expect("Open test1");
|
||||
//!
|
||||
//! // Get the ELF file's build-id
|
||||
//! let abi_shdr: SectionHeader = file
|
||||
//! .section_header_by_name(".note.gnu.build-id")
|
||||
//! .expect("section table should be parseable")
|
||||
//! .expect("file should have a .note.ABI-tag section");
|
||||
//!
|
||||
//! let notes: Vec<Note> = file
|
||||
//! .section_data_as_notes(&abi_shdr)
|
||||
//! .expect("Should be able to get note section data")
|
||||
//! .collect();
|
||||
//! assert_eq!(
|
||||
//! notes[0],
|
||||
//! Note::GnuBuildId(NoteGnuBuildId(
|
||||
//! &[140, 51, 19, 23, 221, 90, 215, 131, 169, 13,
|
||||
//! 210, 183, 215, 77, 216, 175, 167, 110, 3, 209]))
|
||||
//! );
|
||||
//!
|
||||
//! // Find lazy-parsing types for the common ELF sections (we want .dynsym, .dynstr, .hash)
|
||||
//! let common = file.find_common_data().expect("shdrs should parse");
|
||||
//! let (dynsyms, strtab) = (common.dynsyms.unwrap(), common.dynsyms_strs.unwrap());
|
||||
//! let hash_table = common.sysv_hash.unwrap();
|
||||
//!
|
||||
//! // Use the hash table to find a given symbol in it.
|
||||
//! let name = b"memset";
|
||||
//! let (sym_idx, sym) = hash_table.find(name, &dynsyms, &strtab)
|
||||
//! .expect("hash table and symbols should parse").unwrap();
|
||||
//!
|
||||
//! // Verify that we got the same symbol from the hash table we expected
|
||||
//! assert_eq!(sym_idx, 2);
|
||||
//! assert_eq!(strtab.get(sym.st_name as usize).unwrap(), "memset");
|
||||
//! assert_eq!(sym, dynsyms.get(sym_idx).unwrap());
|
||||
//! ```
|
||||
|
||||
#![cfg_attr(not(feature = "std"), no_std)]
|
||||
#![cfg_attr(all(feature = "nightly", not(feature = "std")), feature(error_in_core))]
|
||||
#![warn(rust_2018_idioms)]
|
||||
#![deny(missing_debug_implementations)]
|
||||
#![forbid(unsafe_code)]
|
||||
|
||||
pub mod abi;
|
||||
|
||||
pub mod compression;
|
||||
pub mod dynamic;
|
||||
pub mod file;
|
||||
pub mod gnu_symver;
|
||||
pub mod hash;
|
||||
pub mod note;
|
||||
pub mod relocation;
|
||||
pub mod section;
|
||||
pub mod segment;
|
||||
pub mod string_table;
|
||||
pub mod symbol;
|
||||
|
||||
#[cfg(feature = "to_str")]
|
||||
pub mod to_str;
|
||||
|
||||
pub mod endian;
|
||||
pub mod parse;
|
||||
|
||||
mod elf_bytes;
|
||||
pub use elf_bytes::CommonElfData;
|
||||
pub use elf_bytes::ElfBytes;
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
mod elf_stream;
|
||||
#[cfg(feature = "std")]
|
||||
pub use elf_stream::ElfStream;
|
||||
|
||||
pub use parse::ParseError;
|
599
mikros_std_deps/elf-0.7.4/src/note.rs
Normal file
599
mikros_std_deps/elf-0.7.4/src/note.rs
Normal file
@ -0,0 +1,599 @@
|
||||
//! Parsing ELF notes: `.note.*`, [SHT_NOTE](crate::abi::SHT_NOTE), [PT_NOTE](crate::abi::PT_NOTE)
|
||||
//!
|
||||
//! Example for getting the GNU ABI-tag note:
|
||||
//! ```
|
||||
//! use elf::ElfBytes;
|
||||
//! use elf::endian::AnyEndian;
|
||||
//! use elf::note::Note;
|
||||
//! use elf::note::NoteGnuAbiTag;
|
||||
//!
|
||||
//! let path = std::path::PathBuf::from("sample-objects/basic.x86_64");
|
||||
//! let file_data = std::fs::read(path).expect("Could not read file.");
|
||||
//! let slice = file_data.as_slice();
|
||||
//! let file = ElfBytes::<AnyEndian>::minimal_parse(slice).expect("Open test1");
|
||||
//!
|
||||
//! let shdr = file
|
||||
//! .section_header_by_name(".note.ABI-tag")
|
||||
//! .expect("section table should be parseable")
|
||||
//! .expect("file should have a .note.ABI-tag section");
|
||||
//!
|
||||
//! let notes: Vec<_> = file
|
||||
//! .section_data_as_notes(&shdr)
|
||||
//! .expect("Should be able to get note section data")
|
||||
//! .collect();
|
||||
//! assert_eq!(
|
||||
//! notes[0],
|
||||
//! Note::GnuAbiTag(NoteGnuAbiTag {
|
||||
//! os: 0,
|
||||
//! major: 2,
|
||||
//! minor: 6,
|
||||
//! subminor: 32
|
||||
//! })
|
||||
//! );
|
||||
//! ```
|
||||
use crate::abi;
|
||||
use crate::endian::EndianParse;
|
||||
use crate::file::Class;
|
||||
use crate::parse::{ParseAt, ParseError, ReadBytesExt};
|
||||
use core::mem::size_of;
|
||||
use core::str::from_utf8;
|
||||
|
||||
/// This enum contains parsed Note variants which can be matched on
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
pub enum Note<'data> {
|
||||
/// (name: [abi::ELF_NOTE_GNU], n_type: [abi::NT_GNU_ABI_TAG])
|
||||
GnuAbiTag(NoteGnuAbiTag),
|
||||
/// (name: [abi::ELF_NOTE_GNU], n_type: [abi::NT_GNU_BUILD_ID])
|
||||
GnuBuildId(NoteGnuBuildId<'data>),
|
||||
/// All other notes that we don't know how to parse
|
||||
Unknown(NoteAny<'data>),
|
||||
}
|
||||
|
||||
impl<'data> Note<'data> {
|
||||
fn parse_at<E: EndianParse>(
|
||||
endian: E,
|
||||
_class: Class,
|
||||
align: usize,
|
||||
offset: &mut usize,
|
||||
data: &'data [u8],
|
||||
) -> Result<Self, ParseError> {
|
||||
// We don't know what to do if the section or segment header specified a zero alignment, so error
|
||||
// (this is likely a file corruption)
|
||||
if align == 0 {
|
||||
return Err(ParseError::UnexpectedAlignment(align));
|
||||
}
|
||||
|
||||
// It looks like clang and gcc emit 32-bit notes for 64-bit files, so we
|
||||
// currently always parse all note headers as 32-bit.
|
||||
let nhdr = NoteHeader::parse_at(endian, Class::ELF32, offset, data)?;
|
||||
|
||||
let name_start = *offset;
|
||||
let name_buf_size: usize = nhdr.n_namesz.saturating_sub(1).try_into()?;
|
||||
let name_buf_end = name_start
|
||||
.checked_add(name_buf_size)
|
||||
.ok_or(ParseError::IntegerOverflow)?;
|
||||
let name_buf = data.get_bytes(name_start..name_buf_end)?;
|
||||
let name = from_utf8(name_buf)?;
|
||||
|
||||
// move forward for entire namesz, including the NUL byte we left out of our str
|
||||
*offset = (*offset)
|
||||
.checked_add(nhdr.n_namesz.try_into()?)
|
||||
.ok_or(ParseError::IntegerOverflow)?;
|
||||
|
||||
// skip over padding if needed to get back to 4-byte alignment
|
||||
if *offset % align > 0 {
|
||||
*offset = (*offset)
|
||||
.checked_add(align - *offset % align)
|
||||
.ok_or(ParseError::IntegerOverflow)?;
|
||||
}
|
||||
|
||||
let desc_start = *offset;
|
||||
let desc_size: usize = nhdr.n_descsz.try_into()?;
|
||||
let desc_end = desc_start
|
||||
.checked_add(desc_size)
|
||||
.ok_or(ParseError::IntegerOverflow)?;
|
||||
let raw_desc = data.get_bytes(desc_start..desc_end)?;
|
||||
*offset = desc_end;
|
||||
|
||||
// skip over padding if needed to get back to 4-byte alignment
|
||||
if *offset % align > 0 {
|
||||
*offset = (*offset)
|
||||
.checked_add(align - *offset % align)
|
||||
.ok_or(ParseError::IntegerOverflow)?;
|
||||
}
|
||||
|
||||
// Interpret the note contents to try to return a known note variant
|
||||
match name {
|
||||
abi::ELF_NOTE_GNU => match nhdr.n_type {
|
||||
abi::NT_GNU_ABI_TAG => {
|
||||
let mut offset = 0;
|
||||
Ok(Note::GnuAbiTag(NoteGnuAbiTag::parse_at(
|
||||
endian,
|
||||
_class,
|
||||
&mut offset,
|
||||
raw_desc,
|
||||
)?))
|
||||
}
|
||||
abi::NT_GNU_BUILD_ID => Ok(Note::GnuBuildId(NoteGnuBuildId(raw_desc))),
|
||||
_ => Ok(Note::Unknown(NoteAny {
|
||||
n_type: nhdr.n_type,
|
||||
name,
|
||||
desc: raw_desc,
|
||||
})),
|
||||
},
|
||||
_ => Ok(Note::Unknown(NoteAny {
|
||||
n_type: nhdr.n_type,
|
||||
name,
|
||||
desc: raw_desc,
|
||||
})),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Contains four 4-byte integers.
|
||||
/// The first 4-byte integer specifies the os. The second, third, and fourth
|
||||
/// 4-byte integers contain the earliest compatible kernel version.
|
||||
/// For example, if the 3 integers are 6, 0, and 7, this signifies a 6.0.7 kernel.
|
||||
///
|
||||
/// (see: <https://raw.githubusercontent.com/wiki/hjl-tools/linux-abi/linux-abi-draft.pdf>)
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub struct NoteGnuAbiTag {
|
||||
pub os: u32,
|
||||
pub major: u32,
|
||||
pub minor: u32,
|
||||
pub subminor: u32,
|
||||
}
|
||||
|
||||
impl ParseAt for NoteGnuAbiTag {
|
||||
fn parse_at<E: EndianParse>(
|
||||
endian: E,
|
||||
_class: Class,
|
||||
offset: &mut usize,
|
||||
data: &[u8],
|
||||
) -> Result<Self, ParseError> {
|
||||
Ok(NoteGnuAbiTag {
|
||||
os: endian.parse_u32_at(offset, data)?,
|
||||
major: endian.parse_u32_at(offset, data)?,
|
||||
minor: endian.parse_u32_at(offset, data)?,
|
||||
subminor: endian.parse_u32_at(offset, data)?,
|
||||
})
|
||||
}
|
||||
|
||||
fn size_for(_class: Class) -> usize {
|
||||
size_of::<u32>() * 4
|
||||
}
|
||||
}
|
||||
|
||||
/// Contains a build ID note which is unique among the set of meaningful contents
|
||||
/// for ELF files and identical when the output file would otherwise have been identical.
|
||||
/// This is a zero-copy type which merely contains a slice of the note data from which it was parsed.
|
||||
///
|
||||
/// (see: <https://raw.githubusercontent.com/wiki/hjl-tools/linux-abi/linux-abi-draft.pdf>)
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub struct NoteGnuBuildId<'data>(pub &'data [u8]);
|
||||
|
||||
/// Contains the raw fields found in any ELF note. Used for notes that we don't know
|
||||
/// how to parse into more specific types.
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
pub struct NoteAny<'data> {
|
||||
pub n_type: u64,
|
||||
pub name: &'data str,
|
||||
pub desc: &'data [u8],
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct NoteIterator<'data, E: EndianParse> {
|
||||
endian: E,
|
||||
class: Class,
|
||||
align: usize,
|
||||
data: &'data [u8],
|
||||
offset: usize,
|
||||
}
|
||||
|
||||
impl<'data, E: EndianParse> NoteIterator<'data, E> {
|
||||
pub fn new(endian: E, class: Class, align: usize, data: &'data [u8]) -> Self {
|
||||
NoteIterator {
|
||||
endian,
|
||||
class,
|
||||
align,
|
||||
data,
|
||||
offset: 0,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'data, E: EndianParse> Iterator for NoteIterator<'data, E> {
|
||||
type Item = Note<'data>;
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
if self.data.is_empty() {
|
||||
return None;
|
||||
}
|
||||
|
||||
Note::parse_at(
|
||||
self.endian,
|
||||
self.class,
|
||||
self.align,
|
||||
&mut self.offset,
|
||||
self.data,
|
||||
)
|
||||
.ok()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
struct NoteHeader {
|
||||
pub n_namesz: u64,
|
||||
pub n_descsz: u64,
|
||||
pub n_type: u64,
|
||||
}
|
||||
|
||||
impl ParseAt for NoteHeader {
|
||||
fn parse_at<E: EndianParse>(
|
||||
endian: E,
|
||||
class: Class,
|
||||
offset: &mut usize,
|
||||
data: &[u8],
|
||||
) -> Result<Self, ParseError> {
|
||||
match class {
|
||||
Class::ELF32 => Ok(NoteHeader {
|
||||
n_namesz: endian.parse_u32_at(offset, data)? as u64,
|
||||
n_descsz: endian.parse_u32_at(offset, data)? as u64,
|
||||
n_type: endian.parse_u32_at(offset, data)? as u64,
|
||||
}),
|
||||
Class::ELF64 => Ok(NoteHeader {
|
||||
n_namesz: endian.parse_u64_at(offset, data)?,
|
||||
n_descsz: endian.parse_u64_at(offset, data)?,
|
||||
n_type: endian.parse_u64_at(offset, data)?,
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn size_for(class: Class) -> usize {
|
||||
match class {
|
||||
Class::ELF32 => 12,
|
||||
Class::ELF64 => 24,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod parse_tests {
|
||||
use super::*;
|
||||
use crate::abi;
|
||||
use crate::endian::{BigEndian, LittleEndian};
|
||||
|
||||
#[test]
|
||||
fn parse_nt_gnu_abi_tag() {
|
||||
#[rustfmt::skip]
|
||||
let data = [
|
||||
0x04, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
|
||||
0x01, 0x00, 0x00, 0x00, 0x47, 0x4e, 0x55, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
|
||||
0x06, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00,
|
||||
];
|
||||
|
||||
let mut offset = 0;
|
||||
let note = Note::parse_at(LittleEndian, Class::ELF32, 4, &mut offset, &data)
|
||||
.expect("Failed to parse");
|
||||
|
||||
assert_eq!(
|
||||
note,
|
||||
Note::GnuAbiTag(NoteGnuAbiTag {
|
||||
os: abi::ELF_NOTE_GNU_ABI_TAG_OS_LINUX,
|
||||
major: 2,
|
||||
minor: 6,
|
||||
subminor: 32
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_desc_gnu_build_id() {
|
||||
let data = [
|
||||
0x04, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x47, 0x4e,
|
||||
0x55, 0x00, 0x77, 0x41, 0x9f, 0x0d, 0xa5, 0x10, 0x83, 0x0c, 0x57, 0xa7, 0xc8, 0xcc,
|
||||
0xb0, 0xee, 0x85, 0x5f, 0xee, 0xd3, 0x76, 0xa3,
|
||||
];
|
||||
|
||||
let mut offset = 0;
|
||||
let note = Note::parse_at(LittleEndian, Class::ELF32, 4, &mut offset, &data)
|
||||
.expect("Failed to parse");
|
||||
|
||||
assert_eq!(
|
||||
note,
|
||||
Note::GnuBuildId(NoteGnuBuildId(&[
|
||||
0x77, 0x41, 0x9f, 0x0d, 0xa5, 0x10, 0x83, 0x0c, 0x57, 0xa7, 0xc8, 0xcc, 0xb0, 0xee,
|
||||
0x85, 0x5f, 0xee, 0xd3, 0x76, 0xa3,
|
||||
]))
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_note_errors_with_zero_alignment() {
|
||||
// This is a .note.gnu.property section
|
||||
#[rustfmt::skip]
|
||||
let data = [
|
||||
0x04, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
|
||||
0x05, 0x00, 0x00, 0x00, 0x47, 0x4e, 0x55, 0x00,
|
||||
0x02, 0x00, 0x00, 0xc0, 0x04, 0x00, 0x00, 0x00,
|
||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
];
|
||||
|
||||
let mut offset = 0;
|
||||
Note::parse_at(LittleEndian, Class::ELF64, 0, &mut offset, &data)
|
||||
.expect_err("Should have gotten an alignment error");
|
||||
}
|
||||
#[test]
|
||||
fn parse_note_with_8_byte_alignment() {
|
||||
// This is a .note.gnu.property section, which has been seen generated with 8-byte alignment
|
||||
#[rustfmt::skip]
|
||||
let data = [
|
||||
0x04, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
|
||||
0x05, 0x00, 0x00, 0x00, 0x47, 0x4e, 0x55, 0x00,
|
||||
0x02, 0x00, 0x00, 0xc0, 0x04, 0x00, 0x00, 0x00,
|
||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
];
|
||||
|
||||
// Even though the file class is ELF64, we parse it as a 32-bit struct. gcc/clang seem to output 32-bit notes
|
||||
// even though the gABI states that ELF64 files should contain 64-bit notes. Sometimes those notes are generated
|
||||
// in sections with 4-byte alignment, and other times with 8-byte alignment, as specified by shdr.sh_addralign.
|
||||
//
|
||||
// See https://raw.githubusercontent.com/wiki/hjl-tools/linux-abi/linux-abi-draft.pdf
|
||||
// Excerpt:
|
||||
// All entries in a PT_NOTE segment have the same alignment which equals to the
|
||||
// p_align field in program header.
|
||||
// According to gABI, each note entry should be aligned to 4 bytes in 32-bit
|
||||
// objects or 8 bytes in 64-bit objects. But .note.ABI-tag section (see Sec-
|
||||
// tion 2.1.6) and .note.gnu.build-id section (see Section 2.1.4) are aligned
|
||||
// to 4 bytes in both 32-bit and 64-bit objects. Note parser should use p_align for
|
||||
// note alignment, instead of assuming alignment based on ELF file class.
|
||||
let mut offset = 0;
|
||||
let note = Note::parse_at(LittleEndian, Class::ELF64, 8, &mut offset, &data)
|
||||
.expect("Failed to parse");
|
||||
assert_eq!(
|
||||
note,
|
||||
Note::Unknown(NoteAny {
|
||||
n_type: 5,
|
||||
name: abi::ELF_NOTE_GNU,
|
||||
desc: &[
|
||||
0x2, 0x0, 0x0, 0xc0, 0x4, 0x0, 0x0, 0x0, 0x3, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0
|
||||
]
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_note_with_8_byte_alignment_unaligned_namesz() {
|
||||
let data = [
|
||||
0x05, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, // namesz 5, descsz 2
|
||||
0x42, 0x00, 0x00, 0x00, 0x47, 0x4e, 0x55, 0x55, // type 42 (unknown), name GNUU
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // NUL + 7 pad for 8 alignment
|
||||
0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // desc 0102 + 6 pad for alignment
|
||||
];
|
||||
|
||||
let mut offset = 0;
|
||||
let note = Note::parse_at(LittleEndian, Class::ELF32, 8, &mut offset, &data)
|
||||
.expect("Failed to parse");
|
||||
assert_eq!(
|
||||
note,
|
||||
Note::Unknown(NoteAny {
|
||||
n_type: 0x42,
|
||||
name: &"GNUU",
|
||||
desc: &[0x01, 0x02],
|
||||
})
|
||||
);
|
||||
assert_eq!(offset, 32);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_note_for_elf64_expects_nhdr32() {
|
||||
let data = [
|
||||
0x04, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x47, 0x4e,
|
||||
0x55, 0x00, 0x77, 0x41, 0x9f, 0x0d, 0xa5, 0x10, 0x83, 0x0c, 0x57, 0xa7, 0xc8, 0xcc,
|
||||
0xb0, 0xee, 0x85, 0x5f, 0xee, 0xd3, 0x76, 0xa3,
|
||||
];
|
||||
|
||||
let mut offset = 0;
|
||||
// Even though the file class is ELF64, we parse it as a 32-bit struct. gcc/clang seem to output 32-bit notes
|
||||
// even though the gABI states that ELF64 files should contain 64-bit notes.
|
||||
let note = Note::parse_at(LittleEndian, Class::ELF64, 4, &mut offset, &data)
|
||||
.expect("Failed to parse");
|
||||
assert_eq!(
|
||||
note,
|
||||
Note::GnuBuildId(NoteGnuBuildId(&[
|
||||
0x77, 0x41, 0x9f, 0x0d, 0xa5, 0x10, 0x83, 0x0c, 0x57, 0xa7, 0xc8, 0xcc, 0xb0, 0xee,
|
||||
0x85, 0x5f, 0xee, 0xd3, 0x76, 0xa3,
|
||||
]))
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_note_32_lsb() {
|
||||
let data = [
|
||||
0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x20, 0x00,
|
||||
0x00, 0x00,
|
||||
];
|
||||
|
||||
let mut offset = 0;
|
||||
let note = Note::parse_at(LittleEndian, Class::ELF32, 4, &mut offset, &data)
|
||||
.expect("Failed to parse");
|
||||
assert_eq!(
|
||||
note,
|
||||
Note::Unknown(NoteAny {
|
||||
n_type: 6,
|
||||
name: "",
|
||||
desc: &[0x20, 0x0],
|
||||
})
|
||||
);
|
||||
assert_eq!(offset, 16);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_note_32_lsb_with_name_padding() {
|
||||
let data = [
|
||||
0x03, 0x00, 0x00, 0x00, // namesz 3
|
||||
0x04, 0x00, 0x00, 0x00, // descsz 4
|
||||
0x01, 0x00, 0x00, 0x00, // type 1
|
||||
0x47, 0x4e, 0x00, 0x00, // name GN\0 + 1 pad byte
|
||||
0x01, 0x02, 0x03, 0x04,
|
||||
]; // desc 01020304
|
||||
|
||||
let mut offset = 0;
|
||||
let note = Note::parse_at(LittleEndian, Class::ELF32, 4, &mut offset, &data)
|
||||
.expect("Failed to parse");
|
||||
assert_eq!(
|
||||
note,
|
||||
Note::Unknown(NoteAny {
|
||||
n_type: 1,
|
||||
name: "GN",
|
||||
desc: &[0x01, 0x02, 0x03, 0x04],
|
||||
})
|
||||
);
|
||||
assert_eq!(offset, 20);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_note_32_lsb_with_desc_padding() {
|
||||
let data = [
|
||||
0x04, 0x00, 0x00, 0x00, // namesz 4
|
||||
0x02, 0x00, 0x00, 0x00, // descsz 2
|
||||
0x42, 0x00, 0x00, 0x00, // type 42 (unknown)
|
||||
0x47, 0x4e, 0x55, 0x00, // name GNU\0
|
||||
0x01, 0x02, 0x00, 0x00, // desc 0102 + 2 pad bytes
|
||||
];
|
||||
|
||||
let mut offset = 0;
|
||||
let note = Note::parse_at(LittleEndian, Class::ELF32, 4, &mut offset, &data)
|
||||
.expect("Failed to parse");
|
||||
assert_eq!(
|
||||
note,
|
||||
Note::Unknown(NoteAny {
|
||||
n_type: 0x42,
|
||||
name: abi::ELF_NOTE_GNU,
|
||||
desc: &[0x01, 0x02],
|
||||
})
|
||||
);
|
||||
assert_eq!(offset, 20);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_note_32_lsb_with_no_name() {
|
||||
let data = [
|
||||
0x00, 0x00, 0x00, 0x00, // namesz 0
|
||||
0x02, 0x00, 0x00, 0x00, // descsz 2
|
||||
0x42, 0x00, 0x00, 0x00, // type 42 (unknown)
|
||||
0x20, 0x00, 0x00, 0x00, // desc 20, 00 + 2 pad bytes
|
||||
];
|
||||
|
||||
let mut offset = 0;
|
||||
let note = Note::parse_at(LittleEndian, Class::ELF32, 4, &mut offset, &data)
|
||||
.expect("Failed to parse");
|
||||
assert_eq!(
|
||||
note,
|
||||
Note::Unknown(NoteAny {
|
||||
n_type: 0x42,
|
||||
name: "",
|
||||
desc: &[0x20, 0x0],
|
||||
})
|
||||
);
|
||||
assert_eq!(offset, 16);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_note_32_lsb_with_no_desc() {
|
||||
let data = [
|
||||
0x04, 0x00, 0x00, 0x00, // namesz 4
|
||||
0x00, 0x00, 0x00, 0x00, // descsz 0
|
||||
0x42, 0x00, 0x00, 0x00, // type 42 (unknown)
|
||||
0x47, 0x4e, 0x55, 0x00, // name GNU\0
|
||||
];
|
||||
|
||||
let mut offset = 0;
|
||||
let note = Note::parse_at(LittleEndian, Class::ELF32, 4, &mut offset, &data)
|
||||
.expect("Failed to parse");
|
||||
assert_eq!(
|
||||
note,
|
||||
Note::Unknown(NoteAny {
|
||||
n_type: 0x42,
|
||||
name: abi::ELF_NOTE_GNU,
|
||||
desc: &[],
|
||||
})
|
||||
);
|
||||
assert_eq!(offset, 16);
|
||||
}
|
||||
|
||||
use crate::parse::{test_parse_for, test_parse_fuzz_too_short};
|
||||
|
||||
#[test]
|
||||
fn parse_nhdr32_lsb() {
|
||||
test_parse_for(
|
||||
LittleEndian,
|
||||
Class::ELF32,
|
||||
NoteHeader {
|
||||
n_namesz: 0x03020100,
|
||||
n_descsz: 0x07060504,
|
||||
n_type: 0x0B0A0908,
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_nhdr32_msb() {
|
||||
test_parse_for(
|
||||
BigEndian,
|
||||
Class::ELF32,
|
||||
NoteHeader {
|
||||
n_namesz: 0x00010203,
|
||||
n_descsz: 0x04050607,
|
||||
n_type: 0x08090A0B,
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_nhdr64_lsb() {
|
||||
test_parse_for(
|
||||
LittleEndian,
|
||||
Class::ELF64,
|
||||
NoteHeader {
|
||||
n_namesz: 0x0706050403020100,
|
||||
n_descsz: 0x0F0E0D0C0B0A0908,
|
||||
n_type: 0x1716151413121110,
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_nhdr64_msb() {
|
||||
test_parse_for(
|
||||
BigEndian,
|
||||
Class::ELF64,
|
||||
NoteHeader {
|
||||
n_namesz: 0x0001020304050607,
|
||||
n_descsz: 0x08090A0B0C0D0E0F,
|
||||
n_type: 0x1011121314151617,
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_nhdr32_lsb_fuzz_too_short() {
|
||||
test_parse_fuzz_too_short::<_, NoteHeader>(LittleEndian, Class::ELF32);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_nhdr32_msb_fuzz_too_short() {
|
||||
test_parse_fuzz_too_short::<_, NoteHeader>(BigEndian, Class::ELF32);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_nhdr64_lsb_fuzz_too_short() {
|
||||
test_parse_fuzz_too_short::<_, NoteHeader>(LittleEndian, Class::ELF64);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_nhdr64_msb_fuzz_too_short() {
|
||||
test_parse_fuzz_too_short::<_, NoteHeader>(BigEndian, Class::ELF64);
|
||||
}
|
||||
}
|
502
mikros_std_deps/elf-0.7.4/src/parse.rs
Normal file
502
mikros_std_deps/elf-0.7.4/src/parse.rs
Normal file
@ -0,0 +1,502 @@
|
||||
//! Utilities to drive safe and lazy parsing of ELF structures.
|
||||
use core::{marker::PhantomData, ops::Range};
|
||||
|
||||
use crate::endian::EndianParse;
|
||||
use crate::file::Class;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum ParseError {
|
||||
/// Returned when the ELF File Header's magic bytes weren't ELF's defined
|
||||
/// magic bytes
|
||||
BadMagic([u8; 4]),
|
||||
/// Returned when the ELF File Header's `e_ident[EI_CLASS]` wasn't one of the
|
||||
/// defined `ELFCLASS*` constants
|
||||
UnsupportedElfClass(u8),
|
||||
/// Returned when the ELF File Header's `e_ident[EI_DATA]` wasn't one of the
|
||||
/// defined `ELFDATA*` constants
|
||||
UnsupportedElfEndianness(u8),
|
||||
/// Returned when parsing an ELF struct with a version field whose value wasn't
|
||||
/// something we support and know how to parse.
|
||||
UnsupportedVersion((u64, u64)),
|
||||
/// Returned when parsing an ELF structure resulted in an offset which fell
|
||||
/// out of bounds of the requested structure
|
||||
BadOffset(u64),
|
||||
/// Returned when parsing a string out of a StringTable failed to find the
|
||||
/// terminating NUL byte
|
||||
StringTableMissingNul(u64),
|
||||
/// Returned when parsing a table of ELF structures and the file specified
|
||||
/// an entry size for that table that was different than what we had
|
||||
/// expected
|
||||
BadEntsize((u64, u64)),
|
||||
/// Returned when trying to interpret a section's data as the wrong type.
|
||||
/// For example, trying to treat an SHT_PROGBIGS section as a SHT_STRTAB.
|
||||
UnexpectedSectionType((u32, u32)),
|
||||
/// Returned when trying to interpret a segment's data as the wrong type.
|
||||
/// For example, trying to treat an PT_LOAD section as a PT_NOTE.
|
||||
UnexpectedSegmentType((u32, u32)),
|
||||
/// Returned when a section has a sh_addralign value that was different
|
||||
/// than we expected.
|
||||
UnexpectedAlignment(usize),
|
||||
/// Returned when parsing an ELF structure out of an in-memory `&[u8]`
|
||||
/// resulted in a request for a section of file bytes outside the range of
|
||||
/// the slice. Commonly caused by truncated file contents.
|
||||
SliceReadError((usize, usize)),
|
||||
/// Returned when doing math with parsed elf fields that resulted in integer overflow.
|
||||
IntegerOverflow,
|
||||
/// Returned when parsing a string out of a StringTable that contained
|
||||
/// invalid Utf8
|
||||
Utf8Error(core::str::Utf8Error),
|
||||
/// Returned when parsing an ELF structure and the underlying structure data
|
||||
/// was truncated and thus the full structure contents could not be parsed.
|
||||
TryFromSliceError(core::array::TryFromSliceError),
|
||||
/// Returned when parsing an ELF structure whose on-disk fields were too big
|
||||
/// to represent in the native machine's usize type for in-memory processing.
|
||||
/// This could be the case when processessing large 64-bit files on a 32-bit machine.
|
||||
TryFromIntError(core::num::TryFromIntError),
|
||||
#[cfg(feature = "std")]
|
||||
/// Returned when parsing an ELF structure out of an io stream encountered
|
||||
/// an io error.
|
||||
IOError(std::io::Error),
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl std::error::Error for ParseError {
|
||||
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
|
||||
match *self {
|
||||
ParseError::BadMagic(_) => None,
|
||||
ParseError::UnsupportedElfClass(_) => None,
|
||||
ParseError::UnsupportedElfEndianness(_) => None,
|
||||
ParseError::UnsupportedVersion(_) => None,
|
||||
ParseError::BadOffset(_) => None,
|
||||
ParseError::StringTableMissingNul(_) => None,
|
||||
ParseError::BadEntsize(_) => None,
|
||||
ParseError::UnexpectedSectionType(_) => None,
|
||||
ParseError::UnexpectedSegmentType(_) => None,
|
||||
ParseError::UnexpectedAlignment(_) => None,
|
||||
ParseError::SliceReadError(_) => None,
|
||||
ParseError::IntegerOverflow => None,
|
||||
ParseError::Utf8Error(ref err) => Some(err),
|
||||
ParseError::TryFromSliceError(ref err) => Some(err),
|
||||
ParseError::TryFromIntError(ref err) => Some(err),
|
||||
ParseError::IOError(ref err) => Some(err),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(all(feature = "nightly", not(feature = "std")))]
|
||||
impl core::error::Error for ParseError {
|
||||
fn source(&self) -> Option<&(dyn core::error::Error + 'static)> {
|
||||
match *self {
|
||||
ParseError::BadMagic(_) => None,
|
||||
ParseError::UnsupportedElfClass(_) => None,
|
||||
ParseError::UnsupportedElfEndianness(_) => None,
|
||||
ParseError::UnsupportedVersion(_) => None,
|
||||
ParseError::BadOffset(_) => None,
|
||||
ParseError::StringTableMissingNul(_) => None,
|
||||
ParseError::BadEntsize(_) => None,
|
||||
ParseError::UnexpectedSectionType(_) => None,
|
||||
ParseError::UnexpectedSegmentType(_) => None,
|
||||
ParseError::UnexpectedAlignment(_) => None,
|
||||
ParseError::SliceReadError(_) => None,
|
||||
ParseError::IntegerOverflow => None,
|
||||
ParseError::Utf8Error(ref err) => Some(err),
|
||||
ParseError::TryFromSliceError(ref err) => Some(err),
|
||||
ParseError::TryFromIntError(ref err) => Some(err),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl core::fmt::Display for ParseError {
|
||||
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
||||
match *self {
|
||||
ParseError::BadMagic(ref magic) => {
|
||||
write!(f, "Invalid Magic Bytes: {magic:X?}")
|
||||
}
|
||||
ParseError::UnsupportedElfClass(class) => {
|
||||
write!(f, "Unsupported ELF Class: {class}")
|
||||
}
|
||||
ParseError::UnsupportedElfEndianness(endianness) => {
|
||||
write!(f, "Unsupported ELF Endianness: {endianness}")
|
||||
}
|
||||
ParseError::UnsupportedVersion((found, expected)) => {
|
||||
write!(
|
||||
f,
|
||||
"Unsupported ELF Version field found: {found} expected: {expected}"
|
||||
)
|
||||
}
|
||||
ParseError::BadOffset(offset) => {
|
||||
write!(f, "Bad offset: {offset:#X}")
|
||||
}
|
||||
ParseError::StringTableMissingNul(offset) => {
|
||||
write!(
|
||||
f,
|
||||
"Could not find terminating NUL byte starting at offset: {offset:#X}"
|
||||
)
|
||||
}
|
||||
ParseError::BadEntsize((found, expected)) => {
|
||||
write!(
|
||||
f,
|
||||
"Invalid entsize. Expected: {expected:#X}, Found: {found:#X}"
|
||||
)
|
||||
}
|
||||
ParseError::UnexpectedSectionType((found, expected)) => {
|
||||
write!(
|
||||
f,
|
||||
"Could not interpret section of type {found} as type {expected}"
|
||||
)
|
||||
}
|
||||
ParseError::UnexpectedSegmentType((found, expected)) => {
|
||||
write!(
|
||||
f,
|
||||
"Could not interpret section of type {found} as type {expected}"
|
||||
)
|
||||
}
|
||||
ParseError::UnexpectedAlignment(align) => {
|
||||
write!(
|
||||
f,
|
||||
"Could not interpret section with unexpected alignment of {align}"
|
||||
)
|
||||
}
|
||||
ParseError::SliceReadError((start, end)) => {
|
||||
write!(f, "Could not read bytes in range [{start:#X}, {end:#X})")
|
||||
}
|
||||
ParseError::IntegerOverflow => {
|
||||
write!(f, "Integer overflow detected")
|
||||
}
|
||||
ParseError::Utf8Error(ref err) => err.fmt(f),
|
||||
ParseError::TryFromSliceError(ref err) => err.fmt(f),
|
||||
ParseError::TryFromIntError(ref err) => err.fmt(f),
|
||||
#[cfg(feature = "std")]
|
||||
ParseError::IOError(ref err) => err.fmt(f),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<core::str::Utf8Error> for ParseError {
|
||||
fn from(err: core::str::Utf8Error) -> Self {
|
||||
ParseError::Utf8Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<core::array::TryFromSliceError> for ParseError {
|
||||
fn from(err: core::array::TryFromSliceError) -> Self {
|
||||
ParseError::TryFromSliceError(err)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<core::num::TryFromIntError> for ParseError {
|
||||
fn from(err: core::num::TryFromIntError) -> Self {
|
||||
ParseError::TryFromIntError(err)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl From<std::io::Error> for ParseError {
|
||||
fn from(err: std::io::Error) -> ParseError {
|
||||
ParseError::IOError(err)
|
||||
}
|
||||
}
|
||||
|
||||
/// Trait for safely parsing an ELF structure of a given class (32/64 bit) with
|
||||
/// an given endian-awareness at the given offset into the data buffer.
|
||||
///
|
||||
/// This is the trait that drives our elf parser, where the various ELF
|
||||
/// structures implement ParseAt in order to parse their Rust-native representation
|
||||
/// from a buffer, all using safe code.
|
||||
pub trait ParseAt: Sized {
|
||||
/// Parse this type by using the given endian-awareness and ELF class layout.
|
||||
/// This is generic on EndianParse in order to allow users to optimize for
|
||||
/// their expectations of data layout. See EndianParse for more details.
|
||||
fn parse_at<E: EndianParse>(
|
||||
endian: E,
|
||||
class: Class,
|
||||
offset: &mut usize,
|
||||
data: &[u8],
|
||||
) -> Result<Self, ParseError>;
|
||||
|
||||
/// Returns the expected size of the type being parsed for the given ELF class
|
||||
fn size_for(class: Class) -> usize;
|
||||
|
||||
/// Checks whether the given entsize matches what we need to parse this type
|
||||
///
|
||||
/// Returns a ParseError for bad/unexpected entsizes that don't match what this type parses.
|
||||
fn validate_entsize(class: Class, entsize: usize) -> Result<usize, ParseError> {
|
||||
let expected = Self::size_for(class);
|
||||
match entsize == expected {
|
||||
true => Ok(entsize),
|
||||
false => Err(ParseError::BadEntsize((entsize as u64, expected as u64))),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Lazy-parsing iterator which wraps bytes and parses out a `P: ParseAt` on each `next()`
|
||||
#[derive(Debug)]
|
||||
pub struct ParsingIterator<'data, E: EndianParse, P: ParseAt> {
|
||||
endian: E,
|
||||
class: Class,
|
||||
data: &'data [u8],
|
||||
offset: usize,
|
||||
// This struct doesn't technically own a P, but it yields them
|
||||
// as it iterates
|
||||
pd: PhantomData<&'data P>,
|
||||
}
|
||||
|
||||
impl<'data, E: EndianParse, P: ParseAt> ParsingIterator<'data, E, P> {
|
||||
pub fn new(endian: E, class: Class, data: &'data [u8]) -> Self {
|
||||
ParsingIterator {
|
||||
endian,
|
||||
class,
|
||||
data,
|
||||
offset: 0,
|
||||
pd: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'data, E: EndianParse, P: ParseAt> Iterator for ParsingIterator<'data, E, P> {
|
||||
type Item = P;
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
if self.data.is_empty() {
|
||||
return None;
|
||||
}
|
||||
|
||||
Self::Item::parse_at(self.endian, self.class, &mut self.offset, self.data).ok()
|
||||
}
|
||||
}
|
||||
|
||||
/// Lazy-parsing table which wraps bytes and parses out a `P: ParseAt` at a given index into
|
||||
/// the table on each `get()`.
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct ParsingTable<'data, E: EndianParse, P: ParseAt> {
|
||||
endian: E,
|
||||
class: Class,
|
||||
data: &'data [u8],
|
||||
// This struct doesn't technically own a P, but it yields them
|
||||
pd: PhantomData<&'data P>,
|
||||
}
|
||||
|
||||
impl<'data, E: EndianParse, P: ParseAt> ParsingTable<'data, E, P> {
|
||||
pub fn new(endian: E, class: Class, data: &'data [u8]) -> Self {
|
||||
ParsingTable {
|
||||
endian,
|
||||
class,
|
||||
data,
|
||||
pd: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
/// Get a lazy-parsing iterator for the table's bytes
|
||||
pub fn iter(&self) -> ParsingIterator<'data, E, P> {
|
||||
ParsingIterator::new(self.endian, self.class, self.data)
|
||||
}
|
||||
|
||||
/// Returns the number of elements of type P in the table.
|
||||
pub fn len(&self) -> usize {
|
||||
self.data.len() / P::size_for(self.class)
|
||||
}
|
||||
|
||||
/// Returns whether the table is empty (contains zero elements).
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.len() == 0
|
||||
}
|
||||
|
||||
/// Parse the element at `index` in the table.
|
||||
pub fn get(&self, index: usize) -> Result<P, ParseError> {
|
||||
if self.data.is_empty() {
|
||||
return Err(ParseError::BadOffset(index as u64));
|
||||
}
|
||||
|
||||
let entsize = P::size_for(self.class);
|
||||
let mut start = index
|
||||
.checked_mul(entsize)
|
||||
.ok_or(ParseError::IntegerOverflow)?;
|
||||
if start > self.data.len() {
|
||||
return Err(ParseError::BadOffset(index as u64));
|
||||
}
|
||||
|
||||
P::parse_at(self.endian, self.class, &mut start, self.data)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'data, E: EndianParse, P: ParseAt> IntoIterator for ParsingTable<'data, E, P> {
|
||||
type IntoIter = ParsingIterator<'data, E, P>;
|
||||
type Item = P;
|
||||
|
||||
fn into_iter(self) -> Self::IntoIter {
|
||||
ParsingIterator::new(self.endian, self.class, self.data)
|
||||
}
|
||||
}
|
||||
|
||||
// Simple convenience extension trait to wrap get() with .ok_or(SliceReadError)
|
||||
pub(crate) trait ReadBytesExt<'data> {
|
||||
fn get_bytes(self, range: Range<usize>) -> Result<&'data [u8], ParseError>;
|
||||
}
|
||||
|
||||
impl<'data> ReadBytesExt<'data> for &'data [u8] {
|
||||
fn get_bytes(self, range: Range<usize>) -> Result<&'data [u8], ParseError> {
|
||||
let start = range.start;
|
||||
let end = range.end;
|
||||
self.get(range)
|
||||
.ok_or(ParseError::SliceReadError((start, end)))
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
pub(crate) fn test_parse_for<E: EndianParse, P: ParseAt + core::fmt::Debug + PartialEq>(
|
||||
endian: E,
|
||||
class: Class,
|
||||
expected: P,
|
||||
) {
|
||||
let size = P::size_for(class);
|
||||
let mut data = vec![0u8; size];
|
||||
for (n, elem) in data.iter_mut().enumerate().take(size) {
|
||||
*elem = n as u8;
|
||||
}
|
||||
|
||||
let mut offset = 0;
|
||||
let entry = P::parse_at(endian, class, &mut offset, data.as_ref()).expect("Failed to parse");
|
||||
|
||||
assert_eq!(entry, expected);
|
||||
assert_eq!(offset, size);
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
pub(crate) fn test_parse_fuzz_too_short<E: EndianParse, P: ParseAt + core::fmt::Debug>(
|
||||
endian: E,
|
||||
class: Class,
|
||||
) {
|
||||
let size = P::size_for(class);
|
||||
let data = vec![0u8; size];
|
||||
for n in 0..size {
|
||||
let buf = data.split_at(n).0;
|
||||
let mut offset: usize = 0;
|
||||
let error = P::parse_at(endian, class, &mut offset, buf).expect_err("Expected an error");
|
||||
assert!(
|
||||
matches!(error, ParseError::SliceReadError(_)),
|
||||
"Unexpected Error type found: {error}"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod read_bytes_tests {
|
||||
use super::ParseError;
|
||||
use super::ReadBytesExt;
|
||||
|
||||
#[test]
|
||||
fn get_bytes_works() {
|
||||
let data = &[0u8, 1, 2, 3];
|
||||
let subslice = data.get_bytes(1..3).expect("should be within range");
|
||||
assert_eq!(subslice, [1, 2]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn get_bytes_out_of_range_errors() {
|
||||
let data = &[0u8, 1, 2, 3];
|
||||
let err = data.get_bytes(3..9).expect_err("should be out of range");
|
||||
assert!(
|
||||
matches!(err, ParseError::SliceReadError((3, 9))),
|
||||
"Unexpected Error type found: {err}"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod parsing_table_tests {
|
||||
use crate::endian::{AnyEndian, BigEndian, LittleEndian};
|
||||
|
||||
use super::*;
|
||||
|
||||
type U32Table<'data, E> = ParsingTable<'data, E, u32>;
|
||||
|
||||
#[test]
|
||||
fn test_u32_validate_entsize() {
|
||||
assert!(matches!(u32::validate_entsize(Class::ELF32, 4), Ok(4)));
|
||||
assert!(matches!(
|
||||
u32::validate_entsize(Class::ELF32, 8),
|
||||
Err(ParseError::BadEntsize((8, 4)))
|
||||
));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_u32_parse_at() {
|
||||
let data = vec![0u8, 1, 2, 3, 4, 5, 6, 7];
|
||||
let mut offset = 2;
|
||||
let result = u32::parse_at(LittleEndian, Class::ELF32, &mut offset, data.as_ref())
|
||||
.expect("Expected to parse but:");
|
||||
assert_eq!(result, 0x05040302);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_u32_table_len() {
|
||||
let data = vec![0u8, 1, 2, 3, 4, 5, 6, 7];
|
||||
let table = U32Table::new(LittleEndian, Class::ELF32, data.as_ref());
|
||||
assert_eq!(table.len(), 2);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_u32_table_is_empty() {
|
||||
let data = vec![0u8, 1, 2, 3, 4, 5, 6, 7];
|
||||
let table = U32Table::new(LittleEndian, Class::ELF32, data.as_ref());
|
||||
assert!(!table.is_empty());
|
||||
|
||||
let table = U32Table::new(LittleEndian, Class::ELF32, &[]);
|
||||
assert!(table.is_empty());
|
||||
|
||||
let table = U32Table::new(LittleEndian, Class::ELF32, data.get(0..1).unwrap());
|
||||
assert!(table.is_empty());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_u32_table_get_parse_failure() {
|
||||
let data = vec![0u8, 1];
|
||||
let table = U32Table::new(LittleEndian, Class::ELF32, data.as_ref());
|
||||
assert!(matches!(
|
||||
table.get(0),
|
||||
Err(ParseError::SliceReadError((0, 4)))
|
||||
));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_lsb_u32_table_get() {
|
||||
let data = vec![0u8, 1, 2, 3, 4, 5, 6, 7];
|
||||
let table = U32Table::new(LittleEndian, Class::ELF32, data.as_ref());
|
||||
assert!(matches!(table.get(0), Ok(0x03020100)));
|
||||
assert!(matches!(table.get(1), Ok(0x07060504)));
|
||||
assert!(matches!(table.get(7), Err(ParseError::BadOffset(7))));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_any_lsb_u32_table_get() {
|
||||
let data = vec![0u8, 1, 2, 3, 4, 5, 6, 7];
|
||||
let table = U32Table::new(AnyEndian::Little, Class::ELF32, data.as_ref());
|
||||
assert!(matches!(table.get(0), Ok(0x03020100)));
|
||||
assert!(matches!(table.get(1), Ok(0x07060504)));
|
||||
assert!(matches!(table.get(7), Err(ParseError::BadOffset(7))));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_msb_u32_table_get() {
|
||||
let data = vec![0u8, 1, 2, 3, 4, 5, 6, 7];
|
||||
let table = U32Table::new(BigEndian, Class::ELF32, data.as_ref());
|
||||
assert!(matches!(table.get(0), Ok(0x00010203)));
|
||||
assert!(matches!(table.get(1), Ok(0x04050607)));
|
||||
assert!(matches!(table.get(7), Err(ParseError::BadOffset(7))));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_any_msb_u32_table_get() {
|
||||
let data = vec![0u8, 1, 2, 3, 4, 5, 6, 7];
|
||||
let table = U32Table::new(AnyEndian::Big, Class::ELF32, data.as_ref());
|
||||
assert!(matches!(table.get(0), Ok(0x00010203)));
|
||||
assert!(matches!(table.get(1), Ok(0x04050607)));
|
||||
assert!(matches!(table.get(7), Err(ParseError::BadOffset(7))));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_u32_table_get_unaligned() {
|
||||
let data = [0u8, 1, 2, 3, 4, 5, 6, 7];
|
||||
let table = U32Table::new(LittleEndian, Class::ELF32, data.get(1..).unwrap());
|
||||
assert!(matches!(table.get(0), Ok(0x04030201)));
|
||||
}
|
||||
}
|
299
mikros_std_deps/elf-0.7.4/src/relocation.rs
Normal file
299
mikros_std_deps/elf-0.7.4/src/relocation.rs
Normal file
@ -0,0 +1,299 @@
|
||||
//! Parsing relocation sections: `.rel.*`, `.rela.*`, [SHT_REL](crate::abi::SHT_REL), [SHT_RELA](crate::abi::SHT_RELA)
|
||||
use crate::endian::EndianParse;
|
||||
use crate::file::Class;
|
||||
use crate::parse::{ParseAt, ParseError, ParsingIterator};
|
||||
|
||||
pub type RelIterator<'data, E> = ParsingIterator<'data, E, Rel>;
|
||||
pub type RelaIterator<'data, E> = ParsingIterator<'data, E, Rela>;
|
||||
|
||||
/// C-style 32-bit ELF Relocation definition
|
||||
///
|
||||
/// These C-style definitions are for users who want to implement their own ELF manipulation logic.
|
||||
#[derive(Debug)]
|
||||
#[repr(C)]
|
||||
pub struct Elf32_Rel {
|
||||
pub r_offset: u32,
|
||||
pub r_info: u32,
|
||||
}
|
||||
|
||||
/// C-style 64-bit ELF Relocation definition
|
||||
///
|
||||
/// These C-style definitions are for users who want to implement their own ELF manipulation logic.
|
||||
#[derive(Debug)]
|
||||
#[repr(C)]
|
||||
pub struct Elf64_Rel {
|
||||
pub r_offset: u64,
|
||||
pub r_info: u64,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct Rel {
|
||||
pub r_offset: u64,
|
||||
pub r_sym: u32,
|
||||
pub r_type: u32,
|
||||
}
|
||||
|
||||
impl ParseAt for Rel {
|
||||
fn parse_at<E: EndianParse>(
|
||||
endian: E,
|
||||
class: Class,
|
||||
offset: &mut usize,
|
||||
data: &[u8],
|
||||
) -> Result<Self, ParseError> {
|
||||
match class {
|
||||
Class::ELF32 => {
|
||||
let r_offset = endian.parse_u32_at(offset, data)? as u64;
|
||||
let r_info = endian.parse_u32_at(offset, data)?;
|
||||
Ok(Rel {
|
||||
r_offset,
|
||||
r_sym: r_info >> 8,
|
||||
r_type: r_info & 0xFF,
|
||||
})
|
||||
}
|
||||
Class::ELF64 => {
|
||||
let r_offset = endian.parse_u64_at(offset, data)?;
|
||||
let r_info = endian.parse_u64_at(offset, data)?;
|
||||
Ok(Rel {
|
||||
r_offset,
|
||||
r_sym: (r_info >> 32) as u32,
|
||||
r_type: (r_info & 0xFFFFFFFF) as u32,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn size_for(class: Class) -> usize {
|
||||
match class {
|
||||
Class::ELF32 => 8,
|
||||
Class::ELF64 => 16,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// C-style 32-bit ELF Relocation (with addend) definition
|
||||
///
|
||||
/// These C-style definitions are for users who want to implement their own ELF manipulation logic.
|
||||
#[derive(Debug)]
|
||||
#[repr(C)]
|
||||
pub struct Elf32_Rela {
|
||||
pub r_offset: u32,
|
||||
pub r_info: u32,
|
||||
pub r_addend: i32,
|
||||
}
|
||||
|
||||
/// C-style 64-bit ELF Relocation (with addend) definition
|
||||
///
|
||||
/// These C-style definitions are for users who want to implement their own ELF manipulation logic.
|
||||
#[derive(Debug)]
|
||||
#[repr(C)]
|
||||
pub struct Elf64_Rela {
|
||||
pub r_offset: u64,
|
||||
pub r_info: u64,
|
||||
pub r_addend: i64,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct Rela {
|
||||
pub r_offset: u64,
|
||||
pub r_sym: u32,
|
||||
pub r_type: u32,
|
||||
pub r_addend: i64,
|
||||
}
|
||||
|
||||
impl ParseAt for Rela {
|
||||
fn parse_at<E: EndianParse>(
|
||||
endian: E,
|
||||
class: Class,
|
||||
offset: &mut usize,
|
||||
data: &[u8],
|
||||
) -> Result<Self, ParseError> {
|
||||
match class {
|
||||
Class::ELF32 => {
|
||||
let r_offset = endian.parse_u32_at(offset, data)? as u64;
|
||||
let r_info = endian.parse_u32_at(offset, data)?;
|
||||
let r_addend = endian.parse_i32_at(offset, data)? as i64;
|
||||
Ok(Rela {
|
||||
r_offset,
|
||||
r_sym: r_info >> 8,
|
||||
r_type: r_info & 0xFF,
|
||||
r_addend,
|
||||
})
|
||||
}
|
||||
Class::ELF64 => {
|
||||
let r_offset = endian.parse_u64_at(offset, data)?;
|
||||
let r_info = endian.parse_u64_at(offset, data)?;
|
||||
let r_addend = endian.parse_i64_at(offset, data)?;
|
||||
Ok(Rela {
|
||||
r_offset,
|
||||
r_sym: (r_info >> 32) as u32,
|
||||
r_type: (r_info & 0xFFFFFFFF) as u32,
|
||||
r_addend,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn size_for(class: Class) -> usize {
|
||||
match class {
|
||||
Class::ELF32 => 12,
|
||||
Class::ELF64 => 24,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod parse_tests {
|
||||
use super::*;
|
||||
use crate::endian::{BigEndian, LittleEndian};
|
||||
use crate::parse::{test_parse_for, test_parse_fuzz_too_short};
|
||||
|
||||
#[test]
|
||||
fn parse_rel32_lsb() {
|
||||
test_parse_for(
|
||||
LittleEndian,
|
||||
Class::ELF32,
|
||||
Rel {
|
||||
r_offset: 0x03020100,
|
||||
r_sym: 0x00070605,
|
||||
r_type: 0x00000004,
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_rel32_msb() {
|
||||
test_parse_for(
|
||||
BigEndian,
|
||||
Class::ELF32,
|
||||
Rel {
|
||||
r_offset: 0x00010203,
|
||||
r_sym: 0x00040506,
|
||||
r_type: 0x00000007,
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_rel64_lsb() {
|
||||
test_parse_for(
|
||||
LittleEndian,
|
||||
Class::ELF64,
|
||||
Rel {
|
||||
r_offset: 0x0706050403020100,
|
||||
r_sym: 0x0F0E0D0C,
|
||||
r_type: 0x0B0A0908,
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_rel64_msb() {
|
||||
test_parse_for(
|
||||
BigEndian,
|
||||
Class::ELF64,
|
||||
Rel {
|
||||
r_offset: 0x0001020304050607,
|
||||
r_sym: 0x08090A0B,
|
||||
r_type: 0x0C0D0E0F,
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_rel32_lsb_fuzz_too_short() {
|
||||
test_parse_fuzz_too_short::<_, Rel>(LittleEndian, Class::ELF32);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_rel32_msb_fuzz_too_short() {
|
||||
test_parse_fuzz_too_short::<_, Rel>(BigEndian, Class::ELF32);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_rel64_lsb_fuzz_too_short() {
|
||||
test_parse_fuzz_too_short::<_, Rel>(LittleEndian, Class::ELF64);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_rel64_msb_fuzz_too_short() {
|
||||
test_parse_fuzz_too_short::<_, Rel>(BigEndian, Class::ELF64);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_rela32_lsb() {
|
||||
test_parse_for(
|
||||
LittleEndian,
|
||||
Class::ELF32,
|
||||
Rela {
|
||||
r_offset: 0x03020100,
|
||||
r_sym: 0x00070605,
|
||||
r_type: 0x00000004,
|
||||
r_addend: 0x0B0A0908,
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_rela32_msb() {
|
||||
test_parse_for(
|
||||
BigEndian,
|
||||
Class::ELF32,
|
||||
Rela {
|
||||
r_offset: 0x00010203,
|
||||
r_sym: 0x00040506,
|
||||
r_type: 0x00000007,
|
||||
r_addend: 0x08090A0B,
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_rela64_lsb() {
|
||||
test_parse_for(
|
||||
LittleEndian,
|
||||
Class::ELF64,
|
||||
Rela {
|
||||
r_offset: 0x0706050403020100,
|
||||
r_sym: 0x0F0E0D0C,
|
||||
r_type: 0x0B0A0908,
|
||||
r_addend: 0x1716151413121110,
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_rela64_msb() {
|
||||
test_parse_for(
|
||||
BigEndian,
|
||||
Class::ELF64,
|
||||
Rela {
|
||||
r_offset: 0x0001020304050607,
|
||||
r_sym: 0x08090A0B,
|
||||
r_type: 0x0C0D0E0F,
|
||||
r_addend: 0x1011121314151617,
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_rela32_lsb_fuzz_too_short() {
|
||||
test_parse_fuzz_too_short::<_, Rela>(LittleEndian, Class::ELF32);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_rela32_msb_fuzz_too_short() {
|
||||
test_parse_fuzz_too_short::<_, Rela>(BigEndian, Class::ELF32);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_rela64_lsb_fuzz_too_short() {
|
||||
test_parse_fuzz_too_short::<_, Rela>(LittleEndian, Class::ELF64);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_rela64_msb_fuzz_too_short() {
|
||||
test_parse_fuzz_too_short::<_, Rela>(BigEndian, Class::ELF64);
|
||||
}
|
||||
}
|
231
mikros_std_deps/elf-0.7.4/src/section.rs
Normal file
231
mikros_std_deps/elf-0.7.4/src/section.rs
Normal file
@ -0,0 +1,231 @@
|
||||
//! Parsing the Section Header table
|
||||
use crate::endian::EndianParse;
|
||||
use crate::file::Class;
|
||||
use crate::parse::{ParseAt, ParseError, ParsingTable};
|
||||
|
||||
pub type SectionHeaderTable<'data, E> = ParsingTable<'data, E, SectionHeader>;
|
||||
|
||||
/// C-style 32-bit ELF Section Header definition
|
||||
///
|
||||
/// These C-style definitions are for users who want to implement their own ELF manipulation logic.
|
||||
#[derive(Debug)]
|
||||
#[repr(C)]
|
||||
pub struct Elf32_Shdr {
|
||||
pub sh_name: u32,
|
||||
pub sh_type: u32,
|
||||
pub sh_flags: u32,
|
||||
pub sh_addr: u32,
|
||||
pub sh_offset: u32,
|
||||
pub sh_size: u32,
|
||||
pub sh_link: u32,
|
||||
pub sh_info: u32,
|
||||
pub sh_addralign: u32,
|
||||
pub sh_entsize: u32,
|
||||
}
|
||||
|
||||
/// C-style 64-bit ELF Section Header definition
|
||||
///
|
||||
/// These C-style definitions are for users who want to implement their own ELF manipulation logic.
|
||||
#[derive(Debug)]
|
||||
#[repr(C)]
|
||||
pub struct Elf64_Shdr {
|
||||
pub sh_name: u32,
|
||||
pub sh_type: u32,
|
||||
pub sh_flags: u64,
|
||||
pub sh_addr: u64,
|
||||
pub sh_offset: u64,
|
||||
pub sh_size: u64,
|
||||
pub sh_link: u32,
|
||||
pub sh_info: u32,
|
||||
pub sh_addralign: u64,
|
||||
pub sh_entsize: u64,
|
||||
}
|
||||
|
||||
/// Encapsulates the contents of an ELF Section Header
|
||||
///
|
||||
/// This is a Rust-native type that represents a Section Header that is bit-width-agnostic.
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||
pub struct SectionHeader {
|
||||
/// Section Name
|
||||
pub sh_name: u32,
|
||||
/// Section Type
|
||||
pub sh_type: u32,
|
||||
/// Section Flags
|
||||
pub sh_flags: u64,
|
||||
/// in-memory address where this section is loaded
|
||||
pub sh_addr: u64,
|
||||
/// Byte-offset into the file where this section starts
|
||||
pub sh_offset: u64,
|
||||
/// Section size in bytes
|
||||
pub sh_size: u64,
|
||||
/// Defined by section type
|
||||
pub sh_link: u32,
|
||||
/// Defined by section type
|
||||
pub sh_info: u32,
|
||||
/// address alignment
|
||||
pub sh_addralign: u64,
|
||||
/// size of an entry if section data is an array of entries
|
||||
pub sh_entsize: u64,
|
||||
}
|
||||
|
||||
impl ParseAt for SectionHeader {
|
||||
fn parse_at<E: EndianParse>(
|
||||
endian: E,
|
||||
class: Class,
|
||||
offset: &mut usize,
|
||||
data: &[u8],
|
||||
) -> Result<Self, ParseError> {
|
||||
match class {
|
||||
Class::ELF32 => Ok(SectionHeader {
|
||||
sh_name: endian.parse_u32_at(offset, data)?,
|
||||
sh_type: endian.parse_u32_at(offset, data)?,
|
||||
sh_flags: endian.parse_u32_at(offset, data)? as u64,
|
||||
sh_addr: endian.parse_u32_at(offset, data)? as u64,
|
||||
sh_offset: endian.parse_u32_at(offset, data)? as u64,
|
||||
sh_size: endian.parse_u32_at(offset, data)? as u64,
|
||||
sh_link: endian.parse_u32_at(offset, data)?,
|
||||
sh_info: endian.parse_u32_at(offset, data)?,
|
||||
sh_addralign: endian.parse_u32_at(offset, data)? as u64,
|
||||
sh_entsize: endian.parse_u32_at(offset, data)? as u64,
|
||||
}),
|
||||
Class::ELF64 => Ok(SectionHeader {
|
||||
sh_name: endian.parse_u32_at(offset, data)?,
|
||||
sh_type: endian.parse_u32_at(offset, data)?,
|
||||
sh_flags: endian.parse_u64_at(offset, data)?,
|
||||
sh_addr: endian.parse_u64_at(offset, data)?,
|
||||
sh_offset: endian.parse_u64_at(offset, data)?,
|
||||
sh_size: endian.parse_u64_at(offset, data)?,
|
||||
sh_link: endian.parse_u32_at(offset, data)?,
|
||||
sh_info: endian.parse_u32_at(offset, data)?,
|
||||
sh_addralign: endian.parse_u64_at(offset, data)?,
|
||||
sh_entsize: endian.parse_u64_at(offset, data)?,
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn size_for(class: Class) -> usize {
|
||||
match class {
|
||||
Class::ELF32 => 40,
|
||||
Class::ELF64 => 64,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl SectionHeader {
|
||||
/// Helper method which uses checked integer math to get a tuple of (start,end) for
|
||||
/// this SectionHeader's (sh_offset, sh_offset + sh_size)
|
||||
pub(crate) fn get_data_range(&self) -> Result<(usize, usize), ParseError> {
|
||||
let start: usize = self.sh_offset.try_into()?;
|
||||
let size: usize = self.sh_size.try_into()?;
|
||||
let end = start.checked_add(size).ok_or(ParseError::IntegerOverflow)?;
|
||||
Ok((start, end))
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod parse_tests {
|
||||
use super::*;
|
||||
use crate::endian::{BigEndian, LittleEndian};
|
||||
use crate::parse::{test_parse_for, test_parse_fuzz_too_short};
|
||||
|
||||
#[test]
|
||||
fn parse_shdr32_lsb() {
|
||||
test_parse_for(
|
||||
LittleEndian,
|
||||
Class::ELF32,
|
||||
SectionHeader {
|
||||
sh_name: 0x03020100,
|
||||
sh_type: 0x07060504,
|
||||
sh_flags: 0xB0A0908,
|
||||
sh_addr: 0x0F0E0D0C,
|
||||
sh_offset: 0x13121110,
|
||||
sh_size: 0x17161514,
|
||||
sh_link: 0x1B1A1918,
|
||||
sh_info: 0x1F1E1D1C,
|
||||
sh_addralign: 0x23222120,
|
||||
sh_entsize: 0x27262524,
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_shdr32_msb() {
|
||||
test_parse_for(
|
||||
BigEndian,
|
||||
Class::ELF32,
|
||||
SectionHeader {
|
||||
sh_name: 0x00010203,
|
||||
sh_type: 0x04050607,
|
||||
sh_flags: 0x08090A0B,
|
||||
sh_addr: 0x0C0D0E0F,
|
||||
sh_offset: 0x10111213,
|
||||
sh_size: 0x14151617,
|
||||
sh_link: 0x18191A1B,
|
||||
sh_info: 0x1C1D1E1F,
|
||||
sh_addralign: 0x20212223,
|
||||
sh_entsize: 0x24252627,
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_shdr64_lsb() {
|
||||
test_parse_for(
|
||||
LittleEndian,
|
||||
Class::ELF64,
|
||||
SectionHeader {
|
||||
sh_name: 0x03020100,
|
||||
sh_type: 0x07060504,
|
||||
sh_flags: 0x0F0E0D0C0B0A0908,
|
||||
sh_addr: 0x1716151413121110,
|
||||
sh_offset: 0x1F1E1D1C1B1A1918,
|
||||
sh_size: 0x2726252423222120,
|
||||
sh_link: 0x2B2A2928,
|
||||
sh_info: 0x2F2E2D2C,
|
||||
sh_addralign: 0x3736353433323130,
|
||||
sh_entsize: 0x3F3E3D3C3B3A3938,
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_shdr64_msb() {
|
||||
test_parse_for(
|
||||
BigEndian,
|
||||
Class::ELF64,
|
||||
SectionHeader {
|
||||
sh_name: 0x00010203,
|
||||
sh_type: 0x04050607,
|
||||
sh_flags: 0x08090A0B0C0D0E0F,
|
||||
sh_addr: 0x1011121314151617,
|
||||
sh_offset: 0x18191A1B1C1D1E1F,
|
||||
sh_size: 0x2021222324252627,
|
||||
sh_link: 0x28292A2B,
|
||||
sh_info: 0x2C2D2E2F,
|
||||
sh_addralign: 0x3031323334353637,
|
||||
sh_entsize: 0x38393A3B3C3D3E3F,
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_shdr32_lsb_fuzz_too_short() {
|
||||
test_parse_fuzz_too_short::<_, SectionHeader>(LittleEndian, Class::ELF32);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_shdr32_msb_fuzz_too_short() {
|
||||
test_parse_fuzz_too_short::<_, SectionHeader>(BigEndian, Class::ELF32);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_shdr64_lsb_fuzz_too_short() {
|
||||
test_parse_fuzz_too_short::<_, SectionHeader>(LittleEndian, Class::ELF64);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_shdr64_msb_fuzz_too_short() {
|
||||
test_parse_fuzz_too_short::<_, SectionHeader>(BigEndian, Class::ELF64);
|
||||
}
|
||||
}
|
223
mikros_std_deps/elf-0.7.4/src/segment.rs
Normal file
223
mikros_std_deps/elf-0.7.4/src/segment.rs
Normal file
@ -0,0 +1,223 @@
|
||||
//! Parsing the Program Header table aka Segment table aka `Elf_Phdr`
|
||||
use crate::endian::EndianParse;
|
||||
use crate::file::Class;
|
||||
use crate::parse::{ParseAt, ParseError, ParsingTable};
|
||||
|
||||
pub type SegmentTable<'data, E> = ParsingTable<'data, E, ProgramHeader>;
|
||||
|
||||
/// C-style 32-bit ELF Program Segment Header definition
|
||||
///
|
||||
/// These C-style definitions are for users who want to implement their own ELF manipulation logic.
|
||||
#[derive(Debug)]
|
||||
#[repr(C)]
|
||||
pub struct Elf32_Phdr {
|
||||
pub p_type: u32,
|
||||
pub p_offset: u32,
|
||||
pub p_vaddr: u32,
|
||||
pub p_paddr: u32,
|
||||
pub p_filesz: u32,
|
||||
pub p_memsz: u32,
|
||||
pub p_flags: u32,
|
||||
pub p_align: u32,
|
||||
}
|
||||
|
||||
/// C-style 64-bit ELF Program Segment Header definition
|
||||
///
|
||||
/// These C-style definitions are for users who want to implement their own ELF manipulation logic.
|
||||
#[derive(Debug)]
|
||||
#[repr(C)]
|
||||
pub struct Elf64_Phdr {
|
||||
pub p_type: u32,
|
||||
pub p_flags: u32,
|
||||
pub p_offset: u64,
|
||||
pub p_vaddr: u64,
|
||||
pub p_paddr: u64,
|
||||
pub p_filesz: u64,
|
||||
pub p_memsz: u64,
|
||||
pub p_align: u64,
|
||||
}
|
||||
|
||||
/// Encapsulates the contents of an ELF Program Header
|
||||
///
|
||||
/// The program header table is an array of program header structures describing
|
||||
/// the various segments for program execution.
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||
pub struct ProgramHeader {
|
||||
/// Program segment type
|
||||
pub p_type: u32,
|
||||
/// Offset into the ELF file where this segment begins
|
||||
pub p_offset: u64,
|
||||
/// Virtual adress where this segment should be loaded
|
||||
pub p_vaddr: u64,
|
||||
/// Physical address where this segment should be loaded
|
||||
pub p_paddr: u64,
|
||||
/// Size of this segment in the file
|
||||
pub p_filesz: u64,
|
||||
/// Size of this segment in memory
|
||||
pub p_memsz: u64,
|
||||
/// Flags for this segment
|
||||
pub p_flags: u32,
|
||||
/// file and memory alignment
|
||||
pub p_align: u64,
|
||||
}
|
||||
|
||||
impl ParseAt for ProgramHeader {
|
||||
fn parse_at<E: EndianParse>(
|
||||
endian: E,
|
||||
class: Class,
|
||||
offset: &mut usize,
|
||||
data: &[u8],
|
||||
) -> Result<Self, ParseError> {
|
||||
if class == Class::ELF32 {
|
||||
return Ok(ProgramHeader {
|
||||
p_type: endian.parse_u32_at(offset, data)?,
|
||||
p_offset: endian.parse_u32_at(offset, data)? as u64,
|
||||
p_vaddr: endian.parse_u32_at(offset, data)? as u64,
|
||||
p_paddr: endian.parse_u32_at(offset, data)? as u64,
|
||||
p_filesz: endian.parse_u32_at(offset, data)? as u64,
|
||||
p_memsz: endian.parse_u32_at(offset, data)? as u64,
|
||||
p_flags: endian.parse_u32_at(offset, data)?,
|
||||
p_align: endian.parse_u32_at(offset, data)? as u64,
|
||||
});
|
||||
}
|
||||
|
||||
// Note: 64-bit fields are in a different order
|
||||
let p_type = endian.parse_u32_at(offset, data)?;
|
||||
let p_flags = endian.parse_u32_at(offset, data)?;
|
||||
let p_offset = endian.parse_u64_at(offset, data)?;
|
||||
let p_vaddr = endian.parse_u64_at(offset, data)?;
|
||||
let p_paddr = endian.parse_u64_at(offset, data)?;
|
||||
let p_filesz = endian.parse_u64_at(offset, data)?;
|
||||
let p_memsz = endian.parse_u64_at(offset, data)?;
|
||||
let p_align = endian.parse_u64_at(offset, data)?;
|
||||
Ok(ProgramHeader {
|
||||
p_type,
|
||||
p_offset,
|
||||
p_vaddr,
|
||||
p_paddr,
|
||||
p_filesz,
|
||||
p_memsz,
|
||||
p_flags,
|
||||
p_align,
|
||||
})
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn size_for(class: Class) -> usize {
|
||||
match class {
|
||||
Class::ELF32 => 32,
|
||||
Class::ELF64 => 56,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ProgramHeader {
|
||||
/// Helper method which uses checked integer math to get a tuple of (start, end) for
|
||||
/// the location in bytes for this ProgramHeader's data in the file.
|
||||
/// i.e. (p_offset, p_offset + p_filesz)
|
||||
pub(crate) fn get_file_data_range(&self) -> Result<(usize, usize), ParseError> {
|
||||
let start: usize = self.p_offset.try_into()?;
|
||||
let size: usize = self.p_filesz.try_into()?;
|
||||
let end = start.checked_add(size).ok_or(ParseError::IntegerOverflow)?;
|
||||
Ok((start, end))
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod parse_tests {
|
||||
use super::*;
|
||||
use crate::endian::{BigEndian, LittleEndian};
|
||||
use crate::parse::{test_parse_for, test_parse_fuzz_too_short};
|
||||
|
||||
#[test]
|
||||
fn parse_phdr32_lsb() {
|
||||
test_parse_for(
|
||||
LittleEndian,
|
||||
Class::ELF32,
|
||||
ProgramHeader {
|
||||
p_type: 0x03020100,
|
||||
p_offset: 0x07060504,
|
||||
p_vaddr: 0xB0A0908,
|
||||
p_paddr: 0x0F0E0D0C,
|
||||
p_filesz: 0x13121110,
|
||||
p_memsz: 0x17161514,
|
||||
p_flags: 0x1B1A1918,
|
||||
p_align: 0x1F1E1D1C,
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_phdr32_msb() {
|
||||
test_parse_for(
|
||||
BigEndian,
|
||||
Class::ELF32,
|
||||
ProgramHeader {
|
||||
p_type: 0x00010203,
|
||||
p_offset: 0x04050607,
|
||||
p_vaddr: 0x08090A0B,
|
||||
p_paddr: 0x0C0D0E0F,
|
||||
p_filesz: 0x10111213,
|
||||
p_memsz: 0x14151617,
|
||||
p_flags: 0x18191A1B,
|
||||
p_align: 0x1C1D1E1F,
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_phdr64_lsb() {
|
||||
test_parse_for(
|
||||
LittleEndian,
|
||||
Class::ELF64,
|
||||
ProgramHeader {
|
||||
p_type: 0x03020100,
|
||||
p_offset: 0x0F0E0D0C0B0A0908,
|
||||
p_vaddr: 0x1716151413121110,
|
||||
p_paddr: 0x1F1E1D1C1B1A1918,
|
||||
p_filesz: 0x2726252423222120,
|
||||
p_memsz: 0x2F2E2D2C2B2A2928,
|
||||
p_flags: 0x07060504,
|
||||
p_align: 0x3736353433323130,
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_phdr64_msb() {
|
||||
test_parse_for(
|
||||
BigEndian,
|
||||
Class::ELF64,
|
||||
ProgramHeader {
|
||||
p_type: 0x00010203,
|
||||
p_offset: 0x08090A0B0C0D0E0F,
|
||||
p_vaddr: 0x1011121314151617,
|
||||
p_paddr: 0x18191A1B1C1D1E1F,
|
||||
p_filesz: 0x2021222324252627,
|
||||
p_memsz: 0x28292A2B2C2D2E2F,
|
||||
p_flags: 0x04050607,
|
||||
p_align: 0x3031323334353637,
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_phdr32_lsb_fuzz_too_short() {
|
||||
test_parse_fuzz_too_short::<_, ProgramHeader>(LittleEndian, Class::ELF32);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_phdr32_msb_fuzz_too_short() {
|
||||
test_parse_fuzz_too_short::<_, ProgramHeader>(BigEndian, Class::ELF32);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_phdr64_lsb_fuzz_too_short() {
|
||||
test_parse_fuzz_too_short::<_, ProgramHeader>(LittleEndian, Class::ELF64);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_phdr64_msb_fuzz_too_short() {
|
||||
test_parse_fuzz_too_short::<_, ProgramHeader>(BigEndian, Class::ELF64);
|
||||
}
|
||||
}
|
116
mikros_std_deps/elf-0.7.4/src/string_table.rs
Normal file
116
mikros_std_deps/elf-0.7.4/src/string_table.rs
Normal file
@ -0,0 +1,116 @@
|
||||
//! Interpreting string table sections: `.strtab`, [SHT_STRTAB][crate::abi::SHT_STRTAB]
|
||||
use crate::parse::ParseError;
|
||||
use core::str::from_utf8;
|
||||
|
||||
#[derive(Debug, Default, Clone, Copy)]
|
||||
pub struct StringTable<'data> {
|
||||
data: &'data [u8],
|
||||
}
|
||||
|
||||
impl<'data> StringTable<'data> {
|
||||
pub fn new(data: &'data [u8]) -> Self {
|
||||
StringTable { data }
|
||||
}
|
||||
|
||||
pub fn get_raw(&self, offset: usize) -> Result<&'data [u8], ParseError> {
|
||||
if self.data.is_empty() {
|
||||
return Err(ParseError::BadOffset(offset as u64));
|
||||
};
|
||||
|
||||
let start = self
|
||||
.data
|
||||
.get(offset..)
|
||||
.ok_or(ParseError::BadOffset(offset as u64))?;
|
||||
let end = start
|
||||
.iter()
|
||||
.position(|&b| b == 0u8)
|
||||
.ok_or(ParseError::StringTableMissingNul(offset as u64))?;
|
||||
|
||||
Ok(start.split_at(end).0)
|
||||
}
|
||||
|
||||
pub fn get(&self, offset: usize) -> Result<&'data str, ParseError> {
|
||||
let raw_data = self.get_raw(offset)?;
|
||||
Ok(from_utf8(raw_data)?)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_empty_table_errors() {
|
||||
let st = StringTable::default();
|
||||
assert!(matches!(st.get(0), Err(ParseError::BadOffset(0))));
|
||||
assert!(matches!(st.get(1), Err(ParseError::BadOffset(1))));
|
||||
}
|
||||
|
||||
/// Note: ELF string tables are defined to always start with a NUL and use
|
||||
/// index 0 to give an empty string, so getting a string starting at a NUL
|
||||
/// should properly give an empty string.
|
||||
#[test]
|
||||
fn test_get_index_0_gives_empty_string() {
|
||||
let data = [0u8, 42u8, 0u8];
|
||||
let st = StringTable::new(&data);
|
||||
assert_eq!(st.get(0).unwrap(), "");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_get_raw_works() {
|
||||
let data = [0u8, 0x45, 0x4C, 0x46, 0u8];
|
||||
let st = StringTable::new(&data);
|
||||
assert_eq!(st.get_raw(1).unwrap(), [0x45, 0x4c, 0x46]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_get_string_works() {
|
||||
let data = [0u8, 0x45, 0x4C, 0x46, 0u8];
|
||||
let st = StringTable::new(&data);
|
||||
assert_eq!(st.get(1).unwrap(), "ELF");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_get_raw_index_out_of_bounds_errors() {
|
||||
let data = [0u8, 0x45, 0x4C, 0x46, 0u8];
|
||||
let st = StringTable::new(&data);
|
||||
let result = st.get_raw(7);
|
||||
assert!(
|
||||
matches!(result, Err(ParseError::BadOffset(7))),
|
||||
"Unexpected Error type found: {result:?}"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_get_index_out_of_bounds_errors() {
|
||||
let data = [0u8, 0x45, 0x4C, 0x46, 0u8];
|
||||
let st = StringTable::new(&data);
|
||||
let result = st.get(7);
|
||||
assert!(
|
||||
matches!(result, Err(ParseError::BadOffset(7))),
|
||||
"Unexpected Error type found: {result:?}"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_get_raw_with_malformed_table_no_trailing_nul() {
|
||||
let data = [0u8, 0x45, 0x4C, 0x46];
|
||||
let st = StringTable::new(&data);
|
||||
let result = st.get_raw(1);
|
||||
assert!(
|
||||
matches!(result, Err(ParseError::StringTableMissingNul(1))),
|
||||
"Unexpected Error type found: {result:?}"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_get_with_malformed_table_no_trailing_nul() {
|
||||
let data = [0u8, 0x45, 0x4C, 0x46];
|
||||
let st = StringTable::new(&data);
|
||||
let result = st.get(1);
|
||||
assert!(
|
||||
matches!(result, Err(ParseError::StringTableMissingNul(1))),
|
||||
"Unexpected Error type found: {result:?}"
|
||||
);
|
||||
}
|
||||
}
|
271
mikros_std_deps/elf-0.7.4/src/symbol.rs
Normal file
271
mikros_std_deps/elf-0.7.4/src/symbol.rs
Normal file
@ -0,0 +1,271 @@
|
||||
//! Parsing symbol table sections: `.symtab`, `.dynsym`
|
||||
use crate::abi;
|
||||
use crate::endian::EndianParse;
|
||||
use crate::file::Class;
|
||||
use crate::parse::{ParseAt, ParseError, ParsingTable};
|
||||
|
||||
pub type SymbolTable<'data, E> = ParsingTable<'data, E, Symbol>;
|
||||
|
||||
/// C-style 32-bit ELF Symbol definition
|
||||
///
|
||||
/// These C-style definitions are for users who want to implement their own ELF manipulation logic.
|
||||
#[derive(Debug)]
|
||||
#[repr(C)]
|
||||
pub struct Elf32_Sym {
|
||||
pub st_name: u32,
|
||||
pub st_value: u32,
|
||||
pub st_size: u32,
|
||||
pub st_info: u8,
|
||||
pub st_other: u8,
|
||||
pub st_shndx: u32,
|
||||
}
|
||||
|
||||
/// C-style 64-bit ELF Symbol definition
|
||||
///
|
||||
/// These C-style definitions are for users who want to implement their own ELF manipulation logic.
|
||||
#[derive(Debug)]
|
||||
#[repr(C)]
|
||||
pub struct Elf64_Sym {
|
||||
pub st_name: u32,
|
||||
pub st_info: u8,
|
||||
pub st_other: u8,
|
||||
pub st_shndx: u16,
|
||||
pub st_value: u64,
|
||||
pub st_size: u64,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct Symbol {
|
||||
/// This member holds an index into the symbol table's string table,
|
||||
/// which holds the character representations of the symbol names. If the
|
||||
/// value is non-zero, it represents a string table index that gives the
|
||||
/// symbol name. Otherwise, the symbol table entry has no name.
|
||||
pub st_name: u32,
|
||||
|
||||
/// Every symbol table entry is defined in relation to some section. This
|
||||
/// member holds the relevant section header table index. As the sh_link and
|
||||
/// sh_info interpretation table and the related text describe, some section
|
||||
/// indexes indicate special meanings.
|
||||
///
|
||||
/// If this member contains SHN_XINDEX, then the actual section header index
|
||||
/// is too large to fit in this field. The actual value is contained in the
|
||||
/// associated section of type SHT_SYMTAB_SHNDX.
|
||||
pub st_shndx: u16,
|
||||
|
||||
/// This member specifies the symbol's type and binding attributes.
|
||||
pub(super) st_info: u8,
|
||||
|
||||
/// This member currently specifies a symbol's visibility.
|
||||
pub(super) st_other: u8,
|
||||
|
||||
/// This member gives the value of the associated symbol. Depending on the
|
||||
/// context, this may be an absolute value, an address, and so on.
|
||||
///
|
||||
/// * In relocatable files, st_value holds alignment constraints for a
|
||||
/// symbol whose section index is SHN_COMMON.
|
||||
/// * In relocatable files, st_value holds a section offset for a defined
|
||||
/// symbol. st_value is an offset from the beginning of the section that
|
||||
/// st_shndx identifies.
|
||||
/// * In executable and shared object files, st_value holds a virtual
|
||||
/// address. To make these files' symbols more useful for the dynamic
|
||||
/// linker, the section offset (file interpretation) gives way to a
|
||||
/// virtual address (memory interpretation) for which the section number
|
||||
/// is irrelevant.
|
||||
pub st_value: u64,
|
||||
|
||||
/// This member gives the symbol's size.
|
||||
/// For example, a data object's size is the number of bytes contained in
|
||||
/// the object. This member holds 0 if the symbol has no size or an unknown
|
||||
/// size.
|
||||
pub st_size: u64,
|
||||
}
|
||||
|
||||
impl Symbol {
|
||||
/// Returns true if a symbol is undefined in this ELF object.
|
||||
///
|
||||
/// When linking and loading, undefined symbols in this object get linked to
|
||||
/// a defined symbol in another object.
|
||||
pub fn is_undefined(&self) -> bool {
|
||||
self.st_shndx == abi::SHN_UNDEF
|
||||
}
|
||||
|
||||
pub fn st_symtype(&self) -> u8 {
|
||||
self.st_info & 0xf
|
||||
}
|
||||
|
||||
pub fn st_bind(&self) -> u8 {
|
||||
self.st_info >> 4
|
||||
}
|
||||
|
||||
pub fn st_vis(&self) -> u8 {
|
||||
self.st_other & 0x3
|
||||
}
|
||||
}
|
||||
|
||||
impl ParseAt for Symbol {
|
||||
fn parse_at<E: EndianParse>(
|
||||
endian: E,
|
||||
class: Class,
|
||||
offset: &mut usize,
|
||||
data: &[u8],
|
||||
) -> Result<Self, ParseError> {
|
||||
let st_name: u32;
|
||||
let st_value: u64;
|
||||
let st_size: u64;
|
||||
let st_shndx: u16;
|
||||
let st_info: u8;
|
||||
let st_other: u8;
|
||||
|
||||
if class == Class::ELF32 {
|
||||
st_name = endian.parse_u32_at(offset, data)?;
|
||||
st_value = endian.parse_u32_at(offset, data)? as u64;
|
||||
st_size = endian.parse_u32_at(offset, data)? as u64;
|
||||
st_info = endian.parse_u8_at(offset, data)?;
|
||||
st_other = endian.parse_u8_at(offset, data)?;
|
||||
st_shndx = endian.parse_u16_at(offset, data)?;
|
||||
} else {
|
||||
st_name = endian.parse_u32_at(offset, data)?;
|
||||
st_info = endian.parse_u8_at(offset, data)?;
|
||||
st_other = endian.parse_u8_at(offset, data)?;
|
||||
st_shndx = endian.parse_u16_at(offset, data)?;
|
||||
st_value = endian.parse_u64_at(offset, data)?;
|
||||
st_size = endian.parse_u64_at(offset, data)?;
|
||||
}
|
||||
|
||||
Ok(Symbol {
|
||||
st_name,
|
||||
st_value,
|
||||
st_size,
|
||||
st_shndx,
|
||||
st_info,
|
||||
st_other,
|
||||
})
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn size_for(class: Class) -> usize {
|
||||
match class {
|
||||
Class::ELF32 => 16,
|
||||
Class::ELF64 => 24,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod symbol_tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn symbol_undefined() {
|
||||
let undef_sym = Symbol {
|
||||
st_name: 0,
|
||||
st_value: 0,
|
||||
st_size: 0,
|
||||
st_shndx: 0,
|
||||
st_info: 0,
|
||||
st_other: 0,
|
||||
};
|
||||
assert!(undef_sym.is_undefined());
|
||||
|
||||
let def_sym = Symbol {
|
||||
st_name: 0,
|
||||
st_value: 0,
|
||||
st_size: 0,
|
||||
st_shndx: 42,
|
||||
st_info: 0,
|
||||
st_other: 0,
|
||||
};
|
||||
assert!(!def_sym.is_undefined());
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod parse_tests {
|
||||
use super::*;
|
||||
use crate::endian::{BigEndian, LittleEndian};
|
||||
use crate::parse::{test_parse_for, test_parse_fuzz_too_short};
|
||||
|
||||
#[test]
|
||||
fn parse_sym32_lsb() {
|
||||
test_parse_for(
|
||||
LittleEndian,
|
||||
Class::ELF32,
|
||||
Symbol {
|
||||
st_name: 0x03020100,
|
||||
st_value: 0x07060504,
|
||||
st_size: 0x0B0A0908,
|
||||
st_shndx: 0x0F0E,
|
||||
st_info: 0x0C,
|
||||
st_other: 0x0D,
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_sym32_msb() {
|
||||
test_parse_for(
|
||||
BigEndian,
|
||||
Class::ELF32,
|
||||
Symbol {
|
||||
st_name: 0x00010203,
|
||||
st_value: 0x04050607,
|
||||
st_size: 0x08090A0B,
|
||||
st_shndx: 0x0E0F,
|
||||
st_info: 0x0C,
|
||||
st_other: 0x0D,
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_sym64_lsb() {
|
||||
test_parse_for(
|
||||
LittleEndian,
|
||||
Class::ELF64,
|
||||
Symbol {
|
||||
st_name: 0x03020100,
|
||||
st_value: 0x0F0E0D0C0B0A0908,
|
||||
st_size: 0x1716151413121110,
|
||||
st_shndx: 0x0706,
|
||||
st_info: 0x04,
|
||||
st_other: 0x05,
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_sym64_msb() {
|
||||
test_parse_for(
|
||||
BigEndian,
|
||||
Class::ELF64,
|
||||
Symbol {
|
||||
st_name: 0x00010203,
|
||||
st_value: 0x08090A0B0C0D0E0F,
|
||||
st_size: 0x1011121314151617,
|
||||
st_shndx: 0x0607,
|
||||
st_info: 0x04,
|
||||
st_other: 0x05,
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_sym32_lsb_fuzz_too_short() {
|
||||
test_parse_fuzz_too_short::<_, Symbol>(LittleEndian, Class::ELF32);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_sym32_msb_fuzz_too_short() {
|
||||
test_parse_fuzz_too_short::<_, Symbol>(BigEndian, Class::ELF32);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_sym64_lsb_fuzz_too_short() {
|
||||
test_parse_fuzz_too_short::<_, Symbol>(LittleEndian, Class::ELF64);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_sym64_msb_fuzz_too_short() {
|
||||
test_parse_fuzz_too_short::<_, Symbol>(BigEndian, Class::ELF64);
|
||||
}
|
||||
}
|
677
mikros_std_deps/elf-0.7.4/src/to_str.rs
Normal file
677
mikros_std_deps/elf-0.7.4/src/to_str.rs
Normal file
@ -0,0 +1,677 @@
|
||||
//! Optional module for getting string representations of ELF constants
|
||||
use crate::abi;
|
||||
|
||||
pub fn e_osabi_to_str(e_osabi: u8) -> Option<&'static str> {
|
||||
match e_osabi {
|
||||
abi::ELFOSABI_SYSV => Some("ELFOSABI_SYSV"),
|
||||
abi::ELFOSABI_HPUX => Some("ELFOSABI_HPUX"),
|
||||
abi::ELFOSABI_NETBSD => Some("ELFOSABI_NETBSD"),
|
||||
abi::ELFOSABI_LINUX => Some("ELFOSABI_LINUX"),
|
||||
abi::ELFOSABI_SOLARIS => Some("ELFOSABI_SOLARIS"),
|
||||
abi::ELFOSABI_AIX => Some("ELFOSABI_AIX"),
|
||||
abi::ELFOSABI_IRIX => Some("ELFOSABI_IRIX"),
|
||||
abi::ELFOSABI_FREEBSD => Some("ELFOSABI_FREEBSD"),
|
||||
abi::ELFOSABI_TRU64 => Some("ELFOSABI_TRU64"),
|
||||
abi::ELFOSABI_MODESTO => Some("ELFOSABI_MODESTO"),
|
||||
abi::ELFOSABI_OPENBSD => Some("ELFOSABI_OPENBSD"),
|
||||
abi::ELFOSABI_OPENVMS => Some("ELFOSABI_OPENVMS"),
|
||||
abi::ELFOSABI_NSK => Some("ELFOSABI_NSK"),
|
||||
abi::ELFOSABI_AROS => Some("ELFOSABI_AROS"),
|
||||
abi::ELFOSABI_FENIXOS => Some("ELFOSABI_FENIXOS"),
|
||||
abi::ELFOSABI_CLOUDABI => Some("ELFOSABI_CLOUDABI"),
|
||||
abi::ELFOSABI_OPENVOS => Some("ELFOSABI_OPENVOS"),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn e_osabi_to_string(e_osabi: u8) -> String {
|
||||
match e_osabi_to_str(e_osabi) {
|
||||
Some(s) => s.to_string(),
|
||||
None => format!("e_osabi({e_osabi:#x})"),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn e_type_to_human_str(e_type: u16) -> Option<&'static str> {
|
||||
match e_type {
|
||||
abi::ET_NONE => Some("No file type"),
|
||||
abi::ET_REL => Some("Relocatable file"),
|
||||
abi::ET_EXEC => Some("Executable file"),
|
||||
abi::ET_DYN => Some("Shared object file"),
|
||||
abi::ET_CORE => Some("Core file"),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn e_type_to_str(e_type: u16) -> Option<&'static str> {
|
||||
match e_type {
|
||||
abi::ET_NONE => Some("ET_NONE"),
|
||||
abi::ET_REL => Some("ET_REL"),
|
||||
abi::ET_EXEC => Some("ET_EXEC"),
|
||||
abi::ET_DYN => Some("ET_DYN"),
|
||||
abi::ET_CORE => Some("ET_CORE"),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn e_type_to_string(e_type: u16) -> String {
|
||||
match e_type_to_str(e_type) {
|
||||
Some(s) => s.to_string(),
|
||||
None => format!("e_type({e_type:#x})"),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn e_machine_to_human_str(e_machine: u16) -> Option<&'static str> {
|
||||
match e_machine {
|
||||
abi::EM_NONE => Some("No machine"),
|
||||
abi::EM_M32 => Some("AT&T WE 32100"),
|
||||
abi::EM_SPARC => Some("SPARC"),
|
||||
abi::EM_386 => Some("Intel 80386"),
|
||||
abi::EM_68K => Some("Motorola 68000"),
|
||||
abi::EM_88K => Some("Motorola 88000"),
|
||||
abi::EM_IAMCU => Some("Intel MCU"),
|
||||
abi::EM_860 => Some("Intel 80860"),
|
||||
abi::EM_MIPS => Some("MIPS I Architecture"),
|
||||
abi::EM_S370 => Some("IBM System/370 Processor"),
|
||||
abi::EM_MIPS_RS3_LE => Some("MIPS RS3000 Little-endian"),
|
||||
abi::EM_PARISC => Some("Hewlett-Packard PA-RISC"),
|
||||
abi::EM_VPP500 => Some("Fujitsu VPP500"),
|
||||
abi::EM_SPARC32PLUS => Some("Enhanced instruction set SPARC"),
|
||||
abi::EM_960 => Some("Intel 80960"),
|
||||
abi::EM_PPC => Some("PowerPC"),
|
||||
abi::EM_PPC64 => Some("64-bit PowerPC"),
|
||||
abi::EM_S390 => Some("IBM System/390 Processor"),
|
||||
abi::EM_SPU => Some("IBM SPU/SPC"),
|
||||
abi::EM_V800 => Some("NEC V800"),
|
||||
abi::EM_FR20 => Some("Fujitsu FR20"),
|
||||
abi::EM_RH32 => Some("TRW RH-32"),
|
||||
abi::EM_RCE => Some("Motorola RCE"),
|
||||
abi::EM_ARM => Some("ARM 32-bit architecture (AARCH32)"),
|
||||
abi::EM_ALPHA => Some("Digital Alpha"),
|
||||
abi::EM_SH => Some("Hitachi SH"),
|
||||
abi::EM_SPARCV9 => Some("SPARC Version 9"),
|
||||
abi::EM_TRICORE => Some("Siemens TriCore embedded processor"),
|
||||
abi::EM_ARC => Some("Argonaut RISC Core, Argonaut Technologies Inc."),
|
||||
abi::EM_H8_300 => Some("Hitachi H8/300"),
|
||||
abi::EM_H8_300H => Some("Hitachi H8/300H"),
|
||||
abi::EM_H8S => Some("Hitachi H8S"),
|
||||
abi::EM_H8_500 => Some("Hitachi H8/500"),
|
||||
abi::EM_IA_64 => Some("Intel IA-64 processor architecture"),
|
||||
abi::EM_MIPS_X => Some("Stanford MIPS-X"),
|
||||
abi::EM_COLDFIRE => Some("Motorola ColdFire"),
|
||||
abi::EM_68HC12 => Some("Motorola M68HC12"),
|
||||
abi::EM_MMA => Some("Fujitsu MMA Multimedia Accelerator"),
|
||||
abi::EM_PCP => Some("Siemens PCP"),
|
||||
abi::EM_NCPU => Some("Sony nCPU embedded RISC processor"),
|
||||
abi::EM_NDR1 => Some("Denso NDR1 microprocessor"),
|
||||
abi::EM_STARCORE => Some("Motorola Star*Core processor"),
|
||||
abi::EM_ME16 => Some("Toyota ME16 processor"),
|
||||
abi::EM_ST100 => Some("STMicroelectronics ST100 processor"),
|
||||
abi::EM_TINYJ => Some("Advanced Logic Corp. TinyJ embedded processor family"),
|
||||
abi::EM_X86_64 => Some("AMD x86-64 architecture"),
|
||||
abi::EM_PDSP => Some("Sony DSP Processor"),
|
||||
abi::EM_PDP10 => Some("Digital Equipment Corp. PDP-10"),
|
||||
abi::EM_PDP11 => Some("Digital Equipment Corp. PDP-11"),
|
||||
abi::EM_FX66 => Some("Siemens FX66 microcontroller"),
|
||||
abi::EM_ST9PLUS => Some("STMicroelectronics ST9+ 8/16 bit microcontroller"),
|
||||
abi::EM_ST7 => Some("STMicroelectronics ST7 8-bit microcontroller"),
|
||||
abi::EM_68HC16 => Some("Motorola MC68HC16 Microcontroller"),
|
||||
abi::EM_68HC11 => Some("Motorola MC68HC11 Microcontroller"),
|
||||
abi::EM_68HC08 => Some("Motorola MC68HC08 Microcontroller"),
|
||||
abi::EM_68HC05 => Some("Motorola MC68HC05 Microcontroller"),
|
||||
abi::EM_SVX => Some("Silicon Graphics SVx"),
|
||||
abi::EM_ST19 => Some("STMicroelectronics ST19 8-bit microcontroller"),
|
||||
abi::EM_VAX => Some("Digital VAX"),
|
||||
abi::EM_CRIS => Some("Axis Communications 32-bit embedded processor"),
|
||||
abi::EM_JAVELIN => Some("Infineon Technologies 32-bit embedded processor"),
|
||||
abi::EM_FIREPATH => Some("Element 14 64-bit DSP Processor"),
|
||||
abi::EM_ZSP => Some("LSI Logic 16-bit DSP Processor"),
|
||||
abi::EM_MMIX => Some("Donald Knuth's educational 64-bit processor"),
|
||||
abi::EM_HUANY => Some("Harvard University machine-independent object files"),
|
||||
abi::EM_PRISM => Some("SiTera Prism"),
|
||||
abi::EM_AVR => Some("Atmel AVR 8-bit microcontroller"),
|
||||
abi::EM_FR30 => Some("Fujitsu FR30"),
|
||||
abi::EM_D10V => Some("Mitsubishi D10V"),
|
||||
abi::EM_D30V => Some("Mitsubishi D30V"),
|
||||
abi::EM_V850 => Some("NEC v850"),
|
||||
abi::EM_M32R => Some("Mitsubishi M32R"),
|
||||
abi::EM_MN10300 => Some("Matsushita MN10300"),
|
||||
abi::EM_MN10200 => Some("Matsushita MN10200"),
|
||||
abi::EM_PJ => Some("picoJava"),
|
||||
abi::EM_OPENRISC => Some("OpenRISC 32-bit embedded processor"),
|
||||
abi::EM_ARC_COMPACT => Some("ARC International ARCompact processor"),
|
||||
abi::EM_XTENSA => Some("Tensilica Xtensa Architecture"),
|
||||
abi::EM_VIDEOCORE => Some("Alphamosaic VideoCore processor"),
|
||||
abi::EM_TMM_GPP => Some("Thompson Multimedia General Purpose Processor"),
|
||||
abi::EM_NS32K => Some("National Semiconductor 32000 series"),
|
||||
abi::EM_TPC => Some("Tenor Network TPC processor"),
|
||||
abi::EM_SNP1K => Some("Trebia SNP 1000 processor"),
|
||||
abi::EM_ST200 => Some("STMicroelectronics (www.st.com) ST200 microcontroller"),
|
||||
abi::EM_IP2K => Some("Ubicom IP2xxx microcontroller family"),
|
||||
abi::EM_MAX => Some("MAX Processor"),
|
||||
abi::EM_CR => Some("National Semiconductor CompactRISC microprocessor"),
|
||||
abi::EM_F2MC16 => Some("Fujitsu F2MC16"),
|
||||
abi::EM_MSP430 => Some("Texas Instruments embedded microcontroller msp430"),
|
||||
abi::EM_BLACKFIN => Some("Analog Devices Blackfin (DSP) processor"),
|
||||
abi::EM_SE_C33 => Some("S1C33 Family of Seiko Epson processors"),
|
||||
abi::EM_SEP => Some("Sharp embedded microprocessor"),
|
||||
abi::EM_ARCA => Some("Arca RISC Microprocessor"),
|
||||
abi::EM_UNICORE => {
|
||||
Some("Microprocessor series from PKU-Unity Ltd. and MPRC of Peking University")
|
||||
}
|
||||
abi::EM_EXCESS => Some("eXcess: 16/32/64-bit configurable embedded CPU"),
|
||||
abi::EM_DXP => Some("Icera Semiconductor Inc. Deep Execution Processor"),
|
||||
abi::EM_ALTERA_NIOS2 => Some("Altera Nios II soft-core processor"),
|
||||
abi::EM_CRX => Some("National Semiconductor CompactRISC CRX microprocessor"),
|
||||
abi::EM_XGATE => Some("Motorola XGATE embedded processor"),
|
||||
abi::EM_C166 => Some("Infineon C16x/XC16x processor"),
|
||||
abi::EM_M16C => Some("Renesas M16C series microprocessors"),
|
||||
abi::EM_DSPIC30F => Some("Microchip Technology dsPIC30F Digital Signal Controller"),
|
||||
abi::EM_CE => Some("Freescale Communication Engine RISC core"),
|
||||
abi::EM_M32C => Some("Renesas M32C series microprocessors"),
|
||||
abi::EM_TSK3000 => Some("Altium TSK3000 core"),
|
||||
abi::EM_RS08 => Some("Freescale RS08 embedded processor"),
|
||||
abi::EM_SHARC => Some("Analog Devices SHARC family of 32-bit DSP processors"),
|
||||
abi::EM_ECOG2 => Some("Cyan Technology eCOG2 microprocessor"),
|
||||
abi::EM_SCORE7 => Some("Sunplus S+core7 RISC processor"),
|
||||
abi::EM_DSP24 => Some("New Japan Radio (NJR) 24-bit DSP Processor"),
|
||||
abi::EM_VIDEOCORE3 => Some("Broadcom VideoCore III processor"),
|
||||
abi::EM_LATTICEMICO32 => Some("RISC processor for Lattice FPGA architecture"),
|
||||
abi::EM_SE_C17 => Some("Seiko Epson C17 family"),
|
||||
abi::EM_TI_C6000 => Some("The Texas Instruments TMS320C6000 DSP family"),
|
||||
abi::EM_TI_C2000 => Some("The Texas Instruments TMS320C2000 DSP family"),
|
||||
abi::EM_TI_C5500 => Some("The Texas Instruments TMS320C55x DSP family"),
|
||||
abi::EM_TI_ARP32 => {
|
||||
Some("Texas Instruments Application Specific RISC Processor, 32bit fetch")
|
||||
}
|
||||
abi::EM_TI_PRU => Some("Texas Instruments Programmable Realtime Unit"),
|
||||
abi::EM_MMDSP_PLUS => Some("STMicroelectronics 64bit VLIW Data Signal Processor"),
|
||||
abi::EM_CYPRESS_M8C => Some("Cypress M8C microprocessor"),
|
||||
abi::EM_R32C => Some("Renesas R32C series microprocessors"),
|
||||
abi::EM_TRIMEDIA => Some("NXP Semiconductors TriMedia architecture family"),
|
||||
abi::EM_QDSP6 => Some("QUALCOMM DSP6 Processor"),
|
||||
abi::EM_8051 => Some("Intel 8051 and variants"),
|
||||
abi::EM_STXP7X => {
|
||||
Some("STMicroelectronics STxP7x family of configurable and extensible RISC processors")
|
||||
}
|
||||
abi::EM_NDS32 => Some("Andes Technology compact code size embedded RISC processor family"),
|
||||
abi::EM_ECOG1X => Some("Cyan Technology eCOG1X family"),
|
||||
abi::EM_MAXQ30 => Some("Dallas Semiconductor MAXQ30 Core Micro-controllers"),
|
||||
abi::EM_XIMO16 => Some("New Japan Radio (NJR) 16-bit DSP Processor"),
|
||||
abi::EM_MANIK => Some("M2000 Reconfigurable RISC Microprocessor"),
|
||||
abi::EM_CRAYNV2 => Some("Cray Inc. NV2 vector architecture"),
|
||||
abi::EM_RX => Some("Renesas RX family"),
|
||||
abi::EM_METAG => Some("Imagination Technologies META processor architecture"),
|
||||
abi::EM_MCST_ELBRUS => Some("MCST Elbrus general purpose hardware architecture"),
|
||||
abi::EM_ECOG16 => Some("Cyan Technology eCOG16 family"),
|
||||
abi::EM_CR16 => Some("National Semiconductor CompactRISC CR16 16-bit microprocessor"),
|
||||
abi::EM_ETPU => Some("Freescale Extended Time Processing Unit"),
|
||||
abi::EM_SLE9X => Some("Infineon Technologies SLE9X core"),
|
||||
abi::EM_L10M => Some("Intel L10M"),
|
||||
abi::EM_K10M => Some("Intel K10M"),
|
||||
abi::EM_AARCH64 => Some("ARM 64-bit architecture (AARCH64)"),
|
||||
abi::EM_AVR32 => Some("Atmel Corporation 32-bit microprocessor family"),
|
||||
abi::EM_STM8 => Some("STMicroeletronics STM8 8-bit microcontroller"),
|
||||
abi::EM_TILE64 => Some("Tilera TILE64 multicore architecture family"),
|
||||
abi::EM_TILEPRO => Some("Tilera TILEPro multicore architecture family"),
|
||||
abi::EM_MICROBLAZE => Some("Xilinx MicroBlaze 32-bit RISC soft processor core"),
|
||||
abi::EM_CUDA => Some("NVIDIA CUDA architecture"),
|
||||
abi::EM_TILEGX => Some("Tilera TILE-Gx multicore architecture family"),
|
||||
abi::EM_CLOUDSHIELD => Some("CloudShield architecture family"),
|
||||
abi::EM_COREA_1ST => Some("KIPO-KAIST Core-A 1st generation processor family"),
|
||||
abi::EM_COREA_2ND => Some("KIPO-KAIST Core-A 2nd generation processor family"),
|
||||
abi::EM_ARC_COMPACT2 => Some("Synopsys ARCompact V2"),
|
||||
abi::EM_OPEN8 => Some("Open8 8-bit RISC soft processor core"),
|
||||
abi::EM_RL78 => Some("Renesas RL78 family"),
|
||||
abi::EM_VIDEOCORE5 => Some("Broadcom VideoCore V processor"),
|
||||
abi::EM_78KOR => Some("Renesas 78KOR family"),
|
||||
abi::EM_56800EX => Some("Freescale 56800EX Digital Signal Controller (DSC)"),
|
||||
abi::EM_BA1 => Some("Beyond BA1 CPU architecture"),
|
||||
abi::EM_BA2 => Some("Beyond BA2 CPU architecture"),
|
||||
abi::EM_XCORE => Some("XMOS xCORE processor family"),
|
||||
abi::EM_MCHP_PIC => Some("Microchip 8-bit PIC(r) family"),
|
||||
abi::EM_INTEL205 => Some("Reserved by Intel"),
|
||||
abi::EM_INTEL206 => Some("Reserved by Intel"),
|
||||
abi::EM_INTEL207 => Some("Reserved by Intel"),
|
||||
abi::EM_INTEL208 => Some("Reserved by Intel"),
|
||||
abi::EM_INTEL209 => Some("Reserved by Intel"),
|
||||
abi::EM_KM32 => Some("KM211 KM32 32-bit processor"),
|
||||
abi::EM_KMX32 => Some("KM211 KMX32 32-bit processor"),
|
||||
abi::EM_KMX16 => Some("KM211 KMX16 16-bit processor"),
|
||||
abi::EM_KMX8 => Some("KM211 KMX8 8-bit processor"),
|
||||
abi::EM_KVARC => Some("KM211 KVARC processor"),
|
||||
abi::EM_CDP => Some("Paneve CDP architecture family"),
|
||||
abi::EM_COGE => Some("Cognitive Smart Memory Processor"),
|
||||
abi::EM_COOL => Some("Bluechip Systems CoolEngine"),
|
||||
abi::EM_NORC => Some("Nanoradio Optimized RISC"),
|
||||
abi::EM_CSR_KALIMBA => Some("CSR Kalimba architecture family"),
|
||||
abi::EM_Z80 => Some("Zilog Z80"),
|
||||
abi::EM_VISIUM => Some("Controls and Data Services VISIUMcore processor"),
|
||||
abi::EM_FT32 => Some("FTDI Chip FT32 high performance 32-bit RISC architecture"),
|
||||
abi::EM_MOXIE => Some("Moxie processor family"),
|
||||
abi::EM_AMDGPU => Some("AMD GPU architecture"),
|
||||
abi::EM_RISCV => Some("RISC-V"),
|
||||
abi::EM_BPF => Some("Linux BPF"),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn e_machine_to_str(e_machine: u16) -> Option<&'static str> {
|
||||
match e_machine {
|
||||
abi::EM_NONE => Some("EM_NONE"),
|
||||
abi::EM_M32 => Some("EM_M32"),
|
||||
abi::EM_SPARC => Some("EM_SPARC"),
|
||||
abi::EM_386 => Some("EM_386"),
|
||||
abi::EM_68K => Some("EM_68K"),
|
||||
abi::EM_88K => Some("EM_88K"),
|
||||
abi::EM_IAMCU => Some("EM_IAMCU"),
|
||||
abi::EM_860 => Some("EM_860"),
|
||||
abi::EM_MIPS => Some("EM_MIPS"),
|
||||
abi::EM_S370 => Some("EM_S370"),
|
||||
abi::EM_MIPS_RS3_LE => Some("EM_MIPS_RS3_LE"),
|
||||
abi::EM_PARISC => Some("EM_PARISC"),
|
||||
abi::EM_VPP500 => Some("EM_VPP500"),
|
||||
abi::EM_SPARC32PLUS => Some("EM_SPARC32PLUS"),
|
||||
abi::EM_960 => Some("EM_960"),
|
||||
abi::EM_PPC => Some("EM_PPC"),
|
||||
abi::EM_PPC64 => Some("EM_PPC64"),
|
||||
abi::EM_S390 => Some("EM_S390"),
|
||||
abi::EM_SPU => Some("EM_SPU"),
|
||||
abi::EM_V800 => Some("EM_V800"),
|
||||
abi::EM_FR20 => Some("EM_FR20"),
|
||||
abi::EM_RH32 => Some("EM_RH32"),
|
||||
abi::EM_RCE => Some("EM_RCE"),
|
||||
abi::EM_ARM => Some("EM_ARM"),
|
||||
abi::EM_ALPHA => Some("EM_ALPHA"),
|
||||
abi::EM_SH => Some("EM_SH"),
|
||||
abi::EM_SPARCV9 => Some("EM_SPARCV9"),
|
||||
abi::EM_TRICORE => Some("EM_TRICORE"),
|
||||
abi::EM_ARC => Some("EM_ARC"),
|
||||
abi::EM_H8_300 => Some("EM_H8_300"),
|
||||
abi::EM_H8_300H => Some("EM_H8_300H"),
|
||||
abi::EM_H8S => Some("EM_H8S"),
|
||||
abi::EM_H8_500 => Some("EM_H8_500"),
|
||||
abi::EM_IA_64 => Some("EM_IA_64"),
|
||||
abi::EM_MIPS_X => Some("EM_MIPS_X"),
|
||||
abi::EM_COLDFIRE => Some("EM_COLDFIRE"),
|
||||
abi::EM_68HC12 => Some("EM_68HC12"),
|
||||
abi::EM_MMA => Some("EM_MMA"),
|
||||
abi::EM_PCP => Some("EM_PCP"),
|
||||
abi::EM_NCPU => Some("EM_NCPU"),
|
||||
abi::EM_NDR1 => Some("EM_NDR1"),
|
||||
abi::EM_STARCORE => Some("EM_STARCORE"),
|
||||
abi::EM_ME16 => Some("EM_ME16"),
|
||||
abi::EM_ST100 => Some("EM_ST100"),
|
||||
abi::EM_TINYJ => Some("EM_TINYJ"),
|
||||
abi::EM_X86_64 => Some("EM_X86_64"),
|
||||
abi::EM_PDSP => Some("EM_PDSP"),
|
||||
abi::EM_PDP10 => Some("EM_PDP10"),
|
||||
abi::EM_PDP11 => Some("EM_PDP11"),
|
||||
abi::EM_FX66 => Some("EM_FX66"),
|
||||
abi::EM_ST9PLUS => Some("EM_ST9PLUS"),
|
||||
abi::EM_ST7 => Some("EM_ST7"),
|
||||
abi::EM_68HC16 => Some("EM_68HC16"),
|
||||
abi::EM_68HC11 => Some("EM_68HC11"),
|
||||
abi::EM_68HC08 => Some("EM_68HC08"),
|
||||
abi::EM_68HC05 => Some("EM_68HC05"),
|
||||
abi::EM_SVX => Some("EM_SVX"),
|
||||
abi::EM_ST19 => Some("EM_ST19"),
|
||||
abi::EM_VAX => Some("EM_VAX"),
|
||||
abi::EM_CRIS => Some("EM_CRIS"),
|
||||
abi::EM_JAVELIN => Some("EM_JAVELIN"),
|
||||
abi::EM_FIREPATH => Some("EM_FIREPATH"),
|
||||
abi::EM_ZSP => Some("EM_ZSP"),
|
||||
abi::EM_MMIX => Some("EM_MMIX"),
|
||||
abi::EM_HUANY => Some("EM_HUANY"),
|
||||
abi::EM_PRISM => Some("EM_PRISM"),
|
||||
abi::EM_AVR => Some("EM_AVR"),
|
||||
abi::EM_FR30 => Some("EM_FR30"),
|
||||
abi::EM_D10V => Some("EM_D10V"),
|
||||
abi::EM_D30V => Some("EM_D30V"),
|
||||
abi::EM_V850 => Some("EM_V850"),
|
||||
abi::EM_M32R => Some("EM_M32R"),
|
||||
abi::EM_MN10300 => Some("EM_MN10300"),
|
||||
abi::EM_MN10200 => Some("EM_MN10200"),
|
||||
abi::EM_PJ => Some("EM_PJ"),
|
||||
abi::EM_OPENRISC => Some("EM_OPENRISC"),
|
||||
abi::EM_ARC_COMPACT => Some("EM_ARC_COMPACT"),
|
||||
abi::EM_XTENSA => Some("EM_XTENSA"),
|
||||
abi::EM_VIDEOCORE => Some("EM_VIDEOCORE"),
|
||||
abi::EM_TMM_GPP => Some("EM_TMM_GPP"),
|
||||
abi::EM_NS32K => Some("EM_NS32K"),
|
||||
abi::EM_TPC => Some("EM_TPC"),
|
||||
abi::EM_SNP1K => Some("EM_SNP1K"),
|
||||
abi::EM_ST200 => Some("EM_ST200"),
|
||||
abi::EM_IP2K => Some("EM_IP2K"),
|
||||
abi::EM_MAX => Some("EM_MAX"),
|
||||
abi::EM_CR => Some("EM_CR"),
|
||||
abi::EM_F2MC16 => Some("EM_F2MC16"),
|
||||
abi::EM_MSP430 => Some("EM_MSP430"),
|
||||
abi::EM_BLACKFIN => Some("EM_BLACKFIN"),
|
||||
abi::EM_SE_C33 => Some("EM_SE_C33"),
|
||||
abi::EM_SEP => Some("EM_SEP"),
|
||||
abi::EM_ARCA => Some("EM_ARCA"),
|
||||
abi::EM_UNICORE => Some("EM_UNICORE"),
|
||||
abi::EM_EXCESS => Some("EM_EXCESS"),
|
||||
abi::EM_DXP => Some("EM_DXP"),
|
||||
abi::EM_ALTERA_NIOS2 => Some("EM_ALTERA_NIOS2"),
|
||||
abi::EM_CRX => Some("EM_CRX"),
|
||||
abi::EM_XGATE => Some("EM_XGATE"),
|
||||
abi::EM_C166 => Some("EM_C166"),
|
||||
abi::EM_M16C => Some("EM_M16C"),
|
||||
abi::EM_DSPIC30F => Some("EM_DSPIC30F"),
|
||||
abi::EM_CE => Some("EM_CE"),
|
||||
abi::EM_M32C => Some("EM_M32C"),
|
||||
abi::EM_TSK3000 => Some("EM_TSK3000"),
|
||||
abi::EM_RS08 => Some("EM_RS08"),
|
||||
abi::EM_SHARC => Some("EM_SHARC"),
|
||||
abi::EM_ECOG2 => Some("EM_ECOG2"),
|
||||
abi::EM_SCORE7 => Some("EM_SCORE7"),
|
||||
abi::EM_DSP24 => Some("EM_DSP24"),
|
||||
abi::EM_VIDEOCORE3 => Some("EM_VIDEOCORE3"),
|
||||
abi::EM_LATTICEMICO32 => Some("EM_LATTICEMICO32"),
|
||||
abi::EM_SE_C17 => Some("EM_SE_C17"),
|
||||
abi::EM_TI_C6000 => Some("EM_TI_C6000"),
|
||||
abi::EM_TI_C2000 => Some("EM_TI_C2000"),
|
||||
abi::EM_TI_C5500 => Some("EM_TI_C5500"),
|
||||
abi::EM_TI_ARP32 => Some("EM_TI_ARP32"),
|
||||
abi::EM_TI_PRU => Some("EM_TI_PRU"),
|
||||
abi::EM_MMDSP_PLUS => Some("EM_MMDSP_PLUS"),
|
||||
abi::EM_CYPRESS_M8C => Some("EM_CYPRESS_M8C"),
|
||||
abi::EM_R32C => Some("EM_R32C"),
|
||||
abi::EM_TRIMEDIA => Some("EM_TRIMEDIA"),
|
||||
abi::EM_QDSP6 => Some("EM_QDSP6"),
|
||||
abi::EM_8051 => Some("EM_8051"),
|
||||
abi::EM_STXP7X => Some("EM_STXP7X"),
|
||||
abi::EM_NDS32 => Some("EM_NDS32"),
|
||||
abi::EM_ECOG1X => Some("EM_ECOG1X"),
|
||||
abi::EM_MAXQ30 => Some("EM_MAXQ30"),
|
||||
abi::EM_XIMO16 => Some("EM_XIMO16"),
|
||||
abi::EM_MANIK => Some("EM_MANIK"),
|
||||
abi::EM_CRAYNV2 => Some("EM_CRAYNV2"),
|
||||
abi::EM_RX => Some("EM_RX"),
|
||||
abi::EM_METAG => Some("EM_METAG"),
|
||||
abi::EM_MCST_ELBRUS => Some("EM_MCST_ELBRUS"),
|
||||
abi::EM_ECOG16 => Some("EM_ECOG16"),
|
||||
abi::EM_CR16 => Some("EM_CR16"),
|
||||
abi::EM_ETPU => Some("EM_ETPU"),
|
||||
abi::EM_SLE9X => Some("EM_SLE9X"),
|
||||
abi::EM_L10M => Some("EM_L10M"),
|
||||
abi::EM_K10M => Some("EM_K10M"),
|
||||
abi::EM_AARCH64 => Some("EM_AARCH64"),
|
||||
abi::EM_AVR32 => Some("EM_AVR32"),
|
||||
abi::EM_STM8 => Some("EM_STM8"),
|
||||
abi::EM_TILE64 => Some("EM_TILE64"),
|
||||
abi::EM_TILEPRO => Some("EM_TILEPRO"),
|
||||
abi::EM_MICROBLAZE => Some("EM_MICROBLAZE"),
|
||||
abi::EM_CUDA => Some("EM_CUDA"),
|
||||
abi::EM_TILEGX => Some("EM_TILEGX"),
|
||||
abi::EM_CLOUDSHIELD => Some("EM_CLOUDSHIELD"),
|
||||
abi::EM_COREA_1ST => Some("EM_COREA_1ST"),
|
||||
abi::EM_COREA_2ND => Some("EM_COREA_2ND"),
|
||||
abi::EM_ARC_COMPACT2 => Some("EM_ARC_COMPACT2"),
|
||||
abi::EM_OPEN8 => Some("EM_OPEN8"),
|
||||
abi::EM_RL78 => Some("EM_RL78"),
|
||||
abi::EM_VIDEOCORE5 => Some("EM_VIDEOCORE5"),
|
||||
abi::EM_78KOR => Some("EM_78KOR"),
|
||||
abi::EM_56800EX => Some("EM_56800EX"),
|
||||
abi::EM_BA1 => Some("EM_BA1"),
|
||||
abi::EM_BA2 => Some("EM_BA2"),
|
||||
abi::EM_XCORE => Some("EM_XCORE"),
|
||||
abi::EM_MCHP_PIC => Some("EM_MCHP_PIC"),
|
||||
abi::EM_INTEL205 => Some("EM_INTEL205"),
|
||||
abi::EM_INTEL206 => Some("EM_INTEL206"),
|
||||
abi::EM_INTEL207 => Some("EM_INTEL207"),
|
||||
abi::EM_INTEL208 => Some("EM_INTEL208"),
|
||||
abi::EM_INTEL209 => Some("EM_INTEL209"),
|
||||
abi::EM_KM32 => Some("EM_KM32"),
|
||||
abi::EM_KMX32 => Some("EM_KMX32"),
|
||||
abi::EM_KMX16 => Some("EM_KMX16"),
|
||||
abi::EM_KMX8 => Some("EM_KMX8"),
|
||||
abi::EM_KVARC => Some("EM_KVARC"),
|
||||
abi::EM_CDP => Some("EM_CDP"),
|
||||
abi::EM_COGE => Some("EM_COGE"),
|
||||
abi::EM_COOL => Some("EM_COOL"),
|
||||
abi::EM_NORC => Some("EM_NORC"),
|
||||
abi::EM_CSR_KALIMBA => Some("EM_CSR_KALIMBA"),
|
||||
abi::EM_Z80 => Some("EM_Z80"),
|
||||
abi::EM_VISIUM => Some("EM_VISIUM"),
|
||||
abi::EM_FT32 => Some("EM_FT32"),
|
||||
abi::EM_MOXIE => Some("EM_MOXIE"),
|
||||
abi::EM_AMDGPU => Some("EM_AMDGPU"),
|
||||
abi::EM_RISCV => Some("RISC-V"),
|
||||
abi::EM_BPF => Some("EM_BPF"),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn e_machine_to_string(e_machine: u16) -> String {
|
||||
match e_machine_to_str(e_machine) {
|
||||
Some(s) => s.to_string(),
|
||||
None => format!("e_machine({e_machine:#x})"),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn sh_type_to_str(sh_type: u32) -> Option<&'static str> {
|
||||
match sh_type {
|
||||
abi::SHT_NULL => Some("SHT_NULL"),
|
||||
abi::SHT_PROGBITS => Some("SHT_PROGBITS"),
|
||||
abi::SHT_SYMTAB => Some("SHT_SYMTAB"),
|
||||
abi::SHT_STRTAB => Some("SHT_STRTAB"),
|
||||
abi::SHT_RELA => Some("SHT_RELA"),
|
||||
abi::SHT_HASH => Some("SHT_HASH"),
|
||||
abi::SHT_DYNAMIC => Some("SHT_DYNAMIC"),
|
||||
abi::SHT_NOTE => Some("SHT_NOTE"),
|
||||
abi::SHT_NOBITS => Some("SHT_NOBITS"),
|
||||
abi::SHT_REL => Some("SHT_REL"),
|
||||
abi::SHT_SHLIB => Some("SHT_SHLIB"),
|
||||
abi::SHT_DYNSYM => Some("SHT_DYNSYM"),
|
||||
abi::SHT_INIT_ARRAY => Some("SHT_INIT_ARRAY"),
|
||||
abi::SHT_FINI_ARRAY => Some("SHT_FINI_ARRAY"),
|
||||
abi::SHT_PREINIT_ARRAY => Some("SHT_PREINIT_ARRAY"),
|
||||
abi::SHT_GROUP => Some("SHT_GROUP"),
|
||||
abi::SHT_SYMTAB_SHNDX => Some("SHT_SYMTAB_SHNDX"),
|
||||
abi::SHT_GNU_ATTRIBUTES => Some("SHT_GNU_ATTRIBUTES"),
|
||||
abi::SHT_GNU_HASH => Some("SHT_GNU_HASH"),
|
||||
abi::SHT_GNU_LIBLIST => Some("SHT_GNU_LIBLIST"),
|
||||
abi::SHT_GNU_VERDEF => Some("SHT_GNU_VERDEF"),
|
||||
abi::SHT_GNU_VERNEED => Some("SHT_GNU_VERNEED"),
|
||||
abi::SHT_GNU_VERSYM => Some("SHT_GNU_VERSYM"),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn sh_type_to_string(sh_type: u32) -> String {
|
||||
match sh_type_to_str(sh_type) {
|
||||
Some(s) => s.to_string(),
|
||||
None => format!("sh_type({sh_type:#x})"),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn p_flags_to_string(p_flags: u32) -> String {
|
||||
match p_flags < 8 {
|
||||
true => {
|
||||
let r = if p_flags & abi::PF_R != 0 { "R" } else { " " };
|
||||
let w = if p_flags & abi::PF_W != 0 { "W" } else { " " };
|
||||
let x = if p_flags & abi::PF_X != 0 { "E" } else { " " };
|
||||
format!("{r}{w}{x}")
|
||||
}
|
||||
false => format!("p_flags({p_flags:#x})"),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn p_type_to_str(p_type: u32) -> Option<&'static str> {
|
||||
match p_type {
|
||||
abi::PT_NULL => Some("PT_NULL"),
|
||||
abi::PT_LOAD => Some("PT_LOAD"),
|
||||
abi::PT_DYNAMIC => Some("PT_DYNAMIC"),
|
||||
abi::PT_INTERP => Some("PT_INTERP"),
|
||||
abi::PT_NOTE => Some("PT_NOTE"),
|
||||
abi::PT_SHLIB => Some("PT_SHLIB"),
|
||||
abi::PT_PHDR => Some("PT_PHDR"),
|
||||
abi::PT_TLS => Some("PT_TLS"),
|
||||
abi::PT_GNU_EH_FRAME => Some("PT_GNU_EH_FRAME"),
|
||||
abi::PT_GNU_STACK => Some("PT_GNU_STACK"),
|
||||
abi::PT_GNU_RELRO => Some("PT_GNU_RELRO"),
|
||||
abi::PT_GNU_PROPERTY => Some("PT_GNU_PROPERTY"),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn p_type_to_string(p_type: u32) -> String {
|
||||
match p_type_to_str(p_type) {
|
||||
Some(s) => s.to_string(),
|
||||
None => format!("p_type({p_type:#x})"),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn st_symtype_to_str(st_symtype: u8) -> Option<&'static str> {
|
||||
match st_symtype {
|
||||
abi::STT_NOTYPE => Some("STT_NOTYPE"),
|
||||
abi::STT_OBJECT => Some("STT_OBJECT"),
|
||||
abi::STT_FUNC => Some("STT_FUNC"),
|
||||
abi::STT_SECTION => Some("STT_SECTION"),
|
||||
abi::STT_FILE => Some("STT_FILE"),
|
||||
abi::STT_COMMON => Some("STT_COMMON"),
|
||||
abi::STT_TLS => Some("STT_TLS"),
|
||||
abi::STT_GNU_IFUNC => Some("STT_GNU_IFUNC"),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn st_symtype_to_string(st_symtype: u8) -> String {
|
||||
match st_symtype_to_str(st_symtype) {
|
||||
Some(s) => s.to_string(),
|
||||
None => format!("st_symtype({st_symtype:#x})"),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn st_bind_to_str(st_bind: u8) -> Option<&'static str> {
|
||||
match st_bind {
|
||||
abi::STB_LOCAL => Some("STB_LOCAL"),
|
||||
abi::STB_GLOBAL => Some("STB_GLOBAL"),
|
||||
abi::STB_WEAK => Some("STB_WEAK"),
|
||||
abi::STB_GNU_UNIQUE => Some("STB_GNU_UNIQUE"),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn st_bind_to_string(st_bind: u8) -> String {
|
||||
match st_bind_to_str(st_bind) {
|
||||
Some(s) => s.to_string(),
|
||||
None => format!("st_bind({st_bind:#x})"),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn st_vis_to_str(st_vis: u8) -> Option<&'static str> {
|
||||
match st_vis {
|
||||
abi::STV_DEFAULT => Some("STV_DEFAULT"),
|
||||
abi::STV_INTERNAL => Some("STV_INTERNAL"),
|
||||
abi::STV_HIDDEN => Some("STV_HIDDEN"),
|
||||
abi::STV_PROTECTED => Some("STV_PROTECTED"),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn st_vis_to_string(st_vis: u8) -> String {
|
||||
match st_vis_to_str(st_vis) {
|
||||
Some(s) => s.to_string(),
|
||||
None => format!("st_vis({st_vis:#x})"),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn ch_type_to_str(ch_type: u32) -> Option<&'static str> {
|
||||
match ch_type {
|
||||
abi::ELFCOMPRESS_ZLIB => Some("ELFCOMPRESS_ZLIB"),
|
||||
abi::ELFCOMPRESS_ZSTD => Some("ELFCOMPRESS_ZSTD "),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn note_abi_tag_os_to_str(os: u32) -> Option<&'static str> {
|
||||
match os {
|
||||
abi::ELF_NOTE_GNU_ABI_TAG_OS_LINUX => Some("Linux"),
|
||||
abi::ELF_NOTE_GNU_ABI_TAG_OS_GNU => Some("GNU"),
|
||||
abi::ELF_NOTE_GNU_ABI_TAG_OS_SOLARIS2 => Some("Solaris"),
|
||||
abi::ELF_NOTE_GNU_ABI_TAG_OS_FREEBSD => Some("FreeBSD"),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn d_tag_to_str(d_tag: i64) -> Option<&'static str> {
|
||||
match d_tag {
|
||||
abi::DT_NULL => Some("DT_NULL"),
|
||||
abi::DT_NEEDED => Some("DT_NEEDED"),
|
||||
abi::DT_PLTRELSZ => Some("DT_PLTRELSZ"),
|
||||
abi::DT_PLTGOT => Some("DT_PLTGOT"),
|
||||
abi::DT_HASH => Some("DT_HASH"),
|
||||
abi::DT_STRTAB => Some("DT_STRTAB"),
|
||||
abi::DT_SYMTAB => Some("DT_SYMTAB"),
|
||||
abi::DT_RELA => Some("DT_RELA"),
|
||||
abi::DT_RELASZ => Some("DT_RELASZ"),
|
||||
abi::DT_RELAENT => Some("DT_RELAENT"),
|
||||
abi::DT_STRSZ => Some("DT_STRSZ"),
|
||||
abi::DT_SYMENT => Some("DT_SYMENT"),
|
||||
abi::DT_INIT => Some("DT_INIT"),
|
||||
abi::DT_FINI => Some("DT_FINI"),
|
||||
abi::DT_SONAME => Some("DT_SONAME"),
|
||||
abi::DT_RPATH => Some("DT_RPATH"),
|
||||
abi::DT_SYMBOLIC => Some("DT_SYMBOLIC"),
|
||||
abi::DT_REL => Some("DT_REL"),
|
||||
abi::DT_RELSZ => Some("DT_RELSZ"),
|
||||
abi::DT_RELENT => Some("DT_RELENT"),
|
||||
abi::DT_PLTREL => Some("DT_PLTREL"),
|
||||
abi::DT_DEBUG => Some("DT_DEBUG"),
|
||||
abi::DT_TEXTREL => Some("DT_TEXTREL"),
|
||||
abi::DT_JMPREL => Some("DT_JMPREL"),
|
||||
abi::DT_BIND_NOW => Some("DT_BIND_NOW"),
|
||||
abi::DT_INIT_ARRAY => Some("DT_INIT_ARRAY"),
|
||||
abi::DT_FINI_ARRAY => Some("DT_FINI_ARRAY"),
|
||||
abi::DT_INIT_ARRAYSZ => Some("DT_INIT_ARRAYSZ"),
|
||||
abi::DT_FINI_ARRAYSZ => Some("DT_FINI_ARRAYSZ"),
|
||||
abi::DT_RUNPATH => Some("DT_RUNPATH"),
|
||||
abi::DT_FLAGS => Some("DT_FLAGS"),
|
||||
abi::DT_PREINIT_ARRAY => Some("DT_PREINIT_ARRAY"),
|
||||
abi::DT_PREINIT_ARRAYSZ => Some("DT_PREINIT_ARRAYSZ"),
|
||||
abi::DT_SYMTAB_SHNDX => Some("DT_SYMTAB_SHNDX"),
|
||||
abi::DT_GUILE_GC_ROOT => Some("DT_GUILE_GC_ROOT"),
|
||||
abi::DT_GUILE_GC_ROOT_SZ => Some("DT_GUILE_GC_ROOT_SZ"),
|
||||
abi::DT_GUILE_ENTRY => Some("DT_GUILE_ENTRY"),
|
||||
abi::DT_GUILE_VM_VERSION => Some("DT_GUILE_VM_VERSION"),
|
||||
abi::DT_GUILE_FRAME_MAPS => Some("DT_GUILE_FRAME_MAPS"),
|
||||
abi::DT_LOOS => Some("DT_LOOS"),
|
||||
abi::DT_GNU_PRELINKED => Some("DT_GNU_PRELINKED"),
|
||||
abi::DT_GNU_CONFLICTSZ => Some("DT_GNU_CONFLICTSZ"),
|
||||
abi::DT_GNU_LIBLISTSZ => Some("DT_GNU_LIBLISTSZ"),
|
||||
abi::DT_CHECKSUM => Some("DT_CHECKSUM"),
|
||||
abi::DT_PLTPADSZ => Some("DT_PLTPADSZ"),
|
||||
abi::DT_MOVEENT => Some("DT_MOVEENT"),
|
||||
abi::DT_MOVESZ => Some("DT_MOVESZ"),
|
||||
abi::DT_FEATURE_1 => Some("DT_FEATURE_1"),
|
||||
abi::DT_POSFLAG_1 => Some("DT_POSFLAG_1"),
|
||||
abi::DT_SYMINSZ => Some("DT_SYMINSZ"),
|
||||
abi::DT_SYMINENT => Some("DT_SYMINENT"),
|
||||
abi::DT_GNU_HASH => Some("DT_GNU_HASH"),
|
||||
abi::DT_TLSDESC_PLT => Some("DT_TLSDESC_PLT"),
|
||||
abi::DT_TLSDESC_GOT => Some("DT_TLSDESC_GOT"),
|
||||
abi::DT_GNU_CONFLICT => Some("DT_GNU_CONFLICT"),
|
||||
abi::DT_GNU_LIBLIST => Some("DT_GNU_LIBLIST"),
|
||||
abi::DT_CONFIG => Some("DT_CONFIG"),
|
||||
abi::DT_DEPAUDIT => Some("DT_DEPAUDIT"),
|
||||
abi::DT_AUDIT => Some("DT_AUDIT"),
|
||||
abi::DT_PLTPAD => Some("DT_PLTPAD"),
|
||||
abi::DT_MOVETAB => Some("DT_MOVETAB"),
|
||||
abi::DT_SYMINFO => Some("DT_SYMINFO"),
|
||||
abi::DT_VERSYM => Some("DT_VERSYM"),
|
||||
abi::DT_RELACOUNT => Some("DT_RELACOUNT"),
|
||||
abi::DT_RELCOUNT => Some("DT_RELCOUNT"),
|
||||
abi::DT_FLAGS_1 => Some("DT_FLAGS_1"),
|
||||
abi::DT_VERDEF => Some("DT_VERDEF"),
|
||||
abi::DT_VERDEFNUM => Some("DT_VERDEFNUM"),
|
||||
abi::DT_VERNEED => Some("DT_VERNEED"),
|
||||
abi::DT_VERNEEDNUM => Some("DT_VERNEEDNUM"),
|
||||
abi::DT_HIOS => Some("DT_HIOS"),
|
||||
abi::DT_LOPROC => Some("DT_LOPROC"),
|
||||
abi::DT_HIPROC => Some("DT_HIPROC"),
|
||||
_ => None,
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user