summaryrefslogtreecommitdiffstats
path: root/freebsd/contrib/libpcap/optimize.c
diff options
context:
space:
mode:
Diffstat (limited to 'freebsd/contrib/libpcap/optimize.c')
-rw-r--r--freebsd/contrib/libpcap/optimize.c318
1 files changed, 242 insertions, 76 deletions
diff --git a/freebsd/contrib/libpcap/optimize.c b/freebsd/contrib/libpcap/optimize.c
index 7d2a1826..3c401d7d 100644
--- a/freebsd/contrib/libpcap/optimize.c
+++ b/freebsd/contrib/libpcap/optimize.c
@@ -32,6 +32,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <memory.h>
+#include <setjmp.h>
#include <string.h>
#include <errno.h>
@@ -229,6 +230,16 @@ struct vmapinfo {
typedef struct {
/*
+ * Place to longjmp to on an error.
+ */
+ jmp_buf top_ctx;
+
+ /*
+ * The buffer into which to put error message.
+ */
+ char *errbuf;
+
+ /*
* A flag to indicate that further optimization is needed.
* Iterative passes are continued until a given pass yields no
* branch movement.
@@ -254,19 +265,19 @@ typedef struct {
* True if a is in uset {p}
*/
#define SET_MEMBER(p, a) \
-((p)[(unsigned)(a) / BITS_PER_WORD] & (1 << ((unsigned)(a) % BITS_PER_WORD)))
+((p)[(unsigned)(a) / BITS_PER_WORD] & ((bpf_u_int32)1 << ((unsigned)(a) % BITS_PER_WORD)))
/*
* Add 'a' to uset p.
*/
#define SET_INSERT(p, a) \
-(p)[(unsigned)(a) / BITS_PER_WORD] |= (1 << ((unsigned)(a) % BITS_PER_WORD))
+(p)[(unsigned)(a) / BITS_PER_WORD] |= ((bpf_u_int32)1 << ((unsigned)(a) % BITS_PER_WORD))
/*
* Delete 'a' from uset p.
*/
#define SET_DELETE(p, a) \
-(p)[(unsigned)(a) / BITS_PER_WORD] &= ~(1 << ((unsigned)(a) % BITS_PER_WORD))
+(p)[(unsigned)(a) / BITS_PER_WORD] &= ~((bpf_u_int32)1 << ((unsigned)(a) % BITS_PER_WORD))
/*
* a := a intersect b
@@ -314,6 +325,16 @@ typedef struct {
typedef struct {
/*
+ * Place to longjmp to on an error.
+ */
+ jmp_buf top_ctx;
+
+ /*
+ * The buffer into which to put error message.
+ */
+ char *errbuf;
+
+ /*
* Some pointers used to convert the basic block form of the code,
* into the array form that BPF requires. 'fstart' will point to
* the malloc'd array while 'ftail' is used during the recursive
@@ -323,14 +344,16 @@ typedef struct {
struct bpf_insn *ftail;
} conv_state_t;
-static void opt_init(compiler_state_t *, opt_state_t *, struct icode *);
+static void opt_init(opt_state_t *, struct icode *);
static void opt_cleanup(opt_state_t *);
+static void PCAP_NORETURN opt_error(opt_state_t *, const char *, ...)
+ PCAP_PRINTFLIKE(2, 3);
static void intern_blocks(opt_state_t *, struct icode *);
static void find_inedges(opt_state_t *, struct block *);
#ifdef BDEBUG
-static void opt_dump(compiler_state_t *, struct icode *);
+static void opt_dump(opt_state_t *, struct icode *);
#endif
#ifndef MAX
@@ -663,7 +686,7 @@ F(opt_state_t *opt_state, int code, int v0, int v1)
int val;
struct valnode *p;
- hash = (u_int)code ^ (v0 << 4) ^ (v1 << 8);
+ hash = (u_int)code ^ ((u_int)v0 << 4) ^ ((u_int)v1 << 8);
hash %= MODULUS;
for (p = opt_state->hashtbl[hash]; p; p = p->next)
@@ -701,8 +724,7 @@ vstore(struct stmt *s, int *valp, int newval, int alter)
* (Unary operators are handled elsewhere.)
*/
static void
-fold_op(compiler_state_t *cstate, opt_state_t *opt_state,
- struct stmt *s, int v0, int v1)
+fold_op(opt_state_t *opt_state, struct stmt *s, int v0, int v1)
{
bpf_u_int32 a, b;
@@ -724,13 +746,13 @@ fold_op(compiler_state_t *cstate, opt_state_t *opt_state,
case BPF_DIV:
if (b == 0)
- bpf_error(cstate, "division by zero");
+ opt_error(opt_state, "division by zero");
a /= b;
break;
case BPF_MOD:
if (b == 0)
- bpf_error(cstate, "modulus by zero");
+ opt_error(opt_state, "modulus by zero");
a %= b;
break;
@@ -747,11 +769,39 @@ fold_op(compiler_state_t *cstate, opt_state_t *opt_state,
break;
case BPF_LSH:
- a <<= b;
+ /*
+ * A left shift of more than the width of the type
+ * is undefined in C; we'll just treat it as shifting
+ * all the bits out.
+ *
+ * XXX - the BPF interpreter doesn't check for this,
+ * so its behavior is dependent on the behavior of
+ * the processor on which it's running. There are
+ * processors on which it shifts all the bits out
+ * and processors on which it does no shift.
+ */
+ if (b < 32)
+ a <<= b;
+ else
+ a = 0;
break;
case BPF_RSH:
- a >>= b;
+ /*
+ * A right shift of more than the width of the type
+ * is undefined in C; we'll just treat it as shifting
+ * all the bits out.
+ *
+ * XXX - the BPF interpreter doesn't check for this,
+ * so its behavior is dependent on the behavior of
+ * the processor on which it's running. There are
+ * processors on which it shifts all the bits out
+ * and processors on which it does no shift.
+ */
+ if (b < 32)
+ a >>= b;
+ else
+ a = 0;
break;
default:
@@ -1043,8 +1093,7 @@ opt_peep(opt_state_t *opt_state, struct block *b)
* evaluation and code transformations weren't folded together.
*/
static void
-opt_stmt(compiler_state_t *cstate, opt_state_t *opt_state,
- struct stmt *s, int val[], int alter)
+opt_stmt(opt_state_t *opt_state, struct stmt *s, int val[], int alter)
{
int op;
int v;
@@ -1096,7 +1145,23 @@ opt_stmt(compiler_state_t *cstate, opt_state_t *opt_state,
case BPF_ALU|BPF_NEG:
if (alter && opt_state->vmap[val[A_ATOM]].is_const) {
s->code = BPF_LD|BPF_IMM;
- s->k = -opt_state->vmap[val[A_ATOM]].const_val;
+ /*
+ * Do this negation as unsigned arithmetic; that's
+ * what modern BPF engines do, and it guarantees
+ * that all possible values can be negated. (Yeah,
+ * negating 0x80000000, the minimum signed 32-bit
+ * two's-complement value, results in 0x80000000,
+ * so it's still negative, but we *should* be doing
+ * all unsigned arithmetic here, to match what
+ * modern BPF engines do.)
+ *
+ * Express it as 0U - (unsigned value) so that we
+ * don't get compiler warnings about negating an
+ * unsigned value and don't get UBSan warnings
+ * about the result of negating 0x80000000 being
+ * undefined.
+ */
+ s->k = 0U - (bpf_u_int32)(opt_state->vmap[val[A_ATOM]].const_val);
val[A_ATOM] = K(s->k);
}
else
@@ -1116,9 +1181,17 @@ opt_stmt(compiler_state_t *cstate, opt_state_t *opt_state,
op = BPF_OP(s->code);
if (alter) {
if (s->k == 0) {
- /* don't optimize away "sub #0"
+ /*
+ * Optimize operations where the constant
+ * is zero.
+ *
+ * Don't optimize away "sub #0"
* as it may be needed later to
- * fixup the generated math code */
+ * fixup the generated math code.
+ *
+ * Fail if we're dividing by zero or taking
+ * a modulus by zero.
+ */
if (op == BPF_ADD ||
op == BPF_LSH || op == BPF_RSH ||
op == BPF_OR || op == BPF_XOR) {
@@ -1130,9 +1203,15 @@ opt_stmt(compiler_state_t *cstate, opt_state_t *opt_state,
val[A_ATOM] = K(s->k);
break;
}
+ if (op == BPF_DIV)
+ opt_error(opt_state,
+ "division by zero");
+ if (op == BPF_MOD)
+ opt_error(opt_state,
+ "modulus by zero");
}
if (opt_state->vmap[val[A_ATOM]].is_const) {
- fold_op(cstate, opt_state, s, val[A_ATOM], K(s->k));
+ fold_op(opt_state, s, val[A_ATOM], K(s->k));
val[A_ATOM] = K(s->k);
break;
}
@@ -1153,12 +1232,22 @@ opt_stmt(compiler_state_t *cstate, opt_state_t *opt_state,
op = BPF_OP(s->code);
if (alter && opt_state->vmap[val[X_ATOM]].is_const) {
if (opt_state->vmap[val[A_ATOM]].is_const) {
- fold_op(cstate, opt_state, s, val[A_ATOM], val[X_ATOM]);
+ fold_op(opt_state, s, val[A_ATOM], val[X_ATOM]);
val[A_ATOM] = K(s->k);
}
else {
s->code = BPF_ALU|BPF_K|op;
s->k = opt_state->vmap[val[X_ATOM]].const_val;
+ /*
+ * XXX - we need to make up our minds
+ * as to what integers are signed and
+ * what integers are unsigned in BPF
+ * programs and in our IR.
+ */
+ if ((op == BPF_LSH || op == BPF_RSH) &&
+ (s->k < 0 || s->k > 31))
+ opt_error(opt_state,
+ "shift by more than 31 bits");
opt_state->done = 0;
val[A_ATOM] =
F(opt_state, s->code, val[A_ATOM], K(s->k));
@@ -1277,8 +1366,7 @@ opt_deadstores(opt_state_t *opt_state, register struct block *b)
}
static void
-opt_blk(compiler_state_t *cstate, opt_state_t *opt_state,
- struct block *b, int do_stmts)
+opt_blk(opt_state_t *opt_state, struct block *b, int do_stmts)
{
struct slist *s;
struct edge *p;
@@ -1328,7 +1416,7 @@ opt_blk(compiler_state_t *cstate, opt_state_t *opt_state,
aval = b->val[A_ATOM];
xval = b->val[X_ATOM];
for (s = b->stmts; s; s = s->next)
- opt_stmt(cstate, opt_state, &s->s, b->val, do_stmts);
+ opt_stmt(opt_state, &s->s, b->val, do_stmts);
/*
* This is a special case: if we don't use anything from this
@@ -1482,7 +1570,7 @@ opt_j(opt_state_t *opt_state, struct edge *ep)
while (x != 0) {
k = lowest_set_bit(x);
- x &=~ (1 << k);
+ x &=~ ((bpf_u_int32)1 << k);
k += i * BITS_PER_WORD;
target = fold_edge(ep->succ, opt_state->edges[k]);
@@ -1689,8 +1777,7 @@ and_pullup(opt_state_t *opt_state, struct block *b)
}
static void
-opt_blks(compiler_state_t *cstate, opt_state_t *opt_state, struct icode *ic,
- int do_stmts)
+opt_blks(opt_state_t *opt_state, struct icode *ic, int do_stmts)
{
int i, maxlevel;
struct block *p;
@@ -1701,7 +1788,7 @@ opt_blks(compiler_state_t *cstate, opt_state_t *opt_state, struct icode *ic,
find_inedges(opt_state, ic->root);
for (i = maxlevel; i >= 0; --i)
for (p = opt_state->levels[i]; p; p = p->link)
- opt_blk(cstate, opt_state, p, do_stmts);
+ opt_blk(opt_state, p, do_stmts);
if (do_stmts)
/*
@@ -1779,14 +1866,13 @@ opt_root(struct block **b)
}
static void
-opt_loop(compiler_state_t *cstate, opt_state_t *opt_state, struct icode *ic,
- int do_stmts)
+opt_loop(opt_state_t *opt_state, struct icode *ic, int do_stmts)
{
#ifdef BDEBUG
if (pcap_optimizer_debug > 1 || pcap_print_dot_graph) {
printf("opt_loop(root, %d) begin\n", do_stmts);
- opt_dump(cstate, ic);
+ opt_dump(opt_state, ic);
}
#endif
do {
@@ -1796,11 +1882,11 @@ opt_loop(compiler_state_t *cstate, opt_state_t *opt_state, struct icode *ic,
find_closure(opt_state, ic->root);
find_ud(opt_state, ic->root);
find_edom(opt_state, ic->root);
- opt_blks(cstate, opt_state, ic, do_stmts);
+ opt_blks(opt_state, ic, do_stmts);
#ifdef BDEBUG
if (pcap_optimizer_debug > 1 || pcap_print_dot_graph) {
printf("opt_loop(root, %d) bottom, done=%d\n", do_stmts, opt_state->done);
- opt_dump(cstate, ic);
+ opt_dump(opt_state, ic);
}
#endif
} while (!opt_state->done);
@@ -1808,30 +1894,38 @@ opt_loop(compiler_state_t *cstate, opt_state_t *opt_state, struct icode *ic,
/*
* Optimize the filter code in its dag representation.
+ * Return 0 on success, -1 on error.
*/
-void
-bpf_optimize(compiler_state_t *cstate, struct icode *ic)
+int
+bpf_optimize(struct icode *ic, char *errbuf)
{
opt_state_t opt_state;
- opt_init(cstate, &opt_state, ic);
- opt_loop(cstate, &opt_state, ic, 0);
- opt_loop(cstate, &opt_state, ic, 1);
+ memset(&opt_state, 0, sizeof(opt_state));
+ opt_state.errbuf = errbuf;
+ if (setjmp(opt_state.top_ctx)) {
+ opt_cleanup(&opt_state);
+ return -1;
+ }
+ opt_init(&opt_state, ic);
+ opt_loop(&opt_state, ic, 0);
+ opt_loop(&opt_state, ic, 1);
intern_blocks(&opt_state, ic);
#ifdef BDEBUG
if (pcap_optimizer_debug > 1 || pcap_print_dot_graph) {
printf("after intern_blocks()\n");
- opt_dump(cstate, ic);
+ opt_dump(&opt_state, ic);
}
#endif
opt_root(&ic->root);
#ifdef BDEBUG
if (pcap_optimizer_debug > 1 || pcap_print_dot_graph) {
printf("after opt_root()\n");
- opt_dump(cstate, ic);
+ opt_dump(&opt_state, ic);
}
#endif
opt_cleanup(&opt_state);
+ return 0;
}
static void
@@ -1946,6 +2040,24 @@ opt_cleanup(opt_state_t *opt_state)
}
/*
+ * For optimizer errors.
+ */
+static void PCAP_NORETURN
+opt_error(opt_state_t *opt_state, const char *fmt, ...)
+{
+ va_list ap;
+
+ if (opt_state->errbuf != NULL) {
+ va_start(ap, fmt);
+ (void)pcap_vsnprintf(opt_state->errbuf,
+ PCAP_ERRBUF_SIZE, fmt, ap);
+ va_end(ap);
+ }
+ longjmp(opt_state->top_ctx, 1);
+ /* NOTREACHED */
+}
+
+/*
* Return the number of stmts in 's'.
*/
static u_int
@@ -2029,7 +2141,7 @@ count_stmts(struct icode *ic, struct block *p)
* from the total number of blocks and/or statements.
*/
static void
-opt_init(compiler_state_t *cstate, opt_state_t *opt_state, struct icode *ic)
+opt_init(opt_state_t *opt_state, struct icode *ic)
{
bpf_u_int32 *p;
int i, n, max_stmts;
@@ -2042,22 +2154,24 @@ opt_init(compiler_state_t *cstate, opt_state_t *opt_state, struct icode *ic)
n = count_blocks(ic, ic->root);
opt_state->blocks = (struct block **)calloc(n, sizeof(*opt_state->blocks));
if (opt_state->blocks == NULL)
- bpf_error(cstate, "malloc");
+ opt_error(opt_state, "malloc");
unMarkAll(ic);
opt_state->n_blocks = 0;
number_blks_r(opt_state, ic, ic->root);
opt_state->n_edges = 2 * opt_state->n_blocks;
opt_state->edges = (struct edge **)calloc(opt_state->n_edges, sizeof(*opt_state->edges));
- if (opt_state->edges == NULL)
- bpf_error(cstate, "malloc");
+ if (opt_state->edges == NULL) {
+ opt_error(opt_state, "malloc");
+ }
/*
* The number of levels is bounded by the number of nodes.
*/
opt_state->levels = (struct block **)calloc(opt_state->n_blocks, sizeof(*opt_state->levels));
- if (opt_state->levels == NULL)
- bpf_error(cstate, "malloc");
+ if (opt_state->levels == NULL) {
+ opt_error(opt_state, "malloc");
+ }
opt_state->edgewords = opt_state->n_edges / (8 * sizeof(bpf_u_int32)) + 1;
opt_state->nodewords = opt_state->n_blocks / (8 * sizeof(bpf_u_int32)) + 1;
@@ -2065,8 +2179,9 @@ opt_init(compiler_state_t *cstate, opt_state_t *opt_state, struct icode *ic)
/* XXX */
opt_state->space = (bpf_u_int32 *)malloc(2 * opt_state->n_blocks * opt_state->nodewords * sizeof(*opt_state->space)
+ opt_state->n_edges * opt_state->edgewords * sizeof(*opt_state->space));
- if (opt_state->space == NULL)
- bpf_error(cstate, "malloc");
+ if (opt_state->space == NULL) {
+ opt_error(opt_state, "malloc");
+ }
p = opt_state->space;
opt_state->all_dom_sets = p;
for (i = 0; i < n; ++i) {
@@ -2103,9 +2218,13 @@ opt_init(compiler_state_t *cstate, opt_state_t *opt_state, struct icode *ic)
*/
opt_state->maxval = 3 * max_stmts;
opt_state->vmap = (struct vmapinfo *)calloc(opt_state->maxval, sizeof(*opt_state->vmap));
+ if (opt_state->vmap == NULL) {
+ opt_error(opt_state, "malloc");
+ }
opt_state->vnode_base = (struct valnode *)calloc(opt_state->maxval, sizeof(*opt_state->vnode_base));
- if (opt_state->vmap == NULL || opt_state->vnode_base == NULL)
- bpf_error(cstate, "malloc");
+ if (opt_state->vnode_base == NULL) {
+ opt_error(opt_state, "malloc");
+ }
}
/*
@@ -2117,6 +2236,9 @@ opt_init(compiler_state_t *cstate, opt_state_t *opt_state, struct icode *ic)
int bids[NBIDS];
#endif
+static void PCAP_NORETURN conv_error(conv_state_t *, const char *, ...)
+ PCAP_PRINTFLIKE(2, 3);
+
/*
* Returns true if successful. Returns false if a branch has
* an offset that is too large. If so, we have marked that
@@ -2124,8 +2246,7 @@ int bids[NBIDS];
* properly.
*/
static int
-convert_code_r(compiler_state_t *cstate, conv_state_t *conv_state,
- struct icode *ic, struct block *p)
+convert_code_r(conv_state_t *conv_state, struct icode *ic, struct block *p)
{
struct bpf_insn *dst;
struct slist *src;
@@ -2138,9 +2259,9 @@ convert_code_r(compiler_state_t *cstate, conv_state_t *conv_state,
return (1);
Mark(ic, p);
- if (convert_code_r(cstate, conv_state, ic, JF(p)) == 0)
+ if (convert_code_r(conv_state, ic, JF(p)) == 0)
return (0);
- if (convert_code_r(cstate, conv_state, ic, JT(p)) == 0)
+ if (convert_code_r(conv_state, ic, JT(p)) == 0)
return (0);
slen = slength(p->stmts);
@@ -2153,7 +2274,7 @@ convert_code_r(compiler_state_t *cstate, conv_state_t *conv_state,
if (slen) {
offset = (struct slist **)calloc(slen, sizeof(struct slist *));
if (!offset) {
- bpf_error(cstate, "not enough core");
+ conv_error(conv_state, "not enough core");
/*NOTREACHED*/
}
}
@@ -2177,7 +2298,8 @@ convert_code_r(compiler_state_t *cstate, conv_state_t *conv_state,
if (BPF_CLASS(src->s.code) != BPF_JMP || src->s.code == (BPF_JMP|BPF_JA)) {
#if 0
if (src->s.jt || src->s.jf) {
- bpf_error(cstate, "illegal jmp destination");
+ free(offset);
+ conv_error(conv_state, "illegal jmp destination");
/*NOTREACHED*/
}
#endif
@@ -2197,7 +2319,8 @@ convert_code_r(compiler_state_t *cstate, conv_state_t *conv_state,
#endif
if (!src->s.jt || !src->s.jf) {
- bpf_error(cstate, ljerr, "no jmp destination", off);
+ free(offset);
+ conv_error(conv_state, ljerr, "no jmp destination", off);
/*NOTREACHED*/
}
@@ -2205,12 +2328,14 @@ convert_code_r(compiler_state_t *cstate, conv_state_t *conv_state,
for (i = 0; i < slen; i++) {
if (offset[i] == src->s.jt) {
if (jt) {
- bpf_error(cstate, ljerr, "multiple matches", off);
+ free(offset);
+ conv_error(conv_state, ljerr, "multiple matches", off);
/*NOTREACHED*/
}
if (i - off - 1 >= 256) {
- bpf_error(cstate, ljerr, "out-of-range jump", off);
+ free(offset);
+ conv_error(conv_state, ljerr, "out-of-range jump", off);
/*NOTREACHED*/
}
dst->jt = (u_char)(i - off - 1);
@@ -2218,11 +2343,13 @@ convert_code_r(compiler_state_t *cstate, conv_state_t *conv_state,
}
if (offset[i] == src->s.jf) {
if (jf) {
- bpf_error(cstate, ljerr, "multiple matches", off);
+ free(offset);
+ conv_error(conv_state, ljerr, "multiple matches", off);
/*NOTREACHED*/
}
if (i - off - 1 >= 256) {
- bpf_error(cstate, ljerr, "out-of-range jump", off);
+ free(offset);
+ conv_error(conv_state, ljerr, "out-of-range jump", off);
/*NOTREACHED*/
}
dst->jf = (u_char)(i - off - 1);
@@ -2230,7 +2357,8 @@ convert_code_r(compiler_state_t *cstate, conv_state_t *conv_state,
}
}
if (!jt || !jf) {
- bpf_error(cstate, ljerr, "no destination found", off);
+ free(offset);
+ conv_error(conv_state, ljerr, "no destination found", off);
/*NOTREACHED*/
}
}
@@ -2259,7 +2387,7 @@ filled:
}
/* branch if T to following jump */
if (extrajmps >= 256) {
- bpf_error(cstate, "too many extra jumps");
+ conv_error(conv_state, "too many extra jumps");
/*NOTREACHED*/
}
dst->jt = (u_char)extrajmps;
@@ -2280,7 +2408,7 @@ filled:
/* branch if F to following jump */
/* if two jumps are inserted, F goes to second one */
if (extrajmps >= 256) {
- bpf_error(cstate, "too many extra jumps");
+ conv_error(conv_state, "too many extra jumps");
/*NOTREACHED*/
}
dst->jf = (u_char)extrajmps;
@@ -2314,13 +2442,20 @@ filled:
* done with the filter program. See the pcap man page.
*/
struct bpf_insn *
-icode_to_fcode(compiler_state_t *cstate, struct icode *ic,
- struct block *root, u_int *lenp)
+icode_to_fcode(struct icode *ic, struct block *root, u_int *lenp,
+ char *errbuf)
{
u_int n;
struct bpf_insn *fp;
conv_state_t conv_state;
+ conv_state.fstart = NULL;
+ conv_state.errbuf = errbuf;
+ if (setjmp(conv_state.top_ctx) != 0) {
+ free(conv_state.fstart);
+ return NULL;
+ }
+
/*
* Loop doing convert_code_r() until no branches remain
* with too-large offsets.
@@ -2330,14 +2465,18 @@ icode_to_fcode(compiler_state_t *cstate, struct icode *ic,
n = *lenp = count_stmts(ic, root);
fp = (struct bpf_insn *)malloc(sizeof(*fp) * n);
- if (fp == NULL)
- bpf_error(cstate, "malloc");
+ if (fp == NULL) {
+ (void)pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE,
+ "malloc");
+ free(fp);
+ return NULL;
+ }
memset((char *)fp, 0, sizeof(*fp) * n);
conv_state.fstart = fp;
conv_state.ftail = fp + n;
unMarkAll(ic);
- if (convert_code_r(cstate, &conv_state, ic, root))
+ if (convert_code_r(&conv_state, ic, root))
break;
free(fp);
}
@@ -2346,6 +2485,22 @@ icode_to_fcode(compiler_state_t *cstate, struct icode *ic,
}
/*
+ * For iconv_to_fconv() errors.
+ */
+static void PCAP_NORETURN
+conv_error(conv_state_t *conv_state, const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ (void)pcap_vsnprintf(conv_state->errbuf,
+ PCAP_ERRBUF_SIZE, fmt, ap);
+ va_end(ap);
+ longjmp(conv_state->top_ctx, 1);
+ /* NOTREACHED */
+}
+
+/*
* Make a copy of a BPF program and put it in the "fcode" member of
* a "pcap_t".
*
@@ -2454,14 +2609,16 @@ dot_dump_edge(struct icode *ic, struct block *block, FILE *out)
* 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(compiler_state_t *cstate, struct icode *ic)
+static int
+dot_dump(struct icode *ic, char *errbuf)
{
struct bpf_program f;
FILE *out = stdout;
memset(bids, 0, sizeof bids);
- f.bf_insns = icode_to_fcode(cstate, ic, ic->root, &f.bf_len);
+ f.bf_insns = icode_to_fcode(ic, ic->root, &f.bf_len, errbuf);
+ if (f.bf_insns == NULL)
+ return -1;
fprintf(out, "digraph BPF {\n");
unMarkAll(ic);
@@ -2471,30 +2628,39 @@ dot_dump(compiler_state_t *cstate, struct icode *ic)
fprintf(out, "}\n");
free((char *)f.bf_insns);
+ return 0;
}
-static void
-plain_dump(compiler_state_t *cstate, struct icode *ic)
+static int
+plain_dump(struct icode *ic, char *errbuf)
{
struct bpf_program f;
memset(bids, 0, sizeof bids);
- f.bf_insns = icode_to_fcode(cstate, ic, ic->root, &f.bf_len);
+ f.bf_insns = icode_to_fcode(ic, ic->root, &f.bf_len, errbuf);
+ if (f.bf_insns == NULL)
+ return -1;
bpf_dump(&f, 1);
putchar('\n');
free((char *)f.bf_insns);
+ return 0;
}
static void
-opt_dump(compiler_state_t *cstate, struct icode *ic)
+opt_dump(opt_state_t *opt_state, struct icode *ic)
{
+ int status;
+ char errbuf[PCAP_ERRBUF_SIZE];
+
/*
* If the CFG, in DOT format, is requested, output it rather than
* the code that would be generated from that graph.
*/
if (pcap_print_dot_graph)
- dot_dump(cstate, ic);
+ status = dot_dump(ic, errbuf);
else
- plain_dump(cstate, ic);
+ status = plain_dump(ic, errbuf);
+ if (status == -1)
+ opt_error(opt_state, "opt_dump: icode_to_fcode failed: %s", errbuf);
}
#endif