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