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) 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