cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

jit_disasm.c (4442B)


      1// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
      2/*
      3 * Based on:
      4 *
      5 * Minimal BPF JIT image disassembler
      6 *
      7 * Disassembles BPF JIT compiler emitted opcodes back to asm insn's for
      8 * debugging or verification purposes.
      9 *
     10 * Copyright 2013 Daniel Borkmann <daniel@iogearbox.net>
     11 * Licensed under the GNU General Public License, version 2.0 (GPLv2)
     12 */
     13
     14#define _GNU_SOURCE
     15#include <stdio.h>
     16#include <stdarg.h>
     17#include <stdint.h>
     18#include <stdlib.h>
     19#include <assert.h>
     20#include <unistd.h>
     21#include <string.h>
     22#include <bfd.h>
     23#include <dis-asm.h>
     24#include <sys/stat.h>
     25#include <limits.h>
     26#include <bpf/libbpf.h>
     27
     28#include "json_writer.h"
     29#include "main.h"
     30
     31static void get_exec_path(char *tpath, size_t size)
     32{
     33	const char *path = "/proc/self/exe";
     34	ssize_t len;
     35
     36	len = readlink(path, tpath, size - 1);
     37	assert(len > 0);
     38	tpath[len] = 0;
     39}
     40
     41static int oper_count;
     42static int fprintf_json(void *out, const char *fmt, ...)
     43{
     44	va_list ap;
     45	char *s;
     46	int err;
     47
     48	va_start(ap, fmt);
     49	err = vasprintf(&s, fmt, ap);
     50	va_end(ap);
     51	if (err < 0)
     52		return -1;
     53
     54	if (!oper_count) {
     55		int i;
     56
     57		/* Strip trailing spaces */
     58		i = strlen(s) - 1;
     59		while (s[i] == ' ')
     60			s[i--] = '\0';
     61
     62		jsonw_string_field(json_wtr, "operation", s);
     63		jsonw_name(json_wtr, "operands");
     64		jsonw_start_array(json_wtr);
     65		oper_count++;
     66	} else if (!strcmp(fmt, ",")) {
     67		   /* Skip */
     68	} else {
     69		jsonw_string(json_wtr, s);
     70		oper_count++;
     71	}
     72	free(s);
     73	return 0;
     74}
     75
     76void disasm_print_insn(unsigned char *image, ssize_t len, int opcodes,
     77		       const char *arch, const char *disassembler_options,
     78		       const struct btf *btf,
     79		       const struct bpf_prog_linfo *prog_linfo,
     80		       __u64 func_ksym, unsigned int func_idx,
     81		       bool linum)
     82{
     83	const struct bpf_line_info *linfo = NULL;
     84	disassembler_ftype disassemble;
     85	struct disassemble_info info;
     86	unsigned int nr_skip = 0;
     87	int count, i, pc = 0;
     88	char tpath[PATH_MAX];
     89	bfd *bfdf;
     90
     91	if (!len)
     92		return;
     93
     94	memset(tpath, 0, sizeof(tpath));
     95	get_exec_path(tpath, sizeof(tpath));
     96
     97	bfdf = bfd_openr(tpath, NULL);
     98	assert(bfdf);
     99	assert(bfd_check_format(bfdf, bfd_object));
    100
    101	if (json_output)
    102		init_disassemble_info(&info, stdout,
    103				      (fprintf_ftype) fprintf_json);
    104	else
    105		init_disassemble_info(&info, stdout,
    106				      (fprintf_ftype) fprintf);
    107
    108	/* Update architecture info for offload. */
    109	if (arch) {
    110		const bfd_arch_info_type *inf = bfd_scan_arch(arch);
    111
    112		if (inf) {
    113			bfdf->arch_info = inf;
    114		} else {
    115			p_err("No libbfd support for %s", arch);
    116			return;
    117		}
    118	}
    119
    120	info.arch = bfd_get_arch(bfdf);
    121	info.mach = bfd_get_mach(bfdf);
    122	if (disassembler_options)
    123		info.disassembler_options = disassembler_options;
    124	info.buffer = image;
    125	info.buffer_length = len;
    126
    127	disassemble_init_for_target(&info);
    128
    129#ifdef DISASM_FOUR_ARGS_SIGNATURE
    130	disassemble = disassembler(info.arch,
    131				   bfd_big_endian(bfdf),
    132				   info.mach,
    133				   bfdf);
    134#else
    135	disassemble = disassembler(bfdf);
    136#endif
    137	assert(disassemble);
    138
    139	if (json_output)
    140		jsonw_start_array(json_wtr);
    141	do {
    142		if (prog_linfo) {
    143			linfo = bpf_prog_linfo__lfind_addr_func(prog_linfo,
    144								func_ksym + pc,
    145								func_idx,
    146								nr_skip);
    147			if (linfo)
    148				nr_skip++;
    149		}
    150
    151		if (json_output) {
    152			jsonw_start_object(json_wtr);
    153			oper_count = 0;
    154			if (linfo)
    155				btf_dump_linfo_json(btf, linfo, linum);
    156			jsonw_name(json_wtr, "pc");
    157			jsonw_printf(json_wtr, "\"0x%x\"", pc);
    158		} else {
    159			if (linfo)
    160				btf_dump_linfo_plain(btf, linfo, "; ",
    161						     linum);
    162			printf("%4x:\t", pc);
    163		}
    164
    165		count = disassemble(pc, &info);
    166		if (json_output) {
    167			/* Operand array, was started in fprintf_json. Before
    168			 * that, make sure we have a _null_ value if no operand
    169			 * other than operation code was present.
    170			 */
    171			if (oper_count == 1)
    172				jsonw_null(json_wtr);
    173			jsonw_end_array(json_wtr);
    174		}
    175
    176		if (opcodes) {
    177			if (json_output) {
    178				jsonw_name(json_wtr, "opcodes");
    179				jsonw_start_array(json_wtr);
    180				for (i = 0; i < count; ++i)
    181					jsonw_printf(json_wtr, "\"0x%02hhx\"",
    182						     (uint8_t)image[pc + i]);
    183				jsonw_end_array(json_wtr);
    184			} else {
    185				printf("\n\t");
    186				for (i = 0; i < count; ++i)
    187					printf("%02x ",
    188					       (uint8_t)image[pc + i]);
    189			}
    190		}
    191		if (json_output)
    192			jsonw_end_object(json_wtr);
    193		else
    194			printf("\n");
    195
    196		pc += count;
    197	} while (count > 0 && pc < len);
    198	if (json_output)
    199		jsonw_end_array(json_wtr);
    200
    201	bfd_close(bfdf);
    202}
    203
    204int disasm_init(void)
    205{
    206	bfd_init();
    207	return 0;
    208}