0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014 #define _GNU_SOURCE
0015 #include <stdio.h>
0016 #include <stdarg.h>
0017 #include <stdint.h>
0018 #include <stdlib.h>
0019 #include <assert.h>
0020 #include <unistd.h>
0021 #include <string.h>
0022 #include <bfd.h>
0023 #include <dis-asm.h>
0024 #include <sys/stat.h>
0025 #include <limits.h>
0026 #include <bpf/libbpf.h>
0027 #include <tools/dis-asm-compat.h>
0028
0029 #include "json_writer.h"
0030 #include "main.h"
0031
0032 static void get_exec_path(char *tpath, size_t size)
0033 {
0034 const char *path = "/proc/self/exe";
0035 ssize_t len;
0036
0037 len = readlink(path, tpath, size - 1);
0038 assert(len > 0);
0039 tpath[len] = 0;
0040 }
0041
0042 static int oper_count;
0043 static int printf_json(void *out, const char *fmt, va_list ap)
0044 {
0045 char *s;
0046 int err;
0047
0048 err = vasprintf(&s, fmt, ap);
0049 if (err < 0)
0050 return -1;
0051
0052 if (!oper_count) {
0053 int i;
0054
0055
0056 i = strlen(s) - 1;
0057 while (s[i] == ' ')
0058 s[i--] = '\0';
0059
0060 jsonw_string_field(json_wtr, "operation", s);
0061 jsonw_name(json_wtr, "operands");
0062 jsonw_start_array(json_wtr);
0063 oper_count++;
0064 } else if (!strcmp(fmt, ",")) {
0065
0066 } else {
0067 jsonw_string(json_wtr, s);
0068 oper_count++;
0069 }
0070 free(s);
0071 return 0;
0072 }
0073
0074 static int fprintf_json(void *out, const char *fmt, ...)
0075 {
0076 va_list ap;
0077 int r;
0078
0079 va_start(ap, fmt);
0080 r = printf_json(out, fmt, ap);
0081 va_end(ap);
0082
0083 return r;
0084 }
0085
0086 static int fprintf_json_styled(void *out,
0087 enum disassembler_style style __maybe_unused,
0088 const char *fmt, ...)
0089 {
0090 va_list ap;
0091 int r;
0092
0093 va_start(ap, fmt);
0094 r = printf_json(out, fmt, ap);
0095 va_end(ap);
0096
0097 return r;
0098 }
0099
0100 void disasm_print_insn(unsigned char *image, ssize_t len, int opcodes,
0101 const char *arch, const char *disassembler_options,
0102 const struct btf *btf,
0103 const struct bpf_prog_linfo *prog_linfo,
0104 __u64 func_ksym, unsigned int func_idx,
0105 bool linum)
0106 {
0107 const struct bpf_line_info *linfo = NULL;
0108 disassembler_ftype disassemble;
0109 struct disassemble_info info;
0110 unsigned int nr_skip = 0;
0111 int count, i, pc = 0;
0112 char tpath[PATH_MAX];
0113 bfd *bfdf;
0114
0115 if (!len)
0116 return;
0117
0118 memset(tpath, 0, sizeof(tpath));
0119 get_exec_path(tpath, sizeof(tpath));
0120
0121 bfdf = bfd_openr(tpath, NULL);
0122 assert(bfdf);
0123 assert(bfd_check_format(bfdf, bfd_object));
0124
0125 if (json_output)
0126 init_disassemble_info_compat(&info, stdout,
0127 (fprintf_ftype) fprintf_json,
0128 fprintf_json_styled);
0129 else
0130 init_disassemble_info_compat(&info, stdout,
0131 (fprintf_ftype) fprintf,
0132 fprintf_styled);
0133
0134
0135 if (arch) {
0136 const bfd_arch_info_type *inf = bfd_scan_arch(arch);
0137
0138 if (inf) {
0139 bfdf->arch_info = inf;
0140 } else {
0141 p_err("No libbfd support for %s", arch);
0142 return;
0143 }
0144 }
0145
0146 info.arch = bfd_get_arch(bfdf);
0147 info.mach = bfd_get_mach(bfdf);
0148 if (disassembler_options)
0149 info.disassembler_options = disassembler_options;
0150 info.buffer = image;
0151 info.buffer_length = len;
0152
0153 disassemble_init_for_target(&info);
0154
0155 #ifdef DISASM_FOUR_ARGS_SIGNATURE
0156 disassemble = disassembler(info.arch,
0157 bfd_big_endian(bfdf),
0158 info.mach,
0159 bfdf);
0160 #else
0161 disassemble = disassembler(bfdf);
0162 #endif
0163 assert(disassemble);
0164
0165 if (json_output)
0166 jsonw_start_array(json_wtr);
0167 do {
0168 if (prog_linfo) {
0169 linfo = bpf_prog_linfo__lfind_addr_func(prog_linfo,
0170 func_ksym + pc,
0171 func_idx,
0172 nr_skip);
0173 if (linfo)
0174 nr_skip++;
0175 }
0176
0177 if (json_output) {
0178 jsonw_start_object(json_wtr);
0179 oper_count = 0;
0180 if (linfo)
0181 btf_dump_linfo_json(btf, linfo, linum);
0182 jsonw_name(json_wtr, "pc");
0183 jsonw_printf(json_wtr, "\"0x%x\"", pc);
0184 } else {
0185 if (linfo)
0186 btf_dump_linfo_plain(btf, linfo, "; ",
0187 linum);
0188 printf("%4x:\t", pc);
0189 }
0190
0191 count = disassemble(pc, &info);
0192 if (json_output) {
0193
0194
0195
0196
0197 if (oper_count == 1)
0198 jsonw_null(json_wtr);
0199 jsonw_end_array(json_wtr);
0200 }
0201
0202 if (opcodes) {
0203 if (json_output) {
0204 jsonw_name(json_wtr, "opcodes");
0205 jsonw_start_array(json_wtr);
0206 for (i = 0; i < count; ++i)
0207 jsonw_printf(json_wtr, "\"0x%02hhx\"",
0208 (uint8_t)image[pc + i]);
0209 jsonw_end_array(json_wtr);
0210 } else {
0211 printf("\n\t");
0212 for (i = 0; i < count; ++i)
0213 printf("%02x ",
0214 (uint8_t)image[pc + i]);
0215 }
0216 }
0217 if (json_output)
0218 jsonw_end_object(json_wtr);
0219 else
0220 printf("\n");
0221
0222 pc += count;
0223 } while (count > 0 && pc < len);
0224 if (json_output)
0225 jsonw_end_array(json_wtr);
0226
0227 bfd_close(bfdf);
0228 }
0229
0230 int disasm_init(void)
0231 {
0232 bfd_init();
0233 return 0;
0234 }