gimli/write/
abbrev.rs

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