BPF BTF 详解

BPF BTF 详解

1. 介绍BTF(BPF Type Format)是内嵌在BPF(Berkeley Packet Filter)程序中的数据结构描述信息。BPF原本是用于数据包过滤的编程语言,但随着eBPF(extended BPF)的发展,它的用途已经扩展到多种内核子系统中,包括性能监测、网络安全和配置管理等。

BTF是为了实现更复杂的eBPF程序而设计的。其提供了一种机制,通过它可以将编程时使用的数据结构(如C语言中的结构体、联合体、枚举等)的信息嵌入到eBPF程序中。这样做的主要目的是为了让eBPF程序在运行时能够具有类型安全(Type Safety),同时也便于内核和用户空间的程序理解和操作这些数据结构。

在eBPF程序开发过程中,用户通常会在用户空间编写C代码,然后使用特定的编译器(如clang)编译这些代码为eBPF字节码。由于C程序中定义的复杂数据结构信息在编译为eBPF字节码过程中会丢失,因此BTF被设计来保留这些信息。当eBPF程序加载到内核时,BTF信息可以被内核使用,以确保程序操作的数据结构与内核预期的一致,从而保证程序的正确运行。

举个例子,如果eBPF程序需要访问内核数据结构,BTF就能够提供这些内核数据结构的确切布局,让eBPF程序能够安全而准确地读取或修改这些数据。

总之,BTF使得eBPF程序能更安全且方便地与复杂的数据类型互动,并有助于提高eBPF程序与内核间的兼容性和稳定性。

BTF(BPF 类型格式)是一种元数据格式,对与 BPF 程序 /map 有关的调试信息进行编码。BTF 这个名字最初是用来描述数据类型。后来,BTF 被扩展到包括已定义的子程序的函数信息和行信息。

调试信息可用于 map 的更好打印、函数签名等。函数签名能够更好地实现 bpf 程序/函数的内核符号。行信息有助于生成源注释的翻译字节码、JIT 代码和验证器的日志。

BTF 规范包含两个部分:

BTF 内核 APIBTF ELF 文件格式

内核 API 是用户空间和内核之间的约定。内核在使用之前使用 BTF 信息对其进行验证。ELF 文件格式是一个用户空间 ELF 文件和 libbpf 加载器之间的约定。类型和字符串部分(section)是 BTF 内核 API 的一部分,描述了 bpf 程序所引用的调试信息(主要是与类型有关的)。这两个部分将在 BTF_Type_String 章节中详细讨论。

2. BTF 类型和字符串编码文件 include/uapi/linux/btf.h 提供了关于类型/字符串如何编码的更高层次的定义。

数据块(blob)的开头必须是:

代码语言:javascript复制struct btf_header {

__u16 magic;

__u8 version;

__u8 flags;

__u32 hdr_len;

/* 所有的偏移量都是相对于这个头的末尾的字节 */

__u32 type_off; /* 类型部分的偏移量 */

__u32 type_len; /* 类型部分的长度 */

__u32 str_off; /* 字符串部分的偏移量 */

__u32 str_len; /* 字符串部分的长度 */

};magic 数值是 0xeB9F,其在对大、小端系统上的编码有所不同,这可以用来测试 BTF 所在系统是否为大、小端系统。btf_header 被设计为可扩展的,当数据 blob 生成时, hdr_len 等于 sizeof(struct btf_header)。

2.1 字符串编码字符串部分的第一个字符串必须以 null 结尾字符串。字符串表的其他部分有其他非 null 结尾的字符串连接而成。

2.2 类型编码类型标识 0 是为 void 类型保留的。类型部分(section)是按顺序解析,每个类型以 ID 从 1 开始的进行编码。目前,支持以下类型:

代码语言:javascript复制#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 /* VOLATILE 变量 */

#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 /* 数据部分 */注意,类型部分是对调试信息进行编码的,而不是类型自身。BTF_KIND_FUNC 不是一个类型, 它代表一个已定义的子程序。

每个类型都包含以下常见的数据:

代码语言:javascript复制struct btf_type {

__u32 name_off;

/* "info" 位值设置如下:

* 第 0-15 位:vlen(例如结构的成员)

* bits 16-23: unused

* bits 24-27: kind (e.g. int, ptr, array...etc)

* bits 28-30 位:未使用

* bits 31: kind_flag, 目前被 struct, union 和 fwd 使用

*/

__u32 info;

/* "size" 被 INT、ENUM、STRUCT 和 UNION 使用

* "size" 用于描述类型的大小

*

* "type“ 被 PTR, TYPEDEF, VOLATILE, CONST, RESTRICT, FUNC 和 FUNC_PROTO 使用。

* "type" 是指另一个类型的 type_id

*/

union {

__u32 size;

__u32 type;

};

};libbpf 库底层使用的结构:

代码语言:javascript复制struct btf {

void *data;

struct btf_type **types;

u32 *resolved_ids;

u32 *resolved_sizes;

const char *strings;

void *nohdr_data;

struct btf_header hdr;

u32 nr_types;

u32 types_size;

u32 data_size;

refcount_t refcnt;

u32 id;

struct rcu_head rcu;

};对于某些类别来讲,通用数据之后是特定类型的数据。在 struct btf_type 中的 name_off 字段指定了字符串表中的偏移。

相关推荐

世界杯小组赛图片
365bet网投官网

世界杯小组赛图片

📅 11-01 👁️ 2368
爱他美10大版本详细解读,这份攻略值得收藏!
淘婚记一共多少集
365bet网投官网

淘婚记一共多少集

📅 10-06 👁️ 5553