aya_obj/btf/
info.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
use alloc::{string::String, vec, vec::Vec};

use bytes::BufMut;
use object::Endianness;

use crate::{
    generated::{bpf_func_info, bpf_line_info},
    relocation::INS_SIZE,
    util::{bytes_of, HashMap},
};

/* The func_info subsection layout:
 *   record size for struct bpf_func_info in the func_info subsection
 *   struct btf_sec_func_info for section #1
 *   a list of bpf_func_info records for section #1
 *     where struct bpf_func_info mimics one in include/uapi/linux/bpf.h
 *     but may not be identical
 *   struct btf_sec_func_info for section #2
 *   a list of bpf_func_info records for section #2
 *   ......
 */

/// A collection of [bpf_func_info] collected from the `btf_ext_info_sec` struct
/// inside the [FuncInfo] subsection.
///
/// See [BPF Type Format (BTF) — The Linux Kernel documentation](https://docs.kernel.org/bpf/btf.html)
/// for more information.
#[derive(Debug, Clone, Default)]
pub struct FuncSecInfo {
    pub(crate) _sec_name_offset: u32,
    /// The number of info entries
    pub num_info: u32,
    /// Info entries
    pub func_info: Vec<bpf_func_info>,
}

impl FuncSecInfo {
    pub(crate) fn parse(
        sec_name_offset: u32,
        num_info: u32,
        rec_size: usize,
        func_info_data: &[u8],
        endianness: Endianness,
    ) -> FuncSecInfo {
        let func_info = func_info_data
            .chunks(rec_size)
            .map(|data| {
                let read_u32 = if endianness == Endianness::Little {
                    u32::from_le_bytes
                } else {
                    u32::from_be_bytes
                };

                let mut offset = 0;

                // ELF instruction offsets are in bytes
                // Kernel instruction offsets are in instructions units
                // We can convert by dividing the length in bytes by INS_SIZE
                let insn_off =
                    read_u32(data[offset..offset + 4].try_into().unwrap()) / INS_SIZE as u32;
                offset += 4;
                let type_id = read_u32(data[offset..offset + 4].try_into().unwrap());

                bpf_func_info { insn_off, type_id }
            })
            .collect();

        FuncSecInfo {
            _sec_name_offset: sec_name_offset,
            num_info,
            func_info,
        }
    }

    /// Encodes the [bpf_func_info] entries.
    pub fn func_info_bytes(&self) -> Vec<u8> {
        let mut buf = vec![];
        for l in &self.func_info {
            // Safety: bpf_func_info is POD
            buf.put(unsafe { bytes_of::<bpf_func_info>(l) })
        }
        buf
    }

    /// Returns the number of [bpf_func_info] entries.
    pub fn len(&self) -> usize {
        self.func_info.len()
    }
}

/// A collection of [FuncSecInfo] collected from the `func_info` subsection
/// in the `.BTF.ext` section.
///
/// See [BPF Type Format (BTF) — The Linux Kernel documentation](https://docs.kernel.org/bpf/btf.html)
/// for more information.
#[derive(Debug, Clone)]
pub struct FuncInfo {
    /// The [FuncSecInfo] subsections for some sections, referenced by section names
    pub data: HashMap<String, FuncSecInfo>,
}

impl FuncInfo {
    pub(crate) fn new() -> FuncInfo {
        FuncInfo {
            data: HashMap::new(),
        }
    }

    pub(crate) fn get(&self, name: &str) -> FuncSecInfo {
        match self.data.get(name) {
            Some(d) => d.clone(),
            None => FuncSecInfo::default(),
        }
    }
}

/// A collection of [bpf_line_info] collected from the `btf_ext_info_sec` struct
/// inside the `line_info` subsection.
///
/// See [BPF Type Format (BTF) — The Linux Kernel documentation](https://docs.kernel.org/bpf/btf.html)
/// for more information.
#[derive(Debug, Clone, Default)]
pub struct LineSecInfo {
    // each line info section has a header
    pub(crate) _sec_name_offset: u32,
    /// The number of entries
    pub num_info: u32,
    // followed by one or more bpf_line_info structs
    /// The [bpf_line_info] entries
    pub line_info: Vec<bpf_line_info>,
}

impl LineSecInfo {
    pub(crate) fn parse(
        sec_name_offset: u32,
        num_info: u32,
        rec_size: usize,
        func_info_data: &[u8],
        endianness: Endianness,
    ) -> LineSecInfo {
        let line_info = func_info_data
            .chunks(rec_size)
            .map(|data| {
                let read_u32 = if endianness == Endianness::Little {
                    u32::from_le_bytes
                } else {
                    u32::from_be_bytes
                };

                let mut offset = 0;

                // ELF instruction offsets are in bytes
                // Kernel instruction offsets are in instructions units
                // We can convert by dividing the length in bytes by INS_SIZE
                let insn_off =
                    read_u32(data[offset..offset + 4].try_into().unwrap()) / INS_SIZE as u32;
                offset += 4;
                let file_name_off = read_u32(data[offset..offset + 4].try_into().unwrap());
                offset += 4;
                let line_off = read_u32(data[offset..offset + 4].try_into().unwrap());
                offset += 4;
                let line_col = read_u32(data[offset..offset + 4].try_into().unwrap());

                bpf_line_info {
                    insn_off,
                    file_name_off,
                    line_off,
                    line_col,
                }
            })
            .collect();

        LineSecInfo {
            _sec_name_offset: sec_name_offset,
            num_info,
            line_info,
        }
    }

    /// Encodes the entries.
    pub fn line_info_bytes(&self) -> Vec<u8> {
        let mut buf = vec![];
        for l in &self.line_info {
            // Safety: bpf_func_info is POD
            buf.put(unsafe { bytes_of::<bpf_line_info>(l) })
        }
        buf
    }

    /// Returns the number of entries.
    pub fn len(&self) -> usize {
        self.line_info.len()
    }
}

#[derive(Debug, Clone)]
pub(crate) struct LineInfo {
    pub data: HashMap<String, LineSecInfo>,
}

impl LineInfo {
    pub(crate) fn new() -> LineInfo {
        LineInfo {
            data: HashMap::new(),
        }
    }

    pub(crate) fn get(&self, name: &str) -> LineSecInfo {
        match self.data.get(name) {
            Some(d) => d.clone(),
            None => LineSecInfo::default(),
        }
    }
}