name change
[gd/wireshark/.git] / epan / dfilter / gencode.c
1 /*
2  * $Id$
3  *
4  * Wireshark - Network traffic analyzer
5  * By Gerald Combs <gerald@wireshark.org>
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 "gencode.h"
29 #include "dfvm.h"
30 #include "syntax-tree.h"
31 #include "sttype-range.h"
32 #include "sttype-test.h"
33 #include "sttype-function.h"
34 #include "ftypes/ftypes.h"
35
36 static void
37 gencode(dfwork_t *dfw, stnode_t *st_node);
38
39 static int
40 gen_entity(dfwork_t *dfw, stnode_t *st_arg, dfvm_value_t **p_jmp);
41
42 static void
43 dfw_append_insn(dfwork_t *dfw, dfvm_insn_t *insn)
44 {
45         insn->id = dfw->next_insn_id;
46         dfw->next_insn_id++;
47         g_ptr_array_add(dfw->insns, insn);
48 }
49
50 /* returns register number */
51 static int
52 dfw_append_read_tree(dfwork_t *dfw, header_field_info *hfinfo)
53 {
54         dfvm_insn_t     *insn;
55         dfvm_value_t    *val1, *val2;
56         int             reg = -1;
57         gboolean        added_new_hfinfo = FALSE;
58
59         /* Rewind to find the first field of this name. */
60         while (hfinfo->same_name_prev) {
61                 hfinfo = hfinfo->same_name_prev;
62         }
63
64         /* Keep track of which registers
65          * were used for which hfinfo's so that we
66          * can re-use registers. */
67         reg = GPOINTER_TO_UINT(
68                         g_hash_table_lookup(dfw->loaded_fields, hfinfo));
69         if (reg) {
70                 /* Reg's are stored in has as reg+1, so
71                  * that the non-existence of a hfinfo in
72                  * the hash, or 0, can be differentiated from
73                  * a hfinfo being loaded into register #0. */
74                 reg--;
75         }
76         else {
77                 reg = dfw->next_register++;
78                 g_hash_table_insert(dfw->loaded_fields,
79                         hfinfo, GUINT_TO_POINTER(reg + 1));
80
81                 added_new_hfinfo = TRUE;
82         }
83
84         insn = dfvm_insn_new(READ_TREE);
85         val1 = dfvm_value_new(HFINFO);
86         val1->value.hfinfo = hfinfo;
87         val2 = dfvm_value_new(REGISTER);
88         val2->value.numeric = reg;
89
90         insn->arg1 = val1;
91         insn->arg2 = val2;
92         dfw_append_insn(dfw, insn);
93         
94         if (added_new_hfinfo) {
95                 while (hfinfo) {
96                         /* Record the FIELD_ID in hash of interesting fields. */
97                         g_hash_table_insert(dfw->interesting_fields,
98                             GINT_TO_POINTER(hfinfo->id),
99                             GUINT_TO_POINTER(TRUE));
100                         hfinfo = hfinfo->same_name_next;
101                 }
102         }
103
104         return reg;
105 }
106
107 /* returns register number */
108 static int
109 dfw_append_put_fvalue(dfwork_t *dfw, fvalue_t *fv)
110 {
111         dfvm_insn_t     *insn;
112         dfvm_value_t    *val1, *val2;
113         int             reg;
114
115         insn = dfvm_insn_new(PUT_FVALUE);
116         val1 = dfvm_value_new(FVALUE);
117         val1->value.fvalue = fv;
118         val2 = dfvm_value_new(REGISTER);
119         reg = dfw->next_register++;
120         val2->value.numeric = reg;
121         insn->arg1 = val1;
122         insn->arg2 = val2;
123         dfw_append_insn(dfw, insn);
124
125         return reg;
126 }
127
128 /* returns register number */
129 static int
130 dfw_append_mk_range(dfwork_t *dfw, stnode_t *node)
131 {
132         int                     hf_reg, reg;
133         header_field_info       *hfinfo;
134         dfvm_insn_t             *insn;
135         dfvm_value_t            *val;
136
137         hfinfo = sttype_range_hfinfo(node);
138         hf_reg = dfw_append_read_tree(dfw, hfinfo);
139
140         insn = dfvm_insn_new(MK_RANGE);
141
142         val = dfvm_value_new(REGISTER);
143         val->value.numeric = hf_reg;
144         insn->arg1 = val;
145
146         val = dfvm_value_new(REGISTER);
147         reg =dfw->next_register++;
148         val->value.numeric = reg;
149         insn->arg2 = val;
150
151         val = dfvm_value_new(DRANGE);
152         val->value.drange = sttype_range_drange(node);
153         insn->arg3 = val;
154
155         sttype_range_remove_drange(node);
156
157         dfw_append_insn(dfw, insn);
158
159         return reg;
160 }
161
162 /* returns register number that the functions's result will be in. */
163 static int
164 dfw_append_function(dfwork_t *dfw, stnode_t *node, dfvm_value_t **p_jmp)
165 {
166     GSList *params;
167     int i, num_params, reg;
168     dfvm_value_t **jmps;
169         dfvm_insn_t     *insn;
170         dfvm_value_t    *val1, *val2, *val;
171
172     params = sttype_function_params(node);
173     num_params = g_slist_length(params);
174
175     /* Array to hold the instructions that need to jump to
176      * an instruction if they fail. */
177     jmps = g_malloc(num_params * sizeof(dfvm_value_t*));
178
179     /* Create the new DFVM instruction */
180     insn = dfvm_insn_new(CALL_FUNCTION);
181     
182     val1 = dfvm_value_new(FUNCTION_DEF);
183     val1->value.funcdef = sttype_function_funcdef(node);
184     insn->arg1 = val1;
185         val2 = dfvm_value_new(REGISTER);
186         val2->value.numeric = dfw->next_register++;
187     insn->arg2 = val2;
188     insn->arg3 = NULL;
189     insn->arg4 = NULL;
190
191     i = 0;
192     while (params) {
193         jmps[i] = NULL;
194         reg = gen_entity(dfw, params->data, &jmps[i]);
195
196         val = dfvm_value_new(REGISTER);
197         val->value.numeric = reg;
198
199         switch(i) {
200             case 0:
201                 insn->arg3 = val;
202                 break;
203             case 1:
204                 insn->arg4 = val;
205                 break;
206             default:
207                 g_assert_not_reached();
208         }
209
210         params = params->next;
211         i++;
212     }
213
214         dfw_append_insn(dfw, insn);
215
216     /* If any of our parameters failed, send them to
217      * our own failure instruction. This *has* to be done
218      * after we caled dfw_append_insn above so that
219      * we know what the next DFVM insruction is, via
220      * dfw->next_insn_id */
221     for (i = 0; i < num_params; i++) {
222         if (jmps[i]) {
223             jmps[i]->value.numeric = dfw->next_insn_id;
224         }
225     }
226
227     /* We need another instruction to jump to another exit
228      * place, if the call() of our function failed for some reaosn */
229     insn = dfvm_insn_new(IF_FALSE_GOTO);
230     g_assert(p_jmp);
231     *p_jmp = dfvm_value_new(INSN_NUMBER);
232     insn->arg1 = *p_jmp;
233     dfw_append_insn(dfw, insn);
234
235     g_free(jmps);
236     
237     return val2->value.numeric;
238 }
239
240
241 static void
242 gen_relation(dfwork_t *dfw, dfvm_opcode_t op, stnode_t *st_arg1, stnode_t *st_arg2)
243 {
244         dfvm_insn_t     *insn;
245         dfvm_value_t    *val1, *val2;
246         dfvm_value_t    *jmp1 = NULL, *jmp2 = NULL;
247         int             reg1 = -1, reg2 = -1;
248
249     /* Create code for the LHS and RHS of the relation */
250     reg1 = gen_entity(dfw, st_arg1, &jmp1);
251     reg2 = gen_entity(dfw, st_arg2, &jmp2);
252
253     /* Then combine them in a DFVM insruction */
254         insn = dfvm_insn_new(op);
255         val1 = dfvm_value_new(REGISTER);
256         val1->value.numeric = reg1;
257         val2 = dfvm_value_new(REGISTER);
258         val2->value.numeric = reg2;
259         insn->arg1 = val1;
260         insn->arg2 = val2;
261         dfw_append_insn(dfw, insn);
262
263     /* If either of the relation argumnents need an "exit" instruction
264      * to jump to (on failure), mark them */
265         if (jmp1) {
266                 jmp1->value.numeric = dfw->next_insn_id;
267         }
268
269         if (jmp2) {
270                 jmp2->value.numeric = dfw->next_insn_id;
271         }
272 }
273
274 /* Parse an entity, returning the reg that it gets put into.
275  * p_jmp will be set if it has to be set by the calling code; it should
276  * be set to the place to jump to, to return to the calling code,
277  * if the load of a field from the proto_tree fails. */
278 static int
279 gen_entity(dfwork_t *dfw, stnode_t *st_arg, dfvm_value_t **p_jmp)
280 {
281         sttype_id_t     e_type;
282         dfvm_insn_t     *insn;
283         header_field_info       *hfinfo;
284     int reg = -1;
285         e_type = stnode_type_id(st_arg);
286
287         if (e_type == STTYPE_FIELD) {
288                 hfinfo = stnode_data(st_arg);
289                 reg = dfw_append_read_tree(dfw, hfinfo);
290
291                 insn = dfvm_insn_new(IF_FALSE_GOTO);
292         g_assert(p_jmp);
293                 *p_jmp = dfvm_value_new(INSN_NUMBER);
294                 insn->arg1 = *p_jmp;
295                 dfw_append_insn(dfw, insn);
296         }
297         else if (e_type == STTYPE_FVALUE) {
298                 reg = dfw_append_put_fvalue(dfw, stnode_data(st_arg));
299         }
300         else if (e_type == STTYPE_RANGE) {
301                 reg = dfw_append_mk_range(dfw, st_arg);
302         }
303         else if (e_type == STTYPE_FUNCTION) {
304         reg = dfw_append_function(dfw, st_arg, p_jmp);
305     }
306         else {
307         printf("sttype_id is %u\n", e_type);
308                 g_assert_not_reached();
309         }
310     return reg;
311 }
312
313
314 static void
315 gen_test(dfwork_t *dfw, stnode_t *st_node)
316 {
317         test_op_t       st_op;
318         stnode_t        *st_arg1, *st_arg2;
319         dfvm_value_t    *val1;
320         dfvm_insn_t     *insn;
321
322         header_field_info       *hfinfo;
323
324         sttype_test_get(st_node, &st_op, &st_arg1, &st_arg2);
325
326         switch (st_op) {
327                 case TEST_OP_UNINITIALIZED:
328                         g_assert_not_reached();
329                         break;
330
331                 case TEST_OP_EXISTS:
332                         val1 = dfvm_value_new(HFINFO);
333                         hfinfo = stnode_data(st_arg1);
334
335                         /* Rewind to find the first field of this name. */
336                         while (hfinfo->same_name_prev) {
337                                 hfinfo = hfinfo->same_name_prev;
338                         }
339                         val1->value.hfinfo = hfinfo;
340                         insn = dfvm_insn_new(CHECK_EXISTS);
341                         insn->arg1 = val1;
342                         dfw_append_insn(dfw, insn);
343
344                         /* Record the FIELD_ID in hash of interesting fields. */
345                         while (hfinfo) {
346                                 g_hash_table_insert(dfw->interesting_fields,
347                                         GINT_TO_POINTER(hfinfo->id),
348                                         GUINT_TO_POINTER(TRUE));
349                                 hfinfo = hfinfo->same_name_next;
350                         }
351
352                         break;
353
354                 case TEST_OP_NOT:
355                         gencode(dfw, st_arg1);
356                         insn = dfvm_insn_new(NOT);
357                         dfw_append_insn(dfw, insn);
358                         break;
359
360                 case TEST_OP_AND:
361                         gencode(dfw, st_arg1);
362
363                         insn = dfvm_insn_new(IF_FALSE_GOTO);
364                         val1 = dfvm_value_new(INSN_NUMBER);
365                         insn->arg1 = val1;
366                         dfw_append_insn(dfw, insn);
367
368                         gencode(dfw, st_arg2);
369                         val1->value.numeric = dfw->next_insn_id;
370                         break;
371
372                 case TEST_OP_OR:
373                         gencode(dfw, st_arg1);
374
375                         insn = dfvm_insn_new(IF_TRUE_GOTO);
376                         val1 = dfvm_value_new(INSN_NUMBER);
377                         insn->arg1 = val1;
378                         dfw_append_insn(dfw, insn);
379
380                         gencode(dfw, st_arg2);
381                         val1->value.numeric = dfw->next_insn_id;
382                         break;
383
384                 case TEST_OP_EQ:
385                         gen_relation(dfw, ANY_EQ, st_arg1, st_arg2);
386                         break;
387
388                 case TEST_OP_NE:
389                         gen_relation(dfw, ANY_NE, st_arg1, st_arg2);
390                         break;
391
392                 case TEST_OP_GT:
393                         gen_relation(dfw, ANY_GT, st_arg1, st_arg2);
394                         break;
395
396                 case TEST_OP_GE:
397                         gen_relation(dfw, ANY_GE, st_arg1, st_arg2);
398                         break;
399
400                 case TEST_OP_LT:
401                         gen_relation(dfw, ANY_LT, st_arg1, st_arg2);
402                         break;
403
404                 case TEST_OP_LE:
405                         gen_relation(dfw, ANY_LE, st_arg1, st_arg2);
406                         break;
407
408                 case TEST_OP_BITWISE_AND:
409                         gen_relation(dfw, ANY_BITWISE_AND, st_arg1, st_arg2);
410                         break;
411
412                 case TEST_OP_CONTAINS:
413                         gen_relation(dfw, ANY_CONTAINS, st_arg1, st_arg2);
414                         break;
415
416                 case TEST_OP_MATCHES:
417                         gen_relation(dfw, ANY_MATCHES, st_arg1, st_arg2);
418                         break;
419         }
420 }
421
422 static void
423 gencode(dfwork_t *dfw, stnode_t *st_node)
424 {
425         const char      *name;
426
427         name = stnode_type_name(st_node);
428
429         switch (stnode_type_id(st_node)) {
430                 case STTYPE_TEST:
431                         gen_test(dfw, st_node);
432                         break;
433                 default:
434                         g_assert_not_reached();
435         }
436 }
437
438
439 void
440 dfw_gencode(dfwork_t *dfw)
441 {
442         dfw->insns = g_ptr_array_new();
443         dfw->loaded_fields = g_hash_table_new(g_direct_hash, g_direct_equal);
444         dfw->interesting_fields = g_hash_table_new(g_direct_hash, g_direct_equal);
445         gencode(dfw, dfw->st_root);
446         dfw_append_insn(dfw, dfvm_insn_new(RETURN));
447 }
448
449
450
451 typedef struct {
452     int i;
453     int *fields;
454 } hash_key_iterator;
455
456 static void
457 get_hash_key(gpointer key, gpointer value _U_, gpointer user_data)
458 {
459     int field_id = GPOINTER_TO_INT(key);
460     hash_key_iterator *hki = user_data;
461
462     hki->fields[hki->i] = field_id;
463     hki->i++;
464 }
465
466 int*
467 dfw_interesting_fields(dfwork_t *dfw, int *caller_num_fields)
468 {
469     int num_fields = g_hash_table_size(dfw->interesting_fields);
470
471     hash_key_iterator hki;
472
473     if (num_fields == 0) {
474         *caller_num_fields = 0;
475         return NULL;
476     }
477
478     hki.fields = g_new(int, num_fields);
479     hki.i = 0;
480
481     g_hash_table_foreach(dfw->interesting_fields, get_hash_key, &hki);
482     *caller_num_fields = num_fields;
483     return hki.fields;
484 }