jit_disasm.c 3.3 KB
Newer Older
J
Jakub Kicinski 已提交
1 2 3 4 5 6 7 8 9 10 11 12
/*
 * Based on:
 *
 * Minimal BPF JIT image disassembler
 *
 * Disassembles BPF JIT compiler emitted opcodes back to asm insn's for
 * debugging or verification purposes.
 *
 * Copyright 2013 Daniel Borkmann <daniel@iogearbox.net>
 * Licensed under the GNU General Public License, version 2.0 (GPLv2)
 */

13
#include <stdarg.h>
J
Jakub Kicinski 已提交
14 15 16 17 18 19 20 21 22 23
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <unistd.h>
#include <string.h>
#include <bfd.h>
#include <dis-asm.h>
#include <sys/types.h>
#include <sys/stat.h>
24
#include <limits.h>
J
Jakub Kicinski 已提交
25

26 27 28
#include "json_writer.h"
#include "main.h"

J
Jakub Kicinski 已提交
29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46
static void get_exec_path(char *tpath, size_t size)
{
	ssize_t len;
	char *path;

	snprintf(tpath, size, "/proc/%d/exe", (int) getpid());
	tpath[size - 1] = 0;

	path = strdup(tpath);
	assert(path);

	len = readlink(path, tpath, size - 1);
	assert(len > 0);
	tpath[len] = 0;

	free(path);
}

47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78
static int oper_count;
static int fprintf_json(void *out, const char *fmt, ...)
{
	va_list ap;
	char *s;

	va_start(ap, fmt);
	if (!oper_count) {
		int i;

		s = va_arg(ap, char *);

		/* Strip trailing spaces */
		i = strlen(s) - 1;
		while (s[i] == ' ')
			s[i--] = '\0';

		jsonw_string_field(json_wtr, "operation", s);
		jsonw_name(json_wtr, "operands");
		jsonw_start_array(json_wtr);
		oper_count++;
	} else if (!strcmp(fmt, ",")) {
		   /* Skip */
	} else {
		s = va_arg(ap, char *);
		jsonw_string(json_wtr, s);
		oper_count++;
	}
	va_end(ap);
	return 0;
}

J
Jakub Kicinski 已提交
79 80 81 82 83
void disasm_print_insn(unsigned char *image, ssize_t len, int opcodes)
{
	disassembler_ftype disassemble;
	struct disassemble_info info;
	int count, i, pc = 0;
84
	char tpath[PATH_MAX];
J
Jakub Kicinski 已提交
85 86 87 88 89 90 91 92 93 94 95 96
	bfd *bfdf;

	if (!len)
		return;

	memset(tpath, 0, sizeof(tpath));
	get_exec_path(tpath, sizeof(tpath));

	bfdf = bfd_openr(tpath, NULL);
	assert(bfdf);
	assert(bfd_check_format(bfdf, bfd_object));

97 98 99 100 101 102
	if (json_output)
		init_disassemble_info(&info, stdout,
				      (fprintf_ftype) fprintf_json);
	else
		init_disassemble_info(&info, stdout,
				      (fprintf_ftype) fprintf);
J
Jakub Kicinski 已提交
103 104 105 106 107 108 109 110 111 112
	info.arch = bfd_get_arch(bfdf);
	info.mach = bfd_get_mach(bfdf);
	info.buffer = image;
	info.buffer_length = len;

	disassemble_init_for_target(&info);

	disassemble = disassembler(bfdf);
	assert(disassemble);

113 114
	if (json_output)
		jsonw_start_array(json_wtr);
J
Jakub Kicinski 已提交
115
	do {
116 117 118 119 120 121 122 123
		if (json_output) {
			jsonw_start_object(json_wtr);
			oper_count = 0;
			jsonw_name(json_wtr, "pc");
			jsonw_printf(json_wtr, "\"0x%x\"", pc);
		} else {
			printf("%4x:\t", pc);
		}
J
Jakub Kicinski 已提交
124 125

		count = disassemble(pc, &info);
126 127 128 129 130 131 132 133 134
		if (json_output) {
			/* Operand array, was started in fprintf_json. Before
			 * that, make sure we have a _null_ value if no operand
			 * other than operation code was present.
			 */
			if (oper_count == 1)
				jsonw_null(json_wtr);
			jsonw_end_array(json_wtr);
		}
J
Jakub Kicinski 已提交
135 136

		if (opcodes) {
137 138 139 140 141 142 143 144 145 146 147 148 149
			if (json_output) {
				jsonw_name(json_wtr, "opcodes");
				jsonw_start_array(json_wtr);
				for (i = 0; i < count; ++i)
					jsonw_printf(json_wtr, "\"0x%02hhx\"",
						     (uint8_t)image[pc + i]);
				jsonw_end_array(json_wtr);
			} else {
				printf("\n\t");
				for (i = 0; i < count; ++i)
					printf("%02x ",
					       (uint8_t)image[pc + i]);
			}
J
Jakub Kicinski 已提交
150
		}
151 152 153 154
		if (json_output)
			jsonw_end_object(json_wtr);
		else
			printf("\n");
J
Jakub Kicinski 已提交
155 156 157

		pc += count;
	} while (count > 0 && pc < len);
158 159
	if (json_output)
		jsonw_end_array(json_wtr);
J
Jakub Kicinski 已提交
160 161 162

	bfd_close(bfdf);
}