aya_obj/btf/
info.rs

1use alloc::{string::String, vec, vec::Vec};
2
3use bytes::BufMut;
4use object::Endianness;
5
6use crate::{
7    generated::{bpf_func_info, bpf_line_info},
8    relocation::INS_SIZE,
9    util::{bytes_of, HashMap},
10};
11
12/* The func_info subsection layout:
13 *   record size for struct bpf_func_info in the func_info subsection
14 *   struct btf_sec_func_info for section #1
15 *   a list of bpf_func_info records for section #1
16 *     where struct bpf_func_info mimics one in include/uapi/linux/bpf.h
17 *     but may not be identical
18 *   struct btf_sec_func_info for section #2
19 *   a list of bpf_func_info records for section #2
20 *   ......
21 */
22
23/// A collection of [bpf_func_info] collected from the `btf_ext_info_sec` struct
24/// inside the [FuncInfo] subsection.
25///
26/// See [BPF Type Format (BTF) — The Linux Kernel documentation](https://docs.kernel.org/bpf/btf.html)
27/// for more information.
28#[derive(Debug, Clone, Default)]
29pub struct FuncSecInfo {
30    pub(crate) _sec_name_offset: u32,
31    /// The number of info entries
32    pub num_info: u32,
33    /// Info entries
34    pub func_info: Vec<bpf_func_info>,
35}
36
37impl FuncSecInfo {
38    pub(crate) fn parse(
39        sec_name_offset: u32,
40        num_info: u32,
41        rec_size: usize,
42        func_info_data: &[u8],
43        endianness: Endianness,
44    ) -> FuncSecInfo {
45        let func_info = func_info_data
46            .chunks(rec_size)
47            .map(|data| {
48                let read_u32 = if endianness == Endianness::Little {
49                    u32::from_le_bytes
50                } else {
51                    u32::from_be_bytes
52                };
53
54                let mut offset = 0;
55
56                // ELF instruction offsets are in bytes
57                // Kernel instruction offsets are in instructions units
58                // We can convert by dividing the length in bytes by INS_SIZE
59                let insn_off =
60                    read_u32(data[offset..offset + 4].try_into().unwrap()) / INS_SIZE as u32;
61                offset += 4;
62                let type_id = read_u32(data[offset..offset + 4].try_into().unwrap());
63
64                bpf_func_info { insn_off, type_id }
65            })
66            .collect();
67
68        FuncSecInfo {
69            _sec_name_offset: sec_name_offset,
70            num_info,
71            func_info,
72        }
73    }
74
75    /// Encodes the [bpf_func_info] entries.
76    pub fn func_info_bytes(&self) -> Vec<u8> {
77        let mut buf = vec![];
78        for l in &self.func_info {
79            // Safety: bpf_func_info is POD
80            buf.put(unsafe { bytes_of::<bpf_func_info>(l) })
81        }
82        buf
83    }
84
85    /// Returns the number of [bpf_func_info] entries.
86    pub fn len(&self) -> usize {
87        self.func_info.len()
88    }
89}
90
91/// A collection of [FuncSecInfo] collected from the `func_info` subsection
92/// in the `.BTF.ext` section.
93///
94/// See [BPF Type Format (BTF) — The Linux Kernel documentation](https://docs.kernel.org/bpf/btf.html)
95/// for more information.
96#[derive(Debug, Clone)]
97pub struct FuncInfo {
98    /// The [FuncSecInfo] subsections for some sections, referenced by section names
99    pub data: HashMap<String, FuncSecInfo>,
100}
101
102impl FuncInfo {
103    pub(crate) fn new() -> FuncInfo {
104        FuncInfo {
105            data: HashMap::new(),
106        }
107    }
108
109    pub(crate) fn get(&self, name: &str) -> FuncSecInfo {
110        match self.data.get(name) {
111            Some(d) => d.clone(),
112            None => FuncSecInfo::default(),
113        }
114    }
115}
116
117/// A collection of [bpf_line_info] collected from the `btf_ext_info_sec` struct
118/// inside the `line_info` subsection.
119///
120/// See [BPF Type Format (BTF) — The Linux Kernel documentation](https://docs.kernel.org/bpf/btf.html)
121/// for more information.
122#[derive(Debug, Clone, Default)]
123pub struct LineSecInfo {
124    // each line info section has a header
125    pub(crate) _sec_name_offset: u32,
126    /// The number of entries
127    pub num_info: u32,
128    // followed by one or more bpf_line_info structs
129    /// The [bpf_line_info] entries
130    pub line_info: Vec<bpf_line_info>,
131}
132
133impl LineSecInfo {
134    pub(crate) fn parse(
135        sec_name_offset: u32,
136        num_info: u32,
137        rec_size: usize,
138        func_info_data: &[u8],
139        endianness: Endianness,
140    ) -> LineSecInfo {
141        let line_info = func_info_data
142            .chunks(rec_size)
143            .map(|data| {
144                let read_u32 = if endianness == Endianness::Little {
145                    u32::from_le_bytes
146                } else {
147                    u32::from_be_bytes
148                };
149
150                let mut offset = 0;
151
152                // ELF instruction offsets are in bytes
153                // Kernel instruction offsets are in instructions units
154                // We can convert by dividing the length in bytes by INS_SIZE
155                let insn_off =
156                    read_u32(data[offset..offset + 4].try_into().unwrap()) / INS_SIZE as u32;
157                offset += 4;
158                let file_name_off = read_u32(data[offset..offset + 4].try_into().unwrap());
159                offset += 4;
160                let line_off = read_u32(data[offset..offset + 4].try_into().unwrap());
161                offset += 4;
162                let line_col = read_u32(data[offset..offset + 4].try_into().unwrap());
163
164                bpf_line_info {
165                    insn_off,
166                    file_name_off,
167                    line_off,
168                    line_col,
169                }
170            })
171            .collect();
172
173        LineSecInfo {
174            _sec_name_offset: sec_name_offset,
175            num_info,
176            line_info,
177        }
178    }
179
180    /// Encodes the entries.
181    pub fn line_info_bytes(&self) -> Vec<u8> {
182        let mut buf = vec![];
183        for l in &self.line_info {
184            // Safety: bpf_func_info is POD
185            buf.put(unsafe { bytes_of::<bpf_line_info>(l) })
186        }
187        buf
188    }
189
190    /// Returns the number of entries.
191    pub fn len(&self) -> usize {
192        self.line_info.len()
193    }
194}
195
196#[derive(Debug, Clone)]
197pub(crate) struct LineInfo {
198    pub data: HashMap<String, LineSecInfo>,
199}
200
201impl LineInfo {
202    pub(crate) fn new() -> LineInfo {
203        LineInfo {
204            data: HashMap::new(),
205        }
206    }
207
208    pub(crate) fn get(&self, name: &str) -> LineSecInfo {
209        match self.data.get(name) {
210            Some(d) => d.clone(),
211            None => LineSecInfo::default(),
212        }
213    }
214}