From patchwork Mon Oct 23 16:24:10 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jakub Kicinski X-Patchwork-Id: 829401 X-Patchwork-Delegate: davem@davemloft.net Return-Path: X-Original-To: patchwork-incoming@ozlabs.org Delivered-To: patchwork-incoming@ozlabs.org Authentication-Results: ozlabs.org; spf=none (mailfrom) smtp.mailfrom=vger.kernel.org (client-ip=209.132.180.67; helo=vger.kernel.org; envelope-from=netdev-owner@vger.kernel.org; receiver=) Authentication-Results: ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=netronome-com.20150623.gappssmtp.com header.i=@netronome-com.20150623.gappssmtp.com header.b="AwfE1wZf"; dkim-atps=neutral Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 3yLMFh4BRtz9t5s for ; Tue, 24 Oct 2017 03:25:28 +1100 (AEDT) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1751735AbdJWQZ0 (ORCPT ); Mon, 23 Oct 2017 12:25:26 -0400 Received: from mail-pf0-f193.google.com ([209.85.192.193]:45742 "EHLO mail-pf0-f193.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751608AbdJWQZB (ORCPT ); Mon, 23 Oct 2017 12:25:01 -0400 Received: by mail-pf0-f193.google.com with SMTP id d28so17482330pfe.2 for ; Mon, 23 Oct 2017 09:25:00 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=netronome-com.20150623.gappssmtp.com; s=20150623; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=2thUwJrMrUWwcxusl6RPFDkkDLgPn2ufAPmNVdWhXZI=; b=AwfE1wZfn6zQBHxc+C5rqzvOODHYJ74h/bI6NCCax1Y9naMMTE0yoKkOmYeiL1QMmR fwzabAnuOP7L5nWuRyGTo5vAxH5d3iSoi7bDG2uURZgKwgEbN6azxYuZzfJX39os0p4x 91dNai1x5xDuYFXcvxAKprRn1uoc9GckjUlAaSRYM4hkBNVc6gapwbZ7vxSwYbOWeccF f2Ep+GpbRoOJTp7e9PNJ0wJRu6ZWQclYpHzrNW/aqhXiv7HSYJc7QiY7obO2xBVvQ7s1 OS1v3rWGwq5Hh2YdhYLG8cNVFcncdv8oYKKSciQwTzdJZIkz0vdIpkTGM6XoaiaUKTNF J5GQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=2thUwJrMrUWwcxusl6RPFDkkDLgPn2ufAPmNVdWhXZI=; b=OoRWSP/q6f0B+0fhGvOdPDDMzilIOvRzKvDk/mQ9o5Nm8ihiGHqQoAXYNmDQgMrtba ZzaNM7UekuoNxwS4WY3XbOQVmhWh26KWQWf99NQJtaOJEOWYzeIFusAFBb32OFCyGEzC gdYYdORHS0n+9Qu5JgXt5GD3+xjUgUR75Er+irIaCzYADZFuJ3bAlS6tsEE1E6XUhD78 uQ7UFQdr0zcZRh+JbjbB3HGmY5SB1qnjhHgMR0QkD2JU5ltJzQyIcOFbGG9ohyEkkMoR ca2wcNz5JJL88FXw00qN2vfBvrTpneuJ0XdiZw4+tATtpP/DBkjoCuoE+MvqEgeFPRK1 gPQQ== X-Gm-Message-State: AMCzsaVX855XQczOJfz7yFPgGbTXRrEaYop31PpUWKlydGaqIKBcaxB0 aarj/lXcFZtniYwsI5S/XO89WLDH X-Google-Smtp-Source: ABhQp+R/EuH8pnuUyMhCJvZBDJSiCQGAmZklKn33Bd5zlH3SiBuLcCGFKsyY6+uEcODwO7ZuKZKszw== X-Received: by 10.101.82.8 with SMTP id o8mr12447690pgp.422.1508775899952; Mon, 23 Oct 2017 09:24:59 -0700 (PDT) Received: from jkicinski-Precision-T1700.netronome.com ([75.53.12.129]) by smtp.gmail.com with ESMTPSA id a19sm13586540pfh.30.2017.10.23.09.24.59 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Mon, 23 Oct 2017 09:24:59 -0700 (PDT) From: Jakub Kicinski To: netdev@vger.kernel.org Cc: oss-drivers@netronome.com, alexei.starovoitov@gmail.com, daniel@iogearbox.net, Quentin Monnet Subject: [PATCH net-next 06/12] tools: bpftool: add JSON output for `bpftool prog dump xlated *` command Date: Mon, 23 Oct 2017 09:24:10 -0700 Message-Id: <20171023162416.32753-7-jakub.kicinski@netronome.com> X-Mailer: git-send-email 2.14.1 In-Reply-To: <20171023162416.32753-1-jakub.kicinski@netronome.com> References: <20171023162416.32753-1-jakub.kicinski@netronome.com> Sender: netdev-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org From: Quentin Monnet 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 Acked-by: Daniel Borkmann --- tools/bpf/bpftool/common.c | 10 ++++++ tools/bpf/bpftool/json_writer.c | 8 +++++ tools/bpf/bpftool/json_writer.h | 2 ++ tools/bpf/bpftool/main.h | 1 + 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) fclose(fdi); return NULL; } + +void print_hex_data_json(uint8_t *data, size_t len) +{ + unsigned int i; + + jsonw_start_array(json_wtr); + for (i = 0; i < len; i++) + jsonw_printf(json_wtr, "\"0x%02hhx\"", data[i]); + jsonw_end_array(json_wtr); +} 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) putc(' ', self->out); } +void jsonw_vprintf_enquote(json_writer_t *self, const char *fmt, va_list ap) +{ + jsonw_eor(self); + putc('"', self->out); + vfprintf(self->out, fmt, ap); + putc('"', self->out); +} + void jsonw_printf(json_writer_t *self, const char *fmt, ...) { 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 @@ #include #include +#include /* Opaque class structure */ typedef struct json_writer json_writer_t; @@ -33,6 +34,7 @@ void jsonw_pretty(json_writer_t *self, bool on); void jsonw_name(json_writer_t *self, const char *name); /* Add value */ +void jsonw_vprintf_enquote(json_writer_t *self, const char *fmt, va_list ap); void jsonw_printf(json_writer_t *self, const char *fmt, ...); void jsonw_string(json_writer_t *self, const char *value); 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); int prog_parse_fd(int *argc, char ***argv); void disasm_print_insn(unsigned char *image, ssize_t len, int opcodes); +void print_hex_data_json(uint8_t *data, size_t len); #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, ...) va_end(args); } -static void dump_xlated(void *buf, unsigned int len, bool opcodes) +static void dump_xlated_plain(void *buf, unsigned int len, bool opcodes) { struct bpf_insn *insn = buf; bool double_insn = false; @@ -414,6 +414,69 @@ static void dump_xlated(void *buf, unsigned int len, bool opcodes) } } +static void print_insn_json(struct bpf_verifier_env *env, const char *fmt, ...) +{ + unsigned int l = strlen(fmt); + char chomped_fmt[l]; + va_list args; + + va_start(args, fmt); + if (l > 0) { + strncpy(chomped_fmt, fmt, l - 1); + chomped_fmt[l - 1] = '\0'; + } + jsonw_vprintf_enquote(json_wtr, chomped_fmt, args); + va_end(args); +} + +static void dump_xlated_json(void *buf, unsigned int len, bool opcodes) +{ + struct bpf_insn *insn = buf; + bool double_insn = false; + unsigned int i; + + jsonw_start_array(json_wtr); + for (i = 0; i < len / sizeof(*insn); i++) { + if (double_insn) { + double_insn = false; + continue; + } + double_insn = insn[i].code == (BPF_LD | BPF_IMM | BPF_DW); + + jsonw_start_object(json_wtr); + jsonw_name(json_wtr, "disasm"); + print_bpf_insn(print_insn_json, NULL, insn + i, true); + + if (opcodes) { + jsonw_name(json_wtr, "opcodes"); + jsonw_start_object(json_wtr); + + jsonw_name(json_wtr, "code"); + jsonw_printf(json_wtr, "\"0x%02hhx\"", insn[i].code); + + jsonw_name(json_wtr, "src_reg"); + jsonw_printf(json_wtr, "\"0x%hhx\"", insn[i].src_reg); + + jsonw_name(json_wtr, "dst_reg"); + jsonw_printf(json_wtr, "\"0x%hhx\"", insn[i].dst_reg); + + jsonw_name(json_wtr, "off"); + print_hex_data_json((uint8_t *)(&insn[i].off), 2); + + jsonw_name(json_wtr, "imm"); + if (double_insn && i < len - 1) + print_hex_data_json((uint8_t *)(&insn[i].imm), + 12); + else + print_hex_data_json((uint8_t *)(&insn[i].imm), + 4); + jsonw_end_object(json_wtr); + } + jsonw_end_object(json_wtr); + } + jsonw_end_array(json_wtr); +} + static int do_dump(int argc, char **argv) { struct bpf_prog_info info = {}; @@ -523,7 +586,10 @@ static int do_dump(int argc, char **argv) if (member_len == &info.jited_prog_len) disasm_print_insn(buf, *member_len, opcodes); else - dump_xlated(buf, *member_len, opcodes); + if (json_output) + dump_xlated_json(buf, *member_len, opcodes); + else + dump_xlated_plain(buf, *member_len, opcodes); } free(buf);