Skip to content

Commit

Permalink
tools: bpftool: factor out xlated dump related code into separate file
Browse files Browse the repository at this point in the history
This patch factors out those code of dumping xlated eBPF instructions into
xlated_dumper.[h|c].

They are quite independent dumper functions, so better to be kept
separately.

New dumper support will be added in later patches in this set.

Signed-off-by: Jiong Wang <jiong.wang@netronome.com>
Acked-by: Jakub Kicinski <jakub.kicinski@netronome.com>
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
  • Loading branch information
Jiong Wang authored and Alexei Starovoitov committed Mar 2, 2018
1 parent 3197239 commit 73bb5b4
Show file tree
Hide file tree
Showing 3 changed files with 349 additions and 254 deletions.
255 changes: 1 addition & 254 deletions tools/bpf/bpftool/prog.c
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@
#include <libbpf.h>

#include "main.h"
#include "disasm.h"
#include "xlated_dumper.h"

static const char * const prog_type_name[] = {
[BPF_PROG_TYPE_UNSPEC] = "unspec",
Expand Down Expand Up @@ -407,259 +407,6 @@ static int do_show(int argc, char **argv)
return err;
}

#define SYM_MAX_NAME 256

struct kernel_sym {
unsigned long address;
char name[SYM_MAX_NAME];
};

struct dump_data {
unsigned long address_call_base;
struct kernel_sym *sym_mapping;
__u32 sym_count;
char scratch_buff[SYM_MAX_NAME];
};

static int kernel_syms_cmp(const void *sym_a, const void *sym_b)
{
return ((struct kernel_sym *)sym_a)->address -
((struct kernel_sym *)sym_b)->address;
}

static void kernel_syms_load(struct dump_data *dd)
{
struct kernel_sym *sym;
char buff[256];
void *tmp, *address;
FILE *fp;

fp = fopen("/proc/kallsyms", "r");
if (!fp)
return;

while (!feof(fp)) {
if (!fgets(buff, sizeof(buff), fp))
break;
tmp = realloc(dd->sym_mapping,
(dd->sym_count + 1) *
sizeof(*dd->sym_mapping));
if (!tmp) {
out:
free(dd->sym_mapping);
dd->sym_mapping = NULL;
fclose(fp);
return;
}
dd->sym_mapping = tmp;
sym = &dd->sym_mapping[dd->sym_count];
if (sscanf(buff, "%p %*c %s", &address, sym->name) != 2)
continue;
sym->address = (unsigned long)address;
if (!strcmp(sym->name, "__bpf_call_base")) {
dd->address_call_base = sym->address;
/* sysctl kernel.kptr_restrict was set */
if (!sym->address)
goto out;
}
if (sym->address)
dd->sym_count++;
}

fclose(fp);

qsort(dd->sym_mapping, dd->sym_count,
sizeof(*dd->sym_mapping), kernel_syms_cmp);
}

static void kernel_syms_destroy(struct dump_data *dd)
{
free(dd->sym_mapping);
}

static struct kernel_sym *kernel_syms_search(struct dump_data *dd,
unsigned long key)
{
struct kernel_sym sym = {
.address = key,
};

return dd->sym_mapping ?
bsearch(&sym, dd->sym_mapping, dd->sym_count,
sizeof(*dd->sym_mapping), kernel_syms_cmp) : NULL;
}

static void print_insn(struct bpf_verifier_env *env, const char *fmt, ...)
{
va_list args;

va_start(args, fmt);
vprintf(fmt, args);
va_end(args);
}

static const char *print_call_pcrel(struct dump_data *dd,
struct kernel_sym *sym,
unsigned long address,
const struct bpf_insn *insn)
{
if (sym)
snprintf(dd->scratch_buff, sizeof(dd->scratch_buff),
"%+d#%s", insn->off, sym->name);
else
snprintf(dd->scratch_buff, sizeof(dd->scratch_buff),
"%+d#0x%lx", insn->off, address);
return dd->scratch_buff;
}

static const char *print_call_helper(struct dump_data *dd,
struct kernel_sym *sym,
unsigned long address)
{
if (sym)
snprintf(dd->scratch_buff, sizeof(dd->scratch_buff),
"%s", sym->name);
else
snprintf(dd->scratch_buff, sizeof(dd->scratch_buff),
"0x%lx", address);
return dd->scratch_buff;
}

static const char *print_call(void *private_data,
const struct bpf_insn *insn)
{
struct dump_data *dd = private_data;
unsigned long address = dd->address_call_base + insn->imm;
struct kernel_sym *sym;

sym = kernel_syms_search(dd, address);
if (insn->src_reg == BPF_PSEUDO_CALL)
return print_call_pcrel(dd, sym, address, insn);
else
return print_call_helper(dd, sym, address);
}

static const char *print_imm(void *private_data,
const struct bpf_insn *insn,
__u64 full_imm)
{
struct dump_data *dd = private_data;

if (insn->src_reg == BPF_PSEUDO_MAP_FD)
snprintf(dd->scratch_buff, sizeof(dd->scratch_buff),
"map[id:%u]", insn->imm);
else
snprintf(dd->scratch_buff, sizeof(dd->scratch_buff),
"0x%llx", (unsigned long long)full_imm);
return dd->scratch_buff;
}

static void dump_xlated_plain(struct dump_data *dd, void *buf,
unsigned int len, bool opcodes)
{
const struct bpf_insn_cbs cbs = {
.cb_print = print_insn,
.cb_call = print_call,
.cb_imm = print_imm,
.private_data = dd,
};
struct bpf_insn *insn = buf;
bool double_insn = false;
unsigned int i;

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);

printf("% 4d: ", i);
print_bpf_insn(&cbs, NULL, insn + i, true);

if (opcodes) {
printf(" ");
fprint_hex(stdout, insn + i, 8, " ");
if (double_insn && i < len - 1) {
printf(" ");
fprint_hex(stdout, insn + i + 1, 8, " ");
}
printf("\n");
}
}
}

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(struct dump_data *dd, void *buf,
unsigned int len, bool opcodes)
{
const struct bpf_insn_cbs cbs = {
.cb_print = print_insn_json,
.cb_call = print_call,
.cb_imm = print_imm,
.private_data = dd,
};
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(&cbs, 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 = {};
Expand Down
Loading

0 comments on commit 73bb5b4

Please sign in to comment.