Commit | Line | Data |
---|---|---|
0ae3cfc6 SM |
1 | /* |
2 | * Copyright 2020 EfficiOS, Inc. | |
3 | * | |
c922647d | 4 | * SPDX-License-Identifier: LGPL-2.1-only |
0ae3cfc6 SM |
5 | * |
6 | */ | |
7 | ||
c9e313bc | 8 | #include "bytecode.hpp" |
28ab034a | 9 | #include "common/align.hpp" |
0ae3cfc6 | 10 | |
d5552a4c | 11 | #include <algorithm> |
28ab034a | 12 | #include <errno.h> |
0ae3cfc6 SM |
13 | |
14 | #define INIT_ALLOC_SIZE 4 | |
15 | ||
28ab034a | 16 | static inline int get_count_order(unsigned int count) |
0ae3cfc6 SM |
17 | { |
18 | int order; | |
19 | ||
20 | order = lttng_fls(count) - 1; | |
21 | if (count & (count - 1)) | |
22 | order++; | |
23 | return order; | |
24 | } | |
25 | ||
2b00d462 | 26 | int bytecode_init(struct lttng_bytecode_alloc **fb) |
0ae3cfc6 SM |
27 | { |
28 | uint32_t alloc_len; | |
29 | ||
2b00d462 | 30 | alloc_len = sizeof(struct lttng_bytecode_alloc) + INIT_ALLOC_SIZE; |
d5552a4c | 31 | *fb = (lttng_bytecode_alloc *) calloc(alloc_len, 1); |
0ae3cfc6 SM |
32 | if (!*fb) { |
33 | return -ENOMEM; | |
34 | } else { | |
35 | (*fb)->alloc_len = alloc_len; | |
36 | return 0; | |
37 | } | |
38 | } | |
39 | ||
28ab034a | 40 | static int32_t bytecode_reserve(struct lttng_bytecode_alloc **fb, uint32_t align, uint32_t len) |
0ae3cfc6 SM |
41 | { |
42 | int32_t ret; | |
07c4863f JG |
43 | const uint32_t padding = lttng_offset_align((*fb)->b.len, align); |
44 | const uint32_t new_len = (*fb)->b.len + padding + len; | |
2b00d462 | 45 | uint32_t new_alloc_len = sizeof(struct lttng_bytecode_alloc) + new_len; |
07c4863f | 46 | const uint32_t old_alloc_len = (*fb)->alloc_len; |
0ae3cfc6 SM |
47 | |
48 | if (new_len > LTTNG_FILTER_MAX_LEN) | |
49 | return -EINVAL; | |
50 | ||
51 | if (new_alloc_len > old_alloc_len) { | |
2b00d462 | 52 | struct lttng_bytecode_alloc *newptr; |
0ae3cfc6 | 53 | |
28ab034a | 54 | new_alloc_len = std::max(1U << get_count_order(new_alloc_len), old_alloc_len << 1); |
d5552a4c | 55 | newptr = (lttng_bytecode_alloc *) realloc(*fb, new_alloc_len); |
0ae3cfc6 SM |
56 | if (!newptr) |
57 | return -ENOMEM; | |
58 | *fb = newptr; | |
59 | /* We zero directly the memory from start of allocation. */ | |
60 | memset(&((char *) *fb)[old_alloc_len], 0, new_alloc_len - old_alloc_len); | |
61 | (*fb)->alloc_len = new_alloc_len; | |
62 | } | |
63 | (*fb)->b.len += padding; | |
64 | ret = (*fb)->b.len; | |
65 | (*fb)->b.len += len; | |
66 | return ret; | |
67 | } | |
68 | ||
28ab034a | 69 | int bytecode_push(struct lttng_bytecode_alloc **fb, const void *data, uint32_t align, uint32_t len) |
0ae3cfc6 SM |
70 | { |
71 | int32_t offset; | |
72 | ||
73 | offset = bytecode_reserve(fb, align, len); | |
74 | if (offset < 0) | |
75 | return offset; | |
76 | memcpy(&(*fb)->b.data[offset], data, len); | |
77 | return 0; | |
78 | } | |
79 | ||
2b00d462 | 80 | int bytecode_push_logical(struct lttng_bytecode_alloc **fb, |
28ab034a JG |
81 | struct logical_op *data, |
82 | uint32_t align, | |
83 | uint32_t len, | |
84 | uint16_t *skip_offset) | |
0ae3cfc6 SM |
85 | { |
86 | int32_t offset; | |
87 | ||
88 | offset = bytecode_reserve(fb, align, len); | |
89 | if (offset < 0) | |
90 | return offset; | |
91 | memcpy(&(*fb)->b.data[offset], data, len); | |
28ab034a JG |
92 | *skip_offset = (char *) &((struct logical_op *) &(*fb)->b.data[offset])->skip_offset - |
93 | (char *) &(*fb)->b.data[0]; | |
0ae3cfc6 SM |
94 | return 0; |
95 | } | |
763f0d4c | 96 | |
6afbab01 SM |
97 | int bytecode_push_get_payload_root(struct lttng_bytecode_alloc **bytecode) |
98 | { | |
99 | int ret; | |
100 | struct load_op *insn; | |
101 | const uint32_t insn_len = sizeof(struct load_op); | |
102 | ||
d5552a4c | 103 | insn = (load_op *) calloc(insn_len, 1); |
6afbab01 SM |
104 | if (!insn) { |
105 | ret = -ENOMEM; | |
106 | goto end; | |
107 | } | |
108 | ||
109 | insn->op = BYTECODE_OP_GET_PAYLOAD_ROOT; | |
110 | ret = bytecode_push(bytecode, insn, 1, insn_len); | |
111 | free(insn); | |
112 | end: | |
113 | return ret; | |
114 | } | |
115 | ||
6afbab01 SM |
116 | int bytecode_push_get_context_root(struct lttng_bytecode_alloc **bytecode) |
117 | { | |
118 | int ret; | |
119 | struct load_op *insn; | |
120 | const uint32_t insn_len = sizeof(struct load_op); | |
121 | ||
d5552a4c | 122 | insn = (load_op *) calloc(insn_len, 1); |
6afbab01 SM |
123 | if (!insn) { |
124 | ret = -ENOMEM; | |
125 | goto end; | |
126 | } | |
127 | ||
128 | insn->op = BYTECODE_OP_GET_CONTEXT_ROOT; | |
129 | ret = bytecode_push(bytecode, insn, 1, insn_len); | |
130 | free(insn); | |
131 | end: | |
132 | return ret; | |
133 | } | |
134 | ||
6afbab01 SM |
135 | int bytecode_push_get_app_context_root(struct lttng_bytecode_alloc **bytecode) |
136 | { | |
137 | int ret; | |
138 | struct load_op *insn; | |
139 | const uint32_t insn_len = sizeof(struct load_op); | |
140 | ||
d5552a4c | 141 | insn = (load_op *) calloc(insn_len, 1); |
6afbab01 SM |
142 | if (!insn) { |
143 | ret = -ENOMEM; | |
144 | goto end; | |
145 | } | |
146 | ||
147 | insn->op = BYTECODE_OP_GET_APP_CONTEXT_ROOT; | |
148 | ret = bytecode_push(bytecode, insn, 1, insn_len); | |
149 | free(insn); | |
150 | end: | |
151 | return ret; | |
152 | } | |
153 | ||
28ab034a | 154 | int bytecode_push_get_index_u64(struct lttng_bytecode_alloc **bytecode, uint64_t index) |
6afbab01 SM |
155 | { |
156 | int ret; | |
157 | struct load_op *insn; | |
158 | struct get_index_u64 index_op_data; | |
28ab034a | 159 | const uint32_t insn_len = sizeof(struct load_op) + sizeof(struct get_index_u64); |
6afbab01 | 160 | |
d5552a4c | 161 | insn = (load_op *) calloc(insn_len, 1); |
6afbab01 SM |
162 | if (!insn) { |
163 | ret = -ENOMEM; | |
164 | goto end; | |
165 | } | |
166 | ||
167 | insn->op = BYTECODE_OP_GET_INDEX_U64; | |
168 | index_op_data.index = index; | |
169 | memcpy(insn->data, &index_op_data, sizeof(index)); | |
170 | ret = bytecode_push(bytecode, insn, 1, insn_len); | |
171 | ||
172 | free(insn); | |
173 | end: | |
174 | return ret; | |
175 | } | |
176 | ||
6afbab01 | 177 | int bytecode_push_get_symbol(struct lttng_bytecode_alloc **bytecode, |
28ab034a JG |
178 | struct lttng_bytecode_alloc **bytecode_reloc, |
179 | const char *symbol) | |
6afbab01 SM |
180 | { |
181 | int ret; | |
182 | struct load_op *insn; | |
183 | struct get_symbol symbol_offset; | |
184 | uint32_t reloc_offset_u32; | |
185 | uint16_t reloc_offset; | |
186 | uint32_t bytecode_reloc_offset_u32; | |
28ab034a | 187 | const uint32_t insn_len = sizeof(struct load_op) + sizeof(struct get_symbol); |
6afbab01 | 188 | |
d5552a4c | 189 | insn = (load_op *) calloc(insn_len, 1); |
6afbab01 SM |
190 | if (!insn) { |
191 | ret = -ENOMEM; | |
192 | goto end; | |
193 | } | |
194 | ||
195 | insn->op = BYTECODE_OP_GET_SYMBOL; | |
196 | ||
197 | /* | |
198 | * Get offset in the reloc portion at which the symbol name | |
199 | * will end up at (GET_SYMBOL's operand points there). | |
200 | */ | |
28ab034a | 201 | bytecode_reloc_offset_u32 = bytecode_get_len(&(*bytecode_reloc)->b) + sizeof(reloc_offset); |
6afbab01 SM |
202 | symbol_offset.offset = (uint16_t) bytecode_reloc_offset_u32; |
203 | memcpy(insn->data, &symbol_offset, sizeof(symbol_offset)); | |
204 | ||
205 | /* | |
206 | * Get offset in the bytecode where the opcode will end up at, | |
207 | * the reloc offset points to it. | |
208 | */ | |
209 | reloc_offset_u32 = bytecode_get_len(&(*bytecode)->b); | |
210 | if (reloc_offset_u32 > LTTNG_FILTER_MAX_LEN - 1) { | |
211 | ret = -EINVAL; | |
212 | goto end; | |
213 | } | |
214 | reloc_offset = (uint16_t) reloc_offset_u32; | |
215 | ||
216 | /* Append op in bytecode. */ | |
217 | ret = bytecode_push(bytecode, insn, 1, insn_len); | |
218 | if (ret) { | |
219 | goto end; | |
220 | } | |
221 | ||
222 | /* Append reloc offset. */ | |
28ab034a | 223 | ret = bytecode_push(bytecode_reloc, &reloc_offset, 1, sizeof(reloc_offset)); |
6afbab01 SM |
224 | if (ret) { |
225 | goto end; | |
226 | } | |
227 | ||
228 | /* Append symbol name. */ | |
229 | ret = bytecode_push(bytecode_reloc, symbol, 1, strlen(symbol) + 1); | |
230 | ||
231 | end: | |
232 | free(insn); | |
233 | return ret; | |
234 | } | |
235 | ||
763f0d4c SM |
236 | /* |
237 | * Allocate an lttng_bytecode object and copy the given original bytecode. | |
238 | * | |
239 | * Return allocated bytecode or NULL on error. | |
240 | */ | |
28ab034a | 241 | struct lttng_bytecode *lttng_bytecode_copy(const struct lttng_bytecode *orig_f) |
763f0d4c | 242 | { |
28ab034a | 243 | lttng_bytecode *bytecode = zmalloc<lttng_bytecode>(sizeof(*bytecode) + orig_f->len); |
763f0d4c SM |
244 | if (!bytecode) { |
245 | goto error; | |
246 | } | |
247 | ||
248 | memcpy(bytecode, orig_f, sizeof(*bytecode) + orig_f->len); | |
249 | ||
250 | error: | |
251 | return bytecode; | |
252 | } |