📄 optimize.c
字号:
opt_root(rootp);
#ifdef BDEBUG
if (dflag > 1) {
printf("after opt_root()\n");
opt_dump(root);
}
#endif
opt_cleanup();
}
static void
make_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 void
mark_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 int
eq_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 int
eq_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 void
intern_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 void
opt_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 int
slength(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 int
count_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 void
number_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 int
count_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 void
opt_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));
unMarkAll();
n_blocks = 0;
number_blks_r(root);
n_edges = 2 * n_blocks;
edges = (struct edge **)malloc(n_edges * sizeof(*edges));
/*
* The number of levels is bounded by the number of nodes.
*/
levels = (struct block **)malloc(n_blocks * sizeof(*levels));
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));
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));
}
/*
* 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 BDEBUG
int 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 int
convert_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);
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.
*/
int
install_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 BDEBUG
static void
opt_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 + -