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