1use std::collections::HashMap;
2
3use lazy_static::lazy_static;
4use regex::RegexSet;
5
6use crate::types::*;
7use crate::{btf_error, BtfResult};
8
9#[derive(Debug, Copy, Clone, Eq, PartialEq)]
10enum OrderState {
11 NotOrdered,
12 Ordering,
13 Ordered,
14}
15
16impl Default for OrderState {
17 fn default() -> Self {
18 OrderState::NotOrdered
19 }
20}
21
22#[derive(Debug, Copy, Clone, Eq, PartialEq)]
23enum EmitState {
24 NotEmitted,
25 Emitting,
26 Emitted,
27}
28
29impl Default for EmitState {
30 fn default() -> Self {
31 EmitState::NotEmitted
32 }
33}
34
35#[derive(Default)]
36struct TypeState {
37 order_state: OrderState,
38 emit_state: EmitState,
39 fwd_emitted: bool,
40 name: String,
41}
42
43#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
44enum NamedKind {
45 Type,
46 Ident,
47}
48
49#[derive(Debug)]
50pub struct CDumperCfg {
51 pub verbose: bool,
52 pub union_as_struct: bool,
53}
54
55pub struct CDumper<'a> {
56 btf: &'a Btf<'a>,
57 cfg: CDumperCfg,
58 state: Vec<TypeState>,
59 names: HashMap<(NamedKind, &'a str), u32>,
60}
61
62impl<'a> CDumper<'a> {
63 pub fn new(btf: &'a Btf<'a>, cfg: CDumperCfg) -> CDumper<'a> {
64 let mut dumper = CDumper {
65 btf: btf,
66 cfg: cfg,
67 state: Vec::new(),
68 names: HashMap::new(),
69 };
70 dumper
71 .state
72 .resize_with(btf.type_cnt() as usize, Default::default);
73 dumper
74 }
75
76 pub fn dump_types(
77 &mut self,
78 filter: Box<dyn Fn(u32, &'a BtfType<'a>) -> bool>,
79 ) -> BtfResult<()> {
80 for id in 1..self.btf.type_cnt() {
81 let bt = self.btf.type_by_id(id);
82 if filter(id, bt) {
83 self.dump_type(id)?;
84 }
85 }
86 Ok(())
87 }
88
89 pub fn dump_type(&mut self, id: u32) -> BtfResult<()> {
90 let mut order = Vec::new();
91 if self.cfg.verbose {
92 println!("===================================================");
93 println!("ORDERING id: {}, type: {}", id, self.btf.type_by_id(id));
94 }
95 self.order_type(id, false, &mut order)?;
96 if self.cfg.verbose {
97 for (i, &id) in order.iter().enumerate() {
98 println!("ORDER #{} id: {}, type: {}", i, id, self.btf.type_by_id(id));
99 }
100 }
101 for id in order {
103 self.emit_type(id, 0)?;
104 }
105 Ok(())
106 }
107
108 fn order_type(&mut self, id: u32, has_ptr: bool, order: &mut Vec<u32>) -> BtfResult<bool> {
109 if self.cfg.verbose && self.get_order_state(id) != OrderState::Ordered {
110 println!(
111 "ORDER TYPE id:{}, has_ptr:{}, type:{}, order_state:{:?}",
112 id,
113 has_ptr,
114 self.btf.type_by_id(id),
115 self.get_order_state(id)
116 );
117 }
118 match self.get_order_state(id) {
126 OrderState::NotOrdered => {}
127 OrderState::Ordering => match self.btf.type_by_id(id) {
128 BtfType::Struct(t) | BtfType::Union(t) if has_ptr && !t.name.is_empty() => {
129 return Ok(false);
130 }
131 _ => {
132 return btf_error(format!(
133 "Unsatisfiable type cycle, id: {}, type: {}",
134 id,
135 self.btf.type_by_id(id)
136 ));
137 }
138 },
139 OrderState::Ordered => return Ok(true),
141 }
142 match self.btf.type_by_id(id) {
143 BtfType::Func(_) | BtfType::Var(_) | BtfType::Datasec(_) | BtfType::DeclTag(_) => {}
144 BtfType::Void | BtfType::Int(_) | BtfType::Float(_) => {
145 self.set_order_state(id, OrderState::Ordered);
146 return Ok(false);
147 }
148 BtfType::Volatile(t) => return self.order_type(t.type_id, has_ptr, order),
149 BtfType::Const(t) => return self.order_type(t.type_id, has_ptr, order),
150 BtfType::Restrict(t) => return self.order_type(t.type_id, has_ptr, order),
151 BtfType::TypeTag(t) => return self.order_type(t.type_id, has_ptr, order),
152 BtfType::Ptr(t) => {
153 let res = self.order_type(t.type_id, true, order);
154 self.set_order_state(id, OrderState::Ordered);
155 return res;
156 }
157 BtfType::Array(t) => return self.order_type(t.val_type_id, has_ptr, order),
158 BtfType::FuncProto(t) => {
159 let mut is_strong = self.order_type(t.res_type_id, has_ptr, order)?;
160 for p in &t.params {
161 if self.order_type(p.type_id, has_ptr, order)? {
162 is_strong = true;
163 }
164 }
165 return Ok(is_strong);
166 }
167 BtfType::Struct(t) | BtfType::Union(t) => {
168 if !has_ptr || t.name.is_empty() {
171 self.set_order_state(id, OrderState::Ordering);
172
173 for m in &t.members {
174 self.order_type(m.type_id, false, order)?;
175 }
176 if !t.name.is_empty() {
178 order.push(id);
179 }
180
181 self.set_order_state(id, OrderState::Ordered);
182 return Ok(true);
184 }
185 }
186 BtfType::Enum(t) => {
187 if !t.name.is_empty() {
188 order.push(id);
189 }
190 self.set_order_state(id, OrderState::Ordered);
191 return Ok(true);
193 }
194 BtfType::Enum64(t) => {
195 if !t.name.is_empty() {
196 order.push(id);
197 }
198 self.set_order_state(id, OrderState::Ordered);
199 return Ok(true);
201 }
202 BtfType::Fwd(t) => {
203 if !t.name.is_empty() {
204 order.push(id);
205 }
206 self.set_order_state(id, OrderState::Ordered);
207 return Ok(true);
209 }
210 BtfType::Typedef(t) => {
211 let is_strong = self.order_type(t.type_id, has_ptr, order)?;
212 if !has_ptr || is_strong {
213 order.push(id);
214 self.set_order_state(id, OrderState::Ordered);
215 return Ok(true);
217 }
218 }
219 }
220 Ok(false)
221 }
222
223 fn emit_type(&mut self, id: u32, cont_id: u32) -> BtfResult<()> {
224 let top_level_def = cont_id == 0;
225 if self.cfg.verbose {
226 println!(
227 "EMIT_TYPE id: {}, cont_id: {}, is_def: {}, state: {:?}, type: {}",
228 id,
229 cont_id,
230 top_level_def,
231 self.get_emit_state(id),
232 self.btf.type_by_id(id)
233 );
234 }
235 match self.get_emit_state(id) {
236 EmitState::NotEmitted => {}
237 EmitState::Emitting => {
238 if self.get_fwd_emitted(id) {
239 return Ok(());
240 }
241 match self.btf.type_by_id(id) {
242 BtfType::Struct(t) | BtfType::Union(t) => {
243 if id == cont_id {
246 return Ok(());
247 }
248 if t.name.is_empty() {
249 return btf_error(format!(
250 "anonymous struct loop, id: {}, type: {}",
251 id,
252 self.btf.type_by_id(id)
253 ));
254 }
255 if self.emit_composite_fwd(id, t) {
256 println!(";\n");
257 }
258 self.set_fwd_emitted(id, true);
259 return Ok(());
260 }
261 BtfType::Typedef(t) => {
262 if self.emit_typedef_def(id, t, 0) {
265 println!(";\n");
266 }
267 self.set_fwd_emitted(id, true);
268 return Ok(());
269 }
270 _ => return Ok(()),
271 };
272 }
273 EmitState::Emitted => return Ok(()),
274 }
275
276 if top_level_def && self.btf.type_by_id(id).name().is_empty() {
277 return btf_error(format!(
278 "unexpected nameless definition, id: {}, type: {}",
279 id,
280 self.btf.type_by_id(id)
281 ));
282 }
283
284 match self.btf.type_by_id(id) {
285 BtfType::Func(_) | BtfType::Var(_) | BtfType::Datasec(_) | BtfType::DeclTag(_) => {}
286 BtfType::Void | BtfType::Int(_) | BtfType::Float(_) => {}
287 BtfType::Volatile(t) => self.emit_type(t.type_id, cont_id)?,
288 BtfType::Const(t) => self.emit_type(t.type_id, cont_id)?,
289 BtfType::Restrict(t) => self.emit_type(t.type_id, cont_id)?,
290 BtfType::TypeTag(t) => self.emit_type(t.type_id, cont_id)?,
291 BtfType::Ptr(t) => self.emit_type(t.type_id, cont_id)?,
292 BtfType::Array(t) => self.emit_type(t.val_type_id, cont_id)?,
293 BtfType::FuncProto(t) => {
294 self.emit_type(t.res_type_id, cont_id)?;
295 for p in &t.params {
296 self.emit_type(p.type_id, cont_id)?;
297 }
298 }
299 BtfType::Struct(t) | BtfType::Union(t) => {
300 self.set_emit_state(id, EmitState::Emitting);
301 if top_level_def || t.name.is_empty() {
302 for m in &t.members {
305 self.emit_type(m.type_id, if t.name.is_empty() { cont_id } else { id })?;
306 }
307 } else if !self.get_fwd_emitted(id) && id != cont_id {
308 if self.emit_composite_fwd(id, t) {
309 println!(";\n");
310 }
311 self.set_fwd_emitted(id, true);
312 }
313 if top_level_def {
314 self.emit_composite_def(id, t, 0);
315 println!(";\n");
316 self.set_emit_state(id, EmitState::Emitted);
317 } else {
318 self.set_emit_state(id, EmitState::NotEmitted);
319 }
320 }
321 BtfType::Enum(t) => {
322 if top_level_def {
323 self.emit_enum_def(id, t, 0);
324 println!(";\n");
325 }
326 self.set_emit_state(id, EmitState::Emitted);
327 }
328 BtfType::Enum64(t) => {
329 if top_level_def {
330 self.emit_enum64_def(id, t, 0);
331 println!(";\n");
332 }
333 self.set_emit_state(id, EmitState::Emitted);
334 }
335 BtfType::Fwd(t) => {
336 self.emit_fwd_def(id, t);
337 println!(";\n");
338 self.set_emit_state(id, EmitState::Emitted);
339 }
340 BtfType::Typedef(t) => {
341 self.set_emit_state(id, EmitState::Emitting);
342 self.emit_type(t.type_id, id)?;
343 if !self.get_fwd_emitted(id) {
344 if self.emit_typedef_def(id, t, 0) {
346 println!(";\n");
347 }
348 self.set_fwd_emitted(id, true);
349 }
350 self.set_emit_state(id, EmitState::Emitted);
351 }
352 }
353 Ok(())
354 }
355
356 fn get_fwd_emitted(&self, id: u32) -> bool {
357 self.state[id as usize].fwd_emitted
358 }
359
360 fn set_fwd_emitted(&mut self, id: u32, emitted: bool) {
361 self.state[id as usize].fwd_emitted = emitted;
362 }
363
364 fn get_order_state(&self, id: u32) -> OrderState {
365 self.state[id as usize].order_state
366 }
367
368 fn set_order_state(&mut self, id: u32, state: OrderState) {
369 self.state[id as usize].order_state = state;
370 }
371
372 fn get_emit_state(&self, id: u32) -> EmitState {
373 self.state[id as usize].emit_state
374 }
375
376 fn set_emit_state(&mut self, id: u32, state: EmitState) {
377 self.state[id as usize].emit_state = state;
378 }
379
380 fn emit_composite_fwd(&mut self, id: u32, t: &'a BtfComposite) -> bool {
381 if NAMES_BLACKLIST.is_match(&t.name) {
382 return false;
383 }
384 let keyword = if !t.is_struct && self.cfg.union_as_struct {
385 "struct /*union*/"
386 } else if t.is_struct {
387 "struct"
388 } else {
389 "union"
390 };
391 print!(
392 "{} {}",
393 keyword,
394 self.resolve_type_name(NamedKind::Type, id, t.name)
395 );
396 return true;
397 }
398
399 fn emit_composite_def(&mut self, id: u32, t: &'a BtfComposite, lvl: usize) {
400 if NAMES_BLACKLIST.is_match(&t.name) {
401 return;
402 }
403 let keyword = if !t.is_struct && self.cfg.union_as_struct {
404 "struct /*union*/"
405 } else if t.is_struct {
406 "struct"
407 } else {
408 "union"
409 };
410 let packed = self.is_struct_packed(id, t);
411 let name = self.resolve_type_name(NamedKind::Type, id, t.name);
412 print!("{}{}{} {{", keyword, sep(&name), name);
413 let mut offset = 0;
414 for m in &t.members {
415 self.emit_bit_padding(offset, m, packed, lvl + 1);
416
417 print!("\n{}", pfx(lvl + 1));
418 self.emit_type_decl(m.type_id, &m.name, lvl + 1);
419
420 if m.bit_size == 0 {
421 offset = m.bit_offset + self.btf.get_size_of(m.type_id) * 8;
422 } else {
423 print!(": {}", m.bit_size);
424 offset = m.bit_offset + m.bit_size as u32;
425 }
426 print!(";");
427 }
428 if !t.members.is_empty() {
429 print!("\n");
430 }
431 print!("{}}}", pfx(lvl));
432 if packed {
433 print!(" __attribute__((packed))");
434 }
435 }
436
437 fn is_struct_packed(&self, id: u32, t: &BtfComposite) -> bool {
438 if !t.is_struct {
439 return false;
440 }
441 if t.sz % self.btf.get_align_of(id) != 0 {
443 return true;
444 }
445 for m in &t.members {
447 if m.bit_size == 0 && m.bit_offset % (self.btf.get_align_of(m.type_id) * 8) != 0 {
448 return true;
449 }
450 }
451 return false;
454 }
455
456 fn emit_bit_padding(&self, offset: u32, m: &BtfMember, packed: bool, lvl: usize) {
457 if offset >= m.bit_offset {
458 return;
459 }
460 let mut bit_diff = m.bit_offset - offset;
461 let align = if packed {
462 1
463 } else {
464 self.btf.get_align_of(m.type_id)
465 };
466 if m.bit_size == 0 && bit_diff < align * 8 {
467 return;
469 }
470 let ptr_sz_bits = self.btf.ptr_sz() * 8;
471 while bit_diff > 0 {
472 let (pad_type, pad_bits) = if ptr_sz_bits > 32 && bit_diff > 32 {
473 ("long", CDumper::chip_away_bits(bit_diff, ptr_sz_bits))
474 } else if bit_diff > 16 {
475 ("int", CDumper::chip_away_bits(bit_diff, 32))
476 } else if bit_diff > 8 {
477 ("short", CDumper::chip_away_bits(bit_diff, 16))
478 } else {
479 ("char", CDumper::chip_away_bits(bit_diff, 8))
480 };
481 bit_diff -= pad_bits;
482 print!("\n{}{}: {};", pfx(lvl), pad_type, pad_bits);
483 }
484 }
485
486 fn chip_away_bits(total: u32, at_most: u32) -> u32 {
487 if total % at_most == 0 {
488 at_most
489 } else {
490 total % at_most
491 }
492 }
493
494 fn emit_enum_def(&mut self, id: u32, t: &'a BtfEnum, lvl: usize) {
495 if NAMES_BLACKLIST.is_match(&t.name) {
496 return;
497 }
498 let name = self.resolve_type_name(NamedKind::Type, id, t.name);
499 if t.values.is_empty() {
500 print!("enum{}{}", sep(&name), name);
502 } else {
503 print!("enum{}{} {{", sep(&name), name);
504 for v in &t.values {
505 let val_uniq_name = self.resolve_name(NamedKind::Ident, &v.name);
506 print!("\n{}{} = {},", pfx(lvl + 1), &val_uniq_name, v.value);
507 }
508 print!("\n{}}}", pfx(lvl));
509 }
510 }
511
512 fn emit_enum64_def(&mut self, id: u32, t: &'a BtfEnum64, lvl: usize) {
513 if NAMES_BLACKLIST.is_match(&t.name) {
514 return;
515 }
516 let name = self.resolve_type_name(NamedKind::Type, id, t.name);
517 if t.values.is_empty() {
518 print!("enum{}{}", sep(&name), name);
520 } else {
521 print!("enum{}{} {{", sep(&name), name);
522 for v in &t.values {
523 let val_uniq_name = self.resolve_name(NamedKind::Ident, &v.name);
524 print!("\n{}{} = {},", pfx(lvl + 1), &val_uniq_name, v.value);
525 }
526 print!("\n{}}}", pfx(lvl));
527 }
528 }
529
530 fn emit_fwd_def(&mut self, id: u32, t: &'a BtfFwd) {
531 if NAMES_BLACKLIST.is_match(&t.name) {
532 return;
533 }
534 let name = self.resolve_type_name(NamedKind::Type, id, t.name);
535 match t.kind {
536 BtfFwdKind::Struct => print!("struct {}", name),
537 BtfFwdKind::Union => {
538 if self.cfg.union_as_struct {
539 print!("struct /*union*/ {}", name)
540 } else {
541 print!("union {}", name)
542 }
543 }
544 }
545 }
546
547 fn emit_typedef_def(&mut self, id: u32, t: &'a BtfTypedef, lvl: usize) -> bool {
548 if NAMES_BLACKLIST.is_match(&t.name) {
549 return false;
550 }
551 let name = self.resolve_type_name(NamedKind::Ident, id, t.name);
552 print!("typedef ");
553 self.emit_type_decl(t.type_id, &name, lvl);
554 return true;
555 }
556
557 fn emit_type_decl(&mut self, mut id: u32, fname: &str, lvl: usize) {
558 let mut chain = Vec::new();
571 loop {
572 chain.push(id);
573 match self.btf.type_by_id(id) {
574 BtfType::Ptr(t) => id = t.type_id,
575 BtfType::Const(t) => id = t.type_id,
576 BtfType::Volatile(t) => id = t.type_id,
577 BtfType::Restrict(t) => id = t.type_id,
578 BtfType::Array(t) => id = t.val_type_id,
579 BtfType::FuncProto(t) => id = t.res_type_id,
580 BtfType::Var(_) | BtfType::Datasec(_) | BtfType::Func(_) => {
581 chain.pop();
582 print!("!@#! UNEXPECT TYPE DECL CHAIN ");
583 for parent_id in chain.iter().rev() {
584 print!("[{}] --> ", parent_id);
585 }
586 print!("[{}] {}", id, self.btf.type_by_id(id));
587 return;
588 }
589 _ => break,
590 }
591 }
592 self.emit_type_chain(chain, fname, lvl);
593 }
594
595 fn emit_type_chain(&mut self, mut chain: Vec<u32>, fname: &str, lvl: usize) {
596 let mut last_was_ptr = true;
600 while let Some(id) = chain.pop() {
601 match self.btf.type_by_id(id) {
602 BtfType::Void => {
603 self.emit_mods(&mut chain);
604 print!("void");
605 }
606 BtfType::Int(t) => {
607 self.emit_mods(&mut chain);
608 print!("{}", t.name);
609 }
610 BtfType::Struct(t) | BtfType::Union(t) => {
611 self.emit_mods(&mut chain);
612 if t.name.is_empty() {
613 self.emit_composite_def(id, t, lvl); } else {
615 self.emit_composite_fwd(id, t);
616 }
617 }
618 BtfType::Enum(t) => {
619 self.emit_mods(&mut chain);
620 if t.name.is_empty() {
621 self.emit_enum_def(id, t, lvl); } else {
623 let uniq_name = self.resolve_type_name(NamedKind::Type, id, t.name);
624 print!("enum {}", &uniq_name);
625 }
626 }
627 BtfType::Enum64(t) => {
628 self.emit_mods(&mut chain);
629 if t.name.is_empty() {
630 self.emit_enum64_def(id, t, lvl); } else {
632 let uniq_name = self.resolve_type_name(NamedKind::Type, id, t.name);
633 print!("enum {}", &uniq_name);
634 }
635 }
636 BtfType::Fwd(t) => {
637 self.emit_mods(&mut chain);
638 self.emit_fwd_def(id, t);
639 }
640 BtfType::Typedef(t) => {
641 self.emit_mods(&mut chain);
642 let uniq_name = self.resolve_type_name(NamedKind::Ident, id, t.name);
643 print!("{}", &uniq_name);
644 }
645 BtfType::Ptr(_) => {
646 if last_was_ptr {
647 print!("*")
648 } else {
649 print!(" *")
650 }
651 }
652 BtfType::Volatile(_) => {
653 print!(" volatile");
654 }
655 BtfType::Const(_) => {
656 print!(" const");
657 }
658 BtfType::Restrict(_) => {
659 print!(" restrict");
660 }
661 BtfType::Array(t) => {
662 while let Some(id) = chain.pop() {
668 match self.btf.type_by_id(id) {
669 BtfType::Volatile(_) | BtfType::Const(_) | BtfType::Restrict(_) => {}
670 _ => {
671 chain.push(id);
672 break;
673 }
674 }
675 }
676 if let Some(&next_id) = chain.last() {
677 let t = self.btf.type_by_id(next_id);
678 if !fname.is_empty() && !last_was_ptr {
679 print!(" ");
680 }
681 if t.kind() != BtfKind::Array {
682 print!("(");
683 }
684 self.emit_type_chain(chain, fname, lvl);
685 if t.kind() != BtfKind::Array {
686 print!(")");
687 }
688 } else {
689 self.emit_name(fname, last_was_ptr);
690 }
691 print!("[{}]", t.nelems);
692 return;
693 }
694 BtfType::FuncProto(t) => {
695 self.emit_mods(&mut chain);
696 if chain.is_empty() {
697 self.emit_name(fname, last_was_ptr);
698 } else {
699 print!(" (");
700 self.emit_type_chain(chain, fname, lvl);
701 print!(")");
702 }
703 print!("(");
704 let arg_cnt = t.params.len();
709 if arg_cnt == 1 && t.params[0].type_id == 0 {
710 print!(")");
711 return;
712 }
713
714 for (i, p) in t.params.iter().enumerate() {
715 if i > 0 {
716 print!(", ");
717 }
718 if i == arg_cnt - 1 && t.params[arg_cnt - 1].type_id == 0 {
720 print!("...");
721 } else {
722 self.emit_type_decl(p.type_id, &p.name, lvl);
723 }
724 }
725 print!(")");
726 return;
727 }
728 BtfType::Float(t) => {
729 self.emit_mods(&mut chain);
730 print!("{}", t.name);
731 }
732 BtfType::TypeTag(t) => {
733 self.emit_mods(&mut chain);
734 print!(" __attribute__((btf_tag((\"{}\")))", &t.name);
735 }
736 BtfType::Func(_) | BtfType::Var(_) | BtfType::Datasec(_) | BtfType::DeclTag(_) => {
737 print!(
738 "!@#! UNEXPECT TYPE DECL id: {}, type: {}",
739 id,
740 self.btf.type_by_id(id)
741 );
742 }
743 }
744 if let BtfType::Ptr(_) = self.btf.type_by_id(id) {
745 last_was_ptr = true;
746 } else {
747 last_was_ptr = false;
748 }
749 }
750 self.emit_name(fname, last_was_ptr);
751 }
752
753 fn emit_name(&self, fname: &str, last_was_ptr: bool) {
754 if last_was_ptr {
755 print!("{}", fname);
756 } else {
757 print!("{}{}", sep(fname), fname);
758 }
759 }
760
761 fn emit_mods(&self, chain: &mut Vec<u32>) {
762 while let Some(id) = chain.pop() {
763 match self.btf.type_by_id(id) {
764 BtfType::Volatile(_) => {
765 print!("volatile ");
766 }
767 BtfType::Const(_) => {
768 print!("const ");
769 }
770 BtfType::Restrict(_) => {
771 print!("restrict ");
772 }
773 _ => {
774 chain.push(id);
775 break;
776 }
777 }
778 }
779 }
780
781 fn resolve_type_name(&mut self, kind: NamedKind, id: u32, name: &'a str) -> String {
782 if name.is_empty() {
783 return EMPTY.to_owned();
784 }
785 let s = &mut self.state[id as usize];
786 if s.name.is_empty() {
787 let version = self.names.entry((kind, name)).or_insert(0);
788 *version += 1;
789 if *version == 1 {
790 s.name = name.to_string()
791 } else {
792 s.name = format!("{}___{}", name, version)
793 }
794 }
795 s.name.clone()
796 }
797
798 fn resolve_name(&mut self, kind: NamedKind, name: &'a str) -> String {
799 let version = self.names.entry((kind, name)).or_insert(0);
800 *version += 1;
801 if *version == 1 {
802 name.to_string()
803 } else {
804 format!("{}___{}", name, version)
805 }
806 }
807}
808
809lazy_static! {
810 static ref NAMES_BLACKLIST: RegexSet =
811 RegexSet::new(&["__builtin_va_list"]).expect("invalid blacklist regexes");
812}
813
814const EMPTY: &str = "";
815const SPACE: &str = " ";
816const PREFIXES: &str = "\t\t\t\t\t\t\t\t\t\t\t\t";
817
818fn sep(name: &str) -> &str {
819 if name.is_empty() {
820 EMPTY
821 } else {
822 SPACE
823 }
824}
825
826fn pfx(lvl: usize) -> &'static str {
827 if lvl >= PREFIXES.len() {
828 PREFIXES
829 } else {
830 &PREFIXES[0..lvl]
831 }
832}