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 { 81 disassembler_ftype disassemble; 82 struct disassemble_info info; 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 info.arch = bfd_get_arch(bfdf); 104 info.mach = bfd_get_mach(bfdf); 105 info.buffer = image; 106 info.buffer_length = len; 107 108 disassemble_init_for_target(&info); 109 110 #ifdef DISASM_FOUR_ARGS_SIGNATURE 111 disassemble = disassembler(info.arch, 112 bfd_big_endian(bfdf), 113 info.mach, 114 bfdf); 115 #else 116 disassemble = disassembler(bfdf); 117 #endif 118 assert(disassemble); 119 120 if (json_output) 121 jsonw_start_array(json_wtr); 122 do { 123 if (json_output) { 124 jsonw_start_object(json_wtr); 125 oper_count = 0; 126 jsonw_name(json_wtr, "pc"); 127 jsonw_printf(json_wtr, "\"0x%x\"", pc); 128 } else { 129 printf("%4x:\t", pc); 130 } 131 132 count = disassemble(pc, &info); 133 if (json_output) { 134 /* Operand array, was started in fprintf_json. Before 135 * that, make sure we have a _null_ value if no operand 136 * other than operation code was present. 137 */ 138 if (oper_count == 1) 139 jsonw_null(json_wtr); 140 jsonw_end_array(json_wtr); 141 } 142 143 if (opcodes) { 144 if (json_output) { 145 jsonw_name(json_wtr, "opcodes"); 146 jsonw_start_array(json_wtr); 147 for (i = 0; i < count; ++i) 148 jsonw_printf(json_wtr, "\"0x%02hhx\"", 149 (uint8_t)image[pc + i]); 150 jsonw_end_array(json_wtr); 151 } else { 152 printf("\n\t"); 153 for (i = 0; i < count; ++i) 154 printf("%02x ", 155 (uint8_t)image[pc + i]); 156 } 157 } 158 if (json_output) 159 jsonw_end_object(json_wtr); 160 else 161 printf("\n"); 162 163 pc += count; 164 } while (count > 0 && pc < len); 165 if (json_output) 166 jsonw_end_array(json_wtr); 167 168 bfd_close(bfdf); 169 } 170