RPA Toolkit
Fixed a bug in RPAVM where a non special character was treated as special
[rpatk.git] / rpa / rpavm.c
1 #include "rpa/rpavm.h"
2 #include "rpa/rpastatpriv.h"
3 #include "rlib/rutf.h"
4 #include "rlib/rmem.h"
5
6
7 static void rpavm_swi_shift(rvmcpu_t *cpu, rvm_asmins_t *ins)
8 {
9         rpastat_t *stat = (rpastat_t *)cpu->userdata1;
10         rlong top = RVM_CPUREG_GETL(cpu, R_TOP);
11
12         if ((top = rpa_stat_shift(stat, top)) >= 0)
13                 RVM_CPUREG_SETL(cpu, R_TOP, top);
14 }
15
16
17 static void rpavm_swi_matchchr_nan(rvmcpu_t *cpu, rvm_asmins_t *ins)
18 {
19         rpastat_t *stat = (rpastat_t *)cpu->userdata1;
20         rword wc = RVM_CPUREG_GETU(cpu, ins->op1);
21         rword matched = 0;
22
23         if (rpa_stat_matchchr(stat, RVM_CPUREG_GETL(cpu, R_TOP), wc) > 0) {
24                 rpavm_swi_shift(cpu, ins);
25                 matched = 1;
26         }
27         cpu->status = matched ? 0 : RVM_STATUS_N;
28         RVM_CPUREG_SETU(cpu, R0, matched ? matched : (rword)-1);
29 }
30
31
32 static void rpavm_swi_matchchr_opt(rvmcpu_t *cpu, rvm_asmins_t *ins)
33 {
34         rpastat_t *stat = (rpastat_t *)cpu->userdata1;
35         rword wc = RVM_CPUREG_GETU(cpu, ins->op1);
36         rword matched = 0;
37
38         if (rpa_stat_matchchr(stat, RVM_CPUREG_GETL(cpu, R_TOP), wc) > 0) {
39                 rpavm_swi_shift(cpu, ins);
40                 matched = 1;
41         }
42         cpu->status = matched ? 0 : RVM_STATUS_Z;
43         RVM_CPUREG_SETU(cpu, R0, matched);
44 }
45
46
47 static void rpavm_swi_matchchr_mul(rvmcpu_t *cpu, rvm_asmins_t *ins)
48 {
49         rpastat_t *stat = (rpastat_t *)cpu->userdata1;
50         rword wc = RVM_CPUREG_GETU(cpu, ins->op1);
51         rword matched = 0;
52
53         while (rpa_stat_matchchr(stat, RVM_CPUREG_GETL(cpu, R_TOP), wc) > 0) {
54                 rpavm_swi_shift(cpu, ins);
55                 matched += 1;
56         }
57         cpu->status = matched ? 0 : RVM_STATUS_N;
58         RVM_CPUREG_SETU(cpu, R0, matched ? matched : (rword)-1);
59 }
60
61
62 static void rpavm_swi_matchchr_mop(rvmcpu_t *cpu, rvm_asmins_t *ins)
63 {
64         rpastat_t *stat = (rpastat_t *)cpu->userdata1;
65         rword wc = RVM_CPUREG_GETU(cpu, ins->op1);
66         rword matched = 0;
67
68         while (rpa_stat_matchchr(stat, RVM_CPUREG_GETL(cpu, R_TOP), wc) > 0) {
69                 rpavm_swi_shift(cpu, ins);
70                 matched += 1;
71         }
72         cpu->status = matched ? 0 : RVM_STATUS_Z;
73         RVM_CPUREG_SETU(cpu, R0, matched );
74 }
75
76
77 static void rpavm_swi_matchspchr_nan(rvmcpu_t *cpu, rvm_asmins_t *ins)
78 {
79         rpastat_t *stat = (rpastat_t *)cpu->userdata1;
80         rword wc = RVM_CPUREG_GETU(cpu, ins->op1);
81         rword matched = 0;
82
83         if (rpa_stat_matchspchr(stat, RVM_CPUREG_GETL(cpu, R_TOP), wc) > 0) {
84                 rpavm_swi_shift(cpu, ins);
85                 matched = 1;
86         }
87         cpu->status = matched ? 0 : RVM_STATUS_N;
88         RVM_CPUREG_SETU(cpu, R0, matched ? matched : (rword)-1);
89 }
90
91
92 static void rpavm_swi_matchspchr_opt(rvmcpu_t *cpu, rvm_asmins_t *ins)
93 {
94         rpastat_t *stat = (rpastat_t *)cpu->userdata1;
95         rword wc = RVM_CPUREG_GETU(cpu, ins->op1);
96         rword matched = 0;
97
98         if (rpa_stat_matchspchr(stat, RVM_CPUREG_GETL(cpu, R_TOP), wc) > 0) {
99                 rpavm_swi_shift(cpu, ins);
100                 matched = 1;
101         }
102         cpu->status = matched ? 0 : RVM_STATUS_Z;
103         RVM_CPUREG_SETU(cpu, R0, matched);
104
105 }
106
107
108 static void rpavm_swi_matchspchr_mul(rvmcpu_t *cpu, rvm_asmins_t *ins)
109 {
110         rpastat_t *stat = (rpastat_t *)cpu->userdata1;
111         rword wc = RVM_CPUREG_GETU(cpu, ins->op1);
112         rword matched = 0;
113
114         while (rpa_stat_matchspchr(stat, RVM_CPUREG_GETL(cpu, R_TOP), wc) > 0) {
115                 rpavm_swi_shift(cpu, ins);
116                 matched += 1;
117         }
118         cpu->status = matched ? 0 : RVM_STATUS_N;
119         RVM_CPUREG_SETU(cpu, R0, matched ? matched : (rword)-1);
120
121 }
122
123
124 static void rpavm_swi_matchspchr_mop(rvmcpu_t *cpu, rvm_asmins_t *ins)
125 {
126         rpastat_t *stat = (rpastat_t *)cpu->userdata1;
127         rword wc = RVM_CPUREG_GETU(cpu, ins->op1);
128         rword matched = 0;
129
130         while (rpa_stat_matchspchr(stat, RVM_CPUREG_GETL(cpu, R_TOP), wc) > 0) {
131                 rpavm_swi_shift(cpu, ins);
132                 matched += 1;
133         }
134         cpu->status = matched ? 0 : RVM_STATUS_Z;
135         RVM_CPUREG_SETU(cpu, R0, matched );
136 }
137
138
139 static void rpavm_swi_matchrng_peek(rvmcpu_t *cpu, rvm_asmins_t *ins)
140 {
141         rpastat_t *stat = (rpastat_t *)cpu->userdata1;
142         rpair_t pr = RVM_CPUREG_GETPAIR(cpu, ins->op1);
143         rword matched = 0;
144
145         if (rpa_stat_matchrng(stat, RVM_CPUREG_GETL(cpu, R_TOP), pr.p1, pr.p2) <= 0) {
146                 cpu->status = matched ? 0 : RVM_STATUS_N;
147                 RVM_CPUREG_SETU(cpu, R0, matched ? matched : (rword)-1);
148         }
149 }
150
151
152 static void rpavm_swi_matchrng_nan(rvmcpu_t *cpu, rvm_asmins_t *ins)
153 {
154         rpastat_t *stat = (rpastat_t *)cpu->userdata1;
155         rpair_t pr = RVM_CPUREG_GETPAIR(cpu, ins->op1);
156         rword matched = 0;
157
158         if (rpa_stat_matchrng(stat, RVM_CPUREG_GETL(cpu, R_TOP), pr.p1, pr.p2) > 0) {
159                 rpavm_swi_shift(cpu, ins);
160                 matched = 1;
161         }
162         cpu->status = matched ? 0 : RVM_STATUS_N;
163         RVM_CPUREG_SETU(cpu, R0, matched ? matched : (rword)-1);
164 }
165
166
167 static void rpavm_swi_matchrng_opt(rvmcpu_t *cpu, rvm_asmins_t *ins)
168 {
169         rpastat_t *stat = (rpastat_t *)cpu->userdata1;
170         rpair_t pr = RVM_CPUREG_GETPAIR(cpu, ins->op1);
171         rword matched = 0;
172
173         if (rpa_stat_matchrng(stat, RVM_CPUREG_GETL(cpu, R_TOP), pr.p1, pr.p2) > 0) {
174                 rpavm_swi_shift(cpu, ins);
175                 matched = 1;
176         }
177         cpu->status = matched ? 0 : RVM_STATUS_Z;
178         RVM_CPUREG_SETU(cpu, R0, matched);
179 }
180
181
182 static void rpavm_swi_matchrng_mul(rvmcpu_t *cpu, rvm_asmins_t *ins)
183 {
184         rpastat_t *stat = (rpastat_t *)cpu->userdata1;
185         rpair_t pr = RVM_CPUREG_GETPAIR(cpu, ins->op1);
186         rword matched = 0;
187
188         while (rpa_stat_matchrng(stat, RVM_CPUREG_GETL(cpu, R_TOP), pr.p1, pr.p2) > 0) {
189                 rpavm_swi_shift(cpu, ins);
190                 matched += 1;
191         }
192         cpu->status = matched ? 0 : RVM_STATUS_N;
193         RVM_CPUREG_SETU(cpu, R0, matched ? matched : (rword)-1);
194 }
195
196
197 static void rpavm_swi_matchrng_mop(rvmcpu_t *cpu, rvm_asmins_t *ins)
198 {
199         rpastat_t *stat = (rpastat_t *)cpu->userdata1;
200         rpair_t pr = RVM_CPUREG_GETPAIR(cpu, ins->op1);
201         rword matched = 0;
202
203         while (rpa_stat_matchrng(stat, RVM_CPUREG_GETL(cpu, R_TOP), pr.p1, pr.p2) > 0) {
204                 rpavm_swi_shift(cpu, ins);
205                 matched += 1;
206         }
207         cpu->status = matched ? 0 : RVM_STATUS_Z;
208         RVM_CPUREG_SETU(cpu, R0, matched );
209 }
210
211
212 static void rpavm_swi_emittail(rvmcpu_t *cpu, rvm_asmins_t *ins)
213 {
214         rpastat_t *stat = (rpastat_t *)cpu->userdata1;
215         rlong index = RVM_CPUREG_GETL(cpu, R_REC);
216
217         if (stat->records)
218                 r_array_setlength(stat->records, index + 1);
219 }
220
221
222 static void rpavm_swi_abort(rvmcpu_t *cpu, rvm_asmins_t *ins)
223 {
224         rpa_ruledata_t *ruledata = RVM_CPUREG_GETP(cpu, ins->op1);
225         rstr_t name = {(rchar*)ruledata + ruledata->name, ruledata->namesize};
226         rpastat_t *stat = (rpastat_t *)cpu->userdata1;
227         rlong index = RVM_CPUREG_GETL(cpu, R_REC);
228         rword tp = RVM_CPUREG_GETU(cpu, ins->op2);
229
230
231         if (stat->records)
232                 r_array_setlength(stat->records, index + 1);
233         RPA_STAT_SETERROR_CODE(stat, RPA_E_RULEABORT);
234         RPA_STAT_SETERRINFO_RULEUID(stat, ruledata->ruleuid);
235         if (name.str) {
236                 RPA_STAT_SETERRINFO_NAME(stat, name.str, name.size);
237         }
238         if (stat->instack[tp].input) {
239                 RPA_STAT_SETERRINFO_OFFSET(stat, stat->instack[tp].input - stat->start);
240         }
241         rvm_cpu_abort(cpu);
242 }
243
244
245 static void rpavm_swi_emitstart(rvmcpu_t *cpu, rvm_asmins_t *ins)
246 {
247         rpa_ruledata_t *ruledata = RVM_CPUREG_GETP(cpu, ins->op1);
248         rpastat_t *stat = (rpastat_t *)cpu->userdata1;
249         rparecord_t *rec;
250         rlong index = RVM_CPUREG_GETL(cpu, R_REC);
251         rword tp = RVM_CPUREG_GETU(cpu, ins->op2);
252         rstr_t name = {(rchar*)ruledata + ruledata->name, ruledata->namesize};
253
254         if (stat->debug)
255                 r_printf("%ld: %s, %s, tp = %ld\n", RVM_CPUREG_GETU(cpu, FP), "START", name.str, tp);
256         if (!stat->records || !(ruledata->flags & RPA_RFLAG_EMITRECORD))
257                 return;
258         index = r_array_replace(stat->records, index + 1, NULL);
259
260         /*
261          * Important: get the pointer to crec after modifying the array, because if
262          * it gets reallocated the pointer will be invalid.
263          */
264         RVM_CPUREG_SETL(cpu, R_REC, index);
265         rec = (rparecord_t *)r_array_slot(stat->records, index);
266         rec->rule = name.str;
267         rec->top = tp;
268         rec->ruleid = ruledata->ruleid;
269         rec->ruleuid = ruledata->ruleuid;
270         rec->type = RPA_RECORD_START;
271         rec->input = stat->instack[tp].input;
272         rec->inputoff = stat->instack[tp].input - stat->start;
273         rec->inputsiz = 0;
274 }
275
276
277
278 static void rpavm_swi_emitend(rvmcpu_t *cpu, rvm_asmins_t *ins)
279 {
280         rpa_ruledata_t *ruledata = RVM_CPUREG_GETP(cpu, ins->op1);
281         rpastat_t *stat = (rpastat_t *)cpu->userdata1;
282         rparecord_t *rec, *startrec;
283         rlong startindex = RVM_CPUREG_GETL(cpu, R1) + 1;
284         rlong index = RVM_CPUREG_GETL(cpu, R_REC);
285         rword tp = RVM_CPUREG_GETU(cpu, ins->op2);
286         rword tplen = RVM_CPUREG_GETU(cpu, ins->op3);
287         rstr_t name = {(rchar*)ruledata + ruledata->name, ruledata->namesize};
288
289         if (stat->debug)
290                 r_printf("%ld: %s, %s, tp = %ld, tplen = %ld\n", RVM_CPUREG_GETU(cpu, FP), "END ", name.str, tp, tplen);
291         if (!stat->records || !(ruledata->flags & RPA_RFLAG_EMITRECORD))
292                 return;
293
294         index = r_array_replace(stat->records, index + 1, NULL);
295         RVM_CPUREG_SETL(cpu, R_REC, index);
296         rec = (rparecord_t *)r_array_slot(stat->records, index);
297         startrec = (rparecord_t *)r_array_slot(stat->records, startindex);
298         rec->rule = name.str;
299         rec->top = tp;
300         rec->size = tplen;
301         rec->type = RPA_RECORD_END;
302         rec->ruleid = ruledata->ruleid;
303         rec->ruleuid = ruledata->ruleuid;
304         rec->input = stat->instack[tp].input;
305         rec->inputsiz = stat->instack[tp + tplen].input - stat->instack[tp].input;
306         rec->inputoff = stat->instack[tp].input - stat->start;
307         startrec->size = tplen;
308         startrec->inputsiz = rec->inputsiz;
309 }
310
311
312
313
314 static void rpavm_swi_prninfo(rvmcpu_t *cpu, rvm_asmins_t *ins)
315 {
316         rpastat_t *stat = (rpastat_t *)cpu->userdata1;
317         rpa_ruledata_t *ruledata = RVM_CPUREG_GETP(cpu, ins->op1);
318         rstr_t name = {"unknown", 7};
319         if (!stat->debug)
320                 return;
321         if (ruledata) {
322                 name.str = (rchar*)ruledata + ruledata->name;
323                 name.size = ruledata->namesize;
324         }
325
326         r_printf("%s: ", name.str);
327         rvm_cpu_dumpregs(cpu, ins);
328 }
329
330
331 static void rpavm_swi_setcache(rvmcpu_t *cpu, rvm_asmins_t *ins)
332 {
333         rpastat_t *stat = (rpastat_t *)cpu->userdata1;
334         rlong r0 = RVM_CPUREG_GETL(cpu, R0);
335         rlong ruleid = RVM_CPUREG_GETL(cpu, ins->op1);
336         rlong prevrec = RVM_CPUREG_GETL(cpu, ins->op2);
337         rlong endrec = RVM_CPUREG_GETL(cpu, ins->op3);
338         rlong top = RVM_CPUREG_GETL(cpu, R_OTP);
339         rlong startrec = 0;
340
341         if (r0 > 0 && prevrec != endrec) {
342                 startrec = prevrec + 1;
343                 rpa_cache_set(stat->cache, top, ruleid, r0, stat->records, startrec, endrec - prevrec);
344         } else {
345                 rpa_cache_set(stat->cache, top, ruleid, r0, stat->records, 0, 0);
346         }
347 }
348
349
350 static void rpavm_swi_checkcache(rvmcpu_t *cpu, rvm_asmins_t *ins)
351 {
352         rpastat_t *stat = (rpastat_t *)cpu->userdata1;
353         rpacachedentry_t *entry;
354         rlong ruleid = RVM_CPUREG_GETL(cpu, ins->op1);
355         rlong top = RVM_CPUREG_GETL(cpu, ins->op2);
356         rlong r0 = 0;
357         entry = rpa_cache_lookup(stat->cache, top, ruleid);
358         if (entry) {
359                 r0 = entry->ret;
360
361                 if (r0 > 0) {
362                         if (entry->recsize) {
363                                 long i;
364                                 if (stat->records) {
365                                         r_array_setlength(stat->records, RVM_CPUREG_GETL(cpu, R_REC) + 1);
366                                         for (i = 0; i < r_array_length(entry->records); i++) {
367                                                 r_array_add(stat->records, r_array_slot(entry->records, i));
368                                         }
369                                 }
370                                 RVM_CPUREG_SETL(cpu, R_REC, r_array_length(stat->records) - 1);
371                         }
372                         top += r0;
373                         RVM_CPUREG_SETU(cpu, R_TOP, top);
374                 }
375         }
376
377         RVM_STATUS_CLRALL(cpu);
378         RVM_CPUREG_SETU(cpu, R0, r0);
379         RVM_STATUS_UPDATE(cpu, RVM_STATUS_Z, !r0);
380         if (r0 < 0 && entry) {
381                 RVM_STATUS_UPDATE(cpu, RVM_STATUS_N, (r0 < 0));
382 //              r_printf("Hit the cache for: %ld, r0 = %ld\n", entry->ruleid, entry->ret);
383         }
384 }
385
386
387 static rvm_switable_t rpavm_swi_table[] = {
388                 {"RPA_MATCHCHR_NAN", rpavm_swi_matchchr_nan},
389                 {"RPA_MATCHCHR_OPT", rpavm_swi_matchchr_opt},
390                 {"RPA_MATCHCHR_MUL", rpavm_swi_matchchr_mul},
391                 {"RPA_MATCHCHR_MOP", rpavm_swi_matchchr_mop},
392                 {"RPA_MATCHRNG_NAN", rpavm_swi_matchrng_nan},
393                 {"RPA_MATCHRNG_OPT", rpavm_swi_matchrng_opt},
394                 {"RPA_MATCHRNG_MUL", rpavm_swi_matchrng_mul},
395                 {"RPA_MATCHRNG_MOP", rpavm_swi_matchrng_mop},
396                 {"RPA_MATCHRNG_PEEK", rpavm_swi_matchrng_peek},
397                 {"RPA_MATCHSPCHR_NAN", rpavm_swi_matchspchr_nan},
398                 {"RPA_MATCHSPCHR_OPT", rpavm_swi_matchspchr_opt},
399                 {"RPA_MATCHSPCHR_MUL", rpavm_swi_matchspchr_mul},
400                 {"RPA_MATCHSPCHR_MOP", rpavm_swi_matchspchr_mop},
401                 {"RPA_SHIFT", rpavm_swi_shift},
402                 {"RPA_SETCACHE", rpavm_swi_setcache},
403                 {"RPA_CHECKCACHE", rpavm_swi_checkcache},
404                 {"RPA_EMITSTART", rpavm_swi_emitstart},
405                 {"RPA_EMITEND", rpavm_swi_emitend},
406                 {"RPA_EMITTAIL", rpavm_swi_emittail},
407                 {"RPA_ABORT", rpavm_swi_abort},
408                 {"RPA_PRNINFO", rpavm_swi_prninfo},
409                 {NULL, NULL},
410 };
411
412
413 rvmcpu_t *rpavm_cpu_create(rulong stacksize)
414 {
415         rvmcpu_t *cpu = rvm_cpu_create(stacksize);
416         rinteger tableid = rvm_cpu_addswitable(cpu, "rpavm_swi_table", rpavm_swi_table);
417
418         if (tableid != RPAVM_SWI_TABLEID) {
419                 rpavm_cpu_destroy(cpu);
420                 return NULL;
421         }
422         return cpu;
423 }
424
425
426 void rpavm_cpu_destroy(rvmcpu_t * cpu)
427 {
428         rvm_cpu_destroy(cpu);
429 }
430
431