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