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

Alan-Jowett / ebpf-verifier / 22235569093

20 Feb 2026 02:12AM UTC coverage: 88.002% (-0.2%) from 88.157%
22235569093

push

github

web-flow
Handle Call builtins: fix handling of Falco tests  (#1025)

* falco: fix raw_tracepoint privilege and group expected failures

Mark raw_tracepoint/raw_tracepoint_writable as privileged program types so Falco raw-tracepoint sections are not treated as unprivileged argument checks.

Update Falco sample matrix to move now-passing sections out of TEST_SECTION_FAIL and group the remaining expected failures by root-cause class (offset lower-bound loss vs size lower-bound loss at correlated joins).

Signed-off-by: Elazar Gershuni <elazarg@gmail.com>

* elf/unmarshal: gate builtin relocations via platform call model

Add platform hooks to resolve builtin symbols and provide builtin call contracts, thread relocation-gated builtin call offsets through ProgramInfo, and only treat static helper IDs as builtins at gated call sites.

Also extend platform-table, marshal, and YAML-platform tests to cover builtin resolver wiring and call unmarshal behavior.
* crab: canonicalize unsigned intervals in bitwise_and
When uvalue intervals temporarily carry signed lower bounds (e.g. after joins), Interval::bitwise_and asserted in debug builds. Canonicalize both operands via zero_extend(64) before unsigned bitwise reasoning, preserving soundness and avoiding debug aborts.

Validated by reproducing SIGABRT on reverted code in [falco][verify] and confirming the patched build completes with expected 73 pass / 20 failed-as-expected.

* Fix unsound bitwise_and case for non-singleton all-ones rhs

Signed-off-by: Elazar Gershuni <elazarg@gmail.com>

239 of 252 new or added lines in 9 files covered. (94.84%)

602 existing lines in 16 files now uncovered.

11743 of 13344 relevant lines covered (88.0%)

3262592.78 hits per line

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

81.55
/src/linux/linux_platform.cpp
1
// Copyright (c) Prevail Verifier contributors.
2
// SPDX-License-Identifier: MIT
3
#include <stdexcept>
4
#if __linux__
5
#include <linux/bpf.h>
6

7
#ifndef BPF_PROG_TYPE_CGROUP_SYSCTL
8
#define BPF_PROG_TYPE_CGROUP_SYSCTL 23
9
#endif
10
#ifndef BPF_PROG_TYPE_RAW_TRACEPOINT_WRITABLE
11
#define BPF_PROG_TYPE_RAW_TRACEPOINT_WRITABLE 24
12
#endif
13
#ifndef BPF_PROG_TYPE_CGROUP_SOCKOPT
14
#define BPF_PROG_TYPE_CGROUP_SOCKOPT 25
15
#endif
16
#ifndef BPF_PROG_TYPE_TRACING
17
#define BPF_PROG_TYPE_TRACING 26
18
#endif
19
#ifndef BPF_PROG_TYPE_STRUCT_OPS
20
#define BPF_PROG_TYPE_STRUCT_OPS 27
21
#endif
22
#ifndef BPF_PROG_TYPE_EXT
23
#define BPF_PROG_TYPE_EXT 28
24
#endif
25
#ifndef BPF_PROG_TYPE_LSM
26
#define BPF_PROG_TYPE_LSM 29
27
#endif
28
#ifndef BPF_PROG_TYPE_SK_LOOKUP
29
#define BPF_PROG_TYPE_SK_LOOKUP 30
30
#endif
31
#ifndef BPF_PROG_TYPE_SYSCALL
32
#define BPF_PROG_TYPE_SYSCALL 31
33
#endif
34
#ifndef BPF_PROG_TYPE_NETFILTER
35
#define BPF_PROG_TYPE_NETFILTER 32
36
#endif
37

38
#ifndef BPF_MAP_TYPE_XSKMAP
39
#define BPF_MAP_TYPE_XSKMAP 17
40
#endif
41
#ifndef BPF_MAP_TYPE_SOCKHASH
42
#define BPF_MAP_TYPE_SOCKHASH 18
43
#endif
44
#ifndef BPF_MAP_TYPE_CGROUP_STORAGE
45
#define BPF_MAP_TYPE_CGROUP_STORAGE 19
46
#endif
47
#ifndef BPF_MAP_TYPE_REUSEPORT_SOCKARRAY
48
#define BPF_MAP_TYPE_REUSEPORT_SOCKARRAY 20
49
#endif
50
#ifndef BPF_MAP_TYPE_PERCPU_CGROUP_STORAGE
51
#define BPF_MAP_TYPE_PERCPU_CGROUP_STORAGE 21
52
#endif
53
#ifndef BPF_MAP_TYPE_QUEUE
54
#define BPF_MAP_TYPE_QUEUE 22
55
#endif
56
#ifndef BPF_MAP_TYPE_STACK
57
#define BPF_MAP_TYPE_STACK 23
58
#endif
59
#ifndef BPF_MAP_TYPE_SK_STORAGE
60
#define BPF_MAP_TYPE_SK_STORAGE 24
61
#endif
62
#ifndef BPF_MAP_TYPE_DEVMAP_HASH
63
#define BPF_MAP_TYPE_DEVMAP_HASH 25
64
#endif
65
#ifndef BPF_MAP_TYPE_STRUCT_OPS
66
#define BPF_MAP_TYPE_STRUCT_OPS 26
67
#endif
68
#ifndef BPF_MAP_TYPE_RINGBUF
69
#define BPF_MAP_TYPE_RINGBUF 27
70
#endif
71
#ifndef BPF_MAP_TYPE_INODE_STORAGE
72
#define BPF_MAP_TYPE_INODE_STORAGE 28
73
#endif
74
#ifndef BPF_MAP_TYPE_TASK_STORAGE
75
#define BPF_MAP_TYPE_TASK_STORAGE 29
76
#endif
77
#ifndef BPF_MAP_TYPE_BLOOM_FILTER
78
#define BPF_MAP_TYPE_BLOOM_FILTER 30
79
#endif
80
#ifndef BPF_MAP_TYPE_USER_RINGBUF
81
#define BPF_MAP_TYPE_USER_RINGBUF 31
82
#endif
83
#ifndef BPF_MAP_TYPE_CGRP_STORAGE
84
#define BPF_MAP_TYPE_CGRP_STORAGE 32
85
#endif
86
#ifndef BPF_MAP_TYPE_ARENA
87
#define BPF_MAP_TYPE_ARENA 33
88
#endif
89

90
#define PTYPE(name, descr, native_type, prefixes) {name, descr, native_type, prefixes}
91
#define PTYPE_PRIVILEGED(name, descr, native_type, prefixes) {name, descr, native_type, prefixes, true}
92
#else
93
#define PTYPE(name, descr, native_type, prefixes) {name, descr, 0, prefixes}
94
#define PTYPE_PRIVILEGED(name, descr, native_type, prefixes) {name, descr, 0, prefixes, true}
95
#endif
96
#include "elf_loader.hpp"
97
#include "linux/gpl/spec_type_descriptors.hpp"
98
#include "linux/kfunc.hpp"
99
#include "linux/linux_platform.hpp"
100
#include "platform.hpp"
101
#include "verifier.hpp"
102

103
namespace prevail {
104
// Map definitions as they appear in an ELF file, so field width matters.
105
struct BpfLoadMapDef {
106
    uint32_t type;
107
    uint32_t key_size;
108
    uint32_t value_size;
109
    uint32_t max_entries;
110
    uint32_t map_flags;
111
    uint32_t inner_map_idx;
112
    uint32_t numa_node;
113
};
114

115
static int create_map_linux(uint32_t map_type, uint32_t key_size, uint32_t value_size, uint32_t max_entries,
116
                            ebpf_verifier_options_t options);
117

118
// Allow for comma as a separator between multiple prefixes, to make
119
// the preprocessor treat a prefix list as one macro argument.
120
#define COMMA ,
121

122
const EbpfProgramType linux_socket_filter_program_type =
123
    PTYPE("socket_filter", &g_socket_filter_descr, BPF_PROG_TYPE_SOCKET_FILTER, {"socket"});
124

125
const EbpfProgramType linux_xdp_program_type = PTYPE("xdp", &g_xdp_descr, BPF_PROG_TYPE_XDP, {"xdp"});
126

127
const EbpfProgramType cilium_lxc_program_type = PTYPE("lxc", &g_sched_descr, BPF_PROG_TYPE_SOCKET_FILTER, {});
128

129
const std::vector<EbpfProgramType> linux_program_types = {
130
    PTYPE("unspec", &g_unspec_descr, BPF_PROG_TYPE_UNSPEC, {}),
131
    linux_socket_filter_program_type,
132
    linux_xdp_program_type,
133
    PTYPE("cgroup_device", &g_cgroup_dev_descr, BPF_PROG_TYPE_CGROUP_DEVICE, {"cgroup/dev"}),
134
    PTYPE("cgroup_skb", &g_socket_filter_descr, BPF_PROG_TYPE_CGROUP_SKB, {"cgroup/skb"}),
135
    PTYPE("cgroup_sock", &g_cgroup_sock_descr, BPF_PROG_TYPE_CGROUP_SOCK, {"cgroup/sock"}),
136
    PTYPE_PRIVILEGED("kprobe", &g_kprobe_descr, BPF_PROG_TYPE_KPROBE, {"kprobe/" COMMA "kretprobe/"}),
137
    PTYPE("lwt_in", &g_lwt_inout_descr, BPF_PROG_TYPE_LWT_IN, {"lwt_in"}),
138
    PTYPE("lwt_out", &g_lwt_inout_descr, BPF_PROG_TYPE_LWT_OUT, {"lwt_out"}),
139
    PTYPE("lwt_xmit", &g_lwt_xmit_descr, BPF_PROG_TYPE_LWT_XMIT, {"lwt_xmit"}),
140
    PTYPE("perf_event", &g_perf_event_descr, BPF_PROG_TYPE_PERF_EVENT, {"perf_section" COMMA "perf_event"}),
141
    PTYPE("sched_act", &g_sched_descr, BPF_PROG_TYPE_SCHED_ACT, {"action"}),
142
    PTYPE("sched_cls", &g_sched_descr, BPF_PROG_TYPE_SCHED_CLS, {"classifier"}),
143
    PTYPE("sk_skb", &g_sk_skb_descr, BPF_PROG_TYPE_SK_SKB, {"sk_skb"}),
144
    PTYPE("sock_ops", &g_sock_ops_descr, BPF_PROG_TYPE_SOCK_OPS, {"sockops"}),
145
    PTYPE("tracepoint", &g_tracepoint_descr, BPF_PROG_TYPE_TRACEPOINT, {"tracepoint/"}),
146
    PTYPE("cgroup_sockopt", &g_sockopt_descr, BPF_PROG_TYPE_CGROUP_SOCKOPT,
147
          {"cgroup/getsockopt" COMMA "cgroup/setsockopt"}),
148
    PTYPE("sk_msg", &g_sk_msg_md, BPF_PROG_TYPE_SK_MSG, {"sk_msg"}),
149
    PTYPE_PRIVILEGED("raw_tracepoint", &g_tracepoint_descr, BPF_PROG_TYPE_RAW_TRACEPOINT,
150
                     {"raw_tracepoint/" COMMA "raw_tp/"}),
151
    PTYPE_PRIVILEGED("raw_tracepoint_writable", &g_tracepoint_descr, BPF_PROG_TYPE_RAW_TRACEPOINT_WRITABLE,
152
                     {"raw_tracepoint.w/" COMMA "raw_tp.w/"}),
153
    PTYPE("cgroup_sock_addr", &g_sock_addr_descr, BPF_PROG_TYPE_CGROUP_SOCK_ADDR,
154
          {"cgroup/bind" COMMA "cgroup/post_bind" COMMA "cgroup/connect" COMMA "cgroup/sendmsg" COMMA
155
           "cgroup/recvmsg" COMMA "cgroup/getpeername" COMMA "cgroup/getsockname"}),
156
    PTYPE("lwt_seg6local", &g_lwt_xmit_descr, BPF_PROG_TYPE_LWT_SEG6LOCAL, {"lwt_seg6local"}),
157
    PTYPE("lirc_mode2", &g_unspec_descr, BPF_PROG_TYPE_LIRC_MODE2, {"lirc_mode2"}),
158
    PTYPE("sk_reuseport", &g_sk_reuseport_descr, BPF_PROG_TYPE_SK_REUSEPORT, {"sk_reuseport/"}),
159
    PTYPE("flow_dissector", &g_flow_dissector_descr, BPF_PROG_TYPE_FLOW_DISSECTOR, {"flow_dissector"}),
160
    PTYPE("cgroup_sysctl", &g_cgroup_sysctl_descr, BPF_PROG_TYPE_CGROUP_SYSCTL, {"cgroup/sysctl"}),
161
    PTYPE("ext", &g_unspec_descr, BPF_PROG_TYPE_EXT, {"freplace/"}),
162
    PTYPE("tracing", &g_unspec_descr, BPF_PROG_TYPE_TRACING,
163
          {"fentry/" COMMA "fexit/" COMMA "fmod_ret/" COMMA "iter/" COMMA "lsm.s/" COMMA "tp_btf/"}),
164
    PTYPE("struct_ops", &g_unspec_descr, BPF_PROG_TYPE_STRUCT_OPS, {"struct_ops/"}),
165
    PTYPE("lsm", &g_unspec_descr, BPF_PROG_TYPE_LSM, {"lsm/"}),
166
    PTYPE("sk_lookup", &g_sk_lookup_descr, BPF_PROG_TYPE_SK_LOOKUP, {"sk_lookup/"}),
167
    PTYPE("syscall", &g_unspec_descr, BPF_PROG_TYPE_SYSCALL, {"syscall/"}),
168
    PTYPE("netfilter", &g_unspec_descr, BPF_PROG_TYPE_NETFILTER, {"netfilter/"}),
169
};
170

171
static EbpfProgramType get_program_type_linux(const std::string& section, const std::string& path) {
25,372✔
172
    EbpfProgramType type{};
25,372✔
173

174
    // linux only deduces from section, but cilium and cilium_test have this information
175
    // in the filename:
176
    // * cilium/bpf_xdp.o:from-netdev is XDP
177
    // * bpf_cilium_test/bpf_lb-DLB_L3.o:from-netdev is SK_SKB
178
    if (path.find("cilium") != std::string::npos) {
25,372✔
179
        if (path.find("xdp") != std::string::npos) {
2,198✔
180
            return linux_xdp_program_type;
522✔
181
        }
182
        if (path.find("lxc") != std::string::npos) {
1,676✔
183
            return cilium_lxc_program_type;
936✔
184
        }
185
    }
186

187
    for (const EbpfProgramType& t : linux_program_types) {
496,398✔
188
        for (const std::string& prefix : t.section_prefixes) {
1,062,864✔
189
            if (section.find(prefix) == 0) {
590,380✔
190
                return t;
22,554✔
191
            }
192
        }
193
    }
194

195
    return linux_socket_filter_program_type;
4,178✔
196
}
25,372✔
197

198
#ifdef __linux__
199
#define BPF_MAP_TYPE(x) BPF_MAP_TYPE_##x, #x
200
#else
201
#define BPF_MAP_TYPE(x) 0, #x
202
#endif
203

204
static const EbpfMapType linux_map_types[] = {
205
    {BPF_MAP_TYPE(UNSPEC)},
206
    {BPF_MAP_TYPE(HASH)},
207
    {BPF_MAP_TYPE(ARRAY), true},
208
    {BPF_MAP_TYPE(PROG_ARRAY), true, EbpfMapValueType::PROGRAM},
209
    {BPF_MAP_TYPE(PERF_EVENT_ARRAY), true},
210
    {BPF_MAP_TYPE(PERCPU_HASH)},
211
    {BPF_MAP_TYPE(PERCPU_ARRAY), true},
212
    {BPF_MAP_TYPE(STACK_TRACE)},
213
    {BPF_MAP_TYPE(CGROUP_ARRAY), true},
214
    {BPF_MAP_TYPE(LRU_HASH)},
215
    {BPF_MAP_TYPE(LRU_PERCPU_HASH)},
216
    {BPF_MAP_TYPE(LPM_TRIE)},
217
    {BPF_MAP_TYPE(ARRAY_OF_MAPS), true, EbpfMapValueType::MAP},
218
    {BPF_MAP_TYPE(HASH_OF_MAPS), false, EbpfMapValueType::MAP},
219
    {BPF_MAP_TYPE(DEVMAP)},
220
    {BPF_MAP_TYPE(SOCKMAP)},
221
    {BPF_MAP_TYPE(CPUMAP)},
222
    {BPF_MAP_TYPE(XSKMAP)},
223
    {BPF_MAP_TYPE(SOCKHASH)},
224
    {BPF_MAP_TYPE(CGROUP_STORAGE)},
225
    {BPF_MAP_TYPE(REUSEPORT_SOCKARRAY)},
226
    {BPF_MAP_TYPE(PERCPU_CGROUP_STORAGE)},
227
    {BPF_MAP_TYPE(QUEUE)},
228
    {BPF_MAP_TYPE(STACK)},
229
    {BPF_MAP_TYPE(SK_STORAGE)},
230
    {BPF_MAP_TYPE(DEVMAP_HASH)},
231
    {BPF_MAP_TYPE(STRUCT_OPS)},
232
    {BPF_MAP_TYPE(RINGBUF)},
233
    {BPF_MAP_TYPE(INODE_STORAGE)},
234
    {BPF_MAP_TYPE(TASK_STORAGE)},
235
    {BPF_MAP_TYPE(BLOOM_FILTER)},
236
    {BPF_MAP_TYPE(USER_RINGBUF)},
237
    {BPF_MAP_TYPE(CGRP_STORAGE)},
238
    {BPF_MAP_TYPE(ARENA)},
239
};
240

241
EbpfMapType get_map_type_linux(uint32_t platform_specific_type) {
25,394✔
242
    const uint32_t index = platform_specific_type;
25,394✔
243
    if (index == 0 || index >= std::size(linux_map_types)) {
37,938✔
244
        return linux_map_types[0];
306✔
245
    }
246
    EbpfMapType type = linux_map_types[index];
25,088✔
247
#ifdef __linux__
248
    assert(type.platform_specific_type == platform_specific_type);
25,088✔
249
#else
250
    type.platform_specific_type = platform_specific_type;
251
#endif
252
    return type;
25,088✔
253
}
25,088✔
254

255
void parse_maps_section_linux(std::vector<EbpfMapDescriptor>& map_descriptors, const char* data,
728✔
256
                              const size_t map_def_size, const int map_count, const ebpf_platform_t* platform,
257
                              const ebpf_verifier_options_t options) {
258
    // Copy map definitions from the ELF section into a local list.
259
    auto mapdefs = std::vector<BpfLoadMapDef>();
728✔
260
    for (int i = 0; i < map_count; i++) {
8,148✔
261
        BpfLoadMapDef def = {0};
7,420✔
262
        memcpy(&def, data + i * map_def_size, std::min(map_def_size, sizeof(def)));
8,179✔
263
        mapdefs.emplace_back(def);
7,420✔
264
    }
265

266
    // Add map definitions into the map_descriptors list.
267
    for (const auto& s : mapdefs) {
8,148✔
268
        EbpfMapType type = get_map_type_linux(s.type);
7,420✔
269
        map_descriptors.emplace_back(EbpfMapDescriptor{
3,710✔
270
            .original_fd = create_map_linux(s.type, s.key_size, s.value_size, s.max_entries, options),
7,420✔
271
            .type = s.type,
7,420✔
272
            .key_size = s.key_size,
7,420✔
273
            .value_size = s.value_size,
7,420✔
274
            .max_entries = s.max_entries,
7,420✔
275
            .inner_map_fd = gsl::narrow<int32_t>(s.inner_map_idx) // Temporarily fill in the index. This will be
7,420✔
276
                                                                  // replaced in the resolve_inner_map_references pass.
277
        });
278
    }
7,420✔
279
}
728✔
280

281
// Initialize the inner_map_fd in each map descriptor.
282
void resolve_inner_map_references_linux(std::vector<EbpfMapDescriptor>& map_descriptors) {
726✔
283
    for (size_t i = 0; i < map_descriptors.size(); i++) {
8,146✔
284
        const int inner = map_descriptors[i].inner_map_fd; // Get the inner_map_idx back.
7,420✔
285
        if (inner < 0 || inner >= gsl::narrow<int>(map_descriptors.size())) {
7,420✔
UNCOV
286
            throw UnmarshalError("bad inner map index " + std::to_string(inner) + " for map " + std::to_string(i));
×
287
        }
288
        map_descriptors[i].inner_map_fd = map_descriptors.at(inner).original_fd;
7,420✔
289
    }
290
}
726✔
291

292
#if __linux__
UNCOV
293
static int do_bpf(const bpf_cmd cmd, bpf_attr& attr) { return syscall(321, cmd, &attr, sizeof(attr)); }
×
294
#endif
295

296
/** Try to allocate a Linux map.
297
 *
298
 *  This function requires admin privileges.
299
 */
300
static int create_map_linux(const uint32_t map_type, const uint32_t key_size, const uint32_t value_size,
7,420✔
301
                            const uint32_t max_entries, const ebpf_verifier_options_t options) {
302
    if (options.mock_map_fds) {
7,420✔
303
        const EbpfMapType type = get_map_type_linux(map_type);
7,420✔
304
        return create_map_crab(type, key_size, value_size, max_entries, options);
7,420✔
305
    }
7,420✔
306

307
#if __linux__
UNCOV
308
    bpf_attr attr{};
×
UNCOV
309
    memset(&attr, '\0', sizeof(attr));
×
UNCOV
310
    attr.map_type = map_type;
×
UNCOV
311
    attr.key_size = key_size;
×
UNCOV
312
    attr.value_size = value_size;
×
UNCOV
313
    attr.max_entries = 20;
×
UNCOV
314
    attr.map_flags = map_type == BPF_MAP_TYPE_HASH ? BPF_F_NO_PREALLOC : 0;
×
UNCOV
315
    const int map_fd = do_bpf(BPF_MAP_CREATE, attr);
×
UNCOV
316
    if (map_fd < 0) {
×
UNCOV
317
        std::cerr << "Failed to create map, " << strerror(errno) << "\n";
×
318
        std::cerr << "Map: \n"
UNCOV
319
                  << " map_type = " << attr.map_type << "\n"
×
UNCOV
320
                  << " key_size = " << attr.key_size << "\n"
×
UNCOV
321
                  << " value_size = " << attr.value_size << "\n"
×
UNCOV
322
                  << " max_entries = " << attr.max_entries << "\n"
×
UNCOV
323
                  << " map_flags = " << attr.map_flags << "\n";
×
UNCOV
324
        exit(2);
×
325
    }
326
    return map_fd;
327
#else
328
    throw std::runtime_error(std::string("cannot create a Linux map"));
329
#endif
330
}
331

332
EbpfMapDescriptor& get_map_descriptor_linux(const int map_fd) {
24,806✔
333
    // First check if we already have the map descriptor cached.
334
    EbpfMapDescriptor* map = find_map_descriptor(map_fd);
24,806✔
335
    if (map != nullptr) {
24,806✔
336
        return *map;
24,806✔
337
    }
338

339
    // This fd was not created from the maps section of an ELF file,
340
    // but it may be an fd created by an app before calling the verifier.
341
    // In this case, we would like to query the map descriptor info
342
    // (key size, value size) from the execution context, but this is
343
    // not yet supported on Linux.
344

UNCOV
345
    throw UnmarshalError("map_fd " + std::to_string(map_fd) + " not found");
×
346
}
347

348
static std::optional<Call> resolve_kfunc_call_linux(const int32_t btf_id, const ProgramInfo* info,
36✔
349
                                                    std::string* why_not) {
350
    return make_kfunc_call(btf_id, info, why_not);
36✔
351
}
352

353
namespace {
354
constexpr int32_t LINUX_BUILTIN_CALL_MEMSET = -11;
355
constexpr int32_t LINUX_BUILTIN_CALL_MEMCPY = -12;
356
constexpr int32_t LINUX_BUILTIN_CALL_MEMMOVE = -13;
357
constexpr int32_t LINUX_BUILTIN_CALL_MEMCMP = -14;
358
} // namespace
359

360
std::optional<int32_t> resolve_builtin_call_linux(const std::string& name) {
227,678✔
361
    if (name == "memset") {
227,678✔
362
        return LINUX_BUILTIN_CALL_MEMSET;
215,764✔
363
    }
364
    if (name == "memcpy") {
11,914✔
365
        return LINUX_BUILTIN_CALL_MEMCPY;
11,906✔
366
    }
367
    if (name == "memmove") {
8✔
368
        return LINUX_BUILTIN_CALL_MEMMOVE;
2✔
369
    }
370
    if (name == "memcmp") {
6✔
371
        return LINUX_BUILTIN_CALL_MEMCMP;
2✔
372
    }
373
    return std::nullopt;
4✔
374
}
375

376
static std::optional<Call> get_builtin_call_linux(const int32_t id) {
2,460✔
377
    switch (id) {
2,460✔
378
    case LINUX_BUILTIN_CALL_MEMSET:
2,324✔
379
        return Call{
9,296✔
380
            .func = id,
381
            .name = "memset",
1,162✔
382
            .singles = {{ArgSingle::Kind::ANYTHING, false, Reg{2}}},
383
            .pairs = {{ArgPair::Kind::PTR_TO_WRITABLE_MEM, false, Reg{1}, Reg{3}, false}},
384
        };
2,324✔
385
    case LINUX_BUILTIN_CALL_MEMCPY:
130✔
386
        return Call{
455✔
387
            .func = id,
388
            .name = "memcpy",
65✔
389
            .pairs = {{ArgPair::Kind::PTR_TO_WRITABLE_MEM, false, Reg{1}, Reg{3}, false},
390
                      {ArgPair::Kind::PTR_TO_READABLE_MEM, false, Reg{2}, Reg{3}, false}},
391
        };
130✔
392
    case LINUX_BUILTIN_CALL_MEMMOVE:
2✔
393
        return Call{
7✔
394
            .func = id,
395
            .name = "memmove",
1✔
396
            .pairs = {{ArgPair::Kind::PTR_TO_WRITABLE_MEM, false, Reg{1}, Reg{3}, false},
397
                      {ArgPair::Kind::PTR_TO_READABLE_MEM, false, Reg{2}, Reg{3}, false}},
398
        };
2✔
399
    case LINUX_BUILTIN_CALL_MEMCMP:
2✔
400
        return Call{
7✔
401
            .func = id,
402
            .name = "memcmp",
1✔
403
            .pairs = {{ArgPair::Kind::PTR_TO_READABLE_MEM, false, Reg{1}, Reg{3}, false},
404
                      {ArgPair::Kind::PTR_TO_READABLE_MEM, false, Reg{2}, Reg{3}, false}},
405
        };
2✔
406
    default: return std::nullopt;
2✔
407
    }
408
}
409

410
const ebpf_platform_t g_ebpf_platform_linux = {
411
    .get_program_type = get_program_type_linux,
412
    .get_helper_prototype = get_helper_prototype_linux,
413
    .is_helper_usable = is_helper_usable_linux,
414
    .resolve_builtin_call = resolve_builtin_call_linux,
415
    .get_builtin_call = get_builtin_call_linux,
416
    .resolve_kfunc_call = resolve_kfunc_call_linux,
417
    .map_record_size = sizeof(BpfLoadMapDef),
418
    .parse_maps_section = parse_maps_section_linux,
419
    .get_map_descriptor = get_map_descriptor_linux,
420
    .get_map_type = get_map_type_linux,
421
    .resolve_inner_map_references = resolve_inner_map_references_linux,
422
    .supported_conformance_groups = bpf_conformance_groups_t::default_groups | bpf_conformance_groups_t::packet,
423
};
424
} // namespace prevail
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