1 | /* |
2 | * Copyright (c) 2016-2017, 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 | #ifndef ROSE_BUILD_ENGINE_BLOB_H |
30 | #define ROSE_BUILD_ENGINE_BLOB_H |
31 | |
32 | #include "rose_internal.h" |
33 | |
34 | #include "ue2common.h" |
35 | #include "util/alloc.h" |
36 | #include "util/bytecode_ptr.h" |
37 | #include "util/charreach.h" |
38 | #include "util/container.h" |
39 | #include "util/hash.h" |
40 | #include "util/multibit_build.h" |
41 | #include "util/noncopyable.h" |
42 | #include "util/verify_types.h" |
43 | #include "util/unordered.h" |
44 | |
45 | #include <type_traits> |
46 | #include <vector> |
47 | |
48 | namespace ue2 { |
49 | |
50 | class RoseEngineBlob; |
51 | |
52 | struct lookaround_info : noncopyable { |
53 | u32 get_offset_of(const std::vector<std::vector<CharReach>> &look, |
54 | RoseEngineBlob &blob); |
55 | u32 get_offset_of(const std::vector<CharReach> &reach, |
56 | RoseEngineBlob &blob); |
57 | u32 get_offset_of(const std::vector<s8> &look, RoseEngineBlob &blob); |
58 | |
59 | private: |
60 | using Path = std::vector<CharReach>; |
61 | ue2_unordered_map<std::vector<Path>, u32> multi_cache; |
62 | ue2_unordered_map<std::vector<s8>, u32> lcache; |
63 | ue2_unordered_map<Path, u32> rcache; |
64 | }; |
65 | |
66 | class RoseEngineBlob : noncopyable { |
67 | public: |
68 | /** \brief Base offset of engine_blob in the Rose engine bytecode. */ |
69 | static constexpr u32 base_offset = ROUNDUP_CL(sizeof(RoseEngine)); |
70 | |
71 | bool empty() const { |
72 | return blob.empty(); |
73 | } |
74 | |
75 | size_t size() const { |
76 | return blob.size(); |
77 | } |
78 | |
79 | u32 add(const void *a, const size_t len, const size_t align) { |
80 | pad(align); |
81 | |
82 | size_t rv = base_offset + blob.size(); |
83 | assert(rv >= base_offset); |
84 | DEBUG_PRINTF("write %zu bytes at offset %zu\n" , len, rv); |
85 | |
86 | assert(ISALIGNED_N(blob.size(), align)); |
87 | |
88 | blob.resize(blob.size() + len); |
89 | memcpy(&blob.back() - len + 1, a, len); |
90 | |
91 | return verify_u32(rv); |
92 | } |
93 | |
94 | template<typename T> |
95 | u32 add(const bytecode_ptr<T> &a) { |
96 | return add(a.get(), a.size(), a.align()); |
97 | } |
98 | |
99 | template<typename T> |
100 | u32 add(const T &a) { |
101 | static_assert(std::is_pod<T>::value, "should be pod" ); |
102 | return add(&a, sizeof(a), alignof(T)); |
103 | } |
104 | |
105 | template<typename T> |
106 | u32 add(const T &a, const size_t len) { |
107 | static_assert(std::is_pod<T>::value, "should be pod" ); |
108 | return add(&a, len, alignof(T)); |
109 | } |
110 | |
111 | template<typename Iter> |
112 | u32 add(Iter b, const Iter &e) { |
113 | using value_type = typename std::iterator_traits<Iter>::value_type; |
114 | static_assert(std::is_pod<value_type>::value, "should be pod" ); |
115 | |
116 | if (b == e) { |
117 | return 0; |
118 | } |
119 | |
120 | u32 offset = add(*b); |
121 | for (++b; b != e; ++b) { |
122 | add(*b); |
123 | } |
124 | |
125 | return offset; |
126 | } |
127 | |
128 | template<typename Range> |
129 | u32 add_range(const Range &range) { |
130 | return add(begin(range), end(range)); |
131 | } |
132 | |
133 | u32 add_iterator(const std::vector<mmbit_sparse_iter> &iter) { |
134 | auto cache_it = cached_iters.find(iter); |
135 | if (cache_it != cached_iters.end()) { |
136 | u32 offset = cache_it->second; |
137 | DEBUG_PRINTF("cache hit for iter at %u\n" , offset); |
138 | return offset; |
139 | } |
140 | |
141 | u32 offset = add(iter.begin(), iter.end()); |
142 | cached_iters.emplace(iter, offset); |
143 | return offset; |
144 | } |
145 | |
146 | void write_bytes(RoseEngine *engine) { |
147 | copy_bytes((char *)engine + base_offset, blob); |
148 | } |
149 | |
150 | lookaround_info lookaround_cache; |
151 | |
152 | private: |
153 | void pad(size_t align) { |
154 | assert(ISALIGNED_N(base_offset, align)); |
155 | size_t s = blob.size(); |
156 | |
157 | if (ISALIGNED_N(s, align)) { |
158 | return; |
159 | } |
160 | |
161 | blob.resize(s + align - s % align); |
162 | } |
163 | |
164 | /** \brief Cache of previously-written sparse iterators. */ |
165 | ue2_unordered_map<std::vector<mmbit_sparse_iter>, u32> cached_iters; |
166 | |
167 | /** |
168 | * \brief Contents of the Rose bytecode immediately following the |
169 | * RoseEngine. |
170 | */ |
171 | std::vector<char, AlignedAllocator<char, 64>> blob; |
172 | }; |
173 | |
174 | } // namespace ue2 |
175 | |
176 | #endif // ROSE_BUILD_ENGINE_BLOB_H |
177 | |