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)] pubstruct LocationListTable {
base_id: BaseId,
locations: IndexSet<LocationList>,
}
impl LocationListTable { /// Add a location list to the table. pubfn add(&mutself, 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> { ifself.locations.is_empty() { return Ok(LocationListOffsets::none());
}
/// 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; letmut offsets = Vec::new(); for loc_list inself.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> { 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
/// A locations list that will be stored in a `.debug_loc` or `.debug_loclists` section. #[derive(Clone, Debug, Eq, PartialEq, Hash)] pubstruct LocationList(pub Vec<Location>);
/// A single location. #[derive(Clone, Debug, Eq, PartialEq, Hash)] pubenum 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,
},
}
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> { letmut 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,
)
}; letmut loc_list = Vec::new(); whilelet 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: 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 { usesuper::*; usecrate::common::{
DebugAbbrevOffset, DebugAddrBase, DebugInfoOffset, DebugLocListsBase, DebugRngListsBase,
DebugStrOffsetsBase, Format,
}; usecrate::read; usecrate::write::{
ConvertUnitContext, EndianVec, LineStringTable, 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,
};
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();
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.