btf/
c_dumper.rs

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        // emit struct/union and fwds required by them in correct order
102        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        // order state is used to detect strong link cycles, but only for BTF kinds that are or
119        // could be an independent definition (i.e., stand-alone fwd decl, enum, typedef, struct,
120        // union). Ptrs, arrays, func_protos, modifiers are just means to get to these definitions.
121        // Int/void don't need definitions, they are assumed to be always properly defined.
122        // We also ignore datasec, var, and funcs. So for all non-defining kinds, we never even set
123        // ordering state, for defining kinds we set OrderState::Ordering and subsequently
124        // OrderState::Ordered only if it forms a strong link.
125        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            // return true, letting typedefs know that it's ok to be emitted
140            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                // struct/union is part of strong link, only if it's embedded (so no ptr in a path)
169                // or it's anonymous (so has to be defined inline, even if declared through ptr)
170                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                    // no need to explicitly order anonymous embedded struct
177                    if !t.name.is_empty() {
178                        order.push(id);
179                    }
180
181                    self.set_order_state(id, OrderState::Ordered);
182                    // report this was strong link
183                    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                // report this was strong link
192                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                // report this was strong link
200                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                // report this was strong link
208                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                    // report this was strong link
216                    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                        // fwd was already emitted or no need for fwd declare if we are referencing
244                        // a struct/union we are part of
245                        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                        // for typedef fwd_emitted means typedef definition was emitted, but it can
263                        // be used only for "weak" references through pointer only
264                        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                    // top-level struct definition or embedded anonymous struct, ensure all field
303                    // types have their fwds declared
304                    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                    // emit typedef right now, if someone depends on it "weakly" (though pointer)
345                    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        // size of a struct has to be a multiple of its alignment
442        if t.sz % self.btf.get_align_of(id) != 0 {
443            return true;
444        }
445        // all the non-bitfield fields have to be naturally aligned
446        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        // even if original struct was marked as packed, we haven't detected any misalignment, so
452        // there is no effect of packedness for given struct
453        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            // natural padding will take care of a gap
468            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            // enum fwd
501            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            // enum fwd
519            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        // This algorithm emits correct C syntax for any type definition.
559        //
560        // For most types it's trivial, but there are few quirky type declaration  cases worth
561        // mentioning:
562        //   - function prototypes;
563        //   - arrays;
564        //   - const/volatile/restrict for pointers vs other types.
565        // See Peter van der Linden's "Expert C Programming: Deep C Secrets", Ch.3 "Unscrambling
566        // Declarations in C" for good discussion of this topic.
567        //
568        // This algorithm is in reverse to van der Linden's parsing algorithm. It goes from
569        // structured BTF representation of type declaration to a valid compilable C syntax.
570        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        // default to true, in case we have single ptr in a chain. E.g., in ptr -> func_proto case.
597        // func_proto will start a new emit_type_chain with just ptr, which should be emitted as
598        // (*) or (*<fname>), so we don't want to preprend space for that last ptr.
599        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); // inline anonymous struct
614                    } 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); // inline anonymous enum
622                    } 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); // inline anonymous enum
631                    } 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                    // GCC has a bug (https://gcc.gnu.org/bugzilla/show_bug.cgi?id=8354) which
663                    // causes it to emit extra const/volatile modifier for array, if array's
664                    // element type has const/volatile modifier. Clang doesn't do that.
665                    // In general, it doesn't seem very meaningful to have a const/volatile
666                    // modifier for array, so we are going to silently skip them here.
667                    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                    //
705                    // Clang for BPF target generates func_proto with no args as a func_proto with
706                    // a single void arg (i.e., <ret-type> (*f)(void) vs just <ret_type> (*f)()).
707                    // We are going to pretend there are no args for such case.
708                    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                        // func_proto with vararg has last arg of type 'void'
719                        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}