]> The Tcpdump Group git mirrors - libpcap/commitdiff
issue: https://github.com/the-tcpdump-group/libpcap/pull/319
authorMichael Richardson <[email protected]>
Sun, 15 Feb 2015 16:48:46 +0000 (11:48 -0500)
committerMichael Richardson <[email protected]>
Sun, 15 Feb 2015 16:48:46 +0000 (11:48 -0500)
Merge branch 'master' of https://github.com/solofox/libpcap into solofox-master

1  2 
optimize.c
tests/filtertest.c

diff --combined optimize.c
index feaf2017213ae09ed3a01a574b3865951cb59dac,8a5210860486594e819178e00d5a9b46a386cef3..ada20197647d5e2f114d469fa91d008bf90dd9f3
   *
   *  Optimization module for tcpdump intermediate representation.
   */
 -#ifndef lint
 -static const char rcsid[] _U_ =
 -    "@(#) $Header: /tcpdump/master/libpcap/optimize.c,v 1.91 2008-01-02 04:16:46 guy Exp $ (LBL)";
 -#endif
  
  #ifdef HAVE_CONFIG_H
  #include "config.h"
@@@ -606,12 -610,6 +606,12 @@@ fold_op(struct stmt *s, int v0, int v1
                a /= b;
                break;
  
 +      case BPF_MOD:
 +              if (b == 0)
 +                      bpf_error("modulus by zero");
 +              a %= b;
 +              break;
 +
        case BPF_AND:
                a &= b;
                break;
                a |= b;
                break;
  
 +      case BPF_XOR:
 +              a ^= b;
 +              break;
 +
        case BPF_LSH:
                a <<= b;
                break;
@@@ -984,10 -978,8 +984,10 @@@ opt_stmt(struct stmt *s, int val[], in
        case BPF_ALU|BPF_SUB|BPF_K:
        case BPF_ALU|BPF_MUL|BPF_K:
        case BPF_ALU|BPF_DIV|BPF_K:
 +      case BPF_ALU|BPF_MOD|BPF_K:
        case BPF_ALU|BPF_AND|BPF_K:
        case BPF_ALU|BPF_OR|BPF_K:
 +      case BPF_ALU|BPF_XOR|BPF_K:
        case BPF_ALU|BPF_LSH|BPF_K:
        case BPF_ALU|BPF_RSH|BPF_K:
                op = BPF_OP(s->code);
                                 * fixup the generated math code */
                                if (op == BPF_ADD ||
                                    op == BPF_LSH || op == BPF_RSH ||
 -                                  op == BPF_OR) {
 +                                  op == BPF_OR || op == BPF_XOR) {
                                        s->code = NOP;
                                        break;
                                }
        case BPF_ALU|BPF_SUB|BPF_X:
        case BPF_ALU|BPF_MUL|BPF_X:
        case BPF_ALU|BPF_DIV|BPF_X:
 +      case BPF_ALU|BPF_MOD|BPF_X:
        case BPF_ALU|BPF_AND|BPF_X:
        case BPF_ALU|BPF_OR|BPF_X:
 +      case BPF_ALU|BPF_XOR|BPF_X:
        case BPF_ALU|BPF_LSH|BPF_X:
        case BPF_ALU|BPF_RSH|BPF_X:
                op = BPF_OP(s->code);
                 */
                if (alter && vmap[val[A_ATOM]].is_const
                    && vmap[val[A_ATOM]].const_val == 0) {
 -                      if (op == BPF_ADD || op == BPF_OR) {
 +                      if (op == BPF_ADD || op == BPF_OR || op == BPF_XOR) {
                                s->code = BPF_MISC|BPF_TXA;
                                vstore(s, &val[A_ATOM], val[X_ATOM], alter);
                                break;
                        }
 -                      else if (op == BPF_MUL || op == BPF_DIV ||
 +                      else if (op == BPF_MUL || op == BPF_DIV || op == BPF_MOD ||
                                 op == BPF_AND || op == BPF_LSH || op == BPF_RSH) {
                                s->code = BPF_LD|BPF_IMM;
                                s->k = 0;
@@@ -2244,7 -2234,92 +2244,92 @@@ install_bpf_program(pcap_t *p, struct b
  
  #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;
  
        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
diff --combined tests/filtertest.c
index a36490d4c58efccbc9098a63f6600e412fa2e411,e5ebcb72ad8f732d3f336453b80cc98672e37126..e45db21eabbfd8f78806ac3e7b3bd39e19bf7d25
@@@ -23,6 -23,8 +23,6 @@@
  static const char copyright[] _U_ =
      "@(#) Copyright (c) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 2000\n\
  The Regents of the University of California.  All rights reserved.\n";
 -static const char rcsid[] _U_ =
 -    "@(#) $Header: /tcpdump/master/libpcap/filtertest.c,v 1.2 2005-08-08 17:50:13 guy Exp $ (LBL)";
  #endif
  
  #ifdef HAVE_CONFIG_H
@@@ -51,12 -53,13 +51,15 @@@ static char *program_name
  static void usage(void) __attribute__((noreturn));
  static void error(const char *, ...)
      __attribute__((noreturn, format (printf, 1, 2)));
 +static void warn(const char *, ...)
 +    __attribute__((format (printf, 1, 2)));
  
  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
@@@ -122,23 -125,6 +125,23 @@@ error(const char *fmt, ...
        /* NOTREACHED */
  }
  
 +/* VARARGS */
 +static void
 +warn(const char *fmt, ...)
 +{
 +      va_list ap;
 +
 +      (void)fprintf(stderr, "%s: WARNING: ", program_name);
 +      va_start(ap, fmt);
 +      (void)vfprintf(stderr, fmt, ap);
 +      va_end(ap);
 +      if (*fmt) {
 +              fmt += strlen(fmt);
 +              if (fmt[-1] != '\n')
 +                      (void)fputc('\n', stderr);
 +      }
 +}
 +
  /*
   * Copy arg vector into a new buffer, concatenating arguments with spaces.
   */
@@@ -178,11 -164,12 +181,13 @@@ main(int argc, char **argv
  {
        char *cp;
        int op;
+ #ifndef BDEBUG
        int dflag;
+ #endif
        char *infile;
        int Oflag;
        long snaplen;
 +      char *p;
        int dlt;
        bpf_u_int32 netmask = PCAP_NETMASK_UNKNOWN;
        char *cmdbuf;
        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;
--  
++
        if ((cp = strrchr(argv[0], '/')) != NULL)
                program_name = cp + 1;
        else
        }
  
        dlt = pcap_datalink_name_to_val(argv[optind]);
 -      if (dlt < 0)
 -              error("invalid data link type %s", argv[optind]);
 -      
 +      if (dlt < 0) {
 +              dlt = (int)strtol(argv[optind], &p, 10);
 +              if (p == argv[optind] || *p != '\0')
 +                      error("invalid data link type %s", argv[optind]);
 +      }
-       
++
        if (infile)
                cmdbuf = read_infile(infile);
        else
  
        if (pcap_compile(pd, &fcode, cmdbuf, Oflag, netmask) < 0)
                error("%s", pcap_geterr(pd));
++
 +      if (!bpf_validate(fcode.bf_insns, fcode.bf_len))
 +              warn("Filter doesn't pass validation");
++
+ #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);