Skip to main content

gimli/write/
abbrev.rs

1use alloc::vec::Vec;
2use core::ops::{Deref, DerefMut};
3
4use crate::common::{DebugAbbrevOffset, SectionId};
5use crate::constants;
6use crate::write::{FnvIndexSet, Result, Section, Writer};
7
8/// A table of abbreviations that will be stored in a `.debug_abbrev` section.
9// Requirements:
10// - values are `Abbreviation`
11// - insertion returns an abbreviation code for use in writing a DIE
12// - inserting a duplicate returns the code of the existing value
13#[derive(Debug, Default)]
14pub(crate) struct AbbreviationTable {
15    abbrevs: FnvIndexSet<Abbreviation>,
16}
17
18impl AbbreviationTable {
19    /// Add an abbreviation to the table and return its code.
20    pub fn add(&mut self, abbrev: Abbreviation) -> u64 {
21        let (code, _) = self.abbrevs.insert_full(abbrev);
22        // Code must be non-zero
23        (code + 1) as u64
24    }
25
26    /// Write the abbreviation table to the `.debug_abbrev` section.
27    pub fn write<W: Writer>(&self, w: &mut DebugAbbrev<W>) -> Result<()> {
28        for (code, abbrev) in self.abbrevs.iter().enumerate() {
29            w.write_uleb128((code + 1) as u64)?;
30            abbrev.write(w)?;
31        }
32        // Null abbreviation code
33        w.write_u8(0)
34    }
35}
36
37/// An abbreviation describes the shape of a `DebuggingInformationEntry`'s type:
38/// its tag type, whether it has children, and its set of attributes.
39#[derive(Debug, Clone, PartialEq, Eq, Hash)]
40pub(crate) struct Abbreviation {
41    tag: constants::DwTag,
42    has_children: bool,
43    attributes: Vec<AttributeSpecification>,
44}
45
46impl Abbreviation {
47    /// Construct a new `Abbreviation`.
48    #[inline]
49    pub fn new(
50        tag: constants::DwTag,
51        has_children: bool,
52        attributes: Vec<AttributeSpecification>,
53    ) -> Abbreviation {
54        Abbreviation {
55            tag,
56            has_children,
57            attributes,
58        }
59    }
60
61    /// Write the abbreviation to the `.debug_abbrev` section.
62    pub fn write<W: Writer>(&self, w: &mut DebugAbbrev<W>) -> Result<()> {
63        w.write_uleb128(self.tag.0.into())?;
64        w.write_u8(if self.has_children {
65            constants::DW_CHILDREN_yes.0
66        } else {
67            constants::DW_CHILDREN_no.0
68        })?;
69        for attr in &self.attributes {
70            attr.write(w)?;
71        }
72        // Null name and form
73        w.write_u8(0)?;
74        w.write_u8(0)
75    }
76}
77
78/// The description of an attribute in an abbreviated type.
79// TODO: support implicit const
80#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
81pub(crate) struct AttributeSpecification {
82    name: constants::DwAt,
83    form: constants::DwForm,
84    implicit_const_value: i64,
85}
86
87impl AttributeSpecification {
88    /// Construct a new `AttributeSpecification`.
89    #[inline]
90    pub fn new(
91        name: constants::DwAt,
92        form: constants::DwForm,
93        implicit_const_value: Option<i64>,
94    ) -> AttributeSpecification {
95        debug_assert_eq!(
96            form == constants::DW_FORM_implicit_const,
97            implicit_const_value.is_some()
98        );
99        AttributeSpecification {
100            name,
101            form,
102            implicit_const_value: implicit_const_value.unwrap_or(0),
103        }
104    }
105
106    /// Write the attribute specification to the `.debug_abbrev` section.
107    #[inline]
108    pub fn write<W: Writer>(&self, w: &mut DebugAbbrev<W>) -> Result<()> {
109        w.write_uleb128(self.name.0.into())?;
110        w.write_uleb128(self.form.0.into())?;
111        if self.form == constants::DW_FORM_implicit_const {
112            w.write_sleb128(self.implicit_const_value)?;
113        }
114        Ok(())
115    }
116}
117
118define_section!(
119    DebugAbbrev,
120    DebugAbbrevOffset,
121    "A writable `.debug_abbrev` section."
122);
123
124#[cfg(test)]
125#[cfg(feature = "read")]
126mod tests {
127    use super::*;
128    use crate::LittleEndian;
129    use crate::constants;
130    use crate::read;
131    use crate::write::EndianVec;
132
133    #[test]
134    fn test_abbreviation_table() {
135        let mut abbrevs = AbbreviationTable::default();
136        let abbrev1 = Abbreviation::new(
137            constants::DW_TAG_subprogram,
138            false,
139            vec![AttributeSpecification::new(
140                constants::DW_AT_name,
141                constants::DW_FORM_string,
142                None,
143            )],
144        );
145        let abbrev2 = Abbreviation::new(
146            constants::DW_TAG_compile_unit,
147            true,
148            vec![
149                AttributeSpecification::new(
150                    constants::DW_AT_producer,
151                    constants::DW_FORM_strp,
152                    None,
153                ),
154                AttributeSpecification::new(
155                    constants::DW_AT_language,
156                    constants::DW_FORM_data2,
157                    None,
158                ),
159            ],
160        );
161        let code1 = abbrevs.add(abbrev1.clone());
162        assert_eq!(code1, 1);
163        let code2 = abbrevs.add(abbrev2.clone());
164        assert_eq!(code2, 2);
165        assert_eq!(abbrevs.add(abbrev1.clone()), code1);
166        assert_eq!(abbrevs.add(abbrev2.clone()), code2);
167
168        let mut debug_abbrev = DebugAbbrev::from(EndianVec::new(LittleEndian));
169        let debug_abbrev_offset = debug_abbrev.offset();
170        assert_eq!(debug_abbrev_offset, DebugAbbrevOffset(0));
171        abbrevs.write(&mut debug_abbrev).unwrap();
172        assert_eq!(debug_abbrev.offset(), DebugAbbrevOffset(17));
173
174        let read_debug_abbrev = read::DebugAbbrev::new(debug_abbrev.slice(), LittleEndian);
175        let read_abbrevs = read_debug_abbrev
176            .abbreviations(debug_abbrev_offset)
177            .unwrap();
178
179        let read_abbrev1 = read_abbrevs.get(code1).unwrap();
180        assert_eq!(abbrev1.tag, read_abbrev1.tag());
181        assert_eq!(abbrev1.has_children, read_abbrev1.has_children());
182        assert_eq!(abbrev1.attributes.len(), read_abbrev1.attributes().len());
183        assert_eq!(
184            abbrev1.attributes[0].name,
185            read_abbrev1.attributes()[0].name()
186        );
187        assert_eq!(
188            abbrev1.attributes[0].form,
189            read_abbrev1.attributes()[0].form()
190        );
191
192        let read_abbrev2 = read_abbrevs.get(code2).unwrap();
193        assert_eq!(abbrev2.tag, read_abbrev2.tag());
194        assert_eq!(abbrev2.has_children, read_abbrev2.has_children());
195        assert_eq!(abbrev2.attributes.len(), read_abbrev2.attributes().len());
196        assert_eq!(
197            abbrev2.attributes[0].name,
198            read_abbrev2.attributes()[0].name()
199        );
200        assert_eq!(
201            abbrev2.attributes[0].form,
202            read_abbrev2.attributes()[0].form()
203        );
204        assert_eq!(
205            abbrev2.attributes[1].name,
206            read_abbrev2.attributes()[1].name()
207        );
208        assert_eq!(
209            abbrev2.attributes[1].form,
210            read_abbrev2.attributes()[1].form()
211        );
212    }
213}