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