linux/tools/bpf/bpftool/jit_disasm.c
<<
>>
Prefs
   1// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
   2/*
   3 * Based on:
   4 *
   5 * Minimal BPF JIT image disassembler
   6 *
   7 * Disassembles BPF JIT compiler emitted opcodes back to asm insn's for
   8 * debugging or verification purposes.
   9 *
  10 * Copyright 2013 Daniel Borkmann <daniel@iogearbox.net>
  11 * Licensed under the GNU General Public License, version 2.0 (GPLv2)
  12 */
  13
  14#define _GNU_SOURCE
  15#include <stdio.h>
  16#include <stdarg.h>
  17#include <stdint.h>
  18#include <stdlib.h>
  19#include <assert.h>
  20#include <unistd.h>
  21#include <string.h>
  22#include <bfd.h>
  23#include <dis-asm.h>
  24#include <sys/stat.h>
  25#include <limits.h>
  26#include <bpf/libbpf.h>
  27
  28#include "json_writer.h"
  29#include "main.h"
  30
  31static void get_exec_path(char *tpath, size_t size)
  32{
  33        const char *path = "/proc/self/exe";
  34        ssize_t len;
  35
  36        len = readlink(path, tpath, size - 1);
  37        assert(len > 0);
  38        tpath[len] = 0;
  39}
  40
  41static int oper_count;
  42static int fprintf_json(void *out, const char *fmt, ...)
  43{
  44        va_list ap;
  45        char *s;
  46        int err;
  47
  48        va_start(ap, fmt);
  49        err = vasprintf(&s, fmt, ap);
  50        va_end(ap);
  51        if (err < 0)
  52                return -1;
  53
  54        if (!oper_count) {
  55                int i;
  56
  57                /* Strip trailing spaces */
  58                i = strlen(s) - 1;
  59                while (s[i] == ' ')
  60                        s[i--] = '\0';
  61
  62                jsonw_string_field(json_wtr, "operation", s);
  63                jsonw_name(json_wtr, "operands");
  64                jsonw_start_array(json_wtr);
  65                oper_count++;
  66        } else if (!strcmp(fmt, ",")) {
  67                   /* Skip */
  68        } else {
  69                jsonw_string(json_wtr, s);
  70                oper_count++;
  71        }
  72        free(s);
  73        return 0;
  74}
  75
  76void disasm_print_insn(unsigned char *image, ssize_t len, int opcodes,
  77                       const char *arch, const char *disassembler_options,
  78                       const struct btf *btf,
  79                       const struct bpf_prog_linfo *prog_linfo,
  80                       __u64 func_ksym, unsigned int func_idx,
  81                       bool linum)
  82{
  83        const struct bpf_line_info *linfo = NULL;
  84        disassembler_ftype disassemble;
  85        struct disassemble_info info;
  86        unsigned int nr_skip = 0;
  87        int count, i, pc = 0;
  88        char tpath[PATH_MAX];
  89        bfd *bfdf;
  90
  91        if (!len)
  92                return;
  93
  94        memset(tpath, 0, sizeof(tpath));
  95        get_exec_path(tpath, sizeof(tpath));
  96
  97        bfdf = bfd_openr(tpath, NULL);
  98        assert(bfdf);
  99        assert(bfd_check_format(bfdf, bfd_object));
 100
 101        if (json_output)
 102                init_disassemble_info(&info, stdout,
 103                                      (fprintf_ftype) fprintf_json);
 104        else
 105                init_disassemble_info(&info, stdout,
 106                                      (fprintf_ftype) fprintf);
 107
 108        /* Update architecture info for offload. */
 109        if (arch) {
 110                const bfd_arch_info_type *inf = bfd_scan_arch(arch);
 111
 112                if (inf) {
 113                        bfdf->arch_info = inf;
 114                } else {
 115                        p_err("No libbfd support for %s", arch);
 116                        return;
 117                }
 118        }
 119
 120        info.arch = bfd_get_arch(bfdf);
 121        info.mach = bfd_get_mach(bfdf);
 122        if (disassembler_options)
 123                info.disassembler_options = disassembler_options;
 124        info.buffer = image;
 125        info.buffer_length = len;
 126
 127        disassemble_init_for_target(&info);
 128
 129#ifdef DISASM_FOUR_ARGS_SIGNATURE
 130        disassemble = disassembler(info.arch,
 131                                   bfd_big_endian(bfdf),
 132                                   info.mach,
 133                                   bfdf);
 134#else
 135        disassemble = disassembler(bfdf);
 136#endif
 137        assert(disassemble);
 138
 139        if (json_output)
 140                jsonw_start_array(json_wtr);
 141        do {
 142                if (prog_linfo) {
 143                        linfo = bpf_prog_linfo__lfind_addr_func(prog_linfo,
 144                                                                func_ksym + pc,
 145                                                                func_idx,
 146                                                                nr_skip);
 147                        if (linfo)
 148                                nr_skip++;
 149                }
 150
 151                if (json_output) {
 152                        jsonw_start_object(json_wtr);
 153                        oper_count = 0;
 154                        if (linfo)
 155                                btf_dump_linfo_json(btf, linfo, linum);
 156                        jsonw_name(json_wtr, "pc");
 157                        jsonw_printf(json_wtr, "\"0x%x\"", pc);
 158                } else {
 159                        if (linfo)
 160                                btf_dump_linfo_plain(btf, linfo, "; ",
 161                                                     linum);
 162                        printf("%4x:\t", pc);
 163                }
 164
 165                count = disassemble(pc, &info);
 166                if (json_output) {
 167                        /* Operand array, was started in fprintf_json. Before
 168                         * that, make sure we have a _null_ value if no operand
 169                         * other than operation code was present.
 170                         */
 171                        if (oper_count == 1)
 172                                jsonw_null(json_wtr);
 173                        jsonw_end_array(json_wtr);
 174                }
 175
 176                if (opcodes) {
 177                        if (json_output) {
 178                                jsonw_name(json_wtr, "opcodes");
 179                                jsonw_start_array(json_wtr);
 180                                for (i = 0; i < count; ++i)
 181                                        jsonw_printf(json_wtr, "\"0x%02hhx\"",
 182                                                     (uint8_t)image[pc + i]);
 183                                jsonw_end_array(json_wtr);
 184                        } else {
 185                                printf("\n\t");
 186                                for (i = 0; i < count; ++i)
 187                                        printf("%02x ",
 188                                               (uint8_t)image[pc + i]);
 189                        }
 190                }
 191                if (json_output)
 192                        jsonw_end_object(json_wtr);
 193                else
 194                        printf("\n");
 195
 196                pc += count;
 197        } while (count > 0 && pc < len);
 198        if (json_output)
 199                jsonw_end_array(json_wtr);
 200
 201        bfd_close(bfdf);
 202}
 203
 204int disasm_init(void)
 205{
 206        bfd_init();
 207        return 0;
 208}
 209