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
  47        va_start(ap, fmt);
  48        if (vasprintf(&s, fmt, ap) < 0)
  49                return -1;
  50        va_end(ap);
  51
  52        if (!oper_count) {
  53                int i;
  54
  55                /* Strip trailing spaces */
  56                i = strlen(s) - 1;
  57                while (s[i] == ' ')
  58                        s[i--] = '\0';
  59
  60                jsonw_string_field(json_wtr, "operation", s);
  61                jsonw_name(json_wtr, "operands");
  62                jsonw_start_array(json_wtr);
  63                oper_count++;
  64        } else if (!strcmp(fmt, ",")) {
  65                   /* Skip */
  66        } else {
  67                jsonw_string(json_wtr, s);
  68                oper_count++;
  69        }
  70        free(s);
  71        return 0;
  72}
  73
  74void disasm_print_insn(unsigned char *image, ssize_t len, int opcodes,
  75                       const char *arch, const char *disassembler_options,
  76                       const struct btf *btf,
  77                       const struct bpf_prog_linfo *prog_linfo,
  78                       __u64 func_ksym, unsigned int func_idx,
  79                       bool linum)
  80{
  81        const struct bpf_line_info *linfo = NULL;
  82        disassembler_ftype disassemble;
  83        struct disassemble_info info;
  84        unsigned int nr_skip = 0;
  85        int count, i, pc = 0;
  86        char tpath[PATH_MAX];
  87        bfd *bfdf;
  88
  89        if (!len)
  90                return;
  91
  92        memset(tpath, 0, sizeof(tpath));
  93        get_exec_path(tpath, sizeof(tpath));
  94
  95        bfdf = bfd_openr(tpath, NULL);
  96        assert(bfdf);
  97        assert(bfd_check_format(bfdf, bfd_object));
  98
  99        if (json_output)
 100                init_disassemble_info(&info, stdout,
 101                                      (fprintf_ftype) fprintf_json);
 102        else
 103                init_disassemble_info(&info, stdout,
 104                                      (fprintf_ftype) fprintf);
 105
 106        /* Update architecture info for offload. */
 107        if (arch) {
 108                const bfd_arch_info_type *inf = bfd_scan_arch(arch);
 109
 110                if (inf) {
 111                        bfdf->arch_info = inf;
 112                } else {
 113                        p_err("No libbfd support for %s", arch);
 114                        return;
 115                }
 116        }
 117
 118        info.arch = bfd_get_arch(bfdf);
 119        info.mach = bfd_get_mach(bfdf);
 120        if (disassembler_options)
 121                info.disassembler_options = disassembler_options;
 122        info.buffer = image;
 123        info.buffer_length = len;
 124
 125        disassemble_init_for_target(&info);
 126
 127#ifdef DISASM_FOUR_ARGS_SIGNATURE
 128        disassemble = disassembler(info.arch,
 129                                   bfd_big_endian(bfdf),
 130                                   info.mach,
 131                                   bfdf);
 132#else
 133        disassemble = disassembler(bfdf);
 134#endif
 135        assert(disassemble);
 136
 137        if (json_output)
 138                jsonw_start_array(json_wtr);
 139        do {
 140                if (prog_linfo) {
 141                        linfo = bpf_prog_linfo__lfind_addr_func(prog_linfo,
 142                                                                func_ksym + pc,
 143                                                                func_idx,
 144                                                                nr_skip);
 145                        if (linfo)
 146                                nr_skip++;
 147                }
 148
 149                if (json_output) {
 150                        jsonw_start_object(json_wtr);
 151                        oper_count = 0;
 152                        if (linfo)
 153                                btf_dump_linfo_json(btf, linfo, linum);
 154                        jsonw_name(json_wtr, "pc");
 155                        jsonw_printf(json_wtr, "\"0x%x\"", pc);
 156                } else {
 157                        if (linfo)
 158                                btf_dump_linfo_plain(btf, linfo, "; ",
 159                                                     linum);
 160                        printf("%4x:\t", pc);
 161                }
 162
 163                count = disassemble(pc, &info);
 164                if (json_output) {
 165                        /* Operand array, was started in fprintf_json. Before
 166                         * that, make sure we have a _null_ value if no operand
 167                         * other than operation code was present.
 168                         */
 169                        if (oper_count == 1)
 170                                jsonw_null(json_wtr);
 171                        jsonw_end_array(json_wtr);
 172                }
 173
 174                if (opcodes) {
 175                        if (json_output) {
 176                                jsonw_name(json_wtr, "opcodes");
 177                                jsonw_start_array(json_wtr);
 178                                for (i = 0; i < count; ++i)
 179                                        jsonw_printf(json_wtr, "\"0x%02hhx\"",
 180                                                     (uint8_t)image[pc + i]);
 181                                jsonw_end_array(json_wtr);
 182                        } else {
 183                                printf("\n\t");
 184                                for (i = 0; i < count; ++i)
 185                                        printf("%02x ",
 186                                               (uint8_t)image[pc + i]);
 187                        }
 188                }
 189                if (json_output)
 190                        jsonw_end_object(json_wtr);
 191                else
 192                        printf("\n");
 193
 194                pc += count;
 195        } while (count > 0 && pc < len);
 196        if (json_output)
 197                jsonw_end_array(json_wtr);
 198
 199        bfd_close(bfdf);
 200}
 201
 202int disasm_init(void)
 203{
 204        bfd_init();
 205        return 0;
 206}
 207