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