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.
The table has additional helpful features, like .get() to parse a given index in the table,
while still allowing access to the ParsingIterator interface via .iter()
Also remove dubiously helpful File::section_strings() method
If you want the strings, you probably also want the headers, so use the section_headers_with_strtab()
method.
The table has additional helpful features, like .get() to parse a given index in the table,
while still allowing access to the ParsingIterator interface via .iter()
New interfaces:
* 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)
Previously, it would forget to load and then just try to get the strings section data
This would work if some other processing on the file had already loaded the string table
but not if this was the first method that wanted to inspect those strings.
This class of bugs is really an integration with the CachedReadBytes interface, so it
can only get caught if we're testing with that impl. These interface tests should be parameterized
for both interfaces.
This is a zero-alloc interface which parses on-demand, which can be desireable if you can't
or don't want to allocate, but is less CPU-efficient if you're doing a lot of look ups on the table.
This more closely matches the datastructure and its use-case. Users are likely
wanting to look up the VerNeeds and VerDefs for a particular symbol in the .dynsym
table, and to do so they'll need to look up the VersionIndex by the Symbol's index
in the .dynsym table. The ParsingTable helps provide that interface with its .get(index)
method.
Alternatively, someone could do a variant of zip(SymbolTable.iter(), VersionTable.iter())
to have the Symbol alongside the VersionIndex, which is also supported by VersionTable.
Also, use this ParsingTable to replace the hand-rolled SymbolTable.
This implements a lazily-parsed table/array of structs that can be parsed
with the ParseAt trait that drives the parsing of our ELF structs.
Elements in the table are lazily parsed on-demand via the .get(index)
method. The table can also optionally be converted into a ParsingIterator
with either iter() or into_iter(), meaning the ParsingTable can be used
like so:
```
let table = ParsingTable<Foo>::new(...)
for foo in Table {
... do things with parsed Foo
}
```
or
```
let table = ParsingTable<Foo>::new(...)
for foo in Table.iter() {
... do things with parsed Foo
}
for foo in Table.iter() {
... do another pass of things with parsed Foo
}
```
Note that the second pattern will re-parse the second time. Useful
if you're wanting to avoid allocations, but otherwise it's probably
more useful to .collect() the iterator into a Vec<Foo>.
I think that ideally this would be able to yield a ParseError in some way,
as it likely indicates corrupted section data. All of our iterators silently
end iteration on ParseErrors currently, though, so this is in line with
existing patterns of behavior.
There was only one implementer of this trait, on &[u8], and the indirection
didn't serve any real purpose. The indirection via the double &&[u8] impl was
more expensive than necessary, and the indirection also added a layer of unnecessary
cognitive overhead to reading the code.
This goes back to having simple parse methods for the endian-aware integer parsing
which operate on byte slices.
These other type of entries are found in the .gnu.version_r section of type SHT_GNU_VERNEED.
This only parses the type, and is not hooked up to anything else yet.