pahole: Allow encoding BTF into a detached file

Previously the newly encoded BTF info was stored into a ELF section in
the file where the DWARF info was obtained, but it is useful to just
dump it into a separate file, do it.

  $ ls -la vmlinux.btf
  ls: cannot access 'vmlinux.btf': No such file or directory
  $ pahole -j vmlinux.btf vmlinux
  $ ls -la vmlinux.btf
  -rw-r-----. 1 acme acme 4630082 Jun  1 16:15 vmlinux.btf
  $ pahole -C list_head ./vmlinux.btf
  struct list_head {
  	struct list_head *         next;                 /*     0     8 */
  	struct list_head *         prev;                 /*     8     8 */

  	/* size: 16, cachelines: 1, members: 2 */
  	/* last cacheline: 16 bytes */
  };
  acme@toolbox pahole]$ pahole -C raw_spinlock_t ./vmlinux.btf
  typedef struct raw_spinlock raw_spinlock_t;
  acme@toolbox pahole]$ pahole -EC raw_spinlock ./vmlinux.btf
  struct raw_spinlock {
  	/* typedef arch_spinlock_t */ struct qspinlock {
  		union {
  			/* typedef atomic_t */ struct {
  				int counter;                                                  /*     0     4 */
  			} val;                                                                /*     0     4 */
  			struct {
  				/* typedef u8 -> __u8 */ unsigned char locked;                /*     0     1 */
  				/* typedef u8 -> __u8 */ unsigned char pending;               /*     1     1 */
  			};                                                                    /*     0     2 */
  			struct {
  				/* typedef u16 -> __u16 */ short unsigned int locked_pending; /*     0     2 */
  				/* typedef u16 -> __u16 */ short unsigned int tail;           /*     2     2 */
  			};                                                                    /*     0     4 */
  		};                                                                            /*     0     4 */
  	} raw_lock;                                                                           /*     0     4 */

  	/* size: 4, cachelines: 1, members: 1 */
  	/* last cacheline: 4 bytes */
  };
  ⬢[acme@toolbox pahole]$

Requested-by: Andrii Nakryiko <andrii@kernel.org>
Acked-by: Andrii Nakryiko <andrii@kernel.org>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
This commit is contained in:
Arnaldo Carvalho de Melo 2021-05-28 16:41:30 -03:00
parent 22a76fbc8b
commit 89be5646a0
4 changed files with 76 additions and 8 deletions

View File

@ -21,6 +21,14 @@
#include <stdlib.h> /* for qsort() and bsearch() */
#include <inttypes.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
/*
* This corresponds to the same macro defined in
* include/linux/kallsyms.h
@ -267,14 +275,62 @@ static struct btf_elf *btfe;
static uint32_t array_index_id;
static bool has_index_type;
int btf_encoder__encode()
static int btf__encode_as_raw_file(struct btf *btf, const char *filename)
{
uint32_t raw_btf_size;
const void *raw_btf_data;
int fd, err;
/* Empty file, nothing to do, so... done! */
if (btf__get_nr_types(btf) == 0)
return 0;
if (btf__dedup(btf, NULL, NULL)) {
fprintf(stderr, "%s: btf__dedup failed!\n", __func__);
return -1;
}
raw_btf_data = btf__get_raw_data(btf, &raw_btf_size);
if (raw_btf_data == NULL) {
fprintf(stderr, "%s: btf__get_raw_data failed!\n", __func__);
return -1;
}
fd = open(filename, O_WRONLY | O_CREAT, 0640);
if (fd < 0) {
fprintf(stderr, "%s: Couldn't open %s for writing the raw BTF info: %s\n", __func__, filename, strerror(errno));
return -1;
}
err = write(fd, raw_btf_data, raw_btf_size);
if (err < 0)
fprintf(stderr, "%s: Couldn't write the raw BTF info to %s: %s\n", __func__, filename, strerror(errno));
close(fd);
if (err != raw_btf_size) {
fprintf(stderr, "%s: Could only write %d bytes to %s of raw BTF info out of %d, aborting\n", __func__, err, filename, raw_btf_size);
unlink(filename);
err = -1;
} else {
/* go from bytes written == raw_btf_size to an indication that all went fine */
err = 0;
}
return err;
}
int btf_encoder__encode(const char *filename)
{
int err;
if (gobuffer__size(&btfe->percpu_secinfo) != 0)
btf_elf__add_datasec_type(btfe, PERCPU_SECTION, &btfe->percpu_secinfo);
err = btf_elf__encode(btfe, 0);
if (filename == NULL)
err = btf_elf__encode(btfe, 0);
else
err = btf__encode_as_raw_file(btfe->btf, filename);
delete_functions();
btf_elf__delete(btfe);
btfe = NULL;
@ -412,7 +468,7 @@ static bool has_arg_names(struct cu *cu, struct ftype *ftype)
}
int cu__encode_btf(struct cu *cu, int verbose, bool force,
bool skip_encoding_vars)
bool skip_encoding_vars, const char *detached_btf_filename)
{
uint32_t type_id_off;
uint32_t core_id;
@ -425,7 +481,7 @@ int cu__encode_btf(struct cu *cu, int verbose, bool force,
btf_elf__force = force;
if (btfe && strcmp(btfe->filename, cu->filename)) {
err = btf_encoder__encode();
err = btf_encoder__encode(detached_btf_filename);
if (err)
goto out;

View File

@ -11,9 +11,9 @@
struct cu;
int btf_encoder__encode();
int btf_encoder__encode(const char *filename);
int cu__encode_btf(struct cu *cu, int verbose, bool force,
bool skip_encoding_vars);
bool skip_encoding_vars, const char *detached_btf_filename);
#endif /* _BTF_ENCODER_H_ */

View File

@ -189,6 +189,10 @@ features such as BPF CO-RE (Compile Once - Run Everywhere).
See \fIhttps://nakryiko.com/posts/bpf-portability-and-co-re/\fR.
.TP
.B \-j, \-\-btf_encode_detached=FILENAME
Same thing as -J/--btf_encode, but storing the raw BTF info into a separate file.
.TP
.B \-\-btf_encode_force
Ignore those symbols found invalid when encoding BTF.

View File

@ -26,6 +26,7 @@
#include "lib/bpf/src/libbpf.h"
#include "pahole_strings.h"
static char *detached_btf_filename;
static bool btf_encode;
static bool ctf_encode;
static bool first_obj_only;
@ -1152,6 +1153,12 @@ static const struct argp_option pahole__options[] = {
.key = 'J',
.doc = "Encode as BTF",
},
{
.name = "btf_encode_detached",
.key = 'j',
.arg = "FILENAME",
.doc = "Encode as BTF in a detached file",
},
{
.name = "skip_encoding_btf_vars",
.key = ARGP_skip_encoding_btf_vars,
@ -1223,6 +1230,7 @@ static error_t pahole__options_parser(int key, char *arg,
conf_load.extra_dbg_info = 1; break;
case 'i': find_containers = 1;
class_name = arg; break;
case 'j': detached_btf_filename = arg; // fallthru
case 'J': btf_encode = 1;
conf_load.get_addr_info = true;
no_bitfield_type_recode = true; break;
@ -2458,7 +2466,7 @@ static enum load_steal_kind pahole_stealer(struct cu *cu,
if (btf_encode) {
if (cu__encode_btf(cu, global_verbose, btf_encode_force,
skip_encoding_btf_vars)) {
skip_encoding_btf_vars, detached_btf_filename)) {
fprintf(stderr, "Encountered error while encoding BTF.\n");
exit(1);
}
@ -2872,7 +2880,7 @@ try_sole_arg_as_class_names:
header = NULL;
if (btf_encode) {
err = btf_encoder__encode();
err = btf_encoder__encode(detached_btf_filename);
if (err) {
fputs("Failed to encode BTF\n", stderr);
goto out_cus_delete;