aboutsummaryrefslogtreecommitdiff
path: root/vendor/gimli/src/write
diff options
context:
space:
mode:
authorValentin Popov <valentin@popov.link>2024-07-19 15:37:58 +0300
committerValentin Popov <valentin@popov.link>2024-07-19 15:37:58 +0300
commita990de90fe41456a23e58bd087d2f107d321f3a1 (patch)
tree15afc392522a9e85dc3332235e311b7d39352ea9 /vendor/gimli/src/write
parent3d48cd3f81164bbfc1a755dc1d4a9a02f98c8ddd (diff)
downloadfparkan-a990de90fe41456a23e58bd087d2f107d321f3a1.tar.xz
fparkan-a990de90fe41456a23e58bd087d2f107d321f3a1.zip
Deleted vendor folder
Diffstat (limited to 'vendor/gimli/src/write')
-rw-r--r--vendor/gimli/src/write/abbrev.rs188
-rw-r--r--vendor/gimli/src/write/cfi.rs1050
-rw-r--r--vendor/gimli/src/write/dwarf.rs138
-rw-r--r--vendor/gimli/src/write/endian_vec.rs117
-rw-r--r--vendor/gimli/src/write/line.rs1957
-rw-r--r--vendor/gimli/src/write/loc.rs550
-rw-r--r--vendor/gimli/src/write/mod.rs425
-rw-r--r--vendor/gimli/src/write/op.rs1618
-rw-r--r--vendor/gimli/src/write/range.rs416
-rw-r--r--vendor/gimli/src/write/section.rs172
-rw-r--r--vendor/gimli/src/write/str.rs172
-rw-r--r--vendor/gimli/src/write/unit.rs3152
-rw-r--r--vendor/gimli/src/write/writer.rs494
13 files changed, 0 insertions, 10449 deletions
diff --git a/vendor/gimli/src/write/abbrev.rs b/vendor/gimli/src/write/abbrev.rs
deleted file mode 100644
index 7cdfa96..0000000
--- a/vendor/gimli/src/write/abbrev.rs
+++ /dev/null
@@ -1,188 +0,0 @@
-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()
- );
- }
-}
diff --git a/vendor/gimli/src/write/cfi.rs b/vendor/gimli/src/write/cfi.rs
deleted file mode 100644
index 5e108f1..0000000
--- a/vendor/gimli/src/write/cfi.rs
+++ /dev/null
@@ -1,1050 +0,0 @@
-use alloc::vec::Vec;
-use indexmap::IndexSet;
-use std::ops::{Deref, DerefMut};
-
-use crate::common::{DebugFrameOffset, EhFrameOffset, Encoding, Format, Register, SectionId};
-use crate::constants;
-use crate::write::{Address, BaseId, Error, Expression, Result, Section, Writer};
-
-define_section!(
- DebugFrame,
- DebugFrameOffset,
- "A writable `.debug_frame` section."
-);
-
-define_section!(EhFrame, EhFrameOffset, "A writable `.eh_frame` section.");
-
-define_id!(CieId, "An identifier for a CIE in a `FrameTable`.");
-
-/// A table of frame description entries.
-#[derive(Debug, Default)]
-pub struct FrameTable {
- /// Base id for CIEs.
- base_id: BaseId,
- /// The common information entries.
- cies: IndexSet<CommonInformationEntry>,
- /// The frame description entries.
- fdes: Vec<(CieId, FrameDescriptionEntry)>,
-}
-
-impl FrameTable {
- /// Add a CIE and return its id.
- ///
- /// If the CIE already exists, then return the id of the existing CIE.
- pub fn add_cie(&mut self, cie: CommonInformationEntry) -> CieId {
- let (index, _) = self.cies.insert_full(cie);
- CieId::new(self.base_id, index)
- }
-
- /// The number of CIEs.
- pub fn cie_count(&self) -> usize {
- self.cies.len()
- }
-
- /// Add a FDE.
- ///
- /// Does not check for duplicates.
- ///
- /// # Panics
- ///
- /// Panics if the CIE id is invalid.
- pub fn add_fde(&mut self, cie: CieId, fde: FrameDescriptionEntry) {
- debug_assert_eq!(self.base_id, cie.base_id);
- self.fdes.push((cie, fde));
- }
-
- /// The number of FDEs.
- pub fn fde_count(&self) -> usize {
- self.fdes.len()
- }
-
- /// Write the frame table entries to the given `.debug_frame` section.
- pub fn write_debug_frame<W: Writer>(&self, w: &mut DebugFrame<W>) -> Result<()> {
- self.write(&mut w.0, false)
- }
-
- /// Write the frame table entries to the given `.eh_frame` section.
- pub fn write_eh_frame<W: Writer>(&self, w: &mut EhFrame<W>) -> Result<()> {
- self.write(&mut w.0, true)
- }
-
- fn write<W: Writer>(&self, w: &mut W, eh_frame: bool) -> Result<()> {
- let mut cie_offsets = vec![None; self.cies.len()];
- for (cie_id, fde) in &self.fdes {
- let cie_index = cie_id.index;
- let cie = self.cies.get_index(cie_index).unwrap();
- let cie_offset = match cie_offsets[cie_index] {
- Some(offset) => offset,
- None => {
- // Only write CIEs as they are referenced.
- let offset = cie.write(w, eh_frame)?;
- cie_offsets[cie_index] = Some(offset);
- offset
- }
- };
-
- fde.write(w, eh_frame, cie_offset, cie)?;
- }
- // TODO: write length 0 terminator for eh_frame?
- Ok(())
- }
-}
-
-/// A common information entry. This contains information that is shared between FDEs.
-#[derive(Debug, Clone, PartialEq, Eq, Hash)]
-pub struct CommonInformationEntry {
- encoding: Encoding,
-
- /// A constant that is factored out of code offsets.
- ///
- /// This should be set to the minimum instruction length.
- /// Writing a code offset that is not a multiple of this factor will generate an error.
- code_alignment_factor: u8,
-
- /// A constant that is factored out of data offsets.
- ///
- /// This should be set to the minimum data alignment for the frame.
- /// Writing a data offset that is not a multiple of this factor will generate an error.
- data_alignment_factor: i8,
-
- /// The return address register. This might not correspond to an actual machine register.
- return_address_register: Register,
-
- /// The address of the personality function and its encoding.
- pub personality: Option<(constants::DwEhPe, Address)>,
-
- /// The encoding to use for the LSDA address in FDEs.
- ///
- /// If set then all FDEs which use this CIE must have a LSDA address.
- pub lsda_encoding: Option<constants::DwEhPe>,
-
- /// The encoding to use for addresses in FDEs.
- pub fde_address_encoding: constants::DwEhPe,
-
- /// True for signal trampolines.
- pub signal_trampoline: bool,
-
- /// The initial instructions upon entry to this function.
- instructions: Vec<CallFrameInstruction>,
-}
-
-impl CommonInformationEntry {
- /// Create a new common information entry.
- ///
- /// The encoding version must be a CFI version, not a DWARF version.
- pub fn new(
- encoding: Encoding,
- code_alignment_factor: u8,
- data_alignment_factor: i8,
- return_address_register: Register,
- ) -> Self {
- CommonInformationEntry {
- encoding,
- code_alignment_factor,
- data_alignment_factor,
- return_address_register,
- personality: None,
- lsda_encoding: None,
- fde_address_encoding: constants::DW_EH_PE_absptr,
- signal_trampoline: false,
- instructions: Vec::new(),
- }
- }
-
- /// Add an initial instruction.
- pub fn add_instruction(&mut self, instruction: CallFrameInstruction) {
- self.instructions.push(instruction);
- }
-
- fn has_augmentation(&self) -> bool {
- self.personality.is_some()
- || self.lsda_encoding.is_some()
- || self.signal_trampoline
- || self.fde_address_encoding != constants::DW_EH_PE_absptr
- }
-
- /// Returns the section offset of the CIE.
- fn write<W: Writer>(&self, w: &mut W, eh_frame: bool) -> Result<usize> {
- let encoding = self.encoding;
- let offset = w.len();
-
- let length_offset = w.write_initial_length(encoding.format)?;
- let length_base = w.len();
-
- if eh_frame {
- w.write_u32(0)?;
- } else {
- match encoding.format {
- Format::Dwarf32 => w.write_u32(0xffff_ffff)?,
- Format::Dwarf64 => w.write_u64(0xffff_ffff_ffff_ffff)?,
- }
- }
-
- if eh_frame {
- if encoding.version != 1 {
- return Err(Error::UnsupportedVersion(encoding.version));
- };
- } else {
- match encoding.version {
- 1 | 3 | 4 => {}
- _ => return Err(Error::UnsupportedVersion(encoding.version)),
- };
- }
- w.write_u8(encoding.version as u8)?;
-
- let augmentation = self.has_augmentation();
- if augmentation {
- w.write_u8(b'z')?;
- if self.lsda_encoding.is_some() {
- w.write_u8(b'L')?;
- }
- if self.personality.is_some() {
- w.write_u8(b'P')?;
- }
- if self.fde_address_encoding != constants::DW_EH_PE_absptr {
- w.write_u8(b'R')?;
- }
- if self.signal_trampoline {
- w.write_u8(b'S')?;
- }
- }
- w.write_u8(0)?;
-
- if encoding.version >= 4 {
- w.write_u8(encoding.address_size)?;
- // TODO: segment_selector_size
- w.write_u8(0)?;
- }
-
- w.write_uleb128(self.code_alignment_factor.into())?;
- w.write_sleb128(self.data_alignment_factor.into())?;
-
- if !eh_frame && encoding.version == 1 {
- let register = self.return_address_register.0 as u8;
- if u16::from(register) != self.return_address_register.0 {
- return Err(Error::ValueTooLarge);
- }
- w.write_u8(register)?;
- } else {
- w.write_uleb128(self.return_address_register.0.into())?;
- }
-
- if augmentation {
- let augmentation_length_offset = w.len();
- w.write_u8(0)?;
- let augmentation_length_base = w.len();
-
- if let Some(eh_pe) = self.lsda_encoding {
- w.write_u8(eh_pe.0)?;
- }
- if let Some((eh_pe, address)) = self.personality {
- w.write_u8(eh_pe.0)?;
- w.write_eh_pointer(address, eh_pe, encoding.address_size)?;
- }
- if self.fde_address_encoding != constants::DW_EH_PE_absptr {
- w.write_u8(self.fde_address_encoding.0)?;
- }
-
- let augmentation_length = (w.len() - augmentation_length_base) as u64;
- debug_assert!(augmentation_length < 0x80);
- w.write_udata_at(augmentation_length_offset, augmentation_length, 1)?;
- }
-
- for instruction in &self.instructions {
- instruction.write(w, encoding, self)?;
- }
-
- write_nop(
- w,
- encoding.format.word_size() as usize + w.len() - length_base,
- encoding.address_size,
- )?;
-
- let length = (w.len() - length_base) as u64;
- w.write_initial_length_at(length_offset, length, encoding.format)?;
-
- Ok(offset)
- }
-}
-
-/// A frame description entry. There should be one FDE per function.
-#[derive(Debug, Clone, PartialEq, Eq)]
-pub struct FrameDescriptionEntry {
- /// The initial address of the function.
- address: Address,
-
- /// The length in bytes of the function.
- length: u32,
-
- /// The address of the LSDA.
- pub lsda: Option<Address>,
-
- /// The instructions for this function, ordered by offset.
- instructions: Vec<(u32, CallFrameInstruction)>,
-}
-
-impl FrameDescriptionEntry {
- /// Create a new frame description entry for a function.
- pub fn new(address: Address, length: u32) -> Self {
- FrameDescriptionEntry {
- address,
- length,
- lsda: None,
- instructions: Vec::new(),
- }
- }
-
- /// Add an instruction.
- ///
- /// Instructions must be added in increasing order of offset, or writing will fail.
- pub fn add_instruction(&mut self, offset: u32, instruction: CallFrameInstruction) {
- debug_assert!(self.instructions.last().map(|x| x.0).unwrap_or(0) <= offset);
- self.instructions.push((offset, instruction));
- }
-
- fn write<W: Writer>(
- &self,
- w: &mut W,
- eh_frame: bool,
- cie_offset: usize,
- cie: &CommonInformationEntry,
- ) -> Result<()> {
- let encoding = cie.encoding;
- let length_offset = w.write_initial_length(encoding.format)?;
- let length_base = w.len();
-
- if eh_frame {
- // .eh_frame uses a relative offset which doesn't need relocation.
- w.write_udata((w.len() - cie_offset) as u64, 4)?;
- } else {
- w.write_offset(
- cie_offset,
- SectionId::DebugFrame,
- encoding.format.word_size(),
- )?;
- }
-
- if cie.fde_address_encoding != constants::DW_EH_PE_absptr {
- w.write_eh_pointer(
- self.address,
- cie.fde_address_encoding,
- encoding.address_size,
- )?;
- w.write_eh_pointer_data(
- self.length.into(),
- cie.fde_address_encoding.format(),
- encoding.address_size,
- )?;
- } else {
- w.write_address(self.address, encoding.address_size)?;
- w.write_udata(self.length.into(), encoding.address_size)?;
- }
-
- if cie.has_augmentation() {
- let mut augmentation_length = 0u64;
- if self.lsda.is_some() {
- augmentation_length += u64::from(encoding.address_size);
- }
- w.write_uleb128(augmentation_length)?;
-
- debug_assert_eq!(self.lsda.is_some(), cie.lsda_encoding.is_some());
- if let (Some(lsda), Some(lsda_encoding)) = (self.lsda, cie.lsda_encoding) {
- w.write_eh_pointer(lsda, lsda_encoding, encoding.address_size)?;
- }
- }
-
- let mut prev_offset = 0;
- for (offset, instruction) in &self.instructions {
- write_advance_loc(w, cie.code_alignment_factor, prev_offset, *offset)?;
- prev_offset = *offset;
- instruction.write(w, encoding, cie)?;
- }
-
- write_nop(
- w,
- encoding.format.word_size() as usize + w.len() - length_base,
- encoding.address_size,
- )?;
-
- let length = (w.len() - length_base) as u64;
- w.write_initial_length_at(length_offset, length, encoding.format)?;
-
- Ok(())
- }
-}
-
-/// An instruction in a frame description entry.
-///
-/// This may be a CFA definition, a register rule, or some other directive.
-#[derive(Debug, Clone, PartialEq, Eq, Hash)]
-#[non_exhaustive]
-pub enum CallFrameInstruction {
- /// Define the CFA rule to use the provided register and offset.
- Cfa(Register, i32),
- /// Update the CFA rule to use the provided register. The offset is unchanged.
- CfaRegister(Register),
- /// Update the CFA rule to use the provided offset. The register is unchanged.
- CfaOffset(i32),
- /// Define the CFA rule to use the provided expression.
- CfaExpression(Expression),
-
- /// Restore the initial rule for the register.
- Restore(Register),
- /// The previous value of the register is not recoverable.
- Undefined(Register),
- /// The register has not been modified.
- SameValue(Register),
- /// The previous value of the register is saved at address CFA + offset.
- Offset(Register, i32),
- /// The previous value of the register is CFA + offset.
- ValOffset(Register, i32),
- /// The previous value of the register is stored in another register.
- Register(Register, Register),
- /// The previous value of the register is saved at address given by the expression.
- Expression(Register, Expression),
- /// The previous value of the register is given by the expression.
- ValExpression(Register, Expression),
-
- /// Push all register rules onto a stack.
- RememberState,
- /// Pop all register rules off the stack.
- RestoreState,
- /// The size of the arguments that have been pushed onto the stack.
- ArgsSize(u32),
-
- /// AAarch64 extension: negate the `RA_SIGN_STATE` pseudo-register.
- NegateRaState,
-}
-
-impl CallFrameInstruction {
- fn write<W: Writer>(
- &self,
- w: &mut W,
- encoding: Encoding,
- cie: &CommonInformationEntry,
- ) -> Result<()> {
- match *self {
- CallFrameInstruction::Cfa(register, offset) => {
- if offset < 0 {
- let offset = factored_data_offset(offset, cie.data_alignment_factor)?;
- w.write_u8(constants::DW_CFA_def_cfa_sf.0)?;
- w.write_uleb128(register.0.into())?;
- w.write_sleb128(offset.into())?;
- } else {
- // Unfactored offset.
- w.write_u8(constants::DW_CFA_def_cfa.0)?;
- w.write_uleb128(register.0.into())?;
- w.write_uleb128(offset as u64)?;
- }
- }
- CallFrameInstruction::CfaRegister(register) => {
- w.write_u8(constants::DW_CFA_def_cfa_register.0)?;
- w.write_uleb128(register.0.into())?;
- }
- CallFrameInstruction::CfaOffset(offset) => {
- if offset < 0 {
- let offset = factored_data_offset(offset, cie.data_alignment_factor)?;
- w.write_u8(constants::DW_CFA_def_cfa_offset_sf.0)?;
- w.write_sleb128(offset.into())?;
- } else {
- // Unfactored offset.
- w.write_u8(constants::DW_CFA_def_cfa_offset.0)?;
- w.write_uleb128(offset as u64)?;
- }
- }
- CallFrameInstruction::CfaExpression(ref expression) => {
- w.write_u8(constants::DW_CFA_def_cfa_expression.0)?;
- w.write_uleb128(expression.size(encoding, None) as u64)?;
- expression.write(w, None, encoding, None)?;
- }
- CallFrameInstruction::Restore(register) => {
- if register.0 < 0x40 {
- w.write_u8(constants::DW_CFA_restore.0 | register.0 as u8)?;
- } else {
- w.write_u8(constants::DW_CFA_restore_extended.0)?;
- w.write_uleb128(register.0.into())?;
- }
- }
- CallFrameInstruction::Undefined(register) => {
- w.write_u8(constants::DW_CFA_undefined.0)?;
- w.write_uleb128(register.0.into())?;
- }
- CallFrameInstruction::SameValue(register) => {
- w.write_u8(constants::DW_CFA_same_value.0)?;
- w.write_uleb128(register.0.into())?;
- }
- CallFrameInstruction::Offset(register, offset) => {
- let offset = factored_data_offset(offset, cie.data_alignment_factor)?;
- if offset < 0 {
- w.write_u8(constants::DW_CFA_offset_extended_sf.0)?;
- w.write_uleb128(register.0.into())?;
- w.write_sleb128(offset.into())?;
- } else if register.0 < 0x40 {
- w.write_u8(constants::DW_CFA_offset.0 | register.0 as u8)?;
- w.write_uleb128(offset as u64)?;
- } else {
- w.write_u8(constants::DW_CFA_offset_extended.0)?;
- w.write_uleb128(register.0.into())?;
- w.write_uleb128(offset as u64)?;
- }
- }
- CallFrameInstruction::ValOffset(register, offset) => {
- let offset = factored_data_offset(offset, cie.data_alignment_factor)?;
- if offset < 0 {
- w.write_u8(constants::DW_CFA_val_offset_sf.0)?;
- w.write_uleb128(register.0.into())?;
- w.write_sleb128(offset.into())?;
- } else {
- w.write_u8(constants::DW_CFA_val_offset.0)?;
- w.write_uleb128(register.0.into())?;
- w.write_uleb128(offset as u64)?;
- }
- }
- CallFrameInstruction::Register(register1, register2) => {
- w.write_u8(constants::DW_CFA_register.0)?;
- w.write_uleb128(register1.0.into())?;
- w.write_uleb128(register2.0.into())?;
- }
- CallFrameInstruction::Expression(register, ref expression) => {
- w.write_u8(constants::DW_CFA_expression.0)?;
- w.write_uleb128(register.0.into())?;
- w.write_uleb128(expression.size(encoding, None) as u64)?;
- expression.write(w, None, encoding, None)?;
- }
- CallFrameInstruction::ValExpression(register, ref expression) => {
- w.write_u8(constants::DW_CFA_val_expression.0)?;
- w.write_uleb128(register.0.into())?;
- w.write_uleb128(expression.size(encoding, None) as u64)?;
- expression.write(w, None, encoding, None)?;
- }
- CallFrameInstruction::RememberState => {
- w.write_u8(constants::DW_CFA_remember_state.0)?;
- }
- CallFrameInstruction::RestoreState => {
- w.write_u8(constants::DW_CFA_restore_state.0)?;
- }
- CallFrameInstruction::ArgsSize(size) => {
- w.write_u8(constants::DW_CFA_GNU_args_size.0)?;
- w.write_uleb128(size.into())?;
- }
- CallFrameInstruction::NegateRaState => {
- w.write_u8(constants::DW_CFA_AARCH64_negate_ra_state.0)?;
- }
- }
- Ok(())
- }
-}
-
-fn write_advance_loc<W: Writer>(
- w: &mut W,
- code_alignment_factor: u8,
- prev_offset: u32,
- offset: u32,
-) -> Result<()> {
- if offset == prev_offset {
- return Ok(());
- }
- let delta = factored_code_delta(prev_offset, offset, code_alignment_factor)?;
- if delta < 0x40 {
- w.write_u8(constants::DW_CFA_advance_loc.0 | delta as u8)?;
- } else if delta < 0x100 {
- w.write_u8(constants::DW_CFA_advance_loc1.0)?;
- w.write_u8(delta as u8)?;
- } else if delta < 0x10000 {
- w.write_u8(constants::DW_CFA_advance_loc2.0)?;
- w.write_u16(delta as u16)?;
- } else {
- w.write_u8(constants::DW_CFA_advance_loc4.0)?;
- w.write_u32(delta)?;
- }
- Ok(())
-}
-
-fn write_nop<W: Writer>(w: &mut W, len: usize, align: u8) -> Result<()> {
- debug_assert_eq!(align & (align - 1), 0);
- let tail_len = (!len + 1) & (align as usize - 1);
- for _ in 0..tail_len {
- w.write_u8(constants::DW_CFA_nop.0)?;
- }
- Ok(())
-}
-
-fn factored_code_delta(prev_offset: u32, offset: u32, factor: u8) -> Result<u32> {
- if offset < prev_offset {
- return Err(Error::InvalidFrameCodeOffset(offset));
- }
- let delta = offset - prev_offset;
- let factor = u32::from(factor);
- let factored_delta = delta / factor;
- if delta != factored_delta * factor {
- return Err(Error::InvalidFrameCodeOffset(offset));
- }
- Ok(factored_delta)
-}
-
-fn factored_data_offset(offset: i32, factor: i8) -> Result<i32> {
- let factor = i32::from(factor);
- let factored_offset = offset / factor;
- if offset != factored_offset * factor {
- return Err(Error::InvalidFrameDataOffset(offset));
- }
- Ok(factored_offset)
-}
-
-#[cfg(feature = "read")]
-pub(crate) mod convert {
- use super::*;
- use crate::read::{self, Reader};
- use crate::write::{ConvertError, ConvertResult};
- use std::collections::{hash_map, HashMap};
-
- impl FrameTable {
- /// Create a frame table by reading the data in the given section.
- ///
- /// `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, Section>(
- frame: &Section,
- convert_address: &dyn Fn(u64) -> Option<Address>,
- ) -> ConvertResult<FrameTable>
- where
- R: Reader<Offset = usize>,
- Section: read::UnwindSection<R>,
- Section::Offset: read::UnwindOffset<usize>,
- {
- let bases = read::BaseAddresses::default().set_eh_frame(0);
-
- let mut frame_table = FrameTable::default();
-
- let mut cie_ids = HashMap::new();
- let mut entries = frame.entries(&bases);
- while let Some(entry) = entries.next()? {
- let partial = match entry {
- read::CieOrFde::Cie(_) => continue,
- read::CieOrFde::Fde(partial) => partial,
- };
-
- // TODO: is it worth caching the parsed CIEs? It would be better if FDEs only
- // stored a reference.
- let from_fde = partial.parse(Section::cie_from_offset)?;
- let from_cie = from_fde.cie();
- let cie_id = match cie_ids.entry(from_cie.offset()) {
- hash_map::Entry::Occupied(o) => *o.get(),
- hash_map::Entry::Vacant(e) => {
- let cie =
- CommonInformationEntry::from(from_cie, frame, &bases, convert_address)?;
- let cie_id = frame_table.add_cie(cie);
- e.insert(cie_id);
- cie_id
- }
- };
- let fde = FrameDescriptionEntry::from(&from_fde, frame, &bases, convert_address)?;
- frame_table.add_fde(cie_id, fde);
- }
-
- Ok(frame_table)
- }
- }
-
- impl CommonInformationEntry {
- fn from<R, Section>(
- from_cie: &read::CommonInformationEntry<R>,
- frame: &Section,
- bases: &read::BaseAddresses,
- convert_address: &dyn Fn(u64) -> Option<Address>,
- ) -> ConvertResult<CommonInformationEntry>
- where
- R: Reader<Offset = usize>,
- Section: read::UnwindSection<R>,
- Section::Offset: read::UnwindOffset<usize>,
- {
- let mut cie = CommonInformationEntry::new(
- from_cie.encoding(),
- from_cie.code_alignment_factor() as u8,
- from_cie.data_alignment_factor() as i8,
- from_cie.return_address_register(),
- );
-
- cie.personality = match from_cie.personality_with_encoding() {
- // We treat these the same because the encoding already determines
- // whether it is indirect.
- Some((eh_pe, read::Pointer::Direct(p)))
- | Some((eh_pe, read::Pointer::Indirect(p))) => {
- let address = convert_address(p).ok_or(ConvertError::InvalidAddress)?;
- Some((eh_pe, address))
- }
- _ => None,
- };
- cie.lsda_encoding = from_cie.lsda_encoding();
- cie.fde_address_encoding = from_cie
- .fde_address_encoding()
- .unwrap_or(constants::DW_EH_PE_absptr);
- cie.signal_trampoline = from_cie.is_signal_trampoline();
-
- let mut offset = 0;
- let mut from_instructions = from_cie.instructions(frame, bases);
- while let Some(from_instruction) = from_instructions.next()? {
- if let Some(instruction) = CallFrameInstruction::from(
- from_instruction,
- from_cie,
- convert_address,
- &mut offset,
- )? {
- cie.instructions.push(instruction);
- }
- }
- Ok(cie)
- }
- }
-
- impl FrameDescriptionEntry {
- fn from<R, Section>(
- from_fde: &read::FrameDescriptionEntry<R>,
- frame: &Section,
- bases: &read::BaseAddresses,
- convert_address: &dyn Fn(u64) -> Option<Address>,
- ) -> ConvertResult<FrameDescriptionEntry>
- where
- R: Reader<Offset = usize>,
- Section: read::UnwindSection<R>,
- Section::Offset: read::UnwindOffset<usize>,
- {
- let address =
- convert_address(from_fde.initial_address()).ok_or(ConvertError::InvalidAddress)?;
- let length = from_fde.len() as u32;
- let mut fde = FrameDescriptionEntry::new(address, length);
-
- match from_fde.lsda() {
- // We treat these the same because the encoding already determines
- // whether it is indirect.
- Some(read::Pointer::Direct(p)) | Some(read::Pointer::Indirect(p)) => {
- let address = convert_address(p).ok_or(ConvertError::InvalidAddress)?;
- fde.lsda = Some(address);
- }
- None => {}
- }
-
- let from_cie = from_fde.cie();
- let mut offset = 0;
- let mut from_instructions = from_fde.instructions(frame, bases);
- while let Some(from_instruction) = from_instructions.next()? {
- if let Some(instruction) = CallFrameInstruction::from(
- from_instruction,
- from_cie,
- convert_address,
- &mut offset,
- )? {
- fde.instructions.push((offset, instruction));
- }
- }
-
- Ok(fde)
- }
- }
-
- impl CallFrameInstruction {
- fn from<R: Reader<Offset = usize>>(
- from_instruction: read::CallFrameInstruction<R>,
- from_cie: &read::CommonInformationEntry<R>,
- convert_address: &dyn Fn(u64) -> Option<Address>,
- offset: &mut u32,
- ) -> ConvertResult<Option<CallFrameInstruction>> {
- let convert_expression =
- |x| Expression::from(x, from_cie.encoding(), None, None, None, convert_address);
- // TODO: validate integer type conversions
- Ok(Some(match from_instruction {
- read::CallFrameInstruction::SetLoc { .. } => {
- return Err(ConvertError::UnsupportedCfiInstruction);
- }
- read::CallFrameInstruction::AdvanceLoc { delta } => {
- *offset += delta * from_cie.code_alignment_factor() as u32;
- return Ok(None);
- }
- read::CallFrameInstruction::DefCfa { register, offset } => {
- CallFrameInstruction::Cfa(register, offset as i32)
- }
- read::CallFrameInstruction::DefCfaSf {
- register,
- factored_offset,
- } => {
- let offset = factored_offset * from_cie.data_alignment_factor();
- CallFrameInstruction::Cfa(register, offset as i32)
- }
- read::CallFrameInstruction::DefCfaRegister { register } => {
- CallFrameInstruction::CfaRegister(register)
- }
-
- read::CallFrameInstruction::DefCfaOffset { offset } => {
- CallFrameInstruction::CfaOffset(offset as i32)
- }
- read::CallFrameInstruction::DefCfaOffsetSf { factored_offset } => {
- let offset = factored_offset * from_cie.data_alignment_factor();
- CallFrameInstruction::CfaOffset(offset as i32)
- }
- read::CallFrameInstruction::DefCfaExpression { expression } => {
- CallFrameInstruction::CfaExpression(convert_expression(expression)?)
- }
- read::CallFrameInstruction::Undefined { register } => {
- CallFrameInstruction::Undefined(register)
- }
- read::CallFrameInstruction::SameValue { register } => {
- CallFrameInstruction::SameValue(register)
- }
- read::CallFrameInstruction::Offset {
- register,
- factored_offset,
- } => {
- let offset = factored_offset as i64 * from_cie.data_alignment_factor();
- CallFrameInstruction::Offset(register, offset as i32)
- }
- read::CallFrameInstruction::OffsetExtendedSf {
- register,
- factored_offset,
- } => {
- let offset = factored_offset * from_cie.data_alignment_factor();
- CallFrameInstruction::Offset(register, offset as i32)
- }
- read::CallFrameInstruction::ValOffset {
- register,
- factored_offset,
- } => {
- let offset = factored_offset as i64 * from_cie.data_alignment_factor();
- CallFrameInstruction::ValOffset(register, offset as i32)
- }
- read::CallFrameInstruction::ValOffsetSf {
- register,
- factored_offset,
- } => {
- let offset = factored_offset * from_cie.data_alignment_factor();
- CallFrameInstruction::ValOffset(register, offset as i32)
- }
- read::CallFrameInstruction::Register {
- dest_register,
- src_register,
- } => CallFrameInstruction::Register(dest_register, src_register),
- read::CallFrameInstruction::Expression {
- register,
- expression,
- } => CallFrameInstruction::Expression(register, convert_expression(expression)?),
- read::CallFrameInstruction::ValExpression {
- register,
- expression,
- } => CallFrameInstruction::ValExpression(register, convert_expression(expression)?),
- read::CallFrameInstruction::Restore { register } => {
- CallFrameInstruction::Restore(register)
- }
- read::CallFrameInstruction::RememberState => CallFrameInstruction::RememberState,
- read::CallFrameInstruction::RestoreState => CallFrameInstruction::RestoreState,
- read::CallFrameInstruction::ArgsSize { size } => {
- CallFrameInstruction::ArgsSize(size as u32)
- }
- read::CallFrameInstruction::NegateRaState => CallFrameInstruction::NegateRaState,
- read::CallFrameInstruction::Nop => return Ok(None),
- }))
- }
- }
-}
-
-#[cfg(test)]
-#[cfg(feature = "read")]
-mod tests {
- use super::*;
- use crate::arch::X86_64;
- use crate::read;
- use crate::write::EndianVec;
- use crate::{LittleEndian, Vendor};
-
- #[test]
- fn test_frame_table() {
- for &version in &[1, 3, 4] {
- for &address_size in &[4, 8] {
- for &format in &[Format::Dwarf32, Format::Dwarf64] {
- let encoding = Encoding {
- format,
- version,
- address_size,
- };
- let mut frames = FrameTable::default();
-
- let cie1 = CommonInformationEntry::new(encoding, 1, 8, X86_64::RA);
- let cie1_id = frames.add_cie(cie1.clone());
- assert_eq!(cie1_id, frames.add_cie(cie1.clone()));
-
- let mut cie2 = CommonInformationEntry::new(encoding, 1, 8, X86_64::RA);
- cie2.lsda_encoding = Some(constants::DW_EH_PE_absptr);
- cie2.personality =
- Some((constants::DW_EH_PE_absptr, Address::Constant(0x1234)));
- cie2.signal_trampoline = true;
- let cie2_id = frames.add_cie(cie2.clone());
- assert_ne!(cie1_id, cie2_id);
- assert_eq!(cie2_id, frames.add_cie(cie2.clone()));
-
- let fde1 = FrameDescriptionEntry::new(Address::Constant(0x1000), 0x10);
- frames.add_fde(cie1_id, fde1.clone());
-
- let fde2 = FrameDescriptionEntry::new(Address::Constant(0x2000), 0x20);
- frames.add_fde(cie1_id, fde2.clone());
-
- let mut fde3 = FrameDescriptionEntry::new(Address::Constant(0x3000), 0x30);
- fde3.lsda = Some(Address::Constant(0x3300));
- frames.add_fde(cie2_id, fde3.clone());
-
- let mut fde4 = FrameDescriptionEntry::new(Address::Constant(0x4000), 0x40);
- fde4.lsda = Some(Address::Constant(0x4400));
- frames.add_fde(cie2_id, fde4.clone());
-
- let mut cie3 = CommonInformationEntry::new(encoding, 1, 8, X86_64::RA);
- cie3.fde_address_encoding = constants::DW_EH_PE_pcrel;
- cie3.lsda_encoding = Some(constants::DW_EH_PE_pcrel);
- cie3.personality = Some((constants::DW_EH_PE_pcrel, Address::Constant(0x1235)));
- cie3.signal_trampoline = true;
- let cie3_id = frames.add_cie(cie3.clone());
- assert_ne!(cie2_id, cie3_id);
- assert_eq!(cie3_id, frames.add_cie(cie3.clone()));
-
- let mut fde5 = FrameDescriptionEntry::new(Address::Constant(0x5000), 0x50);
- fde5.lsda = Some(Address::Constant(0x5500));
- frames.add_fde(cie3_id, fde5.clone());
-
- // Test writing `.debug_frame`.
- let mut debug_frame = DebugFrame::from(EndianVec::new(LittleEndian));
- frames.write_debug_frame(&mut debug_frame).unwrap();
-
- let mut read_debug_frame =
- read::DebugFrame::new(debug_frame.slice(), LittleEndian);
- read_debug_frame.set_address_size(address_size);
- let convert_frames = FrameTable::from(&read_debug_frame, &|address| {
- Some(Address::Constant(address))
- })
- .unwrap();
- assert_eq!(frames.cies, convert_frames.cies);
- assert_eq!(frames.fdes.len(), convert_frames.fdes.len());
- for (a, b) in frames.fdes.iter().zip(convert_frames.fdes.iter()) {
- assert_eq!(a.1, b.1);
- }
-
- if version == 1 {
- // Test writing `.eh_frame`.
- let mut eh_frame = EhFrame::from(EndianVec::new(LittleEndian));
- frames.write_eh_frame(&mut eh_frame).unwrap();
-
- let mut read_eh_frame = read::EhFrame::new(eh_frame.slice(), LittleEndian);
- read_eh_frame.set_address_size(address_size);
- let convert_frames = FrameTable::from(&read_eh_frame, &|address| {
- Some(Address::Constant(address))
- })
- .unwrap();
- assert_eq!(frames.cies, convert_frames.cies);
- assert_eq!(frames.fdes.len(), convert_frames.fdes.len());
- for (a, b) in frames.fdes.iter().zip(convert_frames.fdes.iter()) {
- assert_eq!(a.1, b.1);
- }
- }
- }
- }
- }
- }
-
- #[test]
- fn test_frame_instruction() {
- let mut expression = Expression::new();
- expression.op_constu(0);
-
- let cie_instructions = [
- CallFrameInstruction::Cfa(X86_64::RSP, 8),
- CallFrameInstruction::Offset(X86_64::RA, -8),
- ];
-
- let fde_instructions = [
- (0, CallFrameInstruction::Cfa(X86_64::RSP, 0)),
- (0, CallFrameInstruction::Cfa(X86_64::RSP, -8)),
- (2, CallFrameInstruction::CfaRegister(X86_64::RBP)),
- (4, CallFrameInstruction::CfaOffset(8)),
- (4, CallFrameInstruction::CfaOffset(0)),
- (4, CallFrameInstruction::CfaOffset(-8)),
- (6, CallFrameInstruction::CfaExpression(expression.clone())),
- (8, CallFrameInstruction::Restore(Register(1))),
- (8, CallFrameInstruction::Restore(Register(101))),
- (10, CallFrameInstruction::Undefined(Register(2))),
- (12, CallFrameInstruction::SameValue(Register(3))),
- (14, CallFrameInstruction::Offset(Register(4), 16)),
- (14, CallFrameInstruction::Offset(Register(104), 16)),
- (16, CallFrameInstruction::ValOffset(Register(5), -24)),
- (16, CallFrameInstruction::ValOffset(Register(5), 24)),
- (18, CallFrameInstruction::Register(Register(6), Register(7))),
- (
- 20,
- CallFrameInstruction::Expression(Register(8), expression.clone()),
- ),
- (
- 22,
- CallFrameInstruction::ValExpression(Register(9), expression.clone()),
- ),
- (24 + 0x80, CallFrameInstruction::RememberState),
- (26 + 0x280, CallFrameInstruction::RestoreState),
- (28 + 0x20280, CallFrameInstruction::ArgsSize(23)),
- ];
-
- let fde_instructions_aarch64 = [(0, CallFrameInstruction::NegateRaState)];
-
- for &version in &[1, 3, 4] {
- for &address_size in &[4, 8] {
- for &vendor in &[Vendor::Default, Vendor::AArch64] {
- for &format in &[Format::Dwarf32, Format::Dwarf64] {
- let encoding = Encoding {
- format,
- version,
- address_size,
- };
- let mut frames = FrameTable::default();
-
- let mut cie = CommonInformationEntry::new(encoding, 2, 8, X86_64::RA);
- for i in &cie_instructions {
- cie.add_instruction(i.clone());
- }
- let cie_id = frames.add_cie(cie);
-
- let mut fde = FrameDescriptionEntry::new(Address::Constant(0x1000), 0x10);
- for (o, i) in &fde_instructions {
- fde.add_instruction(*o, i.clone());
- }
- frames.add_fde(cie_id, fde);
-
- if vendor == Vendor::AArch64 {
- let mut fde =
- FrameDescriptionEntry::new(Address::Constant(0x2000), 0x10);
- for (o, i) in &fde_instructions_aarch64 {
- fde.add_instruction(*o, i.clone());
- }
- frames.add_fde(cie_id, fde);
- }
-
- let mut debug_frame = DebugFrame::from(EndianVec::new(LittleEndian));
- frames.write_debug_frame(&mut debug_frame).unwrap();
-
- let mut read_debug_frame =
- read::DebugFrame::new(debug_frame.slice(), LittleEndian);
- read_debug_frame.set_address_size(address_size);
- read_debug_frame.set_vendor(vendor);
- let frames = FrameTable::from(&read_debug_frame, &|address| {
- Some(Address::Constant(address))
- })
- .unwrap();
-
- assert_eq!(
- &frames.cies.get_index(0).unwrap().instructions,
- &cie_instructions
- );
- assert_eq!(&frames.fdes[0].1.instructions, &fde_instructions);
- if vendor == Vendor::AArch64 {
- assert_eq!(&frames.fdes[1].1.instructions, &fde_instructions_aarch64);
- }
- }
- }
- }
- }
- }
-}
diff --git a/vendor/gimli/src/write/dwarf.rs b/vendor/gimli/src/write/dwarf.rs
deleted file mode 100644
index ea50712..0000000
--- a/vendor/gimli/src/write/dwarf.rs
+++ /dev/null
@@ -1,138 +0,0 @@
-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,
- })
- }
- }
-}
diff --git a/vendor/gimli/src/write/endian_vec.rs b/vendor/gimli/src/write/endian_vec.rs
deleted file mode 100644
index 7b04060..0000000
--- a/vendor/gimli/src/write/endian_vec.rs
+++ /dev/null
@@ -1,117 +0,0 @@
-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]);
- }
-}
diff --git a/vendor/gimli/src/write/line.rs b/vendor/gimli/src/write/line.rs
deleted file mode 100644
index c88b735..0000000
--- a/vendor/gimli/src/write/line.rs
+++ /dev/null
@@ -1,1957 +0,0 @@
-use alloc::vec::Vec;
-use indexmap::{IndexMap, IndexSet};
-use std::ops::{Deref, DerefMut};
-
-use crate::common::{DebugLineOffset, Encoding, Format, LineEncoding, SectionId};
-use crate::constants;
-use crate::leb128;
-use crate::write::{
- Address, DebugLineStrOffsets, DebugStrOffsets, Error, LineStringId, LineStringTable, Result,
- Section, StringId, Writer,
-};
-
-/// The number assigned to the first special opcode.
-//
-// We output all instructions for all DWARF versions, since readers
-// should be able to ignore instructions they don't support.
-const OPCODE_BASE: u8 = 13;
-
-/// A line number program.
-#[derive(Debug, Clone)]
-pub struct LineProgram {
- /// True if this line program was created with `LineProgram::none()`.
- none: bool,
- encoding: Encoding,
- line_encoding: LineEncoding,
-
- /// A list of source directory path names.
- ///
- /// If a path is relative, then the directory is located relative to the working
- /// directory of the compilation unit.
- ///
- /// The first entry is for the working directory of the compilation unit.
- directories: IndexSet<LineString>,
-
- /// A list of source file entries.
- ///
- /// Each entry has a path name and a directory.
- ///
- /// If a path is a relative, then the file is located relative to the
- /// directory. Otherwise the directory is meaningless.
- ///
- /// Does not include comp_file, even for version >= 5.
- files: IndexMap<(LineString, DirectoryId), FileInfo>,
-
- /// The primary source file of the compilation unit.
- /// This is required for version >= 5, but we never reference it elsewhere
- /// because DWARF defines DW_AT_decl_file=0 to mean not specified.
- comp_file: (LineString, FileInfo),
-
- /// True if the file entries may have valid timestamps.
- ///
- /// Entries may still have a timestamp of 0 even if this is set.
- /// For version <= 4, this is ignored.
- /// For version 5, this controls whether to emit `DW_LNCT_timestamp`.
- pub file_has_timestamp: bool,
-
- /// True if the file entries may have valid sizes.
- ///
- /// Entries may still have a size of 0 even if this is set.
- /// For version <= 4, this is ignored.
- /// For version 5, this controls whether to emit `DW_LNCT_size`.
- pub file_has_size: bool,
-
- /// True if the file entries have valid MD5 checksums.
- ///
- /// For version <= 4, this is ignored.
- /// For version 5, this controls whether to emit `DW_LNCT_MD5`.
- pub file_has_md5: bool,
-
- prev_row: LineRow,
- row: LineRow,
- // TODO: this probably should be either rows or sequences instead
- instructions: Vec<LineInstruction>,
- in_sequence: bool,
-}
-
-impl LineProgram {
- /// Create a new `LineProgram`.
- ///
- /// `comp_dir` defines the working directory of the compilation unit,
- /// and must be the same as the `DW_AT_comp_dir` attribute
- /// of the compilation unit DIE.
- ///
- /// `comp_file` and `comp_file_info` define the primary source file
- /// of the compilation unit and must be the same as the `DW_AT_name`
- /// attribute of the compilation unit DIE.
- ///
- /// # Panics
- ///
- /// Panics if `line_encoding.line_base` > 0.
- ///
- /// Panics if `line_encoding.line_base` + `line_encoding.line_range` <= 0.
- ///
- /// Panics if `comp_dir` is empty or contains a null byte.
- ///
- /// Panics if `comp_file` is empty or contains a null byte.
- pub fn new(
- encoding: Encoding,
- line_encoding: LineEncoding,
- comp_dir: LineString,
- comp_file: LineString,
- comp_file_info: Option<FileInfo>,
- ) -> LineProgram {
- // We require a special opcode for a line advance of 0.
- // See the debug_asserts in generate_row().
- assert!(line_encoding.line_base <= 0);
- assert!(line_encoding.line_base + line_encoding.line_range as i8 > 0);
- let mut program = LineProgram {
- none: false,
- encoding,
- line_encoding,
- directories: IndexSet::new(),
- files: IndexMap::new(),
- comp_file: (comp_file, comp_file_info.unwrap_or_default()),
- prev_row: LineRow::initial_state(line_encoding),
- row: LineRow::initial_state(line_encoding),
- instructions: Vec::new(),
- in_sequence: false,
- file_has_timestamp: false,
- file_has_size: false,
- file_has_md5: false,
- };
- // For all DWARF versions, directory index 0 is comp_dir.
- // For version <= 4, the entry is implicit. We still add
- // it here so that we use it, but we don't emit it.
- program.add_directory(comp_dir);
- program
- }
-
- /// Create a new `LineProgram` with no fields set.
- ///
- /// This can be used when the `LineProgram` will not be used.
- ///
- /// You should not attempt to add files or line instructions to
- /// this line program, or write it to the `.debug_line` section.
- pub fn none() -> Self {
- let line_encoding = LineEncoding::default();
- LineProgram {
- none: true,
- encoding: Encoding {
- format: Format::Dwarf32,
- version: 2,
- address_size: 0,
- },
- line_encoding,
- directories: IndexSet::new(),
- files: IndexMap::new(),
- comp_file: (LineString::String(Vec::new()), FileInfo::default()),
- prev_row: LineRow::initial_state(line_encoding),
- row: LineRow::initial_state(line_encoding),
- instructions: Vec::new(),
- in_sequence: false,
- file_has_timestamp: false,
- file_has_size: false,
- file_has_md5: false,
- }
- }
-
- /// Return true if this line program was created with `LineProgram::none()`.
- #[inline]
- pub fn is_none(&self) -> bool {
- self.none
- }
-
- /// Return the encoding parameters for this line program.
- #[inline]
- pub fn encoding(&self) -> Encoding {
- self.encoding
- }
-
- /// Return the DWARF version for this line program.
- #[inline]
- pub fn version(&self) -> u16 {
- self.encoding.version
- }
-
- /// Return the address size in bytes for this line program.
- #[inline]
- pub fn address_size(&self) -> u8 {
- self.encoding.address_size
- }
-
- /// Return the DWARF format for this line program.
- #[inline]
- pub fn format(&self) -> Format {
- self.encoding.format
- }
-
- /// Return the id for the working directory of the compilation unit.
- #[inline]
- pub fn default_directory(&self) -> DirectoryId {
- DirectoryId(0)
- }
-
- /// Add a directory entry and return its id.
- ///
- /// If the directory already exists, then return the id of the existing entry.
- ///
- /// If the path is relative, then the directory is located relative to the working
- /// directory of the compilation unit.
- ///
- /// # Panics
- ///
- /// Panics if `directory` is empty or contains a null byte.
- pub fn add_directory(&mut self, directory: LineString) -> DirectoryId {
- if let LineString::String(ref val) = directory {
- // For DWARF version <= 4, directories must not be empty.
- // The first directory isn't emitted so skip the check for it.
- if self.encoding.version <= 4 && !self.directories.is_empty() {
- assert!(!val.is_empty());
- }
- assert!(!val.contains(&0));
- }
- let (index, _) = self.directories.insert_full(directory);
- DirectoryId(index)
- }
-
- /// Get a reference to a directory entry.
- ///
- /// # Panics
- ///
- /// Panics if `id` is invalid.
- pub fn get_directory(&self, id: DirectoryId) -> &LineString {
- self.directories.get_index(id.0).unwrap()
- }
-
- /// Add a file entry and return its id.
- ///
- /// If the file already exists, then return the id of the existing entry.
- ///
- /// If the file path is relative, then the file is located relative
- /// to the directory. Otherwise the directory is meaningless, but it
- /// is still used as a key for file entries.
- ///
- /// If `info` is `None`, then new entries are assigned
- /// default information, and existing entries are unmodified.
- ///
- /// If `info` is not `None`, then it is always assigned to the
- /// entry, even if the entry already exists.
- ///
- /// # Panics
- ///
- /// Panics if 'file' is empty or contains a null byte.
- pub fn add_file(
- &mut self,
- file: LineString,
- directory: DirectoryId,
- info: Option<FileInfo>,
- ) -> FileId {
- if let LineString::String(ref val) = file {
- assert!(!val.is_empty());
- assert!(!val.contains(&0));
- }
-
- let key = (file, directory);
- let index = if let Some(info) = info {
- let (index, _) = self.files.insert_full(key, info);
- index
- } else {
- let entry = self.files.entry(key);
- let index = entry.index();
- entry.or_default();
- index
- };
- FileId::new(index)
- }
-
- /// Get a reference to a file entry.
- ///
- /// # Panics
- ///
- /// Panics if `id` is invalid.
- pub fn get_file(&self, id: FileId) -> (&LineString, DirectoryId) {
- match id.index() {
- None => (&self.comp_file.0, DirectoryId(0)),
- Some(index) => self
- .files
- .get_index(index)
- .map(|entry| (&(entry.0).0, (entry.0).1))
- .unwrap(),
- }
- }
-
- /// Get a reference to the info for a file entry.
- ///
- /// # Panics
- ///
- /// Panics if `id` is invalid.
- pub fn get_file_info(&self, id: FileId) -> &FileInfo {
- match id.index() {
- None => &self.comp_file.1,
- Some(index) => self.files.get_index(index).map(|entry| entry.1).unwrap(),
- }
- }
-
- /// Get a mutable reference to the info for a file entry.
- ///
- /// # Panics
- ///
- /// Panics if `id` is invalid.
- pub fn get_file_info_mut(&mut self, id: FileId) -> &mut FileInfo {
- match id.index() {
- None => &mut self.comp_file.1,
- Some(index) => self
- .files
- .get_index_mut(index)
- .map(|entry| entry.1)
- .unwrap(),
- }
- }
-
- /// Begin a new sequence and set its base address.
- ///
- /// # Panics
- ///
- /// Panics if a sequence has already begun.
- pub fn begin_sequence(&mut self, address: Option<Address>) {
- assert!(!self.in_sequence);
- self.in_sequence = true;
- if let Some(address) = address {
- self.instructions.push(LineInstruction::SetAddress(address));
- }
- }
-
- /// End the sequence, and reset the row to its default values.
- ///
- /// Only the `address_offset` and op_index` fields of the current row are used.
- ///
- /// # Panics
- ///
- /// Panics if a sequence has not begun.
- pub fn end_sequence(&mut self, address_offset: u64) {
- assert!(self.in_sequence);
- self.in_sequence = false;
- self.row.address_offset = address_offset;
- let op_advance = self.op_advance();
- if op_advance != 0 {
- self.instructions
- .push(LineInstruction::AdvancePc(op_advance));
- }
- self.instructions.push(LineInstruction::EndSequence);
- self.prev_row = LineRow::initial_state(self.line_encoding);
- self.row = LineRow::initial_state(self.line_encoding);
- }
-
- /// Return true if a sequence has begun.
- #[inline]
- pub fn in_sequence(&self) -> bool {
- self.in_sequence
- }
-
- /// Returns a reference to the data for the current row.
- #[inline]
- pub fn row(&mut self) -> &mut LineRow {
- &mut self.row
- }
-
- /// Generates the line number information instructions for the current row.
- ///
- /// After the instructions are generated, it sets `discriminator` to 0, and sets
- /// `basic_block`, `prologue_end`, and `epilogue_begin` to false.
- ///
- /// # Panics
- ///
- /// Panics if a sequence has not begun.
- /// Panics if the address_offset decreases.
- pub fn generate_row(&mut self) {
- assert!(self.in_sequence);
-
- // Output fields that are reset on every row.
- if self.row.discriminator != 0 {
- self.instructions
- .push(LineInstruction::SetDiscriminator(self.row.discriminator));
- self.row.discriminator = 0;
- }
- if self.row.basic_block {
- self.instructions.push(LineInstruction::SetBasicBlock);
- self.row.basic_block = false;
- }
- if self.row.prologue_end {
- self.instructions.push(LineInstruction::SetPrologueEnd);
- self.row.prologue_end = false;
- }
- if self.row.epilogue_begin {
- self.instructions.push(LineInstruction::SetEpilogueBegin);
- self.row.epilogue_begin = false;
- }
-
- // Output fields that are not reset on every row.
- if self.row.is_statement != self.prev_row.is_statement {
- self.instructions.push(LineInstruction::NegateStatement);
- }
- if self.row.file != self.prev_row.file {
- self.instructions
- .push(LineInstruction::SetFile(self.row.file));
- }
- if self.row.column != self.prev_row.column {
- self.instructions
- .push(LineInstruction::SetColumn(self.row.column));
- }
- if self.row.isa != self.prev_row.isa {
- self.instructions
- .push(LineInstruction::SetIsa(self.row.isa));
- }
-
- // Advance the line, address, and operation index.
- let line_base = i64::from(self.line_encoding.line_base) as u64;
- let line_range = u64::from(self.line_encoding.line_range);
- let line_advance = self.row.line as i64 - self.prev_row.line as i64;
- let op_advance = self.op_advance();
-
- // Default to special advances of 0.
- let special_base = u64::from(OPCODE_BASE);
- // TODO: handle lack of special opcodes for 0 line advance
- debug_assert!(self.line_encoding.line_base <= 0);
- debug_assert!(self.line_encoding.line_base + self.line_encoding.line_range as i8 >= 0);
- let special_default = special_base.wrapping_sub(line_base);
- let mut special = special_default;
- let mut use_special = false;
-
- if line_advance != 0 {
- let special_line = (line_advance as u64).wrapping_sub(line_base);
- if special_line < line_range {
- special = special_base + special_line;
- use_special = true;
- } else {
- self.instructions
- .push(LineInstruction::AdvanceLine(line_advance));
- }
- }
-
- if op_advance != 0 {
- // Using ConstAddPc can save a byte.
- let (special_op_advance, const_add_pc) = if special + op_advance * line_range <= 255 {
- (op_advance, false)
- } else {
- let op_range = (255 - special_base) / line_range;
- (op_advance - op_range, true)
- };
-
- let special_op = special_op_advance * line_range;
- if special + special_op <= 255 {
- special += special_op;
- use_special = true;
- if const_add_pc {
- self.instructions.push(LineInstruction::ConstAddPc);
- }
- } else {
- self.instructions
- .push(LineInstruction::AdvancePc(op_advance));
- }
- }
-
- if use_special && special != special_default {
- debug_assert!(special >= special_base);
- debug_assert!(special <= 255);
- self.instructions
- .push(LineInstruction::Special(special as u8));
- } else {
- self.instructions.push(LineInstruction::Copy);
- }
-
- self.prev_row = self.row;
- }
-
- fn op_advance(&self) -> u64 {
- debug_assert!(self.row.address_offset >= self.prev_row.address_offset);
- let mut address_advance = self.row.address_offset - self.prev_row.address_offset;
- if self.line_encoding.minimum_instruction_length != 1 {
- debug_assert_eq!(
- self.row.address_offset % u64::from(self.line_encoding.minimum_instruction_length),
- 0
- );
- address_advance /= u64::from(self.line_encoding.minimum_instruction_length);
- }
- address_advance * u64::from(self.line_encoding.maximum_operations_per_instruction)
- + self.row.op_index
- - self.prev_row.op_index
- }
-
- /// Returns true if the line number program has no instructions.
- ///
- /// Does not check the file or directory entries.
- #[inline]
- pub fn is_empty(&self) -> bool {
- self.instructions.is_empty()
- }
-
- /// Write the line number program to the given section.
- ///
- /// # Panics
- ///
- /// Panics if `self.is_none()`.
- pub fn write<W: Writer>(
- &self,
- w: &mut DebugLine<W>,
- encoding: Encoding,
- debug_line_str_offsets: &DebugLineStrOffsets,
- debug_str_offsets: &DebugStrOffsets,
- ) -> Result<DebugLineOffset> {
- assert!(!self.is_none());
-
- if encoding.version < self.version()
- || encoding.format != self.format()
- || encoding.address_size != self.address_size()
- {
- return Err(Error::IncompatibleLineProgramEncoding);
- }
-
- let offset = w.offset();
-
- let length_offset = w.write_initial_length(self.format())?;
- let length_base = w.len();
-
- if self.version() < 2 || self.version() > 5 {
- return Err(Error::UnsupportedVersion(self.version()));
- }
- w.write_u16(self.version())?;
-
- if self.version() >= 5 {
- w.write_u8(self.address_size())?;
- // Segment selector size.
- w.write_u8(0)?;
- }
-
- let header_length_offset = w.len();
- w.write_udata(0, self.format().word_size())?;
- let header_length_base = w.len();
-
- w.write_u8(self.line_encoding.minimum_instruction_length)?;
- if self.version() >= 4 {
- w.write_u8(self.line_encoding.maximum_operations_per_instruction)?;
- } else if self.line_encoding.maximum_operations_per_instruction != 1 {
- return Err(Error::NeedVersion(4));
- };
- w.write_u8(if self.line_encoding.default_is_stmt {
- 1
- } else {
- 0
- })?;
- w.write_u8(self.line_encoding.line_base as u8)?;
- w.write_u8(self.line_encoding.line_range)?;
- w.write_u8(OPCODE_BASE)?;
- w.write(&[0, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 1])?;
-
- if self.version() <= 4 {
- // The first directory is stored as DW_AT_comp_dir.
- for dir in self.directories.iter().skip(1) {
- dir.write(
- w,
- constants::DW_FORM_string,
- self.encoding,
- debug_line_str_offsets,
- debug_str_offsets,
- )?;
- }
- w.write_u8(0)?;
-
- for ((file, dir), info) in self.files.iter() {
- file.write(
- w,
- constants::DW_FORM_string,
- self.encoding,
- debug_line_str_offsets,
- debug_str_offsets,
- )?;
- w.write_uleb128(dir.0 as u64)?;
- w.write_uleb128(info.timestamp)?;
- w.write_uleb128(info.size)?;
- }
- w.write_u8(0)?;
- } else {
- // Directory entry formats (only ever 1).
- w.write_u8(1)?;
- w.write_uleb128(u64::from(constants::DW_LNCT_path.0))?;
- let dir_form = self.directories.get_index(0).unwrap().form();
- w.write_uleb128(dir_form.0.into())?;
-
- // Directory entries.
- w.write_uleb128(self.directories.len() as u64)?;
- for dir in self.directories.iter() {
- dir.write(
- w,
- dir_form,
- self.encoding,
- debug_line_str_offsets,
- debug_str_offsets,
- )?;
- }
-
- // File name entry formats.
- let count = 2
- + if self.file_has_timestamp { 1 } else { 0 }
- + if self.file_has_size { 1 } else { 0 }
- + if self.file_has_md5 { 1 } else { 0 };
- w.write_u8(count)?;
- w.write_uleb128(u64::from(constants::DW_LNCT_path.0))?;
- let file_form = self.comp_file.0.form();
- w.write_uleb128(file_form.0.into())?;
- w.write_uleb128(u64::from(constants::DW_LNCT_directory_index.0))?;
- w.write_uleb128(constants::DW_FORM_udata.0.into())?;
- if self.file_has_timestamp {
- w.write_uleb128(u64::from(constants::DW_LNCT_timestamp.0))?;
- w.write_uleb128(constants::DW_FORM_udata.0.into())?;
- }
- if self.file_has_size {
- w.write_uleb128(u64::from(constants::DW_LNCT_size.0))?;
- w.write_uleb128(constants::DW_FORM_udata.0.into())?;
- }
- if self.file_has_md5 {
- w.write_uleb128(u64::from(constants::DW_LNCT_MD5.0))?;
- w.write_uleb128(constants::DW_FORM_data16.0.into())?;
- }
-
- // File name entries.
- w.write_uleb128(self.files.len() as u64 + 1)?;
- let mut write_file = |file: &LineString, dir: DirectoryId, info: &FileInfo| {
- file.write(
- w,
- file_form,
- self.encoding,
- debug_line_str_offsets,
- debug_str_offsets,
- )?;
- w.write_uleb128(dir.0 as u64)?;
- if self.file_has_timestamp {
- w.write_uleb128(info.timestamp)?;
- }
- if self.file_has_size {
- w.write_uleb128(info.size)?;
- }
- if self.file_has_md5 {
- w.write(&info.md5)?;
- }
- Ok(())
- };
- write_file(&self.comp_file.0, DirectoryId(0), &self.comp_file.1)?;
- for ((file, dir), info) in self.files.iter() {
- write_file(file, *dir, info)?;
- }
- }
-
- let header_length = (w.len() - header_length_base) as u64;
- w.write_udata_at(
- header_length_offset,
- header_length,
- self.format().word_size(),
- )?;
-
- for instruction in &self.instructions {
- instruction.write(w, self.address_size())?;
- }
-
- let length = (w.len() - length_base) as u64;
- w.write_initial_length_at(length_offset, length, self.format())?;
-
- Ok(offset)
- }
-}
-
-/// A row in the line number table that corresponds to a machine instruction.
-#[derive(Debug, Clone, Copy)]
-pub struct LineRow {
- /// The offset of the instruction from the start address of the sequence.
- pub address_offset: u64,
- /// The index of an operation within a VLIW instruction.
- ///
- /// The index of the first operation is 0.
- /// Set to 0 for non-VLIW instructions.
- pub op_index: u64,
-
- /// The source file corresponding to the instruction.
- pub file: FileId,
- /// The line number within the source file.
- ///
- /// Lines are numbered beginning at 1. Set to 0 if there is no source line.
- pub line: u64,
- /// The column number within the source line.
- ///
- /// Columns are numbered beginning at 1. Set to 0 for the "left edge" of the line.
- pub column: u64,
- /// An additional discriminator used to distinguish between source locations.
- /// This value is assigned arbitrarily by the DWARF producer.
- pub discriminator: u64,
-
- /// Set to true if the instruction is a recommended breakpoint for a statement.
- pub is_statement: bool,
- /// Set to true if the instruction is the beginning of a basic block.
- pub basic_block: bool,
- /// Set to true if the instruction is a recommended breakpoint at the entry of a
- /// function.
- pub prologue_end: bool,
- /// Set to true if the instruction is a recommended breakpoint prior to the exit of
- /// a function.
- pub epilogue_begin: bool,
-
- /// The instruction set architecture of the instruction.
- ///
- /// Set to 0 for the default ISA. Other values are defined by the architecture ABI.
- pub isa: u64,
-}
-
-impl LineRow {
- /// Return the initial state as specified in the DWARF standard.
- fn initial_state(line_encoding: LineEncoding) -> Self {
- LineRow {
- address_offset: 0,
- op_index: 0,
-
- file: FileId::initial_state(),
- line: 1,
- column: 0,
- discriminator: 0,
-
- is_statement: line_encoding.default_is_stmt,
- basic_block: false,
- prologue_end: false,
- epilogue_begin: false,
-
- isa: 0,
- }
- }
-}
-
-/// An instruction in a line number program.
-#[derive(Debug, Clone, Copy, PartialEq, Eq)]
-enum LineInstruction {
- // Special opcodes
- Special(u8),
-
- // Standard opcodes
- Copy,
- AdvancePc(u64),
- AdvanceLine(i64),
- SetFile(FileId),
- SetColumn(u64),
- NegateStatement,
- SetBasicBlock,
- ConstAddPc,
- // DW_LNS_fixed_advance_pc is not supported.
- SetPrologueEnd,
- SetEpilogueBegin,
- SetIsa(u64),
-
- // Extended opcodes
- EndSequence,
- // TODO: this doubles the size of this enum.
- SetAddress(Address),
- // DW_LNE_define_file is not supported.
- SetDiscriminator(u64),
-}
-
-impl LineInstruction {
- /// Write the line number instruction to the given section.
- fn write<W: Writer>(self, w: &mut DebugLine<W>, address_size: u8) -> Result<()> {
- use self::LineInstruction::*;
- match self {
- Special(val) => w.write_u8(val)?,
- Copy => w.write_u8(constants::DW_LNS_copy.0)?,
- AdvancePc(val) => {
- w.write_u8(constants::DW_LNS_advance_pc.0)?;
- w.write_uleb128(val)?;
- }
- AdvanceLine(val) => {
- w.write_u8(constants::DW_LNS_advance_line.0)?;
- w.write_sleb128(val)?;
- }
- SetFile(val) => {
- w.write_u8(constants::DW_LNS_set_file.0)?;
- w.write_uleb128(val.raw())?;
- }
- SetColumn(val) => {
- w.write_u8(constants::DW_LNS_set_column.0)?;
- w.write_uleb128(val)?;
- }
- NegateStatement => w.write_u8(constants::DW_LNS_negate_stmt.0)?,
- SetBasicBlock => w.write_u8(constants::DW_LNS_set_basic_block.0)?,
- ConstAddPc => w.write_u8(constants::DW_LNS_const_add_pc.0)?,
- SetPrologueEnd => w.write_u8(constants::DW_LNS_set_prologue_end.0)?,
- SetEpilogueBegin => w.write_u8(constants::DW_LNS_set_epilogue_begin.0)?,
- SetIsa(val) => {
- w.write_u8(constants::DW_LNS_set_isa.0)?;
- w.write_uleb128(val)?;
- }
- EndSequence => {
- w.write_u8(0)?;
- w.write_uleb128(1)?;
- w.write_u8(constants::DW_LNE_end_sequence.0)?;
- }
- SetAddress(address) => {
- w.write_u8(0)?;
- w.write_uleb128(1 + u64::from(address_size))?;
- w.write_u8(constants::DW_LNE_set_address.0)?;
- w.write_address(address, address_size)?;
- }
- SetDiscriminator(val) => {
- let mut bytes = [0u8; 10];
- // bytes is long enough so this will never fail.
- let len = leb128::write::unsigned(&mut { &mut bytes[..] }, val).unwrap();
- w.write_u8(0)?;
- w.write_uleb128(1 + len as u64)?;
- w.write_u8(constants::DW_LNE_set_discriminator.0)?;
- w.write(&bytes[..len])?;
- }
- }
- Ok(())
- }
-}
-
-/// A string value for use in defining paths in line number programs.
-#[derive(Debug, Clone, PartialEq, Eq, Hash)]
-pub enum LineString {
- /// A slice of bytes representing a string. Must not include null bytes.
- /// Not guaranteed to be UTF-8 or anything like that.
- String(Vec<u8>),
-
- /// A reference to a string in the `.debug_str` section.
- StringRef(StringId),
-
- /// A reference to a string in the `.debug_line_str` section.
- LineStringRef(LineStringId),
-}
-
-impl LineString {
- /// Create a `LineString` using the normal form for the given encoding.
- pub fn new<T>(val: T, encoding: Encoding, line_strings: &mut LineStringTable) -> Self
- where
- T: Into<Vec<u8>>,
- {
- let val = val.into();
- if encoding.version <= 4 {
- LineString::String(val)
- } else {
- LineString::LineStringRef(line_strings.add(val))
- }
- }
-
- fn form(&self) -> constants::DwForm {
- match *self {
- LineString::String(..) => constants::DW_FORM_string,
- LineString::StringRef(..) => constants::DW_FORM_strp,
- LineString::LineStringRef(..) => constants::DW_FORM_line_strp,
- }
- }
-
- fn write<W: Writer>(
- &self,
- w: &mut DebugLine<W>,
- form: constants::DwForm,
- encoding: Encoding,
- debug_line_str_offsets: &DebugLineStrOffsets,
- debug_str_offsets: &DebugStrOffsets,
- ) -> Result<()> {
- if form != self.form() {
- return Err(Error::LineStringFormMismatch);
- }
-
- match *self {
- LineString::String(ref val) => {
- if encoding.version <= 4 {
- debug_assert!(!val.is_empty());
- }
- w.write(val)?;
- w.write_u8(0)?;
- }
- LineString::StringRef(val) => {
- if encoding.version < 5 {
- return Err(Error::NeedVersion(5));
- }
- w.write_offset(
- debug_str_offsets.get(val).0,
- SectionId::DebugStr,
- encoding.format.word_size(),
- )?;
- }
- LineString::LineStringRef(val) => {
- if encoding.version < 5 {
- return Err(Error::NeedVersion(5));
- }
- w.write_offset(
- debug_line_str_offsets.get(val).0,
- SectionId::DebugLineStr,
- encoding.format.word_size(),
- )?;
- }
- }
- Ok(())
- }
-}
-
-/// An identifier for a directory in a `LineProgram`.
-///
-/// Defaults to the working directory of the compilation unit.
-#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
-pub struct DirectoryId(usize);
-
-// Force FileId access via the methods.
-mod id {
- /// An identifier for a file in a `LineProgram`.
- #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
- pub struct FileId(usize);
-
- impl FileId {
- /// Create a FileId given an index into `LineProgram::files`.
- pub(crate) fn new(index: usize) -> Self {
- FileId(index + 1)
- }
-
- /// The index of the file in `LineProgram::files`.
- pub(super) fn index(self) -> Option<usize> {
- if self.0 == 0 {
- None
- } else {
- Some(self.0 - 1)
- }
- }
-
- /// The initial state of the file register.
- pub(super) fn initial_state() -> Self {
- FileId(1)
- }
-
- /// The raw value used when writing.
- pub(crate) fn raw(self) -> u64 {
- self.0 as u64
- }
-
- /// The id for file index 0 in DWARF version 5.
- /// Only used when converting.
- // Used for tests only.
- #[allow(unused)]
- pub(super) fn zero() -> Self {
- FileId(0)
- }
- }
-}
-pub use self::id::*;
-
-/// Extra information for file in a `LineProgram`.
-#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
-pub struct FileInfo {
- /// The implementation defined timestamp of the last modification of the file,
- /// or 0 if not available.
- pub timestamp: u64,
-
- /// The size of the file in bytes, or 0 if not available.
- pub size: u64,
-
- /// A 16-byte MD5 digest of the file contents.
- ///
- /// Only used if version >= 5 and `LineProgram::file_has_md5` is `true`.
- pub md5: [u8; 16],
-}
-
-define_section!(
- DebugLine,
- DebugLineOffset,
- "A writable `.debug_line` section."
-);
-
-#[cfg(feature = "read")]
-mod convert {
- use super::*;
- use crate::read::{self, Reader};
- use crate::write::{self, ConvertError, ConvertResult};
-
- impl LineProgram {
- /// Create a line number program by reading the data from the given program.
- ///
- /// Return the program and a mapping from file index to `FileId`.
- pub fn from<R: Reader<Offset = usize>>(
- mut from_program: read::IncompleteLineProgram<R>,
- dwarf: &read::Dwarf<R>,
- line_strings: &mut write::LineStringTable,
- strings: &mut write::StringTable,
- convert_address: &dyn Fn(u64) -> Option<Address>,
- ) -> ConvertResult<(LineProgram, Vec<FileId>)> {
- // Create mappings in case the source has duplicate files or directories.
- let mut dirs = Vec::new();
- let mut files = Vec::new();
-
- let mut program = {
- let from_header = from_program.header();
- let encoding = from_header.encoding();
-
- let comp_dir = match from_header.directory(0) {
- Some(comp_dir) => LineString::from(comp_dir, dwarf, line_strings, strings)?,
- None => LineString::new(&[][..], encoding, line_strings),
- };
-
- let (comp_name, comp_file_info) = match from_header.file(0) {
- Some(comp_file) => {
- if comp_file.directory_index() != 0 {
- return Err(ConvertError::InvalidDirectoryIndex);
- }
- (
- LineString::from(comp_file.path_name(), dwarf, line_strings, strings)?,
- Some(FileInfo {
- timestamp: comp_file.timestamp(),
- size: comp_file.size(),
- md5: *comp_file.md5(),
- }),
- )
- }
- None => (LineString::new(&[][..], encoding, line_strings), None),
- };
-
- if from_header.line_base() > 0 {
- return Err(ConvertError::InvalidLineBase);
- }
- let mut program = LineProgram::new(
- encoding,
- from_header.line_encoding(),
- comp_dir,
- comp_name,
- comp_file_info,
- );
-
- let file_skip;
- if from_header.version() <= 4 {
- // The first directory is implicit.
- dirs.push(DirectoryId(0));
- // A file index of 0 is invalid for version <= 4, but putting
- // something there makes the indexing easier.
- file_skip = 0;
- files.push(FileId::zero());
- } else {
- // We don't add the first file to `files`, but still allow
- // it to be referenced from converted instructions.
- file_skip = 1;
- files.push(FileId::zero());
- }
-
- for from_dir in from_header.include_directories() {
- let from_dir =
- LineString::from(from_dir.clone(), dwarf, line_strings, strings)?;
- dirs.push(program.add_directory(from_dir));
- }
-
- program.file_has_timestamp = from_header.file_has_timestamp();
- program.file_has_size = from_header.file_has_size();
- program.file_has_md5 = from_header.file_has_md5();
- for from_file in from_header.file_names().iter().skip(file_skip) {
- let from_name =
- LineString::from(from_file.path_name(), dwarf, line_strings, strings)?;
- let from_dir = from_file.directory_index();
- if from_dir >= dirs.len() as u64 {
- return Err(ConvertError::InvalidDirectoryIndex);
- }
- let from_dir = dirs[from_dir as usize];
- let from_info = Some(FileInfo {
- timestamp: from_file.timestamp(),
- size: from_file.size(),
- md5: *from_file.md5(),
- });
- files.push(program.add_file(from_name, from_dir, from_info));
- }
-
- program
- };
-
- // We can't use the `from_program.rows()` because that wouldn't let
- // us preserve address relocations.
- let mut from_row = read::LineRow::new(from_program.header());
- let mut instructions = from_program.header().instructions();
- let mut address = None;
- while let Some(instruction) = instructions.next_instruction(from_program.header())? {
- match instruction {
- read::LineInstruction::SetAddress(val) => {
- if program.in_sequence() {
- return Err(ConvertError::UnsupportedLineInstruction);
- }
- match convert_address(val) {
- Some(val) => address = Some(val),
- None => return Err(ConvertError::InvalidAddress),
- }
- from_row.execute(read::LineInstruction::SetAddress(0), &mut from_program);
- }
- read::LineInstruction::DefineFile(_) => {
- return Err(ConvertError::UnsupportedLineInstruction);
- }
- _ => {
- if from_row.execute(instruction, &mut from_program) {
- if !program.in_sequence() {
- program.begin_sequence(address);
- address = None;
- }
- if from_row.end_sequence() {
- program.end_sequence(from_row.address());
- } else {
- program.row().address_offset = from_row.address();
- program.row().op_index = from_row.op_index();
- program.row().file = {
- let file = from_row.file_index();
- if file >= files.len() as u64 {
- return Err(ConvertError::InvalidFileIndex);
- }
- if file == 0 && program.version() <= 4 {
- return Err(ConvertError::InvalidFileIndex);
- }
- files[file as usize]
- };
- program.row().line = match from_row.line() {
- Some(line) => line.get(),
- None => 0,
- };
- program.row().column = match from_row.column() {
- read::ColumnType::LeftEdge => 0,
- read::ColumnType::Column(val) => val.get(),
- };
- program.row().discriminator = from_row.discriminator();
- program.row().is_statement = from_row.is_stmt();
- program.row().basic_block = from_row.basic_block();
- program.row().prologue_end = from_row.prologue_end();
- program.row().epilogue_begin = from_row.epilogue_begin();
- program.row().isa = from_row.isa();
- program.generate_row();
- }
- from_row.reset(from_program.header());
- }
- }
- };
- }
- Ok((program, files))
- }
- }
-
- impl LineString {
- fn from<R: Reader<Offset = usize>>(
- from_attr: read::AttributeValue<R>,
- dwarf: &read::Dwarf<R>,
- line_strings: &mut write::LineStringTable,
- strings: &mut write::StringTable,
- ) -> ConvertResult<LineString> {
- Ok(match from_attr {
- read::AttributeValue::String(r) => LineString::String(r.to_slice()?.to_vec()),
- read::AttributeValue::DebugStrRef(offset) => {
- let r = dwarf.debug_str.get_str(offset)?;
- let id = strings.add(r.to_slice()?);
- LineString::StringRef(id)
- }
- read::AttributeValue::DebugLineStrRef(offset) => {
- let r = dwarf.debug_line_str.get_str(offset)?;
- let id = line_strings.add(r.to_slice()?);
- LineString::LineStringRef(id)
- }
- _ => return Err(ConvertError::UnsupportedLineStringForm),
- })
- }
- }
-}
-
-#[cfg(test)]
-#[cfg(feature = "read")]
-mod tests {
- use super::*;
- use crate::read;
- use crate::write::{DebugLineStr, DebugStr, EndianVec, StringTable};
- use crate::LittleEndian;
-
- #[test]
- fn test_line_program_table() {
- let dir1 = LineString::String(b"dir1".to_vec());
- let file1 = LineString::String(b"file1".to_vec());
- let dir2 = LineString::String(b"dir2".to_vec());
- let file2 = LineString::String(b"file2".to_vec());
-
- let mut programs = Vec::new();
- 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 program = LineProgram::new(
- encoding,
- LineEncoding::default(),
- dir1.clone(),
- file1.clone(),
- None,
- );
-
- {
- assert_eq!(&dir1, program.get_directory(program.default_directory()));
- program.file_has_timestamp = true;
- program.file_has_size = true;
- if encoding.version >= 5 {
- program.file_has_md5 = true;
- }
-
- let dir_id = program.add_directory(dir2.clone());
- assert_eq!(&dir2, program.get_directory(dir_id));
- assert_eq!(dir_id, program.add_directory(dir2.clone()));
-
- let file_info = FileInfo {
- timestamp: 1,
- size: 2,
- md5: if encoding.version >= 5 {
- [3; 16]
- } else {
- [0; 16]
- },
- };
- let file_id = program.add_file(file2.clone(), dir_id, Some(file_info));
- assert_eq!((&file2, dir_id), program.get_file(file_id));
- assert_eq!(file_info, *program.get_file_info(file_id));
-
- program.get_file_info_mut(file_id).size = 3;
- assert_ne!(file_info, *program.get_file_info(file_id));
- assert_eq!(file_id, program.add_file(file2.clone(), dir_id, None));
- assert_ne!(file_info, *program.get_file_info(file_id));
- assert_eq!(
- file_id,
- program.add_file(file2.clone(), dir_id, Some(file_info))
- );
- assert_eq!(file_info, *program.get_file_info(file_id));
-
- programs.push((program, file_id, encoding));
- }
- }
- }
- }
-
- let debug_line_str_offsets = DebugLineStrOffsets::none();
- let debug_str_offsets = DebugStrOffsets::none();
- let mut debug_line = DebugLine::from(EndianVec::new(LittleEndian));
- let mut debug_line_offsets = Vec::new();
- for (program, _, encoding) in &programs {
- debug_line_offsets.push(
- program
- .write(
- &mut debug_line,
- *encoding,
- &debug_line_str_offsets,
- &debug_str_offsets,
- )
- .unwrap(),
- );
- }
-
- let read_debug_line = read::DebugLine::new(debug_line.slice(), LittleEndian);
-
- let convert_address = &|address| Some(Address::Constant(address));
- for ((program, file_id, encoding), offset) in programs.iter().zip(debug_line_offsets.iter())
- {
- let read_program = read_debug_line
- .program(
- *offset,
- encoding.address_size,
- Some(read::EndianSlice::new(b"dir1", LittleEndian)),
- Some(read::EndianSlice::new(b"file1", LittleEndian)),
- )
- .unwrap();
-
- let dwarf = read::Dwarf::default();
- let mut convert_line_strings = LineStringTable::default();
- let mut convert_strings = StringTable::default();
- let (convert_program, convert_files) = LineProgram::from(
- read_program,
- &dwarf,
- &mut convert_line_strings,
- &mut convert_strings,
- convert_address,
- )
- .unwrap();
- assert_eq!(convert_program.version(), program.version());
- assert_eq!(convert_program.address_size(), program.address_size());
- assert_eq!(convert_program.format(), program.format());
-
- let convert_file_id = convert_files[file_id.raw() as usize];
- let (file, dir) = program.get_file(*file_id);
- let (convert_file, convert_dir) = convert_program.get_file(convert_file_id);
- assert_eq!(file, convert_file);
- assert_eq!(
- program.get_directory(dir),
- convert_program.get_directory(convert_dir)
- );
- assert_eq!(
- program.get_file_info(*file_id),
- convert_program.get_file_info(convert_file_id)
- );
- }
- }
-
- #[test]
- fn test_line_row() {
- let dir1 = &b"dir1"[..];
- let file1 = &b"file1"[..];
- let file2 = &b"file2"[..];
- let convert_address = &|address| Some(Address::Constant(address));
-
- let debug_line_str_offsets = DebugLineStrOffsets::none();
- let debug_str_offsets = DebugStrOffsets::none();
-
- 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 line_base = -5;
- let line_range = 14;
- let neg_line_base = (-line_base) as u8;
- let mut program = LineProgram::new(
- encoding,
- LineEncoding {
- line_base,
- line_range,
- ..Default::default()
- },
- LineString::String(dir1.to_vec()),
- LineString::String(file1.to_vec()),
- None,
- );
- let dir_id = program.default_directory();
- program.add_file(LineString::String(file1.to_vec()), dir_id, None);
- let file_id =
- program.add_file(LineString::String(file2.to_vec()), dir_id, None);
-
- // Test sequences.
- {
- let mut program = program.clone();
- let address = Address::Constant(0x12);
- program.begin_sequence(Some(address));
- assert_eq!(
- program.instructions,
- vec![LineInstruction::SetAddress(address)]
- );
- }
-
- {
- let mut program = program.clone();
- program.begin_sequence(None);
- assert_eq!(program.instructions, Vec::new());
- }
-
- {
- let mut program = program.clone();
- program.begin_sequence(None);
- program.end_sequence(0x1234);
- assert_eq!(
- program.instructions,
- vec![
- LineInstruction::AdvancePc(0x1234),
- LineInstruction::EndSequence
- ]
- );
- }
-
- // Create a base program.
- program.begin_sequence(None);
- program.row.line = 0x1000;
- program.generate_row();
- let base_row = program.row;
- let base_instructions = program.instructions.clone();
-
- // Create test cases.
- let mut tests = Vec::new();
-
- let row = base_row;
- tests.push((row, vec![LineInstruction::Copy]));
-
- let mut row = base_row;
- row.line -= u64::from(neg_line_base);
- tests.push((row, vec![LineInstruction::Special(OPCODE_BASE)]));
-
- let mut row = base_row;
- row.line += u64::from(line_range) - 1;
- row.line -= u64::from(neg_line_base);
- tests.push((
- row,
- vec![LineInstruction::Special(OPCODE_BASE + line_range - 1)],
- ));
-
- let mut row = base_row;
- row.line += u64::from(line_range);
- row.line -= u64::from(neg_line_base);
- tests.push((
- row,
- vec![
- LineInstruction::AdvanceLine(i64::from(line_range - neg_line_base)),
- LineInstruction::Copy,
- ],
- ));
-
- let mut row = base_row;
- row.address_offset = 1;
- row.line -= u64::from(neg_line_base);
- tests.push((
- row,
- vec![LineInstruction::Special(OPCODE_BASE + line_range)],
- ));
-
- let op_range = (255 - OPCODE_BASE) / line_range;
- let mut row = base_row;
- row.address_offset = u64::from(op_range);
- row.line -= u64::from(neg_line_base);
- tests.push((
- row,
- vec![LineInstruction::Special(
- OPCODE_BASE + op_range * line_range,
- )],
- ));
-
- let mut row = base_row;
- row.address_offset = u64::from(op_range);
- row.line += u64::from(255 - OPCODE_BASE - op_range * line_range);
- row.line -= u64::from(neg_line_base);
- tests.push((row, vec![LineInstruction::Special(255)]));
-
- let mut row = base_row;
- row.address_offset = u64::from(op_range);
- row.line += u64::from(255 - OPCODE_BASE - op_range * line_range) + 1;
- row.line -= u64::from(neg_line_base);
- tests.push((
- row,
- vec![LineInstruction::ConstAddPc, LineInstruction::Copy],
- ));
-
- let mut row = base_row;
- row.address_offset = u64::from(op_range);
- row.line += u64::from(255 - OPCODE_BASE - op_range * line_range) + 2;
- row.line -= u64::from(neg_line_base);
- tests.push((
- row,
- vec![
- LineInstruction::ConstAddPc,
- LineInstruction::Special(OPCODE_BASE + 6),
- ],
- ));
-
- let mut row = base_row;
- row.address_offset = u64::from(op_range) * 2;
- row.line += u64::from(255 - OPCODE_BASE - op_range * line_range);
- row.line -= u64::from(neg_line_base);
- tests.push((
- row,
- vec![LineInstruction::ConstAddPc, LineInstruction::Special(255)],
- ));
-
- let mut row = base_row;
- row.address_offset = u64::from(op_range) * 2;
- row.line += u64::from(255 - OPCODE_BASE - op_range * line_range) + 1;
- row.line -= u64::from(neg_line_base);
- tests.push((
- row,
- vec![
- LineInstruction::AdvancePc(row.address_offset),
- LineInstruction::Copy,
- ],
- ));
-
- let mut row = base_row;
- row.address_offset = u64::from(op_range) * 2;
- row.line += u64::from(255 - OPCODE_BASE - op_range * line_range) + 2;
- row.line -= u64::from(neg_line_base);
- tests.push((
- row,
- vec![
- LineInstruction::AdvancePc(row.address_offset),
- LineInstruction::Special(OPCODE_BASE + 6),
- ],
- ));
-
- let mut row = base_row;
- row.address_offset = 0x1234;
- tests.push((
- row,
- vec![LineInstruction::AdvancePc(0x1234), LineInstruction::Copy],
- ));
-
- let mut row = base_row;
- row.line += 0x1234;
- tests.push((
- row,
- vec![LineInstruction::AdvanceLine(0x1234), LineInstruction::Copy],
- ));
-
- let mut row = base_row;
- row.file = file_id;
- tests.push((
- row,
- vec![LineInstruction::SetFile(file_id), LineInstruction::Copy],
- ));
-
- let mut row = base_row;
- row.column = 0x1234;
- tests.push((
- row,
- vec![LineInstruction::SetColumn(0x1234), LineInstruction::Copy],
- ));
-
- let mut row = base_row;
- row.discriminator = 0x1234;
- tests.push((
- row,
- vec![
- LineInstruction::SetDiscriminator(0x1234),
- LineInstruction::Copy,
- ],
- ));
-
- let mut row = base_row;
- row.is_statement = !row.is_statement;
- tests.push((
- row,
- vec![LineInstruction::NegateStatement, LineInstruction::Copy],
- ));
-
- let mut row = base_row;
- row.basic_block = true;
- tests.push((
- row,
- vec![LineInstruction::SetBasicBlock, LineInstruction::Copy],
- ));
-
- let mut row = base_row;
- row.prologue_end = true;
- tests.push((
- row,
- vec![LineInstruction::SetPrologueEnd, LineInstruction::Copy],
- ));
-
- let mut row = base_row;
- row.epilogue_begin = true;
- tests.push((
- row,
- vec![LineInstruction::SetEpilogueBegin, LineInstruction::Copy],
- ));
-
- let mut row = base_row;
- row.isa = 0x1234;
- tests.push((
- row,
- vec![LineInstruction::SetIsa(0x1234), LineInstruction::Copy],
- ));
-
- for test in tests {
- // Test generate_row().
- let mut program = program.clone();
- program.row = test.0;
- program.generate_row();
- assert_eq!(
- &program.instructions[base_instructions.len()..],
- &test.1[..]
- );
-
- // Test LineProgram::from().
- let mut debug_line = DebugLine::from(EndianVec::new(LittleEndian));
- let debug_line_offset = program
- .write(
- &mut debug_line,
- encoding,
- &debug_line_str_offsets,
- &debug_str_offsets,
- )
- .unwrap();
-
- let read_debug_line =
- read::DebugLine::new(debug_line.slice(), LittleEndian);
- let read_program = read_debug_line
- .program(
- debug_line_offset,
- address_size,
- Some(read::EndianSlice::new(dir1, LittleEndian)),
- Some(read::EndianSlice::new(file1, LittleEndian)),
- )
- .unwrap();
-
- let dwarf = read::Dwarf::default();
- let mut convert_line_strings = LineStringTable::default();
- let mut convert_strings = StringTable::default();
- let (convert_program, _convert_files) = LineProgram::from(
- read_program,
- &dwarf,
- &mut convert_line_strings,
- &mut convert_strings,
- convert_address,
- )
- .unwrap();
- assert_eq!(
- &convert_program.instructions[base_instructions.len()..],
- &test.1[..]
- );
- }
- }
- }
- }
- }
-
- #[test]
- fn test_line_instruction() {
- let dir1 = &b"dir1"[..];
- let file1 = &b"file1"[..];
-
- let debug_line_str_offsets = DebugLineStrOffsets::none();
- let debug_str_offsets = DebugStrOffsets::none();
-
- 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 program = LineProgram::new(
- encoding,
- LineEncoding::default(),
- LineString::String(dir1.to_vec()),
- LineString::String(file1.to_vec()),
- None,
- );
- let dir_id = program.default_directory();
- let file_id =
- program.add_file(LineString::String(file1.to_vec()), dir_id, None);
-
- for &(ref inst, ref expect_inst) in &[
- (
- LineInstruction::Special(OPCODE_BASE),
- read::LineInstruction::Special(OPCODE_BASE),
- ),
- (
- LineInstruction::Special(255),
- read::LineInstruction::Special(255),
- ),
- (LineInstruction::Copy, read::LineInstruction::Copy),
- (
- LineInstruction::AdvancePc(0x12),
- read::LineInstruction::AdvancePc(0x12),
- ),
- (
- LineInstruction::AdvanceLine(0x12),
- read::LineInstruction::AdvanceLine(0x12),
- ),
- (
- LineInstruction::SetFile(file_id),
- read::LineInstruction::SetFile(file_id.raw()),
- ),
- (
- LineInstruction::SetColumn(0x12),
- read::LineInstruction::SetColumn(0x12),
- ),
- (
- LineInstruction::NegateStatement,
- read::LineInstruction::NegateStatement,
- ),
- (
- LineInstruction::SetBasicBlock,
- read::LineInstruction::SetBasicBlock,
- ),
- (
- LineInstruction::ConstAddPc,
- read::LineInstruction::ConstAddPc,
- ),
- (
- LineInstruction::SetPrologueEnd,
- read::LineInstruction::SetPrologueEnd,
- ),
- (
- LineInstruction::SetEpilogueBegin,
- read::LineInstruction::SetEpilogueBegin,
- ),
- (
- LineInstruction::SetIsa(0x12),
- read::LineInstruction::SetIsa(0x12),
- ),
- (
- LineInstruction::EndSequence,
- read::LineInstruction::EndSequence,
- ),
- (
- LineInstruction::SetAddress(Address::Constant(0x12)),
- read::LineInstruction::SetAddress(0x12),
- ),
- (
- LineInstruction::SetDiscriminator(0x12),
- read::LineInstruction::SetDiscriminator(0x12),
- ),
- ][..]
- {
- let mut program = program.clone();
- program.instructions.push(*inst);
-
- let mut debug_line = DebugLine::from(EndianVec::new(LittleEndian));
- let debug_line_offset = program
- .write(
- &mut debug_line,
- encoding,
- &debug_line_str_offsets,
- &debug_str_offsets,
- )
- .unwrap();
-
- let read_debug_line =
- read::DebugLine::new(debug_line.slice(), LittleEndian);
- let read_program = read_debug_line
- .program(
- debug_line_offset,
- address_size,
- Some(read::EndianSlice::new(dir1, LittleEndian)),
- Some(read::EndianSlice::new(file1, LittleEndian)),
- )
- .unwrap();
- let read_header = read_program.header();
- let mut read_insts = read_header.instructions();
- assert_eq!(
- *expect_inst,
- read_insts.next_instruction(read_header).unwrap().unwrap()
- );
- assert_eq!(None, read_insts.next_instruction(read_header).unwrap());
- }
- }
- }
- }
- }
-
- // Test that the address/line advance is correct. We don't test for optimality.
- #[test]
- fn test_advance() {
- let encoding = Encoding {
- format: Format::Dwarf32,
- version: 4,
- address_size: 8,
- };
-
- let dir1 = &b"dir1"[..];
- let file1 = &b"file1"[..];
-
- let addresses = 0..50;
- let lines = -10..25i64;
-
- let debug_line_str_offsets = DebugLineStrOffsets::none();
- let debug_str_offsets = DebugStrOffsets::none();
-
- for minimum_instruction_length in vec![1, 4] {
- for maximum_operations_per_instruction in vec![1, 3] {
- for line_base in vec![-5, 0] {
- for line_range in vec![10, 20] {
- let line_encoding = LineEncoding {
- minimum_instruction_length,
- maximum_operations_per_instruction,
- line_base,
- line_range,
- default_is_stmt: true,
- };
- let mut program = LineProgram::new(
- encoding,
- line_encoding,
- LineString::String(dir1.to_vec()),
- LineString::String(file1.to_vec()),
- None,
- );
- for address_advance in addresses.clone() {
- program.begin_sequence(Some(Address::Constant(0x1000)));
- program.row().line = 0x10000;
- program.generate_row();
- for line_advance in lines.clone() {
- {
- let row = program.row();
- row.address_offset +=
- address_advance * u64::from(minimum_instruction_length);
- row.line = row.line.wrapping_add(line_advance as u64);
- }
- program.generate_row();
- }
- let address_offset = program.row().address_offset
- + u64::from(minimum_instruction_length);
- program.end_sequence(address_offset);
- }
-
- let mut debug_line = DebugLine::from(EndianVec::new(LittleEndian));
- let debug_line_offset = program
- .write(
- &mut debug_line,
- encoding,
- &debug_line_str_offsets,
- &debug_str_offsets,
- )
- .unwrap();
-
- let read_debug_line =
- read::DebugLine::new(debug_line.slice(), LittleEndian);
- let read_program = read_debug_line
- .program(
- debug_line_offset,
- 8,
- Some(read::EndianSlice::new(dir1, LittleEndian)),
- Some(read::EndianSlice::new(file1, LittleEndian)),
- )
- .unwrap();
-
- let mut rows = read_program.rows();
- for address_advance in addresses.clone() {
- let mut address;
- let mut line;
- {
- let row = rows.next_row().unwrap().unwrap().1;
- address = row.address();
- line = row.line().unwrap().get();
- }
- assert_eq!(address, 0x1000);
- assert_eq!(line, 0x10000);
- for line_advance in lines.clone() {
- let row = rows.next_row().unwrap().unwrap().1;
- assert_eq!(
- row.address() - address,
- address_advance * u64::from(minimum_instruction_length)
- );
- assert_eq!(
- (row.line().unwrap().get() as i64) - (line as i64),
- line_advance
- );
- address = row.address();
- line = row.line().unwrap().get();
- }
- let row = rows.next_row().unwrap().unwrap().1;
- assert!(row.end_sequence());
- }
- }
- }
- }
- }
- }
-
- #[test]
- fn test_line_string() {
- let version = 5;
-
- let file = b"file1";
-
- let mut strings = StringTable::default();
- let string_id = strings.add("file2");
- let mut debug_str = DebugStr::from(EndianVec::new(LittleEndian));
- let debug_str_offsets = strings.write(&mut debug_str).unwrap();
-
- let mut line_strings = LineStringTable::default();
- let line_string_id = line_strings.add("file3");
- let mut debug_line_str = DebugLineStr::from(EndianVec::new(LittleEndian));
- let debug_line_str_offsets = line_strings.write(&mut debug_line_str).unwrap();
-
- for &address_size in &[4, 8] {
- for &format in &[Format::Dwarf32, Format::Dwarf64] {
- let encoding = Encoding {
- format,
- version,
- address_size,
- };
-
- for (file, expect_file) in vec![
- (
- LineString::String(file.to_vec()),
- read::AttributeValue::String(read::EndianSlice::new(file, LittleEndian)),
- ),
- (
- LineString::StringRef(string_id),
- read::AttributeValue::DebugStrRef(debug_str_offsets.get(string_id)),
- ),
- (
- LineString::LineStringRef(line_string_id),
- read::AttributeValue::DebugLineStrRef(
- debug_line_str_offsets.get(line_string_id),
- ),
- ),
- ] {
- let program = LineProgram::new(
- encoding,
- LineEncoding::default(),
- LineString::String(b"dir".to_vec()),
- file,
- None,
- );
-
- let mut debug_line = DebugLine::from(EndianVec::new(LittleEndian));
- let debug_line_offset = program
- .write(
- &mut debug_line,
- encoding,
- &debug_line_str_offsets,
- &debug_str_offsets,
- )
- .unwrap();
-
- let read_debug_line = read::DebugLine::new(debug_line.slice(), LittleEndian);
- let read_program = read_debug_line
- .program(debug_line_offset, address_size, None, None)
- .unwrap();
- let read_header = read_program.header();
- assert_eq!(read_header.file(0).unwrap().path_name(), expect_file);
- }
- }
- }
- }
-
- #[test]
- fn test_missing_comp_dir() {
- let debug_line_str_offsets = DebugLineStrOffsets::none();
- let debug_str_offsets = DebugStrOffsets::none();
-
- 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 program = LineProgram::new(
- encoding,
- LineEncoding::default(),
- LineString::String(Vec::new()),
- LineString::String(Vec::new()),
- None,
- );
-
- let mut debug_line = DebugLine::from(EndianVec::new(LittleEndian));
- let debug_line_offset = program
- .write(
- &mut debug_line,
- encoding,
- &debug_line_str_offsets,
- &debug_str_offsets,
- )
- .unwrap();
-
- let read_debug_line = read::DebugLine::new(debug_line.slice(), LittleEndian);
- let read_program = read_debug_line
- .program(
- debug_line_offset,
- address_size,
- // Testing missing comp_dir/comp_name.
- None,
- None,
- )
- .unwrap();
-
- let dwarf = read::Dwarf::default();
- let mut convert_line_strings = LineStringTable::default();
- let mut convert_strings = StringTable::default();
- let convert_address = &|address| Some(Address::Constant(address));
- LineProgram::from(
- read_program,
- &dwarf,
- &mut convert_line_strings,
- &mut convert_strings,
- convert_address,
- )
- .unwrap();
- }
- }
- }
- }
-}
diff --git a/vendor/gimli/src/write/loc.rs b/vendor/gimli/src/write/loc.rs
deleted file mode 100644
index 6dfe45a..0000000
--- a/vendor/gimli/src/write/loc.rs
+++ /dev/null
@@ -1,550 +0,0 @@
-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);
- }
- }
- }
- }
-}
diff --git a/vendor/gimli/src/write/mod.rs b/vendor/gimli/src/write/mod.rs
deleted file mode 100644
index 47ba631..0000000
--- a/vendor/gimli/src/write/mod.rs
+++ /dev/null
@@ -1,425 +0,0 @@
-//! 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::*;
diff --git a/vendor/gimli/src/write/op.rs b/vendor/gimli/src/write/op.rs
deleted file mode 100644
index 287083b..0000000
--- a/vendor/gimli/src/write/op.rs
+++ /dev/null
@@ -1,1618 +0,0 @@
-use alloc::boxed::Box;
-use alloc::vec::Vec;
-
-use crate::common::{Encoding, Register};
-use crate::constants::{self, DwOp};
-use crate::leb128::write::{sleb128_size, uleb128_size};
-use crate::write::{
- Address, DebugInfoReference, Error, Reference, Result, UnitEntryId, UnitOffsets, Writer,
-};
-
-/// The bytecode for a DWARF expression or location description.
-#[derive(Debug, Default, Clone, PartialEq, Eq, Hash)]
-pub struct Expression {
- operations: Vec<Operation>,
-}
-
-impl Expression {
- /// Create an empty expression.
- #[inline]
- pub fn new() -> Self {
- Self::default()
- }
-
- /// Create an expression from raw bytecode.
- ///
- /// This does not support operations that require references, such as `DW_OP_addr`.
- #[inline]
- pub fn raw(bytecode: Vec<u8>) -> Self {
- Expression {
- operations: vec![Operation::Raw(bytecode)],
- }
- }
-
- /// Add an operation to the expression.
- ///
- /// This should only be used for operations that have no explicit operands.
- pub fn op(&mut self, opcode: DwOp) {
- self.operations.push(Operation::Simple(opcode));
- }
-
- /// Add a `DW_OP_addr` operation to the expression.
- pub fn op_addr(&mut self, address: Address) {
- self.operations.push(Operation::Address(address));
- }
-
- /// Add a `DW_OP_constu` operation to the expression.
- ///
- /// This may be emitted as a smaller equivalent operation.
- pub fn op_constu(&mut self, value: u64) {
- self.operations.push(Operation::UnsignedConstant(value));
- }
-
- /// Add a `DW_OP_consts` operation to the expression.
- ///
- /// This may be emitted as a smaller equivalent operation.
- pub fn op_consts(&mut self, value: i64) {
- self.operations.push(Operation::SignedConstant(value));
- }
-
- /// Add a `DW_OP_const_type` or `DW_OP_GNU_const_type` operation to the expression.
- pub fn op_const_type(&mut self, base: UnitEntryId, value: Box<[u8]>) {
- self.operations.push(Operation::ConstantType(base, value));
- }
-
- /// Add a `DW_OP_fbreg` operation to the expression.
- pub fn op_fbreg(&mut self, offset: i64) {
- self.operations.push(Operation::FrameOffset(offset));
- }
-
- /// Add a `DW_OP_bregx` operation to the expression.
- ///
- /// This may be emitted as a smaller equivalent operation.
- pub fn op_breg(&mut self, register: Register, offset: i64) {
- self.operations
- .push(Operation::RegisterOffset(register, offset));
- }
-
- /// Add a `DW_OP_regval_type` or `DW_OP_GNU_regval_type` operation to the expression.
- ///
- /// This may be emitted as a smaller equivalent operation.
- pub fn op_regval_type(&mut self, register: Register, base: UnitEntryId) {
- self.operations
- .push(Operation::RegisterType(register, base));
- }
-
- /// Add a `DW_OP_pick` operation to the expression.
- ///
- /// This may be emitted as a `DW_OP_dup` or `DW_OP_over` operation.
- pub fn op_pick(&mut self, index: u8) {
- self.operations.push(Operation::Pick(index));
- }
-
- /// Add a `DW_OP_deref` operation to the expression.
- pub fn op_deref(&mut self) {
- self.operations.push(Operation::Deref { space: false });
- }
-
- /// Add a `DW_OP_xderef` operation to the expression.
- pub fn op_xderef(&mut self) {
- self.operations.push(Operation::Deref { space: true });
- }
-
- /// Add a `DW_OP_deref_size` operation to the expression.
- pub fn op_deref_size(&mut self, size: u8) {
- self.operations
- .push(Operation::DerefSize { size, space: false });
- }
-
- /// Add a `DW_OP_xderef_size` operation to the expression.
- pub fn op_xderef_size(&mut self, size: u8) {
- self.operations
- .push(Operation::DerefSize { size, space: true });
- }
-
- /// Add a `DW_OP_deref_type` or `DW_OP_GNU_deref_type` operation to the expression.
- pub fn op_deref_type(&mut self, size: u8, base: UnitEntryId) {
- self.operations.push(Operation::DerefType {
- size,
- base,
- space: false,
- });
- }
-
- /// Add a `DW_OP_xderef_type` operation to the expression.
- pub fn op_xderef_type(&mut self, size: u8, base: UnitEntryId) {
- self.operations.push(Operation::DerefType {
- size,
- base,
- space: true,
- });
- }
-
- /// Add a `DW_OP_plus_uconst` operation to the expression.
- pub fn op_plus_uconst(&mut self, value: u64) {
- self.operations.push(Operation::PlusConstant(value));
- }
-
- /// Add a `DW_OP_skip` operation to the expression.
- ///
- /// Returns the index of the operation. The caller must call `set_target` with
- /// this index to set the target of the branch.
- pub fn op_skip(&mut self) -> usize {
- let index = self.next_index();
- self.operations.push(Operation::Skip(!0));
- index
- }
-
- /// Add a `DW_OP_bra` operation to the expression.
- ///
- /// Returns the index of the operation. The caller must call `set_target` with
- /// this index to set the target of the branch.
- pub fn op_bra(&mut self) -> usize {
- let index = self.next_index();
- self.operations.push(Operation::Branch(!0));
- index
- }
-
- /// Return the index that will be assigned to the next operation.
- ///
- /// This can be passed to `set_target`.
- #[inline]
- pub fn next_index(&self) -> usize {
- self.operations.len()
- }
-
- /// Set the target of a `DW_OP_skip` or `DW_OP_bra` operation .
- pub fn set_target(&mut self, operation: usize, new_target: usize) {
- debug_assert!(new_target <= self.next_index());
- debug_assert_ne!(operation, new_target);
- match self.operations[operation] {
- Operation::Skip(ref mut target) | Operation::Branch(ref mut target) => {
- *target = new_target;
- }
- _ => unimplemented!(),
- }
- }
-
- /// Add a `DW_OP_call4` operation to the expression.
- pub fn op_call(&mut self, entry: UnitEntryId) {
- self.operations.push(Operation::Call(entry));
- }
-
- /// Add a `DW_OP_call_ref` operation to the expression.
- pub fn op_call_ref(&mut self, entry: Reference) {
- self.operations.push(Operation::CallRef(entry));
- }
-
- /// Add a `DW_OP_convert` or `DW_OP_GNU_convert` operation to the expression.
- ///
- /// `base` is the DIE of the base type, or `None` for the generic type.
- pub fn op_convert(&mut self, base: Option<UnitEntryId>) {
- self.operations.push(Operation::Convert(base));
- }
-
- /// Add a `DW_OP_reinterpret` or `DW_OP_GNU_reinterpret` operation to the expression.
- ///
- /// `base` is the DIE of the base type, or `None` for the generic type.
- pub fn op_reinterpret(&mut self, base: Option<UnitEntryId>) {
- self.operations.push(Operation::Reinterpret(base));
- }
-
- /// Add a `DW_OP_entry_value` or `DW_OP_GNU_entry_value` operation to the expression.
- pub fn op_entry_value(&mut self, expression: Expression) {
- self.operations.push(Operation::EntryValue(expression));
- }
-
- /// Add a `DW_OP_regx` operation to the expression.
- ///
- /// This may be emitted as a smaller equivalent operation.
- pub fn op_reg(&mut self, register: Register) {
- self.operations.push(Operation::Register(register));
- }
-
- /// Add a `DW_OP_implicit_value` operation to the expression.
- pub fn op_implicit_value(&mut self, data: Box<[u8]>) {
- self.operations.push(Operation::ImplicitValue(data));
- }
-
- /// Add a `DW_OP_implicit_pointer` or `DW_OP_GNU_implicit_pointer` operation to the expression.
- pub fn op_implicit_pointer(&mut self, entry: Reference, byte_offset: i64) {
- self.operations
- .push(Operation::ImplicitPointer { entry, byte_offset });
- }
-
- /// Add a `DW_OP_piece` operation to the expression.
- pub fn op_piece(&mut self, size_in_bytes: u64) {
- self.operations.push(Operation::Piece { size_in_bytes });
- }
-
- /// Add a `DW_OP_bit_piece` operation to the expression.
- pub fn op_bit_piece(&mut self, size_in_bits: u64, bit_offset: u64) {
- self.operations.push(Operation::BitPiece {
- size_in_bits,
- bit_offset,
- });
- }
-
- /// Add a `DW_OP_GNU_parameter_ref` operation to the expression.
- pub fn op_gnu_parameter_ref(&mut self, entry: UnitEntryId) {
- self.operations.push(Operation::ParameterRef(entry));
- }
-
- /// Add a `DW_OP_WASM_location 0x0` operation to the expression.
- pub fn op_wasm_local(&mut self, index: u32) {
- self.operations.push(Operation::WasmLocal(index));
- }
-
- /// Add a `DW_OP_WASM_location 0x1` operation to the expression.
- pub fn op_wasm_global(&mut self, index: u32) {
- self.operations.push(Operation::WasmGlobal(index));
- }
-
- /// Add a `DW_OP_WASM_location 0x2` operation to the expression.
- pub fn op_wasm_stack(&mut self, index: u32) {
- self.operations.push(Operation::WasmStack(index));
- }
-
- pub(crate) fn size(&self, encoding: Encoding, unit_offsets: Option<&UnitOffsets>) -> usize {
- let mut size = 0;
- for operation in &self.operations {
- size += operation.size(encoding, unit_offsets);
- }
- size
- }
-
- pub(crate) fn write<W: Writer>(
- &self,
- w: &mut W,
- mut refs: Option<&mut Vec<DebugInfoReference>>,
- encoding: Encoding,
- unit_offsets: Option<&UnitOffsets>,
- ) -> Result<()> {
- // TODO: only calculate offsets if needed?
- let mut offsets = Vec::with_capacity(self.operations.len());
- let mut offset = w.len();
- for operation in &self.operations {
- offsets.push(offset);
- offset += operation.size(encoding, unit_offsets);
- }
- offsets.push(offset);
- for (operation, offset) in self.operations.iter().zip(offsets.iter().copied()) {
- debug_assert_eq!(w.len(), offset);
- operation.write(w, refs.as_deref_mut(), encoding, unit_offsets, &offsets)?;
- }
- Ok(())
- }
-}
-
-/// A single DWARF operation.
-//
-// This type is intentionally not public so that we can change the
-// representation of expressions as needed.
-//
-// Variants are listed in the order they appear in Section 2.5.
-#[derive(Debug, Clone, PartialEq, Eq, Hash)]
-enum Operation {
- /// Raw bytecode.
- ///
- /// Does not support references.
- Raw(Vec<u8>),
- /// An operation that has no explicit operands.
- ///
- /// Represents:
- /// - `DW_OP_drop`, `DW_OP_swap`, `DW_OP_rot`
- /// - `DW_OP_push_object_address`, `DW_OP_form_tls_address`, `DW_OP_call_frame_cfa`
- /// - `DW_OP_abs`, `DW_OP_and`, `DW_OP_div`, `DW_OP_minus`, `DW_OP_mod`, `DW_OP_mul`,
- /// `DW_OP_neg`, `DW_OP_not`, `DW_OP_or`, `DW_OP_plus`, `DW_OP_shl`, `DW_OP_shr`,
- /// `DW_OP_shra`, `DW_OP_xor`
- /// - `DW_OP_le`, `DW_OP_ge`, `DW_OP_eq`, `DW_OP_lt`, `DW_OP_gt`, `DW_OP_ne`
- /// - `DW_OP_nop`
- /// - `DW_OP_stack_value`
- Simple(DwOp),
- /// Relocate the address if needed, and push it on the stack.
- ///
- /// Represents `DW_OP_addr`.
- Address(Address),
- /// Push an unsigned constant value on the stack.
- ///
- /// Represents `DW_OP_constu`.
- UnsignedConstant(u64),
- /// Push a signed constant value on the stack.
- ///
- /// Represents `DW_OP_consts`.
- SignedConstant(i64),
- /* TODO: requires .debug_addr write support
- /// Read the address at the given index in `.debug_addr, relocate the address if needed,
- /// and push it on the stack.
- ///
- /// Represents `DW_OP_addrx`.
- AddressIndex(DebugAddrIndex<Offset>),
- /// Read the address at the given index in `.debug_addr, and push it on the stack.
- /// Do not relocate the address.
- ///
- /// Represents `DW_OP_constx`.
- ConstantIndex(DebugAddrIndex<Offset>),
- */
- /// Interpret the value bytes as a constant of a given type, and push it on the stack.
- ///
- /// Represents `DW_OP_const_type`.
- ConstantType(UnitEntryId, Box<[u8]>),
- /// Compute the frame base (using `DW_AT_frame_base`), add the
- /// given offset, and then push the resulting sum on the stack.
- ///
- /// Represents `DW_OP_fbreg`.
- FrameOffset(i64),
- /// Find the contents of the given register, add the offset, and then
- /// push the resulting sum on the stack.
- ///
- /// Represents `DW_OP_bregx`.
- RegisterOffset(Register, i64),
- /// Interpret the contents of the given register as a value of the given type,
- /// and push it on the stack.
- ///
- /// Represents `DW_OP_regval_type`.
- RegisterType(Register, UnitEntryId),
- /// Copy the item at a stack index and push it on top of the stack.
- ///
- /// Represents `DW_OP_pick`, `DW_OP_dup`, and `DW_OP_over`.
- Pick(u8),
- /// Pop the topmost value of the stack, dereference it, and push the
- /// resulting value.
- ///
- /// Represents `DW_OP_deref` and `DW_OP_xderef`.
- Deref {
- /// True if the dereference operation takes an address space
- /// argument from the stack; false otherwise.
- space: bool,
- },
- /// Pop the topmost value of the stack, dereference it to obtain a value
- /// of the given size, and push the resulting value.
- ///
- /// Represents `DW_OP_deref_size` and `DW_OP_xderef_size`.
- DerefSize {
- /// True if the dereference operation takes an address space
- /// argument from the stack; false otherwise.
- space: bool,
- /// The size of the data to dereference.
- size: u8,
- },
- /// Pop the topmost value of the stack, dereference it to obtain a value
- /// of the given type, and push the resulting value.
- ///
- /// Represents `DW_OP_deref_type` and `DW_OP_xderef_type`.
- DerefType {
- /// True if the dereference operation takes an address space
- /// argument from the stack; false otherwise.
- space: bool,
- /// The size of the data to dereference.
- size: u8,
- /// The DIE of the base type, or `None` for the generic type.
- base: UnitEntryId,
- },
- /// Add an unsigned constant to the topmost value on the stack.
- ///
- /// Represents `DW_OP_plus_uconst`.
- PlusConstant(u64),
- /// Unconditional branch to the target location.
- ///
- /// The value is the index within the expression of the operation to branch to.
- /// This will be converted to a relative offset when writing.
- ///
- /// Represents `DW_OP_skip`.
- Skip(usize),
- /// Branch to the target location if the top of stack is nonzero.
- ///
- /// The value is the index within the expression of the operation to branch to.
- /// This will be converted to a relative offset when writing.
- ///
- /// Represents `DW_OP_bra`.
- Branch(usize),
- /// Evaluate a DWARF expression as a subroutine.
- ///
- /// The expression comes from the `DW_AT_location` attribute of the indicated DIE.
- ///
- /// Represents `DW_OP_call4`.
- Call(UnitEntryId),
- /// Evaluate an external DWARF expression as a subroutine.
- ///
- /// The expression comes from the `DW_AT_location` attribute of the indicated DIE,
- /// which may be in another compilation unit or shared object.
- ///
- /// Represents `DW_OP_call_ref`.
- CallRef(Reference),
- /// Pop the top stack entry, convert it to a different type, and push it on the stack.
- ///
- /// Represents `DW_OP_convert`.
- Convert(Option<UnitEntryId>),
- /// Pop the top stack entry, reinterpret the bits in its value as a different type,
- /// and push it on the stack.
- ///
- /// Represents `DW_OP_reinterpret`.
- Reinterpret(Option<UnitEntryId>),
- /// Evaluate an expression at the entry to the current subprogram, and push it on the stack.
- ///
- /// Represents `DW_OP_entry_value`.
- EntryValue(Expression),
- // FIXME: EntryRegister
- /// Indicate that this piece's location is in the given register.
- ///
- /// Completes the piece or expression.
- ///
- /// Represents `DW_OP_regx`.
- Register(Register),
- /// The object has no location, but has a known constant value.
- ///
- /// Completes the piece or expression.
- ///
- /// Represents `DW_OP_implicit_value`.
- ImplicitValue(Box<[u8]>),
- /// The object is a pointer to a value which has no actual location, such as
- /// an implicit value or a stack value.
- ///
- /// Completes the piece or expression.
- ///
- /// Represents `DW_OP_implicit_pointer`.
- ImplicitPointer {
- /// The DIE of the value that this is an implicit pointer into.
- entry: Reference,
- /// The byte offset into the value that the implicit pointer points to.
- byte_offset: i64,
- },
- /// Terminate a piece.
- ///
- /// Represents `DW_OP_piece`.
- Piece {
- /// The size of this piece in bytes.
- size_in_bytes: u64,
- },
- /// Terminate a piece with a size in bits.
- ///
- /// Represents `DW_OP_bit_piece`.
- BitPiece {
- /// The size of this piece in bits.
- size_in_bits: u64,
- /// The bit offset of this piece.
- bit_offset: u64,
- },
- /// This represents a parameter that was optimized out.
- ///
- /// The entry is the definition of the parameter, and is matched to
- /// the `DW_TAG_GNU_call_site_parameter` in the caller that also
- /// points to the same definition of the parameter.
- ///
- /// Represents `DW_OP_GNU_parameter_ref`.
- ParameterRef(UnitEntryId),
- /// The index of a local in the currently executing function.
- ///
- /// Represents `DW_OP_WASM_location 0x00`.
- WasmLocal(u32),
- /// The index of a global.
- ///
- /// Represents `DW_OP_WASM_location 0x01`.
- WasmGlobal(u32),
- /// The index of an item on the operand stack.
- ///
- /// Represents `DW_OP_WASM_location 0x02`.
- WasmStack(u32),
-}
-
-impl Operation {
- fn size(&self, encoding: Encoding, unit_offsets: Option<&UnitOffsets>) -> usize {
- let base_size = |base| {
- // Errors are handled during writes.
- match unit_offsets {
- Some(offsets) => uleb128_size(offsets.unit_offset(base)),
- None => 0,
- }
- };
- 1 + match *self {
- Operation::Raw(ref bytecode) => return bytecode.len(),
- Operation::Simple(_) => 0,
- Operation::Address(_) => encoding.address_size as usize,
- Operation::UnsignedConstant(value) => {
- if value < 32 {
- 0
- } else {
- uleb128_size(value)
- }
- }
- Operation::SignedConstant(value) => sleb128_size(value),
- Operation::ConstantType(base, ref value) => base_size(base) + 1 + value.len(),
- Operation::FrameOffset(offset) => sleb128_size(offset),
- Operation::RegisterOffset(register, offset) => {
- if register.0 < 32 {
- sleb128_size(offset)
- } else {
- uleb128_size(register.0.into()) + sleb128_size(offset)
- }
- }
- Operation::RegisterType(register, base) => {
- uleb128_size(register.0.into()) + base_size(base)
- }
- Operation::Pick(index) => {
- if index > 1 {
- 1
- } else {
- 0
- }
- }
- Operation::Deref { .. } => 0,
- Operation::DerefSize { .. } => 1,
- Operation::DerefType { base, .. } => 1 + base_size(base),
- Operation::PlusConstant(value) => uleb128_size(value),
- Operation::Skip(_) => 2,
- Operation::Branch(_) => 2,
- Operation::Call(_) => 4,
- Operation::CallRef(_) => encoding.format.word_size() as usize,
- Operation::Convert(base) => match base {
- Some(base) => base_size(base),
- None => 1,
- },
- Operation::Reinterpret(base) => match base {
- Some(base) => base_size(base),
- None => 1,
- },
- Operation::EntryValue(ref expression) => {
- let length = expression.size(encoding, unit_offsets);
- uleb128_size(length as u64) + length
- }
- Operation::Register(register) => {
- if register.0 < 32 {
- 0
- } else {
- uleb128_size(register.0.into())
- }
- }
- Operation::ImplicitValue(ref data) => uleb128_size(data.len() as u64) + data.len(),
- Operation::ImplicitPointer { byte_offset, .. } => {
- encoding.format.word_size() as usize + sleb128_size(byte_offset)
- }
- Operation::Piece { size_in_bytes } => uleb128_size(size_in_bytes),
- Operation::BitPiece {
- size_in_bits,
- bit_offset,
- } => uleb128_size(size_in_bits) + uleb128_size(bit_offset),
- Operation::ParameterRef(_) => 4,
- Operation::WasmLocal(index)
- | Operation::WasmGlobal(index)
- | Operation::WasmStack(index) => 1 + uleb128_size(index.into()),
- }
- }
-
- pub(crate) fn write<W: Writer>(
- &self,
- w: &mut W,
- refs: Option<&mut Vec<DebugInfoReference>>,
- encoding: Encoding,
- unit_offsets: Option<&UnitOffsets>,
- offsets: &[usize],
- ) -> Result<()> {
- let entry_offset = |entry| match unit_offsets {
- Some(offsets) => {
- let offset = offsets.unit_offset(entry);
- if offset == 0 {
- Err(Error::UnsupportedExpressionForwardReference)
- } else {
- Ok(offset)
- }
- }
- None => Err(Error::UnsupportedCfiExpressionReference),
- };
- match *self {
- Operation::Raw(ref bytecode) => w.write(bytecode)?,
- Operation::Simple(opcode) => w.write_u8(opcode.0)?,
- Operation::Address(address) => {
- w.write_u8(constants::DW_OP_addr.0)?;
- w.write_address(address, encoding.address_size)?;
- }
- Operation::UnsignedConstant(value) => {
- if value < 32 {
- w.write_u8(constants::DW_OP_lit0.0 + value as u8)?;
- } else {
- w.write_u8(constants::DW_OP_constu.0)?;
- w.write_uleb128(value)?;
- }
- }
- Operation::SignedConstant(value) => {
- w.write_u8(constants::DW_OP_consts.0)?;
- w.write_sleb128(value)?;
- }
- Operation::ConstantType(base, ref value) => {
- if encoding.version >= 5 {
- w.write_u8(constants::DW_OP_const_type.0)?;
- } else {
- w.write_u8(constants::DW_OP_GNU_const_type.0)?;
- }
- w.write_uleb128(entry_offset(base)?)?;
- w.write_udata(value.len() as u64, 1)?;
- w.write(value)?;
- }
- Operation::FrameOffset(offset) => {
- w.write_u8(constants::DW_OP_fbreg.0)?;
- w.write_sleb128(offset)?;
- }
- Operation::RegisterOffset(register, offset) => {
- if register.0 < 32 {
- w.write_u8(constants::DW_OP_breg0.0 + register.0 as u8)?;
- } else {
- w.write_u8(constants::DW_OP_bregx.0)?;
- w.write_uleb128(register.0.into())?;
- }
- w.write_sleb128(offset)?;
- }
- Operation::RegisterType(register, base) => {
- if encoding.version >= 5 {
- w.write_u8(constants::DW_OP_regval_type.0)?;
- } else {
- w.write_u8(constants::DW_OP_GNU_regval_type.0)?;
- }
- w.write_uleb128(register.0.into())?;
- w.write_uleb128(entry_offset(base)?)?;
- }
- Operation::Pick(index) => match index {
- 0 => w.write_u8(constants::DW_OP_dup.0)?,
- 1 => w.write_u8(constants::DW_OP_over.0)?,
- _ => {
- w.write_u8(constants::DW_OP_pick.0)?;
- w.write_u8(index)?;
- }
- },
- Operation::Deref { space } => {
- if space {
- w.write_u8(constants::DW_OP_xderef.0)?;
- } else {
- w.write_u8(constants::DW_OP_deref.0)?;
- }
- }
- Operation::DerefSize { space, size } => {
- if space {
- w.write_u8(constants::DW_OP_xderef_size.0)?;
- } else {
- w.write_u8(constants::DW_OP_deref_size.0)?;
- }
- w.write_u8(size)?;
- }
- Operation::DerefType { space, size, base } => {
- if space {
- w.write_u8(constants::DW_OP_xderef_type.0)?;
- } else {
- if encoding.version >= 5 {
- w.write_u8(constants::DW_OP_deref_type.0)?;
- } else {
- w.write_u8(constants::DW_OP_GNU_deref_type.0)?;
- }
- }
- w.write_u8(size)?;
- w.write_uleb128(entry_offset(base)?)?;
- }
- Operation::PlusConstant(value) => {
- w.write_u8(constants::DW_OP_plus_uconst.0)?;
- w.write_uleb128(value)?;
- }
- Operation::Skip(target) => {
- w.write_u8(constants::DW_OP_skip.0)?;
- let offset = offsets[target] as i64 - (w.len() as i64 + 2);
- w.write_sdata(offset, 2)?;
- }
- Operation::Branch(target) => {
- w.write_u8(constants::DW_OP_bra.0)?;
- let offset = offsets[target] as i64 - (w.len() as i64 + 2);
- w.write_sdata(offset, 2)?;
- }
- Operation::Call(entry) => {
- w.write_u8(constants::DW_OP_call4.0)?;
- // TODO: this probably won't work in practice, because we may
- // only know the offsets of base type DIEs at this point.
- w.write_udata(entry_offset(entry)?, 4)?;
- }
- Operation::CallRef(entry) => {
- w.write_u8(constants::DW_OP_call_ref.0)?;
- let size = encoding.format.word_size();
- match entry {
- Reference::Symbol(symbol) => w.write_reference(symbol, size)?,
- Reference::Entry(unit, entry) => {
- let refs = refs.ok_or(Error::InvalidReference)?;
- refs.push(DebugInfoReference {
- offset: w.len(),
- unit,
- entry,
- size,
- });
- w.write_udata(0, size)?;
- }
- }
- }
- Operation::Convert(base) => {
- if encoding.version >= 5 {
- w.write_u8(constants::DW_OP_convert.0)?;
- } else {
- w.write_u8(constants::DW_OP_GNU_convert.0)?;
- }
- match base {
- Some(base) => w.write_uleb128(entry_offset(base)?)?,
- None => w.write_u8(0)?,
- }
- }
- Operation::Reinterpret(base) => {
- if encoding.version >= 5 {
- w.write_u8(constants::DW_OP_reinterpret.0)?;
- } else {
- w.write_u8(constants::DW_OP_GNU_reinterpret.0)?;
- }
- match base {
- Some(base) => w.write_uleb128(entry_offset(base)?)?,
- None => w.write_u8(0)?,
- }
- }
- Operation::EntryValue(ref expression) => {
- if encoding.version >= 5 {
- w.write_u8(constants::DW_OP_entry_value.0)?;
- } else {
- w.write_u8(constants::DW_OP_GNU_entry_value.0)?;
- }
- let length = expression.size(encoding, unit_offsets);
- w.write_uleb128(length as u64)?;
- expression.write(w, refs, encoding, unit_offsets)?;
- }
- Operation::Register(register) => {
- if register.0 < 32 {
- w.write_u8(constants::DW_OP_reg0.0 + register.0 as u8)?;
- } else {
- w.write_u8(constants::DW_OP_regx.0)?;
- w.write_uleb128(register.0.into())?;
- }
- }
- Operation::ImplicitValue(ref data) => {
- w.write_u8(constants::DW_OP_implicit_value.0)?;
- w.write_uleb128(data.len() as u64)?;
- w.write(data)?;
- }
- Operation::ImplicitPointer { entry, byte_offset } => {
- if encoding.version >= 5 {
- w.write_u8(constants::DW_OP_implicit_pointer.0)?;
- } else {
- w.write_u8(constants::DW_OP_GNU_implicit_pointer.0)?;
- }
- let size = if encoding.version == 2 {
- encoding.address_size
- } else {
- encoding.format.word_size()
- };
- match entry {
- Reference::Symbol(symbol) => {
- w.write_reference(symbol, size)?;
- }
- Reference::Entry(unit, entry) => {
- let refs = refs.ok_or(Error::InvalidReference)?;
- refs.push(DebugInfoReference {
- offset: w.len(),
- unit,
- entry,
- size,
- });
- w.write_udata(0, size)?;
- }
- }
- w.write_sleb128(byte_offset)?;
- }
- Operation::Piece { size_in_bytes } => {
- w.write_u8(constants::DW_OP_piece.0)?;
- w.write_uleb128(size_in_bytes)?;
- }
- Operation::BitPiece {
- size_in_bits,
- bit_offset,
- } => {
- w.write_u8(constants::DW_OP_bit_piece.0)?;
- w.write_uleb128(size_in_bits)?;
- w.write_uleb128(bit_offset)?;
- }
- Operation::ParameterRef(entry) => {
- w.write_u8(constants::DW_OP_GNU_parameter_ref.0)?;
- w.write_udata(entry_offset(entry)?, 4)?;
- }
- Operation::WasmLocal(index) => {
- w.write(&[constants::DW_OP_WASM_location.0, 0])?;
- w.write_uleb128(index.into())?;
- }
- Operation::WasmGlobal(index) => {
- w.write(&[constants::DW_OP_WASM_location.0, 1])?;
- w.write_uleb128(index.into())?;
- }
- Operation::WasmStack(index) => {
- w.write(&[constants::DW_OP_WASM_location.0, 2])?;
- w.write_uleb128(index.into())?;
- }
- }
- Ok(())
- }
-}
-
-#[cfg(feature = "read")]
-pub(crate) mod convert {
- use super::*;
- use crate::common::UnitSectionOffset;
- use crate::read::{self, Reader};
- use crate::write::{ConvertError, ConvertResult, UnitEntryId, UnitId};
- use std::collections::HashMap;
-
- impl Expression {
- /// Create an expression from the input expression.
- pub fn from<R: Reader<Offset = usize>>(
- from_expression: read::Expression<R>,
- encoding: Encoding,
- dwarf: Option<&read::Dwarf<R>>,
- unit: Option<&read::Unit<R>>,
- entry_ids: Option<&HashMap<UnitSectionOffset, (UnitId, UnitEntryId)>>,
- convert_address: &dyn Fn(u64) -> Option<Address>,
- ) -> ConvertResult<Expression> {
- let convert_unit_offset = |offset: read::UnitOffset| -> ConvertResult<_> {
- let entry_ids = entry_ids.ok_or(ConvertError::UnsupportedOperation)?;
- let unit = unit.ok_or(ConvertError::UnsupportedOperation)?;
- let id = entry_ids
- .get(&offset.to_unit_section_offset(unit))
- .ok_or(ConvertError::InvalidUnitRef)?;
- Ok(id.1)
- };
- let convert_debug_info_offset = |offset| -> ConvertResult<_> {
- // TODO: support relocations
- let entry_ids = entry_ids.ok_or(ConvertError::UnsupportedOperation)?;
- let id = entry_ids
- .get(&UnitSectionOffset::DebugInfoOffset(offset))
- .ok_or(ConvertError::InvalidDebugInfoRef)?;
- Ok(Reference::Entry(id.0, id.1))
- };
-
- // Calculate offsets for use in branch/skip operations.
- let mut offsets = Vec::new();
- let mut offset = 0;
- let mut from_operations = from_expression.clone().operations(encoding);
- while from_operations.next()?.is_some() {
- offsets.push(offset);
- offset = from_operations.offset_from(&from_expression);
- }
- offsets.push(from_expression.0.len());
-
- let mut from_operations = from_expression.clone().operations(encoding);
- let mut operations = Vec::new();
- while let Some(from_operation) = from_operations.next()? {
- let operation = match from_operation {
- read::Operation::Deref {
- base_type,
- size,
- space,
- } => {
- if base_type.0 != 0 {
- let base = convert_unit_offset(base_type)?;
- Operation::DerefType { space, size, base }
- } else if size != encoding.address_size {
- Operation::DerefSize { space, size }
- } else {
- Operation::Deref { space }
- }
- }
- read::Operation::Drop => Operation::Simple(constants::DW_OP_drop),
- read::Operation::Pick { index } => Operation::Pick(index),
- read::Operation::Swap => Operation::Simple(constants::DW_OP_swap),
- read::Operation::Rot => Operation::Simple(constants::DW_OP_rot),
- read::Operation::Abs => Operation::Simple(constants::DW_OP_abs),
- read::Operation::And => Operation::Simple(constants::DW_OP_and),
- read::Operation::Div => Operation::Simple(constants::DW_OP_div),
- read::Operation::Minus => Operation::Simple(constants::DW_OP_minus),
- read::Operation::Mod => Operation::Simple(constants::DW_OP_mod),
- read::Operation::Mul => Operation::Simple(constants::DW_OP_mul),
- read::Operation::Neg => Operation::Simple(constants::DW_OP_neg),
- read::Operation::Not => Operation::Simple(constants::DW_OP_not),
- read::Operation::Or => Operation::Simple(constants::DW_OP_or),
- read::Operation::Plus => Operation::Simple(constants::DW_OP_plus),
- read::Operation::PlusConstant { value } => Operation::PlusConstant(value),
- read::Operation::Shl => Operation::Simple(constants::DW_OP_shl),
- read::Operation::Shr => Operation::Simple(constants::DW_OP_shr),
- read::Operation::Shra => Operation::Simple(constants::DW_OP_shra),
- read::Operation::Xor => Operation::Simple(constants::DW_OP_xor),
- read::Operation::Eq => Operation::Simple(constants::DW_OP_eq),
- read::Operation::Ge => Operation::Simple(constants::DW_OP_ge),
- read::Operation::Gt => Operation::Simple(constants::DW_OP_gt),
- read::Operation::Le => Operation::Simple(constants::DW_OP_le),
- read::Operation::Lt => Operation::Simple(constants::DW_OP_lt),
- read::Operation::Ne => Operation::Simple(constants::DW_OP_ne),
- read::Operation::Bra { target } => {
- let offset = from_operations
- .offset_from(&from_expression)
- .wrapping_add(i64::from(target) as usize);
- let index = offsets
- .binary_search(&offset)
- .map_err(|_| ConvertError::InvalidBranchTarget)?;
- Operation::Branch(index)
- }
- read::Operation::Skip { target } => {
- let offset = from_operations
- .offset_from(&from_expression)
- .wrapping_add(i64::from(target) as usize);
- let index = offsets
- .binary_search(&offset)
- .map_err(|_| ConvertError::InvalidBranchTarget)?;
- Operation::Skip(index)
- }
- read::Operation::UnsignedConstant { value } => {
- Operation::UnsignedConstant(value)
- }
- read::Operation::SignedConstant { value } => Operation::SignedConstant(value),
- read::Operation::Register { register } => Operation::Register(register),
- read::Operation::RegisterOffset {
- register,
- offset,
- base_type,
- } => {
- if base_type.0 != 0 {
- Operation::RegisterType(register, convert_unit_offset(base_type)?)
- } else {
- Operation::RegisterOffset(register, offset)
- }
- }
- read::Operation::FrameOffset { offset } => Operation::FrameOffset(offset),
- read::Operation::Nop => Operation::Simple(constants::DW_OP_nop),
- read::Operation::PushObjectAddress => {
- Operation::Simple(constants::DW_OP_push_object_address)
- }
- read::Operation::Call { offset } => match offset {
- read::DieReference::UnitRef(offset) => {
- Operation::Call(convert_unit_offset(offset)?)
- }
- read::DieReference::DebugInfoRef(offset) => {
- Operation::CallRef(convert_debug_info_offset(offset)?)
- }
- },
- read::Operation::TLS => Operation::Simple(constants::DW_OP_form_tls_address),
- read::Operation::CallFrameCFA => {
- Operation::Simple(constants::DW_OP_call_frame_cfa)
- }
- read::Operation::Piece {
- size_in_bits,
- bit_offset: None,
- } => Operation::Piece {
- size_in_bytes: size_in_bits / 8,
- },
- read::Operation::Piece {
- size_in_bits,
- bit_offset: Some(bit_offset),
- } => Operation::BitPiece {
- size_in_bits,
- bit_offset,
- },
- read::Operation::ImplicitValue { data } => {
- Operation::ImplicitValue(data.to_slice()?.into_owned().into())
- }
- read::Operation::StackValue => Operation::Simple(constants::DW_OP_stack_value),
- read::Operation::ImplicitPointer { value, byte_offset } => {
- let entry = convert_debug_info_offset(value)?;
- Operation::ImplicitPointer { entry, byte_offset }
- }
- read::Operation::EntryValue { expression } => {
- let expression = Expression::from(
- read::Expression(expression),
- encoding,
- dwarf,
- unit,
- entry_ids,
- convert_address,
- )?;
- Operation::EntryValue(expression)
- }
- read::Operation::ParameterRef { offset } => {
- let entry = convert_unit_offset(offset)?;
- Operation::ParameterRef(entry)
- }
- read::Operation::Address { address } => {
- let address =
- convert_address(address).ok_or(ConvertError::InvalidAddress)?;
- Operation::Address(address)
- }
- read::Operation::AddressIndex { index } => {
- let dwarf = dwarf.ok_or(ConvertError::UnsupportedOperation)?;
- let unit = unit.ok_or(ConvertError::UnsupportedOperation)?;
- let val = dwarf.address(unit, index)?;
- let address = convert_address(val).ok_or(ConvertError::InvalidAddress)?;
- Operation::Address(address)
- }
- read::Operation::ConstantIndex { index } => {
- let dwarf = dwarf.ok_or(ConvertError::UnsupportedOperation)?;
- let unit = unit.ok_or(ConvertError::UnsupportedOperation)?;
- let val = dwarf.address(unit, index)?;
- Operation::UnsignedConstant(val)
- }
- read::Operation::TypedLiteral { base_type, value } => {
- let entry = convert_unit_offset(base_type)?;
- Operation::ConstantType(entry, value.to_slice()?.into_owned().into())
- }
- read::Operation::Convert { base_type } => {
- if base_type.0 == 0 {
- Operation::Convert(None)
- } else {
- let entry = convert_unit_offset(base_type)?;
- Operation::Convert(Some(entry))
- }
- }
- read::Operation::Reinterpret { base_type } => {
- if base_type.0 == 0 {
- Operation::Reinterpret(None)
- } else {
- let entry = convert_unit_offset(base_type)?;
- Operation::Reinterpret(Some(entry))
- }
- }
- read::Operation::WasmLocal { index } => Operation::WasmLocal(index),
- read::Operation::WasmGlobal { index } => Operation::WasmGlobal(index),
- read::Operation::WasmStack { index } => Operation::WasmStack(index),
- };
- operations.push(operation);
- }
- Ok(Expression { operations })
- }
- }
-}
-
-#[cfg(test)]
-#[cfg(feature = "read")]
-mod tests {
- use super::*;
- use crate::common::{
- DebugAbbrevOffset, DebugAddrBase, DebugInfoOffset, DebugLocListsBase, DebugRngListsBase,
- DebugStrOffsetsBase, Format, SectionId,
- };
- use crate::read;
- use crate::write::{
- DebugLineStrOffsets, DebugStrOffsets, EndianVec, LineProgram, Sections, Unit, UnitTable,
- };
- use crate::LittleEndian;
- use std::collections::HashMap;
- use std::sync::Arc;
-
- #[test]
- fn test_operation() {
- for &version in &[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 units = UnitTable::default();
- let unit_id = units.add(Unit::new(encoding, LineProgram::none()));
- let unit = units.get_mut(unit_id);
- let entry_id = unit.add(unit.root(), constants::DW_TAG_base_type);
- let reference = Reference::Entry(unit_id, entry_id);
-
- let mut sections = Sections::new(EndianVec::new(LittleEndian));
- let debug_line_str_offsets = DebugLineStrOffsets::none();
- let debug_str_offsets = DebugStrOffsets::none();
- let debug_info_offsets = units
- .write(&mut sections, &debug_line_str_offsets, &debug_str_offsets)
- .unwrap();
- let unit_offsets = debug_info_offsets.unit_offsets(unit_id);
- let debug_info_offset = unit_offsets.debug_info_offset(entry_id);
- let entry_offset =
- read::UnitOffset(unit_offsets.unit_offset(entry_id) as usize);
-
- let mut reg_expression = Expression::new();
- reg_expression.op_reg(Register(23));
-
- let operations: &[(&dyn Fn(&mut Expression), Operation, read::Operation<_>)] =
- &[
- (
- &|x| x.op_deref(),
- Operation::Deref { space: false },
- read::Operation::Deref {
- base_type: read::UnitOffset(0),
- size: address_size,
- space: false,
- },
- ),
- (
- &|x| x.op_xderef(),
- Operation::Deref { space: true },
- read::Operation::Deref {
- base_type: read::UnitOffset(0),
- size: address_size,
- space: true,
- },
- ),
- (
- &|x| x.op_deref_size(2),
- Operation::DerefSize {
- space: false,
- size: 2,
- },
- read::Operation::Deref {
- base_type: read::UnitOffset(0),
- size: 2,
- space: false,
- },
- ),
- (
- &|x| x.op_xderef_size(2),
- Operation::DerefSize {
- space: true,
- size: 2,
- },
- read::Operation::Deref {
- base_type: read::UnitOffset(0),
- size: 2,
- space: true,
- },
- ),
- (
- &|x| x.op_deref_type(2, entry_id),
- Operation::DerefType {
- space: false,
- size: 2,
- base: entry_id,
- },
- read::Operation::Deref {
- base_type: entry_offset,
- size: 2,
- space: false,
- },
- ),
- (
- &|x| x.op_xderef_type(2, entry_id),
- Operation::DerefType {
- space: true,
- size: 2,
- base: entry_id,
- },
- read::Operation::Deref {
- base_type: entry_offset,
- size: 2,
- space: true,
- },
- ),
- (
- &|x| x.op(constants::DW_OP_drop),
- Operation::Simple(constants::DW_OP_drop),
- read::Operation::Drop,
- ),
- (
- &|x| x.op_pick(0),
- Operation::Pick(0),
- read::Operation::Pick { index: 0 },
- ),
- (
- &|x| x.op_pick(1),
- Operation::Pick(1),
- read::Operation::Pick { index: 1 },
- ),
- (
- &|x| x.op_pick(2),
- Operation::Pick(2),
- read::Operation::Pick { index: 2 },
- ),
- (
- &|x| x.op(constants::DW_OP_swap),
- Operation::Simple(constants::DW_OP_swap),
- read::Operation::Swap,
- ),
- (
- &|x| x.op(constants::DW_OP_rot),
- Operation::Simple(constants::DW_OP_rot),
- read::Operation::Rot,
- ),
- (
- &|x| x.op(constants::DW_OP_abs),
- Operation::Simple(constants::DW_OP_abs),
- read::Operation::Abs,
- ),
- (
- &|x| x.op(constants::DW_OP_and),
- Operation::Simple(constants::DW_OP_and),
- read::Operation::And,
- ),
- (
- &|x| x.op(constants::DW_OP_div),
- Operation::Simple(constants::DW_OP_div),
- read::Operation::Div,
- ),
- (
- &|x| x.op(constants::DW_OP_minus),
- Operation::Simple(constants::DW_OP_minus),
- read::Operation::Minus,
- ),
- (
- &|x| x.op(constants::DW_OP_mod),
- Operation::Simple(constants::DW_OP_mod),
- read::Operation::Mod,
- ),
- (
- &|x| x.op(constants::DW_OP_mul),
- Operation::Simple(constants::DW_OP_mul),
- read::Operation::Mul,
- ),
- (
- &|x| x.op(constants::DW_OP_neg),
- Operation::Simple(constants::DW_OP_neg),
- read::Operation::Neg,
- ),
- (
- &|x| x.op(constants::DW_OP_not),
- Operation::Simple(constants::DW_OP_not),
- read::Operation::Not,
- ),
- (
- &|x| x.op(constants::DW_OP_or),
- Operation::Simple(constants::DW_OP_or),
- read::Operation::Or,
- ),
- (
- &|x| x.op(constants::DW_OP_plus),
- Operation::Simple(constants::DW_OP_plus),
- read::Operation::Plus,
- ),
- (
- &|x| x.op_plus_uconst(23),
- Operation::PlusConstant(23),
- read::Operation::PlusConstant { value: 23 },
- ),
- (
- &|x| x.op(constants::DW_OP_shl),
- Operation::Simple(constants::DW_OP_shl),
- read::Operation::Shl,
- ),
- (
- &|x| x.op(constants::DW_OP_shr),
- Operation::Simple(constants::DW_OP_shr),
- read::Operation::Shr,
- ),
- (
- &|x| x.op(constants::DW_OP_shra),
- Operation::Simple(constants::DW_OP_shra),
- read::Operation::Shra,
- ),
- (
- &|x| x.op(constants::DW_OP_xor),
- Operation::Simple(constants::DW_OP_xor),
- read::Operation::Xor,
- ),
- (
- &|x| x.op(constants::DW_OP_eq),
- Operation::Simple(constants::DW_OP_eq),
- read::Operation::Eq,
- ),
- (
- &|x| x.op(constants::DW_OP_ge),
- Operation::Simple(constants::DW_OP_ge),
- read::Operation::Ge,
- ),
- (
- &|x| x.op(constants::DW_OP_gt),
- Operation::Simple(constants::DW_OP_gt),
- read::Operation::Gt,
- ),
- (
- &|x| x.op(constants::DW_OP_le),
- Operation::Simple(constants::DW_OP_le),
- read::Operation::Le,
- ),
- (
- &|x| x.op(constants::DW_OP_lt),
- Operation::Simple(constants::DW_OP_lt),
- read::Operation::Lt,
- ),
- (
- &|x| x.op(constants::DW_OP_ne),
- Operation::Simple(constants::DW_OP_ne),
- read::Operation::Ne,
- ),
- (
- &|x| x.op_constu(23),
- Operation::UnsignedConstant(23),
- read::Operation::UnsignedConstant { value: 23 },
- ),
- (
- &|x| x.op_consts(-23),
- Operation::SignedConstant(-23),
- read::Operation::SignedConstant { value: -23 },
- ),
- (
- &|x| x.op_reg(Register(23)),
- Operation::Register(Register(23)),
- read::Operation::Register {
- register: Register(23),
- },
- ),
- (
- &|x| x.op_reg(Register(123)),
- Operation::Register(Register(123)),
- read::Operation::Register {
- register: Register(123),
- },
- ),
- (
- &|x| x.op_breg(Register(23), 34),
- Operation::RegisterOffset(Register(23), 34),
- read::Operation::RegisterOffset {
- register: Register(23),
- offset: 34,
- base_type: read::UnitOffset(0),
- },
- ),
- (
- &|x| x.op_breg(Register(123), 34),
- Operation::RegisterOffset(Register(123), 34),
- read::Operation::RegisterOffset {
- register: Register(123),
- offset: 34,
- base_type: read::UnitOffset(0),
- },
- ),
- (
- &|x| x.op_regval_type(Register(23), entry_id),
- Operation::RegisterType(Register(23), entry_id),
- read::Operation::RegisterOffset {
- register: Register(23),
- offset: 0,
- base_type: entry_offset,
- },
- ),
- (
- &|x| x.op_fbreg(34),
- Operation::FrameOffset(34),
- read::Operation::FrameOffset { offset: 34 },
- ),
- (
- &|x| x.op(constants::DW_OP_nop),
- Operation::Simple(constants::DW_OP_nop),
- read::Operation::Nop,
- ),
- (
- &|x| x.op(constants::DW_OP_push_object_address),
- Operation::Simple(constants::DW_OP_push_object_address),
- read::Operation::PushObjectAddress,
- ),
- (
- &|x| x.op_call(entry_id),
- Operation::Call(entry_id),
- read::Operation::Call {
- offset: read::DieReference::UnitRef(entry_offset),
- },
- ),
- (
- &|x| x.op_call_ref(reference),
- Operation::CallRef(reference),
- read::Operation::Call {
- offset: read::DieReference::DebugInfoRef(debug_info_offset),
- },
- ),
- (
- &|x| x.op(constants::DW_OP_form_tls_address),
- Operation::Simple(constants::DW_OP_form_tls_address),
- read::Operation::TLS,
- ),
- (
- &|x| x.op(constants::DW_OP_call_frame_cfa),
- Operation::Simple(constants::DW_OP_call_frame_cfa),
- read::Operation::CallFrameCFA,
- ),
- (
- &|x| x.op_piece(23),
- Operation::Piece { size_in_bytes: 23 },
- read::Operation::Piece {
- size_in_bits: 23 * 8,
- bit_offset: None,
- },
- ),
- (
- &|x| x.op_bit_piece(23, 34),
- Operation::BitPiece {
- size_in_bits: 23,
- bit_offset: 34,
- },
- read::Operation::Piece {
- size_in_bits: 23,
- bit_offset: Some(34),
- },
- ),
- (
- &|x| x.op_implicit_value(vec![23].into()),
- Operation::ImplicitValue(vec![23].into()),
- read::Operation::ImplicitValue {
- data: read::EndianSlice::new(&[23], LittleEndian),
- },
- ),
- (
- &|x| x.op(constants::DW_OP_stack_value),
- Operation::Simple(constants::DW_OP_stack_value),
- read::Operation::StackValue,
- ),
- (
- &|x| x.op_implicit_pointer(reference, 23),
- Operation::ImplicitPointer {
- entry: reference,
- byte_offset: 23,
- },
- read::Operation::ImplicitPointer {
- value: debug_info_offset,
- byte_offset: 23,
- },
- ),
- (
- &|x| x.op_entry_value(reg_expression.clone()),
- Operation::EntryValue(reg_expression.clone()),
- read::Operation::EntryValue {
- expression: read::EndianSlice::new(
- &[constants::DW_OP_reg23.0],
- LittleEndian,
- ),
- },
- ),
- (
- &|x| x.op_gnu_parameter_ref(entry_id),
- Operation::ParameterRef(entry_id),
- read::Operation::ParameterRef {
- offset: entry_offset,
- },
- ),
- (
- &|x| x.op_addr(Address::Constant(23)),
- Operation::Address(Address::Constant(23)),
- read::Operation::Address { address: 23 },
- ),
- (
- &|x| x.op_const_type(entry_id, vec![23].into()),
- Operation::ConstantType(entry_id, vec![23].into()),
- read::Operation::TypedLiteral {
- base_type: entry_offset,
- value: read::EndianSlice::new(&[23], LittleEndian),
- },
- ),
- (
- &|x| x.op_convert(None),
- Operation::Convert(None),
- read::Operation::Convert {
- base_type: read::UnitOffset(0),
- },
- ),
- (
- &|x| x.op_convert(Some(entry_id)),
- Operation::Convert(Some(entry_id)),
- read::Operation::Convert {
- base_type: entry_offset,
- },
- ),
- (
- &|x| x.op_reinterpret(None),
- Operation::Reinterpret(None),
- read::Operation::Reinterpret {
- base_type: read::UnitOffset(0),
- },
- ),
- (
- &|x| x.op_reinterpret(Some(entry_id)),
- Operation::Reinterpret(Some(entry_id)),
- read::Operation::Reinterpret {
- base_type: entry_offset,
- },
- ),
- (
- &|x| x.op_wasm_local(1000),
- Operation::WasmLocal(1000),
- read::Operation::WasmLocal { index: 1000 },
- ),
- (
- &|x| x.op_wasm_global(1000),
- Operation::WasmGlobal(1000),
- read::Operation::WasmGlobal { index: 1000 },
- ),
- (
- &|x| x.op_wasm_stack(1000),
- Operation::WasmStack(1000),
- read::Operation::WasmStack { index: 1000 },
- ),
- ];
-
- let mut expression = Expression::new();
- let start_index = expression.next_index();
- for (f, o, _) in operations {
- f(&mut expression);
- assert_eq!(expression.operations.last(), Some(o));
- }
-
- let bra_index = expression.op_bra();
- let skip_index = expression.op_skip();
- expression.op(constants::DW_OP_nop);
- let end_index = expression.next_index();
- expression.set_target(bra_index, start_index);
- expression.set_target(skip_index, end_index);
-
- let mut w = EndianVec::new(LittleEndian);
- let mut refs = Vec::new();
- expression
- .write(&mut w, Some(&mut refs), encoding, Some(&unit_offsets))
- .unwrap();
- for r in &refs {
- assert_eq!(r.unit, unit_id);
- assert_eq!(r.entry, entry_id);
- w.write_offset_at(
- r.offset,
- debug_info_offset.0,
- SectionId::DebugInfo,
- r.size,
- )
- .unwrap();
- }
-
- let read_expression =
- read::Expression(read::EndianSlice::new(w.slice(), LittleEndian));
- let mut read_operations = read_expression.operations(encoding);
- for (_, _, operation) in operations {
- assert_eq!(read_operations.next(), Ok(Some(*operation)));
- }
-
- // 4 = DW_OP_skip + i16 + DW_OP_nop
- assert_eq!(
- read_operations.next(),
- Ok(Some(read::Operation::Bra {
- target: -(w.len() as i16) + 4
- }))
- );
- // 1 = DW_OP_nop
- assert_eq!(
- read_operations.next(),
- Ok(Some(read::Operation::Skip { target: 1 }))
- );
- assert_eq!(read_operations.next(), Ok(Some(read::Operation::Nop)));
- assert_eq!(read_operations.next(), Ok(None));
-
- // Fake the unit.
- let unit = read::Unit {
- header: read::UnitHeader::new(
- encoding,
- 0,
- read::UnitType::Compilation,
- DebugAbbrevOffset(0),
- DebugInfoOffset(0).into(),
- read::EndianSlice::new(&[], LittleEndian),
- ),
- 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 mut entry_ids = HashMap::new();
- entry_ids.insert(debug_info_offset.into(), (unit_id, entry_id));
- let convert_expression = Expression::from(
- read_expression,
- encoding,
- None, /* dwarf */
- Some(&unit),
- Some(&entry_ids),
- &|address| Some(Address::Constant(address)),
- )
- .unwrap();
- let mut convert_operations = convert_expression.operations.iter();
- for (_, operation, _) in operations {
- assert_eq!(convert_operations.next(), Some(operation));
- }
- assert_eq!(
- convert_operations.next(),
- Some(&Operation::Branch(start_index))
- );
- assert_eq!(convert_operations.next(), Some(&Operation::Skip(end_index)));
- assert_eq!(
- convert_operations.next(),
- Some(&Operation::Simple(constants::DW_OP_nop))
- );
- }
- }
- }
- }
-}
diff --git a/vendor/gimli/src/write/range.rs b/vendor/gimli/src/write/range.rs
deleted file mode 100644
index c707e1e..0000000
--- a/vendor/gimli/src/write/range.rs
+++ /dev/null
@@ -1,416 +0,0 @@
-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);
- }
- }
- }
- }
-}
diff --git a/vendor/gimli/src/write/section.rs b/vendor/gimli/src/write/section.rs
deleted file mode 100644
index db5eb9a..0000000
--- a/vendor/gimli/src/write/section.rs
+++ /dev/null
@@ -1,172 +0,0 @@
-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(())
- }
-}
diff --git a/vendor/gimli/src/write/str.rs b/vendor/gimli/src/write/str.rs
deleted file mode 100644
index 83285c0..0000000
--- a/vendor/gimli/src/write/str.rs
+++ /dev/null
@@ -1,172 +0,0 @@
-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"[..]);
- }
-}
diff --git a/vendor/gimli/src/write/unit.rs b/vendor/gimli/src/write/unit.rs
deleted file mode 100644
index dd8ba67..0000000
--- a/vendor/gimli/src/write/unit.rs
+++ /dev/null
@@ -1,3152 +0,0 @@
-use alloc::vec::Vec;
-use std::ops::{Deref, DerefMut};
-use std::{slice, usize};
-
-use crate::common::{
- DebugAbbrevOffset, DebugInfoOffset, DebugLineOffset, DebugMacinfoOffset, DebugMacroOffset,
- DebugStrOffset, DebugTypeSignature, Encoding, Format, SectionId,
-};
-use crate::constants;
-use crate::leb128::write::{sleb128_size, uleb128_size};
-use crate::write::{
- Abbreviation, AbbreviationTable, Address, AttributeSpecification, BaseId, DebugLineStrOffsets,
- DebugStrOffsets, Error, Expression, FileId, LineProgram, LineStringId, LocationListId,
- LocationListOffsets, LocationListTable, RangeListId, RangeListOffsets, RangeListTable,
- Reference, Result, Section, Sections, StringId, Writer,
-};
-
-define_id!(UnitId, "An identifier for a unit in a `UnitTable`.");
-
-define_id!(UnitEntryId, "An identifier for an entry in a `Unit`.");
-
-/// A table of units that will be stored in the `.debug_info` section.
-#[derive(Debug, Default)]
-pub struct UnitTable {
- base_id: BaseId,
- units: Vec<Unit>,
-}
-
-impl UnitTable {
- /// Create a new unit and add it to the table.
- ///
- /// `address_size` must be in bytes.
- ///
- /// Returns the `UnitId` of the new unit.
- #[inline]
- pub fn add(&mut self, unit: Unit) -> UnitId {
- let id = UnitId::new(self.base_id, self.units.len());
- self.units.push(unit);
- id
- }
-
- /// Return the number of units.
- #[inline]
- pub fn count(&self) -> usize {
- self.units.len()
- }
-
- /// Return the id of a unit.
- ///
- /// # Panics
- ///
- /// Panics if `index >= self.count()`.
- #[inline]
- pub fn id(&self, index: usize) -> UnitId {
- assert!(index < self.count());
- UnitId::new(self.base_id, index)
- }
-
- /// Get a reference to a unit.
- ///
- /// # Panics
- ///
- /// Panics if `id` is invalid.
- #[inline]
- pub fn get(&self, id: UnitId) -> &Unit {
- debug_assert_eq!(self.base_id, id.base_id);
- &self.units[id.index]
- }
-
- /// Get a mutable reference to a unit.
- ///
- /// # Panics
- ///
- /// Panics if `id` is invalid.
- #[inline]
- pub fn get_mut(&mut self, id: UnitId) -> &mut Unit {
- debug_assert_eq!(self.base_id, id.base_id);
- &mut self.units[id.index]
- }
-
- /// Write the units to the given sections.
- ///
- /// `strings` must contain the `.debug_str` offsets of the corresponding
- /// `StringTable`.
- pub fn write<W: Writer>(
- &mut self,
- sections: &mut Sections<W>,
- line_strings: &DebugLineStrOffsets,
- strings: &DebugStrOffsets,
- ) -> Result<DebugInfoOffsets> {
- let mut offsets = DebugInfoOffsets {
- base_id: self.base_id,
- units: Vec::new(),
- };
- for unit in &mut self.units {
- // TODO: maybe share abbreviation tables
- let abbrev_offset = sections.debug_abbrev.offset();
- let mut abbrevs = AbbreviationTable::default();
-
- offsets.units.push(unit.write(
- sections,
- abbrev_offset,
- &mut abbrevs,
- line_strings,
- strings,
- )?);
-
- abbrevs.write(&mut sections.debug_abbrev)?;
- }
-
- write_section_refs(
- &mut sections.debug_info_refs,
- &mut sections.debug_info.0,
- &offsets,
- )?;
- write_section_refs(
- &mut sections.debug_loc_refs,
- &mut sections.debug_loc.0,
- &offsets,
- )?;
- write_section_refs(
- &mut sections.debug_loclists_refs,
- &mut sections.debug_loclists.0,
- &offsets,
- )?;
-
- Ok(offsets)
- }
-}
-
-fn write_section_refs<W: Writer>(
- references: &mut Vec<DebugInfoReference>,
- w: &mut W,
- offsets: &DebugInfoOffsets,
-) -> Result<()> {
- for r in references.drain(..) {
- let entry_offset = offsets.entry(r.unit, r.entry).0;
- debug_assert_ne!(entry_offset, 0);
- w.write_offset_at(r.offset, entry_offset, SectionId::DebugInfo, r.size)?;
- }
- Ok(())
-}
-
-/// A unit's debugging information.
-#[derive(Debug)]
-pub struct Unit {
- base_id: BaseId,
- /// The encoding parameters for this unit.
- encoding: Encoding,
- /// The line number program for this unit.
- pub line_program: LineProgram,
- /// A table of range lists used by this unit.
- pub ranges: RangeListTable,
- /// A table of location lists used by this unit.
- pub locations: LocationListTable,
- /// All entries in this unit. The order is unrelated to the tree order.
- // Requirements:
- // - entries form a tree
- // - entries can be added in any order
- // - entries have a fixed id
- // - able to quickly lookup an entry from its id
- // Limitations of current implementation:
- // - mutable iteration of children is messy due to borrow checker
- entries: Vec<DebuggingInformationEntry>,
- /// The index of the root entry in entries.
- root: UnitEntryId,
-}
-
-impl Unit {
- /// Create a new `Unit`.
- pub fn new(encoding: Encoding, line_program: LineProgram) -> Self {
- let base_id = BaseId::default();
- let ranges = RangeListTable::default();
- let locations = LocationListTable::default();
- let mut entries = Vec::new();
- let root = DebuggingInformationEntry::new(
- base_id,
- &mut entries,
- None,
- constants::DW_TAG_compile_unit,
- );
- Unit {
- base_id,
- encoding,
- line_program,
- ranges,
- locations,
- entries,
- root,
- }
- }
-
- /// Return the encoding parameters for this unit.
- #[inline]
- pub fn encoding(&self) -> Encoding {
- self.encoding
- }
-
- /// Return the DWARF version for this unit.
- #[inline]
- pub fn version(&self) -> u16 {
- self.encoding.version
- }
-
- /// Return the address size in bytes for this unit.
- #[inline]
- pub fn address_size(&self) -> u8 {
- self.encoding.address_size
- }
-
- /// Return the DWARF format for this unit.
- #[inline]
- pub fn format(&self) -> Format {
- self.encoding.format
- }
-
- /// Return the number of `DebuggingInformationEntry`s created for this unit.
- ///
- /// This includes entries that no longer have a parent.
- #[inline]
- pub fn count(&self) -> usize {
- self.entries.len()
- }
-
- /// Return the id of the root entry.
- #[inline]
- pub fn root(&self) -> UnitEntryId {
- self.root
- }
-
- /// Add a new `DebuggingInformationEntry` to this unit and return its id.
- ///
- /// The `parent` must be within the same unit.
- ///
- /// # Panics
- ///
- /// Panics if `parent` is invalid.
- #[inline]
- pub fn add(&mut self, parent: UnitEntryId, tag: constants::DwTag) -> UnitEntryId {
- debug_assert_eq!(self.base_id, parent.base_id);
- DebuggingInformationEntry::new(self.base_id, &mut self.entries, Some(parent), tag)
- }
-
- /// Get a reference to an entry.
- ///
- /// # Panics
- ///
- /// Panics if `id` is invalid.
- #[inline]
- pub fn get(&self, id: UnitEntryId) -> &DebuggingInformationEntry {
- debug_assert_eq!(self.base_id, id.base_id);
- &self.entries[id.index]
- }
-
- /// Get a mutable reference to an entry.
- ///
- /// # Panics
- ///
- /// Panics if `id` is invalid.
- #[inline]
- pub fn get_mut(&mut self, id: UnitEntryId) -> &mut DebuggingInformationEntry {
- debug_assert_eq!(self.base_id, id.base_id);
- &mut self.entries[id.index]
- }
-
- /// Return true if `self.line_program` is used by a DIE.
- fn line_program_in_use(&self) -> bool {
- if self.line_program.is_none() {
- return false;
- }
- if !self.line_program.is_empty() {
- return true;
- }
-
- for entry in &self.entries {
- for attr in &entry.attrs {
- if let AttributeValue::FileIndex(Some(_)) = attr.value {
- return true;
- }
- }
- }
-
- false
- }
-
- /// Write the unit to the given sections.
- pub(crate) fn write<W: Writer>(
- &mut self,
- sections: &mut Sections<W>,
- abbrev_offset: DebugAbbrevOffset,
- abbrevs: &mut AbbreviationTable,
- line_strings: &DebugLineStrOffsets,
- strings: &DebugStrOffsets,
- ) -> Result<UnitOffsets> {
- let line_program = if self.line_program_in_use() {
- self.entries[self.root.index]
- .set(constants::DW_AT_stmt_list, AttributeValue::LineProgramRef);
- Some(self.line_program.write(
- &mut sections.debug_line,
- self.encoding,
- line_strings,
- strings,
- )?)
- } else {
- self.entries[self.root.index].delete(constants::DW_AT_stmt_list);
- None
- };
-
- // TODO: use .debug_types for type units in DWARF v4.
- let w = &mut sections.debug_info;
-
- let mut offsets = UnitOffsets {
- base_id: self.base_id,
- unit: w.offset(),
- // Entries can be written in any order, so create the complete vec now.
- entries: vec![EntryOffset::none(); self.entries.len()],
- };
-
- let length_offset = w.write_initial_length(self.format())?;
- let length_base = w.len();
-
- w.write_u16(self.version())?;
- if 2 <= self.version() && self.version() <= 4 {
- w.write_offset(
- abbrev_offset.0,
- SectionId::DebugAbbrev,
- self.format().word_size(),
- )?;
- w.write_u8(self.address_size())?;
- } else if self.version() == 5 {
- w.write_u8(constants::DW_UT_compile.0)?;
- w.write_u8(self.address_size())?;
- w.write_offset(
- abbrev_offset.0,
- SectionId::DebugAbbrev,
- self.format().word_size(),
- )?;
- } else {
- return Err(Error::UnsupportedVersion(self.version()));
- }
-
- // Calculate all DIE offsets, so that we are able to output references to them.
- // However, references to base types in expressions use ULEB128, so base types
- // must be moved to the front before we can calculate offsets.
- self.reorder_base_types();
- let mut offset = w.len();
- self.entries[self.root.index].calculate_offsets(
- self,
- &mut offset,
- &mut offsets,
- abbrevs,
- )?;
-
- let range_lists = self.ranges.write(sections, self.encoding)?;
- // Location lists can't be written until we have DIE offsets.
- let loc_lists = self
- .locations
- .write(sections, self.encoding, Some(&offsets))?;
-
- let w = &mut sections.debug_info;
- let mut unit_refs = Vec::new();
- self.entries[self.root.index].write(
- w,
- &mut sections.debug_info_refs,
- &mut unit_refs,
- self,
- &mut offsets,
- line_program,
- line_strings,
- strings,
- &range_lists,
- &loc_lists,
- )?;
-
- let length = (w.len() - length_base) as u64;
- w.write_initial_length_at(length_offset, length, self.format())?;
-
- for (offset, entry) in unit_refs {
- // This does not need relocation.
- w.write_udata_at(
- offset.0,
- offsets.unit_offset(entry),
- self.format().word_size(),
- )?;
- }
-
- Ok(offsets)
- }
-
- /// Reorder base types to come first so that typed stack operations
- /// can get their offset.
- fn reorder_base_types(&mut self) {
- let root = &self.entries[self.root.index];
- let mut root_children = Vec::with_capacity(root.children.len());
- for entry in &root.children {
- if self.entries[entry.index].tag == constants::DW_TAG_base_type {
- root_children.push(*entry);
- }
- }
- for entry in &root.children {
- if self.entries[entry.index].tag != constants::DW_TAG_base_type {
- root_children.push(*entry);
- }
- }
- self.entries[self.root.index].children = root_children;
- }
-}
-
-/// A Debugging Information Entry (DIE).
-///
-/// DIEs have a set of attributes and optionally have children DIEs as well.
-///
-/// DIEs form a tree without any cycles. This is enforced by specifying the
-/// parent when creating a DIE, and disallowing changes of parent.
-#[derive(Debug)]
-pub struct DebuggingInformationEntry {
- id: UnitEntryId,
- parent: Option<UnitEntryId>,
- tag: constants::DwTag,
- /// Whether to emit `DW_AT_sibling`.
- sibling: bool,
- attrs: Vec<Attribute>,
- children: Vec<UnitEntryId>,
-}
-
-impl DebuggingInformationEntry {
- /// Create a new `DebuggingInformationEntry`.
- ///
- /// # Panics
- ///
- /// Panics if `parent` is invalid.
- #[allow(clippy::new_ret_no_self)]
- fn new(
- base_id: BaseId,
- entries: &mut Vec<DebuggingInformationEntry>,
- parent: Option<UnitEntryId>,
- tag: constants::DwTag,
- ) -> UnitEntryId {
- let id = UnitEntryId::new(base_id, entries.len());
- entries.push(DebuggingInformationEntry {
- id,
- parent,
- tag,
- sibling: false,
- attrs: Vec::new(),
- children: Vec::new(),
- });
- if let Some(parent) = parent {
- debug_assert_eq!(base_id, parent.base_id);
- assert_ne!(parent, id);
- entries[parent.index].children.push(id);
- }
- id
- }
-
- /// Return the id of this entry.
- #[inline]
- pub fn id(&self) -> UnitEntryId {
- self.id
- }
-
- /// Return the parent of this entry.
- #[inline]
- pub fn parent(&self) -> Option<UnitEntryId> {
- self.parent
- }
-
- /// Return the tag of this entry.
- #[inline]
- pub fn tag(&self) -> constants::DwTag {
- self.tag
- }
-
- /// Return `true` if a `DW_AT_sibling` attribute will be emitted.
- #[inline]
- pub fn sibling(&self) -> bool {
- self.sibling
- }
-
- /// Set whether a `DW_AT_sibling` attribute will be emitted.
- ///
- /// The attribute will only be emitted if the DIE has children.
- #[inline]
- pub fn set_sibling(&mut self, sibling: bool) {
- self.sibling = sibling;
- }
-
- /// Iterate over the attributes of this entry.
- #[inline]
- pub fn attrs(&self) -> slice::Iter<Attribute> {
- self.attrs.iter()
- }
-
- /// Iterate over the attributes of this entry for modification.
- #[inline]
- pub fn attrs_mut(&mut self) -> slice::IterMut<Attribute> {
- self.attrs.iter_mut()
- }
-
- /// Get an attribute.
- pub fn get(&self, name: constants::DwAt) -> Option<&AttributeValue> {
- self.attrs
- .iter()
- .find(|attr| attr.name == name)
- .map(|attr| &attr.value)
- }
-
- /// Get an attribute for modification.
- pub fn get_mut(&mut self, name: constants::DwAt) -> Option<&mut AttributeValue> {
- self.attrs
- .iter_mut()
- .find(|attr| attr.name == name)
- .map(|attr| &mut attr.value)
- }
-
- /// Set an attribute.
- ///
- /// Replaces any existing attribute with the same name.
- ///
- /// # Panics
- ///
- /// Panics if `name` is `DW_AT_sibling`. Use `set_sibling` instead.
- pub fn set(&mut self, name: constants::DwAt, value: AttributeValue) {
- assert_ne!(name, constants::DW_AT_sibling);
- if let Some(attr) = self.attrs.iter_mut().find(|attr| attr.name == name) {
- attr.value = value;
- return;
- }
- self.attrs.push(Attribute { name, value });
- }
-
- /// Delete an attribute.
- ///
- /// Replaces any existing attribute with the same name.
- pub fn delete(&mut self, name: constants::DwAt) {
- self.attrs.retain(|x| x.name != name);
- }
-
- /// Iterate over the children of this entry.
- ///
- /// Note: use `Unit::add` to add a new child to this entry.
- #[inline]
- pub fn children(&self) -> slice::Iter<UnitEntryId> {
- self.children.iter()
- }
-
- /// Delete a child entry and all of its children.
- pub fn delete_child(&mut self, id: UnitEntryId) {
- self.children.retain(|&child| child != id);
- }
-
- /// Return the type abbreviation for this DIE.
- fn abbreviation(&self, encoding: Encoding) -> Result<Abbreviation> {
- let mut attrs = Vec::new();
-
- if self.sibling && !self.children.is_empty() {
- let form = match encoding.format {
- Format::Dwarf32 => constants::DW_FORM_ref4,
- Format::Dwarf64 => constants::DW_FORM_ref8,
- };
- attrs.push(AttributeSpecification::new(constants::DW_AT_sibling, form));
- }
-
- for attr in &self.attrs {
- attrs.push(attr.specification(encoding)?);
- }
-
- Ok(Abbreviation::new(
- self.tag,
- !self.children.is_empty(),
- attrs,
- ))
- }
-
- fn calculate_offsets(
- &self,
- unit: &Unit,
- offset: &mut usize,
- offsets: &mut UnitOffsets,
- abbrevs: &mut AbbreviationTable,
- ) -> Result<()> {
- offsets.entries[self.id.index].offset = DebugInfoOffset(*offset);
- offsets.entries[self.id.index].abbrev = abbrevs.add(self.abbreviation(unit.encoding())?);
- *offset += self.size(unit, offsets);
- if !self.children.is_empty() {
- for child in &self.children {
- unit.entries[child.index].calculate_offsets(unit, offset, offsets, abbrevs)?;
- }
- // Null child
- *offset += 1;
- }
- Ok(())
- }
-
- fn size(&self, unit: &Unit, offsets: &UnitOffsets) -> usize {
- let mut size = uleb128_size(offsets.abbrev(self.id));
- if self.sibling && !self.children.is_empty() {
- size += unit.format().word_size() as usize;
- }
- for attr in &self.attrs {
- size += attr.value.size(unit, offsets);
- }
- size
- }
-
- /// Write the entry to the given sections.
- fn write<W: Writer>(
- &self,
- w: &mut DebugInfo<W>,
- debug_info_refs: &mut Vec<DebugInfoReference>,
- unit_refs: &mut Vec<(DebugInfoOffset, UnitEntryId)>,
- unit: &Unit,
- offsets: &mut UnitOffsets,
- line_program: Option<DebugLineOffset>,
- line_strings: &DebugLineStrOffsets,
- strings: &DebugStrOffsets,
- range_lists: &RangeListOffsets,
- loc_lists: &LocationListOffsets,
- ) -> Result<()> {
- debug_assert_eq!(offsets.debug_info_offset(self.id), w.offset());
- w.write_uleb128(offsets.abbrev(self.id))?;
-
- let sibling_offset = if self.sibling && !self.children.is_empty() {
- let offset = w.offset();
- w.write_udata(0, unit.format().word_size())?;
- Some(offset)
- } else {
- None
- };
-
- for attr in &self.attrs {
- attr.value.write(
- w,
- debug_info_refs,
- unit_refs,
- unit,
- offsets,
- line_program,
- line_strings,
- strings,
- range_lists,
- loc_lists,
- )?;
- }
-
- if !self.children.is_empty() {
- for child in &self.children {
- unit.entries[child.index].write(
- w,
- debug_info_refs,
- unit_refs,
- unit,
- offsets,
- line_program,
- line_strings,
- strings,
- range_lists,
- loc_lists,
- )?;
- }
- // Null child
- w.write_u8(0)?;
- }
-
- if let Some(offset) = sibling_offset {
- let next_offset = (w.offset().0 - offsets.unit.0) as u64;
- // This does not need relocation.
- w.write_udata_at(offset.0, next_offset, unit.format().word_size())?;
- }
- Ok(())
- }
-}
-
-/// An attribute in a `DebuggingInformationEntry`, consisting of a name and
-/// associated value.
-#[derive(Debug, Clone, PartialEq, Eq)]
-pub struct Attribute {
- name: constants::DwAt,
- value: AttributeValue,
-}
-
-impl Attribute {
- /// Get the name of this attribute.
- #[inline]
- pub fn name(&self) -> constants::DwAt {
- self.name
- }
-
- /// Get the value of this attribute.
- #[inline]
- pub fn get(&self) -> &AttributeValue {
- &self.value
- }
-
- /// Set the value of this attribute.
- #[inline]
- pub fn set(&mut self, value: AttributeValue) {
- self.value = value;
- }
-
- /// Return the type specification for this attribute.
- fn specification(&self, encoding: Encoding) -> Result<AttributeSpecification> {
- Ok(AttributeSpecification::new(
- self.name,
- self.value.form(encoding)?,
- ))
- }
-}
-
-/// The value of an attribute in a `DebuggingInformationEntry`.
-#[derive(Debug, Clone, PartialEq, Eq)]
-pub enum AttributeValue {
- /// "Refers to some location in the address space of the described program."
- Address(Address),
-
- /// A slice of an arbitrary number of bytes.
- Block(Vec<u8>),
-
- /// A one byte constant data value. How to interpret the byte depends on context.
- ///
- /// From section 7 of the standard: "Depending on context, it may be a
- /// signed integer, an unsigned integer, a floating-point constant, or
- /// anything else."
- Data1(u8),
-
- /// A two byte constant data value. How to interpret the bytes depends on context.
- ///
- /// This value will be converted to the target endian before writing.
- ///
- /// From section 7 of the standard: "Depending on context, it may be a
- /// signed integer, an unsigned integer, a floating-point constant, or
- /// anything else."
- Data2(u16),
-
- /// A four byte constant data value. How to interpret the bytes depends on context.
- ///
- /// This value will be converted to the target endian before writing.
- ///
- /// From section 7 of the standard: "Depending on context, it may be a
- /// signed integer, an unsigned integer, a floating-point constant, or
- /// anything else."
- Data4(u32),
-
- /// An eight byte constant data value. How to interpret the bytes depends on context.
- ///
- /// This value will be converted to the target endian before writing.
- ///
- /// From section 7 of the standard: "Depending on context, it may be a
- /// signed integer, an unsigned integer, a floating-point constant, or
- /// anything else."
- Data8(u64),
-
- /// A signed integer constant.
- Sdata(i64),
-
- /// An unsigned integer constant.
- Udata(u64),
-
- /// "The information bytes contain a DWARF expression (see Section 2.5) or
- /// location description (see Section 2.6)."
- Exprloc(Expression),
-
- /// A boolean that indicates presence or absence of the attribute.
- Flag(bool),
-
- /// An attribute that is always present.
- FlagPresent,
-
- /// A reference to a `DebuggingInformationEntry` in this unit.
- UnitRef(UnitEntryId),
-
- /// A reference to a `DebuggingInformationEntry` in a potentially different unit.
- DebugInfoRef(Reference),
-
- /// An offset into the `.debug_info` section of the supplementary object file.
- ///
- /// The API does not currently assist with generating this offset.
- /// This variant will be removed from the API once support for writing
- /// supplementary object files is implemented.
- DebugInfoRefSup(DebugInfoOffset),
-
- /// A reference to a line number program.
- LineProgramRef,
-
- /// A reference to a location list.
- LocationListRef(LocationListId),
-
- /// An offset into the `.debug_macinfo` section.
- ///
- /// The API does not currently assist with generating this offset.
- /// This variant will be removed from the API once support for writing
- /// `.debug_macinfo` sections is implemented.
- DebugMacinfoRef(DebugMacinfoOffset),
-
- /// An offset into the `.debug_macro` section.
- ///
- /// The API does not currently assist with generating this offset.
- /// This variant will be removed from the API once support for writing
- /// `.debug_macro` sections is implemented.
- DebugMacroRef(DebugMacroOffset),
-
- /// A reference to a range list.
- RangeListRef(RangeListId),
-
- /// A type signature.
- ///
- /// The API does not currently assist with generating this signature.
- /// This variant will be removed from the API once support for writing
- /// `.debug_types` sections is implemented.
- DebugTypesRef(DebugTypeSignature),
-
- /// A reference to a string in the `.debug_str` section.
- StringRef(StringId),
-
- /// An offset into the `.debug_str` section of the supplementary object file.
- ///
- /// The API does not currently assist with generating this offset.
- /// This variant will be removed from the API once support for writing
- /// supplementary object files is implemented.
- DebugStrRefSup(DebugStrOffset),
-
- /// A reference to a string in the `.debug_line_str` section.
- LineStringRef(LineStringId),
-
- /// A slice of bytes representing a string. Must not include null bytes.
- /// Not guaranteed to be UTF-8 or anything like that.
- String(Vec<u8>),
-
- /// The value of a `DW_AT_encoding` attribute.
- Encoding(constants::DwAte),
-
- /// The value of a `DW_AT_decimal_sign` attribute.
- DecimalSign(constants::DwDs),
-
- /// The value of a `DW_AT_endianity` attribute.
- Endianity(constants::DwEnd),
-
- /// The value of a `DW_AT_accessibility` attribute.
- Accessibility(constants::DwAccess),
-
- /// The value of a `DW_AT_visibility` attribute.
- Visibility(constants::DwVis),
-
- /// The value of a `DW_AT_virtuality` attribute.
- Virtuality(constants::DwVirtuality),
-
- /// The value of a `DW_AT_language` attribute.
- Language(constants::DwLang),
-
- /// The value of a `DW_AT_address_class` attribute.
- AddressClass(constants::DwAddr),
-
- /// The value of a `DW_AT_identifier_case` attribute.
- IdentifierCase(constants::DwId),
-
- /// The value of a `DW_AT_calling_convention` attribute.
- CallingConvention(constants::DwCc),
-
- /// The value of a `DW_AT_inline` attribute.
- Inline(constants::DwInl),
-
- /// The value of a `DW_AT_ordering` attribute.
- Ordering(constants::DwOrd),
-
- /// An index into the filename entries from the line number information
- /// table for the unit containing this value.
- FileIndex(Option<FileId>),
-}
-
-impl AttributeValue {
- /// Return the form that will be used to encode this value.
- pub fn form(&self, encoding: Encoding) -> Result<constants::DwForm> {
- // TODO: missing forms:
- // - DW_FORM_indirect
- // - DW_FORM_implicit_const
- // - FW_FORM_block1/block2/block4
- // - DW_FORM_str/strx1/strx2/strx3/strx4
- // - DW_FORM_addrx/addrx1/addrx2/addrx3/addrx4
- // - DW_FORM_data16
- // - DW_FORM_line_strp
- // - DW_FORM_loclistx
- // - DW_FORM_rnglistx
- let form = match *self {
- AttributeValue::Address(_) => constants::DW_FORM_addr,
- AttributeValue::Block(_) => constants::DW_FORM_block,
- AttributeValue::Data1(_) => constants::DW_FORM_data1,
- AttributeValue::Data2(_) => constants::DW_FORM_data2,
- AttributeValue::Data4(_) => constants::DW_FORM_data4,
- AttributeValue::Data8(_) => constants::DW_FORM_data8,
- AttributeValue::Exprloc(_) => constants::DW_FORM_exprloc,
- AttributeValue::Flag(_) => constants::DW_FORM_flag,
- AttributeValue::FlagPresent => constants::DW_FORM_flag_present,
- AttributeValue::UnitRef(_) => {
- // Using a fixed size format lets us write a placeholder before we know
- // the value.
- match encoding.format {
- Format::Dwarf32 => constants::DW_FORM_ref4,
- Format::Dwarf64 => constants::DW_FORM_ref8,
- }
- }
- AttributeValue::DebugInfoRef(_) => constants::DW_FORM_ref_addr,
- AttributeValue::DebugInfoRefSup(_) => {
- // TODO: should this depend on the size of supplementary section?
- match encoding.format {
- Format::Dwarf32 => constants::DW_FORM_ref_sup4,
- Format::Dwarf64 => constants::DW_FORM_ref_sup8,
- }
- }
- AttributeValue::LineProgramRef
- | AttributeValue::LocationListRef(_)
- | AttributeValue::DebugMacinfoRef(_)
- | AttributeValue::DebugMacroRef(_)
- | AttributeValue::RangeListRef(_) => {
- if encoding.version == 2 || encoding.version == 3 {
- match encoding.format {
- Format::Dwarf32 => constants::DW_FORM_data4,
- Format::Dwarf64 => constants::DW_FORM_data8,
- }
- } else {
- constants::DW_FORM_sec_offset
- }
- }
- AttributeValue::DebugTypesRef(_) => constants::DW_FORM_ref_sig8,
- AttributeValue::StringRef(_) => constants::DW_FORM_strp,
- AttributeValue::DebugStrRefSup(_) => constants::DW_FORM_strp_sup,
- AttributeValue::LineStringRef(_) => constants::DW_FORM_line_strp,
- AttributeValue::String(_) => constants::DW_FORM_string,
- AttributeValue::Encoding(_)
- | AttributeValue::DecimalSign(_)
- | AttributeValue::Endianity(_)
- | AttributeValue::Accessibility(_)
- | AttributeValue::Visibility(_)
- | AttributeValue::Virtuality(_)
- | AttributeValue::Language(_)
- | AttributeValue::AddressClass(_)
- | AttributeValue::IdentifierCase(_)
- | AttributeValue::CallingConvention(_)
- | AttributeValue::Inline(_)
- | AttributeValue::Ordering(_)
- | AttributeValue::FileIndex(_)
- | AttributeValue::Udata(_) => constants::DW_FORM_udata,
- AttributeValue::Sdata(_) => constants::DW_FORM_sdata,
- };
- Ok(form)
- }
-
- fn size(&self, unit: &Unit, offsets: &UnitOffsets) -> usize {
- macro_rules! debug_assert_form {
- ($form:expr) => {
- debug_assert_eq!(self.form(unit.encoding()).unwrap(), $form)
- };
- }
- match *self {
- AttributeValue::Address(_) => {
- debug_assert_form!(constants::DW_FORM_addr);
- unit.address_size() as usize
- }
- AttributeValue::Block(ref val) => {
- debug_assert_form!(constants::DW_FORM_block);
- uleb128_size(val.len() as u64) + val.len()
- }
- AttributeValue::Data1(_) => {
- debug_assert_form!(constants::DW_FORM_data1);
- 1
- }
- AttributeValue::Data2(_) => {
- debug_assert_form!(constants::DW_FORM_data2);
- 2
- }
- AttributeValue::Data4(_) => {
- debug_assert_form!(constants::DW_FORM_data4);
- 4
- }
- AttributeValue::Data8(_) => {
- debug_assert_form!(constants::DW_FORM_data8);
- 8
- }
- AttributeValue::Sdata(val) => {
- debug_assert_form!(constants::DW_FORM_sdata);
- sleb128_size(val)
- }
- AttributeValue::Udata(val) => {
- debug_assert_form!(constants::DW_FORM_udata);
- uleb128_size(val)
- }
- AttributeValue::Exprloc(ref val) => {
- debug_assert_form!(constants::DW_FORM_exprloc);
- let size = val.size(unit.encoding(), Some(offsets));
- uleb128_size(size as u64) + size
- }
- AttributeValue::Flag(_) => {
- debug_assert_form!(constants::DW_FORM_flag);
- 1
- }
- AttributeValue::FlagPresent => {
- debug_assert_form!(constants::DW_FORM_flag_present);
- 0
- }
- AttributeValue::UnitRef(_) => {
- match unit.format() {
- Format::Dwarf32 => debug_assert_form!(constants::DW_FORM_ref4),
- Format::Dwarf64 => debug_assert_form!(constants::DW_FORM_ref8),
- }
- unit.format().word_size() as usize
- }
- AttributeValue::DebugInfoRef(_) => {
- debug_assert_form!(constants::DW_FORM_ref_addr);
- if unit.version() == 2 {
- unit.address_size() as usize
- } else {
- unit.format().word_size() as usize
- }
- }
- AttributeValue::DebugInfoRefSup(_) => {
- match unit.format() {
- Format::Dwarf32 => debug_assert_form!(constants::DW_FORM_ref_sup4),
- Format::Dwarf64 => debug_assert_form!(constants::DW_FORM_ref_sup8),
- }
- unit.format().word_size() as usize
- }
- AttributeValue::LineProgramRef => {
- if unit.version() >= 4 {
- debug_assert_form!(constants::DW_FORM_sec_offset);
- }
- unit.format().word_size() as usize
- }
- AttributeValue::LocationListRef(_) => {
- if unit.version() >= 4 {
- debug_assert_form!(constants::DW_FORM_sec_offset);
- }
- unit.format().word_size() as usize
- }
- AttributeValue::DebugMacinfoRef(_) => {
- if unit.version() >= 4 {
- debug_assert_form!(constants::DW_FORM_sec_offset);
- }
- unit.format().word_size() as usize
- }
- AttributeValue::DebugMacroRef(_) => {
- if unit.version() >= 4 {
- debug_assert_form!(constants::DW_FORM_sec_offset);
- }
- unit.format().word_size() as usize
- }
- AttributeValue::RangeListRef(_) => {
- if unit.version() >= 4 {
- debug_assert_form!(constants::DW_FORM_sec_offset);
- }
- unit.format().word_size() as usize
- }
- AttributeValue::DebugTypesRef(_) => {
- debug_assert_form!(constants::DW_FORM_ref_sig8);
- 8
- }
- AttributeValue::StringRef(_) => {
- debug_assert_form!(constants::DW_FORM_strp);
- unit.format().word_size() as usize
- }
- AttributeValue::DebugStrRefSup(_) => {
- debug_assert_form!(constants::DW_FORM_strp_sup);
- unit.format().word_size() as usize
- }
- AttributeValue::LineStringRef(_) => {
- debug_assert_form!(constants::DW_FORM_line_strp);
- unit.format().word_size() as usize
- }
- AttributeValue::String(ref val) => {
- debug_assert_form!(constants::DW_FORM_string);
- val.len() + 1
- }
- AttributeValue::Encoding(val) => {
- debug_assert_form!(constants::DW_FORM_udata);
- uleb128_size(val.0 as u64)
- }
- AttributeValue::DecimalSign(val) => {
- debug_assert_form!(constants::DW_FORM_udata);
- uleb128_size(val.0 as u64)
- }
- AttributeValue::Endianity(val) => {
- debug_assert_form!(constants::DW_FORM_udata);
- uleb128_size(val.0 as u64)
- }
- AttributeValue::Accessibility(val) => {
- debug_assert_form!(constants::DW_FORM_udata);
- uleb128_size(val.0 as u64)
- }
- AttributeValue::Visibility(val) => {
- debug_assert_form!(constants::DW_FORM_udata);
- uleb128_size(val.0 as u64)
- }
- AttributeValue::Virtuality(val) => {
- debug_assert_form!(constants::DW_FORM_udata);
- uleb128_size(val.0 as u64)
- }
- AttributeValue::Language(val) => {
- debug_assert_form!(constants::DW_FORM_udata);
- uleb128_size(val.0 as u64)
- }
- AttributeValue::AddressClass(val) => {
- debug_assert_form!(constants::DW_FORM_udata);
- uleb128_size(val.0 as u64)
- }
- AttributeValue::IdentifierCase(val) => {
- debug_assert_form!(constants::DW_FORM_udata);
- uleb128_size(val.0 as u64)
- }
- AttributeValue::CallingConvention(val) => {
- debug_assert_form!(constants::DW_FORM_udata);
- uleb128_size(val.0 as u64)
- }
- AttributeValue::Inline(val) => {
- debug_assert_form!(constants::DW_FORM_udata);
- uleb128_size(val.0 as u64)
- }
- AttributeValue::Ordering(val) => {
- debug_assert_form!(constants::DW_FORM_udata);
- uleb128_size(val.0 as u64)
- }
- AttributeValue::FileIndex(val) => {
- debug_assert_form!(constants::DW_FORM_udata);
- uleb128_size(val.map(FileId::raw).unwrap_or(0))
- }
- }
- }
-
- /// Write the attribute value to the given sections.
- fn write<W: Writer>(
- &self,
- w: &mut DebugInfo<W>,
- debug_info_refs: &mut Vec<DebugInfoReference>,
- unit_refs: &mut Vec<(DebugInfoOffset, UnitEntryId)>,
- unit: &Unit,
- offsets: &UnitOffsets,
- line_program: Option<DebugLineOffset>,
- line_strings: &DebugLineStrOffsets,
- strings: &DebugStrOffsets,
- range_lists: &RangeListOffsets,
- loc_lists: &LocationListOffsets,
- ) -> Result<()> {
- macro_rules! debug_assert_form {
- ($form:expr) => {
- debug_assert_eq!(self.form(unit.encoding()).unwrap(), $form)
- };
- }
- match *self {
- AttributeValue::Address(val) => {
- debug_assert_form!(constants::DW_FORM_addr);
- w.write_address(val, unit.address_size())?;
- }
- AttributeValue::Block(ref val) => {
- debug_assert_form!(constants::DW_FORM_block);
- w.write_uleb128(val.len() as u64)?;
- w.write(val)?;
- }
- AttributeValue::Data1(val) => {
- debug_assert_form!(constants::DW_FORM_data1);
- w.write_u8(val)?;
- }
- AttributeValue::Data2(val) => {
- debug_assert_form!(constants::DW_FORM_data2);
- w.write_u16(val)?;
- }
- AttributeValue::Data4(val) => {
- debug_assert_form!(constants::DW_FORM_data4);
- w.write_u32(val)?;
- }
- AttributeValue::Data8(val) => {
- debug_assert_form!(constants::DW_FORM_data8);
- w.write_u64(val)?;
- }
- AttributeValue::Sdata(val) => {
- debug_assert_form!(constants::DW_FORM_sdata);
- w.write_sleb128(val)?;
- }
- AttributeValue::Udata(val) => {
- debug_assert_form!(constants::DW_FORM_udata);
- w.write_uleb128(val)?;
- }
- AttributeValue::Exprloc(ref val) => {
- debug_assert_form!(constants::DW_FORM_exprloc);
- w.write_uleb128(val.size(unit.encoding(), Some(offsets)) as u64)?;
- val.write(
- &mut w.0,
- Some(debug_info_refs),
- unit.encoding(),
- Some(offsets),
- )?;
- }
- AttributeValue::Flag(val) => {
- debug_assert_form!(constants::DW_FORM_flag);
- w.write_u8(val as u8)?;
- }
- AttributeValue::FlagPresent => {
- debug_assert_form!(constants::DW_FORM_flag_present);
- }
- AttributeValue::UnitRef(id) => {
- match unit.format() {
- Format::Dwarf32 => debug_assert_form!(constants::DW_FORM_ref4),
- Format::Dwarf64 => debug_assert_form!(constants::DW_FORM_ref8),
- }
- unit_refs.push((w.offset(), id));
- w.write_udata(0, unit.format().word_size())?;
- }
- AttributeValue::DebugInfoRef(reference) => {
- debug_assert_form!(constants::DW_FORM_ref_addr);
- let size = if unit.version() == 2 {
- unit.address_size()
- } else {
- unit.format().word_size()
- };
- match reference {
- Reference::Symbol(symbol) => w.write_reference(symbol, size)?,
- Reference::Entry(unit, entry) => {
- debug_info_refs.push(DebugInfoReference {
- offset: w.len(),
- unit,
- entry,
- size,
- });
- w.write_udata(0, size)?;
- }
- }
- }
- AttributeValue::DebugInfoRefSup(val) => {
- match unit.format() {
- Format::Dwarf32 => debug_assert_form!(constants::DW_FORM_ref_sup4),
- Format::Dwarf64 => debug_assert_form!(constants::DW_FORM_ref_sup8),
- }
- w.write_udata(val.0 as u64, unit.format().word_size())?;
- }
- AttributeValue::LineProgramRef => {
- if unit.version() >= 4 {
- debug_assert_form!(constants::DW_FORM_sec_offset);
- }
- match line_program {
- Some(line_program) => {
- w.write_offset(
- line_program.0,
- SectionId::DebugLine,
- unit.format().word_size(),
- )?;
- }
- None => return Err(Error::InvalidAttributeValue),
- }
- }
- AttributeValue::LocationListRef(val) => {
- if unit.version() >= 4 {
- debug_assert_form!(constants::DW_FORM_sec_offset);
- }
- let section = if unit.version() <= 4 {
- SectionId::DebugLoc
- } else {
- SectionId::DebugLocLists
- };
- w.write_offset(loc_lists.get(val).0, section, unit.format().word_size())?;
- }
- AttributeValue::DebugMacinfoRef(val) => {
- if unit.version() >= 4 {
- debug_assert_form!(constants::DW_FORM_sec_offset);
- }
- w.write_offset(val.0, SectionId::DebugMacinfo, unit.format().word_size())?;
- }
- AttributeValue::DebugMacroRef(val) => {
- if unit.version() >= 4 {
- debug_assert_form!(constants::DW_FORM_sec_offset);
- }
- w.write_offset(val.0, SectionId::DebugMacro, unit.format().word_size())?;
- }
- AttributeValue::RangeListRef(val) => {
- if unit.version() >= 4 {
- debug_assert_form!(constants::DW_FORM_sec_offset);
- }
- let section = if unit.version() <= 4 {
- SectionId::DebugRanges
- } else {
- SectionId::DebugRngLists
- };
- w.write_offset(range_lists.get(val).0, section, unit.format().word_size())?;
- }
- AttributeValue::DebugTypesRef(val) => {
- debug_assert_form!(constants::DW_FORM_ref_sig8);
- w.write_u64(val.0)?;
- }
- AttributeValue::StringRef(val) => {
- debug_assert_form!(constants::DW_FORM_strp);
- w.write_offset(
- strings.get(val).0,
- SectionId::DebugStr,
- unit.format().word_size(),
- )?;
- }
- AttributeValue::DebugStrRefSup(val) => {
- debug_assert_form!(constants::DW_FORM_strp_sup);
- w.write_udata(val.0 as u64, unit.format().word_size())?;
- }
- AttributeValue::LineStringRef(val) => {
- debug_assert_form!(constants::DW_FORM_line_strp);
- w.write_offset(
- line_strings.get(val).0,
- SectionId::DebugLineStr,
- unit.format().word_size(),
- )?;
- }
- AttributeValue::String(ref val) => {
- debug_assert_form!(constants::DW_FORM_string);
- w.write(val)?;
- w.write_u8(0)?;
- }
- AttributeValue::Encoding(val) => {
- debug_assert_form!(constants::DW_FORM_udata);
- w.write_uleb128(u64::from(val.0))?;
- }
- AttributeValue::DecimalSign(val) => {
- debug_assert_form!(constants::DW_FORM_udata);
- w.write_uleb128(u64::from(val.0))?;
- }
- AttributeValue::Endianity(val) => {
- debug_assert_form!(constants::DW_FORM_udata);
- w.write_uleb128(u64::from(val.0))?;
- }
- AttributeValue::Accessibility(val) => {
- debug_assert_form!(constants::DW_FORM_udata);
- w.write_uleb128(u64::from(val.0))?;
- }
- AttributeValue::Visibility(val) => {
- debug_assert_form!(constants::DW_FORM_udata);
- w.write_uleb128(u64::from(val.0))?;
- }
- AttributeValue::Virtuality(val) => {
- debug_assert_form!(constants::DW_FORM_udata);
- w.write_uleb128(u64::from(val.0))?;
- }
- AttributeValue::Language(val) => {
- debug_assert_form!(constants::DW_FORM_udata);
- w.write_uleb128(u64::from(val.0))?;
- }
- AttributeValue::AddressClass(val) => {
- debug_assert_form!(constants::DW_FORM_udata);
- w.write_uleb128(val.0)?;
- }
- AttributeValue::IdentifierCase(val) => {
- debug_assert_form!(constants::DW_FORM_udata);
- w.write_uleb128(u64::from(val.0))?;
- }
- AttributeValue::CallingConvention(val) => {
- debug_assert_form!(constants::DW_FORM_udata);
- w.write_uleb128(u64::from(val.0))?;
- }
- AttributeValue::Inline(val) => {
- debug_assert_form!(constants::DW_FORM_udata);
- w.write_uleb128(u64::from(val.0))?;
- }
- AttributeValue::Ordering(val) => {
- debug_assert_form!(constants::DW_FORM_udata);
- w.write_uleb128(u64::from(val.0))?;
- }
- AttributeValue::FileIndex(val) => {
- debug_assert_form!(constants::DW_FORM_udata);
- w.write_uleb128(val.map(FileId::raw).unwrap_or(0))?;
- }
- }
- Ok(())
- }
-}
-
-define_section!(
- DebugInfo,
- DebugInfoOffset,
- "A writable `.debug_info` section."
-);
-
-/// The section offsets of all elements within a `.debug_info` section.
-#[derive(Debug, Default)]
-pub struct DebugInfoOffsets {
- base_id: BaseId,
- units: Vec<UnitOffsets>,
-}
-
-impl DebugInfoOffsets {
- #[cfg(test)]
- #[cfg(feature = "read")]
- pub(crate) fn unit_offsets(&self, unit: UnitId) -> &UnitOffsets {
- debug_assert_eq!(self.base_id, unit.base_id);
- &self.units[unit.index]
- }
-
- /// Get the `.debug_info` section offset for the given unit.
- #[inline]
- pub fn unit(&self, unit: UnitId) -> DebugInfoOffset {
- debug_assert_eq!(self.base_id, unit.base_id);
- self.units[unit.index].unit
- }
-
- /// Get the `.debug_info` section offset for the given entry.
- #[inline]
- pub fn entry(&self, unit: UnitId, entry: UnitEntryId) -> DebugInfoOffset {
- debug_assert_eq!(self.base_id, unit.base_id);
- self.units[unit.index].debug_info_offset(entry)
- }
-}
-
-/// The section offsets of all elements of a unit within a `.debug_info` section.
-#[derive(Debug)]
-pub(crate) struct UnitOffsets {
- base_id: BaseId,
- unit: DebugInfoOffset,
- entries: Vec<EntryOffset>,
-}
-
-impl UnitOffsets {
- #[cfg(test)]
- #[cfg(feature = "read")]
- fn none() -> Self {
- UnitOffsets {
- base_id: BaseId::default(),
- unit: DebugInfoOffset(0),
- entries: Vec::new(),
- }
- }
-
- /// Get the .debug_info offset for the given entry.
- #[inline]
- pub(crate) fn debug_info_offset(&self, entry: UnitEntryId) -> DebugInfoOffset {
- debug_assert_eq!(self.base_id, entry.base_id);
- let offset = self.entries[entry.index].offset;
- debug_assert_ne!(offset.0, 0);
- offset
- }
-
- /// Get the unit offset for the given entry.
- #[inline]
- pub(crate) fn unit_offset(&self, entry: UnitEntryId) -> u64 {
- let offset = self.debug_info_offset(entry);
- (offset.0 - self.unit.0) as u64
- }
-
- /// Get the abbreviation code for the given entry.
- #[inline]
- pub(crate) fn abbrev(&self, entry: UnitEntryId) -> u64 {
- debug_assert_eq!(self.base_id, entry.base_id);
- self.entries[entry.index].abbrev
- }
-}
-
-#[derive(Debug, Clone, Copy)]
-pub(crate) struct EntryOffset {
- offset: DebugInfoOffset,
- abbrev: u64,
-}
-
-impl EntryOffset {
- fn none() -> Self {
- EntryOffset {
- offset: DebugInfoOffset(0),
- abbrev: 0,
- }
- }
-}
-
-/// A reference to a `.debug_info` entry that has yet to be resolved.
-#[derive(Debug, Clone, Copy)]
-pub(crate) struct DebugInfoReference {
- /// The offset within the section of the reference.
- pub offset: usize,
- /// The size of the reference.
- pub size: u8,
- /// The unit containing the entry.
- pub unit: UnitId,
- /// The entry being referenced.
- pub entry: UnitEntryId,
-}
-
-#[cfg(feature = "read")]
-pub(crate) mod convert {
- use super::*;
- use crate::common::{DwoId, UnitSectionOffset};
- use crate::read::{self, Reader};
- use crate::write::{self, ConvertError, ConvertResult, LocationList, RangeList};
- use std::collections::HashMap;
-
- pub(crate) struct ConvertUnit<R: Reader<Offset = usize>> {
- from_unit: read::Unit<R>,
- base_id: BaseId,
- encoding: Encoding,
- entries: Vec<DebuggingInformationEntry>,
- entry_offsets: Vec<read::UnitOffset>,
- root: UnitEntryId,
- }
-
- pub(crate) struct ConvertUnitContext<'a, R: Reader<Offset = usize>> {
- pub dwarf: &'a read::Dwarf<R>,
- pub unit: &'a read::Unit<R>,
- pub line_strings: &'a mut write::LineStringTable,
- pub strings: &'a mut write::StringTable,
- pub ranges: &'a mut write::RangeListTable,
- pub locations: &'a mut write::LocationListTable,
- pub convert_address: &'a dyn Fn(u64) -> Option<Address>,
- pub base_address: Address,
- pub line_program_offset: Option<DebugLineOffset>,
- pub line_program_files: Vec<FileId>,
- pub entry_ids: &'a HashMap<UnitSectionOffset, (UnitId, UnitEntryId)>,
- }
-
- impl UnitTable {
- /// Create a unit table by reading the data in the given sections.
- ///
- /// This also updates the given tables with the values that are referenced from
- /// attributes in this section.
- ///
- /// `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>,
- line_strings: &mut write::LineStringTable,
- strings: &mut write::StringTable,
- convert_address: &dyn Fn(u64) -> Option<Address>,
- ) -> ConvertResult<UnitTable> {
- let base_id = BaseId::default();
- let mut unit_entries = Vec::new();
- let mut entry_ids = HashMap::new();
-
- let mut from_units = dwarf.units();
- while let Some(from_unit) = from_units.next()? {
- let unit_id = UnitId::new(base_id, unit_entries.len());
- unit_entries.push(Unit::convert_entries(
- from_unit,
- unit_id,
- &mut entry_ids,
- dwarf,
- )?);
- }
-
- // Attributes must be converted in a separate pass so that we can handle
- // references to other compilation units.
- let mut units = Vec::new();
- for unit_entries in unit_entries.drain(..) {
- units.push(Unit::convert_attributes(
- unit_entries,
- &entry_ids,
- dwarf,
- line_strings,
- strings,
- convert_address,
- )?);
- }
-
- Ok(UnitTable { base_id, units })
- }
- }
-
- impl Unit {
- /// Create a unit by reading the data in the input sections.
- ///
- /// Does not add entry attributes.
- pub(crate) fn convert_entries<R: Reader<Offset = usize>>(
- from_header: read::UnitHeader<R>,
- unit_id: UnitId,
- entry_ids: &mut HashMap<UnitSectionOffset, (UnitId, UnitEntryId)>,
- dwarf: &read::Dwarf<R>,
- ) -> ConvertResult<ConvertUnit<R>> {
- match from_header.type_() {
- read::UnitType::Compilation => (),
- _ => return Err(ConvertError::UnsupportedUnitType),
- }
- let base_id = BaseId::default();
-
- let from_unit = dwarf.unit(from_header)?;
- let encoding = from_unit.encoding();
-
- let mut entries = Vec::new();
- let mut entry_offsets = Vec::new();
-
- let mut from_tree = from_unit.entries_tree(None)?;
- let from_root = from_tree.root()?;
- let root = DebuggingInformationEntry::convert_entry(
- from_root,
- &from_unit,
- base_id,
- &mut entries,
- &mut entry_offsets,
- entry_ids,
- None,
- unit_id,
- )?;
-
- Ok(ConvertUnit {
- from_unit,
- base_id,
- encoding,
- entries,
- entry_offsets,
- root,
- })
- }
-
- /// Create entry attributes by reading the data in the input sections.
- fn convert_attributes<R: Reader<Offset = usize>>(
- unit: ConvertUnit<R>,
- entry_ids: &HashMap<UnitSectionOffset, (UnitId, UnitEntryId)>,
- dwarf: &read::Dwarf<R>,
- line_strings: &mut write::LineStringTable,
- strings: &mut write::StringTable,
- convert_address: &dyn Fn(u64) -> Option<Address>,
- ) -> ConvertResult<Unit> {
- let from_unit = unit.from_unit;
- let base_address =
- convert_address(from_unit.low_pc).ok_or(ConvertError::InvalidAddress)?;
-
- let (line_program_offset, line_program, line_program_files) =
- match from_unit.line_program {
- Some(ref from_program) => {
- let from_program = from_program.clone();
- let line_program_offset = from_program.header().offset();
- let (line_program, line_program_files) = LineProgram::from(
- from_program,
- dwarf,
- line_strings,
- strings,
- convert_address,
- )?;
- (Some(line_program_offset), line_program, line_program_files)
- }
- None => (None, LineProgram::none(), Vec::new()),
- };
-
- let mut ranges = RangeListTable::default();
- let mut locations = LocationListTable::default();
-
- let mut context = ConvertUnitContext {
- entry_ids,
- dwarf,
- unit: &from_unit,
- line_strings,
- strings,
- ranges: &mut ranges,
- locations: &mut locations,
- convert_address,
- base_address,
- line_program_offset,
- line_program_files,
- };
-
- let mut entries = unit.entries;
- for entry in &mut entries {
- entry.convert_attributes(&mut context, &unit.entry_offsets)?;
- }
-
- Ok(Unit {
- base_id: unit.base_id,
- encoding: unit.encoding,
- line_program,
- ranges,
- locations,
- entries,
- root: unit.root,
- })
- }
- }
-
- impl DebuggingInformationEntry {
- /// Create an entry by reading the data in the input sections.
- ///
- /// Does not add the entry attributes.
- fn convert_entry<R: Reader<Offset = usize>>(
- from: read::EntriesTreeNode<R>,
- from_unit: &read::Unit<R>,
- base_id: BaseId,
- entries: &mut Vec<DebuggingInformationEntry>,
- entry_offsets: &mut Vec<read::UnitOffset>,
- entry_ids: &mut HashMap<UnitSectionOffset, (UnitId, UnitEntryId)>,
- parent: Option<UnitEntryId>,
- unit_id: UnitId,
- ) -> ConvertResult<UnitEntryId> {
- let from_entry = from.entry();
- let id = DebuggingInformationEntry::new(base_id, entries, parent, from_entry.tag());
- let offset = from_entry.offset();
- entry_offsets.push(offset);
- entry_ids.insert(offset.to_unit_section_offset(from_unit), (unit_id, id));
-
- let mut from_children = from.children();
- while let Some(from_child) = from_children.next()? {
- DebuggingInformationEntry::convert_entry(
- from_child,
- from_unit,
- base_id,
- entries,
- entry_offsets,
- entry_ids,
- Some(id),
- unit_id,
- )?;
- }
- Ok(id)
- }
-
- /// Create an entry's attributes by reading the data in the input sections.
- fn convert_attributes<R: Reader<Offset = usize>>(
- &mut self,
- context: &mut ConvertUnitContext<R>,
- entry_offsets: &[read::UnitOffset],
- ) -> ConvertResult<()> {
- let offset = entry_offsets[self.id.index];
- let from = context.unit.entry(offset)?;
- let mut from_attrs = from.attrs();
- while let Some(from_attr) = from_attrs.next()? {
- if from_attr.name() == constants::DW_AT_sibling {
- // This may point to a null entry, so we have to treat it differently.
- self.set_sibling(true);
- } else if let Some(attr) = Attribute::from(context, &from_attr)? {
- self.set(attr.name, attr.value);
- }
- }
- Ok(())
- }
- }
-
- impl Attribute {
- /// Create an attribute by reading the data in the given sections.
- pub(crate) fn from<R: Reader<Offset = usize>>(
- context: &mut ConvertUnitContext<R>,
- from: &read::Attribute<R>,
- ) -> ConvertResult<Option<Attribute>> {
- let value = AttributeValue::from(context, from.value())?;
- Ok(value.map(|value| Attribute {
- name: from.name(),
- value,
- }))
- }
- }
-
- impl AttributeValue {
- /// Create an attribute value by reading the data in the given sections.
- pub(crate) fn from<R: Reader<Offset = usize>>(
- context: &mut ConvertUnitContext<R>,
- from: read::AttributeValue<R>,
- ) -> ConvertResult<Option<AttributeValue>> {
- let to = match from {
- read::AttributeValue::Addr(val) => match (context.convert_address)(val) {
- Some(val) => AttributeValue::Address(val),
- None => return Err(ConvertError::InvalidAddress),
- },
- read::AttributeValue::Block(r) => AttributeValue::Block(r.to_slice()?.into()),
- read::AttributeValue::Data1(val) => AttributeValue::Data1(val),
- read::AttributeValue::Data2(val) => AttributeValue::Data2(val),
- read::AttributeValue::Data4(val) => AttributeValue::Data4(val),
- read::AttributeValue::Data8(val) => AttributeValue::Data8(val),
- read::AttributeValue::Sdata(val) => AttributeValue::Sdata(val),
- read::AttributeValue::Udata(val) => AttributeValue::Udata(val),
- read::AttributeValue::Exprloc(expression) => {
- let expression = Expression::from(
- expression,
- context.unit.encoding(),
- Some(context.dwarf),
- Some(context.unit),
- Some(context.entry_ids),
- context.convert_address,
- )?;
- AttributeValue::Exprloc(expression)
- }
- // TODO: it would be nice to preserve the flag form.
- read::AttributeValue::Flag(val) => AttributeValue::Flag(val),
- read::AttributeValue::DebugAddrBase(_base) => {
- // We convert all address indices to addresses,
- // so this is unneeded.
- return Ok(None);
- }
- read::AttributeValue::DebugAddrIndex(index) => {
- let val = context.dwarf.address(context.unit, index)?;
- match (context.convert_address)(val) {
- Some(val) => AttributeValue::Address(val),
- None => return Err(ConvertError::InvalidAddress),
- }
- }
- read::AttributeValue::UnitRef(val) => {
- if !context.unit.header.is_valid_offset(val) {
- return Err(ConvertError::InvalidUnitRef);
- }
- let id = context
- .entry_ids
- .get(&val.to_unit_section_offset(context.unit))
- .ok_or(ConvertError::InvalidUnitRef)?;
- AttributeValue::UnitRef(id.1)
- }
- read::AttributeValue::DebugInfoRef(val) => {
- // TODO: support relocation of this value
- let id = context
- .entry_ids
- .get(&UnitSectionOffset::DebugInfoOffset(val))
- .ok_or(ConvertError::InvalidDebugInfoRef)?;
- AttributeValue::DebugInfoRef(Reference::Entry(id.0, id.1))
- }
- read::AttributeValue::DebugInfoRefSup(val) => AttributeValue::DebugInfoRefSup(val),
- read::AttributeValue::DebugLineRef(val) => {
- // There should only be the line program in the CU DIE which we've already
- // converted, so check if it matches that.
- if Some(val) == context.line_program_offset {
- AttributeValue::LineProgramRef
- } else {
- return Err(ConvertError::InvalidLineRef);
- }
- }
- read::AttributeValue::DebugMacinfoRef(val) => AttributeValue::DebugMacinfoRef(val),
- read::AttributeValue::DebugMacroRef(val) => AttributeValue::DebugMacroRef(val),
- read::AttributeValue::LocationListsRef(val) => {
- let iter = context
- .dwarf
- .locations
- .raw_locations(val, context.unit.encoding())?;
- let loc_list = LocationList::from(iter, context)?;
- let loc_id = context.locations.add(loc_list);
- AttributeValue::LocationListRef(loc_id)
- }
- read::AttributeValue::DebugLocListsBase(_base) => {
- // We convert all location list indices to offsets,
- // so this is unneeded.
- return Ok(None);
- }
- read::AttributeValue::DebugLocListsIndex(index) => {
- let offset = context.dwarf.locations_offset(context.unit, index)?;
- let iter = context
- .dwarf
- .locations
- .raw_locations(offset, context.unit.encoding())?;
- let loc_list = LocationList::from(iter, context)?;
- let loc_id = context.locations.add(loc_list);
- AttributeValue::LocationListRef(loc_id)
- }
- read::AttributeValue::RangeListsRef(offset) => {
- let offset = context.dwarf.ranges_offset_from_raw(context.unit, offset);
- let iter = context.dwarf.raw_ranges(context.unit, offset)?;
- let range_list = RangeList::from(iter, context)?;
- let range_id = context.ranges.add(range_list);
- AttributeValue::RangeListRef(range_id)
- }
- read::AttributeValue::DebugRngListsBase(_base) => {
- // We convert all range list indices to offsets,
- // so this is unneeded.
- return Ok(None);
- }
- read::AttributeValue::DebugRngListsIndex(index) => {
- let offset = context.dwarf.ranges_offset(context.unit, index)?;
- let iter = context
- .dwarf
- .ranges
- .raw_ranges(offset, context.unit.encoding())?;
- let range_list = RangeList::from(iter, context)?;
- let range_id = context.ranges.add(range_list);
- AttributeValue::RangeListRef(range_id)
- }
- read::AttributeValue::DebugTypesRef(val) => AttributeValue::DebugTypesRef(val),
- read::AttributeValue::DebugStrRef(offset) => {
- let r = context.dwarf.string(offset)?;
- let id = context.strings.add(r.to_slice()?);
- AttributeValue::StringRef(id)
- }
- read::AttributeValue::DebugStrRefSup(val) => AttributeValue::DebugStrRefSup(val),
- read::AttributeValue::DebugStrOffsetsBase(_base) => {
- // We convert all string offsets to `.debug_str` references,
- // so this is unneeded.
- return Ok(None);
- }
- read::AttributeValue::DebugStrOffsetsIndex(index) => {
- let offset = context.dwarf.string_offset(context.unit, index)?;
- let r = context.dwarf.string(offset)?;
- let id = context.strings.add(r.to_slice()?);
- AttributeValue::StringRef(id)
- }
- read::AttributeValue::DebugLineStrRef(offset) => {
- let r = context.dwarf.line_string(offset)?;
- let id = context.line_strings.add(r.to_slice()?);
- AttributeValue::LineStringRef(id)
- }
- read::AttributeValue::String(r) => AttributeValue::String(r.to_slice()?.into()),
- read::AttributeValue::Encoding(val) => AttributeValue::Encoding(val),
- read::AttributeValue::DecimalSign(val) => AttributeValue::DecimalSign(val),
- read::AttributeValue::Endianity(val) => AttributeValue::Endianity(val),
- read::AttributeValue::Accessibility(val) => AttributeValue::Accessibility(val),
- read::AttributeValue::Visibility(val) => AttributeValue::Visibility(val),
- read::AttributeValue::Virtuality(val) => AttributeValue::Virtuality(val),
- read::AttributeValue::Language(val) => AttributeValue::Language(val),
- read::AttributeValue::AddressClass(val) => AttributeValue::AddressClass(val),
- read::AttributeValue::IdentifierCase(val) => AttributeValue::IdentifierCase(val),
- read::AttributeValue::CallingConvention(val) => {
- AttributeValue::CallingConvention(val)
- }
- read::AttributeValue::Inline(val) => AttributeValue::Inline(val),
- read::AttributeValue::Ordering(val) => AttributeValue::Ordering(val),
- read::AttributeValue::FileIndex(val) => {
- if val == 0 {
- // 0 means not specified, even for version 5.
- AttributeValue::FileIndex(None)
- } else {
- match context.line_program_files.get(val as usize) {
- Some(id) => AttributeValue::FileIndex(Some(*id)),
- None => return Err(ConvertError::InvalidFileIndex),
- }
- }
- }
- // Should always be a more specific section reference.
- read::AttributeValue::SecOffset(_) => {
- return Err(ConvertError::InvalidAttributeValue);
- }
- read::AttributeValue::DwoId(DwoId(val)) => AttributeValue::Udata(val),
- };
- Ok(Some(to))
- }
- }
-}
-
-#[cfg(test)]
-#[cfg(feature = "read")]
-mod tests {
- use super::*;
- use crate::common::{
- DebugAddrBase, DebugLocListsBase, DebugRngListsBase, DebugStrOffsetsBase, LineEncoding,
- };
- use crate::constants;
- use crate::read;
- use crate::write::{
- DebugLine, DebugLineStr, DebugStr, DwarfUnit, EndianVec, LineString, LineStringTable,
- Location, LocationList, LocationListTable, Range, RangeList, RangeListOffsets,
- RangeListTable, StringTable,
- };
- use crate::LittleEndian;
- use std::collections::HashMap;
- use std::mem;
- use std::sync::Arc;
-
- #[test]
- fn test_unit_table() {
- let mut strings = StringTable::default();
-
- let mut units = UnitTable::default();
- let unit_id1 = units.add(Unit::new(
- Encoding {
- version: 4,
- address_size: 8,
- format: Format::Dwarf32,
- },
- LineProgram::none(),
- ));
- let unit2 = units.add(Unit::new(
- Encoding {
- version: 2,
- address_size: 4,
- format: Format::Dwarf64,
- },
- LineProgram::none(),
- ));
- let unit3 = units.add(Unit::new(
- Encoding {
- version: 5,
- address_size: 4,
- format: Format::Dwarf32,
- },
- LineProgram::none(),
- ));
- assert_eq!(units.count(), 3);
- {
- let unit1 = units.get_mut(unit_id1);
- assert_eq!(unit1.version(), 4);
- assert_eq!(unit1.address_size(), 8);
- assert_eq!(unit1.format(), Format::Dwarf32);
- assert_eq!(unit1.count(), 1);
-
- let root_id = unit1.root();
- assert_eq!(root_id, UnitEntryId::new(unit1.base_id, 0));
- {
- let root = unit1.get_mut(root_id);
- assert_eq!(root.id(), root_id);
- assert!(root.parent().is_none());
- assert_eq!(root.tag(), constants::DW_TAG_compile_unit);
-
- // Test get/get_mut
- assert!(root.get(constants::DW_AT_producer).is_none());
- assert!(root.get_mut(constants::DW_AT_producer).is_none());
- let mut producer = AttributeValue::String(b"root"[..].into());
- root.set(constants::DW_AT_producer, producer.clone());
- assert_eq!(root.get(constants::DW_AT_producer), Some(&producer));
- assert_eq!(root.get_mut(constants::DW_AT_producer), Some(&mut producer));
-
- // Test attrs
- let mut attrs = root.attrs();
- let attr = attrs.next().unwrap();
- assert_eq!(attr.name(), constants::DW_AT_producer);
- assert_eq!(attr.get(), &producer);
- assert!(attrs.next().is_none());
- }
-
- let child1 = unit1.add(root_id, constants::DW_TAG_subprogram);
- assert_eq!(child1, UnitEntryId::new(unit1.base_id, 1));
- {
- let child1 = unit1.get_mut(child1);
- assert_eq!(child1.parent(), Some(root_id));
-
- let tmp = AttributeValue::String(b"tmp"[..].into());
- child1.set(constants::DW_AT_name, tmp.clone());
- assert_eq!(child1.get(constants::DW_AT_name), Some(&tmp));
-
- // Test attrs_mut
- let name = AttributeValue::StringRef(strings.add(&b"child1"[..]));
- {
- let attr = child1.attrs_mut().next().unwrap();
- assert_eq!(attr.name(), constants::DW_AT_name);
- attr.set(name.clone());
- }
- assert_eq!(child1.get(constants::DW_AT_name), Some(&name));
- }
-
- let child2 = unit1.add(root_id, constants::DW_TAG_subprogram);
- assert_eq!(child2, UnitEntryId::new(unit1.base_id, 2));
- {
- let child2 = unit1.get_mut(child2);
- assert_eq!(child2.parent(), Some(root_id));
-
- let tmp = AttributeValue::String(b"tmp"[..].into());
- child2.set(constants::DW_AT_name, tmp.clone());
- assert_eq!(child2.get(constants::DW_AT_name), Some(&tmp));
-
- // Test replace
- let name = AttributeValue::StringRef(strings.add(&b"child2"[..]));
- child2.set(constants::DW_AT_name, name.clone());
- assert_eq!(child2.get(constants::DW_AT_name), Some(&name));
- }
-
- {
- let root = unit1.get(root_id);
- assert_eq!(
- root.children().cloned().collect::<Vec<_>>(),
- vec![child1, child2]
- );
- }
- }
- {
- let unit2 = units.get(unit2);
- assert_eq!(unit2.version(), 2);
- assert_eq!(unit2.address_size(), 4);
- assert_eq!(unit2.format(), Format::Dwarf64);
- assert_eq!(unit2.count(), 1);
-
- let root = unit2.root();
- assert_eq!(root, UnitEntryId::new(unit2.base_id, 0));
- let root = unit2.get(root);
- assert_eq!(root.id(), UnitEntryId::new(unit2.base_id, 0));
- assert!(root.parent().is_none());
- assert_eq!(root.tag(), constants::DW_TAG_compile_unit);
- }
-
- let mut sections = Sections::new(EndianVec::new(LittleEndian));
- let debug_line_str_offsets = DebugLineStrOffsets::none();
- let debug_str_offsets = strings.write(&mut sections.debug_str).unwrap();
- units
- .write(&mut sections, &debug_line_str_offsets, &debug_str_offsets)
- .unwrap();
-
- println!("{:?}", sections.debug_str);
- println!("{:?}", sections.debug_info);
- println!("{:?}", sections.debug_abbrev);
-
- let dwarf = read::Dwarf {
- debug_abbrev: read::DebugAbbrev::new(sections.debug_abbrev.slice(), LittleEndian),
- debug_info: read::DebugInfo::new(sections.debug_info.slice(), LittleEndian),
- debug_str: read::DebugStr::new(sections.debug_str.slice(), LittleEndian),
- ..Default::default()
- };
- let mut read_units = dwarf.units();
-
- {
- let read_unit1 = read_units.next().unwrap().unwrap();
- let unit1 = units.get(unit_id1);
- assert_eq!(unit1.version(), read_unit1.version());
- assert_eq!(unit1.address_size(), read_unit1.address_size());
- assert_eq!(unit1.format(), read_unit1.format());
-
- let read_unit1 = dwarf.unit(read_unit1).unwrap();
- let mut read_entries = read_unit1.entries();
-
- let root = unit1.get(unit1.root());
- {
- let (depth, read_root) = read_entries.next_dfs().unwrap().unwrap();
- assert_eq!(depth, 0);
- assert_eq!(root.tag(), read_root.tag());
- assert!(read_root.has_children());
-
- let producer = match root.get(constants::DW_AT_producer).unwrap() {
- AttributeValue::String(ref producer) => &**producer,
- otherwise => panic!("unexpected {:?}", otherwise),
- };
- assert_eq!(producer, b"root");
- let read_producer = read_root
- .attr_value(constants::DW_AT_producer)
- .unwrap()
- .unwrap();
- assert_eq!(
- dwarf
- .attr_string(&read_unit1, read_producer)
- .unwrap()
- .slice(),
- producer
- );
- }
-
- let mut children = root.children().cloned();
-
- {
- let child = children.next().unwrap();
- assert_eq!(child, UnitEntryId::new(unit1.base_id, 1));
- let child = unit1.get(child);
- let (depth, read_child) = read_entries.next_dfs().unwrap().unwrap();
- assert_eq!(depth, 1);
- assert_eq!(child.tag(), read_child.tag());
- assert!(!read_child.has_children());
-
- let name = match child.get(constants::DW_AT_name).unwrap() {
- AttributeValue::StringRef(name) => *name,
- otherwise => panic!("unexpected {:?}", otherwise),
- };
- let name = strings.get(name);
- assert_eq!(name, b"child1");
- let read_name = read_child
- .attr_value(constants::DW_AT_name)
- .unwrap()
- .unwrap();
- assert_eq!(
- dwarf.attr_string(&read_unit1, read_name).unwrap().slice(),
- name
- );
- }
-
- {
- let child = children.next().unwrap();
- assert_eq!(child, UnitEntryId::new(unit1.base_id, 2));
- let child = unit1.get(child);
- let (depth, read_child) = read_entries.next_dfs().unwrap().unwrap();
- assert_eq!(depth, 0);
- assert_eq!(child.tag(), read_child.tag());
- assert!(!read_child.has_children());
-
- let name = match child.get(constants::DW_AT_name).unwrap() {
- AttributeValue::StringRef(name) => *name,
- otherwise => panic!("unexpected {:?}", otherwise),
- };
- let name = strings.get(name);
- assert_eq!(name, b"child2");
- let read_name = read_child
- .attr_value(constants::DW_AT_name)
- .unwrap()
- .unwrap();
- assert_eq!(
- dwarf.attr_string(&read_unit1, read_name).unwrap().slice(),
- name
- );
- }
-
- assert!(read_entries.next_dfs().unwrap().is_none());
- }
-
- {
- let read_unit2 = read_units.next().unwrap().unwrap();
- let unit2 = units.get(unit2);
- assert_eq!(unit2.version(), read_unit2.version());
- assert_eq!(unit2.address_size(), read_unit2.address_size());
- assert_eq!(unit2.format(), read_unit2.format());
-
- let abbrevs = dwarf.abbreviations(&read_unit2).unwrap();
- let mut read_entries = read_unit2.entries(&abbrevs);
-
- {
- let root = unit2.get(unit2.root());
- let (depth, read_root) = read_entries.next_dfs().unwrap().unwrap();
- assert_eq!(depth, 0);
- assert_eq!(root.tag(), read_root.tag());
- assert!(!read_root.has_children());
- }
-
- assert!(read_entries.next_dfs().unwrap().is_none());
- }
-
- {
- let read_unit3 = read_units.next().unwrap().unwrap();
- let unit3 = units.get(unit3);
- assert_eq!(unit3.version(), read_unit3.version());
- assert_eq!(unit3.address_size(), read_unit3.address_size());
- assert_eq!(unit3.format(), read_unit3.format());
-
- let abbrevs = dwarf.abbreviations(&read_unit3).unwrap();
- let mut read_entries = read_unit3.entries(&abbrevs);
-
- {
- let root = unit3.get(unit3.root());
- let (depth, read_root) = read_entries.next_dfs().unwrap().unwrap();
- assert_eq!(depth, 0);
- assert_eq!(root.tag(), read_root.tag());
- assert!(!read_root.has_children());
- }
-
- assert!(read_entries.next_dfs().unwrap().is_none());
- }
-
- assert!(read_units.next().unwrap().is_none());
-
- let mut convert_line_strings = LineStringTable::default();
- let mut convert_strings = StringTable::default();
- let convert_units = UnitTable::from(
- &dwarf,
- &mut convert_line_strings,
- &mut convert_strings,
- &|address| Some(Address::Constant(address)),
- )
- .unwrap();
- assert_eq!(convert_units.count(), units.count());
-
- for i in 0..convert_units.count() {
- let unit_id = units.id(i);
- let unit = units.get(unit_id);
- let convert_unit_id = convert_units.id(i);
- let convert_unit = convert_units.get(convert_unit_id);
- assert_eq!(convert_unit.version(), unit.version());
- assert_eq!(convert_unit.address_size(), unit.address_size());
- assert_eq!(convert_unit.format(), unit.format());
- assert_eq!(convert_unit.count(), unit.count());
-
- let root = unit.get(unit.root());
- let convert_root = convert_unit.get(convert_unit.root());
- assert_eq!(convert_root.tag(), root.tag());
- for (convert_attr, attr) in convert_root.attrs().zip(root.attrs()) {
- assert_eq!(convert_attr, attr);
- }
- }
- }
-
- #[test]
- fn test_attribute_value() {
- // Create a string table and a string with a non-zero id/offset.
- let mut strings = StringTable::default();
- strings.add("string one");
- let string_id = strings.add("string two");
- let mut debug_str = DebugStr::from(EndianVec::new(LittleEndian));
- let debug_str_offsets = strings.write(&mut debug_str).unwrap();
- let read_debug_str = read::DebugStr::new(debug_str.slice(), LittleEndian);
-
- let mut line_strings = LineStringTable::default();
- line_strings.add("line string one");
- let line_string_id = line_strings.add("line string two");
- let mut debug_line_str = DebugLineStr::from(EndianVec::new(LittleEndian));
- let debug_line_str_offsets = line_strings.write(&mut debug_line_str).unwrap();
- let read_debug_line_str =
- read::DebugLineStr::from(read::EndianSlice::new(debug_line_str.slice(), LittleEndian));
-
- let data = vec![1, 2, 3, 4];
- let read_data = read::EndianSlice::new(&[1, 2, 3, 4], LittleEndian);
-
- let mut expression = Expression::new();
- expression.op_constu(57);
- let read_expression = read::Expression(read::EndianSlice::new(
- &[constants::DW_OP_constu.0, 57],
- LittleEndian,
- ));
-
- let mut ranges = RangeListTable::default();
- let range_id = ranges.add(RangeList(vec![Range::StartEnd {
- begin: Address::Constant(0x1234),
- end: Address::Constant(0x2345),
- }]));
-
- let mut locations = LocationListTable::default();
- let loc_id = locations.add(LocationList(vec![Location::StartEnd {
- begin: Address::Constant(0x1234),
- end: Address::Constant(0x2345),
- data: expression.clone(),
- }]));
-
- 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 sections = Sections::new(EndianVec::new(LittleEndian));
- let range_list_offsets = ranges.write(&mut sections, encoding).unwrap();
- let loc_list_offsets = locations.write(&mut sections, encoding, None).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_debug_loc =
- read::DebugLoc::new(sections.debug_loc.slice(), LittleEndian);
- let read_debug_loclists =
- read::DebugLocLists::new(sections.debug_loclists.slice(), LittleEndian);
-
- let mut units = UnitTable::default();
- let unit = units.add(Unit::new(encoding, LineProgram::none()));
- let unit = units.get(unit);
- let encoding = Encoding {
- format,
- version,
- address_size,
- };
- let from_unit = read::UnitHeader::new(
- encoding,
- 0,
- read::UnitType::Compilation,
- DebugAbbrevOffset(0),
- DebugInfoOffset(0).into(),
- read::EndianSlice::new(&[], LittleEndian),
- );
-
- for &(ref name, ref value, ref expect_value) in &[
- (
- constants::DW_AT_name,
- AttributeValue::Address(Address::Constant(0x1234)),
- read::AttributeValue::Addr(0x1234),
- ),
- (
- constants::DW_AT_name,
- AttributeValue::Block(data.clone()),
- read::AttributeValue::Block(read_data),
- ),
- (
- constants::DW_AT_name,
- AttributeValue::Data1(0x12),
- read::AttributeValue::Data1(0x12),
- ),
- (
- constants::DW_AT_name,
- AttributeValue::Data2(0x1234),
- read::AttributeValue::Data2(0x1234),
- ),
- (
- constants::DW_AT_name,
- AttributeValue::Data4(0x1234),
- read::AttributeValue::Data4(0x1234),
- ),
- (
- constants::DW_AT_name,
- AttributeValue::Data8(0x1234),
- read::AttributeValue::Data8(0x1234),
- ),
- (
- constants::DW_AT_name,
- AttributeValue::Sdata(0x1234),
- read::AttributeValue::Sdata(0x1234),
- ),
- (
- constants::DW_AT_name,
- AttributeValue::Udata(0x1234),
- read::AttributeValue::Udata(0x1234),
- ),
- (
- constants::DW_AT_name,
- AttributeValue::Exprloc(expression.clone()),
- read::AttributeValue::Exprloc(read_expression),
- ),
- (
- constants::DW_AT_name,
- AttributeValue::Flag(false),
- read::AttributeValue::Flag(false),
- ),
- /*
- (
- constants::DW_AT_name,
- AttributeValue::FlagPresent,
- read::AttributeValue::Flag(true),
- ),
- */
- (
- constants::DW_AT_name,
- AttributeValue::DebugInfoRefSup(DebugInfoOffset(0x1234)),
- read::AttributeValue::DebugInfoRefSup(DebugInfoOffset(0x1234)),
- ),
- (
- constants::DW_AT_location,
- AttributeValue::LocationListRef(loc_id),
- read::AttributeValue::SecOffset(loc_list_offsets.get(loc_id).0),
- ),
- (
- constants::DW_AT_macro_info,
- AttributeValue::DebugMacinfoRef(DebugMacinfoOffset(0x1234)),
- read::AttributeValue::SecOffset(0x1234),
- ),
- (
- constants::DW_AT_macros,
- AttributeValue::DebugMacroRef(DebugMacroOffset(0x1234)),
- read::AttributeValue::SecOffset(0x1234),
- ),
- (
- constants::DW_AT_ranges,
- AttributeValue::RangeListRef(range_id),
- read::AttributeValue::SecOffset(range_list_offsets.get(range_id).0),
- ),
- (
- constants::DW_AT_name,
- AttributeValue::DebugTypesRef(DebugTypeSignature(0x1234)),
- read::AttributeValue::DebugTypesRef(DebugTypeSignature(0x1234)),
- ),
- (
- constants::DW_AT_name,
- AttributeValue::StringRef(string_id),
- read::AttributeValue::DebugStrRef(debug_str_offsets.get(string_id)),
- ),
- (
- constants::DW_AT_name,
- AttributeValue::DebugStrRefSup(DebugStrOffset(0x1234)),
- read::AttributeValue::DebugStrRefSup(DebugStrOffset(0x1234)),
- ),
- (
- constants::DW_AT_name,
- AttributeValue::LineStringRef(line_string_id),
- read::AttributeValue::DebugLineStrRef(
- debug_line_str_offsets.get(line_string_id),
- ),
- ),
- (
- constants::DW_AT_name,
- AttributeValue::String(data.clone()),
- read::AttributeValue::String(read_data),
- ),
- (
- constants::DW_AT_encoding,
- AttributeValue::Encoding(constants::DwAte(0x12)),
- read::AttributeValue::Udata(0x12),
- ),
- (
- constants::DW_AT_decimal_sign,
- AttributeValue::DecimalSign(constants::DwDs(0x12)),
- read::AttributeValue::Udata(0x12),
- ),
- (
- constants::DW_AT_endianity,
- AttributeValue::Endianity(constants::DwEnd(0x12)),
- read::AttributeValue::Udata(0x12),
- ),
- (
- constants::DW_AT_accessibility,
- AttributeValue::Accessibility(constants::DwAccess(0x12)),
- read::AttributeValue::Udata(0x12),
- ),
- (
- constants::DW_AT_visibility,
- AttributeValue::Visibility(constants::DwVis(0x12)),
- read::AttributeValue::Udata(0x12),
- ),
- (
- constants::DW_AT_virtuality,
- AttributeValue::Virtuality(constants::DwVirtuality(0x12)),
- read::AttributeValue::Udata(0x12),
- ),
- (
- constants::DW_AT_language,
- AttributeValue::Language(constants::DwLang(0x12)),
- read::AttributeValue::Udata(0x12),
- ),
- (
- constants::DW_AT_address_class,
- AttributeValue::AddressClass(constants::DwAddr(0x12)),
- read::AttributeValue::Udata(0x12),
- ),
- (
- constants::DW_AT_identifier_case,
- AttributeValue::IdentifierCase(constants::DwId(0x12)),
- read::AttributeValue::Udata(0x12),
- ),
- (
- constants::DW_AT_calling_convention,
- AttributeValue::CallingConvention(constants::DwCc(0x12)),
- read::AttributeValue::Udata(0x12),
- ),
- (
- constants::DW_AT_ordering,
- AttributeValue::Ordering(constants::DwOrd(0x12)),
- read::AttributeValue::Udata(0x12),
- ),
- (
- constants::DW_AT_inline,
- AttributeValue::Inline(constants::DwInl(0x12)),
- read::AttributeValue::Udata(0x12),
- ),
- ][..]
- {
- let form = value.form(encoding).unwrap();
- let attr = Attribute {
- name: *name,
- value: value.clone(),
- };
-
- let offsets = UnitOffsets::none();
- let line_program_offset = None;
- let mut debug_info_refs = Vec::new();
- let mut unit_refs = Vec::new();
- let mut debug_info = DebugInfo::from(EndianVec::new(LittleEndian));
- attr.value
- .write(
- &mut debug_info,
- &mut debug_info_refs,
- &mut unit_refs,
- &unit,
- &offsets,
- line_program_offset,
- &debug_line_str_offsets,
- &debug_str_offsets,
- &range_list_offsets,
- &loc_list_offsets,
- )
- .unwrap();
-
- let spec = read::AttributeSpecification::new(*name, form, None);
- let mut r = read::EndianSlice::new(debug_info.slice(), LittleEndian);
- let read_attr = read::parse_attribute(&mut r, encoding, spec).unwrap();
- let read_value = &read_attr.raw_value();
- // read::AttributeValue is invariant in the lifetime of R.
- // The lifetimes here are all okay, so transmute it.
- let read_value = unsafe {
- mem::transmute::<
- &read::AttributeValue<read::EndianSlice<LittleEndian>>,
- &read::AttributeValue<read::EndianSlice<LittleEndian>>,
- >(read_value)
- };
- assert_eq!(read_value, expect_value);
-
- let dwarf = read::Dwarf {
- debug_str: read_debug_str.clone(),
- debug_line_str: read_debug_line_str.clone(),
- ranges: read::RangeLists::new(read_debug_ranges, read_debug_rnglists),
- locations: read::LocationLists::new(
- read_debug_loc,
- read_debug_loclists,
- ),
- ..Default::default()
- };
-
- let unit = read::Unit {
- header: from_unit,
- 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 mut context = convert::ConvertUnitContext {
- dwarf: &dwarf,
- unit: &unit,
- line_strings: &mut line_strings,
- strings: &mut strings,
- ranges: &mut ranges,
- 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_attr =
- Attribute::from(&mut context, &read_attr).unwrap().unwrap();
- assert_eq!(convert_attr, attr);
- }
- }
- }
- }
- }
-
- #[test]
- fn test_unit_ref() {
- let mut units = UnitTable::default();
- let unit_id1 = units.add(Unit::new(
- Encoding {
- version: 4,
- address_size: 8,
- format: Format::Dwarf32,
- },
- LineProgram::none(),
- ));
- assert_eq!(unit_id1, units.id(0));
- let unit_id2 = units.add(Unit::new(
- Encoding {
- version: 2,
- address_size: 4,
- format: Format::Dwarf64,
- },
- LineProgram::none(),
- ));
- assert_eq!(unit_id2, units.id(1));
- let unit1_child1 = UnitEntryId::new(units.get(unit_id1).base_id, 1);
- let unit1_child2 = UnitEntryId::new(units.get(unit_id1).base_id, 2);
- let unit2_child1 = UnitEntryId::new(units.get(unit_id2).base_id, 1);
- let unit2_child2 = UnitEntryId::new(units.get(unit_id2).base_id, 2);
- {
- let unit1 = units.get_mut(unit_id1);
- let root = unit1.root();
- let child_id1 = unit1.add(root, constants::DW_TAG_subprogram);
- assert_eq!(child_id1, unit1_child1);
- let child_id2 = unit1.add(root, constants::DW_TAG_subprogram);
- assert_eq!(child_id2, unit1_child2);
- {
- let child1 = unit1.get_mut(child_id1);
- child1.set(constants::DW_AT_type, AttributeValue::UnitRef(child_id2));
- }
- {
- let child2 = unit1.get_mut(child_id2);
- child2.set(
- constants::DW_AT_type,
- AttributeValue::DebugInfoRef(Reference::Entry(unit_id2, unit2_child1)),
- );
- }
- }
- {
- let unit2 = units.get_mut(unit_id2);
- let root = unit2.root();
- let child_id1 = unit2.add(root, constants::DW_TAG_subprogram);
- assert_eq!(child_id1, unit2_child1);
- let child_id2 = unit2.add(root, constants::DW_TAG_subprogram);
- assert_eq!(child_id2, unit2_child2);
- {
- let child1 = unit2.get_mut(child_id1);
- child1.set(constants::DW_AT_type, AttributeValue::UnitRef(child_id2));
- }
- {
- let child2 = unit2.get_mut(child_id2);
- child2.set(
- constants::DW_AT_type,
- AttributeValue::DebugInfoRef(Reference::Entry(unit_id1, unit1_child1)),
- );
- }
- }
-
- let debug_line_str_offsets = DebugLineStrOffsets::none();
- let debug_str_offsets = DebugStrOffsets::none();
- let mut sections = Sections::new(EndianVec::new(LittleEndian));
- let debug_info_offsets = units
- .write(&mut sections, &debug_line_str_offsets, &debug_str_offsets)
- .unwrap();
-
- println!("{:?}", sections.debug_info);
- println!("{:?}", sections.debug_abbrev);
-
- let dwarf = read::Dwarf {
- debug_abbrev: read::DebugAbbrev::new(sections.debug_abbrev.slice(), LittleEndian),
- debug_info: read::DebugInfo::new(sections.debug_info.slice(), LittleEndian),
- ..Default::default()
- };
-
- let mut read_units = dwarf.units();
- {
- let read_unit1 = read_units.next().unwrap().unwrap();
- assert_eq!(
- read_unit1.offset(),
- debug_info_offsets.unit(unit_id1).into()
- );
-
- let abbrevs = dwarf.abbreviations(&read_unit1).unwrap();
- let mut read_entries = read_unit1.entries(&abbrevs);
- {
- let (_, _read_root) = read_entries.next_dfs().unwrap().unwrap();
- }
- {
- let (_, read_child1) = read_entries.next_dfs().unwrap().unwrap();
- let offset = debug_info_offsets
- .entry(unit_id1, unit1_child2)
- .to_unit_offset(&read_unit1)
- .unwrap();
- assert_eq!(
- read_child1.attr_value(constants::DW_AT_type).unwrap(),
- Some(read::AttributeValue::UnitRef(offset))
- );
- }
- {
- let (_, read_child2) = read_entries.next_dfs().unwrap().unwrap();
- let offset = debug_info_offsets.entry(unit_id2, unit2_child1);
- assert_eq!(
- read_child2.attr_value(constants::DW_AT_type).unwrap(),
- Some(read::AttributeValue::DebugInfoRef(offset))
- );
- }
- }
- {
- let read_unit2 = read_units.next().unwrap().unwrap();
- assert_eq!(
- read_unit2.offset(),
- debug_info_offsets.unit(unit_id2).into()
- );
-
- let abbrevs = dwarf.abbreviations(&read_unit2).unwrap();
- let mut read_entries = read_unit2.entries(&abbrevs);
- {
- let (_, _read_root) = read_entries.next_dfs().unwrap().unwrap();
- }
- {
- let (_, read_child1) = read_entries.next_dfs().unwrap().unwrap();
- let offset = debug_info_offsets
- .entry(unit_id2, unit2_child2)
- .to_unit_offset(&read_unit2)
- .unwrap();
- assert_eq!(
- read_child1.attr_value(constants::DW_AT_type).unwrap(),
- Some(read::AttributeValue::UnitRef(offset))
- );
- }
- {
- let (_, read_child2) = read_entries.next_dfs().unwrap().unwrap();
- let offset = debug_info_offsets.entry(unit_id1, unit1_child1);
- assert_eq!(
- read_child2.attr_value(constants::DW_AT_type).unwrap(),
- Some(read::AttributeValue::DebugInfoRef(offset))
- );
- }
- }
-
- let mut convert_line_strings = LineStringTable::default();
- let mut convert_strings = StringTable::default();
- let convert_units = UnitTable::from(
- &dwarf,
- &mut convert_line_strings,
- &mut convert_strings,
- &|address| Some(Address::Constant(address)),
- )
- .unwrap();
- assert_eq!(convert_units.count(), units.count());
-
- for i in 0..convert_units.count() {
- let unit = units.get(units.id(i));
- let convert_unit = convert_units.get(convert_units.id(i));
- assert_eq!(convert_unit.version(), unit.version());
- assert_eq!(convert_unit.address_size(), unit.address_size());
- assert_eq!(convert_unit.format(), unit.format());
- assert_eq!(convert_unit.count(), unit.count());
-
- let root = unit.get(unit.root());
- let convert_root = convert_unit.get(convert_unit.root());
- assert_eq!(convert_root.tag(), root.tag());
- for (convert_attr, attr) in convert_root.attrs().zip(root.attrs()) {
- assert_eq!(convert_attr, attr);
- }
-
- let child1 = unit.get(UnitEntryId::new(unit.base_id, 1));
- let convert_child1 = convert_unit.get(UnitEntryId::new(convert_unit.base_id, 1));
- assert_eq!(convert_child1.tag(), child1.tag());
- for (convert_attr, attr) in convert_child1.attrs().zip(child1.attrs()) {
- assert_eq!(convert_attr.name, attr.name);
- match (convert_attr.value.clone(), attr.value.clone()) {
- (
- AttributeValue::DebugInfoRef(Reference::Entry(convert_unit, convert_entry)),
- AttributeValue::DebugInfoRef(Reference::Entry(unit, entry)),
- ) => {
- assert_eq!(convert_unit.index, unit.index);
- assert_eq!(convert_entry.index, entry.index);
- }
- (AttributeValue::UnitRef(convert_id), AttributeValue::UnitRef(id)) => {
- assert_eq!(convert_id.index, id.index);
- }
- (convert_value, value) => assert_eq!(convert_value, value),
- }
- }
-
- let child2 = unit.get(UnitEntryId::new(unit.base_id, 2));
- let convert_child2 = convert_unit.get(UnitEntryId::new(convert_unit.base_id, 2));
- assert_eq!(convert_child2.tag(), child2.tag());
- for (convert_attr, attr) in convert_child2.attrs().zip(child2.attrs()) {
- assert_eq!(convert_attr.name, attr.name);
- match (convert_attr.value.clone(), attr.value.clone()) {
- (
- AttributeValue::DebugInfoRef(Reference::Entry(convert_unit, convert_entry)),
- AttributeValue::DebugInfoRef(Reference::Entry(unit, entry)),
- ) => {
- assert_eq!(convert_unit.index, unit.index);
- assert_eq!(convert_entry.index, entry.index);
- }
- (AttributeValue::UnitRef(convert_id), AttributeValue::UnitRef(id)) => {
- assert_eq!(convert_id.index, id.index);
- }
- (convert_value, value) => assert_eq!(convert_value, value),
- }
- }
- }
- }
-
- #[test]
- fn test_sibling() {
- fn add_child(
- unit: &mut Unit,
- parent: UnitEntryId,
- tag: constants::DwTag,
- name: &str,
- ) -> UnitEntryId {
- let id = unit.add(parent, tag);
- let child = unit.get_mut(id);
- child.set(constants::DW_AT_name, AttributeValue::String(name.into()));
- child.set_sibling(true);
- id
- }
-
- fn add_children(units: &mut UnitTable, unit_id: UnitId) {
- let unit = units.get_mut(unit_id);
- let root = unit.root();
- let child1 = add_child(unit, root, constants::DW_TAG_subprogram, "child1");
- add_child(unit, child1, constants::DW_TAG_variable, "grandchild1");
- add_child(unit, root, constants::DW_TAG_subprogram, "child2");
- add_child(unit, root, constants::DW_TAG_subprogram, "child3");
- }
-
- fn next_child<R: read::Reader<Offset = usize>>(
- entries: &mut read::EntriesCursor<R>,
- ) -> (read::UnitOffset, Option<read::UnitOffset>) {
- let (_, entry) = entries.next_dfs().unwrap().unwrap();
- let offset = entry.offset();
- let sibling =
- entry
- .attr_value(constants::DW_AT_sibling)
- .unwrap()
- .map(|attr| match attr {
- read::AttributeValue::UnitRef(offset) => offset,
- _ => panic!("bad sibling value"),
- });
- (offset, sibling)
- }
-
- fn check_sibling<R: read::Reader<Offset = usize>>(
- unit: &read::UnitHeader<R>,
- debug_abbrev: &read::DebugAbbrev<R>,
- ) {
- let abbrevs = unit.abbreviations(debug_abbrev).unwrap();
- let mut entries = unit.entries(&abbrevs);
- // root
- entries.next_dfs().unwrap().unwrap();
- // child1
- let (_, sibling1) = next_child(&mut entries);
- // grandchild1
- entries.next_dfs().unwrap().unwrap();
- // child2
- let (offset2, sibling2) = next_child(&mut entries);
- // child3
- let (_, _) = next_child(&mut entries);
- assert_eq!(sibling1, Some(offset2));
- assert_eq!(sibling2, None);
- }
-
- let encoding = Encoding {
- format: Format::Dwarf32,
- version: 4,
- address_size: 8,
- };
- let mut units = UnitTable::default();
- let unit_id1 = units.add(Unit::new(encoding, LineProgram::none()));
- add_children(&mut units, unit_id1);
- let unit_id2 = units.add(Unit::new(encoding, LineProgram::none()));
- add_children(&mut units, unit_id2);
-
- let debug_line_str_offsets = DebugLineStrOffsets::none();
- let debug_str_offsets = DebugStrOffsets::none();
- let mut sections = Sections::new(EndianVec::new(LittleEndian));
- units
- .write(&mut sections, &debug_line_str_offsets, &debug_str_offsets)
- .unwrap();
-
- println!("{:?}", sections.debug_info);
- println!("{:?}", sections.debug_abbrev);
-
- let read_debug_info = read::DebugInfo::new(sections.debug_info.slice(), LittleEndian);
- let read_debug_abbrev = read::DebugAbbrev::new(sections.debug_abbrev.slice(), LittleEndian);
- let mut read_units = read_debug_info.units();
- check_sibling(&read_units.next().unwrap().unwrap(), &read_debug_abbrev);
- check_sibling(&read_units.next().unwrap().unwrap(), &read_debug_abbrev);
- }
-
- #[test]
- fn test_line_ref() {
- 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,
- };
-
- // The line program we'll be referencing.
- let mut line_program = LineProgram::new(
- encoding,
- LineEncoding::default(),
- LineString::String(b"comp_dir".to_vec()),
- LineString::String(b"comp_name".to_vec()),
- None,
- );
- let dir = line_program.default_directory();
- let file1 =
- line_program.add_file(LineString::String(b"file1".to_vec()), dir, None);
- let file2 =
- line_program.add_file(LineString::String(b"file2".to_vec()), dir, None);
-
- // Write, read, and convert the line program, so that we have the info
- // required to convert the attributes.
- let line_strings = DebugLineStrOffsets::none();
- let strings = DebugStrOffsets::none();
- let mut debug_line = DebugLine::from(EndianVec::new(LittleEndian));
- let line_program_offset = line_program
- .write(&mut debug_line, encoding, &line_strings, &strings)
- .unwrap();
- let read_debug_line = read::DebugLine::new(debug_line.slice(), LittleEndian);
- let read_line_program = read_debug_line
- .program(
- line_program_offset,
- address_size,
- Some(read::EndianSlice::new(b"comp_dir", LittleEndian)),
- Some(read::EndianSlice::new(b"comp_name", LittleEndian)),
- )
- .unwrap();
- let dwarf = read::Dwarf::default();
- let mut convert_line_strings = LineStringTable::default();
- let mut convert_strings = StringTable::default();
- let (_, line_program_files) = LineProgram::from(
- read_line_program,
- &dwarf,
- &mut convert_line_strings,
- &mut convert_strings,
- &|address| Some(Address::Constant(address)),
- )
- .unwrap();
-
- // Fake the unit.
- let mut units = UnitTable::default();
- let unit = units.add(Unit::new(encoding, LineProgram::none()));
- let unit = units.get(unit);
- let from_unit = read::UnitHeader::new(
- encoding,
- 0,
- read::UnitType::Compilation,
- DebugAbbrevOffset(0),
- DebugInfoOffset(0).into(),
- read::EndianSlice::new(&[], LittleEndian),
- );
-
- for &(ref name, ref value, ref expect_value) in &[
- (
- constants::DW_AT_stmt_list,
- AttributeValue::LineProgramRef,
- read::AttributeValue::SecOffset(line_program_offset.0),
- ),
- (
- constants::DW_AT_decl_file,
- AttributeValue::FileIndex(Some(file1)),
- read::AttributeValue::Udata(file1.raw()),
- ),
- (
- constants::DW_AT_decl_file,
- AttributeValue::FileIndex(Some(file2)),
- read::AttributeValue::Udata(file2.raw()),
- ),
- ][..]
- {
- let mut ranges = RangeListTable::default();
- let mut locations = LocationListTable::default();
- let mut strings = StringTable::default();
- let mut line_strings = LineStringTable::default();
-
- let form = value.form(encoding).unwrap();
- let attr = Attribute {
- name: *name,
- value: value.clone(),
- };
-
- let mut debug_info_refs = Vec::new();
- let mut unit_refs = Vec::new();
- let mut debug_info = DebugInfo::from(EndianVec::new(LittleEndian));
- let offsets = UnitOffsets::none();
- let debug_line_str_offsets = DebugLineStrOffsets::none();
- let debug_str_offsets = DebugStrOffsets::none();
- let range_list_offsets = RangeListOffsets::none();
- let loc_list_offsets = LocationListOffsets::none();
- attr.value
- .write(
- &mut debug_info,
- &mut debug_info_refs,
- &mut unit_refs,
- &unit,
- &offsets,
- Some(line_program_offset),
- &debug_line_str_offsets,
- &debug_str_offsets,
- &range_list_offsets,
- &loc_list_offsets,
- )
- .unwrap();
-
- let spec = read::AttributeSpecification::new(*name, form, None);
- let mut r = read::EndianSlice::new(debug_info.slice(), LittleEndian);
- let read_attr = read::parse_attribute(&mut r, encoding, spec).unwrap();
- let read_value = &read_attr.raw_value();
- // read::AttributeValue is invariant in the lifetime of R.
- // The lifetimes here are all okay, so transmute it.
- let read_value = unsafe {
- mem::transmute::<
- &read::AttributeValue<read::EndianSlice<LittleEndian>>,
- &read::AttributeValue<read::EndianSlice<LittleEndian>>,
- >(read_value)
- };
- assert_eq!(read_value, expect_value);
-
- let unit = read::Unit {
- header: from_unit,
- 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 mut context = convert::ConvertUnitContext {
- dwarf: &dwarf,
- unit: &unit,
- line_strings: &mut line_strings,
- strings: &mut strings,
- ranges: &mut ranges,
- locations: &mut locations,
- convert_address: &|address| Some(Address::Constant(address)),
- base_address: Address::Constant(0),
- line_program_offset: Some(line_program_offset),
- line_program_files: line_program_files.clone(),
- entry_ids: &HashMap::new(),
- };
-
- let convert_attr =
- Attribute::from(&mut context, &read_attr).unwrap().unwrap();
- assert_eq!(convert_attr, attr);
- }
- }
- }
- }
- }
-
- #[test]
- fn test_line_program_used() {
- for used in vec![false, true] {
- let encoding = Encoding {
- format: Format::Dwarf32,
- version: 5,
- address_size: 8,
- };
-
- let line_program = LineProgram::new(
- encoding,
- LineEncoding::default(),
- LineString::String(b"comp_dir".to_vec()),
- LineString::String(b"comp_name".to_vec()),
- None,
- );
-
- let mut unit = Unit::new(encoding, line_program);
- let file_id = if used { Some(FileId::new(0)) } else { None };
- let root = unit.root();
- unit.get_mut(root).set(
- constants::DW_AT_decl_file,
- AttributeValue::FileIndex(file_id),
- );
-
- let mut units = UnitTable::default();
- units.add(unit);
-
- let debug_line_str_offsets = DebugLineStrOffsets::none();
- let debug_str_offsets = DebugStrOffsets::none();
- let mut sections = Sections::new(EndianVec::new(LittleEndian));
- units
- .write(&mut sections, &debug_line_str_offsets, &debug_str_offsets)
- .unwrap();
- assert_eq!(!used, sections.debug_line.slice().is_empty());
- }
- }
-
- #[test]
- fn test_delete_child() {
- fn set_name(unit: &mut Unit, id: UnitEntryId, name: &str) {
- let entry = unit.get_mut(id);
- entry.set(constants::DW_AT_name, AttributeValue::String(name.into()));
- }
- fn check_name<R: read::Reader>(
- entry: &read::DebuggingInformationEntry<R>,
- debug_str: &read::DebugStr<R>,
- name: &str,
- ) {
- let name_attr = entry.attr(constants::DW_AT_name).unwrap().unwrap();
- let entry_name = name_attr.string_value(debug_str).unwrap();
- let entry_name_str = entry_name.to_string().unwrap();
- assert_eq!(entry_name_str, name);
- }
- let encoding = Encoding {
- format: Format::Dwarf32,
- version: 4,
- address_size: 8,
- };
- let mut dwarf = DwarfUnit::new(encoding);
- let root = dwarf.unit.root();
-
- // Add and delete entries in the root unit
- let child1 = dwarf.unit.add(root, constants::DW_TAG_subprogram);
- set_name(&mut dwarf.unit, child1, "child1");
- let grandchild1 = dwarf.unit.add(child1, constants::DW_TAG_variable);
- set_name(&mut dwarf.unit, grandchild1, "grandchild1");
- let child2 = dwarf.unit.add(root, constants::DW_TAG_subprogram);
- set_name(&mut dwarf.unit, child2, "child2");
- // This deletes both `child1` and its child `grandchild1`
- dwarf.unit.get_mut(root).delete_child(child1);
- let child3 = dwarf.unit.add(root, constants::DW_TAG_subprogram);
- set_name(&mut dwarf.unit, child3, "child3");
- let child4 = dwarf.unit.add(root, constants::DW_TAG_subprogram);
- set_name(&mut dwarf.unit, child4, "child4");
- let grandchild4 = dwarf.unit.add(child4, constants::DW_TAG_variable);
- set_name(&mut dwarf.unit, grandchild4, "grandchild4");
- dwarf.unit.get_mut(child4).delete_child(grandchild4);
-
- let mut sections = Sections::new(EndianVec::new(LittleEndian));
-
- // Write DWARF data which should only include `child2`, `child3` and `child4`
- dwarf.write(&mut sections).unwrap();
-
- let read_debug_info = read::DebugInfo::new(sections.debug_info.slice(), LittleEndian);
- let read_debug_abbrev = read::DebugAbbrev::new(sections.debug_abbrev.slice(), LittleEndian);
- let read_debug_str = read::DebugStr::new(sections.debug_str.slice(), LittleEndian);
- let read_unit = read_debug_info.units().next().unwrap().unwrap();
- let abbrevs = read_unit.abbreviations(&read_debug_abbrev).unwrap();
- let mut entries = read_unit.entries(&abbrevs);
- // root
- entries.next_dfs().unwrap().unwrap();
- // child2
- let (_, read_child2) = entries.next_dfs().unwrap().unwrap();
- check_name(read_child2, &read_debug_str, "child2");
- // child3
- let (_, read_child3) = entries.next_dfs().unwrap().unwrap();
- check_name(read_child3, &read_debug_str, "child3");
- // child4
- let (_, read_child4) = entries.next_dfs().unwrap().unwrap();
- check_name(read_child4, &read_debug_str, "child4");
- // There should be no more entries
- assert!(entries.next_dfs().unwrap().is_none());
- }
-}
diff --git a/vendor/gimli/src/write/writer.rs b/vendor/gimli/src/write/writer.rs
deleted file mode 100644
index 1ce3641..0000000
--- a/vendor/gimli/src/write/writer.rs
+++ /dev/null
@@ -1,494 +0,0 @@
-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]
- );
- }
-}