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 | |
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')
-rw-r--r-- | tools/bpf/bpftool/common.c | 10 | ||||
-rw-r--r-- | tools/bpf/bpftool/json_writer.c | 8 | ||||
-rw-r--r-- | tools/bpf/bpftool/json_writer.h | 2 | ||||
-rw-r--r-- | tools/bpf/bpftool/main.h | 1 | ||||
-rw-r--r-- | tools/bpf/bpftool/prog.c | 70 |
5 files changed, 89 insertions, 2 deletions
diff --git a/tools/bpf/bpftool/common.c b/tools/bpf/bpftool/common.c index df8396a0c400..e7a756b8ee21 100644 --- a/tools/bpf/bpftool/common.c +++ b/tools/bpf/bpftool/common.c | |||
@@ -214,3 +214,13 @@ char *get_fdinfo(int fd, const char *key) | |||
214 | fclose(fdi); | 214 | fclose(fdi); |
215 | return NULL; | 215 | return NULL; |
216 | } | 216 | } |
217 | |||
218 | void print_hex_data_json(uint8_t *data, size_t len) | ||
219 | { | ||
220 | unsigned int i; | ||
221 | |||
222 | jsonw_start_array(json_wtr); | ||
223 | for (i = 0; i < len; i++) | ||
224 | jsonw_printf(json_wtr, "\"0x%02hhx\"", data[i]); | ||
225 | jsonw_end_array(json_wtr); | ||
226 | } | ||
diff --git a/tools/bpf/bpftool/json_writer.c b/tools/bpf/bpftool/json_writer.c index 6b77d288cce2..c6eef76322ae 100644 --- a/tools/bpf/bpftool/json_writer.c +++ b/tools/bpf/bpftool/json_writer.c | |||
@@ -156,6 +156,14 @@ void jsonw_name(json_writer_t *self, const char *name) | |||
156 | putc(' ', self->out); | 156 | putc(' ', self->out); |
157 | } | 157 | } |
158 | 158 | ||
159 | void jsonw_vprintf_enquote(json_writer_t *self, const char *fmt, va_list ap) | ||
160 | { | ||
161 | jsonw_eor(self); | ||
162 | putc('"', self->out); | ||
163 | vfprintf(self->out, fmt, ap); | ||
164 | putc('"', self->out); | ||
165 | } | ||
166 | |||
159 | void jsonw_printf(json_writer_t *self, const char *fmt, ...) | 167 | void jsonw_printf(json_writer_t *self, const char *fmt, ...) |
160 | { | 168 | { |
161 | va_list ap; | 169 | va_list ap; |
diff --git a/tools/bpf/bpftool/json_writer.h b/tools/bpf/bpftool/json_writer.h index 1516aafba59d..0fa2fb1b6351 100644 --- a/tools/bpf/bpftool/json_writer.h +++ b/tools/bpf/bpftool/json_writer.h | |||
@@ -17,6 +17,7 @@ | |||
17 | 17 | ||
18 | #include <stdbool.h> | 18 | #include <stdbool.h> |
19 | #include <stdint.h> | 19 | #include <stdint.h> |
20 | #include <stdarg.h> | ||
20 | 21 | ||
21 | /* Opaque class structure */ | 22 | /* Opaque class structure */ |
22 | typedef struct json_writer json_writer_t; | 23 | typedef struct json_writer json_writer_t; |
@@ -33,6 +34,7 @@ void jsonw_pretty(json_writer_t *self, bool on); | |||
33 | void jsonw_name(json_writer_t *self, const char *name); | 34 | void jsonw_name(json_writer_t *self, const char *name); |
34 | 35 | ||
35 | /* Add value */ | 36 | /* Add value */ |
37 | void jsonw_vprintf_enquote(json_writer_t *self, const char *fmt, va_list ap); | ||
36 | void jsonw_printf(json_writer_t *self, const char *fmt, ...); | 38 | void jsonw_printf(json_writer_t *self, const char *fmt, ...); |
37 | void jsonw_string(json_writer_t *self, const char *value); | 39 | void jsonw_string(json_writer_t *self, const char *value); |
38 | void jsonw_bool(json_writer_t *self, bool value); | 40 | void jsonw_bool(json_writer_t *self, bool value); |
diff --git a/tools/bpf/bpftool/main.h b/tools/bpf/bpftool/main.h index 15927fc9fb31..693fc9710be1 100644 --- a/tools/bpf/bpftool/main.h +++ b/tools/bpf/bpftool/main.h | |||
@@ -95,5 +95,6 @@ int do_map(int argc, char **arg); | |||
95 | int prog_parse_fd(int *argc, char ***argv); | 95 | int prog_parse_fd(int *argc, char ***argv); |
96 | 96 | ||
97 | void disasm_print_insn(unsigned char *image, ssize_t len, int opcodes); | 97 | void disasm_print_insn(unsigned char *image, ssize_t len, int opcodes); |
98 | void print_hex_data_json(uint8_t *data, size_t len); | ||
98 | 99 | ||
99 | #endif | 100 | #endif |
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); |