bpf_jit_disasm: also support reading jit dump from file
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 <daniel@iogearbox.net> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
committed by
David S. Miller
parent
1df33a1145
commit
a6ed38361b
@@ -22,9 +22,14 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <bfd.h>
|
#include <bfd.h>
|
||||||
#include <dis-asm.h>
|
#include <dis-asm.h>
|
||||||
|
#include <regex.h>
|
||||||
|
#include <fcntl.h>
|
||||||
#include <sys/klog.h>
|
#include <sys/klog.h>
|
||||||
#include <sys/types.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)
|
static void get_exec_path(char *tpath, size_t size)
|
||||||
{
|
{
|
||||||
@@ -87,20 +92,66 @@ static void get_asm_insns(uint8_t *image, size_t len, int opcodes)
|
|||||||
bfd_close(bfdf);
|
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);
|
int ret, len;
|
||||||
char *buff = malloc(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;
|
*klen = ret;
|
||||||
|
|
||||||
return buff;
|
return buff;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void put_klog_buff(char *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_log_buff(char *buff)
|
||||||
{
|
{
|
||||||
free(buff);
|
free(buff);
|
||||||
}
|
}
|
||||||
@@ -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);
|
ptr = haystack + off - (pmatch[0].rm_eo - pmatch[0].rm_so);
|
||||||
ret = sscanf(ptr, "flen=%d proglen=%d pass=%d image=%lx",
|
ret = sscanf(ptr, "flen=%d proglen=%d pass=%d image=%lx",
|
||||||
&flen, &proglen, &pass, &base);
|
&flen, &proglen, &pass, &base);
|
||||||
if (ret != 4)
|
if (ret != 4) {
|
||||||
|
regfree(®ex);
|
||||||
return 0;
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
tmp = ptr = haystack + off;
|
tmp = ptr = haystack + off;
|
||||||
while ((ptr = strtok(tmp, "\n")) != NULL && ulen < ilen) {
|
while ((ptr = strtok(tmp, "\n")) != NULL && ulen < ilen) {
|
||||||
@@ -169,31 +222,49 @@ static int get_last_jit_image(char *haystack, size_t hlen,
|
|||||||
return ulen;
|
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 main(int argc, char **argv)
|
||||||
{
|
{
|
||||||
int len, klen, opcodes = 0;
|
unsigned int len, klen, opt, opcodes = 0;
|
||||||
char *kbuff;
|
|
||||||
static uint8_t image[32768];
|
static uint8_t image[32768];
|
||||||
|
char *kbuff, *file = NULL;
|
||||||
|
|
||||||
if (argc > 1) {
|
while ((opt = getopt(argc, argv, "of:")) != -1) {
|
||||||
if (!strncmp("-o", argv[argc - 1], 2)) {
|
switch (opt) {
|
||||||
|
case 'o':
|
||||||
opcodes = 1;
|
opcodes = 1;
|
||||||
} else {
|
break;
|
||||||
printf("usage: bpf_jit_disasm [-o: show opcodes]\n");
|
case 'f':
|
||||||
exit(0);
|
file = optarg;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
usage();
|
||||||
|
return -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bfd_init();
|
bfd_init();
|
||||||
memset(image, 0, sizeof(image));
|
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));
|
len = get_last_jit_image(kbuff, klen, image, sizeof(image));
|
||||||
if (len > 0)
|
if (len > 0)
|
||||||
get_asm_insns(image, len, opcodes);
|
get_asm_insns(image, len, opcodes);
|
||||||
|
else
|
||||||
|
fprintf(stderr, "No JIT image found!\n");
|
||||||
|
|
||||||
put_klog_buff(kbuff);
|
put_log_buff(kbuff);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user