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 29 static 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 47 static int oper_count; 48 static 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 79 void disasm_print_insn(unsigned char *image, ssize_t len, int opcodes, 80 const char *arch, const char *disassembler_options) 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 if (disassembler_options) 120 info.disassembler_options = disassembler_options; 121 info.buffer = image; 122 info.buffer_length = len; 123 124 disassemble_init_for_target(&info); 125 126 #ifdef DISASM_FOUR_ARGS_SIGNATURE 127 disassemble = disassembler(info.arch, 128 bfd_big_endian(bfdf), 129 info.mach, 130 bfdf); 131 #else 132 disassemble = disassembler(bfdf); 133 #endif 134 assert(disassemble); 135 136 if (json_output) 137 jsonw_start_array(json_wtr); 138 do { 139 if (json_output) { 140 jsonw_start_object(json_wtr); 141 oper_count = 0; 142 jsonw_name(json_wtr, "pc"); 143 jsonw_printf(json_wtr, "\"0x%x\"", pc); 144 } else { 145 printf("%4x:\t", pc); 146 } 147 148 count = disassemble(pc, &info); 149 if (json_output) { 150 /* Operand array, was started in fprintf_json. Before 151 * that, make sure we have a _null_ value if no operand 152 * other than operation code was present. 153 */ 154 if (oper_count == 1) 155 jsonw_null(json_wtr); 156 jsonw_end_array(json_wtr); 157 } 158 159 if (opcodes) { 160 if (json_output) { 161 jsonw_name(json_wtr, "opcodes"); 162 jsonw_start_array(json_wtr); 163 for (i = 0; i < count; ++i) 164 jsonw_printf(json_wtr, "\"0x%02hhx\"", 165 (uint8_t)image[pc + i]); 166 jsonw_end_array(json_wtr); 167 } else { 168 printf("\n\t"); 169 for (i = 0; i < count; ++i) 170 printf("%02x ", 171 (uint8_t)image[pc + i]); 172 } 173 } 174 if (json_output) 175 jsonw_end_object(json_wtr); 176 else 177 printf("\n"); 178 179 pc += count; 180 } while (count > 0 && pc < len); 181 if (json_output) 182 jsonw_end_array(json_wtr); 183 184 bfd_close(bfdf); 185 } 186