Linux Audio

Check our new training course

Loading...
Note: File does not exist in v6.2.
  1/*
  2 * Minimal BPF JIT image disassembler
  3 *
  4 * Disassembles BPF JIT compiler emitted opcodes back to asm insn's for
  5 * debugging or verification purposes.
  6 *
  7 * To get the disassembly of the JIT code, do the following:
  8 *
  9 *  1) `echo 2 > /proc/sys/net/core/bpf_jit_enable`
 10 *  2) Load a BPF filter (e.g. `tcpdump -p -n -s 0 -i eth1 host 192.168.20.0/24`)
 11 *  3) Run e.g. `bpf_jit_disasm -o` to read out the last JIT code
 12 *
 13 * Copyright 2013 Daniel Borkmann <borkmann@redhat.com>
 14 * Licensed under the GNU General Public License, version 2.0 (GPLv2)
 15 */
 16
 17#include <stdint.h>
 18#include <stdio.h>
 19#include <stdlib.h>
 20#include <assert.h>
 21#include <unistd.h>
 22#include <string.h>
 23#include <bfd.h>
 24#include <dis-asm.h>
 25#include <sys/klog.h>
 26#include <sys/types.h>
 27#include <regex.h>
 28
 29static void get_exec_path(char *tpath, size_t size)
 30{
 31	char *path;
 32	ssize_t len;
 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);
 41	tpath[len] = 0;
 42
 43	free(path);
 44}
 45
 46static void get_asm_insns(uint8_t *image, size_t len, unsigned long base,
 47			  int opcodes)
 48{
 49	int count, i, pc = 0;
 50	char tpath[256];
 51	struct disassemble_info info;
 52	disassembler_ftype disassemble;
 53	bfd *bfdf;
 54
 55	memset(tpath, 0, sizeof(tpath));
 56	get_exec_path(tpath, sizeof(tpath));
 57
 58	bfdf = bfd_openr(tpath, NULL);
 59	assert(bfdf);
 60	assert(bfd_check_format(bfdf, bfd_object));
 61
 62	init_disassemble_info(&info, stdout, (fprintf_ftype) fprintf);
 63	info.arch = bfd_get_arch(bfdf);
 64	info.mach = bfd_get_mach(bfdf);
 65	info.buffer = image;
 66	info.buffer_length = len;
 67
 68	disassemble_init_for_target(&info);
 69
 70	disassemble = disassembler(bfdf);
 71	assert(disassemble);
 72
 73	do {
 74		printf("%4x:\t", pc);
 75
 76		count = disassemble(pc, &info);
 77
 78		if (opcodes) {
 79			printf("\n\t");
 80			for (i = 0; i < count; ++i)
 81				printf("%02x ", (uint8_t) image[pc + i]);
 82		}
 83		printf("\n");
 84
 85		pc += count;
 86	} while(count > 0 && pc < len);
 87
 88	bfd_close(bfdf);
 89}
 90
 91static char *get_klog_buff(int *klen)
 92{
 93	int ret, len = klogctl(10, NULL, 0);
 94	char *buff = malloc(len);
 95
 96	assert(buff && klen);
 97	ret = klogctl(3, buff, len);
 98	assert(ret >= 0);
 99	*klen = ret;
100
101	return buff;
102}
103
104static void put_klog_buff(char *buff)
105{
106	free(buff);
107}
108
109static int get_last_jit_image(char *haystack, size_t hlen,
110			      uint8_t *image, size_t ilen,
111			      unsigned long *base)
112{
113	char *ptr, *pptr, *tmp;
114	off_t off = 0;
115	int ret, flen, proglen, pass, ulen = 0;
116	regmatch_t pmatch[1];
117	regex_t regex;
118
119	if (hlen == 0)
120		return 0;
121
122	ret = regcomp(&regex, "flen=[[:alnum:]]+ proglen=[[:digit:]]+ "
123		      "pass=[[:digit:]]+ image=[[:xdigit:]]+", REG_EXTENDED);
124	assert(ret == 0);
125
126	ptr = haystack;
127	while (1) {
128		ret = regexec(&regex, ptr, 1, pmatch, 0);
129		if (ret == 0) {
130			ptr += pmatch[0].rm_eo;
131			off += pmatch[0].rm_eo;
132			assert(off < hlen);
133		} else
134			break;
135	}
136
137	ptr = haystack + off - (pmatch[0].rm_eo - pmatch[0].rm_so);
138	ret = sscanf(ptr, "flen=%d proglen=%d pass=%d image=%lx",
139		     &flen, &proglen, &pass, base);
140	if (ret != 4)
141		return 0;
142
143	tmp = ptr = haystack + off;
144	while ((ptr = strtok(tmp, "\n")) != NULL && ulen < ilen) {
145		tmp = NULL;
146		if (!strstr(ptr, "JIT code"))
147			continue;
148		pptr = ptr;
149		while ((ptr = strstr(pptr, ":")))
150			pptr = ptr + 1;
151		ptr = pptr;
152		do {
153			image[ulen++] = (uint8_t) strtoul(pptr, &pptr, 16);
154			if (ptr == pptr || ulen >= ilen) {
155				ulen--;
156				break;
157			}
158			ptr = pptr;
159		} while (1);
160	}
161
162	assert(ulen == proglen);
163	printf("%d bytes emitted from JIT compiler (pass:%d, flen:%d)\n",
164	       proglen, pass, flen);
165	printf("%lx + <x>:\n", *base);
166
167	regfree(&regex);
168	return ulen;
169}
170
171int main(int argc, char **argv)
172{
173	int len, klen, opcodes = 0;
174	char *kbuff;
175	unsigned long base;
176	uint8_t image[4096];
177
178	if (argc > 1) {
179		if (!strncmp("-o", argv[argc - 1], 2)) {
180			opcodes = 1;
181		} else {
182			printf("usage: bpf_jit_disasm [-o: show opcodes]\n");
183			exit(0);
184		}
185	}
186
187	bfd_init();
188	memset(image, 0, sizeof(image));
189
190	kbuff = get_klog_buff(&klen);
191
192	len = get_last_jit_image(kbuff, klen, image, sizeof(image), &base);
193	if (len > 0 && base > 0)
194		get_asm_insns(image, len, base, opcodes);
195
196	put_klog_buff(kbuff);
197
198	return 0;
199}