Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add events dimensions file generator in modern probe #2232

Merged
merged 1 commit into from
Jan 21, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .clang-format-ignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ driver/modern_bpf/definitions/aarch64/vmlinux.h
driver/modern_bpf/definitions/ppc64le/vmlinux.h
driver/modern_bpf/definitions/s390x/vmlinux.h
driver/modern_bpf/definitions/x86_64/vmlinux.h
# Autogenerated events dimensions file for modern probe is not formatted
driver/modern_bpf/definitions/events_dimensions.h
# All syscall_compat autogenerated headers are not formatted
driver/syscall_compat_aarch64.h
driver/syscall_compat_loongarch64.h
Expand Down
28 changes: 27 additions & 1 deletion driver/modern_bpf/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -256,6 +256,32 @@ file(GLOB_RECURSE BPF_H_FILES ${CMAKE_CURRENT_SOURCE_DIR}/*.h)
# Search all bpf.c files
file(GLOB_RECURSE BPF_C_FILES ${CMAKE_CURRENT_SOURCE_DIR}/*.bpf.c)

# ##################################################################################################
# Generate the events dimensions file generator executable.
# ##################################################################################################

add_executable(
events_dimensions_generator ${CMAKE_CURRENT_SOURCE_DIR}/definitions/generator/generator.cpp
)
target_link_libraries(events_dimensions_generator PRIVATE scap_event_schema)
add_dependencies(events_dimensions_generator scap_event_schema)

# ##################################################################################################
# Generate the events dimensions file.
# ##################################################################################################

set(BPF_EVENTS_DIMENSIONS_FILE ${CMAKE_CURRENT_SOURCE_DIR}/definitions/events_dimensions.h)
add_custom_command(
OUTPUT ${BPF_EVENTS_DIMENSIONS_FILE}
COMMAND events_dimensions_generator ${BPF_EVENTS_DIMENSIONS_FILE}
VERBATIM
DEPENDS events_dimensions_generator ${CMAKE_CURRENT_SOURCE_DIR}/../event_table.c
COMMENT
"${MODERN_BPF_LOG_PREFIX} Building events dimensions file: ${BPF_EVENTS_DIMENSIONS_FILE}"
)

add_custom_target(EventsDimensions ALL DEPENDS ${BPF_EVENTS_DIMENSIONS_FILE})

# ##################################################################################################
# Generate an `bpf.o` file for every `bpf.c`
# ##################################################################################################
Expand All @@ -278,7 +304,7 @@ foreach(BPF_C_FILE ${BPF_C_FILES})
${BPF_O_FILE}
VERBATIM
DEPENDS lbpf
DEPENDS ${BPF_C_FILE} ${BPF_H_FILES}
DEPENDS ${BPF_C_FILE} ${BPF_H_FILES} EventsDimensions
COMMENT "${MODERN_BPF_LOG_PREFIX} Building BPF object: ${BPF_O_FILE}"
)

Expand Down
411 changes: 198 additions & 213 deletions driver/modern_bpf/definitions/events_dimensions.h

Large diffs are not rendered by default.

234 changes: 234 additions & 0 deletions driver/modern_bpf/definitions/generator/generator.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,234 @@
#include <functional>
#include <iostream>
#include <map>
#include <sstream>
#include <fstream>
#include <algorithm>

#include "driver/ppm_events_public.h"

extern const struct ppm_event_info g_event_info[];

auto PREFACE = R"(// SPDX-License-Identifier: GPL-2.0-only OR MIT
/*
* Copyright (C) 2025 The Falco Authors.
*
* This file is dual licensed under either the MIT or GPL 2. See MIT.txt
* or GPL2.txt for full copies of the license.
*/

#ifndef __EVENT_DIMENSIONS_H__
#define __EVENT_DIMENSIONS_H__

#include "vmlinux.h"

/* Here we have all the dimensions for fixed-size events.
*/

#define PARAM_LEN 2
#define HEADER_LEN sizeof(struct ppm_evt_hdr)

/// TODO: We have to move these in the event_table.c. Right now we don't
/// want to touch scap tables.

/* Syscall events */
)";

auto POSTFACE = R"(
#endif /* __EVENT_DIMENSIONS_H__ */
)";

// Use the following macro to get the stringified version of the C expression retrieving the type
// size (e.g.: SIZE_OF_EXPR(uint8_t) is resolved in "sizeof(uint8_t)").
#define SIZE_OF_EXPR(type) SIZE_OF_EXPR_##type

// Generate the "sizeof" stringified expression for the listed types. New handled types must be
// appended to the list.
#define SIZE_OF_EXPR_DECL_LIST_GEN(FN) \
FN(int8_t) \
FN(int16_t) \
FN(int32_t) \
FN(int64_t) \
FN(uint8_t) \
FN(uint16_t) \
FN(uint32_t) \
FN(uint64_t)
#define SIZE_OF_EXPR_DECL(type) char SIZE_OF_EXPR(type)[] = "sizeof(" #type ")";
SIZE_OF_EXPR_DECL_LIST_GEN(SIZE_OF_EXPR_DECL)
#undef SIZE_OF_EXPR_DECL
#undef SIZE_OF_EXPR_DECL_LIST_GEN

// Special expressions denoting variable size or unused parameter types.
char SIZE_OF_EXPR_VARIABLE_SIZE[] = "<variable_size>", SIZE_OF_EXPR_UNUSED[] = "<unused>";

// Table containing the mapping between parameter types and the corresponding stringified "sizeof"
// expression.
std::map<long long, char *> type_to_size_expr{
{PT_NONE, SIZE_OF_EXPR_UNUSED},
{PT_INT8, SIZE_OF_EXPR(int8_t)},
{PT_INT16, SIZE_OF_EXPR(int16_t)},
{PT_INT32, SIZE_OF_EXPR(int32_t)},
{PT_INT64, SIZE_OF_EXPR(int64_t)},
{PT_UINT8, SIZE_OF_EXPR(uint8_t)},
{PT_UINT16, SIZE_OF_EXPR(uint16_t)},
{PT_UINT32, SIZE_OF_EXPR(uint32_t)},
{PT_UINT64, SIZE_OF_EXPR(uint64_t)},
{PT_CHARBUF, SIZE_OF_EXPR_VARIABLE_SIZE},
{PT_BYTEBUF, SIZE_OF_EXPR_VARIABLE_SIZE},
{PT_ERRNO, SIZE_OF_EXPR(int64_t)},
{PT_SOCKADDR, SIZE_OF_EXPR_VARIABLE_SIZE},
{PT_SOCKTUPLE, SIZE_OF_EXPR_VARIABLE_SIZE},
{PT_FD, SIZE_OF_EXPR(int64_t)},
{PT_PID, SIZE_OF_EXPR(int64_t)},
{PT_FDLIST, SIZE_OF_EXPR_VARIABLE_SIZE},
{PT_FSPATH, SIZE_OF_EXPR_VARIABLE_SIZE},
{PT_SYSCALLID, SIZE_OF_EXPR(uint16_t)},
{PT_SIGTYPE, SIZE_OF_EXPR(uint8_t)},
{PT_RELTIME, SIZE_OF_EXPR(uint64_t)},
{PT_ABSTIME, SIZE_OF_EXPR(uint64_t)},
{PT_PORT, SIZE_OF_EXPR_UNUSED},
{PT_L4PROTO, SIZE_OF_EXPR_UNUSED},
{PT_SOCKFAMILY, SIZE_OF_EXPR_UNUSED},
{PT_BOOL, SIZE_OF_EXPR_UNUSED},
{PT_IPV4ADDR, SIZE_OF_EXPR_UNUSED},
{PT_DYN, SIZE_OF_EXPR_VARIABLE_SIZE},
{PT_FLAGS8, SIZE_OF_EXPR(uint8_t)},
{PT_FLAGS16, SIZE_OF_EXPR(uint16_t)},
{PT_FLAGS32, SIZE_OF_EXPR(uint32_t)},
{PT_UID, SIZE_OF_EXPR(uint32_t)},
{PT_GID, SIZE_OF_EXPR(uint32_t)},
{PT_DOUBLE, SIZE_OF_EXPR_UNUSED},
{PT_SIGSET, SIZE_OF_EXPR(uint32_t)},
{PT_CHARBUFARRAY, SIZE_OF_EXPR_VARIABLE_SIZE},
{PT_CHARBUF_PAIR_ARRAY, SIZE_OF_EXPR_VARIABLE_SIZE},
{PT_IPV4NET, SIZE_OF_EXPR_UNUSED},
{PT_IPV6ADDR, SIZE_OF_EXPR_UNUSED},
{PT_IPV6NET, SIZE_OF_EXPR_UNUSED},
{PT_IPADDR, SIZE_OF_EXPR_UNUSED},
{PT_IPNET, SIZE_OF_EXPR_UNUSED},
{PT_MODE, SIZE_OF_EXPR(uint32_t)},
{PT_FSRELPATH, SIZE_OF_EXPR_VARIABLE_SIZE},
{PT_ENUMFLAGS8, SIZE_OF_EXPR(uint8_t)},
{PT_ENUMFLAGS16, SIZE_OF_EXPR(uint16_t)},
{PT_ENUMFLAGS32, SIZE_OF_EXPR(uint32_t)},
};

// is_fixed_size_event determines if the provided event has a fixed size or not.
bool is_fixed_size_event(struct ppm_event_info const *const evt) {
for(uint32_t i = 0; i < evt->nparams; i++) {
auto &param = evt->params[i];
auto const param_type = param.type;

auto it = type_to_size_expr.find(param_type);
if(it == type_to_size_expr.end()) {
throw std::runtime_error("Unknown event parameter type: " + std::to_string(param_type));
}

auto const size_expr = it->second;
// Just compare pointers is enough.
if(size_expr == SIZE_OF_EXPR_UNUSED) {
throw std::runtime_error("Unexpected unused event parameter type: " +
std::to_string(param_type));
}
if(size_expr == SIZE_OF_EXPR_VARIABLE_SIZE) {
return false;
}
}
return true;
}

// get_vent_size_expr_counts returns, given the provided event and the resulting size expression of
// its parameters, a map containing, for each size expression, the number of occurrences.
std::map<std::string, size_t> get_event_size_expr_counts(struct ppm_event_info const *const evt) {
std::map<std::string, size_t> size_expr_counts;
for(uint32_t i = 0; i < evt->nparams; i++) {
auto const &param = evt->params[i];
auto const param_type = param.type;
auto const it = type_to_size_expr.find(param_type);
if(it == type_to_size_expr.end()) {
throw std::runtime_error("Unknown event parameter type: " + std::to_string(param_type));
}
auto const size_expr = it->second;
size_expr_counts[size_expr]++;
}
return size_expr_counts;
}

// output_event_size outputs the event size macro for the provided event into the provided output
// stream.
void output_event_size(std::ostream &os,
struct ppm_event_info const *const evt,
bool const is_enter_evt) {
// Exclude old versions.
if(evt->flags & EF_OLD_VERSION) {
return;
}

std::string name{evt->name};
// Ignore events without name.
if(name == "NA") {
return;
}

// Exclude events not having a fixed size.
if(!is_fixed_size_event(evt)) {
return;
}

// Generate the complete event size macro name.
std::transform(name.cbegin(), name.cend(), name.begin(), toupper);
if((evt->category & EC_TRACEPOINT) == 0) {
name += is_enter_evt ? "_E" : "_X";
}
name += "_SIZE";

// The event contains at least the header.
os << "#define " << name << " HEADER_LEN";

auto const params_num = evt->nparams;

// Count the number of occurrences for each size expression.
auto size_expr_counts = get_event_size_expr_counts(evt);

// Output "size expression" * "number of occurrences of size expression", for each size
// expression.
for(auto const &[size_expr, count] : size_expr_counts) {
os << " + " << size_expr;
if(count != 1) {
os << " * " << count;
}
}

// Add "number of parameters" * PARAM_LEN, to account the size of each parameter length.
if(params_num != 0) {
os << " + PARAM_LEN";
if(params_num != 1) {
os << " * " << params_num;
}
}
os << '\n';
}

int main(int argc, char *argv[]) {
if(argc != 2) {
std::cerr << "Usage: " << argv[0] << " <filepath>\n";
std::exit(EXIT_FAILURE);
}

std::string filepath{argv[1]};

// Build file content.
std::ostringstream oss;
oss << PREFACE;
for(int i = 0; i < PPM_EVENT_MAX; i++) {
output_event_size(oss, &g_event_info[i], i % 2 == 0);
}
oss << POSTFACE;

// Write content to file.
std::ofstream f{filepath, std::fstream::out | std::fstream::trunc};
f << oss.str();
f.close();

return 0;
}
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,9 @@ int BPF_PROG(t_hotplug) {
* the event collection.
*/
struct ringbuf_struct ringbuf;
ringbuf.reserved_event_size = HOTPLUG_E_SIZE;
ringbuf.reserved_event_size = CPU_HOTPLUG_E_SIZE;
ringbuf.event_type = PPME_CPU_HOTPLUG_E;
ringbuf.data = bpf_ringbuf_reserve(rb, HOTPLUG_E_SIZE, 0);
ringbuf.data = bpf_ringbuf_reserve(rb, CPU_HOTPLUG_E_SIZE, 0);
if(!ringbuf.data) {
counter->n_drops_buffer++;
return 0;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ int BPF_PROG(sched_switch, bool preempt, struct task_struct *prev, struct task_s
/// TODO: we could avoid switches from kernel threads to kernel threads (?).

struct ringbuf_struct ringbuf;
if(!ringbuf__reserve_space(&ringbuf, SCHED_SWITCH_SIZE, PPME_SCHEDSWITCH_6_E)) {
if(!ringbuf__reserve_space(&ringbuf, SWITCH_SIZE, PPME_SCHEDSWITCH_6_E)) {
return 0;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ int BPF_PROG(signal_deliver, int sig, struct kernel_siginfo *info, struct k_siga
}

struct ringbuf_struct ringbuf;
if(!ringbuf__reserve_space(&ringbuf, SIGNAL_DELIVER_SIZE, PPME_SIGNALDELIVER_E)) {
if(!ringbuf__reserve_space(&ringbuf, SIGNALDELIVER_SIZE, PPME_SIGNALDELIVER_E)) {
return 0;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
SEC("tp_btf/sys_enter")
int BPF_PROG(generic_e, struct pt_regs *regs, long id) {
struct ringbuf_struct ringbuf;
if(!ringbuf__reserve_space(&ringbuf, GENERIC_E_SIZE, PPME_GENERIC_E)) {
if(!ringbuf__reserve_space(&ringbuf, SYSCALL_E_SIZE, PPME_GENERIC_E)) {
return 0;
}

Expand Down Expand Up @@ -52,7 +52,7 @@ int BPF_PROG(generic_e, struct pt_regs *regs, long id) {
SEC("tp_btf/sys_exit")
int BPF_PROG(generic_x, struct pt_regs *regs, long ret) {
struct ringbuf_struct ringbuf;
if(!ringbuf__reserve_space(&ringbuf, GENERIC_X_SIZE, PPME_GENERIC_X)) {
if(!ringbuf__reserve_space(&ringbuf, SYSCALL_X_SIZE, PPME_GENERIC_X)) {
return 0;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
SEC("tp_btf/sys_enter")
int BPF_PROG(pread64_e, struct pt_regs *regs, long id) {
struct ringbuf_struct ringbuf;
if(!ringbuf__reserve_space(&ringbuf, PREAD64_E_SIZE, PPME_SYSCALL_PREAD_E)) {
if(!ringbuf__reserve_space(&ringbuf, PREAD_E_SIZE, PPME_SYSCALL_PREAD_E)) {
return 0;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
SEC("tp_btf/sys_enter")
int BPF_PROG(prlimit64_e, struct pt_regs *regs, long id) {
struct ringbuf_struct ringbuf;
if(!ringbuf__reserve_space(&ringbuf, PRLIMIT64_E_SIZE, PPME_SYSCALL_PRLIMIT_E)) {
if(!ringbuf__reserve_space(&ringbuf, PRLIMIT_E_SIZE, PPME_SYSCALL_PRLIMIT_E)) {
return 0;
}

Expand Down Expand Up @@ -43,7 +43,7 @@ int BPF_PROG(prlimit64_e, struct pt_regs *regs, long id) {
SEC("tp_btf/sys_exit")
int BPF_PROG(prlimit64_x, struct pt_regs *regs, long ret) {
struct ringbuf_struct ringbuf;
if(!ringbuf__reserve_space(&ringbuf, PRLIMIT64_X_SIZE, PPME_SYSCALL_PRLIMIT_X)) {
if(!ringbuf__reserve_space(&ringbuf, PRLIMIT_X_SIZE, PPME_SYSCALL_PRLIMIT_X)) {
return 0;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
SEC("tp_btf/sys_enter")
int BPF_PROG(pwrite64_e, struct pt_regs *regs, long id) {
struct ringbuf_struct ringbuf;
if(!ringbuf__reserve_space(&ringbuf, PWRITE64_E_SIZE, PPME_SYSCALL_PWRITE_E)) {
if(!ringbuf__reserve_space(&ringbuf, PWRITE_E_SIZE, PPME_SYSCALL_PWRITE_E)) {
return 0;
}

Expand Down
Loading