aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorYonghong Song <yhs@fb.com>2018-11-19 18:29:21 -0500
committerAlexei Starovoitov <ast@kernel.org>2018-11-20 13:54:39 -0500
commit254471e57a86b8dc1a2cc19848e99f5d7c0558f4 (patch)
tree1892de2dc8c361322df68d459f0e63e59d901450
parent999d82cbc04416cc7f2b5cb6daab947c16f0fd3a (diff)
tools/bpf: bpftool: add support for func types
This patch added support to print function signature if btf func_info is available. Note that ksym now uses function name instead of prog_name as prog_name has a limit of 16 bytes including ending '\0'. The following is a sample output for selftests test_btf with file test_btf_haskv.o for translated insns and jited insns respectively. $ bpftool prog dump xlated id 1 int _dummy_tracepoint(struct dummy_tracepoint_args * arg): 0: (85) call pc+2#bpf_prog_2dcecc18072623fc_test_long_fname_1 1: (b7) r0 = 0 2: (95) exit int test_long_fname_1(struct dummy_tracepoint_args * arg): 3: (85) call pc+1#bpf_prog_89d64e4abf0f0126_test_long_fname_2 4: (95) exit int test_long_fname_2(struct dummy_tracepoint_args * arg): 5: (b7) r2 = 0 6: (63) *(u32 *)(r10 -4) = r2 7: (79) r1 = *(u64 *)(r1 +8) ... 22: (07) r1 += 1 23: (63) *(u32 *)(r0 +4) = r1 24: (95) exit $ bpftool prog dump jited id 1 int _dummy_tracepoint(struct dummy_tracepoint_args * arg): bpf_prog_b07ccb89267cf242__dummy_tracepoint: 0: push %rbp 1: mov %rsp,%rbp ...... 3c: add $0x28,%rbp 40: leaveq 41: retq int test_long_fname_1(struct dummy_tracepoint_args * arg): bpf_prog_2dcecc18072623fc_test_long_fname_1: 0: push %rbp 1: mov %rsp,%rbp ...... 3a: add $0x28,%rbp 3e: leaveq 3f: retq int test_long_fname_2(struct dummy_tracepoint_args * arg): bpf_prog_89d64e4abf0f0126_test_long_fname_2: 0: push %rbp 1: mov %rsp,%rbp ...... 80: add $0x28,%rbp 84: leaveq 85: retq Signed-off-by: Yonghong Song <yhs@fb.com> Signed-off-by: Martin KaFai Lau <kafai@fb.com> Signed-off-by: Alexei Starovoitov <ast@kernel.org>
-rw-r--r--tools/bpf/bpftool/btf_dumper.c136
-rw-r--r--tools/bpf/bpftool/main.h2
-rw-r--r--tools/bpf/bpftool/prog.c56
-rw-r--r--tools/bpf/bpftool/xlated_dumper.c33
-rw-r--r--tools/bpf/bpftool/xlated_dumper.h3
5 files changed, 230 insertions, 0 deletions
diff --git a/tools/bpf/bpftool/btf_dumper.c b/tools/bpf/bpftool/btf_dumper.c
index 55bc512a1831..c3fd3a7cb787 100644
--- a/tools/bpf/bpftool/btf_dumper.c
+++ b/tools/bpf/bpftool/btf_dumper.c
@@ -249,3 +249,139 @@ int btf_dumper_type(const struct btf_dumper *d, __u32 type_id,
249{ 249{
250 return btf_dumper_do_type(d, type_id, 0, data); 250 return btf_dumper_do_type(d, type_id, 0, data);
251} 251}
252
253#define BTF_PRINT_ARG(...) \
254 do { \
255 pos += snprintf(func_sig + pos, size - pos, \
256 __VA_ARGS__); \
257 if (pos >= size) \
258 return -1; \
259 } while (0)
260#define BTF_PRINT_TYPE(type) \
261 do { \
262 pos = __btf_dumper_type_only(btf, type, func_sig, \
263 pos, size); \
264 if (pos == -1) \
265 return -1; \
266 } while (0)
267
268static int btf_dump_func(const struct btf *btf, char *func_sig,
269 const struct btf_type *func_proto,
270 const struct btf_type *func, int pos, int size);
271
272static int __btf_dumper_type_only(const struct btf *btf, __u32 type_id,
273 char *func_sig, int pos, int size)
274{
275 const struct btf_type *proto_type;
276 const struct btf_array *array;
277 const struct btf_type *t;
278
279 if (!type_id) {
280 BTF_PRINT_ARG("void ");
281 return pos;
282 }
283
284 t = btf__type_by_id(btf, type_id);
285
286 switch (BTF_INFO_KIND(t->info)) {
287 case BTF_KIND_INT:
288 BTF_PRINT_ARG("%s ", btf__name_by_offset(btf, t->name_off));
289 break;
290 case BTF_KIND_STRUCT:
291 BTF_PRINT_ARG("struct %s ",
292 btf__name_by_offset(btf, t->name_off));
293 break;
294 case BTF_KIND_UNION:
295 BTF_PRINT_ARG("union %s ",
296 btf__name_by_offset(btf, t->name_off));
297 break;
298 case BTF_KIND_ENUM:
299 BTF_PRINT_ARG("enum %s ",
300 btf__name_by_offset(btf, t->name_off));
301 break;
302 case BTF_KIND_ARRAY:
303 array = (struct btf_array *)(t + 1);
304 BTF_PRINT_TYPE(array->type);
305 BTF_PRINT_ARG("[%d]", array->nelems);
306 break;
307 case BTF_KIND_PTR:
308 BTF_PRINT_TYPE(t->type);
309 BTF_PRINT_ARG("* ");
310 break;
311 case BTF_KIND_UNKN:
312 case BTF_KIND_FWD:
313 case BTF_KIND_TYPEDEF:
314 return -1;
315 case BTF_KIND_VOLATILE:
316 BTF_PRINT_ARG("volatile ");
317 BTF_PRINT_TYPE(t->type);
318 break;
319 case BTF_KIND_CONST:
320 BTF_PRINT_ARG("const ");
321 BTF_PRINT_TYPE(t->type);
322 break;
323 case BTF_KIND_RESTRICT:
324 BTF_PRINT_ARG("restrict ");
325 BTF_PRINT_TYPE(t->type);
326 break;
327 case BTF_KIND_FUNC_PROTO:
328 pos = btf_dump_func(btf, func_sig, t, NULL, pos, size);
329 if (pos == -1)
330 return -1;
331 break;
332 case BTF_KIND_FUNC:
333 proto_type = btf__type_by_id(btf, t->type);
334 pos = btf_dump_func(btf, func_sig, proto_type, t, pos, size);
335 if (pos == -1)
336 return -1;
337 break;
338 default:
339 return -1;
340 }
341
342 return pos;
343}
344
345static int btf_dump_func(const struct btf *btf, char *func_sig,
346 const struct btf_type *func_proto,
347 const struct btf_type *func, int pos, int size)
348{
349 int i, vlen;
350
351 BTF_PRINT_TYPE(func_proto->type);
352 if (func)
353 BTF_PRINT_ARG("%s(", btf__name_by_offset(btf, func->name_off));
354 else
355 BTF_PRINT_ARG("(");
356 vlen = BTF_INFO_VLEN(func_proto->info);
357 for (i = 0; i < vlen; i++) {
358 struct btf_param *arg = &((struct btf_param *)(func_proto + 1))[i];
359
360 if (i)
361 BTF_PRINT_ARG(", ");
362 if (arg->type) {
363 BTF_PRINT_TYPE(arg->type);
364 BTF_PRINT_ARG("%s",
365 btf__name_by_offset(btf, arg->name_off));
366 } else {
367 BTF_PRINT_ARG("...");
368 }
369 }
370 BTF_PRINT_ARG(")");
371
372 return pos;
373}
374
375void btf_dumper_type_only(const struct btf *btf, __u32 type_id, char *func_sig,
376 int size)
377{
378 int err;
379
380 func_sig[0] = '\0';
381 if (!btf)
382 return;
383
384 err = __btf_dumper_type_only(btf, type_id, func_sig, 0, size);
385 if (err < 0)
386 func_sig[0] = '\0';
387}
diff --git a/tools/bpf/bpftool/main.h b/tools/bpf/bpftool/main.h
index 10c6c16fae29..3e8979567cf1 100644
--- a/tools/bpf/bpftool/main.h
+++ b/tools/bpf/bpftool/main.h
@@ -187,6 +187,8 @@ struct btf_dumper {
187 */ 187 */
188int btf_dumper_type(const struct btf_dumper *d, __u32 type_id, 188int btf_dumper_type(const struct btf_dumper *d, __u32 type_id,
189 const void *data); 189 const void *data);
190void btf_dumper_type_only(const struct btf *btf, __u32 func_type_id,
191 char *func_only, int size);
190 192
191struct nlattr; 193struct nlattr;
192struct ifinfomsg; 194struct ifinfomsg;
diff --git a/tools/bpf/bpftool/prog.c b/tools/bpf/bpftool/prog.c
index c176e1aa66fe..37b1daf19da6 100644
--- a/tools/bpf/bpftool/prog.c
+++ b/tools/bpf/bpftool/prog.c
@@ -47,6 +47,7 @@
47#include <linux/err.h> 47#include <linux/err.h>
48 48
49#include <bpf.h> 49#include <bpf.h>
50#include <btf.h>
50#include <libbpf.h> 51#include <libbpf.h>
51 52
52#include "cfg.h" 53#include "cfg.h"
@@ -451,14 +452,19 @@ static int do_dump(int argc, char **argv)
451 struct bpf_prog_info info = {}; 452 struct bpf_prog_info info = {};
452 unsigned int *func_lens = NULL; 453 unsigned int *func_lens = NULL;
453 const char *disasm_opt = NULL; 454 const char *disasm_opt = NULL;
455 unsigned int finfo_rec_size;
454 unsigned int nr_func_ksyms; 456 unsigned int nr_func_ksyms;
455 unsigned int nr_func_lens; 457 unsigned int nr_func_lens;
456 struct dump_data dd = {}; 458 struct dump_data dd = {};
457 __u32 len = sizeof(info); 459 __u32 len = sizeof(info);
460 struct btf *btf = NULL;
461 void *func_info = NULL;
462 unsigned int finfo_cnt;
458 unsigned int buf_size; 463 unsigned int buf_size;
459 char *filepath = NULL; 464 char *filepath = NULL;
460 bool opcodes = false; 465 bool opcodes = false;
461 bool visual = false; 466 bool visual = false;
467 char func_sig[1024];
462 unsigned char *buf; 468 unsigned char *buf;
463 __u32 *member_len; 469 __u32 *member_len;
464 __u64 *member_ptr; 470 __u64 *member_ptr;
@@ -551,6 +557,17 @@ static int do_dump(int argc, char **argv)
551 } 557 }
552 } 558 }
553 559
560 finfo_cnt = info.func_info_cnt;
561 finfo_rec_size = info.func_info_rec_size;
562 if (finfo_cnt && finfo_rec_size) {
563 func_info = malloc(finfo_cnt * finfo_rec_size);
564 if (!func_info) {
565 p_err("mem alloc failed");
566 close(fd);
567 goto err_free;
568 }
569 }
570
554 memset(&info, 0, sizeof(info)); 571 memset(&info, 0, sizeof(info));
555 572
556 *member_ptr = ptr_to_u64(buf); 573 *member_ptr = ptr_to_u64(buf);
@@ -559,6 +576,9 @@ static int do_dump(int argc, char **argv)
559 info.nr_jited_ksyms = nr_func_ksyms; 576 info.nr_jited_ksyms = nr_func_ksyms;
560 info.jited_func_lens = ptr_to_u64(func_lens); 577 info.jited_func_lens = ptr_to_u64(func_lens);
561 info.nr_jited_func_lens = nr_func_lens; 578 info.nr_jited_func_lens = nr_func_lens;
579 info.func_info_cnt = finfo_cnt;
580 info.func_info_rec_size = finfo_rec_size;
581 info.func_info = ptr_to_u64(func_info);
562 582
563 err = bpf_obj_get_info_by_fd(fd, &info, &len); 583 err = bpf_obj_get_info_by_fd(fd, &info, &len);
564 close(fd); 584 close(fd);
@@ -582,6 +602,18 @@ static int do_dump(int argc, char **argv)
582 goto err_free; 602 goto err_free;
583 } 603 }
584 604
605 if (info.func_info_cnt != finfo_cnt) {
606 p_err("incorrect func_info_cnt %d vs. expected %d",
607 info.func_info_cnt, finfo_cnt);
608 goto err_free;
609 }
610
611 if (info.func_info_rec_size != finfo_rec_size) {
612 p_err("incorrect func_info_rec_size %d vs. expected %d",
613 info.func_info_rec_size, finfo_rec_size);
614 goto err_free;
615 }
616
585 if ((member_len == &info.jited_prog_len && 617 if ((member_len == &info.jited_prog_len &&
586 info.jited_prog_insns == 0) || 618 info.jited_prog_insns == 0) ||
587 (member_len == &info.xlated_prog_len && 619 (member_len == &info.xlated_prog_len &&
@@ -590,6 +622,11 @@ static int do_dump(int argc, char **argv)
590 goto err_free; 622 goto err_free;
591 } 623 }
592 624
625 if (info.btf_id && btf_get_from_id(info.btf_id, &btf)) {
626 p_err("failed to get btf");
627 goto err_free;
628 }
629
593 if (filepath) { 630 if (filepath) {
594 fd = open(filepath, O_WRONLY | O_CREAT | O_TRUNC, 0600); 631 fd = open(filepath, O_WRONLY | O_CREAT | O_TRUNC, 0600);
595 if (fd < 0) { 632 if (fd < 0) {
@@ -622,6 +659,7 @@ static int do_dump(int argc, char **argv)
622 659
623 if (info.nr_jited_func_lens && info.jited_func_lens) { 660 if (info.nr_jited_func_lens && info.jited_func_lens) {
624 struct kernel_sym *sym = NULL; 661 struct kernel_sym *sym = NULL;
662 struct bpf_func_info *record;
625 char sym_name[SYM_MAX_NAME]; 663 char sym_name[SYM_MAX_NAME];
626 unsigned char *img = buf; 664 unsigned char *img = buf;
627 __u64 *ksyms = NULL; 665 __u64 *ksyms = NULL;
@@ -648,12 +686,25 @@ static int do_dump(int argc, char **argv)
648 strcpy(sym_name, "unknown"); 686 strcpy(sym_name, "unknown");
649 } 687 }
650 688
689 if (func_info) {
690 record = func_info + i * finfo_rec_size;
691 btf_dumper_type_only(btf, record->type_id,
692 func_sig,
693 sizeof(func_sig));
694 }
695
651 if (json_output) { 696 if (json_output) {
652 jsonw_start_object(json_wtr); 697 jsonw_start_object(json_wtr);
698 if (func_info && func_sig[0] != '\0') {
699 jsonw_name(json_wtr, "proto");
700 jsonw_string(json_wtr, func_sig);
701 }
653 jsonw_name(json_wtr, "name"); 702 jsonw_name(json_wtr, "name");
654 jsonw_string(json_wtr, sym_name); 703 jsonw_string(json_wtr, sym_name);
655 jsonw_name(json_wtr, "insns"); 704 jsonw_name(json_wtr, "insns");
656 } else { 705 } else {
706 if (func_info && func_sig[0] != '\0')
707 printf("%s:\n", func_sig);
657 printf("%s:\n", sym_name); 708 printf("%s:\n", sym_name);
658 } 709 }
659 710
@@ -682,6 +733,9 @@ static int do_dump(int argc, char **argv)
682 kernel_syms_load(&dd); 733 kernel_syms_load(&dd);
683 dd.nr_jited_ksyms = info.nr_jited_ksyms; 734 dd.nr_jited_ksyms = info.nr_jited_ksyms;
684 dd.jited_ksyms = (__u64 *) info.jited_ksyms; 735 dd.jited_ksyms = (__u64 *) info.jited_ksyms;
736 dd.btf = btf;
737 dd.func_info = func_info;
738 dd.finfo_rec_size = finfo_rec_size;
685 739
686 if (json_output) 740 if (json_output)
687 dump_xlated_json(&dd, buf, *member_len, opcodes); 741 dump_xlated_json(&dd, buf, *member_len, opcodes);
@@ -693,12 +747,14 @@ static int do_dump(int argc, char **argv)
693 free(buf); 747 free(buf);
694 free(func_ksyms); 748 free(func_ksyms);
695 free(func_lens); 749 free(func_lens);
750 free(func_info);
696 return 0; 751 return 0;
697 752
698err_free: 753err_free:
699 free(buf); 754 free(buf);
700 free(func_ksyms); 755 free(func_ksyms);
701 free(func_lens); 756 free(func_lens);
757 free(func_info);
702 return -1; 758 return -1;
703} 759}
704 760
diff --git a/tools/bpf/bpftool/xlated_dumper.c b/tools/bpf/bpftool/xlated_dumper.c
index 3284759df98a..e06ac0286a75 100644
--- a/tools/bpf/bpftool/xlated_dumper.c
+++ b/tools/bpf/bpftool/xlated_dumper.c
@@ -242,11 +242,15 @@ void dump_xlated_json(struct dump_data *dd, void *buf, unsigned int len,
242 .cb_imm = print_imm, 242 .cb_imm = print_imm,
243 .private_data = dd, 243 .private_data = dd,
244 }; 244 };
245 struct bpf_func_info *record;
245 struct bpf_insn *insn = buf; 246 struct bpf_insn *insn = buf;
247 struct btf *btf = dd->btf;
246 bool double_insn = false; 248 bool double_insn = false;
249 char func_sig[1024];
247 unsigned int i; 250 unsigned int i;
248 251
249 jsonw_start_array(json_wtr); 252 jsonw_start_array(json_wtr);
253 record = dd->func_info;
250 for (i = 0; i < len / sizeof(*insn); i++) { 254 for (i = 0; i < len / sizeof(*insn); i++) {
251 if (double_insn) { 255 if (double_insn) {
252 double_insn = false; 256 double_insn = false;
@@ -255,6 +259,20 @@ void dump_xlated_json(struct dump_data *dd, void *buf, unsigned int len,
255 double_insn = insn[i].code == (BPF_LD | BPF_IMM | BPF_DW); 259 double_insn = insn[i].code == (BPF_LD | BPF_IMM | BPF_DW);
256 260
257 jsonw_start_object(json_wtr); 261 jsonw_start_object(json_wtr);
262
263 if (btf && record) {
264 if (record->insn_offset == i) {
265 btf_dumper_type_only(btf, record->type_id,
266 func_sig,
267 sizeof(func_sig));
268 if (func_sig[0] != '\0') {
269 jsonw_name(json_wtr, "proto");
270 jsonw_string(json_wtr, func_sig);
271 }
272 record = (void *)record + dd->finfo_rec_size;
273 }
274 }
275
258 jsonw_name(json_wtr, "disasm"); 276 jsonw_name(json_wtr, "disasm");
259 print_bpf_insn(&cbs, insn + i, true); 277 print_bpf_insn(&cbs, insn + i, true);
260 278
@@ -297,16 +315,31 @@ void dump_xlated_plain(struct dump_data *dd, void *buf, unsigned int len,
297 .cb_imm = print_imm, 315 .cb_imm = print_imm,
298 .private_data = dd, 316 .private_data = dd,
299 }; 317 };
318 struct bpf_func_info *record;
300 struct bpf_insn *insn = buf; 319 struct bpf_insn *insn = buf;
320 struct btf *btf = dd->btf;
301 bool double_insn = false; 321 bool double_insn = false;
322 char func_sig[1024];
302 unsigned int i; 323 unsigned int i;
303 324
325 record = dd->func_info;
304 for (i = 0; i < len / sizeof(*insn); i++) { 326 for (i = 0; i < len / sizeof(*insn); i++) {
305 if (double_insn) { 327 if (double_insn) {
306 double_insn = false; 328 double_insn = false;
307 continue; 329 continue;
308 } 330 }
309 331
332 if (btf && record) {
333 if (record->insn_offset == i) {
334 btf_dumper_type_only(btf, record->type_id,
335 func_sig,
336 sizeof(func_sig));
337 if (func_sig[0] != '\0')
338 printf("%s:\n", func_sig);
339 record = (void *)record + dd->finfo_rec_size;
340 }
341 }
342
310 double_insn = insn[i].code == (BPF_LD | BPF_IMM | BPF_DW); 343 double_insn = insn[i].code == (BPF_LD | BPF_IMM | BPF_DW);
311 344
312 printf("% 4d: ", i); 345 printf("% 4d: ", i);
diff --git a/tools/bpf/bpftool/xlated_dumper.h b/tools/bpf/bpftool/xlated_dumper.h
index 33d86e2b369b..aec31723e1e5 100644
--- a/tools/bpf/bpftool/xlated_dumper.h
+++ b/tools/bpf/bpftool/xlated_dumper.h
@@ -51,6 +51,9 @@ struct dump_data {
51 __u32 sym_count; 51 __u32 sym_count;
52 __u64 *jited_ksyms; 52 __u64 *jited_ksyms;
53 __u32 nr_jited_ksyms; 53 __u32 nr_jited_ksyms;
54 struct btf *btf;
55 void *func_info;
56 __u32 finfo_rec_size;
54 char scratch_buff[SYM_MAX_NAME + 8]; 57 char scratch_buff[SYM_MAX_NAME + 8];
55}; 58};
56 59