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

Alan-Jowett / libbtf / 17277962087

27 Aug 2025 08:28PM UTC coverage: 95.328% (-0.07%) from 95.395%
17277962087

push

github

web-flow
Bump the actions group across 1 directory with 2 updates (#160)

Bumps the actions group with 2 updates in the / directory: [github/codeql-action](https://github.com/github/codeql-action) and [actions/dependency-review-action](https://github.com/actions/dependency-review-action).


Updates `github/codeql-action` from 3.29.10 to 3.29.11
- [Release notes](https://github.com/github/codeql-action/releases)
- [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md)
- [Commits](https://github.com/github/codeql-action/compare/96f518a34...3c3833e0f)

Updates `actions/dependency-review-action` from 4.7.2 to 4.7.3
- [Release notes](https://github.com/actions/dependency-review-action/releases)
- [Commits](https://github.com/actions/dependency-review-action/compare/bc41886e1...595b5aeba)

---
updated-dependencies:
- dependency-name: github/codeql-action
  dependency-version: 3.29.11
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: actions
- dependency-name: actions/dependency-review-action
  dependency-version: 4.7.3
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: actions
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

1367 of 1434 relevant lines covered (95.33%)

1879.1 hits per line

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

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

4
#include "btf_type_data.h"
5

6
#include "btf.h"
7
#include "btf_json.h"
8
#include "btf_parse.h"
9
#include "btf_write.h"
10

11
#include <algorithm>
12
#include <iomanip>
13
#include <sstream>
14
#include <stdexcept>
15

16
namespace libbtf {
17

18
btf_type_data::btf_type_data(const std::vector<std::byte> &btf_data, bool reject_cycles) {
73✔
19
  auto visitor = [&, this](btf_type_id id,
1,118✔
20
                           const std::optional<std::string> &name,
21
                           const btf_kind &kind) {
1,702✔
22
    this->id_to_kind.insert({id, kind});
1,118✔
23
    if (name.has_value()) {
1,118✔
24
      this->name_to_id.insert({name.value(), id});
584✔
25
    }
26
  };
1,118✔
27
  btf_parse_types(btf_data, visitor);
75✔
28
  // If reject_cycles is true, validate the type graph.
29
  // This will throw an exception if there are cycles.
30
  if (reject_cycles) {
73✔
31
    // Validate that the type graph is valid.
32
    for (const auto &[id, kind] : id_to_kind) {
1,179✔
33
      std::set<btf_type_id> visited;
34
      validate_type_graph(id, visited);
1,108✔
35
    }
36
  }
37
}
71✔
38

39
btf_type_id btf_type_data::get_id(const std::string &name) const {
55✔
40
  auto it = name_to_id.find(name);
41
  if (it == name_to_id.end()) {
55✔
42
    return 0;
43
  }
44
  return it->second;
33✔
45
}
46

47
btf_kind btf_type_data::get_kind(btf_type_id id) const {
12,762✔
48
  auto it = id_to_kind.find(id);
49
  if (it == id_to_kind.end()) {
12,762✔
50
    throw std::runtime_error("BTF type id not found: " + std::to_string(id));
2✔
51
  }
52
  return it->second;
12,761✔
53
}
54

55
btf_type_id btf_type_data::dereference_pointer(btf_type_id id) const {
41✔
56
  return get_kind_type<btf_kind_ptr>(id).type;
41✔
57
}
58

59
uint32_t btf_type_data::get_size(btf_type_id id) const {
483✔
60
  // Compute the effective size of a BTF type.
61
  return std::visit(
483✔
62
      [this, id](auto kind) -> uint32_t {
130✔
63
        if constexpr (std::is_same_v<decltype(kind), btf_kind_ptr>) {
64
          return sizeof(void *);
65
        } else if constexpr (btf_kind_traits<decltype(kind)>::has_type) {
66
          return get_size(kind.type);
95✔
67
        } else if constexpr (btf_kind_traits<decltype(
68
                                 kind)>::has_size_in_bytes) {
69
          return kind.size_in_bytes;
×
70
        } else if constexpr (std::is_same_v<decltype(kind), btf_kind_array>) {
71
          return kind.count_of_elements * get_size(kind.element_type);
35✔
72
        } else
73
          return 0;
74
      },
75
      get_kind(id));
966✔
76
}
77

78
void btf_type_data::to_json(
50✔
79
    std::ostream &out,
80
    std::optional<std::function<bool(btf_type_id)>> filter) const {
81
  btf_type_to_json(id_to_kind, out, filter);
50✔
82
}
50✔
83

84
void btf_type_data::validate_type_graph(btf_type_id id,
1,108✔
85
                                        std::set<btf_type_id> &visited) const {
86
  auto before = [&](btf_type_id id) -> bool {
7,722✔
87
    if (visited.find(id) != visited.end()) {
15,444✔
88
      throw std::runtime_error("BTF type cycle detected: " +
4✔
89
                               std::to_string(id));
4✔
90
    } else {
91
      visited.insert(id);
92
    }
93
    return true;
7,720✔
94
  };
95

96
  auto after = [&](btf_type_id id) { visited.erase(id); };
7,718✔
97

98
  visit_depth_first(before, after, id);
2,216✔
99
}
1,106✔
100

101
std::vector<std::byte> btf_type_data::to_bytes() const {
27✔
102
  std::vector<btf_kind> kinds;
103
  for (const auto &[id, kind] : id_to_kind) {
377✔
104
    kinds.push_back(kind);
350✔
105
  }
106
  return btf_write_types(kinds);
54✔
107
}
27✔
108

109
void btf_type_data::replace(btf_type_id id, const btf_kind &kind) {
1✔
110
  if (id_to_kind.find(id) == id_to_kind.end()) {
1✔
111
    throw std::runtime_error("BTF type not found: " + std::to_string(id));
×
112
  }
113

114
  id_to_kind[id] = kind;
1✔
115
  update_name_to_id(id);
1✔
116
}
1✔
117

118
btf_type_id btf_type_data::append(const btf_kind &kind) {
53✔
119
  if (id_to_kind.size() > UINT32_MAX) {
53✔
120
    throw std::runtime_error("Too many BTF types");
×
121
  }
122
  btf_type_id next_id = static_cast<btf_type_id>(id_to_kind.size());
53✔
123
  id_to_kind.insert({next_id, kind});
53✔
124
  update_name_to_id(next_id);
53✔
125
  return next_id;
53✔
126
}
127

128
void btf_type_data::update_name_to_id(btf_type_id id) {
54✔
129

130
  auto name = get_type_name(id);
54✔
131
  if (!name.empty()) {
54✔
132
    name_to_id.insert({name, id});
14✔
133
  }
134
}
54✔
135

136
void btf_type_data::visit_depth_first(
9,914✔
137
    std::optional<std::function<bool(btf_type_id)>> before,
138
    std::optional<std::function<void(btf_type_id)>> after,
139
    btf_type_id id) const {
140
  if (before) {
9,914✔
141
    if (!(*before)(id)) {
9,912✔
142
      return;
143
    }
144
  }
145

146
  std::visit(
9,912✔
147
      [&, this](auto kind) {
6,698✔
148
        if constexpr (btf_kind_traits<decltype(kind)>::has_type) {
149
          visit_depth_first(before, after, kind.type);
21,099✔
150
        }
151
        if constexpr (btf_kind_traits<decltype(kind)>::has_index_type) {
152
          visit_depth_first(before, after, kind.index_type);
2,904✔
153
        }
154
        if constexpr (btf_kind_traits<decltype(kind)>::has_element_type) {
155
          visit_depth_first(before, after, kind.element_type);
2,904✔
156
        }
157
        if constexpr (btf_kind_traits<decltype(kind)>::has_members) {
158
          for (auto member : kind.members) {
2,774✔
159
            if constexpr (btf_kind_traits<decltype(member)>::has_type) {
160
              visit_depth_first(before, after, member.type);
6,319✔
161
            }
162
          }
163
        }
164
        if constexpr (btf_kind_traits<decltype(kind)>::has_return_type) {
165
          visit_depth_first(before, after, kind.return_type);
764✔
166
        }
167
        if constexpr (btf_kind_traits<decltype(kind)>::has_parameters) {
168
          for (auto param : kind.parameters) {
404✔
169
            if constexpr (btf_kind_traits<decltype(param)>::has_type) {
170
              visit_depth_first(before, after, param.type);
562✔
171
            }
172
          }
173
        }
174
      },
5,526✔
175
      get_kind(id));
19,822✔
176

177
  if (after) {
9,910✔
178
    (*after)(id);
7,718✔
179
  }
180
}
181

182
std::vector<btf_type_id> btf_type_data::dependency_order(
20✔
183
    std::optional<std::function<bool(btf_type_id)>> filter) const {
184
  std::map<btf_type_id, std::set<btf_type_id>> children;
185
  std::map<btf_type_id, std::set<btf_type_id>> parents;
186
  std::set<btf_type_id> filtered_types;
187
  std::vector<btf_type_id> result;
188

189
  // Build list of dependencies.
190
  for (const auto &[id, kind] : id_to_kind) {
336✔
191
    // Copy id to a local variable to workaround a bug in Apple's clang.
192
    // See: https://github.com/llvm/llvm-project/issues/48582
193
    auto local_id = id;
316✔
194
    bool match = false;
316✔
195
    if (!filter || (*filter)(local_id)) {
316✔
196
      match = true;
316✔
197
    }
198
    auto pre = [&](btf_type_id visit_id) -> bool {
2,192✔
199
      if (match) {
2,192✔
200
        filtered_types.insert(visit_id);
2,192✔
201
      }
202
      if (visit_id != local_id) {
4,068✔
203
        children[local_id].insert(visit_id);
1,876✔
204
        parents[visit_id].insert(local_id);
2,192✔
205
      } else {
206
        parents.insert({local_id, {}});
316✔
207
        children.insert({local_id, {}});
316✔
208
      }
209
      return true;
2,192✔
210
    };
316✔
211

212
    visit_depth_first(pre, std::nullopt, local_id);
632✔
213
  }
214

215
  while (!parents.empty()) {
151✔
216
    std::vector<btf_type_id> types_to_remove;
217
    // Find all types with no parents.
218
    for (auto &[id, child_set] : parents) {
1,382✔
219
      if (child_set.empty()) {
1,251✔
220
        types_to_remove.push_back(id);
316✔
221
      }
222
    }
223

224
    // Remove these parents from all children.
225
    for (auto id : types_to_remove) {
447✔
226
      for (auto child : children[id]) {
1,402✔
227
        parents[child].erase(id);
1,086✔
228
      }
229
      parents.erase(id);
230
    }
231
    // Append these types to the result.
232
    result.insert(result.end(), types_to_remove.begin(), types_to_remove.end());
131✔
233
  }
234

235
  // Remove types that are not children of the filtered type.
236
  std::vector<btf_type_id> filtered_result;
237
  for (auto id : result) {
336✔
238
    if (filtered_types.find(id) != filtered_types.end()) {
316✔
239
      filtered_result.push_back(id);
316✔
240
    }
241
  }
242

243
  std::reverse(filtered_result.begin(), filtered_result.end());
244
  return filtered_result;
20✔
245
}
246

247
void btf_type_data::to_c_header(
20✔
248
    std::ostream &out,
249
    std::optional<std::function<bool(btf_type_id)>> filter) const {
250
  std::set<btf_type_id> declared_types;
251

252
  size_t indent = 0;
20✔
253
  out << "#pragma once\n\n";
20✔
254

255
  // Print each type in dependency order.
256
  for (auto id : dependency_order(filter)) {
356✔
257
    if (get_type_name(id).empty()) {
632✔
258
      continue;
167✔
259
    }
260
    std::visit(
149✔
261
        [&, this](auto kind) {
137✔
262
          if constexpr (std::is_same_v<decltype(kind), btf_kind_typedef>) {
263
            out << "typedef ";
84✔
264
            out << get_type_declaration(kind.type, kind.name, indent)
74✔
265
                << ";\n\n";
62✔
266
          } else if constexpr (std::is_same_v<decltype(kind),
267
                                              btf_kind_struct>) {
268
            out << get_type_declaration(id, "", indent) << ";\n\n";
18✔
269
          } else if constexpr (std::is_same_v<decltype(kind), btf_kind_union>) {
270
            out << get_type_declaration(id, "", indent) << ";\n\n";
×
271
          } else if constexpr (std::is_same_v<decltype(kind), btf_kind_fwd>) {
272
            out << (kind.is_struct ? "union" : "struct ") << kind.name
10✔
273
                << ";\n\n";
30✔
274
          } else if constexpr (std::is_same_v<decltype(kind), btf_kind_var>) {
275
            out << get_type_declaration(kind.type, kind.name, indent)
15✔
276
                << ";\n\n";
30✔
277
          } else if constexpr (std::is_same_v<decltype(kind),
278
                                              btf_kind_function>) {
279
            if (kind.linkage == BTF_LINKAGE_STATIC) {
22✔
280
              out << "static ";
×
281
            } else if (kind.linkage == BTF_LINKAGE_EXTERN) {
22✔
282
              out << "extern ";
×
283
            }
284
            out << get_type_declaration(kind.type, kind.name, indent)
22✔
285
                << ";\n\n";
44✔
286
          }
287
        },
84✔
288
        get_kind(id));
298✔
289
  }
290
}
20✔
291

292
std::string btf_type_data::get_type_name(btf_type_id id) const {
606✔
293
  // Use visit to return the name if the type has it.
294
  auto kind = get_kind(id);
606✔
295
  return std::visit(
296
      [](auto kind) -> std::string {
297
        if constexpr (btf_kind_traits<decltype(kind)>::has_optional_name) {
298
          return kind.name.value_or("");
30✔
299
        } else if constexpr (btf_kind_traits<decltype(kind)>::has_name) {
300
          return kind.name;
314✔
301
        } else {
302
          return "";
262✔
303
        }
304
      },
305
      get_kind(id));
1,818✔
306
}
307

308
std::string btf_type_data::get_qualified_type_name(btf_type_id id) const {
66✔
309
  // Use visit to return the name if the type has it.
310
  auto kind = get_kind(id);
66✔
311
  return std::visit(
312
      [this](auto kind) -> std::string {
66✔
313
        // Add possible qualifiers.
314
        std::string qualifier;
315
        if constexpr (std::is_same_v<decltype(kind), btf_kind_const>) {
316
          qualifier = "const ";
317
        } else if constexpr (std::is_same_v<decltype(kind),
318
                                            btf_kind_volatile>) {
319
          qualifier = "volatile ";
320
        } else if constexpr (std::is_same_v<decltype(kind),
321
                                            btf_kind_restrict>) {
322
          qualifier = "restrict ";
323
        }
324

325
        std::string suffix;
326
        if constexpr (std::is_same_v<decltype(kind), btf_kind_ptr>) {
327
          suffix = "*";
328
        }
329

330
        if constexpr (btf_kind_traits<decltype(kind)>::has_optional_name) {
331
          return qualifier + kind.name.value_or("") + suffix;
24✔
332
        } else if constexpr (btf_kind_traits<decltype(kind)>::has_name) {
333
          return kind.name + suffix;
60✔
334
        } else if constexpr (btf_kind_traits<decltype(kind)>::has_type) {
335
          return qualifier + this->get_qualified_type_name(kind.type) + suffix;
66✔
336
        } else if constexpr (std::is_same_v<decltype(kind), btf_kind_void>) {
337
          return qualifier + "void" + suffix;
18✔
338
        } else {
339
          return "";
×
340
        }
341
      },
342
      get_kind(id));
198✔
343
}
344

345
btf_type_id btf_type_data::get_descendant_type_id(btf_type_id id) const {
×
346
  // Get the type id lowest in the tree.
347
  auto kind = get_kind(id);
×
348
  return std::visit(
×
349
      [id, this](auto kind) -> btf_type_id {
×
350
        if constexpr (btf_kind_traits<decltype(kind)>::has_type) {
351
          return this->get_descendant_type_id(kind.type);
×
352
        } else {
353
          return id;
×
354
        }
355
      },
356
      kind);
×
357
}
358

359
std::string btf_type_data::get_type_declaration(btf_type_id id,
221✔
360
                                                const std::string &name,
361
                                                size_t indent) const {
362
  // Build a string of type qualifiers.
363
  std::string result = std::string(indent, ' ');
221✔
364
  auto kind = get_kind(id);
221✔
365
  std::visit(
221✔
366
      [&](auto kind) {
221✔
367
        if constexpr (std::is_same_v<decltype(kind), btf_kind_typedef>) {
368
          result += get_type_name(id) + " " + name;
645✔
369
        } else if constexpr (std::is_same_v<decltype(kind), btf_kind_array>) {
370
          auto local_name = name;
371
          if (!local_name.empty() && local_name[0] == '*') {
42✔
372
            local_name = "(" + local_name + ")";
74✔
373
          }
374
          auto local_type = get_type_name(kind.element_type);
42✔
375
          if (local_type.empty()) {
42✔
376
            local_type = get_type_declaration(kind.element_type, "", indent);
231✔
377
          }
378
          result += local_type + " " + local_name + "[" +
84✔
379
                    std::to_string(kind.count_of_elements) + "]";
380
        } else
381
            // If kind is btf_kind_const, add const
382
            if constexpr (std::is_same_v<decltype(kind), btf_kind_const>) {
383
          result += "const " + get_type_declaration(kind.type, name, indent);
×
384
        } else
385
            // If kind is btf_kind_volatile, add volatile
386
            if constexpr (std::is_same_v<decltype(kind), btf_kind_volatile>) {
387
          result += "volatile " + get_type_declaration(kind.type, name, indent);
×
388
        } else
389
            // If kind is btf_kind_restrict, add restrict
390
            if constexpr (std::is_same_v<decltype(kind), btf_kind_restrict>) {
391
          result += "restrict " + get_type_declaration(kind.type, name, indent);
×
392
        } else
393
            // If kind is btf_kind_ptr, add *
394
            if constexpr (std::is_same_v<decltype(kind), btf_kind_ptr>) {
395
          result = get_type_declaration(kind.type, "*" + name, indent);
140✔
396
        } else if constexpr (std::is_same_v<decltype(kind), btf_kind_struct>) {
397
          if (kind.name.has_value()) {
23✔
398
            result = "struct " + kind.name.value_or("") + " {\n";
12✔
399
          } else {
400
            result = "struct {\n";
401
          }
402
          for (auto member : kind.members) {
153✔
403
            std::string type_name = get_type_name(member.type);
130✔
404
            if (type_name.empty()) {
130✔
405
              result += get_type_declaration(
146✔
406
                            member.type, member.name.value_or(""), indent + 2) +
407
                        ";\n";
408
            } else {
409
              result += std::string(indent + 2, ' ') + type_name + " " +
114✔
410
                        member.name.value_or("") + ";\n";
411
            }
412
          }
413
          result += std::string(indent, ' ') + "}";
46✔
414
          if (!name.empty()) {
23✔
415
            result += " " + name;
34✔
416
          }
417
        } else if constexpr (std::is_same_v<decltype(kind), btf_kind_union>) {
418
          if (kind.name.has_value()) {
2✔
419
            result += "union " + kind.name.value_or("") + " {\n";
×
420
          } else {
421
            result += "union {\n";
422
          }
423
          for (auto member : kind.members) {
4✔
424
            std::string type_name = get_type_name(member.type);
2✔
425
            if (type_name.empty()) {
2✔
426
              result += get_type_declaration(
4✔
427
                            member.type, member.name.value_or(""), indent + 2) +
428
                        ";\n";
429
            } else {
430
              result += std::string(indent + 2, ' ') + type_name + " " +
×
431
                        member.name.value_or("") + ";\n";
432
            }
433
          }
434
          result += std::string(indent, ' ') + "}";
4✔
435
          if (!name.empty()) {
2✔
436
            result += " " + name;
×
437
          }
438
        } else if constexpr (std::is_same_v<decltype(kind),
439
                                            btf_kind_function_prototype>) {
440
          result +=
44✔
441
              get_qualified_type_name(kind.return_type) + " " + name + "(";
442
          for (auto param : kind.parameters) {
44✔
443
            result += get_qualified_type_name(param.type);
44✔
444
            if (!param.name.empty()) {
22✔
445
              result += " " + param.name;
44✔
446
            }
447
            result += ", ";
448
          }
449
          if (kind.parameters.size() > 0) {
22✔
450
            result.pop_back();
451
            result.pop_back();
452
          }
453
          result += ")";
454
        } else if constexpr (!btf_kind_traits<decltype(kind)>::has_type) {
455
          result += get_type_name(id) + " " + name;
56✔
456
        }
457
      },
221✔
458
      kind);
459

460
  return result;
221✔
461
}
462
} // 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