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)
This was caused by the alignment modulus calculation when fuzzing gave a note section header with zero-byte alignment
"attempt to calculate the remainder with a divisor of zero"
I kept this as pub(crate) for now, as I'm not sure if the naming is confusing for users or not,
so I want to keep it out of the public interface for now.
My plan is to use the correct width of the corresponding ELF types when parsing ELF structures
and then converting them into usize as appropriate when those fields are being interpreted
to locate other elf structures within in-memory buffers. For the common case these days
of 64-bit machines with 64-bit usizes, these conversions will all succeed. For 32-bit
machines, this conversion means that the library will not be able to parse large 64-bit
files. When that happens, though, the library should helpfully return an error instead of crashing.
These same sorts of changes will need to be made throughout the library in order to
harden it against crashing due to integer overflow math (often due to corrupted files).
Fuzzing catches this sort of thing really quickly.
Also, introduce two new resulting ParseError types:
TryFromIntError and IntegerOverflow
Note that the SysVHashTable::find() method does not currently take any symbol versioning
into account.
Also, add another sample elf file that contains a two versioned exported
symbols, a SHT_HASH section, a SHT_GNU_HASH section, GNU Symbol
Versioning sections, and .note.gnu.property and .note.gnu.build-id sections.
This skips the utf8 validation done in StringTable::get() and is helpful
for code that wants to interpret the raw bytes (such as for calculating hash values).
This didn't end up providing much value. As an interface, we want to be able
to be able to parse files with unknown section types the type had to allow
unknown values anyway. All it provided was an opinionated Display impl,
which can be easily recovered with sh_type_to_str() or sh_type_to_string()
This reduces a ton of boiler-plate code. It can also probably be reduced even
further with some macros, but I generally find macros add more cognitive overhead
than they're worth for simple tests like this. Maybe a project for another rainy day ;)
All of the uses validate the entsize as found in the file, so there's no need
to perform the duplicate validation again in the constructor. It's desireable
to do the validation before trying to get the buffer to back the table. So while
it'd be nice to have the table do the checking automatically for you, it happens
too late when done automatically that way.
There's no need to represent it as bytes in the actual table representation when
we've validated that it's a known constant for the given ELF class that we're parsing.
This is done by making each ParseAt type aware of the sizes based on the ELF class
via a new ParseAT::size_for(class) method, then adding validation checks based on that.
This output is opinionated in a way that is likely unhelpful for users of this
library. If someone is wanting to display FileHeader contents, they likely want
their own string formatting, and can construct it with the to_str helpers.
This output is opinionated in a way that is likely unhelpful for users of this
library. If someone is wanting to display ProgramHeader contents, they likely want
their own string formatting, and can construct it with the to_str helpers.
This output is opinionated in a way that is likely unhelpful for users of this
library. If someone is wanting to display SectionHeader contents, they likely want
their own string formatting, and can construct it with the to_str helpers.
This output is opinionated in a way that is likely unhelpful for users of this
library. If someone is wanting to display Symbol contents, they likely want
their own string formatting, and can construct it with the to_str helpers.
This has a few motivations:
* Move the big blocks of code dedicated to providing human readable strings for
gabi constants out of the way. This code can be long and distracting from the actual
parsing functionality.
* Allow users to opt out of this functionality if they don't need it. The big blocks
of &'static str definitions can add a fair amount to the resulting library size. For
users who are trying to optimize for library size, these to_str methods are often unneeded.
* The to_str method's Option return value allows users to decide how they want to display
unknown values.