Initial vendor packages
Signed-off-by: Valentin Popov <valentin@popov.link>
This commit is contained in:
321
vendor/gimli/src/read/str.rs
vendored
Normal file
321
vendor/gimli/src/read/str.rs
vendored
Normal file
@ -0,0 +1,321 @@
|
||||
use crate::common::{
|
||||
DebugLineStrOffset, DebugStrOffset, DebugStrOffsetsBase, DebugStrOffsetsIndex, DwarfFileType,
|
||||
Encoding, SectionId,
|
||||
};
|
||||
use crate::endianity::Endianity;
|
||||
use crate::read::{EndianSlice, Reader, ReaderOffset, Result, Section};
|
||||
use crate::Format;
|
||||
|
||||
/// The `DebugStr` struct represents the DWARF strings
|
||||
/// found in the `.debug_str` section.
|
||||
#[derive(Debug, Default, Clone, Copy)]
|
||||
pub struct DebugStr<R> {
|
||||
debug_str_section: R,
|
||||
}
|
||||
|
||||
impl<'input, Endian> DebugStr<EndianSlice<'input, Endian>>
|
||||
where
|
||||
Endian: Endianity,
|
||||
{
|
||||
/// Construct a new `DebugStr` instance from the data in the `.debug_str`
|
||||
/// section.
|
||||
///
|
||||
/// It is the caller's responsibility to read the `.debug_str` section and
|
||||
/// present it as a `&[u8]` slice. That means using some ELF loader on
|
||||
/// Linux, a Mach-O loader on macOS, etc.
|
||||
///
|
||||
/// ```
|
||||
/// use gimli::{DebugStr, LittleEndian};
|
||||
///
|
||||
/// # let buf = [0x00, 0x01, 0x02, 0x03];
|
||||
/// # let read_debug_str_section_somehow = || &buf;
|
||||
/// let debug_str = DebugStr::new(read_debug_str_section_somehow(), LittleEndian);
|
||||
/// ```
|
||||
pub fn new(debug_str_section: &'input [u8], endian: Endian) -> Self {
|
||||
Self::from(EndianSlice::new(debug_str_section, endian))
|
||||
}
|
||||
}
|
||||
|
||||
impl<R: Reader> DebugStr<R> {
|
||||
/// Lookup a string from the `.debug_str` section by DebugStrOffset.
|
||||
///
|
||||
/// ```
|
||||
/// use gimli::{DebugStr, DebugStrOffset, LittleEndian};
|
||||
///
|
||||
/// # let buf = [0x01, 0x02, 0x00];
|
||||
/// # let offset = DebugStrOffset(0);
|
||||
/// # let read_debug_str_section_somehow = || &buf;
|
||||
/// # let debug_str_offset_somehow = || offset;
|
||||
/// let debug_str = DebugStr::new(read_debug_str_section_somehow(), LittleEndian);
|
||||
/// println!("Found string {:?}", debug_str.get_str(debug_str_offset_somehow()));
|
||||
/// ```
|
||||
pub fn get_str(&self, offset: DebugStrOffset<R::Offset>) -> Result<R> {
|
||||
let input = &mut self.debug_str_section.clone();
|
||||
input.skip(offset.0)?;
|
||||
input.read_null_terminated_slice()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> DebugStr<T> {
|
||||
/// Create a `DebugStr` section that references the data in `self`.
|
||||
///
|
||||
/// This is useful when `R` implements `Reader` but `T` does not.
|
||||
///
|
||||
/// ## Example Usage
|
||||
///
|
||||
/// ```rust,no_run
|
||||
/// # let load_section = || unimplemented!();
|
||||
/// // Read the DWARF section into a `Vec` with whatever object loader you're using.
|
||||
/// let owned_section: gimli::DebugStr<Vec<u8>> = load_section();
|
||||
/// // Create a reference to the DWARF section.
|
||||
/// let section = owned_section.borrow(|section| {
|
||||
/// gimli::EndianSlice::new(§ion, gimli::LittleEndian)
|
||||
/// });
|
||||
/// ```
|
||||
pub fn borrow<'a, F, R>(&'a self, mut borrow: F) -> DebugStr<R>
|
||||
where
|
||||
F: FnMut(&'a T) -> R,
|
||||
{
|
||||
borrow(&self.debug_str_section).into()
|
||||
}
|
||||
}
|
||||
|
||||
impl<R> Section<R> for DebugStr<R> {
|
||||
fn id() -> SectionId {
|
||||
SectionId::DebugStr
|
||||
}
|
||||
|
||||
fn reader(&self) -> &R {
|
||||
&self.debug_str_section
|
||||
}
|
||||
}
|
||||
|
||||
impl<R> From<R> for DebugStr<R> {
|
||||
fn from(debug_str_section: R) -> Self {
|
||||
DebugStr { debug_str_section }
|
||||
}
|
||||
}
|
||||
|
||||
/// The raw contents of the `.debug_str_offsets` section.
|
||||
#[derive(Debug, Default, Clone, Copy)]
|
||||
pub struct DebugStrOffsets<R> {
|
||||
section: R,
|
||||
}
|
||||
|
||||
impl<R: Reader> DebugStrOffsets<R> {
|
||||
// TODO: add an iterator over the sets of entries in the section.
|
||||
// This is not needed for common usage of the section though.
|
||||
|
||||
/// Returns the `.debug_str` offset at the given `base` and `index`.
|
||||
///
|
||||
/// A set of entries in the `.debug_str_offsets` section consists of a header
|
||||
/// followed by a series of string table offsets.
|
||||
///
|
||||
/// The `base` must be the `DW_AT_str_offsets_base` value from the compilation unit DIE.
|
||||
/// This is an offset that points to the first entry following the header.
|
||||
///
|
||||
/// The `index` is the value of a `DW_FORM_strx` attribute.
|
||||
///
|
||||
/// The `format` must be the DWARF format of the compilation unit. This format must
|
||||
/// match the header. However, note that we do not parse the header to validate this,
|
||||
/// since locating the header is unreliable, and the GNU extensions do not emit it.
|
||||
pub fn get_str_offset(
|
||||
&self,
|
||||
format: Format,
|
||||
base: DebugStrOffsetsBase<R::Offset>,
|
||||
index: DebugStrOffsetsIndex<R::Offset>,
|
||||
) -> Result<DebugStrOffset<R::Offset>> {
|
||||
let input = &mut self.section.clone();
|
||||
input.skip(base.0)?;
|
||||
input.skip(R::Offset::from_u64(
|
||||
index.0.into_u64() * u64::from(format.word_size()),
|
||||
)?)?;
|
||||
input.read_offset(format).map(DebugStrOffset)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> DebugStrOffsets<T> {
|
||||
/// Create a `DebugStrOffsets` section that references the data in `self`.
|
||||
///
|
||||
/// This is useful when `R` implements `Reader` but `T` does not.
|
||||
///
|
||||
/// ## Example Usage
|
||||
///
|
||||
/// ```rust,no_run
|
||||
/// # let load_section = || unimplemented!();
|
||||
/// // Read the DWARF section into a `Vec` with whatever object loader you're using.
|
||||
/// let owned_section: gimli::DebugStrOffsets<Vec<u8>> = load_section();
|
||||
/// // Create a reference to the DWARF section.
|
||||
/// let section = owned_section.borrow(|section| {
|
||||
/// gimli::EndianSlice::new(§ion, gimli::LittleEndian)
|
||||
/// });
|
||||
/// ```
|
||||
pub fn borrow<'a, F, R>(&'a self, mut borrow: F) -> DebugStrOffsets<R>
|
||||
where
|
||||
F: FnMut(&'a T) -> R,
|
||||
{
|
||||
borrow(&self.section).into()
|
||||
}
|
||||
}
|
||||
|
||||
impl<R> Section<R> for DebugStrOffsets<R> {
|
||||
fn id() -> SectionId {
|
||||
SectionId::DebugStrOffsets
|
||||
}
|
||||
|
||||
fn reader(&self) -> &R {
|
||||
&self.section
|
||||
}
|
||||
}
|
||||
|
||||
impl<R> From<R> for DebugStrOffsets<R> {
|
||||
fn from(section: R) -> Self {
|
||||
DebugStrOffsets { section }
|
||||
}
|
||||
}
|
||||
|
||||
impl<Offset> DebugStrOffsetsBase<Offset>
|
||||
where
|
||||
Offset: ReaderOffset,
|
||||
{
|
||||
/// Returns a `DebugStrOffsetsBase` with the default value of DW_AT_str_offsets_base
|
||||
/// for the given `Encoding` and `DwarfFileType`.
|
||||
pub fn default_for_encoding_and_file(
|
||||
encoding: Encoding,
|
||||
file_type: DwarfFileType,
|
||||
) -> DebugStrOffsetsBase<Offset> {
|
||||
if encoding.version >= 5 && file_type == DwarfFileType::Dwo {
|
||||
// In .dwo files, the compiler omits the DW_AT_str_offsets_base attribute (because there is
|
||||
// only a single unit in the file) but we must skip past the header, which the attribute
|
||||
// would normally do for us.
|
||||
// initial_length_size + version + 2 bytes of padding.
|
||||
DebugStrOffsetsBase(Offset::from_u8(
|
||||
encoding.format.initial_length_size() + 2 + 2,
|
||||
))
|
||||
} else {
|
||||
DebugStrOffsetsBase(Offset::from_u8(0))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// The `DebugLineStr` struct represents the DWARF strings
|
||||
/// found in the `.debug_line_str` section.
|
||||
#[derive(Debug, Default, Clone, Copy)]
|
||||
pub struct DebugLineStr<R> {
|
||||
section: R,
|
||||
}
|
||||
|
||||
impl<'input, Endian> DebugLineStr<EndianSlice<'input, Endian>>
|
||||
where
|
||||
Endian: Endianity,
|
||||
{
|
||||
/// Construct a new `DebugLineStr` instance from the data in the `.debug_line_str`
|
||||
/// section.
|
||||
///
|
||||
/// It is the caller's responsibility to read the `.debug_line_str` section and
|
||||
/// present it as a `&[u8]` slice. That means using some ELF loader on
|
||||
/// Linux, a Mach-O loader on macOS, etc.
|
||||
///
|
||||
/// ```
|
||||
/// use gimli::{DebugLineStr, LittleEndian};
|
||||
///
|
||||
/// # let buf = [0x00, 0x01, 0x02, 0x03];
|
||||
/// # let read_debug_line_str_section_somehow = || &buf;
|
||||
/// let debug_str = DebugLineStr::new(read_debug_line_str_section_somehow(), LittleEndian);
|
||||
/// ```
|
||||
pub fn new(debug_line_str_section: &'input [u8], endian: Endian) -> Self {
|
||||
Self::from(EndianSlice::new(debug_line_str_section, endian))
|
||||
}
|
||||
}
|
||||
|
||||
impl<R: Reader> DebugLineStr<R> {
|
||||
/// Lookup a string from the `.debug_line_str` section by DebugLineStrOffset.
|
||||
pub fn get_str(&self, offset: DebugLineStrOffset<R::Offset>) -> Result<R> {
|
||||
let input = &mut self.section.clone();
|
||||
input.skip(offset.0)?;
|
||||
input.read_null_terminated_slice()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> DebugLineStr<T> {
|
||||
/// Create a `DebugLineStr` section that references the data in `self`.
|
||||
///
|
||||
/// This is useful when `R` implements `Reader` but `T` does not.
|
||||
///
|
||||
/// ## Example Usage
|
||||
///
|
||||
/// ```rust,no_run
|
||||
/// # let load_section = || unimplemented!();
|
||||
/// // Read the DWARF section into a `Vec` with whatever object loader you're using.
|
||||
/// let owned_section: gimli::DebugLineStr<Vec<u8>> = load_section();
|
||||
/// // Create a reference to the DWARF section.
|
||||
/// let section = owned_section.borrow(|section| {
|
||||
/// gimli::EndianSlice::new(§ion, gimli::LittleEndian)
|
||||
/// });
|
||||
/// ```
|
||||
pub fn borrow<'a, F, R>(&'a self, mut borrow: F) -> DebugLineStr<R>
|
||||
where
|
||||
F: FnMut(&'a T) -> R,
|
||||
{
|
||||
borrow(&self.section).into()
|
||||
}
|
||||
}
|
||||
|
||||
impl<R> Section<R> for DebugLineStr<R> {
|
||||
fn id() -> SectionId {
|
||||
SectionId::DebugLineStr
|
||||
}
|
||||
|
||||
fn reader(&self) -> &R {
|
||||
&self.section
|
||||
}
|
||||
}
|
||||
|
||||
impl<R> From<R> for DebugLineStr<R> {
|
||||
fn from(section: R) -> Self {
|
||||
DebugLineStr { section }
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::test_util::GimliSectionMethods;
|
||||
use crate::LittleEndian;
|
||||
use test_assembler::{Endian, Label, LabelMaker, Section};
|
||||
|
||||
#[test]
|
||||
fn test_get_str_offset() {
|
||||
for format in vec![Format::Dwarf32, Format::Dwarf64] {
|
||||
let zero = Label::new();
|
||||
let length = Label::new();
|
||||
let start = Label::new();
|
||||
let first = Label::new();
|
||||
let end = Label::new();
|
||||
let mut section = Section::with_endian(Endian::Little)
|
||||
.mark(&zero)
|
||||
.initial_length(format, &length, &start)
|
||||
.D16(5)
|
||||
.D16(0)
|
||||
.mark(&first);
|
||||
for i in 0..20 {
|
||||
section = section.word(format.word_size(), 1000 + i);
|
||||
}
|
||||
section = section.mark(&end);
|
||||
length.set_const((&end - &start) as u64);
|
||||
|
||||
let section = section.get_contents().unwrap();
|
||||
let debug_str_offsets = DebugStrOffsets::from(EndianSlice::new(§ion, LittleEndian));
|
||||
let base = DebugStrOffsetsBase((&first - &zero) as usize);
|
||||
|
||||
assert_eq!(
|
||||
debug_str_offsets.get_str_offset(format, base, DebugStrOffsetsIndex(0)),
|
||||
Ok(DebugStrOffset(1000))
|
||||
);
|
||||
assert_eq!(
|
||||
debug_str_offsets.get_str_offset(format, base, DebugStrOffsetsIndex(19)),
|
||||
Ok(DebugStrOffset(1019))
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user