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)] pubstruct RangeListTable {
base_id: BaseId,
ranges: IndexSet<RangeList>,
}
impl RangeListTable { /// Add a range list to the table. pubfn add(&mutself, 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> { ifself.ranges.is_empty() { return Ok(RangeListOffsets::none());
}
/// 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> { letmut offsets = Vec::new(); for range_list inself.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> { letmut 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 inself.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)?;
}
}
}
/// A range list that will be stored in a `.debug_ranges` or `.debug_rnglists` section. #[derive(Clone, Debug, Eq, PartialEq, Hash)] pubstruct RangeList(pub Vec<Range>);
/// A single range. #[derive(Clone, Debug, Eq, PartialEq, Hash)] pubenum 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 { usesuper::*;
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> { letmut have_base_address = context.base_address != Address::Constant(0); let convert_address =
|x| (context.convert_address)(x).ok_or(ConvertError::InvalidAddress); letmut ranges = Vec::new(); whilelet 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: 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 { usesuper::*; usecrate::common::{
DebugAbbrevOffset, DebugAddrBase, DebugInfoOffset, DebugLocListsBase, DebugRngListsBase,
DebugStrOffsetsBase, Format,
}; usecrate::read; usecrate::write::{
ConvertUnitContext, EndianVec, LineStringTable, LocationListTable, Range, RangeListTable,
StringTable,
}; usecrate::LittleEndian; use std::collections::HashMap; use std::sync::Arc;
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,
};
letmut ranges = RangeListTable::default(); let range_list_id = ranges.add(range_list.clone());
letmut 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();
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.