Vendor things
This commit is contained in:
parent
5deceec006
commit
977e3c17e5
19434 changed files with 10682014 additions and 0 deletions
550
third-party/vendor/gimli/src/write/loc.rs
vendored
Normal file
550
third-party/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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue