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

Alan-Jowett / libbtf / 12959776278

25 Jan 2025 12:14AM UTC coverage: 95.324% (-0.07%) from 95.389%
12959776278

Pull #127

github

web-flow
Merge 79c7c2d85 into d583107b6
Pull Request #127: Add check for empty data sections.

1 of 1 new or added line in 1 file covered. (100.0%)

1 existing line in 1 file now uncovered.

1366 of 1433 relevant lines covered (95.32%)

1880.42 hits per line

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

90.05
/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) {
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);
148✔
28
  // Validate that the type graph is valid.
29
  for (const auto &[id, kind] : id_to_kind) {
1,179✔
30
    std::set<btf_type_id> visited;
31
    validate_type_graph(id, visited);
1,108✔
32
  }
33
}
71✔
34

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

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

51
btf_type_id btf_type_data::dereference_pointer(btf_type_id id) const {
41✔
52
  return get_kind_type<btf_kind_ptr>(id).type;
41✔
53
}
54

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

74
void btf_type_data::to_json(
50✔
75
    std::ostream &out,
76
    std::optional<std::function<bool(btf_type_id)>> filter) const {
77
  btf_type_to_json(id_to_kind, out, filter);
50✔
78
}
50✔
79

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

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

94
  visit_depth_first(before, after, id);
2,216✔
95
}
1,106✔
96

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

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

110
  id_to_kind[id] = kind;
1✔
111
  update_name_to_id(id);
1✔
112
}
1✔
113

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

124
void btf_type_data::update_name_to_id(btf_type_id id) {
54✔
125

126
  auto name = get_type_name(id);
54✔
127
  if (!name.empty()) {
54✔
128
    name_to_id.insert({name, id});
14✔
129
  }
130
}
54✔
131

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

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

173
  if (after) {
9,910✔
174
    (*after)(id);
7,718✔
175
  }
176
}
177

178
std::vector<btf_type_id> btf_type_data::dependency_order(
20✔
179
    std::optional<std::function<bool(btf_type_id)>> filter) const {
180
  std::map<btf_type_id, std::set<btf_type_id>> children;
181
  std::map<btf_type_id, std::set<btf_type_id>> parents;
182
  std::set<btf_type_id> filtered_types;
183
  std::vector<btf_type_id> result;
184

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

208
    visit_depth_first(pre, std::nullopt, local_id);
632✔
209
  }
210

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

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

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

239
  std::reverse(filtered_result.begin(), filtered_result.end());
240
  return filtered_result;
20✔
241
}
242

243
void btf_type_data::to_c_header(
20✔
244
    std::ostream &out,
245
    std::optional<std::function<bool(btf_type_id)>> filter) const {
246
  std::set<btf_type_id> declared_types;
247

248
  size_t indent = 0;
20✔
249
  out << "#pragma once\n\n";
20✔
250

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

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

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

321
        std::string suffix;
322
        if constexpr (std::is_same_v<decltype(kind), btf_kind_ptr>) {
323
          suffix = "*";
324
        }
325

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

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

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

456
  return result;
221✔
457
}
458
} // 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