1*8b26181fSAndroid Build Coastguard Worker /*
2*8b26181fSAndroid Build Coastguard Worker * Copyright (c) 1988, 1989, 1990, 1991, 1993, 1994, 1995, 1996
3*8b26181fSAndroid Build Coastguard Worker * The Regents of the University of California. All rights reserved.
4*8b26181fSAndroid Build Coastguard Worker *
5*8b26181fSAndroid Build Coastguard Worker * Redistribution and use in source and binary forms, with or without
6*8b26181fSAndroid Build Coastguard Worker * modification, are permitted provided that: (1) source code distributions
7*8b26181fSAndroid Build Coastguard Worker * retain the above copyright notice and this paragraph in its entirety, (2)
8*8b26181fSAndroid Build Coastguard Worker * distributions including binary code include the above copyright notice and
9*8b26181fSAndroid Build Coastguard Worker * this paragraph in its entirety in the documentation or other materials
10*8b26181fSAndroid Build Coastguard Worker * provided with the distribution, and (3) all advertising materials mentioning
11*8b26181fSAndroid Build Coastguard Worker * features or use of this software display the following acknowledgement:
12*8b26181fSAndroid Build Coastguard Worker * ``This product includes software developed by the University of California,
13*8b26181fSAndroid Build Coastguard Worker * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
14*8b26181fSAndroid Build Coastguard Worker * the University nor the names of its contributors may be used to endorse
15*8b26181fSAndroid Build Coastguard Worker * or promote products derived from this software without specific prior
16*8b26181fSAndroid Build Coastguard Worker * written permission.
17*8b26181fSAndroid Build Coastguard Worker * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
18*8b26181fSAndroid Build Coastguard Worker * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
19*8b26181fSAndroid Build Coastguard Worker * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
20*8b26181fSAndroid Build Coastguard Worker *
21*8b26181fSAndroid Build Coastguard Worker * Optimization module for BPF code intermediate representation.
22*8b26181fSAndroid Build Coastguard Worker */
23*8b26181fSAndroid Build Coastguard Worker
24*8b26181fSAndroid Build Coastguard Worker #ifdef HAVE_CONFIG_H
25*8b26181fSAndroid Build Coastguard Worker #include <config.h>
26*8b26181fSAndroid Build Coastguard Worker #endif
27*8b26181fSAndroid Build Coastguard Worker
28*8b26181fSAndroid Build Coastguard Worker #include <pcap-types.h>
29*8b26181fSAndroid Build Coastguard Worker
30*8b26181fSAndroid Build Coastguard Worker #include <stdio.h>
31*8b26181fSAndroid Build Coastguard Worker #include <stdlib.h>
32*8b26181fSAndroid Build Coastguard Worker #include <memory.h>
33*8b26181fSAndroid Build Coastguard Worker #include <setjmp.h>
34*8b26181fSAndroid Build Coastguard Worker #include <string.h>
35*8b26181fSAndroid Build Coastguard Worker #include <limits.h> /* for SIZE_MAX */
36*8b26181fSAndroid Build Coastguard Worker #include <errno.h>
37*8b26181fSAndroid Build Coastguard Worker
38*8b26181fSAndroid Build Coastguard Worker #include "pcap-int.h"
39*8b26181fSAndroid Build Coastguard Worker
40*8b26181fSAndroid Build Coastguard Worker #include "gencode.h"
41*8b26181fSAndroid Build Coastguard Worker #include "optimize.h"
42*8b26181fSAndroid Build Coastguard Worker #include "diag-control.h"
43*8b26181fSAndroid Build Coastguard Worker
44*8b26181fSAndroid Build Coastguard Worker #ifdef HAVE_OS_PROTO_H
45*8b26181fSAndroid Build Coastguard Worker #include "os-proto.h"
46*8b26181fSAndroid Build Coastguard Worker #endif
47*8b26181fSAndroid Build Coastguard Worker
48*8b26181fSAndroid Build Coastguard Worker #ifdef BDEBUG
49*8b26181fSAndroid Build Coastguard Worker /*
50*8b26181fSAndroid Build Coastguard Worker * The internal "debug printout" flag for the filter expression optimizer.
51*8b26181fSAndroid Build Coastguard Worker * The code to print that stuff is present only if BDEBUG is defined, so
52*8b26181fSAndroid Build Coastguard Worker * the flag, and the routine to set it, are defined only if BDEBUG is
53*8b26181fSAndroid Build Coastguard Worker * defined.
54*8b26181fSAndroid Build Coastguard Worker */
55*8b26181fSAndroid Build Coastguard Worker static int pcap_optimizer_debug;
56*8b26181fSAndroid Build Coastguard Worker
57*8b26181fSAndroid Build Coastguard Worker /*
58*8b26181fSAndroid Build Coastguard Worker * Routine to set that flag.
59*8b26181fSAndroid Build Coastguard Worker *
60*8b26181fSAndroid Build Coastguard Worker * This is intended for libpcap developers, not for general use.
61*8b26181fSAndroid Build Coastguard Worker * If you want to set these in a program, you'll have to declare this
62*8b26181fSAndroid Build Coastguard Worker * routine yourself, with the appropriate DLL import attribute on Windows;
63*8b26181fSAndroid Build Coastguard Worker * it's not declared in any header file, and won't be declared in any
64*8b26181fSAndroid Build Coastguard Worker * header file provided by libpcap.
65*8b26181fSAndroid Build Coastguard Worker */
66*8b26181fSAndroid Build Coastguard Worker PCAP_API void pcap_set_optimizer_debug(int value);
67*8b26181fSAndroid Build Coastguard Worker
68*8b26181fSAndroid Build Coastguard Worker PCAP_API_DEF void
pcap_set_optimizer_debug(int value)69*8b26181fSAndroid Build Coastguard Worker pcap_set_optimizer_debug(int value)
70*8b26181fSAndroid Build Coastguard Worker {
71*8b26181fSAndroid Build Coastguard Worker pcap_optimizer_debug = value;
72*8b26181fSAndroid Build Coastguard Worker }
73*8b26181fSAndroid Build Coastguard Worker
74*8b26181fSAndroid Build Coastguard Worker /*
75*8b26181fSAndroid Build Coastguard Worker * The internal "print dot graph" flag for the filter expression optimizer.
76*8b26181fSAndroid Build Coastguard Worker * The code to print that stuff is present only if BDEBUG is defined, so
77*8b26181fSAndroid Build Coastguard Worker * the flag, and the routine to set it, are defined only if BDEBUG is
78*8b26181fSAndroid Build Coastguard Worker * defined.
79*8b26181fSAndroid Build Coastguard Worker */
80*8b26181fSAndroid Build Coastguard Worker static int pcap_print_dot_graph;
81*8b26181fSAndroid Build Coastguard Worker
82*8b26181fSAndroid Build Coastguard Worker /*
83*8b26181fSAndroid Build Coastguard Worker * Routine to set that flag.
84*8b26181fSAndroid Build Coastguard Worker *
85*8b26181fSAndroid Build Coastguard Worker * This is intended for libpcap developers, not for general use.
86*8b26181fSAndroid Build Coastguard Worker * If you want to set these in a program, you'll have to declare this
87*8b26181fSAndroid Build Coastguard Worker * routine yourself, with the appropriate DLL import attribute on Windows;
88*8b26181fSAndroid Build Coastguard Worker * it's not declared in any header file, and won't be declared in any
89*8b26181fSAndroid Build Coastguard Worker * header file provided by libpcap.
90*8b26181fSAndroid Build Coastguard Worker */
91*8b26181fSAndroid Build Coastguard Worker PCAP_API void pcap_set_print_dot_graph(int value);
92*8b26181fSAndroid Build Coastguard Worker
93*8b26181fSAndroid Build Coastguard Worker PCAP_API_DEF void
pcap_set_print_dot_graph(int value)94*8b26181fSAndroid Build Coastguard Worker pcap_set_print_dot_graph(int value)
95*8b26181fSAndroid Build Coastguard Worker {
96*8b26181fSAndroid Build Coastguard Worker pcap_print_dot_graph = value;
97*8b26181fSAndroid Build Coastguard Worker }
98*8b26181fSAndroid Build Coastguard Worker
99*8b26181fSAndroid Build Coastguard Worker #endif
100*8b26181fSAndroid Build Coastguard Worker
101*8b26181fSAndroid Build Coastguard Worker /*
102*8b26181fSAndroid Build Coastguard Worker * lowest_set_bit().
103*8b26181fSAndroid Build Coastguard Worker *
104*8b26181fSAndroid Build Coastguard Worker * Takes a 32-bit integer as an argument.
105*8b26181fSAndroid Build Coastguard Worker *
106*8b26181fSAndroid Build Coastguard Worker * If handed a non-zero value, returns the index of the lowest set bit,
107*8b26181fSAndroid Build Coastguard Worker * counting upwards from zero.
108*8b26181fSAndroid Build Coastguard Worker *
109*8b26181fSAndroid Build Coastguard Worker * If handed zero, the results are platform- and compiler-dependent.
110*8b26181fSAndroid Build Coastguard Worker * Keep it out of the light, don't give it any water, don't feed it
111*8b26181fSAndroid Build Coastguard Worker * after midnight, and don't pass zero to it.
112*8b26181fSAndroid Build Coastguard Worker *
113*8b26181fSAndroid Build Coastguard Worker * This is the same as the count of trailing zeroes in the word.
114*8b26181fSAndroid Build Coastguard Worker */
115*8b26181fSAndroid Build Coastguard Worker #if PCAP_IS_AT_LEAST_GNUC_VERSION(3,4)
116*8b26181fSAndroid Build Coastguard Worker /*
117*8b26181fSAndroid Build Coastguard Worker * GCC 3.4 and later; we have __builtin_ctz().
118*8b26181fSAndroid Build Coastguard Worker */
119*8b26181fSAndroid Build Coastguard Worker #define lowest_set_bit(mask) ((u_int)__builtin_ctz(mask))
120*8b26181fSAndroid Build Coastguard Worker #elif defined(_MSC_VER)
121*8b26181fSAndroid Build Coastguard Worker /*
122*8b26181fSAndroid Build Coastguard Worker * Visual Studio; we support only 2005 and later, so use
123*8b26181fSAndroid Build Coastguard Worker * _BitScanForward().
124*8b26181fSAndroid Build Coastguard Worker */
125*8b26181fSAndroid Build Coastguard Worker #include <intrin.h>
126*8b26181fSAndroid Build Coastguard Worker
127*8b26181fSAndroid Build Coastguard Worker #ifndef __clang__
128*8b26181fSAndroid Build Coastguard Worker #pragma intrinsic(_BitScanForward)
129*8b26181fSAndroid Build Coastguard Worker #endif
130*8b26181fSAndroid Build Coastguard Worker
131*8b26181fSAndroid Build Coastguard Worker static __forceinline u_int
lowest_set_bit(int mask)132*8b26181fSAndroid Build Coastguard Worker lowest_set_bit(int mask)
133*8b26181fSAndroid Build Coastguard Worker {
134*8b26181fSAndroid Build Coastguard Worker unsigned long bit;
135*8b26181fSAndroid Build Coastguard Worker
136*8b26181fSAndroid Build Coastguard Worker /*
137*8b26181fSAndroid Build Coastguard Worker * Don't sign-extend mask if long is longer than int.
138*8b26181fSAndroid Build Coastguard Worker * (It's currently not, in MSVC, even on 64-bit platforms, but....)
139*8b26181fSAndroid Build Coastguard Worker */
140*8b26181fSAndroid Build Coastguard Worker if (_BitScanForward(&bit, (unsigned int)mask) == 0)
141*8b26181fSAndroid Build Coastguard Worker abort(); /* mask is zero */
142*8b26181fSAndroid Build Coastguard Worker return (u_int)bit;
143*8b26181fSAndroid Build Coastguard Worker }
144*8b26181fSAndroid Build Coastguard Worker #elif defined(MSDOS) && defined(__DJGPP__)
145*8b26181fSAndroid Build Coastguard Worker /*
146*8b26181fSAndroid Build Coastguard Worker * MS-DOS with DJGPP, which declares ffs() in <string.h>, which
147*8b26181fSAndroid Build Coastguard Worker * we've already included.
148*8b26181fSAndroid Build Coastguard Worker */
149*8b26181fSAndroid Build Coastguard Worker #define lowest_set_bit(mask) ((u_int)(ffs((mask)) - 1))
150*8b26181fSAndroid Build Coastguard Worker #elif (defined(MSDOS) && defined(__WATCOMC__)) || defined(STRINGS_H_DECLARES_FFS)
151*8b26181fSAndroid Build Coastguard Worker /*
152*8b26181fSAndroid Build Coastguard Worker * MS-DOS with Watcom C, which has <strings.h> and declares ffs() there,
153*8b26181fSAndroid Build Coastguard Worker * or some other platform (UN*X conforming to a sufficient recent version
154*8b26181fSAndroid Build Coastguard Worker * of the Single UNIX Specification).
155*8b26181fSAndroid Build Coastguard Worker */
156*8b26181fSAndroid Build Coastguard Worker #include <strings.h>
157*8b26181fSAndroid Build Coastguard Worker #define lowest_set_bit(mask) (u_int)((ffs((mask)) - 1))
158*8b26181fSAndroid Build Coastguard Worker #else
159*8b26181fSAndroid Build Coastguard Worker /*
160*8b26181fSAndroid Build Coastguard Worker * None of the above.
161*8b26181fSAndroid Build Coastguard Worker * Use a perfect-hash-function-based function.
162*8b26181fSAndroid Build Coastguard Worker */
163*8b26181fSAndroid Build Coastguard Worker static u_int
lowest_set_bit(int mask)164*8b26181fSAndroid Build Coastguard Worker lowest_set_bit(int mask)
165*8b26181fSAndroid Build Coastguard Worker {
166*8b26181fSAndroid Build Coastguard Worker unsigned int v = (unsigned int)mask;
167*8b26181fSAndroid Build Coastguard Worker
168*8b26181fSAndroid Build Coastguard Worker static const u_int MultiplyDeBruijnBitPosition[32] = {
169*8b26181fSAndroid Build Coastguard Worker 0, 1, 28, 2, 29, 14, 24, 3, 30, 22, 20, 15, 25, 17, 4, 8,
170*8b26181fSAndroid Build Coastguard Worker 31, 27, 13, 23, 21, 19, 16, 7, 26, 12, 18, 6, 11, 5, 10, 9
171*8b26181fSAndroid Build Coastguard Worker };
172*8b26181fSAndroid Build Coastguard Worker
173*8b26181fSAndroid Build Coastguard Worker /*
174*8b26181fSAndroid Build Coastguard Worker * We strip off all but the lowermost set bit (v & ~v),
175*8b26181fSAndroid Build Coastguard Worker * and perform a minimal perfect hash on it to look up the
176*8b26181fSAndroid Build Coastguard Worker * number of low-order zero bits in a table.
177*8b26181fSAndroid Build Coastguard Worker *
178*8b26181fSAndroid Build Coastguard Worker * See:
179*8b26181fSAndroid Build Coastguard Worker *
180*8b26181fSAndroid Build Coastguard Worker * http://7ooo.mooo.com/text/ComputingTrailingZerosHOWTO.pdf
181*8b26181fSAndroid Build Coastguard Worker *
182*8b26181fSAndroid Build Coastguard Worker * http://supertech.csail.mit.edu/papers/debruijn.pdf
183*8b26181fSAndroid Build Coastguard Worker */
184*8b26181fSAndroid Build Coastguard Worker return (MultiplyDeBruijnBitPosition[((v & -v) * 0x077CB531U) >> 27]);
185*8b26181fSAndroid Build Coastguard Worker }
186*8b26181fSAndroid Build Coastguard Worker #endif
187*8b26181fSAndroid Build Coastguard Worker
188*8b26181fSAndroid Build Coastguard Worker /*
189*8b26181fSAndroid Build Coastguard Worker * Represents a deleted instruction.
190*8b26181fSAndroid Build Coastguard Worker */
191*8b26181fSAndroid Build Coastguard Worker #define NOP -1
192*8b26181fSAndroid Build Coastguard Worker
193*8b26181fSAndroid Build Coastguard Worker /*
194*8b26181fSAndroid Build Coastguard Worker * Register numbers for use-def values.
195*8b26181fSAndroid Build Coastguard Worker * 0 through BPF_MEMWORDS-1 represent the corresponding scratch memory
196*8b26181fSAndroid Build Coastguard Worker * location. A_ATOM is the accumulator and X_ATOM is the index
197*8b26181fSAndroid Build Coastguard Worker * register.
198*8b26181fSAndroid Build Coastguard Worker */
199*8b26181fSAndroid Build Coastguard Worker #define A_ATOM BPF_MEMWORDS
200*8b26181fSAndroid Build Coastguard Worker #define X_ATOM (BPF_MEMWORDS+1)
201*8b26181fSAndroid Build Coastguard Worker
202*8b26181fSAndroid Build Coastguard Worker /*
203*8b26181fSAndroid Build Coastguard Worker * This define is used to represent *both* the accumulator and
204*8b26181fSAndroid Build Coastguard Worker * x register in use-def computations.
205*8b26181fSAndroid Build Coastguard Worker * Currently, the use-def code assumes only one definition per instruction.
206*8b26181fSAndroid Build Coastguard Worker */
207*8b26181fSAndroid Build Coastguard Worker #define AX_ATOM N_ATOMS
208*8b26181fSAndroid Build Coastguard Worker
209*8b26181fSAndroid Build Coastguard Worker /*
210*8b26181fSAndroid Build Coastguard Worker * These data structures are used in a Cocke and Shwarz style
211*8b26181fSAndroid Build Coastguard Worker * value numbering scheme. Since the flowgraph is acyclic,
212*8b26181fSAndroid Build Coastguard Worker * exit values can be propagated from a node's predecessors
213*8b26181fSAndroid Build Coastguard Worker * provided it is uniquely defined.
214*8b26181fSAndroid Build Coastguard Worker */
215*8b26181fSAndroid Build Coastguard Worker struct valnode {
216*8b26181fSAndroid Build Coastguard Worker int code;
217*8b26181fSAndroid Build Coastguard Worker bpf_u_int32 v0, v1;
218*8b26181fSAndroid Build Coastguard Worker int val; /* the value number */
219*8b26181fSAndroid Build Coastguard Worker struct valnode *next;
220*8b26181fSAndroid Build Coastguard Worker };
221*8b26181fSAndroid Build Coastguard Worker
222*8b26181fSAndroid Build Coastguard Worker /* Integer constants mapped with the load immediate opcode. */
223*8b26181fSAndroid Build Coastguard Worker #define K(i) F(opt_state, BPF_LD|BPF_IMM|BPF_W, i, 0U)
224*8b26181fSAndroid Build Coastguard Worker
225*8b26181fSAndroid Build Coastguard Worker struct vmapinfo {
226*8b26181fSAndroid Build Coastguard Worker int is_const;
227*8b26181fSAndroid Build Coastguard Worker bpf_u_int32 const_val;
228*8b26181fSAndroid Build Coastguard Worker };
229*8b26181fSAndroid Build Coastguard Worker
230*8b26181fSAndroid Build Coastguard Worker typedef struct {
231*8b26181fSAndroid Build Coastguard Worker /*
232*8b26181fSAndroid Build Coastguard Worker * Place to longjmp to on an error.
233*8b26181fSAndroid Build Coastguard Worker */
234*8b26181fSAndroid Build Coastguard Worker jmp_buf top_ctx;
235*8b26181fSAndroid Build Coastguard Worker
236*8b26181fSAndroid Build Coastguard Worker /*
237*8b26181fSAndroid Build Coastguard Worker * The buffer into which to put error message.
238*8b26181fSAndroid Build Coastguard Worker */
239*8b26181fSAndroid Build Coastguard Worker char *errbuf;
240*8b26181fSAndroid Build Coastguard Worker
241*8b26181fSAndroid Build Coastguard Worker /*
242*8b26181fSAndroid Build Coastguard Worker * A flag to indicate that further optimization is needed.
243*8b26181fSAndroid Build Coastguard Worker * Iterative passes are continued until a given pass yields no
244*8b26181fSAndroid Build Coastguard Worker * code simplification or branch movement.
245*8b26181fSAndroid Build Coastguard Worker */
246*8b26181fSAndroid Build Coastguard Worker int done;
247*8b26181fSAndroid Build Coastguard Worker
248*8b26181fSAndroid Build Coastguard Worker /*
249*8b26181fSAndroid Build Coastguard Worker * XXX - detect loops that do nothing but repeated AND/OR pullups
250*8b26181fSAndroid Build Coastguard Worker * and edge moves.
251*8b26181fSAndroid Build Coastguard Worker * If 100 passes in a row do nothing but that, treat that as a
252*8b26181fSAndroid Build Coastguard Worker * sign that we're in a loop that just shuffles in a cycle in
253*8b26181fSAndroid Build Coastguard Worker * which each pass just shuffles the code and we eventually
254*8b26181fSAndroid Build Coastguard Worker * get back to the original configuration.
255*8b26181fSAndroid Build Coastguard Worker *
256*8b26181fSAndroid Build Coastguard Worker * XXX - we need a non-heuristic way of detecting, or preventing,
257*8b26181fSAndroid Build Coastguard Worker * such a cycle.
258*8b26181fSAndroid Build Coastguard Worker */
259*8b26181fSAndroid Build Coastguard Worker int non_branch_movement_performed;
260*8b26181fSAndroid Build Coastguard Worker
261*8b26181fSAndroid Build Coastguard Worker u_int n_blocks; /* number of blocks in the CFG; guaranteed to be > 0, as it's a RET instruction at a minimum */
262*8b26181fSAndroid Build Coastguard Worker struct block **blocks;
263*8b26181fSAndroid Build Coastguard Worker u_int n_edges; /* twice n_blocks, so guaranteed to be > 0 */
264*8b26181fSAndroid Build Coastguard Worker struct edge **edges;
265*8b26181fSAndroid Build Coastguard Worker
266*8b26181fSAndroid Build Coastguard Worker /*
267*8b26181fSAndroid Build Coastguard Worker * A bit vector set representation of the dominators.
268*8b26181fSAndroid Build Coastguard Worker * We round up the set size to the next power of two.
269*8b26181fSAndroid Build Coastguard Worker */
270*8b26181fSAndroid Build Coastguard Worker u_int nodewords; /* number of 32-bit words for a bit vector of "number of nodes" bits; guaranteed to be > 0 */
271*8b26181fSAndroid Build Coastguard Worker u_int edgewords; /* number of 32-bit words for a bit vector of "number of edges" bits; guaranteed to be > 0 */
272*8b26181fSAndroid Build Coastguard Worker struct block **levels;
273*8b26181fSAndroid Build Coastguard Worker bpf_u_int32 *space;
274*8b26181fSAndroid Build Coastguard Worker
275*8b26181fSAndroid Build Coastguard Worker #define BITS_PER_WORD (8*sizeof(bpf_u_int32))
276*8b26181fSAndroid Build Coastguard Worker /*
277*8b26181fSAndroid Build Coastguard Worker * True if a is in uset {p}
278*8b26181fSAndroid Build Coastguard Worker */
279*8b26181fSAndroid Build Coastguard Worker #define SET_MEMBER(p, a) \
280*8b26181fSAndroid Build Coastguard Worker ((p)[(unsigned)(a) / BITS_PER_WORD] & ((bpf_u_int32)1 << ((unsigned)(a) % BITS_PER_WORD)))
281*8b26181fSAndroid Build Coastguard Worker
282*8b26181fSAndroid Build Coastguard Worker /*
283*8b26181fSAndroid Build Coastguard Worker * Add 'a' to uset p.
284*8b26181fSAndroid Build Coastguard Worker */
285*8b26181fSAndroid Build Coastguard Worker #define SET_INSERT(p, a) \
286*8b26181fSAndroid Build Coastguard Worker (p)[(unsigned)(a) / BITS_PER_WORD] |= ((bpf_u_int32)1 << ((unsigned)(a) % BITS_PER_WORD))
287*8b26181fSAndroid Build Coastguard Worker
288*8b26181fSAndroid Build Coastguard Worker /*
289*8b26181fSAndroid Build Coastguard Worker * Delete 'a' from uset p.
290*8b26181fSAndroid Build Coastguard Worker */
291*8b26181fSAndroid Build Coastguard Worker #define SET_DELETE(p, a) \
292*8b26181fSAndroid Build Coastguard Worker (p)[(unsigned)(a) / BITS_PER_WORD] &= ~((bpf_u_int32)1 << ((unsigned)(a) % BITS_PER_WORD))
293*8b26181fSAndroid Build Coastguard Worker
294*8b26181fSAndroid Build Coastguard Worker /*
295*8b26181fSAndroid Build Coastguard Worker * a := a intersect b
296*8b26181fSAndroid Build Coastguard Worker * n must be guaranteed to be > 0
297*8b26181fSAndroid Build Coastguard Worker */
298*8b26181fSAndroid Build Coastguard Worker #define SET_INTERSECT(a, b, n)\
299*8b26181fSAndroid Build Coastguard Worker {\
300*8b26181fSAndroid Build Coastguard Worker register bpf_u_int32 *_x = a, *_y = b;\
301*8b26181fSAndroid Build Coastguard Worker register u_int _n = n;\
302*8b26181fSAndroid Build Coastguard Worker do *_x++ &= *_y++; while (--_n != 0);\
303*8b26181fSAndroid Build Coastguard Worker }
304*8b26181fSAndroid Build Coastguard Worker
305*8b26181fSAndroid Build Coastguard Worker /*
306*8b26181fSAndroid Build Coastguard Worker * a := a - b
307*8b26181fSAndroid Build Coastguard Worker * n must be guaranteed to be > 0
308*8b26181fSAndroid Build Coastguard Worker */
309*8b26181fSAndroid Build Coastguard Worker #define SET_SUBTRACT(a, b, n)\
310*8b26181fSAndroid Build Coastguard Worker {\
311*8b26181fSAndroid Build Coastguard Worker register bpf_u_int32 *_x = a, *_y = b;\
312*8b26181fSAndroid Build Coastguard Worker register u_int _n = n;\
313*8b26181fSAndroid Build Coastguard Worker do *_x++ &=~ *_y++; while (--_n != 0);\
314*8b26181fSAndroid Build Coastguard Worker }
315*8b26181fSAndroid Build Coastguard Worker
316*8b26181fSAndroid Build Coastguard Worker /*
317*8b26181fSAndroid Build Coastguard Worker * a := a union b
318*8b26181fSAndroid Build Coastguard Worker * n must be guaranteed to be > 0
319*8b26181fSAndroid Build Coastguard Worker */
320*8b26181fSAndroid Build Coastguard Worker #define SET_UNION(a, b, n)\
321*8b26181fSAndroid Build Coastguard Worker {\
322*8b26181fSAndroid Build Coastguard Worker register bpf_u_int32 *_x = a, *_y = b;\
323*8b26181fSAndroid Build Coastguard Worker register u_int _n = n;\
324*8b26181fSAndroid Build Coastguard Worker do *_x++ |= *_y++; while (--_n != 0);\
325*8b26181fSAndroid Build Coastguard Worker }
326*8b26181fSAndroid Build Coastguard Worker
327*8b26181fSAndroid Build Coastguard Worker uset all_dom_sets;
328*8b26181fSAndroid Build Coastguard Worker uset all_closure_sets;
329*8b26181fSAndroid Build Coastguard Worker uset all_edge_sets;
330*8b26181fSAndroid Build Coastguard Worker
331*8b26181fSAndroid Build Coastguard Worker #define MODULUS 213
332*8b26181fSAndroid Build Coastguard Worker struct valnode *hashtbl[MODULUS];
333*8b26181fSAndroid Build Coastguard Worker bpf_u_int32 curval;
334*8b26181fSAndroid Build Coastguard Worker bpf_u_int32 maxval;
335*8b26181fSAndroid Build Coastguard Worker
336*8b26181fSAndroid Build Coastguard Worker struct vmapinfo *vmap;
337*8b26181fSAndroid Build Coastguard Worker struct valnode *vnode_base;
338*8b26181fSAndroid Build Coastguard Worker struct valnode *next_vnode;
339*8b26181fSAndroid Build Coastguard Worker } opt_state_t;
340*8b26181fSAndroid Build Coastguard Worker
341*8b26181fSAndroid Build Coastguard Worker typedef struct {
342*8b26181fSAndroid Build Coastguard Worker /*
343*8b26181fSAndroid Build Coastguard Worker * Place to longjmp to on an error.
344*8b26181fSAndroid Build Coastguard Worker */
345*8b26181fSAndroid Build Coastguard Worker jmp_buf top_ctx;
346*8b26181fSAndroid Build Coastguard Worker
347*8b26181fSAndroid Build Coastguard Worker /*
348*8b26181fSAndroid Build Coastguard Worker * The buffer into which to put error message.
349*8b26181fSAndroid Build Coastguard Worker */
350*8b26181fSAndroid Build Coastguard Worker char *errbuf;
351*8b26181fSAndroid Build Coastguard Worker
352*8b26181fSAndroid Build Coastguard Worker /*
353*8b26181fSAndroid Build Coastguard Worker * Some pointers used to convert the basic block form of the code,
354*8b26181fSAndroid Build Coastguard Worker * into the array form that BPF requires. 'fstart' will point to
355*8b26181fSAndroid Build Coastguard Worker * the malloc'd array while 'ftail' is used during the recursive
356*8b26181fSAndroid Build Coastguard Worker * traversal.
357*8b26181fSAndroid Build Coastguard Worker */
358*8b26181fSAndroid Build Coastguard Worker struct bpf_insn *fstart;
359*8b26181fSAndroid Build Coastguard Worker struct bpf_insn *ftail;
360*8b26181fSAndroid Build Coastguard Worker } conv_state_t;
361*8b26181fSAndroid Build Coastguard Worker
362*8b26181fSAndroid Build Coastguard Worker static void opt_init(opt_state_t *, struct icode *);
363*8b26181fSAndroid Build Coastguard Worker static void opt_cleanup(opt_state_t *);
364*8b26181fSAndroid Build Coastguard Worker static void PCAP_NORETURN opt_error(opt_state_t *, const char *, ...)
365*8b26181fSAndroid Build Coastguard Worker PCAP_PRINTFLIKE(2, 3);
366*8b26181fSAndroid Build Coastguard Worker
367*8b26181fSAndroid Build Coastguard Worker static void intern_blocks(opt_state_t *, struct icode *);
368*8b26181fSAndroid Build Coastguard Worker
369*8b26181fSAndroid Build Coastguard Worker static void find_inedges(opt_state_t *, struct block *);
370*8b26181fSAndroid Build Coastguard Worker #ifdef BDEBUG
371*8b26181fSAndroid Build Coastguard Worker static void opt_dump(opt_state_t *, struct icode *);
372*8b26181fSAndroid Build Coastguard Worker #endif
373*8b26181fSAndroid Build Coastguard Worker
374*8b26181fSAndroid Build Coastguard Worker #ifndef MAX
375*8b26181fSAndroid Build Coastguard Worker #define MAX(a,b) ((a)>(b)?(a):(b))
376*8b26181fSAndroid Build Coastguard Worker #endif
377*8b26181fSAndroid Build Coastguard Worker
378*8b26181fSAndroid Build Coastguard Worker static void
find_levels_r(opt_state_t * opt_state,struct icode * ic,struct block * b)379*8b26181fSAndroid Build Coastguard Worker find_levels_r(opt_state_t *opt_state, struct icode *ic, struct block *b)
380*8b26181fSAndroid Build Coastguard Worker {
381*8b26181fSAndroid Build Coastguard Worker int level;
382*8b26181fSAndroid Build Coastguard Worker
383*8b26181fSAndroid Build Coastguard Worker if (isMarked(ic, b))
384*8b26181fSAndroid Build Coastguard Worker return;
385*8b26181fSAndroid Build Coastguard Worker
386*8b26181fSAndroid Build Coastguard Worker Mark(ic, b);
387*8b26181fSAndroid Build Coastguard Worker b->link = 0;
388*8b26181fSAndroid Build Coastguard Worker
389*8b26181fSAndroid Build Coastguard Worker if (JT(b)) {
390*8b26181fSAndroid Build Coastguard Worker find_levels_r(opt_state, ic, JT(b));
391*8b26181fSAndroid Build Coastguard Worker find_levels_r(opt_state, ic, JF(b));
392*8b26181fSAndroid Build Coastguard Worker level = MAX(JT(b)->level, JF(b)->level) + 1;
393*8b26181fSAndroid Build Coastguard Worker } else
394*8b26181fSAndroid Build Coastguard Worker level = 0;
395*8b26181fSAndroid Build Coastguard Worker b->level = level;
396*8b26181fSAndroid Build Coastguard Worker b->link = opt_state->levels[level];
397*8b26181fSAndroid Build Coastguard Worker opt_state->levels[level] = b;
398*8b26181fSAndroid Build Coastguard Worker }
399*8b26181fSAndroid Build Coastguard Worker
400*8b26181fSAndroid Build Coastguard Worker /*
401*8b26181fSAndroid Build Coastguard Worker * Level graph. The levels go from 0 at the leaves to
402*8b26181fSAndroid Build Coastguard Worker * N_LEVELS at the root. The opt_state->levels[] array points to the
403*8b26181fSAndroid Build Coastguard Worker * first node of the level list, whose elements are linked
404*8b26181fSAndroid Build Coastguard Worker * with the 'link' field of the struct block.
405*8b26181fSAndroid Build Coastguard Worker */
406*8b26181fSAndroid Build Coastguard Worker static void
find_levels(opt_state_t * opt_state,struct icode * ic)407*8b26181fSAndroid Build Coastguard Worker find_levels(opt_state_t *opt_state, struct icode *ic)
408*8b26181fSAndroid Build Coastguard Worker {
409*8b26181fSAndroid Build Coastguard Worker memset((char *)opt_state->levels, 0, opt_state->n_blocks * sizeof(*opt_state->levels));
410*8b26181fSAndroid Build Coastguard Worker unMarkAll(ic);
411*8b26181fSAndroid Build Coastguard Worker find_levels_r(opt_state, ic, ic->root);
412*8b26181fSAndroid Build Coastguard Worker }
413*8b26181fSAndroid Build Coastguard Worker
414*8b26181fSAndroid Build Coastguard Worker /*
415*8b26181fSAndroid Build Coastguard Worker * Find dominator relationships.
416*8b26181fSAndroid Build Coastguard Worker * Assumes graph has been leveled.
417*8b26181fSAndroid Build Coastguard Worker */
418*8b26181fSAndroid Build Coastguard Worker static void
find_dom(opt_state_t * opt_state,struct block * root)419*8b26181fSAndroid Build Coastguard Worker find_dom(opt_state_t *opt_state, struct block *root)
420*8b26181fSAndroid Build Coastguard Worker {
421*8b26181fSAndroid Build Coastguard Worker u_int i;
422*8b26181fSAndroid Build Coastguard Worker int level;
423*8b26181fSAndroid Build Coastguard Worker struct block *b;
424*8b26181fSAndroid Build Coastguard Worker bpf_u_int32 *x;
425*8b26181fSAndroid Build Coastguard Worker
426*8b26181fSAndroid Build Coastguard Worker /*
427*8b26181fSAndroid Build Coastguard Worker * Initialize sets to contain all nodes.
428*8b26181fSAndroid Build Coastguard Worker */
429*8b26181fSAndroid Build Coastguard Worker x = opt_state->all_dom_sets;
430*8b26181fSAndroid Build Coastguard Worker /*
431*8b26181fSAndroid Build Coastguard Worker * In opt_init(), we've made sure the product doesn't overflow.
432*8b26181fSAndroid Build Coastguard Worker */
433*8b26181fSAndroid Build Coastguard Worker i = opt_state->n_blocks * opt_state->nodewords;
434*8b26181fSAndroid Build Coastguard Worker while (i != 0) {
435*8b26181fSAndroid Build Coastguard Worker --i;
436*8b26181fSAndroid Build Coastguard Worker *x++ = 0xFFFFFFFFU;
437*8b26181fSAndroid Build Coastguard Worker }
438*8b26181fSAndroid Build Coastguard Worker /* Root starts off empty. */
439*8b26181fSAndroid Build Coastguard Worker for (i = opt_state->nodewords; i != 0;) {
440*8b26181fSAndroid Build Coastguard Worker --i;
441*8b26181fSAndroid Build Coastguard Worker root->dom[i] = 0;
442*8b26181fSAndroid Build Coastguard Worker }
443*8b26181fSAndroid Build Coastguard Worker
444*8b26181fSAndroid Build Coastguard Worker /* root->level is the highest level no found. */
445*8b26181fSAndroid Build Coastguard Worker for (level = root->level; level >= 0; --level) {
446*8b26181fSAndroid Build Coastguard Worker for (b = opt_state->levels[level]; b; b = b->link) {
447*8b26181fSAndroid Build Coastguard Worker SET_INSERT(b->dom, b->id);
448*8b26181fSAndroid Build Coastguard Worker if (JT(b) == 0)
449*8b26181fSAndroid Build Coastguard Worker continue;
450*8b26181fSAndroid Build Coastguard Worker SET_INTERSECT(JT(b)->dom, b->dom, opt_state->nodewords);
451*8b26181fSAndroid Build Coastguard Worker SET_INTERSECT(JF(b)->dom, b->dom, opt_state->nodewords);
452*8b26181fSAndroid Build Coastguard Worker }
453*8b26181fSAndroid Build Coastguard Worker }
454*8b26181fSAndroid Build Coastguard Worker }
455*8b26181fSAndroid Build Coastguard Worker
456*8b26181fSAndroid Build Coastguard Worker static void
propedom(opt_state_t * opt_state,struct edge * ep)457*8b26181fSAndroid Build Coastguard Worker propedom(opt_state_t *opt_state, struct edge *ep)
458*8b26181fSAndroid Build Coastguard Worker {
459*8b26181fSAndroid Build Coastguard Worker SET_INSERT(ep->edom, ep->id);
460*8b26181fSAndroid Build Coastguard Worker if (ep->succ) {
461*8b26181fSAndroid Build Coastguard Worker SET_INTERSECT(ep->succ->et.edom, ep->edom, opt_state->edgewords);
462*8b26181fSAndroid Build Coastguard Worker SET_INTERSECT(ep->succ->ef.edom, ep->edom, opt_state->edgewords);
463*8b26181fSAndroid Build Coastguard Worker }
464*8b26181fSAndroid Build Coastguard Worker }
465*8b26181fSAndroid Build Coastguard Worker
466*8b26181fSAndroid Build Coastguard Worker /*
467*8b26181fSAndroid Build Coastguard Worker * Compute edge dominators.
468*8b26181fSAndroid Build Coastguard Worker * Assumes graph has been leveled and predecessors established.
469*8b26181fSAndroid Build Coastguard Worker */
470*8b26181fSAndroid Build Coastguard Worker static void
find_edom(opt_state_t * opt_state,struct block * root)471*8b26181fSAndroid Build Coastguard Worker find_edom(opt_state_t *opt_state, struct block *root)
472*8b26181fSAndroid Build Coastguard Worker {
473*8b26181fSAndroid Build Coastguard Worker u_int i;
474*8b26181fSAndroid Build Coastguard Worker uset x;
475*8b26181fSAndroid Build Coastguard Worker int level;
476*8b26181fSAndroid Build Coastguard Worker struct block *b;
477*8b26181fSAndroid Build Coastguard Worker
478*8b26181fSAndroid Build Coastguard Worker x = opt_state->all_edge_sets;
479*8b26181fSAndroid Build Coastguard Worker /*
480*8b26181fSAndroid Build Coastguard Worker * In opt_init(), we've made sure the product doesn't overflow.
481*8b26181fSAndroid Build Coastguard Worker */
482*8b26181fSAndroid Build Coastguard Worker for (i = opt_state->n_edges * opt_state->edgewords; i != 0; ) {
483*8b26181fSAndroid Build Coastguard Worker --i;
484*8b26181fSAndroid Build Coastguard Worker x[i] = 0xFFFFFFFFU;
485*8b26181fSAndroid Build Coastguard Worker }
486*8b26181fSAndroid Build Coastguard Worker
487*8b26181fSAndroid Build Coastguard Worker /* root->level is the highest level no found. */
488*8b26181fSAndroid Build Coastguard Worker memset(root->et.edom, 0, opt_state->edgewords * sizeof(*(uset)0));
489*8b26181fSAndroid Build Coastguard Worker memset(root->ef.edom, 0, opt_state->edgewords * sizeof(*(uset)0));
490*8b26181fSAndroid Build Coastguard Worker for (level = root->level; level >= 0; --level) {
491*8b26181fSAndroid Build Coastguard Worker for (b = opt_state->levels[level]; b != 0; b = b->link) {
492*8b26181fSAndroid Build Coastguard Worker propedom(opt_state, &b->et);
493*8b26181fSAndroid Build Coastguard Worker propedom(opt_state, &b->ef);
494*8b26181fSAndroid Build Coastguard Worker }
495*8b26181fSAndroid Build Coastguard Worker }
496*8b26181fSAndroid Build Coastguard Worker }
497*8b26181fSAndroid Build Coastguard Worker
498*8b26181fSAndroid Build Coastguard Worker /*
499*8b26181fSAndroid Build Coastguard Worker * Find the backwards transitive closure of the flow graph. These sets
500*8b26181fSAndroid Build Coastguard Worker * are backwards in the sense that we find the set of nodes that reach
501*8b26181fSAndroid Build Coastguard Worker * a given node, not the set of nodes that can be reached by a node.
502*8b26181fSAndroid Build Coastguard Worker *
503*8b26181fSAndroid Build Coastguard Worker * Assumes graph has been leveled.
504*8b26181fSAndroid Build Coastguard Worker */
505*8b26181fSAndroid Build Coastguard Worker static void
find_closure(opt_state_t * opt_state,struct block * root)506*8b26181fSAndroid Build Coastguard Worker find_closure(opt_state_t *opt_state, struct block *root)
507*8b26181fSAndroid Build Coastguard Worker {
508*8b26181fSAndroid Build Coastguard Worker int level;
509*8b26181fSAndroid Build Coastguard Worker struct block *b;
510*8b26181fSAndroid Build Coastguard Worker
511*8b26181fSAndroid Build Coastguard Worker /*
512*8b26181fSAndroid Build Coastguard Worker * Initialize sets to contain no nodes.
513*8b26181fSAndroid Build Coastguard Worker */
514*8b26181fSAndroid Build Coastguard Worker memset((char *)opt_state->all_closure_sets, 0,
515*8b26181fSAndroid Build Coastguard Worker opt_state->n_blocks * opt_state->nodewords * sizeof(*opt_state->all_closure_sets));
516*8b26181fSAndroid Build Coastguard Worker
517*8b26181fSAndroid Build Coastguard Worker /* root->level is the highest level no found. */
518*8b26181fSAndroid Build Coastguard Worker for (level = root->level; level >= 0; --level) {
519*8b26181fSAndroid Build Coastguard Worker for (b = opt_state->levels[level]; b; b = b->link) {
520*8b26181fSAndroid Build Coastguard Worker SET_INSERT(b->closure, b->id);
521*8b26181fSAndroid Build Coastguard Worker if (JT(b) == 0)
522*8b26181fSAndroid Build Coastguard Worker continue;
523*8b26181fSAndroid Build Coastguard Worker SET_UNION(JT(b)->closure, b->closure, opt_state->nodewords);
524*8b26181fSAndroid Build Coastguard Worker SET_UNION(JF(b)->closure, b->closure, opt_state->nodewords);
525*8b26181fSAndroid Build Coastguard Worker }
526*8b26181fSAndroid Build Coastguard Worker }
527*8b26181fSAndroid Build Coastguard Worker }
528*8b26181fSAndroid Build Coastguard Worker
529*8b26181fSAndroid Build Coastguard Worker /*
530*8b26181fSAndroid Build Coastguard Worker * Return the register number that is used by s.
531*8b26181fSAndroid Build Coastguard Worker *
532*8b26181fSAndroid Build Coastguard Worker * Returns ATOM_A if A is used, ATOM_X if X is used, AX_ATOM if both A and X
533*8b26181fSAndroid Build Coastguard Worker * are used, the scratch memory location's number if a scratch memory
534*8b26181fSAndroid Build Coastguard Worker * location is used (e.g., 0 for M[0]), or -1 if none of those are used.
535*8b26181fSAndroid Build Coastguard Worker *
536*8b26181fSAndroid Build Coastguard Worker * The implementation should probably change to an array access.
537*8b26181fSAndroid Build Coastguard Worker */
538*8b26181fSAndroid Build Coastguard Worker static int
atomuse(struct stmt * s)539*8b26181fSAndroid Build Coastguard Worker atomuse(struct stmt *s)
540*8b26181fSAndroid Build Coastguard Worker {
541*8b26181fSAndroid Build Coastguard Worker register int c = s->code;
542*8b26181fSAndroid Build Coastguard Worker
543*8b26181fSAndroid Build Coastguard Worker if (c == NOP)
544*8b26181fSAndroid Build Coastguard Worker return -1;
545*8b26181fSAndroid Build Coastguard Worker
546*8b26181fSAndroid Build Coastguard Worker switch (BPF_CLASS(c)) {
547*8b26181fSAndroid Build Coastguard Worker
548*8b26181fSAndroid Build Coastguard Worker case BPF_RET:
549*8b26181fSAndroid Build Coastguard Worker return (BPF_RVAL(c) == BPF_A) ? A_ATOM :
550*8b26181fSAndroid Build Coastguard Worker (BPF_RVAL(c) == BPF_X) ? X_ATOM : -1;
551*8b26181fSAndroid Build Coastguard Worker
552*8b26181fSAndroid Build Coastguard Worker case BPF_LD:
553*8b26181fSAndroid Build Coastguard Worker case BPF_LDX:
554*8b26181fSAndroid Build Coastguard Worker /*
555*8b26181fSAndroid Build Coastguard Worker * As there are fewer than 2^31 memory locations,
556*8b26181fSAndroid Build Coastguard Worker * s->k should be convertible to int without problems.
557*8b26181fSAndroid Build Coastguard Worker */
558*8b26181fSAndroid Build Coastguard Worker return (BPF_MODE(c) == BPF_IND) ? X_ATOM :
559*8b26181fSAndroid Build Coastguard Worker (BPF_MODE(c) == BPF_MEM) ? (int)s->k : -1;
560*8b26181fSAndroid Build Coastguard Worker
561*8b26181fSAndroid Build Coastguard Worker case BPF_ST:
562*8b26181fSAndroid Build Coastguard Worker return A_ATOM;
563*8b26181fSAndroid Build Coastguard Worker
564*8b26181fSAndroid Build Coastguard Worker case BPF_STX:
565*8b26181fSAndroid Build Coastguard Worker return X_ATOM;
566*8b26181fSAndroid Build Coastguard Worker
567*8b26181fSAndroid Build Coastguard Worker case BPF_JMP:
568*8b26181fSAndroid Build Coastguard Worker case BPF_ALU:
569*8b26181fSAndroid Build Coastguard Worker if (BPF_SRC(c) == BPF_X)
570*8b26181fSAndroid Build Coastguard Worker return AX_ATOM;
571*8b26181fSAndroid Build Coastguard Worker return A_ATOM;
572*8b26181fSAndroid Build Coastguard Worker
573*8b26181fSAndroid Build Coastguard Worker case BPF_MISC:
574*8b26181fSAndroid Build Coastguard Worker return BPF_MISCOP(c) == BPF_TXA ? X_ATOM : A_ATOM;
575*8b26181fSAndroid Build Coastguard Worker }
576*8b26181fSAndroid Build Coastguard Worker abort();
577*8b26181fSAndroid Build Coastguard Worker /* NOTREACHED */
578*8b26181fSAndroid Build Coastguard Worker }
579*8b26181fSAndroid Build Coastguard Worker
580*8b26181fSAndroid Build Coastguard Worker /*
581*8b26181fSAndroid Build Coastguard Worker * Return the register number that is defined by 's'. We assume that
582*8b26181fSAndroid Build Coastguard Worker * a single stmt cannot define more than one register. If no register
583*8b26181fSAndroid Build Coastguard Worker * is defined, return -1.
584*8b26181fSAndroid Build Coastguard Worker *
585*8b26181fSAndroid Build Coastguard Worker * The implementation should probably change to an array access.
586*8b26181fSAndroid Build Coastguard Worker */
587*8b26181fSAndroid Build Coastguard Worker static int
atomdef(struct stmt * s)588*8b26181fSAndroid Build Coastguard Worker atomdef(struct stmt *s)
589*8b26181fSAndroid Build Coastguard Worker {
590*8b26181fSAndroid Build Coastguard Worker if (s->code == NOP)
591*8b26181fSAndroid Build Coastguard Worker return -1;
592*8b26181fSAndroid Build Coastguard Worker
593*8b26181fSAndroid Build Coastguard Worker switch (BPF_CLASS(s->code)) {
594*8b26181fSAndroid Build Coastguard Worker
595*8b26181fSAndroid Build Coastguard Worker case BPF_LD:
596*8b26181fSAndroid Build Coastguard Worker case BPF_ALU:
597*8b26181fSAndroid Build Coastguard Worker return A_ATOM;
598*8b26181fSAndroid Build Coastguard Worker
599*8b26181fSAndroid Build Coastguard Worker case BPF_LDX:
600*8b26181fSAndroid Build Coastguard Worker return X_ATOM;
601*8b26181fSAndroid Build Coastguard Worker
602*8b26181fSAndroid Build Coastguard Worker case BPF_ST:
603*8b26181fSAndroid Build Coastguard Worker case BPF_STX:
604*8b26181fSAndroid Build Coastguard Worker return s->k;
605*8b26181fSAndroid Build Coastguard Worker
606*8b26181fSAndroid Build Coastguard Worker case BPF_MISC:
607*8b26181fSAndroid Build Coastguard Worker return BPF_MISCOP(s->code) == BPF_TAX ? X_ATOM : A_ATOM;
608*8b26181fSAndroid Build Coastguard Worker }
609*8b26181fSAndroid Build Coastguard Worker return -1;
610*8b26181fSAndroid Build Coastguard Worker }
611*8b26181fSAndroid Build Coastguard Worker
612*8b26181fSAndroid Build Coastguard Worker /*
613*8b26181fSAndroid Build Coastguard Worker * Compute the sets of registers used, defined, and killed by 'b'.
614*8b26181fSAndroid Build Coastguard Worker *
615*8b26181fSAndroid Build Coastguard Worker * "Used" means that a statement in 'b' uses the register before any
616*8b26181fSAndroid Build Coastguard Worker * statement in 'b' defines it, i.e. it uses the value left in
617*8b26181fSAndroid Build Coastguard Worker * that register by a predecessor block of this block.
618*8b26181fSAndroid Build Coastguard Worker * "Defined" means that a statement in 'b' defines it.
619*8b26181fSAndroid Build Coastguard Worker * "Killed" means that a statement in 'b' defines it before any
620*8b26181fSAndroid Build Coastguard Worker * statement in 'b' uses it, i.e. it kills the value left in that
621*8b26181fSAndroid Build Coastguard Worker * register by a predecessor block of this block.
622*8b26181fSAndroid Build Coastguard Worker */
623*8b26181fSAndroid Build Coastguard Worker static void
compute_local_ud(struct block * b)624*8b26181fSAndroid Build Coastguard Worker compute_local_ud(struct block *b)
625*8b26181fSAndroid Build Coastguard Worker {
626*8b26181fSAndroid Build Coastguard Worker struct slist *s;
627*8b26181fSAndroid Build Coastguard Worker atomset def = 0, use = 0, killed = 0;
628*8b26181fSAndroid Build Coastguard Worker int atom;
629*8b26181fSAndroid Build Coastguard Worker
630*8b26181fSAndroid Build Coastguard Worker for (s = b->stmts; s; s = s->next) {
631*8b26181fSAndroid Build Coastguard Worker if (s->s.code == NOP)
632*8b26181fSAndroid Build Coastguard Worker continue;
633*8b26181fSAndroid Build Coastguard Worker atom = atomuse(&s->s);
634*8b26181fSAndroid Build Coastguard Worker if (atom >= 0) {
635*8b26181fSAndroid Build Coastguard Worker if (atom == AX_ATOM) {
636*8b26181fSAndroid Build Coastguard Worker if (!ATOMELEM(def, X_ATOM))
637*8b26181fSAndroid Build Coastguard Worker use |= ATOMMASK(X_ATOM);
638*8b26181fSAndroid Build Coastguard Worker if (!ATOMELEM(def, A_ATOM))
639*8b26181fSAndroid Build Coastguard Worker use |= ATOMMASK(A_ATOM);
640*8b26181fSAndroid Build Coastguard Worker }
641*8b26181fSAndroid Build Coastguard Worker else if (atom < N_ATOMS) {
642*8b26181fSAndroid Build Coastguard Worker if (!ATOMELEM(def, atom))
643*8b26181fSAndroid Build Coastguard Worker use |= ATOMMASK(atom);
644*8b26181fSAndroid Build Coastguard Worker }
645*8b26181fSAndroid Build Coastguard Worker else
646*8b26181fSAndroid Build Coastguard Worker abort();
647*8b26181fSAndroid Build Coastguard Worker }
648*8b26181fSAndroid Build Coastguard Worker atom = atomdef(&s->s);
649*8b26181fSAndroid Build Coastguard Worker if (atom >= 0) {
650*8b26181fSAndroid Build Coastguard Worker if (!ATOMELEM(use, atom))
651*8b26181fSAndroid Build Coastguard Worker killed |= ATOMMASK(atom);
652*8b26181fSAndroid Build Coastguard Worker def |= ATOMMASK(atom);
653*8b26181fSAndroid Build Coastguard Worker }
654*8b26181fSAndroid Build Coastguard Worker }
655*8b26181fSAndroid Build Coastguard Worker if (BPF_CLASS(b->s.code) == BPF_JMP) {
656*8b26181fSAndroid Build Coastguard Worker /*
657*8b26181fSAndroid Build Coastguard Worker * XXX - what about RET?
658*8b26181fSAndroid Build Coastguard Worker */
659*8b26181fSAndroid Build Coastguard Worker atom = atomuse(&b->s);
660*8b26181fSAndroid Build Coastguard Worker if (atom >= 0) {
661*8b26181fSAndroid Build Coastguard Worker if (atom == AX_ATOM) {
662*8b26181fSAndroid Build Coastguard Worker if (!ATOMELEM(def, X_ATOM))
663*8b26181fSAndroid Build Coastguard Worker use |= ATOMMASK(X_ATOM);
664*8b26181fSAndroid Build Coastguard Worker if (!ATOMELEM(def, A_ATOM))
665*8b26181fSAndroid Build Coastguard Worker use |= ATOMMASK(A_ATOM);
666*8b26181fSAndroid Build Coastguard Worker }
667*8b26181fSAndroid Build Coastguard Worker else if (atom < N_ATOMS) {
668*8b26181fSAndroid Build Coastguard Worker if (!ATOMELEM(def, atom))
669*8b26181fSAndroid Build Coastguard Worker use |= ATOMMASK(atom);
670*8b26181fSAndroid Build Coastguard Worker }
671*8b26181fSAndroid Build Coastguard Worker else
672*8b26181fSAndroid Build Coastguard Worker abort();
673*8b26181fSAndroid Build Coastguard Worker }
674*8b26181fSAndroid Build Coastguard Worker }
675*8b26181fSAndroid Build Coastguard Worker
676*8b26181fSAndroid Build Coastguard Worker b->def = def;
677*8b26181fSAndroid Build Coastguard Worker b->kill = killed;
678*8b26181fSAndroid Build Coastguard Worker b->in_use = use;
679*8b26181fSAndroid Build Coastguard Worker }
680*8b26181fSAndroid Build Coastguard Worker
681*8b26181fSAndroid Build Coastguard Worker /*
682*8b26181fSAndroid Build Coastguard Worker * Assume graph is already leveled.
683*8b26181fSAndroid Build Coastguard Worker */
684*8b26181fSAndroid Build Coastguard Worker static void
find_ud(opt_state_t * opt_state,struct block * root)685*8b26181fSAndroid Build Coastguard Worker find_ud(opt_state_t *opt_state, struct block *root)
686*8b26181fSAndroid Build Coastguard Worker {
687*8b26181fSAndroid Build Coastguard Worker int i, maxlevel;
688*8b26181fSAndroid Build Coastguard Worker struct block *p;
689*8b26181fSAndroid Build Coastguard Worker
690*8b26181fSAndroid Build Coastguard Worker /*
691*8b26181fSAndroid Build Coastguard Worker * root->level is the highest level no found;
692*8b26181fSAndroid Build Coastguard Worker * count down from there.
693*8b26181fSAndroid Build Coastguard Worker */
694*8b26181fSAndroid Build Coastguard Worker maxlevel = root->level;
695*8b26181fSAndroid Build Coastguard Worker for (i = maxlevel; i >= 0; --i)
696*8b26181fSAndroid Build Coastguard Worker for (p = opt_state->levels[i]; p; p = p->link) {
697*8b26181fSAndroid Build Coastguard Worker compute_local_ud(p);
698*8b26181fSAndroid Build Coastguard Worker p->out_use = 0;
699*8b26181fSAndroid Build Coastguard Worker }
700*8b26181fSAndroid Build Coastguard Worker
701*8b26181fSAndroid Build Coastguard Worker for (i = 1; i <= maxlevel; ++i) {
702*8b26181fSAndroid Build Coastguard Worker for (p = opt_state->levels[i]; p; p = p->link) {
703*8b26181fSAndroid Build Coastguard Worker p->out_use |= JT(p)->in_use | JF(p)->in_use;
704*8b26181fSAndroid Build Coastguard Worker p->in_use |= p->out_use &~ p->kill;
705*8b26181fSAndroid Build Coastguard Worker }
706*8b26181fSAndroid Build Coastguard Worker }
707*8b26181fSAndroid Build Coastguard Worker }
708*8b26181fSAndroid Build Coastguard Worker static void
init_val(opt_state_t * opt_state)709*8b26181fSAndroid Build Coastguard Worker init_val(opt_state_t *opt_state)
710*8b26181fSAndroid Build Coastguard Worker {
711*8b26181fSAndroid Build Coastguard Worker opt_state->curval = 0;
712*8b26181fSAndroid Build Coastguard Worker opt_state->next_vnode = opt_state->vnode_base;
713*8b26181fSAndroid Build Coastguard Worker memset((char *)opt_state->vmap, 0, opt_state->maxval * sizeof(*opt_state->vmap));
714*8b26181fSAndroid Build Coastguard Worker memset((char *)opt_state->hashtbl, 0, sizeof opt_state->hashtbl);
715*8b26181fSAndroid Build Coastguard Worker }
716*8b26181fSAndroid Build Coastguard Worker
717*8b26181fSAndroid Build Coastguard Worker /*
718*8b26181fSAndroid Build Coastguard Worker * Because we really don't have an IR, this stuff is a little messy.
719*8b26181fSAndroid Build Coastguard Worker *
720*8b26181fSAndroid Build Coastguard Worker * This routine looks in the table of existing value number for a value
721*8b26181fSAndroid Build Coastguard Worker * with generated from an operation with the specified opcode and
722*8b26181fSAndroid Build Coastguard Worker * the specified values. If it finds it, it returns its value number,
723*8b26181fSAndroid Build Coastguard Worker * otherwise it makes a new entry in the table and returns the
724*8b26181fSAndroid Build Coastguard Worker * value number of that entry.
725*8b26181fSAndroid Build Coastguard Worker */
726*8b26181fSAndroid Build Coastguard Worker static bpf_u_int32
F(opt_state_t * opt_state,int code,bpf_u_int32 v0,bpf_u_int32 v1)727*8b26181fSAndroid Build Coastguard Worker F(opt_state_t *opt_state, int code, bpf_u_int32 v0, bpf_u_int32 v1)
728*8b26181fSAndroid Build Coastguard Worker {
729*8b26181fSAndroid Build Coastguard Worker u_int hash;
730*8b26181fSAndroid Build Coastguard Worker bpf_u_int32 val;
731*8b26181fSAndroid Build Coastguard Worker struct valnode *p;
732*8b26181fSAndroid Build Coastguard Worker
733*8b26181fSAndroid Build Coastguard Worker hash = (u_int)code ^ (v0 << 4) ^ (v1 << 8);
734*8b26181fSAndroid Build Coastguard Worker hash %= MODULUS;
735*8b26181fSAndroid Build Coastguard Worker
736*8b26181fSAndroid Build Coastguard Worker for (p = opt_state->hashtbl[hash]; p; p = p->next)
737*8b26181fSAndroid Build Coastguard Worker if (p->code == code && p->v0 == v0 && p->v1 == v1)
738*8b26181fSAndroid Build Coastguard Worker return p->val;
739*8b26181fSAndroid Build Coastguard Worker
740*8b26181fSAndroid Build Coastguard Worker /*
741*8b26181fSAndroid Build Coastguard Worker * Not found. Allocate a new value, and assign it a new
742*8b26181fSAndroid Build Coastguard Worker * value number.
743*8b26181fSAndroid Build Coastguard Worker *
744*8b26181fSAndroid Build Coastguard Worker * opt_state->curval starts out as 0, which means VAL_UNKNOWN; we
745*8b26181fSAndroid Build Coastguard Worker * increment it before using it as the new value number, which
746*8b26181fSAndroid Build Coastguard Worker * means we never assign VAL_UNKNOWN.
747*8b26181fSAndroid Build Coastguard Worker *
748*8b26181fSAndroid Build Coastguard Worker * XXX - unless we overflow, but we probably won't have 2^32-1
749*8b26181fSAndroid Build Coastguard Worker * values; we treat 32 bits as effectively infinite.
750*8b26181fSAndroid Build Coastguard Worker */
751*8b26181fSAndroid Build Coastguard Worker val = ++opt_state->curval;
752*8b26181fSAndroid Build Coastguard Worker if (BPF_MODE(code) == BPF_IMM &&
753*8b26181fSAndroid Build Coastguard Worker (BPF_CLASS(code) == BPF_LD || BPF_CLASS(code) == BPF_LDX)) {
754*8b26181fSAndroid Build Coastguard Worker opt_state->vmap[val].const_val = v0;
755*8b26181fSAndroid Build Coastguard Worker opt_state->vmap[val].is_const = 1;
756*8b26181fSAndroid Build Coastguard Worker }
757*8b26181fSAndroid Build Coastguard Worker p = opt_state->next_vnode++;
758*8b26181fSAndroid Build Coastguard Worker p->val = val;
759*8b26181fSAndroid Build Coastguard Worker p->code = code;
760*8b26181fSAndroid Build Coastguard Worker p->v0 = v0;
761*8b26181fSAndroid Build Coastguard Worker p->v1 = v1;
762*8b26181fSAndroid Build Coastguard Worker p->next = opt_state->hashtbl[hash];
763*8b26181fSAndroid Build Coastguard Worker opt_state->hashtbl[hash] = p;
764*8b26181fSAndroid Build Coastguard Worker
765*8b26181fSAndroid Build Coastguard Worker return val;
766*8b26181fSAndroid Build Coastguard Worker }
767*8b26181fSAndroid Build Coastguard Worker
768*8b26181fSAndroid Build Coastguard Worker static inline void
vstore(struct stmt * s,bpf_u_int32 * valp,bpf_u_int32 newval,int alter)769*8b26181fSAndroid Build Coastguard Worker vstore(struct stmt *s, bpf_u_int32 *valp, bpf_u_int32 newval, int alter)
770*8b26181fSAndroid Build Coastguard Worker {
771*8b26181fSAndroid Build Coastguard Worker if (alter && newval != VAL_UNKNOWN && *valp == newval)
772*8b26181fSAndroid Build Coastguard Worker s->code = NOP;
773*8b26181fSAndroid Build Coastguard Worker else
774*8b26181fSAndroid Build Coastguard Worker *valp = newval;
775*8b26181fSAndroid Build Coastguard Worker }
776*8b26181fSAndroid Build Coastguard Worker
777*8b26181fSAndroid Build Coastguard Worker /*
778*8b26181fSAndroid Build Coastguard Worker * Do constant-folding on binary operators.
779*8b26181fSAndroid Build Coastguard Worker * (Unary operators are handled elsewhere.)
780*8b26181fSAndroid Build Coastguard Worker */
781*8b26181fSAndroid Build Coastguard Worker static void
fold_op(opt_state_t * opt_state,struct stmt * s,bpf_u_int32 v0,bpf_u_int32 v1)782*8b26181fSAndroid Build Coastguard Worker fold_op(opt_state_t *opt_state, struct stmt *s, bpf_u_int32 v0, bpf_u_int32 v1)
783*8b26181fSAndroid Build Coastguard Worker {
784*8b26181fSAndroid Build Coastguard Worker bpf_u_int32 a, b;
785*8b26181fSAndroid Build Coastguard Worker
786*8b26181fSAndroid Build Coastguard Worker a = opt_state->vmap[v0].const_val;
787*8b26181fSAndroid Build Coastguard Worker b = opt_state->vmap[v1].const_val;
788*8b26181fSAndroid Build Coastguard Worker
789*8b26181fSAndroid Build Coastguard Worker switch (BPF_OP(s->code)) {
790*8b26181fSAndroid Build Coastguard Worker case BPF_ADD:
791*8b26181fSAndroid Build Coastguard Worker a += b;
792*8b26181fSAndroid Build Coastguard Worker break;
793*8b26181fSAndroid Build Coastguard Worker
794*8b26181fSAndroid Build Coastguard Worker case BPF_SUB:
795*8b26181fSAndroid Build Coastguard Worker a -= b;
796*8b26181fSAndroid Build Coastguard Worker break;
797*8b26181fSAndroid Build Coastguard Worker
798*8b26181fSAndroid Build Coastguard Worker case BPF_MUL:
799*8b26181fSAndroid Build Coastguard Worker a *= b;
800*8b26181fSAndroid Build Coastguard Worker break;
801*8b26181fSAndroid Build Coastguard Worker
802*8b26181fSAndroid Build Coastguard Worker case BPF_DIV:
803*8b26181fSAndroid Build Coastguard Worker if (b == 0)
804*8b26181fSAndroid Build Coastguard Worker opt_error(opt_state, "division by zero");
805*8b26181fSAndroid Build Coastguard Worker a /= b;
806*8b26181fSAndroid Build Coastguard Worker break;
807*8b26181fSAndroid Build Coastguard Worker
808*8b26181fSAndroid Build Coastguard Worker case BPF_MOD:
809*8b26181fSAndroid Build Coastguard Worker if (b == 0)
810*8b26181fSAndroid Build Coastguard Worker opt_error(opt_state, "modulus by zero");
811*8b26181fSAndroid Build Coastguard Worker a %= b;
812*8b26181fSAndroid Build Coastguard Worker break;
813*8b26181fSAndroid Build Coastguard Worker
814*8b26181fSAndroid Build Coastguard Worker case BPF_AND:
815*8b26181fSAndroid Build Coastguard Worker a &= b;
816*8b26181fSAndroid Build Coastguard Worker break;
817*8b26181fSAndroid Build Coastguard Worker
818*8b26181fSAndroid Build Coastguard Worker case BPF_OR:
819*8b26181fSAndroid Build Coastguard Worker a |= b;
820*8b26181fSAndroid Build Coastguard Worker break;
821*8b26181fSAndroid Build Coastguard Worker
822*8b26181fSAndroid Build Coastguard Worker case BPF_XOR:
823*8b26181fSAndroid Build Coastguard Worker a ^= b;
824*8b26181fSAndroid Build Coastguard Worker break;
825*8b26181fSAndroid Build Coastguard Worker
826*8b26181fSAndroid Build Coastguard Worker case BPF_LSH:
827*8b26181fSAndroid Build Coastguard Worker /*
828*8b26181fSAndroid Build Coastguard Worker * A left shift of more than the width of the type
829*8b26181fSAndroid Build Coastguard Worker * is undefined in C; we'll just treat it as shifting
830*8b26181fSAndroid Build Coastguard Worker * all the bits out.
831*8b26181fSAndroid Build Coastguard Worker *
832*8b26181fSAndroid Build Coastguard Worker * XXX - the BPF interpreter doesn't check for this,
833*8b26181fSAndroid Build Coastguard Worker * so its behavior is dependent on the behavior of
834*8b26181fSAndroid Build Coastguard Worker * the processor on which it's running. There are
835*8b26181fSAndroid Build Coastguard Worker * processors on which it shifts all the bits out
836*8b26181fSAndroid Build Coastguard Worker * and processors on which it does no shift.
837*8b26181fSAndroid Build Coastguard Worker */
838*8b26181fSAndroid Build Coastguard Worker if (b < 32)
839*8b26181fSAndroid Build Coastguard Worker a <<= b;
840*8b26181fSAndroid Build Coastguard Worker else
841*8b26181fSAndroid Build Coastguard Worker a = 0;
842*8b26181fSAndroid Build Coastguard Worker break;
843*8b26181fSAndroid Build Coastguard Worker
844*8b26181fSAndroid Build Coastguard Worker case BPF_RSH:
845*8b26181fSAndroid Build Coastguard Worker /*
846*8b26181fSAndroid Build Coastguard Worker * A right shift of more than the width of the type
847*8b26181fSAndroid Build Coastguard Worker * is undefined in C; we'll just treat it as shifting
848*8b26181fSAndroid Build Coastguard Worker * all the bits out.
849*8b26181fSAndroid Build Coastguard Worker *
850*8b26181fSAndroid Build Coastguard Worker * XXX - the BPF interpreter doesn't check for this,
851*8b26181fSAndroid Build Coastguard Worker * so its behavior is dependent on the behavior of
852*8b26181fSAndroid Build Coastguard Worker * the processor on which it's running. There are
853*8b26181fSAndroid Build Coastguard Worker * processors on which it shifts all the bits out
854*8b26181fSAndroid Build Coastguard Worker * and processors on which it does no shift.
855*8b26181fSAndroid Build Coastguard Worker */
856*8b26181fSAndroid Build Coastguard Worker if (b < 32)
857*8b26181fSAndroid Build Coastguard Worker a >>= b;
858*8b26181fSAndroid Build Coastguard Worker else
859*8b26181fSAndroid Build Coastguard Worker a = 0;
860*8b26181fSAndroid Build Coastguard Worker break;
861*8b26181fSAndroid Build Coastguard Worker
862*8b26181fSAndroid Build Coastguard Worker default:
863*8b26181fSAndroid Build Coastguard Worker abort();
864*8b26181fSAndroid Build Coastguard Worker }
865*8b26181fSAndroid Build Coastguard Worker s->k = a;
866*8b26181fSAndroid Build Coastguard Worker s->code = BPF_LD|BPF_IMM;
867*8b26181fSAndroid Build Coastguard Worker /*
868*8b26181fSAndroid Build Coastguard Worker * XXX - optimizer loop detection.
869*8b26181fSAndroid Build Coastguard Worker */
870*8b26181fSAndroid Build Coastguard Worker opt_state->non_branch_movement_performed = 1;
871*8b26181fSAndroid Build Coastguard Worker opt_state->done = 0;
872*8b26181fSAndroid Build Coastguard Worker }
873*8b26181fSAndroid Build Coastguard Worker
874*8b26181fSAndroid Build Coastguard Worker static inline struct slist *
this_op(struct slist * s)875*8b26181fSAndroid Build Coastguard Worker this_op(struct slist *s)
876*8b26181fSAndroid Build Coastguard Worker {
877*8b26181fSAndroid Build Coastguard Worker while (s != 0 && s->s.code == NOP)
878*8b26181fSAndroid Build Coastguard Worker s = s->next;
879*8b26181fSAndroid Build Coastguard Worker return s;
880*8b26181fSAndroid Build Coastguard Worker }
881*8b26181fSAndroid Build Coastguard Worker
882*8b26181fSAndroid Build Coastguard Worker static void
opt_not(struct block * b)883*8b26181fSAndroid Build Coastguard Worker opt_not(struct block *b)
884*8b26181fSAndroid Build Coastguard Worker {
885*8b26181fSAndroid Build Coastguard Worker struct block *tmp = JT(b);
886*8b26181fSAndroid Build Coastguard Worker
887*8b26181fSAndroid Build Coastguard Worker JT(b) = JF(b);
888*8b26181fSAndroid Build Coastguard Worker JF(b) = tmp;
889*8b26181fSAndroid Build Coastguard Worker }
890*8b26181fSAndroid Build Coastguard Worker
891*8b26181fSAndroid Build Coastguard Worker static void
opt_peep(opt_state_t * opt_state,struct block * b)892*8b26181fSAndroid Build Coastguard Worker opt_peep(opt_state_t *opt_state, struct block *b)
893*8b26181fSAndroid Build Coastguard Worker {
894*8b26181fSAndroid Build Coastguard Worker struct slist *s;
895*8b26181fSAndroid Build Coastguard Worker struct slist *next, *last;
896*8b26181fSAndroid Build Coastguard Worker bpf_u_int32 val;
897*8b26181fSAndroid Build Coastguard Worker
898*8b26181fSAndroid Build Coastguard Worker s = b->stmts;
899*8b26181fSAndroid Build Coastguard Worker if (s == 0)
900*8b26181fSAndroid Build Coastguard Worker return;
901*8b26181fSAndroid Build Coastguard Worker
902*8b26181fSAndroid Build Coastguard Worker last = s;
903*8b26181fSAndroid Build Coastguard Worker for (/*empty*/; /*empty*/; s = next) {
904*8b26181fSAndroid Build Coastguard Worker /*
905*8b26181fSAndroid Build Coastguard Worker * Skip over nops.
906*8b26181fSAndroid Build Coastguard Worker */
907*8b26181fSAndroid Build Coastguard Worker s = this_op(s);
908*8b26181fSAndroid Build Coastguard Worker if (s == 0)
909*8b26181fSAndroid Build Coastguard Worker break; /* nothing left in the block */
910*8b26181fSAndroid Build Coastguard Worker
911*8b26181fSAndroid Build Coastguard Worker /*
912*8b26181fSAndroid Build Coastguard Worker * Find the next real instruction after that one
913*8b26181fSAndroid Build Coastguard Worker * (skipping nops).
914*8b26181fSAndroid Build Coastguard Worker */
915*8b26181fSAndroid Build Coastguard Worker next = this_op(s->next);
916*8b26181fSAndroid Build Coastguard Worker if (next == 0)
917*8b26181fSAndroid Build Coastguard Worker break; /* no next instruction */
918*8b26181fSAndroid Build Coastguard Worker last = next;
919*8b26181fSAndroid Build Coastguard Worker
920*8b26181fSAndroid Build Coastguard Worker /*
921*8b26181fSAndroid Build Coastguard Worker * st M[k] --> st M[k]
922*8b26181fSAndroid Build Coastguard Worker * ldx M[k] tax
923*8b26181fSAndroid Build Coastguard Worker */
924*8b26181fSAndroid Build Coastguard Worker if (s->s.code == BPF_ST &&
925*8b26181fSAndroid Build Coastguard Worker next->s.code == (BPF_LDX|BPF_MEM) &&
926*8b26181fSAndroid Build Coastguard Worker s->s.k == next->s.k) {
927*8b26181fSAndroid Build Coastguard Worker /*
928*8b26181fSAndroid Build Coastguard Worker * XXX - optimizer loop detection.
929*8b26181fSAndroid Build Coastguard Worker */
930*8b26181fSAndroid Build Coastguard Worker opt_state->non_branch_movement_performed = 1;
931*8b26181fSAndroid Build Coastguard Worker opt_state->done = 0;
932*8b26181fSAndroid Build Coastguard Worker next->s.code = BPF_MISC|BPF_TAX;
933*8b26181fSAndroid Build Coastguard Worker }
934*8b26181fSAndroid Build Coastguard Worker /*
935*8b26181fSAndroid Build Coastguard Worker * ld #k --> ldx #k
936*8b26181fSAndroid Build Coastguard Worker * tax txa
937*8b26181fSAndroid Build Coastguard Worker */
938*8b26181fSAndroid Build Coastguard Worker if (s->s.code == (BPF_LD|BPF_IMM) &&
939*8b26181fSAndroid Build Coastguard Worker next->s.code == (BPF_MISC|BPF_TAX)) {
940*8b26181fSAndroid Build Coastguard Worker s->s.code = BPF_LDX|BPF_IMM;
941*8b26181fSAndroid Build Coastguard Worker next->s.code = BPF_MISC|BPF_TXA;
942*8b26181fSAndroid Build Coastguard Worker /*
943*8b26181fSAndroid Build Coastguard Worker * XXX - optimizer loop detection.
944*8b26181fSAndroid Build Coastguard Worker */
945*8b26181fSAndroid Build Coastguard Worker opt_state->non_branch_movement_performed = 1;
946*8b26181fSAndroid Build Coastguard Worker opt_state->done = 0;
947*8b26181fSAndroid Build Coastguard Worker }
948*8b26181fSAndroid Build Coastguard Worker /*
949*8b26181fSAndroid Build Coastguard Worker * This is an ugly special case, but it happens
950*8b26181fSAndroid Build Coastguard Worker * when you say tcp[k] or udp[k] where k is a constant.
951*8b26181fSAndroid Build Coastguard Worker */
952*8b26181fSAndroid Build Coastguard Worker if (s->s.code == (BPF_LD|BPF_IMM)) {
953*8b26181fSAndroid Build Coastguard Worker struct slist *add, *tax, *ild;
954*8b26181fSAndroid Build Coastguard Worker
955*8b26181fSAndroid Build Coastguard Worker /*
956*8b26181fSAndroid Build Coastguard Worker * Check that X isn't used on exit from this
957*8b26181fSAndroid Build Coastguard Worker * block (which the optimizer might cause).
958*8b26181fSAndroid Build Coastguard Worker * We know the code generator won't generate
959*8b26181fSAndroid Build Coastguard Worker * any local dependencies.
960*8b26181fSAndroid Build Coastguard Worker */
961*8b26181fSAndroid Build Coastguard Worker if (ATOMELEM(b->out_use, X_ATOM))
962*8b26181fSAndroid Build Coastguard Worker continue;
963*8b26181fSAndroid Build Coastguard Worker
964*8b26181fSAndroid Build Coastguard Worker /*
965*8b26181fSAndroid Build Coastguard Worker * Check that the instruction following the ldi
966*8b26181fSAndroid Build Coastguard Worker * is an addx, or it's an ldxms with an addx
967*8b26181fSAndroid Build Coastguard Worker * following it (with 0 or more nops between the
968*8b26181fSAndroid Build Coastguard Worker * ldxms and addx).
969*8b26181fSAndroid Build Coastguard Worker */
970*8b26181fSAndroid Build Coastguard Worker if (next->s.code != (BPF_LDX|BPF_MSH|BPF_B))
971*8b26181fSAndroid Build Coastguard Worker add = next;
972*8b26181fSAndroid Build Coastguard Worker else
973*8b26181fSAndroid Build Coastguard Worker add = this_op(next->next);
974*8b26181fSAndroid Build Coastguard Worker if (add == 0 || add->s.code != (BPF_ALU|BPF_ADD|BPF_X))
975*8b26181fSAndroid Build Coastguard Worker continue;
976*8b26181fSAndroid Build Coastguard Worker
977*8b26181fSAndroid Build Coastguard Worker /*
978*8b26181fSAndroid Build Coastguard Worker * Check that a tax follows that (with 0 or more
979*8b26181fSAndroid Build Coastguard Worker * nops between them).
980*8b26181fSAndroid Build Coastguard Worker */
981*8b26181fSAndroid Build Coastguard Worker tax = this_op(add->next);
982*8b26181fSAndroid Build Coastguard Worker if (tax == 0 || tax->s.code != (BPF_MISC|BPF_TAX))
983*8b26181fSAndroid Build Coastguard Worker continue;
984*8b26181fSAndroid Build Coastguard Worker
985*8b26181fSAndroid Build Coastguard Worker /*
986*8b26181fSAndroid Build Coastguard Worker * Check that an ild follows that (with 0 or more
987*8b26181fSAndroid Build Coastguard Worker * nops between them).
988*8b26181fSAndroid Build Coastguard Worker */
989*8b26181fSAndroid Build Coastguard Worker ild = this_op(tax->next);
990*8b26181fSAndroid Build Coastguard Worker if (ild == 0 || BPF_CLASS(ild->s.code) != BPF_LD ||
991*8b26181fSAndroid Build Coastguard Worker BPF_MODE(ild->s.code) != BPF_IND)
992*8b26181fSAndroid Build Coastguard Worker continue;
993*8b26181fSAndroid Build Coastguard Worker /*
994*8b26181fSAndroid Build Coastguard Worker * We want to turn this sequence:
995*8b26181fSAndroid Build Coastguard Worker *
996*8b26181fSAndroid Build Coastguard Worker * (004) ldi #0x2 {s}
997*8b26181fSAndroid Build Coastguard Worker * (005) ldxms [14] {next} -- optional
998*8b26181fSAndroid Build Coastguard Worker * (006) addx {add}
999*8b26181fSAndroid Build Coastguard Worker * (007) tax {tax}
1000*8b26181fSAndroid Build Coastguard Worker * (008) ild [x+0] {ild}
1001*8b26181fSAndroid Build Coastguard Worker *
1002*8b26181fSAndroid Build Coastguard Worker * into this sequence:
1003*8b26181fSAndroid Build Coastguard Worker *
1004*8b26181fSAndroid Build Coastguard Worker * (004) nop
1005*8b26181fSAndroid Build Coastguard Worker * (005) ldxms [14]
1006*8b26181fSAndroid Build Coastguard Worker * (006) nop
1007*8b26181fSAndroid Build Coastguard Worker * (007) nop
1008*8b26181fSAndroid Build Coastguard Worker * (008) ild [x+2]
1009*8b26181fSAndroid Build Coastguard Worker *
1010*8b26181fSAndroid Build Coastguard Worker * XXX We need to check that X is not
1011*8b26181fSAndroid Build Coastguard Worker * subsequently used, because we want to change
1012*8b26181fSAndroid Build Coastguard Worker * what'll be in it after this sequence.
1013*8b26181fSAndroid Build Coastguard Worker *
1014*8b26181fSAndroid Build Coastguard Worker * We know we can eliminate the accumulator
1015*8b26181fSAndroid Build Coastguard Worker * modifications earlier in the sequence since
1016*8b26181fSAndroid Build Coastguard Worker * it is defined by the last stmt of this sequence
1017*8b26181fSAndroid Build Coastguard Worker * (i.e., the last statement of the sequence loads
1018*8b26181fSAndroid Build Coastguard Worker * a value into the accumulator, so we can eliminate
1019*8b26181fSAndroid Build Coastguard Worker * earlier operations on the accumulator).
1020*8b26181fSAndroid Build Coastguard Worker */
1021*8b26181fSAndroid Build Coastguard Worker ild->s.k += s->s.k;
1022*8b26181fSAndroid Build Coastguard Worker s->s.code = NOP;
1023*8b26181fSAndroid Build Coastguard Worker add->s.code = NOP;
1024*8b26181fSAndroid Build Coastguard Worker tax->s.code = NOP;
1025*8b26181fSAndroid Build Coastguard Worker /*
1026*8b26181fSAndroid Build Coastguard Worker * XXX - optimizer loop detection.
1027*8b26181fSAndroid Build Coastguard Worker */
1028*8b26181fSAndroid Build Coastguard Worker opt_state->non_branch_movement_performed = 1;
1029*8b26181fSAndroid Build Coastguard Worker opt_state->done = 0;
1030*8b26181fSAndroid Build Coastguard Worker }
1031*8b26181fSAndroid Build Coastguard Worker }
1032*8b26181fSAndroid Build Coastguard Worker /*
1033*8b26181fSAndroid Build Coastguard Worker * If the comparison at the end of a block is an equality
1034*8b26181fSAndroid Build Coastguard Worker * comparison against a constant, and nobody uses the value
1035*8b26181fSAndroid Build Coastguard Worker * we leave in the A register at the end of a block, and
1036*8b26181fSAndroid Build Coastguard Worker * the operation preceding the comparison is an arithmetic
1037*8b26181fSAndroid Build Coastguard Worker * operation, we can sometime optimize it away.
1038*8b26181fSAndroid Build Coastguard Worker */
1039*8b26181fSAndroid Build Coastguard Worker if (b->s.code == (BPF_JMP|BPF_JEQ|BPF_K) &&
1040*8b26181fSAndroid Build Coastguard Worker !ATOMELEM(b->out_use, A_ATOM)) {
1041*8b26181fSAndroid Build Coastguard Worker /*
1042*8b26181fSAndroid Build Coastguard Worker * We can optimize away certain subtractions of the
1043*8b26181fSAndroid Build Coastguard Worker * X register.
1044*8b26181fSAndroid Build Coastguard Worker */
1045*8b26181fSAndroid Build Coastguard Worker if (last->s.code == (BPF_ALU|BPF_SUB|BPF_X)) {
1046*8b26181fSAndroid Build Coastguard Worker val = b->val[X_ATOM];
1047*8b26181fSAndroid Build Coastguard Worker if (opt_state->vmap[val].is_const) {
1048*8b26181fSAndroid Build Coastguard Worker /*
1049*8b26181fSAndroid Build Coastguard Worker * If we have a subtract to do a comparison,
1050*8b26181fSAndroid Build Coastguard Worker * and the X register is a known constant,
1051*8b26181fSAndroid Build Coastguard Worker * we can merge this value into the
1052*8b26181fSAndroid Build Coastguard Worker * comparison:
1053*8b26181fSAndroid Build Coastguard Worker *
1054*8b26181fSAndroid Build Coastguard Worker * sub x -> nop
1055*8b26181fSAndroid Build Coastguard Worker * jeq #y jeq #(x+y)
1056*8b26181fSAndroid Build Coastguard Worker */
1057*8b26181fSAndroid Build Coastguard Worker b->s.k += opt_state->vmap[val].const_val;
1058*8b26181fSAndroid Build Coastguard Worker last->s.code = NOP;
1059*8b26181fSAndroid Build Coastguard Worker /*
1060*8b26181fSAndroid Build Coastguard Worker * XXX - optimizer loop detection.
1061*8b26181fSAndroid Build Coastguard Worker */
1062*8b26181fSAndroid Build Coastguard Worker opt_state->non_branch_movement_performed = 1;
1063*8b26181fSAndroid Build Coastguard Worker opt_state->done = 0;
1064*8b26181fSAndroid Build Coastguard Worker } else if (b->s.k == 0) {
1065*8b26181fSAndroid Build Coastguard Worker /*
1066*8b26181fSAndroid Build Coastguard Worker * If the X register isn't a constant,
1067*8b26181fSAndroid Build Coastguard Worker * and the comparison in the test is
1068*8b26181fSAndroid Build Coastguard Worker * against 0, we can compare with the
1069*8b26181fSAndroid Build Coastguard Worker * X register, instead:
1070*8b26181fSAndroid Build Coastguard Worker *
1071*8b26181fSAndroid Build Coastguard Worker * sub x -> nop
1072*8b26181fSAndroid Build Coastguard Worker * jeq #0 jeq x
1073*8b26181fSAndroid Build Coastguard Worker */
1074*8b26181fSAndroid Build Coastguard Worker last->s.code = NOP;
1075*8b26181fSAndroid Build Coastguard Worker b->s.code = BPF_JMP|BPF_JEQ|BPF_X;
1076*8b26181fSAndroid Build Coastguard Worker /*
1077*8b26181fSAndroid Build Coastguard Worker * XXX - optimizer loop detection.
1078*8b26181fSAndroid Build Coastguard Worker */
1079*8b26181fSAndroid Build Coastguard Worker opt_state->non_branch_movement_performed = 1;
1080*8b26181fSAndroid Build Coastguard Worker opt_state->done = 0;
1081*8b26181fSAndroid Build Coastguard Worker }
1082*8b26181fSAndroid Build Coastguard Worker }
1083*8b26181fSAndroid Build Coastguard Worker /*
1084*8b26181fSAndroid Build Coastguard Worker * Likewise, a constant subtract can be simplified:
1085*8b26181fSAndroid Build Coastguard Worker *
1086*8b26181fSAndroid Build Coastguard Worker * sub #x -> nop
1087*8b26181fSAndroid Build Coastguard Worker * jeq #y -> jeq #(x+y)
1088*8b26181fSAndroid Build Coastguard Worker */
1089*8b26181fSAndroid Build Coastguard Worker else if (last->s.code == (BPF_ALU|BPF_SUB|BPF_K)) {
1090*8b26181fSAndroid Build Coastguard Worker last->s.code = NOP;
1091*8b26181fSAndroid Build Coastguard Worker b->s.k += last->s.k;
1092*8b26181fSAndroid Build Coastguard Worker /*
1093*8b26181fSAndroid Build Coastguard Worker * XXX - optimizer loop detection.
1094*8b26181fSAndroid Build Coastguard Worker */
1095*8b26181fSAndroid Build Coastguard Worker opt_state->non_branch_movement_performed = 1;
1096*8b26181fSAndroid Build Coastguard Worker opt_state->done = 0;
1097*8b26181fSAndroid Build Coastguard Worker }
1098*8b26181fSAndroid Build Coastguard Worker /*
1099*8b26181fSAndroid Build Coastguard Worker * And, similarly, a constant AND can be simplified
1100*8b26181fSAndroid Build Coastguard Worker * if we're testing against 0, i.e.:
1101*8b26181fSAndroid Build Coastguard Worker *
1102*8b26181fSAndroid Build Coastguard Worker * and #k nop
1103*8b26181fSAndroid Build Coastguard Worker * jeq #0 -> jset #k
1104*8b26181fSAndroid Build Coastguard Worker */
1105*8b26181fSAndroid Build Coastguard Worker else if (last->s.code == (BPF_ALU|BPF_AND|BPF_K) &&
1106*8b26181fSAndroid Build Coastguard Worker b->s.k == 0) {
1107*8b26181fSAndroid Build Coastguard Worker b->s.k = last->s.k;
1108*8b26181fSAndroid Build Coastguard Worker b->s.code = BPF_JMP|BPF_K|BPF_JSET;
1109*8b26181fSAndroid Build Coastguard Worker last->s.code = NOP;
1110*8b26181fSAndroid Build Coastguard Worker /*
1111*8b26181fSAndroid Build Coastguard Worker * XXX - optimizer loop detection.
1112*8b26181fSAndroid Build Coastguard Worker */
1113*8b26181fSAndroid Build Coastguard Worker opt_state->non_branch_movement_performed = 1;
1114*8b26181fSAndroid Build Coastguard Worker opt_state->done = 0;
1115*8b26181fSAndroid Build Coastguard Worker opt_not(b);
1116*8b26181fSAndroid Build Coastguard Worker }
1117*8b26181fSAndroid Build Coastguard Worker }
1118*8b26181fSAndroid Build Coastguard Worker /*
1119*8b26181fSAndroid Build Coastguard Worker * jset #0 -> never
1120*8b26181fSAndroid Build Coastguard Worker * jset #ffffffff -> always
1121*8b26181fSAndroid Build Coastguard Worker */
1122*8b26181fSAndroid Build Coastguard Worker if (b->s.code == (BPF_JMP|BPF_K|BPF_JSET)) {
1123*8b26181fSAndroid Build Coastguard Worker if (b->s.k == 0)
1124*8b26181fSAndroid Build Coastguard Worker JT(b) = JF(b);
1125*8b26181fSAndroid Build Coastguard Worker if (b->s.k == 0xffffffffU)
1126*8b26181fSAndroid Build Coastguard Worker JF(b) = JT(b);
1127*8b26181fSAndroid Build Coastguard Worker }
1128*8b26181fSAndroid Build Coastguard Worker /*
1129*8b26181fSAndroid Build Coastguard Worker * If we're comparing against the index register, and the index
1130*8b26181fSAndroid Build Coastguard Worker * register is a known constant, we can just compare against that
1131*8b26181fSAndroid Build Coastguard Worker * constant.
1132*8b26181fSAndroid Build Coastguard Worker */
1133*8b26181fSAndroid Build Coastguard Worker val = b->val[X_ATOM];
1134*8b26181fSAndroid Build Coastguard Worker if (opt_state->vmap[val].is_const && BPF_SRC(b->s.code) == BPF_X) {
1135*8b26181fSAndroid Build Coastguard Worker bpf_u_int32 v = opt_state->vmap[val].const_val;
1136*8b26181fSAndroid Build Coastguard Worker b->s.code &= ~BPF_X;
1137*8b26181fSAndroid Build Coastguard Worker b->s.k = v;
1138*8b26181fSAndroid Build Coastguard Worker }
1139*8b26181fSAndroid Build Coastguard Worker /*
1140*8b26181fSAndroid Build Coastguard Worker * If the accumulator is a known constant, we can compute the
1141*8b26181fSAndroid Build Coastguard Worker * comparison result.
1142*8b26181fSAndroid Build Coastguard Worker */
1143*8b26181fSAndroid Build Coastguard Worker val = b->val[A_ATOM];
1144*8b26181fSAndroid Build Coastguard Worker if (opt_state->vmap[val].is_const && BPF_SRC(b->s.code) == BPF_K) {
1145*8b26181fSAndroid Build Coastguard Worker bpf_u_int32 v = opt_state->vmap[val].const_val;
1146*8b26181fSAndroid Build Coastguard Worker switch (BPF_OP(b->s.code)) {
1147*8b26181fSAndroid Build Coastguard Worker
1148*8b26181fSAndroid Build Coastguard Worker case BPF_JEQ:
1149*8b26181fSAndroid Build Coastguard Worker v = v == b->s.k;
1150*8b26181fSAndroid Build Coastguard Worker break;
1151*8b26181fSAndroid Build Coastguard Worker
1152*8b26181fSAndroid Build Coastguard Worker case BPF_JGT:
1153*8b26181fSAndroid Build Coastguard Worker v = v > b->s.k;
1154*8b26181fSAndroid Build Coastguard Worker break;
1155*8b26181fSAndroid Build Coastguard Worker
1156*8b26181fSAndroid Build Coastguard Worker case BPF_JGE:
1157*8b26181fSAndroid Build Coastguard Worker v = v >= b->s.k;
1158*8b26181fSAndroid Build Coastguard Worker break;
1159*8b26181fSAndroid Build Coastguard Worker
1160*8b26181fSAndroid Build Coastguard Worker case BPF_JSET:
1161*8b26181fSAndroid Build Coastguard Worker v &= b->s.k;
1162*8b26181fSAndroid Build Coastguard Worker break;
1163*8b26181fSAndroid Build Coastguard Worker
1164*8b26181fSAndroid Build Coastguard Worker default:
1165*8b26181fSAndroid Build Coastguard Worker abort();
1166*8b26181fSAndroid Build Coastguard Worker }
1167*8b26181fSAndroid Build Coastguard Worker if (JF(b) != JT(b)) {
1168*8b26181fSAndroid Build Coastguard Worker /*
1169*8b26181fSAndroid Build Coastguard Worker * XXX - optimizer loop detection.
1170*8b26181fSAndroid Build Coastguard Worker */
1171*8b26181fSAndroid Build Coastguard Worker opt_state->non_branch_movement_performed = 1;
1172*8b26181fSAndroid Build Coastguard Worker opt_state->done = 0;
1173*8b26181fSAndroid Build Coastguard Worker }
1174*8b26181fSAndroid Build Coastguard Worker if (v)
1175*8b26181fSAndroid Build Coastguard Worker JF(b) = JT(b);
1176*8b26181fSAndroid Build Coastguard Worker else
1177*8b26181fSAndroid Build Coastguard Worker JT(b) = JF(b);
1178*8b26181fSAndroid Build Coastguard Worker }
1179*8b26181fSAndroid Build Coastguard Worker }
1180*8b26181fSAndroid Build Coastguard Worker
1181*8b26181fSAndroid Build Coastguard Worker /*
1182*8b26181fSAndroid Build Coastguard Worker * Compute the symbolic value of expression of 's', and update
1183*8b26181fSAndroid Build Coastguard Worker * anything it defines in the value table 'val'. If 'alter' is true,
1184*8b26181fSAndroid Build Coastguard Worker * do various optimizations. This code would be cleaner if symbolic
1185*8b26181fSAndroid Build Coastguard Worker * evaluation and code transformations weren't folded together.
1186*8b26181fSAndroid Build Coastguard Worker */
1187*8b26181fSAndroid Build Coastguard Worker static void
opt_stmt(opt_state_t * opt_state,struct stmt * s,bpf_u_int32 val[],int alter)1188*8b26181fSAndroid Build Coastguard Worker opt_stmt(opt_state_t *opt_state, struct stmt *s, bpf_u_int32 val[], int alter)
1189*8b26181fSAndroid Build Coastguard Worker {
1190*8b26181fSAndroid Build Coastguard Worker int op;
1191*8b26181fSAndroid Build Coastguard Worker bpf_u_int32 v;
1192*8b26181fSAndroid Build Coastguard Worker
1193*8b26181fSAndroid Build Coastguard Worker switch (s->code) {
1194*8b26181fSAndroid Build Coastguard Worker
1195*8b26181fSAndroid Build Coastguard Worker case BPF_LD|BPF_ABS|BPF_W:
1196*8b26181fSAndroid Build Coastguard Worker case BPF_LD|BPF_ABS|BPF_H:
1197*8b26181fSAndroid Build Coastguard Worker case BPF_LD|BPF_ABS|BPF_B:
1198*8b26181fSAndroid Build Coastguard Worker v = F(opt_state, s->code, s->k, 0L);
1199*8b26181fSAndroid Build Coastguard Worker vstore(s, &val[A_ATOM], v, alter);
1200*8b26181fSAndroid Build Coastguard Worker break;
1201*8b26181fSAndroid Build Coastguard Worker
1202*8b26181fSAndroid Build Coastguard Worker case BPF_LD|BPF_IND|BPF_W:
1203*8b26181fSAndroid Build Coastguard Worker case BPF_LD|BPF_IND|BPF_H:
1204*8b26181fSAndroid Build Coastguard Worker case BPF_LD|BPF_IND|BPF_B:
1205*8b26181fSAndroid Build Coastguard Worker v = val[X_ATOM];
1206*8b26181fSAndroid Build Coastguard Worker if (alter && opt_state->vmap[v].is_const) {
1207*8b26181fSAndroid Build Coastguard Worker s->code = BPF_LD|BPF_ABS|BPF_SIZE(s->code);
1208*8b26181fSAndroid Build Coastguard Worker s->k += opt_state->vmap[v].const_val;
1209*8b26181fSAndroid Build Coastguard Worker v = F(opt_state, s->code, s->k, 0L);
1210*8b26181fSAndroid Build Coastguard Worker /*
1211*8b26181fSAndroid Build Coastguard Worker * XXX - optimizer loop detection.
1212*8b26181fSAndroid Build Coastguard Worker */
1213*8b26181fSAndroid Build Coastguard Worker opt_state->non_branch_movement_performed = 1;
1214*8b26181fSAndroid Build Coastguard Worker opt_state->done = 0;
1215*8b26181fSAndroid Build Coastguard Worker }
1216*8b26181fSAndroid Build Coastguard Worker else
1217*8b26181fSAndroid Build Coastguard Worker v = F(opt_state, s->code, s->k, v);
1218*8b26181fSAndroid Build Coastguard Worker vstore(s, &val[A_ATOM], v, alter);
1219*8b26181fSAndroid Build Coastguard Worker break;
1220*8b26181fSAndroid Build Coastguard Worker
1221*8b26181fSAndroid Build Coastguard Worker case BPF_LD|BPF_LEN:
1222*8b26181fSAndroid Build Coastguard Worker v = F(opt_state, s->code, 0L, 0L);
1223*8b26181fSAndroid Build Coastguard Worker vstore(s, &val[A_ATOM], v, alter);
1224*8b26181fSAndroid Build Coastguard Worker break;
1225*8b26181fSAndroid Build Coastguard Worker
1226*8b26181fSAndroid Build Coastguard Worker case BPF_LD|BPF_IMM:
1227*8b26181fSAndroid Build Coastguard Worker v = K(s->k);
1228*8b26181fSAndroid Build Coastguard Worker vstore(s, &val[A_ATOM], v, alter);
1229*8b26181fSAndroid Build Coastguard Worker break;
1230*8b26181fSAndroid Build Coastguard Worker
1231*8b26181fSAndroid Build Coastguard Worker case BPF_LDX|BPF_IMM:
1232*8b26181fSAndroid Build Coastguard Worker v = K(s->k);
1233*8b26181fSAndroid Build Coastguard Worker vstore(s, &val[X_ATOM], v, alter);
1234*8b26181fSAndroid Build Coastguard Worker break;
1235*8b26181fSAndroid Build Coastguard Worker
1236*8b26181fSAndroid Build Coastguard Worker case BPF_LDX|BPF_MSH|BPF_B:
1237*8b26181fSAndroid Build Coastguard Worker v = F(opt_state, s->code, s->k, 0L);
1238*8b26181fSAndroid Build Coastguard Worker vstore(s, &val[X_ATOM], v, alter);
1239*8b26181fSAndroid Build Coastguard Worker break;
1240*8b26181fSAndroid Build Coastguard Worker
1241*8b26181fSAndroid Build Coastguard Worker case BPF_ALU|BPF_NEG:
1242*8b26181fSAndroid Build Coastguard Worker if (alter && opt_state->vmap[val[A_ATOM]].is_const) {
1243*8b26181fSAndroid Build Coastguard Worker s->code = BPF_LD|BPF_IMM;
1244*8b26181fSAndroid Build Coastguard Worker /*
1245*8b26181fSAndroid Build Coastguard Worker * Do this negation as unsigned arithmetic; that's
1246*8b26181fSAndroid Build Coastguard Worker * what modern BPF engines do, and it guarantees
1247*8b26181fSAndroid Build Coastguard Worker * that all possible values can be negated. (Yeah,
1248*8b26181fSAndroid Build Coastguard Worker * negating 0x80000000, the minimum signed 32-bit
1249*8b26181fSAndroid Build Coastguard Worker * two's-complement value, results in 0x80000000,
1250*8b26181fSAndroid Build Coastguard Worker * so it's still negative, but we *should* be doing
1251*8b26181fSAndroid Build Coastguard Worker * all unsigned arithmetic here, to match what
1252*8b26181fSAndroid Build Coastguard Worker * modern BPF engines do.)
1253*8b26181fSAndroid Build Coastguard Worker *
1254*8b26181fSAndroid Build Coastguard Worker * Express it as 0U - (unsigned value) so that we
1255*8b26181fSAndroid Build Coastguard Worker * don't get compiler warnings about negating an
1256*8b26181fSAndroid Build Coastguard Worker * unsigned value and don't get UBSan warnings
1257*8b26181fSAndroid Build Coastguard Worker * about the result of negating 0x80000000 being
1258*8b26181fSAndroid Build Coastguard Worker * undefined.
1259*8b26181fSAndroid Build Coastguard Worker */
1260*8b26181fSAndroid Build Coastguard Worker s->k = 0U - opt_state->vmap[val[A_ATOM]].const_val;
1261*8b26181fSAndroid Build Coastguard Worker val[A_ATOM] = K(s->k);
1262*8b26181fSAndroid Build Coastguard Worker }
1263*8b26181fSAndroid Build Coastguard Worker else
1264*8b26181fSAndroid Build Coastguard Worker val[A_ATOM] = F(opt_state, s->code, val[A_ATOM], 0L);
1265*8b26181fSAndroid Build Coastguard Worker break;
1266*8b26181fSAndroid Build Coastguard Worker
1267*8b26181fSAndroid Build Coastguard Worker case BPF_ALU|BPF_ADD|BPF_K:
1268*8b26181fSAndroid Build Coastguard Worker case BPF_ALU|BPF_SUB|BPF_K:
1269*8b26181fSAndroid Build Coastguard Worker case BPF_ALU|BPF_MUL|BPF_K:
1270*8b26181fSAndroid Build Coastguard Worker case BPF_ALU|BPF_DIV|BPF_K:
1271*8b26181fSAndroid Build Coastguard Worker case BPF_ALU|BPF_MOD|BPF_K:
1272*8b26181fSAndroid Build Coastguard Worker case BPF_ALU|BPF_AND|BPF_K:
1273*8b26181fSAndroid Build Coastguard Worker case BPF_ALU|BPF_OR|BPF_K:
1274*8b26181fSAndroid Build Coastguard Worker case BPF_ALU|BPF_XOR|BPF_K:
1275*8b26181fSAndroid Build Coastguard Worker case BPF_ALU|BPF_LSH|BPF_K:
1276*8b26181fSAndroid Build Coastguard Worker case BPF_ALU|BPF_RSH|BPF_K:
1277*8b26181fSAndroid Build Coastguard Worker op = BPF_OP(s->code);
1278*8b26181fSAndroid Build Coastguard Worker if (alter) {
1279*8b26181fSAndroid Build Coastguard Worker if (s->k == 0) {
1280*8b26181fSAndroid Build Coastguard Worker /*
1281*8b26181fSAndroid Build Coastguard Worker * Optimize operations where the constant
1282*8b26181fSAndroid Build Coastguard Worker * is zero.
1283*8b26181fSAndroid Build Coastguard Worker *
1284*8b26181fSAndroid Build Coastguard Worker * Don't optimize away "sub #0"
1285*8b26181fSAndroid Build Coastguard Worker * as it may be needed later to
1286*8b26181fSAndroid Build Coastguard Worker * fixup the generated math code.
1287*8b26181fSAndroid Build Coastguard Worker *
1288*8b26181fSAndroid Build Coastguard Worker * Fail if we're dividing by zero or taking
1289*8b26181fSAndroid Build Coastguard Worker * a modulus by zero.
1290*8b26181fSAndroid Build Coastguard Worker */
1291*8b26181fSAndroid Build Coastguard Worker if (op == BPF_ADD ||
1292*8b26181fSAndroid Build Coastguard Worker op == BPF_LSH || op == BPF_RSH ||
1293*8b26181fSAndroid Build Coastguard Worker op == BPF_OR || op == BPF_XOR) {
1294*8b26181fSAndroid Build Coastguard Worker s->code = NOP;
1295*8b26181fSAndroid Build Coastguard Worker break;
1296*8b26181fSAndroid Build Coastguard Worker }
1297*8b26181fSAndroid Build Coastguard Worker if (op == BPF_MUL || op == BPF_AND) {
1298*8b26181fSAndroid Build Coastguard Worker s->code = BPF_LD|BPF_IMM;
1299*8b26181fSAndroid Build Coastguard Worker val[A_ATOM] = K(s->k);
1300*8b26181fSAndroid Build Coastguard Worker break;
1301*8b26181fSAndroid Build Coastguard Worker }
1302*8b26181fSAndroid Build Coastguard Worker if (op == BPF_DIV)
1303*8b26181fSAndroid Build Coastguard Worker opt_error(opt_state,
1304*8b26181fSAndroid Build Coastguard Worker "division by zero");
1305*8b26181fSAndroid Build Coastguard Worker if (op == BPF_MOD)
1306*8b26181fSAndroid Build Coastguard Worker opt_error(opt_state,
1307*8b26181fSAndroid Build Coastguard Worker "modulus by zero");
1308*8b26181fSAndroid Build Coastguard Worker }
1309*8b26181fSAndroid Build Coastguard Worker if (opt_state->vmap[val[A_ATOM]].is_const) {
1310*8b26181fSAndroid Build Coastguard Worker fold_op(opt_state, s, val[A_ATOM], K(s->k));
1311*8b26181fSAndroid Build Coastguard Worker val[A_ATOM] = K(s->k);
1312*8b26181fSAndroid Build Coastguard Worker break;
1313*8b26181fSAndroid Build Coastguard Worker }
1314*8b26181fSAndroid Build Coastguard Worker }
1315*8b26181fSAndroid Build Coastguard Worker val[A_ATOM] = F(opt_state, s->code, val[A_ATOM], K(s->k));
1316*8b26181fSAndroid Build Coastguard Worker break;
1317*8b26181fSAndroid Build Coastguard Worker
1318*8b26181fSAndroid Build Coastguard Worker case BPF_ALU|BPF_ADD|BPF_X:
1319*8b26181fSAndroid Build Coastguard Worker case BPF_ALU|BPF_SUB|BPF_X:
1320*8b26181fSAndroid Build Coastguard Worker case BPF_ALU|BPF_MUL|BPF_X:
1321*8b26181fSAndroid Build Coastguard Worker case BPF_ALU|BPF_DIV|BPF_X:
1322*8b26181fSAndroid Build Coastguard Worker case BPF_ALU|BPF_MOD|BPF_X:
1323*8b26181fSAndroid Build Coastguard Worker case BPF_ALU|BPF_AND|BPF_X:
1324*8b26181fSAndroid Build Coastguard Worker case BPF_ALU|BPF_OR|BPF_X:
1325*8b26181fSAndroid Build Coastguard Worker case BPF_ALU|BPF_XOR|BPF_X:
1326*8b26181fSAndroid Build Coastguard Worker case BPF_ALU|BPF_LSH|BPF_X:
1327*8b26181fSAndroid Build Coastguard Worker case BPF_ALU|BPF_RSH|BPF_X:
1328*8b26181fSAndroid Build Coastguard Worker op = BPF_OP(s->code);
1329*8b26181fSAndroid Build Coastguard Worker if (alter && opt_state->vmap[val[X_ATOM]].is_const) {
1330*8b26181fSAndroid Build Coastguard Worker if (opt_state->vmap[val[A_ATOM]].is_const) {
1331*8b26181fSAndroid Build Coastguard Worker fold_op(opt_state, s, val[A_ATOM], val[X_ATOM]);
1332*8b26181fSAndroid Build Coastguard Worker val[A_ATOM] = K(s->k);
1333*8b26181fSAndroid Build Coastguard Worker }
1334*8b26181fSAndroid Build Coastguard Worker else {
1335*8b26181fSAndroid Build Coastguard Worker s->code = BPF_ALU|BPF_K|op;
1336*8b26181fSAndroid Build Coastguard Worker s->k = opt_state->vmap[val[X_ATOM]].const_val;
1337*8b26181fSAndroid Build Coastguard Worker if ((op == BPF_LSH || op == BPF_RSH) &&
1338*8b26181fSAndroid Build Coastguard Worker s->k > 31)
1339*8b26181fSAndroid Build Coastguard Worker opt_error(opt_state,
1340*8b26181fSAndroid Build Coastguard Worker "shift by more than 31 bits");
1341*8b26181fSAndroid Build Coastguard Worker /*
1342*8b26181fSAndroid Build Coastguard Worker * XXX - optimizer loop detection.
1343*8b26181fSAndroid Build Coastguard Worker */
1344*8b26181fSAndroid Build Coastguard Worker opt_state->non_branch_movement_performed = 1;
1345*8b26181fSAndroid Build Coastguard Worker opt_state->done = 0;
1346*8b26181fSAndroid Build Coastguard Worker val[A_ATOM] =
1347*8b26181fSAndroid Build Coastguard Worker F(opt_state, s->code, val[A_ATOM], K(s->k));
1348*8b26181fSAndroid Build Coastguard Worker }
1349*8b26181fSAndroid Build Coastguard Worker break;
1350*8b26181fSAndroid Build Coastguard Worker }
1351*8b26181fSAndroid Build Coastguard Worker /*
1352*8b26181fSAndroid Build Coastguard Worker * Check if we're doing something to an accumulator
1353*8b26181fSAndroid Build Coastguard Worker * that is 0, and simplify. This may not seem like
1354*8b26181fSAndroid Build Coastguard Worker * much of a simplification but it could open up further
1355*8b26181fSAndroid Build Coastguard Worker * optimizations.
1356*8b26181fSAndroid Build Coastguard Worker * XXX We could also check for mul by 1, etc.
1357*8b26181fSAndroid Build Coastguard Worker */
1358*8b26181fSAndroid Build Coastguard Worker if (alter && opt_state->vmap[val[A_ATOM]].is_const
1359*8b26181fSAndroid Build Coastguard Worker && opt_state->vmap[val[A_ATOM]].const_val == 0) {
1360*8b26181fSAndroid Build Coastguard Worker if (op == BPF_ADD || op == BPF_OR || op == BPF_XOR) {
1361*8b26181fSAndroid Build Coastguard Worker s->code = BPF_MISC|BPF_TXA;
1362*8b26181fSAndroid Build Coastguard Worker vstore(s, &val[A_ATOM], val[X_ATOM], alter);
1363*8b26181fSAndroid Build Coastguard Worker break;
1364*8b26181fSAndroid Build Coastguard Worker }
1365*8b26181fSAndroid Build Coastguard Worker else if (op == BPF_MUL || op == BPF_DIV || op == BPF_MOD ||
1366*8b26181fSAndroid Build Coastguard Worker op == BPF_AND || op == BPF_LSH || op == BPF_RSH) {
1367*8b26181fSAndroid Build Coastguard Worker s->code = BPF_LD|BPF_IMM;
1368*8b26181fSAndroid Build Coastguard Worker s->k = 0;
1369*8b26181fSAndroid Build Coastguard Worker vstore(s, &val[A_ATOM], K(s->k), alter);
1370*8b26181fSAndroid Build Coastguard Worker break;
1371*8b26181fSAndroid Build Coastguard Worker }
1372*8b26181fSAndroid Build Coastguard Worker else if (op == BPF_NEG) {
1373*8b26181fSAndroid Build Coastguard Worker s->code = NOP;
1374*8b26181fSAndroid Build Coastguard Worker break;
1375*8b26181fSAndroid Build Coastguard Worker }
1376*8b26181fSAndroid Build Coastguard Worker }
1377*8b26181fSAndroid Build Coastguard Worker val[A_ATOM] = F(opt_state, s->code, val[A_ATOM], val[X_ATOM]);
1378*8b26181fSAndroid Build Coastguard Worker break;
1379*8b26181fSAndroid Build Coastguard Worker
1380*8b26181fSAndroid Build Coastguard Worker case BPF_MISC|BPF_TXA:
1381*8b26181fSAndroid Build Coastguard Worker vstore(s, &val[A_ATOM], val[X_ATOM], alter);
1382*8b26181fSAndroid Build Coastguard Worker break;
1383*8b26181fSAndroid Build Coastguard Worker
1384*8b26181fSAndroid Build Coastguard Worker case BPF_LD|BPF_MEM:
1385*8b26181fSAndroid Build Coastguard Worker v = val[s->k];
1386*8b26181fSAndroid Build Coastguard Worker if (alter && opt_state->vmap[v].is_const) {
1387*8b26181fSAndroid Build Coastguard Worker s->code = BPF_LD|BPF_IMM;
1388*8b26181fSAndroid Build Coastguard Worker s->k = opt_state->vmap[v].const_val;
1389*8b26181fSAndroid Build Coastguard Worker /*
1390*8b26181fSAndroid Build Coastguard Worker * XXX - optimizer loop detection.
1391*8b26181fSAndroid Build Coastguard Worker */
1392*8b26181fSAndroid Build Coastguard Worker opt_state->non_branch_movement_performed = 1;
1393*8b26181fSAndroid Build Coastguard Worker opt_state->done = 0;
1394*8b26181fSAndroid Build Coastguard Worker }
1395*8b26181fSAndroid Build Coastguard Worker vstore(s, &val[A_ATOM], v, alter);
1396*8b26181fSAndroid Build Coastguard Worker break;
1397*8b26181fSAndroid Build Coastguard Worker
1398*8b26181fSAndroid Build Coastguard Worker case BPF_MISC|BPF_TAX:
1399*8b26181fSAndroid Build Coastguard Worker vstore(s, &val[X_ATOM], val[A_ATOM], alter);
1400*8b26181fSAndroid Build Coastguard Worker break;
1401*8b26181fSAndroid Build Coastguard Worker
1402*8b26181fSAndroid Build Coastguard Worker case BPF_LDX|BPF_MEM:
1403*8b26181fSAndroid Build Coastguard Worker v = val[s->k];
1404*8b26181fSAndroid Build Coastguard Worker if (alter && opt_state->vmap[v].is_const) {
1405*8b26181fSAndroid Build Coastguard Worker s->code = BPF_LDX|BPF_IMM;
1406*8b26181fSAndroid Build Coastguard Worker s->k = opt_state->vmap[v].const_val;
1407*8b26181fSAndroid Build Coastguard Worker /*
1408*8b26181fSAndroid Build Coastguard Worker * XXX - optimizer loop detection.
1409*8b26181fSAndroid Build Coastguard Worker */
1410*8b26181fSAndroid Build Coastguard Worker opt_state->non_branch_movement_performed = 1;
1411*8b26181fSAndroid Build Coastguard Worker opt_state->done = 0;
1412*8b26181fSAndroid Build Coastguard Worker }
1413*8b26181fSAndroid Build Coastguard Worker vstore(s, &val[X_ATOM], v, alter);
1414*8b26181fSAndroid Build Coastguard Worker break;
1415*8b26181fSAndroid Build Coastguard Worker
1416*8b26181fSAndroid Build Coastguard Worker case BPF_ST:
1417*8b26181fSAndroid Build Coastguard Worker vstore(s, &val[s->k], val[A_ATOM], alter);
1418*8b26181fSAndroid Build Coastguard Worker break;
1419*8b26181fSAndroid Build Coastguard Worker
1420*8b26181fSAndroid Build Coastguard Worker case BPF_STX:
1421*8b26181fSAndroid Build Coastguard Worker vstore(s, &val[s->k], val[X_ATOM], alter);
1422*8b26181fSAndroid Build Coastguard Worker break;
1423*8b26181fSAndroid Build Coastguard Worker }
1424*8b26181fSAndroid Build Coastguard Worker }
1425*8b26181fSAndroid Build Coastguard Worker
1426*8b26181fSAndroid Build Coastguard Worker static void
deadstmt(opt_state_t * opt_state,register struct stmt * s,register struct stmt * last[])1427*8b26181fSAndroid Build Coastguard Worker deadstmt(opt_state_t *opt_state, register struct stmt *s, register struct stmt *last[])
1428*8b26181fSAndroid Build Coastguard Worker {
1429*8b26181fSAndroid Build Coastguard Worker register int atom;
1430*8b26181fSAndroid Build Coastguard Worker
1431*8b26181fSAndroid Build Coastguard Worker atom = atomuse(s);
1432*8b26181fSAndroid Build Coastguard Worker if (atom >= 0) {
1433*8b26181fSAndroid Build Coastguard Worker if (atom == AX_ATOM) {
1434*8b26181fSAndroid Build Coastguard Worker last[X_ATOM] = 0;
1435*8b26181fSAndroid Build Coastguard Worker last[A_ATOM] = 0;
1436*8b26181fSAndroid Build Coastguard Worker }
1437*8b26181fSAndroid Build Coastguard Worker else
1438*8b26181fSAndroid Build Coastguard Worker last[atom] = 0;
1439*8b26181fSAndroid Build Coastguard Worker }
1440*8b26181fSAndroid Build Coastguard Worker atom = atomdef(s);
1441*8b26181fSAndroid Build Coastguard Worker if (atom >= 0) {
1442*8b26181fSAndroid Build Coastguard Worker if (last[atom]) {
1443*8b26181fSAndroid Build Coastguard Worker /*
1444*8b26181fSAndroid Build Coastguard Worker * XXX - optimizer loop detection.
1445*8b26181fSAndroid Build Coastguard Worker */
1446*8b26181fSAndroid Build Coastguard Worker opt_state->non_branch_movement_performed = 1;
1447*8b26181fSAndroid Build Coastguard Worker opt_state->done = 0;
1448*8b26181fSAndroid Build Coastguard Worker last[atom]->code = NOP;
1449*8b26181fSAndroid Build Coastguard Worker }
1450*8b26181fSAndroid Build Coastguard Worker last[atom] = s;
1451*8b26181fSAndroid Build Coastguard Worker }
1452*8b26181fSAndroid Build Coastguard Worker }
1453*8b26181fSAndroid Build Coastguard Worker
1454*8b26181fSAndroid Build Coastguard Worker static void
opt_deadstores(opt_state_t * opt_state,register struct block * b)1455*8b26181fSAndroid Build Coastguard Worker opt_deadstores(opt_state_t *opt_state, register struct block *b)
1456*8b26181fSAndroid Build Coastguard Worker {
1457*8b26181fSAndroid Build Coastguard Worker register struct slist *s;
1458*8b26181fSAndroid Build Coastguard Worker register int atom;
1459*8b26181fSAndroid Build Coastguard Worker struct stmt *last[N_ATOMS];
1460*8b26181fSAndroid Build Coastguard Worker
1461*8b26181fSAndroid Build Coastguard Worker memset((char *)last, 0, sizeof last);
1462*8b26181fSAndroid Build Coastguard Worker
1463*8b26181fSAndroid Build Coastguard Worker for (s = b->stmts; s != 0; s = s->next)
1464*8b26181fSAndroid Build Coastguard Worker deadstmt(opt_state, &s->s, last);
1465*8b26181fSAndroid Build Coastguard Worker deadstmt(opt_state, &b->s, last);
1466*8b26181fSAndroid Build Coastguard Worker
1467*8b26181fSAndroid Build Coastguard Worker for (atom = 0; atom < N_ATOMS; ++atom)
1468*8b26181fSAndroid Build Coastguard Worker if (last[atom] && !ATOMELEM(b->out_use, atom)) {
1469*8b26181fSAndroid Build Coastguard Worker last[atom]->code = NOP;
1470*8b26181fSAndroid Build Coastguard Worker /*
1471*8b26181fSAndroid Build Coastguard Worker * XXX - optimizer loop detection.
1472*8b26181fSAndroid Build Coastguard Worker */
1473*8b26181fSAndroid Build Coastguard Worker opt_state->non_branch_movement_performed = 1;
1474*8b26181fSAndroid Build Coastguard Worker opt_state->done = 0;
1475*8b26181fSAndroid Build Coastguard Worker }
1476*8b26181fSAndroid Build Coastguard Worker }
1477*8b26181fSAndroid Build Coastguard Worker
1478*8b26181fSAndroid Build Coastguard Worker static void
opt_blk(opt_state_t * opt_state,struct block * b,int do_stmts)1479*8b26181fSAndroid Build Coastguard Worker opt_blk(opt_state_t *opt_state, struct block *b, int do_stmts)
1480*8b26181fSAndroid Build Coastguard Worker {
1481*8b26181fSAndroid Build Coastguard Worker struct slist *s;
1482*8b26181fSAndroid Build Coastguard Worker struct edge *p;
1483*8b26181fSAndroid Build Coastguard Worker int i;
1484*8b26181fSAndroid Build Coastguard Worker bpf_u_int32 aval, xval;
1485*8b26181fSAndroid Build Coastguard Worker
1486*8b26181fSAndroid Build Coastguard Worker #if 0
1487*8b26181fSAndroid Build Coastguard Worker for (s = b->stmts; s && s->next; s = s->next)
1488*8b26181fSAndroid Build Coastguard Worker if (BPF_CLASS(s->s.code) == BPF_JMP) {
1489*8b26181fSAndroid Build Coastguard Worker do_stmts = 0;
1490*8b26181fSAndroid Build Coastguard Worker break;
1491*8b26181fSAndroid Build Coastguard Worker }
1492*8b26181fSAndroid Build Coastguard Worker #endif
1493*8b26181fSAndroid Build Coastguard Worker
1494*8b26181fSAndroid Build Coastguard Worker /*
1495*8b26181fSAndroid Build Coastguard Worker * Initialize the atom values.
1496*8b26181fSAndroid Build Coastguard Worker */
1497*8b26181fSAndroid Build Coastguard Worker p = b->in_edges;
1498*8b26181fSAndroid Build Coastguard Worker if (p == 0) {
1499*8b26181fSAndroid Build Coastguard Worker /*
1500*8b26181fSAndroid Build Coastguard Worker * We have no predecessors, so everything is undefined
1501*8b26181fSAndroid Build Coastguard Worker * upon entry to this block.
1502*8b26181fSAndroid Build Coastguard Worker */
1503*8b26181fSAndroid Build Coastguard Worker memset((char *)b->val, 0, sizeof(b->val));
1504*8b26181fSAndroid Build Coastguard Worker } else {
1505*8b26181fSAndroid Build Coastguard Worker /*
1506*8b26181fSAndroid Build Coastguard Worker * Inherit values from our predecessors.
1507*8b26181fSAndroid Build Coastguard Worker *
1508*8b26181fSAndroid Build Coastguard Worker * First, get the values from the predecessor along the
1509*8b26181fSAndroid Build Coastguard Worker * first edge leading to this node.
1510*8b26181fSAndroid Build Coastguard Worker */
1511*8b26181fSAndroid Build Coastguard Worker memcpy((char *)b->val, (char *)p->pred->val, sizeof(b->val));
1512*8b26181fSAndroid Build Coastguard Worker /*
1513*8b26181fSAndroid Build Coastguard Worker * Now look at all the other nodes leading to this node.
1514*8b26181fSAndroid Build Coastguard Worker * If, for the predecessor along that edge, a register
1515*8b26181fSAndroid Build Coastguard Worker * has a different value from the one we have (i.e.,
1516*8b26181fSAndroid Build Coastguard Worker * control paths are merging, and the merging paths
1517*8b26181fSAndroid Build Coastguard Worker * assign different values to that register), give the
1518*8b26181fSAndroid Build Coastguard Worker * register the undefined value of 0.
1519*8b26181fSAndroid Build Coastguard Worker */
1520*8b26181fSAndroid Build Coastguard Worker while ((p = p->next) != NULL) {
1521*8b26181fSAndroid Build Coastguard Worker for (i = 0; i < N_ATOMS; ++i)
1522*8b26181fSAndroid Build Coastguard Worker if (b->val[i] != p->pred->val[i])
1523*8b26181fSAndroid Build Coastguard Worker b->val[i] = 0;
1524*8b26181fSAndroid Build Coastguard Worker }
1525*8b26181fSAndroid Build Coastguard Worker }
1526*8b26181fSAndroid Build Coastguard Worker aval = b->val[A_ATOM];
1527*8b26181fSAndroid Build Coastguard Worker xval = b->val[X_ATOM];
1528*8b26181fSAndroid Build Coastguard Worker for (s = b->stmts; s; s = s->next)
1529*8b26181fSAndroid Build Coastguard Worker opt_stmt(opt_state, &s->s, b->val, do_stmts);
1530*8b26181fSAndroid Build Coastguard Worker
1531*8b26181fSAndroid Build Coastguard Worker /*
1532*8b26181fSAndroid Build Coastguard Worker * This is a special case: if we don't use anything from this
1533*8b26181fSAndroid Build Coastguard Worker * block, and we load the accumulator or index register with a
1534*8b26181fSAndroid Build Coastguard Worker * value that is already there, or if this block is a return,
1535*8b26181fSAndroid Build Coastguard Worker * eliminate all the statements.
1536*8b26181fSAndroid Build Coastguard Worker *
1537*8b26181fSAndroid Build Coastguard Worker * XXX - what if it does a store? Presumably that falls under
1538*8b26181fSAndroid Build Coastguard Worker * the heading of "if we don't use anything from this block",
1539*8b26181fSAndroid Build Coastguard Worker * i.e., if we use any memory location set to a different
1540*8b26181fSAndroid Build Coastguard Worker * value by this block, then we use something from this block.
1541*8b26181fSAndroid Build Coastguard Worker *
1542*8b26181fSAndroid Build Coastguard Worker * XXX - why does it matter whether we use anything from this
1543*8b26181fSAndroid Build Coastguard Worker * block? If the accumulator or index register doesn't change
1544*8b26181fSAndroid Build Coastguard Worker * its value, isn't that OK even if we use that value?
1545*8b26181fSAndroid Build Coastguard Worker *
1546*8b26181fSAndroid Build Coastguard Worker * XXX - if we load the accumulator with a different value,
1547*8b26181fSAndroid Build Coastguard Worker * and the block ends with a conditional branch, we obviously
1548*8b26181fSAndroid Build Coastguard Worker * can't eliminate it, as the branch depends on that value.
1549*8b26181fSAndroid Build Coastguard Worker * For the index register, the conditional branch only depends
1550*8b26181fSAndroid Build Coastguard Worker * on the index register value if the test is against the index
1551*8b26181fSAndroid Build Coastguard Worker * register value rather than a constant; if nothing uses the
1552*8b26181fSAndroid Build Coastguard Worker * value we put into the index register, and we're not testing
1553*8b26181fSAndroid Build Coastguard Worker * against the index register's value, and there aren't any
1554*8b26181fSAndroid Build Coastguard Worker * other problems that would keep us from eliminating this
1555*8b26181fSAndroid Build Coastguard Worker * block, can we eliminate it?
1556*8b26181fSAndroid Build Coastguard Worker */
1557*8b26181fSAndroid Build Coastguard Worker if (do_stmts &&
1558*8b26181fSAndroid Build Coastguard Worker ((b->out_use == 0 &&
1559*8b26181fSAndroid Build Coastguard Worker aval != VAL_UNKNOWN && b->val[A_ATOM] == aval &&
1560*8b26181fSAndroid Build Coastguard Worker xval != VAL_UNKNOWN && b->val[X_ATOM] == xval) ||
1561*8b26181fSAndroid Build Coastguard Worker BPF_CLASS(b->s.code) == BPF_RET)) {
1562*8b26181fSAndroid Build Coastguard Worker if (b->stmts != 0) {
1563*8b26181fSAndroid Build Coastguard Worker b->stmts = 0;
1564*8b26181fSAndroid Build Coastguard Worker /*
1565*8b26181fSAndroid Build Coastguard Worker * XXX - optimizer loop detection.
1566*8b26181fSAndroid Build Coastguard Worker */
1567*8b26181fSAndroid Build Coastguard Worker opt_state->non_branch_movement_performed = 1;
1568*8b26181fSAndroid Build Coastguard Worker opt_state->done = 0;
1569*8b26181fSAndroid Build Coastguard Worker }
1570*8b26181fSAndroid Build Coastguard Worker } else {
1571*8b26181fSAndroid Build Coastguard Worker opt_peep(opt_state, b);
1572*8b26181fSAndroid Build Coastguard Worker opt_deadstores(opt_state, b);
1573*8b26181fSAndroid Build Coastguard Worker }
1574*8b26181fSAndroid Build Coastguard Worker /*
1575*8b26181fSAndroid Build Coastguard Worker * Set up values for branch optimizer.
1576*8b26181fSAndroid Build Coastguard Worker */
1577*8b26181fSAndroid Build Coastguard Worker if (BPF_SRC(b->s.code) == BPF_K)
1578*8b26181fSAndroid Build Coastguard Worker b->oval = K(b->s.k);
1579*8b26181fSAndroid Build Coastguard Worker else
1580*8b26181fSAndroid Build Coastguard Worker b->oval = b->val[X_ATOM];
1581*8b26181fSAndroid Build Coastguard Worker b->et.code = b->s.code;
1582*8b26181fSAndroid Build Coastguard Worker b->ef.code = -b->s.code;
1583*8b26181fSAndroid Build Coastguard Worker }
1584*8b26181fSAndroid Build Coastguard Worker
1585*8b26181fSAndroid Build Coastguard Worker /*
1586*8b26181fSAndroid Build Coastguard Worker * Return true if any register that is used on exit from 'succ', has
1587*8b26181fSAndroid Build Coastguard Worker * an exit value that is different from the corresponding exit value
1588*8b26181fSAndroid Build Coastguard Worker * from 'b'.
1589*8b26181fSAndroid Build Coastguard Worker */
1590*8b26181fSAndroid Build Coastguard Worker static int
use_conflict(struct block * b,struct block * succ)1591*8b26181fSAndroid Build Coastguard Worker use_conflict(struct block *b, struct block *succ)
1592*8b26181fSAndroid Build Coastguard Worker {
1593*8b26181fSAndroid Build Coastguard Worker int atom;
1594*8b26181fSAndroid Build Coastguard Worker atomset use = succ->out_use;
1595*8b26181fSAndroid Build Coastguard Worker
1596*8b26181fSAndroid Build Coastguard Worker if (use == 0)
1597*8b26181fSAndroid Build Coastguard Worker return 0;
1598*8b26181fSAndroid Build Coastguard Worker
1599*8b26181fSAndroid Build Coastguard Worker for (atom = 0; atom < N_ATOMS; ++atom)
1600*8b26181fSAndroid Build Coastguard Worker if (ATOMELEM(use, atom))
1601*8b26181fSAndroid Build Coastguard Worker if (b->val[atom] != succ->val[atom])
1602*8b26181fSAndroid Build Coastguard Worker return 1;
1603*8b26181fSAndroid Build Coastguard Worker return 0;
1604*8b26181fSAndroid Build Coastguard Worker }
1605*8b26181fSAndroid Build Coastguard Worker
1606*8b26181fSAndroid Build Coastguard Worker /*
1607*8b26181fSAndroid Build Coastguard Worker * Given a block that is the successor of an edge, and an edge that
1608*8b26181fSAndroid Build Coastguard Worker * dominates that edge, return either a pointer to a child of that
1609*8b26181fSAndroid Build Coastguard Worker * block (a block to which that block jumps) if that block is a
1610*8b26181fSAndroid Build Coastguard Worker * candidate to replace the successor of the latter edge or NULL
1611*8b26181fSAndroid Build Coastguard Worker * if neither of the children of the first block are candidates.
1612*8b26181fSAndroid Build Coastguard Worker */
1613*8b26181fSAndroid Build Coastguard Worker static struct block *
fold_edge(struct block * child,struct edge * ep)1614*8b26181fSAndroid Build Coastguard Worker fold_edge(struct block *child, struct edge *ep)
1615*8b26181fSAndroid Build Coastguard Worker {
1616*8b26181fSAndroid Build Coastguard Worker int sense;
1617*8b26181fSAndroid Build Coastguard Worker bpf_u_int32 aval0, aval1, oval0, oval1;
1618*8b26181fSAndroid Build Coastguard Worker int code = ep->code;
1619*8b26181fSAndroid Build Coastguard Worker
1620*8b26181fSAndroid Build Coastguard Worker if (code < 0) {
1621*8b26181fSAndroid Build Coastguard Worker /*
1622*8b26181fSAndroid Build Coastguard Worker * This edge is a "branch if false" edge.
1623*8b26181fSAndroid Build Coastguard Worker */
1624*8b26181fSAndroid Build Coastguard Worker code = -code;
1625*8b26181fSAndroid Build Coastguard Worker sense = 0;
1626*8b26181fSAndroid Build Coastguard Worker } else {
1627*8b26181fSAndroid Build Coastguard Worker /*
1628*8b26181fSAndroid Build Coastguard Worker * This edge is a "branch if true" edge.
1629*8b26181fSAndroid Build Coastguard Worker */
1630*8b26181fSAndroid Build Coastguard Worker sense = 1;
1631*8b26181fSAndroid Build Coastguard Worker }
1632*8b26181fSAndroid Build Coastguard Worker
1633*8b26181fSAndroid Build Coastguard Worker /*
1634*8b26181fSAndroid Build Coastguard Worker * If the opcode for the branch at the end of the block we
1635*8b26181fSAndroid Build Coastguard Worker * were handed isn't the same as the opcode for the branch
1636*8b26181fSAndroid Build Coastguard Worker * to which the edge we were handed corresponds, the tests
1637*8b26181fSAndroid Build Coastguard Worker * for those branches aren't testing the same conditions,
1638*8b26181fSAndroid Build Coastguard Worker * so the blocks to which the first block branches aren't
1639*8b26181fSAndroid Build Coastguard Worker * candidates to replace the successor of the edge.
1640*8b26181fSAndroid Build Coastguard Worker */
1641*8b26181fSAndroid Build Coastguard Worker if (child->s.code != code)
1642*8b26181fSAndroid Build Coastguard Worker return 0;
1643*8b26181fSAndroid Build Coastguard Worker
1644*8b26181fSAndroid Build Coastguard Worker aval0 = child->val[A_ATOM];
1645*8b26181fSAndroid Build Coastguard Worker oval0 = child->oval;
1646*8b26181fSAndroid Build Coastguard Worker aval1 = ep->pred->val[A_ATOM];
1647*8b26181fSAndroid Build Coastguard Worker oval1 = ep->pred->oval;
1648*8b26181fSAndroid Build Coastguard Worker
1649*8b26181fSAndroid Build Coastguard Worker /*
1650*8b26181fSAndroid Build Coastguard Worker * If the A register value on exit from the successor block
1651*8b26181fSAndroid Build Coastguard Worker * isn't the same as the A register value on exit from the
1652*8b26181fSAndroid Build Coastguard Worker * predecessor of the edge, the blocks to which the first
1653*8b26181fSAndroid Build Coastguard Worker * block branches aren't candidates to replace the successor
1654*8b26181fSAndroid Build Coastguard Worker * of the edge.
1655*8b26181fSAndroid Build Coastguard Worker */
1656*8b26181fSAndroid Build Coastguard Worker if (aval0 != aval1)
1657*8b26181fSAndroid Build Coastguard Worker return 0;
1658*8b26181fSAndroid Build Coastguard Worker
1659*8b26181fSAndroid Build Coastguard Worker if (oval0 == oval1)
1660*8b26181fSAndroid Build Coastguard Worker /*
1661*8b26181fSAndroid Build Coastguard Worker * The operands of the branch instructions are
1662*8b26181fSAndroid Build Coastguard Worker * identical, so the branches are testing the
1663*8b26181fSAndroid Build Coastguard Worker * same condition, and the result is true if a true
1664*8b26181fSAndroid Build Coastguard Worker * branch was taken to get here, otherwise false.
1665*8b26181fSAndroid Build Coastguard Worker */
1666*8b26181fSAndroid Build Coastguard Worker return sense ? JT(child) : JF(child);
1667*8b26181fSAndroid Build Coastguard Worker
1668*8b26181fSAndroid Build Coastguard Worker if (sense && code == (BPF_JMP|BPF_JEQ|BPF_K))
1669*8b26181fSAndroid Build Coastguard Worker /*
1670*8b26181fSAndroid Build Coastguard Worker * At this point, we only know the comparison if we
1671*8b26181fSAndroid Build Coastguard Worker * came down the true branch, and it was an equality
1672*8b26181fSAndroid Build Coastguard Worker * comparison with a constant.
1673*8b26181fSAndroid Build Coastguard Worker *
1674*8b26181fSAndroid Build Coastguard Worker * I.e., if we came down the true branch, and the branch
1675*8b26181fSAndroid Build Coastguard Worker * was an equality comparison with a constant, we know the
1676*8b26181fSAndroid Build Coastguard Worker * accumulator contains that constant. If we came down
1677*8b26181fSAndroid Build Coastguard Worker * the false branch, or the comparison wasn't with a
1678*8b26181fSAndroid Build Coastguard Worker * constant, we don't know what was in the accumulator.
1679*8b26181fSAndroid Build Coastguard Worker *
1680*8b26181fSAndroid Build Coastguard Worker * We rely on the fact that distinct constants have distinct
1681*8b26181fSAndroid Build Coastguard Worker * value numbers.
1682*8b26181fSAndroid Build Coastguard Worker */
1683*8b26181fSAndroid Build Coastguard Worker return JF(child);
1684*8b26181fSAndroid Build Coastguard Worker
1685*8b26181fSAndroid Build Coastguard Worker return 0;
1686*8b26181fSAndroid Build Coastguard Worker }
1687*8b26181fSAndroid Build Coastguard Worker
1688*8b26181fSAndroid Build Coastguard Worker /*
1689*8b26181fSAndroid Build Coastguard Worker * If we can make this edge go directly to a child of the edge's current
1690*8b26181fSAndroid Build Coastguard Worker * successor, do so.
1691*8b26181fSAndroid Build Coastguard Worker */
1692*8b26181fSAndroid Build Coastguard Worker static void
opt_j(opt_state_t * opt_state,struct edge * ep)1693*8b26181fSAndroid Build Coastguard Worker opt_j(opt_state_t *opt_state, struct edge *ep)
1694*8b26181fSAndroid Build Coastguard Worker {
1695*8b26181fSAndroid Build Coastguard Worker register u_int i, k;
1696*8b26181fSAndroid Build Coastguard Worker register struct block *target;
1697*8b26181fSAndroid Build Coastguard Worker
1698*8b26181fSAndroid Build Coastguard Worker /*
1699*8b26181fSAndroid Build Coastguard Worker * Does this edge go to a block where, if the test
1700*8b26181fSAndroid Build Coastguard Worker * at the end of it succeeds, it goes to a block
1701*8b26181fSAndroid Build Coastguard Worker * that's a leaf node of the DAG, i.e. a return
1702*8b26181fSAndroid Build Coastguard Worker * statement?
1703*8b26181fSAndroid Build Coastguard Worker * If so, there's nothing to optimize.
1704*8b26181fSAndroid Build Coastguard Worker */
1705*8b26181fSAndroid Build Coastguard Worker if (JT(ep->succ) == 0)
1706*8b26181fSAndroid Build Coastguard Worker return;
1707*8b26181fSAndroid Build Coastguard Worker
1708*8b26181fSAndroid Build Coastguard Worker /*
1709*8b26181fSAndroid Build Coastguard Worker * Does this edge go to a block that goes, in turn, to
1710*8b26181fSAndroid Build Coastguard Worker * the same block regardless of whether the test at the
1711*8b26181fSAndroid Build Coastguard Worker * end succeeds or fails?
1712*8b26181fSAndroid Build Coastguard Worker */
1713*8b26181fSAndroid Build Coastguard Worker if (JT(ep->succ) == JF(ep->succ)) {
1714*8b26181fSAndroid Build Coastguard Worker /*
1715*8b26181fSAndroid Build Coastguard Worker * Common branch targets can be eliminated, provided
1716*8b26181fSAndroid Build Coastguard Worker * there is no data dependency.
1717*8b26181fSAndroid Build Coastguard Worker *
1718*8b26181fSAndroid Build Coastguard Worker * Check whether any register used on exit from the
1719*8b26181fSAndroid Build Coastguard Worker * block to which the successor of this edge goes
1720*8b26181fSAndroid Build Coastguard Worker * has a value at that point that's different from
1721*8b26181fSAndroid Build Coastguard Worker * the value it has on exit from the predecessor of
1722*8b26181fSAndroid Build Coastguard Worker * this edge. If not, the predecessor of this edge
1723*8b26181fSAndroid Build Coastguard Worker * can just go to the block to which the successor
1724*8b26181fSAndroid Build Coastguard Worker * of this edge goes, bypassing the successor of this
1725*8b26181fSAndroid Build Coastguard Worker * edge, as the successor of this edge isn't doing
1726*8b26181fSAndroid Build Coastguard Worker * any calculations whose results are different
1727*8b26181fSAndroid Build Coastguard Worker * from what the blocks before it did and isn't
1728*8b26181fSAndroid Build Coastguard Worker * doing any tests the results of which matter.
1729*8b26181fSAndroid Build Coastguard Worker */
1730*8b26181fSAndroid Build Coastguard Worker if (!use_conflict(ep->pred, JT(ep->succ))) {
1731*8b26181fSAndroid Build Coastguard Worker /*
1732*8b26181fSAndroid Build Coastguard Worker * No, there isn't.
1733*8b26181fSAndroid Build Coastguard Worker * Make this edge go to the block to
1734*8b26181fSAndroid Build Coastguard Worker * which the successor of that edge
1735*8b26181fSAndroid Build Coastguard Worker * goes.
1736*8b26181fSAndroid Build Coastguard Worker *
1737*8b26181fSAndroid Build Coastguard Worker * XXX - optimizer loop detection.
1738*8b26181fSAndroid Build Coastguard Worker */
1739*8b26181fSAndroid Build Coastguard Worker opt_state->non_branch_movement_performed = 1;
1740*8b26181fSAndroid Build Coastguard Worker opt_state->done = 0;
1741*8b26181fSAndroid Build Coastguard Worker ep->succ = JT(ep->succ);
1742*8b26181fSAndroid Build Coastguard Worker }
1743*8b26181fSAndroid Build Coastguard Worker }
1744*8b26181fSAndroid Build Coastguard Worker /*
1745*8b26181fSAndroid Build Coastguard Worker * For each edge dominator that matches the successor of this
1746*8b26181fSAndroid Build Coastguard Worker * edge, promote the edge successor to the its grandchild.
1747*8b26181fSAndroid Build Coastguard Worker *
1748*8b26181fSAndroid Build Coastguard Worker * XXX We violate the set abstraction here in favor a reasonably
1749*8b26181fSAndroid Build Coastguard Worker * efficient loop.
1750*8b26181fSAndroid Build Coastguard Worker */
1751*8b26181fSAndroid Build Coastguard Worker top:
1752*8b26181fSAndroid Build Coastguard Worker for (i = 0; i < opt_state->edgewords; ++i) {
1753*8b26181fSAndroid Build Coastguard Worker /* i'th word in the bitset of dominators */
1754*8b26181fSAndroid Build Coastguard Worker register bpf_u_int32 x = ep->edom[i];
1755*8b26181fSAndroid Build Coastguard Worker
1756*8b26181fSAndroid Build Coastguard Worker while (x != 0) {
1757*8b26181fSAndroid Build Coastguard Worker /* Find the next dominator in that word and mark it as found */
1758*8b26181fSAndroid Build Coastguard Worker k = lowest_set_bit(x);
1759*8b26181fSAndroid Build Coastguard Worker x &=~ ((bpf_u_int32)1 << k);
1760*8b26181fSAndroid Build Coastguard Worker k += i * BITS_PER_WORD;
1761*8b26181fSAndroid Build Coastguard Worker
1762*8b26181fSAndroid Build Coastguard Worker target = fold_edge(ep->succ, opt_state->edges[k]);
1763*8b26181fSAndroid Build Coastguard Worker /*
1764*8b26181fSAndroid Build Coastguard Worker * We have a candidate to replace the successor
1765*8b26181fSAndroid Build Coastguard Worker * of ep.
1766*8b26181fSAndroid Build Coastguard Worker *
1767*8b26181fSAndroid Build Coastguard Worker * Check that there is no data dependency between
1768*8b26181fSAndroid Build Coastguard Worker * nodes that will be violated if we move the edge;
1769*8b26181fSAndroid Build Coastguard Worker * i.e., if any register used on exit from the
1770*8b26181fSAndroid Build Coastguard Worker * candidate has a value at that point different
1771*8b26181fSAndroid Build Coastguard Worker * from the value it has when we exit the
1772*8b26181fSAndroid Build Coastguard Worker * predecessor of that edge, there's a data
1773*8b26181fSAndroid Build Coastguard Worker * dependency that will be violated.
1774*8b26181fSAndroid Build Coastguard Worker */
1775*8b26181fSAndroid Build Coastguard Worker if (target != 0 && !use_conflict(ep->pred, target)) {
1776*8b26181fSAndroid Build Coastguard Worker /*
1777*8b26181fSAndroid Build Coastguard Worker * It's safe to replace the successor of
1778*8b26181fSAndroid Build Coastguard Worker * ep; do so, and note that we've made
1779*8b26181fSAndroid Build Coastguard Worker * at least one change.
1780*8b26181fSAndroid Build Coastguard Worker *
1781*8b26181fSAndroid Build Coastguard Worker * XXX - this is one of the operations that
1782*8b26181fSAndroid Build Coastguard Worker * happens when the optimizer gets into
1783*8b26181fSAndroid Build Coastguard Worker * one of those infinite loops.
1784*8b26181fSAndroid Build Coastguard Worker */
1785*8b26181fSAndroid Build Coastguard Worker opt_state->done = 0;
1786*8b26181fSAndroid Build Coastguard Worker ep->succ = target;
1787*8b26181fSAndroid Build Coastguard Worker if (JT(target) != 0)
1788*8b26181fSAndroid Build Coastguard Worker /*
1789*8b26181fSAndroid Build Coastguard Worker * Start over unless we hit a leaf.
1790*8b26181fSAndroid Build Coastguard Worker */
1791*8b26181fSAndroid Build Coastguard Worker goto top;
1792*8b26181fSAndroid Build Coastguard Worker return;
1793*8b26181fSAndroid Build Coastguard Worker }
1794*8b26181fSAndroid Build Coastguard Worker }
1795*8b26181fSAndroid Build Coastguard Worker }
1796*8b26181fSAndroid Build Coastguard Worker }
1797*8b26181fSAndroid Build Coastguard Worker
1798*8b26181fSAndroid Build Coastguard Worker /*
1799*8b26181fSAndroid Build Coastguard Worker * XXX - is this, and and_pullup(), what's described in section 6.1.2
1800*8b26181fSAndroid Build Coastguard Worker * "Predicate Assertion Propagation" in the BPF+ paper?
1801*8b26181fSAndroid Build Coastguard Worker *
1802*8b26181fSAndroid Build Coastguard Worker * Note that this looks at block dominators, not edge dominators.
1803*8b26181fSAndroid Build Coastguard Worker * Don't think so.
1804*8b26181fSAndroid Build Coastguard Worker *
1805*8b26181fSAndroid Build Coastguard Worker * "A or B" compiles into
1806*8b26181fSAndroid Build Coastguard Worker *
1807*8b26181fSAndroid Build Coastguard Worker * A
1808*8b26181fSAndroid Build Coastguard Worker * t / \ f
1809*8b26181fSAndroid Build Coastguard Worker * / B
1810*8b26181fSAndroid Build Coastguard Worker * / t / \ f
1811*8b26181fSAndroid Build Coastguard Worker * \ /
1812*8b26181fSAndroid Build Coastguard Worker * \ /
1813*8b26181fSAndroid Build Coastguard Worker * X
1814*8b26181fSAndroid Build Coastguard Worker *
1815*8b26181fSAndroid Build Coastguard Worker *
1816*8b26181fSAndroid Build Coastguard Worker */
1817*8b26181fSAndroid Build Coastguard Worker static void
or_pullup(opt_state_t * opt_state,struct block * b)1818*8b26181fSAndroid Build Coastguard Worker or_pullup(opt_state_t *opt_state, struct block *b)
1819*8b26181fSAndroid Build Coastguard Worker {
1820*8b26181fSAndroid Build Coastguard Worker bpf_u_int32 val;
1821*8b26181fSAndroid Build Coastguard Worker int at_top;
1822*8b26181fSAndroid Build Coastguard Worker struct block *pull;
1823*8b26181fSAndroid Build Coastguard Worker struct block **diffp, **samep;
1824*8b26181fSAndroid Build Coastguard Worker struct edge *ep;
1825*8b26181fSAndroid Build Coastguard Worker
1826*8b26181fSAndroid Build Coastguard Worker ep = b->in_edges;
1827*8b26181fSAndroid Build Coastguard Worker if (ep == 0)
1828*8b26181fSAndroid Build Coastguard Worker return;
1829*8b26181fSAndroid Build Coastguard Worker
1830*8b26181fSAndroid Build Coastguard Worker /*
1831*8b26181fSAndroid Build Coastguard Worker * Make sure each predecessor loads the same value.
1832*8b26181fSAndroid Build Coastguard Worker * XXX why?
1833*8b26181fSAndroid Build Coastguard Worker */
1834*8b26181fSAndroid Build Coastguard Worker val = ep->pred->val[A_ATOM];
1835*8b26181fSAndroid Build Coastguard Worker for (ep = ep->next; ep != 0; ep = ep->next)
1836*8b26181fSAndroid Build Coastguard Worker if (val != ep->pred->val[A_ATOM])
1837*8b26181fSAndroid Build Coastguard Worker return;
1838*8b26181fSAndroid Build Coastguard Worker
1839*8b26181fSAndroid Build Coastguard Worker /*
1840*8b26181fSAndroid Build Coastguard Worker * For the first edge in the list of edges coming into this block,
1841*8b26181fSAndroid Build Coastguard Worker * see whether the predecessor of that edge comes here via a true
1842*8b26181fSAndroid Build Coastguard Worker * branch or a false branch.
1843*8b26181fSAndroid Build Coastguard Worker */
1844*8b26181fSAndroid Build Coastguard Worker if (JT(b->in_edges->pred) == b)
1845*8b26181fSAndroid Build Coastguard Worker diffp = &JT(b->in_edges->pred); /* jt */
1846*8b26181fSAndroid Build Coastguard Worker else
1847*8b26181fSAndroid Build Coastguard Worker diffp = &JF(b->in_edges->pred); /* jf */
1848*8b26181fSAndroid Build Coastguard Worker
1849*8b26181fSAndroid Build Coastguard Worker /*
1850*8b26181fSAndroid Build Coastguard Worker * diffp is a pointer to a pointer to the block.
1851*8b26181fSAndroid Build Coastguard Worker *
1852*8b26181fSAndroid Build Coastguard Worker * Go down the false chain looking as far as you can,
1853*8b26181fSAndroid Build Coastguard Worker * making sure that each jump-compare is doing the
1854*8b26181fSAndroid Build Coastguard Worker * same as the original block.
1855*8b26181fSAndroid Build Coastguard Worker *
1856*8b26181fSAndroid Build Coastguard Worker * If you reach the bottom before you reach a
1857*8b26181fSAndroid Build Coastguard Worker * different jump-compare, just exit. There's nothing
1858*8b26181fSAndroid Build Coastguard Worker * to do here. XXX - no, this version is checking for
1859*8b26181fSAndroid Build Coastguard Worker * the value leaving the block; that's from the BPF+
1860*8b26181fSAndroid Build Coastguard Worker * pullup routine.
1861*8b26181fSAndroid Build Coastguard Worker */
1862*8b26181fSAndroid Build Coastguard Worker at_top = 1;
1863*8b26181fSAndroid Build Coastguard Worker for (;;) {
1864*8b26181fSAndroid Build Coastguard Worker /*
1865*8b26181fSAndroid Build Coastguard Worker * Done if that's not going anywhere XXX
1866*8b26181fSAndroid Build Coastguard Worker */
1867*8b26181fSAndroid Build Coastguard Worker if (*diffp == 0)
1868*8b26181fSAndroid Build Coastguard Worker return;
1869*8b26181fSAndroid Build Coastguard Worker
1870*8b26181fSAndroid Build Coastguard Worker /*
1871*8b26181fSAndroid Build Coastguard Worker * Done if that predecessor blah blah blah isn't
1872*8b26181fSAndroid Build Coastguard Worker * going the same place we're going XXX
1873*8b26181fSAndroid Build Coastguard Worker *
1874*8b26181fSAndroid Build Coastguard Worker * Does the true edge of this block point to the same
1875*8b26181fSAndroid Build Coastguard Worker * location as the true edge of b?
1876*8b26181fSAndroid Build Coastguard Worker */
1877*8b26181fSAndroid Build Coastguard Worker if (JT(*diffp) != JT(b))
1878*8b26181fSAndroid Build Coastguard Worker return;
1879*8b26181fSAndroid Build Coastguard Worker
1880*8b26181fSAndroid Build Coastguard Worker /*
1881*8b26181fSAndroid Build Coastguard Worker * Done if this node isn't a dominator of that
1882*8b26181fSAndroid Build Coastguard Worker * node blah blah blah XXX
1883*8b26181fSAndroid Build Coastguard Worker *
1884*8b26181fSAndroid Build Coastguard Worker * Does b dominate diffp?
1885*8b26181fSAndroid Build Coastguard Worker */
1886*8b26181fSAndroid Build Coastguard Worker if (!SET_MEMBER((*diffp)->dom, b->id))
1887*8b26181fSAndroid Build Coastguard Worker return;
1888*8b26181fSAndroid Build Coastguard Worker
1889*8b26181fSAndroid Build Coastguard Worker /*
1890*8b26181fSAndroid Build Coastguard Worker * Break out of the loop if that node's value of A
1891*8b26181fSAndroid Build Coastguard Worker * isn't the value of A above XXX
1892*8b26181fSAndroid Build Coastguard Worker */
1893*8b26181fSAndroid Build Coastguard Worker if ((*diffp)->val[A_ATOM] != val)
1894*8b26181fSAndroid Build Coastguard Worker break;
1895*8b26181fSAndroid Build Coastguard Worker
1896*8b26181fSAndroid Build Coastguard Worker /*
1897*8b26181fSAndroid Build Coastguard Worker * Get the JF for that node XXX
1898*8b26181fSAndroid Build Coastguard Worker * Go down the false path.
1899*8b26181fSAndroid Build Coastguard Worker */
1900*8b26181fSAndroid Build Coastguard Worker diffp = &JF(*diffp);
1901*8b26181fSAndroid Build Coastguard Worker at_top = 0;
1902*8b26181fSAndroid Build Coastguard Worker }
1903*8b26181fSAndroid Build Coastguard Worker
1904*8b26181fSAndroid Build Coastguard Worker /*
1905*8b26181fSAndroid Build Coastguard Worker * Now that we've found a different jump-compare in a chain
1906*8b26181fSAndroid Build Coastguard Worker * below b, search further down until we find another
1907*8b26181fSAndroid Build Coastguard Worker * jump-compare that looks at the original value. This
1908*8b26181fSAndroid Build Coastguard Worker * jump-compare should get pulled up. XXX again we're
1909*8b26181fSAndroid Build Coastguard Worker * comparing values not jump-compares.
1910*8b26181fSAndroid Build Coastguard Worker */
1911*8b26181fSAndroid Build Coastguard Worker samep = &JF(*diffp);
1912*8b26181fSAndroid Build Coastguard Worker for (;;) {
1913*8b26181fSAndroid Build Coastguard Worker /*
1914*8b26181fSAndroid Build Coastguard Worker * Done if that's not going anywhere XXX
1915*8b26181fSAndroid Build Coastguard Worker */
1916*8b26181fSAndroid Build Coastguard Worker if (*samep == 0)
1917*8b26181fSAndroid Build Coastguard Worker return;
1918*8b26181fSAndroid Build Coastguard Worker
1919*8b26181fSAndroid Build Coastguard Worker /*
1920*8b26181fSAndroid Build Coastguard Worker * Done if that predecessor blah blah blah isn't
1921*8b26181fSAndroid Build Coastguard Worker * going the same place we're going XXX
1922*8b26181fSAndroid Build Coastguard Worker */
1923*8b26181fSAndroid Build Coastguard Worker if (JT(*samep) != JT(b))
1924*8b26181fSAndroid Build Coastguard Worker return;
1925*8b26181fSAndroid Build Coastguard Worker
1926*8b26181fSAndroid Build Coastguard Worker /*
1927*8b26181fSAndroid Build Coastguard Worker * Done if this node isn't a dominator of that
1928*8b26181fSAndroid Build Coastguard Worker * node blah blah blah XXX
1929*8b26181fSAndroid Build Coastguard Worker *
1930*8b26181fSAndroid Build Coastguard Worker * Does b dominate samep?
1931*8b26181fSAndroid Build Coastguard Worker */
1932*8b26181fSAndroid Build Coastguard Worker if (!SET_MEMBER((*samep)->dom, b->id))
1933*8b26181fSAndroid Build Coastguard Worker return;
1934*8b26181fSAndroid Build Coastguard Worker
1935*8b26181fSAndroid Build Coastguard Worker /*
1936*8b26181fSAndroid Build Coastguard Worker * Break out of the loop if that node's value of A
1937*8b26181fSAndroid Build Coastguard Worker * is the value of A above XXX
1938*8b26181fSAndroid Build Coastguard Worker */
1939*8b26181fSAndroid Build Coastguard Worker if ((*samep)->val[A_ATOM] == val)
1940*8b26181fSAndroid Build Coastguard Worker break;
1941*8b26181fSAndroid Build Coastguard Worker
1942*8b26181fSAndroid Build Coastguard Worker /* XXX Need to check that there are no data dependencies
1943*8b26181fSAndroid Build Coastguard Worker between dp0 and dp1. Currently, the code generator
1944*8b26181fSAndroid Build Coastguard Worker will not produce such dependencies. */
1945*8b26181fSAndroid Build Coastguard Worker samep = &JF(*samep);
1946*8b26181fSAndroid Build Coastguard Worker }
1947*8b26181fSAndroid Build Coastguard Worker #ifdef notdef
1948*8b26181fSAndroid Build Coastguard Worker /* XXX This doesn't cover everything. */
1949*8b26181fSAndroid Build Coastguard Worker for (i = 0; i < N_ATOMS; ++i)
1950*8b26181fSAndroid Build Coastguard Worker if ((*samep)->val[i] != pred->val[i])
1951*8b26181fSAndroid Build Coastguard Worker return;
1952*8b26181fSAndroid Build Coastguard Worker #endif
1953*8b26181fSAndroid Build Coastguard Worker /* Pull up the node. */
1954*8b26181fSAndroid Build Coastguard Worker pull = *samep;
1955*8b26181fSAndroid Build Coastguard Worker *samep = JF(pull);
1956*8b26181fSAndroid Build Coastguard Worker JF(pull) = *diffp;
1957*8b26181fSAndroid Build Coastguard Worker
1958*8b26181fSAndroid Build Coastguard Worker /*
1959*8b26181fSAndroid Build Coastguard Worker * At the top of the chain, each predecessor needs to point at the
1960*8b26181fSAndroid Build Coastguard Worker * pulled up node. Inside the chain, there is only one predecessor
1961*8b26181fSAndroid Build Coastguard Worker * to worry about.
1962*8b26181fSAndroid Build Coastguard Worker */
1963*8b26181fSAndroid Build Coastguard Worker if (at_top) {
1964*8b26181fSAndroid Build Coastguard Worker for (ep = b->in_edges; ep != 0; ep = ep->next) {
1965*8b26181fSAndroid Build Coastguard Worker if (JT(ep->pred) == b)
1966*8b26181fSAndroid Build Coastguard Worker JT(ep->pred) = pull;
1967*8b26181fSAndroid Build Coastguard Worker else
1968*8b26181fSAndroid Build Coastguard Worker JF(ep->pred) = pull;
1969*8b26181fSAndroid Build Coastguard Worker }
1970*8b26181fSAndroid Build Coastguard Worker }
1971*8b26181fSAndroid Build Coastguard Worker else
1972*8b26181fSAndroid Build Coastguard Worker *diffp = pull;
1973*8b26181fSAndroid Build Coastguard Worker
1974*8b26181fSAndroid Build Coastguard Worker /*
1975*8b26181fSAndroid Build Coastguard Worker * XXX - this is one of the operations that happens when the
1976*8b26181fSAndroid Build Coastguard Worker * optimizer gets into one of those infinite loops.
1977*8b26181fSAndroid Build Coastguard Worker */
1978*8b26181fSAndroid Build Coastguard Worker opt_state->done = 0;
1979*8b26181fSAndroid Build Coastguard Worker }
1980*8b26181fSAndroid Build Coastguard Worker
1981*8b26181fSAndroid Build Coastguard Worker static void
and_pullup(opt_state_t * opt_state,struct block * b)1982*8b26181fSAndroid Build Coastguard Worker and_pullup(opt_state_t *opt_state, struct block *b)
1983*8b26181fSAndroid Build Coastguard Worker {
1984*8b26181fSAndroid Build Coastguard Worker bpf_u_int32 val;
1985*8b26181fSAndroid Build Coastguard Worker int at_top;
1986*8b26181fSAndroid Build Coastguard Worker struct block *pull;
1987*8b26181fSAndroid Build Coastguard Worker struct block **diffp, **samep;
1988*8b26181fSAndroid Build Coastguard Worker struct edge *ep;
1989*8b26181fSAndroid Build Coastguard Worker
1990*8b26181fSAndroid Build Coastguard Worker ep = b->in_edges;
1991*8b26181fSAndroid Build Coastguard Worker if (ep == 0)
1992*8b26181fSAndroid Build Coastguard Worker return;
1993*8b26181fSAndroid Build Coastguard Worker
1994*8b26181fSAndroid Build Coastguard Worker /*
1995*8b26181fSAndroid Build Coastguard Worker * Make sure each predecessor loads the same value.
1996*8b26181fSAndroid Build Coastguard Worker */
1997*8b26181fSAndroid Build Coastguard Worker val = ep->pred->val[A_ATOM];
1998*8b26181fSAndroid Build Coastguard Worker for (ep = ep->next; ep != 0; ep = ep->next)
1999*8b26181fSAndroid Build Coastguard Worker if (val != ep->pred->val[A_ATOM])
2000*8b26181fSAndroid Build Coastguard Worker return;
2001*8b26181fSAndroid Build Coastguard Worker
2002*8b26181fSAndroid Build Coastguard Worker if (JT(b->in_edges->pred) == b)
2003*8b26181fSAndroid Build Coastguard Worker diffp = &JT(b->in_edges->pred);
2004*8b26181fSAndroid Build Coastguard Worker else
2005*8b26181fSAndroid Build Coastguard Worker diffp = &JF(b->in_edges->pred);
2006*8b26181fSAndroid Build Coastguard Worker
2007*8b26181fSAndroid Build Coastguard Worker at_top = 1;
2008*8b26181fSAndroid Build Coastguard Worker for (;;) {
2009*8b26181fSAndroid Build Coastguard Worker if (*diffp == 0)
2010*8b26181fSAndroid Build Coastguard Worker return;
2011*8b26181fSAndroid Build Coastguard Worker
2012*8b26181fSAndroid Build Coastguard Worker if (JF(*diffp) != JF(b))
2013*8b26181fSAndroid Build Coastguard Worker return;
2014*8b26181fSAndroid Build Coastguard Worker
2015*8b26181fSAndroid Build Coastguard Worker if (!SET_MEMBER((*diffp)->dom, b->id))
2016*8b26181fSAndroid Build Coastguard Worker return;
2017*8b26181fSAndroid Build Coastguard Worker
2018*8b26181fSAndroid Build Coastguard Worker if ((*diffp)->val[A_ATOM] != val)
2019*8b26181fSAndroid Build Coastguard Worker break;
2020*8b26181fSAndroid Build Coastguard Worker
2021*8b26181fSAndroid Build Coastguard Worker diffp = &JT(*diffp);
2022*8b26181fSAndroid Build Coastguard Worker at_top = 0;
2023*8b26181fSAndroid Build Coastguard Worker }
2024*8b26181fSAndroid Build Coastguard Worker samep = &JT(*diffp);
2025*8b26181fSAndroid Build Coastguard Worker for (;;) {
2026*8b26181fSAndroid Build Coastguard Worker if (*samep == 0)
2027*8b26181fSAndroid Build Coastguard Worker return;
2028*8b26181fSAndroid Build Coastguard Worker
2029*8b26181fSAndroid Build Coastguard Worker if (JF(*samep) != JF(b))
2030*8b26181fSAndroid Build Coastguard Worker return;
2031*8b26181fSAndroid Build Coastguard Worker
2032*8b26181fSAndroid Build Coastguard Worker if (!SET_MEMBER((*samep)->dom, b->id))
2033*8b26181fSAndroid Build Coastguard Worker return;
2034*8b26181fSAndroid Build Coastguard Worker
2035*8b26181fSAndroid Build Coastguard Worker if ((*samep)->val[A_ATOM] == val)
2036*8b26181fSAndroid Build Coastguard Worker break;
2037*8b26181fSAndroid Build Coastguard Worker
2038*8b26181fSAndroid Build Coastguard Worker /* XXX Need to check that there are no data dependencies
2039*8b26181fSAndroid Build Coastguard Worker between diffp and samep. Currently, the code generator
2040*8b26181fSAndroid Build Coastguard Worker will not produce such dependencies. */
2041*8b26181fSAndroid Build Coastguard Worker samep = &JT(*samep);
2042*8b26181fSAndroid Build Coastguard Worker }
2043*8b26181fSAndroid Build Coastguard Worker #ifdef notdef
2044*8b26181fSAndroid Build Coastguard Worker /* XXX This doesn't cover everything. */
2045*8b26181fSAndroid Build Coastguard Worker for (i = 0; i < N_ATOMS; ++i)
2046*8b26181fSAndroid Build Coastguard Worker if ((*samep)->val[i] != pred->val[i])
2047*8b26181fSAndroid Build Coastguard Worker return;
2048*8b26181fSAndroid Build Coastguard Worker #endif
2049*8b26181fSAndroid Build Coastguard Worker /* Pull up the node. */
2050*8b26181fSAndroid Build Coastguard Worker pull = *samep;
2051*8b26181fSAndroid Build Coastguard Worker *samep = JT(pull);
2052*8b26181fSAndroid Build Coastguard Worker JT(pull) = *diffp;
2053*8b26181fSAndroid Build Coastguard Worker
2054*8b26181fSAndroid Build Coastguard Worker /*
2055*8b26181fSAndroid Build Coastguard Worker * At the top of the chain, each predecessor needs to point at the
2056*8b26181fSAndroid Build Coastguard Worker * pulled up node. Inside the chain, there is only one predecessor
2057*8b26181fSAndroid Build Coastguard Worker * to worry about.
2058*8b26181fSAndroid Build Coastguard Worker */
2059*8b26181fSAndroid Build Coastguard Worker if (at_top) {
2060*8b26181fSAndroid Build Coastguard Worker for (ep = b->in_edges; ep != 0; ep = ep->next) {
2061*8b26181fSAndroid Build Coastguard Worker if (JT(ep->pred) == b)
2062*8b26181fSAndroid Build Coastguard Worker JT(ep->pred) = pull;
2063*8b26181fSAndroid Build Coastguard Worker else
2064*8b26181fSAndroid Build Coastguard Worker JF(ep->pred) = pull;
2065*8b26181fSAndroid Build Coastguard Worker }
2066*8b26181fSAndroid Build Coastguard Worker }
2067*8b26181fSAndroid Build Coastguard Worker else
2068*8b26181fSAndroid Build Coastguard Worker *diffp = pull;
2069*8b26181fSAndroid Build Coastguard Worker
2070*8b26181fSAndroid Build Coastguard Worker /*
2071*8b26181fSAndroid Build Coastguard Worker * XXX - this is one of the operations that happens when the
2072*8b26181fSAndroid Build Coastguard Worker * optimizer gets into one of those infinite loops.
2073*8b26181fSAndroid Build Coastguard Worker */
2074*8b26181fSAndroid Build Coastguard Worker opt_state->done = 0;
2075*8b26181fSAndroid Build Coastguard Worker }
2076*8b26181fSAndroid Build Coastguard Worker
2077*8b26181fSAndroid Build Coastguard Worker static void
opt_blks(opt_state_t * opt_state,struct icode * ic,int do_stmts)2078*8b26181fSAndroid Build Coastguard Worker opt_blks(opt_state_t *opt_state, struct icode *ic, int do_stmts)
2079*8b26181fSAndroid Build Coastguard Worker {
2080*8b26181fSAndroid Build Coastguard Worker int i, maxlevel;
2081*8b26181fSAndroid Build Coastguard Worker struct block *p;
2082*8b26181fSAndroid Build Coastguard Worker
2083*8b26181fSAndroid Build Coastguard Worker init_val(opt_state);
2084*8b26181fSAndroid Build Coastguard Worker maxlevel = ic->root->level;
2085*8b26181fSAndroid Build Coastguard Worker
2086*8b26181fSAndroid Build Coastguard Worker find_inedges(opt_state, ic->root);
2087*8b26181fSAndroid Build Coastguard Worker for (i = maxlevel; i >= 0; --i)
2088*8b26181fSAndroid Build Coastguard Worker for (p = opt_state->levels[i]; p; p = p->link)
2089*8b26181fSAndroid Build Coastguard Worker opt_blk(opt_state, p, do_stmts);
2090*8b26181fSAndroid Build Coastguard Worker
2091*8b26181fSAndroid Build Coastguard Worker if (do_stmts)
2092*8b26181fSAndroid Build Coastguard Worker /*
2093*8b26181fSAndroid Build Coastguard Worker * No point trying to move branches; it can't possibly
2094*8b26181fSAndroid Build Coastguard Worker * make a difference at this point.
2095*8b26181fSAndroid Build Coastguard Worker *
2096*8b26181fSAndroid Build Coastguard Worker * XXX - this might be after we detect a loop where
2097*8b26181fSAndroid Build Coastguard Worker * we were just looping infinitely moving branches
2098*8b26181fSAndroid Build Coastguard Worker * in such a fashion that we went through two or more
2099*8b26181fSAndroid Build Coastguard Worker * versions of the machine code, eventually returning
2100*8b26181fSAndroid Build Coastguard Worker * to the first version. (We're really not doing a
2101*8b26181fSAndroid Build Coastguard Worker * full loop detection, we're just testing for two
2102*8b26181fSAndroid Build Coastguard Worker * passes in a row where we do nothing but
2103*8b26181fSAndroid Build Coastguard Worker * move branches.)
2104*8b26181fSAndroid Build Coastguard Worker */
2105*8b26181fSAndroid Build Coastguard Worker return;
2106*8b26181fSAndroid Build Coastguard Worker
2107*8b26181fSAndroid Build Coastguard Worker /*
2108*8b26181fSAndroid Build Coastguard Worker * Is this what the BPF+ paper describes in sections 6.1.1,
2109*8b26181fSAndroid Build Coastguard Worker * 6.1.2, and 6.1.3?
2110*8b26181fSAndroid Build Coastguard Worker */
2111*8b26181fSAndroid Build Coastguard Worker for (i = 1; i <= maxlevel; ++i) {
2112*8b26181fSAndroid Build Coastguard Worker for (p = opt_state->levels[i]; p; p = p->link) {
2113*8b26181fSAndroid Build Coastguard Worker opt_j(opt_state, &p->et);
2114*8b26181fSAndroid Build Coastguard Worker opt_j(opt_state, &p->ef);
2115*8b26181fSAndroid Build Coastguard Worker }
2116*8b26181fSAndroid Build Coastguard Worker }
2117*8b26181fSAndroid Build Coastguard Worker
2118*8b26181fSAndroid Build Coastguard Worker find_inedges(opt_state, ic->root);
2119*8b26181fSAndroid Build Coastguard Worker for (i = 1; i <= maxlevel; ++i) {
2120*8b26181fSAndroid Build Coastguard Worker for (p = opt_state->levels[i]; p; p = p->link) {
2121*8b26181fSAndroid Build Coastguard Worker or_pullup(opt_state, p);
2122*8b26181fSAndroid Build Coastguard Worker and_pullup(opt_state, p);
2123*8b26181fSAndroid Build Coastguard Worker }
2124*8b26181fSAndroid Build Coastguard Worker }
2125*8b26181fSAndroid Build Coastguard Worker }
2126*8b26181fSAndroid Build Coastguard Worker
2127*8b26181fSAndroid Build Coastguard Worker static inline void
link_inedge(struct edge * parent,struct block * child)2128*8b26181fSAndroid Build Coastguard Worker link_inedge(struct edge *parent, struct block *child)
2129*8b26181fSAndroid Build Coastguard Worker {
2130*8b26181fSAndroid Build Coastguard Worker parent->next = child->in_edges;
2131*8b26181fSAndroid Build Coastguard Worker child->in_edges = parent;
2132*8b26181fSAndroid Build Coastguard Worker }
2133*8b26181fSAndroid Build Coastguard Worker
2134*8b26181fSAndroid Build Coastguard Worker static void
find_inedges(opt_state_t * opt_state,struct block * root)2135*8b26181fSAndroid Build Coastguard Worker find_inedges(opt_state_t *opt_state, struct block *root)
2136*8b26181fSAndroid Build Coastguard Worker {
2137*8b26181fSAndroid Build Coastguard Worker u_int i;
2138*8b26181fSAndroid Build Coastguard Worker int level;
2139*8b26181fSAndroid Build Coastguard Worker struct block *b;
2140*8b26181fSAndroid Build Coastguard Worker
2141*8b26181fSAndroid Build Coastguard Worker for (i = 0; i < opt_state->n_blocks; ++i)
2142*8b26181fSAndroid Build Coastguard Worker opt_state->blocks[i]->in_edges = 0;
2143*8b26181fSAndroid Build Coastguard Worker
2144*8b26181fSAndroid Build Coastguard Worker /*
2145*8b26181fSAndroid Build Coastguard Worker * Traverse the graph, adding each edge to the predecessor
2146*8b26181fSAndroid Build Coastguard Worker * list of its successors. Skip the leaves (i.e. level 0).
2147*8b26181fSAndroid Build Coastguard Worker */
2148*8b26181fSAndroid Build Coastguard Worker for (level = root->level; level > 0; --level) {
2149*8b26181fSAndroid Build Coastguard Worker for (b = opt_state->levels[level]; b != 0; b = b->link) {
2150*8b26181fSAndroid Build Coastguard Worker link_inedge(&b->et, JT(b));
2151*8b26181fSAndroid Build Coastguard Worker link_inedge(&b->ef, JF(b));
2152*8b26181fSAndroid Build Coastguard Worker }
2153*8b26181fSAndroid Build Coastguard Worker }
2154*8b26181fSAndroid Build Coastguard Worker }
2155*8b26181fSAndroid Build Coastguard Worker
2156*8b26181fSAndroid Build Coastguard Worker static void
opt_root(struct block ** b)2157*8b26181fSAndroid Build Coastguard Worker opt_root(struct block **b)
2158*8b26181fSAndroid Build Coastguard Worker {
2159*8b26181fSAndroid Build Coastguard Worker struct slist *tmp, *s;
2160*8b26181fSAndroid Build Coastguard Worker
2161*8b26181fSAndroid Build Coastguard Worker s = (*b)->stmts;
2162*8b26181fSAndroid Build Coastguard Worker (*b)->stmts = 0;
2163*8b26181fSAndroid Build Coastguard Worker while (BPF_CLASS((*b)->s.code) == BPF_JMP && JT(*b) == JF(*b))
2164*8b26181fSAndroid Build Coastguard Worker *b = JT(*b);
2165*8b26181fSAndroid Build Coastguard Worker
2166*8b26181fSAndroid Build Coastguard Worker tmp = (*b)->stmts;
2167*8b26181fSAndroid Build Coastguard Worker if (tmp != 0)
2168*8b26181fSAndroid Build Coastguard Worker sappend(s, tmp);
2169*8b26181fSAndroid Build Coastguard Worker (*b)->stmts = s;
2170*8b26181fSAndroid Build Coastguard Worker
2171*8b26181fSAndroid Build Coastguard Worker /*
2172*8b26181fSAndroid Build Coastguard Worker * If the root node is a return, then there is no
2173*8b26181fSAndroid Build Coastguard Worker * point executing any statements (since the bpf machine
2174*8b26181fSAndroid Build Coastguard Worker * has no side effects).
2175*8b26181fSAndroid Build Coastguard Worker */
2176*8b26181fSAndroid Build Coastguard Worker if (BPF_CLASS((*b)->s.code) == BPF_RET)
2177*8b26181fSAndroid Build Coastguard Worker (*b)->stmts = 0;
2178*8b26181fSAndroid Build Coastguard Worker }
2179*8b26181fSAndroid Build Coastguard Worker
2180*8b26181fSAndroid Build Coastguard Worker static void
opt_loop(opt_state_t * opt_state,struct icode * ic,int do_stmts)2181*8b26181fSAndroid Build Coastguard Worker opt_loop(opt_state_t *opt_state, struct icode *ic, int do_stmts)
2182*8b26181fSAndroid Build Coastguard Worker {
2183*8b26181fSAndroid Build Coastguard Worker
2184*8b26181fSAndroid Build Coastguard Worker #ifdef BDEBUG
2185*8b26181fSAndroid Build Coastguard Worker if (pcap_optimizer_debug > 1 || pcap_print_dot_graph) {
2186*8b26181fSAndroid Build Coastguard Worker printf("opt_loop(root, %d) begin\n", do_stmts);
2187*8b26181fSAndroid Build Coastguard Worker opt_dump(opt_state, ic);
2188*8b26181fSAndroid Build Coastguard Worker }
2189*8b26181fSAndroid Build Coastguard Worker #endif
2190*8b26181fSAndroid Build Coastguard Worker
2191*8b26181fSAndroid Build Coastguard Worker /*
2192*8b26181fSAndroid Build Coastguard Worker * XXX - optimizer loop detection.
2193*8b26181fSAndroid Build Coastguard Worker */
2194*8b26181fSAndroid Build Coastguard Worker int loop_count = 0;
2195*8b26181fSAndroid Build Coastguard Worker for (;;) {
2196*8b26181fSAndroid Build Coastguard Worker opt_state->done = 1;
2197*8b26181fSAndroid Build Coastguard Worker /*
2198*8b26181fSAndroid Build Coastguard Worker * XXX - optimizer loop detection.
2199*8b26181fSAndroid Build Coastguard Worker */
2200*8b26181fSAndroid Build Coastguard Worker opt_state->non_branch_movement_performed = 0;
2201*8b26181fSAndroid Build Coastguard Worker find_levels(opt_state, ic);
2202*8b26181fSAndroid Build Coastguard Worker find_dom(opt_state, ic->root);
2203*8b26181fSAndroid Build Coastguard Worker find_closure(opt_state, ic->root);
2204*8b26181fSAndroid Build Coastguard Worker find_ud(opt_state, ic->root);
2205*8b26181fSAndroid Build Coastguard Worker find_edom(opt_state, ic->root);
2206*8b26181fSAndroid Build Coastguard Worker opt_blks(opt_state, ic, do_stmts);
2207*8b26181fSAndroid Build Coastguard Worker #ifdef BDEBUG
2208*8b26181fSAndroid Build Coastguard Worker if (pcap_optimizer_debug > 1 || pcap_print_dot_graph) {
2209*8b26181fSAndroid Build Coastguard Worker printf("opt_loop(root, %d) bottom, done=%d\n", do_stmts, opt_state->done);
2210*8b26181fSAndroid Build Coastguard Worker opt_dump(opt_state, ic);
2211*8b26181fSAndroid Build Coastguard Worker }
2212*8b26181fSAndroid Build Coastguard Worker #endif
2213*8b26181fSAndroid Build Coastguard Worker
2214*8b26181fSAndroid Build Coastguard Worker /*
2215*8b26181fSAndroid Build Coastguard Worker * Was anything done in this optimizer pass?
2216*8b26181fSAndroid Build Coastguard Worker */
2217*8b26181fSAndroid Build Coastguard Worker if (opt_state->done) {
2218*8b26181fSAndroid Build Coastguard Worker /*
2219*8b26181fSAndroid Build Coastguard Worker * No, so we've reached a fixed point.
2220*8b26181fSAndroid Build Coastguard Worker * We're done.
2221*8b26181fSAndroid Build Coastguard Worker */
2222*8b26181fSAndroid Build Coastguard Worker break;
2223*8b26181fSAndroid Build Coastguard Worker }
2224*8b26181fSAndroid Build Coastguard Worker
2225*8b26181fSAndroid Build Coastguard Worker /*
2226*8b26181fSAndroid Build Coastguard Worker * XXX - was anything done other than branch movement
2227*8b26181fSAndroid Build Coastguard Worker * in this pass?
2228*8b26181fSAndroid Build Coastguard Worker */
2229*8b26181fSAndroid Build Coastguard Worker if (opt_state->non_branch_movement_performed) {
2230*8b26181fSAndroid Build Coastguard Worker /*
2231*8b26181fSAndroid Build Coastguard Worker * Yes. Clear any loop-detection counter;
2232*8b26181fSAndroid Build Coastguard Worker * we're making some form of progress (assuming
2233*8b26181fSAndroid Build Coastguard Worker * we can't get into a cycle doing *other*
2234*8b26181fSAndroid Build Coastguard Worker * optimizations...).
2235*8b26181fSAndroid Build Coastguard Worker */
2236*8b26181fSAndroid Build Coastguard Worker loop_count = 0;
2237*8b26181fSAndroid Build Coastguard Worker } else {
2238*8b26181fSAndroid Build Coastguard Worker /*
2239*8b26181fSAndroid Build Coastguard Worker * No - increment the counter, and quit if
2240*8b26181fSAndroid Build Coastguard Worker * it's up to 100.
2241*8b26181fSAndroid Build Coastguard Worker */
2242*8b26181fSAndroid Build Coastguard Worker loop_count++;
2243*8b26181fSAndroid Build Coastguard Worker if (loop_count >= 100) {
2244*8b26181fSAndroid Build Coastguard Worker /*
2245*8b26181fSAndroid Build Coastguard Worker * We've done nothing but branch movement
2246*8b26181fSAndroid Build Coastguard Worker * for 100 passes; we're probably
2247*8b26181fSAndroid Build Coastguard Worker * in a cycle and will never reach a
2248*8b26181fSAndroid Build Coastguard Worker * fixed point.
2249*8b26181fSAndroid Build Coastguard Worker *
2250*8b26181fSAndroid Build Coastguard Worker * XXX - yes, we really need a non-
2251*8b26181fSAndroid Build Coastguard Worker * heuristic way of detecting a cycle.
2252*8b26181fSAndroid Build Coastguard Worker */
2253*8b26181fSAndroid Build Coastguard Worker opt_state->done = 1;
2254*8b26181fSAndroid Build Coastguard Worker break;
2255*8b26181fSAndroid Build Coastguard Worker }
2256*8b26181fSAndroid Build Coastguard Worker }
2257*8b26181fSAndroid Build Coastguard Worker }
2258*8b26181fSAndroid Build Coastguard Worker }
2259*8b26181fSAndroid Build Coastguard Worker
2260*8b26181fSAndroid Build Coastguard Worker /*
2261*8b26181fSAndroid Build Coastguard Worker * Optimize the filter code in its dag representation.
2262*8b26181fSAndroid Build Coastguard Worker * Return 0 on success, -1 on error.
2263*8b26181fSAndroid Build Coastguard Worker */
2264*8b26181fSAndroid Build Coastguard Worker int
bpf_optimize(struct icode * ic,char * errbuf)2265*8b26181fSAndroid Build Coastguard Worker bpf_optimize(struct icode *ic, char *errbuf)
2266*8b26181fSAndroid Build Coastguard Worker {
2267*8b26181fSAndroid Build Coastguard Worker opt_state_t opt_state;
2268*8b26181fSAndroid Build Coastguard Worker
2269*8b26181fSAndroid Build Coastguard Worker memset(&opt_state, 0, sizeof(opt_state));
2270*8b26181fSAndroid Build Coastguard Worker opt_state.errbuf = errbuf;
2271*8b26181fSAndroid Build Coastguard Worker opt_state.non_branch_movement_performed = 0;
2272*8b26181fSAndroid Build Coastguard Worker if (setjmp(opt_state.top_ctx)) {
2273*8b26181fSAndroid Build Coastguard Worker opt_cleanup(&opt_state);
2274*8b26181fSAndroid Build Coastguard Worker return -1;
2275*8b26181fSAndroid Build Coastguard Worker }
2276*8b26181fSAndroid Build Coastguard Worker opt_init(&opt_state, ic);
2277*8b26181fSAndroid Build Coastguard Worker opt_loop(&opt_state, ic, 0);
2278*8b26181fSAndroid Build Coastguard Worker opt_loop(&opt_state, ic, 1);
2279*8b26181fSAndroid Build Coastguard Worker intern_blocks(&opt_state, ic);
2280*8b26181fSAndroid Build Coastguard Worker #ifdef BDEBUG
2281*8b26181fSAndroid Build Coastguard Worker if (pcap_optimizer_debug > 1 || pcap_print_dot_graph) {
2282*8b26181fSAndroid Build Coastguard Worker printf("after intern_blocks()\n");
2283*8b26181fSAndroid Build Coastguard Worker opt_dump(&opt_state, ic);
2284*8b26181fSAndroid Build Coastguard Worker }
2285*8b26181fSAndroid Build Coastguard Worker #endif
2286*8b26181fSAndroid Build Coastguard Worker opt_root(&ic->root);
2287*8b26181fSAndroid Build Coastguard Worker #ifdef BDEBUG
2288*8b26181fSAndroid Build Coastguard Worker if (pcap_optimizer_debug > 1 || pcap_print_dot_graph) {
2289*8b26181fSAndroid Build Coastguard Worker printf("after opt_root()\n");
2290*8b26181fSAndroid Build Coastguard Worker opt_dump(&opt_state, ic);
2291*8b26181fSAndroid Build Coastguard Worker }
2292*8b26181fSAndroid Build Coastguard Worker #endif
2293*8b26181fSAndroid Build Coastguard Worker opt_cleanup(&opt_state);
2294*8b26181fSAndroid Build Coastguard Worker return 0;
2295*8b26181fSAndroid Build Coastguard Worker }
2296*8b26181fSAndroid Build Coastguard Worker
2297*8b26181fSAndroid Build Coastguard Worker static void
make_marks(struct icode * ic,struct block * p)2298*8b26181fSAndroid Build Coastguard Worker make_marks(struct icode *ic, struct block *p)
2299*8b26181fSAndroid Build Coastguard Worker {
2300*8b26181fSAndroid Build Coastguard Worker if (!isMarked(ic, p)) {
2301*8b26181fSAndroid Build Coastguard Worker Mark(ic, p);
2302*8b26181fSAndroid Build Coastguard Worker if (BPF_CLASS(p->s.code) != BPF_RET) {
2303*8b26181fSAndroid Build Coastguard Worker make_marks(ic, JT(p));
2304*8b26181fSAndroid Build Coastguard Worker make_marks(ic, JF(p));
2305*8b26181fSAndroid Build Coastguard Worker }
2306*8b26181fSAndroid Build Coastguard Worker }
2307*8b26181fSAndroid Build Coastguard Worker }
2308*8b26181fSAndroid Build Coastguard Worker
2309*8b26181fSAndroid Build Coastguard Worker /*
2310*8b26181fSAndroid Build Coastguard Worker * Mark code array such that isMarked(ic->cur_mark, i) is true
2311*8b26181fSAndroid Build Coastguard Worker * only for nodes that are alive.
2312*8b26181fSAndroid Build Coastguard Worker */
2313*8b26181fSAndroid Build Coastguard Worker static void
mark_code(struct icode * ic)2314*8b26181fSAndroid Build Coastguard Worker mark_code(struct icode *ic)
2315*8b26181fSAndroid Build Coastguard Worker {
2316*8b26181fSAndroid Build Coastguard Worker ic->cur_mark += 1;
2317*8b26181fSAndroid Build Coastguard Worker make_marks(ic, ic->root);
2318*8b26181fSAndroid Build Coastguard Worker }
2319*8b26181fSAndroid Build Coastguard Worker
2320*8b26181fSAndroid Build Coastguard Worker /*
2321*8b26181fSAndroid Build Coastguard Worker * True iff the two stmt lists load the same value from the packet into
2322*8b26181fSAndroid Build Coastguard Worker * the accumulator.
2323*8b26181fSAndroid Build Coastguard Worker */
2324*8b26181fSAndroid Build Coastguard Worker static int
eq_slist(struct slist * x,struct slist * y)2325*8b26181fSAndroid Build Coastguard Worker eq_slist(struct slist *x, struct slist *y)
2326*8b26181fSAndroid Build Coastguard Worker {
2327*8b26181fSAndroid Build Coastguard Worker for (;;) {
2328*8b26181fSAndroid Build Coastguard Worker while (x && x->s.code == NOP)
2329*8b26181fSAndroid Build Coastguard Worker x = x->next;
2330*8b26181fSAndroid Build Coastguard Worker while (y && y->s.code == NOP)
2331*8b26181fSAndroid Build Coastguard Worker y = y->next;
2332*8b26181fSAndroid Build Coastguard Worker if (x == 0)
2333*8b26181fSAndroid Build Coastguard Worker return y == 0;
2334*8b26181fSAndroid Build Coastguard Worker if (y == 0)
2335*8b26181fSAndroid Build Coastguard Worker return x == 0;
2336*8b26181fSAndroid Build Coastguard Worker if (x->s.code != y->s.code || x->s.k != y->s.k)
2337*8b26181fSAndroid Build Coastguard Worker return 0;
2338*8b26181fSAndroid Build Coastguard Worker x = x->next;
2339*8b26181fSAndroid Build Coastguard Worker y = y->next;
2340*8b26181fSAndroid Build Coastguard Worker }
2341*8b26181fSAndroid Build Coastguard Worker }
2342*8b26181fSAndroid Build Coastguard Worker
2343*8b26181fSAndroid Build Coastguard Worker static inline int
eq_blk(struct block * b0,struct block * b1)2344*8b26181fSAndroid Build Coastguard Worker eq_blk(struct block *b0, struct block *b1)
2345*8b26181fSAndroid Build Coastguard Worker {
2346*8b26181fSAndroid Build Coastguard Worker if (b0->s.code == b1->s.code &&
2347*8b26181fSAndroid Build Coastguard Worker b0->s.k == b1->s.k &&
2348*8b26181fSAndroid Build Coastguard Worker b0->et.succ == b1->et.succ &&
2349*8b26181fSAndroid Build Coastguard Worker b0->ef.succ == b1->ef.succ)
2350*8b26181fSAndroid Build Coastguard Worker return eq_slist(b0->stmts, b1->stmts);
2351*8b26181fSAndroid Build Coastguard Worker return 0;
2352*8b26181fSAndroid Build Coastguard Worker }
2353*8b26181fSAndroid Build Coastguard Worker
2354*8b26181fSAndroid Build Coastguard Worker static void
intern_blocks(opt_state_t * opt_state,struct icode * ic)2355*8b26181fSAndroid Build Coastguard Worker intern_blocks(opt_state_t *opt_state, struct icode *ic)
2356*8b26181fSAndroid Build Coastguard Worker {
2357*8b26181fSAndroid Build Coastguard Worker struct block *p;
2358*8b26181fSAndroid Build Coastguard Worker u_int i, j;
2359*8b26181fSAndroid Build Coastguard Worker int done1; /* don't shadow global */
2360*8b26181fSAndroid Build Coastguard Worker top:
2361*8b26181fSAndroid Build Coastguard Worker done1 = 1;
2362*8b26181fSAndroid Build Coastguard Worker for (i = 0; i < opt_state->n_blocks; ++i)
2363*8b26181fSAndroid Build Coastguard Worker opt_state->blocks[i]->link = 0;
2364*8b26181fSAndroid Build Coastguard Worker
2365*8b26181fSAndroid Build Coastguard Worker mark_code(ic);
2366*8b26181fSAndroid Build Coastguard Worker
2367*8b26181fSAndroid Build Coastguard Worker for (i = opt_state->n_blocks - 1; i != 0; ) {
2368*8b26181fSAndroid Build Coastguard Worker --i;
2369*8b26181fSAndroid Build Coastguard Worker if (!isMarked(ic, opt_state->blocks[i]))
2370*8b26181fSAndroid Build Coastguard Worker continue;
2371*8b26181fSAndroid Build Coastguard Worker for (j = i + 1; j < opt_state->n_blocks; ++j) {
2372*8b26181fSAndroid Build Coastguard Worker if (!isMarked(ic, opt_state->blocks[j]))
2373*8b26181fSAndroid Build Coastguard Worker continue;
2374*8b26181fSAndroid Build Coastguard Worker if (eq_blk(opt_state->blocks[i], opt_state->blocks[j])) {
2375*8b26181fSAndroid Build Coastguard Worker opt_state->blocks[i]->link = opt_state->blocks[j]->link ?
2376*8b26181fSAndroid Build Coastguard Worker opt_state->blocks[j]->link : opt_state->blocks[j];
2377*8b26181fSAndroid Build Coastguard Worker break;
2378*8b26181fSAndroid Build Coastguard Worker }
2379*8b26181fSAndroid Build Coastguard Worker }
2380*8b26181fSAndroid Build Coastguard Worker }
2381*8b26181fSAndroid Build Coastguard Worker for (i = 0; i < opt_state->n_blocks; ++i) {
2382*8b26181fSAndroid Build Coastguard Worker p = opt_state->blocks[i];
2383*8b26181fSAndroid Build Coastguard Worker if (JT(p) == 0)
2384*8b26181fSAndroid Build Coastguard Worker continue;
2385*8b26181fSAndroid Build Coastguard Worker if (JT(p)->link) {
2386*8b26181fSAndroid Build Coastguard Worker done1 = 0;
2387*8b26181fSAndroid Build Coastguard Worker JT(p) = JT(p)->link;
2388*8b26181fSAndroid Build Coastguard Worker }
2389*8b26181fSAndroid Build Coastguard Worker if (JF(p)->link) {
2390*8b26181fSAndroid Build Coastguard Worker done1 = 0;
2391*8b26181fSAndroid Build Coastguard Worker JF(p) = JF(p)->link;
2392*8b26181fSAndroid Build Coastguard Worker }
2393*8b26181fSAndroid Build Coastguard Worker }
2394*8b26181fSAndroid Build Coastguard Worker if (!done1)
2395*8b26181fSAndroid Build Coastguard Worker goto top;
2396*8b26181fSAndroid Build Coastguard Worker }
2397*8b26181fSAndroid Build Coastguard Worker
2398*8b26181fSAndroid Build Coastguard Worker static void
opt_cleanup(opt_state_t * opt_state)2399*8b26181fSAndroid Build Coastguard Worker opt_cleanup(opt_state_t *opt_state)
2400*8b26181fSAndroid Build Coastguard Worker {
2401*8b26181fSAndroid Build Coastguard Worker free((void *)opt_state->vnode_base);
2402*8b26181fSAndroid Build Coastguard Worker free((void *)opt_state->vmap);
2403*8b26181fSAndroid Build Coastguard Worker free((void *)opt_state->edges);
2404*8b26181fSAndroid Build Coastguard Worker free((void *)opt_state->space);
2405*8b26181fSAndroid Build Coastguard Worker free((void *)opt_state->levels);
2406*8b26181fSAndroid Build Coastguard Worker free((void *)opt_state->blocks);
2407*8b26181fSAndroid Build Coastguard Worker }
2408*8b26181fSAndroid Build Coastguard Worker
2409*8b26181fSAndroid Build Coastguard Worker /*
2410*8b26181fSAndroid Build Coastguard Worker * For optimizer errors.
2411*8b26181fSAndroid Build Coastguard Worker */
2412*8b26181fSAndroid Build Coastguard Worker static void PCAP_NORETURN
opt_error(opt_state_t * opt_state,const char * fmt,...)2413*8b26181fSAndroid Build Coastguard Worker opt_error(opt_state_t *opt_state, const char *fmt, ...)
2414*8b26181fSAndroid Build Coastguard Worker {
2415*8b26181fSAndroid Build Coastguard Worker va_list ap;
2416*8b26181fSAndroid Build Coastguard Worker
2417*8b26181fSAndroid Build Coastguard Worker if (opt_state->errbuf != NULL) {
2418*8b26181fSAndroid Build Coastguard Worker va_start(ap, fmt);
2419*8b26181fSAndroid Build Coastguard Worker (void)vsnprintf(opt_state->errbuf,
2420*8b26181fSAndroid Build Coastguard Worker PCAP_ERRBUF_SIZE, fmt, ap);
2421*8b26181fSAndroid Build Coastguard Worker va_end(ap);
2422*8b26181fSAndroid Build Coastguard Worker }
2423*8b26181fSAndroid Build Coastguard Worker longjmp(opt_state->top_ctx, 1);
2424*8b26181fSAndroid Build Coastguard Worker /* NOTREACHED */
2425*8b26181fSAndroid Build Coastguard Worker #ifdef _AIX
2426*8b26181fSAndroid Build Coastguard Worker PCAP_UNREACHABLE
2427*8b26181fSAndroid Build Coastguard Worker #endif /* _AIX */
2428*8b26181fSAndroid Build Coastguard Worker }
2429*8b26181fSAndroid Build Coastguard Worker
2430*8b26181fSAndroid Build Coastguard Worker /*
2431*8b26181fSAndroid Build Coastguard Worker * Return the number of stmts in 's'.
2432*8b26181fSAndroid Build Coastguard Worker */
2433*8b26181fSAndroid Build Coastguard Worker static u_int
slength(struct slist * s)2434*8b26181fSAndroid Build Coastguard Worker slength(struct slist *s)
2435*8b26181fSAndroid Build Coastguard Worker {
2436*8b26181fSAndroid Build Coastguard Worker u_int n = 0;
2437*8b26181fSAndroid Build Coastguard Worker
2438*8b26181fSAndroid Build Coastguard Worker for (; s; s = s->next)
2439*8b26181fSAndroid Build Coastguard Worker if (s->s.code != NOP)
2440*8b26181fSAndroid Build Coastguard Worker ++n;
2441*8b26181fSAndroid Build Coastguard Worker return n;
2442*8b26181fSAndroid Build Coastguard Worker }
2443*8b26181fSAndroid Build Coastguard Worker
2444*8b26181fSAndroid Build Coastguard Worker /*
2445*8b26181fSAndroid Build Coastguard Worker * Return the number of nodes reachable by 'p'.
2446*8b26181fSAndroid Build Coastguard Worker * All nodes should be initially unmarked.
2447*8b26181fSAndroid Build Coastguard Worker */
2448*8b26181fSAndroid Build Coastguard Worker static int
count_blocks(struct icode * ic,struct block * p)2449*8b26181fSAndroid Build Coastguard Worker count_blocks(struct icode *ic, struct block *p)
2450*8b26181fSAndroid Build Coastguard Worker {
2451*8b26181fSAndroid Build Coastguard Worker if (p == 0 || isMarked(ic, p))
2452*8b26181fSAndroid Build Coastguard Worker return 0;
2453*8b26181fSAndroid Build Coastguard Worker Mark(ic, p);
2454*8b26181fSAndroid Build Coastguard Worker return count_blocks(ic, JT(p)) + count_blocks(ic, JF(p)) + 1;
2455*8b26181fSAndroid Build Coastguard Worker }
2456*8b26181fSAndroid Build Coastguard Worker
2457*8b26181fSAndroid Build Coastguard Worker /*
2458*8b26181fSAndroid Build Coastguard Worker * Do a depth first search on the flow graph, numbering the
2459*8b26181fSAndroid Build Coastguard Worker * the basic blocks, and entering them into the 'blocks' array.`
2460*8b26181fSAndroid Build Coastguard Worker */
2461*8b26181fSAndroid Build Coastguard Worker static void
number_blks_r(opt_state_t * opt_state,struct icode * ic,struct block * p)2462*8b26181fSAndroid Build Coastguard Worker number_blks_r(opt_state_t *opt_state, struct icode *ic, struct block *p)
2463*8b26181fSAndroid Build Coastguard Worker {
2464*8b26181fSAndroid Build Coastguard Worker u_int n;
2465*8b26181fSAndroid Build Coastguard Worker
2466*8b26181fSAndroid Build Coastguard Worker if (p == 0 || isMarked(ic, p))
2467*8b26181fSAndroid Build Coastguard Worker return;
2468*8b26181fSAndroid Build Coastguard Worker
2469*8b26181fSAndroid Build Coastguard Worker Mark(ic, p);
2470*8b26181fSAndroid Build Coastguard Worker n = opt_state->n_blocks++;
2471*8b26181fSAndroid Build Coastguard Worker if (opt_state->n_blocks == 0) {
2472*8b26181fSAndroid Build Coastguard Worker /*
2473*8b26181fSAndroid Build Coastguard Worker * Overflow.
2474*8b26181fSAndroid Build Coastguard Worker */
2475*8b26181fSAndroid Build Coastguard Worker opt_error(opt_state, "filter is too complex to optimize");
2476*8b26181fSAndroid Build Coastguard Worker }
2477*8b26181fSAndroid Build Coastguard Worker p->id = n;
2478*8b26181fSAndroid Build Coastguard Worker opt_state->blocks[n] = p;
2479*8b26181fSAndroid Build Coastguard Worker
2480*8b26181fSAndroid Build Coastguard Worker number_blks_r(opt_state, ic, JT(p));
2481*8b26181fSAndroid Build Coastguard Worker number_blks_r(opt_state, ic, JF(p));
2482*8b26181fSAndroid Build Coastguard Worker }
2483*8b26181fSAndroid Build Coastguard Worker
2484*8b26181fSAndroid Build Coastguard Worker /*
2485*8b26181fSAndroid Build Coastguard Worker * Return the number of stmts in the flowgraph reachable by 'p'.
2486*8b26181fSAndroid Build Coastguard Worker * The nodes should be unmarked before calling.
2487*8b26181fSAndroid Build Coastguard Worker *
2488*8b26181fSAndroid Build Coastguard Worker * Note that "stmts" means "instructions", and that this includes
2489*8b26181fSAndroid Build Coastguard Worker *
2490*8b26181fSAndroid Build Coastguard Worker * side-effect statements in 'p' (slength(p->stmts));
2491*8b26181fSAndroid Build Coastguard Worker *
2492*8b26181fSAndroid Build Coastguard Worker * statements in the true branch from 'p' (count_stmts(JT(p)));
2493*8b26181fSAndroid Build Coastguard Worker *
2494*8b26181fSAndroid Build Coastguard Worker * statements in the false branch from 'p' (count_stmts(JF(p)));
2495*8b26181fSAndroid Build Coastguard Worker *
2496*8b26181fSAndroid Build Coastguard Worker * the conditional jump itself (1);
2497*8b26181fSAndroid Build Coastguard Worker *
2498*8b26181fSAndroid Build Coastguard Worker * an extra long jump if the true branch requires it (p->longjt);
2499*8b26181fSAndroid Build Coastguard Worker *
2500*8b26181fSAndroid Build Coastguard Worker * an extra long jump if the false branch requires it (p->longjf).
2501*8b26181fSAndroid Build Coastguard Worker */
2502*8b26181fSAndroid Build Coastguard Worker static u_int
count_stmts(struct icode * ic,struct block * p)2503*8b26181fSAndroid Build Coastguard Worker count_stmts(struct icode *ic, struct block *p)
2504*8b26181fSAndroid Build Coastguard Worker {
2505*8b26181fSAndroid Build Coastguard Worker u_int n;
2506*8b26181fSAndroid Build Coastguard Worker
2507*8b26181fSAndroid Build Coastguard Worker if (p == 0 || isMarked(ic, p))
2508*8b26181fSAndroid Build Coastguard Worker return 0;
2509*8b26181fSAndroid Build Coastguard Worker Mark(ic, p);
2510*8b26181fSAndroid Build Coastguard Worker n = count_stmts(ic, JT(p)) + count_stmts(ic, JF(p));
2511*8b26181fSAndroid Build Coastguard Worker return slength(p->stmts) + n + 1 + p->longjt + p->longjf;
2512*8b26181fSAndroid Build Coastguard Worker }
2513*8b26181fSAndroid Build Coastguard Worker
2514*8b26181fSAndroid Build Coastguard Worker /*
2515*8b26181fSAndroid Build Coastguard Worker * Allocate memory. All allocation is done before optimization
2516*8b26181fSAndroid Build Coastguard Worker * is begun. A linear bound on the size of all data structures is computed
2517*8b26181fSAndroid Build Coastguard Worker * from the total number of blocks and/or statements.
2518*8b26181fSAndroid Build Coastguard Worker */
2519*8b26181fSAndroid Build Coastguard Worker static void
opt_init(opt_state_t * opt_state,struct icode * ic)2520*8b26181fSAndroid Build Coastguard Worker opt_init(opt_state_t *opt_state, struct icode *ic)
2521*8b26181fSAndroid Build Coastguard Worker {
2522*8b26181fSAndroid Build Coastguard Worker bpf_u_int32 *p;
2523*8b26181fSAndroid Build Coastguard Worker int i, n, max_stmts;
2524*8b26181fSAndroid Build Coastguard Worker u_int product;
2525*8b26181fSAndroid Build Coastguard Worker size_t block_memsize, edge_memsize;
2526*8b26181fSAndroid Build Coastguard Worker
2527*8b26181fSAndroid Build Coastguard Worker /*
2528*8b26181fSAndroid Build Coastguard Worker * First, count the blocks, so we can malloc an array to map
2529*8b26181fSAndroid Build Coastguard Worker * block number to block. Then, put the blocks into the array.
2530*8b26181fSAndroid Build Coastguard Worker */
2531*8b26181fSAndroid Build Coastguard Worker unMarkAll(ic);
2532*8b26181fSAndroid Build Coastguard Worker n = count_blocks(ic, ic->root);
2533*8b26181fSAndroid Build Coastguard Worker opt_state->blocks = (struct block **)calloc(n, sizeof(*opt_state->blocks));
2534*8b26181fSAndroid Build Coastguard Worker if (opt_state->blocks == NULL)
2535*8b26181fSAndroid Build Coastguard Worker opt_error(opt_state, "malloc");
2536*8b26181fSAndroid Build Coastguard Worker unMarkAll(ic);
2537*8b26181fSAndroid Build Coastguard Worker opt_state->n_blocks = 0;
2538*8b26181fSAndroid Build Coastguard Worker number_blks_r(opt_state, ic, ic->root);
2539*8b26181fSAndroid Build Coastguard Worker
2540*8b26181fSAndroid Build Coastguard Worker /*
2541*8b26181fSAndroid Build Coastguard Worker * This "should not happen".
2542*8b26181fSAndroid Build Coastguard Worker */
2543*8b26181fSAndroid Build Coastguard Worker if (opt_state->n_blocks == 0)
2544*8b26181fSAndroid Build Coastguard Worker opt_error(opt_state, "filter has no instructions; please report this as a libpcap issue");
2545*8b26181fSAndroid Build Coastguard Worker
2546*8b26181fSAndroid Build Coastguard Worker opt_state->n_edges = 2 * opt_state->n_blocks;
2547*8b26181fSAndroid Build Coastguard Worker if ((opt_state->n_edges / 2) != opt_state->n_blocks) {
2548*8b26181fSAndroid Build Coastguard Worker /*
2549*8b26181fSAndroid Build Coastguard Worker * Overflow.
2550*8b26181fSAndroid Build Coastguard Worker */
2551*8b26181fSAndroid Build Coastguard Worker opt_error(opt_state, "filter is too complex to optimize");
2552*8b26181fSAndroid Build Coastguard Worker }
2553*8b26181fSAndroid Build Coastguard Worker opt_state->edges = (struct edge **)calloc(opt_state->n_edges, sizeof(*opt_state->edges));
2554*8b26181fSAndroid Build Coastguard Worker if (opt_state->edges == NULL) {
2555*8b26181fSAndroid Build Coastguard Worker opt_error(opt_state, "malloc");
2556*8b26181fSAndroid Build Coastguard Worker }
2557*8b26181fSAndroid Build Coastguard Worker
2558*8b26181fSAndroid Build Coastguard Worker /*
2559*8b26181fSAndroid Build Coastguard Worker * The number of levels is bounded by the number of nodes.
2560*8b26181fSAndroid Build Coastguard Worker */
2561*8b26181fSAndroid Build Coastguard Worker opt_state->levels = (struct block **)calloc(opt_state->n_blocks, sizeof(*opt_state->levels));
2562*8b26181fSAndroid Build Coastguard Worker if (opt_state->levels == NULL) {
2563*8b26181fSAndroid Build Coastguard Worker opt_error(opt_state, "malloc");
2564*8b26181fSAndroid Build Coastguard Worker }
2565*8b26181fSAndroid Build Coastguard Worker
2566*8b26181fSAndroid Build Coastguard Worker opt_state->edgewords = opt_state->n_edges / BITS_PER_WORD + 1;
2567*8b26181fSAndroid Build Coastguard Worker opt_state->nodewords = opt_state->n_blocks / BITS_PER_WORD + 1;
2568*8b26181fSAndroid Build Coastguard Worker
2569*8b26181fSAndroid Build Coastguard Worker /*
2570*8b26181fSAndroid Build Coastguard Worker * Make sure opt_state->n_blocks * opt_state->nodewords fits
2571*8b26181fSAndroid Build Coastguard Worker * in a u_int; we use it as a u_int number-of-iterations
2572*8b26181fSAndroid Build Coastguard Worker * value.
2573*8b26181fSAndroid Build Coastguard Worker */
2574*8b26181fSAndroid Build Coastguard Worker product = opt_state->n_blocks * opt_state->nodewords;
2575*8b26181fSAndroid Build Coastguard Worker if ((product / opt_state->n_blocks) != opt_state->nodewords) {
2576*8b26181fSAndroid Build Coastguard Worker /*
2577*8b26181fSAndroid Build Coastguard Worker * XXX - just punt and don't try to optimize?
2578*8b26181fSAndroid Build Coastguard Worker * In practice, this is unlikely to happen with
2579*8b26181fSAndroid Build Coastguard Worker * a normal filter.
2580*8b26181fSAndroid Build Coastguard Worker */
2581*8b26181fSAndroid Build Coastguard Worker opt_error(opt_state, "filter is too complex to optimize");
2582*8b26181fSAndroid Build Coastguard Worker }
2583*8b26181fSAndroid Build Coastguard Worker
2584*8b26181fSAndroid Build Coastguard Worker /*
2585*8b26181fSAndroid Build Coastguard Worker * Make sure the total memory required for that doesn't
2586*8b26181fSAndroid Build Coastguard Worker * overflow.
2587*8b26181fSAndroid Build Coastguard Worker */
2588*8b26181fSAndroid Build Coastguard Worker block_memsize = (size_t)2 * product * sizeof(*opt_state->space);
2589*8b26181fSAndroid Build Coastguard Worker if ((block_memsize / product) != 2 * sizeof(*opt_state->space)) {
2590*8b26181fSAndroid Build Coastguard Worker opt_error(opt_state, "filter is too complex to optimize");
2591*8b26181fSAndroid Build Coastguard Worker }
2592*8b26181fSAndroid Build Coastguard Worker
2593*8b26181fSAndroid Build Coastguard Worker /*
2594*8b26181fSAndroid Build Coastguard Worker * Make sure opt_state->n_edges * opt_state->edgewords fits
2595*8b26181fSAndroid Build Coastguard Worker * in a u_int; we use it as a u_int number-of-iterations
2596*8b26181fSAndroid Build Coastguard Worker * value.
2597*8b26181fSAndroid Build Coastguard Worker */
2598*8b26181fSAndroid Build Coastguard Worker product = opt_state->n_edges * opt_state->edgewords;
2599*8b26181fSAndroid Build Coastguard Worker if ((product / opt_state->n_edges) != opt_state->edgewords) {
2600*8b26181fSAndroid Build Coastguard Worker opt_error(opt_state, "filter is too complex to optimize");
2601*8b26181fSAndroid Build Coastguard Worker }
2602*8b26181fSAndroid Build Coastguard Worker
2603*8b26181fSAndroid Build Coastguard Worker /*
2604*8b26181fSAndroid Build Coastguard Worker * Make sure the total memory required for that doesn't
2605*8b26181fSAndroid Build Coastguard Worker * overflow.
2606*8b26181fSAndroid Build Coastguard Worker */
2607*8b26181fSAndroid Build Coastguard Worker edge_memsize = (size_t)product * sizeof(*opt_state->space);
2608*8b26181fSAndroid Build Coastguard Worker if (edge_memsize / product != sizeof(*opt_state->space)) {
2609*8b26181fSAndroid Build Coastguard Worker opt_error(opt_state, "filter is too complex to optimize");
2610*8b26181fSAndroid Build Coastguard Worker }
2611*8b26181fSAndroid Build Coastguard Worker
2612*8b26181fSAndroid Build Coastguard Worker /*
2613*8b26181fSAndroid Build Coastguard Worker * Make sure the total memory required for both of them doesn't
2614*8b26181fSAndroid Build Coastguard Worker * overflow.
2615*8b26181fSAndroid Build Coastguard Worker */
2616*8b26181fSAndroid Build Coastguard Worker if (block_memsize > SIZE_MAX - edge_memsize) {
2617*8b26181fSAndroid Build Coastguard Worker opt_error(opt_state, "filter is too complex to optimize");
2618*8b26181fSAndroid Build Coastguard Worker }
2619*8b26181fSAndroid Build Coastguard Worker
2620*8b26181fSAndroid Build Coastguard Worker /* XXX */
2621*8b26181fSAndroid Build Coastguard Worker opt_state->space = (bpf_u_int32 *)malloc(block_memsize + edge_memsize);
2622*8b26181fSAndroid Build Coastguard Worker if (opt_state->space == NULL) {
2623*8b26181fSAndroid Build Coastguard Worker opt_error(opt_state, "malloc");
2624*8b26181fSAndroid Build Coastguard Worker }
2625*8b26181fSAndroid Build Coastguard Worker p = opt_state->space;
2626*8b26181fSAndroid Build Coastguard Worker opt_state->all_dom_sets = p;
2627*8b26181fSAndroid Build Coastguard Worker for (i = 0; i < n; ++i) {
2628*8b26181fSAndroid Build Coastguard Worker opt_state->blocks[i]->dom = p;
2629*8b26181fSAndroid Build Coastguard Worker p += opt_state->nodewords;
2630*8b26181fSAndroid Build Coastguard Worker }
2631*8b26181fSAndroid Build Coastguard Worker opt_state->all_closure_sets = p;
2632*8b26181fSAndroid Build Coastguard Worker for (i = 0; i < n; ++i) {
2633*8b26181fSAndroid Build Coastguard Worker opt_state->blocks[i]->closure = p;
2634*8b26181fSAndroid Build Coastguard Worker p += opt_state->nodewords;
2635*8b26181fSAndroid Build Coastguard Worker }
2636*8b26181fSAndroid Build Coastguard Worker opt_state->all_edge_sets = p;
2637*8b26181fSAndroid Build Coastguard Worker for (i = 0; i < n; ++i) {
2638*8b26181fSAndroid Build Coastguard Worker register struct block *b = opt_state->blocks[i];
2639*8b26181fSAndroid Build Coastguard Worker
2640*8b26181fSAndroid Build Coastguard Worker b->et.edom = p;
2641*8b26181fSAndroid Build Coastguard Worker p += opt_state->edgewords;
2642*8b26181fSAndroid Build Coastguard Worker b->ef.edom = p;
2643*8b26181fSAndroid Build Coastguard Worker p += opt_state->edgewords;
2644*8b26181fSAndroid Build Coastguard Worker b->et.id = i;
2645*8b26181fSAndroid Build Coastguard Worker opt_state->edges[i] = &b->et;
2646*8b26181fSAndroid Build Coastguard Worker b->ef.id = opt_state->n_blocks + i;
2647*8b26181fSAndroid Build Coastguard Worker opt_state->edges[opt_state->n_blocks + i] = &b->ef;
2648*8b26181fSAndroid Build Coastguard Worker b->et.pred = b;
2649*8b26181fSAndroid Build Coastguard Worker b->ef.pred = b;
2650*8b26181fSAndroid Build Coastguard Worker }
2651*8b26181fSAndroid Build Coastguard Worker max_stmts = 0;
2652*8b26181fSAndroid Build Coastguard Worker for (i = 0; i < n; ++i)
2653*8b26181fSAndroid Build Coastguard Worker max_stmts += slength(opt_state->blocks[i]->stmts) + 1;
2654*8b26181fSAndroid Build Coastguard Worker /*
2655*8b26181fSAndroid Build Coastguard Worker * We allocate at most 3 value numbers per statement,
2656*8b26181fSAndroid Build Coastguard Worker * so this is an upper bound on the number of valnodes
2657*8b26181fSAndroid Build Coastguard Worker * we'll need.
2658*8b26181fSAndroid Build Coastguard Worker */
2659*8b26181fSAndroid Build Coastguard Worker opt_state->maxval = 3 * max_stmts;
2660*8b26181fSAndroid Build Coastguard Worker opt_state->vmap = (struct vmapinfo *)calloc(opt_state->maxval, sizeof(*opt_state->vmap));
2661*8b26181fSAndroid Build Coastguard Worker if (opt_state->vmap == NULL) {
2662*8b26181fSAndroid Build Coastguard Worker opt_error(opt_state, "malloc");
2663*8b26181fSAndroid Build Coastguard Worker }
2664*8b26181fSAndroid Build Coastguard Worker opt_state->vnode_base = (struct valnode *)calloc(opt_state->maxval, sizeof(*opt_state->vnode_base));
2665*8b26181fSAndroid Build Coastguard Worker if (opt_state->vnode_base == NULL) {
2666*8b26181fSAndroid Build Coastguard Worker opt_error(opt_state, "malloc");
2667*8b26181fSAndroid Build Coastguard Worker }
2668*8b26181fSAndroid Build Coastguard Worker }
2669*8b26181fSAndroid Build Coastguard Worker
2670*8b26181fSAndroid Build Coastguard Worker /*
2671*8b26181fSAndroid Build Coastguard Worker * This is only used when supporting optimizer debugging. It is
2672*8b26181fSAndroid Build Coastguard Worker * global state, so do *not* do more than one compile in parallel
2673*8b26181fSAndroid Build Coastguard Worker * and expect it to provide meaningful information.
2674*8b26181fSAndroid Build Coastguard Worker */
2675*8b26181fSAndroid Build Coastguard Worker #ifdef BDEBUG
2676*8b26181fSAndroid Build Coastguard Worker int bids[NBIDS];
2677*8b26181fSAndroid Build Coastguard Worker #endif
2678*8b26181fSAndroid Build Coastguard Worker
2679*8b26181fSAndroid Build Coastguard Worker static void PCAP_NORETURN conv_error(conv_state_t *, const char *, ...)
2680*8b26181fSAndroid Build Coastguard Worker PCAP_PRINTFLIKE(2, 3);
2681*8b26181fSAndroid Build Coastguard Worker
2682*8b26181fSAndroid Build Coastguard Worker /*
2683*8b26181fSAndroid Build Coastguard Worker * Returns true if successful. Returns false if a branch has
2684*8b26181fSAndroid Build Coastguard Worker * an offset that is too large. If so, we have marked that
2685*8b26181fSAndroid Build Coastguard Worker * branch so that on a subsequent iteration, it will be treated
2686*8b26181fSAndroid Build Coastguard Worker * properly.
2687*8b26181fSAndroid Build Coastguard Worker */
2688*8b26181fSAndroid Build Coastguard Worker static int
convert_code_r(conv_state_t * conv_state,struct icode * ic,struct block * p)2689*8b26181fSAndroid Build Coastguard Worker convert_code_r(conv_state_t *conv_state, struct icode *ic, struct block *p)
2690*8b26181fSAndroid Build Coastguard Worker {
2691*8b26181fSAndroid Build Coastguard Worker struct bpf_insn *dst;
2692*8b26181fSAndroid Build Coastguard Worker struct slist *src;
2693*8b26181fSAndroid Build Coastguard Worker u_int slen;
2694*8b26181fSAndroid Build Coastguard Worker u_int off;
2695*8b26181fSAndroid Build Coastguard Worker struct slist **offset = NULL;
2696*8b26181fSAndroid Build Coastguard Worker
2697*8b26181fSAndroid Build Coastguard Worker if (p == 0 || isMarked(ic, p))
2698*8b26181fSAndroid Build Coastguard Worker return (1);
2699*8b26181fSAndroid Build Coastguard Worker Mark(ic, p);
2700*8b26181fSAndroid Build Coastguard Worker
2701*8b26181fSAndroid Build Coastguard Worker if (convert_code_r(conv_state, ic, JF(p)) == 0)
2702*8b26181fSAndroid Build Coastguard Worker return (0);
2703*8b26181fSAndroid Build Coastguard Worker if (convert_code_r(conv_state, ic, JT(p)) == 0)
2704*8b26181fSAndroid Build Coastguard Worker return (0);
2705*8b26181fSAndroid Build Coastguard Worker
2706*8b26181fSAndroid Build Coastguard Worker slen = slength(p->stmts);
2707*8b26181fSAndroid Build Coastguard Worker dst = conv_state->ftail -= (slen + 1 + p->longjt + p->longjf);
2708*8b26181fSAndroid Build Coastguard Worker /* inflate length by any extra jumps */
2709*8b26181fSAndroid Build Coastguard Worker
2710*8b26181fSAndroid Build Coastguard Worker p->offset = (int)(dst - conv_state->fstart);
2711*8b26181fSAndroid Build Coastguard Worker
2712*8b26181fSAndroid Build Coastguard Worker /* generate offset[] for convenience */
2713*8b26181fSAndroid Build Coastguard Worker if (slen) {
2714*8b26181fSAndroid Build Coastguard Worker offset = (struct slist **)calloc(slen, sizeof(struct slist *));
2715*8b26181fSAndroid Build Coastguard Worker if (!offset) {
2716*8b26181fSAndroid Build Coastguard Worker conv_error(conv_state, "not enough core");
2717*8b26181fSAndroid Build Coastguard Worker /*NOTREACHED*/
2718*8b26181fSAndroid Build Coastguard Worker }
2719*8b26181fSAndroid Build Coastguard Worker }
2720*8b26181fSAndroid Build Coastguard Worker src = p->stmts;
2721*8b26181fSAndroid Build Coastguard Worker for (off = 0; off < slen && src; off++) {
2722*8b26181fSAndroid Build Coastguard Worker #if 0
2723*8b26181fSAndroid Build Coastguard Worker printf("off=%d src=%x\n", off, src);
2724*8b26181fSAndroid Build Coastguard Worker #endif
2725*8b26181fSAndroid Build Coastguard Worker offset[off] = src;
2726*8b26181fSAndroid Build Coastguard Worker src = src->next;
2727*8b26181fSAndroid Build Coastguard Worker }
2728*8b26181fSAndroid Build Coastguard Worker
2729*8b26181fSAndroid Build Coastguard Worker off = 0;
2730*8b26181fSAndroid Build Coastguard Worker for (src = p->stmts; src; src = src->next) {
2731*8b26181fSAndroid Build Coastguard Worker if (src->s.code == NOP)
2732*8b26181fSAndroid Build Coastguard Worker continue;
2733*8b26181fSAndroid Build Coastguard Worker dst->code = (u_short)src->s.code;
2734*8b26181fSAndroid Build Coastguard Worker dst->k = src->s.k;
2735*8b26181fSAndroid Build Coastguard Worker
2736*8b26181fSAndroid Build Coastguard Worker /* fill block-local relative jump */
2737*8b26181fSAndroid Build Coastguard Worker if (BPF_CLASS(src->s.code) != BPF_JMP || src->s.code == (BPF_JMP|BPF_JA)) {
2738*8b26181fSAndroid Build Coastguard Worker #if 0
2739*8b26181fSAndroid Build Coastguard Worker if (src->s.jt || src->s.jf) {
2740*8b26181fSAndroid Build Coastguard Worker free(offset);
2741*8b26181fSAndroid Build Coastguard Worker conv_error(conv_state, "illegal jmp destination");
2742*8b26181fSAndroid Build Coastguard Worker /*NOTREACHED*/
2743*8b26181fSAndroid Build Coastguard Worker }
2744*8b26181fSAndroid Build Coastguard Worker #endif
2745*8b26181fSAndroid Build Coastguard Worker goto filled;
2746*8b26181fSAndroid Build Coastguard Worker }
2747*8b26181fSAndroid Build Coastguard Worker if (off == slen - 2) /*???*/
2748*8b26181fSAndroid Build Coastguard Worker goto filled;
2749*8b26181fSAndroid Build Coastguard Worker
2750*8b26181fSAndroid Build Coastguard Worker {
2751*8b26181fSAndroid Build Coastguard Worker u_int i;
2752*8b26181fSAndroid Build Coastguard Worker int jt, jf;
2753*8b26181fSAndroid Build Coastguard Worker const char ljerr[] = "%s for block-local relative jump: off=%d";
2754*8b26181fSAndroid Build Coastguard Worker
2755*8b26181fSAndroid Build Coastguard Worker #if 0
2756*8b26181fSAndroid Build Coastguard Worker printf("code=%x off=%d %x %x\n", src->s.code,
2757*8b26181fSAndroid Build Coastguard Worker off, src->s.jt, src->s.jf);
2758*8b26181fSAndroid Build Coastguard Worker #endif
2759*8b26181fSAndroid Build Coastguard Worker
2760*8b26181fSAndroid Build Coastguard Worker if (!src->s.jt || !src->s.jf) {
2761*8b26181fSAndroid Build Coastguard Worker free(offset);
2762*8b26181fSAndroid Build Coastguard Worker conv_error(conv_state, ljerr, "no jmp destination", off);
2763*8b26181fSAndroid Build Coastguard Worker /*NOTREACHED*/
2764*8b26181fSAndroid Build Coastguard Worker }
2765*8b26181fSAndroid Build Coastguard Worker
2766*8b26181fSAndroid Build Coastguard Worker jt = jf = 0;
2767*8b26181fSAndroid Build Coastguard Worker for (i = 0; i < slen; i++) {
2768*8b26181fSAndroid Build Coastguard Worker if (offset[i] == src->s.jt) {
2769*8b26181fSAndroid Build Coastguard Worker if (jt) {
2770*8b26181fSAndroid Build Coastguard Worker free(offset);
2771*8b26181fSAndroid Build Coastguard Worker conv_error(conv_state, ljerr, "multiple matches", off);
2772*8b26181fSAndroid Build Coastguard Worker /*NOTREACHED*/
2773*8b26181fSAndroid Build Coastguard Worker }
2774*8b26181fSAndroid Build Coastguard Worker
2775*8b26181fSAndroid Build Coastguard Worker if (i - off - 1 >= 256) {
2776*8b26181fSAndroid Build Coastguard Worker free(offset);
2777*8b26181fSAndroid Build Coastguard Worker conv_error(conv_state, ljerr, "out-of-range jump", off);
2778*8b26181fSAndroid Build Coastguard Worker /*NOTREACHED*/
2779*8b26181fSAndroid Build Coastguard Worker }
2780*8b26181fSAndroid Build Coastguard Worker dst->jt = (u_char)(i - off - 1);
2781*8b26181fSAndroid Build Coastguard Worker jt++;
2782*8b26181fSAndroid Build Coastguard Worker }
2783*8b26181fSAndroid Build Coastguard Worker if (offset[i] == src->s.jf) {
2784*8b26181fSAndroid Build Coastguard Worker if (jf) {
2785*8b26181fSAndroid Build Coastguard Worker free(offset);
2786*8b26181fSAndroid Build Coastguard Worker conv_error(conv_state, ljerr, "multiple matches", off);
2787*8b26181fSAndroid Build Coastguard Worker /*NOTREACHED*/
2788*8b26181fSAndroid Build Coastguard Worker }
2789*8b26181fSAndroid Build Coastguard Worker if (i - off - 1 >= 256) {
2790*8b26181fSAndroid Build Coastguard Worker free(offset);
2791*8b26181fSAndroid Build Coastguard Worker conv_error(conv_state, ljerr, "out-of-range jump", off);
2792*8b26181fSAndroid Build Coastguard Worker /*NOTREACHED*/
2793*8b26181fSAndroid Build Coastguard Worker }
2794*8b26181fSAndroid Build Coastguard Worker dst->jf = (u_char)(i - off - 1);
2795*8b26181fSAndroid Build Coastguard Worker jf++;
2796*8b26181fSAndroid Build Coastguard Worker }
2797*8b26181fSAndroid Build Coastguard Worker }
2798*8b26181fSAndroid Build Coastguard Worker if (!jt || !jf) {
2799*8b26181fSAndroid Build Coastguard Worker free(offset);
2800*8b26181fSAndroid Build Coastguard Worker conv_error(conv_state, ljerr, "no destination found", off);
2801*8b26181fSAndroid Build Coastguard Worker /*NOTREACHED*/
2802*8b26181fSAndroid Build Coastguard Worker }
2803*8b26181fSAndroid Build Coastguard Worker }
2804*8b26181fSAndroid Build Coastguard Worker filled:
2805*8b26181fSAndroid Build Coastguard Worker ++dst;
2806*8b26181fSAndroid Build Coastguard Worker ++off;
2807*8b26181fSAndroid Build Coastguard Worker }
2808*8b26181fSAndroid Build Coastguard Worker if (offset)
2809*8b26181fSAndroid Build Coastguard Worker free(offset);
2810*8b26181fSAndroid Build Coastguard Worker
2811*8b26181fSAndroid Build Coastguard Worker #ifdef BDEBUG
2812*8b26181fSAndroid Build Coastguard Worker if (dst - conv_state->fstart < NBIDS)
2813*8b26181fSAndroid Build Coastguard Worker bids[dst - conv_state->fstart] = p->id + 1;
2814*8b26181fSAndroid Build Coastguard Worker #endif
2815*8b26181fSAndroid Build Coastguard Worker dst->code = (u_short)p->s.code;
2816*8b26181fSAndroid Build Coastguard Worker dst->k = p->s.k;
2817*8b26181fSAndroid Build Coastguard Worker if (JT(p)) {
2818*8b26181fSAndroid Build Coastguard Worker /* number of extra jumps inserted */
2819*8b26181fSAndroid Build Coastguard Worker u_char extrajmps = 0;
2820*8b26181fSAndroid Build Coastguard Worker off = JT(p)->offset - (p->offset + slen) - 1;
2821*8b26181fSAndroid Build Coastguard Worker if (off >= 256) {
2822*8b26181fSAndroid Build Coastguard Worker /* offset too large for branch, must add a jump */
2823*8b26181fSAndroid Build Coastguard Worker if (p->longjt == 0) {
2824*8b26181fSAndroid Build Coastguard Worker /* mark this instruction and retry */
2825*8b26181fSAndroid Build Coastguard Worker p->longjt++;
2826*8b26181fSAndroid Build Coastguard Worker return(0);
2827*8b26181fSAndroid Build Coastguard Worker }
2828*8b26181fSAndroid Build Coastguard Worker dst->jt = extrajmps;
2829*8b26181fSAndroid Build Coastguard Worker extrajmps++;
2830*8b26181fSAndroid Build Coastguard Worker dst[extrajmps].code = BPF_JMP|BPF_JA;
2831*8b26181fSAndroid Build Coastguard Worker dst[extrajmps].k = off - extrajmps;
2832*8b26181fSAndroid Build Coastguard Worker }
2833*8b26181fSAndroid Build Coastguard Worker else
2834*8b26181fSAndroid Build Coastguard Worker dst->jt = (u_char)off;
2835*8b26181fSAndroid Build Coastguard Worker off = JF(p)->offset - (p->offset + slen) - 1;
2836*8b26181fSAndroid Build Coastguard Worker if (off >= 256) {
2837*8b26181fSAndroid Build Coastguard Worker /* offset too large for branch, must add a jump */
2838*8b26181fSAndroid Build Coastguard Worker if (p->longjf == 0) {
2839*8b26181fSAndroid Build Coastguard Worker /* mark this instruction and retry */
2840*8b26181fSAndroid Build Coastguard Worker p->longjf++;
2841*8b26181fSAndroid Build Coastguard Worker return(0);
2842*8b26181fSAndroid Build Coastguard Worker }
2843*8b26181fSAndroid Build Coastguard Worker /* branch if F to following jump */
2844*8b26181fSAndroid Build Coastguard Worker /* if two jumps are inserted, F goes to second one */
2845*8b26181fSAndroid Build Coastguard Worker dst->jf = extrajmps;
2846*8b26181fSAndroid Build Coastguard Worker extrajmps++;
2847*8b26181fSAndroid Build Coastguard Worker dst[extrajmps].code = BPF_JMP|BPF_JA;
2848*8b26181fSAndroid Build Coastguard Worker dst[extrajmps].k = off - extrajmps;
2849*8b26181fSAndroid Build Coastguard Worker }
2850*8b26181fSAndroid Build Coastguard Worker else
2851*8b26181fSAndroid Build Coastguard Worker dst->jf = (u_char)off;
2852*8b26181fSAndroid Build Coastguard Worker }
2853*8b26181fSAndroid Build Coastguard Worker return (1);
2854*8b26181fSAndroid Build Coastguard Worker }
2855*8b26181fSAndroid Build Coastguard Worker
2856*8b26181fSAndroid Build Coastguard Worker
2857*8b26181fSAndroid Build Coastguard Worker /*
2858*8b26181fSAndroid Build Coastguard Worker * Convert flowgraph intermediate representation to the
2859*8b26181fSAndroid Build Coastguard Worker * BPF array representation. Set *lenp to the number of instructions.
2860*8b26181fSAndroid Build Coastguard Worker *
2861*8b26181fSAndroid Build Coastguard Worker * This routine does *NOT* leak the memory pointed to by fp. It *must
2862*8b26181fSAndroid Build Coastguard Worker * not* do free(fp) before returning fp; doing so would make no sense,
2863*8b26181fSAndroid Build Coastguard Worker * as the BPF array pointed to by the return value of icode_to_fcode()
2864*8b26181fSAndroid Build Coastguard Worker * must be valid - it's being returned for use in a bpf_program structure.
2865*8b26181fSAndroid Build Coastguard Worker *
2866*8b26181fSAndroid Build Coastguard Worker * If it appears that icode_to_fcode() is leaking, the problem is that
2867*8b26181fSAndroid Build Coastguard Worker * the program using pcap_compile() is failing to free the memory in
2868*8b26181fSAndroid Build Coastguard Worker * the BPF program when it's done - the leak is in the program, not in
2869*8b26181fSAndroid Build Coastguard Worker * the routine that happens to be allocating the memory. (By analogy, if
2870*8b26181fSAndroid Build Coastguard Worker * a program calls fopen() without ever calling fclose() on the FILE *,
2871*8b26181fSAndroid Build Coastguard Worker * it will leak the FILE structure; the leak is not in fopen(), it's in
2872*8b26181fSAndroid Build Coastguard Worker * the program.) Change the program to use pcap_freecode() when it's
2873*8b26181fSAndroid Build Coastguard Worker * done with the filter program. See the pcap man page.
2874*8b26181fSAndroid Build Coastguard Worker */
2875*8b26181fSAndroid Build Coastguard Worker struct bpf_insn *
icode_to_fcode(struct icode * ic,struct block * root,u_int * lenp,char * errbuf)2876*8b26181fSAndroid Build Coastguard Worker icode_to_fcode(struct icode *ic, struct block *root, u_int *lenp,
2877*8b26181fSAndroid Build Coastguard Worker char *errbuf)
2878*8b26181fSAndroid Build Coastguard Worker {
2879*8b26181fSAndroid Build Coastguard Worker u_int n;
2880*8b26181fSAndroid Build Coastguard Worker struct bpf_insn *fp;
2881*8b26181fSAndroid Build Coastguard Worker conv_state_t conv_state;
2882*8b26181fSAndroid Build Coastguard Worker
2883*8b26181fSAndroid Build Coastguard Worker conv_state.fstart = NULL;
2884*8b26181fSAndroid Build Coastguard Worker conv_state.errbuf = errbuf;
2885*8b26181fSAndroid Build Coastguard Worker if (setjmp(conv_state.top_ctx) != 0) {
2886*8b26181fSAndroid Build Coastguard Worker free(conv_state.fstart);
2887*8b26181fSAndroid Build Coastguard Worker return NULL;
2888*8b26181fSAndroid Build Coastguard Worker }
2889*8b26181fSAndroid Build Coastguard Worker
2890*8b26181fSAndroid Build Coastguard Worker /*
2891*8b26181fSAndroid Build Coastguard Worker * Loop doing convert_code_r() until no branches remain
2892*8b26181fSAndroid Build Coastguard Worker * with too-large offsets.
2893*8b26181fSAndroid Build Coastguard Worker */
2894*8b26181fSAndroid Build Coastguard Worker for (;;) {
2895*8b26181fSAndroid Build Coastguard Worker unMarkAll(ic);
2896*8b26181fSAndroid Build Coastguard Worker n = *lenp = count_stmts(ic, root);
2897*8b26181fSAndroid Build Coastguard Worker
2898*8b26181fSAndroid Build Coastguard Worker fp = (struct bpf_insn *)malloc(sizeof(*fp) * n);
2899*8b26181fSAndroid Build Coastguard Worker if (fp == NULL) {
2900*8b26181fSAndroid Build Coastguard Worker (void)snprintf(errbuf, PCAP_ERRBUF_SIZE,
2901*8b26181fSAndroid Build Coastguard Worker "malloc");
2902*8b26181fSAndroid Build Coastguard Worker return NULL;
2903*8b26181fSAndroid Build Coastguard Worker }
2904*8b26181fSAndroid Build Coastguard Worker memset((char *)fp, 0, sizeof(*fp) * n);
2905*8b26181fSAndroid Build Coastguard Worker conv_state.fstart = fp;
2906*8b26181fSAndroid Build Coastguard Worker conv_state.ftail = fp + n;
2907*8b26181fSAndroid Build Coastguard Worker
2908*8b26181fSAndroid Build Coastguard Worker unMarkAll(ic);
2909*8b26181fSAndroid Build Coastguard Worker if (convert_code_r(&conv_state, ic, root))
2910*8b26181fSAndroid Build Coastguard Worker break;
2911*8b26181fSAndroid Build Coastguard Worker free(fp);
2912*8b26181fSAndroid Build Coastguard Worker }
2913*8b26181fSAndroid Build Coastguard Worker
2914*8b26181fSAndroid Build Coastguard Worker return fp;
2915*8b26181fSAndroid Build Coastguard Worker }
2916*8b26181fSAndroid Build Coastguard Worker
2917*8b26181fSAndroid Build Coastguard Worker /*
2918*8b26181fSAndroid Build Coastguard Worker * For iconv_to_fconv() errors.
2919*8b26181fSAndroid Build Coastguard Worker */
2920*8b26181fSAndroid Build Coastguard Worker static void PCAP_NORETURN
conv_error(conv_state_t * conv_state,const char * fmt,...)2921*8b26181fSAndroid Build Coastguard Worker conv_error(conv_state_t *conv_state, const char *fmt, ...)
2922*8b26181fSAndroid Build Coastguard Worker {
2923*8b26181fSAndroid Build Coastguard Worker va_list ap;
2924*8b26181fSAndroid Build Coastguard Worker
2925*8b26181fSAndroid Build Coastguard Worker va_start(ap, fmt);
2926*8b26181fSAndroid Build Coastguard Worker (void)vsnprintf(conv_state->errbuf,
2927*8b26181fSAndroid Build Coastguard Worker PCAP_ERRBUF_SIZE, fmt, ap);
2928*8b26181fSAndroid Build Coastguard Worker va_end(ap);
2929*8b26181fSAndroid Build Coastguard Worker longjmp(conv_state->top_ctx, 1);
2930*8b26181fSAndroid Build Coastguard Worker /* NOTREACHED */
2931*8b26181fSAndroid Build Coastguard Worker #ifdef _AIX
2932*8b26181fSAndroid Build Coastguard Worker PCAP_UNREACHABLE
2933*8b26181fSAndroid Build Coastguard Worker #endif /* _AIX */
2934*8b26181fSAndroid Build Coastguard Worker }
2935*8b26181fSAndroid Build Coastguard Worker
2936*8b26181fSAndroid Build Coastguard Worker /*
2937*8b26181fSAndroid Build Coastguard Worker * Make a copy of a BPF program and put it in the "fcode" member of
2938*8b26181fSAndroid Build Coastguard Worker * a "pcap_t".
2939*8b26181fSAndroid Build Coastguard Worker *
2940*8b26181fSAndroid Build Coastguard Worker * If we fail to allocate memory for the copy, fill in the "errbuf"
2941*8b26181fSAndroid Build Coastguard Worker * member of the "pcap_t" with an error message, and return -1;
2942*8b26181fSAndroid Build Coastguard Worker * otherwise, return 0.
2943*8b26181fSAndroid Build Coastguard Worker */
2944*8b26181fSAndroid Build Coastguard Worker int
install_bpf_program(pcap_t * p,struct bpf_program * fp)2945*8b26181fSAndroid Build Coastguard Worker install_bpf_program(pcap_t *p, struct bpf_program *fp)
2946*8b26181fSAndroid Build Coastguard Worker {
2947*8b26181fSAndroid Build Coastguard Worker size_t prog_size;
2948*8b26181fSAndroid Build Coastguard Worker
2949*8b26181fSAndroid Build Coastguard Worker /*
2950*8b26181fSAndroid Build Coastguard Worker * Validate the program.
2951*8b26181fSAndroid Build Coastguard Worker */
2952*8b26181fSAndroid Build Coastguard Worker if (!pcap_validate_filter(fp->bf_insns, fp->bf_len)) {
2953*8b26181fSAndroid Build Coastguard Worker snprintf(p->errbuf, sizeof(p->errbuf),
2954*8b26181fSAndroid Build Coastguard Worker "BPF program is not valid");
2955*8b26181fSAndroid Build Coastguard Worker return (-1);
2956*8b26181fSAndroid Build Coastguard Worker }
2957*8b26181fSAndroid Build Coastguard Worker
2958*8b26181fSAndroid Build Coastguard Worker /*
2959*8b26181fSAndroid Build Coastguard Worker * Free up any already installed program.
2960*8b26181fSAndroid Build Coastguard Worker */
2961*8b26181fSAndroid Build Coastguard Worker pcap_freecode(&p->fcode);
2962*8b26181fSAndroid Build Coastguard Worker
2963*8b26181fSAndroid Build Coastguard Worker prog_size = sizeof(*fp->bf_insns) * fp->bf_len;
2964*8b26181fSAndroid Build Coastguard Worker p->fcode.bf_len = fp->bf_len;
2965*8b26181fSAndroid Build Coastguard Worker p->fcode.bf_insns = (struct bpf_insn *)malloc(prog_size);
2966*8b26181fSAndroid Build Coastguard Worker if (p->fcode.bf_insns == NULL) {
2967*8b26181fSAndroid Build Coastguard Worker pcap_fmt_errmsg_for_errno(p->errbuf, sizeof(p->errbuf),
2968*8b26181fSAndroid Build Coastguard Worker errno, "malloc");
2969*8b26181fSAndroid Build Coastguard Worker return (-1);
2970*8b26181fSAndroid Build Coastguard Worker }
2971*8b26181fSAndroid Build Coastguard Worker memcpy(p->fcode.bf_insns, fp->bf_insns, prog_size);
2972*8b26181fSAndroid Build Coastguard Worker return (0);
2973*8b26181fSAndroid Build Coastguard Worker }
2974*8b26181fSAndroid Build Coastguard Worker
2975*8b26181fSAndroid Build Coastguard Worker #ifdef BDEBUG
2976*8b26181fSAndroid Build Coastguard Worker static void
dot_dump_node(struct icode * ic,struct block * block,struct bpf_program * prog,FILE * out)2977*8b26181fSAndroid Build Coastguard Worker dot_dump_node(struct icode *ic, struct block *block, struct bpf_program *prog,
2978*8b26181fSAndroid Build Coastguard Worker FILE *out)
2979*8b26181fSAndroid Build Coastguard Worker {
2980*8b26181fSAndroid Build Coastguard Worker int icount, noffset;
2981*8b26181fSAndroid Build Coastguard Worker int i;
2982*8b26181fSAndroid Build Coastguard Worker
2983*8b26181fSAndroid Build Coastguard Worker if (block == NULL || isMarked(ic, block))
2984*8b26181fSAndroid Build Coastguard Worker return;
2985*8b26181fSAndroid Build Coastguard Worker Mark(ic, block);
2986*8b26181fSAndroid Build Coastguard Worker
2987*8b26181fSAndroid Build Coastguard Worker icount = slength(block->stmts) + 1 + block->longjt + block->longjf;
2988*8b26181fSAndroid Build Coastguard Worker noffset = min(block->offset + icount, (int)prog->bf_len);
2989*8b26181fSAndroid Build Coastguard Worker
2990*8b26181fSAndroid Build Coastguard Worker fprintf(out, "\tblock%u [shape=ellipse, id=\"block-%u\" label=\"BLOCK%u\\n", block->id, block->id, block->id);
2991*8b26181fSAndroid Build Coastguard Worker for (i = block->offset; i < noffset; i++) {
2992*8b26181fSAndroid Build Coastguard Worker fprintf(out, "\\n%s", bpf_image(prog->bf_insns + i, i));
2993*8b26181fSAndroid Build Coastguard Worker }
2994*8b26181fSAndroid Build Coastguard Worker fprintf(out, "\" tooltip=\"");
2995*8b26181fSAndroid Build Coastguard Worker for (i = 0; i < BPF_MEMWORDS; i++)
2996*8b26181fSAndroid Build Coastguard Worker if (block->val[i] != VAL_UNKNOWN)
2997*8b26181fSAndroid Build Coastguard Worker fprintf(out, "val[%d]=%d ", i, block->val[i]);
2998*8b26181fSAndroid Build Coastguard Worker fprintf(out, "val[A]=%d ", block->val[A_ATOM]);
2999*8b26181fSAndroid Build Coastguard Worker fprintf(out, "val[X]=%d", block->val[X_ATOM]);
3000*8b26181fSAndroid Build Coastguard Worker fprintf(out, "\"");
3001*8b26181fSAndroid Build Coastguard Worker if (JT(block) == NULL)
3002*8b26181fSAndroid Build Coastguard Worker fprintf(out, ", peripheries=2");
3003*8b26181fSAndroid Build Coastguard Worker fprintf(out, "];\n");
3004*8b26181fSAndroid Build Coastguard Worker
3005*8b26181fSAndroid Build Coastguard Worker dot_dump_node(ic, JT(block), prog, out);
3006*8b26181fSAndroid Build Coastguard Worker dot_dump_node(ic, JF(block), prog, out);
3007*8b26181fSAndroid Build Coastguard Worker }
3008*8b26181fSAndroid Build Coastguard Worker
3009*8b26181fSAndroid Build Coastguard Worker static void
dot_dump_edge(struct icode * ic,struct block * block,FILE * out)3010*8b26181fSAndroid Build Coastguard Worker dot_dump_edge(struct icode *ic, struct block *block, FILE *out)
3011*8b26181fSAndroid Build Coastguard Worker {
3012*8b26181fSAndroid Build Coastguard Worker if (block == NULL || isMarked(ic, block))
3013*8b26181fSAndroid Build Coastguard Worker return;
3014*8b26181fSAndroid Build Coastguard Worker Mark(ic, block);
3015*8b26181fSAndroid Build Coastguard Worker
3016*8b26181fSAndroid Build Coastguard Worker if (JT(block)) {
3017*8b26181fSAndroid Build Coastguard Worker fprintf(out, "\t\"block%u\":se -> \"block%u\":n [label=\"T\"]; \n",
3018*8b26181fSAndroid Build Coastguard Worker block->id, JT(block)->id);
3019*8b26181fSAndroid Build Coastguard Worker fprintf(out, "\t\"block%u\":sw -> \"block%u\":n [label=\"F\"]; \n",
3020*8b26181fSAndroid Build Coastguard Worker block->id, JF(block)->id);
3021*8b26181fSAndroid Build Coastguard Worker }
3022*8b26181fSAndroid Build Coastguard Worker dot_dump_edge(ic, JT(block), out);
3023*8b26181fSAndroid Build Coastguard Worker dot_dump_edge(ic, JF(block), out);
3024*8b26181fSAndroid Build Coastguard Worker }
3025*8b26181fSAndroid Build Coastguard Worker
3026*8b26181fSAndroid Build Coastguard Worker /* Output the block CFG using graphviz/DOT language
3027*8b26181fSAndroid Build Coastguard Worker * In the CFG, block's code, value index for each registers at EXIT,
3028*8b26181fSAndroid Build Coastguard Worker * and the jump relationship is show.
3029*8b26181fSAndroid Build Coastguard Worker *
3030*8b26181fSAndroid Build Coastguard Worker * example DOT for BPF `ip src host 1.1.1.1' is:
3031*8b26181fSAndroid Build Coastguard Worker digraph BPF {
3032*8b26181fSAndroid Build Coastguard Worker 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"];
3033*8b26181fSAndroid Build Coastguard Worker 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"];
3034*8b26181fSAndroid Build Coastguard Worker block2 [shape=ellipse, id="block-2" label="BLOCK2\n\n(004) ret #68" tooltip="val[A]=0 val[X]=0", peripheries=2];
3035*8b26181fSAndroid Build Coastguard Worker block3 [shape=ellipse, id="block-3" label="BLOCK3\n\n(005) ret #0" tooltip="val[A]=0 val[X]=0", peripheries=2];
3036*8b26181fSAndroid Build Coastguard Worker "block0":se -> "block1":n [label="T"];
3037*8b26181fSAndroid Build Coastguard Worker "block0":sw -> "block3":n [label="F"];
3038*8b26181fSAndroid Build Coastguard Worker "block1":se -> "block2":n [label="T"];
3039*8b26181fSAndroid Build Coastguard Worker "block1":sw -> "block3":n [label="F"];
3040*8b26181fSAndroid Build Coastguard Worker }
3041*8b26181fSAndroid Build Coastguard Worker *
3042*8b26181fSAndroid Build Coastguard Worker * After install graphviz on https://www.graphviz.org/, save it as bpf.dot
3043*8b26181fSAndroid Build Coastguard Worker * and run `dot -Tpng -O bpf.dot' to draw the graph.
3044*8b26181fSAndroid Build Coastguard Worker */
3045*8b26181fSAndroid Build Coastguard Worker static int
dot_dump(struct icode * ic,char * errbuf)3046*8b26181fSAndroid Build Coastguard Worker dot_dump(struct icode *ic, char *errbuf)
3047*8b26181fSAndroid Build Coastguard Worker {
3048*8b26181fSAndroid Build Coastguard Worker struct bpf_program f;
3049*8b26181fSAndroid Build Coastguard Worker FILE *out = stdout;
3050*8b26181fSAndroid Build Coastguard Worker
3051*8b26181fSAndroid Build Coastguard Worker memset(bids, 0, sizeof bids);
3052*8b26181fSAndroid Build Coastguard Worker f.bf_insns = icode_to_fcode(ic, ic->root, &f.bf_len, errbuf);
3053*8b26181fSAndroid Build Coastguard Worker if (f.bf_insns == NULL)
3054*8b26181fSAndroid Build Coastguard Worker return -1;
3055*8b26181fSAndroid Build Coastguard Worker
3056*8b26181fSAndroid Build Coastguard Worker fprintf(out, "digraph BPF {\n");
3057*8b26181fSAndroid Build Coastguard Worker unMarkAll(ic);
3058*8b26181fSAndroid Build Coastguard Worker dot_dump_node(ic, ic->root, &f, out);
3059*8b26181fSAndroid Build Coastguard Worker unMarkAll(ic);
3060*8b26181fSAndroid Build Coastguard Worker dot_dump_edge(ic, ic->root, out);
3061*8b26181fSAndroid Build Coastguard Worker fprintf(out, "}\n");
3062*8b26181fSAndroid Build Coastguard Worker
3063*8b26181fSAndroid Build Coastguard Worker free((char *)f.bf_insns);
3064*8b26181fSAndroid Build Coastguard Worker return 0;
3065*8b26181fSAndroid Build Coastguard Worker }
3066*8b26181fSAndroid Build Coastguard Worker
3067*8b26181fSAndroid Build Coastguard Worker static int
plain_dump(struct icode * ic,char * errbuf)3068*8b26181fSAndroid Build Coastguard Worker plain_dump(struct icode *ic, char *errbuf)
3069*8b26181fSAndroid Build Coastguard Worker {
3070*8b26181fSAndroid Build Coastguard Worker struct bpf_program f;
3071*8b26181fSAndroid Build Coastguard Worker
3072*8b26181fSAndroid Build Coastguard Worker memset(bids, 0, sizeof bids);
3073*8b26181fSAndroid Build Coastguard Worker f.bf_insns = icode_to_fcode(ic, ic->root, &f.bf_len, errbuf);
3074*8b26181fSAndroid Build Coastguard Worker if (f.bf_insns == NULL)
3075*8b26181fSAndroid Build Coastguard Worker return -1;
3076*8b26181fSAndroid Build Coastguard Worker bpf_dump(&f, 1);
3077*8b26181fSAndroid Build Coastguard Worker putchar('\n');
3078*8b26181fSAndroid Build Coastguard Worker free((char *)f.bf_insns);
3079*8b26181fSAndroid Build Coastguard Worker return 0;
3080*8b26181fSAndroid Build Coastguard Worker }
3081*8b26181fSAndroid Build Coastguard Worker
3082*8b26181fSAndroid Build Coastguard Worker static void
opt_dump(opt_state_t * opt_state,struct icode * ic)3083*8b26181fSAndroid Build Coastguard Worker opt_dump(opt_state_t *opt_state, struct icode *ic)
3084*8b26181fSAndroid Build Coastguard Worker {
3085*8b26181fSAndroid Build Coastguard Worker int status;
3086*8b26181fSAndroid Build Coastguard Worker char errbuf[PCAP_ERRBUF_SIZE];
3087*8b26181fSAndroid Build Coastguard Worker
3088*8b26181fSAndroid Build Coastguard Worker /*
3089*8b26181fSAndroid Build Coastguard Worker * If the CFG, in DOT format, is requested, output it rather than
3090*8b26181fSAndroid Build Coastguard Worker * the code that would be generated from that graph.
3091*8b26181fSAndroid Build Coastguard Worker */
3092*8b26181fSAndroid Build Coastguard Worker if (pcap_print_dot_graph)
3093*8b26181fSAndroid Build Coastguard Worker status = dot_dump(ic, errbuf);
3094*8b26181fSAndroid Build Coastguard Worker else
3095*8b26181fSAndroid Build Coastguard Worker status = plain_dump(ic, errbuf);
3096*8b26181fSAndroid Build Coastguard Worker if (status == -1)
3097*8b26181fSAndroid Build Coastguard Worker opt_error(opt_state, "opt_dump: icode_to_fcode failed: %s", errbuf);
3098*8b26181fSAndroid Build Coastguard Worker }
3099*8b26181fSAndroid Build Coastguard Worker #endif
3100