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(val: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}
189