mirror of
https://github.com/AuxXxilium/linux_dsm_epyc7002.git
synced 2024-12-21 09:24:37 +07:00
9d5f9f701b
This patch fixed two issues with BTF. One is related to
struct/union bitfield encoding and the other is related to
forward type.
Issue #1 and solution:
======================
Current btf encoding of bitfield follows what pahole generates.
For each bitfield, pahole will duplicate the type chain and
put the bitfield size at the final int or enum type.
Since the BTF enum type cannot encode bit size,
pahole workarounds the issue by generating
an int type whenever the enum bit size is not 32.
For example,
-bash-4.4$ cat t.c
typedef int ___int;
enum A { A1, A2, A3 };
struct t {
int a[5];
___int b:4;
volatile enum A c:4;
} g;
-bash-4.4$ gcc -c -O2 -g t.c
The current kernel supports the following BTF encoding:
$ pahole -JV t.o
[1] TYPEDEF ___int type_id=2
[2] INT int size=4 bit_offset=0 nr_bits=32 encoding=SIGNED
[3] ENUM A size=4 vlen=3
A1 val=0
A2 val=1
A3 val=2
[4] STRUCT t size=24 vlen=3
a type_id=5 bits_offset=0
b type_id=9 bits_offset=160
c type_id=11 bits_offset=164
[5] ARRAY (anon) type_id=2 index_type_id=2 nr_elems=5
[6] INT sizetype size=8 bit_offset=0 nr_bits=64 encoding=(none)
[7] VOLATILE (anon) type_id=3
[8] INT int size=1 bit_offset=0 nr_bits=4 encoding=(none)
[9] TYPEDEF ___int type_id=8
[10] INT (anon) size=1 bit_offset=0 nr_bits=4 encoding=SIGNED
[11] VOLATILE (anon) type_id=10
Two issues are in the above:
. by changing enum type to int, we lost the original
type information and this will not be ideal later
when we try to convert BTF to a header file.
. the type duplication for bitfields will cause
BTF bloat. Duplicated types cannot be deduplicated
later if the bitfield size is different.
To fix this issue, this patch implemented a compatible
change for BTF struct type encoding:
. the bit 31 of struct_type->info, previously reserved,
now is used to indicate whether bitfield_size is
encoded in btf_member or not.
. if bit 31 of struct_type->info is set,
btf_member->offset will encode like:
bit 0 - 23: bit offset
bit 24 - 31: bitfield size
if bit 31 is not set, the old behavior is preserved:
bit 0 - 31: bit offset
So if the struct contains a bit field, the maximum bit offset
will be reduced to (2^24 - 1) instead of MAX_UINT. The maximum
bitfield size will be 256 which is enough for today as maximum
bitfield in compiler can be 128 where int128 type is supported.
This kernel patch intends to support the new BTF encoding:
$ pahole -JV t.o
[1] TYPEDEF ___int type_id=2
[2] INT int size=4 bit_offset=0 nr_bits=32 encoding=SIGNED
[3] ENUM A size=4 vlen=3
A1 val=0
A2 val=1
A3 val=2
[4] STRUCT t kind_flag=1 size=24 vlen=3
a type_id=5 bitfield_size=0 bits_offset=0
b type_id=1 bitfield_size=4 bits_offset=160
c type_id=7 bitfield_size=4 bits_offset=164
[5] ARRAY (anon) type_id=2 index_type_id=2 nr_elems=5
[6] INT sizetype size=8 bit_offset=0 nr_bits=64 encoding=(none)
[7] VOLATILE (anon) type_id=3
Issue #2 and solution:
======================
Current forward type in BTF does not specify whether the original
type is struct or union. This will not work for type pretty print
and BTF-to-header-file conversion as struct/union must be specified.
$ cat tt.c
struct t;
union u;
int foo(struct t *t, union u *u) { return 0; }
$ gcc -c -g -O2 tt.c
$ pahole -JV tt.o
[1] INT int size=4 bit_offset=0 nr_bits=32 encoding=SIGNED
[2] FWD t type_id=0
[3] PTR (anon) type_id=2
[4] FWD u type_id=0
[5] PTR (anon) type_id=4
To fix this issue, similar to issue #1, type->info bit 31
is used. If the bit is set, it is union type. Otherwise, it is
a struct type.
$ pahole -JV tt.o
[1] INT int size=4 bit_offset=0 nr_bits=32 encoding=SIGNED
[2] FWD t kind_flag=0 type_id=0
[3] PTR (anon) kind_flag=0 type_id=2
[4] FWD u kind_flag=1 type_id=0
[5] PTR (anon) kind_flag=0 type_id=4
Pahole/LLVM change:
===================
The new kind_flag functionality has been implemented in pahole
and llvm:
https://github.com/yonghong-song/pahole/tree/bitfield
https://github.com/yonghong-song/llvm/tree/bitfield
Note that pahole hasn't implemented func/func_proto kind
and .BTF.ext. So to print function signature with bpftool,
the llvm compiler should be used.
Fixes: 69b693f0ae
("bpf: btf: Introduce BPF Type Format (BTF)")
Acked-by: Martin KaFai Lau <kafai@fb.com>
Signed-off-by: Martin KaFai Lau <kafai@fb.com>
Signed-off-by: Yonghong Song <yhs@fb.com>
Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
142 lines
3.9 KiB
C
142 lines
3.9 KiB
C
/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
|
|
/* Copyright (c) 2018 Facebook */
|
|
#ifndef _UAPI__LINUX_BTF_H__
|
|
#define _UAPI__LINUX_BTF_H__
|
|
|
|
#include <linux/types.h>
|
|
|
|
#define BTF_MAGIC 0xeB9F
|
|
#define BTF_VERSION 1
|
|
|
|
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 */
|
|
};
|
|
|
|
/* Max # of type identifier */
|
|
#define BTF_MAX_TYPE 0x0000ffff
|
|
/* Max offset into the string section */
|
|
#define BTF_MAX_NAME_OFFSET 0x0000ffff
|
|
/* Max # of struct/union/enum members or func args */
|
|
#define BTF_MAX_VLEN 0xffff
|
|
|
|
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;
|
|
};
|
|
};
|
|
|
|
#define BTF_INFO_KIND(info) (((info) >> 24) & 0x0f)
|
|
#define BTF_INFO_VLEN(info) ((info) & 0xffff)
|
|
#define BTF_INFO_KFLAG(info) ((info) >> 31)
|
|
|
|
#define BTF_KIND_UNKN 0 /* Unknown */
|
|
#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_MAX 13
|
|
#define NR_BTF_KINDS 14
|
|
|
|
/* For some specific BTF_KIND, "struct btf_type" is immediately
|
|
* followed by extra data.
|
|
*/
|
|
|
|
/* BTF_KIND_INT is followed by a u32 and the following
|
|
* is the 32 bits arrangement:
|
|
*/
|
|
#define BTF_INT_ENCODING(VAL) (((VAL) & 0x0f000000) >> 24)
|
|
#define BTF_INT_OFFSET(VAL) (((VAL & 0x00ff0000)) >> 16)
|
|
#define BTF_INT_BITS(VAL) ((VAL) & 0x000000ff)
|
|
|
|
/* Attributes stored in the BTF_INT_ENCODING */
|
|
#define BTF_INT_SIGNED (1 << 0)
|
|
#define BTF_INT_CHAR (1 << 1)
|
|
#define BTF_INT_BOOL (1 << 2)
|
|
|
|
/* BTF_KIND_ENUM is followed by multiple "struct btf_enum".
|
|
* The exact number of btf_enum is stored in the vlen (of the
|
|
* info in "struct btf_type").
|
|
*/
|
|
struct btf_enum {
|
|
__u32 name_off;
|
|
__s32 val;
|
|
};
|
|
|
|
/* BTF_KIND_ARRAY is followed by one "struct btf_array" */
|
|
struct btf_array {
|
|
__u32 type;
|
|
__u32 index_type;
|
|
__u32 nelems;
|
|
};
|
|
|
|
/* BTF_KIND_STRUCT and BTF_KIND_UNION are followed
|
|
* by multiple "struct btf_member". The exact number
|
|
* of btf_member is stored in the vlen (of the info in
|
|
* "struct btf_type").
|
|
*/
|
|
struct btf_member {
|
|
__u32 name_off;
|
|
__u32 type;
|
|
/* If the type info kind_flag is set, the btf_member offset
|
|
* contains both member bitfield size and bit offset. The
|
|
* bitfield size is set for bitfield members. If the type
|
|
* info kind_flag is not set, the offset contains only bit
|
|
* offset.
|
|
*/
|
|
__u32 offset;
|
|
};
|
|
|
|
/* If the struct/union type info kind_flag is set, the
|
|
* following two macros are used to access bitfield_size
|
|
* and bit_offset from btf_member.offset.
|
|
*/
|
|
#define BTF_MEMBER_BITFIELD_SIZE(val) ((val) >> 24)
|
|
#define BTF_MEMBER_BIT_OFFSET(val) ((val) & 0xffffff)
|
|
|
|
/* BTF_KIND_FUNC_PROTO is followed by multiple "struct btf_param".
|
|
* The exact number of btf_param is stored in the vlen (of the
|
|
* info in "struct btf_type").
|
|
*/
|
|
struct btf_param {
|
|
__u32 name_off;
|
|
__u32 type;
|
|
};
|
|
|
|
#endif /* _UAPI__LINUX_BTF_H__ */
|