1use std;
2use std::io::Write;
3use byteorder::WriteBytesExt;
4
5use super::*;
6use leb128;
7
8#[derive(Debug)]
9pub enum WriteError {
10 Io(std::io::Error),
11 Invalid(String),
12 Unsupported(String),
13}
14
15impl std::convert::From<std::io::Error> for WriteError {
16 fn from(e: std::io::Error) -> Self {
17 WriteError::Io(e)
18 }
19}
20
21impl<'a> CompilationUnit<'a> {
22 pub fn write<W: Write>(&self, w: &mut W) -> Result<(), WriteError> {
23 let len = self.base_len();
24 match self.offset_size {
25 4 => {
26 if len >= 0xfffffff0 {
27 return Err(WriteError::Invalid(format!("compilation unit length {}", len)));
28 }
29 try!(self.endian.write_u32(w, len as u32));
30 }
31 8 => {
32 try!(self.endian.write_u32(w, 0xffffffff));
33 try!(self.endian.write_u64(w, len as u64));
34 }
35 _ => return Err(WriteError::Unsupported(format!("offset size {}", self.offset_size))),
36 };
37 try!(self.endian.write_u16(w, self.version));
38 try!(write_offset(w, self.endian, self.offset_size, self.abbrev_offset));
39 try!(w.write_u8(self.address_size));
40 try!(w.write_all(&*self.data));
41 Ok(())
42 }
43}
44
45impl<'a, 'b> Die<'a> {
46 pub fn write_null(unit: &mut CompilationUnit<'b>) -> std::io::Result<()> {
47 let w = unit.data.to_mut();
48 leb128::write_u64(w, 0)
49 }
50
51 pub fn write(
52 &self,
53 unit: &mut CompilationUnit<'b>,
54 abbrev_hash: &AbbrevHash,
55 ) -> Result<(), WriteError> {
56 if self.code == 0 {
57 try!(Die::write_null(unit));
58 return Ok(());
59 }
60 let abbrev = match abbrev_hash.get(self.code) {
61 Some(abbrev) => abbrev,
62 None => return Err(WriteError::Invalid(format!("missing abbrev {}", self.code))),
63 };
64 if self.children != abbrev.children {
65 return Err(WriteError::Invalid("die/abbrev children mismatch".to_string()));
66 }
67 if self.attributes.len() != abbrev.attributes.len() {
68 return Err(WriteError::Invalid("die/abbrev attribute length mismatch".to_string()));
69 }
70 try!(leb128::write_u64(unit.data.to_mut(), abbrev.code));
71 for (attribute, abbrev_attribute) in self.attributes.iter().zip(&abbrev.attributes) {
72 try!(attribute.write(unit, abbrev_attribute));
73 }
74 Ok(())
75 }
76}
77
78impl<'a, 'b> Attribute<'a> {
79 pub fn write(
80 &self,
81 unit: &mut CompilationUnit<'b>,
82 abbrev: &AbbrevAttribute,
83 ) -> Result<(), WriteError> {
84 if self.at != abbrev.at {
85 return Err(WriteError::Invalid("attribute type mismatch".to_string()));
86 }
87 try!(self.data.write(unit, abbrev.form, false));
88 Ok(())
89 }
90}
91
92#[cfg_attr(feature = "clippy", allow(match_same_arms))]
93impl<'a, 'b> AttributeData<'a> {
94 pub fn write(
95 &self,
96 unit: &mut CompilationUnit<'b>,
97 form: constant::DwForm,
98 indirect: bool,
99 ) -> Result<(), WriteError> {
100 let w = unit.data.to_mut();
101 if indirect {
102 try!(leb128::write_u16(w, form.0));
103 }
104 match (self, form) {
105 (&AttributeData::Address(ref val), constant::DW_FORM_addr) => {
106 try!(write_address(w, unit.endian, unit.address_size, *val));
107 },
108 (&AttributeData::Block(ref val), constant::DW_FORM_block1) => {
109 try!(w.write_u8(val.len() as u8));
110 try!(w.write_all(val));
111 },
112 (&AttributeData::Block(ref val), constant::DW_FORM_block2) => {
113 try!(unit.endian.write_u16(w, val.len() as u16));
114 try!(w.write_all(val));
115 },
116 (&AttributeData::Block(ref val), constant::DW_FORM_block4) => {
117 try!(unit.endian.write_u32(w, val.len() as u32));
118 try!(w.write_all(val));
119 },
120 (&AttributeData::Block(ref val), constant::DW_FORM_block) => {
121 try!(leb128::write_u64(w, val.len() as u64));
122 try!(w.write_all(val));
123 },
124 (&AttributeData::Data1(ref val), constant::DW_FORM_data1) => {
125 try!(w.write_u8(*val));
126 },
127 (&AttributeData::Data2(ref val), constant::DW_FORM_data2) => {
128 try!(unit.endian.write_u16(w, *val));
129 },
130 (&AttributeData::Data4(ref val), constant::DW_FORM_data4) => {
131 try!(unit.endian.write_u32(w, *val));
132 },
133 (&AttributeData::Data8(ref val), constant::DW_FORM_data8) => {
134 try!(unit.endian.write_u64(w, *val));
135 },
136 (&AttributeData::UData(ref val), constant::DW_FORM_udata) => {
137 try!(leb128::write_u64(w, *val));
138 },
139 (&AttributeData::SData(ref val), constant::DW_FORM_sdata) => {
140 try!(leb128::write_i64(w, *val));
141 },
142 (&AttributeData::Flag(ref val), constant::DW_FORM_flag) => {
143 try!(w.write_u8(if *val { 1 } else { 0 }));
144 },
145 (&AttributeData::Flag(ref val), constant::DW_FORM_flag_present) => {
146 assert!(*val);
147 },
148 (&AttributeData::String(ref val), constant::DW_FORM_string) => {
149 try!(w.write_all(val.as_bytes()));
150 try!(w.write_u8(0));
151 },
152 (&AttributeData::StringOffset(ref val), constant::DW_FORM_strp) => {
153 try!(write_offset(w, unit.endian, unit.offset_size, *val));
154 },
155 (&AttributeData::Ref(ref val), constant::DW_FORM_ref1) => {
156 try!(w.write_u8(*val as u8));
157 },
158 (&AttributeData::Ref(ref val), constant::DW_FORM_ref2) => {
159 try!(unit.endian.write_u16(w, *val as u16));
160 },
161 (&AttributeData::Ref(ref val), constant::DW_FORM_ref4) => {
162 try!(unit.endian.write_u32(w, *val as u32));
163 },
164 (&AttributeData::Ref(ref val), constant::DW_FORM_ref8) => {
165 try!(unit.endian.write_u64(w, *val as u64));
166 },
167 (&AttributeData::Ref(ref val), constant::DW_FORM_ref_udata) => {
168 try!(leb128::write_u64(w, *val as u64));
169 },
170 (&AttributeData::RefAddress(ref val), constant::DW_FORM_ref_addr) => {
171 try!(write_offset(w, unit.endian, unit.offset_size, *val));
172 },
173 (&AttributeData::RefSig(ref val), constant::DW_FORM_ref_sig8) => {
174 try!(unit.endian.write_u64(w, *val));
175 },
176 (&AttributeData::SecOffset(ref val), constant::DW_FORM_sec_offset) => {
177 try!(write_offset(w, unit.endian, unit.offset_size, *val));
178 },
179 (&AttributeData::ExprLoc(ref val), constant::DW_FORM_exprloc) => {
180 try!(leb128::write_u64(w, val.len() as u64));
181 try!(w.write_all(val));
182 },
183 _ => return Err(WriteError::Unsupported(format!("attribute form {}", form.0))),
184 }
185 Ok(())
186 }
187}
188
189fn write_offset<W: Write>(w: &mut W, endian: Endian, offset_size: u8, val: u64) -> Result<(), WriteError> {
190 match offset_size {
191 4 => try!(endian.write_u32(w, val as u32)),
192 8 => try!(endian.write_u64(w, val)),
193 _ => return Err(WriteError::Unsupported(format!("offset size {}", offset_size))),
194 };
195 Ok(())
196}
197
198fn write_address<W: Write>(w: &mut W, endian: Endian, address_size: u8, val: u64) -> Result<(), WriteError> {
199 match address_size {
200 4 => try!(endian.write_u32(w, val as u32)),
201 8 => try!(endian.write_u64(w, val)),
202 _ => return Err(WriteError::Unsupported(format!("address size {}", address_size))),
203 };
204 Ok(())
205}
206
207impl AbbrevVec {
208 pub fn write<W: Write>(&self, w: &mut W) -> std::io::Result<()> {
209 for abbrev in self.iter() {
210 try!(abbrev.write(w));
211 }
212 try!(Abbrev::write_null(w));
213 Ok(())
214 }
215}
216
217impl Abbrev {
218 pub fn write_null<W: Write>(w: &mut W) -> std::io::Result<()> {
219 leb128::write_u64(w, 0)
220 }
221
222 pub fn write<W: Write>(&self, w: &mut W) -> std::io::Result<()> {
223 try!(leb128::write_u64(w, self.code));
224 if self.code == 0 {
226 return Ok(());
227 }
228
229 try!(leb128::write_u16(w, self.tag.0));
230
231 let children = if self.children {
232 constant::DW_CHILDREN_yes
233 } else {
234 constant::DW_CHILDREN_no
235 };
236 try!(w.write_u8(children.0));
237
238 for attribute in &self.attributes {
239 try!(attribute.write(w));
240 }
241 try!(AbbrevAttribute::write_null(w));
242
243 Ok(())
244 }
245}
246
247impl AbbrevAttribute {
248 pub fn write_null<W: Write>(w: &mut W) -> std::io::Result<()> {
249 Self::null().write(w)
250 }
251
252 pub fn write<W: Write>(&self, w: &mut W) -> std::io::Result<()> {
253 try!(leb128::write_u16(w, self.at.0));
254 try!(leb128::write_u16(w, self.form.0));
255 Ok(())
256 }
257}