OLD | NEW |
1 /* | 1 /* |
2 * Copyright 2010 The Native Client Authors. All rights reserved. | 2 * Copyright 2010 The Native Client Authors. All rights reserved. |
3 * Use of this source code is governed by a BSD-style license that can | 3 * Use of this source code is governed by a BSD-style license that can |
4 * be found in the LICENSE file. | 4 * be found in the LICENSE file. |
5 */ | 5 */ |
6 | 6 |
7 #include <assert.h> | 7 #include <assert.h> |
8 #include <errno.h> | 8 #include <errno.h> |
9 #include <stdint.h> | 9 #include <stdint.h> |
10 #include <stdio.h> | 10 #include <stdio.h> |
11 #include <stdlib.h> | 11 #include <stdlib.h> |
12 #include <string.h> | 12 #include <string.h> |
13 #include <sys/mman.h> | 13 #include <sys/mman.h> |
14 | 14 |
15 #include <sys/nacl_syscalls.h> | 15 #include <sys/nacl_syscalls.h> |
16 | 16 |
17 #include "native_client/tests/dynamic_code_loading/templates.h" | 17 #include "native_client/tests/dynamic_code_loading/templates.h" |
18 #include "native_client/tests/inbrowser_test_runner/test_runner.h" | 18 #include "native_client/tests/inbrowser_test_runner/test_runner.h" |
19 | 19 |
| 20 #if defined(__x86_64__) |
| 21 /* On x86-64, template functions do not fit in 32-byte buffers */ |
| 22 #define BUF_SIZE 64 |
| 23 #elif defined(__i386__) || defined(__arm__) |
| 24 #define BUF_SIZE 32 |
| 25 #else |
| 26 #error "Unknown Platform" |
| 27 #endif |
| 28 |
| 29 #if defined(__i386__) || defined(__x86_64__) |
20 #define NACL_BUNDLE_SIZE 32 | 30 #define NACL_BUNDLE_SIZE 32 |
| 31 #elif defined(__arm__) |
| 32 #define NACL_BUNDLE_SIZE 16 |
| 33 #else |
| 34 #error "Unknown Platform" |
| 35 #endif |
| 36 |
21 /* | 37 /* |
22 * TODO(bsy): get this value from the toolchain. Get the toolchain | 38 * TODO(bsy): get this value from the toolchain. Get the toolchain |
23 * team to provide this value. | 39 * team to provide this value. |
24 */ | 40 */ |
25 #define NUM_BUNDLES_FOR_HLT 3 | 41 #define NUM_BUNDLES_FOR_HLT 3 |
26 | 42 |
27 /* | 43 /* |
28 * This is an address that is well into the dynamic code region and page | 44 * This is an address that is well into the dynamic code region and page |
29 * aligned. There is a test below specifically for installing a function | 45 * aligned. There is a test below specifically for installing a function |
30 * at the very beginning of the dynamic code region. | 46 * at the very beginning of the dynamic code region. |
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
86 /* Getting the assembler to pad our code fragments in templates.S is | 102 /* Getting the assembler to pad our code fragments in templates.S is |
87 awkward because we have to output them in data mode, in which the | 103 awkward because we have to output them in data mode, in which the |
88 assembler wants to output zeroes instead of NOPs for padding. | 104 assembler wants to output zeroes instead of NOPs for padding. |
89 Also, the assembler won't put in a terminating HLT, which we need | 105 Also, the assembler won't put in a terminating HLT, which we need |
90 on x86-32. So we do the padding at run time. */ | 106 on x86-32. So we do the padding at run time. */ |
91 void copy_and_pad_fragment(void *dest, | 107 void copy_and_pad_fragment(void *dest, |
92 int dest_size, | 108 int dest_size, |
93 const char *fragment_start, | 109 const char *fragment_start, |
94 const char *fragment_end) { | 110 const char *fragment_end) { |
95 int fragment_size = fragment_end - fragment_start; | 111 int fragment_size = fragment_end - fragment_start; |
96 assert(dest_size % 32 == 0); | 112 assert(dest_size % NACL_BUNDLE_SIZE == 0); |
97 assert(fragment_size < dest_size); | 113 assert(fragment_size <= dest_size); |
98 fill_nops(dest, dest_size); | 114 fill_nops(dest, dest_size); |
99 memcpy(dest, fragment_start, fragment_size); | 115 memcpy(dest, fragment_start, fragment_size); |
100 } | 116 } |
101 | 117 |
102 /* Check that we can load and run code. */ | 118 /* Check that we can load and run code. */ |
103 void test_loading_code() { | 119 void test_loading_code() { |
104 void *load_area = allocate_code_space(1); | 120 void *load_area = allocate_code_space(1); |
105 uint8_t buf[32]; | 121 uint8_t buf[BUF_SIZE]; |
106 int rc; | 122 int rc; |
107 int (*func)(); | 123 int (*func)(); |
108 | 124 |
109 copy_and_pad_fragment(buf, sizeof(buf), &template_func, &template_func_end); | 125 copy_and_pad_fragment(buf, sizeof(buf), &template_func, &template_func_end); |
110 | 126 |
111 rc = nacl_load_code(load_area, buf, sizeof(buf)); | 127 rc = nacl_load_code(load_area, buf, sizeof(buf)); |
112 assert(rc == 0); | 128 assert(rc == 0); |
113 assert(memcmp(load_area, buf, sizeof(buf)) == 0); | 129 assert(memcmp(load_area, buf, sizeof(buf)) == 0); |
114 /* Need double cast otherwise gcc complains with "ISO C forbids | 130 /* Need double cast otherwise gcc complains with "ISO C forbids |
115 conversion of object pointer to function pointer type | 131 conversion of object pointer to function pointer type |
116 [-pedantic]". */ | 132 [-pedantic]". */ |
117 func = (int (*)()) (uintptr_t) load_area; | 133 func = (int (*)()) (uintptr_t) load_area; |
118 rc = func(); | 134 rc = func(); |
119 assert(rc == 1234); | 135 assert(rc == 1234); |
120 } | 136 } |
121 | 137 |
122 /* The syscall may have to mmap() shared memory temporarily, | 138 /* The syscall may have to mmap() shared memory temporarily, |
123 so there is some interaction with page size. | 139 so there is some interaction with page size. |
124 Check that we can load to non-page-aligned addresses. */ | 140 Check that we can load to non-page-aligned addresses. */ |
125 void test_loading_code_non_page_aligned() { | 141 void test_loading_code_non_page_aligned() { |
126 char *load_area = allocate_code_space(1); | 142 char *load_area = allocate_code_space(1); |
127 uint8_t buf[32]; | 143 uint8_t buf[BUF_SIZE]; |
128 int rc; | 144 int rc; |
129 | 145 |
130 copy_and_pad_fragment(buf, sizeof(buf), &template_func, &template_func_end); | 146 copy_and_pad_fragment(buf, sizeof(buf), &template_func, &template_func_end); |
131 | 147 |
132 rc = nacl_load_code(load_area, buf, sizeof(buf)); | 148 rc = nacl_load_code(load_area, buf, sizeof(buf)); |
133 assert(rc == 0); | 149 assert(rc == 0); |
134 assert(memcmp(load_area, buf, sizeof(buf)) == 0); | 150 assert(memcmp(load_area, buf, sizeof(buf)) == 0); |
135 | 151 |
136 load_area += 32; | 152 load_area += sizeof(buf); |
137 rc = nacl_load_code(load_area, buf, sizeof(buf)); | 153 rc = nacl_load_code(load_area, buf, sizeof(buf)); |
138 assert(rc == 0); | 154 assert(rc == 0); |
139 assert(memcmp(load_area, buf, sizeof(buf)) == 0); | 155 assert(memcmp(load_area, buf, sizeof(buf)) == 0); |
140 } | 156 } |
141 | 157 |
142 /* Since there is an interaction with page size, we also test loading | 158 /* Since there is an interaction with page size, we also test loading |
143 a multi-page chunk of code. */ | 159 a multi-page chunk of code. */ |
144 void test_loading_large_chunk() { | 160 void test_loading_large_chunk() { |
145 char *load_area = allocate_code_space(2); | 161 char *load_area = allocate_code_space(2); |
146 int size = 0x20000; | 162 int size = 0x20000; |
147 uint8_t *data = alloca(size); | 163 uint8_t *data = alloca(size); |
148 int rc; | 164 int rc; |
149 | 165 |
150 fill_nops(data, size); | 166 fill_nops(data, size); |
151 rc = nacl_load_code(load_area, data, size); | 167 rc = nacl_load_code(load_area, data, size); |
152 assert(rc == 0); | 168 assert(rc == 0); |
153 assert(memcmp(load_area, data, size) == 0); | 169 assert(memcmp(load_area, data, size) == 0); |
154 } | 170 } |
155 | 171 |
156 void test_loading_zero_size() { | 172 void test_loading_zero_size() { |
157 char *load_area = allocate_code_space(1); | 173 char *load_area = allocate_code_space(1); |
158 int rc = nacl_load_code(load_area, &template_func, 0); | 174 int rc = nacl_load_code(load_area, &template_func, 0); |
159 assert(rc == 0); | 175 assert(rc == 0); |
160 } | 176 } |
161 | 177 |
162 /* Check that we can load code at the very beginning of the dynamic section. */ | 178 /* Check that we can load code at the very beginning of the dynamic section. */ |
163 void test_loading_code_on_first_dynamic_page() { | 179 void test_loading_code_on_first_dynamic_page() { |
164 const unsigned int kPageMask = 0xFFFF; | 180 const unsigned int kPageMask = 0xFFFF; |
165 void *load_area = (void*)((uintptr_t)(etext + kPageMask) & ~kPageMask); | 181 void *load_area = (void*)((uintptr_t)(etext + kPageMask) & ~kPageMask); |
166 uint8_t buf[32]; | 182 uint8_t buf[BUF_SIZE]; |
167 int rc; | 183 int rc; |
168 int (*func)(); | 184 int (*func)(); |
169 | 185 |
170 copy_and_pad_fragment(buf, sizeof(buf), &template_func, &template_func_end); | 186 copy_and_pad_fragment(buf, sizeof(buf), &template_func, &template_func_end); |
171 | 187 |
172 rc = nacl_load_code(load_area, buf, sizeof(buf)); | 188 rc = nacl_load_code(load_area, buf, sizeof(buf)); |
173 assert(rc == 0); | 189 assert(rc == 0); |
174 assert(memcmp(load_area, buf, sizeof(buf)) == 0); | 190 assert(memcmp(load_area, buf, sizeof(buf)) == 0); |
175 /* Need double cast otherwise gcc complains with "ISO C forbids | 191 /* Need double cast otherwise gcc complains with "ISO C forbids |
176 conversion of object pointer to function pointer type | 192 conversion of object pointer to function pointer type |
177 [-pedantic]". */ | 193 [-pedantic]". */ |
178 func = (int (*)()) (uintptr_t) load_area; | 194 func = (int (*)()) (uintptr_t) load_area; |
179 rc = func(); | 195 rc = func(); |
180 assert(rc == 1234); | 196 assert(rc == 1234); |
181 } | 197 } |
182 | 198 |
183 /* In general, the failure tests don't check that loading fails for | 199 /* In general, the failure tests don't check that loading fails for |
184 the reason we expect. TODO(mseaborn): We could do this by | 200 the reason we expect. TODO(mseaborn): We could do this by |
185 comparing with expected log output. */ | 201 comparing with expected log output. */ |
186 | 202 |
187 void test_fail_on_validation_error() { | 203 void test_fail_on_validation_error() { |
188 void *load_area = allocate_code_space(1); | 204 void *load_area = allocate_code_space(1); |
189 uint8_t buf[32]; | 205 uint8_t buf[BUF_SIZE]; |
190 int rc; | 206 int rc; |
191 | 207 |
192 copy_and_pad_fragment(buf, sizeof(buf), &invalid_code, &invalid_code_end); | 208 copy_and_pad_fragment(buf, sizeof(buf), &invalid_code, &invalid_code_end); |
193 | 209 |
194 rc = nacl_load_code(load_area, buf, sizeof(buf)); | 210 rc = nacl_load_code(load_area, buf, sizeof(buf)); |
195 assert(rc == -EINVAL); | 211 assert(rc == -EINVAL); |
196 } | 212 } |
197 | 213 |
198 void test_fail_on_non_bundle_aligned_dest_addresses() { | 214 void test_fail_on_non_bundle_aligned_dest_addresses() { |
199 char *load_area = allocate_code_space(1); | 215 char *load_area = allocate_code_space(1); |
200 int rc; | 216 int rc; |
201 uint8_t nops[32]; | 217 uint8_t nops[BUF_SIZE]; |
202 | 218 |
203 fill_nops(nops, sizeof(nops)); | 219 fill_nops(nops, sizeof(nops)); |
204 | 220 |
205 /* Test unaligned destination. */ | 221 /* Test unaligned destination. */ |
206 rc = nacl_load_code(load_area + 1, nops, 32); | 222 rc = nacl_load_code(load_area + 1, nops, NACL_BUNDLE_SIZE); |
207 assert(rc == -EINVAL); | 223 assert(rc == -EINVAL); |
208 rc = nacl_load_code(load_area + 4, nops, 32); | 224 rc = nacl_load_code(load_area + 4, nops, NACL_BUNDLE_SIZE); |
209 assert(rc == -EINVAL); | 225 assert(rc == -EINVAL); |
210 | 226 |
211 /* Test unaligned size. */ | 227 /* Test unaligned size. */ |
212 rc = nacl_load_code(load_area, nops + 1, 31); | 228 rc = nacl_load_code(load_area, nops + 1, NACL_BUNDLE_SIZE - 1); |
213 assert(rc == -EINVAL); | 229 assert(rc == -EINVAL); |
214 rc = nacl_load_code(load_area, nops + 4, 28); | 230 rc = nacl_load_code(load_area, nops + 4, NACL_BUNDLE_SIZE - 4); |
215 assert(rc == -EINVAL); | 231 assert(rc == -EINVAL); |
216 | 232 |
217 /* Check that the code we're trying works otherwise. */ | 233 /* Check that the code we're trying works otherwise. */ |
218 rc = nacl_load_code(load_area, nops, 32); | 234 rc = nacl_load_code(load_area, nops, NACL_BUNDLE_SIZE); |
219 assert(rc == 0); | 235 assert(rc == 0); |
220 } | 236 } |
221 | 237 |
222 /* In principle we could load into the initially-loaded executable's | 238 /* In principle we could load into the initially-loaded executable's |
223 code area, but at the moment we don't allow it. */ | 239 code area, but at the moment we don't allow it. */ |
224 void test_fail_on_load_to_static_code_area() { | 240 void test_fail_on_load_to_static_code_area() { |
225 int size = &hlts_end - &hlts; | 241 int size = &hlts_end - &hlts; |
226 int rc = nacl_load_code(&hlts, &hlts, size); | 242 int rc = nacl_load_code(&hlts, &hlts, size); |
227 assert(rc == -EFAULT); | 243 assert(rc == -EFAULT); |
228 } | 244 } |
229 | 245 |
230 uint8_t block_in_data_segment[64]; | 246 uint8_t block_in_data_segment[64]; |
231 | 247 |
232 void test_fail_on_load_to_data_area() { | 248 void test_fail_on_load_to_data_area() { |
233 uint8_t *data; | 249 uint8_t *data; |
234 int rc; | 250 int rc; |
235 | 251 |
236 fill_hlts(block_in_data_segment, sizeof(block_in_data_segment)); | 252 fill_hlts(block_in_data_segment, sizeof(block_in_data_segment)); |
237 | 253 |
238 /* Align to 32 byte boundary so that we don't fail for a reason | 254 /* Align to bundle size so that we don't fail for a reason |
239 we're not testing for. */ | 255 we're not testing for. */ |
240 data = block_in_data_segment; | 256 data = block_in_data_segment; |
241 while (((int) data) % 32 != 0) | 257 while (((int) data) % NACL_BUNDLE_SIZE != 0) |
242 data++; | 258 data++; |
243 rc = nacl_load_code(data, data, 32); | 259 rc = nacl_load_code(data, data, NACL_BUNDLE_SIZE); |
244 assert(rc == -EFAULT); | 260 assert(rc == -EFAULT); |
245 } | 261 } |
246 | 262 |
247 void test_fail_on_overwrite() { | 263 void test_fail_on_overwrite() { |
248 void *load_area = allocate_code_space(1); | 264 void *load_area = allocate_code_space(1); |
249 uint8_t buf[32]; | 265 uint8_t buf[BUF_SIZE]; |
250 int rc; | 266 int rc; |
251 | 267 |
252 copy_and_pad_fragment(buf, sizeof(buf), &template_func, &template_func_end); | 268 copy_and_pad_fragment(buf, sizeof(buf), &template_func, &template_func_end); |
253 | 269 |
254 rc = nacl_load_code(load_area, buf, sizeof(buf)); | 270 rc = nacl_load_code(load_area, buf, sizeof(buf)); |
255 assert(rc == 0); | 271 assert(rc == 0); |
256 | 272 |
257 copy_and_pad_fragment(buf, sizeof(buf), &template_func, | 273 copy_and_pad_fragment(buf, sizeof(buf), &template_func, |
258 &template_func_end); | 274 &template_func_end); |
259 | 275 |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
291 | 307 |
292 rc = nacl_load_code(load_area, &branch_forwards, size); | 308 rc = nacl_load_code(load_area, &branch_forwards, size); |
293 assert(rc == 0); | 309 assert(rc == 0); |
294 rc = nacl_load_code(load_area + size, &branch_backwards, size); | 310 rc = nacl_load_code(load_area + size, &branch_backwards, size); |
295 assert(rc == 0); | 311 assert(rc == 0); |
296 } | 312 } |
297 | 313 |
298 void test_end_of_code_region() { | 314 void test_end_of_code_region() { |
299 int rc; | 315 int rc; |
300 void *dest; | 316 void *dest; |
301 uint8_t data[32]; | 317 uint8_t data[BUF_SIZE]; |
302 fill_nops(data, sizeof(data)); | 318 fill_nops(data, sizeof(data)); |
303 | 319 |
304 /* This tries to load into the data segment, which is definitely not | 320 /* This tries to load into the data segment, which is definitely not |
305 allowed. */ | 321 allowed. */ |
306 dest = (uint8_t *) DYNAMIC_CODE_SEGMENT_END; | 322 dest = (uint8_t *) DYNAMIC_CODE_SEGMENT_END; |
307 rc = nacl_load_code(dest, data, sizeof(data)); | 323 rc = nacl_load_code(dest, data, sizeof(data)); |
308 assert(rc == -EFAULT); | 324 assert(rc == -EFAULT); |
309 | 325 |
310 /* This tries to load into the last bundle of the code region, which | 326 /* This tries to load into the last bundle of the code region, which |
311 sel_ldr disallows just in case there is some CPU bug in which the | 327 sel_ldr disallows just in case there is some CPU bug in which the |
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
367 | 383 |
368 /* Test again to make sure we didn't run out of space. */ | 384 /* Test again to make sure we didn't run out of space. */ |
369 RUN_TEST(test_loading_code); | 385 RUN_TEST(test_loading_code); |
370 | 386 |
371 return 0; | 387 return 0; |
372 } | 388 } |
373 | 389 |
374 int main() { | 390 int main() { |
375 return RunTests(TestMain); | 391 return RunTests(TestMain); |
376 } | 392 } |
OLD | NEW |