Skip to content

Commit

Permalink
bpf_jit_disasm: also support reading jit dump from file
Browse files Browse the repository at this point in the history
This patch adds support to read the dmesg BPF JIT dump also from a
file instead of the klog buffer. I found this quite useful when going
through some 'before/after patch' logs. It also fixes a regex leak
found by valgrind when no image dump was found.

Signed-off-by: Daniel Borkmann <[email protected]>
Signed-off-by: David S. Miller <[email protected]>
  • Loading branch information
borkmann authored and davem330 committed Jul 31, 2015
1 parent 1df33a1 commit a6ed383
Showing 1 changed file with 90 additions and 19 deletions.
109 changes: 90 additions & 19 deletions tools/net/bpf_jit_disasm.c
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,14 @@
#include <string.h>
#include <bfd.h>
#include <dis-asm.h>
#include <regex.h>
#include <fcntl.h>
#include <sys/klog.h>
#include <sys/types.h>
#include <regex.h>
#include <sys/stat.h>

#define CMD_ACTION_SIZE_BUFFER 10
#define CMD_ACTION_READ_ALL 3

static void get_exec_path(char *tpath, size_t size)
{
Expand Down Expand Up @@ -87,20 +92,66 @@ static void get_asm_insns(uint8_t *image, size_t len, int opcodes)
bfd_close(bfdf);
}

static char *get_klog_buff(int *klen)
static char *get_klog_buff(unsigned int *klen)
{
int ret, len = klogctl(10, NULL, 0);
char *buff = malloc(len);
int ret, len;
char *buff;

len = klogctl(CMD_ACTION_SIZE_BUFFER, NULL, 0);
buff = malloc(len);
if (!buff)
return NULL;

ret = klogctl(CMD_ACTION_READ_ALL, buff, len);
if (ret < 0) {
free(buff);
return NULL;
}

assert(buff && klen);
ret = klogctl(3, buff, len);
assert(ret >= 0);
*klen = ret;
return buff;
}

static char *get_flog_buff(const char *file, unsigned int *klen)
{
int fd, ret, len;
struct stat fi;
char *buff;

fd = open(file, O_RDONLY);
if (fd < 0)
return NULL;

ret = fstat(fd, &fi);
if (ret < 0 || !S_ISREG(fi.st_mode))
goto out;

len = fi.st_size + 1;
buff = malloc(len);
if (!buff)
goto out;

memset(buff, 0, len);
ret = read(fd, buff, len - 1);
if (ret <= 0)
goto out_free;

close(fd);
*klen = ret;
return buff;
out_free:
free(buff);
out:
close(fd);
return NULL;
}

static char *get_log_buff(const char *file, unsigned int *klen)
{
return file ? get_flog_buff(file, klen) : get_klog_buff(klen);
}

static void put_klog_buff(char *buff)
static void put_log_buff(char *buff)
{
free(buff);
}
Expand Down Expand Up @@ -138,8 +189,10 @@ static int get_last_jit_image(char *haystack, size_t hlen,
ptr = haystack + off - (pmatch[0].rm_eo - pmatch[0].rm_so);
ret = sscanf(ptr, "flen=%d proglen=%d pass=%d image=%lx",
&flen, &proglen, &pass, &base);
if (ret != 4)
if (ret != 4) {
regfree(&regex);
return 0;
}

tmp = ptr = haystack + off;
while ((ptr = strtok(tmp, "\n")) != NULL && ulen < ilen) {
Expand Down Expand Up @@ -169,31 +222,49 @@ static int get_last_jit_image(char *haystack, size_t hlen,
return ulen;
}

static void usage(void)
{
printf("Usage: bpf_jit_disasm [...]\n");
printf(" -o Also display related opcodes (default: off).\n");
printf(" -f <file> Read last image dump from file or stdin (default: klog).\n");
printf(" -h Display this help.\n");
}

int main(int argc, char **argv)
{
int len, klen, opcodes = 0;
char *kbuff;
unsigned int len, klen, opt, opcodes = 0;
static uint8_t image[32768];
char *kbuff, *file = NULL;

if (argc > 1) {
if (!strncmp("-o", argv[argc - 1], 2)) {
while ((opt = getopt(argc, argv, "of:")) != -1) {
switch (opt) {
case 'o':
opcodes = 1;
} else {
printf("usage: bpf_jit_disasm [-o: show opcodes]\n");
exit(0);
break;
case 'f':
file = optarg;
break;
default:
usage();
return -1;
}
}

bfd_init();
memset(image, 0, sizeof(image));

kbuff = get_klog_buff(&klen);
kbuff = get_log_buff(file, &klen);
if (!kbuff) {
fprintf(stderr, "Could not retrieve log buffer!\n");
return -1;
}

len = get_last_jit_image(kbuff, klen, image, sizeof(image));
if (len > 0)
get_asm_insns(image, len, opcodes);
else
fprintf(stderr, "No JIT image found!\n");

put_klog_buff(kbuff);

put_log_buff(kbuff);
return 0;
}

0 comments on commit a6ed383

Please sign in to comment.