1a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project/* -----------------------------------------------------------------------
2a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project   closures.c - Copyright (c) 2007  Red Hat, Inc.
3a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project   Copyright (C) 2007 Free Software Foundation, Inc
4a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project
5a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project   Code to allocate and deallocate memory for closures.
6a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project
7a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project   Permission is hereby granted, free of charge, to any person obtaining
8a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project   a copy of this software and associated documentation files (the
9a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project   ``Software''), to deal in the Software without restriction, including
10a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project   without limitation the rights to use, copy, modify, merge, publish,
11a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project   distribute, sublicense, and/or sell copies of the Software, and to
12a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project   permit persons to whom the Software is furnished to do so, subject to
13a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project   the following conditions:
14a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project
15a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project   The above copyright notice and this permission notice shall be included
16a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project   in all copies or substantial portions of the Software.
17a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project
18a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project   THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND,
19a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project   MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
21a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project   NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
22a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project   HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
23a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project   WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project   OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
25a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project   DEALINGS IN THE SOFTWARE.
26a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project   ----------------------------------------------------------------------- */
27a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project
28a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project#if defined __linux__ && !defined _GNU_SOURCE
29a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project#define _GNU_SOURCE 1
30a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project#endif
31a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project
32a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project#include <ffi.h>
33a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project#include <ffi_common.h>
34a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project
35a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project#ifndef FFI_MMAP_EXEC_WRIT
36a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project# if __gnu_linux__
37a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project/* This macro indicates it may be forbidden to map anonymous memory
38a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project   with both write and execute permission.  Code compiled when this
39a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project   option is defined will attempt to map such pages once, but if it
40a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project   fails, it falls back to creating a temporary file in a writable and
41a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project   executable filesystem and mapping pages from it into separate
42a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project   locations in the virtual memory space, one location writable and
43a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project   another executable.  */
44a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project#  define FFI_MMAP_EXEC_WRIT 1
45a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project# endif
46a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project#endif
47a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project
48a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project#if FFI_MMAP_EXEC_WRIT && !defined FFI_MMAP_EXEC_SELINUX
49a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project# ifdef __linux__
50a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project/* When defined to 1 check for SELinux and if SELinux is active,
51a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project   don't attempt PROT_EXEC|PROT_WRITE mapping at all, as that
52a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project   might cause audit messages.  */
53a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project#  define FFI_MMAP_EXEC_SELINUX 1
54a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project# endif
55a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project#endif
56a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project
57a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project#if FFI_CLOSURES
58a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project
59a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project# if FFI_MMAP_EXEC_WRIT
60a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project
61a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project#define USE_LOCKS 1
62a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project#define USE_DL_PREFIX 1
63a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project#define USE_BUILTIN_FFS 1
64a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project
65a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project/* We need to use mmap, not sbrk.  */
66a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project#define HAVE_MORECORE 0
67a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project
68a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project/* We could, in theory, support mremap, but it wouldn't buy us anything.  */
69a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project#define HAVE_MREMAP 0
70a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project
71a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project/* We have no use for this, so save some code and data.  */
72a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project#define NO_MALLINFO 1
73a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project
74a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project/* We need all allocations to be in regular segments, otherwise we
75a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project   lose track of the corresponding code address.  */
76a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project#define DEFAULT_MMAP_THRESHOLD MAX_SIZE_T
77a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project
78a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project/* Don't allocate more than a page unless needed.  */
79a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project#define DEFAULT_GRANULARITY ((size_t)malloc_getpagesize)
80a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project
81a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project#if FFI_CLOSURE_TEST
82a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project/* Don't release single pages, to avoid a worst-case scenario of
83a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project   continuously allocating and releasing single pages, but release
84a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project   pairs of pages, which should do just as well given that allocations
85a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project   are likely to be small.  */
86a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project#define DEFAULT_TRIM_THRESHOLD ((size_t)malloc_getpagesize)
87a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project#endif
88a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project
89a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project#include <sys/types.h>
90a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project#include <sys/stat.h>
91a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project#include <fcntl.h>
92a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project#include <errno.h>
93a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project#include <unistd.h>
94a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project#include <string.h>
95a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project#include <stdio.h>
96a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project#include <mntent.h>
97a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project#include <sys/param.h>
98a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project#include <pthread.h>
99a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project
100a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project/* We don't want sys/mman.h to be included after we redefine mmap and
101a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project   dlmunmap.  */
102a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project#include <sys/mman.h>
103a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project#define LACKS_SYS_MMAN_H 1
104a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project
105a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project#if FFI_MMAP_EXEC_SELINUX
106a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project#include <sys/statfs.h>
107a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project#include <stdlib.h>
108a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project
109a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Projectstatic int selinux_enabled = -1;
110a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project
111a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Projectstatic int
112a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Projectselinux_enabled_check (void)
113a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project{
114a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project  struct statfs sfs;
115a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project  FILE *f;
116a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project  char *buf = NULL;
117a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project  size_t len = 0;
118a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project
119a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project  if (statfs ("/selinux", &sfs) >= 0
120a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project      && (unsigned int) sfs.f_type == 0xf97cff8cU)
121a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project    return 1;
122a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project  f = fopen ("/proc/mounts", "r");
123a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project  if (f == NULL)
124a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project    return 0;
125a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project  while (getline (&buf, &len, f) >= 0)
126a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project    {
127a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project      char *p = strchr (buf, ' ');
128a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project      if (p == NULL)
129a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project        break;
130a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project      p = strchr (p + 1, ' ');
131a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project      if (p == NULL)
132a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project        break;
133a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project      if (strncmp (p + 1, "selinuxfs ", 10) != 0)
134a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project        {
135a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project          free (buf);
136a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project          fclose (f);
137a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project          return 1;
138a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project        }
139a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project    }
140a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project  free (buf);
141a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project  fclose (f);
142a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project  return 0;
143a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project}
144a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project
145a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project#define is_selinux_enabled() (selinux_enabled >= 0 ? selinux_enabled \
146a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project			      : (selinux_enabled = selinux_enabled_check ()))
147a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project
148a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project#else
149a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project
150a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project#define is_selinux_enabled() 0
151a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project
152a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project#endif
153a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project
154a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project/* Declare all functions defined in dlmalloc.c as static.  */
155a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Projectstatic void *dlmalloc(size_t);
156a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Projectstatic void dlfree(void*);
157a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Projectstatic void *dlcalloc(size_t, size_t) MAYBE_UNUSED;
158a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Projectstatic void *dlrealloc(void *, size_t) MAYBE_UNUSED;
159a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Projectstatic void *dlmemalign(size_t, size_t) MAYBE_UNUSED;
160a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Projectstatic void *dlvalloc(size_t) MAYBE_UNUSED;
161a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Projectstatic int dlmallopt(int, int) MAYBE_UNUSED;
162a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Projectstatic size_t dlmalloc_footprint(void) MAYBE_UNUSED;
163a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Projectstatic size_t dlmalloc_max_footprint(void) MAYBE_UNUSED;
164a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Projectstatic void** dlindependent_calloc(size_t, size_t, void**) MAYBE_UNUSED;
165a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Projectstatic void** dlindependent_comalloc(size_t, size_t*, void**) MAYBE_UNUSED;
166a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Projectstatic void *dlpvalloc(size_t) MAYBE_UNUSED;
167a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Projectstatic int dlmalloc_trim(size_t) MAYBE_UNUSED;
168a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Projectstatic size_t dlmalloc_usable_size(void*) MAYBE_UNUSED;
169a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Projectstatic void dlmalloc_stats(void) MAYBE_UNUSED;
170a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project
171a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project/* Use these for mmap and munmap within dlmalloc.c.  */
172a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Projectstatic void *dlmmap(void *, size_t, int, int, int, off_t);
173a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Projectstatic int dlmunmap(void *, size_t);
174a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project
175a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project#define mmap dlmmap
176a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project#define munmap dlmunmap
177a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project
178a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project#include "dlmalloc.c"
179a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project
180a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project#undef mmap
181a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project#undef munmap
182a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project
183a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project/* A mutex used to synchronize access to *exec* variables in this file.  */
184a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Projectstatic pthread_mutex_t open_temp_exec_file_mutex = PTHREAD_MUTEX_INITIALIZER;
185a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project
186a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project/* A file descriptor of a temporary file from which we'll map
187a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project   executable pages.  */
188a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Projectstatic int execfd = -1;
189a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project
190a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project/* The amount of space already allocated from the temporary file.  */
191a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Projectstatic size_t execsize = 0;
192a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project
193a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project/* Open a temporary file name, and immediately unlink it.  */
194a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Projectstatic int
195a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Projectopen_temp_exec_file_name (char *name)
196a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project{
197a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project  int fd = mkstemp (name);
198a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project
199a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project  if (fd != -1)
200a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project    unlink (name);
201a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project
202a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project  return fd;
203a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project}
204a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project
205a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project/* Open a temporary file in the named directory.  */
206a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Projectstatic int
207a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Projectopen_temp_exec_file_dir (const char *dir)
208a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project{
209a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project  static const char suffix[] = "/ffiXXXXXX";
210a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project  int lendir = strlen (dir);
211a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project  char *tempname = __builtin_alloca (lendir + sizeof (suffix));
212a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project
213a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project  if (!tempname)
214a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project    return -1;
215a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project
216a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project  memcpy (tempname, dir, lendir);
217a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project  memcpy (tempname + lendir, suffix, sizeof (suffix));
218a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project
219a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project  return open_temp_exec_file_name (tempname);
220a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project}
221a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project
222a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project/* Open a temporary file in the directory in the named environment
223a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project   variable.  */
224a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Projectstatic int
225a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Projectopen_temp_exec_file_env (const char *envvar)
226a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project{
227a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project  const char *value = getenv (envvar);
228a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project
229a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project  if (!value)
230a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project    return -1;
231a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project
232a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project  return open_temp_exec_file_dir (value);
233a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project}
234a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project
235a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project/* Open a temporary file in an executable and writable mount point
236a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project   listed in the mounts file.  Subsequent calls with the same mounts
237a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project   keep searching for mount points in the same file.  Providing NULL
238a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project   as the mounts file closes the file.  */
239a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Projectstatic int
240a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Projectopen_temp_exec_file_mnt (const char *mounts)
241a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project{
242a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project  static const char *last_mounts;
243a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project  static FILE *last_mntent;
244a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project
245a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project  if (mounts != last_mounts)
246a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project    {
247a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project      if (last_mntent)
248a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project	endmntent (last_mntent);
249a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project
250a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project      last_mounts = mounts;
251a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project
252a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project      if (mounts)
253a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project	last_mntent = setmntent (mounts, "r");
254a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project      else
255a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project	last_mntent = NULL;
256a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project    }
257a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project
258a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project  if (!last_mntent)
259a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project    return -1;
260a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project
261a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project  for (;;)
262a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project    {
263a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project      int fd;
264a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project      struct mntent mnt;
265a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project      char buf[MAXPATHLEN * 3];
266a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project
267a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project      if (getmntent_r (last_mntent, &mnt, buf, sizeof (buf)))
268a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project	return -1;
269a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project
270a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project      if (hasmntopt (&mnt, "ro")
271a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project	  || hasmntopt (&mnt, "noexec")
272a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project	  || access (mnt.mnt_dir, W_OK))
273a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project	continue;
274a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project
275a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project      fd = open_temp_exec_file_dir (mnt.mnt_dir);
276a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project
277a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project      if (fd != -1)
278a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project	return fd;
279a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project    }
280a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project}
281a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project
282a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project/* Instructions to look for a location to hold a temporary file that
283a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project   can be mapped in for execution.  */
284a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Projectstatic struct
285a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project{
286a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project  int (*func)(const char *);
287a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project  const char *arg;
288a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project  int repeat;
289a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project} open_temp_exec_file_opts[] = {
290a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project  { open_temp_exec_file_env, "TMPDIR", 0 },
291a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project  { open_temp_exec_file_dir, "/tmp", 0 },
292a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project  { open_temp_exec_file_dir, "/var/tmp", 0 },
293a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project  { open_temp_exec_file_dir, "/dev/shm", 0 },
294a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project  { open_temp_exec_file_env, "HOME", 0 },
295a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project  { open_temp_exec_file_mnt, "/etc/mtab", 1 },
296a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project  { open_temp_exec_file_mnt, "/proc/mounts", 1 },
297a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project};
298a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project
299a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project/* Current index into open_temp_exec_file_opts.  */
300a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Projectstatic int open_temp_exec_file_opts_idx = 0;
301a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project
302a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project/* Reset a current multi-call func, then advances to the next entry.
303a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project   If we're at the last, go back to the first and return nonzero,
304a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project   otherwise return zero.  */
305a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Projectstatic int
306a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Projectopen_temp_exec_file_opts_next (void)
307a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project{
308a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project  if (open_temp_exec_file_opts[open_temp_exec_file_opts_idx].repeat)
309a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project    open_temp_exec_file_opts[open_temp_exec_file_opts_idx].func (NULL);
310a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project
311a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project  open_temp_exec_file_opts_idx++;
312a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project  if (open_temp_exec_file_opts_idx
313a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project      == (sizeof (open_temp_exec_file_opts)
314a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project	  / sizeof (*open_temp_exec_file_opts)))
315a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project    {
316a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project      open_temp_exec_file_opts_idx = 0;
317a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project      return 1;
318a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project    }
319a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project
320a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project  return 0;
321a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project}
322a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project
323a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project/* Return a file descriptor of a temporary zero-sized file in a
324a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project   writable and exexutable filesystem.  */
325a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Projectstatic int
326a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Projectopen_temp_exec_file (void)
327a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project{
328a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project  int fd;
329a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project
330a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project  do
331a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project    {
332a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project      fd = open_temp_exec_file_opts[open_temp_exec_file_opts_idx].func
333a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project	(open_temp_exec_file_opts[open_temp_exec_file_opts_idx].arg);
334a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project
335a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project      if (!open_temp_exec_file_opts[open_temp_exec_file_opts_idx].repeat
336a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project	  || fd == -1)
337a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project	{
338a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project	  if (open_temp_exec_file_opts_next ())
339a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project	    break;
340a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project	}
341a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project    }
342a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project  while (fd == -1);
343a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project
344a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project  return fd;
345a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project}
346a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project
347a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project/* Map in a chunk of memory from the temporary exec file into separate
348a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project   locations in the virtual memory address space, one writable and one
349a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project   executable.  Returns the address of the writable portion, after
350a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project   storing an offset to the corresponding executable portion at the
351a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project   last word of the requested chunk.  */
352a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Projectstatic void *
353a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Projectdlmmap_locked (void *start, size_t length, int prot, int flags, off_t offset)
354a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project{
355a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project  void *ptr;
356a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project
357a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project  if (execfd == -1)
358a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project    {
359a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project      open_temp_exec_file_opts_idx = 0;
360a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project    retry_open:
361a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project      execfd = open_temp_exec_file ();
362a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project      if (execfd == -1)
363a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project	return MFAIL;
364a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project    }
365a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project
366a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project  offset = execsize;
367a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project
368a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project  if (ftruncate (execfd, offset + length))
369a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project    return MFAIL;
370a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project
371a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project  flags &= ~(MAP_PRIVATE | MAP_ANONYMOUS);
372a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project  flags |= MAP_SHARED;
373a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project
374a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project  ptr = mmap (NULL, length, (prot & ~PROT_WRITE) | PROT_EXEC,
375a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project	      flags, execfd, offset);
376a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project  if (ptr == MFAIL)
377a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project    {
378a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project      if (!offset)
379a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project	{
380a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project	  close (execfd);
381a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project	  goto retry_open;
382a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project	}
383a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project      ftruncate (execfd, offset);
384a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project      return MFAIL;
385a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project    }
386a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project  else if (!offset
387a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project	   && open_temp_exec_file_opts[open_temp_exec_file_opts_idx].repeat)
388a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project    open_temp_exec_file_opts_next ();
389a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project
390a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project  start = mmap (start, length, prot, flags, execfd, offset);
391a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project
392a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project  if (start == MFAIL)
393a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project    {
394a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project      munmap (ptr, length);
395a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project      ftruncate (execfd, offset);
396a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project      return start;
397a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project    }
398a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project
399a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project  mmap_exec_offset ((char *)start, length) = (char*)ptr - (char*)start;
400a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project
401a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project  execsize += length;
402a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project
403a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project  return start;
404a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project}
405a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project
406a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project/* Map in a writable and executable chunk of memory if possible.
407a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project   Failing that, fall back to dlmmap_locked.  */
408a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Projectstatic void *
409a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Projectdlmmap (void *start, size_t length, int prot,
410a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project	int flags, int fd, off_t offset)
411a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project{
412a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project  void *ptr;
413a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project
414a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project  assert (start == NULL && length % malloc_getpagesize == 0
415a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project	  && prot == (PROT_READ | PROT_WRITE)
416a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project	  && flags == (MAP_PRIVATE | MAP_ANONYMOUS)
417a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project	  && fd == -1 && offset == 0);
418a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project
419a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project#if FFI_CLOSURE_TEST
420a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project  printf ("mapping in %zi\n", length);
421a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project#endif
422a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project
423a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project  if (execfd == -1 && !is_selinux_enabled ())
424a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project    {
425a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project      ptr = mmap (start, length, prot | PROT_EXEC, flags, fd, offset);
426a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project
427a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project      if (ptr != MFAIL || (errno != EPERM && errno != EACCES))
428a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project	/* Cool, no need to mess with separate segments.  */
429a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project	return ptr;
430a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project
431a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project      /* If MREMAP_DUP is ever introduced and implemented, try mmap
432a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project	 with ((prot & ~PROT_WRITE) | PROT_EXEC) and mremap with
433a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project	 MREMAP_DUP and prot at this point.  */
434a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project    }
435a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project
436a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project  if (execsize == 0 || execfd == -1)
437a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project    {
438a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project      pthread_mutex_lock (&open_temp_exec_file_mutex);
439a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project      ptr = dlmmap_locked (start, length, prot, flags, offset);
440a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project      pthread_mutex_unlock (&open_temp_exec_file_mutex);
441a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project
442a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project      return ptr;
443a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project    }
444a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project
445a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project  return dlmmap_locked (start, length, prot, flags, offset);
446a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project}
447a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project
448a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project/* Release memory at the given address, as well as the corresponding
449a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project   executable page if it's separate.  */
450a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Projectstatic int
451a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Projectdlmunmap (void *start, size_t length)
452a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project{
453a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project  /* We don't bother decreasing execsize or truncating the file, since
454a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project     we can't quite tell whether we're unmapping the end of the file.
455a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project     We don't expect frequent deallocation anyway.  If we did, we
456a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project     could locate pages in the file by writing to the pages being
457a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project     deallocated and checking that the file contents change.
458a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project     Yuck.  */
459a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project  msegmentptr seg = segment_holding (gm, start);
460a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project  void *code;
461a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project
462a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project#if FFI_CLOSURE_TEST
463a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project  printf ("unmapping %zi\n", length);
464a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project#endif
465a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project
466a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project  if (seg && (code = add_segment_exec_offset (start, seg)) != start)
467a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project    {
468a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project      int ret = munmap (code, length);
469a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project      if (ret)
470a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project	return ret;
471a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project    }
472a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project
473a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project  return munmap (start, length);
474a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project}
475a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project
476a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project#if FFI_CLOSURE_FREE_CODE
477a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project/* Return segment holding given code address.  */
478a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Projectstatic msegmentptr
479a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Projectsegment_holding_code (mstate m, char* addr)
480a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project{
481a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project  msegmentptr sp = &m->seg;
482a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project  for (;;) {
483a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project    if (addr >= add_segment_exec_offset (sp->base, sp)
484a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project	&& addr < add_segment_exec_offset (sp->base, sp) + sp->size)
485a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project      return sp;
486a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project    if ((sp = sp->next) == 0)
487a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project      return 0;
488a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project  }
489a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project}
490a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project#endif
491a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project
492a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project/* Allocate a chunk of memory with the given size.  Returns a pointer
493a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project   to the writable address, and sets *CODE to the executable
494a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project   corresponding virtual address.  */
495a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Projectvoid *
496a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Projectffi_closure_alloc (size_t size, void **code)
497a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project{
498a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project  void *ptr;
499a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project
500a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project  if (!code)
501a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project    return NULL;
502a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project
503a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project  ptr = dlmalloc (size);
504a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project
505a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project  if (ptr)
506a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project    {
507a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project      msegmentptr seg = segment_holding (gm, ptr);
508a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project
509a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project      *code = add_segment_exec_offset (ptr, seg);
510a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project    }
511a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project
512a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project  return ptr;
513a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project}
514a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project
515a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project/* Release a chunk of memory allocated with ffi_closure_alloc.  If
516a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project   FFI_CLOSURE_FREE_CODE is nonzero, the given address can be the
517a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project   writable or the executable address given.  Otherwise, only the
518a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project   writable address can be provided here.  */
519a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Projectvoid
520a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Projectffi_closure_free (void *ptr)
521a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project{
522a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project#if FFI_CLOSURE_FREE_CODE
523a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project  msegmentptr seg = segment_holding_code (gm, ptr);
524a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project
525a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project  if (seg)
526a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project    ptr = sub_segment_exec_offset (ptr, seg);
527a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project#endif
528a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project
529a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project  dlfree (ptr);
530a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project}
531a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project
532a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project
533a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project#if FFI_CLOSURE_TEST
534a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project/* Do some internal sanity testing to make sure allocation and
535a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project   deallocation of pages are working as intended.  */
536a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Projectint main ()
537a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project{
538a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project  void *p[3];
539a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project#define GET(idx, len) do { p[idx] = dlmalloc (len); printf ("allocated %zi for p[%i]\n", (len), (idx)); } while (0)
540a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project#define PUT(idx) do { printf ("freeing p[%i]\n", (idx)); dlfree (p[idx]); } while (0)
541a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project  GET (0, malloc_getpagesize / 2);
542a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project  GET (1, 2 * malloc_getpagesize - 64 * sizeof (void*));
543a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project  PUT (1);
544a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project  GET (1, 2 * malloc_getpagesize);
545a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project  GET (2, malloc_getpagesize / 2);
546a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project  PUT (1);
547a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project  PUT (0);
548a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project  PUT (2);
549a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project  return 0;
550a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project}
551a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project#endif /* FFI_CLOSURE_TEST */
552a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project# else /* ! FFI_MMAP_EXEC_WRIT */
553a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project
554a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project/* On many systems, memory returned by malloc is writable and
555a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project   executable, so just use it.  */
556a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project
557a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project#include <stdlib.h>
558a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project
559a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Projectvoid *
560a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Projectffi_closure_alloc (size_t size, void **code)
561a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project{
562a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project  if (!code)
563a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project    return NULL;
564a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project
565a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project  return *code = malloc (size);
566a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project}
567a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project
568a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Projectvoid
569a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Projectffi_closure_free (void *ptr)
570a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project{
571a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project  free (ptr);
572a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project}
573a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project
574a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project# endif /* ! FFI_MMAP_EXEC_WRIT */
575a89495f48f185779ff7d9d64ce6e6b037c9ded87The Android Open Source Project#endif /* FFI_CLOSURES */
576