*
* 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"
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;
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;
#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
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
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
/* 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.
*/
{
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);