void test_external_jump_target_replacement(void) {
  uint8_t *load_area = allocate_code_space(1);
  /* BUF_SIZE * 2 because this function necessarily has an extra bundle. */
  uint8_t buf[BUF_SIZE * 2];
  int rc;
  int (*func)(void);
  const int kNaClBundleSize = NACL_BUNDLE_SIZE;

  copy_and_pad_fragment(buf, sizeof(buf),
                        &template_func_external_jump_target,
                        &template_func_external_jump_target_end);

  rc = nacl_dyncode_create(load_area, buf, sizeof(buf));
  assert(rc == 0);
  func = (int (*)(void)) (uintptr_t) load_area;
  rc = func();
  assert(rc == MARKER_OLD);

  copy_and_pad_fragment(buf, sizeof(buf),
                        &template_func_external_jump_target_replace,
                        &template_func_external_jump_target_replace_end);
  /* Only copy one bundle so we can test an unaligned external jump target */
  rc = nacl_dyncode_modify(load_area, buf, kNaClBundleSize);
  assert(rc == 0);
  func = (int (*)(void)) (uintptr_t) load_area;
  rc = func();
  assert(rc == MARKER_NEW);
}
/* Check that we can dynamically rewrite code. */
void test_replacing_code_unaligned(void) {
  uint8_t *load_area = allocate_code_space(1);
  uint8_t buf[BUF_SIZE];
  int first_diff = 0;
  int rc;
  int (*func)(void);

  copy_and_pad_fragment(buf, sizeof(buf), &template_func, &template_func_end);
  rc = nacl_dyncode_create(load_area, buf, sizeof(buf));
  assert(rc == 0);
  func = (int (*)(void)) (uintptr_t) load_area;
  rc = func();
  assert(rc == MARKER_OLD);

  /* write replacement to the same location, unaligned */
  copy_and_pad_fragment(buf, sizeof(buf), &template_func_replacement,
                                          &template_func_replacement_end);
  /* we find first byte where old and new code differs */
  while (buf[first_diff] == load_area[first_diff] && first_diff < sizeof buf) {
    first_diff++;
  }
  /* and check, that there is some data in common, and some different */
  assert(first_diff > 0 && first_diff < sizeof(buf));
  rc = nacl_dyncode_modify(load_area+first_diff, buf+first_diff,
                           sizeof(buf)-first_diff);
  assert(rc == 0);
  func = (int (*)(void)) (uintptr_t) load_area;
  rc = func();
  assert(rc == MARKER_NEW);
}
/* Check code replacement constraints */
void test_illegal_code_replacment(void) {
  uint8_t *load_area = allocate_code_space(1);
  uint8_t buf[BUF_SIZE];
  int rc;
  int i;
  int (*func)(void);

  copy_and_pad_fragment(buf, sizeof(buf), &template_func, &template_func_end);
  rc = nacl_dyncode_create(load_area, buf, sizeof(buf));
  assert(rc == 0);
  func = (int (*)(void)) (uintptr_t) load_area;
  rc = func();
  assert(rc == MARKER_OLD);

  for (i = 0;
       i < (sizeof(illegal_code_sections) / sizeof(struct code_section));
       i++) {
    printf("\t%s\n", illegal_code_sections[i].name);

    /* write illegal replacement to the same location */
    copy_and_pad_fragment(buf, sizeof(buf), illegal_code_sections[i].start,
                                            illegal_code_sections[i].end);
    rc = nacl_dyncode_modify(load_area, buf, sizeof(buf));
    assert(rc != 0);
    func = (int (*)(void)) (uintptr_t) load_area;
    rc = func();
    assert(rc == MARKER_OLD);
  }
}
/* Check that we can dynamically delete code. */
void test_deleting_code(void) {
  uint8_t *load_area = (uint8_t *) allocate_code_space(1);
  uint8_t buf[BUF_SIZE];
  int rc;
  int (*func)(void);

  copy_and_pad_fragment(buf, sizeof(buf), &template_func, &template_func_end);
  rc = nacl_dyncode_create(load_area, buf, sizeof(buf));
  assert(rc == 0);
  func = (int (*)(void)) (uintptr_t) load_area;
  rc = func();
  assert(rc == MARKER_OLD);

  rc = dyncode_delete_with_retry(load_area, sizeof(buf));
  assert(rc == 0);
  assert(load_area[0] != buf[0]);

  /* Attempting to unload the code again should fail. */
  rc = nacl_dyncode_delete(load_area, sizeof(buf));
  assert(rc == -1);
  assert(errno == EFAULT);

  /*
   * We should be able to load new code at the same address.  This
   * assumes that no other threads are running, otherwise this request
   * can be rejected.
   *
   * This fails under ARM QEMU.  QEMU will flush its instruction
   * translation cache based on writes to the same virtual address,
   * but it ignores our explicit cache flush system calls.  Valgrind
   * has a similar problem, except that there is no cache flush system
   * call on x86.
   */
  if (getenv("UNDER_QEMU_ARM") != NULL ||
      getenv("RUNNING_ON_VALGRIND") != NULL) {
    printf("Skipping loading new code under emulator\n");
  } else {
    printf("Testing loading new code...\n");
    copy_and_pad_fragment(buf, sizeof(buf), &template_func_replacement,
                          &template_func_replacement_end);
    rc = nacl_dyncode_create(load_area, buf, sizeof(buf));
    assert(rc == 0);
    func = (int (*)(void)) (uintptr_t) load_area;
    rc = func();
    assert(rc == MARKER_NEW);

    rc = nacl_dyncode_delete(load_area, sizeof(buf));
    assert(rc == 0);
    assert(load_area[0] != buf[0]);
  }
}
int test_simle_replacement(const char *fragment1, const char *fragment1_end,
                           const char *fragment2, const char *fragment2_end) {
  uint8_t *load_area = allocate_code_space(1);
  uint8_t buf[BUF_SIZE];
  int rc;

  /* The original version is fine. */
  copy_and_pad_fragment(buf, sizeof(buf), fragment1, fragment1_end);
  rc = nacl_dyncode_create(load_area, buf, sizeof(buf));
  assert(rc == 0);

  copy_and_pad_fragment(buf, sizeof(buf), fragment2, fragment2_end);
  rc = nacl_dyncode_modify(load_area, buf, sizeof(buf));
  return rc;
}
void test_fail_on_overwrite() {
  void *load_area = allocate_code_space(1);
  uint8_t buf[32];
  int rc;

  copy_and_pad_fragment(buf, sizeof(buf), &template_func, &template_func_end);

  rc = nacl_load_code(load_area, buf, sizeof(buf));
  assert(rc == 0);

  copy_and_pad_fragment(buf, sizeof(buf), &template_func,
                                          &template_func_end);

  rc = nacl_load_code(load_area, buf, sizeof(buf));
  assert(rc == -EINVAL);
}
void test_validation_error_does_not_leak(void) {
  void *load_area = allocate_code_space(1);
  uint8_t buf[BUF_SIZE];
  int rc;

  copy_and_pad_fragment(buf, sizeof(buf), &invalid_code, &invalid_code_end);
  rc = nacl_load_code(load_area, buf, sizeof(buf));
  assert(rc == -EINVAL);

  /*
   * Make sure that the failed validation didn't claim the memory.
   * See: http://code.google.com/p/nativeclient/issues/detail?id=2566
   */
  copy_and_pad_fragment(buf, sizeof(buf), &template_func, &template_func_end);
  rc = nacl_load_code(load_area, buf, sizeof(buf));
  assert(rc == 0);
}
void test_fail_on_validation_error() {
  void *load_area = allocate_code_space(1);
  uint8_t buf[32];
  int rc;

  copy_and_pad_fragment(buf, sizeof(buf), &invalid_code, &invalid_code_end);

  rc = nacl_load_code(load_area, buf, sizeof(buf));
  assert(rc == -EINVAL);
}
void test_jump_into_super_inst_create(void) {
  uint8_t *load_area = allocate_code_space(1);
  uint8_t buf[BUF_SIZE];
  int rc;

  /* A direct jump into a bundle is invalid. */
  copy_and_pad_fragment(buf, sizeof(buf), &jump_into_super_inst_modified,
                        &jump_into_super_inst_modified_end);
  rc = nacl_dyncode_create(load_area, buf, sizeof(buf));
  assert(rc != 0);
  assert(errno == EINVAL);
}
/* Check that we can dynamically rewrite code. */
void test_replacing_code(void) {
  uint8_t *load_area = allocate_code_space(1);
  uint8_t buf[BUF_SIZE];
  int rc;
  int (*func)(void);

  copy_and_pad_fragment(buf, sizeof(buf), &template_func, &template_func_end);
  rc = nacl_dyncode_create(load_area, buf, sizeof(buf));
  assert(rc == 0);
  func = (int (*)(void)) (uintptr_t) load_area;
  rc = func();
  assert(rc == MARKER_OLD);

  /* write replacement to the same location */
  copy_and_pad_fragment(buf, sizeof(buf), &template_func_replacement,
                                          &template_func_replacement_end);
  rc = nacl_dyncode_modify(load_area, buf, sizeof(buf));
  assert(rc == 0);
  func = (int (*)(void)) (uintptr_t) load_area;
  rc = func();
  assert(rc == MARKER_NEW);
}
/* The syscall may have to mmap() shared memory temporarily,
   so there is some interaction with page size.
   Check that we can load to non-page-aligned addresses. */
void test_loading_code_non_page_aligned() {
  char *load_area = allocate_code_space(1);
  uint8_t buf[32];
  int rc;

  copy_and_pad_fragment(buf, sizeof(buf), &template_func, &template_func_end);

  rc = nacl_load_code(load_area, buf, sizeof(buf));
  assert(rc == 0);
  assert(memcmp(load_area, buf, sizeof(buf)) == 0);

  load_area += 32;
  rc = nacl_load_code(load_area, buf, sizeof(buf));
  assert(rc == 0);
  assert(memcmp(load_area, buf, sizeof(buf)) == 0);
}
/* Check that we can load and run code. */
void test_loading_code() {
  void *load_area = allocate_code_space(1);
  uint8_t buf[32];
  int rc;
  int (*func)();

  copy_and_pad_fragment(buf, sizeof(buf), &template_func, &template_func_end);

  rc = nacl_load_code(load_area, buf, sizeof(buf));
  assert(rc == 0);
  assert(memcmp(load_area, buf, sizeof(buf)) == 0);
  /* Need double cast otherwise gcc complains with "ISO C forbids
     conversion of object pointer to function pointer type
     [-pedantic]". */
  func = (int (*)()) (uintptr_t) load_area;
  rc = func();
  assert(rc == 1234);
}
/* Check that we can load code at the very beginning of the dynamic section. */
void test_loading_code_on_first_dynamic_page() {
  const unsigned int kPageMask = 0xFFFF;
  void *load_area = (void*)((uintptr_t)(etext + kPageMask) & ~kPageMask);
  uint8_t buf[32];
  int rc;
  int (*func)();

  copy_and_pad_fragment(buf, sizeof(buf), &template_func, &template_func_end);

  rc = nacl_load_code(load_area, buf, sizeof(buf));
  assert(rc == 0);
  assert(memcmp(load_area, buf, sizeof(buf)) == 0);
  /* Need double cast otherwise gcc complains with "ISO C forbids
     conversion of object pointer to function pointer type
     [-pedantic]". */
  func = (int (*)()) (uintptr_t) load_area;
  rc = func();
  assert(rc == 1234);
}
/*
 * This is mostly the same as test_loading_code() except that we
 * repeat the test many times within the same page.  Unlike the other
 * tests, this will consistently fail on ARM if we do not flush the
 * instruction cache, so it reproduces the bug
 * http://code.google.com/p/nativeclient/issues/detail?id=699
 */
void test_stress(void) {
  void *load_area = allocate_code_space(1);
  uint8_t *dest;
  uint8_t *dest_max;
  uint8_t buf[BUF_SIZE];

  copy_and_pad_fragment(buf, sizeof(buf), &template_func, &template_func_end);

  dest_max = (uint8_t *) load_area + DYNAMIC_CODE_PAGE_SIZE;
  for (dest = load_area; dest < dest_max; dest += sizeof(buf)) {
    int (*func)(void);
    int rc;

    rc = nacl_load_code(dest, buf, sizeof(buf));
    assert(rc == 0);
    func = (int (*)(void)) (uintptr_t) dest;
    rc = func();
    assert(rc == MARKER_OLD);
  }
}