1 /*
2  * Copyright (c) 2015-2018, Intel Corporation
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions are met:
6  *
7  *  * Redistributions of source code must retain the above copyright notice,
8  *    this list of conditions and the following disclaimer.
9  *  * Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *  * Neither the name of Intel Corporation nor the names of its contributors
13  *    may be used to endorse or promote products derived from this software
14  *    without specific prior written permission.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
20  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26  * POSSIBILITY OF SUCH DAMAGE.
27  */
28 
29 /** \file
30  * \brief Report structure used to manage data associated with a report at
31  * compile time.
32  */
33 
34 #ifndef UTIL_REPORT_H
35 #define UTIL_REPORT_H
36 
37 #include "ue2common.h"
38 #include "util/exhaust.h" // for INVALID_EKEY
39 #include "util/logical.h" // for INVALID_LKEY
40 #include "util/hash.h"
41 #include "util/order_check.h"
42 
43 #include <cassert>
44 
45 namespace ue2 {
46 
47 class ReportManager;
48 
49 enum ReportType {
50     EXTERNAL_CALLBACK,
51     EXTERNAL_CALLBACK_SOM_REL,
52     INTERNAL_SOM_LOC_SET,
53     INTERNAL_SOM_LOC_SET_IF_UNSET,
54     INTERNAL_SOM_LOC_SET_IF_WRITABLE,
55     INTERNAL_SOM_LOC_SET_SOM_REV_NFA,
56     INTERNAL_SOM_LOC_SET_SOM_REV_NFA_IF_UNSET,
57     INTERNAL_SOM_LOC_SET_SOM_REV_NFA_IF_WRITABLE,
58     INTERNAL_SOM_LOC_COPY,
59     INTERNAL_SOM_LOC_COPY_IF_WRITABLE,
60     INTERNAL_SOM_LOC_MAKE_WRITABLE,
61     EXTERNAL_CALLBACK_SOM_STORED,
62     EXTERNAL_CALLBACK_SOM_ABS,
63     EXTERNAL_CALLBACK_SOM_REV_NFA,
64     INTERNAL_SOM_LOC_SET_FROM,
65     INTERNAL_SOM_LOC_SET_FROM_IF_WRITABLE,
66     INTERNAL_ROSE_CHAIN,
67     EXTERNAL_CALLBACK_SOM_PASS
68 };
69 
70 /**
71  * \brief All the data we use for handling a match.
72  *
73  * Includes extparam constraints and bounds, exhaustion/dedupe keys, offset
74  * adjustment and SOM information.
75  *
76  * The data in this structure eventually becomes a list of Rose programs
77  * instructions.
78  */
79 struct Report {
ReportReport80     Report(ReportType type_in, u32 onmatch_in)
81         : type(type_in), onmatch(onmatch_in) {}
82 
83     /** \brief True if this report has bounds from extended parameters, i.e.
84      * min offset, max offset, min length. */
hasBoundsReport85     bool hasBounds() const {
86         return minOffset > 0 || maxOffset < MAX_OFFSET || minLength > 0;
87     }
88 
89     /** \brief Type of this report. */
90     ReportType type;
91 
92     /** \brief use SOM for minLength, but don't report it to user callback. */
93     bool quashSom = false;
94 
95     /** \brief min offset in the stream at which this report can match. */
96     u64a minOffset = 0;
97 
98     /** \brief max offset in the stream at which this report can match. */
99     u64a maxOffset = MAX_OFFSET;
100 
101     /** \brief min match length (start of match to current offset) */
102     u64a minLength = 0;
103 
104     /** \brief Exhaustion key.
105      *
106      * If exhaustible, the ekey to check before reporting a match.
107      * Additionally after reporting a match the ekey will be set. If not
108      * exhaustible, this will be INVALID_EKEY. */
109     u32 ekey = INVALID_EKEY;
110 
111     /** \brief Logical Combination key in each combination.
112      *
113      * If in Logical Combination, the lkey to check before reporting a match.
114      * Additionally before checking the lkey will be set. If not
115      * in Logical Combination, this will be INVALID_LKEY. */
116     u32 lkey = INVALID_LKEY;
117 
118     /** \brief Quiet flag for expressions in any logical combination. */
119     bool quiet = false;
120 
121     /** \brief Adjustment to add to the match offset when we report a match.
122      *
123      * This is usually used for reports attached to states that form part of a
124      * zero-width assertion, like '$'. */
125     s32 offsetAdjust = 0;
126 
127     /** \brief Match report ID, for external reports.
128      *
129      * - external callback -> external report id
130      * - internal_som_* -> som loc to modify
131      * - INTERNAL_ROSE_CHAIN -> top event to push on
132      * - otherwise -> target subnfa */
133     u32 onmatch;
134 
135     /** \brief Index of the reverse nfa.
136      *
137      * Used by EXTERNAL_CALLBACK_SOM_REV_NFA and
138      * INTERNAL_SOM_LOC_SET_SOM_REV_NFA*.
139      */
140     u32 revNfaIndex = 0;
141 
142     /** \brief SOM distance value, use varies according to type.
143      *
144      *  - for EXTERNAL_CALLBACK_SOM_REL, from-offset is this many bytes
145      *    before the to-offset.
146      *  - for EXTERNAL_CALLBACK_SOM_ABS, set from-offset to this value.
147      *  - for INTERNAL_SOM_LOC_COPY*, som location read_from.
148      */
149     u64a somDistance = 0;
150 
151     /** \brief Number of bytes behind us that we are allowed to squash
152      * identical top events on the queue.
153      *
154      * Used by INTERNAL_ROSE_CHAIN.
155      */
156     u64a topSquashDistance = 0;
157 };
158 
159 static inline
isExternalReport(const Report & r)160 bool isExternalReport(const Report &r) {
161     switch (r.type) {
162     case INTERNAL_SOM_LOC_SET:
163     case INTERNAL_SOM_LOC_SET_IF_UNSET:
164     case INTERNAL_SOM_LOC_SET_IF_WRITABLE:
165     case INTERNAL_SOM_LOC_SET_SOM_REV_NFA:
166     case INTERNAL_SOM_LOC_SET_SOM_REV_NFA_IF_UNSET:
167     case INTERNAL_SOM_LOC_SET_SOM_REV_NFA_IF_WRITABLE:
168     case INTERNAL_SOM_LOC_COPY:
169     case INTERNAL_SOM_LOC_COPY_IF_WRITABLE:
170     case INTERNAL_SOM_LOC_MAKE_WRITABLE:
171     case INTERNAL_SOM_LOC_SET_FROM:
172     case INTERNAL_SOM_LOC_SET_FROM_IF_WRITABLE:
173     case INTERNAL_ROSE_CHAIN:
174         return false;
175     case EXTERNAL_CALLBACK:
176     case EXTERNAL_CALLBACK_SOM_REL:
177     case EXTERNAL_CALLBACK_SOM_STORED:
178     case EXTERNAL_CALLBACK_SOM_ABS:
179     case EXTERNAL_CALLBACK_SOM_REV_NFA:
180     case EXTERNAL_CALLBACK_SOM_PASS:
181         return true;
182     default:
183         break; // fall through
184     }
185     assert(0); // unknown?
186     return true;
187 }
188 
189 static inline
isExternalSomReport(const Report & r)190 bool isExternalSomReport(const Report &r) {
191     return r.type != EXTERNAL_CALLBACK && isExternalReport(r);
192 }
193 
194 static inline
195 bool operator<(const Report &a, const Report &b) {
196     ORDER_CHECK(type);
197     ORDER_CHECK(quashSom);
198     ORDER_CHECK(ekey);
199     ORDER_CHECK(offsetAdjust);
200     ORDER_CHECK(onmatch);
201     ORDER_CHECK(minOffset);
202     ORDER_CHECK(maxOffset);
203     ORDER_CHECK(minLength);
204     ORDER_CHECK(somDistance);
205     ORDER_CHECK(revNfaIndex);
206     ORDER_CHECK(topSquashDistance);
207     return false;
208 }
209 
210 inline
211 bool operator==(const Report &a, const Report &b) {
212     return a.type == b.type && a.quashSom == b.quashSom &&
213            a.minOffset == b.minOffset && a.maxOffset == b.maxOffset &&
214            a.minLength == b.minLength && a.ekey == b.ekey &&
215            a.offsetAdjust == b.offsetAdjust && a.onmatch == b.onmatch &&
216            a.revNfaIndex == b.revNfaIndex && a.somDistance == b.somDistance &&
217            a.topSquashDistance == b.topSquashDistance;
218 }
219 
220 static inline
makeECallback(u32 report,s32 offsetAdjust,u32 ekey,bool quiet)221 Report makeECallback(u32 report, s32 offsetAdjust, u32 ekey, bool quiet) {
222     Report ir(EXTERNAL_CALLBACK, report);
223     ir.offsetAdjust = offsetAdjust;
224     ir.ekey = ekey;
225     ir.quiet = (u8)quiet;
226     return ir;
227 }
228 
229 static inline
makeCallback(u32 report,s32 offsetAdjust)230 Report makeCallback(u32 report, s32 offsetAdjust) {
231     return makeECallback(report, offsetAdjust, INVALID_EKEY, false);
232 }
233 
234 static inline
makeSomRelativeCallback(u32 report,s32 offsetAdjust,u64a distance)235 Report makeSomRelativeCallback(u32 report, s32 offsetAdjust, u64a distance) {
236     Report ir(EXTERNAL_CALLBACK_SOM_REL, report);
237     ir.offsetAdjust = offsetAdjust;
238     ir.ekey = INVALID_EKEY;
239     ir.somDistance = distance;
240     return ir;
241 }
242 
243 static inline
makeMpvTrigger(u32 event,u64a squashDistance)244 Report makeMpvTrigger(u32 event, u64a squashDistance) {
245     Report ir(INTERNAL_ROSE_CHAIN, event);
246     ir.ekey = INVALID_EKEY;
247     ir.topSquashDistance = squashDistance;
248     return ir;
249 }
250 
251 /** simple exhaustible: exhaustible and if the first attempted match does not
252  * succeed, no later matches will succeed either  */
253 static inline
isSimpleExhaustible(const Report & ir)254 bool isSimpleExhaustible(const Report &ir) {
255     if (ir.ekey == INVALID_EKEY) {
256         return false;
257     }
258 
259     if (ir.hasBounds() && (ir.minOffset || ir.minLength)) {
260         return false;
261     }
262 
263     if (!isExternalReport(ir)) {
264         return false;
265     }
266 
267     return true;
268 }
269 
270 } // namespace ue2
271 
272 namespace std {
273 
274 template<>
275 struct hash<ue2::Report> {
276     std::size_t operator()(const ue2::Report &r) const {
277         return ue2::hash_all(r.type, r.quashSom, r.minOffset, r.maxOffset,
278                              r.minLength, r.ekey, r.offsetAdjust, r.onmatch,
279                              r.revNfaIndex, r.somDistance, r.topSquashDistance);
280     }
281 };
282 
283 } // namespace std
284 
285 #endif // UTIL_REPORT_H
286