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

Alan-Jowett / libbtf / 21368819186

26 Jan 2026 06:16PM UTC coverage: 94.862% (-1.2%) from 96.04%
21368819186

Pull #183

github

web-flow
Merge d63d8ae1e into e1e4e01b7
Pull Request #183: Support big-endian BPF programs

73 of 105 new or added lines in 2 files covered. (69.52%)

1 existing line in 1 file now uncovered.

2234 of 2355 relevant lines covered (94.86%)

1529.26 hits per line

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

85.79
/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 <cstring>
9
#include <stdexcept>
10
#include <algorithm>
11

12
namespace libbtf {
13

14
// Byte swap utilities for endianness conversion
15
static inline uint16_t bswap_16(uint16_t val) {
16
  return (val >> 8) | (val << 8);
17
}
18

19
static inline uint32_t bswap_32(uint32_t val) {
14✔
20
  return ((val >> 24) & 0x000000FF) |
18✔
21
         ((val >> 8)  & 0x0000FF00) |
18✔
22
         ((val << 8)  & 0x00FF0000) |
18✔
23
         ((val << 24) & 0xFF000000);
18✔
24
}
25

26
// Template to swap bytes for multi-byte types
27
template <typename T>
28
static void swap_bytes(T& value);
29

30
template <>
31
void swap_bytes<uint16_t>(uint16_t& value) {
32
  value = bswap_16(value);
33
}
34

35
template <>
36
void swap_bytes<uint32_t>(uint32_t& value) {
14✔
37
  value = bswap_32(value);
17✔
38
}
15✔
39

40
template <>
41
void swap_bytes<int32_t>(int32_t& value) {
42
  value = static_cast<int32_t>(bswap_32(static_cast<uint32_t>(value)));
43
}
44

45
// Swap bytes for BTF structures
46
static void swap_btf_header(btf_header_t& header) {
4✔
47
  // Don't swap magic - it's used for endianness detection
48
  // version and flags are single bytes, no swap needed
49
  swap_bytes(header.hdr_len);
2✔
50
  swap_bytes(header.type_off);
2✔
51
  swap_bytes(header.type_len);
2✔
52
  swap_bytes(header.str_off);
2✔
53
  swap_bytes(header.str_len);
2✔
54
}
4✔
55

NEW
56
static void swap_btf_ext_header(btf_ext_header_t& header) {
×
57
  // Don't swap magic - it's used for endianness detection
58
  // version and flags are single bytes, no swap needed
59
  swap_bytes(header.hdr_len);
60
  swap_bytes(header.func_info_off);
61
  swap_bytes(header.func_info_len);
62
  swap_bytes(header.line_info_off);
63
  swap_bytes(header.line_info_len);
NEW
64
}
×
65

66
static void swap_btf_type(btf_type_t& type) {
2✔
67
  swap_bytes(type.name_off);
1✔
68
  swap_bytes(type.info);
1✔
69
  swap_bytes(type.size); // size and type are in a union, so swapping one swaps both
1✔
70
}
2✔
71

NEW
72
static void swap_btf_array(btf_array_t& array) {
×
73
  swap_bytes(array.type);
74
  swap_bytes(array.index_type);
75
  swap_bytes(array.nelems);
NEW
76
}
×
77

NEW
78
static void swap_btf_member(btf_member_t& member) {
×
79
  swap_bytes(member.name_off);
80
  swap_bytes(member.type);
81
  swap_bytes(member.offset);
NEW
82
}
×
83

NEW
84
static void swap_btf_param(btf_param_t& param) {
×
85
  swap_bytes(param.name_off);
86
  swap_bytes(param.type);
NEW
87
}
×
88

89
static void swap_btf_var(btf_var_t& var) {
90
  swap_bytes(var.linkage);
NEW
91
}
×
92

NEW
93
static void swap_btf_var_secinfo(btf_var_secinfo_t& secinfo) {
×
94
  swap_bytes(secinfo.type);
95
  swap_bytes(secinfo.offset);
96
  swap_bytes(secinfo.size);
NEW
97
}
×
98

NEW
99
static void swap_btf_enum(btf_enum_t& enm) {
×
100
  swap_bytes(enm.name_off);
101
  swap_bytes(enm.val);
NEW
102
}
×
103

NEW
104
static void swap_btf_enum64(btf_enum64_t& enm) {
×
105
  swap_bytes(enm.name_off);
106
  swap_bytes(enm.val_lo32);
107
  swap_bytes(enm.val_hi32);
NEW
108
}
×
109

110
static void swap_btf_decl_tag(btf_decl_tag_t& tag) {
111
  swap_bytes(tag.component_idx);
NEW
112
}
×
113

NEW
114
static void swap_btf_ext_info_sec(btf_ext_info_sec_t& sec) {
×
115
  swap_bytes(sec.sec_name_off);
116
  swap_bytes(sec.num_info);
NEW
117
}
×
118

NEW
119
static void swap_bpf_line_info(bpf_line_info_t& info) {
×
120
  swap_bytes(info.insn_off);
121
  swap_bytes(info.file_name_off);
122
  swap_bytes(info.line_off);
123
  swap_bytes(info.line_col);
NEW
124
}
×
125

126
static void swap_bpf_func_info(bpf_func_info_t& info) {
127
  swap_bytes(info.insn_off);
128
  swap_bytes(info.type_id);
129
}
130
template <typename T>
131
static T read_btf(const std::vector<std::byte> &btf, size_t &offset,
10,884✔
132
                  bool swap_endian = false,
133
                  size_t minimum_offset = 0, size_t maximum_offset = 0) {
134
  size_t length = 0;
5,442✔
135
  if (maximum_offset == 0) {
10,884✔
136
    maximum_offset = btf.size();
209✔
137
  }
138
  if (offset < minimum_offset || offset > maximum_offset) {
10,884✔
139
    throw std::runtime_error("Invalid .BTF section - invalid offset");
×
140
  }
141

142
  if constexpr (std::is_same<T, std::string>::value) {
143
    length = strnlen(reinterpret_cast<const char *>(btf.data()) + offset,
3,918✔
144
                     maximum_offset - offset);
145
    offset += length + 1;
3,918✔
146
    if (offset > maximum_offset) {
3,918✔
147
      throw std::runtime_error("Invalid .BTF section - invalid string length");
×
148
    }
149
    return std::string(reinterpret_cast<const char *>(btf.data()) + offset -
3,918✔
150
                           length - 1,
3,918✔
151
                       length);
3,918✔
152
  } else {
153
    length = sizeof(T);
3,483✔
154
    offset += length;
6,966✔
155
    if (offset > maximum_offset) {
6,966✔
156
      throw std::runtime_error("Invalid .BTF section - invalid type length");
×
157
    }
158
    T value = *reinterpret_cast<const T *>(btf.data() + offset - length);
6,966✔
159
    
160
    // Swap bytes if needed for multi-byte types
161
    // Note: Using if constexpr ensures zero runtime overhead - the compiler evaluates
162
    // these branches at compile time and only instantiates the matching branch for each type
163
    if (swap_endian && length > 1) {
6,966✔
164
      if constexpr (std::is_same<T, btf_header_t>::value) {
165
        swap_btf_header(value);
2✔
166
      } else if constexpr (std::is_same<T, btf_ext_header_t>::value) {
NEW
167
        swap_btf_ext_header(value);
×
168
      } else if constexpr (std::is_same<T, btf_type_t>::value) {
169
        swap_btf_type(value);
2✔
170
      } else if constexpr (std::is_same<T, btf_array_t>::value) {
NEW
171
        swap_btf_array(value);
×
172
      } else if constexpr (std::is_same<T, btf_member_t>::value) {
NEW
173
        swap_btf_member(value);
×
174
      } else if constexpr (std::is_same<T, btf_param_t>::value) {
NEW
175
        swap_btf_param(value);
×
176
      } else if constexpr (std::is_same<T, btf_var_t>::value) {
177
        swap_btf_var(value);
178
      } else if constexpr (std::is_same<T, btf_var_secinfo_t>::value) {
NEW
179
        swap_btf_var_secinfo(value);
×
180
      } else if constexpr (std::is_same<T, btf_enum_t>::value) {
NEW
181
        swap_btf_enum(value);
×
182
      } else if constexpr (std::is_same<T, btf_enum64_t>::value) {
NEW
183
        swap_btf_enum64(value);
×
184
      } else if constexpr (std::is_same<T, btf_decl_tag_t>::value) {
185
        swap_btf_decl_tag(value);
186
      } else if constexpr (std::is_same<T, btf_ext_info_sec_t>::value) {
NEW
187
        swap_btf_ext_info_sec(value);
×
188
      } else if constexpr (std::is_same<T, bpf_line_info_t>::value) {
NEW
189
        swap_bpf_line_info(value);
×
190
      } else if constexpr (std::is_same<T, bpf_func_info_t>::value) {
191
        swap_bpf_func_info(value);
192
      } else if constexpr (std::is_same<T, uint16_t>::value || 
193
                           std::is_same<T, uint32_t>::value ||
194
                           std::is_same<T, int32_t>::value) {
195
        swap_bytes(value);
1✔
196
      }
197
    }
198
    
199
    return value;
6,966✔
200
  }
201
}
202

203
static void validate_offset(std::vector<std::byte> const &btf, size_t offset) {
822✔
204
  if (offset < 0) {
205
    throw std::runtime_error("Invalid .BTF section - invalid offset");
206
  }
207

208
  if (offset > btf.size()) {
822✔
209
    throw std::runtime_error("Invalid .BTF section - invalid offset");
4✔
210
  }
211
}
818✔
212

213
static void validate_range(std::vector<std::byte> const &btf, size_t start,
412✔
214
                           size_t end) {
215
  validate_offset(btf, start);
412✔
216
  validate_offset(btf, end);
410✔
217

218
  if (start > end) {
408✔
219
    throw std::runtime_error("Invalid .BTF section - invalid range");
×
220
  }
221
}
408✔
222

223
static std::map<size_t, std::string>
224
_btf_parse_string_table(const std::vector<std::byte> &btf, bool& swap_endian) {
214✔
225
  std::map<size_t, std::string> string_table;
107✔
226

227
  size_t offset = 0;
214✔
228
  auto btf_header = read_btf<btf_header_t>(btf, offset, false); // Read without swapping first
214✔
229
  
230
  // Detect endianness from magic number
231
  swap_endian = false;
214✔
232
  if (btf_header.magic == BTF_HEADER_MAGIC) {
214✔
233
    swap_endian = false;
105✔
234
  } else if (btf_header.magic == BTF_HEADER_MAGIC_BIG_ENDIAN) {
4✔
235
    swap_endian = true;
2✔
236
    // Swap the header we just read
237
    swap_btf_header(btf_header);
2✔
238
  } else {
239
    throw std::runtime_error("Invalid .BTF section - wrong magic");
2✔
240
  }
241
  
242
  if (btf_header.version != BTF_HEADER_VERSION) {
212✔
243
    throw std::runtime_error("Invalid .BTF section - wrong version");
2✔
244
  }
245
  if (btf_header.hdr_len < sizeof(btf_header_t)) {
210✔
246
    throw std::runtime_error("Invalid .BTF section - wrong size");
2✔
247
  }
248
  if (btf_header.hdr_len > btf.size()) {
208✔
249
    throw std::runtime_error("Invalid .BTF section - invalid header length");
×
250
  }
251

252
  size_t string_table_start = static_cast<size_t>(btf_header.hdr_len) +
208✔
253
                              static_cast<size_t>(btf_header.str_off);
208✔
254
  size_t string_table_end =
208✔
255
      string_table_start + static_cast<size_t>(btf_header.str_len);
208✔
256

257
  validate_range(btf, string_table_start, string_table_end);
208✔
258

259
  for (offset = string_table_start; offset < string_table_end;) {
4,122✔
260
    size_t string_offset = offset - string_table_start;
3,918✔
261
    std::string value = read_btf<std::string>(btf, offset, swap_endian, string_table_start,
3,918✔
262
                                              string_table_end);
3,918✔
263
    if (offset > string_table_end) {
3,918✔
264
      throw std::runtime_error("Invalid .BTF section - invalid string length");
×
265
    }
266
    string_table.insert({string_offset, value});
3,918✔
267
  }
1,959✔
268
  return string_table;
306✔
269
}
5✔
270

271
static std::string
272
_btf_find_string(const std::map<size_t, std::string> &string_table,
4,972✔
273
                 size_t string_offset) {
274
  auto it = string_table.find(string_offset);
2,486✔
275
  if (it == string_table.end()) {
4,972✔
276
    throw std::runtime_error(
×
277
        std::string("Invalid .BTF section - invalid string offset"));
×
278
  }
279
  return it->second;
7,458✔
280
}
281

282
void btf_parse_line_information(const std::vector<std::byte> &btf,
40✔
283
                                const std::vector<std::byte> &btf_ext,
284
                                btf_line_info_visitor visitor) {
285
  bool swap_endian = false;
40✔
286
  std::map<size_t, std::string> string_table = _btf_parse_string_table(btf, swap_endian);
40✔
287

288
  size_t btf_ext_offset = 0;
40✔
289
  auto bpf_ext_header = read_btf<btf_ext_header_t>(btf_ext, btf_ext_offset, false); // Read without swapping first
40✔
290
  
291
  // Detect endianness from magic number for BTF.ext
292
  bool swap_endian_ext = false;
20✔
293
  if (bpf_ext_header.magic == BTF_HEADER_MAGIC) {
40✔
294
    swap_endian_ext = false;
20✔
NEW
295
  } else if (bpf_ext_header.magic == BTF_HEADER_MAGIC_BIG_ENDIAN) {
×
296
    swap_endian_ext = true;
297
    // Swap the header we just read
NEW
298
    swap_btf_ext_header(bpf_ext_header);
×
299
  } else {
NEW
300
    throw std::runtime_error("Invalid .BTF.ext section - wrong magic");
×
301
  }
302
  
303
  if (bpf_ext_header.hdr_len < sizeof(btf_ext_header_t)) {
40✔
304
    throw std::runtime_error("Invalid .BTF.ext section - wrong size");
×
305
  }
306
  if (bpf_ext_header.version != BTF_HEADER_VERSION) {
40✔
307
    throw std::runtime_error("Invalid .BTF.ext section - wrong version");
×
308
  }
309
  if (bpf_ext_header.hdr_len > btf_ext.size()) {
40✔
310
    throw std::runtime_error(
×
311
        "Invalid .BTF.ext section - invalid header length");
×
312
  }
313

314
  size_t line_info_start = static_cast<size_t>(bpf_ext_header.hdr_len) +
40✔
315
                           static_cast<size_t>(bpf_ext_header.line_info_off);
40✔
316
  size_t line_info_end =
40✔
317
      line_info_start + static_cast<size_t>(bpf_ext_header.line_info_len);
40✔
318

319
  validate_range(btf_ext, line_info_start, line_info_end);
40✔
320

321
  btf_ext_offset = line_info_start;
40✔
322
  uint32_t line_info_record_size = read_btf<uint32_t>(
40✔
323
      btf_ext, btf_ext_offset, swap_endian_ext, line_info_start, line_info_end);
324
  if (line_info_record_size < sizeof(bpf_line_info_t)) {
40✔
325
    throw std::runtime_error(std::string(
×
326
        "Invalid .BTF.ext section - invalid line info record size"));
×
327
  }
328

329
// Suppress warning C4815 on MSVC
330
// section_info is declared on the stack, but its size depends on the number of
331
// elements in the section. This is not a problem, because the number the code
332
// only uses the header.
333
#pragma warning(push)
334
#pragma warning(disable : 4815)
335
  for (; btf_ext_offset < line_info_end;) {
84✔
336
    auto section_info = read_btf<btf_ext_info_sec_t>(
44✔
337
        btf_ext, btf_ext_offset, swap_endian_ext, line_info_start, line_info_end);
338
    auto section_name =
339
        _btf_find_string(string_table, section_info.sec_name_off);
44✔
340
    for (size_t index = 0; index < section_info.num_info; index++) {
446✔
341
      auto btf_line_info = read_btf<bpf_line_info_t>(
402✔
342
          btf_ext, btf_ext_offset, swap_endian_ext, line_info_start, line_info_end);
343
      auto file_name =
344
          _btf_find_string(string_table, btf_line_info.file_name_off);
402✔
345
      auto source = _btf_find_string(string_table, btf_line_info.line_off);
402✔
346
      visitor(section_name, btf_line_info.insn_off, file_name, source,
603✔
347
              BPF_LINE_INFO_LINE_NUM(btf_line_info.line_col),
201✔
348
              BPF_LINE_INFO_LINE_COL(btf_line_info.line_col));
201✔
349
    }
201✔
350
  }
22✔
351
#pragma warning(pop)
352
}
40✔
353

354
void btf_parse_types(const std::vector<std::byte> &btf,
174✔
355
                     btf_type_visitor visitor) {
356
  bool swap_endian = false;
174✔
357
  std::map<size_t, std::string> string_table = _btf_parse_string_table(btf, swap_endian);
174✔
358
  btf_type_id id = 0;
82✔
359
  size_t offset = 0;
164✔
360

361
  auto btf_header = read_btf<btf_header_t>(btf, offset, swap_endian);
164✔
362

363
  // Magic was already validated in _btf_parse_string_table
364
  
365
  if (btf_header.version != BTF_HEADER_VERSION) {
164✔
366
    throw std::runtime_error("Invalid .BTF section - wrong version");
×
367
  }
368

369
  if (btf_header.hdr_len < sizeof(btf_header_t)) {
164✔
370
    throw std::runtime_error("Invalid .BTF section - wrong size");
×
371
  }
372

373
  size_t type_start = static_cast<size_t>(btf_header.hdr_len) +
164✔
374
                      static_cast<size_t>(btf_header.type_off);
164✔
375
  size_t type_end = type_start + static_cast<size_t>(btf_header.type_len);
164✔
376

377
  validate_range(btf, type_start, type_end);
164✔
378

379
  btf_kind_void kind_null;
380
  visitor(0, "void", {kind_null});
164✔
381

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

© 2026 Coveralls, Inc