btf_encoder: run BTF deduplication before writing out to ELF

After btf_encoder completes DWARF to BTF 0-to-1 conversion, utilize
libbpf to construct struct btf and run btf__dedup() algorithm on it.
This significantly reduces number of BTF types and strings section size
without losing any information.

Committer testing:

Before:

  $ cp ../build/v5.0-rc3+/vmlinux .
  $ ls -la vmlinux
  -rwxrwxr-x. 1 acme acme 654357792 Feb 18 10:51 vmlinux
  $ pahole -J vmlinux
  $ ls -la vmlinux
  -rwxrwxr-x. 1 acme acme 824950072 Feb 18 10:52 vmlinux
  $ echo $((824950072 - 654357792))
  170592280
  $
  $ readelf -SW vmlinux  | head -4
  There are 79 section headers, starting at offset 0x312ba978:

  Section Headers:
    [Nr] Name   Type      Address          Off      Size    ES Flg Lk Inf Al
  <SNIP>
    [78] .BTF   PROGBITS  0000000000000000 27053da9 a266bcd 00      0   0  1
    $
  >>> 0xa266bcd
  170290125

After:

  $ cp ../build/v5.0-rc3+/vmlinux .
  $ ls -la vmlinux
-rwxrwxr-x. 1 acme acme 654357792 Feb 18 11:01 vmlinux
  $ pahole -J vmlinux
  $ ls -la vmlinux
-rwxrwxr-x. 1 acme acme 656641544 Feb 18 11:01 vmlinux
  $ echo $((656641544 - 654357792))
2283752
  $ readelf -SW vmlinux  | grep BTF
  [78] .BTF              PROGBITS        0000000000000000 27053da9 1e3c9e 00      0   0  1
>>> 0x1e3c9e
1981598
>>>

Signed-off-by: Andrii Nakryiko <andriin@fb.com>
Tested-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: Alexei Starovoitov <ast@fb.com>
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 2019-02-17 00:20:18 -08:00 committed by Arnaldo Carvalho de Melo
parent 54106025cd
commit dd3a7d3ab3
1 changed files with 33 additions and 9 deletions

View File

@ -17,6 +17,9 @@
#include "libbtf.h"
#include "lib/bpf/include/uapi/linux/btf.h"
#include "lib/bpf/include/linux/err.h"
#include "lib/bpf/src/btf.h"
#include "lib/bpf/src/libbpf.h"
#include "dutil.h"
#include "gobuffer.h"
#include "dwarves.h"
@ -566,19 +569,21 @@ int32_t btf_elf__add_func_proto(struct btf_elf *btfe, struct ftype *ftype, uint3
return type_id;
}
static int btf_elf__write(struct btf_elf *btfe)
static int btf_elf__write(const char *filename, struct btf *btf)
{
GElf_Shdr shdr_mem, *shdr;
GElf_Ehdr ehdr_mem, *ehdr;
Elf_Data *btf_elf = NULL;
Elf_Scn *scn = NULL;
Elf *elf = NULL;
const void *btf_data;
uint32_t btf_size;
int fd, err = -1;
size_t strndx;
fd = open(btfe->filename, O_RDWR);
fd = open(filename, O_RDWR);
if (fd < 0) {
fprintf(stderr, "Cannot open %s\n", btfe->filename);
fprintf(stderr, "Cannot open %s\n", filename);
return -1;
}
@ -617,10 +622,12 @@ static int btf_elf__write(struct btf_elf *btfe)
}
}
btf_data = btf__get_raw_data(btf, &btf_size);
if (btf_elf) {
/* Exisiting .BTF section found */
btf_elf->d_buf = btfe->data;
btf_elf->d_size = btfe->size;
btf_elf->d_buf = (void *)btf_data;
btf_elf->d_size = btf_size;
elf_flagdata(btf_elf, ELF_C_SET, ELF_F_DIRTY);
if (elf_update(elf, ELF_C_NULL) >= 0 &&
@ -646,10 +653,9 @@ static int btf_elf__write(struct btf_elf *btfe)
}
snprintf(cmd, sizeof(cmd), "%s --add-section .BTF=%s %s",
llvm_objcopy, tmp_fn, btfe->filename);
llvm_objcopy, tmp_fn, filename);
if (write(fd, btfe->data, btfe->size) == btfe->size &&
!system(cmd))
if (write(fd, btf_data, btf_size) == btf_size && !system(cmd))
err = 0;
unlink(tmp_fn);
@ -663,9 +669,15 @@ out:
return err;
}
static int libbpf_log(enum libbpf_print_level level, const char *format, va_list args)
{
return vfprintf(stderr, format, args);
}
int btf_elf__encode(struct btf_elf *btfe, uint8_t flags)
{
struct btf_header *hdr;
struct btf *btf;
/* Empty file, nothing to do, so... done! */
if (gobuffer__size(&btfe->types) == 0)
@ -695,5 +707,17 @@ int btf_elf__encode(struct btf_elf *btfe, uint8_t flags)
*(char *)(btf_elf__nohdr_data(btfe) + hdr->str_off) = '\0';
return btf_elf__write(btfe);
libbpf_set_print(libbpf_log);
btf = btf__new(btfe->data, btfe->size);
if (IS_ERR(btf)) {
fprintf(stderr, "%s: btf__new failed!\n", __func__);
return -1;
}
if (btf__dedup(btf, NULL, NULL)) {
fprintf(stderr, "%s: btf__dedup failed!", __func__);
return -1;
}
return btf_elf__write(btfe->filename, btf);
}