📄 optimize.c
字号:
}#endif } while (!done);}/* * Optimize the filter code in its dag representation. */voidbpf_optimize(rootp) struct block **rootp;{ struct block *root; root = *rootp; opt_init(root); opt_loop(root, 0); opt_loop(root, 1); intern_blocks(root);#ifdef BDEBUG if (dflag > 1) { printf("after intern_blocks()\n"); opt_dump(root); }#endif opt_root(rootp);#ifdef BDEBUG if (dflag > 1) { printf("after opt_root()\n"); opt_dump(root); }#endif opt_cleanup();}static voidmake_marks(p) struct block *p;{ if (!isMarked(p)) { Mark(p); if (BPF_CLASS(p->s.code) != BPF_RET) { make_marks(JT(p)); make_marks(JF(p)); } }}/* * Mark code array such that isMarked(i) is true * only for nodes that are alive. */static voidmark_code(p) struct block *p;{ cur_mark += 1; make_marks(p);}/* * True iff the two stmt lists load the same value from the packet into * the accumulator. */static inteq_slist(x, y) struct slist *x, *y;{ while (1) { while (x && x->s.code == NOP) x = x->next; while (y && y->s.code == NOP) y = y->next; if (x == 0) return y == 0; if (y == 0) return x == 0; if (x->s.code != y->s.code || x->s.k != y->s.k) return 0; x = x->next; y = y->next; }}static inline inteq_blk(b0, b1) struct block *b0, *b1;{ if (b0->s.code == b1->s.code && b0->s.k == b1->s.k && b0->et.succ == b1->et.succ && b0->ef.succ == b1->ef.succ) return eq_slist(b0->stmts, b1->stmts); return 0;}static voidintern_blocks(root) struct block *root;{ struct block *p; int i, j; int done; top: done = 1; for (i = 0; i < n_blocks; ++i) blocks[i]->link = 0; mark_code(root); for (i = n_blocks - 1; --i >= 0; ) { if (!isMarked(blocks[i])) continue; for (j = i + 1; j < n_blocks; ++j) { if (!isMarked(blocks[j])) continue; if (eq_blk(blocks[i], blocks[j])) { blocks[i]->link = blocks[j]->link ? blocks[j]->link : blocks[j]; break; } } } for (i = 0; i < n_blocks; ++i) { p = blocks[i]; if (JT(p) == 0) continue; if (JT(p)->link) { done = 0; JT(p) = JT(p)->link; } if (JF(p)->link) { done = 0; JF(p) = JF(p)->link; } } if (!done) goto top;}static voidopt_cleanup(){ free((void *)vnode_base); free((void *)vmap); free((void *)edges); free((void *)space); free((void *)levels); free((void *)blocks);}/* * Return the number of stmts in 's'. */static intslength(s) struct slist *s;{ int n = 0; for (; s; s = s->next) if (s->s.code != NOP) ++n; return n;}/* * Return the number of nodes reachable by 'p'. * All nodes should be initially unmarked. */static intcount_blocks(p) struct block *p;{ if (p == 0 || isMarked(p)) return 0; Mark(p); return count_blocks(JT(p)) + count_blocks(JF(p)) + 1;}/* * Do a depth first search on the flow graph, numbering the * the basic blocks, and entering them into the 'blocks' array.` */static voidnumber_blks_r(p) struct block *p;{ int n; if (p == 0 || isMarked(p)) return; Mark(p); n = n_blocks++; p->id = n; blocks[n] = p; number_blks_r(JT(p)); number_blks_r(JF(p));}/* * Return the number of stmts in the flowgraph reachable by 'p'. * The nodes should be unmarked before calling. * * Note that "stmts" means "instructions", and that this includes * * side-effect statements in 'p' (slength(p->stmts)); * * statements in the true branch from 'p' (count_stmts(JT(p))); * * statements in the false branch from 'p' (count_stmts(JF(p))); * * the conditional jump itself (1); * * an extra long jump if the true branch requires it (p->longjt); * * an extra long jump if the false branch requires it (p->longjf). */static intcount_stmts(p) struct block *p;{ int n; if (p == 0 || isMarked(p)) return 0; Mark(p); n = count_stmts(JT(p)) + count_stmts(JF(p)); return slength(p->stmts) + n + 1 + p->longjt + p->longjf;}/* * Allocate memory. All allocation is done before optimization * is begun. A linear bound on the size of all data structures is computed * from the total number of blocks and/or statements. */static voidopt_init(root) struct block *root;{ bpf_u_int32 *p; int i, n, max_stmts; /* * First, count the blocks, so we can malloc an array to map * block number to block. Then, put the blocks into the array. */ unMarkAll(); n = count_blocks(root); blocks = (struct block **)malloc(n * sizeof(*blocks)); if (blocks == NULL) bpf_error("malloc"); unMarkAll(); n_blocks = 0; number_blks_r(root); n_edges = 2 * n_blocks; edges = (struct edge **)malloc(n_edges * sizeof(*edges)); if (edges == NULL) bpf_error("malloc"); /* * The number of levels is bounded by the number of nodes. */ levels = (struct block **)malloc(n_blocks * sizeof(*levels)); if (levels == NULL) bpf_error("malloc"); edgewords = n_edges / (8 * sizeof(bpf_u_int32)) + 1; nodewords = n_blocks / (8 * sizeof(bpf_u_int32)) + 1; /* XXX */ space = (bpf_u_int32 *)malloc(2 * n_blocks * nodewords * sizeof(*space) + n_edges * edgewords * sizeof(*space)); if (space == NULL) bpf_error("malloc"); p = space; all_dom_sets = p; for (i = 0; i < n; ++i) { blocks[i]->dom = p; p += nodewords; } all_closure_sets = p; for (i = 0; i < n; ++i) { blocks[i]->closure = p; p += nodewords; } all_edge_sets = p; for (i = 0; i < n; ++i) { register struct block *b = blocks[i]; b->et.edom = p; p += edgewords; b->ef.edom = p; p += edgewords; b->et.id = i; edges[i] = &b->et; b->ef.id = n_blocks + i; edges[n_blocks + i] = &b->ef; b->et.pred = b; b->ef.pred = b; } max_stmts = 0; for (i = 0; i < n; ++i) max_stmts += slength(blocks[i]->stmts) + 1; /* * We allocate at most 3 value numbers per statement, * so this is an upper bound on the number of valnodes * we'll need. */ maxval = 3 * max_stmts; vmap = (struct vmapinfo *)malloc(maxval * sizeof(*vmap)); vnode_base = (struct valnode *)malloc(maxval * sizeof(*vnode_base)); if (vmap == NULL || vnode_base == NULL) bpf_error("malloc");}/* * 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 traversal. */static struct bpf_insn *fstart;static struct bpf_insn *ftail;#ifdef BDEBUGint bids[1000];#endif/* * Returns true if successful. Returns false if a branch has * an offset that is too large. If so, we have marked that * branch so that on a subsequent iteration, it will be treated * properly. */static intconvert_code_r(p) struct block *p;{ struct bpf_insn *dst; struct slist *src; int slen; u_int off; int extrajmps; /* number of extra jumps inserted */ struct slist **offset = NULL; if (p == 0 || isMarked(p)) return (1); Mark(p); if (convert_code_r(JF(p)) == 0) return (0); if (convert_code_r(JT(p)) == 0) return (0); slen = slength(p->stmts); dst = ftail -= (slen + 1 + p->longjt + p->longjf); /* inflate length by any extra jumps */ p->offset = dst - fstart; /* generate offset[] for convenience */ if (slen) { offset = (struct slist **)calloc(slen, sizeof(struct slist *)); if (!offset) { bpf_error("not enough core"); /*NOTREACHED*/ } } src = p->stmts; for (off = 0; off < slen && src; off++) {#if 0 printf("off=%d src=%x\n", off, src);#endif offset[off] = src; src = src->next; } off = 0; for (src = p->stmts; src; src = src->next) { if (src->s.code == NOP) continue; dst->code = (u_short)src->s.code; dst->k = src->s.k; /* fill block-local relative jump */ 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("illegal jmp destination"); /*NOTREACHED*/ }#endif goto filled; } if (off == slen - 2) /*???*/ goto filled; { int i; int jt, jf; char *ljerr = "%s for block-local relative jump: off=%d";#if 0 printf("code=%x off=%d %x %x\n", src->s.code, off, src->s.jt, src->s.jf);#endif if (!src->s.jt || !src->s.jf) { bpf_error(ljerr, "no jmp destination", off); /*NOTREACHED*/ } jt = jf = 0; for (i = 0; i < slen; i++) { if (offset[i] == src->s.jt) { if (jt) { bpf_error(ljerr, "multiple matches", off); /*NOTREACHED*/ } dst->jt = i - off - 1; jt++; } if (offset[i] == src->s.jf) { if (jf) { bpf_error(ljerr, "multiple matches", off); /*NOTREACHED*/ } dst->jf = i - off - 1; jf++; } } if (!jt || !jf) { bpf_error(ljerr, "no destination found", off); /*NOTREACHED*/ } }filled: ++dst; ++off; } if (offset) free(offset);#ifdef BDEBUG bids[dst - fstart] = p->id + 1;#endif dst->code = (u_short)p->s.code; dst->k = p->s.k; if (JT(p)) { extrajmps = 0; off = JT(p)->offset - (p->offset + slen) - 1; if (off >= 256) { /* offset too large for branch, must add a jump */ if (p->longjt == 0) { /* mark this instruction and retry */ p->longjt++; return(0); } /* branch if T to following jump */ dst->jt = extrajmps; extrajmps++; dst[extrajmps].code = BPF_JMP|BPF_JA; dst[extrajmps].k = off - extrajmps; } else dst->jt = off; off = JF(p)->offset - (p->offset + slen) - 1; if (off >= 256) { /* offset too large for branch, must add a jump */ if (p->longjf == 0) { /* mark this instruction and retry */ p->longjf++; return(0); } /* branch if F to following jump */ /* if two jumps are inserted, F goes to second one */ dst->jf = extrajmps; extrajmps++; dst[extrajmps].code = BPF_JMP|BPF_JA; dst[extrajmps].k = off - extrajmps; } else dst->jf = off; } return (1);}/* * Convert flowgraph intermediate representation to the * BPF array representation. Set *lenp to the number of instructions. */struct bpf_insn *icode_to_fcode(root, lenp) struct block *root; int *lenp;{ int n; struct bpf_insn *fp; /* * Loop doing convert_code_r() until no branches remain * with too-large offsets. */ while (1) { unMarkAll(); n = *lenp = count_stmts(root); fp = (struct bpf_insn *)malloc(sizeof(*fp) * n); if (fp == NULL) bpf_error("malloc"); memset((char *)fp, 0, sizeof(*fp) * n); fstart = fp; ftail = fp + n; unMarkAll(); if (convert_code_r(root)) break; free(fp); } return fp;}/* * Make a copy of a BPF program and put it in the "fcode" member of * a "pcap_t". * * If we fail to allocate memory for the copy, fill in the "errbuf" * member of the "pcap_t" with an error message, and return -1; * otherwise, return 0. */intinstall_bpf_program(pcap_t *p, struct bpf_program *fp){ size_t prog_size; /* * Free up any already installed program. */ pcap_freecode(&p->fcode); prog_size = sizeof(*fp->bf_insns) * fp->bf_len; p->fcode.bf_len = fp->bf_len; p->fcode.bf_insns = (struct bpf_insn *)malloc(prog_size); if (p->fcode.bf_insns == NULL) { snprintf(p->errbuf, sizeof(p->errbuf), "malloc: %s", pcap_strerror(errno)); return (-1); } memcpy(p->fcode.bf_insns, fp->bf_insns, prog_size); return (0);}#ifdef BDEBUGstatic voidopt_dump(root) struct block *root;{ struct bpf_program f; memset(bids, 0, sizeof bids); f.bf_insns = icode_to_fcode(root, &f.bf_len); bpf_dump(&f, 1); putchar('\n'); free((char *)f.bf_insns);}#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -