bpf_jit_disasm: also support reading jit dump from file
authorDaniel Borkmann <daniel@iogearbox.net>
Thu, 30 Jul 2015 14:04:22 +0000 (16:04 +0200)
committerDavid S. Miller <davem@davemloft.net>
Fri, 31 Jul 2015 22:13:14 +0000 (15:13 -0700)
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>
tools/net/bpf_jit_disasm.c

index 618c2bcd4eabc6143b0e7f0431f57b8620101fe5..2cd3d4c997383af3fde9ed090eb5d9ab32a7e467 100644 (file)
 #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)
 {
@@ -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);
 }
@@ -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) {
@@ -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;
 }