SchOS/ldls/btf.h
Nexoniarz 26bca020b6 licence: SchOS is GPL-2.0-or-later, no longer Apache-2.0
Nexoniarz is the sole author and SchOS was never published under
Apache-2.0, so this is a straight relicence. LICENSE is the FSF GPLv2 text,
every first-party SPDX header moves to GPL-2.0-or-later, and NOTICE,
README.md, docs/licensing.md and the site say so. projects/schfs-linux
follows the rest of the tree.

The GPL gives copyleft: a fork has to ship its source. It also lifts the
old "Linux drivers, never" rule, since GPL-2.0-only code combines with
GPL-2.0-or-later. "Or later" leaves room for GPLv3, but one binary still
has to pick one version, so docs/licensing.md now keeps Apache-2.0 and
GPLv3 code out of the kernel to keep Linux code possible there. BSD
4-clause code goes from "avoid" to "no", because the advertising clause
is GPL-incompatible.

LDLS still ships no .ko. That boundary is now project policy rather than
a legal requirement, and ldls.md, devices.md and licensing.md section 6
say so. refmod declares license=GPL, and ldls-check passes (27 checks).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-22 08:48:45 +02:00

139 lines
4.9 KiB
C

// SPDX-License-Identifier: GPL-2.0-or-later
//
// Reading BTF: struct layouts and function prototypes, from the kernel that
// the driver was built for.
//
// docs/architecture/ldls.md, rule 3½ -- the thing that makes rule 3 comfortable.
//
// The shim has to agree with a compiled driver about where `pci_driver.probe`
// sits, and a compiled driver is not negotiable about it. Writing those
// offsets into our source would mean a field-for-field match with Linux's
// headers, which *looks* like transcription however it was arrived at.
//
// It does not have to be in our source. A kernel built with
// CONFIG_DEBUG_INFO_BTF publishes `/sys/kernel/btf/vmlinux`: every struct
// layout and every function prototype, as generated binary type data
// describing the kernel that is installed. LDLS reads it at load time, on the
// user's machine, from the user's own kernel.
//
// Two things follow. The offsets are never ours to have copied, and they are
// right for the kernel actually present rather than one we pinned by guessing
// -- which is most of what rule 4 was worried about.
//
// The format is described in Documentation/bpf/btf.rst, which is a published
// specification; implementing it from that is the case ../docs/licensing.md §5
// covers. Freestanding, like the rest of ldls/.
// --- the format -------------------------------------------------------------
#define BTF_MAGIC 0xeB9F
struct btf_header {
unsigned short magic;
unsigned char version;
unsigned char flags;
unsigned int hdr_len;
// Both offsets are from the end of the header, not from the start of it.
unsigned int type_off;
unsigned int type_len;
unsigned int str_off;
unsigned int str_len;
};
struct btf_type {
unsigned int name_off;
// vlen in bits 0-15, kind in bits 24-28, kind_flag in bit 31.
unsigned int info;
union {
unsigned int size; // STRUCT, UNION, ENUM, INT, DATASEC, FLOAT
unsigned int type; // PTR, TYPEDEF, CONST, FUNC, VAR, ...
} u;
};
struct btf_member {
unsigned int name_off;
unsigned int type;
// With kind_flag set this is a bitfield: size in bits 24-31, bit offset in
// bits 0-23. Without it, a plain bit offset.
unsigned int offset;
};
struct btf_param {
unsigned int name_off;
unsigned int type;
};
#define BTF_KIND_INT 1
#define BTF_KIND_PTR 2
#define BTF_KIND_ARRAY 3
#define BTF_KIND_STRUCT 4
#define BTF_KIND_UNION 5
#define BTF_KIND_ENUM 6
#define BTF_KIND_FWD 7
#define BTF_KIND_TYPEDEF 8
#define BTF_KIND_VOLATILE 9
#define BTF_KIND_CONST 10
#define BTF_KIND_RESTRICT 11
#define BTF_KIND_FUNC 12
#define BTF_KIND_FUNC_PROTO 13
#define BTF_KIND_VAR 14
#define BTF_KIND_DATASEC 15
#define BTF_KIND_FLOAT 16
#define BTF_KIND_DECL_TAG 17
#define BTF_KIND_TYPE_TAG 18
#define BTF_KIND_ENUM64 19
#define BTF_INFO_KIND(i) (((i) >> 24) & 0x1f)
#define BTF_INFO_VLEN(i) ((i) & 0xffff)
#define BTF_INFO_KFLAG(i) (((i) >> 31) & 1)
// --- the reader ---------------------------------------------------------------
#define BTF_MAXTYPES 262144 // type ids we will index; vmlinux is ~150k
struct btf {
const unsigned char *img;
unsigned long long len;
const struct btf_header *h;
const unsigned char *types; // start of the type section
unsigned int types_len;
const char *str;
unsigned int str_len;
// Type id -> byte offset into the type section. Id 0 is void and has no
// entry, so this is 1-based and index 0 is unused.
unsigned int *off; // the caller's, ntypes + 1 entries
unsigned int ntypes;
char err[128];
};
// How many type ids this BTF holds, so the caller can size the index. -1 if
// the image is not BTF at all.
long btf_count(const void *image, unsigned long long len);
// Index it. `off` must have btf_count()+1 entries.
int btf_open(struct btf *b, const void *image, unsigned long long len,
unsigned int *off, unsigned int noff);
// The type id of a named type of a given kind, or 0.
int btf_find(struct btf *b, const char *name, int kind);
// Byte offset and size of a named member of a struct or union.
//
// Returns 0 on success. Bitfields are refused rather than rounded: a driver
// that reads one needs the bit position, and a byte offset would be a
// plausible-looking wrong answer.
int btf_member_off(struct btf *b, int struct_id, const char *member,
unsigned int *off_bytes, unsigned int *size_bytes);
// The value of a named enumerator, searched across every enum in the file.
// Constants a driver depends on are not all struct offsets -- see btf.c.
int btf_enum_value(struct btf *b, const char *name, long long *val);
// Size in bytes of a type, following typedefs and qualifiers. 0 if unknown.
unsigned int btf_type_size(struct btf *b, int id);
const char *btf_name_of(struct btf *b, int id);
int btf_kind_of(struct btf *b, int id);
const char *btf_err(const struct btf *b);