]> The Tcpdump Group git mirrors - libpcap/commitdiff
Dump BPF tree representation transformations using dot language in bpf_optimize().
authorsolofox <[email protected]>
Tue, 3 Sep 2013 12:55:55 +0000 (20:55 +0800)
committersolofox <[email protected]>
Tue, 3 Sep 2013 12:55:55 +0000 (20:55 +0800)
optimize.c
tests/filtertest.c

index 82155436de7ea0db823d0c25e98dd1287e72fb96..8a5210860486594e819178e00d5a9b46a386cef3 100644 (file)
@@ -2234,7 +2234,92 @@ install_bpf_program(pcap_t *p, struct bpf_program *fp)
 
 #ifdef BDEBUG
 static void
-opt_dump(struct block *root)
+dot_dump_node(struct block *block, struct bpf_program *prog, FILE *out)
+{
+       int icount, noffset;
+       int i;
+
+       if (block == NULL || isMarked(block))
+               return;
+       Mark(block);
+
+       icount = slength(block->stmts) + 1 + block->longjt + block->longjf;
+       noffset = min(block->offset + icount, (int)prog->bf_len);
+
+       fprintf(out, "\tblock%d [shape=ellipse, id=\"block-%d\" label=\"BLOCK%d\\n", block->id, block->id, block->id);
+       for (i = block->offset; i < noffset; i++) {
+               fprintf(out, "\\n%s", bpf_image(prog->bf_insns + i, i));
+       }
+       fprintf(out, "\" tooltip=\"");
+       for (i = 0; i < BPF_MEMWORDS; i++)
+               if (block->val[i] != 0)
+                       fprintf(out, "val[%d]=%d ", i, block->val[i]);
+       fprintf(out, "val[A]=%d ", block->val[A_ATOM]);
+       fprintf(out, "val[X]=%d", block->val[X_ATOM]);
+       fprintf(out, "\"");
+       if (JT(block) == NULL)
+               fprintf(out, ", peripheries=2");
+       fprintf(out, "];\n");
+
+       dot_dump_node(JT(block), prog, out);
+       dot_dump_node(JF(block), prog, out);
+}
+static void
+dot_dump_edge(struct block *block, FILE *out)
+{
+       if (block == NULL || isMarked(block))
+               return;
+       Mark(block);
+
+       if (JT(block)) {
+               fprintf(out, "\t\"block%d\":se -> \"block%d\":n [label=\"T\"]; \n",
+                               block->id, JT(block)->id);
+               fprintf(out, "\t\"block%d\":sw -> \"block%d\":n [label=\"F\"]; \n",
+                          block->id, JF(block)->id);
+       }
+       dot_dump_edge(JT(block), out);
+       dot_dump_edge(JF(block), out);
+}
+/* Output the block CFG using graphviz/DOT language
+ * In the CFG, block's code, value index for each registers at EXIT,
+ * and the jump relationship is show.
+ *
+ * example DOT for BPF `ip src host 1.1.1.1' is:
+    digraph BPF {
+       block0 [shape=ellipse, id="block-0" label="BLOCK0\n\n(000) ldh      [12]\n(001) jeq      #0x800           jt 2  jf 5" tooltip="val[A]=0 val[X]=0"];
+       block1 [shape=ellipse, id="block-1" label="BLOCK1\n\n(002) ld       [26]\n(003) jeq      #0x1010101       jt 4  jf 5" tooltip="val[A]=0 val[X]=0"];
+       block2 [shape=ellipse, id="block-2" label="BLOCK2\n\n(004) ret      #68" tooltip="val[A]=0 val[X]=0", peripheries=2];
+       block3 [shape=ellipse, id="block-3" label="BLOCK3\n\n(005) ret      #0" tooltip="val[A]=0 val[X]=0", peripheries=2];
+       "block0":se -> "block1":n [label="T"];
+       "block0":sw -> "block3":n [label="F"];
+       "block1":se -> "block2":n [label="T"];
+       "block1":sw -> "block3":n [label="F"];
+    }
+ *
+ *  After install graphviz on http://www.graphviz.org/, save it as bpf.dot
+ *  and run `dot -Tpng -O bpf.dot' to draw the graph.
+ */
+static void
+dot_dump(struct block *root)
+{
+       struct bpf_program f;
+       FILE *out = stdout;
+
+       memset(bids, 0, sizeof bids);
+       f.bf_insns = icode_to_fcode(root, &f.bf_len);
+
+       fprintf(out, "digraph BPF {\n");
+       unMarkAll();
+       dot_dump_node(root, &f, out);
+       unMarkAll();
+       dot_dump_edge(root, out);
+       fprintf(out, "}\n");
+
+       free((char *)f.bf_insns);
+}
+
+static void
+plain_dump(struct block *root)
 {
        struct bpf_program f;
 
@@ -2244,4 +2329,17 @@ opt_dump(struct block *root)
        putchar('\n');
        free((char *)f.bf_insns);
 }
+static void
+opt_dump(struct block *root)
+{
+       /* if optimizer debugging is enabled, output DOT graph
+        * `dflag=4' is equivalent to -dddd to follow -d/-dd/-ddd
+     * convention in tcpdump command line
+        */
+       if (dflag > 3)
+               dot_dump(root);
+       else
+               plain_dump(root);
+}
+
 #endif
index a56d1e49e9236192b35df432e07a3b6b0b1d8a5b..e5ebcb72ad8f732d3f336453b80cc98672e37126 100644 (file)
@@ -57,6 +57,9 @@ static void error(const char *, ...)
 extern int optind;
 extern int opterr;
 extern char *optarg;
+#ifdef BDEBUG
+int dflag;
+#endif
 
 /*
  * On Windows, we need to open the file in binary mode, so that
@@ -161,7 +164,9 @@ main(int argc, char **argv)
 {
        char *cp;
        int op;
+#ifndef BDEBUG
        int dflag;
+#endif
        char *infile;
        int Oflag;
        long snaplen;
@@ -175,7 +180,15 @@ main(int argc, char **argv)
        if(wsockinit() != 0) return 1;
 #endif /* WIN32 */
 
+#ifndef BDEBUG
        dflag = 1;
+#else
+       /* if optimizer debugging is enabled, output DOT graph
+        * `dflag=4' is equivalent to -dddd to follow -d/-dd/-ddd
+     * convention in tcpdump command line
+        */
+       dflag = 4;
+#endif
        infile = NULL;
        Oflag = 1;
        snaplen = 68;
@@ -249,6 +262,16 @@ main(int argc, char **argv)
 
        if (pcap_compile(pd, &fcode, cmdbuf, Oflag, netmask) < 0)
                error("%s", pcap_geterr(pd));
+#ifdef BDEBUG
+       // replace line feed with space
+       for (cp = cmdbuf; *cp != '\0'; ++cp) {
+               if (*cp == '\r' || *cp == '\n') {
+                       *cp = ' ';
+               }
+       }
+       // only show machine code if BDEBUG defined, since dflag > 3
+       printf("machine codes for filter: %s\n", cmdbuf);
+#endif
        bpf_dump(&fcode, dflag);
        pcap_close(pd);
        exit(0);