BPF类型格式BTF

@[TOC](BPF)

这是包含BPF(Berkeley Packet Filter)功能的文档,重点放在扩展的BPF版本(eBPF)上。

该内核方面的文档仍在开发中。 (出于历史原因)主要文本文档在Linux套接字过滤(又称为Berkeley数据包过滤器(BPF))中进行了描述。
该文档描述了经典BPF和扩展BPF指令集。 Cilium项目还维护着一个BPF和XDP参考指南,该指南对BPF体系结构有很深的技术深度。
bpf syscall的主要信息可在bpf(2)的手册页中找到。

BPF类型格式(BTF)

介绍

BTF(BPF类型格式)是对与BPFprogram/map有关的调试信息进行编码的元数据格式。最初使用名称BTF来描述数据类型。 BTF后来进行了扩展,以包括用于定义的子例程的功能信息,以及用于source/line的对应关系。

调试信息用于映射漂亮的打印,函数签名等。函数签名可实现更好的bpfprogram/function内核符号。行信息有助于生成带源注释的翻译后的字节码,引用的代码和验证者日志。

BTF规范包含两部分:

  • BTF内核API
  • BTF ELF文件格式

内核API是用户空间和内核之间的契约。内核在使用前会验证BTF信息。 ELF文件格式是ELF文件和libbpf加载程序之间的用户空间协定。

类型和字符串部分是BTF内核API的一部分,描述了bpf程序引用的调试信息(主要是相关的类型)。这两个部分将在下面详细讨论

BTF类型和字符串编码

文件include/uapi/linux/btf.h提供了有关如何编码·types/strings·的高级定义。
数据Blob的开头必须为:

struct btf_header {
    __u16   magic;
    __u8    version;
    __u8    flags;
    __u32   hdr_len;

    /* All offsets are in bytes relative to the end of this header */
    __u32   type_off;       /* offset of type section       */
    __u32   type_len;       /* length of type section       */
    __u32   str_off;        /* offset of string section     */
    __u32   str_len;        /* length of string section     */
};

魔数是0xeB9F,它对大小端系统使用不同的编码,并且可以用来测试BTF是针对大端还是小端目标生成的。生成数据Blob时,btf_header设计为可扩展的,其中hdr_len等于sizeof(struct btf_header)。

字符串编码

字符串部分中的第一个字符串必须为空字符串。字符串表的其余部分是其他以空值终止的字符串的串联。

#define BTF_KIND_INT            1       /* Integer      */
#define BTF_KIND_PTR            2       /* Pointer      */
#define BTF_KIND_ARRAY          3       /* Array        */
#define BTF_KIND_STRUCT         4       /* Struct       */
#define BTF_KIND_UNION          5       /* Union        */
#define BTF_KIND_ENUM           6       /* Enumeration  */
#define BTF_KIND_FWD            7       /* Forward      */
#define BTF_KIND_TYPEDEF        8       /* Typedef      */
#define BTF_KIND_VOLATILE       9       /* Volatile     */
#define BTF_KIND_CONST          10      /* Const        */
#define BTF_KIND_RESTRICT       11      /* Restrict     */
#define BTF_KIND_FUNC           12      /* Function     */
#define BTF_KIND_FUNC_PROTO     13      /* Function Proto       */
#define BTF_KIND_VAR            14      /* Variable     */
#define BTF_KIND_DATASEC        15      /* Section      */

请注意,类型部分对调试信息进行编码,而不仅仅是纯类型。 BTF_KIND_FUNC不是类型,它表示已定义的子程序。

每种类型包含以下公共数据:

struct btf_type {
    __u32 name_off;
    /* "info" bits arrangement
     * bits  0-15: vlen (e.g. # of struct's members)
     * bits 16-23: unused
     * bits 24-27: kind (e.g. int, ptr, array...etc)
     * bits 28-30: unused
     * bit     31: kind_flag, currently used by
     *             struct, union and fwd
     */
    __u32 info;
    /* "size" is used by INT, ENUM, STRUCT and UNION.
     * "size" tells the size of the type it is describing.
     *
     * "type" is used by PTR, TYPEDEF, VOLATILE, CONST, RESTRICT,
     * FUNC and FUNC_PROTO.
     * "type" is a type_id referring to another type.
     */
    union {
            __u32 size;
            __u32 type;
    };
};

对于某些种类,通用数据后跟特定种类的数据。 struct btf_type中的name_off指定字符串表中的偏移量。以下各节详细介绍了每种编码。

BTF_KIND_INT

struct btf_type编码要求:

  • name_off: 任何有效的偏移量
  • info.kind_flag: 0
  • info.kind: BTF_KIND_INT
  • info.vlen: 0
  • size: int类型的大小(以字节为单位)

btf_type之后是带有以下位排列的u32

#define BTF_INT_ENCODING(VAL)   (((VAL) & 0x0f000000) >> 24)
#define BTF_INT_OFFSET(VAL)     (((VAL) & 0x00ff0000) >> 16)
#define BTF_INT_BITS(VAL)       ((VAL)  & 0x000000ff)

BTF_INT_ENCODING具有以下属性:

#define BTF_INT_SIGNED  (1 << 0)
#define BTF_INT_CHAR    (1 << 1)
#define BTF_INT_BOOL    (1 << 2)

BTF_INT_ENCODING()为int类型提供了额外的信息:signedness,char或bool。 char和bool编码对于漂亮的打印最为有用。最多可以为int类型指定一种编码。

BTF_INT_BITS()指定此int类型保存的实际位数。例如,一个4位的位字段编码的BTF_INT_BITS()等于4。btf_type.size * 8必须等于或大于该类型的BTF_INT_BITS()。 BTF_INT_BITS()的最大值为128。

BTF_INT_OFFSET()指定用于计算此int值的起始位偏移量。例如,位域结构成员具有:

  • btf成员从结构开始偏移100,
  • 指向int类型的btf成员,
  • int类型具有BTF_INT_OFFSET()= 2和BTF_INT_BITS()= 4

然后在结构内存布局中,此成员将从位100 + 2 = 102开始占据4位。

或者,可以使用以下位域结构成员来访问与上述相同的位:

  • btf成员位偏移量102,
  • 指向int类型的btf成员,
  • int类型的BTF_INT_OFFSET()= 0和BTF_INT_BITS()= 4

BTF_INT_OFFSET()的初衷是提供位域编码的灵活性。当前,llvm和pahole都为所有int类型生成BTF_INT_OFFSET()= 0。

BTF_KIND_PTR

struct btf_type编码要求:

  • name_off: 0
  • info.kind_flag: 0
  • info.kind: BTF_KIND_PTR
  • info.vlen: 0
  • type: 指针指向的类型

btf_type之后没有其他类型数据。

BTF_KIND_ARRAY

struct btf_type编码要求:

  • name_off: 0
  • info.kind_flag: 0
  • info.kind: BTF_KIND_ARRAY
  • info.vlen: 0
  • size/type: 0, not used
    btf_type后跟一个结构btf_array:
struct btf_array {
    __u32   type;
    __u32   index_type;
    __u32   nelems;
};

btf_array结构编码:

  • type:元素类型
  • index_type:索引类型
  • nelems: 此数组的元素数(也允许为0)。

index_type可以是任何常规int类型(u8,u16,u32,u64,无符号__int128)。包含index_type的原始设计遵循DWARF,它的数组类型具有index_type。当前在BTF中,除了类型验证之外,未使用index_type。

btf_array结构允许通过元素类型链接来表示多维数组。例如,对于int a [5] [6],以下类型信息说明了链接:

[1]: int
[2]: array, btf_array.type = [1], btf_array.nelems = 6
[3]: array, btf_array.type = [2], btf_array.nelems = 5

当前,pahole和llvm都将多维数组折叠成一维数组,例如对于a [5] [6],btf_array.nelems等于30。这是因为原始用例是整个数组都打印得漂亮的地图被丢弃,因此一维数组就足够了。随着对更多BTF用法的探索,可以更改pahole和llvm以生成多维数组的正确链式表示。

其他的请看:
https://www.kernel.org/doc/html/latest/bpf/btf.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值