btf: Add support for split BTF loading and encoding

Add support for generating split BTF, in which there is a designated base
BTF, containing a base set of types, and a split BTF, which extends main BTF
with extra types, that can reference types and strings from the main BTF.

This is going to be used to generate compact BTFs for kernel modules, with
vmlinux BTF being a main BTF, which all kernel modules are based off of.

These changes rely on patch set [0] to be present in libbpf submodule.

  [0] https://patchwork.kernel.org/project/netdevbpf/list/?series=377859&state=*

Committer notes:

Fixed up wrt ARGP_numeric_version and added a man page entry.

Signed-off-by: Andrii Nakryiko <andrii@kernel.org>
Cc: bpf@vger.kernel.org
Cc: dwarves@vger.kernel.org
Cc: kernel-team@fb.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
This commit is contained in:
Andrii Nakryiko 2020-11-05 21:25:49 -08:00 committed by Arnaldo Carvalho de Melo
parent 7290d08b4a
commit ace05ba941
6 changed files with 38 additions and 7 deletions

View File

@ -12,6 +12,7 @@
#include "dwarves.h"
#include "libbtf.h"
#include "lib/bpf/include/uapi/linux/btf.h"
#include "lib/bpf/src/libbpf.h"
#include "hash.h"
#include "elf_symtab.h"
#include "btf_encoder.h"
@ -595,7 +596,7 @@ int cu__encode_btf(struct cu *cu, int verbose, bool force,
}
if (!btfe) {
btfe = btf_elf__new(cu->filename, cu->elf);
btfe = btf_elf__new(cu->filename, cu->elf, base_btf);
if (!btfe)
return -1;

View File

@ -534,7 +534,7 @@ struct debug_fmt_ops btf_elf__ops;
int btf_elf__load_file(struct cus *cus, struct conf_load *conf, const char *filename)
{
int err;
struct btf_elf *btfe = btf_elf__new(filename, NULL);
struct btf_elf *btfe = btf_elf__new(filename, NULL, base_btf);
if (btfe == NULL)
return -1;

View File

@ -27,6 +27,7 @@
#include "dwarves.h"
#include "elf_symtab.h"
struct btf *base_btf;
uint8_t btf_elf__verbose;
uint8_t btf_elf__force;
@ -52,9 +53,9 @@ int btf_elf__load(struct btf_elf *btfe)
/* free initial empty BTF */
btf__free(btfe->btf);
if (btfe->raw_btf)
btfe->btf = btf__parse_raw(btfe->filename);
btfe->btf = btf__parse_raw_split(btfe->filename, btfe->base_btf);
else
btfe->btf = btf__parse_elf(btfe->filename, NULL);
btfe->btf = btf__parse_elf_split(btfe->filename, btfe->base_btf);
err = libbpf_get_error(btfe->btf);
if (err)
@ -63,7 +64,7 @@ int btf_elf__load(struct btf_elf *btfe)
return 0;
}
struct btf_elf *btf_elf__new(const char *filename, Elf *elf)
struct btf_elf *btf_elf__new(const char *filename, Elf *elf, struct btf *base_btf)
{
struct btf_elf *btfe = zalloc(sizeof(*btfe));
GElf_Shdr shdr;
@ -77,7 +78,8 @@ struct btf_elf *btf_elf__new(const char *filename, Elf *elf)
if (btfe->filename == NULL)
goto errout;
btfe->btf = btf__new_empty();
btfe->base_btf = base_btf;
btfe->btf = btf__new_empty_split(base_btf);
if (libbpf_get_error(btfe->btf)) {
fprintf(stderr, "%s: failed to create empty BTF.\n", __func__);
goto errout;

View File

@ -27,8 +27,10 @@ struct btf_elf {
uint32_t percpu_shndx;
uint64_t percpu_base_addr;
struct btf *btf;
struct btf *base_btf;
};
extern struct btf *base_btf;
extern uint8_t btf_elf__verbose;
extern uint8_t btf_elf__force;
#define btf_elf__verbose_log(fmt, ...) { if (btf_elf__verbose) printf(fmt, __VA_ARGS__); }
@ -39,7 +41,7 @@ struct cu;
struct base_type;
struct ftype;
struct btf_elf *btf_elf__new(const char *filename, Elf *elf);
struct btf_elf *btf_elf__new(const char *filename, Elf *elf, struct btf *base_btf);
void btf_elf__delete(struct btf_elf *btf);
int32_t btf_elf__add_base_type(struct btf_elf *btf, const struct base_type *bt,

View File

@ -185,6 +185,10 @@ Do not encode VARs in BTF.
.B \-\-btf_encode_force
Ignore those symbols found invalid when encoding BTF.
.TP
.B \-\-btf_base
Path to the base BTF file, for instance: vmlinux when encoding kernel module BTF information.
.TP
.B \-l, \-\-show_first_biggest_size_base_type_member
Show first biggest size base_type member.

View File

@ -22,12 +22,15 @@
#include "dutil.h"
#include "ctf_encoder.h"
#include "btf_encoder.h"
#include "libbtf.h"
#include "lib/bpf/src/libbpf.h"
static bool btf_encode;
static bool ctf_encode;
static bool first_obj_only;
static bool skip_encoding_btf_vars;
static bool btf_encode_force;
static const char *base_btf_file;
static uint8_t class__include_anonymous;
static uint8_t class__include_nested_anonymous;
@ -821,6 +824,7 @@ ARGP_PROGRAM_VERSION_HOOK_DEF = dwarves_print_version;
#define ARGP_btf_encode_force 318
#define ARGP_just_packed_structs 319
#define ARGP_numeric_version 320
#define ARGP_btf_base 321
static const struct argp_option pahole__options[] = {
{
@ -1094,6 +1098,12 @@ static const struct argp_option pahole__options[] = {
.key = ARGP_hex_fmt,
.doc = "Print offsets and sizes in hexadecimal",
},
{
.name = "btf_base",
.key = ARGP_btf_base,
.arg = "SIZE",
.doc = "Path to the base BTF file",
},
{
.name = "btf_encode",
.key = 'J',
@ -1240,6 +1250,8 @@ static error_t pahole__options_parser(int key, char *arg,
skip_encoding_btf_vars = true; break;
case ARGP_btf_encode_force:
btf_encode_force = true; break;
case ARGP_btf_base:
base_btf_file = arg; break;
case ARGP_numeric_version:
print_numeric_version = true; break;
default:
@ -2695,6 +2707,15 @@ int main(int argc, char *argv[])
goto out;
}
if (base_btf_file) {
base_btf = btf__parse(base_btf_file, NULL);
if (libbpf_get_error(base_btf)) {
fprintf(stderr, "Failed to parse base BTF '%s': %ld\n",
base_btf_file, libbpf_get_error(base_btf));
goto out;
}
}
struct cus *cus = cus__new();
if (cus == NULL) {
fputs("pahole: insufficient memory\n", stderr);
@ -2784,6 +2805,7 @@ out_cus_delete:
#ifdef DEBUG_CHECK_LEAKS
cus__delete(cus);
structures__delete();
btf__free(base_btf);
#endif
out_dwarves_exit:
#ifdef DEBUG_CHECK_LEAKS