diff options
author | Quentin Monnet <quentin.monnet@netronome.com> | 2017-10-23 12:24:10 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2017-10-23 20:25:08 -0400 |
commit | f05e2c32f715985f54265b1e237b5cce1b576c71 (patch) | |
tree | e2038a3c68b105bf6e58bb58d6c3d995a0bafe70 /tools/bpf/bpftool/prog.c | |
parent | 107f041212c1dfd3bf72b01c0d2013e98b6f32c2 (diff) |
tools: bpftool: add JSON output for `bpftool prog dump xlated *` command
Add a new printing function to dump translated eBPF instructions as
JSON. As for plain output, opcodes are printed only on request (when
`opcodes` is provided on the command line).
The disassembled output is generated by the same code that is used by
the kernel verifier.
Example output:
$ bpftool --json --pretty prog dump xlated id 1
[{
"disasm": "(bf) r6 = r1"
},{
"disasm": "(61) r7 = *(u32 *)(r6 +16)"
},{
"disasm": "(95) exit"
}
]
$ bpftool --json --pretty prog dump xlated id 1 opcodes
[{
"disasm": "(bf) r6 = r1",
"opcodes": {
"code": "0xbf",
"src_reg": "0x1",
"dst_reg": "0x6",
"off": ["0x00","0x00"
],
"imm": ["0x00","0x00","0x00","0x00"
]
}
},{
"disasm": "(61) r7 = *(u32 *)(r6 +16)",
"opcodes": {
"code": "0x61",
"src_reg": "0x6",
"dst_reg": "0x7",
"off": ["0x10","0x00"
],
"imm": ["0x00","0x00","0x00","0x00"
]
}
},{
"disasm": "(95) exit",
"opcodes": {
"code": "0x95",
"src_reg": "0x0",
"dst_reg": "0x0",
"off": ["0x00","0x00"
],
"imm": ["0x00","0x00","0x00","0x00"
]
}
}
]
Signed-off-by: Quentin Monnet <quentin.monnet@netronome.com>
Acked-by: Daniel Borkmann <daniel@iogearbox.net>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'tools/bpf/bpftool/prog.c')
-rw-r--r-- | tools/bpf/bpftool/prog.c | 70 |
1 files changed, 68 insertions, 2 deletions
diff --git a/tools/bpf/bpftool/prog.c b/tools/bpf/bpftool/prog.c index f373f2baef5a..43e49799a624 100644 --- a/tools/bpf/bpftool/prog.c +++ b/tools/bpf/bpftool/prog.c | |||
@@ -385,7 +385,7 @@ static void print_insn(struct bpf_verifier_env *env, const char *fmt, ...) | |||
385 | va_end(args); | 385 | va_end(args); |
386 | } | 386 | } |
387 | 387 | ||
388 | static void dump_xlated(void *buf, unsigned int len, bool opcodes) | 388 | static void dump_xlated_plain(void *buf, unsigned int len, bool opcodes) |
389 | { | 389 | { |
390 | struct bpf_insn *insn = buf; | 390 | struct bpf_insn *insn = buf; |
391 | bool double_insn = false; | 391 | bool double_insn = false; |
@@ -414,6 +414,69 @@ static void dump_xlated(void *buf, unsigned int len, bool opcodes) | |||
414 | } | 414 | } |
415 | } | 415 | } |
416 | 416 | ||
417 | static void print_insn_json(struct bpf_verifier_env *env, const char *fmt, ...) | ||
418 | { | ||
419 | unsigned int l = strlen(fmt); | ||
420 | char chomped_fmt[l]; | ||
421 | va_list args; | ||
422 | |||
423 | va_start(args, fmt); | ||
424 | if (l > 0) { | ||
425 | strncpy(chomped_fmt, fmt, l - 1); | ||
426 | chomped_fmt[l - 1] = '\0'; | ||
427 | } | ||
428 | jsonw_vprintf_enquote(json_wtr, chomped_fmt, args); | ||
429 | va_end(args); | ||
430 | } | ||
431 | |||
432 | static void dump_xlated_json(void *buf, unsigned int len, bool opcodes) | ||
433 | { | ||
434 | struct bpf_insn *insn = buf; | ||
435 | bool double_insn = false; | ||
436 | unsigned int i; | ||
437 | |||
438 | jsonw_start_array(json_wtr); | ||
439 | for (i = 0; i < len / sizeof(*insn); i++) { | ||
440 | if (double_insn) { | ||
441 | double_insn = false; | ||
442 | continue; | ||
443 | } | ||
444 | double_insn = insn[i].code == (BPF_LD | BPF_IMM | BPF_DW); | ||
445 | |||
446 | jsonw_start_object(json_wtr); | ||
447 | jsonw_name(json_wtr, "disasm"); | ||
448 | print_bpf_insn(print_insn_json, NULL, insn + i, true); | ||
449 | |||
450 | if (opcodes) { | ||
451 | jsonw_name(json_wtr, "opcodes"); | ||
452 | jsonw_start_object(json_wtr); | ||
453 | |||
454 | jsonw_name(json_wtr, "code"); | ||
455 | jsonw_printf(json_wtr, "\"0x%02hhx\"", insn[i].code); | ||
456 | |||
457 | jsonw_name(json_wtr, "src_reg"); | ||
458 | jsonw_printf(json_wtr, "\"0x%hhx\"", insn[i].src_reg); | ||
459 | |||
460 | jsonw_name(json_wtr, "dst_reg"); | ||
461 | jsonw_printf(json_wtr, "\"0x%hhx\"", insn[i].dst_reg); | ||
462 | |||
463 | jsonw_name(json_wtr, "off"); | ||
464 | print_hex_data_json((uint8_t *)(&insn[i].off), 2); | ||
465 | |||
466 | jsonw_name(json_wtr, "imm"); | ||
467 | if (double_insn && i < len - 1) | ||
468 | print_hex_data_json((uint8_t *)(&insn[i].imm), | ||
469 | 12); | ||
470 | else | ||
471 | print_hex_data_json((uint8_t *)(&insn[i].imm), | ||
472 | 4); | ||
473 | jsonw_end_object(json_wtr); | ||
474 | } | ||
475 | jsonw_end_object(json_wtr); | ||
476 | } | ||
477 | jsonw_end_array(json_wtr); | ||
478 | } | ||
479 | |||
417 | static int do_dump(int argc, char **argv) | 480 | static int do_dump(int argc, char **argv) |
418 | { | 481 | { |
419 | struct bpf_prog_info info = {}; | 482 | struct bpf_prog_info info = {}; |
@@ -523,7 +586,10 @@ static int do_dump(int argc, char **argv) | |||
523 | if (member_len == &info.jited_prog_len) | 586 | if (member_len == &info.jited_prog_len) |
524 | disasm_print_insn(buf, *member_len, opcodes); | 587 | disasm_print_insn(buf, *member_len, opcodes); |
525 | else | 588 | else |
526 | dump_xlated(buf, *member_len, opcodes); | 589 | if (json_output) |
590 | dump_xlated_json(buf, *member_len, opcodes); | ||
591 | else | ||
592 | dump_xlated_plain(buf, *member_len, opcodes); | ||
527 | } | 593 | } |
528 | 594 | ||
529 | free(buf); | 595 | free(buf); |