bpftool: Use bpf_obj_get_info_by_fd directly
To prepare for impending deprecation of libbpf's bpf_program__get_prog_info_linear, migrate uses of this function to use bpf_obj_get_info_by_fd. Since the profile_target_name and dump_prog_id_as_func_ptr helpers were only looking at the first func_info, avoid grabbing the rest to save a malloc. For do_dump, add a more full-featured helper, but avoid free/realloc of buffer when possible for multi-prog dumps. Signed-off-by: Dave Marchevsky <davemarchevsky@fb.com> Signed-off-by: Andrii Nakryiko <andrii@kernel.org> Acked-by: Quentin Monnet <quentin@isovalent.com> Link: https://lore.kernel.org/bpf/20211101224357.2651181-3-davemarchevsky@fb.com
This commit is contained in:
Родитель
60f2707539
Коммит
c59765cfd1
|
@ -32,14 +32,16 @@ static int dump_prog_id_as_func_ptr(const struct btf_dumper *d,
|
||||||
const struct btf_type *func_proto,
|
const struct btf_type *func_proto,
|
||||||
__u32 prog_id)
|
__u32 prog_id)
|
||||||
{
|
{
|
||||||
struct bpf_prog_info_linear *prog_info = NULL;
|
|
||||||
const struct btf_type *func_type;
|
const struct btf_type *func_type;
|
||||||
|
int prog_fd = -1, func_sig_len;
|
||||||
|
struct bpf_prog_info info = {};
|
||||||
|
__u32 info_len = sizeof(info);
|
||||||
const char *prog_name = NULL;
|
const char *prog_name = NULL;
|
||||||
struct bpf_func_info *finfo;
|
|
||||||
struct btf *prog_btf = NULL;
|
struct btf *prog_btf = NULL;
|
||||||
struct bpf_prog_info *info;
|
struct bpf_func_info finfo;
|
||||||
int prog_fd, func_sig_len;
|
__u32 finfo_rec_size;
|
||||||
char prog_str[1024];
|
char prog_str[1024];
|
||||||
|
int err;
|
||||||
|
|
||||||
/* Get the ptr's func_proto */
|
/* Get the ptr's func_proto */
|
||||||
func_sig_len = btf_dump_func(d->btf, prog_str, func_proto, NULL, 0,
|
func_sig_len = btf_dump_func(d->btf, prog_str, func_proto, NULL, 0,
|
||||||
|
@ -55,22 +57,27 @@ static int dump_prog_id_as_func_ptr(const struct btf_dumper *d,
|
||||||
if (prog_fd < 0)
|
if (prog_fd < 0)
|
||||||
goto print;
|
goto print;
|
||||||
|
|
||||||
prog_info = bpf_program__get_prog_info_linear(prog_fd,
|
err = bpf_obj_get_info_by_fd(prog_fd, &info, &info_len);
|
||||||
1UL << BPF_PROG_INFO_FUNC_INFO);
|
if (err)
|
||||||
close(prog_fd);
|
|
||||||
if (IS_ERR(prog_info)) {
|
|
||||||
prog_info = NULL;
|
|
||||||
goto print;
|
goto print;
|
||||||
}
|
|
||||||
info = &prog_info->info;
|
|
||||||
|
|
||||||
if (!info->btf_id || !info->nr_func_info)
|
if (!info.btf_id || !info.nr_func_info)
|
||||||
goto print;
|
goto print;
|
||||||
prog_btf = btf__load_from_kernel_by_id(info->btf_id);
|
|
||||||
|
finfo_rec_size = info.func_info_rec_size;
|
||||||
|
memset(&info, 0, sizeof(info));
|
||||||
|
info.nr_func_info = 1;
|
||||||
|
info.func_info_rec_size = finfo_rec_size;
|
||||||
|
info.func_info = ptr_to_u64(&finfo);
|
||||||
|
|
||||||
|
err = bpf_obj_get_info_by_fd(prog_fd, &info, &info_len);
|
||||||
|
if (err)
|
||||||
|
goto print;
|
||||||
|
|
||||||
|
prog_btf = btf__load_from_kernel_by_id(info.btf_id);
|
||||||
if (libbpf_get_error(prog_btf))
|
if (libbpf_get_error(prog_btf))
|
||||||
goto print;
|
goto print;
|
||||||
finfo = u64_to_ptr(info->func_info);
|
func_type = btf__type_by_id(prog_btf, finfo.type_id);
|
||||||
func_type = btf__type_by_id(prog_btf, finfo->type_id);
|
|
||||||
if (!func_type || !btf_is_func(func_type))
|
if (!func_type || !btf_is_func(func_type))
|
||||||
goto print;
|
goto print;
|
||||||
|
|
||||||
|
@ -92,7 +99,8 @@ print:
|
||||||
prog_str[sizeof(prog_str) - 1] = '\0';
|
prog_str[sizeof(prog_str) - 1] = '\0';
|
||||||
jsonw_string(d->jw, prog_str);
|
jsonw_string(d->jw, prog_str);
|
||||||
btf__free(prog_btf);
|
btf__free(prog_btf);
|
||||||
free(prog_info);
|
if (prog_fd >= 0)
|
||||||
|
close(prog_fd);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -100,6 +100,76 @@ static enum bpf_attach_type parse_attach_type(const char *str)
|
||||||
return __MAX_BPF_ATTACH_TYPE;
|
return __MAX_BPF_ATTACH_TYPE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int prep_prog_info(struct bpf_prog_info *const info, enum dump_mode mode,
|
||||||
|
void **info_data, size_t *const info_data_sz)
|
||||||
|
{
|
||||||
|
struct bpf_prog_info holder = {};
|
||||||
|
size_t needed = 0;
|
||||||
|
void *ptr;
|
||||||
|
|
||||||
|
if (mode == DUMP_JITED) {
|
||||||
|
holder.jited_prog_len = info->jited_prog_len;
|
||||||
|
needed += info->jited_prog_len;
|
||||||
|
} else {
|
||||||
|
holder.xlated_prog_len = info->xlated_prog_len;
|
||||||
|
needed += info->xlated_prog_len;
|
||||||
|
}
|
||||||
|
|
||||||
|
holder.nr_jited_ksyms = info->nr_jited_ksyms;
|
||||||
|
needed += info->nr_jited_ksyms * sizeof(__u64);
|
||||||
|
|
||||||
|
holder.nr_jited_func_lens = info->nr_jited_func_lens;
|
||||||
|
needed += info->nr_jited_func_lens * sizeof(__u32);
|
||||||
|
|
||||||
|
holder.nr_func_info = info->nr_func_info;
|
||||||
|
holder.func_info_rec_size = info->func_info_rec_size;
|
||||||
|
needed += info->nr_func_info * info->func_info_rec_size;
|
||||||
|
|
||||||
|
holder.nr_line_info = info->nr_line_info;
|
||||||
|
holder.line_info_rec_size = info->line_info_rec_size;
|
||||||
|
needed += info->nr_line_info * info->line_info_rec_size;
|
||||||
|
|
||||||
|
holder.nr_jited_line_info = info->nr_jited_line_info;
|
||||||
|
holder.jited_line_info_rec_size = info->jited_line_info_rec_size;
|
||||||
|
needed += info->nr_jited_line_info * info->jited_line_info_rec_size;
|
||||||
|
|
||||||
|
if (needed > *info_data_sz) {
|
||||||
|
ptr = realloc(*info_data, needed);
|
||||||
|
if (!ptr)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
*info_data = ptr;
|
||||||
|
*info_data_sz = needed;
|
||||||
|
}
|
||||||
|
ptr = *info_data;
|
||||||
|
|
||||||
|
if (mode == DUMP_JITED) {
|
||||||
|
holder.jited_prog_insns = ptr_to_u64(ptr);
|
||||||
|
ptr += holder.jited_prog_len;
|
||||||
|
} else {
|
||||||
|
holder.xlated_prog_insns = ptr_to_u64(ptr);
|
||||||
|
ptr += holder.xlated_prog_len;
|
||||||
|
}
|
||||||
|
|
||||||
|
holder.jited_ksyms = ptr_to_u64(ptr);
|
||||||
|
ptr += holder.nr_jited_ksyms * sizeof(__u64);
|
||||||
|
|
||||||
|
holder.jited_func_lens = ptr_to_u64(ptr);
|
||||||
|
ptr += holder.nr_jited_func_lens * sizeof(__u32);
|
||||||
|
|
||||||
|
holder.func_info = ptr_to_u64(ptr);
|
||||||
|
ptr += holder.nr_func_info * holder.func_info_rec_size;
|
||||||
|
|
||||||
|
holder.line_info = ptr_to_u64(ptr);
|
||||||
|
ptr += holder.nr_line_info * holder.line_info_rec_size;
|
||||||
|
|
||||||
|
holder.jited_line_info = ptr_to_u64(ptr);
|
||||||
|
ptr += holder.nr_jited_line_info * holder.jited_line_info_rec_size;
|
||||||
|
|
||||||
|
*info = holder;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static void print_boot_time(__u64 nsecs, char *buf, unsigned int size)
|
static void print_boot_time(__u64 nsecs, char *buf, unsigned int size)
|
||||||
{
|
{
|
||||||
struct timespec real_time_ts, boot_time_ts;
|
struct timespec real_time_ts, boot_time_ts;
|
||||||
|
@ -803,16 +873,18 @@ prog_dump(struct bpf_prog_info *info, enum dump_mode mode,
|
||||||
|
|
||||||
static int do_dump(int argc, char **argv)
|
static int do_dump(int argc, char **argv)
|
||||||
{
|
{
|
||||||
struct bpf_prog_info_linear *info_linear;
|
struct bpf_prog_info info;
|
||||||
|
__u32 info_len = sizeof(info);
|
||||||
|
size_t info_data_sz = 0;
|
||||||
|
void *info_data = NULL;
|
||||||
char *filepath = NULL;
|
char *filepath = NULL;
|
||||||
bool opcodes = false;
|
bool opcodes = false;
|
||||||
bool visual = false;
|
bool visual = false;
|
||||||
enum dump_mode mode;
|
enum dump_mode mode;
|
||||||
bool linum = false;
|
bool linum = false;
|
||||||
int *fds = NULL;
|
|
||||||
int nb_fds, i = 0;
|
int nb_fds, i = 0;
|
||||||
|
int *fds = NULL;
|
||||||
int err = -1;
|
int err = -1;
|
||||||
__u64 arrays;
|
|
||||||
|
|
||||||
if (is_prefix(*argv, "jited")) {
|
if (is_prefix(*argv, "jited")) {
|
||||||
if (disasm_init())
|
if (disasm_init())
|
||||||
|
@ -872,43 +944,44 @@ static int do_dump(int argc, char **argv)
|
||||||
goto exit_close;
|
goto exit_close;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mode == DUMP_JITED)
|
|
||||||
arrays = 1UL << BPF_PROG_INFO_JITED_INSNS;
|
|
||||||
else
|
|
||||||
arrays = 1UL << BPF_PROG_INFO_XLATED_INSNS;
|
|
||||||
|
|
||||||
arrays |= 1UL << BPF_PROG_INFO_JITED_KSYMS;
|
|
||||||
arrays |= 1UL << BPF_PROG_INFO_JITED_FUNC_LENS;
|
|
||||||
arrays |= 1UL << BPF_PROG_INFO_FUNC_INFO;
|
|
||||||
arrays |= 1UL << BPF_PROG_INFO_LINE_INFO;
|
|
||||||
arrays |= 1UL << BPF_PROG_INFO_JITED_LINE_INFO;
|
|
||||||
|
|
||||||
if (json_output && nb_fds > 1)
|
if (json_output && nb_fds > 1)
|
||||||
jsonw_start_array(json_wtr); /* root array */
|
jsonw_start_array(json_wtr); /* root array */
|
||||||
for (i = 0; i < nb_fds; i++) {
|
for (i = 0; i < nb_fds; i++) {
|
||||||
info_linear = bpf_program__get_prog_info_linear(fds[i], arrays);
|
memset(&info, 0, sizeof(info));
|
||||||
if (IS_ERR_OR_NULL(info_linear)) {
|
|
||||||
|
err = bpf_obj_get_info_by_fd(fds[i], &info, &info_len);
|
||||||
|
if (err) {
|
||||||
|
p_err("can't get prog info: %s", strerror(errno));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
err = prep_prog_info(&info, mode, &info_data, &info_data_sz);
|
||||||
|
if (err) {
|
||||||
|
p_err("can't grow prog info_data");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
err = bpf_obj_get_info_by_fd(fds[i], &info, &info_len);
|
||||||
|
if (err) {
|
||||||
p_err("can't get prog info: %s", strerror(errno));
|
p_err("can't get prog info: %s", strerror(errno));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (json_output && nb_fds > 1) {
|
if (json_output && nb_fds > 1) {
|
||||||
jsonw_start_object(json_wtr); /* prog object */
|
jsonw_start_object(json_wtr); /* prog object */
|
||||||
print_prog_header_json(&info_linear->info);
|
print_prog_header_json(&info);
|
||||||
jsonw_name(json_wtr, "insns");
|
jsonw_name(json_wtr, "insns");
|
||||||
} else if (nb_fds > 1) {
|
} else if (nb_fds > 1) {
|
||||||
print_prog_header_plain(&info_linear->info);
|
print_prog_header_plain(&info);
|
||||||
}
|
}
|
||||||
|
|
||||||
err = prog_dump(&info_linear->info, mode, filepath, opcodes,
|
err = prog_dump(&info, mode, filepath, opcodes, visual, linum);
|
||||||
visual, linum);
|
|
||||||
|
|
||||||
if (json_output && nb_fds > 1)
|
if (json_output && nb_fds > 1)
|
||||||
jsonw_end_object(json_wtr); /* prog object */
|
jsonw_end_object(json_wtr); /* prog object */
|
||||||
else if (i != nb_fds - 1 && nb_fds > 1)
|
else if (i != nb_fds - 1 && nb_fds > 1)
|
||||||
printf("\n");
|
printf("\n");
|
||||||
|
|
||||||
free(info_linear);
|
|
||||||
if (err)
|
if (err)
|
||||||
break;
|
break;
|
||||||
close(fds[i]);
|
close(fds[i]);
|
||||||
|
@ -920,6 +993,7 @@ exit_close:
|
||||||
for (; i < nb_fds; i++)
|
for (; i < nb_fds; i++)
|
||||||
close(fds[i]);
|
close(fds[i]);
|
||||||
exit_free:
|
exit_free:
|
||||||
|
free(info_data);
|
||||||
free(fds);
|
free(fds);
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
@ -2016,41 +2090,58 @@ static void profile_print_readings(void)
|
||||||
|
|
||||||
static char *profile_target_name(int tgt_fd)
|
static char *profile_target_name(int tgt_fd)
|
||||||
{
|
{
|
||||||
struct bpf_prog_info_linear *info_linear;
|
struct bpf_func_info func_info;
|
||||||
struct bpf_func_info *func_info;
|
struct bpf_prog_info info = {};
|
||||||
|
__u32 info_len = sizeof(info);
|
||||||
const struct btf_type *t;
|
const struct btf_type *t;
|
||||||
|
__u32 func_info_rec_size;
|
||||||
struct btf *btf = NULL;
|
struct btf *btf = NULL;
|
||||||
char *name = NULL;
|
char *name = NULL;
|
||||||
|
int err;
|
||||||
|
|
||||||
info_linear = bpf_program__get_prog_info_linear(
|
err = bpf_obj_get_info_by_fd(tgt_fd, &info, &info_len);
|
||||||
tgt_fd, 1UL << BPF_PROG_INFO_FUNC_INFO);
|
if (err) {
|
||||||
if (IS_ERR_OR_NULL(info_linear)) {
|
p_err("failed to bpf_obj_get_info_by_fd for prog FD %d", tgt_fd);
|
||||||
p_err("failed to get info_linear for prog FD %d", tgt_fd);
|
goto out;
|
||||||
return NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (info_linear->info.btf_id == 0) {
|
if (info.btf_id == 0) {
|
||||||
p_err("prog FD %d doesn't have valid btf", tgt_fd);
|
p_err("prog FD %d doesn't have valid btf", tgt_fd);
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
btf = btf__load_from_kernel_by_id(info_linear->info.btf_id);
|
func_info_rec_size = info.func_info_rec_size;
|
||||||
|
if (info.nr_func_info == 0) {
|
||||||
|
p_err("bpf_obj_get_info_by_fd for prog FD %d found 0 func_info", tgt_fd);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
memset(&info, 0, sizeof(info));
|
||||||
|
info.nr_func_info = 1;
|
||||||
|
info.func_info_rec_size = func_info_rec_size;
|
||||||
|
info.func_info = ptr_to_u64(&func_info);
|
||||||
|
|
||||||
|
err = bpf_obj_get_info_by_fd(tgt_fd, &info, &info_len);
|
||||||
|
if (err) {
|
||||||
|
p_err("failed to get func_info for prog FD %d", tgt_fd);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
btf = btf__load_from_kernel_by_id(info.btf_id);
|
||||||
if (libbpf_get_error(btf)) {
|
if (libbpf_get_error(btf)) {
|
||||||
p_err("failed to load btf for prog FD %d", tgt_fd);
|
p_err("failed to load btf for prog FD %d", tgt_fd);
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
func_info = u64_to_ptr(info_linear->info.func_info);
|
t = btf__type_by_id(btf, func_info.type_id);
|
||||||
t = btf__type_by_id(btf, func_info[0].type_id);
|
|
||||||
if (!t) {
|
if (!t) {
|
||||||
p_err("btf %d doesn't have type %d",
|
p_err("btf %d doesn't have type %d",
|
||||||
info_linear->info.btf_id, func_info[0].type_id);
|
info.btf_id, func_info.type_id);
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
name = strdup(btf__name_by_offset(btf, t->name_off));
|
name = strdup(btf__name_by_offset(btf, t->name_off));
|
||||||
out:
|
out:
|
||||||
btf__free(btf);
|
btf__free(btf);
|
||||||
free(info_linear);
|
|
||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Загрузка…
Ссылка в новой задаче