d8d0119005dd60a62cafcfd9cc070a9503c96bc5
[obnox/wireshark/wip.git] / epan / dfilter / gencode.c
1 /*
2  * $Id: gencode.c,v 1.4 2001/12/18 19:09:06 gram Exp $
3  *
4  * Ethereal - Network traffic analyzer
5  * By Gerald Combs <gerald@zing.org>
6  * Copyright 2001 Gerald Combs
7  *
8  * 
9  * This program is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU General Public License
11  * as published by the Free Software Foundation; either version 2
12  * of the License, or (at your option) any later version.
13  * 
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  * 
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
22  */
23
24 #ifdef HAVE_CONFIG_H
25 #include "config.h"
26 #endif
27
28 #include "dfilter-int.h"
29 #include "dfvm.h"
30 #include "syntax-tree.h"
31 #include "sttype-range.h"
32 #include "sttype-test.h"
33 #include "ftypes/ftypes.h"
34 #include "gdebug.h"
35
36 static void
37 gencode(dfwork_t *dfw, stnode_t *st_node);
38
39 static void
40 dfw_append_insn(dfwork_t *dfw, dfvm_insn_t *insn)
41 {
42         insn->id = dfw->next_insn_id;
43         dfw->next_insn_id++;
44         g_ptr_array_add(dfw->insns, insn);
45 }
46
47 /* returns register number */
48 static int
49 dfw_append_read_tree(dfwork_t *dfw, int field_id)
50 {
51         dfvm_insn_t     *insn;
52         dfvm_value_t    *val1, *val2;
53         int             reg = -1;
54
55         /* Keep track of which registers
56          * were used for which field_id's so that we
57          * can re-use registers. */
58         reg = GPOINTER_TO_UINT(
59                         g_hash_table_lookup(dfw->loaded_fields,
60                         GINT_TO_POINTER(field_id)));
61         if (reg) {
62                 /* Reg's are stored in has as reg+1, so
63                  * that the non-existence of a field_id in
64                  * the hash, or 0, can be differentiated from
65                  * a field_id being loaded into register #0. */
66                 reg--;
67         }
68         else {
69                 reg = dfw->next_register++;
70                 g_hash_table_insert(dfw->loaded_fields,
71                         GUINT_TO_POINTER(field_id),
72                         GUINT_TO_POINTER(reg + 1));
73
74         /* Record the FIELD_ID in hash of interesting fields. */
75         g_hash_table_insert(dfw->interesting_fields,
76             GINT_TO_POINTER(field_id), GUINT_TO_POINTER(TRUE));
77         }
78
79         insn = dfvm_insn_new(READ_TREE);
80         val1 = dfvm_value_new(FIELD_ID);
81         val1->value.numeric = field_id;
82         val2 = dfvm_value_new(REGISTER);
83         val2->value.numeric = reg;
84
85         insn->arg1 = val1;
86         insn->arg2 = val2;
87         dfw_append_insn(dfw, insn);
88
89         return reg;
90 }
91
92 /* returns register number */
93 static int
94 dfw_append_put_fvalue(dfwork_t *dfw, fvalue_t *fv)
95 {
96         dfvm_insn_t     *insn;
97         dfvm_value_t    *val1, *val2;
98         int             reg;
99
100         insn = dfvm_insn_new(PUT_FVALUE);
101         val1 = dfvm_value_new(FVALUE);
102         val1->value.fvalue = fv;
103         val2 = dfvm_value_new(REGISTER);
104         reg = dfw->next_register++;
105         val2->value.numeric = reg;
106         insn->arg1 = val1;
107         insn->arg2 = val2;
108         dfw_append_insn(dfw, insn);
109
110         return reg;
111 }
112
113 /* returns register number */
114 static int
115 dfw_append_mk_range(dfwork_t *dfw, stnode_t *node)
116 {
117         int                     hf_reg, reg;
118         header_field_info       *hfinfo;
119         dfvm_insn_t             *insn;
120         dfvm_value_t            *val;
121
122         hfinfo = sttype_range_hfinfo(node);
123         hf_reg = dfw_append_read_tree(dfw, hfinfo->id);
124
125         insn = dfvm_insn_new(MK_RANGE);
126
127         val = dfvm_value_new(REGISTER);
128         val->value.numeric = hf_reg;
129         insn->arg1 = val;
130
131         val = dfvm_value_new(REGISTER);
132         reg =dfw->next_register++;
133         val->value.numeric = reg;
134         insn->arg2 = val;
135
136         val = dfvm_value_new(DRANGE);
137         val->value.drange = sttype_range_drange(node);
138         insn->arg3 = val;
139
140         sttype_range_remove_drange(node);
141
142         dfw_append_insn(dfw, insn);
143
144         return reg;
145 }
146
147
148 static void
149 gen_relation(dfwork_t *dfw, dfvm_opcode_t op, stnode_t *st_arg1, stnode_t *st_arg2)
150 {
151         sttype_id_t     type1, type2;
152         dfvm_insn_t     *insn;
153         dfvm_value_t    *val1, *val2;
154         dfvm_value_t    *jmp1 = NULL, *jmp2 = NULL;
155         int             reg1 = -1, reg2 = -1;
156         header_field_info       *hfinfo;
157
158         type1 = stnode_type_id(st_arg1);
159         type2 = stnode_type_id(st_arg2);
160
161         if (type1 == STTYPE_FIELD) {
162                 hfinfo = stnode_data(st_arg1);
163                 reg1 = dfw_append_read_tree(dfw, hfinfo->id);
164
165                 insn = dfvm_insn_new(IF_FALSE_GOTO);
166                 jmp1 = dfvm_value_new(INSN_NUMBER);
167                 insn->arg1 = jmp1;
168                 dfw_append_insn(dfw, insn);
169         }
170         else if (type1 == STTYPE_FVALUE) {
171                 reg1 = dfw_append_put_fvalue(dfw, stnode_data(st_arg1));
172         }
173         else if (type1 == STTYPE_RANGE) {
174                 reg1 = dfw_append_mk_range(dfw, st_arg1);
175         }
176         else {
177                 g_assert_not_reached();
178         }
179
180         if (type2 == STTYPE_FIELD) {
181                 hfinfo = stnode_data(st_arg2);
182                 reg2 = dfw_append_read_tree(dfw, hfinfo->id);
183
184                 insn = dfvm_insn_new(IF_FALSE_GOTO);
185                 jmp2 = dfvm_value_new(INSN_NUMBER);
186                 insn->arg1 = jmp2;
187                 dfw_append_insn(dfw, insn);
188         }
189         else if (type2 == STTYPE_FVALUE) {
190                 reg2 = dfw_append_put_fvalue(dfw, stnode_data(st_arg2));
191         }
192         else {
193                 g_assert_not_reached();
194         }
195
196         insn = dfvm_insn_new(op);
197         val1 = dfvm_value_new(REGISTER);
198         val1->value.numeric = reg1;
199         val2 = dfvm_value_new(REGISTER);
200         val2->value.numeric = reg2;
201         insn->arg1 = val1;
202         insn->arg2 = val2;
203         dfw_append_insn(dfw, insn);
204
205         if (jmp1) {
206                 jmp1->value.numeric = dfw->next_insn_id;
207         }
208
209         if (jmp2) {
210                 jmp2->value.numeric = dfw->next_insn_id;
211         }
212 }
213
214
215 static void
216 gen_test(dfwork_t *dfw, stnode_t *st_node)
217 {
218         test_op_t       st_op;
219         stnode_t        *st_arg1, *st_arg2;
220         dfvm_value_t    *val1;
221         dfvm_insn_t     *insn;
222
223         header_field_info       *hfinfo;
224
225         sttype_test_get(st_node, &st_op, &st_arg1, &st_arg2);
226
227         switch (st_op) {
228                 case TEST_OP_UNINITIALIZED:
229                         g_assert_not_reached();
230                         break;
231
232                 case TEST_OP_EXISTS:
233                         val1 = dfvm_value_new(FIELD_ID);
234                         hfinfo = stnode_data(st_arg1);
235                         val1->value.numeric = hfinfo->id;
236                         insn = dfvm_insn_new(CHECK_EXISTS);
237                         insn->arg1 = val1;
238                         dfw_append_insn(dfw, insn);
239
240             /* Record the FIELD_ID in hash of interesting fields. */
241             g_hash_table_insert(dfw->interesting_fields,
242                 GINT_TO_POINTER(hfinfo->id), GUINT_TO_POINTER(TRUE));
243
244                         break;
245
246                 case TEST_OP_NOT:
247                         gencode(dfw, st_arg1);
248                         insn = dfvm_insn_new(NOT);
249                         dfw_append_insn(dfw, insn);
250                         break;
251
252                 case TEST_OP_AND:
253                         gencode(dfw, st_arg1);
254
255                         insn = dfvm_insn_new(IF_FALSE_GOTO);
256                         val1 = dfvm_value_new(INSN_NUMBER);
257                         insn->arg1 = val1;
258                         dfw_append_insn(dfw, insn);
259
260                         gencode(dfw, st_arg2);
261                         val1->value.numeric = dfw->next_insn_id;
262                         break;
263
264                 case TEST_OP_OR:
265                         gencode(dfw, st_arg1);
266
267                         insn = dfvm_insn_new(IF_TRUE_GOTO);
268                         val1 = dfvm_value_new(INSN_NUMBER);
269                         insn->arg1 = val1;
270                         dfw_append_insn(dfw, insn);
271
272                         gencode(dfw, st_arg2);
273                         val1->value.numeric = dfw->next_insn_id;
274                         break;
275
276                 case TEST_OP_EQ:
277                         gen_relation(dfw, ANY_EQ, st_arg1, st_arg2);
278                         break;
279
280                 case TEST_OP_NE:
281                         gen_relation(dfw, ANY_NE, st_arg1, st_arg2);
282                         break;
283
284                 case TEST_OP_GT:
285                         gen_relation(dfw, ANY_GT, st_arg1, st_arg2);
286                         break;
287
288                 case TEST_OP_GE:
289                         gen_relation(dfw, ANY_GE, st_arg1, st_arg2);
290                         break;
291
292                 case TEST_OP_LT:
293                         gen_relation(dfw, ANY_LT, st_arg1, st_arg2);
294                         break;
295
296                 case TEST_OP_LE:
297                         gen_relation(dfw, ANY_LE, st_arg1, st_arg2);
298                         break;
299         }
300 }
301
302 static void
303 gencode(dfwork_t *dfw, stnode_t *st_node)
304 {
305         const char      *name;
306
307         name = stnode_type_name(st_node);
308
309         switch (stnode_type_id(st_node)) {
310                 case STTYPE_TEST:
311                         gen_test(dfw, st_node);
312                         break;
313                 default:
314                         g_assert_not_reached();
315         }
316 }
317
318
319 void
320 dfw_gencode(dfwork_t *dfw)
321 {
322         dfw->insns = g_ptr_array_new();
323         dfw->loaded_fields = g_hash_table_new(g_direct_hash, g_direct_equal);
324         dfw->interesting_fields = g_hash_table_new(g_direct_hash, g_direct_equal);
325         gencode(dfw, dfw->st_root);
326         dfw_append_insn(dfw, dfvm_insn_new(RETURN));
327 }
328
329
330
331 typedef struct {
332     int i;
333     int *fields;
334 } hash_key_iterator;
335  
336 static void
337 get_hash_key(gpointer key, gpointer value, gpointer user_data)
338 {
339     int field_id = GPOINTER_TO_INT(key);
340     hash_key_iterator *hki = user_data;
341
342     hki->fields[hki->i] = field_id;
343     hki->i++;
344 }
345
346 int*
347 dfw_interesting_fields(dfwork_t *dfw, int *caller_num_fields)
348 {
349     int num_fields = g_hash_table_size(dfw->interesting_fields);
350
351     hash_key_iterator hki;
352
353     if (num_fields == 0) {
354         *caller_num_fields = 0;
355         return NULL;
356     }
357
358     hki.fields = g_new(int, num_fields);
359     hki.i = 0;
360         
361     g_hash_table_foreach(dfw->interesting_fields, get_hash_key, &hki);
362     *caller_num_fields = num_fields;
363     return hki.fields;
364 }