root/tools/bpf/bpftool/jit_disasm.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. get_exec_path
  2. fprintf_json
  3. disasm_print_insn
  4. disasm_init

   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 
  32 static 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 
  42 static int oper_count;
  43 static 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 
  75 void 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 
 203 int disasm_init(void)
 204 {
 205         bfd_init();
 206         return 0;
 207 }

/* [<][>][^][v][top][bottom][index][help] */