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

Alan-Jowett / libbtf / 15799657858

04 Jun 2025 03:15PM UTC coverage: 93.874% (-1.5%) from 95.328%
15799657858

push

github

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

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


Updates `github/codeql-action` from 3.28.18 to 3.28.19
- [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/ff0a06e83...fca7ace96)

Updates `ossf/scorecard-action` from 2.4.1 to 2.4.2
- [Release notes](https://github.com/ossf/scorecard-action/releases)
- [Changelog](https://github.com/ossf/scorecard-action/blob/main/RELEASE.md)
- [Commits](https://github.com/ossf/scorecard-action/compare/f49aabe0b...05b42c624)

---
updated-dependencies:
- dependency-name: github/codeql-action
  dependency-version: 3.28.19
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: actions
- dependency-name: ossf/scorecard-action
  dependency-version: 2.4.2
  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>

1134 of 1208 relevant lines covered (93.87%)

1213.75 hits per line

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

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

4
#include "btf_map.h"
5

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

12
#include <algorithm>
13
#include <stdexcept>
14

15
namespace libbtf {
16
static uint32_t _value_from_BTF__uint(const btf_type_data &btf_types,
28✔
17
                                      btf_type_id type_id) {
18
  // The __uint macro is defined as follows:
19
  // #define __uint(name, val) int (*name)[val]
20
  // So, we need to get the value of val from the BTF type.
21

22
  // Top level should be a pointer. Dereference it.
23
  type_id = btf_types.dereference_pointer(type_id);
28✔
24

25
  // Value is encoded in the count of elements.
26
  return btf_types.get_kind_type<btf_kind_array>(type_id).count_of_elements;
28✔
27
}
28

29
/**
30
 * @brief Walk the type chain removing typedefs, const, and volatile until any
31
 * other type is found.
32
 *
33
 * @param[in] btf_types The BTF types object.
34
 * @param[in] type_id The type ID to unwrap.
35
 * @return The unwrapped type ID.
36
 */
37
static btf_type_id _unwrap_type(const btf_type_data &btf_types,
19✔
38
                                btf_type_id type_id) {
39
  for (;;) {
40
    switch (btf_types.get_kind_index(type_id)) {
23✔
41
    case BTF_KIND_TYPEDEF:
4✔
42
      type_id = btf_types.get_kind_type<btf_kind_typedef>(type_id).type;
4✔
43
      break;
4✔
44
    case BTF_KIND_CONST:
×
45
      type_id = btf_types.get_kind_type<btf_kind_const>(type_id).type;
×
46
      break;
×
47
    case BTF_KIND_VOLATILE:
×
48
      type_id = btf_types.get_kind_type<btf_kind_volatile>(type_id).type;
×
49
      break;
×
50
    default:
19✔
51
      return type_id;
19✔
52
    }
53
  }
54
}
55

56
/**
57
 * @brief Check if the given type is a map. This is done by checking if the type
58
 * is a struct with the following members:
59
 * - type
60
 * - max_entries
61
 *
62
 * @param btf_types The BTF types object.
63
 * @param map_type_id The type id of the type to check.
64
 * @return true This is a map type.
65
 * @return false This is not a map type.
66
 */
67
static bool _is_map_type(const btf_type_data &btf_types,
7✔
68
                         btf_type_id map_type_id) {
69
  if (btf_types.get_kind_index(map_type_id) != BTF_KIND_STRUCT) {
7✔
70
    return false;
71
  }
72

73
  auto map_struct = btf_types.get_kind_type<btf_kind_struct>(map_type_id);
6✔
74
  bool has_type = false;
75
  bool has_max_entries = false;
76

77
  for (const auto &member : map_struct.members) {
28✔
78
    if (member.name == "type") {
79
      has_type = true;
80
    } else if (member.name == "max_entries") {
81
      has_max_entries = true;
82
    }
83
  }
84

85
  return has_type && has_max_entries;
6✔
86
}
87

88
/**
89
 * @brief Accept a BTF type ID for a map and return a BTF map definition.
90
 *
91
 * @param[in] btf_types The BTF types object.
92
 * @param[in] name The name of the map or empty string if the name is not
93
 * available.
94
 * @param[in] map_type_id The ID of the struct type for the map.
95
 * @return btf_map_definition
96
 */
97
static btf_map_definition
98
_get_map_definition_from_btf(const btf_type_data &btf_types,
12✔
99
                             const std::string &name, btf_type_id map_type_id) {
100
  btf_type_id type = 0;
101
  btf_type_id max_entries = 0;
102
  btf_type_id key = 0;
103
  btf_type_id key_size = 0;
104
  btf_type_id value = 0;
105
  btf_type_id value_size = 0;
106
  btf_type_id values = 0;
107

108
  map_type_id = _unwrap_type(btf_types, map_type_id);
12✔
109

110
  auto map_struct = btf_types.get_kind_type<btf_kind_struct>(map_type_id);
12✔
111

112
  for (const auto &member : map_struct.members) {
59✔
113
    if (member.name == "type") {
114
      type = member.type;
12✔
115
    } else if (member.name == "max_entries") {
116
      max_entries = member.type;
12✔
117
    } else if (member.name == "key") {
118
      key = btf_types.dereference_pointer(member.type);
9✔
119
    } else if (member.name == "value") {
120
      value = btf_types.dereference_pointer(member.type);
3✔
121
    } else if (member.name == "key_size") {
122
      key_size = member.type;
2✔
123
    } else if (member.name == "value_size") {
124
      value_size = member.type;
2✔
125
    } else if (member.name == "values") {
126
      values = member.type;
7✔
127
    }
128
  }
129

130
  if (type == 0) {
12✔
131
    throw std::runtime_error("invalid map type");
×
132
  }
133

134
  btf_map_definition map_definition = {};
12✔
135
  map_definition.name = name;
136

137
  // Required fields.
138
  map_definition.type_id = map_type_id;
12✔
139
  map_definition.map_type = _value_from_BTF__uint(btf_types, type);
12✔
140
  map_definition.max_entries = _value_from_BTF__uint(btf_types, max_entries);
12✔
141

142
  // Optional fields.
143
  if (key) {
12✔
144
    size_t key_size_in_bytes = btf_types.get_size(key);
9✔
145
    if (key_size > UINT32_MAX) {
146
      throw std::runtime_error("key size too large");
147
    }
148
    map_definition.key_size = static_cast<uint32_t>(key_size_in_bytes);
9✔
149
  } else if (key_size) {
3✔
150
    map_definition.key_size = _value_from_BTF__uint(btf_types, key_size);
2✔
151
  }
152

153
  if (value) {
12✔
154
    size_t value_size_in_bytes = btf_types.get_size(value);
3✔
155
    if (value_size > UINT32_MAX) {
156
      throw std::runtime_error("value size too large");
157
    }
158
    map_definition.value_size = static_cast<uint32_t>(value_size_in_bytes);
3✔
159
  } else if (value_size) {
9✔
160
    map_definition.value_size = _value_from_BTF__uint(btf_types, value_size);
2✔
161
  }
162

163
  if (values) {
12✔
164
    // Values is an array of pointers to BTF map definitions.
165
    auto values_array = btf_types.get_kind_type<btf_kind_array>(values);
7✔
166
    auto ptr = btf_types.get_kind_type<btf_kind_ptr>(values_array.element_type);
7✔
167

168
    auto inner_map_type_id = _unwrap_type(btf_types, ptr.type);
7✔
169

170
    if (_is_map_type(btf_types, inner_map_type_id)) {
7✔
171
      // Value is a map.
172
      // Store the inner map type ID and set value size to 4 bytes (the size of
173
      // a map id).
174
      map_definition.inner_map_type_id = static_cast<int>(inner_map_type_id);
6✔
175
      map_definition.value_size = sizeof(uint32_t);
6✔
176
    } else if (btf_types.get_kind_index(inner_map_type_id) ==
1✔
177
               BTF_KIND_FUNCTION_PROTOTYPE) {
178
      // Value is a BPF program.
179
      // Set the value size to 4 bytes (the size of a program id).
180
      map_definition.value_size = sizeof(uint32_t);
1✔
181
    } else {
182
      throw std::runtime_error("invalid type for values");
×
183
    }
184
  }
185

186
  return map_definition;
12✔
187
}
188

189
std::vector<btf_map_definition>
190
parse_btf_map_section(const btf_type_data &btf_data) {
7✔
191
  std::multimap<btf_type_id, btf_map_definition> map_definitions;
192

193
  if (btf_data.get_id(".maps") != 0) {
14✔
194
    std::set<btf_type_id> inner_map_type_ids;
195

196
    // Get the .maps data section.
197
    auto maps_section =
198
        btf_data.get_kind_type<btf_kind_data_section>(btf_data.get_id(".maps"));
6✔
199

200
    // Helper function to add a map definition to the map definitions and add the
201
    // inner map type ID to the list of inner map type IDs if it is present.
202
    auto handle_map_type_id = [&](const std::string &name,
12✔
203
                                  btf_type_id map_type_id) {
204
      auto map_definition =
205
          _get_map_definition_from_btf(btf_data, name, map_type_id);
12✔
206
      map_definitions.insert({map_definition.type_id, map_definition});
12✔
207
      // Add the inner map type ID to the list of inner map type IDs if it is
208
      // present.
209
      if (map_definition.inner_map_type_id != 0) {
12✔
210
        inner_map_type_ids.insert(map_definition.inner_map_type_id);
6✔
211
      }
212
    };
18✔
213

214
    // Add all maps in the .maps data section.
215
    for (const auto &var : maps_section.members) {
16✔
216
      auto map_var = btf_data.get_kind_type<btf_kind_var>(var.type);
10✔
217
      handle_map_type_id(map_var.name, map_var.type);
10✔
218
    }
219

220
    // Recursively add all inner maps. Assume that there are at most two levels of
221
    // inner maps. This is the current limit imposed by the BPF verifier on Linux.
222
    for (size_t inner_map_recursion_level = 0; inner_map_recursion_level < 2;
18✔
223
        inner_map_recursion_level++) {
224
      // Add all maps that are not in the .maps data section.
225
      for (const auto &map_type_id : inner_map_type_ids) {
22✔
226
        // Skip if the map is already present.
227
        if (map_definitions.find(map_type_id) != map_definitions.end()) {
10✔
228
          continue;
8✔
229
        }
230
        handle_map_type_id("", map_type_id);
4✔
231
      }
232
    }
233
  }
6✔
234

235
  // Add an array map for this data section.
236
  auto handle_data_section = [&](btf_type_id data_section_id) {
3✔
237
    auto data_section =
238
        btf_data.get_kind_type<btf_kind_data_section>(data_section_id);
3✔
239
    if (data_section.members.empty()) { // Skip empty data sections.
3✔
240
      return;
241
    }
242
    btf_map_definition map_definition = {};
3✔
243
    map_definition.name = data_section.name;
244
    map_definition.type_id = data_section_id;
3✔
245
    map_definition.key_size = sizeof(uint32_t);
3✔
246
    map_definition.value_size = data_section.members.back().offset + data_section.members.back().size;
3✔
247
    map_definition.max_entries = 1;
3✔
248
    map_definitions.insert({map_definition.type_id, map_definition});
6✔
249
  };
3✔
250

251
  // Create a map for .bss, if it exists.
252
  if (btf_data.get_id(".bss") != 0) {
14✔
253
    handle_data_section(btf_data.get_id(".bss"));
2✔
254
  }
255

256
  // Create a map for .data, if it exists.
257
  if (btf_data.get_id(".data") != 0) {
14✔
258
    handle_data_section(btf_data.get_id(".data"));
2✔
259
  }
260

261
  // Create a map for .rodata, if it exists.
262
  if (btf_data.get_id(".rodata") != 0) {
14✔
263
    handle_data_section(btf_data.get_id(".rodata"));
2✔
264
  }
265

266
  std::vector<btf_map_definition> map_definitions_vector;
267
  for (const auto &map_definition : map_definitions) {
22✔
268
    map_definitions_vector.push_back(map_definition.second);
15✔
269
  }
270
  return map_definitions_vector;
7✔
271
}
×
272

273
btf_type_id btf_uint_from_value(btf_type_data &btf_data, uint32_t value) {
8✔
274
  btf_type_id int_id = btf_data.get_id("int");
8✔
275
  if (int_id == 0) {
8✔
276
    int_id = btf_data.append(btf_kind_int{
3✔
277
        .name = "int", .size_in_bytes = 4, .field_width_in_bits = 32});
278
  }
279

280
  btf_type_id array_size_id = btf_data.get_id("__ARRAY_SIZE_TYPE__");
8✔
281
  if (array_size_id == 0) {
8✔
282
    array_size_id = btf_data.append(btf_kind_int{
3✔
283
        .name = "__ARRAY_SIZE_TYPE__",
284
        .size_in_bytes = 4,
285
        .field_width_in_bits = 32,
286
    });
287
  }
288

289
  btf_type_id array = btf_data.append(btf_kind_array{
16✔
290
      .element_type = int_id,
291
      .index_type = array_size_id,
292
      .count_of_elements = value,
293
  });
294

295
  return btf_data.append(btf_kind_ptr{.type = array});
16✔
296
}
297

298
btf_type_id build_btf_map(btf_type_data &btf_data,
2✔
299
                          const btf_map_definition &map_definition) {
300
  uint32_t offset_in_bits = 0;
301
  btf_kind_struct map{
2✔
302
      .members =
303
          {
304
              {
305
                  .name = "type",
306
                  .type =
307
                      btf_uint_from_value(btf_data, map_definition.map_type),
2✔
308
              },
309
              {
310
                  .name = "max_entries",
311
                  .type =
312
                      btf_uint_from_value(btf_data, map_definition.max_entries),
2✔
313
              },
314
          },
315
  };
10✔
316
  if (map_definition.key_size) {
2✔
317
    map.members.push_back({
6✔
318
        .name = "key_size",
319
        .type = btf_uint_from_value(btf_data, map_definition.key_size),
2✔
320
    });
321
  }
322
  if (map_definition.value_size) {
2✔
323
    map.members.push_back({
6✔
324
        .name = "value_size",
325
        .type = btf_uint_from_value(btf_data, map_definition.value_size),
2✔
326
    });
327
  }
328

329
  if (map_definition.inner_map_type_id != 0) {
2✔
330
    map.members.push_back(
3✔
331
        {.name = "values",
332
         .type = btf_data.append({btf_kind_array{
2✔
333
             .element_type = btf_data.append(
2✔
334
                 btf_kind_ptr{.type = map_definition.inner_map_type_id}),
1✔
335
             .index_type = btf_data.get_id("__ARRAY_SIZE_TYPE__"),
2✔
336
         }})});
337
  }
338

339
  for (auto &member : map.members) {
11✔
340
    member.offset_from_start_in_bits = offset_in_bits;
9✔
341
    offset_in_bits += static_cast<uint32_t>(btf_data.get_size(member.type) * 8);
9✔
342
  }
343

344
  map.size_in_bytes = offset_in_bits / 8;
2✔
345

346
  return btf_data.append(btf_kind_var{
6✔
347
      .name = map_definition.name,
348
      .type = btf_data.append(map),
4✔
349
      .linkage = BTF_LINKAGE_STATIC,
350
  });
2✔
351
}
352

353
void build_btf_map_section(
1✔
354
    const std::vector<btf_map_definition> &map_definitions,
355
    btf_type_data &btf_data) {
356
  btf_kind_data_section maps_section{.name = ".maps"};
1✔
357
  std::map<btf_type_id, btf_type_id> old_id_to_new_id;
358

359
  for (auto &map_definition : map_definitions) {
3✔
360
    btf_type_id var_id = build_btf_map(btf_data, map_definition);
2✔
361
    btf_type_id map_id = btf_data.get_kind_type<btf_kind_var>(var_id).type;
2✔
362
    maps_section.members.push_back(btf_kind_data_member{
2✔
363
        .type = var_id,
364
        .size = static_cast<uint32_t>(btf_data.get_size(map_id)),
2✔
365
    });
366
    old_id_to_new_id[map_definition.type_id] = map_id;
2✔
367
  }
368

369
  // Update the map inner_map_type_id in the BTF types.
370
  for (auto &map_definition : map_definitions) {
3✔
371
    if (map_definition.inner_map_type_id == 0) {
2✔
372
      continue;
1✔
373
    }
374
    auto new_id = old_id_to_new_id[map_definition.type_id];
1✔
375
    auto ptr_id = btf_data
376
                      .get_kind_type<btf_kind_array>(
1✔
377
                          btf_data.get_kind_type<btf_kind_struct>(new_id)
1✔
378
                              .members.back()
379
                              .type)
380
                      .element_type;
1✔
381

382
    auto ptr = btf_data.get_kind_type<btf_kind_ptr>(ptr_id);
1✔
383
    ptr.type = old_id_to_new_id[ptr.type];
1✔
384

385
    btf_data.replace(ptr_id, ptr);
2✔
386
  }
387

388
  btf_data.append(maps_section);
2✔
389
  return;
1✔
390
}
1✔
391

392
} // 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