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