1f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)// Copyright 2014 The Chromium Authors. All rights reserved.
2f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
3f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)// found in the LICENSE file.
4f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
5f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#include "crazy_linker_elf_relro.h"
6f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
7f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#include <errno.h>
8f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#include <limits.h>
9f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#include <stdlib.h>
10f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
11f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#include "crazy_linker_elf_relocations.h"
12f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#include "crazy_linker_elf_view.h"
13f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#include "crazy_linker_memory_mapping.h"
14f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#include "crazy_linker_util.h"
15f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
16f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)namespace crazy {
17f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
18f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)namespace {
19f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
20f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)inline bool PageEquals(const char* p1, const char* p2) {
21f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  return ::memcmp(p1, p2, PAGE_SIZE) == 0;
22f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)}
23f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
24f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)// Swap pages between |addr| and |addr + size| with the bytes
25f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)// from the ashmem region identified by |fd|, starting from
26f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)// a given |offset|. On failure return false and set |error| message.
27f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)bool SwapPagesFromFd(void* addr,
28f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                     size_t size,
29f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                     int fd,
30f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                     size_t offset,
31f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                     Error* error) {
32f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  // Unmap current pages.
33f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  if (::munmap(addr, size) < 0) {
34f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    error->Format("%s: Could not unmap %p-%p: %s",
35f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                  __FUNCTION__,
36f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                  addr,
37f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                  (char*)addr + size,
38f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                  strerror(errno));
39f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    return false;
40f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  }
41f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
42f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  // Remap the fd pages at the same location now.
43f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  void* new_map = ::mmap(addr,
44f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                         size,
45f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                         PROT_READ,
46f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                         MAP_FIXED | MAP_SHARED,
47f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                         fd,
48f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                         static_cast<off_t>(offset));
49f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  if (new_map == MAP_FAILED) {
50f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    char* p = reinterpret_cast<char*>(addr);
51f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    error->Format("%s: Could not map %p-%p: %s",
52f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                  __FUNCTION__,
53f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                  p,
54f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                  p + size,
55f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                  strerror(errno));
56f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    return false;
57f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  }
58f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
59f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)// TODO(digit): Is this necessary?
60f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#ifdef __arm__
61f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  __clear_cache(addr, (char*)addr + size);
62f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#endif
63f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
64f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  // Done.
65f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  return true;
66f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)}
67f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
68f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)}  // namespace
69f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
70f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)bool SharedRelro::Allocate(size_t relro_size,
71f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                           const char* library_name,
72f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                           Error* error) {
73f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  // Allocate a new ashmem region.
74f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  String name("RELRO:");
75f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  name += library_name;
76f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  if (!ashmem_.Allocate(relro_size, name.c_str())) {
77f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    error->Format("Could not allocate RELRO ashmem region for %s: %s",
78f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                  library_name,
79f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                  strerror(errno));
80f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    return false;
81f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  }
82f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
83f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  start_ = 0;
84f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  size_ = relro_size;
85f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  return true;
86f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)}
87f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
88f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)bool SharedRelro::CopyFrom(size_t relro_start,
89f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                           size_t relro_size,
90f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                           Error* error) {
91f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  // Map it in the process.
92f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  ScopedMemoryMapping map;
93f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  if (!map.Allocate(NULL, relro_size, MemoryMapping::CAN_WRITE, ashmem_.fd())) {
94f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    error->Format("Could not allocate RELRO mapping: %s", strerror(errno));
95f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    return false;
96f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  }
97f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
98f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  // Copy process' RELRO into it.
99f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  ::memcpy(map.Get(), reinterpret_cast<void*>(relro_start), relro_size);
100f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
101f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  // Unmap it.
102f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  map.Deallocate();
103f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
104f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  // Everything's good.
105f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  start_ = relro_start;
106f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  size_ = relro_size;
107f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  return true;
108f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)}
109f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
110f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)bool SharedRelro::CopyFromRelocated(const ElfView* view,
111f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                                    size_t load_address,
112f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                                    size_t relro_start,
113f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                                    size_t relro_size,
114f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                                    Error* error) {
115f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  // Offset of RELRO section in current library.
116f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  size_t relro_offset = relro_start - view->load_address();
117f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
118f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  ElfRelocations relocations;
119f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  if (!relocations.Init(view, error))
120f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    return false;
121f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
122f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  // Map the region in memory (any address).
123f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  ScopedMemoryMapping map;
124f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  if (!map.Allocate(
125f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)           NULL, relro_size, MemoryMapping::CAN_READ_WRITE, ashmem_.fd())) {
126f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    error->Format("Could not allocate RELRO mapping for: %s", strerror(errno));
127f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    return false;
128f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  }
129f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
130f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  // Copy and relocate.
131f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  relocations.CopyAndRelocate(relro_start,
132f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                              reinterpret_cast<size_t>(map.Get()),
133f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                              load_address + relro_offset,
134f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                              relro_size);
135f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  // Unmap it.
136f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  map.Deallocate();
137f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  start_ = load_address + relro_offset;
138f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  size_ = relro_size;
139f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  return true;
140f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)}
141f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
142f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)bool SharedRelro::ForceReadOnly(Error* error) {
143f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  // Ensure the ashmem region content isn't writable anymore.
144f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  if (!ashmem_.SetProtectionFlags(PROT_READ)) {
145f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    error->Format("Could not make RELRO ashmem region read-only: %s",
146f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                  strerror(errno));
147f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    return false;
148f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  }
149f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  return true;
150f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)}
151f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
152f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)bool SharedRelro::InitFrom(size_t relro_start,
153f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                           size_t relro_size,
154f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                           int ashmem_fd,
155f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                           Error* error) {
156f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  // Create temporary mapping of the ashmem region.
157f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  ScopedMemoryMapping fd_map;
158f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
159f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  LOG("%s: Entering addr=%p size=%p fd=%d\n",
160f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      __FUNCTION__,
161f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      (void*)relro_start,
162f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      (void*)relro_size,
163f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      ashmem_fd);
164f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
165f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  // Sanity check: Ashmem file descriptor must be read-only.
166f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  if (!AshmemRegion::CheckFileDescriptorIsReadOnly(ashmem_fd)) {
167f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    error->Format("Ashmem file descriptor is not read-only: %s\n",
168f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                  strerror(errno));
169f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    return false;
170f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  }
171f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
172f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  if (!fd_map.Allocate(NULL, relro_size, MemoryMapping::CAN_READ, ashmem_fd)) {
173f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    error->Format("Cannot map RELRO ashmem region as read-only: %s\n",
174f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                  strerror(errno));
175f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    return false;
176f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  }
177f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
178f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  LOG("%s: mapping allocated at %p\n", __FUNCTION__, fd_map.Get());
179f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
180f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  char* cur_page = reinterpret_cast<char*>(relro_start);
181f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  char* fd_page = static_cast<char*>(fd_map.Get());
182f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  size_t p = 0;
183f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  size_t size = relro_size;
184f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  size_t similar_size = 0;
185f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
186f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  do {
187f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    // Skip over dissimilar pages.
188f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    while (p < size && !PageEquals(cur_page + p, fd_page + p)) {
189f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      p += PAGE_SIZE;
190f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    }
191f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
192f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    // Count similar pages.
193f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    size_t p2 = p;
194f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    while (p2 < size && PageEquals(cur_page + p2, fd_page + p2)) {
195f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      p2 += PAGE_SIZE;
196f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    }
197f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
198f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    if (p2 > p) {
199f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      // Swap pages between |pos| and |pos2|.
200f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      LOG("%s: Swap pages at %p-%p\n",
201f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)          __FUNCTION__,
202f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)          cur_page + p,
203f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)          cur_page + p2);
204f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      if (!SwapPagesFromFd(cur_page + p, p2 - p, ashmem_fd, p, error))
205f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)        return false;
206f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
207f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      similar_size += (p2 - p);
208f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    }
209f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
210f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    p = p2;
211f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  } while (p < size);
212f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
213f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  LOG("%s: Swapped %d pages over %d (%d %%, %d KB not shared)\n",
214f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      __FUNCTION__,
215f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      similar_size / PAGE_SIZE,
216f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      size / PAGE_SIZE,
217f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      similar_size * 100 / size,
218f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      (size - similar_size) / 4096);
219f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
220f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  if (similar_size == 0)
221f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    return false;
222f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
223f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  start_ = relro_start;
224f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  size_ = relro_size;
225f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  return true;
226f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)}
227f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
228f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)}  // namespace crazy
229