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