• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

Alan-Jowett / libbtf / 28060332906

31 Mar 2026 06:26PM UTC coverage: 92.773% (-2.3%) from 95.029%
28060332906

push

github

web-flow
Merge pull request #194 from Alan-Jowett/dependabot/github_actions/actions-f78bc712d6

Bump the actions group with 3 updates

2285 of 2463 relevant lines covered (92.77%)

768.8 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

78.28
/libbtf/btf_parse.cpp
1
// Copyright (c) Prevail Verifier contributors.
2
// SPDX-License-Identifier: MIT
3

4
#include "btf_parse.h"
5

6
#include "btf_c_type.h"
7

8
#include <algorithm>
9
#include <cstring>
10
#include <stdexcept>
11

12
namespace libbtf {
13

14
// Byte swap utility for endianness conversion
15
static inline uint32_t bswap_32(uint32_t val) {
14✔
16
  return ((val >> 24) & 0x000000FF) | ((val >> 8) & 0x0000FF00) |
14✔
17
         ((val << 8) & 0x00FF0000) | ((val << 24) & 0xFF000000);
14✔
18
}
19

20
// Swap bytes for uint32_t (all BTF struct fields are uint32_t except magic
21
// which is not swapped)
22
static inline void swap_bytes(uint32_t &value) { value = bswap_32(value); }
14✔
23

24
// Swap bytes for BTF structures
25
static void swap_btf_header(btf_header_t &header) {
2✔
26
  // Don't swap magic - it's used for endianness detection
27
  // version and flags are single bytes, no swap needed
28
  swap_bytes(header.hdr_len);
2✔
29
  swap_bytes(header.type_off);
2✔
30
  swap_bytes(header.type_len);
2✔
31
  swap_bytes(header.str_off);
2✔
32
  swap_bytes(header.str_len);
2✔
33
}
2✔
34

35
static void swap_btf_ext_header(btf_ext_header_t &header) {
×
36
  // Don't swap magic - it's used for endianness detection
37
  // version and flags are single bytes, no swap needed
38
  swap_bytes(header.hdr_len);
×
39
  swap_bytes(header.func_info_off);
×
40
  swap_bytes(header.func_info_len);
×
41
  swap_bytes(header.line_info_off);
×
42
  swap_bytes(header.line_info_len);
×
43
}
×
44

45
static void swap_btf_type(btf_type_t &type) {
1✔
46
  swap_bytes(type.name_off);
1✔
47
  swap_bytes(type.info);
1✔
48
  swap_bytes(
1✔
49
      type.size); // size and type are in a union, so swapping one swaps both
1✔
50
}
1✔
51

52
static void swap_btf_array(btf_array_t &array) {
×
53
  swap_bytes(array.type);
×
54
  swap_bytes(array.index_type);
×
55
  swap_bytes(array.nelems);
×
56
}
×
57

58
static void swap_btf_member(btf_member_t &member) {
×
59
  swap_bytes(member.name_off);
×
60
  swap_bytes(member.type);
×
61
  swap_bytes(member.offset);
×
62
}
×
63

64
static void swap_btf_param(btf_param_t &param) {
×
65
  swap_bytes(param.name_off);
×
66
  swap_bytes(param.type);
×
67
}
×
68

69
static void swap_btf_var(btf_var_t &var) { swap_bytes(var.linkage); }
×
70

71
static void swap_btf_var_secinfo(btf_var_secinfo_t &secinfo) {
×
72
  swap_bytes(secinfo.type);
×
73
  swap_bytes(secinfo.offset);
×
74
  swap_bytes(secinfo.size);
×
75
}
×
76

77
static void swap_btf_enum(btf_enum_t &enm) {
×
78
  swap_bytes(enm.name_off);
×
79
  swap_bytes(enm.val);
×
80
}
×
81

82
static void swap_btf_enum64(btf_enum64_t &enm) {
×
83
  swap_bytes(enm.name_off);
×
84
  swap_bytes(enm.val_lo32);
×
85
  swap_bytes(enm.val_hi32);
×
86
}
×
87

88
static void swap_btf_decl_tag(btf_decl_tag_t &tag) {
×
89
  swap_bytes(tag.component_idx);
×
90
}
×
91

92
static void swap_btf_ext_info_sec(btf_ext_info_sec_t &sec) {
×
93
  swap_bytes(sec.sec_name_off);
×
94
  swap_bytes(sec.num_info);
×
95
}
×
96

97
static void swap_bpf_line_info(bpf_line_info_t &info) {
×
98
  swap_bytes(info.insn_off);
×
99
  swap_bytes(info.file_name_off);
×
100
  swap_bytes(info.line_off);
×
101
  swap_bytes(info.line_col);
×
102
}
×
103

104
static void swap_bpf_func_info(bpf_func_info_t &info) {
×
105
  swap_bytes(info.insn_off);
×
106
  swap_bytes(info.type_id);
×
107
}
×
108
template <typename T>
109
static T read_btf(const std::vector<std::byte> &btf, size_t &offset,
5,442✔
110
                  bool swap_endian = false, size_t minimum_offset = 0,
111
                  size_t maximum_offset = 0) {
112
  size_t length = 0;
5,442✔
113
  if (maximum_offset == 0) {
5,442✔
114
    maximum_offset = btf.size();
209✔
115
  }
116
  if (offset < minimum_offset || offset > maximum_offset) {
5,442✔
117
    throw std::runtime_error("Invalid .BTF section - invalid offset");
×
118
  }
119

120
  if constexpr (std::is_same<T, std::string>::value) {
121
    length = strnlen(reinterpret_cast<const char *>(btf.data()) + offset,
1,959✔
122
                     maximum_offset - offset);
123
    offset += length + 1;
1,959✔
124
    if (offset > maximum_offset) {
1,959✔
125
      throw std::runtime_error("Invalid .BTF section - invalid string length");
×
126
    }
127
    return std::string(reinterpret_cast<const char *>(btf.data()) + offset -
1,959✔
128
                           length - 1,
1,959✔
129
                       length);
1,959✔
130
  } else {
131
    length = sizeof(T);
3,483✔
132
    offset += length;
3,483✔
133
    if (offset > maximum_offset) {
3,483✔
134
      throw std::runtime_error("Invalid .BTF section - invalid type length");
×
135
    }
136
    T value = *reinterpret_cast<const T *>(btf.data() + offset - length);
3,483✔
137

138
    // Swap bytes if needed for multi-byte types
139
    // Note: Using if constexpr ensures zero runtime overhead - the compiler
140
    // evaluates these branches at compile time and only instantiates the
141
    // matching branch for each type
142
    if (swap_endian && length > 1) {
3,483✔
143
      if constexpr (std::is_same<T, btf_header_t>::value) {
144
        swap_btf_header(value);
1✔
145
      } else if constexpr (std::is_same<T, btf_ext_header_t>::value) {
146
        swap_btf_ext_header(value);
×
147
      } else if constexpr (std::is_same<T, btf_type_t>::value) {
148
        swap_btf_type(value);
1✔
149
      } else if constexpr (std::is_same<T, btf_array_t>::value) {
150
        swap_btf_array(value);
×
151
      } else if constexpr (std::is_same<T, btf_member_t>::value) {
152
        swap_btf_member(value);
×
153
      } else if constexpr (std::is_same<T, btf_param_t>::value) {
154
        swap_btf_param(value);
×
155
      } else if constexpr (std::is_same<T, btf_var_t>::value) {
156
        swap_btf_var(value);
×
157
      } else if constexpr (std::is_same<T, btf_var_secinfo_t>::value) {
158
        swap_btf_var_secinfo(value);
×
159
      } else if constexpr (std::is_same<T, btf_enum_t>::value) {
160
        swap_btf_enum(value);
×
161
      } else if constexpr (std::is_same<T, btf_enum64_t>::value) {
162
        swap_btf_enum64(value);
×
163
      } else if constexpr (std::is_same<T, btf_decl_tag_t>::value) {
164
        swap_btf_decl_tag(value);
×
165
      } else if constexpr (std::is_same<T, btf_ext_info_sec_t>::value) {
166
        swap_btf_ext_info_sec(value);
×
167
      } else if constexpr (std::is_same<T, bpf_line_info_t>::value) {
168
        swap_bpf_line_info(value);
×
169
      } else if constexpr (std::is_same<T, bpf_func_info_t>::value) {
170
        swap_bpf_func_info(value);
171
      } else if constexpr (std::is_same<T, uint16_t>::value ||
172
                           std::is_same<T, uint32_t>::value ||
173
                           std::is_same<T, int32_t>::value) {
174
        swap_bytes(value);
1✔
175
      }
176
    }
177

178
    return value;
3,483✔
179
  }
180
}
181

182
static void validate_offset(std::vector<std::byte> const &btf, size_t offset) {
411✔
183
  if (offset < 0) {
184
    throw std::runtime_error("Invalid .BTF section - invalid offset");
185
  }
186

187
  if (offset > btf.size()) {
411✔
188
    throw std::runtime_error("Invalid .BTF section - invalid offset");
2✔
189
  }
190
}
409✔
191

192
static void validate_range(std::vector<std::byte> const &btf, size_t start,
206✔
193
                           size_t end) {
194
  validate_offset(btf, start);
206✔
195
  validate_offset(btf, end);
205✔
196

197
  if (start > end) {
204✔
198
    throw std::runtime_error("Invalid .BTF section - invalid range");
×
199
  }
200
}
204✔
201

202
static std::map<size_t, std::string>
203
_btf_parse_string_table(const std::vector<std::byte> &btf, bool &swap_endian) {
107✔
204
  std::map<size_t, std::string> string_table;
107✔
205

206
  size_t offset = 0;
107✔
207
  auto btf_header =
208
      read_btf<btf_header_t>(btf, offset, false); // Read without swapping first
107✔
209

210
  // Detect endianness from magic number
211
  swap_endian = false;
107✔
212
  if (btf_header.magic == BTF_HEADER_MAGIC) {
107✔
213
    swap_endian = false;
105✔
214
  } else if (btf_header.magic == BTF_HEADER_MAGIC_BIG_ENDIAN) {
2✔
215
    swap_endian = true;
1✔
216
    // Swap the header we just read
217
    swap_btf_header(btf_header);
1✔
218
  } else {
219
    throw std::runtime_error("Invalid .BTF section - wrong magic");
1✔
220
  }
221

222
  if (btf_header.version != BTF_HEADER_VERSION) {
106✔
223
    throw std::runtime_error("Invalid .BTF section - wrong version");
1✔
224
  }
225
  if (btf_header.hdr_len < sizeof(btf_header_t)) {
105✔
226
    throw std::runtime_error("Invalid .BTF section - wrong size");
1✔
227
  }
228
  if (btf_header.hdr_len > btf.size()) {
104✔
229
    throw std::runtime_error("Invalid .BTF section - invalid header length");
×
230
  }
231

232
  size_t string_table_start = static_cast<size_t>(btf_header.hdr_len) +
104✔
233
                              static_cast<size_t>(btf_header.str_off);
104✔
234
  size_t string_table_end =
104✔
235
      string_table_start + static_cast<size_t>(btf_header.str_len);
104✔
236

237
  validate_range(btf, string_table_start, string_table_end);
104✔
238

239
  for (offset = string_table_start; offset < string_table_end;) {
2,061✔
240
    size_t string_offset = offset - string_table_start;
1,959✔
241
    std::string value = read_btf<std::string>(
242
        btf, offset, swap_endian, string_table_start, string_table_end);
1,959✔
243
    if (offset > string_table_end) {
1,959✔
244
      throw std::runtime_error("Invalid .BTF section - invalid string length");
×
245
    }
246
    string_table.insert({string_offset, value});
1,959✔
247
  }
1,959✔
248
  return string_table;
204✔
249
}
5✔
250

251
static std::string
252
_btf_find_string(const std::map<size_t, std::string> &string_table,
2,486✔
253
                 size_t string_offset) {
254
  auto it = string_table.find(string_offset);
2,486✔
255
  if (it == string_table.end()) {
2,486✔
256
    throw std::runtime_error(
×
257
        std::string("Invalid .BTF section - invalid string offset"));
×
258
  }
259
  return it->second;
4,972✔
260
}
261

262
void btf_parse_line_information(const std::vector<std::byte> &btf,
20✔
263
                                const std::vector<std::byte> &btf_ext,
264
                                btf_line_info_visitor visitor) {
265
  bool swap_endian = false;
20✔
266
  std::map<size_t, std::string> string_table =
267
      _btf_parse_string_table(btf, swap_endian);
20✔
268

269
  size_t btf_ext_offset = 0;
20✔
270
  auto bpf_ext_header = read_btf<btf_ext_header_t>(
20✔
271
      btf_ext, btf_ext_offset, false); // Read without swapping first
272

273
  // Detect endianness from magic number for BTF.ext
274
  bool swap_endian_ext = false;
20✔
275
  if (bpf_ext_header.magic == BTF_HEADER_MAGIC) {
20✔
276
    swap_endian_ext = false;
20✔
277
  } else if (bpf_ext_header.magic == BTF_HEADER_MAGIC_BIG_ENDIAN) {
×
278
    swap_endian_ext = true;
×
279
    // Swap the header we just read
280
    swap_btf_ext_header(bpf_ext_header);
×
281
  } else {
282
    throw std::runtime_error("Invalid .BTF.ext section - wrong magic");
×
283
  }
284

285
  if (bpf_ext_header.hdr_len < sizeof(btf_ext_header_t)) {
20✔
286
    throw std::runtime_error("Invalid .BTF.ext section - wrong size");
×
287
  }
288
  if (bpf_ext_header.version != BTF_HEADER_VERSION) {
20✔
289
    throw std::runtime_error("Invalid .BTF.ext section - wrong version");
×
290
  }
291
  if (bpf_ext_header.hdr_len > btf_ext.size()) {
20✔
292
    throw std::runtime_error(
×
293
        "Invalid .BTF.ext section - invalid header length");
×
294
  }
295

296
  size_t line_info_start = static_cast<size_t>(bpf_ext_header.hdr_len) +
20✔
297
                           static_cast<size_t>(bpf_ext_header.line_info_off);
20✔
298
  size_t line_info_end =
20✔
299
      line_info_start + static_cast<size_t>(bpf_ext_header.line_info_len);
20✔
300

301
  validate_range(btf_ext, line_info_start, line_info_end);
20✔
302

303
  btf_ext_offset = line_info_start;
20✔
304
  uint32_t line_info_record_size = read_btf<uint32_t>(
20✔
305
      btf_ext, btf_ext_offset, swap_endian_ext, line_info_start, line_info_end);
306
  if (line_info_record_size < sizeof(bpf_line_info_t)) {
20✔
307
    throw std::runtime_error(std::string(
×
308
        "Invalid .BTF.ext section - invalid line info record size"));
×
309
  }
310

311
// Suppress warning C4815 on MSVC
312
// section_info is declared on the stack, but its size depends on the number of
313
// elements in the section. This is not a problem, because the number the code
314
// only uses the header.
315
#pragma warning(push)
316
#pragma warning(disable : 4815)
317
  for (; btf_ext_offset < line_info_end;) {
42✔
318
    auto section_info =
319
        read_btf<btf_ext_info_sec_t>(btf_ext, btf_ext_offset, swap_endian_ext,
22✔
320
                                     line_info_start, line_info_end);
321
    auto section_name =
322
        _btf_find_string(string_table, section_info.sec_name_off);
22✔
323
    for (size_t index = 0; index < section_info.num_info; index++) {
223✔
324
      auto btf_line_info =
325
          read_btf<bpf_line_info_t>(btf_ext, btf_ext_offset, swap_endian_ext,
201✔
326
                                    line_info_start, line_info_end);
327
      auto file_name =
328
          _btf_find_string(string_table, btf_line_info.file_name_off);
201✔
329
      auto source = _btf_find_string(string_table, btf_line_info.line_off);
201✔
330
      visitor(section_name, btf_line_info.insn_off, file_name, source,
201✔
331
              BPF_LINE_INFO_LINE_NUM(btf_line_info.line_col),
201✔
332
              BPF_LINE_INFO_LINE_COL(btf_line_info.line_col));
201✔
333
    }
201✔
334
  }
22✔
335
#pragma warning(pop)
336
}
20✔
337

338
void btf_parse_types(const std::vector<std::byte> &btf,
87✔
339
                     btf_type_visitor visitor) {
340
  bool swap_endian = false;
87✔
341
  std::map<size_t, std::string> string_table =
342
      _btf_parse_string_table(btf, swap_endian);
87✔
343
  btf_type_id id = 0;
82✔
344
  size_t offset = 0;
82✔
345

346
  auto btf_header = read_btf<btf_header_t>(btf, offset, swap_endian);
82✔
347

348
  // Magic was already validated in _btf_parse_string_table
349

350
  if (btf_header.version != BTF_HEADER_VERSION) {
82✔
351
    throw std::runtime_error("Invalid .BTF section - wrong version");
×
352
  }
353

354
  if (btf_header.hdr_len < sizeof(btf_header_t)) {
82✔
355
    throw std::runtime_error("Invalid .BTF section - wrong size");
×
356
  }
357

358
  size_t type_start = static_cast<size_t>(btf_header.hdr_len) +
82✔
359
                      static_cast<size_t>(btf_header.type_off);
82✔
360
  size_t type_end = type_start + static_cast<size_t>(btf_header.type_len);
82✔
361

362
  validate_range(btf, type_start, type_end);
82✔
363

364
  btf_kind_void kind_null;
365
  visitor(0, "void", {kind_null});
82✔
366

367
  for (offset = type_start; offset < type_end;) {
1,192✔
368
    std::optional<std::string> name;
1,110✔
369
    auto btf_type =
370
        read_btf<btf_type_t>(btf, offset, swap_endian, type_start, type_end);
1,110✔
371
    if (btf_type.name_off) {
1,110✔
372
      name = _btf_find_string(string_table, btf_type.name_off);
566✔
373
    } else {
374
      // Throw for types that should have a name.
375
      switch (BPF_TYPE_INFO_KIND(btf_type.info)) {
544✔
376
      case BTF_KIND_INT:
×
377
      case BTF_KIND_FWD:
378
      case BTF_KIND_TYPEDEF:
379
      case BTF_KIND_FUNCTION:
380
      case BTF_KIND_VAR:
381
      case BTF_KIND_DATA_SECTION:
382
      case BTF_KIND_FLOAT:
383
      case BTF_KIND_DECL_TAG:
384
      case BTF_KIND_TYPE_TAG:
385
        throw std::runtime_error("Invalid .BTF section - missing name");
×
386
      default:
544✔
387
        name = std::nullopt;
544✔
388
        break;
544✔
389
      }
390
    }
391
    btf_kind kind;
1,110✔
392
    switch (BPF_TYPE_INFO_KIND(btf_type.info)) {
1,110✔
393
    case BTF_KIND_INT: {
180✔
394
      btf_kind_int kind_int;
180✔
395
      uint32_t int_data =
396
          read_btf<uint32_t>(btf, offset, swap_endian, type_start, type_end);
180✔
397
      uint32_t encoding = BTF_INT_ENCODING(int_data);
180✔
398
      kind_int.offset_from_start_in_bits = BTF_INT_OFFSET(int_data);
180✔
399
      kind_int.field_width_in_bits = BTF_INT_BITS(int_data);
180✔
400
      kind_int.is_signed = BTF_INT_SIGNED & encoding;
180✔
401
      kind_int.is_bool = BTF_INT_BOOL & encoding;
180✔
402
      kind_int.is_char = BTF_INT_CHAR & encoding;
180✔
403
      kind_int.size_in_bytes = btf_type.size;
180✔
404
      kind_int.name = name.value();
180✔
405
      kind = kind_int;
180✔
406
      break;
180✔
407
    }
180✔
408
    case BTF_KIND_PTR: {
273✔
409
      btf_kind_ptr kind_ptr;
410
      kind_ptr.type = btf_type.type;
273✔
411
      kind = kind_ptr;
273✔
412
      break;
273✔
413
    }
414
    case BTF_KIND_ARRAY: {
123✔
415
      auto btf_array =
416
          read_btf<btf_array_t>(btf, offset, swap_endian, type_start, type_end);
123✔
417
      btf_kind_array kind_array;
418
      kind_array.element_type = btf_array.type;
123✔
419
      kind_array.index_type = btf_array.index_type;
123✔
420
      kind_array.count_of_elements = btf_array.nelems;
123✔
421
      kind = kind_array;
123✔
422
      break;
123✔
423
    }
424
    case BTF_KIND_STRUCT: {
126✔
425
      uint32_t member_count = BPF_TYPE_INFO_VLEN(btf_type.info);
126✔
426
      btf_kind_struct kind_struct;
126✔
427
      for (uint32_t index = 0; index < member_count; index++) {
1,540✔
428
        btf_kind_struct_member member;
1,414✔
429
        auto btf_member = read_btf<btf_member_t>(btf, offset, swap_endian,
1,414✔
430
                                                 type_start, type_end);
431
        if (btf_member.name_off) {
1,414✔
432
          member.name = _btf_find_string(string_table, btf_member.name_off);
1,408✔
433
        }
434
        member.type = btf_member.type;
1,414✔
435
        member.offset_from_start_in_bits = btf_member.offset;
1,414✔
436
        kind_struct.members.push_back(member);
1,414✔
437
      }
1,414✔
438
      kind_struct.size_in_bytes = btf_type.size;
126✔
439
      kind_struct.name = name;
126✔
440
      kind = kind_struct;
126✔
441
      break;
126✔
442
    }
126✔
443
    case BTF_KIND_UNION: {
6✔
444
      uint32_t member_count = BPF_TYPE_INFO_VLEN(btf_type.info);
6✔
445
      btf_kind_union kind_union;
6✔
446
      for (uint32_t index = 0; index < member_count; index++) {
12✔
447
        btf_kind_struct_member member;
6✔
448
        auto btf_member = read_btf<btf_member_t>(btf, offset, swap_endian,
6✔
449
                                                 type_start, type_end);
450
        if (btf_member.name_off) {
6✔
451
          member.name = _btf_find_string(string_table, btf_member.name_off);
6✔
452
        }
453
        member.type = btf_member.type;
6✔
454
        member.offset_from_start_in_bits = btf_member.offset;
6✔
455
        kind_union.members.push_back(member);
6✔
456
      }
6✔
457
      kind_union.name = name;
6✔
458
      kind_union.size_in_bytes = btf_type.size;
6✔
459
      kind = kind_union;
6✔
460
      break;
6✔
461
    }
6✔
462
    case BTF_KIND_ENUM: {
1✔
463
      uint32_t enum_count = BPF_TYPE_INFO_VLEN(btf_type.info);
1✔
464
      btf_kind_enum kind_enum;
1✔
465
      for (uint32_t index = 0; index < enum_count; index++) {
4✔
466
        auto btf_enum = read_btf<btf_enum_t>(btf, offset, swap_endian,
3✔
467
                                             type_start, type_end);
468
        btf_kind_enum_member member;
3✔
469
        if (!btf_enum.name_off) {
3✔
470
          throw std::runtime_error(
×
471
              "Invalid .BTF section - invalid BTF_KIND_ENUM member name");
×
472
        }
473
        member.name = _btf_find_string(string_table, btf_enum.name_off);
3✔
474
        member.value = btf_enum.val;
3✔
475
        kind_enum.members.push_back(member);
3✔
476
      }
3✔
477
      kind_enum.is_signed = BPF_TYPE_INFO_KIND_FLAG(btf_type.info);
1✔
478
      kind_enum.name = name;
1✔
479
      kind_enum.size_in_bytes = btf_type.size;
1✔
480
      kind = kind_enum;
1✔
481
      break;
1✔
482
    }
1✔
483
    case BTF_KIND_FWD: {
30✔
484
      btf_kind_fwd kind_fwd;
30✔
485
      kind_fwd.name = name.value();
30✔
486
      kind_fwd.is_struct = BPF_TYPE_INFO_KIND_FLAG(btf_type.info);
30✔
487
      kind = kind_fwd;
30✔
488
      break;
30✔
489
    }
30✔
490
    case BTF_KIND_TYPEDEF: {
102✔
491
      btf_kind_typedef kind_typedef;
102✔
492
      kind_typedef.name = name.value();
102✔
493
      kind_typedef.type = btf_type.type;
102✔
494
      kind = kind_typedef;
102✔
495
      break;
102✔
496
    }
102✔
497
    case BTF_KIND_VOLATILE: {
3✔
498
      btf_kind_volatile kind_volatile;
499
      kind_volatile.type = btf_type.type;
3✔
500
      kind = kind_volatile;
3✔
501
      break;
3✔
502
    }
503
    case BTF_KIND_CONST: {
3✔
504
      btf_kind_const kind_const;
505
      kind_const.type = btf_type.type;
3✔
506
      kind = kind_const;
3✔
507
      break;
3✔
508
    }
509
    case BTF_KIND_RESTRICT: {
2✔
510
      btf_kind_restrict kind_restrict;
511
      kind_restrict.type = btf_type.type;
2✔
512
      kind = kind_restrict;
2✔
513
      break;
2✔
514
    }
515
    case BTF_KIND_FUNCTION: {
76✔
516
      btf_kind_function kind_function;
76✔
517
      kind_function.name = name.value();
76✔
518
      kind_function.type = btf_type.type;
76✔
519
      kind_function.linkage = static_cast<decltype(kind_function.linkage)>(
76✔
520
          BPF_TYPE_INFO_VLEN(btf_type.info));
76✔
521
      kind = kind_function;
76✔
522
      break;
76✔
523
    }
76✔
524
    case BTF_KIND_FUNCTION_PROTOTYPE: {
77✔
525
      btf_kind_function_prototype kind_function;
77✔
526
      uint32_t param_count = BPF_TYPE_INFO_VLEN(btf_type.info);
77✔
527
      for (uint32_t index = 0; index < param_count; index++) {
154✔
528
        auto btf_param = read_btf<btf_param_t>(btf, offset, swap_endian,
77✔
529
                                               type_start, type_end);
530
        btf_kind_function_parameter param;
77✔
531
        // Name is optional.
532
        if (btf_param.name_off) {
77✔
533
          param.name = _btf_find_string(string_table, btf_param.name_off);
76✔
534
        }
535
        param.type = btf_param.type;
77✔
536
        kind_function.parameters.push_back(param);
77✔
537
      }
77✔
538
      kind_function.return_type = btf_type.type;
77✔
539
      kind = kind_function;
77✔
540
      break;
77✔
541
    }
77✔
542
    case BTF_KIND_VAR: {
57✔
543
      btf_kind_var kind_var;
57✔
544
      auto btf_var =
545
          read_btf<btf_var_t>(btf, offset, swap_endian, type_start, type_end);
57✔
546
      kind_var.name = name.value();
57✔
547
      kind_var.type = btf_type.type;
57✔
548
      kind_var.linkage =
57✔
549
          static_cast<decltype(btf_kind_var::linkage)>(btf_var.linkage);
57✔
550
      kind = kind_var;
57✔
551
      break;
57✔
552
    }
57✔
553
    case BTF_KIND_DATA_SECTION: {
47✔
554
      btf_kind_data_section kind_data_section;
47✔
555
      uint32_t section_count = BPF_TYPE_INFO_VLEN(btf_type.info);
47✔
556
      for (uint32_t index = 0; index < section_count; index++) {
104✔
557
        auto btf_section_info = read_btf<btf_var_secinfo_t>(
57✔
558
            btf, offset, swap_endian, type_start, type_end);
559
        btf_kind_data_member member;
560
        member.type = btf_section_info.type;
57✔
561
        member.offset = btf_section_info.offset;
57✔
562
        member.size = btf_section_info.size;
57✔
563
        kind_data_section.members.push_back(member);
57✔
564
      }
565
      kind_data_section.name = name.value();
47✔
566
      kind_data_section.size = btf_type.size;
47✔
567
      kind = kind_data_section;
47✔
568
      break;
47✔
569
    }
47✔
570
    case BTF_KIND_FLOAT: {
1✔
571
      btf_kind_float kind_float;
1✔
572
      kind_float.name = name.value();
1✔
573
      kind_float.size_in_bytes = btf_type.size;
1✔
574
      kind = kind_float;
1✔
575
      break;
1✔
576
    }
1✔
577
    case BTF_KIND_DECL_TAG: {
1✔
578
      btf_kind_decl_tag kind_decl_tag;
1✔
579
      auto btf_decl_tag = read_btf<btf_decl_tag_t>(btf, offset, swap_endian,
1✔
580
                                                   type_start, type_end);
581
      kind_decl_tag.name = name.value();
1✔
582
      kind_decl_tag.type = btf_type.type;
1✔
583
      kind_decl_tag.component_index = btf_decl_tag.component_idx;
1✔
584
      kind = kind_decl_tag;
1✔
585
      break;
1✔
586
    }
1✔
587
    case BTF_KIND_TYPE_TAG: {
1✔
588
      btf_kind_type_tag kind_type_tag;
1✔
589
      kind_type_tag.name = name.value();
1✔
590
      kind_type_tag.type = btf_type.type;
1✔
591
      kind = kind_type_tag;
1✔
592
      break;
1✔
593
    }
1✔
594
    case BTF_KIND_ENUM64: {
1✔
595
      uint32_t enum_count = BPF_TYPE_INFO_VLEN(btf_type.info);
1✔
596
      btf_kind_enum64 kind_enum;
1✔
597
      for (uint32_t index = 0; index < enum_count; index++) {
4✔
598
        auto btf_enum64 = read_btf<btf_enum64_t>(btf, offset, swap_endian,
3✔
599
                                                 type_start, type_end);
600
        btf_kind_enum64_member member;
3✔
601
        member.name = _btf_find_string(string_table, btf_enum64.name_off);
3✔
602
        member.value = (static_cast<uint64_t>(btf_enum64.val_hi32) << 32) |
3✔
603
                       btf_enum64.val_lo32;
3✔
604
        kind_enum.members.push_back(member);
3✔
605
      }
3✔
606
      kind_enum.is_signed = BPF_TYPE_INFO_KIND_FLAG(btf_type.info);
1✔
607
      kind_enum.name = name;
1✔
608
      kind_enum.size_in_bytes = btf_type.size;
1✔
609
      kind = kind_enum;
1✔
610
      break;
1✔
611
    }
1✔
612
    default:
×
613
      throw std::runtime_error("Invalid .BTF section - invalid BTF_KIND - " +
×
614
                               std::to_string(kind.index()));
×
615
    }
616
    visitor(++id, name, kind);
1,110✔
617
  }
1,110✔
618
}
82✔
619
} // namespace libbtf
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE TRIAL · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc