1use crate::dwarf::borrowable_dwarf::BorrowableDwarf;
3use crate::unit_has_members::UnitHasMembers;
4use crate::unit_inner_type::UnitInnerType;
5use crate::unit_name_type::UnitNamedType;
6use crate::{Member, Error, Type};
7use crate::dwarf::{DwarfContext, GimliCU};
8
9pub fn format_type<D>(dwarf: &D, unit: &GimliCU, member_name: String, typ: Type,
10 level: usize, tablevel: usize, verbosity: u8,
11 base_offset: usize)
12-> Result<String, Error>
13where D: DwarfContext + BorrowableDwarf {
14 let mut out = String::new();
15 match typ {
16 Type::Array(a) => {
17 let inner = a.u_get_type(unit)?;
18 let inner_fmt = format_type(dwarf, unit, "".to_string(), inner,
19 level+1, tablevel, verbosity,
20 base_offset)?;
21 out.push_str(&inner_fmt);
22 if !out.ends_with('*') {
23 out.push(' ');
24 }
25 if level == 0 {
26 out.push_str(&member_name);
27 }
28
29 let bound = a.u_get_bound(unit)?;
30 let bound_str = {
31 if bound == 0 {
32 String::from("[]")
33 } else {
34 format!("[{bound}]")
35 }
36 };
37 out.push_str(&bound_str);
38 return Ok(out);
39 }
40 Type::Typedef(t) => {
41 let name = t.u_name(dwarf, unit)?;
42 if level == 0 {
43 out.push_str(
44 &format!("{name} {member_name}")
45 );
46 return Ok(out);
47 }
48 out.push_str(&name);
49 },
50 Type::Struct(t) => {
51 let name = t.u_name(dwarf, unit);
52 match name {
53 Ok(name) => {
54 if level == 0 {
55 out.push_str(
56 &format!("struct {name} {member_name}")
57 );
58 return Ok(out);
59 }
60 out.push_str(&format!("struct {name}"));
61 return Ok(out);
62 }
63 Err(Error::NameAttributeNotFound) => {
64 out.push_str("struct {\n");
66 for memb in t.u_members(unit)?.into_iter() {
67 out.push_str(
68 &format_member(dwarf, unit, memb, tablevel+1,
69 verbosity, base_offset)?
70 );
71 }
72
73 for _ in 0..=tablevel {
74 out.push_str(" ");
75 }
76 out.push('}');
77 return Ok(out);
78 }
79 Err(e) => return Err(e)
80 }
81 },
82 Type::Enum(t) => {
83 match t.u_name(dwarf, unit) {
84 Ok(name) => {
85 if level == 0 {
86 out.push_str(
87 &format!("enum {name} {member_name}")
88 );
89 return Ok(out)
90 }
91 out.push_str(&format!("enum {name}"));
93 }
94 Err(Error::NameAttributeNotFound) => {
95 if level == 0 {
96 out.push_str(&format!("enum {member_name}"));
97 return Ok(out)
98 }
99 out.push_str("enum");
101 }
102 Err(e) => return Err(e)
103 }
104 },
105 Type::Union(u) => {
106 let name = u.u_name(dwarf, unit);
107 match name {
108 Ok(name) => {
109 if level == 0 {
110 out.push_str(
111 &format!("union {name} {member_name}")
112 );
113 return Ok(out);
114 }
115 out.push_str(&format!("union {name}"));
116 return Ok(out);
117 }
118 Err(Error::NameAttributeNotFound) => {
119 out.push_str("union {\n");
120 for memb in u.u_members(unit)?.into_iter() {
121 out.push_str(
122 &format_member(dwarf, unit, memb, tablevel+1,
123 verbosity, base_offset)?);
124 }
125
126 for _ in 0..=tablevel {
127 out.push_str(" ");
128 }
129 out.push('}');
130
131 return Ok(out);
132 }
133 Err(e) => return Err(e)
134 }
135 },
136 Type::Base(t) => {
137 let name = t.u_name(dwarf, unit)?;
138 if level == 0 {
139 out.push_str(&format!("{name} {member_name}"));
140 return Ok(out);
141 }
142 out.push_str(&name);
143 return Ok(out);
144 },
145 Type::Subroutine(t) => {
146 let params = t.u_get_params(unit)?;
148 for pidx in 0..params.len() {
149 let param = params[pidx].u_get_type(unit)?;
150 out.push_str(&format_type(dwarf, unit, "".to_string(),
152 param, level+1, tablevel, verbosity,
153 base_offset)?);
154 if pidx != params.len()-1 {
155 out.push_str(", ");
156 }
157 };
158 },
159 Type::Pointer(p) => {
160 let inner = p.u_get_type(unit);
161
162 if let Ok(Type::Subroutine(subp)) = inner {
164
165 let return_type = match subp.u_get_type(unit) {
166 Ok(rtype) => format_type(dwarf, unit, "".to_string(), rtype,
167 level+1, tablevel, verbosity,
168 base_offset)?,
169 Err(Error::TypeAttributeNotFound) => "void".to_string(),
170 Err(e) => return Err(e)
171 };
172
173 let argstr = {
174 format_type(dwarf, unit, "".to_string(),
175 Type::Subroutine(subp),
176 level+1, tablevel, verbosity,
177 base_offset)?
178 };
179
180 out.push_str(
181 &format!("{return_type} (*{member_name})({argstr})")
182 );
183 return Ok(out);
184 }
185
186 let ptr_type = match inner {
189 Ok(inner) => {
190 format_type(dwarf, unit, "".to_string(), inner,
191 level+1, tablevel, verbosity,
192 base_offset)?
193 },
194 Err(Error::TypeAttributeNotFound) => {
195 "void".to_string()
196 },
197 Err(e) => return Err(e)
198 };
199 out.push_str(&ptr_type);
200
201 if ptr_type.ends_with('*'){
202 out.push('*');
203 } else {
204 out.push_str(" *");
205 }
206
207 if level == 0 {
208 out.push_str(&member_name);
209 return Ok(out);
210 }
211 return Ok(out);
212 },
213 Type::Const(c) => {
214 let inner = c.u_get_type(unit);
215 match inner {
216 Ok(inner) => {
217 let inner_fmt = format_type(dwarf, unit, "".to_string(),
218 inner, level+1, tablevel,
219 verbosity, base_offset)?;
220 out.push_str(&format!("const {inner_fmt}"));
221 }
222 Err(Error::TypeAttributeNotFound) => {
223 out.push_str("const void");
224 }
225 Err(e) => return Err(e)
226 }
227 },
228 Type::Volatile(c) => {
229 let inner = c.u_get_type(unit)?;
230 let inner_fmt = format_type(dwarf, unit, "".to_string(), inner,
231 level+1, tablevel, verbosity,
232 base_offset)?;
233 out.push_str(&format!("volatile {inner_fmt}"));
234 return Ok(out);
235 },
236 Type::Restrict(c) => {
237 let inner = c.u_get_type(unit)?;
238 let inner_fmt = format_type(dwarf, unit, "".to_string(), inner,
239 level+1, tablevel, verbosity,
240 base_offset)?;
241 out.push_str(&format!("{inner_fmt} restrict"));
242 return Ok(out);
243 }
244 Type::Variable(c) => {
245 let name = c.u_name(dwarf, unit)?;
246 out.push_str(&format!("{name}"));
247 return Ok(out);
248 }
249 }
250 Ok(out)
251}
252
253pub fn format_member<D>(
254 dwarf: &D,
255 unit: &GimliCU,
256 member: Member,
257 tablevel: usize,
258 verbosity: u8,
259 base_offset: usize
260)
261-> Result<String, Error>
262where D: DwarfContext + BorrowableDwarf {
263 let mtype = member.u_get_type(unit)?;
264 let name = match member.u_name(dwarf, unit) {
265 Ok(name) => name,
266 Err(Error::NameAttributeNotFound) => {
267 "".to_string()
272 },
273 Err(e) => return Err(e)
274 };
275
276 let mut formatted = String::new();
277 for _ in 0..=tablevel {
278 formatted.push_str(" ");
279 }
280
281 let memb_offset = match member.u_offset(unit) {
282 Ok(memb_offset) => memb_offset,
283 Err(Error::MemberLocationAttributeNotFound) => 0,
284 Err(e) => return Err(e)
285
286 };
287 let offset = base_offset + memb_offset;
288
289 formatted.push_str(
290 &format_type(dwarf, unit, name, mtype, 0, tablevel, verbosity, offset)?
291 );
292
293 match member.u_bit_size(unit) {
294 Ok(bitsz) => {
295 formatted.push_str(&format!(":{bitsz}"));
296 }
297 Err(Error::BitSizeAttributeNotFound) => {},
298 Err(e) => return Err(e)
299 }
300
301 formatted.push(';');
302
303 if verbosity > 0 {
304 let last_newline = formatted.rfind('\n').map(|idx| idx+1).unwrap_or(0);
306
307 let last_line_len: isize = (formatted.len()-last_newline) as isize;
309 for _ in 0..(48-last_line_len) {
310 formatted.push(' ');
311 }
312
313 let bytesz = member.u_byte_size(unit)?;
314 formatted.push_str(&format!("\t/* {bytesz: >4} | \
315 {offset: >4} */"));
316 }
317
318 formatted.push('\n');
319
320 Ok(formatted)
321}