Initial vendor packages
Signed-off-by: Valentin Popov <valentin@popov.link>
This commit is contained in:
188
vendor/gimli/src/write/abbrev.rs
vendored
Normal file
188
vendor/gimli/src/write/abbrev.rs
vendored
Normal 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
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
138
vendor/gimli/src/write/dwarf.rs
vendored
Normal 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
117
vendor/gimli/src/write/endian_vec.rs
vendored
Normal 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
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
550
vendor/gimli/src/write/loc.rs
vendored
Normal 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
425
vendor/gimli/src/write/mod.rs
vendored
Normal 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
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
416
vendor/gimli/src/write/range.rs
vendored
Normal 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
172
vendor/gimli/src/write/section.rs
vendored
Normal 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
172
vendor/gimli/src/write/str.rs
vendored
Normal 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
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
494
vendor/gimli/src/write/writer.rs
vendored
Normal 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]
|
||||
);
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user