Chromium Code Reviews| 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 #define BUF_SIZE 64 | |
|
bsy
2010/11/11 21:27:21
why should code buffers be 64 bytes on x86-64 cpus
petr
2010/11/12 18:11:06
on X86-64 we operate with code samples that do not
| |
| 22 #else | |
| 23 #define BUF_SIZE 32 | |
| 24 #endif | |
| 25 | |
| 20 #define NACL_BUNDLE_SIZE 32 | 26 #define NACL_BUNDLE_SIZE 32 |
| 21 /* | 27 /* |
| 22 * TODO(bsy): get this value from the toolchain. Get the toolchain | 28 * TODO(bsy): get this value from the toolchain. Get the toolchain |
| 23 * team to provide this value. | 29 * team to provide this value. |
| 24 */ | 30 */ |
| 25 #define NUM_BUNDLES_FOR_HLT 3 | 31 #define NUM_BUNDLES_FOR_HLT 3 |
| 26 | 32 |
| 27 /* | 33 /* |
| 28 * This is an address that is well into the dynamic code region and page | 34 * 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 | 35 * aligned. There is a test below specifically for installing a function |
| (...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 86 /* Getting the assembler to pad our code fragments in templates.S is | 92 /* 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 | 93 awkward because we have to output them in data mode, in which the |
| 88 assembler wants to output zeroes instead of NOPs for padding. | 94 assembler wants to output zeroes instead of NOPs for padding. |
| 89 Also, the assembler won't put in a terminating HLT, which we need | 95 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. */ | 96 on x86-32. So we do the padding at run time. */ |
| 91 void copy_and_pad_fragment(void *dest, | 97 void copy_and_pad_fragment(void *dest, |
| 92 int dest_size, | 98 int dest_size, |
| 93 const char *fragment_start, | 99 const char *fragment_start, |
| 94 const char *fragment_end) { | 100 const char *fragment_end) { |
| 95 int fragment_size = fragment_end - fragment_start; | 101 int fragment_size = fragment_end - fragment_start; |
| 96 assert(dest_size % 32 == 0); | 102 assert(dest_size % 32 == 0); |
|
bsy
2010/11/11 21:27:21
is this 32 (always) correct? should it be 16 or 3
petr
2010/11/12 18:11:06
Done.
| |
| 97 assert(fragment_size < dest_size); | 103 assert(fragment_size <= dest_size); |
| 98 fill_nops(dest, dest_size); | 104 fill_nops(dest, dest_size); |
| 99 memcpy(dest, fragment_start, fragment_size); | 105 memcpy(dest, fragment_start, fragment_size); |
| 100 } | 106 } |
| 101 | 107 |
| 102 /* Check that we can load and run code. */ | 108 /* Check that we can load and run code. */ |
| 103 void test_loading_code() { | 109 void test_loading_code() { |
| 104 void *load_area = allocate_code_space(1); | 110 void *load_area = allocate_code_space(1); |
| 105 uint8_t buf[32]; | 111 uint8_t buf[BUF_SIZE]; |
| 106 int rc; | 112 int rc; |
| 107 int (*func)(); | 113 int (*func)(); |
| 108 | 114 |
| 109 copy_and_pad_fragment(buf, sizeof(buf), &template_func, &template_func_end); | 115 copy_and_pad_fragment(buf, sizeof(buf), &template_func, &template_func_end); |
| 110 | 116 |
| 111 rc = nacl_load_code(load_area, buf, sizeof(buf)); | 117 rc = nacl_load_code(load_area, buf, sizeof(buf)); |
| 112 assert(rc == 0); | 118 assert(rc == 0); |
| 113 assert(memcmp(load_area, buf, sizeof(buf)) == 0); | 119 assert(memcmp(load_area, buf, sizeof(buf)) == 0); |
| 114 /* Need double cast otherwise gcc complains with "ISO C forbids | 120 /* Need double cast otherwise gcc complains with "ISO C forbids |
| 115 conversion of object pointer to function pointer type | 121 conversion of object pointer to function pointer type |
| 116 [-pedantic]". */ | 122 [-pedantic]". */ |
| 117 func = (int (*)()) (uintptr_t) load_area; | 123 func = (int (*)()) (uintptr_t) load_area; |
| 118 rc = func(); | 124 rc = func(); |
| 119 assert(rc == 1234); | 125 assert(rc == 1234); |
| 120 } | 126 } |
| 121 | 127 |
| 122 /* The syscall may have to mmap() shared memory temporarily, | 128 /* The syscall may have to mmap() shared memory temporarily, |
| 123 so there is some interaction with page size. | 129 so there is some interaction with page size. |
| 124 Check that we can load to non-page-aligned addresses. */ | 130 Check that we can load to non-page-aligned addresses. */ |
| 125 void test_loading_code_non_page_aligned() { | 131 void test_loading_code_non_page_aligned() { |
| 126 char *load_area = allocate_code_space(1); | 132 char *load_area = allocate_code_space(1); |
| 127 uint8_t buf[32]; | 133 uint8_t buf[BUF_SIZE]; |
| 128 int rc; | 134 int rc; |
| 129 | 135 |
| 130 copy_and_pad_fragment(buf, sizeof(buf), &template_func, &template_func_end); | 136 copy_and_pad_fragment(buf, sizeof(buf), &template_func, &template_func_end); |
| 131 | 137 |
| 132 rc = nacl_load_code(load_area, buf, sizeof(buf)); | 138 rc = nacl_load_code(load_area, buf, sizeof(buf)); |
| 133 assert(rc == 0); | 139 assert(rc == 0); |
| 134 assert(memcmp(load_area, buf, sizeof(buf)) == 0); | 140 assert(memcmp(load_area, buf, sizeof(buf)) == 0); |
| 135 | 141 |
| 136 load_area += 32; | 142 load_area += sizeof(buf); |
| 137 rc = nacl_load_code(load_area, buf, sizeof(buf)); | 143 rc = nacl_load_code(load_area, buf, sizeof(buf)); |
| 138 assert(rc == 0); | 144 assert(rc == 0); |
| 139 assert(memcmp(load_area, buf, sizeof(buf)) == 0); | 145 assert(memcmp(load_area, buf, sizeof(buf)) == 0); |
| 140 } | 146 } |
| 141 | 147 |
| 142 /* Since there is an interaction with page size, we also test loading | 148 /* Since there is an interaction with page size, we also test loading |
| 143 a multi-page chunk of code. */ | 149 a multi-page chunk of code. */ |
| 144 void test_loading_large_chunk() { | 150 void test_loading_large_chunk() { |
| 145 char *load_area = allocate_code_space(2); | 151 char *load_area = allocate_code_space(2); |
| 146 int size = 0x20000; | 152 int size = 0x20000; |
| 147 uint8_t *data = alloca(size); | 153 uint8_t *data = alloca(size); |
| 148 int rc; | 154 int rc; |
| 149 | 155 |
| 150 fill_nops(data, size); | 156 fill_nops(data, size); |
| 151 rc = nacl_load_code(load_area, data, size); | 157 rc = nacl_load_code(load_area, data, size); |
| 152 assert(rc == 0); | 158 assert(rc == 0); |
| 153 assert(memcmp(load_area, data, size) == 0); | 159 assert(memcmp(load_area, data, size) == 0); |
| 154 } | 160 } |
| 155 | 161 |
| 156 void test_loading_zero_size() { | 162 void test_loading_zero_size() { |
| 157 char *load_area = allocate_code_space(1); | 163 char *load_area = allocate_code_space(1); |
| 158 int rc = nacl_load_code(load_area, &template_func, 0); | 164 int rc = nacl_load_code(load_area, &template_func, 0); |
| 159 assert(rc == 0); | 165 assert(rc == 0); |
| 160 } | 166 } |
| 161 | 167 |
| 162 /* Check that we can load code at the very beginning of the dynamic section. */ | 168 /* Check that we can load code at the very beginning of the dynamic section. */ |
| 163 void test_loading_code_on_first_dynamic_page() { | 169 void test_loading_code_on_first_dynamic_page() { |
| 164 const unsigned int kPageMask = 0xFFFF; | 170 const unsigned int kPageMask = 0xFFFF; |
| 165 void *load_area = (void*)((uintptr_t)(etext + kPageMask) & ~kPageMask); | 171 void *load_area = (void*)((uintptr_t)(etext + kPageMask) & ~kPageMask); |
| 166 uint8_t buf[32]; | 172 uint8_t buf[32]; |
|
bsy
2010/11/11 21:27:21
should this be BUF_SIZE? if not, a comment would
petr
2010/11/12 18:11:06
Done.
| |
| 167 int rc; | 173 int rc; |
| 168 int (*func)(); | 174 int (*func)(); |
| 169 | 175 |
| 170 copy_and_pad_fragment(buf, sizeof(buf), &template_func, &template_func_end); | 176 copy_and_pad_fragment(buf, sizeof(buf), &template_func, &template_func_end); |
| 171 | 177 |
| 172 rc = nacl_load_code(load_area, buf, sizeof(buf)); | 178 rc = nacl_load_code(load_area, buf, sizeof(buf)); |
| 173 assert(rc == 0); | 179 assert(rc == 0); |
| 174 assert(memcmp(load_area, buf, sizeof(buf)) == 0); | 180 assert(memcmp(load_area, buf, sizeof(buf)) == 0); |
| 175 /* Need double cast otherwise gcc complains with "ISO C forbids | 181 /* Need double cast otherwise gcc complains with "ISO C forbids |
| 176 conversion of object pointer to function pointer type | 182 conversion of object pointer to function pointer type |
| 177 [-pedantic]". */ | 183 [-pedantic]". */ |
| 178 func = (int (*)()) (uintptr_t) load_area; | 184 func = (int (*)()) (uintptr_t) load_area; |
| 179 rc = func(); | 185 rc = func(); |
| 180 assert(rc == 1234); | 186 assert(rc == 1234); |
| 181 } | 187 } |
| 182 | 188 |
| 183 /* In general, the failure tests don't check that loading fails for | 189 /* In general, the failure tests don't check that loading fails for |
| 184 the reason we expect. TODO(mseaborn): We could do this by | 190 the reason we expect. TODO(mseaborn): We could do this by |
| 185 comparing with expected log output. */ | 191 comparing with expected log output. */ |
| 186 | 192 |
| 187 void test_fail_on_validation_error() { | 193 void test_fail_on_validation_error() { |
| 188 void *load_area = allocate_code_space(1); | 194 void *load_area = allocate_code_space(1); |
| 189 uint8_t buf[32]; | 195 uint8_t buf[BUF_SIZE]; |
| 190 int rc; | 196 int rc; |
| 191 | 197 |
| 192 copy_and_pad_fragment(buf, sizeof(buf), &invalid_code, &invalid_code_end); | 198 copy_and_pad_fragment(buf, sizeof(buf), &invalid_code, &invalid_code_end); |
| 193 | 199 |
| 194 rc = nacl_load_code(load_area, buf, sizeof(buf)); | 200 rc = nacl_load_code(load_area, buf, sizeof(buf)); |
| 195 assert(rc == -EINVAL); | 201 assert(rc == -EINVAL); |
| 196 } | 202 } |
| 197 | 203 |
| 198 void test_fail_on_non_bundle_aligned_dest_addresses() { | 204 void test_fail_on_non_bundle_aligned_dest_addresses() { |
| 199 char *load_area = allocate_code_space(1); | 205 char *load_area = allocate_code_space(1); |
| 200 int rc; | 206 int rc; |
| 201 uint8_t nops[32]; | 207 uint8_t nops[32]; |
|
bsy
2010/11/11 21:27:21
should this be BUF_SIZE too? if not, a comment wo
petr
2010/11/12 18:11:06
Done.
| |
| 202 | 208 |
| 203 fill_nops(nops, sizeof(nops)); | 209 fill_nops(nops, sizeof(nops)); |
| 204 | 210 |
| 205 /* Test unaligned destination. */ | 211 /* Test unaligned destination. */ |
| 206 rc = nacl_load_code(load_area + 1, nops, 32); | 212 rc = nacl_load_code(load_area + 1, nops, 32); |
|
bsy
2010/11/11 21:27:21
NACL_ARRAY_SIZE(nops) or sizeof nops instead of 32
petr
2010/11/12 18:11:06
we are testing that the size of a segment is bundl
| |
| 207 assert(rc == -EINVAL); | 213 assert(rc == -EINVAL); |
| 208 rc = nacl_load_code(load_area + 4, nops, 32); | 214 rc = nacl_load_code(load_area + 4, nops, 32); |
|
bsy
2010/11/11 21:27:21
ditto
petr
2010/11/12 18:11:06
ditto
On 2010/11/11 21:27:21, bsy wrote:
| |
| 209 assert(rc == -EINVAL); | 215 assert(rc == -EINVAL); |
| 210 | 216 |
| 211 /* Test unaligned size. */ | 217 /* Test unaligned size. */ |
| 212 rc = nacl_load_code(load_area, nops + 1, 31); | 218 rc = nacl_load_code(load_area, nops + 1, 31); |
|
bsy
2010/11/11 21:27:21
NACL_ARRAY_SIZE(nops) - 1 instead of 31?
petr
2010/11/12 18:11:06
ditto
On 2010/11/11 21:27:21, bsy wrote:
| |
| 213 assert(rc == -EINVAL); | 219 assert(rc == -EINVAL); |
| 214 rc = nacl_load_code(load_area, nops + 4, 28); | 220 rc = nacl_load_code(load_area, nops + 4, 28); |
|
bsy
2010/11/11 21:27:21
similar to above
petr
2010/11/12 18:11:06
ditto
On 2010/11/11 21:27:21, bsy wrote:
| |
| 215 assert(rc == -EINVAL); | 221 assert(rc == -EINVAL); |
| 216 | 222 |
| 217 /* Check that the code we're trying works otherwise. */ | 223 /* Check that the code we're trying works otherwise. */ |
| 218 rc = nacl_load_code(load_area, nops, 32); | 224 rc = nacl_load_code(load_area, nops, 32); |
|
bsy
2010/11/11 21:27:21
!!
petr
2010/11/12 18:11:06
probably, it is just an additional check (maybe re
| |
| 219 assert(rc == 0); | 225 assert(rc == 0); |
| 220 } | 226 } |
| 221 | 227 |
| 222 /* In principle we could load into the initially-loaded executable's | 228 /* In principle we could load into the initially-loaded executable's |
| 223 code area, but at the moment we don't allow it. */ | 229 code area, but at the moment we don't allow it. */ |
| 224 void test_fail_on_load_to_static_code_area() { | 230 void test_fail_on_load_to_static_code_area() { |
| 225 int size = &hlts_end - &hlts; | 231 int size = &hlts_end - &hlts; |
| 226 int rc = nacl_load_code(&hlts, &hlts, size); | 232 int rc = nacl_load_code(&hlts, &hlts, size); |
| 227 assert(rc == -EFAULT); | 233 assert(rc == -EFAULT); |
| 228 } | 234 } |
| 229 | 235 |
| 230 uint8_t block_in_data_segment[64]; | 236 uint8_t block_in_data_segment[64]; |
| 231 | 237 |
| 232 void test_fail_on_load_to_data_area() { | 238 void test_fail_on_load_to_data_area() { |
| 233 uint8_t *data; | 239 uint8_t *data; |
| 234 int rc; | 240 int rc; |
| 235 | 241 |
| 236 fill_hlts(block_in_data_segment, sizeof(block_in_data_segment)); | 242 fill_hlts(block_in_data_segment, sizeof(block_in_data_segment)); |
| 237 | 243 |
| 238 /* Align to 32 byte boundary so that we don't fail for a reason | 244 /* Align to 32 byte boundary so that we don't fail for a reason |
| 239 we're not testing for. */ | 245 we're not testing for. */ |
| 240 data = block_in_data_segment; | 246 data = block_in_data_segment; |
| 241 while (((int) data) % 32 != 0) | 247 while (((int) data) % 32 != 0) |
| 242 data++; | 248 data++; |
| 243 rc = nacl_load_code(data, data, 32); | 249 rc = nacl_load_code(data, data, 32); |
|
bsy
2010/11/11 21:27:21
!!
petr
2010/11/12 18:11:06
s/32/NACL_BUNDLE_SIZE/
On 2010/11/11 21:27:21, bsy
| |
| 244 assert(rc == -EFAULT); | 250 assert(rc == -EFAULT); |
| 245 } | 251 } |
| 246 | 252 |
| 247 void test_fail_on_overwrite() { | 253 void test_fail_on_overwrite() { |
| 248 void *load_area = allocate_code_space(1); | 254 void *load_area = allocate_code_space(1); |
| 249 uint8_t buf[32]; | 255 uint8_t buf[BUF_SIZE]; |
| 250 int rc; | 256 int rc; |
| 251 | 257 |
| 252 copy_and_pad_fragment(buf, sizeof(buf), &template_func, &template_func_end); | 258 copy_and_pad_fragment(buf, sizeof(buf), &template_func, &template_func_end); |
| 253 | 259 |
| 254 rc = nacl_load_code(load_area, buf, sizeof(buf)); | 260 rc = nacl_load_code(load_area, buf, sizeof(buf)); |
| 255 assert(rc == 0); | 261 assert(rc == 0); |
| 256 | 262 |
| 257 copy_and_pad_fragment(buf, sizeof(buf), &template_func, | 263 copy_and_pad_fragment(buf, sizeof(buf), &template_func, |
| 258 &template_func_end); | 264 &template_func_end); |
| 259 | 265 |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 291 | 297 |
| 292 rc = nacl_load_code(load_area, &branch_forwards, size); | 298 rc = nacl_load_code(load_area, &branch_forwards, size); |
| 293 assert(rc == 0); | 299 assert(rc == 0); |
| 294 rc = nacl_load_code(load_area + size, &branch_backwards, size); | 300 rc = nacl_load_code(load_area + size, &branch_backwards, size); |
| 295 assert(rc == 0); | 301 assert(rc == 0); |
| 296 } | 302 } |
| 297 | 303 |
| 298 void test_end_of_code_region() { | 304 void test_end_of_code_region() { |
| 299 int rc; | 305 int rc; |
| 300 void *dest; | 306 void *dest; |
| 301 uint8_t data[32]; | 307 uint8_t data[32]; |
|
bsy
2010/11/11 21:27:21
!!
petr
2010/11/12 18:11:06
Done.
| |
| 302 fill_nops(data, sizeof(data)); | 308 fill_nops(data, sizeof(data)); |
| 303 | 309 |
| 304 /* This tries to load into the data segment, which is definitely not | 310 /* This tries to load into the data segment, which is definitely not |
| 305 allowed. */ | 311 allowed. */ |
| 306 dest = (uint8_t *) DYNAMIC_CODE_SEGMENT_END; | 312 dest = (uint8_t *) DYNAMIC_CODE_SEGMENT_END; |
| 307 rc = nacl_load_code(dest, data, sizeof(data)); | 313 rc = nacl_load_code(dest, data, sizeof(data)); |
| 308 assert(rc == -EFAULT); | 314 assert(rc == -EFAULT); |
| 309 | 315 |
| 310 /* This tries to load into the last bundle of the code region, which | 316 /* 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 | 317 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 | 373 |
| 368 /* Test again to make sure we didn't run out of space. */ | 374 /* Test again to make sure we didn't run out of space. */ |
| 369 RUN_TEST(test_loading_code); | 375 RUN_TEST(test_loading_code); |
| 370 | 376 |
| 371 return 0; | 377 return 0; |
| 372 } | 378 } |
| 373 | 379 |
| 374 int main() { | 380 int main() { |
| 375 return RunTests(TestMain); | 381 return RunTests(TestMain); |
| 376 } | 382 } |
| OLD | NEW |