Skip to content
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
1 change: 1 addition & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ docs/ AsciiDoc documentation, file format spec, diagrams.
- Meta entries are ordinary `static const` objects; each call site emits a pointer pair `{meta, file-offset cache}` into the custom ELF section `_clltk_<BUFFER_NAME>_metaptr` via an inline-asm `.pushsection` data directive. The constructor registers every meta at startup and writes the resolved file offset into the cache, so the first tracepoint execution needs no lookup (NOT via `__attribute__((section(...)))` -- the attribute would join the enclosing function's COMDAT group inside inline functions and templates, and GCC >= 15.2 rejects mixing grouped and ungrouped sections of the same name). Buffer names MUST be valid C identifiers.
- Constructor/destructor priority is 101 (very early). User code with priority < 101 cannot use tracing; at priority exactly 101 the order against clltk's own constructor/destructor is emission-order dependent (LTO flips it), so tracing there is undefined -- it may or may not be recorded.
- `_CLLTK_INTERNAL` define gates macro expansion. The library itself compiles with `-D_CLLTK_INTERNAL`; consumer code must NOT define it.
- Kernel modules register at load through TWO paths, both idempotent: the per-module constructor (needs `CONFIG_CONSTRUCTORS`, off in most production kernels) AND a module notifier registered by the clltk kernel module (`register_module_notifier`, works on any kernel). Do not remove the notifier assuming the constructor suffices -- without `CONFIG_CONSTRUCTORS` the constructor never runs and tracing would silently do nothing.

### API Typo -- Do NOT Fix
- `clltk_unrecoverbale_error_callback` has a typo ("unrecoverbale"). This IS the public API. Fixing the spelling would be a breaking change.
Expand Down
9 changes: 8 additions & 1 deletion VERSION.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,13 @@
1.7.3
1.7.4

# Change log
## 1.7.4
- fix: kernel tracing registers via a module notifier, so it works on kernels built
without CONFIG_CONSTRUCTORS (the default for most production kernels). Registration
previously ran only from a module constructor, which such kernels never call - the
module loaded but tracing silently did nothing. The constructor path is kept for
CONFIG_CONSTRUCTORS kernels; both are idempotent.

## 1.7.3
- docs: README fixes and additions - remove the (now lifted) in-class-member-function
tracing limitation, correct the minimal-build feature flags and the decoder output
Expand Down
42 changes: 40 additions & 2 deletions kernel_tracing_library/src/module.c
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
// SPDX-License-Identifier: BSD-2-Clause-Patent

#include <linux/module.h>
#include <linux/notifier.h>

#include "CommonLowLevelTracingKit/tracing/tracing.h"

Expand All @@ -10,12 +11,49 @@ char *tracing_path = "/tmp/";
module_param(tracing_path, charp, 0000);
MODULE_PARM_DESC(tracing_path, "path where to write the traces");

// Registration of a traced module's tracebuffers/tracepoints runs from a C
// constructor injected into that module (see _kernel_tracing.h). The kernel
// only calls module constructors when CONFIG_CONSTRUCTORS is enabled, which is
// off in most production kernels - so on those the constructor never fires and
// tracing silently does nothing.
//
// A module notifier does the same work on any kernel and needs no cooperation
// from the traced module: the kernel calls it as each module is (un)loaded.
// Both paths are idempotent, so on a CONFIG_CONSTRUCTORS kernel the constructor
// and the notifier simply agree.
void _clltk_init_tracing_for_this_module(const struct mod_kallsyms *);
void _clltk_deinit_tracing_for_this_module(const struct mod_kallsyms *);

static int clltk_module_notify(struct notifier_block *nb, unsigned long action, void *data)
{
struct module *const mod = data;
(void)nb;
switch (action) {
case MODULE_STATE_COMING: // linked, before the module runs its own init
_clltk_init_tracing_for_this_module(mod->kallsyms);
break;
case MODULE_STATE_GOING: // being removed
_clltk_deinit_tracing_for_this_module(mod->kallsyms);
break;
default:
break;
}
return NOTIFY_OK;
}

static struct notifier_block clltk_module_nb = {
.notifier_call = clltk_module_notify,
};

static int __init init_clltk_kf(void)
{
return 0;
return register_module_notifier(&clltk_module_nb);
}

static void __exit exit_clltk_kf(void) {}
static void __exit exit_clltk_kf(void)
{
unregister_module_notifier(&clltk_module_nb);
}

module_init(init_clltk_kf);
module_exit(exit_clltk_kf);
Expand Down
12 changes: 7 additions & 5 deletions scripts/ci-cd/step_static_analysis.sh
Original file line number Diff line number Diff line change
Expand Up @@ -173,16 +173,18 @@ run_clang_tidy_diff() {
# root; tell git the mount is trusted so `git diff` works
git config --global --add safe.directory "$ROOT_PATH" 2>/dev/null || true

# Only source files: headers are not translation units (not in
# compile_commands.json), and some intentionally #error when compiled
# standalone. Header changes are still covered by the full builds and by
# clang-tidy of the sources that include them.
# Only source files that cmake actually compiles: headers are not
# translation units (not in compile_commands.json), and some intentionally
# #error when compiled standalone. Kernel-module sources are built by Kbuild,
# not cmake, so they are absent from compile_commands.json too - clang-tidy
# would fall back to defaults and fail on the kernel headers. Exclude both;
# they are covered by the full builds and the kernel-module build job.
#
# -U0: no context lines, so only changed lines are analyzed. -p1 strips the
# a/ b/ diff prefix. clang-tidy-diff exits non-zero on findings, so guard the
# assignment (set -e) and decide pass/fail from the output itself.
local out
out=$(git diff -U0 "${DIFF_BASE}" -- '*.c' '*.cpp' \
out=$(git diff -U0 "${DIFF_BASE}" -- '*.c' '*.cpp' ':(exclude)kernel_tracing_library/*' \
| python3 "$diff_tool" -p1 -path "$BUILD_DIR" -clang-tidy-binary clang-tidy \
-extra-arg=-Wno-unknown-warning-option 2>&1) || true
echo "$out"
Expand Down
Loading