Initial vendor packages

Signed-off-by: Valentin Popov <valentin@popov.link>
This commit is contained in:
2024-01-08 01:21:28 +04:00
parent 5ecd8cf2cb
commit 1b6a04ca55
7309 changed files with 2160054 additions and 0 deletions

188
vendor/gimli/src/write/abbrev.rs vendored Normal file
View File

@ -0,0 +1,188 @@
use alloc::vec::Vec;
use indexmap::IndexSet;
use std::ops::{Deref, DerefMut};
use crate::common::{DebugAbbrevOffset, SectionId};
use crate::constants;
use crate::write::{Result, Section, Writer};
/// A table of abbreviations that will be stored in a `.debug_abbrev` section.
// Requirements:
// - values are `Abbreviation`
// - insertion returns an abbreviation code for use in writing a DIE
// - inserting a duplicate returns the code of the existing value
#[derive(Debug, Default)]
pub(crate) struct AbbreviationTable {
abbrevs: IndexSet<Abbreviation>,
}
impl AbbreviationTable {
/// Add an abbreviation to the table and return its code.
pub fn add(&mut self, abbrev: Abbreviation) -> u64 {
let (code, _) = self.abbrevs.insert_full(abbrev);
// Code must be non-zero
(code + 1) as u64
}
/// Write the abbreviation table to the `.debug_abbrev` section.
pub fn write<W: Writer>(&self, w: &mut DebugAbbrev<W>) -> Result<()> {
for (code, abbrev) in self.abbrevs.iter().enumerate() {
w.write_uleb128((code + 1) as u64)?;
abbrev.write(w)?;
}
// Null abbreviation code
w.write_u8(0)
}
}
/// An abbreviation describes the shape of a `DebuggingInformationEntry`'s type:
/// its tag type, whether it has children, and its set of attributes.
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub(crate) struct Abbreviation {
tag: constants::DwTag,
has_children: bool,
attributes: Vec<AttributeSpecification>,
}
impl Abbreviation {
/// Construct a new `Abbreviation`.
#[inline]
pub fn new(
tag: constants::DwTag,
has_children: bool,
attributes: Vec<AttributeSpecification>,
) -> Abbreviation {
Abbreviation {
tag,
has_children,
attributes,
}
}
/// Write the abbreviation to the `.debug_abbrev` section.
pub fn write<W: Writer>(&self, w: &mut DebugAbbrev<W>) -> Result<()> {
w.write_uleb128(self.tag.0.into())?;
w.write_u8(if self.has_children {
constants::DW_CHILDREN_yes.0
} else {
constants::DW_CHILDREN_no.0
})?;
for attr in &self.attributes {
attr.write(w)?;
}
// Null name and form
w.write_u8(0)?;
w.write_u8(0)
}
}
/// The description of an attribute in an abbreviated type.
// TODO: support implicit const
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub(crate) struct AttributeSpecification {
name: constants::DwAt,
form: constants::DwForm,
}
impl AttributeSpecification {
/// Construct a new `AttributeSpecification`.
#[inline]
pub fn new(name: constants::DwAt, form: constants::DwForm) -> AttributeSpecification {
AttributeSpecification { name, form }
}
/// Write the attribute specification to the `.debug_abbrev` section.
#[inline]
pub fn write<W: Writer>(&self, w: &mut DebugAbbrev<W>) -> Result<()> {
w.write_uleb128(self.name.0.into())?;
w.write_uleb128(self.form.0.into())
}
}
define_section!(
DebugAbbrev,
DebugAbbrevOffset,
"A writable `.debug_abbrev` section."
);
#[cfg(test)]
#[cfg(feature = "read")]
mod tests {
use super::*;
use crate::constants;
use crate::read;
use crate::write::EndianVec;
use crate::LittleEndian;
#[test]
fn test_abbreviation_table() {
let mut abbrevs = AbbreviationTable::default();
let abbrev1 = Abbreviation::new(
constants::DW_TAG_subprogram,
false,
vec![AttributeSpecification::new(
constants::DW_AT_name,
constants::DW_FORM_string,
)],
);
let abbrev2 = Abbreviation::new(
constants::DW_TAG_compile_unit,
true,
vec![
AttributeSpecification::new(constants::DW_AT_producer, constants::DW_FORM_strp),
AttributeSpecification::new(constants::DW_AT_language, constants::DW_FORM_data2),
],
);
let code1 = abbrevs.add(abbrev1.clone());
assert_eq!(code1, 1);
let code2 = abbrevs.add(abbrev2.clone());
assert_eq!(code2, 2);
assert_eq!(abbrevs.add(abbrev1.clone()), code1);
assert_eq!(abbrevs.add(abbrev2.clone()), code2);
let mut debug_abbrev = DebugAbbrev::from(EndianVec::new(LittleEndian));
let debug_abbrev_offset = debug_abbrev.offset();
assert_eq!(debug_abbrev_offset, DebugAbbrevOffset(0));
abbrevs.write(&mut debug_abbrev).unwrap();
assert_eq!(debug_abbrev.offset(), DebugAbbrevOffset(17));
let read_debug_abbrev = read::DebugAbbrev::new(debug_abbrev.slice(), LittleEndian);
let read_abbrevs = read_debug_abbrev
.abbreviations(debug_abbrev_offset)
.unwrap();
let read_abbrev1 = read_abbrevs.get(code1).unwrap();
assert_eq!(abbrev1.tag, read_abbrev1.tag());
assert_eq!(abbrev1.has_children, read_abbrev1.has_children());
assert_eq!(abbrev1.attributes.len(), read_abbrev1.attributes().len());
assert_eq!(
abbrev1.attributes[0].name,
read_abbrev1.attributes()[0].name()
);
assert_eq!(
abbrev1.attributes[0].form,
read_abbrev1.attributes()[0].form()
);
let read_abbrev2 = read_abbrevs.get(code2).unwrap();
assert_eq!(abbrev2.tag, read_abbrev2.tag());
assert_eq!(abbrev2.has_children, read_abbrev2.has_children());
assert_eq!(abbrev2.attributes.len(), read_abbrev2.attributes().len());
assert_eq!(
abbrev2.attributes[0].name,
read_abbrev2.attributes()[0].name()
);
assert_eq!(
abbrev2.attributes[0].form,
read_abbrev2.attributes()[0].form()
);
assert_eq!(
abbrev2.attributes[1].name,
read_abbrev2.attributes()[1].name()
);
assert_eq!(
abbrev2.attributes[1].form,
read_abbrev2.attributes()[1].form()
);
}
}

1050
vendor/gimli/src/write/cfi.rs vendored Normal file

File diff suppressed because it is too large Load Diff

138
vendor/gimli/src/write/dwarf.rs vendored Normal file
View File

@ -0,0 +1,138 @@
use alloc::vec::Vec;
use crate::common::Encoding;
use crate::write::{
AbbreviationTable, LineProgram, LineStringTable, Result, Sections, StringTable, Unit,
UnitTable, Writer,
};
/// Writable DWARF information for more than one unit.
#[derive(Debug, Default)]
pub struct Dwarf {
/// A table of units. These are primarily stored in the `.debug_info` section,
/// but they also contain information that is stored in other sections.
pub units: UnitTable,
/// Extra line number programs that are not associated with a unit.
///
/// These should only be used when generating DWARF5 line-only debug
/// information.
pub line_programs: Vec<LineProgram>,
/// A table of strings that will be stored in the `.debug_line_str` section.
pub line_strings: LineStringTable,
/// A table of strings that will be stored in the `.debug_str` section.
pub strings: StringTable,
}
impl Dwarf {
/// Create a new `Dwarf` instance.
#[inline]
pub fn new() -> Self {
Self::default()
}
/// Write the DWARF information to the given sections.
pub fn write<W: Writer>(&mut self, sections: &mut Sections<W>) -> Result<()> {
let line_strings = self.line_strings.write(&mut sections.debug_line_str)?;
let strings = self.strings.write(&mut sections.debug_str)?;
self.units.write(sections, &line_strings, &strings)?;
for line_program in &self.line_programs {
line_program.write(
&mut sections.debug_line,
line_program.encoding(),
&line_strings,
&strings,
)?;
}
Ok(())
}
}
/// Writable DWARF information for a single unit.
#[derive(Debug)]
pub struct DwarfUnit {
/// A unit. This is primarily stored in the `.debug_info` section,
/// but also contains information that is stored in other sections.
pub unit: Unit,
/// A table of strings that will be stored in the `.debug_line_str` section.
pub line_strings: LineStringTable,
/// A table of strings that will be stored in the `.debug_str` section.
pub strings: StringTable,
}
impl DwarfUnit {
/// Create a new `DwarfUnit`.
///
/// Note: you should set `self.unit.line_program` after creation.
/// This cannot be done earlier because it may need to reference
/// `self.line_strings`.
pub fn new(encoding: Encoding) -> Self {
let unit = Unit::new(encoding, LineProgram::none());
DwarfUnit {
unit,
line_strings: LineStringTable::default(),
strings: StringTable::default(),
}
}
/// Write the DWARf information to the given sections.
pub fn write<W: Writer>(&mut self, sections: &mut Sections<W>) -> Result<()> {
let line_strings = self.line_strings.write(&mut sections.debug_line_str)?;
let strings = self.strings.write(&mut sections.debug_str)?;
let abbrev_offset = sections.debug_abbrev.offset();
let mut abbrevs = AbbreviationTable::default();
self.unit.write(
sections,
abbrev_offset,
&mut abbrevs,
&line_strings,
&strings,
)?;
// None should exist because we didn't give out any UnitId.
assert!(sections.debug_info_refs.is_empty());
assert!(sections.debug_loc_refs.is_empty());
assert!(sections.debug_loclists_refs.is_empty());
abbrevs.write(&mut sections.debug_abbrev)?;
Ok(())
}
}
#[cfg(feature = "read")]
pub(crate) mod convert {
use super::*;
use crate::read::{self, Reader};
use crate::write::{Address, ConvertResult};
impl Dwarf {
/// Create a `write::Dwarf` by converting a `read::Dwarf`.
///
/// `convert_address` is a function to convert read addresses into the `Address`
/// type. For non-relocatable addresses, this function may simply return
/// `Address::Constant(address)`. For relocatable addresses, it is the caller's
/// responsibility to determine the symbol and addend corresponding to the address
/// and return `Address::Symbol { symbol, addend }`.
pub fn from<R: Reader<Offset = usize>>(
dwarf: &read::Dwarf<R>,
convert_address: &dyn Fn(u64) -> Option<Address>,
) -> ConvertResult<Dwarf> {
let mut line_strings = LineStringTable::default();
let mut strings = StringTable::default();
let units = UnitTable::from(dwarf, &mut line_strings, &mut strings, convert_address)?;
// TODO: convert the line programs that were not referenced by a unit.
let line_programs = Vec::new();
Ok(Dwarf {
units,
line_programs,
line_strings,
strings,
})
}
}
}

117
vendor/gimli/src/write/endian_vec.rs vendored Normal file
View File

@ -0,0 +1,117 @@
use alloc::vec::Vec;
use std::mem;
use crate::endianity::Endianity;
use crate::write::{Error, Result, Writer};
/// A `Vec<u8>` with endianity metadata.
///
/// This implements the `Writer` trait, which is used for all writing of DWARF sections.
#[derive(Debug, Clone)]
pub struct EndianVec<Endian>
where
Endian: Endianity,
{
vec: Vec<u8>,
endian: Endian,
}
impl<Endian> EndianVec<Endian>
where
Endian: Endianity,
{
/// Construct an empty `EndianVec` with the given endianity.
pub fn new(endian: Endian) -> EndianVec<Endian> {
EndianVec {
vec: Vec::new(),
endian,
}
}
/// Return a reference to the raw slice.
pub fn slice(&self) -> &[u8] {
&self.vec
}
/// Convert into a `Vec<u8>`.
pub fn into_vec(self) -> Vec<u8> {
self.vec
}
/// Take any written data out of the `EndianVec`, leaving an empty `Vec` in its place.
pub fn take(&mut self) -> Vec<u8> {
let mut vec = Vec::new();
mem::swap(&mut self.vec, &mut vec);
vec
}
}
impl<Endian> Writer for EndianVec<Endian>
where
Endian: Endianity,
{
type Endian = Endian;
#[inline]
fn endian(&self) -> Self::Endian {
self.endian
}
#[inline]
fn len(&self) -> usize {
self.vec.len()
}
fn write(&mut self, bytes: &[u8]) -> Result<()> {
self.vec.extend(bytes);
Ok(())
}
fn write_at(&mut self, offset: usize, bytes: &[u8]) -> Result<()> {
if offset > self.vec.len() {
return Err(Error::OffsetOutOfBounds);
}
let to = &mut self.vec[offset..];
if bytes.len() > to.len() {
return Err(Error::LengthOutOfBounds);
}
let to = &mut to[..bytes.len()];
to.copy_from_slice(bytes);
Ok(())
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::LittleEndian;
#[test]
fn test_endian_vec() {
let mut w = EndianVec::new(LittleEndian);
assert_eq!(w.endian(), LittleEndian);
assert_eq!(w.len(), 0);
w.write(&[1, 2]).unwrap();
assert_eq!(w.slice(), &[1, 2]);
assert_eq!(w.len(), 2);
w.write(&[3, 4, 5]).unwrap();
assert_eq!(w.slice(), &[1, 2, 3, 4, 5]);
assert_eq!(w.len(), 5);
w.write_at(0, &[6, 7]).unwrap();
assert_eq!(w.slice(), &[6, 7, 3, 4, 5]);
assert_eq!(w.len(), 5);
w.write_at(3, &[8, 9]).unwrap();
assert_eq!(w.slice(), &[6, 7, 3, 8, 9]);
assert_eq!(w.len(), 5);
assert_eq!(w.write_at(4, &[6, 7]), Err(Error::LengthOutOfBounds));
assert_eq!(w.write_at(5, &[6, 7]), Err(Error::LengthOutOfBounds));
assert_eq!(w.write_at(6, &[6, 7]), Err(Error::OffsetOutOfBounds));
assert_eq!(w.into_vec(), vec![6, 7, 3, 8, 9]);
}
}

1957
vendor/gimli/src/write/line.rs vendored Normal file

File diff suppressed because it is too large Load Diff

550
vendor/gimli/src/write/loc.rs vendored Normal file
View File

@ -0,0 +1,550 @@
use alloc::vec::Vec;
use indexmap::IndexSet;
use std::ops::{Deref, DerefMut};
use crate::common::{Encoding, LocationListsOffset, SectionId};
use crate::write::{
Address, BaseId, DebugInfoReference, Error, Expression, Result, Section, Sections, UnitOffsets,
Writer,
};
define_section!(
DebugLoc,
LocationListsOffset,
"A writable `.debug_loc` section."
);
define_section!(
DebugLocLists,
LocationListsOffset,
"A writable `.debug_loclists` section."
);
define_offsets!(
LocationListOffsets: LocationListId => LocationListsOffset,
"The section offsets of a series of location lists within the `.debug_loc` or `.debug_loclists` sections."
);
define_id!(
LocationListId,
"An identifier for a location list in a `LocationListTable`."
);
/// A table of location lists that will be stored in a `.debug_loc` or `.debug_loclists` section.
#[derive(Debug, Default)]
pub struct LocationListTable {
base_id: BaseId,
locations: IndexSet<LocationList>,
}
impl LocationListTable {
/// Add a location list to the table.
pub fn add(&mut self, loc_list: LocationList) -> LocationListId {
let (index, _) = self.locations.insert_full(loc_list);
LocationListId::new(self.base_id, index)
}
/// Write the location list table to the appropriate section for the given DWARF version.
pub(crate) fn write<W: Writer>(
&self,
sections: &mut Sections<W>,
encoding: Encoding,
unit_offsets: Option<&UnitOffsets>,
) -> Result<LocationListOffsets> {
if self.locations.is_empty() {
return Ok(LocationListOffsets::none());
}
match encoding.version {
2..=4 => self.write_loc(
&mut sections.debug_loc,
&mut sections.debug_loc_refs,
encoding,
unit_offsets,
),
5 => self.write_loclists(
&mut sections.debug_loclists,
&mut sections.debug_loclists_refs,
encoding,
unit_offsets,
),
_ => Err(Error::UnsupportedVersion(encoding.version)),
}
}
/// Write the location list table to the `.debug_loc` section.
fn write_loc<W: Writer>(
&self,
w: &mut DebugLoc<W>,
refs: &mut Vec<DebugInfoReference>,
encoding: Encoding,
unit_offsets: Option<&UnitOffsets>,
) -> Result<LocationListOffsets> {
let address_size = encoding.address_size;
let mut offsets = Vec::new();
for loc_list in self.locations.iter() {
offsets.push(w.offset());
for loc in &loc_list.0 {
// Note that we must ensure none of the ranges have both begin == 0 and end == 0.
// We do this by ensuring that begin != end, which is a bit more restrictive
// than required, but still seems reasonable.
match *loc {
Location::BaseAddress { address } => {
let marker = !0 >> (64 - address_size * 8);
w.write_udata(marker, address_size)?;
w.write_address(address, address_size)?;
}
Location::OffsetPair {
begin,
end,
ref data,
} => {
if begin == end {
return Err(Error::InvalidRange);
}
w.write_udata(begin, address_size)?;
w.write_udata(end, address_size)?;
write_expression(&mut w.0, refs, encoding, unit_offsets, data)?;
}
Location::StartEnd {
begin,
end,
ref data,
} => {
if begin == end {
return Err(Error::InvalidRange);
}
w.write_address(begin, address_size)?;
w.write_address(end, address_size)?;
write_expression(&mut w.0, refs, encoding, unit_offsets, data)?;
}
Location::StartLength {
begin,
length,
ref data,
} => {
let end = match begin {
Address::Constant(begin) => Address::Constant(begin + length),
Address::Symbol { symbol, addend } => Address::Symbol {
symbol,
addend: addend + length as i64,
},
};
if begin == end {
return Err(Error::InvalidRange);
}
w.write_address(begin, address_size)?;
w.write_address(end, address_size)?;
write_expression(&mut w.0, refs, encoding, unit_offsets, data)?;
}
Location::DefaultLocation { .. } => {
return Err(Error::InvalidRange);
}
}
}
w.write_udata(0, address_size)?;
w.write_udata(0, address_size)?;
}
Ok(LocationListOffsets {
base_id: self.base_id,
offsets,
})
}
/// Write the location list table to the `.debug_loclists` section.
fn write_loclists<W: Writer>(
&self,
w: &mut DebugLocLists<W>,
refs: &mut Vec<DebugInfoReference>,
encoding: Encoding,
unit_offsets: Option<&UnitOffsets>,
) -> Result<LocationListOffsets> {
let mut offsets = Vec::new();
if encoding.version != 5 {
return Err(Error::NeedVersion(5));
}
let length_offset = w.write_initial_length(encoding.format)?;
let length_base = w.len();
w.write_u16(encoding.version)?;
w.write_u8(encoding.address_size)?;
w.write_u8(0)?; // segment_selector_size
w.write_u32(0)?; // offset_entry_count (when set to zero DW_FORM_rnglistx can't be used, see section 7.28)
// FIXME implement DW_FORM_rnglistx writing and implement the offset entry list
for loc_list in self.locations.iter() {
offsets.push(w.offset());
for loc in &loc_list.0 {
match *loc {
Location::BaseAddress { address } => {
w.write_u8(crate::constants::DW_LLE_base_address.0)?;
w.write_address(address, encoding.address_size)?;
}
Location::OffsetPair {
begin,
end,
ref data,
} => {
w.write_u8(crate::constants::DW_LLE_offset_pair.0)?;
w.write_uleb128(begin)?;
w.write_uleb128(end)?;
write_expression(&mut w.0, refs, encoding, unit_offsets, data)?;
}
Location::StartEnd {
begin,
end,
ref data,
} => {
w.write_u8(crate::constants::DW_LLE_start_end.0)?;
w.write_address(begin, encoding.address_size)?;
w.write_address(end, encoding.address_size)?;
write_expression(&mut w.0, refs, encoding, unit_offsets, data)?;
}
Location::StartLength {
begin,
length,
ref data,
} => {
w.write_u8(crate::constants::DW_LLE_start_length.0)?;
w.write_address(begin, encoding.address_size)?;
w.write_uleb128(length)?;
write_expression(&mut w.0, refs, encoding, unit_offsets, data)?;
}
Location::DefaultLocation { ref data } => {
w.write_u8(crate::constants::DW_LLE_default_location.0)?;
write_expression(&mut w.0, refs, encoding, unit_offsets, data)?;
}
}
}
w.write_u8(crate::constants::DW_LLE_end_of_list.0)?;
}
let length = (w.len() - length_base) as u64;
w.write_initial_length_at(length_offset, length, encoding.format)?;
Ok(LocationListOffsets {
base_id: self.base_id,
offsets,
})
}
}
/// A locations list that will be stored in a `.debug_loc` or `.debug_loclists` section.
#[derive(Clone, Debug, Eq, PartialEq, Hash)]
pub struct LocationList(pub Vec<Location>);
/// A single location.
#[derive(Clone, Debug, Eq, PartialEq, Hash)]
pub enum Location {
/// DW_LLE_base_address
BaseAddress {
/// Base address.
address: Address,
},
/// DW_LLE_offset_pair
OffsetPair {
/// Start of range relative to base address.
begin: u64,
/// End of range relative to base address.
end: u64,
/// Location description.
data: Expression,
},
/// DW_LLE_start_end
StartEnd {
/// Start of range.
begin: Address,
/// End of range.
end: Address,
/// Location description.
data: Expression,
},
/// DW_LLE_start_length
StartLength {
/// Start of range.
begin: Address,
/// Length of range.
length: u64,
/// Location description.
data: Expression,
},
/// DW_LLE_default_location
DefaultLocation {
/// Location description.
data: Expression,
},
}
fn write_expression<W: Writer>(
w: &mut W,
refs: &mut Vec<DebugInfoReference>,
encoding: Encoding,
unit_offsets: Option<&UnitOffsets>,
val: &Expression,
) -> Result<()> {
let size = val.size(encoding, unit_offsets) as u64;
if encoding.version <= 4 {
w.write_udata(size, 2)?;
} else {
w.write_uleb128(size)?;
}
val.write(w, Some(refs), encoding, unit_offsets)?;
Ok(())
}
#[cfg(feature = "read")]
mod convert {
use super::*;
use crate::read::{self, Reader};
use crate::write::{ConvertError, ConvertResult, ConvertUnitContext};
impl LocationList {
/// Create a location list by reading the data from the give location list iter.
pub(crate) fn from<R: Reader<Offset = usize>>(
mut from: read::RawLocListIter<R>,
context: &ConvertUnitContext<R>,
) -> ConvertResult<Self> {
let mut have_base_address = context.base_address != Address::Constant(0);
let convert_address =
|x| (context.convert_address)(x).ok_or(ConvertError::InvalidAddress);
let convert_expression = |x| {
Expression::from(
x,
context.unit.encoding(),
Some(context.dwarf),
Some(context.unit),
Some(context.entry_ids),
context.convert_address,
)
};
let mut loc_list = Vec::new();
while let Some(from_loc) = from.next()? {
let loc = match from_loc {
read::RawLocListEntry::AddressOrOffsetPair { begin, end, data } => {
// These were parsed as addresses, even if they are offsets.
let begin = convert_address(begin)?;
let end = convert_address(end)?;
let data = convert_expression(data)?;
match (begin, end) {
(Address::Constant(begin_offset), Address::Constant(end_offset)) => {
if have_base_address {
Location::OffsetPair {
begin: begin_offset,
end: end_offset,
data,
}
} else {
Location::StartEnd { begin, end, data }
}
}
_ => {
if have_base_address {
// At least one of begin/end is an address, but we also have
// a base address. Adding addresses is undefined.
return Err(ConvertError::InvalidRangeRelativeAddress);
}
Location::StartEnd { begin, end, data }
}
}
}
read::RawLocListEntry::BaseAddress { addr } => {
have_base_address = true;
let address = convert_address(addr)?;
Location::BaseAddress { address }
}
read::RawLocListEntry::BaseAddressx { addr } => {
have_base_address = true;
let address = convert_address(context.dwarf.address(context.unit, addr)?)?;
Location::BaseAddress { address }
}
read::RawLocListEntry::StartxEndx { begin, end, data } => {
let begin = convert_address(context.dwarf.address(context.unit, begin)?)?;
let end = convert_address(context.dwarf.address(context.unit, end)?)?;
let data = convert_expression(data)?;
Location::StartEnd { begin, end, data }
}
read::RawLocListEntry::StartxLength {
begin,
length,
data,
} => {
let begin = convert_address(context.dwarf.address(context.unit, begin)?)?;
let data = convert_expression(data)?;
Location::StartLength {
begin,
length,
data,
}
}
read::RawLocListEntry::OffsetPair { begin, end, data } => {
let data = convert_expression(data)?;
Location::OffsetPair { begin, end, data }
}
read::RawLocListEntry::StartEnd { begin, end, data } => {
let begin = convert_address(begin)?;
let end = convert_address(end)?;
let data = convert_expression(data)?;
Location::StartEnd { begin, end, data }
}
read::RawLocListEntry::StartLength {
begin,
length,
data,
} => {
let begin = convert_address(begin)?;
let data = convert_expression(data)?;
Location::StartLength {
begin,
length,
data,
}
}
read::RawLocListEntry::DefaultLocation { data } => {
let data = convert_expression(data)?;
Location::DefaultLocation { data }
}
};
// In some cases, existing data may contain begin == end, filtering
// these out.
match loc {
Location::StartLength { length, .. } if length == 0 => continue,
Location::StartEnd { begin, end, .. } if begin == end => continue,
Location::OffsetPair { begin, end, .. } if begin == end => continue,
_ => (),
}
loc_list.push(loc);
}
Ok(LocationList(loc_list))
}
}
}
#[cfg(test)]
#[cfg(feature = "read")]
mod tests {
use super::*;
use crate::common::{
DebugAbbrevOffset, DebugAddrBase, DebugInfoOffset, DebugLocListsBase, DebugRngListsBase,
DebugStrOffsetsBase, Format,
};
use crate::read;
use crate::write::{
ConvertUnitContext, EndianVec, LineStringTable, RangeListTable, StringTable,
};
use crate::LittleEndian;
use std::collections::HashMap;
use std::sync::Arc;
#[test]
fn test_loc_list() {
let mut line_strings = LineStringTable::default();
let mut strings = StringTable::default();
let mut expression = Expression::new();
expression.op_constu(0);
for &version in &[2, 3, 4, 5] {
for &address_size in &[4, 8] {
for &format in &[Format::Dwarf32, Format::Dwarf64] {
let encoding = Encoding {
format,
version,
address_size,
};
let mut loc_list = LocationList(vec![
Location::StartLength {
begin: Address::Constant(6666),
length: 7777,
data: expression.clone(),
},
Location::StartEnd {
begin: Address::Constant(4444),
end: Address::Constant(5555),
data: expression.clone(),
},
Location::BaseAddress {
address: Address::Constant(1111),
},
Location::OffsetPair {
begin: 2222,
end: 3333,
data: expression.clone(),
},
]);
if version >= 5 {
loc_list.0.push(Location::DefaultLocation {
data: expression.clone(),
});
}
let mut locations = LocationListTable::default();
let loc_list_id = locations.add(loc_list.clone());
let mut sections = Sections::new(EndianVec::new(LittleEndian));
let loc_list_offsets = locations.write(&mut sections, encoding, None).unwrap();
assert!(sections.debug_loc_refs.is_empty());
assert!(sections.debug_loclists_refs.is_empty());
let read_debug_loc =
read::DebugLoc::new(sections.debug_loc.slice(), LittleEndian);
let read_debug_loclists =
read::DebugLocLists::new(sections.debug_loclists.slice(), LittleEndian);
let read_loc = read::LocationLists::new(read_debug_loc, read_debug_loclists);
let offset = loc_list_offsets.get(loc_list_id);
let read_loc_list = read_loc.raw_locations(offset, encoding).unwrap();
let dwarf = read::Dwarf {
locations: read_loc,
..Default::default()
};
let unit = read::Unit {
header: read::UnitHeader::new(
encoding,
0,
read::UnitType::Compilation,
DebugAbbrevOffset(0),
DebugInfoOffset(0).into(),
read::EndianSlice::default(),
),
abbreviations: Arc::new(read::Abbreviations::default()),
name: None,
comp_dir: None,
low_pc: 0,
str_offsets_base: DebugStrOffsetsBase(0),
addr_base: DebugAddrBase(0),
loclists_base: DebugLocListsBase(0),
rnglists_base: DebugRngListsBase(0),
line_program: None,
dwo_id: None,
};
let context = ConvertUnitContext {
dwarf: &dwarf,
unit: &unit,
line_strings: &mut line_strings,
strings: &mut strings,
ranges: &mut RangeListTable::default(),
locations: &mut locations,
convert_address: &|address| Some(Address::Constant(address)),
base_address: Address::Constant(0),
line_program_offset: None,
line_program_files: Vec::new(),
entry_ids: &HashMap::new(),
};
let convert_loc_list = LocationList::from(read_loc_list, &context).unwrap();
if version <= 4 {
loc_list.0[0] = Location::StartEnd {
begin: Address::Constant(6666),
end: Address::Constant(6666 + 7777),
data: expression.clone(),
};
}
assert_eq!(loc_list, convert_loc_list);
}
}
}
}
}

425
vendor/gimli/src/write/mod.rs vendored Normal file
View File

@ -0,0 +1,425 @@
//! Write DWARF debugging information.
//!
//! ## API Structure
//!
//! This module works by building up a representation of the debugging information
//! in memory, and then writing it all at once. It supports two major use cases:
//!
//! * Use the [`DwarfUnit`](./struct.DwarfUnit.html) type when writing DWARF
//! for a single compilation unit.
//!
//! * Use the [`Dwarf`](./struct.Dwarf.html) type when writing DWARF for multiple
//! compilation units.
//!
//! The module also supports reading in DWARF debugging information and writing it out
//! again, possibly after modifying it. Create a [`read::Dwarf`](../read/struct.Dwarf.html)
//! instance, and then use [`Dwarf::from`](./struct.Dwarf.html#method.from) to convert
//! it to a writable instance.
//!
//! ## Example Usage
//!
//! Write a compilation unit containing only the top level DIE.
//!
//! ```rust
//! use gimli::write::{
//! Address, AttributeValue, DwarfUnit, EndianVec, Error, Range, RangeList, Sections,
//! };
//!
//! fn example() -> Result<(), Error> {
//! // Choose the encoding parameters.
//! let encoding = gimli::Encoding {
//! format: gimli::Format::Dwarf32,
//! version: 5,
//! address_size: 8,
//! };
//! // Create a container for a single compilation unit.
//! let mut dwarf = DwarfUnit::new(encoding);
//! // Set a range attribute on the root DIE.
//! let range_list = RangeList(vec![Range::StartLength {
//! begin: Address::Constant(0x100),
//! length: 42,
//! }]);
//! let range_list_id = dwarf.unit.ranges.add(range_list);
//! let root = dwarf.unit.root();
//! dwarf.unit.get_mut(root).set(
//! gimli::DW_AT_ranges,
//! AttributeValue::RangeListRef(range_list_id),
//! );
//! // Create a `Vec` for each DWARF section.
//! let mut sections = Sections::new(EndianVec::new(gimli::LittleEndian));
//! // Finally, write the DWARF data to the sections.
//! dwarf.write(&mut sections)?;
//! sections.for_each(|id, data| {
//! // Here you can add the data to the output object file.
//! Ok(())
//! })
//! }
//! # fn main() {
//! # example().unwrap();
//! # }
use std::error;
use std::fmt;
use std::result;
use crate::constants;
mod endian_vec;
pub use self::endian_vec::*;
mod writer;
pub use self::writer::*;
#[macro_use]
mod section;
pub use self::section::*;
macro_rules! define_id {
($name:ident, $docs:expr) => {
#[doc=$docs]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct $name {
base_id: BaseId,
index: usize,
}
impl $name {
#[inline]
fn new(base_id: BaseId, index: usize) -> Self {
$name { base_id, index }
}
}
};
}
macro_rules! define_offsets {
($offsets:ident: $id:ident => $offset:ident, $off_doc:expr) => {
#[doc=$off_doc]
#[derive(Debug)]
pub struct $offsets {
base_id: BaseId,
// We know ids start at 0.
offsets: Vec<$offset>,
}
impl $offsets {
/// Return an empty list of offsets.
#[inline]
pub fn none() -> Self {
$offsets {
base_id: BaseId::default(),
offsets: Vec::new(),
}
}
/// Get the offset
///
/// # Panics
///
/// Panics if `id` is invalid.
#[inline]
pub fn get(&self, id: $id) -> $offset {
debug_assert_eq!(self.base_id, id.base_id);
self.offsets[id.index]
}
/// Return the number of offsets.
#[inline]
pub fn count(&self) -> usize {
self.offsets.len()
}
}
};
}
mod abbrev;
pub use self::abbrev::*;
mod cfi;
pub use self::cfi::*;
mod dwarf;
pub use self::dwarf::*;
mod line;
pub use self::line::*;
mod loc;
pub use self::loc::*;
mod op;
pub use self::op::*;
mod range;
pub use self::range::*;
mod str;
pub use self::str::*;
mod unit;
pub use self::unit::*;
/// An error that occurred when writing.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Error {
/// The given offset is out of bounds.
OffsetOutOfBounds,
/// The given length is out of bounds.
LengthOutOfBounds,
/// The attribute value is an invalid for writing.
InvalidAttributeValue,
/// The value is too large for the encoding form.
ValueTooLarge,
/// Unsupported word size.
UnsupportedWordSize(u8),
/// Unsupported DWARF version.
UnsupportedVersion(u16),
/// The unit length is too large for the requested DWARF format.
InitialLengthOverflow,
/// The address is invalid.
InvalidAddress,
/// The reference is invalid.
InvalidReference,
/// A requested feature requires a different DWARF version.
NeedVersion(u16),
/// Strings in line number program have mismatched forms.
LineStringFormMismatch,
/// The range is empty or otherwise invalid.
InvalidRange,
/// The line number program encoding is incompatible with the unit encoding.
IncompatibleLineProgramEncoding,
/// Could not encode code offset for a frame instruction.
InvalidFrameCodeOffset(u32),
/// Could not encode data offset for a frame instruction.
InvalidFrameDataOffset(i32),
/// Unsupported eh_frame pointer encoding.
UnsupportedPointerEncoding(constants::DwEhPe),
/// Unsupported reference in CFI expression.
UnsupportedCfiExpressionReference,
/// Unsupported forward reference in expression.
UnsupportedExpressionForwardReference,
}
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter) -> result::Result<(), fmt::Error> {
match *self {
Error::OffsetOutOfBounds => write!(f, "The given offset is out of bounds."),
Error::LengthOutOfBounds => write!(f, "The given length is out of bounds."),
Error::InvalidAttributeValue => {
write!(f, "The attribute value is an invalid for writing.")
}
Error::ValueTooLarge => write!(f, "The value is too large for the encoding form."),
Error::UnsupportedWordSize(size) => write!(f, "Unsupported word size: {}", size),
Error::UnsupportedVersion(version) => {
write!(f, "Unsupported DWARF version: {}", version)
}
Error::InitialLengthOverflow => write!(
f,
"The unit length is too large for the requested DWARF format."
),
Error::InvalidAddress => write!(f, "The address is invalid."),
Error::InvalidReference => write!(f, "The reference is invalid."),
Error::NeedVersion(version) => write!(
f,
"A requested feature requires a DWARF version {}.",
version
),
Error::LineStringFormMismatch => {
write!(f, "Strings in line number program have mismatched forms.")
}
Error::InvalidRange => write!(f, "The range is empty or otherwise invalid."),
Error::IncompatibleLineProgramEncoding => write!(
f,
"The line number program encoding is incompatible with the unit encoding."
),
Error::InvalidFrameCodeOffset(offset) => write!(
f,
"Could not encode code offset ({}) for a frame instruction.",
offset,
),
Error::InvalidFrameDataOffset(offset) => write!(
f,
"Could not encode data offset ({}) for a frame instruction.",
offset,
),
Error::UnsupportedPointerEncoding(eh_pe) => {
write!(f, "Unsupported eh_frame pointer encoding ({}).", eh_pe)
}
Error::UnsupportedCfiExpressionReference => {
write!(f, "Unsupported reference in CFI expression.")
}
Error::UnsupportedExpressionForwardReference => {
write!(f, "Unsupported forward reference in expression.")
}
}
}
}
impl error::Error for Error {}
/// The result of a write.
pub type Result<T> = result::Result<T, Error>;
/// An address.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum Address {
/// A fixed address that does not require relocation.
Constant(u64),
/// An address that is relative to a symbol which may be relocated.
Symbol {
/// The symbol that the address is relative to.
///
/// The meaning of this value is decided by the writer, but
/// will typically be an index into a symbol table.
symbol: usize,
/// The offset of the address relative to the symbol.
///
/// This will typically be used as the addend in a relocation.
addend: i64,
},
}
/// A reference to a `.debug_info` entry.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum Reference {
/// An external symbol.
///
/// The meaning of this value is decided by the writer, but
/// will typically be an index into a symbol table.
Symbol(usize),
/// An entry in the same section.
///
/// This only supports references in units that are emitted together.
Entry(UnitId, UnitEntryId),
}
// This type is only used in debug assertions.
#[cfg(not(debug_assertions))]
type BaseId = ();
#[cfg(debug_assertions)]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
struct BaseId(usize);
#[cfg(debug_assertions)]
impl Default for BaseId {
fn default() -> Self {
use std::sync::atomic;
static BASE_ID: atomic::AtomicUsize = atomic::AtomicUsize::new(0);
BaseId(BASE_ID.fetch_add(1, atomic::Ordering::Relaxed))
}
}
#[cfg(feature = "read")]
mod convert {
use super::*;
use crate::read;
pub(crate) use super::unit::convert::*;
/// An error that occurred when converting a read value into a write value.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ConvertError {
/// An error occurred when reading.
Read(read::Error),
/// Writing of this attribute value is not implemented yet.
UnsupportedAttributeValue,
/// This attribute value is an invalid name/form combination.
InvalidAttributeValue,
/// A `.debug_info` reference does not refer to a valid entry.
InvalidDebugInfoOffset,
/// An address could not be converted.
InvalidAddress,
/// Writing this line number instruction is not implemented yet.
UnsupportedLineInstruction,
/// Writing this form of line string is not implemented yet.
UnsupportedLineStringForm,
/// A `.debug_line` file index is invalid.
InvalidFileIndex,
/// A `.debug_line` directory index is invalid.
InvalidDirectoryIndex,
/// A `.debug_line` line base is invalid.
InvalidLineBase,
/// A `.debug_line` reference is invalid.
InvalidLineRef,
/// A `.debug_info` unit entry reference is invalid.
InvalidUnitRef,
/// A `.debug_info` reference is invalid.
InvalidDebugInfoRef,
/// Invalid relative address in a range list.
InvalidRangeRelativeAddress,
/// Writing this CFI instruction is not implemented yet.
UnsupportedCfiInstruction,
/// Writing indirect pointers is not implemented yet.
UnsupportedIndirectAddress,
/// Writing this expression operation is not implemented yet.
UnsupportedOperation,
/// Operation branch target is invalid.
InvalidBranchTarget,
/// Writing this unit type is not supported yet.
UnsupportedUnitType,
}
impl fmt::Display for ConvertError {
fn fmt(&self, f: &mut fmt::Formatter) -> result::Result<(), fmt::Error> {
use self::ConvertError::*;
match *self {
Read(ref e) => e.fmt(f),
UnsupportedAttributeValue => {
write!(f, "Writing of this attribute value is not implemented yet.")
}
InvalidAttributeValue => write!(
f,
"This attribute value is an invalid name/form combination."
),
InvalidDebugInfoOffset => write!(
f,
"A `.debug_info` reference does not refer to a valid entry."
),
InvalidAddress => write!(f, "An address could not be converted."),
UnsupportedLineInstruction => write!(
f,
"Writing this line number instruction is not implemented yet."
),
UnsupportedLineStringForm => write!(
f,
"Writing this form of line string is not implemented yet."
),
InvalidFileIndex => write!(f, "A `.debug_line` file index is invalid."),
InvalidDirectoryIndex => write!(f, "A `.debug_line` directory index is invalid."),
InvalidLineBase => write!(f, "A `.debug_line` line base is invalid."),
InvalidLineRef => write!(f, "A `.debug_line` reference is invalid."),
InvalidUnitRef => write!(f, "A `.debug_info` unit entry reference is invalid."),
InvalidDebugInfoRef => write!(f, "A `.debug_info` reference is invalid."),
InvalidRangeRelativeAddress => {
write!(f, "Invalid relative address in a range list.")
}
UnsupportedCfiInstruction => {
write!(f, "Writing this CFI instruction is not implemented yet.")
}
UnsupportedIndirectAddress => {
write!(f, "Writing indirect pointers is not implemented yet.")
}
UnsupportedOperation => write!(
f,
"Writing this expression operation is not implemented yet."
),
InvalidBranchTarget => write!(f, "Operation branch target is invalid."),
UnsupportedUnitType => write!(f, "Writing this unit type is not supported yet."),
}
}
}
impl error::Error for ConvertError {}
impl From<read::Error> for ConvertError {
fn from(e: read::Error) -> Self {
ConvertError::Read(e)
}
}
/// The result of a conversion.
pub type ConvertResult<T> = result::Result<T, ConvertError>;
}
#[cfg(feature = "read")]
pub use self::convert::*;

1618
vendor/gimli/src/write/op.rs vendored Normal file

File diff suppressed because it is too large Load Diff

416
vendor/gimli/src/write/range.rs vendored Normal file
View File

@ -0,0 +1,416 @@
use alloc::vec::Vec;
use indexmap::IndexSet;
use std::ops::{Deref, DerefMut};
use crate::common::{Encoding, RangeListsOffset, SectionId};
use crate::write::{Address, BaseId, Error, Result, Section, Sections, Writer};
define_section!(
DebugRanges,
RangeListsOffset,
"A writable `.debug_ranges` section."
);
define_section!(
DebugRngLists,
RangeListsOffset,
"A writable `.debug_rnglists` section."
);
define_offsets!(
RangeListOffsets: RangeListId => RangeListsOffset,
"The section offsets of a series of range lists within the `.debug_ranges` or `.debug_rnglists` sections."
);
define_id!(
RangeListId,
"An identifier for a range list in a `RangeListTable`."
);
/// A table of range lists that will be stored in a `.debug_ranges` or `.debug_rnglists` section.
#[derive(Debug, Default)]
pub struct RangeListTable {
base_id: BaseId,
ranges: IndexSet<RangeList>,
}
impl RangeListTable {
/// Add a range list to the table.
pub fn add(&mut self, range_list: RangeList) -> RangeListId {
let (index, _) = self.ranges.insert_full(range_list);
RangeListId::new(self.base_id, index)
}
/// Write the range list table to the appropriate section for the given DWARF version.
pub(crate) fn write<W: Writer>(
&self,
sections: &mut Sections<W>,
encoding: Encoding,
) -> Result<RangeListOffsets> {
if self.ranges.is_empty() {
return Ok(RangeListOffsets::none());
}
match encoding.version {
2..=4 => self.write_ranges(&mut sections.debug_ranges, encoding.address_size),
5 => self.write_rnglists(&mut sections.debug_rnglists, encoding),
_ => Err(Error::UnsupportedVersion(encoding.version)),
}
}
/// Write the range list table to the `.debug_ranges` section.
fn write_ranges<W: Writer>(
&self,
w: &mut DebugRanges<W>,
address_size: u8,
) -> Result<RangeListOffsets> {
let mut offsets = Vec::new();
for range_list in self.ranges.iter() {
offsets.push(w.offset());
for range in &range_list.0 {
// Note that we must ensure none of the ranges have both begin == 0 and end == 0.
// We do this by ensuring that begin != end, which is a bit more restrictive
// than required, but still seems reasonable.
match *range {
Range::BaseAddress { address } => {
let marker = !0 >> (64 - address_size * 8);
w.write_udata(marker, address_size)?;
w.write_address(address, address_size)?;
}
Range::OffsetPair { begin, end } => {
if begin == end {
return Err(Error::InvalidRange);
}
w.write_udata(begin, address_size)?;
w.write_udata(end, address_size)?;
}
Range::StartEnd { begin, end } => {
if begin == end {
return Err(Error::InvalidRange);
}
w.write_address(begin, address_size)?;
w.write_address(end, address_size)?;
}
Range::StartLength { begin, length } => {
let end = match begin {
Address::Constant(begin) => Address::Constant(begin + length),
Address::Symbol { symbol, addend } => Address::Symbol {
symbol,
addend: addend + length as i64,
},
};
if begin == end {
return Err(Error::InvalidRange);
}
w.write_address(begin, address_size)?;
w.write_address(end, address_size)?;
}
}
}
w.write_udata(0, address_size)?;
w.write_udata(0, address_size)?;
}
Ok(RangeListOffsets {
base_id: self.base_id,
offsets,
})
}
/// Write the range list table to the `.debug_rnglists` section.
fn write_rnglists<W: Writer>(
&self,
w: &mut DebugRngLists<W>,
encoding: Encoding,
) -> Result<RangeListOffsets> {
let mut offsets = Vec::new();
if encoding.version != 5 {
return Err(Error::NeedVersion(5));
}
let length_offset = w.write_initial_length(encoding.format)?;
let length_base = w.len();
w.write_u16(encoding.version)?;
w.write_u8(encoding.address_size)?;
w.write_u8(0)?; // segment_selector_size
w.write_u32(0)?; // offset_entry_count (when set to zero DW_FORM_rnglistx can't be used, see section 7.28)
// FIXME implement DW_FORM_rnglistx writing and implement the offset entry list
for range_list in self.ranges.iter() {
offsets.push(w.offset());
for range in &range_list.0 {
match *range {
Range::BaseAddress { address } => {
w.write_u8(crate::constants::DW_RLE_base_address.0)?;
w.write_address(address, encoding.address_size)?;
}
Range::OffsetPair { begin, end } => {
w.write_u8(crate::constants::DW_RLE_offset_pair.0)?;
w.write_uleb128(begin)?;
w.write_uleb128(end)?;
}
Range::StartEnd { begin, end } => {
w.write_u8(crate::constants::DW_RLE_start_end.0)?;
w.write_address(begin, encoding.address_size)?;
w.write_address(end, encoding.address_size)?;
}
Range::StartLength { begin, length } => {
w.write_u8(crate::constants::DW_RLE_start_length.0)?;
w.write_address(begin, encoding.address_size)?;
w.write_uleb128(length)?;
}
}
}
w.write_u8(crate::constants::DW_RLE_end_of_list.0)?;
}
let length = (w.len() - length_base) as u64;
w.write_initial_length_at(length_offset, length, encoding.format)?;
Ok(RangeListOffsets {
base_id: self.base_id,
offsets,
})
}
}
/// A range list that will be stored in a `.debug_ranges` or `.debug_rnglists` section.
#[derive(Clone, Debug, Eq, PartialEq, Hash)]
pub struct RangeList(pub Vec<Range>);
/// A single range.
#[derive(Clone, Debug, Eq, PartialEq, Hash)]
pub enum Range {
/// DW_RLE_base_address
BaseAddress {
/// Base address.
address: Address,
},
/// DW_RLE_offset_pair
OffsetPair {
/// Start of range relative to base address.
begin: u64,
/// End of range relative to base address.
end: u64,
},
/// DW_RLE_start_end
StartEnd {
/// Start of range.
begin: Address,
/// End of range.
end: Address,
},
/// DW_RLE_start_length
StartLength {
/// Start of range.
begin: Address,
/// Length of range.
length: u64,
},
}
#[cfg(feature = "read")]
mod convert {
use super::*;
use crate::read::{self, Reader};
use crate::write::{ConvertError, ConvertResult, ConvertUnitContext};
impl RangeList {
/// Create a range list by reading the data from the give range list iter.
pub(crate) fn from<R: Reader<Offset = usize>>(
mut from: read::RawRngListIter<R>,
context: &ConvertUnitContext<R>,
) -> ConvertResult<Self> {
let mut have_base_address = context.base_address != Address::Constant(0);
let convert_address =
|x| (context.convert_address)(x).ok_or(ConvertError::InvalidAddress);
let mut ranges = Vec::new();
while let Some(from_range) = from.next()? {
let range = match from_range {
read::RawRngListEntry::AddressOrOffsetPair { begin, end } => {
// These were parsed as addresses, even if they are offsets.
let begin = convert_address(begin)?;
let end = convert_address(end)?;
match (begin, end) {
(Address::Constant(begin_offset), Address::Constant(end_offset)) => {
if have_base_address {
Range::OffsetPair {
begin: begin_offset,
end: end_offset,
}
} else {
Range::StartEnd { begin, end }
}
}
_ => {
if have_base_address {
// At least one of begin/end is an address, but we also have
// a base address. Adding addresses is undefined.
return Err(ConvertError::InvalidRangeRelativeAddress);
}
Range::StartEnd { begin, end }
}
}
}
read::RawRngListEntry::BaseAddress { addr } => {
have_base_address = true;
let address = convert_address(addr)?;
Range::BaseAddress { address }
}
read::RawRngListEntry::BaseAddressx { addr } => {
have_base_address = true;
let address = convert_address(context.dwarf.address(context.unit, addr)?)?;
Range::BaseAddress { address }
}
read::RawRngListEntry::StartxEndx { begin, end } => {
let begin = convert_address(context.dwarf.address(context.unit, begin)?)?;
let end = convert_address(context.dwarf.address(context.unit, end)?)?;
Range::StartEnd { begin, end }
}
read::RawRngListEntry::StartxLength { begin, length } => {
let begin = convert_address(context.dwarf.address(context.unit, begin)?)?;
Range::StartLength { begin, length }
}
read::RawRngListEntry::OffsetPair { begin, end } => {
Range::OffsetPair { begin, end }
}
read::RawRngListEntry::StartEnd { begin, end } => {
let begin = convert_address(begin)?;
let end = convert_address(end)?;
Range::StartEnd { begin, end }
}
read::RawRngListEntry::StartLength { begin, length } => {
let begin = convert_address(begin)?;
Range::StartLength { begin, length }
}
};
// Filtering empty ranges out.
match range {
Range::StartLength { length, .. } if length == 0 => continue,
Range::StartEnd { begin, end, .. } if begin == end => continue,
Range::OffsetPair { begin, end, .. } if begin == end => continue,
_ => (),
}
ranges.push(range);
}
Ok(RangeList(ranges))
}
}
}
#[cfg(test)]
#[cfg(feature = "read")]
mod tests {
use super::*;
use crate::common::{
DebugAbbrevOffset, DebugAddrBase, DebugInfoOffset, DebugLocListsBase, DebugRngListsBase,
DebugStrOffsetsBase, Format,
};
use crate::read;
use crate::write::{
ConvertUnitContext, EndianVec, LineStringTable, LocationListTable, Range, RangeListTable,
StringTable,
};
use crate::LittleEndian;
use std::collections::HashMap;
use std::sync::Arc;
#[test]
fn test_range() {
let mut line_strings = LineStringTable::default();
let mut strings = StringTable::default();
for &version in &[2, 3, 4, 5] {
for &address_size in &[4, 8] {
for &format in &[Format::Dwarf32, Format::Dwarf64] {
let encoding = Encoding {
format,
version,
address_size,
};
let mut range_list = RangeList(vec![
Range::StartLength {
begin: Address::Constant(6666),
length: 7777,
},
Range::StartEnd {
begin: Address::Constant(4444),
end: Address::Constant(5555),
},
Range::BaseAddress {
address: Address::Constant(1111),
},
Range::OffsetPair {
begin: 2222,
end: 3333,
},
]);
let mut ranges = RangeListTable::default();
let range_list_id = ranges.add(range_list.clone());
let mut sections = Sections::new(EndianVec::new(LittleEndian));
let range_list_offsets = ranges.write(&mut sections, encoding).unwrap();
let read_debug_ranges =
read::DebugRanges::new(sections.debug_ranges.slice(), LittleEndian);
let read_debug_rnglists =
read::DebugRngLists::new(sections.debug_rnglists.slice(), LittleEndian);
let read_ranges = read::RangeLists::new(read_debug_ranges, read_debug_rnglists);
let offset = range_list_offsets.get(range_list_id);
let read_range_list = read_ranges.raw_ranges(offset, encoding).unwrap();
let dwarf = read::Dwarf {
ranges: read_ranges,
..Default::default()
};
let unit = read::Unit {
header: read::UnitHeader::new(
encoding,
0,
read::UnitType::Compilation,
DebugAbbrevOffset(0),
DebugInfoOffset(0).into(),
read::EndianSlice::default(),
),
abbreviations: Arc::new(read::Abbreviations::default()),
name: None,
comp_dir: None,
low_pc: 0,
str_offsets_base: DebugStrOffsetsBase(0),
addr_base: DebugAddrBase(0),
loclists_base: DebugLocListsBase(0),
rnglists_base: DebugRngListsBase(0),
line_program: None,
dwo_id: None,
};
let context = ConvertUnitContext {
dwarf: &dwarf,
unit: &unit,
line_strings: &mut line_strings,
strings: &mut strings,
ranges: &mut ranges,
locations: &mut LocationListTable::default(),
convert_address: &|address| Some(Address::Constant(address)),
base_address: Address::Constant(0),
line_program_offset: None,
line_program_files: Vec::new(),
entry_ids: &HashMap::new(),
};
let convert_range_list = RangeList::from(read_range_list, &context).unwrap();
if version <= 4 {
range_list.0[0] = Range::StartEnd {
begin: Address::Constant(6666),
end: Address::Constant(6666 + 7777),
};
}
assert_eq!(range_list, convert_range_list);
}
}
}
}
}

172
vendor/gimli/src/write/section.rs vendored Normal file
View File

@ -0,0 +1,172 @@
use std::ops::DerefMut;
use std::result;
use std::vec::Vec;
use crate::common::SectionId;
use crate::write::{
DebugAbbrev, DebugFrame, DebugInfo, DebugInfoReference, DebugLine, DebugLineStr, DebugLoc,
DebugLocLists, DebugRanges, DebugRngLists, DebugStr, EhFrame, Writer,
};
macro_rules! define_section {
($name:ident, $offset:ident, $docs:expr) => {
#[doc=$docs]
#[derive(Debug, Default)]
pub struct $name<W: Writer>(pub W);
impl<W: Writer> $name<W> {
/// Return the offset of the next write.
pub fn offset(&self) -> $offset {
$offset(self.len())
}
}
impl<W: Writer> From<W> for $name<W> {
#[inline]
fn from(w: W) -> Self {
$name(w)
}
}
impl<W: Writer> Deref for $name<W> {
type Target = W;
#[inline]
fn deref(&self) -> &W {
&self.0
}
}
impl<W: Writer> DerefMut for $name<W> {
#[inline]
fn deref_mut(&mut self) -> &mut W {
&mut self.0
}
}
impl<W: Writer> Section<W> for $name<W> {
#[inline]
fn id(&self) -> SectionId {
SectionId::$name
}
}
};
}
/// Functionality common to all writable DWARF sections.
pub trait Section<W: Writer>: DerefMut<Target = W> {
/// Returns the DWARF section kind for this type.
fn id(&self) -> SectionId;
/// Returns the ELF section name for this type.
fn name(&self) -> &'static str {
self.id().name()
}
}
/// All of the writable DWARF sections.
#[derive(Debug, Default)]
pub struct Sections<W: Writer> {
/// The `.debug_abbrev` section.
pub debug_abbrev: DebugAbbrev<W>,
/// The `.debug_info` section.
pub debug_info: DebugInfo<W>,
/// The `.debug_line` section.
pub debug_line: DebugLine<W>,
/// The `.debug_line_str` section.
pub debug_line_str: DebugLineStr<W>,
/// The `.debug_ranges` section.
pub debug_ranges: DebugRanges<W>,
/// The `.debug_rnglists` section.
pub debug_rnglists: DebugRngLists<W>,
/// The `.debug_loc` section.
pub debug_loc: DebugLoc<W>,
/// The `.debug_loclists` section.
pub debug_loclists: DebugLocLists<W>,
/// The `.debug_str` section.
pub debug_str: DebugStr<W>,
/// The `.debug_frame` section.
pub debug_frame: DebugFrame<W>,
/// The `.eh_frame` section.
pub eh_frame: EhFrame<W>,
/// Unresolved references in the `.debug_info` section.
pub(crate) debug_info_refs: Vec<DebugInfoReference>,
/// Unresolved references in the `.debug_loc` section.
pub(crate) debug_loc_refs: Vec<DebugInfoReference>,
/// Unresolved references in the `.debug_loclists` section.
pub(crate) debug_loclists_refs: Vec<DebugInfoReference>,
}
impl<W: Writer + Clone> Sections<W> {
/// Create a new `Sections` using clones of the given `section`.
pub fn new(section: W) -> Self {
Sections {
debug_abbrev: DebugAbbrev(section.clone()),
debug_info: DebugInfo(section.clone()),
debug_line: DebugLine(section.clone()),
debug_line_str: DebugLineStr(section.clone()),
debug_ranges: DebugRanges(section.clone()),
debug_rnglists: DebugRngLists(section.clone()),
debug_loc: DebugLoc(section.clone()),
debug_loclists: DebugLocLists(section.clone()),
debug_str: DebugStr(section.clone()),
debug_frame: DebugFrame(section.clone()),
eh_frame: EhFrame(section),
debug_info_refs: Vec::new(),
debug_loc_refs: Vec::new(),
debug_loclists_refs: Vec::new(),
}
}
}
impl<W: Writer> Sections<W> {
/// For each section, call `f` once with a shared reference.
pub fn for_each<F, E>(&self, mut f: F) -> result::Result<(), E>
where
F: FnMut(SectionId, &W) -> result::Result<(), E>,
{
macro_rules! f {
($s:expr) => {
f($s.id(), &$s)
};
}
// Ordered so that earlier sections do not reference later sections.
f!(self.debug_abbrev)?;
f!(self.debug_str)?;
f!(self.debug_line_str)?;
f!(self.debug_line)?;
f!(self.debug_ranges)?;
f!(self.debug_rnglists)?;
f!(self.debug_loc)?;
f!(self.debug_loclists)?;
f!(self.debug_info)?;
f!(self.debug_frame)?;
f!(self.eh_frame)?;
Ok(())
}
/// For each section, call `f` once with a mutable reference.
pub fn for_each_mut<F, E>(&mut self, mut f: F) -> result::Result<(), E>
where
F: FnMut(SectionId, &mut W) -> result::Result<(), E>,
{
macro_rules! f {
($s:expr) => {
f($s.id(), &mut $s)
};
}
// Ordered so that earlier sections do not reference later sections.
f!(self.debug_abbrev)?;
f!(self.debug_str)?;
f!(self.debug_line_str)?;
f!(self.debug_line)?;
f!(self.debug_ranges)?;
f!(self.debug_rnglists)?;
f!(self.debug_loc)?;
f!(self.debug_loclists)?;
f!(self.debug_info)?;
f!(self.debug_frame)?;
f!(self.eh_frame)?;
Ok(())
}
}

172
vendor/gimli/src/write/str.rs vendored Normal file
View File

@ -0,0 +1,172 @@
use alloc::vec::Vec;
use indexmap::IndexSet;
use std::ops::{Deref, DerefMut};
use crate::common::{DebugLineStrOffset, DebugStrOffset, SectionId};
use crate::write::{BaseId, Result, Section, Writer};
// Requirements:
// - values are `[u8]`, null bytes are not allowed
// - insertion returns a fixed id
// - inserting a duplicate returns the id of the existing value
// - able to convert an id to a section offset
// Optional?
// - able to get an existing value given an id
//
// Limitations of current implementation (using IndexSet):
// - inserting requires either an allocation for duplicates,
// or a double lookup for non-duplicates
// - doesn't preserve offsets when updating an existing `.debug_str` section
//
// Possible changes:
// - calculate offsets as we add values, and use that as the id.
// This would avoid the need for DebugStrOffsets but would make it
// hard to implement `get`.
macro_rules! define_string_table {
($name:ident, $id:ident, $section:ident, $offsets:ident, $docs:expr) => {
#[doc=$docs]
#[derive(Debug, Default)]
pub struct $name {
base_id: BaseId,
strings: IndexSet<Vec<u8>>,
}
impl $name {
/// Add a string to the string table and return its id.
///
/// If the string already exists, then return the id of the existing string.
///
/// # Panics
///
/// Panics if `bytes` contains a null byte.
pub fn add<T>(&mut self, bytes: T) -> $id
where
T: Into<Vec<u8>>,
{
let bytes = bytes.into();
assert!(!bytes.contains(&0));
let (index, _) = self.strings.insert_full(bytes);
$id::new(self.base_id, index)
}
/// Return the number of strings in the table.
#[inline]
pub fn count(&self) -> usize {
self.strings.len()
}
/// Get a reference to a string in the table.
///
/// # Panics
///
/// Panics if `id` is invalid.
pub fn get(&self, id: $id) -> &[u8] {
debug_assert_eq!(self.base_id, id.base_id);
self.strings.get_index(id.index).map(Vec::as_slice).unwrap()
}
/// Write the string table to the `.debug_str` section.
///
/// Returns the offsets at which the strings are written.
pub fn write<W: Writer>(&self, w: &mut $section<W>) -> Result<$offsets> {
let mut offsets = Vec::new();
for bytes in self.strings.iter() {
offsets.push(w.offset());
w.write(bytes)?;
w.write_u8(0)?;
}
Ok($offsets {
base_id: self.base_id,
offsets,
})
}
}
};
}
define_id!(StringId, "An identifier for a string in a `StringTable`.");
define_string_table!(
StringTable,
StringId,
DebugStr,
DebugStrOffsets,
"A table of strings that will be stored in a `.debug_str` section."
);
define_section!(DebugStr, DebugStrOffset, "A writable `.debug_str` section.");
define_offsets!(
DebugStrOffsets: StringId => DebugStrOffset,
"The section offsets of all strings within a `.debug_str` section."
);
define_id!(
LineStringId,
"An identifier for a string in a `LineStringTable`."
);
define_string_table!(
LineStringTable,
LineStringId,
DebugLineStr,
DebugLineStrOffsets,
"A table of strings that will be stored in a `.debug_line_str` section."
);
define_section!(
DebugLineStr,
DebugLineStrOffset,
"A writable `.debug_line_str` section."
);
define_offsets!(
DebugLineStrOffsets: LineStringId => DebugLineStrOffset,
"The section offsets of all strings within a `.debug_line_str` section."
);
#[cfg(test)]
#[cfg(feature = "read")]
mod tests {
use super::*;
use crate::read;
use crate::write::EndianVec;
use crate::LittleEndian;
#[test]
fn test_string_table() {
let mut strings = StringTable::default();
assert_eq!(strings.count(), 0);
let id1 = strings.add(&b"one"[..]);
let id2 = strings.add(&b"two"[..]);
assert_eq!(strings.add(&b"one"[..]), id1);
assert_eq!(strings.add(&b"two"[..]), id2);
assert_eq!(strings.get(id1), &b"one"[..]);
assert_eq!(strings.get(id2), &b"two"[..]);
assert_eq!(strings.count(), 2);
let mut debug_str = DebugStr::from(EndianVec::new(LittleEndian));
let offsets = strings.write(&mut debug_str).unwrap();
assert_eq!(debug_str.slice(), b"one\0two\0");
assert_eq!(offsets.get(id1), DebugStrOffset(0));
assert_eq!(offsets.get(id2), DebugStrOffset(4));
assert_eq!(offsets.count(), 2);
}
#[test]
fn test_string_table_read() {
let mut strings = StringTable::default();
let id1 = strings.add(&b"one"[..]);
let id2 = strings.add(&b"two"[..]);
let mut debug_str = DebugStr::from(EndianVec::new(LittleEndian));
let offsets = strings.write(&mut debug_str).unwrap();
let read_debug_str = read::DebugStr::new(debug_str.slice(), LittleEndian);
let str1 = read_debug_str.get_str(offsets.get(id1)).unwrap();
let str2 = read_debug_str.get_str(offsets.get(id2)).unwrap();
assert_eq!(str1.slice(), &b"one"[..]);
assert_eq!(str2.slice(), &b"two"[..]);
}
}

3152
vendor/gimli/src/write/unit.rs vendored Normal file

File diff suppressed because it is too large Load Diff

494
vendor/gimli/src/write/writer.rs vendored Normal file
View File

@ -0,0 +1,494 @@
use crate::common::{Format, SectionId};
use crate::constants;
use crate::endianity::Endianity;
use crate::leb128;
use crate::write::{Address, Error, Result};
/// A trait for writing the data to a DWARF section.
///
/// All write operations append to the section unless otherwise specified.
#[allow(clippy::len_without_is_empty)]
pub trait Writer {
/// The endianity of bytes that are written.
type Endian: Endianity;
/// Return the endianity of bytes that are written.
fn endian(&self) -> Self::Endian;
/// Return the current section length.
///
/// This may be used as an offset for future `write_at` calls.
fn len(&self) -> usize;
/// Write a slice.
fn write(&mut self, bytes: &[u8]) -> Result<()>;
/// Write a slice at a given offset.
///
/// The write must not extend past the current section length.
fn write_at(&mut self, offset: usize, bytes: &[u8]) -> Result<()>;
/// Write an address.
///
/// If the writer supports relocations, then it must provide its own implementation
/// of this method.
// TODO: use write_reference instead?
fn write_address(&mut self, address: Address, size: u8) -> Result<()> {
match address {
Address::Constant(val) => self.write_udata(val, size),
Address::Symbol { .. } => Err(Error::InvalidAddress),
}
}
/// Write an address with a `.eh_frame` pointer encoding.
///
/// The given size is only used for `DW_EH_PE_absptr` formats.
///
/// If the writer supports relocations, then it must provide its own implementation
/// of this method.
fn write_eh_pointer(
&mut self,
address: Address,
eh_pe: constants::DwEhPe,
size: u8,
) -> Result<()> {
match address {
Address::Constant(val) => {
// Indirect doesn't matter here.
let val = match eh_pe.application() {
constants::DW_EH_PE_absptr => val,
constants::DW_EH_PE_pcrel => {
// TODO: better handling of sign
let offset = self.len() as u64;
val.wrapping_sub(offset)
}
_ => {
return Err(Error::UnsupportedPointerEncoding(eh_pe));
}
};
self.write_eh_pointer_data(val, eh_pe.format(), size)
}
Address::Symbol { .. } => Err(Error::InvalidAddress),
}
}
/// Write a value with a `.eh_frame` pointer format.
///
/// The given size is only used for `DW_EH_PE_absptr` formats.
///
/// This must not be used directly for values that may require relocation.
fn write_eh_pointer_data(
&mut self,
val: u64,
format: constants::DwEhPe,
size: u8,
) -> Result<()> {
match format {
constants::DW_EH_PE_absptr => self.write_udata(val, size),
constants::DW_EH_PE_uleb128 => self.write_uleb128(val),
constants::DW_EH_PE_udata2 => self.write_udata(val, 2),
constants::DW_EH_PE_udata4 => self.write_udata(val, 4),
constants::DW_EH_PE_udata8 => self.write_udata(val, 8),
constants::DW_EH_PE_sleb128 => self.write_sleb128(val as i64),
constants::DW_EH_PE_sdata2 => self.write_sdata(val as i64, 2),
constants::DW_EH_PE_sdata4 => self.write_sdata(val as i64, 4),
constants::DW_EH_PE_sdata8 => self.write_sdata(val as i64, 8),
_ => Err(Error::UnsupportedPointerEncoding(format)),
}
}
/// Write an offset that is relative to the start of the given section.
///
/// If the writer supports relocations, then it must provide its own implementation
/// of this method.
fn write_offset(&mut self, val: usize, _section: SectionId, size: u8) -> Result<()> {
self.write_udata(val as u64, size)
}
/// Write an offset that is relative to the start of the given section.
///
/// If the writer supports relocations, then it must provide its own implementation
/// of this method.
fn write_offset_at(
&mut self,
offset: usize,
val: usize,
_section: SectionId,
size: u8,
) -> Result<()> {
self.write_udata_at(offset, val as u64, size)
}
/// Write a reference to a symbol.
///
/// If the writer supports symbols, then it must provide its own implementation
/// of this method.
fn write_reference(&mut self, _symbol: usize, _size: u8) -> Result<()> {
Err(Error::InvalidReference)
}
/// Write a u8.
fn write_u8(&mut self, val: u8) -> Result<()> {
let bytes = [val];
self.write(&bytes)
}
/// Write a u16.
fn write_u16(&mut self, val: u16) -> Result<()> {
let mut bytes = [0; 2];
self.endian().write_u16(&mut bytes, val);
self.write(&bytes)
}
/// Write a u32.
fn write_u32(&mut self, val: u32) -> Result<()> {
let mut bytes = [0; 4];
self.endian().write_u32(&mut bytes, val);
self.write(&bytes)
}
/// Write a u64.
fn write_u64(&mut self, val: u64) -> Result<()> {
let mut bytes = [0; 8];
self.endian().write_u64(&mut bytes, val);
self.write(&bytes)
}
/// Write a u8 at the given offset.
fn write_u8_at(&mut self, offset: usize, val: u8) -> Result<()> {
let bytes = [val];
self.write_at(offset, &bytes)
}
/// Write a u16 at the given offset.
fn write_u16_at(&mut self, offset: usize, val: u16) -> Result<()> {
let mut bytes = [0; 2];
self.endian().write_u16(&mut bytes, val);
self.write_at(offset, &bytes)
}
/// Write a u32 at the given offset.
fn write_u32_at(&mut self, offset: usize, val: u32) -> Result<()> {
let mut bytes = [0; 4];
self.endian().write_u32(&mut bytes, val);
self.write_at(offset, &bytes)
}
/// Write a u64 at the given offset.
fn write_u64_at(&mut self, offset: usize, val: u64) -> Result<()> {
let mut bytes = [0; 8];
self.endian().write_u64(&mut bytes, val);
self.write_at(offset, &bytes)
}
/// Write unsigned data of the given size.
///
/// Returns an error if the value is too large for the size.
/// This must not be used directly for values that may require relocation.
fn write_udata(&mut self, val: u64, size: u8) -> Result<()> {
match size {
1 => {
let write_val = val as u8;
if val != u64::from(write_val) {
return Err(Error::ValueTooLarge);
}
self.write_u8(write_val)
}
2 => {
let write_val = val as u16;
if val != u64::from(write_val) {
return Err(Error::ValueTooLarge);
}
self.write_u16(write_val)
}
4 => {
let write_val = val as u32;
if val != u64::from(write_val) {
return Err(Error::ValueTooLarge);
}
self.write_u32(write_val)
}
8 => self.write_u64(val),
otherwise => Err(Error::UnsupportedWordSize(otherwise)),
}
}
/// Write signed data of the given size.
///
/// Returns an error if the value is too large for the size.
/// This must not be used directly for values that may require relocation.
fn write_sdata(&mut self, val: i64, size: u8) -> Result<()> {
match size {
1 => {
let write_val = val as i8;
if val != i64::from(write_val) {
return Err(Error::ValueTooLarge);
}
self.write_u8(write_val as u8)
}
2 => {
let write_val = val as i16;
if val != i64::from(write_val) {
return Err(Error::ValueTooLarge);
}
self.write_u16(write_val as u16)
}
4 => {
let write_val = val as i32;
if val != i64::from(write_val) {
return Err(Error::ValueTooLarge);
}
self.write_u32(write_val as u32)
}
8 => self.write_u64(val as u64),
otherwise => Err(Error::UnsupportedWordSize(otherwise)),
}
}
/// Write a word of the given size at the given offset.
///
/// Returns an error if the value is too large for the size.
/// This must not be used directly for values that may require relocation.
fn write_udata_at(&mut self, offset: usize, val: u64, size: u8) -> Result<()> {
match size {
1 => {
let write_val = val as u8;
if val != u64::from(write_val) {
return Err(Error::ValueTooLarge);
}
self.write_u8_at(offset, write_val)
}
2 => {
let write_val = val as u16;
if val != u64::from(write_val) {
return Err(Error::ValueTooLarge);
}
self.write_u16_at(offset, write_val)
}
4 => {
let write_val = val as u32;
if val != u64::from(write_val) {
return Err(Error::ValueTooLarge);
}
self.write_u32_at(offset, write_val)
}
8 => self.write_u64_at(offset, val),
otherwise => Err(Error::UnsupportedWordSize(otherwise)),
}
}
/// Write an unsigned LEB128 encoded integer.
fn write_uleb128(&mut self, val: u64) -> Result<()> {
let mut bytes = [0u8; 10];
// bytes is long enough so this will never fail.
let len = leb128::write::unsigned(&mut { &mut bytes[..] }, val).unwrap();
self.write(&bytes[..len])
}
/// Read an unsigned LEB128 encoded integer.
fn write_sleb128(&mut self, val: i64) -> Result<()> {
let mut bytes = [0u8; 10];
// bytes is long enough so this will never fail.
let len = leb128::write::signed(&mut { &mut bytes[..] }, val).unwrap();
self.write(&bytes[..len])
}
/// Write an initial length according to the given DWARF format.
///
/// This will only write a length of zero, since the length isn't
/// known yet, and a subsequent call to `write_initial_length_at`
/// will write the actual length.
fn write_initial_length(&mut self, format: Format) -> Result<InitialLengthOffset> {
if format == Format::Dwarf64 {
self.write_u32(0xffff_ffff)?;
}
let offset = InitialLengthOffset(self.len());
self.write_udata(0, format.word_size())?;
Ok(offset)
}
/// Write an initial length at the given offset according to the given DWARF format.
///
/// `write_initial_length` must have previously returned the offset.
fn write_initial_length_at(
&mut self,
offset: InitialLengthOffset,
length: u64,
format: Format,
) -> Result<()> {
self.write_udata_at(offset.0, length, format.word_size())
}
}
/// The offset at which an initial length should be written.
#[derive(Debug, Clone, Copy)]
pub struct InitialLengthOffset(usize);
#[cfg(test)]
mod tests {
use super::*;
use crate::write;
use crate::{BigEndian, LittleEndian};
use std::{i64, u64};
#[test]
fn test_writer() {
let mut w = write::EndianVec::new(LittleEndian);
w.write_address(Address::Constant(0x1122_3344), 4).unwrap();
assert_eq!(w.slice(), &[0x44, 0x33, 0x22, 0x11]);
assert_eq!(
w.write_address(
Address::Symbol {
symbol: 0,
addend: 0
},
4
),
Err(Error::InvalidAddress)
);
let mut w = write::EndianVec::new(LittleEndian);
w.write_offset(0x1122_3344, SectionId::DebugInfo, 4)
.unwrap();
assert_eq!(w.slice(), &[0x44, 0x33, 0x22, 0x11]);
w.write_offset_at(1, 0x5566, SectionId::DebugInfo, 2)
.unwrap();
assert_eq!(w.slice(), &[0x44, 0x66, 0x55, 0x11]);
let mut w = write::EndianVec::new(LittleEndian);
w.write_u8(0x11).unwrap();
w.write_u16(0x2233).unwrap();
w.write_u32(0x4455_6677).unwrap();
w.write_u64(0x8081_8283_8485_8687).unwrap();
#[rustfmt::skip]
assert_eq!(w.slice(), &[
0x11,
0x33, 0x22,
0x77, 0x66, 0x55, 0x44,
0x87, 0x86, 0x85, 0x84, 0x83, 0x82, 0x81, 0x80,
]);
w.write_u8_at(14, 0x11).unwrap();
w.write_u16_at(12, 0x2233).unwrap();
w.write_u32_at(8, 0x4455_6677).unwrap();
w.write_u64_at(0, 0x8081_8283_8485_8687).unwrap();
#[rustfmt::skip]
assert_eq!(w.slice(), &[
0x87, 0x86, 0x85, 0x84, 0x83, 0x82, 0x81, 0x80,
0x77, 0x66, 0x55, 0x44,
0x33, 0x22,
0x11,
]);
let mut w = write::EndianVec::new(BigEndian);
w.write_u8(0x11).unwrap();
w.write_u16(0x2233).unwrap();
w.write_u32(0x4455_6677).unwrap();
w.write_u64(0x8081_8283_8485_8687).unwrap();
#[rustfmt::skip]
assert_eq!(w.slice(), &[
0x11,
0x22, 0x33,
0x44, 0x55, 0x66, 0x77,
0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
]);
w.write_u8_at(14, 0x11).unwrap();
w.write_u16_at(12, 0x2233).unwrap();
w.write_u32_at(8, 0x4455_6677).unwrap();
w.write_u64_at(0, 0x8081_8283_8485_8687).unwrap();
#[rustfmt::skip]
assert_eq!(w.slice(), &[
0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
0x44, 0x55, 0x66, 0x77,
0x22, 0x33,
0x11,
]);
let mut w = write::EndianVec::new(LittleEndian);
w.write_udata(0x11, 1).unwrap();
w.write_udata(0x2233, 2).unwrap();
w.write_udata(0x4455_6677, 4).unwrap();
w.write_udata(0x8081_8283_8485_8687, 8).unwrap();
#[rustfmt::skip]
assert_eq!(w.slice(), &[
0x11,
0x33, 0x22,
0x77, 0x66, 0x55, 0x44,
0x87, 0x86, 0x85, 0x84, 0x83, 0x82, 0x81, 0x80,
]);
assert_eq!(w.write_udata(0x100, 1), Err(Error::ValueTooLarge));
assert_eq!(w.write_udata(0x1_0000, 2), Err(Error::ValueTooLarge));
assert_eq!(w.write_udata(0x1_0000_0000, 4), Err(Error::ValueTooLarge));
assert_eq!(w.write_udata(0x00, 3), Err(Error::UnsupportedWordSize(3)));
w.write_udata_at(14, 0x11, 1).unwrap();
w.write_udata_at(12, 0x2233, 2).unwrap();
w.write_udata_at(8, 0x4455_6677, 4).unwrap();
w.write_udata_at(0, 0x8081_8283_8485_8687, 8).unwrap();
#[rustfmt::skip]
assert_eq!(w.slice(), &[
0x87, 0x86, 0x85, 0x84, 0x83, 0x82, 0x81, 0x80,
0x77, 0x66, 0x55, 0x44,
0x33, 0x22,
0x11,
]);
assert_eq!(w.write_udata_at(0, 0x100, 1), Err(Error::ValueTooLarge));
assert_eq!(w.write_udata_at(0, 0x1_0000, 2), Err(Error::ValueTooLarge));
assert_eq!(
w.write_udata_at(0, 0x1_0000_0000, 4),
Err(Error::ValueTooLarge)
);
assert_eq!(
w.write_udata_at(0, 0x00, 3),
Err(Error::UnsupportedWordSize(3))
);
let mut w = write::EndianVec::new(LittleEndian);
w.write_uleb128(0).unwrap();
assert_eq!(w.slice(), &[0]);
let mut w = write::EndianVec::new(LittleEndian);
w.write_uleb128(u64::MAX).unwrap();
assert_eq!(
w.slice(),
&[0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 1]
);
let mut w = write::EndianVec::new(LittleEndian);
w.write_sleb128(0).unwrap();
assert_eq!(w.slice(), &[0]);
let mut w = write::EndianVec::new(LittleEndian);
w.write_sleb128(i64::MAX).unwrap();
assert_eq!(
w.slice(),
&[0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0]
);
let mut w = write::EndianVec::new(LittleEndian);
w.write_sleb128(i64::MIN).unwrap();
assert_eq!(
w.slice(),
&[0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x7f]
);
let mut w = write::EndianVec::new(LittleEndian);
let offset = w.write_initial_length(Format::Dwarf32).unwrap();
assert_eq!(w.slice(), &[0, 0, 0, 0]);
w.write_initial_length_at(offset, 0x1122_3344, Format::Dwarf32)
.unwrap();
assert_eq!(w.slice(), &[0x44, 0x33, 0x22, 0x11]);
assert_eq!(
w.write_initial_length_at(offset, 0x1_0000_0000, Format::Dwarf32),
Err(Error::ValueTooLarge)
);
let mut w = write::EndianVec::new(LittleEndian);
let offset = w.write_initial_length(Format::Dwarf64).unwrap();
assert_eq!(w.slice(), &[0xff, 0xff, 0xff, 0xff, 0, 0, 0, 0, 0, 0, 0, 0]);
w.write_initial_length_at(offset, 0x1122_3344_5566_7788, Format::Dwarf64)
.unwrap();
assert_eq!(
w.slice(),
&[0xff, 0xff, 0xff, 0xff, 0x88, 0x77, 0x66, 0x55, 0x44, 0x33, 0x22, 0x11]
);
}
}