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