Skip to main content

aya_obj/btf/
info.rs

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